From 7693923a363baaf8ac5449127a37117b2326f22b Mon Sep 17 00:00:00 2001 From: Roman Sergeenko Date: Mon, 24 Jun 2024 14:48:30 +0200 Subject: [PATCH 001/256] #RI-5842 - add tabs to browser --- .../main-router/constants/defaultRoutes.ts | 21 +++-- .../main-router/constants/redisStackRoutes.ts | 41 ++++++--- .../constants/sub-routes/browserRoutes.ts | 22 +++++ .../main-router/constants/sub-routes/index.ts | 2 + .../navigation-menu/NavigationMenu.spec.tsx | 29 ++++--- .../navigation-menu/NavigationMenu.tsx | 29 ++----- .../insights-trigger/InsightsTrigger.spec.tsx | 2 +- redisinsight/ui/src/constants/pages.ts | 11 ++- .../ui/src/pages/browser/BrowserPage.spec.tsx | 2 - .../ui/src/pages/browser/BrowserPage.tsx | 2 - .../ui/src/pages/browser/styles.module.scss | 19 +---- .../top-namespace/TopNamespace.spec.tsx | 2 +- .../database-alias/DatabaseAlias.tsx | 11 +-- .../DatabasesListWrapper.tsx | 10 +-- .../ui/src/pages/keys/KeysPage.spec.tsx | 85 +++++++++++++++++++ redisinsight/ui/src/pages/keys/KeysPage.tsx | 62 ++++++++++++++ .../browser-tabs/BrowserTabs.spec.tsx | 40 +++++++++ .../components/browser-tabs/BrowserTabs.tsx | 67 +++++++++++++++ .../keys/components/browser-tabs/index.ts | 3 + .../browser-tabs/styles.module.scss | 44 ++++++++++ redisinsight/ui/src/pages/keys/index.ts | 3 + .../ui/src/pages/search/SearchPage.spec.tsx | 10 +++ .../ui/src/pages/search/SearchPage.tsx | 14 +++ redisinsight/ui/src/pages/search/index.ts | 3 + .../ui/src/pages/workbench/WorkbenchPage.tsx | 6 -- .../components/wb-view/WBViewWrapper.tsx | 2 +- redisinsight/ui/src/slices/app/context.ts | 4 +- redisinsight/ui/src/slices/interfaces/app.ts | 2 +- .../ui/src/slices/tests/app/context.spec.ts | 2 +- .../ui/src/utils/routerWithSubRoutes.tsx | 20 +++-- redisinsight/ui/src/utils/routing.ts | 7 +- .../ui/src/utils/tests/routing.spec.ts | 6 +- 32 files changed, 469 insertions(+), 114 deletions(-) create mode 100644 redisinsight/ui/src/components/main-router/constants/sub-routes/browserRoutes.ts create mode 100644 redisinsight/ui/src/pages/keys/KeysPage.spec.tsx create mode 100644 redisinsight/ui/src/pages/keys/KeysPage.tsx create mode 100644 redisinsight/ui/src/pages/keys/components/browser-tabs/BrowserTabs.spec.tsx create mode 100644 redisinsight/ui/src/pages/keys/components/browser-tabs/BrowserTabs.tsx create mode 100644 redisinsight/ui/src/pages/keys/components/browser-tabs/index.ts create mode 100644 redisinsight/ui/src/pages/keys/components/browser-tabs/styles.module.scss create mode 100644 redisinsight/ui/src/pages/keys/index.ts create mode 100644 redisinsight/ui/src/pages/search/SearchPage.spec.tsx create mode 100644 redisinsight/ui/src/pages/search/SearchPage.tsx create mode 100644 redisinsight/ui/src/pages/search/index.ts diff --git a/redisinsight/ui/src/components/main-router/constants/defaultRoutes.ts b/redisinsight/ui/src/components/main-router/constants/defaultRoutes.ts index 030df4cf24..3e42509952 100644 --- a/redisinsight/ui/src/components/main-router/constants/defaultRoutes.ts +++ b/redisinsight/ui/src/components/main-router/constants/defaultRoutes.ts @@ -1,6 +1,5 @@ import { IRoute, FeatureFlags, PageNames, Pages } from 'uiSrc/constants' import { - BrowserPage, HomePage, InstancePage, RedisCloudDatabasesPage, @@ -9,27 +8,23 @@ import { RedisCloudSubscriptionsPage, RedisClusterDatabasesPage, } from 'uiSrc/pages' -import WorkbenchPage from 'uiSrc/pages/workbench' +import KeysPage from 'uiSrc/pages/keys' import PubSubPage from 'uiSrc/pages/pub-sub' import AnalyticsPage from 'uiSrc/pages/analytics' import RdiPage from 'uiSrc/pages/rdi/home' import RdiInstancePage from 'uiSrc/pages/rdi/instance' import RdiStatisticsPage from 'uiSrc/pages/rdi/statistics' import PipelineManagementPage from 'uiSrc/pages/rdi/pipeline-management' -import { ANALYTICS_ROUTES, RDI_PIPELINE_MANAGEMENT_ROUTES } from './sub-routes' + +import { ANALYTICS_ROUTES, RDI_PIPELINE_MANAGEMENT_ROUTES, BROWSER_ROUTES } from './sub-routes' import COMMON_ROUTES from './commonRoutes' const INSTANCE_ROUTES: IRoute[] = [ { - pageName: PageNames.browser, - path: Pages.browser(':instanceId'), - component: BrowserPage, - }, - { - pageName: PageNames.workbench, - path: Pages.workbench(':instanceId'), - component: WorkbenchPage, + path: Pages.keys(':instanceId'), + component: KeysPage, + routes: BROWSER_ROUTES, }, { pageName: PageNames.pubSub, @@ -41,6 +36,10 @@ const INSTANCE_ROUTES: IRoute[] = [ component: AnalyticsPage, routes: ANALYTICS_ROUTES, }, + { + path: '/:instanceId/workbench', + redirect: (params) => Pages.workbench(params?.instanceId || '') + } ] const RDI_INSTANCE_ROUTES: IRoute[] = [ diff --git a/redisinsight/ui/src/components/main-router/constants/redisStackRoutes.ts b/redisinsight/ui/src/components/main-router/constants/redisStackRoutes.ts index 88502af3bc..043937c1ca 100644 --- a/redisinsight/ui/src/components/main-router/constants/redisStackRoutes.ts +++ b/redisinsight/ui/src/components/main-router/constants/redisStackRoutes.ts @@ -2,6 +2,7 @@ import { PageNames, Pages, IRoute } from 'uiSrc/constants' import { BrowserPage, InstancePage, } from 'uiSrc/pages' +import KeysPage from 'uiSrc/pages/keys' import WorkbenchPage from 'uiSrc/pages/workbench' import SlowLogPage from 'uiSrc/pages/slow-log' import PubSubPage from 'uiSrc/pages/pub-sub' @@ -9,8 +10,30 @@ import EditConnection from 'uiSrc/pages/redis-stack/components/edit-connection' import ClusterDetailsPage from 'uiSrc/pages/cluster-details' import AnalyticsPage from 'uiSrc/pages/analytics' import DatabaseAnalysisPage from 'uiSrc/pages/database-analysis' +import SearchPage from 'uiSrc/pages/search' import COMMON_ROUTES from './commonRoutes' +const BROWSER_ROUTES: IRoute[] = [ + { + pageName: PageNames.browser, + protected: true, + path: Pages.browser(':instanceId'), + component: BrowserPage, + }, + { + pageName: PageNames.search, + protected: true, + path: Pages.search(':instanceId'), + component: SearchPage, + }, + { + pageName: PageNames.workbench, + protected: true, + path: Pages.workbench(':instanceId'), + component: WorkbenchPage, + }, +] + const ANALYTICS_ROUTES: IRoute[] = [ { pageName: PageNames.slowLog, @@ -34,16 +57,9 @@ const ANALYTICS_ROUTES: IRoute[] = [ const INSTANCE_ROUTES: IRoute[] = [ { - pageName: PageNames.browser, - protected: true, - path: Pages.browser(':instanceId'), - component: BrowserPage, - }, - { - pageName: PageNames.workbench, - protected: true, - path: Pages.workbench(':instanceId'), - component: WorkbenchPage, + path: Pages.keys(':instanceId'), + component: KeysPage, + routes: BROWSER_ROUTES, }, { pageName: PageNames.pubSub, @@ -57,6 +73,11 @@ const INSTANCE_ROUTES: IRoute[] = [ component: AnalyticsPage, routes: ANALYTICS_ROUTES, }, + // redirect to the new workbench path + { + path: ':instanceId/workbench', + redirect: (params) => Pages.workbench(params?.instanceId || '') + } ] const ROUTES: IRoute[] = [ diff --git a/redisinsight/ui/src/components/main-router/constants/sub-routes/browserRoutes.ts b/redisinsight/ui/src/components/main-router/constants/sub-routes/browserRoutes.ts new file mode 100644 index 0000000000..16c739a1be --- /dev/null +++ b/redisinsight/ui/src/components/main-router/constants/sub-routes/browserRoutes.ts @@ -0,0 +1,22 @@ +import { IRoute, PageNames, Pages } from 'uiSrc/constants' +import BrowserPage from 'uiSrc/pages/browser' +import SearchPage from 'uiSrc/pages/search' +import WorkbenchPage from 'uiSrc/pages/workbench' + +export const BROWSER_ROUTES: IRoute[] = [ + { + pageName: PageNames.browser, + path: Pages.browser(':instanceId'), + component: BrowserPage, + }, + { + pageName: PageNames.search, + path: Pages.search(':instanceId'), + component: SearchPage, + }, + { + pageName: PageNames.workbench, + path: Pages.workbench(':instanceId'), + component: WorkbenchPage, + } +] diff --git a/redisinsight/ui/src/components/main-router/constants/sub-routes/index.ts b/redisinsight/ui/src/components/main-router/constants/sub-routes/index.ts index 68a3732539..5770a6d4ed 100644 --- a/redisinsight/ui/src/components/main-router/constants/sub-routes/index.ts +++ b/redisinsight/ui/src/components/main-router/constants/sub-routes/index.ts @@ -1,7 +1,9 @@ import { ANALYTICS_ROUTES } from './analyticsRoutes' import { RDI_PIPELINE_MANAGEMENT_ROUTES } from './rdiPipelineManagementRoutes' +import { BROWSER_ROUTES } from './browserRoutes' export { ANALYTICS_ROUTES, RDI_PIPELINE_MANAGEMENT_ROUTES, + BROWSER_ROUTES } diff --git a/redisinsight/ui/src/components/navigation-menu/NavigationMenu.spec.tsx b/redisinsight/ui/src/components/navigation-menu/NavigationMenu.spec.tsx index 118c11783d..2dfa3c3e57 100644 --- a/redisinsight/ui/src/components/navigation-menu/NavigationMenu.spec.tsx +++ b/redisinsight/ui/src/components/navigation-menu/NavigationMenu.spec.tsx @@ -5,6 +5,7 @@ import { EXTERNAL_LINKS } from 'uiSrc/constants/links' import { appInfoSelector } from 'uiSrc/slices/app/info' import { cleanup, mockedStore, render, screen, fireEvent } from 'uiSrc/utils/test-utils' +import { connectedInstanceSelector } from 'uiSrc/slices/instances/instances' import NavigationMenu from './NavigationMenu' let store: typeof mockedStore @@ -23,6 +24,13 @@ jest.mock('uiSrc/slices/app/info', () => ({ }) })) +jest.mock('uiSrc/slices/instances/instances', () => ({ + ...jest.requireActual('uiSrc/slices/instances/instances'), + connectedInstanceSelector: jest.fn().mockReturnValue({ + id: '' + }) +})) + describe('NavigationMenu', () => { describe('without connectedInstance', () => { it('should render', () => { @@ -45,7 +53,6 @@ describe('NavigationMenu', () => { render() expect(screen.queryByTestId('browser-page-btn"')).not.toBeInTheDocument() - expect(screen.queryByTestId('workbench-page-btn')).not.toBeInTheDocument() }) it('should render help menu', () => { @@ -84,15 +91,12 @@ describe('NavigationMenu', () => { }) describe('with connectedInstance', () => { - beforeAll(() => { - jest.mock('uiSrc/slices/instances/instances', () => ({ - ...jest.requireActual('uiSrc/slices/instances/instances'), - connectedInstanceSelector: jest.fn().mockReturnValue({ - id: '123', - connectionType: 'STANDALONE', - db: 0, - }) - })) + beforeEach(() => { + (connectedInstanceSelector as jest.Mock).mockReturnValue({ + id: '123', + connectionType: 'STANDALONE', + db: 0, + }) }) it('should render', () => { @@ -114,8 +118,9 @@ describe('NavigationMenu', () => { })) render() - expect(screen.findByTestId('browser-page-btn')).toBeTruthy() - expect(screen.findByTestId('workbench-page-btn')).toBeTruthy() + screen.debug(undefined, 100_000) + + expect(screen.getByTestId('browser-page-btn')).toBeTruthy() }) it('should render public routes', () => { diff --git a/redisinsight/ui/src/components/navigation-menu/NavigationMenu.tsx b/redisinsight/ui/src/components/navigation-menu/NavigationMenu.tsx index e3a0d24f29..f77a84689f 100644 --- a/redisinsight/ui/src/components/navigation-menu/NavigationMenu.tsx +++ b/redisinsight/ui/src/components/navigation-menu/NavigationMenu.tsx @@ -13,7 +13,7 @@ import { EuiToolTip } from '@elastic/eui' import HighlightedFeature, { Props as HighlightedFeatureProps } from 'uiSrc/components/hightlighted-feature/HighlightedFeature' -import { ANALYTICS_ROUTES } from 'uiSrc/components/main-router/constants/sub-routes' +import { ANALYTICS_ROUTES, BROWSER_ROUTES } from 'uiSrc/components/main-router/constants/sub-routes' import { PageNames, Pages } from 'uiSrc/constants' import { EXTERNAL_LINKS } from 'uiSrc/constants/links' @@ -29,8 +29,6 @@ import SettingsSVG from 'uiSrc/assets/img/sidebar/settings.svg' import SettingsActiveSVG from 'uiSrc/assets/img/sidebar/settings_active.svg' import BrowserSVG from 'uiSrc/assets/img/sidebar/browser.svg' import BrowserActiveSVG from 'uiSrc/assets/img/sidebar/browser_active.svg' -import WorkbenchSVG from 'uiSrc/assets/img/sidebar/workbench.svg' -import WorkbenchActiveSVG from 'uiSrc/assets/img/sidebar/workbench_active.svg' import SlowLogSVG from 'uiSrc/assets/img/sidebar/slowlog.svg' import SlowLogActiveSVG from 'uiSrc/assets/img/sidebar/slowlog_active.svg' import PubSubSVG from 'uiSrc/assets/img/sidebar/pubsub.svg' @@ -53,8 +51,6 @@ import NotificationMenu from './components/notifications-center' import styles from './styles.module.scss' -const workbenchPath = `/${PageNames.workbench}` -const browserPath = `/${PageNames.browser}` const pubSubPath = `/${PageNames.pubSub}` interface INavigations { @@ -96,6 +92,10 @@ const NavigationMenu = () => { ({ path }) => (`/${last(path.split('/'))}` === activePage) ) + const isBrowserPath = (activePage: string) => !!BROWSER_ROUTES.find( + ({ path }) => (`/${last(path.split('/'))}` === activePage) + ) + const isPipelineManagementPath = () => location.pathname?.startsWith(Pages.rdiPipelineManagement(connectedRdiInstanceId)) @@ -115,7 +115,7 @@ const NavigationMenu = () => { { tooltipText: 'Browser', pageName: PageNames.browser, - isActivePage: activePage === browserPath, + isActivePage: isBrowserPath(activePage), ariaLabel: 'Browser page button', onClick: () => handleGoPage(Pages.browser(connectedInstanceId)), dataTestId: 'browser-page-btn', @@ -126,23 +126,6 @@ const NavigationMenu = () => { getIconType() { return this.isActivePage ? BrowserSVG : BrowserActiveSVG }, - onboard: ONBOARDING_FEATURES.BROWSER_PAGE - }, - { - tooltipText: 'Workbench', - pageName: PageNames.workbench, - ariaLabel: 'Workbench page button', - onClick: () => handleGoPage(Pages.workbench(connectedInstanceId)), - dataTestId: 'workbench-page-btn', - connectedInstanceId, - isActivePage: activePage === workbenchPath, - getClassName() { - return cx(styles.navigationButton, { [styles.active]: this.isActivePage }) - }, - getIconType() { - return this.isActivePage ? WorkbenchSVG : WorkbenchActiveSVG - }, - onboard: ONBOARDING_FEATURES.WORKBENCH_PAGE }, { tooltipText: 'Analysis Tools', diff --git a/redisinsight/ui/src/components/triggers/insights-trigger/InsightsTrigger.spec.tsx b/redisinsight/ui/src/components/triggers/insights-trigger/InsightsTrigger.spec.tsx index 2c4dc23b9f..2619b6a388 100644 --- a/redisinsight/ui/src/components/triggers/insights-trigger/InsightsTrigger.spec.tsx +++ b/redisinsight/ui/src/components/triggers/insights-trigger/InsightsTrigger.spec.tsx @@ -86,7 +86,7 @@ describe('InsightsTrigger', () => { databaseId: 'instanceId', provider: 'RE_CLOUD', source: 'overview', - page: '/browser', + page: '/browser/browser', tab: 'tips' }, }); diff --git a/redisinsight/ui/src/constants/pages.ts b/redisinsight/ui/src/constants/pages.ts index 29cc5c1f4b..17b6d7a35c 100644 --- a/redisinsight/ui/src/constants/pages.ts +++ b/redisinsight/ui/src/constants/pages.ts @@ -1,12 +1,14 @@ import { FeatureFlags } from 'uiSrc/constants' +import { Maybe } from 'uiSrc/utils' export interface IRoute { path: any - component: (routes: any) => JSX.Element | Element | null + component?: (routes: any) => JSX.Element | Element | null pageName?: PageNames exact?: boolean routes?: any protected?: boolean + redirect?: (params: Record>) => string isAvailableWithoutAgreements?: boolean featureFlag?: FeatureFlags } @@ -14,6 +16,7 @@ export interface IRoute { export enum PageNames { workbench = 'workbench', browser = 'browser', + search = 'search', slowLog = 'slowlog', pubSub = 'pub-sub', analytics = 'analytics', @@ -44,8 +47,10 @@ export const Pages = { sentinel, sentinelDatabases: `${sentinel}/databases`, sentinelDatabasesResult: `${sentinel}/databases-result`, - browser: (instanceId: string) => `/${instanceId}/${PageNames.browser}`, - workbench: (instanceId: string) => `/${instanceId}/${PageNames.workbench}`, + keys: (instanceId: string) => `/${instanceId}/${PageNames.browser}`, + browser: (instanceId: string) => `/${instanceId}/${PageNames.browser}/${PageNames.browser}`, + search: (instanceId: string) => `/${instanceId}/${PageNames.browser}/${PageNames.search}`, + workbench: (instanceId: string) => `/${instanceId}/${PageNames.browser}/${PageNames.workbench}`, pubSub: (instanceId: string) => `/${instanceId}/${PageNames.pubSub}`, analytics: (instanceId: string) => `/${instanceId}/${PageNames.analytics}`, slowLog: (instanceId: string) => `/${instanceId}/${PageNames.analytics}/${PageNames.slowLog}`, diff --git a/redisinsight/ui/src/pages/browser/BrowserPage.spec.tsx b/redisinsight/ui/src/pages/browser/BrowserPage.spec.tsx index 9279901966..079291de0e 100644 --- a/redisinsight/ui/src/pages/browser/BrowserPage.spec.tsx +++ b/redisinsight/ui/src/pages/browser/BrowserPage.spec.tsx @@ -9,7 +9,6 @@ import { setBrowserBulkActionOpen, setBrowserPanelSizes, setBrowserSelectedKey, - setLastPageContext } from 'uiSrc/slices/app/context' import BrowserPage from './BrowserPage' import KeyList, { Props as KeyListProps } from './components/key-list/KeyList' @@ -161,7 +160,6 @@ describe('BrowserPage', () => { setBrowserPanelSizes(expect.any(Object)), setBrowserBulkActionOpen(expect.any(Boolean)), setBrowserSelectedKey(null), - setLastPageContext('browser'), toggleBrowserFullScreen(false) ] diff --git a/redisinsight/ui/src/pages/browser/BrowserPage.tsx b/redisinsight/ui/src/pages/browser/BrowserPage.tsx index cba22499be..02c6a26d6d 100644 --- a/redisinsight/ui/src/pages/browser/BrowserPage.tsx +++ b/redisinsight/ui/src/pages/browser/BrowserPage.tsx @@ -31,7 +31,6 @@ import { setBrowserSelectedKey, appContextBrowser, setBrowserPanelSizes, - setLastPageContext, setBrowserBulkActionOpen, } from 'uiSrc/slices/app/context' import { resetErrors } from 'uiSrc/slices/app/notifications' @@ -105,7 +104,6 @@ const BrowserPage = () => { }) dispatch(setBrowserBulkActionOpen(isBulkActionsPanelOpenRef.current)) dispatch(setBrowserSelectedKey(selectedKeyRef.current)) - dispatch(setLastPageContext('browser')) if (!selectedKeyRef.current) { dispatch(toggleBrowserFullScreen(false)) diff --git a/redisinsight/ui/src/pages/browser/styles.module.scss b/redisinsight/ui/src/pages/browser/styles.module.scss index 78257fd4fb..99b9613820 100644 --- a/redisinsight/ui/src/pages/browser/styles.module.scss +++ b/redisinsight/ui/src/pages/browser/styles.module.scss @@ -1,29 +1,18 @@ $breakpoint-to-hide-resize-panel: 1280px; .container { - height: 100%; max-width: 100vw; display: flex; flex-direction: column; + flex-grow: 1; + overflow: hidden; } .main { display: flex; - flex: 1; + flex-grow: 1; padding: 0 16px; - height: calc(100% - 280px); - - &.mainWithBackBtn { - height: calc(100% - 338px); - } - - @media only screen and (min-width: 768px) { - max-width: calc(100vw - 60px); - - &.mainWithBackBtn { - height: calc(100% - 118px); - } - } + overflow: hidden; } .resizableButton { diff --git a/redisinsight/ui/src/pages/database-analysis/components/top-namespace/TopNamespace.spec.tsx b/redisinsight/ui/src/pages/database-analysis/components/top-namespace/TopNamespace.spec.tsx index 9a8a0c1c14..88d050d31e 100644 --- a/redisinsight/ui/src/pages/database-analysis/components/top-namespace/TopNamespace.spec.tsx +++ b/redisinsight/ui/src/pages/database-analysis/components/top-namespace/TopNamespace.spec.tsx @@ -166,6 +166,6 @@ describe('TopNamespace', () => { expect(store.getActions()).toEqual(expectedActions) expect(pushMock).toHaveBeenCalledTimes(1) - expect(pushMock).toHaveBeenCalledWith('/instanceId/browser') + expect(pushMock).toHaveBeenCalledWith('/instanceId/browser/browser') }) }) diff --git a/redisinsight/ui/src/pages/home/components/database-alias/DatabaseAlias.tsx b/redisinsight/ui/src/pages/home/components/database-alias/DatabaseAlias.tsx index 24b2a8a3aa..c3510d03ee 100644 --- a/redisinsight/ui/src/pages/home/components/database-alias/DatabaseAlias.tsx +++ b/redisinsight/ui/src/pages/home/components/database-alias/DatabaseAlias.tsx @@ -18,7 +18,7 @@ import { useHistory } from 'react-router' import { BuildType } from 'uiSrc/constants/env' import { appInfoSelector } from 'uiSrc/slices/app/info' import { Nullable, getDbIndex } from 'uiSrc/utils' -import { PageNames, Pages, Theme } from 'uiSrc/constants' +import { Pages, Theme } from 'uiSrc/constants' import { ThemeContext } from 'uiSrc/contexts/themeContext' import InlineItemEditor from 'uiSrc/components/inline-item-editor/InlineItemEditor' import RediStackDarkMin from 'uiSrc/assets/img/modules/redistack/RediStackDark-min.svg' @@ -65,7 +65,7 @@ const DatabaseAlias = (props: Props) => { } = props const { server } = useSelector(appInfoSelector) - const { contextInstanceId, lastPage } = useSelector(appContextSelector) + const { contextInstanceId } = useSelector(appContextSelector) const [isEditing, setIsEditing] = useState(false) const [value, setValue] = useState(alias) @@ -95,12 +95,7 @@ const DatabaseAlias = (props: Props) => { dispatch(setAppContextInitialState()) } dispatch(setConnectedInstanceId(id ?? '')) - - if (lastPage === PageNames.workbench && contextInstanceId === id) { - history.push(Pages.workbench(id)) - return - } - history.push(Pages.browser(id ?? '')) + history.push(Pages.keys(id ?? '')) } const handleOpen = (event: any) => { diff --git a/redisinsight/ui/src/pages/home/components/database-list-component/DatabasesListWrapper.tsx b/redisinsight/ui/src/pages/home/components/database-list-component/DatabasesListWrapper.tsx index 5faac08598..cc57d6ea18 100644 --- a/redisinsight/ui/src/pages/home/components/database-list-component/DatabasesListWrapper.tsx +++ b/redisinsight/ui/src/pages/home/components/database-list-component/DatabasesListWrapper.tsx @@ -25,7 +25,7 @@ import CloudLinkIcon from 'uiSrc/assets/img/oauth/cloud_link.svg?react' import { ShowChildByCondition } from 'uiSrc/components' import DatabaseListModules from 'uiSrc/components/database-list-modules/DatabaseListModules' import ItemList from 'uiSrc/components/item-list' -import { BrowserStorageItem, PageNames, Pages, Theme } from 'uiSrc/constants' +import { BrowserStorageItem, Pages, Theme } from 'uiSrc/constants' import { EXTERNAL_LINKS } from 'uiSrc/constants/links' import { ThemeContext } from 'uiSrc/contexts/themeContext' import PopoverDelete from 'uiSrc/pages/browser/components/popover-delete/PopoverDelete' @@ -63,7 +63,7 @@ const DatabasesListWrapper = ({ width, onEditInstance, editedInstance, onDeleteI const { search } = useLocation() const { theme } = useContext(ThemeContext) - const { contextInstanceId, lastPage } = useSelector(appContextSelector) + const { contextInstanceId } = useSelector(appContextSelector) const instances = useSelector(instancesSelector) const [, forceRerender] = useState({}) @@ -125,11 +125,7 @@ const DatabasesListWrapper = ({ width, onEditInstance, editedInstance, onDeleteI } dispatch(setConnectedInstanceId(id)) - if (lastPage === PageNames.workbench && contextInstanceId === id) { - history.push(Pages.workbench(id)) - return - } - history.push(Pages.browser(id)) + history.push(Pages.keys(id)) } const handleCheckConnectToInstance = ( event: React.MouseEvent | React.KeyboardEvent, diff --git a/redisinsight/ui/src/pages/keys/KeysPage.spec.tsx b/redisinsight/ui/src/pages/keys/KeysPage.spec.tsx new file mode 100644 index 0000000000..b3b4982efe --- /dev/null +++ b/redisinsight/ui/src/pages/keys/KeysPage.spec.tsx @@ -0,0 +1,85 @@ +import React from 'react' +import reactRouterDom, { BrowserRouter } from 'react-router-dom' +import { cleanup } from '@testing-library/react' +import { cloneDeep } from 'lodash' +import { mockedStore, render } from 'uiSrc/utils/test-utils' + +import { Pages } from 'uiSrc/constants' +import { appContextSelector, setLastPageContext } from 'uiSrc/slices/app/context' +import KeysPage from './KeysPage' + +jest.mock('uiSrc/slices/app/context', () => ({ + ...jest.requireActual('uiSrc/slices/app/context'), + appContextSelector: jest.fn().mockReturnValue({ + lastBrowserPage: '', + }), +})) + +let store: typeof mockedStore +beforeEach(() => { + cleanup() + store = cloneDeep(mockedStore) + store.clearActions() +}) + +const mockedRoutes = [ + { + path: '/123/browser', + }, +] + +describe('KeysPage', () => { + it('should render', () => { + expect( + render( + + + + ) + ).toBeTruthy() + }) + + it('should redirect to the browser by default', () => { + const pushMock = jest.fn() + reactRouterDom.useHistory = jest.fn().mockReturnValue({ push: pushMock }) + reactRouterDom.useLocation = jest.fn().mockReturnValue({ pathname: Pages.keys('instanceId') }) + + render( + + + + ) + + expect(pushMock).toBeCalledWith(Pages.browser('instanceId')) + }) + + it('should redirect to the prev page from context', () => { + (appContextSelector as jest.Mock).mockReturnValueOnce({ + lastBrowserPage: Pages.workbench('instanceId') + }) + const pushMock = jest.fn() + reactRouterDom.useHistory = jest.fn().mockReturnValue({ push: pushMock }) + reactRouterDom.useLocation = jest.fn().mockReturnValue({ pathname: Pages.keys('instanceId') }) + + render( + + + + ) + + expect(pushMock).toBeCalledWith(Pages.workbench('instanceId')) + }) + + it('should save proper page on unmount', () => { + reactRouterDom.useLocation = jest.fn().mockReturnValue({ pathname: Pages.workbench('instanceId') }) + + const { unmount } = render( + + + + ) + + unmount() + expect(store.getActions()).toEqual([setLastPageContext('/instanceId/browser/workbench')]) + }) +}) diff --git a/redisinsight/ui/src/pages/keys/KeysPage.tsx b/redisinsight/ui/src/pages/keys/KeysPage.tsx new file mode 100644 index 0000000000..9ac514c88d --- /dev/null +++ b/redisinsight/ui/src/pages/keys/KeysPage.tsx @@ -0,0 +1,62 @@ +import React, { useEffect, useRef } from 'react' +import { Switch, useHistory, useLocation, useParams } from 'react-router-dom' +import { useDispatch, useSelector } from 'react-redux' +import { IRoute, Pages } from 'uiSrc/constants' +import { appContextSelector, setLastPageContext } from 'uiSrc/slices/app/context' +import RouteWithSubRoutes from 'uiSrc/utils/routerWithSubRoutes' + +import BrowserTabs from './components/browser-tabs' + +export interface Props { + routes: IRoute[] +} + +const KeysPage = (props: Props) => { + const { routes } = props + + const { lastBrowserPage } = useSelector(appContextSelector) + const { instanceId } = useParams<{ instanceId: string }>() + const { pathname } = useLocation() + const pathnameRef = useRef('') + + const history = useHistory() + const dispatch = useDispatch() + + useEffect(() => () => { + dispatch(setLastPageContext(pathnameRef.current)) + }, []) + + useEffect(() => { + if (pathname === Pages.keys(instanceId)) { + // restore current inner page and ignore context (as we store context on unmount) + if (pathnameRef.current && pathnameRef.current !== lastBrowserPage) { + history.push(pathnameRef.current) + return + } + + // restore from context + if (lastBrowserPage) { + history.push(lastBrowserPage) + return + } + + history.push(Pages.browser(instanceId)) + } + + pathnameRef.current = pathname === Pages.keys(instanceId) ? '' : pathname + }, [pathname]) + + return ( + <> + + + {routes.map((route, i) => ( + // eslint-disable-next-line react/no-array-index-key + + ))} + + + ) +} + +export default KeysPage diff --git a/redisinsight/ui/src/pages/keys/components/browser-tabs/BrowserTabs.spec.tsx b/redisinsight/ui/src/pages/keys/components/browser-tabs/BrowserTabs.spec.tsx new file mode 100644 index 0000000000..a85228d2e4 --- /dev/null +++ b/redisinsight/ui/src/pages/keys/components/browser-tabs/BrowserTabs.spec.tsx @@ -0,0 +1,40 @@ +import React from 'react' +import reactRouterDom from 'react-router-dom' +import { render, screen, fireEvent } from 'uiSrc/utils/test-utils' + +import BrowserTabs from './BrowserTabs' + +jest.mock('uiSrc/telemetry', () => ({ + ...jest.requireActual('uiSrc/telemetry'), + sendEventTelemetry: jest.fn(), +})) + +jest.mock('react-router-dom', () => ({ + ...jest.requireActual('react-router-dom'), + useHistory: () => ({ + push: jest.fn, + }), +})) + +const MOCKED_INSTANCE_ID = 'instanceId' + +describe('BrowserTabs', () => { + it('should render', () => { + expect(render()).toBeTruthy() + }) + + it('should call proper history push after click on tabs', () => { + const pushMock = jest.fn() + reactRouterDom.useHistory = jest.fn().mockReturnValue({ push: pushMock }) + + render() + + fireEvent.click(screen.getByTestId('browser-tab-workbench')) + expect(pushMock).toBeCalledWith('/instanceId/browser/workbench') + + pushMock.mockRestore() + + fireEvent.click(screen.getByTestId('browser-tab-browser')) + expect(pushMock).toBeCalledWith('/instanceId/browser/browser') + }) +}) diff --git a/redisinsight/ui/src/pages/keys/components/browser-tabs/BrowserTabs.tsx b/redisinsight/ui/src/pages/keys/components/browser-tabs/BrowserTabs.tsx new file mode 100644 index 0000000000..6e34e2e159 --- /dev/null +++ b/redisinsight/ui/src/pages/keys/components/browser-tabs/BrowserTabs.tsx @@ -0,0 +1,67 @@ +import React from 'react' +import { EuiBadge, EuiTab, EuiTabs } from '@elastic/eui' +import { useHistory } from 'react-router-dom' +import { Pages } from 'uiSrc/constants/pages' + +import { renderOnboardingTourWithChild } from 'uiSrc/utils/onboarding' +import { ONBOARDING_FEATURES } from 'uiSrc/components/onboarding-features' +import styles from './styles.module.scss' + +export interface Props { + instanceId: string + pathname: string +} + +const BrowserTabs = (props: Props) => { + const { instanceId, pathname } = props + + const history = useHistory() + + const tabs = [ + { + id: 'browser', + title: 'Browse and filter', + page: Pages.browser(instanceId), + onboard: ONBOARDING_FEATURES.BROWSER_PAGE + }, + { + id: 'search', + title: 'Search and query', + page: Pages.search(instanceId), + isBeta: true + }, + { + id: 'workbench', + title: 'Workbench', + page: Pages.workbench(instanceId), + onboard: ONBOARDING_FEATURES.WORKBENCH_PAGE, + } + ] + + const onClickTab = (page: string) => { + history.push(page) + } + + return ( + + {tabs.map(({ id, title, page, onboard, isBeta }) => renderOnboardingTourWithChild( + ( + onClickTab(page)} + data-testid={`browser-tab-${id}`} + > + {title} + {isBeta && ((New!))} + + ), + { options: onboard, anchorPosition: 'downLeft' }, + pathname === page + ))} + + ) +} + +export default BrowserTabs diff --git a/redisinsight/ui/src/pages/keys/components/browser-tabs/index.ts b/redisinsight/ui/src/pages/keys/components/browser-tabs/index.ts new file mode 100644 index 0000000000..e1617ed596 --- /dev/null +++ b/redisinsight/ui/src/pages/keys/components/browser-tabs/index.ts @@ -0,0 +1,3 @@ +import BrowserTabs from './BrowserTabs' + +export default BrowserTabs diff --git a/redisinsight/ui/src/pages/keys/components/browser-tabs/styles.module.scss b/redisinsight/ui/src/pages/keys/components/browser-tabs/styles.module.scss new file mode 100644 index 0000000000..3072523b71 --- /dev/null +++ b/redisinsight/ui/src/pages/keys/components/browser-tabs/styles.module.scss @@ -0,0 +1,44 @@ +.tabs { + margin: 0 16px 16px; + background: var(--euiColorEmptyShade); + + .tab { + padding: 8px 16px !important; + margin: 0 !important; + border-radius: 0 !important; + color: var(--euiTextSubduedColor) !important; + border-right: 1px solid var(--separatorColor); + + &:hover { + background: var(--tableLightBorderColor); + } + + &:global(.euiTab-isSelected) { + color: var(--euiTextColor) !important; + background: var(--insightsTriggerBgColor) !important; + } + + &:after { + display: none !important; + } + } + + .betaLabel { + margin-left: 12px; + font-size: 8px !important; + line-height: 12px !important; + background-color: var(--recommendationLiveBorderColor) !important; + border: 1px solid var(--triggerIconActiveColor) !important; + color: #FFF7EA !important; + border-radius: 2px !important; + padding: 0 3px !important; + margin-bottom: 2px; + + transition: transform 250ms ease-in-out; + pointer-events: none; + + :global(.euiBadge__content) { + min-height: 12px !important; + } + } +} diff --git a/redisinsight/ui/src/pages/keys/index.ts b/redisinsight/ui/src/pages/keys/index.ts new file mode 100644 index 0000000000..06362669d9 --- /dev/null +++ b/redisinsight/ui/src/pages/keys/index.ts @@ -0,0 +1,3 @@ +import KeysPage from './KeysPage' + +export default KeysPage diff --git a/redisinsight/ui/src/pages/search/SearchPage.spec.tsx b/redisinsight/ui/src/pages/search/SearchPage.spec.tsx new file mode 100644 index 0000000000..f48f5729ff --- /dev/null +++ b/redisinsight/ui/src/pages/search/SearchPage.spec.tsx @@ -0,0 +1,10 @@ +import React from 'react' +import { render, screen } from 'uiSrc/utils/test-utils' + +import SearchPage from './SearchPage' + +describe('SearchPage', () => { + it('should render', () => { + expect(render()).toBeTruthy() + }) +}) diff --git a/redisinsight/ui/src/pages/search/SearchPage.tsx b/redisinsight/ui/src/pages/search/SearchPage.tsx new file mode 100644 index 0000000000..aef47b2781 --- /dev/null +++ b/redisinsight/ui/src/pages/search/SearchPage.tsx @@ -0,0 +1,14 @@ +import React from 'react' + +export interface Props { + +} + +const SearchPage = (props: Props) => { + const {} = props + return ( +
+ ) +} + +export default SearchPage diff --git a/redisinsight/ui/src/pages/search/index.ts b/redisinsight/ui/src/pages/search/index.ts new file mode 100644 index 0000000000..2f6b199b65 --- /dev/null +++ b/redisinsight/ui/src/pages/search/index.ts @@ -0,0 +1,3 @@ +import SearchPage from './SearchPage' + +export default SearchPage diff --git a/redisinsight/ui/src/pages/workbench/WorkbenchPage.tsx b/redisinsight/ui/src/pages/workbench/WorkbenchPage.tsx index 8217ec18e4..8f142d8923 100644 --- a/redisinsight/ui/src/pages/workbench/WorkbenchPage.tsx +++ b/redisinsight/ui/src/pages/workbench/WorkbenchPage.tsx @@ -3,9 +3,7 @@ import { useDispatch, useSelector } from 'react-redux' import { useParams } from 'react-router-dom' import { formatLongName, getDbIndex, setTitle } from 'uiSrc/utils' -import { PageNames } from 'uiSrc/constants' import { connectedInstanceSelector } from 'uiSrc/slices/instances/instances' -import { setLastPageContext } from 'uiSrc/slices/app/context' import { loadPluginsAction } from 'uiSrc/slices/app/plugins' import { sendPageViewTelemetry, TelemetryPageView } from 'uiSrc/telemetry' import WBViewWrapper from './components/wb-view' @@ -38,10 +36,6 @@ const WorkbenchPage = () => { dispatch(loadPluginsAction()) }, []) - useEffect(() => () => { - dispatch(setLastPageContext(PageNames.workbench)) - }) - return () } diff --git a/redisinsight/ui/src/pages/workbench/components/wb-view/WBViewWrapper.tsx b/redisinsight/ui/src/pages/workbench/components/wb-view/WBViewWrapper.tsx index 921c67b96f..0c3e94acb0 100644 --- a/redisinsight/ui/src/pages/workbench/components/wb-view/WBViewWrapper.tsx +++ b/redisinsight/ui/src/pages/workbench/components/wb-view/WBViewWrapper.tsx @@ -44,7 +44,7 @@ interface IState { let state: IState = { loading: false, - instance: instanceInitState.connectedInstance, + instance: instanceInitState?.connectedInstance, unsupportedCommands: [], blockingCommands: [], visualizations: [], diff --git a/redisinsight/ui/src/slices/app/context.ts b/redisinsight/ui/src/slices/app/context.ts index d00dfff572..12928d204c 100644 --- a/redisinsight/ui/src/slices/app/context.ts +++ b/redisinsight/ui/src/slices/app/context.ts @@ -35,7 +35,7 @@ export const initialState: StateAppContext = { : AppWorkspace.Databases, contextInstanceId: '', contextRdiInstanceId: '', - lastPage: '', + lastBrowserPage: '', dbConfig: { treeViewDelimiter: DEFAULT_DELIMITER, treeViewSort: DEFAULT_TREE_SORTING, @@ -179,7 +179,7 @@ const appContextSlice = createSlice({ state.workbench.panelSizes.vertical = payload }, setLastPageContext: (state, { payload }: { payload: string }) => { - state.lastPage = payload + state.lastBrowserPage = payload }, resetBrowserTree: (state) => { state.browser.tree.selectedLeaf = null diff --git a/redisinsight/ui/src/slices/interfaces/app.ts b/redisinsight/ui/src/slices/interfaces/app.ts index 3948d9ba4e..68510f468c 100644 --- a/redisinsight/ui/src/slices/interfaces/app.ts +++ b/redisinsight/ui/src/slices/interfaces/app.ts @@ -54,7 +54,7 @@ export interface StateAppContext { workspace: AppWorkspace contextInstanceId: string contextRdiInstanceId: string - lastPage: string + lastBrowserPage: string dbConfig: { treeViewDelimiter: string treeViewSort: SortOrder diff --git a/redisinsight/ui/src/slices/tests/app/context.spec.ts b/redisinsight/ui/src/slices/tests/app/context.spec.ts index 874ac9da0b..91b8898d17 100644 --- a/redisinsight/ui/src/slices/tests/app/context.spec.ts +++ b/redisinsight/ui/src/slices/tests/app/context.spec.ts @@ -370,7 +370,7 @@ describe('slices', () => { const lastPage = 'workbench' const state = { ...initialState, - lastPage + lastBrowserPage: lastPage } // Act diff --git a/redisinsight/ui/src/utils/routerWithSubRoutes.tsx b/redisinsight/ui/src/utils/routerWithSubRoutes.tsx index a934bfcf2e..690ad23ff3 100644 --- a/redisinsight/ui/src/utils/routerWithSubRoutes.tsx +++ b/redisinsight/ui/src/utils/routerWithSubRoutes.tsx @@ -1,13 +1,12 @@ import React from 'react' import { Redirect, Route } from 'react-router-dom' import { useSelector } from 'react-redux' -import { isUndefined } from 'lodash' import { userSettingsSelector } from 'uiSrc/slices/user/user-settings' import { appFeatureFlagsFeaturesSelector } from 'uiSrc/slices/app/features' import { IRoute, FeatureFlags } from 'uiSrc/constants' const PrivateRoute = (route: IRoute) => { - const { path, exact, routes, featureFlag } = route + const { path, exact, routes, featureFlag, redirect } = route const { [featureFlag as FeatureFlags]: feature, } = useSelector(appFeatureFlagsFeaturesSelector) @@ -17,15 +16,26 @@ const PrivateRoute = (route: IRoute) => { - haveToAcceptAgreements || feature?.flag === false + render={(props) => { + if (redirect) { + return ( + + ) + } + + return haveToAcceptAgreements || feature?.flag === false ? : ( // pass the sub-routes down to keep nesting // @ts-ignore ) - } + }} /> ) } diff --git a/redisinsight/ui/src/utils/routing.ts b/redisinsight/ui/src/utils/routing.ts index 78ea0d2ec2..341b33e01a 100644 --- a/redisinsight/ui/src/utils/routing.ts +++ b/redisinsight/ui/src/utils/routing.ts @@ -1,4 +1,4 @@ -import { IRoute } from 'uiSrc/constants' +import { IRoute, Pages } from 'uiSrc/constants' import { Maybe, Nullable } from 'uiSrc/utils' import DEFAULT_ROUTES from 'uiSrc/components/main-router/constants/defaultRoutes' @@ -43,6 +43,11 @@ export const getRedirectionPage = ( page += '&insights=open' } + // old page - temp redirection + if (page === 'workbench' && databaseId) { + return `${Pages.keys(databaseId)}/${page}` + } + const foundRoute = findRouteByPathname(DEFAULT_ROUTES, pathname) if (!foundRoute) return undefined diff --git a/redisinsight/ui/src/utils/tests/routing.spec.ts b/redisinsight/ui/src/utils/tests/routing.spec.ts index 6d4e88443f..ab019d61b5 100644 --- a/redisinsight/ui/src/utils/tests/routing.spec.ts +++ b/redisinsight/ui/src/utils/tests/routing.spec.ts @@ -14,8 +14,10 @@ Object.defineProperty(window, 'location', { const databaseId = '1' const getRedirectionPageTests = [ { input: ['settings'], expected: '/settings' }, - { input: ['workbench', databaseId], expected: '/1/workbench' }, - { input: ['/workbench', databaseId], expected: '/1/workbench' }, + { input: ['workbench', databaseId], expected: '/1/browser/workbench' }, + { input: ['/workbench', databaseId], expected: '/1/browser/workbench' }, + { input: ['browser/workbench', databaseId], expected: '/1/browser/workbench' }, + { input: ['/browser/workbench', databaseId], expected: '/1/browser/workbench' }, { input: ['/analytics/slowlog', databaseId], expected: '/1/analytics/slowlog' }, { input: ['/analytics/slowlog'], expected: null }, { input: ['/analytics', databaseId], expected: '/1/analytics' }, From 633dc9ceb477f04cc3556560d6d5a850dea92011 Mon Sep 17 00:00:00 2001 From: Roman Sergeenko Date: Thu, 27 Jun 2024 15:32:39 +0200 Subject: [PATCH 002/256] #RI-5682 - update workbench editor --- .../components/query/Query/styles.module.scss | 140 ------------------ .../ui/src/constants/keyboardShortcuts.tsx | 4 +- .../query-actions/QueryActions.spec.tsx | 37 +++++ .../components/query-actions/QueryActions.tsx | 127 ++++++++++++++++ .../components/query-actions/index.ts | 3 + .../query-actions/styles.module.scss | 82 ++++++++++ .../query-tutorials/QueryTutorials.spec.tsx | 58 ++++++++ .../query-tutorials/QueryTutorials.tsx | 66 +++++++++ .../components/query-tutorials/index.ts | 3 + .../query-tutorials/styles.module.scss | 48 ++++++ .../components/query/Query/Query.spec.tsx | 0 .../components/query/Query/Query.tsx | 97 ++---------- .../components/query/Query/index.ts | 0 .../components/query/Query/styles.module.scss | 76 ++++++++++ .../components/query/QueryWrapper.spec.tsx | 0 .../components/query/QueryWrapper.tsx | 3 - .../workbench}/components/query/index.ts | 0 .../wb-results/WBResults/WBResults.tsx | 3 +- .../components/wb-view/WBView/WBView.tsx | 16 +- .../components/wb-view/WBViewWrapper.tsx | 1 - 20 files changed, 524 insertions(+), 240 deletions(-) delete mode 100644 redisinsight/ui/src/components/query/Query/styles.module.scss create mode 100644 redisinsight/ui/src/pages/workbench/components/query-actions/QueryActions.spec.tsx create mode 100644 redisinsight/ui/src/pages/workbench/components/query-actions/QueryActions.tsx create mode 100644 redisinsight/ui/src/pages/workbench/components/query-actions/index.ts create mode 100644 redisinsight/ui/src/pages/workbench/components/query-actions/styles.module.scss create mode 100644 redisinsight/ui/src/pages/workbench/components/query-tutorials/QueryTutorials.spec.tsx create mode 100644 redisinsight/ui/src/pages/workbench/components/query-tutorials/QueryTutorials.tsx create mode 100644 redisinsight/ui/src/pages/workbench/components/query-tutorials/index.ts create mode 100644 redisinsight/ui/src/pages/workbench/components/query-tutorials/styles.module.scss rename redisinsight/ui/src/{ => pages/workbench}/components/query/Query/Query.spec.tsx (100%) rename redisinsight/ui/src/{ => pages/workbench}/components/query/Query/Query.tsx (82%) rename redisinsight/ui/src/{ => pages/workbench}/components/query/Query/index.ts (100%) create mode 100644 redisinsight/ui/src/pages/workbench/components/query/Query/styles.module.scss rename redisinsight/ui/src/{ => pages/workbench}/components/query/QueryWrapper.spec.tsx (100%) rename redisinsight/ui/src/{ => pages/workbench}/components/query/QueryWrapper.tsx (92%) rename redisinsight/ui/src/{ => pages/workbench}/components/query/index.ts (100%) diff --git a/redisinsight/ui/src/components/query/Query/styles.module.scss b/redisinsight/ui/src/components/query/Query/styles.module.scss deleted file mode 100644 index bb80636b81..0000000000 --- a/redisinsight/ui/src/components/query/Query/styles.module.scss +++ /dev/null @@ -1,140 +0,0 @@ -.wrapper { - position: relative; - height: 100%; - - :global(.editorBounder) { - bottom: 6px; - left: 18px; - right: 46px; - } -} -.container { - display: flex; - padding: 8px 0 8px 16px; - width: 100%; - height: 100%; - word-break: break-word; - text-align: left; - letter-spacing: 0; - background-color: var(--rsInputWrapperColor); - color: var(--euiTextSubduedColor) !important; - border: 1px solid var(--euiColorLightShade); -} - -.disabled { - opacity: 0.8; -} - -.disabledActions { - pointer-events: none; - user-select: none; -} - -.containerPlaceholder { - display: flex; - padding: 8px 16px 8px 16px; - width: 100%; - height: 100%; - background-color: var(--rsInputWrapperColor); - color: var(--euiTextSubduedColor) !important; - border: 1px solid var(--euiColorLightShade); - > div { - border: 1px solid var(--euiColorLightShade); - background-color: var(--euiColorEmptyShade); - padding: 8px 20px; - width: 100%; - } -} - -.input { - height: 100%; - width: calc(100% - 44px); - border: 1px solid var(--euiColorLightShade); - background-color: var(--rsInputColor); -} - -#script { - font: normal normal bold 14px/17px Inconsolata !important; - color: var(--textColorShade); - caret-color: var(--euiColorFullShade); - min-width: 5px; - display: inline; -} - -.actions { - width: 44px; - position: relative; - display: flex; - flex-direction: column; - justify-content: space-between; - align-items: center; -} - -.textBtn.textBtn { - border: none !important; - width: 24px; - height: 24px !important; - min-width: auto !important; - min-height: auto !important; - border-radius: 4px !important; - background: transparent !important; - box-shadow: none !important; - - :global(.euiButton__content) { - padding: 0 !important; - } - - &:hover, - &:focus { - border: 1px solid var(--buttonSecondaryHoverColor) !important; - } - - svg path { - fill: var(--euiTextSubduedColor) !important; - } - - &:hover svg path, - &:focus svg path { - fill: var(--wbHoverIconColor) !important; - } - - &.activeBtn { - background: var(--browserComponentActive) !important; - border: 1px solid var(--euiColorSecondary); - - svg path { - fill: var(--wbActiveIconColor) !important; - } - - &:hover, - &:focus { - border: 1px solid var(--buttonSecondaryHoverColor) !important; - } - } -} - -.submitButton { - color: var(--rsSubmitBtn) !important; - width: 44px !important; - height: 44px !important; - - &Loading { - position: absolute; - left: 0; - opacity: 0.5; - margin-top: -10px; - svg { - width: 17px !important; - height: 17px !important; - } - } - - svg { - width: 24px; - height: 24px; - } -} - -.tooltipText { - font-size: 12px !important; -} diff --git a/redisinsight/ui/src/constants/keyboardShortcuts.tsx b/redisinsight/ui/src/constants/keyboardShortcuts.tsx index bf98ebb298..188ad8d421 100644 --- a/redisinsight/ui/src/constants/keyboardShortcuts.tsx +++ b/redisinsight/ui/src/constants/keyboardShortcuts.tsx @@ -107,8 +107,8 @@ const MAC_SHORTCUTS = { }, workbench: { runQuery: { - label: 'Run', - description: 'Run Command', + label: 'Run commands', + description: 'Run Commands', keys: [(), 'Enter'], }, nextLine: { diff --git a/redisinsight/ui/src/pages/workbench/components/query-actions/QueryActions.spec.tsx b/redisinsight/ui/src/pages/workbench/components/query-actions/QueryActions.spec.tsx new file mode 100644 index 0000000000..a913298d14 --- /dev/null +++ b/redisinsight/ui/src/pages/workbench/components/query-actions/QueryActions.spec.tsx @@ -0,0 +1,37 @@ +import React from 'react' +import { mock } from 'ts-mockito' +import { render, screen, fireEvent } from 'uiSrc/utils/test-utils' + +import QueryActions, { Props } from './QueryActions' + +const mockedProps = mock() + +describe('QueryActions', () => { + it('should render', () => { + expect(render()).toBeTruthy() + }) + + it('should call props on click buttons', () => { + const onChangeMode = jest.fn() + const onChangeGroupMode = jest.fn() + const onSubmit = jest.fn() + + render( + + ) + + fireEvent.click(screen.getByTestId('btn-change-mode')) + expect(onChangeMode).toBeCalled() + + fireEvent.click(screen.getByTestId('btn-change-group-mode')) + expect(onChangeGroupMode).toBeCalled() + + fireEvent.click(screen.getByTestId('btn-submit')) + expect(onSubmit).toBeCalled() + }) +}) diff --git a/redisinsight/ui/src/pages/workbench/components/query-actions/QueryActions.tsx b/redisinsight/ui/src/pages/workbench/components/query-actions/QueryActions.tsx new file mode 100644 index 0000000000..d8fc8b047a --- /dev/null +++ b/redisinsight/ui/src/pages/workbench/components/query-actions/QueryActions.tsx @@ -0,0 +1,127 @@ +import React, { useRef } from 'react' + +import cx from 'classnames' +import { EuiButton, EuiSpacer, EuiText, EuiToolTip } from '@elastic/eui' +import { ResultsMode, RunQueryMode } from 'uiSrc/slices/interfaces' +import { KEYBOARD_SHORTCUTS } from 'uiSrc/constants' +import { KeyboardShortcut } from 'uiSrc/components' +import { isGroupMode } from 'uiSrc/utils' + +import GroupModeIcon from 'uiSrc/assets/img/icons/group_mode.svg?react' +import RawModeIcon from 'uiSrc/assets/img/icons/raw_mode.svg?react' + +import Divider from 'uiSrc/components/divider/Divider' +import styles from './styles.module.scss' + +export interface Props { + onChangeMode: () => void + onChangeGroupMode: () => void + onSubmit: () => void + activeMode: RunQueryMode + resultsMode?: ResultsMode + isLoading?: boolean + isDisabled?: boolean +} + +const QueryActions = (props: Props) => { + const { + isLoading, + isDisabled, + activeMode, + resultsMode, + onChangeMode, + onChangeGroupMode, + onSubmit, + } = props + const runTooltipRef = useRef(null) + + const KeyBoardTooltipContent = KEYBOARD_SHORTCUTS?.workbench?.runQuery && ( + <> + + {KEYBOARD_SHORTCUTS.workbench.runQuery?.label}: + + + + + ) + + return ( +
+ + onChangeMode()} + iconType={RawModeIcon} + disabled={isLoading} + className={cx(styles.btn, styles.textBtn, { [styles.activeBtn]: activeMode === RunQueryMode.Raw })} + data-testid="btn-change-mode" + > + Raw mode + + + + Groups the command results into a single window. +
+ When grouped, the results can be visualized only in the text format. + + )} + data-testid="group-results-tooltip" + > + onChangeGroupMode()} + disabled={isLoading} + iconType={GroupModeIcon} + className={cx(styles.btn, styles.textBtn, { [styles.activeBtn]: isGroupMode(resultsMode) })} + data-testid="btn-change-group-mode" + > + Group results + +
+ + + <> + { + onSubmit() + setTimeout(() => runTooltipRef?.current?.hideToolTip?.(), 0) + }} + isLoading={isLoading} + disabled={isLoading} + iconType="playFilled" + className={cx(styles.btn, styles.submitButton)} + aria-label="submit" + data-testid="btn-submit" + > + Run + + + +
+ ) +} + +export default QueryActions diff --git a/redisinsight/ui/src/pages/workbench/components/query-actions/index.ts b/redisinsight/ui/src/pages/workbench/components/query-actions/index.ts new file mode 100644 index 0000000000..474915f557 --- /dev/null +++ b/redisinsight/ui/src/pages/workbench/components/query-actions/index.ts @@ -0,0 +1,3 @@ +import QueryActions from './QueryActions' + +export default QueryActions diff --git a/redisinsight/ui/src/pages/workbench/components/query-actions/styles.module.scss b/redisinsight/ui/src/pages/workbench/components/query-actions/styles.module.scss new file mode 100644 index 0000000000..4764d8d231 --- /dev/null +++ b/redisinsight/ui/src/pages/workbench/components/query-actions/styles.module.scss @@ -0,0 +1,82 @@ +.actions { + display: flex; + justify-content: space-between; + align-items: center; + + .btn { + height: 24px !important; + min-width: auto !important; + min-height: auto !important; + border-radius: 4px !important; + background: transparent !important; + box-shadow: none !important; + + color: var(--euiTextColor) !important; + border: 1px solid transparent !important; + + :global(.euiButton__content) { + padding: 0 6px; + } + + :global(.euiButton__text) { + color: var(--euiTextColor) !important; + font: normal normal 400 14px/17px Graphik, sans-serif !important + } + + &:focus, &:active { + outline: 0 !important; + } + + svg { + margin-top: 1px; + width: 14px; + height: 14px; + } + } + + .textBtn { + margin: 0 8px; + + svg path { + fill: var(--euiTextSubduedColor) !important; + } + + &.activeBtn { + background: var(--browserComponentActive) !important; + border: 1px solid var(--euiColorPrimary) !important; + } + } + + .submitButton { + margin-left: 8px; + + svg { + color: var(--rsSubmitBtn) !important; + } + + :global(.euiLoadingSpinner) { + width: 14px; + height: 14px; + color: var(--rsSubmitBtn) !important; + } + } + + .divider { + height: 20px; + margin-left: 8px; + } + + .tooltipText { + font-size: 12px !important; + } +} + +@include global.insights-open(1220px) { + .actions { + .btn { + :global(.euiButton__text) { + display: none; + } + } + } +} diff --git a/redisinsight/ui/src/pages/workbench/components/query-tutorials/QueryTutorials.spec.tsx b/redisinsight/ui/src/pages/workbench/components/query-tutorials/QueryTutorials.spec.tsx new file mode 100644 index 0000000000..ce7f39786b --- /dev/null +++ b/redisinsight/ui/src/pages/workbench/components/query-tutorials/QueryTutorials.spec.tsx @@ -0,0 +1,58 @@ +import React from 'react' +import reactRouterDom from 'react-router-dom' +import { fireEvent, render, screen } from 'uiSrc/utils/test-utils' + +import { findTutorialPath } from 'uiSrc/utils' + +import { sendEventTelemetry, TelemetryEvent } from 'uiSrc/telemetry' + +import QueryTutorials from './QueryTutorials' + +jest.mock('uiSrc/utils', () => ({ + ...jest.requireActual('uiSrc/utils'), + findTutorialPath: jest.fn(), +})) + +jest.mock('uiSrc/telemetry', () => ({ + ...jest.requireActual('uiSrc/telemetry'), + sendEventTelemetry: jest.fn(), +})) + +describe('QueryTutorial', () => { + it('should render', () => { + expect(render()).toBeTruthy() + }) + + it('should call proper history push after click on guide with tutorial', () => { + const pushMock = jest.fn() + reactRouterDom.useHistory = jest.fn().mockReturnValue({ push: pushMock }); + (findTutorialPath as jest.Mock).mockImplementation(() => 'path') + + render() + + fireEvent.click(screen.getByTestId('wb-tutorials-link_sq-intro')) + + expect(pushMock).toHaveBeenCalledWith({ + search: 'path=tutorials/path' + }) + }) + + it('should call proper telemetry event after click on guide', () => { + const sendEventTelemetryMock = jest.fn(); + (sendEventTelemetry as jest.Mock).mockImplementation(() => sendEventTelemetryMock); + (findTutorialPath as jest.Mock).mockImplementation(() => 'path') + + render() + + fireEvent.click(screen.getByTestId('wb-tutorials-link_sq-intro')) + + expect(sendEventTelemetry).toBeCalledWith({ + event: TelemetryEvent.EXPLORE_PANEL_TUTORIAL_OPENED, + eventData: { + path: 'path', + databaseId: 'instanceId', + source: 'advanced_workbench_editor', + } + }) + }) +}) diff --git a/redisinsight/ui/src/pages/workbench/components/query-tutorials/QueryTutorials.tsx b/redisinsight/ui/src/pages/workbench/components/query-tutorials/QueryTutorials.tsx new file mode 100644 index 0000000000..b009b6b3e9 --- /dev/null +++ b/redisinsight/ui/src/pages/workbench/components/query-tutorials/QueryTutorials.tsx @@ -0,0 +1,66 @@ +import React from 'react' + +import { EuiLink, EuiText } from '@elastic/eui' +import { useDispatch } from 'react-redux' +import { useHistory, useParams } from 'react-router-dom' +import { findTutorialPath } from 'uiSrc/utils' +import { openTutorialByPath } from 'uiSrc/slices/panels/sidePanels' +import { sendEventTelemetry, TELEMETRY_EMPTY_VALUE, TelemetryEvent } from 'uiSrc/telemetry' + +import styles from './styles.module.scss' + +const TUTORIALS = [ + { + id: 'sq-intro', + title: 'Intro to search' + }, + { + id: 'redis_use_cases_basic', + title: 'Basic use cases' + }, + { + id: 'vss-intro', + title: 'Intro to vector search' + }, +] + +const QueryTutorials = () => { + const dispatch = useDispatch() + const history = useHistory() + const { instanceId } = useParams<{ instanceId: string }>() + + const handleClickTutorial = (id: string) => { + const tutorialPath = findTutorialPath({ id }) + dispatch(openTutorialByPath(tutorialPath, history, true)) + + sendEventTelemetry({ + event: TelemetryEvent.EXPLORE_PANEL_TUTORIAL_OPENED, + eventData: { + path: tutorialPath, + databaseId: instanceId || TELEMETRY_EMPTY_VALUE, + source: 'advanced_workbench_editor', + } + }) + } + + return ( +
+ + Tutorials: + + {TUTORIALS.map(({ id, title }) => ( + handleClickTutorial(id)} + data-testid={`wb-tutorials-link_${id}`} + > + {title} + + ))} +
+ ) +} + +export default QueryTutorials diff --git a/redisinsight/ui/src/pages/workbench/components/query-tutorials/index.ts b/redisinsight/ui/src/pages/workbench/components/query-tutorials/index.ts new file mode 100644 index 0000000000..c2c46d3a39 --- /dev/null +++ b/redisinsight/ui/src/pages/workbench/components/query-tutorials/index.ts @@ -0,0 +1,3 @@ +import QueryTutorials from './QueryTutorials' + +export default QueryTutorials diff --git a/redisinsight/ui/src/pages/workbench/components/query-tutorials/styles.module.scss b/redisinsight/ui/src/pages/workbench/components/query-tutorials/styles.module.scss new file mode 100644 index 0000000000..0e1e56dc13 --- /dev/null +++ b/redisinsight/ui/src/pages/workbench/components/query-tutorials/styles.module.scss @@ -0,0 +1,48 @@ +.container { + display: flex; + align-items: center; + + .title { + margin-right: 8px; + } + + .tutorialLink { + padding: 4px 8px; + + background-color: var(--browserTableRowEven); + + border-radius: 4px; + border: 1px solid var(--separatorColor); + + color: var(--htmlColor) !important; + text-decoration: none !important; + font-size: 12px; + + &:not(:first-of-type) { + margin-left: 8px; + } + + &:global(.euiLink) { + &:hover, &:focus { + color: var(--htmlColor); + text-decoration: underline !important; + outline: none !important; + animation: none !important; + } + } + } +} + +@include global.insights-open(1280px) { + .title { + display: none + } +} + +@include global.insights-open(1024px) { + .tutorialLink:last-of-type { + display: none; + } +} + + diff --git a/redisinsight/ui/src/components/query/Query/Query.spec.tsx b/redisinsight/ui/src/pages/workbench/components/query/Query/Query.spec.tsx similarity index 100% rename from redisinsight/ui/src/components/query/Query/Query.spec.tsx rename to redisinsight/ui/src/pages/workbench/components/query/Query/Query.spec.tsx diff --git a/redisinsight/ui/src/components/query/Query/Query.tsx b/redisinsight/ui/src/pages/workbench/components/query/Query/Query.tsx similarity index 82% rename from redisinsight/ui/src/components/query/Query/Query.tsx rename to redisinsight/ui/src/pages/workbench/components/query/Query/Query.tsx index b59b5ec0e4..42ab11c6a0 100644 --- a/redisinsight/ui/src/components/query/Query/Query.tsx +++ b/redisinsight/ui/src/pages/workbench/components/query/Query/Query.tsx @@ -2,14 +2,12 @@ import React, { useContext, useEffect, useRef, useState } from 'react' import { useDispatch, useSelector } from 'react-redux' import { compact, first } from 'lodash' import cx from 'classnames' -import { EuiButtonIcon, EuiButton, EuiIcon, EuiLoadingSpinner, EuiText, EuiToolTip } from '@elastic/eui' import MonacoEditor, { monaco as monacoEditor } from 'react-monaco-editor' import { useParams } from 'react-router-dom' import { Theme, MonacoLanguage, - KEYBOARD_SHORTCUTS, DSLNaming, } from 'uiSrc/constants' import { @@ -21,13 +19,11 @@ import { getMonacoAction, getRedisCompletionProvider, getRedisSignatureHelpProvider, - isGroupMode, isParamsLine, MonacoAction, Nullable, toModelDeltaDecoration } from 'uiSrc/utils' -import { KeyboardShortcut } from 'uiSrc/components' import { ThemeContext } from 'uiSrc/contexts/themeContext' import { appRedisCommandsSelector } from 'uiSrc/slices/app/redis-commands' import { IEditorMount, ISnippetController } from 'uiSrc/pages/workbench/interfaces' @@ -36,9 +32,9 @@ import { RunQueryMode, ResultsMode } from 'uiSrc/slices/interfaces/workbench' import { sendEventTelemetry, TelemetryEvent } from 'uiSrc/telemetry' import { stopProcessing, workbenchResultsSelector } from 'uiSrc/slices/workbench/wb-results' import DedicatedEditor from 'uiSrc/components/monaco-editor/components/dedicated-editor' -import RawModeIcon from 'uiSrc/assets/img/icons/raw_mode.svg?react' -import GroupModeIcon from 'uiSrc/assets/img/icons/group_mode.svg?react' +import QueryActions from '../../query-actions' +import QueryTutorials from '../../query-tutorials' import styles from './styles.module.scss' export interface Props { @@ -47,7 +43,6 @@ export interface Props { resultsMode?: ResultsMode setQueryEl: Function setQuery: (script: string) => void - setIsCodeBtnDisabled: (value: boolean) => void onSubmit: (query?: string) => void onKeyDown?: (e: React.KeyboardEvent, script: string) => void onQueryChangeMode: () => void @@ -73,7 +68,6 @@ const Query = (props: Props) => { onKeyDown = () => {}, onSubmit = () => {}, setQueryEl = () => {}, - setIsCodeBtnDisabled = () => {}, onQueryChangeMode = () => {}, onChangeGroupMode = () => {} } = props @@ -91,7 +85,6 @@ const Query = (props: Props) => { const { items: execHistoryItems, loading, processing } = useSelector(workbenchResultsSelector) const { theme } = useContext(ThemeContext) const monacoObjects = useRef>(null) - const runTooltipRef = useRef(null) const { instanceId = '' } = useParams<{ instanceId: string }>() @@ -143,7 +136,6 @@ const Query = (props: Props) => { }, [query]) useEffect(() => { - setIsCodeBtnDisabled(isDedicatedEditorOpen) isDedicatedEditorOpenRef.current = isDedicatedEditorOpen }, [isDedicatedEditorOpen]) @@ -475,80 +467,19 @@ const Query = (props: Props) => { editorDidMount={editorDidMount} />
-
- - onQueryChangeMode()} - disabled={isLoading} - className={cx(styles.textBtn, { [styles.activeBtn]: activeMode === RunQueryMode.Raw })} - data-testid="btn-change-mode" - > - - - - - {`${KEYBOARD_SHORTCUTS.workbench.runQuery?.label}:\u00A0\u00A0`} - -
- ) - } - data-testid="run-query-tooltip" - > - <> - {isLoading && ( - - )} - { - handleSubmit() - setTimeout(() => runTooltipRef?.current?.hideToolTip?.(), 0) - }} - disabled={isLoading} - iconType="playFilled" - className={cx(styles.submitButton, { [styles.submitButtonLoading]: isLoading })} - aria-label="submit" - data-testid="btn-submit" - /> - - - - <> - onChangeGroupMode()} - disabled={isLoading} - className={cx(styles.textBtn, { [styles.activeBtn]: isGroupMode(resultsMode) })} - data-testid="btn-change-group-mode" - > - - - - +
+ +
+ {isDedicatedEditorOpen && ( div { + border: 1px solid var(--euiColorLightShade); + background-color: var(--euiColorEmptyShade); + padding: 8px 20px; + width: 100%; + } +} + +.input { + overflow: hidden; + flex-grow: 1; + width: 100%; + border: 1px solid var(--euiColorLightShade); + background-color: var(--rsInputColor); +} + +.queryFooter { + display: flex; + align-items: center; + justify-content: space-between; + + margin-top: 8px; + flex-shrink: 0; +} + +#script { + font: normal normal bold 14px/17px Inconsolata !important; + color: var(--textColorShade); + caret-color: var(--euiColorFullShade); + min-width: 5px; + display: inline; +} + diff --git a/redisinsight/ui/src/components/query/QueryWrapper.spec.tsx b/redisinsight/ui/src/pages/workbench/components/query/QueryWrapper.spec.tsx similarity index 100% rename from redisinsight/ui/src/components/query/QueryWrapper.spec.tsx rename to redisinsight/ui/src/pages/workbench/components/query/QueryWrapper.spec.tsx diff --git a/redisinsight/ui/src/components/query/QueryWrapper.tsx b/redisinsight/ui/src/pages/workbench/components/query/QueryWrapper.tsx similarity index 92% rename from redisinsight/ui/src/components/query/QueryWrapper.tsx rename to redisinsight/ui/src/pages/workbench/components/query/QueryWrapper.tsx index cab14f46bf..56a7d9e974 100644 --- a/redisinsight/ui/src/components/query/QueryWrapper.tsx +++ b/redisinsight/ui/src/pages/workbench/components/query/QueryWrapper.tsx @@ -13,7 +13,6 @@ export interface Props { resultsMode?: ResultsMode setQuery: (script: string) => void setQueryEl: Function - setIsCodeBtnDisabled: (value: boolean) => void onKeyDown?: (e: React.KeyboardEvent, script: string) => void onSubmit: (value?: string) => void onQueryChangeMode: () => void @@ -27,7 +26,6 @@ const QueryWrapper = (props: Props) => { resultsMode, setQuery, setQueryEl, - setIsCodeBtnDisabled, onKeyDown, onSubmit, onQueryChangeMode, @@ -53,7 +51,6 @@ const QueryWrapper = (props: Props) => { resultsMode={resultsMode} setQuery={setQuery} setQueryEl={setQueryEl} - setIsCodeBtnDisabled={setIsCodeBtnDisabled} onKeyDown={onKeyDown} onSubmit={onSubmit} onQueryChangeMode={onQueryChangeMode} diff --git a/redisinsight/ui/src/components/query/index.ts b/redisinsight/ui/src/pages/workbench/components/query/index.ts similarity index 100% rename from redisinsight/ui/src/components/query/index.ts rename to redisinsight/ui/src/pages/workbench/components/query/index.ts diff --git a/redisinsight/ui/src/pages/workbench/components/wb-results/WBResults/WBResults.tsx b/redisinsight/ui/src/pages/workbench/components/wb-results/WBResults/WBResults.tsx index 25edfe3dc4..00d4063f0c 100644 --- a/redisinsight/ui/src/pages/workbench/components/wb-results/WBResults/WBResults.tsx +++ b/redisinsight/ui/src/pages/workbench/components/wb-results/WBResults/WBResults.tsx @@ -11,7 +11,8 @@ import { Nullable } from 'uiSrc/utils' import QueryCard from 'uiSrc/components/query-card' import { CommandExecutionUI } from 'uiSrc/slices/interfaces' import { RunQueryMode, ResultsMode } from 'uiSrc/slices/interfaces/workbench' -import WbNoResultsMessage from 'uiSrc/pages/workbench/components/wb-no-results-message' + +import WbNoResultsMessage from '../../wb-no-results-message' import styles from './styles.module.scss' diff --git a/redisinsight/ui/src/pages/workbench/components/wb-view/WBView/WBView.tsx b/redisinsight/ui/src/pages/workbench/components/wb-view/WBView/WBView.tsx index d3f8a74239..1731efb148 100644 --- a/redisinsight/ui/src/pages/workbench/components/wb-view/WBView/WBView.tsx +++ b/redisinsight/ui/src/pages/workbench/components/wb-view/WBView/WBView.tsx @@ -1,10 +1,9 @@ -import React, { Ref, useCallback, useEffect, useRef, useState } from 'react' +import React, { Ref, useCallback, useEffect, useRef } from 'react' import { useDispatch, useSelector } from 'react-redux' import cx from 'classnames' import { isEmpty } from 'lodash' import { useParams } from 'react-router-dom' import { EuiResizableContainer } from '@elastic/eui' -import { monaco as monacoEditor } from 'react-monaco-editor' import { Maybe, @@ -12,7 +11,6 @@ import { getParsedParamsInQuery, getCommandsFromQuery } from 'uiSrc/utils' -import QueryWrapper from 'uiSrc/components/query' import { setWorkbenchVerticalPanelSizes, appContextWorkbench, @@ -25,7 +23,10 @@ import { appRedisCommandsSelector } from 'uiSrc/slices/app/redis-commands' import { userSettingsConfigSelector } from 'uiSrc/slices/user/user-settings' import { PIPELINE_COUNT_DEFAULT } from 'uiSrc/constants/api' import { CodeButtonParams } from 'uiSrc/constants' + +import QueryWrapper from '../../query' import WBResultsWrapper from '../../wb-results' + import styles from './styles.module.scss' const verticalPanelIds = { @@ -41,7 +42,6 @@ export interface Props { isResultsLoaded: boolean setScript: (script: string) => void setScriptEl: Function - scriptEl: Nullable scrollDivRef: Ref activeMode: RunQueryMode resultsMode: ResultsMode @@ -71,7 +71,6 @@ const WBView = (props: Props) => { processing, setScript, setScriptEl, - scriptEl, activeMode, resultsMode, isResultsLoaded, @@ -94,8 +93,6 @@ const WBView = (props: Props) => { const { commandsArray: REDIS_COMMANDS_ARRAY } = useSelector(appRedisCommandsSelector) const { batchSize = PIPELINE_COUNT_DEFAULT } = useSelector(userSettingsConfigSelector) ?? {} - const [isCodeBtnDisabled, setIsCodeBtnDisabled] = useState(false) - const verticalSizesRef = useRef(vertical) const dispatch = useDispatch() @@ -178,7 +175,7 @@ const WBView = (props: Props) => { scrollable={false} className={styles.queryPanel} initialSize={vertical[verticalPanelIds.firstPanelId] ?? 20} - style={{ minHeight: '140px', zIndex: '8' }} + style={{ minHeight: '240px', zIndex: '8' }} > { resultsMode={resultsMode} setQuery={setScript} setQueryEl={setScriptEl} - setIsCodeBtnDisabled={setIsCodeBtnDisabled} onSubmit={handleSubmit} onQueryChangeMode={onQueryChangeMode} onChangeGroupMode={onChangeGroupMode} @@ -206,7 +202,7 @@ const WBView = (props: Props) => { initialSize={vertical[verticalPanelIds.secondPanelId] ?? 80} className={cx(styles.queryResults, styles.queryResultsPanel)} // Fix scroll on low height - 140px (queryPanel) - style={{ maxHeight: 'calc(100% - 140px)' }} + style={{ maxHeight: 'calc(100% - 240px)' }} > { script={script} setScript={setScript} setScriptEl={setScriptEl} - scriptEl={scriptEl} scrollDivRef={scrollDivRef} activeMode={activeRunQueryMode} onSubmit={sourceValueSubmit} From 64959bc4ee2b2e18cc42829c7a7dfafc7749031e Mon Sep 17 00:00:00 2001 From: Roman Sergeenko Date: Thu, 27 Jun 2024 15:35:02 +0200 Subject: [PATCH 003/256] #RI-5682 - remove fragment --- .../components/query-actions/QueryActions.tsx | 30 +++++++++---------- 1 file changed, 14 insertions(+), 16 deletions(-) diff --git a/redisinsight/ui/src/pages/workbench/components/query-actions/QueryActions.tsx b/redisinsight/ui/src/pages/workbench/components/query-actions/QueryActions.tsx index d8fc8b047a..2650352ccd 100644 --- a/redisinsight/ui/src/pages/workbench/components/query-actions/QueryActions.tsx +++ b/redisinsight/ui/src/pages/workbench/components/query-actions/QueryActions.tsx @@ -103,22 +103,20 @@ const QueryActions = (props: Props) => { content={isLoading ? 'Please wait while the commands are being executed…' : KeyBoardTooltipContent} data-testid="run-query-tooltip" > - <> - { - onSubmit() - setTimeout(() => runTooltipRef?.current?.hideToolTip?.(), 0) - }} - isLoading={isLoading} - disabled={isLoading} - iconType="playFilled" - className={cx(styles.btn, styles.submitButton)} - aria-label="submit" - data-testid="btn-submit" - > - Run - - + { + onSubmit() + setTimeout(() => runTooltipRef?.current?.hideToolTip?.(), 0) + }} + isLoading={isLoading} + disabled={isLoading} + iconType="playFilled" + className={cx(styles.btn, styles.submitButton)} + aria-label="submit" + data-testid="btn-submit" + > + Run + ) From 8186468e75080de2b5d8d238bb1ec16b32a9522a Mon Sep 17 00:00:00 2001 From: mariasergeenko Date: Thu, 27 Jun 2024 15:50:15 +0200 Subject: [PATCH 004/256] create structure for new Panel --- .../components/browser-tabs/BrowserTabs.tsx | 2 +- tests/e2e/helpers/constants.ts | 6 ++ .../pageObjects/components/insights-panel.ts | 2 +- .../components/keys-interaction-panel.ts | 56 +++++++++++++++++++ .../e2e/pageObjects/search-and-query-page.ts | 4 ++ 5 files changed, 68 insertions(+), 2 deletions(-) create mode 100644 tests/e2e/pageObjects/components/keys-interaction-panel.ts create mode 100644 tests/e2e/pageObjects/search-and-query-page.ts diff --git a/redisinsight/ui/src/pages/keys/components/browser-tabs/BrowserTabs.tsx b/redisinsight/ui/src/pages/keys/components/browser-tabs/BrowserTabs.tsx index 6e34e2e159..4799a72bf5 100644 --- a/redisinsight/ui/src/pages/keys/components/browser-tabs/BrowserTabs.tsx +++ b/redisinsight/ui/src/pages/keys/components/browser-tabs/BrowserTabs.tsx @@ -43,7 +43,7 @@ const BrowserTabs = (props: Props) => { } return ( - + {tabs.map(({ id, title, page, onboard, isBeta }) => renderOnboardingTourWithChild( ( { + return this.activeTab.textContent; + } + + /** + * Click on Panel tab + * @param type of the tab + */ + async setActiveTab(type: KeysInteractionTabs): Promise { + const activeTabName = await this.getActiveTabName(); + + let tabSelector; + let pageClass; + + switch (type) { + case KeysInteractionTabs.BrowserAndFilter: + tabSelector = this.browserTab; + pageClass = BrowserPage; + break; + case KeysInteractionTabs.Workbench: + tabSelector = this.workbenchTab; + pageClass = WorkbenchPage; + break; + case KeysInteractionTabs.SearchAndQuery: + tabSelector = this.searchTab; + pageClass = SearchAndQueryPage; + break; + default: + throw new Error(`Unknown tab type: ${type}`); + } + + if (type !== activeTabName) { + await t.click(tabSelector); + } + + return new pageClass(); + } +} diff --git a/tests/e2e/pageObjects/search-and-query-page.ts b/tests/e2e/pageObjects/search-and-query-page.ts new file mode 100644 index 0000000000..289e8fb1ec --- /dev/null +++ b/tests/e2e/pageObjects/search-and-query-page.ts @@ -0,0 +1,4 @@ +import { InstancePage } from './instance-page'; + +export class SearchAndQueryPage extends InstancePage { +} From 91ed43be409527cbf14f019f5349b86020e2681b Mon Sep 17 00:00:00 2001 From: Roman Sergeenko Date: Fri, 28 Jun 2024 08:05:43 +0200 Subject: [PATCH 005/256] #RI-5682 - move tutorials to enum --- .../components/expert-chat/ExpertChat.tsx | 4 ++-- redisinsight/ui/src/constants/browser.ts | 2 -- redisinsight/ui/src/constants/index.ts | 1 + redisinsight/ui/src/constants/tutorials.ts | 11 +++++++++++ .../browser/components/no-keys-found/NoKeysFound.tsx | 6 ++++-- .../capability-promotion/CapabilityPromotion.tsx | 3 ++- .../components/query-tutorials/QueryTutorials.tsx | 7 ++++--- 7 files changed, 24 insertions(+), 10 deletions(-) create mode 100644 redisinsight/ui/src/constants/tutorials.ts diff --git a/redisinsight/ui/src/components/side-panels/panels/ai-assistant/components/expert-chat/ExpertChat.tsx b/redisinsight/ui/src/components/side-panels/panels/ai-assistant/components/expert-chat/ExpertChat.tsx index ae3f60d3b8..0dd2cf4048 100644 --- a/redisinsight/ui/src/components/side-panels/panels/ai-assistant/components/expert-chat/ExpertChat.tsx +++ b/redisinsight/ui/src/components/side-panels/panels/ai-assistant/components/expert-chat/ExpertChat.tsx @@ -19,7 +19,7 @@ import { oauthCloudUserSelector } from 'uiSrc/slices/oauth/cloud' import { fetchRedisearchListAction } from 'uiSrc/slices/browser/redisearch' import TelescopeImg from 'uiSrc/assets/img/telescope-dark.svg?react' import { openTutorialByPath } from 'uiSrc/slices/panels/sidePanels' -import { SAMPLE_DATA_TUTORIAL } from 'uiSrc/constants' +import { TutorialsIds } from 'uiSrc/constants' import NoIndexesInitialMessage from './components/no-indexes-initial-message' import ExpertChatHeader from './components/expert-chat-header' @@ -157,7 +157,7 @@ const ExpertChat = () => { }, []) const handleClickTutorial = () => { - const tutorialPath = findTutorialPath({ id: SAMPLE_DATA_TUTORIAL }) + const tutorialPath = findTutorialPath({ id: TutorialsIds.RedisUseCases }) dispatch(openTutorialByPath(tutorialPath, history, true)) sendEventTelemetry({ diff --git a/redisinsight/ui/src/constants/browser.ts b/redisinsight/ui/src/constants/browser.ts index 49d2912cdb..453f28dd97 100644 --- a/redisinsight/ui/src/constants/browser.ts +++ b/redisinsight/ui/src/constants/browser.ts @@ -1,7 +1,5 @@ import { KeyValueFormat, SortOrder } from './keys' -export const SAMPLE_DATA_TUTORIAL = 'redis_use_cases' - export const DEFAULT_DELIMITER = ':' export const DEFAULT_TREE_SORTING = SortOrder.ASC export const DEFAULT_SHOW_HIDDEN_RECOMMENDATIONS = false diff --git a/redisinsight/ui/src/constants/index.ts b/redisinsight/ui/src/constants/index.ts index 0e40368cc8..a0050a56d9 100644 --- a/redisinsight/ui/src/constants/index.ts +++ b/redisinsight/ui/src/constants/index.ts @@ -31,4 +31,5 @@ export * from './customErrorCodes' export * from './securityField' export * from './redisearch' export * from './browser/keyDetailsHeader' +export * from './tutorials' export { ApiEndpoints, BrowserStorageItem, ApiStatusCode, apiErrors } diff --git a/redisinsight/ui/src/constants/tutorials.ts b/redisinsight/ui/src/constants/tutorials.ts new file mode 100644 index 0000000000..45c856417e --- /dev/null +++ b/redisinsight/ui/src/constants/tutorials.ts @@ -0,0 +1,11 @@ +enum TutorialsIds { + IntroToSearch = 'sq-intro', + IntroToJSON = 'ds-json-intro', + BasicRedisUseCases = 'redis_use_cases_basic', + RedisUseCases = 'redis_use_cases', + IntroVectorSearch = 'vss-intro', +} + +export { + TutorialsIds +} diff --git a/redisinsight/ui/src/pages/browser/components/no-keys-found/NoKeysFound.tsx b/redisinsight/ui/src/pages/browser/components/no-keys-found/NoKeysFound.tsx index d783dadacf..6ef178f384 100644 --- a/redisinsight/ui/src/pages/browser/components/no-keys-found/NoKeysFound.tsx +++ b/redisinsight/ui/src/pages/browser/components/no-keys-found/NoKeysFound.tsx @@ -15,8 +15,10 @@ import { SidePanels } from 'uiSrc/slices/interfaces/insights' import { KeyViewType, SearchMode } from 'uiSrc/slices/interfaces/keys' import { changeKeyViewType, fetchKeys, keysSelector } from 'uiSrc/slices/browser/keys' import { SCAN_TREE_COUNT_DEFAULT } from 'uiSrc/constants/api' -import { SAMPLE_DATA_TUTORIAL } from 'uiSrc/constants' +import { TutorialsIds } from 'uiSrc/constants' + import LoadSampleData from '../load-sample-data' + import styles from './styles.module.scss' export interface Props { @@ -33,7 +35,7 @@ const NoKeysFound = (props: Props) => { const onSuccessLoadData = () => { if (openedPanel !== SidePanels.AiAssistant) { - const tutorialPath = findTutorialPath({ id: SAMPLE_DATA_TUTORIAL }) + const tutorialPath = findTutorialPath({ id: TutorialsIds.RedisUseCases }) dispatch(openTutorialByPath(tutorialPath, history, true)) } diff --git a/redisinsight/ui/src/pages/home/components/capability-promotion/CapabilityPromotion.tsx b/redisinsight/ui/src/pages/home/components/capability-promotion/CapabilityPromotion.tsx index 2ca214e307..ba9fc8120c 100644 --- a/redisinsight/ui/src/pages/home/components/capability-promotion/CapabilityPromotion.tsx +++ b/redisinsight/ui/src/pages/home/components/capability-promotion/CapabilityPromotion.tsx @@ -15,6 +15,7 @@ import { guideLinksSelector } from 'uiSrc/slices/content/guide-links' import GUIDE_ICONS from 'uiSrc/components/explore-guides/icons' import { findTutorialPath } from 'uiSrc/utils' import { InsightsPanelTabs, SidePanels } from 'uiSrc/slices/interfaces/insights' +import { TutorialsIds } from 'uiSrc/constants' import styles from './styles.module.scss' export interface Props { @@ -23,7 +24,7 @@ export interface Props { capabilityIds?: string[] } -const displayedCapabilityIds = ['sq-intro', 'ds-json-intro'] +const displayedCapabilityIds = [TutorialsIds.IntroToSearch, TutorialsIds.IntroToJSON] const CapabilityPromotion = (props: Props) => { const { mode = 'wide', wrapperClassName, capabilityIds = displayedCapabilityIds } = props diff --git a/redisinsight/ui/src/pages/workbench/components/query-tutorials/QueryTutorials.tsx b/redisinsight/ui/src/pages/workbench/components/query-tutorials/QueryTutorials.tsx index b009b6b3e9..83e765da76 100644 --- a/redisinsight/ui/src/pages/workbench/components/query-tutorials/QueryTutorials.tsx +++ b/redisinsight/ui/src/pages/workbench/components/query-tutorials/QueryTutorials.tsx @@ -4,6 +4,7 @@ import { EuiLink, EuiText } from '@elastic/eui' import { useDispatch } from 'react-redux' import { useHistory, useParams } from 'react-router-dom' import { findTutorialPath } from 'uiSrc/utils' +import { TutorialsIds } from 'uiSrc/constants' import { openTutorialByPath } from 'uiSrc/slices/panels/sidePanels' import { sendEventTelemetry, TELEMETRY_EMPTY_VALUE, TelemetryEvent } from 'uiSrc/telemetry' @@ -11,15 +12,15 @@ import styles from './styles.module.scss' const TUTORIALS = [ { - id: 'sq-intro', + id: TutorialsIds.IntroToSearch, title: 'Intro to search' }, { - id: 'redis_use_cases_basic', + id: TutorialsIds.BasicRedisUseCases, title: 'Basic use cases' }, { - id: 'vss-intro', + id: TutorialsIds.IntroVectorSearch, title: 'Intro to vector search' }, ] From 401be0e22c3538c526c0d12cc789106691f32b7b Mon Sep 17 00:00:00 2001 From: mariasergeenko Date: Fri, 28 Jun 2024 10:50:32 +0200 Subject: [PATCH 006/256] remove RDI --- .circleci/config.yml | 8 ++++---- tests/e2e/docker.web.docker-compose.yml | 2 +- tests/e2e/rte.docker-compose.yml | 18 +++++++++--------- 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 813c1d7a8d..c749db5e03 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -391,10 +391,10 @@ jobs: - attach_workspace: at: . - run: sudo apt-get install net-tools - - run: - name: Clone mocked RDI server - command: | - git clone https://$GH_RDI_MOCKED_SERVER_KEY@github.com/RedisInsight/RDI_server_mocked.git tests/e2e/rte/rdi + #- run: + # name: Clone mocked RDI server + # command: | + # git clone https://$GH_RDI_MOCKED_SERVER_KEY@github.com/RedisInsight/RDI_server_mocked.git tests/e2e/rte/rdi - run: name: .AppImage tests command: | diff --git a/tests/e2e/docker.web.docker-compose.yml b/tests/e2e/docker.web.docker-compose.yml index b406942cb8..d9dcaaee61 100644 --- a/tests/e2e/docker.web.docker-compose.yml +++ b/tests/e2e/docker.web.docker-compose.yml @@ -13,7 +13,7 @@ services: - rihomedir:/root/.redis-insight - tmp:/tmp - ./remote:/root/remote - - ./rdi:/root/rdi + #- ./rdi:/root/rdi env_file: - ./.env entrypoint: [ diff --git a/tests/e2e/rte.docker-compose.yml b/tests/e2e/rte.docker-compose.yml index a86fa54484..4aedbfda13 100644 --- a/tests/e2e/rte.docker-compose.yml +++ b/tests/e2e/rte.docker-compose.yml @@ -12,15 +12,15 @@ services: ports: - 5551:5551 # RDI mocked - rdi: - logging: *logging - build: - context: rte/rdi - dockerfile: Dockerfile - volumes: - - ./rdi:/data - ports: - - 4000:4000 + #rdi: + # logging: *logging + # build: + # context: rte/rdi + # dockerfile: Dockerfile + #volumes: + # - ./rdi:/data + # ports: + # - 4000:4000 # ssh ssh: logging: *logging From c56140b2fa83974b32192cb7fd31d5abb7ba215f Mon Sep 17 00:00:00 2001 From: vlad-dargel Date: Fri, 28 Jun 2024 11:06:16 +0200 Subject: [PATCH 007/256] fix for rdi --- .circleci/config.yml | 8 ++++---- tests/e2e/local.web.docker-compose.yml | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index c749db5e03..9cd941dd61 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -487,10 +487,10 @@ jobs: name: Load built docker image from workspace command: | docker image load -i /tmp/release/docker/docker-linux-alpine.amd64.tar - - run: - name: Clone mocked RDI server - command: | - git clone https://$GH_RDI_MOCKED_SERVER_KEY@github.com/RedisInsight/RDI_server_mocked.git tests/e2e/rte/rdi + # - run: + # name: Clone mocked RDI server + # command: | + # git clone https://$GH_RDI_MOCKED_SERVER_KEY@github.com/RedisInsight/RDI_server_mocked.git tests/e2e/rte/rdi - run: name: Run tests command: | diff --git a/tests/e2e/local.web.docker-compose.yml b/tests/e2e/local.web.docker-compose.yml index b093f1e149..69db32bc4a 100644 --- a/tests/e2e/local.web.docker-compose.yml +++ b/tests/e2e/local.web.docker-compose.yml @@ -13,7 +13,7 @@ services: - rihomedir:/root/.redis-insight - tmp:/tmp - ./remote:/root/remote - - ./rdi:/root/rdi + # - ./rdi:/root/rdi env_file: - ./.env entrypoint: [ From 58c6252aa4b1e761fc9f330543a81c9f31a93d23 Mon Sep 17 00:00:00 2001 From: mariasergeenko Date: Sat, 29 Jun 2024 13:22:30 +0200 Subject: [PATCH 008/256] fix tests part #1 --- tests/e2e/pageObjects/browser-page.ts | 2 ++ .../enablement-area-autoupdate.e2e.ts | 8 +++++--- .../critical-path/monitor/monitor.e2e.ts | 4 ++-- .../critical-path/workbench/index-schema.e2e.ts | 8 +++++--- .../workbench/json-workbench.e2e.ts | 8 +++++--- .../workbench/redis-stack-commands.e2e.ts | 8 +++++--- .../workbench/workbench-re-cluster.e2e.ts | 8 +++++--- .../critical-path/browser/bulk-delete.e2e.ts | 6 +++--- .../browser/search-capabilities.e2e.ts | 7 +++---- .../database-overview/database-index.e2e.ts | 4 ++-- .../database-overview/database-overview.e2e.ts | 5 +++-- .../memory-efficiency/memory-efficiency.e2e.ts | 2 +- .../web/critical-path/monitor/monitor.e2e.ts | 7 +++---- .../pub-sub/subscribe-unsubscribe.e2e.ts | 8 +++++--- .../critical-path/workbench/autocomplete.e2e.ts | 8 +++++--- .../workbench/command-results.e2e.ts | 8 +++++--- .../web/critical-path/workbench/context.e2e.ts | 12 +++++++----- .../web/critical-path/workbench/cypher.e2e.ts | 8 +++++--- .../workbench/default-scripts-area.e2e.ts | 9 ++++++--- .../workbench/scripting-area.e2e.ts | 8 +++++--- .../tests/web/regression/browser/context.e2e.ts | 9 ++++----- .../browser/keys-all-databases.e2e.ts | 6 +++--- .../web/regression/browser/onboarding.e2e.ts | 6 +++--- .../regression/browser/resize-columns.e2e.ts | 6 +++--- .../web/regression/browser/survey-link.e2e.ts | 4 ++-- .../web/regression/cli/cli-promote-workbench.ts | 5 +++-- .../database-overview/database-info.e2e.ts | 4 ++-- .../database-overview/database-overview.e2e.ts | 4 ++-- .../tests/web/regression/database/github.e2e.ts | 9 +++++---- .../regression/insights/import-tutorials.e2e.ts | 17 ++++++++++++----- .../insights/live-recommendations.e2e.ts | 6 ++++-- .../insights/open-insights-panel.e2e.ts | 4 ++-- .../tests/web/regression/monitor/monitor.e2e.ts | 4 ++-- .../regression/workbench/autocomplete.e2e.ts | 8 ++++---- .../workbench/autoexecute-button.e2e.ts | 8 ++++---- .../regression/workbench/command-results.e2e.ts | 9 +++++---- .../web/regression/workbench/context.e2e.ts | 8 ++++---- .../web/regression/workbench/cypher.e2e.ts | 8 ++++---- .../workbench/default-scripts-area.e2e.ts | 6 +++--- .../regression/workbench/editor-cleanup.e2e.ts | 10 ++++++---- .../workbench/empty-command-history.e2e.ts | 8 ++++---- .../web/regression/workbench/group-mode.e2e.ts | 8 ++++---- .../workbench/history-of-results.e2e.ts | 8 ++++---- .../web/regression/workbench/raw-mode.e2e.ts | 13 +++++++------ .../workbench/redis-stack-commands.e2e.ts | 8 ++++---- .../redisearch-module-not-available.e2e.ts | 8 ++++---- .../regression/workbench/scripting-area.e2e.ts | 13 ++++++++----- .../workbench/workbench-all-db-types.e2e.ts | 8 +++++--- .../workbench/workbench-non-auto-guides.e2e.ts | 9 +++++---- .../workbench/workbench-pipeline.e2e.ts | 17 +++++++++++------ .../web/smoke/workbench/json-workbench.e2e.ts | 8 ++++---- .../web/smoke/workbench/scripting-area.e2e.ts | 8 ++++---- 52 files changed, 223 insertions(+), 172 deletions(-) diff --git a/tests/e2e/pageObjects/browser-page.ts b/tests/e2e/pageObjects/browser-page.ts index 2dab013eb3..051db56250 100644 --- a/tests/e2e/pageObjects/browser-page.ts +++ b/tests/e2e/pageObjects/browser-page.ts @@ -2,10 +2,12 @@ import { t, Selector } from 'testcafe'; import { Common } from '../helpers/common'; import { InstancePage } from './instance-page'; import { BulkActions, TreeView } from './components/browser'; +import { KeysInteractionPanel } from './components/keys-interaction-panel'; export class BrowserPage extends InstancePage { BulkActions = new BulkActions(); TreeView = new TreeView(); + KeysInteractionPanel = new KeysInteractionPanel(); //CSS Selectors cssSelectorGrid = '[aria-label="grid"]'; diff --git a/tests/e2e/tests/electron/critical-path/files-auto-update/enablement-area-autoupdate.e2e.ts b/tests/e2e/tests/electron/critical-path/files-auto-update/enablement-area-autoupdate.e2e.ts index c12367a191..a24e178b01 100644 --- a/tests/e2e/tests/electron/critical-path/files-auto-update/enablement-area-autoupdate.e2e.ts +++ b/tests/e2e/tests/electron/critical-path/files-auto-update/enablement-area-autoupdate.e2e.ts @@ -3,15 +3,16 @@ import * as fs from 'fs'; import * as editJsonFile from 'edit-json-file'; import { DatabaseHelper } from '../../../../helpers/database'; -import { MyRedisDatabasePage, WorkbenchPage } from '../../../../pageObjects'; +import { BrowserPage, MyRedisDatabasePage, WorkbenchPage } from '../../../../pageObjects'; import { commonUrl, ossStandaloneConfig, workingDirectory } from '../../../../helpers/conf'; -import { ExploreTabs, rte } from '../../../../helpers/constants'; +import { ExploreTabs, KeysInteractionTabs, rte } from '../../../../helpers/constants'; import { DatabaseAPIRequests } from '../../../../helpers/api/api-database'; const myRedisDatabasePage = new MyRedisDatabasePage(); const workbenchPage = new WorkbenchPage(); const databaseHelper = new DatabaseHelper(); const databaseAPIRequests = new DatabaseAPIRequests(); +const browserPage = new BrowserPage(); if (fs.existsSync(workingDirectory)) { @@ -46,7 +47,8 @@ if (fs.existsSync(workingDirectory)) { const tutorialsTimestampFileNew = editJsonFile(tutorialsTimestampPath); // Open Workbench page - await t.click(myRedisDatabasePage.NavigationPanel.workbenchButton); + await t.click(myRedisDatabasePage.NavigationPanel.browserButton); + await browserPage.KeysInteractionPanel.setActiveTab(KeysInteractionTabs.Workbench); // Check Enablement area and validate that removed file is existed in Guides await workbenchPage.InsightsPanel.togglePanel(true); diff --git a/tests/e2e/tests/electron/critical-path/monitor/monitor.e2e.ts b/tests/e2e/tests/electron/critical-path/monitor/monitor.e2e.ts index b79adef488..26613c2564 100644 --- a/tests/e2e/tests/electron/critical-path/monitor/monitor.e2e.ts +++ b/tests/e2e/tests/electron/critical-path/monitor/monitor.e2e.ts @@ -5,7 +5,7 @@ import { BrowserPage } from '../../../../pageObjects'; import { commonUrl, ossStandaloneConfig } from '../../../../helpers/conf'; -import { rte } from '../../../../helpers/constants'; +import { KeysInteractionTabs, rte } from '../../../../helpers/constants'; import { DatabaseAPIRequests } from '../../../../helpers/api/api-database'; import { Common } from '../../../../helpers/common'; import { APIKeyRequests } from '../../../../helpers/api/api-keys'; @@ -65,7 +65,7 @@ test('Verify that user can see the list of all commands from all clients ran for await browserPage.addHashKey(keyName); await browserPage.Profiler.checkCommandInMonitorResults(browser_command); //Open Workbench page to create new client - await t.click(myRedisDatabasePage.NavigationPanel.workbenchButton); + await browserPage.KeysInteractionPanel.setActiveTab(KeysInteractionTabs.Workbench); //Send command in Workbench await workbenchPage.sendCommandInWorkbench(workbench_command); //Check that command from Workbench is displayed in monitor diff --git a/tests/e2e/tests/electron/critical-path/workbench/index-schema.e2e.ts b/tests/e2e/tests/electron/critical-path/workbench/index-schema.e2e.ts index a9dc8ae6bd..98e1f7f811 100644 --- a/tests/e2e/tests/electron/critical-path/workbench/index-schema.e2e.ts +++ b/tests/e2e/tests/electron/critical-path/workbench/index-schema.e2e.ts @@ -1,6 +1,6 @@ -import { rte } from '../../../../helpers/constants'; +import { KeysInteractionTabs, rte } from '../../../../helpers/constants'; import { DatabaseHelper } from '../../../../helpers/database'; -import { MyRedisDatabasePage, WorkbenchPage } from '../../../../pageObjects'; +import { BrowserPage, MyRedisDatabasePage, WorkbenchPage } from '../../../../pageObjects'; import { commonUrl, ossStandaloneRedisearch } from '../../../../helpers/conf'; import { DatabaseAPIRequests } from '../../../../helpers/api/api-database'; import { Common } from '../../../../helpers/common'; @@ -9,6 +9,7 @@ const myRedisDatabasePage = new MyRedisDatabasePage(); const workbenchPage = new WorkbenchPage(); const databaseHelper = new DatabaseHelper(); const databaseAPIRequests = new DatabaseAPIRequests(); +const browserPage = new BrowserPage(); let indexName = Common.generateWord(5); @@ -18,7 +19,8 @@ fixture `Index Schema at Workbench` .beforeEach(async t => { await databaseHelper.acceptLicenseTermsAndAddDatabaseApi(ossStandaloneRedisearch); // Go to Workbench page - await t.click(myRedisDatabasePage.NavigationPanel.workbenchButton); + await t.click(myRedisDatabasePage.NavigationPanel.browserButton); + await browserPage.KeysInteractionPanel.setActiveTab(KeysInteractionTabs.Workbench);; }) .afterEach(async t => { // Drop index, documents and database diff --git a/tests/e2e/tests/electron/critical-path/workbench/json-workbench.e2e.ts b/tests/e2e/tests/electron/critical-path/workbench/json-workbench.e2e.ts index cfac929e85..f7d44417fe 100644 --- a/tests/e2e/tests/electron/critical-path/workbench/json-workbench.e2e.ts +++ b/tests/e2e/tests/electron/critical-path/workbench/json-workbench.e2e.ts @@ -1,6 +1,6 @@ -import { rte } from '../../../../helpers/constants'; +import { KeysInteractionTabs, rte } from '../../../../helpers/constants'; import { DatabaseHelper } from '../../../../helpers/database'; -import { MyRedisDatabasePage, WorkbenchPage } from '../../../../pageObjects'; +import { BrowserPage, MyRedisDatabasePage, WorkbenchPage } from '../../../../pageObjects'; import { commonUrl, ossStandaloneRedisearch } from '../../../../helpers/conf'; import { DatabaseAPIRequests } from '../../../../helpers/api/api-database'; import { Common } from '../../../../helpers/common'; @@ -9,6 +9,7 @@ const myRedisDatabasePage = new MyRedisDatabasePage(); const workbenchPage = new WorkbenchPage(); const databaseHelper = new DatabaseHelper(); const databaseAPIRequests = new DatabaseAPIRequests(); +const browserPage = new BrowserPage(); let indexName = Common.generateWord(5); @@ -18,7 +19,8 @@ fixture `JSON verifications at Workbench` .beforeEach(async t => { await databaseHelper.acceptLicenseTermsAndAddDatabaseApi(ossStandaloneRedisearch); // Go to Workbench page - await t.click(myRedisDatabasePage.NavigationPanel.workbenchButton); + await t.click(myRedisDatabasePage.NavigationPanel.browserButton); + await browserPage.KeysInteractionPanel.setActiveTab(KeysInteractionTabs.Workbench); }) .afterEach(async t => { // Drop index, documents and database diff --git a/tests/e2e/tests/electron/regression/workbench/redis-stack-commands.e2e.ts b/tests/e2e/tests/electron/regression/workbench/redis-stack-commands.e2e.ts index 3215ef5ce7..71ab459442 100644 --- a/tests/e2e/tests/electron/regression/workbench/redis-stack-commands.e2e.ts +++ b/tests/e2e/tests/electron/regression/workbench/redis-stack-commands.e2e.ts @@ -1,14 +1,15 @@ import { t } from 'testcafe'; import { DatabaseHelper } from '../../../../helpers/database'; -import { WorkbenchPage, MyRedisDatabasePage } from '../../../../pageObjects'; +import { WorkbenchPage, MyRedisDatabasePage, BrowserPage } from '../../../../pageObjects'; import { commonUrl, ossStandaloneConfig } from '../../../../helpers/conf'; -import { ExploreTabs, rte } from '../../../../helpers/constants'; +import { ExploreTabs, KeysInteractionTabs, rte } from '../../../../helpers/constants'; import { DatabaseAPIRequests } from '../../../../helpers/api/api-database'; const myRedisDatabasePage = new MyRedisDatabasePage(); const workbenchPage = new WorkbenchPage(); const databaseHelper = new DatabaseHelper(); const databaseAPIRequests = new DatabaseAPIRequests(); +const browserPage = new BrowserPage(); const keyNameGraph = 'bikes_graph'; @@ -17,7 +18,8 @@ fixture `Redis Stack command in Workbench` .page(commonUrl) .beforeEach(async t => { await databaseHelper.acceptLicenseTermsAndAddDatabaseApi(ossStandaloneConfig); - await t.click(myRedisDatabasePage.NavigationPanel.workbenchButton); + await t.click(myRedisDatabasePage.NavigationPanel.browserButton); + await browserPage.KeysInteractionPanel.setActiveTab(KeysInteractionTabs.Workbench); }) .afterEach(async() => { // Drop key and database diff --git a/tests/e2e/tests/electron/regression/workbench/workbench-re-cluster.e2e.ts b/tests/e2e/tests/electron/regression/workbench/workbench-re-cluster.e2e.ts index afb39c0ce2..b6f207a0db 100644 --- a/tests/e2e/tests/electron/regression/workbench/workbench-re-cluster.e2e.ts +++ b/tests/e2e/tests/electron/regression/workbench/workbench-re-cluster.e2e.ts @@ -1,12 +1,13 @@ import { t } from 'testcafe'; -import { rte } from '../../../../helpers/constants'; +import { KeysInteractionTabs, rte } from '../../../../helpers/constants'; import { DatabaseHelper } from '../../../../helpers/database'; -import { MyRedisDatabasePage, WorkbenchPage } from '../../../../pageObjects'; +import { BrowserPage, MyRedisDatabasePage, WorkbenchPage } from '../../../../pageObjects'; import { commonUrl, redisEnterpriseClusterConfig } from '../../../../helpers/conf'; const myRedisDatabasePage = new MyRedisDatabasePage(); const workbenchPage = new WorkbenchPage(); const databaseHelper = new DatabaseHelper(); +const browserPage = new BrowserPage(); const commandForSend1 = 'info'; const commandForSend2 = 'FT._LIST'; @@ -17,7 +18,8 @@ const verifyCommandsInWorkbench = async(): Promise => { 'FT.SEARCH idx *' ]; - await t.click(myRedisDatabasePage.NavigationPanel.workbenchButton); + await t.click(myRedisDatabasePage.NavigationPanel.browserButton); + await browserPage.KeysInteractionPanel.setActiveTab(KeysInteractionTabs.Workbench); // Send commands await workbenchPage.sendCommandInWorkbench(commandForSend1); await workbenchPage.sendCommandInWorkbench(commandForSend2); diff --git a/tests/e2e/tests/web/critical-path/browser/bulk-delete.e2e.ts b/tests/e2e/tests/web/critical-path/browser/bulk-delete.e2e.ts index a6c48ced1b..af77a10ed5 100644 --- a/tests/e2e/tests/web/critical-path/browser/bulk-delete.e2e.ts +++ b/tests/e2e/tests/web/critical-path/browser/bulk-delete.e2e.ts @@ -1,4 +1,4 @@ -import { KeyTypesTexts, rte } from '../../../../helpers/constants'; +import { KeysInteractionTabs, KeyTypesTexts, rte } from '../../../../helpers/constants'; import { DatabaseHelper } from '../../../../helpers/database'; import { BrowserPage, MyRedisDatabasePage } from '../../../../pageObjects'; import { commonUrl, ossStandaloneRedisearch } from '../../../../helpers/conf'; @@ -99,9 +99,9 @@ test await t.click(browserPage.bulkActionsButton); await browserPage.BulkActions.startBulkDelete(); // Go to Workbench page - await t.click(myRedisDatabasePage.NavigationPanel.workbenchButton); + await browserPage.KeysInteractionPanel.setActiveTab(KeysInteractionTabs.Workbench); // Go to Browser Page - await t.click(myRedisDatabasePage.NavigationPanel.browserButton); + await browserPage.KeysInteractionPanel.setActiveTab(KeysInteractionTabs.BrowserAndFilter); await t.expect(browserPage.BulkActions.bulkStatusInProgress.exists).ok('Progress value not displayed', { timeout: 5000 }); }); test diff --git a/tests/e2e/tests/web/critical-path/browser/search-capabilities.e2e.ts b/tests/e2e/tests/web/critical-path/browser/search-capabilities.e2e.ts index 1728346db0..3aa3195286 100644 --- a/tests/e2e/tests/web/critical-path/browser/search-capabilities.e2e.ts +++ b/tests/e2e/tests/web/critical-path/browser/search-capabilities.e2e.ts @@ -7,7 +7,7 @@ import { ossStandaloneConfig, ossStandaloneV5Config } from '../../../../helpers/conf'; -import { rte } from '../../../../helpers/constants'; +import { KeysInteractionTabs, rte } from '../../../../helpers/constants'; import { DatabaseAPIRequests } from '../../../../helpers/api/api-database'; import { Common } from '../../../../helpers/common'; import { verifyKeysDisplayingInTheList } from '../../../../helpers/keys'; @@ -242,9 +242,8 @@ test await t.click(browserPage.getKeySelectorByName(keyName)); // Verify that Redisearch context (inputs, key selected, scroll, key details) saved after switching between pages - await t - .click(myRedisDatabasePage.NavigationPanel.workbenchButton) - .click(myRedisDatabasePage.NavigationPanel.browserButton); + await browserPage.KeysInteractionPanel.setActiveTab(KeysInteractionTabs.Workbench); + await browserPage.KeysInteractionPanel.setActiveTab(KeysInteractionTabs.BrowserAndFilter); await verifyContext(); // Verify that Redisearch context saved when switching between browser/tree view diff --git a/tests/e2e/tests/web/critical-path/database-overview/database-index.e2e.ts b/tests/e2e/tests/web/critical-path/database-overview/database-index.e2e.ts index 419e1199f9..c87bbcb487 100644 --- a/tests/e2e/tests/web/critical-path/database-overview/database-index.e2e.ts +++ b/tests/e2e/tests/web/critical-path/database-overview/database-index.e2e.ts @@ -1,5 +1,5 @@ import { DatabaseHelper } from '../../../../helpers/database'; -import { KeyTypesTexts, rte } from '../../../../helpers/constants'; +import { KeysInteractionTabs, KeyTypesTexts, rte } from '../../../../helpers/constants'; import { Common } from '../../../../helpers/common'; import { MyRedisDatabasePage, @@ -105,7 +105,7 @@ test('Switching between indexed databases', async t => { await verifySearchFilterValue('Hall School'); // Open Workbench page - await t.click(myRedisDatabasePage.NavigationPanel.workbenchButton); + await browserPage.KeysInteractionPanel.setActiveTab(KeysInteractionTabs.Workbench); await workbenchPage.sendCommandInWorkbench(command); // Verify that user can see the database index before the command name executed in Workbench await workbenchPage.checkWorkbenchCommandResult(`[db1] ${command}`, '8'); diff --git a/tests/e2e/tests/web/critical-path/database-overview/database-overview.e2e.ts b/tests/e2e/tests/web/critical-path/database-overview/database-overview.e2e.ts index 5e25f6d550..b24400f5e0 100644 --- a/tests/e2e/tests/web/critical-path/database-overview/database-overview.e2e.ts +++ b/tests/e2e/tests/web/critical-path/database-overview/database-overview.e2e.ts @@ -1,6 +1,6 @@ import { Chance } from 'chance'; import { DatabaseHelper } from '../../../../helpers/database'; -import { ExploreTabs, rte } from '../../../../helpers/constants'; +import { ExploreTabs, KeysInteractionTabs, rte } from '../../../../helpers/constants'; import { Common } from '../../../../helpers/common'; import { MyRedisDatabasePage, @@ -145,7 +145,8 @@ test }) .after(async t => { //Delete database and index - await t.click(browserPage.NavigationPanel.workbenchButton); + await t.click(myRedisDatabasePage.NavigationPanel.browserButton); + await browserPage.KeysInteractionPanel.setActiveTab(KeysInteractionTabs.Workbench); await workbenchPage.sendCommandInWorkbench('FT.DROPINDEX idx:schools DD'); await databaseAPIRequests.deleteStandaloneDatabaseApi(ossStandaloneBigConfig); })('Verify that user can see additional information in Overview: Connected Clients, Commands/Sec, CPU (%) using Standalone DB connection type', async t => { diff --git a/tests/e2e/tests/web/critical-path/memory-efficiency/memory-efficiency.e2e.ts b/tests/e2e/tests/web/critical-path/memory-efficiency/memory-efficiency.e2e.ts index 26b988f70d..0f3079beb6 100644 --- a/tests/e2e/tests/web/critical-path/memory-efficiency/memory-efficiency.e2e.ts +++ b/tests/e2e/tests/web/critical-path/memory-efficiency/memory-efficiency.e2e.ts @@ -278,7 +278,7 @@ test } // Verify that specific report is saved as context await t.click(memoryEfficiencyPage.reportItem.nth(3)); - await t.click(myRedisDatabasePage.NavigationPanel.workbenchButton); + await t.click(myRedisDatabasePage.NavigationPanel.browserButton); await t.click(myRedisDatabasePage.NavigationPanel.analysisPageButton); await t.expect(memoryEfficiencyPage.donutTotalKeys.sibling(1).textContent).eql(numberOfKeys[2], 'Context is not saved'); // Verify that user can see top keys table saved as context diff --git a/tests/e2e/tests/web/critical-path/monitor/monitor.e2e.ts b/tests/e2e/tests/web/critical-path/monitor/monitor.e2e.ts index b79adef488..c9c1435170 100644 --- a/tests/e2e/tests/web/critical-path/monitor/monitor.e2e.ts +++ b/tests/e2e/tests/web/critical-path/monitor/monitor.e2e.ts @@ -5,12 +5,11 @@ import { BrowserPage } from '../../../../pageObjects'; import { commonUrl, ossStandaloneConfig } from '../../../../helpers/conf'; -import { rte } from '../../../../helpers/constants'; +import { KeysInteractionTabs, rte } from '../../../../helpers/constants'; import { DatabaseAPIRequests } from '../../../../helpers/api/api-database'; import { Common } from '../../../../helpers/common'; import { APIKeyRequests } from '../../../../helpers/api/api-keys'; -const myRedisDatabasePage = new MyRedisDatabasePage(); const workbenchPage = new WorkbenchPage(); const browserPage = new BrowserPage(); const databaseHelper = new DatabaseHelper(); @@ -47,7 +46,7 @@ test('Verify that user can work with Monitor', async t => { await browserPage.Cli.getSuccessCommandResultFromCli(`${command} ${keyName} ${keyValue}`); await browserPage.Profiler.checkCommandInMonitorResults(command, [keyName, keyValue]); }); -test('Verify that user can see the list of all commands from all clients ran for this Redis database in the list of results in Monitor', async t => { +test.only('Verify that user can see the list of all commands from all clients ran for this Redis database in the list of results in Monitor', async t => { //Define commands in different clients const cli_command = 'command'; const workbench_command = 'hello'; @@ -65,7 +64,7 @@ test('Verify that user can see the list of all commands from all clients ran for await browserPage.addHashKey(keyName); await browserPage.Profiler.checkCommandInMonitorResults(browser_command); //Open Workbench page to create new client - await t.click(myRedisDatabasePage.NavigationPanel.workbenchButton); + await browserPage.KeysInteractionPanel.setActiveTab(KeysInteractionTabs.Workbench); //Send command in Workbench await workbenchPage.sendCommandInWorkbench(workbench_command); //Check that command from Workbench is displayed in monitor diff --git a/tests/e2e/tests/web/critical-path/pub-sub/subscribe-unsubscribe.e2e.ts b/tests/e2e/tests/web/critical-path/pub-sub/subscribe-unsubscribe.e2e.ts index f913c1b60f..74b3bdc5a2 100644 --- a/tests/e2e/tests/web/critical-path/pub-sub/subscribe-unsubscribe.e2e.ts +++ b/tests/e2e/tests/web/critical-path/pub-sub/subscribe-unsubscribe.e2e.ts @@ -1,7 +1,7 @@ import { DatabaseHelper } from '../../../../helpers/database'; -import { MyRedisDatabasePage, PubSubPage, WorkbenchPage } from '../../../../pageObjects'; +import { BrowserPage, MyRedisDatabasePage, PubSubPage, WorkbenchPage } from '../../../../pageObjects'; import { commonUrl, ossStandaloneConfig, ossStandaloneV5Config } from '../../../../helpers/conf'; -import { rte } from '../../../../helpers/constants'; +import { KeysInteractionTabs, rte } from '../../../../helpers/constants'; import { verifyMessageDisplayingInPubSub } from '../../../../helpers/pub-sub'; import { DatabaseAPIRequests } from '../../../../helpers/api/api-database'; @@ -10,6 +10,7 @@ const pubSubPage = new PubSubPage(); const workbenchPage = new WorkbenchPage(); const databaseHelper = new DatabaseHelper(); const databaseAPIRequests = new DatabaseAPIRequests(); +const browserPage = new BrowserPage(); fixture `Subscribe/Unsubscribe from a channel` .meta({ rte: rte.standalone, type: 'critical_path' }) @@ -120,7 +121,8 @@ test('Verify that user can see a internal link to pubsub window under word “Pu await t.expect(pubSubPage.pubSubPageContainer.exists).ok('Pubsub page is opened'); // Verify that user can see a custom message when he tries to run SUBSCRIBE command in Workbench: “Use Pub/Sub tool to subscribe to channels.” - await t.click(pubSubPage.NavigationPanel.workbenchButton); + await t.click(pubSubPage.NavigationPanel.browserButton); + await browserPage.KeysInteractionPanel.setActiveTab(KeysInteractionTabs.Workbench); await workbenchPage.sendCommandInWorkbench(commandSecond); await t.expect(await workbenchPage.queryResult.textContent).eql('Use Pub/Sub tool to subscribe to channels.', 'Message is not displayed', { timeout: 10000 }); diff --git a/tests/e2e/tests/web/critical-path/workbench/autocomplete.e2e.ts b/tests/e2e/tests/web/critical-path/workbench/autocomplete.e2e.ts index ca1076997c..6bcb31367c 100644 --- a/tests/e2e/tests/web/critical-path/workbench/autocomplete.e2e.ts +++ b/tests/e2e/tests/web/critical-path/workbench/autocomplete.e2e.ts @@ -1,6 +1,6 @@ -import { rte } from '../../../../helpers/constants'; +import { KeysInteractionTabs, rte } from '../../../../helpers/constants'; import { DatabaseHelper } from '../../../../helpers/database'; -import { MyRedisDatabasePage, WorkbenchPage } from '../../../../pageObjects'; +import { BrowserPage, MyRedisDatabasePage, WorkbenchPage } from '../../../../pageObjects'; import { commonUrl, ossStandaloneConfig } from '../../../../helpers/conf'; import { DatabaseAPIRequests } from '../../../../helpers/api/api-database'; @@ -8,6 +8,7 @@ const myRedisDatabasePage = new MyRedisDatabasePage(); const workbenchPage = new WorkbenchPage(); const databaseHelper = new DatabaseHelper(); const databaseAPIRequests = new DatabaseAPIRequests(); +const browserPage = new BrowserPage(); fixture `Autocomplete for entered commands` .meta({ type: 'critical_path', rte: rte.standalone }) @@ -15,7 +16,8 @@ fixture `Autocomplete for entered commands` .beforeEach(async t => { await databaseHelper.acceptLicenseTermsAndAddDatabaseApi(ossStandaloneConfig); // Go to Workbench page - await t.click(myRedisDatabasePage.NavigationPanel.workbenchButton); + await t.click(myRedisDatabasePage.NavigationPanel.browserButton); + await browserPage.KeysInteractionPanel.setActiveTab(KeysInteractionTabs.Workbench); }) .afterEach(async() => { // Delete database diff --git a/tests/e2e/tests/web/critical-path/workbench/command-results.e2e.ts b/tests/e2e/tests/web/critical-path/workbench/command-results.e2e.ts index ac4e43621b..bb954b91b1 100644 --- a/tests/e2e/tests/web/critical-path/workbench/command-results.e2e.ts +++ b/tests/e2e/tests/web/critical-path/workbench/command-results.e2e.ts @@ -1,6 +1,6 @@ -import { rte } from '../../../../helpers/constants'; +import { KeysInteractionTabs, rte } from '../../../../helpers/constants'; import { DatabaseHelper } from '../../../../helpers/database'; -import { MyRedisDatabasePage, WorkbenchPage } from '../../../../pageObjects'; +import { BrowserPage, MyRedisDatabasePage, WorkbenchPage } from '../../../../pageObjects'; import { commonUrl, ossStandaloneConfig } from '../../../../helpers/conf'; import { DatabaseAPIRequests } from '../../../../helpers/api/api-database'; import { Common } from '../../../../helpers/common'; @@ -9,6 +9,7 @@ const myRedisDatabasePage = new MyRedisDatabasePage(); const workbenchPage = new WorkbenchPage(); const databaseHelper = new DatabaseHelper(); const databaseAPIRequests = new DatabaseAPIRequests(); +const browserPage = new BrowserPage(); const commandForSend1 = 'info'; const commandForSend2 = 'FT._LIST'; @@ -20,7 +21,8 @@ fixture `Command results at Workbench` .beforeEach(async t => { await databaseHelper.acceptLicenseTermsAndAddDatabaseApi(ossStandaloneConfig); // Go to Workbench page - await t.click(myRedisDatabasePage.NavigationPanel.workbenchButton); + await t.click(myRedisDatabasePage.NavigationPanel.browserButton); + await browserPage.KeysInteractionPanel.setActiveTab(KeysInteractionTabs.Workbench); }) .afterEach(async t => { await t.switchToMainWindow(); diff --git a/tests/e2e/tests/web/critical-path/workbench/context.e2e.ts b/tests/e2e/tests/web/critical-path/workbench/context.e2e.ts index ba1892f705..10038dd65c 100644 --- a/tests/e2e/tests/web/critical-path/workbench/context.e2e.ts +++ b/tests/e2e/tests/web/critical-path/workbench/context.e2e.ts @@ -1,6 +1,6 @@ -import { rte } from '../../../../helpers/constants'; +import { KeysInteractionTabs, rte } from '../../../../helpers/constants'; import { DatabaseHelper } from '../../../../helpers/database'; -import { MyRedisDatabasePage, WorkbenchPage } from '../../../../pageObjects'; +import { BrowserPage, MyRedisDatabasePage, WorkbenchPage } from '../../../../pageObjects'; import { commonUrl, ossStandaloneConfig } from '../../../../helpers/conf'; import { DatabaseAPIRequests } from '../../../../helpers/api/api-database'; import { Common } from '../../../../helpers/common'; @@ -9,6 +9,7 @@ const myRedisDatabasePage = new MyRedisDatabasePage(); const workbenchPage = new WorkbenchPage(); const databaseHelper = new DatabaseHelper(); const databaseAPIRequests = new DatabaseAPIRequests(); +const browserPage = new BrowserPage(); const speed = 0.4; let indexName = Common.generateWord(5); @@ -19,7 +20,8 @@ fixture `Workbench Context` .beforeEach(async t => { await databaseHelper.acceptLicenseTermsAndAddDatabaseApi(ossStandaloneConfig); // Go to Workbench page - await t.click(myRedisDatabasePage.NavigationPanel.workbenchButton); + await t.click(myRedisDatabasePage.NavigationPanel.browserButton); + await browserPage.KeysInteractionPanel.setActiveTab(KeysInteractionTabs.Workbench); }) .afterEach(async() => { // Drop index, documents and database @@ -31,8 +33,8 @@ test('Verify that user can see saved input in Editor when navigates away to any const command = `FT.CREATE ${indexName} ON HASH PREFIX 1 product: SCHEMA name TEXT`; // Enter the command in the Workbench editor and navigate to Browser await t.typeText(workbenchPage.queryInput, command, { replace: true, speed: speed }); - await t.click(myRedisDatabasePage.NavigationPanel.browserButton); + await browserPage.KeysInteractionPanel.setActiveTab(KeysInteractionTabs.BrowserAndFilter); // Return back to Workbench and check input in editor - await t.click(myRedisDatabasePage.NavigationPanel.workbenchButton); + await browserPage.KeysInteractionPanel.setActiveTab(KeysInteractionTabs.Workbench); await t.expect((await workbenchPage.queryInputScriptArea.textContent).replace(/\s/g, ' ')).eql(command, 'Input in Editor is saved'); }); diff --git a/tests/e2e/tests/web/critical-path/workbench/cypher.e2e.ts b/tests/e2e/tests/web/critical-path/workbench/cypher.e2e.ts index 6e9a3ce63f..1dc48e7762 100644 --- a/tests/e2e/tests/web/critical-path/workbench/cypher.e2e.ts +++ b/tests/e2e/tests/web/critical-path/workbench/cypher.e2e.ts @@ -1,6 +1,6 @@ -import { rte } from '../../../../helpers/constants'; +import { KeysInteractionTabs, rte } from '../../../../helpers/constants'; import { DatabaseHelper } from '../../../../helpers/database'; -import { MyRedisDatabasePage, WorkbenchPage } from '../../../../pageObjects'; +import { BrowserPage, MyRedisDatabasePage, WorkbenchPage } from '../../../../pageObjects'; import { commonUrl, ossStandaloneConfig } from '../../../../helpers/conf'; import { DatabaseAPIRequests } from '../../../../helpers/api/api-database'; @@ -8,6 +8,7 @@ const myRedisDatabasePage = new MyRedisDatabasePage(); const workbenchPage = new WorkbenchPage(); const databaseHelper = new DatabaseHelper(); const databaseAPIRequests = new DatabaseAPIRequests(); +const browserPage = new BrowserPage(); fixture `Cypher syntax at Workbench` .meta({ type: 'critical_path', rte: rte.standalone }) @@ -15,7 +16,8 @@ fixture `Cypher syntax at Workbench` .beforeEach(async t => { await databaseHelper.acceptLicenseTermsAndAddDatabaseApi(ossStandaloneConfig); // Go to Workbench page - await t.click(myRedisDatabasePage.NavigationPanel.workbenchButton); + await t.click(myRedisDatabasePage.NavigationPanel.browserButton); + await browserPage.KeysInteractionPanel.setActiveTab(KeysInteractionTabs.Workbench); }) .afterEach(async() => { // Drop database diff --git a/tests/e2e/tests/web/critical-path/workbench/default-scripts-area.e2e.ts b/tests/e2e/tests/web/critical-path/workbench/default-scripts-area.e2e.ts index 1791ce82c4..7cd1f5777e 100644 --- a/tests/e2e/tests/web/critical-path/workbench/default-scripts-area.e2e.ts +++ b/tests/e2e/tests/web/critical-path/workbench/default-scripts-area.e2e.ts @@ -1,7 +1,7 @@ import { Chance } from 'chance'; import { DatabaseHelper } from '../../../../helpers/database'; -import { MyRedisDatabasePage, WorkbenchPage } from '../../../../pageObjects'; -import { ExploreTabs, rte } from '../../../../helpers/constants'; +import { BrowserPage, MyRedisDatabasePage, WorkbenchPage } from '../../../../pageObjects'; +import { ExploreTabs, KeysInteractionTabs, rte } from '../../../../helpers/constants'; import { commonUrl, ossStandaloneRedisearch } from '../../../../helpers/conf'; import { DatabaseAPIRequests } from '../../../../helpers/api/api-database'; import { Telemetry } from '../../../../helpers/telemetry'; @@ -10,6 +10,8 @@ const myRedisDatabasePage = new MyRedisDatabasePage(); const workbenchPage = new WorkbenchPage(); const databaseHelper = new DatabaseHelper(); const databaseAPIRequests = new DatabaseAPIRequests(); +const browserPage = new BrowserPage(); + const chance = new Chance(); const telemetry = new Telemetry(); @@ -29,7 +31,8 @@ fixture `Default scripts area at Workbench` .beforeEach(async t => { await databaseHelper.acceptLicenseTermsAndAddDatabaseApi(ossStandaloneRedisearch); // Go to Workbench page - await t.click(myRedisDatabasePage.NavigationPanel.workbenchButton); + await t.click(myRedisDatabasePage.NavigationPanel.browserButton); + await browserPage.KeysInteractionPanel.setActiveTab(KeysInteractionTabs.Workbench); }) .afterEach(async t => { // Drop index, documents and database diff --git a/tests/e2e/tests/web/critical-path/workbench/scripting-area.e2e.ts b/tests/e2e/tests/web/critical-path/workbench/scripting-area.e2e.ts index 4fc4f744c6..1374c4a9f3 100644 --- a/tests/e2e/tests/web/critical-path/workbench/scripting-area.e2e.ts +++ b/tests/e2e/tests/web/critical-path/workbench/scripting-area.e2e.ts @@ -1,6 +1,6 @@ -import { rte } from '../../../../helpers/constants'; +import { KeysInteractionTabs, rte } from '../../../../helpers/constants'; import { DatabaseHelper } from '../../../../helpers/database'; -import { MyRedisDatabasePage, WorkbenchPage } from '../../../../pageObjects'; +import { BrowserPage, MyRedisDatabasePage, WorkbenchPage } from '../../../../pageObjects'; import { commonUrl, ossStandaloneConfig } from '../../../../helpers/conf'; import { DatabaseAPIRequests } from '../../../../helpers/api/api-database'; import { Common } from '../../../../helpers/common'; @@ -9,6 +9,7 @@ const myRedisDatabasePage = new MyRedisDatabasePage(); const workbenchPage = new WorkbenchPage(); const databaseHelper = new DatabaseHelper(); const databaseAPIRequests = new DatabaseAPIRequests(); +const browserPage = new BrowserPage(); let indexName = Common.generateWord(5); let keyName = Common.generateWord(5); @@ -19,7 +20,8 @@ fixture `Scripting area at Workbench` .beforeEach(async t => { await databaseHelper.acceptLicenseTermsAndAddDatabaseApi(ossStandaloneConfig); //Go to Workbench page - await t.click(myRedisDatabasePage.NavigationPanel.workbenchButton); + await t.click(myRedisDatabasePage.NavigationPanel.browserButton); + await browserPage.KeysInteractionPanel.setActiveTab(KeysInteractionTabs.Workbench); }) .afterEach(async t => { await t.switchToMainWindow(); diff --git a/tests/e2e/tests/web/regression/browser/context.e2e.ts b/tests/e2e/tests/web/regression/browser/context.e2e.ts index c54087b6a4..13e11ab855 100644 --- a/tests/e2e/tests/web/regression/browser/context.e2e.ts +++ b/tests/e2e/tests/web/regression/browser/context.e2e.ts @@ -3,7 +3,7 @@ import { MyRedisDatabasePage, BrowserPage } from '../../../../pageObjects'; -import { rte } from '../../../../helpers/constants'; +import { KeysInteractionTabs, rte } from '../../../../helpers/constants'; import { commonUrl, ossStandaloneConfig } from '../../../../helpers/conf'; import { DatabaseAPIRequests } from '../../../../helpers/api/api-database'; import { Common } from '../../../../helpers/common'; @@ -41,7 +41,6 @@ test('Verify that if user has saved context on Browser page and go to Settings p await t.click(myRedisDatabasePage.NavigationPanel.settingsButton); // Verify that Browser and Workbench icons are displayed await t.expect(myRedisDatabasePage.NavigationPanel.browserButton.visible).ok('Browser icon is not displayed'); - await t.expect(myRedisDatabasePage.NavigationPanel.workbenchButton.visible).ok('Workbench icon is not displayed'); // Open Browser page and verify context await t.click(myRedisDatabasePage.NavigationPanel.browserButton); await verifySearchFilterValue(keyName); @@ -54,13 +53,13 @@ test('Verify that when user reload the window with saved context(on any page), c // Create context modificaions and navigate to Workbench await browserPage.addStringKey(keyName); await browserPage.openKeyDetails(keyName); - await t.click(myRedisDatabasePage.NavigationPanel.workbenchButton); + await browserPage.KeysInteractionPanel.setActiveTab(KeysInteractionTabs.Workbench); // Open Browser page and verify context - await t.click(myRedisDatabasePage.NavigationPanel.browserButton); + await browserPage.KeysInteractionPanel.setActiveTab(KeysInteractionTabs.BrowserAndFilter); await verifySearchFilterValue(keyName); await t.expect(browserPage.keyNameFormDetails.withExactText(keyName).exists).ok('The key details is not selected'); // Navigate to Workbench and reload the window - await t.click(myRedisDatabasePage.NavigationPanel.workbenchButton); + await t.click(myRedisDatabasePage.NavigationPanel.pubSubButton); await myRedisDatabasePage.reloadPage(); // Return back to Browser and check context is not saved await t.click(myRedisDatabasePage.NavigationPanel.browserButton); diff --git a/tests/e2e/tests/web/regression/browser/keys-all-databases.e2e.ts b/tests/e2e/tests/web/regression/browser/keys-all-databases.e2e.ts index a9b292375e..c0767b9456 100644 --- a/tests/e2e/tests/web/regression/browser/keys-all-databases.e2e.ts +++ b/tests/e2e/tests/web/regression/browser/keys-all-databases.e2e.ts @@ -1,5 +1,5 @@ import { Selector, t } from 'testcafe'; -import { rte } from '../../../../helpers/constants'; +import { KeysInteractionTabs, rte } from '../../../../helpers/constants'; import { DatabaseHelper } from '../../../../helpers/database'; import { BrowserPage, MyRedisDatabasePage } from '../../../../pageObjects'; import { @@ -108,9 +108,9 @@ test await browserActions.verifyAllRenderedKeysHasText(); // Go to Workbench page - await t.click(myRedisDatabasePage.NavigationPanel.workbenchButton); + await browserPage.KeysInteractionPanel.setActiveTab(KeysInteractionTabs.Workbench); // Go to Browser Page - await t.click(myRedisDatabasePage.NavigationPanel.browserButton); + await browserPage.KeysInteractionPanel.setActiveTab(KeysInteractionTabs.BrowserAndFilter); // Verify that keys info in row not empty after switching between pages await browserActions.verifyAllRenderedKeysHasText(); }); diff --git a/tests/e2e/tests/web/regression/browser/onboarding.e2e.ts b/tests/e2e/tests/web/regression/browser/onboarding.e2e.ts index e136ff7e65..e9f114f800 100644 --- a/tests/e2e/tests/web/regression/browser/onboarding.e2e.ts +++ b/tests/e2e/tests/web/regression/browser/onboarding.e2e.ts @@ -2,7 +2,7 @@ import { DatabaseHelper } from '../../../../helpers/database'; import { commonUrl, ossStandaloneConfigEmpty } from '../../../../helpers/conf'; -import { rte } from '../../../../helpers/constants'; +import { KeysInteractionTabs, rte } from '../../../../helpers/constants'; import { Common } from '../../../../helpers/common'; import { MemoryEfficiencyPage, @@ -132,7 +132,7 @@ test('Verify onboard new user skip tour', async(t) => { await onboardingCardsDialog.clickNextStep(); // verify tree view step is visible await onboardingCardsDialog.verifyStepVisible('Tree view'); - await t.click(browserPage.NavigationPanel.workbenchButton); + await browserPage.KeysInteractionPanel.setActiveTab(KeysInteractionTabs.Workbench); await t.click(myRedisDatabasePage.NavigationPanel.helpCenterButton); await t.expect(myRedisDatabasePage.NavigationPanel.HelpCenter.helpCenterPanel.visible).ok('help center panel is not opened'); await t.click(onboardingCardsDialog.resetOnboardingBtn); @@ -158,7 +158,7 @@ test.requestHooks(logger)('Verify that the final onboarding step is closed when // Verify last step of onboarding process is visible await onboardingCardsDialog.verifyStepVisible('Great job!'); // Go to Workbench page - await t.click(myRedisDatabasePage.NavigationPanel.workbenchButton); + await browserPage.KeysInteractionPanel.setActiveTab(KeysInteractionTabs.Workbench); // Verify that “ONBOARDING_TOUR_FINISHED” event is sent when user opens another page (or close the app) await telemetry.verifyEventHasProperties(telemetryEvent, expectedProperties, logger); diff --git a/tests/e2e/tests/web/regression/browser/resize-columns.e2e.ts b/tests/e2e/tests/web/regression/browser/resize-columns.e2e.ts index 5f86ecff1c..446c4b45a6 100644 --- a/tests/e2e/tests/web/regression/browser/resize-columns.e2e.ts +++ b/tests/e2e/tests/web/regression/browser/resize-columns.e2e.ts @@ -3,7 +3,7 @@ import { MyRedisDatabasePage, BrowserPage } from '../../../../pageObjects'; -import { rte } from '../../../../helpers/constants'; +import { KeysInteractionTabs, rte } from '../../../../helpers/constants'; import { commonUrl, ossStandaloneConfig } from '../../../../helpers/conf'; import { DatabaseAPIRequests } from '../../../../helpers/api/api-database'; import { Common } from '../../../../helpers/common'; @@ -80,8 +80,8 @@ test('Resize of columns in Hash, List, Zset Key details', async t => { } // Verify that resize saved when switching between pages - await t.click(myRedisDatabasePage.NavigationPanel.workbenchButton); - await t.click(myRedisDatabasePage.NavigationPanel.browserButton); + await browserPage.KeysInteractionPanel.setActiveTab(KeysInteractionTabs.Workbench); + await browserPage.KeysInteractionPanel.setActiveTab(KeysInteractionTabs.BrowserAndFilter); await browserPage.openKeyDetails(keys[0].name); await t.expect(field.clientWidth).within(keys[0].fieldWidthEnd - 5, keys[0].fieldWidthEnd + 5, 'Resize context not saved for key when switching between pages'); diff --git a/tests/e2e/tests/web/regression/browser/survey-link.e2e.ts b/tests/e2e/tests/web/regression/browser/survey-link.e2e.ts index 23176285e8..84471aae6e 100644 --- a/tests/e2e/tests/web/regression/browser/survey-link.e2e.ts +++ b/tests/e2e/tests/web/regression/browser/survey-link.e2e.ts @@ -1,5 +1,5 @@ import { DatabaseHelper } from '../../../../helpers/database'; -import { rte } from '../../../../helpers/constants'; +import { KeysInteractionTabs, rte } from '../../../../helpers/constants'; import { BrowserPage, MyRedisDatabasePage } from '../../../../pageObjects'; import { commonUrl, ossStandaloneConfig } from '../../../../helpers/conf'; import { DatabaseAPIRequests } from '../../../../helpers/api/api-database'; @@ -32,7 +32,7 @@ test('Verify that user can use survey link', async t => { // await Common.checkURL(externalPageLink); // await goBackHistory(); // Workbench page - await t.click(myRedisDatabasePage.NavigationPanel.workbenchButton); + await browserPage.KeysInteractionPanel.setActiveTab(KeysInteractionTabs.Workbench); await t.expect(browserPage.userSurveyLink.visible).ok('Survey Link is not displayed'); // Slow Log page await t.click(myRedisDatabasePage.NavigationPanel.analysisPageButton); diff --git a/tests/e2e/tests/web/regression/cli/cli-promote-workbench.ts b/tests/e2e/tests/web/regression/cli/cli-promote-workbench.ts index 17a48dc1a7..30be6c7e77 100644 --- a/tests/e2e/tests/web/regression/cli/cli-promote-workbench.ts +++ b/tests/e2e/tests/web/regression/cli/cli-promote-workbench.ts @@ -1,7 +1,7 @@ import { DatabaseHelper } from '../../../../helpers/database'; import { WorkbenchPage, MyRedisDatabasePage, BrowserPage } from '../../../../pageObjects'; import { commonUrl, ossStandaloneConfig } from '../../../../helpers/conf'; -import { rte } from '../../../../helpers/constants'; +import { KeysInteractionTabs, rte } from '../../../../helpers/constants'; import { DatabaseAPIRequests } from '../../../../helpers/api/api-database'; const browserPage = new BrowserPage(); @@ -22,7 +22,8 @@ fixture `Promote workbench in CLI` }); test('Verify that user can see saved workbench context after redirection from CLI to workbench', async t => { // Open Workbench - await t.click(myRedisDatabasePage.NavigationPanel.workbenchButton); + await t.click(myRedisDatabasePage.NavigationPanel.browserButton); + await browserPage.KeysInteractionPanel.setActiveTab(KeysInteractionTabs.Workbench); const command = 'INFO'; await t.typeText(workbenchPage.queryInput, command, { replace: true, speed: 1, paste: true }); await t.click(myRedisDatabasePage.NavigationPanel.browserButton); diff --git a/tests/e2e/tests/web/regression/database-overview/database-info.e2e.ts b/tests/e2e/tests/web/regression/database-overview/database-info.e2e.ts index 68aa9f9764..522babd78a 100644 --- a/tests/e2e/tests/web/regression/database-overview/database-info.e2e.ts +++ b/tests/e2e/tests/web/regression/database-overview/database-info.e2e.ts @@ -4,7 +4,7 @@ import { WorkbenchPage, BrowserPage } from '../../../../pageObjects'; -import { rte } from '../../../../helpers/constants'; +import { KeysInteractionTabs, rte } from '../../../../helpers/constants'; import { commonUrl, ossStandaloneConfig } from '../../../../helpers/conf'; import { DatabaseAPIRequests } from '../../../../helpers/api/api-database'; @@ -41,6 +41,6 @@ test('Verify that user can see DB name, endpoint, connection type, Redis version // Verify that user can see an (i) icon next to the database name on Browser and Workbench pages await t.expect(browserPage.OverviewPanel.databaseInfoIcon.visible).ok('User can not see (i) icon on Browser page', { timeout: 10000 }); // Move to the Workbench page and check icon - await t.click(myRedisDatabasePage.NavigationPanel.workbenchButton); + await browserPage.KeysInteractionPanel.setActiveTab(KeysInteractionTabs.Workbench); await t.expect(workbenchPage.OverviewPanel.overviewTotalMemory.visible).ok('User can not see (i) icon on Workbench page', { timeout: 10000 }); }); diff --git a/tests/e2e/tests/web/regression/database-overview/database-overview.e2e.ts b/tests/e2e/tests/web/regression/database-overview/database-overview.e2e.ts index 8741192414..a09cc88a66 100644 --- a/tests/e2e/tests/web/regression/database-overview/database-overview.e2e.ts +++ b/tests/e2e/tests/web/regression/database-overview/database-overview.e2e.ts @@ -4,7 +4,7 @@ import { WorkbenchPage, BrowserPage } from '../../../../pageObjects'; -import { rte } from '../../../../helpers/constants'; +import { KeysInteractionTabs, rte } from '../../../../helpers/constants'; import { commonUrl, ossStandaloneConfig } from '../../../../helpers/conf'; import { Common } from '../../../../helpers/common'; import { DatabaseAPIRequests } from '../../../../helpers/api/api-database'; @@ -35,7 +35,7 @@ test('Verify that user can connect to DB and see breadcrumbs at the top of the a // Verify that user can see breadcrumbs in Browser and Workbench views await t.expect(browserPage.breadcrumbsContainer.visible).ok('User can not see breadcrumbs in Browser page', { timeout: 10000 }); - await t.click(myRedisDatabasePage.NavigationPanel.workbenchButton); + await browserPage.KeysInteractionPanel.setActiveTab(KeysInteractionTabs.Workbench); await t.expect(browserPage.breadcrumbsContainer.visible).ok('User can not see breadcrumbs in Workbench page', { timeout: 10000 }); // Verify that user can see total memory and total number of keys updated in DB header in Workbench page diff --git a/tests/e2e/tests/web/regression/database/github.e2e.ts b/tests/e2e/tests/web/regression/database/github.e2e.ts index 2a05263539..d1e5c008d2 100644 --- a/tests/e2e/tests/web/regression/database/github.e2e.ts +++ b/tests/e2e/tests/web/regression/database/github.e2e.ts @@ -1,13 +1,13 @@ -import { rte } from '../../../../helpers/constants'; +import { KeysInteractionTabs, rte } from '../../../../helpers/constants'; import { DatabaseHelper } from '../../../../helpers/database'; -import { MyRedisDatabasePage } from '../../../../pageObjects'; +import { BrowserPage, MyRedisDatabasePage } from '../../../../pageObjects'; import { commonUrl, ossStandaloneConfig } from '../../../../helpers/conf'; import { DatabaseAPIRequests } from '../../../../helpers/api/api-database'; -import { Common } from '../../../../helpers/common'; const myRedisDatabasePage = new MyRedisDatabasePage(); const databaseHelper = new DatabaseHelper(); const databaseAPIRequests = new DatabaseAPIRequests(); +const browserPage = new BrowserPage(); fixture `Github functionality` .meta({ type: 'regression', rte: rte.standalone }) @@ -29,7 +29,8 @@ test('Verify that user can work with Github link in the application', async t => await myRedisDatabasePage.clickOnDBByName(ossStandaloneConfig.databaseName); await t.expect(myRedisDatabasePage.NavigationPanel.githubButton.visible).ok('Github button not found'); // Verify that user can see the icon for GitHub reference at the bottom of the left side bar on the Workbench page - await t.click(myRedisDatabasePage.NavigationPanel.workbenchButton); + await t.click(myRedisDatabasePage.NavigationPanel.browserButton); + await browserPage.KeysInteractionPanel.setActiveTab(KeysInteractionTabs.Workbench); await t.expect(myRedisDatabasePage.NavigationPanel.githubButton.visible).ok('Github button'); // Verify that when user clicks on Github icon he redirects to the URL: https://github.com/RedisInsight/RedisInsight await t.click(myRedisDatabasePage.NavigationPanel.githubButton); diff --git a/tests/e2e/tests/web/regression/insights/import-tutorials.e2e.ts b/tests/e2e/tests/web/regression/insights/import-tutorials.e2e.ts index 644d73ec8a..b85fc6b332 100644 --- a/tests/e2e/tests/web/regression/insights/import-tutorials.e2e.ts +++ b/tests/e2e/tests/web/regression/insights/import-tutorials.e2e.ts @@ -2,7 +2,7 @@ import * as path from 'path'; import * as fs from 'fs'; import { join as joinPath } from 'path'; import { t } from 'testcafe'; -import { ExploreTabs, rte } from '../../../../helpers/constants'; +import { ExploreTabs, KeysInteractionTabs, rte } from '../../../../helpers/constants'; import { DatabaseHelper } from '../../../../helpers/database'; import { BrowserPage, MemoryEfficiencyPage, MyRedisDatabasePage, WorkbenchPage } from '../../../../pageObjects'; import { commonUrl, ossStandaloneConfig, ossStandaloneRedisearch, fileDownloadPath } from '../../../../helpers/conf'; @@ -41,7 +41,8 @@ fixture `Upload custom tutorials` .page(commonUrl) .beforeEach(async t => { await databaseHelper.acceptLicenseTermsAndAddDatabaseApi(ossStandaloneConfig); - await t.click(myRedisDatabasePage.NavigationPanel.workbenchButton); + await t.click(myRedisDatabasePage.NavigationPanel.browserButton); + await browserPage.KeysInteractionPanel.setActiveTab(KeysInteractionTabs.Workbench); }) .afterEach(async() => { await databaseAPIRequests.deleteStandaloneDatabaseApi(ossStandaloneConfig); @@ -53,7 +54,9 @@ https://redislabs.atlassian.net/browse/RI-4302, https://redislabs.atlassian.net/ test.skip .before(async t => { await databaseHelper.acceptLicenseTermsAndAddDatabaseApi(ossStandaloneConfig); - await t.click(myRedisDatabasePage.NavigationPanel.workbenchButton); + await t.click(myRedisDatabasePage.NavigationPanel.browserButton); + await browserPage.KeysInteractionPanel.setActiveTab(KeysInteractionTabs.Workbench); + tutorialName = `${zipFolderName}${Common.generateWord(5)}`; zipFilePath = path.join('..', 'test-data', 'upload-tutorials', `${tutorialName}.zip`); // Create zip file for uploading @@ -168,7 +171,9 @@ test test.skip .before(async t => { await databaseHelper.acceptLicenseTermsAndAddDatabaseApi(ossStandaloneRedisearch); - await t.click(myRedisDatabasePage.NavigationPanel.workbenchButton); + await t.click(myRedisDatabasePage.NavigationPanel.browserButton); + await browserPage.KeysInteractionPanel.setActiveTab(KeysInteractionTabs.Workbench); + tutorialName = `${zipFolderName}${Common.generateWord(5)}`; zipFilePath = path.join('..', 'test-data', 'upload-tutorials', `${tutorialName}.zip`); // Create zip file for uploading @@ -180,7 +185,9 @@ test.skip await Common.deleteFileFromFolder(zipFilePath); await deleteAllKeysFromDB(ossStandaloneRedisearch.host, ossStandaloneRedisearch.port); // Clear and delete database - await t.click(myRedisDatabasePage.NavigationPanel.workbenchButton); + await t.click(browserPage.NavigationPanel.browserButton); + await browserPage.KeysInteractionPanel.setActiveTab(KeysInteractionTabs.Workbench); + await workbenchPage.InsightsPanel.togglePanel(true); const tutorials = await workbenchPage.InsightsPanel.setActiveTab(ExploreTabs.Tutorials); await tutorials.deleteTutorialByName(tutorialName); diff --git a/tests/e2e/tests/web/regression/insights/live-recommendations.e2e.ts b/tests/e2e/tests/web/regression/insights/live-recommendations.e2e.ts index bc14e55c69..50ff1d1fc7 100644 --- a/tests/e2e/tests/web/regression/insights/live-recommendations.e2e.ts +++ b/tests/e2e/tests/web/regression/insights/live-recommendations.e2e.ts @@ -1,6 +1,6 @@ import * as path from 'path'; import { BrowserPage, MemoryEfficiencyPage, MyRedisDatabasePage, WorkbenchPage } from '../../../../pageObjects'; -import { ExploreTabs, RecommendationIds, rte } from '../../../../helpers/constants'; +import { ExploreTabs, KeysInteractionTabs, RecommendationIds, rte } from '../../../../helpers/constants'; import { DatabaseHelper } from '../../../../helpers/database'; import { commonUrl, ossStandaloneConfig, ossStandaloneV5Config } from '../../../../helpers/conf'; import { DatabaseAPIRequests } from '../../../../helpers/api/api-database'; @@ -247,7 +247,9 @@ test('Verify that if user clicks on the Analyze button and link, the pop up with //Verify that user is navigated to DB Analysis page via Analyze button and new report is generated await t.click(memoryEfficiencyPage.selectedReport); await t.expect(memoryEfficiencyPage.reportItem.visible).ok('Database analysis page not opened'); - await t.click(memoryEfficiencyPage.NavigationPanel.workbenchButton); + await t.click(memoryEfficiencyPage.NavigationPanel.browserButton); + await browserPage.KeysInteractionPanel.setActiveTab(KeysInteractionTabs.Workbench); + await workbenchPage.InsightsPanel.togglePanel(true); tab = await browserPage.InsightsPanel.setActiveTab(ExploreTabs.Tips); await t.click(tab.analyzeDatabaseLink); diff --git a/tests/e2e/tests/web/regression/insights/open-insights-panel.e2e.ts b/tests/e2e/tests/web/regression/insights/open-insights-panel.e2e.ts index 4fd89e9874..8cdd8f2257 100644 --- a/tests/e2e/tests/web/regression/insights/open-insights-panel.e2e.ts +++ b/tests/e2e/tests/web/regression/insights/open-insights-panel.e2e.ts @@ -1,5 +1,5 @@ import { BrowserPage, MyRedisDatabasePage, WorkbenchPage } from '../../../../pageObjects'; -import { Compatibility, ExploreTabs, rte } from '../../../../helpers/constants'; +import { Compatibility, ExploreTabs, KeysInteractionTabs, rte } from '../../../../helpers/constants'; import { DatabaseHelper } from '../../../../helpers/database'; import { commonUrl, @@ -47,7 +47,7 @@ test await t.click(browserPage.NavigationPanel.myRedisDBButton); await myRedisDatabasePage.clickOnDBByName(ossStandaloneV5Config.databaseName); - await t.click(browserPage.NavigationPanel.workbenchButton); + await browserPage.KeysInteractionPanel.setActiveTab(KeysInteractionTabs.Workbench); await workbenchPage.sendCommandInWorkbench('TS.'); await t.click(browserPage.NavigationPanel.myRedisDBButton); diff --git a/tests/e2e/tests/web/regression/monitor/monitor.e2e.ts b/tests/e2e/tests/web/regression/monitor/monitor.e2e.ts index f5b5940704..4a86f49853 100644 --- a/tests/e2e/tests/web/regression/monitor/monitor.e2e.ts +++ b/tests/e2e/tests/web/regression/monitor/monitor.e2e.ts @@ -12,7 +12,7 @@ import { ossStandaloneConfig, ossStandaloneNoPermissionsConfig } from '../../../../helpers/conf'; -import { rte } from '../../../../helpers/constants'; +import { KeysInteractionTabs, rte } from '../../../../helpers/constants'; import { DatabaseAPIRequests } from '../../../../helpers/api/api-database'; import { WorkbenchActions } from '../../../../common-actions/workbench-actions'; @@ -148,7 +148,7 @@ test.skip await t.expect(browserPage.Profiler.monitorNoPermissionsMessage.innerText).eql('The Profiler cannot be started. This user has no permissions to run the \'monitor\' command', 'No Permissions message not found'); // Verify that if user doesn't have permissions to run monitor, run monitor button is not available await t.expect(browserPage.Profiler.runMonitorToggle.withAttribute('disabled').exists).ok('No permissions run icon not found'); - await t.click(myRedisDatabasePage.NavigationPanel.workbenchButton); + await browserPage.KeysInteractionPanel.setActiveTab(KeysInteractionTabs.Workbench); await workbenchPage.sendCommandInWorkbench(command); // Verify that user have the following error when there is no permission to run the CLIENT LIST: "NOPERM this user has no permissions to run the 'CLIENT LIST' command or its subcommand" await workbenchActions.verifyClientListErrorMessage(); diff --git a/tests/e2e/tests/web/regression/workbench/autocomplete.e2e.ts b/tests/e2e/tests/web/regression/workbench/autocomplete.e2e.ts index 20cd197b92..db496c2bc3 100644 --- a/tests/e2e/tests/web/regression/workbench/autocomplete.e2e.ts +++ b/tests/e2e/tests/web/regression/workbench/autocomplete.e2e.ts @@ -1,13 +1,13 @@ -import { rte } from '../../../../helpers/constants'; +import { KeysInteractionTabs, rte } from '../../../../helpers/constants'; import { DatabaseHelper } from '../../../../helpers/database'; -import { MyRedisDatabasePage, WorkbenchPage } from '../../../../pageObjects'; +import { BrowserPage, WorkbenchPage } from '../../../../pageObjects'; import { commonUrl, ossStandaloneConfig } from '../../../../helpers/conf'; import { DatabaseAPIRequests } from '../../../../helpers/api/api-database'; -const myRedisDatabasePage = new MyRedisDatabasePage(); const workbenchPage = new WorkbenchPage(); const databaseHelper = new DatabaseHelper(); const databaseAPIRequests = new DatabaseAPIRequests(); +const browserPage = new BrowserPage(); fixture `Autocomplete for entered commands` .meta({ type: 'regression', rte: rte.standalone }) @@ -15,7 +15,7 @@ fixture `Autocomplete for entered commands` .beforeEach(async t => { await databaseHelper.acceptLicenseTermsAndAddDatabaseApi(ossStandaloneConfig); // Go to Workbench page - await t.click(myRedisDatabasePage.NavigationPanel.workbenchButton); + await browserPage.KeysInteractionPanel.setActiveTab(KeysInteractionTabs.Workbench); }) .afterEach(async() => { // Delete database diff --git a/tests/e2e/tests/web/regression/workbench/autoexecute-button.e2e.ts b/tests/e2e/tests/web/regression/workbench/autoexecute-button.e2e.ts index 5eb4caf0f2..9bc30b02ed 100644 --- a/tests/e2e/tests/web/regression/workbench/autoexecute-button.e2e.ts +++ b/tests/e2e/tests/web/regression/workbench/autoexecute-button.e2e.ts @@ -1,20 +1,20 @@ import { DatabaseHelper } from '../../../../helpers/database'; -import { WorkbenchPage, MyRedisDatabasePage } from '../../../../pageObjects'; -import { ExploreTabs, rte } from '../../../../helpers/constants'; +import { WorkbenchPage, BrowserPage } from '../../../../pageObjects'; +import { ExploreTabs, KeysInteractionTabs, rte } from '../../../../helpers/constants'; import { commonUrl, ossStandaloneConfig } from '../../../../helpers/conf'; import { DatabaseAPIRequests } from '../../../../helpers/api/api-database'; -const myRedisDatabasePage = new MyRedisDatabasePage(); const workbenchPage = new WorkbenchPage(); const databaseHelper = new DatabaseHelper(); const databaseAPIRequests = new DatabaseAPIRequests(); +const browserPage = new BrowserPage(); fixture `Workbench Auto-Execute button` .meta({ type: 'regression', rte: rte.standalone }) .page(commonUrl) .beforeEach(async t => { await databaseHelper.acceptLicenseTermsAndAddDatabaseApi(ossStandaloneConfig); - await t.click(myRedisDatabasePage.NavigationPanel.workbenchButton); + await browserPage.KeysInteractionPanel.setActiveTab(KeysInteractionTabs.Workbench); }) .afterEach(async() => { // Clear and delete database diff --git a/tests/e2e/tests/web/regression/workbench/command-results.e2e.ts b/tests/e2e/tests/web/regression/workbench/command-results.e2e.ts index 77cc8c791e..40b725c1e4 100644 --- a/tests/e2e/tests/web/regression/workbench/command-results.e2e.ts +++ b/tests/e2e/tests/web/regression/workbench/command-results.e2e.ts @@ -1,7 +1,7 @@ import { DatabaseHelper } from '../../../../helpers/database'; -import { WorkbenchPage, MyRedisDatabasePage } from '../../../../pageObjects'; +import { WorkbenchPage, MyRedisDatabasePage, BrowserPage } from '../../../../pageObjects'; import { commonUrl, ossStandaloneRedisearch } from '../../../../helpers/conf'; -import { rte } from '../../../../helpers/constants'; +import { KeysInteractionTabs, rte } from '../../../../helpers/constants'; import { DatabaseAPIRequests } from '../../../../helpers/api/api-database'; import { Common } from '../../../../helpers/common'; import { WorkbenchActions } from '../../../../common-actions/workbench-actions'; @@ -11,6 +11,7 @@ const workbenchPage = new WorkbenchPage(); const workBenchActions = new WorkbenchActions(); const databaseHelper = new DatabaseHelper(); const databaseAPIRequests = new DatabaseAPIRequests(); +const browserPage = new BrowserPage(); const indexName = Common.generateWord(5); const commandsForIndex = [ @@ -25,7 +26,7 @@ fixture `Command results at Workbench` .beforeEach(async t => { await databaseHelper.acceptLicenseTermsAndAddDatabaseApi(ossStandaloneRedisearch); // Add index and data - await t.click(myRedisDatabasePage.NavigationPanel.workbenchButton); + await browserPage.KeysInteractionPanel.setActiveTab(KeysInteractionTabs.Workbench); await workbenchPage.sendCommandsArrayInWorkbench(commandsForIndex); }) .afterEach(async t => { @@ -114,7 +115,7 @@ test('Big output in workbench is visible in virtualized table', async t => { test .before(async t => { await databaseHelper.acceptLicenseTermsAndAddDatabaseApi(ossStandaloneRedisearch); - await t.click(myRedisDatabasePage.NavigationPanel.workbenchButton); + await browserPage.KeysInteractionPanel.setActiveTab(KeysInteractionTabs.Workbench); }) .after(async t => { await t.switchToMainWindow(); diff --git a/tests/e2e/tests/web/regression/workbench/context.e2e.ts b/tests/e2e/tests/web/regression/workbench/context.e2e.ts index a51762ecd8..3755ab21d5 100644 --- a/tests/e2e/tests/web/regression/workbench/context.e2e.ts +++ b/tests/e2e/tests/web/regression/workbench/context.e2e.ts @@ -1,4 +1,4 @@ -import { ExploreTabs, rte } from '../../../../helpers/constants'; +import { ExploreTabs, KeysInteractionTabs, rte } from '../../../../helpers/constants'; import { DatabaseHelper } from '../../../../helpers/database'; import { BrowserPage, MyRedisDatabasePage, WorkbenchPage } from '../../../../pageObjects'; import { commonUrl, ossStandaloneConfig } from '../../../../helpers/conf'; @@ -18,7 +18,7 @@ fixture `Workbench Context` .beforeEach(async t => { await databaseHelper.acceptLicenseTermsAndAddDatabaseApi(ossStandaloneConfig); // Go to Workbench page - await t.click(myRedisDatabasePage.NavigationPanel.workbenchButton); + await browserPage.KeysInteractionPanel.setActiveTab(KeysInteractionTabs.Workbench); }) .afterEach(async() => { // Delete database @@ -29,7 +29,7 @@ test('Verify that user can see saved CLI state when navigates away to any other await t.click(workbenchPage.Cli.cliExpandButton); await t.click(myRedisDatabasePage.NavigationPanel.browserButton); // Return back to Workbench and check CLI - await t.click(myRedisDatabasePage.NavigationPanel.workbenchButton); + await browserPage.KeysInteractionPanel.setActiveTab(KeysInteractionTabs.Workbench); await t.expect(workbenchPage.Cli.cliCollapseButton.exists).ok('CLI is not expanded'); }); // Update after resolving https://redislabs.atlassian.net/browse/RI-3299 @@ -55,7 +55,7 @@ test('Verify that user can see all the information removed when reloads the page await t.click(workbenchPage.Cli.cliExpandButton); await t.click(myRedisDatabasePage.NavigationPanel.browserButton); // Open Workbench page and verify context - await t.click(myRedisDatabasePage.NavigationPanel.workbenchButton); + await browserPage.KeysInteractionPanel.setActiveTab(KeysInteractionTabs.Workbench); await t.expect(workbenchPage.Cli.cliCollapseButton.exists).ok('CLI is not expanded'); await t.expect(workbenchPage.queryInputScriptArea.textContent).eql(command, 'Input in Editor is not saved'); // Reload the window and chek context diff --git a/tests/e2e/tests/web/regression/workbench/cypher.e2e.ts b/tests/e2e/tests/web/regression/workbench/cypher.e2e.ts index 044b546c91..13575f7249 100644 --- a/tests/e2e/tests/web/regression/workbench/cypher.e2e.ts +++ b/tests/e2e/tests/web/regression/workbench/cypher.e2e.ts @@ -1,13 +1,13 @@ -import { rte } from '../../../../helpers/constants'; +import { KeysInteractionTabs, rte } from '../../../../helpers/constants'; import { DatabaseHelper } from '../../../../helpers/database'; -import { MyRedisDatabasePage, WorkbenchPage } from '../../../../pageObjects'; +import { BrowserPage, WorkbenchPage } from '../../../../pageObjects'; import { commonUrl, ossStandaloneConfig } from '../../../../helpers/conf'; import { DatabaseAPIRequests } from '../../../../helpers/api/api-database'; -const myRedisDatabasePage = new MyRedisDatabasePage(); const workbenchPage = new WorkbenchPage(); const databaseHelper = new DatabaseHelper(); const databaseAPIRequests = new DatabaseAPIRequests(); +const browserPage = new BrowserPage(); const command = 'GRAPH.QUERY graph'; @@ -17,7 +17,7 @@ fixture `Cypher syntax at Workbench` .beforeEach(async t => { await databaseHelper.acceptLicenseTermsAndAddDatabaseApi(ossStandaloneConfig); // Go to Workbench page - await t.click(myRedisDatabasePage.NavigationPanel.workbenchButton); + await browserPage.KeysInteractionPanel.setActiveTab(KeysInteractionTabs.Workbench); }) .afterEach(async() => { // Drop database diff --git a/tests/e2e/tests/web/regression/workbench/default-scripts-area.e2e.ts b/tests/e2e/tests/web/regression/workbench/default-scripts-area.e2e.ts index db3898c8a7..fb468a9904 100644 --- a/tests/e2e/tests/web/regression/workbench/default-scripts-area.e2e.ts +++ b/tests/e2e/tests/web/regression/workbench/default-scripts-area.e2e.ts @@ -1,4 +1,4 @@ -import { ExploreTabs, rte } from '../../../../helpers/constants'; +import { ExploreTabs, KeysInteractionTabs, rte } from '../../../../helpers/constants'; import { DatabaseHelper } from '../../../../helpers/database'; import { BrowserPage, MyRedisDatabasePage, WorkbenchPage } from '../../../../pageObjects'; import { commonUrl, ossStandaloneConfig } from '../../../../helpers/conf'; @@ -16,7 +16,7 @@ fixture `Default scripts area at Workbench` .beforeEach(async t => { await databaseHelper.acceptLicenseTermsAndAddDatabaseApi(ossStandaloneConfig); // Go to Workbench page - await t.click(myRedisDatabasePage.NavigationPanel.workbenchButton); + await browserPage.KeysInteractionPanel.setActiveTab(KeysInteractionTabs.Workbench); }) .afterEach(async() => { // Delete database @@ -70,7 +70,7 @@ test('Verify that user can see saved article in Enablement area when he leaves W // Go to Browser page await t.click(myRedisDatabasePage.NavigationPanel.browserButton); // Go back to Workbench page - await t.click(myRedisDatabasePage.NavigationPanel.workbenchButton); + await browserPage.KeysInteractionPanel.setActiveTab(KeysInteractionTabs.Workbench); // Verify that the same article is opened in Enablement area selector = tutorials.getRunSelector('Create a hash'); await t.expect(selector.visible).ok('The end of the page is not visible'); diff --git a/tests/e2e/tests/web/regression/workbench/editor-cleanup.e2e.ts b/tests/e2e/tests/web/regression/workbench/editor-cleanup.e2e.ts index 2052959b77..244a827ed5 100644 --- a/tests/e2e/tests/web/regression/workbench/editor-cleanup.e2e.ts +++ b/tests/e2e/tests/web/regression/workbench/editor-cleanup.e2e.ts @@ -1,6 +1,6 @@ import { DatabaseHelper } from '../../../../helpers/database'; -import { WorkbenchPage, MyRedisDatabasePage, SettingsPage } from '../../../../pageObjects'; -import { rte } from '../../../../helpers/constants'; +import { WorkbenchPage, MyRedisDatabasePage, SettingsPage, BrowserPage } from '../../../../pageObjects'; +import { KeysInteractionTabs, rte } from '../../../../helpers/constants'; import { commonUrl, ossStandaloneConfig } from '../../../../helpers/conf'; import { DatabaseAPIRequests } from '../../../../helpers/api/api-database'; @@ -9,6 +9,7 @@ const workbenchPage = new WorkbenchPage(); const settingsPage = new SettingsPage(); const databaseHelper = new DatabaseHelper(); const databaseAPIRequests = new DatabaseAPIRequests(); +const browserPage = new BrowserPage(); const commandToSend = 'info server'; const databasesForAdding = [ @@ -35,7 +36,8 @@ test('Disabled Editor Cleanup toggle behavior', async t => { // Verify that user can see text "Clear the Editor after running commands" for Editor Cleanup In Settings await t.expect(settingsPage.switchEditorCleanupOption.sibling(0).withExactText('Clear the Editor after running commands').visible).ok('Cleanup text is not correct'); // Go to Workbench page - await t.click(myRedisDatabasePage.NavigationPanel.workbenchButton); + await t.click(settingsPage.NavigationPanel.browserButton); + await browserPage.KeysInteractionPanel.setActiveTab(KeysInteractionTabs.Workbench); // Send commands await workbenchPage.sendCommandInWorkbench(commandToSend); await workbenchPage.sendCommandInWorkbench(commandToSend); @@ -44,7 +46,7 @@ test('Disabled Editor Cleanup toggle behavior', async t => { }); test('Enabled Editor Cleanup toggle behavior', async t => { // Go to Workbench page - await t.click(myRedisDatabasePage.NavigationPanel.workbenchButton); + await browserPage.KeysInteractionPanel.setActiveTab(KeysInteractionTabs.Workbench); // Send commands await workbenchPage.sendCommandInWorkbench(commandToSend); await workbenchPage.sendCommandInWorkbench(commandToSend); diff --git a/tests/e2e/tests/web/regression/workbench/empty-command-history.e2e.ts b/tests/e2e/tests/web/regression/workbench/empty-command-history.e2e.ts index fce78be20c..5071c5ae1d 100644 --- a/tests/e2e/tests/web/regression/workbench/empty-command-history.e2e.ts +++ b/tests/e2e/tests/web/regression/workbench/empty-command-history.e2e.ts @@ -1,11 +1,11 @@ import { Selector } from 'testcafe'; -import { rte } from '../../../../helpers/constants'; +import { KeysInteractionTabs, rte } from '../../../../helpers/constants'; import { DatabaseHelper } from '../../../../helpers/database'; -import { MyRedisDatabasePage, WorkbenchPage } from '../../../../pageObjects'; +import { BrowserPage, WorkbenchPage } from '../../../../pageObjects'; import { commonUrl, ossStandaloneConfig } from '../../../../helpers/conf'; import { DatabaseAPIRequests } from '../../../../helpers/api/api-database'; -const myRedisDatabasePage = new MyRedisDatabasePage(); +const browserPage = new BrowserPage(); const workbenchPage = new WorkbenchPage(); const databaseHelper = new DatabaseHelper(); const databaseAPIRequests = new DatabaseAPIRequests(); @@ -16,7 +16,7 @@ fixture `Empty command history in Workbench` .beforeEach(async t => { await databaseHelper.acceptLicenseTermsAndAddDatabaseApi(ossStandaloneConfig); // Go to Workbench page - await t.click(myRedisDatabasePage.NavigationPanel.workbenchButton); + await browserPage.KeysInteractionPanel.setActiveTab(KeysInteractionTabs.Workbench); }) .afterEach(async() => { // Delete database diff --git a/tests/e2e/tests/web/regression/workbench/group-mode.e2e.ts b/tests/e2e/tests/web/regression/workbench/group-mode.e2e.ts index a115c0a95a..64c0cd0bb7 100644 --- a/tests/e2e/tests/web/regression/workbench/group-mode.e2e.ts +++ b/tests/e2e/tests/web/regression/workbench/group-mode.e2e.ts @@ -1,11 +1,11 @@ import { Selector } from 'testcafe'; -import { rte } from '../../../../helpers/constants'; +import { KeysInteractionTabs, rte } from '../../../../helpers/constants'; import { DatabaseHelper } from '../../../../helpers/database'; -import { MyRedisDatabasePage, WorkbenchPage } from '../../../../pageObjects'; +import { BrowserPage, WorkbenchPage } from '../../../../pageObjects'; import { commonUrl, ossStandaloneBigConfig } from '../../../../helpers/conf'; import { DatabaseAPIRequests } from '../../../../helpers/api/api-database'; -const myRedisDatabasePage = new MyRedisDatabasePage(); +const browserPage = new BrowserPage(); const workbenchPage = new WorkbenchPage(); const databaseHelper = new DatabaseHelper(); const databaseAPIRequests = new DatabaseAPIRequests(); @@ -23,7 +23,7 @@ fixture `Workbench Group Mode` .beforeEach(async t => { await databaseHelper.acceptLicenseTermsAndAddDatabaseApi(ossStandaloneBigConfig); // Go to Workbench page - await t.click(myRedisDatabasePage.NavigationPanel.workbenchButton); + await browserPage.KeysInteractionPanel.setActiveTab(KeysInteractionTabs.Workbench); }) .afterEach(async() => { // Delete database diff --git a/tests/e2e/tests/web/regression/workbench/history-of-results.e2e.ts b/tests/e2e/tests/web/regression/workbench/history-of-results.e2e.ts index 79b3e04501..fe0a0d024a 100644 --- a/tests/e2e/tests/web/regression/workbench/history-of-results.e2e.ts +++ b/tests/e2e/tests/web/regression/workbench/history-of-results.e2e.ts @@ -1,12 +1,12 @@ import { getRandomParagraph } from '../../../../helpers/keys'; import { DatabaseHelper } from '../../../../helpers/database'; -import { MyRedisDatabasePage, WorkbenchPage } from '../../../../pageObjects'; -import { rte } from '../../../../helpers/constants'; +import { BrowserPage, WorkbenchPage } from '../../../../pageObjects'; +import { KeysInteractionTabs, rte } from '../../../../helpers/constants'; import { commonUrl, ossStandaloneConfig } from '../../../../helpers/conf'; import { DatabaseAPIRequests } from '../../../../helpers/api/api-database'; import { Common } from '../../../../helpers/common'; -const myRedisDatabasePage = new MyRedisDatabasePage(); +const browserPage = new BrowserPage(); const workbenchPage = new WorkbenchPage(); const databaseHelper = new DatabaseHelper(); const databaseAPIRequests = new DatabaseAPIRequests(); @@ -21,7 +21,7 @@ fixture `History of results at Workbench` .beforeEach(async t => { await databaseHelper.acceptLicenseTermsAndAddDatabaseApi(ossStandaloneConfig); // Go to Workbench page - await t.click(myRedisDatabasePage.NavigationPanel.workbenchButton); + await browserPage.KeysInteractionPanel.setActiveTab(KeysInteractionTabs.Workbench); }) .afterEach(async() => { // Clear and delete database diff --git a/tests/e2e/tests/web/regression/workbench/raw-mode.e2e.ts b/tests/e2e/tests/web/regression/workbench/raw-mode.e2e.ts index 0b87cc4a19..94b08c001e 100644 --- a/tests/e2e/tests/web/regression/workbench/raw-mode.e2e.ts +++ b/tests/e2e/tests/web/regression/workbench/raw-mode.e2e.ts @@ -1,6 +1,6 @@ import { DatabaseHelper } from '../../../../helpers/database'; -import { WorkbenchPage, MyRedisDatabasePage } from '../../../../pageObjects'; -import { rte } from '../../../../helpers/constants'; +import { WorkbenchPage, MyRedisDatabasePage, BrowserPage } from '../../../../pageObjects'; +import { KeysInteractionTabs, rte } from '../../../../helpers/constants'; import { commonUrl, ossStandaloneConfig, ossStandaloneRedisearch } from '../../../../helpers/conf'; import { DatabaseAPIRequests } from '../../../../helpers/api/api-database'; import { Common } from '../../../../helpers/common'; @@ -8,6 +8,7 @@ import { APIKeyRequests } from '../../../../helpers/api/api-keys'; const myRedisDatabasePage = new MyRedisDatabasePage(); const workbenchPage = new WorkbenchPage(); +const browserPage = new BrowserPage(); const databaseHelper = new DatabaseHelper(); const databaseAPIRequests = new DatabaseAPIRequests(); const apiKeyRequests = new APIKeyRequests(); @@ -31,7 +32,7 @@ fixture `Workbench Raw mode` .beforeEach(async t => { await databaseHelper.acceptLicenseTermsAndAddDatabaseApi(ossStandaloneConfig); // Go to Workbench page - await t.click(myRedisDatabasePage.NavigationPanel.workbenchButton); + await browserPage.KeysInteractionPanel.setActiveTab(KeysInteractionTabs.Workbench); }) .afterEach(async t => { // Clear and delete database @@ -64,7 +65,7 @@ test await myRedisDatabasePage.reloadPage(); await myRedisDatabasePage.clickOnDBByName(databasesForAdding[0].databaseName); // Go to Workbench page - await t.click(myRedisDatabasePage.NavigationPanel.workbenchButton); + await browserPage.KeysInteractionPanel.setActiveTab(KeysInteractionTabs.Workbench); }) .after(async() => { // Clear and delete database @@ -81,7 +82,7 @@ test await t.click(myRedisDatabasePage.NavigationPanel.myRedisDBButton); await myRedisDatabasePage.clickOnDBByName(databasesForAdding[1].databaseName); // Go to Workbench page - await t.click(myRedisDatabasePage.NavigationPanel.workbenchButton); + await browserPage.KeysInteractionPanel.setActiveTab(KeysInteractionTabs.Workbench); // Verify that user can see saved Raw mode state after re-connection to another DB await workbenchPage.sendCommandInWorkbench(commandsForSend[1]); await workbenchPage.checkWorkbenchCommandResult(commandsForSend[1], `"${unicodeValue}"`); @@ -93,7 +94,7 @@ test .before(async t => { await databaseHelper.acceptLicenseTermsAndAddDatabaseApi(ossStandaloneRedisearch); // Go to Workbench page - await t.click(myRedisDatabasePage.NavigationPanel.workbenchButton); + await browserPage.KeysInteractionPanel.setActiveTab(KeysInteractionTabs.Workbench); }) .after(async t => { // Drop index, documents and database diff --git a/tests/e2e/tests/web/regression/workbench/redis-stack-commands.e2e.ts b/tests/e2e/tests/web/regression/workbench/redis-stack-commands.e2e.ts index 218411f615..2e6f062018 100644 --- a/tests/e2e/tests/web/regression/workbench/redis-stack-commands.e2e.ts +++ b/tests/e2e/tests/web/regression/workbench/redis-stack-commands.e2e.ts @@ -1,11 +1,11 @@ import { t } from 'testcafe'; import { DatabaseHelper } from '../../../../helpers/database'; -import { WorkbenchPage, MyRedisDatabasePage } from '../../../../pageObjects'; +import { WorkbenchPage, BrowserPage } from '../../../../pageObjects'; import { commonUrl, ossStandaloneConfig } from '../../../../helpers/conf'; -import { ExploreTabs, rte } from '../../../../helpers/constants'; +import { ExploreTabs, KeysInteractionTabs, rte } from '../../../../helpers/constants'; import { DatabaseAPIRequests } from '../../../../helpers/api/api-database'; -const myRedisDatabasePage = new MyRedisDatabasePage(); +const browserPage = new BrowserPage(); const workbenchPage = new WorkbenchPage(); const databaseHelper = new DatabaseHelper(); const databaseAPIRequests = new DatabaseAPIRequests(); @@ -17,7 +17,7 @@ fixture `Redis Stack command in Workbench` .page(commonUrl) .beforeEach(async t => { await databaseHelper.acceptLicenseTermsAndAddDatabaseApi(ossStandaloneConfig); - await t.click(myRedisDatabasePage.NavigationPanel.workbenchButton); + await browserPage.KeysInteractionPanel.setActiveTab(KeysInteractionTabs.Workbench); }) .afterEach(async() => { // Drop key and database diff --git a/tests/e2e/tests/web/regression/workbench/redisearch-module-not-available.e2e.ts b/tests/e2e/tests/web/regression/workbench/redisearch-module-not-available.e2e.ts index 729387935c..ffa713a5d1 100644 --- a/tests/e2e/tests/web/regression/workbench/redisearch-module-not-available.e2e.ts +++ b/tests/e2e/tests/web/regression/workbench/redisearch-module-not-available.e2e.ts @@ -1,11 +1,11 @@ import { ClientFunction } from 'testcafe'; -import { ExploreTabs, rte } from '../../../../helpers/constants'; +import { KeysInteractionTabs, rte } from '../../../../helpers/constants'; import { DatabaseHelper } from '../../../../helpers/database'; -import { MyRedisDatabasePage, WorkbenchPage } from '../../../../pageObjects'; +import { BrowserPage, WorkbenchPage } from '../../../../pageObjects'; import { commonUrl, ossStandaloneV5Config } from '../../../../helpers/conf'; import { DatabaseAPIRequests } from '../../../../helpers/api/api-database'; -const myRedisDatabasePage = new MyRedisDatabasePage(); +const browserPage = new BrowserPage(); const workbenchPage = new WorkbenchPage(); const databaseHelper = new DatabaseHelper(); const databaseAPIRequests = new DatabaseAPIRequests(); @@ -18,7 +18,7 @@ fixture `Redisearch module not available` .page(commonUrl) .beforeEach(async t => { await databaseHelper.acceptLicenseTermsAndAddDatabaseApi(ossStandaloneV5Config); - await t.click(myRedisDatabasePage.NavigationPanel.workbenchButton); + await browserPage.KeysInteractionPanel.setActiveTab(KeysInteractionTabs.Workbench); }) .afterEach(async() => { // Delete database diff --git a/tests/e2e/tests/web/regression/workbench/scripting-area.e2e.ts b/tests/e2e/tests/web/regression/workbench/scripting-area.e2e.ts index 35f701edc5..4904b186e1 100644 --- a/tests/e2e/tests/web/regression/workbench/scripting-area.e2e.ts +++ b/tests/e2e/tests/web/regression/workbench/scripting-area.e2e.ts @@ -1,6 +1,6 @@ -import { ExploreTabs, rte } from '../../../../helpers/constants'; +import { ExploreTabs, KeysInteractionTabs, rte } from '../../../../helpers/constants'; import { DatabaseHelper } from '../../../../helpers/database'; -import { MyRedisDatabasePage, WorkbenchPage, SettingsPage } from '../../../../pageObjects'; +import { MyRedisDatabasePage, WorkbenchPage, SettingsPage, BrowserPage } from '../../../../pageObjects'; import { commonUrl, ossStandaloneConfig } from '../../../../helpers/conf'; import { DatabaseAPIRequests } from '../../../../helpers/api/api-database'; import { Common } from '../../../../helpers/common'; @@ -10,6 +10,7 @@ const workbenchPage = new WorkbenchPage(); const settingsPage = new SettingsPage(); const databaseHelper = new DatabaseHelper(); const databaseAPIRequests = new DatabaseAPIRequests(); +const browserPage = new BrowserPage(); const indexName = Common.generateWord(5); let keyName = Common.generateWord(5); @@ -20,7 +21,7 @@ fixture `Scripting area at Workbench` .beforeEach(async t => { await databaseHelper.acceptLicenseTermsAndAddDatabaseApi(ossStandaloneConfig); // Go to Workbench page - await t.click(myRedisDatabasePage.NavigationPanel.workbenchButton); + await browserPage.KeysInteractionPanel.setActiveTab(KeysInteractionTabs.Workbench); }) .afterEach(async() => { // Clear and delete database @@ -41,7 +42,8 @@ test('Verify that user can run multiple commands written in multiple lines in Wo await t.click(settingsPage.accordionWorkbenchSettings); await settingsPage.changeCommandsInPipeline('1'); // Go to Workbench page - await t.click(myRedisDatabasePage.NavigationPanel.workbenchButton); + await t.click(settingsPage.NavigationPanel.browserButton); + await browserPage.KeysInteractionPanel.setActiveTab(KeysInteractionTabs.Workbench); // Send commands in multiple lines await workbenchPage.sendCommandInWorkbench(commandsForSend.join('\n'), 0.5); // Check the result @@ -68,7 +70,8 @@ test await t.click(settingsPage.accordionWorkbenchSettings); await settingsPage.changeCommandsInPipeline('1'); // Go to Workbench page - await t.click(myRedisDatabasePage.NavigationPanel.workbenchButton); + await t.click(settingsPage.NavigationPanel.browserButton); + await browserPage.KeysInteractionPanel.setActiveTab(KeysInteractionTabs.Workbench); // Send commands in multiple lines with double slashes (//) wrapped in double quotes await workbenchPage.sendCommandInWorkbench(commandsForSend.join('\n"//"'), 0.5); // Check that all commands are executed diff --git a/tests/e2e/tests/web/regression/workbench/workbench-all-db-types.e2e.ts b/tests/e2e/tests/web/regression/workbench/workbench-all-db-types.e2e.ts index 633deadb0d..59de3d7644 100644 --- a/tests/e2e/tests/web/regression/workbench/workbench-all-db-types.e2e.ts +++ b/tests/e2e/tests/web/regression/workbench/workbench-all-db-types.e2e.ts @@ -1,12 +1,13 @@ import { t } from 'testcafe'; -import { rte } from '../../../../helpers/constants'; +import { KeysInteractionTabs, rte } from '../../../../helpers/constants'; import { DatabaseHelper } from '../../../../helpers/database'; -import { MyRedisDatabasePage, WorkbenchPage } from '../../../../pageObjects'; +import { BrowserPage, MyRedisDatabasePage, WorkbenchPage } from '../../../../pageObjects'; import { cloudDatabaseConfig, commonUrl, ossClusterConfig, ossSentinelConfig } from '../../../../helpers/conf'; import { DatabaseAPIRequests } from '../../../../helpers/api/api-database'; const myRedisDatabasePage = new MyRedisDatabasePage(); const workbenchPage = new WorkbenchPage(); +const browserPage = new BrowserPage(); const databaseHelper = new DatabaseHelper(); const databaseAPIRequests = new DatabaseAPIRequests(); @@ -19,7 +20,8 @@ const verifyCommandsInWorkbench = async(): Promise => { 'FT.SEARCH idx *' ]; - await t.click(myRedisDatabasePage.NavigationPanel.workbenchButton); + await t.click(myRedisDatabasePage.NavigationPanel.browserButton); + await browserPage.KeysInteractionPanel.setActiveTab(KeysInteractionTabs.Workbench); // Send commands await workbenchPage.sendCommandInWorkbench(commandForSend1); await workbenchPage.sendCommandInWorkbench(commandForSend2); diff --git a/tests/e2e/tests/web/regression/workbench/workbench-non-auto-guides.e2e.ts b/tests/e2e/tests/web/regression/workbench/workbench-non-auto-guides.e2e.ts index 447c61115f..b920f2b265 100644 --- a/tests/e2e/tests/web/regression/workbench/workbench-non-auto-guides.e2e.ts +++ b/tests/e2e/tests/web/regression/workbench/workbench-non-auto-guides.e2e.ts @@ -1,6 +1,6 @@ import { DatabaseHelper } from '../../../../helpers/database'; -import { WorkbenchPage, MyRedisDatabasePage } from '../../../../pageObjects'; -import { rte } from '../../../../helpers/constants'; +import { WorkbenchPage, MyRedisDatabasePage, BrowserPage } from '../../../../pageObjects'; +import { KeysInteractionTabs, rte } from '../../../../helpers/constants'; import { commonUrl, ossStandaloneConfig } from '../../../../helpers/conf'; import { DatabaseAPIRequests } from '../../../../helpers/api/api-database'; import { Common } from '../../../../helpers/common'; @@ -8,6 +8,7 @@ import { APIKeyRequests } from '../../../../helpers/api/api-keys'; const myRedisDatabasePage = new MyRedisDatabasePage(); const workbenchPage = new WorkbenchPage(); +const browserPage = new BrowserPage(); const databaseHelper = new DatabaseHelper(); const databaseAPIRequests = new DatabaseAPIRequests(); const apiKeyRequests = new APIKeyRequests(); @@ -37,7 +38,7 @@ fixture `Workbench modes to non-auto guides` .page(commonUrl) .beforeEach(async t => { await databaseHelper.acceptLicenseTermsAndAddDatabaseApi(ossStandaloneConfig); - await t.click(myRedisDatabasePage.NavigationPanel.workbenchButton); + await browserPage.KeysInteractionPanel.setActiveTab(KeysInteractionTabs.Workbench); }) .afterEach(async() => { // Delete database @@ -46,7 +47,7 @@ fixture `Workbench modes to non-auto guides` test .before(async t => { await databaseHelper.acceptLicenseTermsAndAddDatabaseApi(ossStandaloneConfig); - await t.click(myRedisDatabasePage.NavigationPanel.workbenchButton); + await browserPage.KeysInteractionPanel.setActiveTab(KeysInteractionTabs.Workbench); await workbenchPage.sendCommandInWorkbench(`set ${keyName} "${keyValue}"`); }) .after(async t => { diff --git a/tests/e2e/tests/web/regression/workbench/workbench-pipeline.e2e.ts b/tests/e2e/tests/web/regression/workbench/workbench-pipeline.e2e.ts index a78097f21e..fc97f27f8a 100644 --- a/tests/e2e/tests/web/regression/workbench/workbench-pipeline.e2e.ts +++ b/tests/e2e/tests/web/regression/workbench/workbench-pipeline.e2e.ts @@ -1,13 +1,14 @@ // import { ClientFunction } from 'testcafe'; -import { rte } from '../../../../helpers/constants'; +import { KeysInteractionTabs, rte } from '../../../../helpers/constants'; import { DatabaseHelper } from '../../../../helpers/database'; -import { MyRedisDatabasePage, SettingsPage, WorkbenchPage } from '../../../../pageObjects'; +import { BrowserPage, MyRedisDatabasePage, SettingsPage, WorkbenchPage } from '../../../../pageObjects'; import { commonUrl, ossStandaloneBigConfig } from '../../../../helpers/conf'; import { DatabaseAPIRequests } from '../../../../helpers/api/api-database'; import { Common } from '../../../../helpers/common'; const myRedisDatabasePage = new MyRedisDatabasePage(); const workbenchPage = new WorkbenchPage(); +const browserPage = new BrowserPage(); const settingsPage = new SettingsPage(); const databaseHelper = new DatabaseHelper(); const databaseAPIRequests = new DatabaseAPIRequests(); @@ -49,7 +50,8 @@ test('Verify that user can see the text in settings for pipeline with link', asy test.skip('Verify that only chosen in pipeline number of commands is loading at the same time in Workbench', async t => { await settingsPage.changeCommandsInPipeline(pipelineValues[1]); // Go to Workbench page - await t.click(myRedisDatabasePage.NavigationPanel.workbenchButton); + await t.click(settingsPage.NavigationPanel.browserButton); + await browserPage.KeysInteractionPanel.setActiveTab(KeysInteractionTabs.Workbench); await workbenchPage.sendCommandInWorkbench(commandForSend, 0.01); // Verify that only selected pipeline number of commands are loaded at the same time await t.expect(workbenchPage.loadedCommand.count).eql(Number(pipelineValues[1]), 'The number of sending commands is incorrect'); @@ -57,7 +59,8 @@ test.skip('Verify that only chosen in pipeline number of commands is loading at test.skip('Verify that user can see spinner over Run button and grey preloader for each command', async t => { await settingsPage.changeCommandsInPipeline(pipelineValues[3]); // Go to Workbench page - await t.click(myRedisDatabasePage.NavigationPanel.workbenchButton); + await t.click(settingsPage.NavigationPanel.browserButton); + await browserPage.KeysInteractionPanel.setActiveTab(KeysInteractionTabs.Workbench); await workbenchPage.sendCommandInWorkbench(commandForSend, 0.01); // Verify that user can`t start new commands from the Workbench while command(s) is executing await t.expect(workbenchPage.submitCommandButton.withAttribute('disabled').exists).ok('Run button is not disabled', { timeout: 5000 }); @@ -70,7 +73,8 @@ test('Verify that user can interact with the Editor while command(s) in progress await settingsPage.changeCommandsInPipeline(pipelineValues[2]); // Go to Workbench page - await t.click(myRedisDatabasePage.NavigationPanel.workbenchButton); + await t.click(settingsPage.NavigationPanel.browserButton); + await browserPage.KeysInteractionPanel.setActiveTab(KeysInteractionTabs.Workbench); await workbenchPage.sendCommandInWorkbench(commandForSend); await t.typeText(workbenchPage.queryInput, commandForSend, { replace: true, paste: true }); await t.pressKey('enter'); @@ -89,7 +93,8 @@ test('Verify that command results are added to history in order most recent - on await settingsPage.changeCommandsInPipeline(pipelineValues[2]); // Go to Workbench page - await t.click(myRedisDatabasePage.NavigationPanel.workbenchButton); + await t.click(settingsPage.NavigationPanel.browserButton); + await browserPage.KeysInteractionPanel.setActiveTab(KeysInteractionTabs.Workbench); await workbenchPage.sendCommandInWorkbench(multipleCommands.join('\n')); // Check that the results for all commands are displayed in workbench history in reverse order (most recent - on top) for (let i = 0; i < multipleCommands.length; i++) { diff --git a/tests/e2e/tests/web/smoke/workbench/json-workbench.e2e.ts b/tests/e2e/tests/web/smoke/workbench/json-workbench.e2e.ts index 7f8ebdd65a..735d3226a2 100644 --- a/tests/e2e/tests/web/smoke/workbench/json-workbench.e2e.ts +++ b/tests/e2e/tests/web/smoke/workbench/json-workbench.e2e.ts @@ -1,11 +1,11 @@ -import { rte } from '../../../../helpers/constants'; +import { KeysInteractionTabs, rte } from '../../../../helpers/constants'; import { DatabaseHelper } from '../../../../helpers/database'; -import { MyRedisDatabasePage, WorkbenchPage } from '../../../../pageObjects'; +import { BrowserPage, WorkbenchPage } from '../../../../pageObjects'; import { commonUrl, ossStandaloneRedisearch } from '../../../../helpers/conf'; import { Common } from '../../../../helpers/common'; import { DatabaseAPIRequests } from '../../../../helpers/api/api-database'; -const myRedisDatabasePage = new MyRedisDatabasePage(); +const browserPage = new BrowserPage(); const workbenchPage = new WorkbenchPage(); const databaseHelper = new DatabaseHelper(); const databaseAPIRequests = new DatabaseAPIRequests(); @@ -18,7 +18,7 @@ fixture `JSON verifications at Workbench` .beforeEach(async t => { await databaseHelper.acceptLicenseTermsAndAddDatabaseApi(ossStandaloneRedisearch); // Go to Workbench page - await t.click(myRedisDatabasePage.NavigationPanel.workbenchButton); + await browserPage.KeysInteractionPanel.setActiveTab(KeysInteractionTabs.Workbench); }) .afterEach(async t => { // Clear and delete database diff --git a/tests/e2e/tests/web/smoke/workbench/scripting-area.e2e.ts b/tests/e2e/tests/web/smoke/workbench/scripting-area.e2e.ts index 64ce6479d0..0a8eae3019 100644 --- a/tests/e2e/tests/web/smoke/workbench/scripting-area.e2e.ts +++ b/tests/e2e/tests/web/smoke/workbench/scripting-area.e2e.ts @@ -1,10 +1,10 @@ import { DatabaseHelper } from '../../../../helpers/database'; -import { MyRedisDatabasePage, WorkbenchPage } from '../../../../pageObjects'; +import { BrowserPage, WorkbenchPage } from '../../../../pageObjects'; import { commonUrl, ossStandaloneConfig } from '../../../../helpers/conf'; -import { rte } from '../../../../helpers/constants'; +import { KeysInteractionTabs, rte } from '../../../../helpers/constants'; import { DatabaseAPIRequests } from '../../../../helpers/api/api-database'; -const myRedisDatabasePage = new MyRedisDatabasePage(); +const browserPage = new BrowserPage(); const workbenchPage = new WorkbenchPage(); const databaseHelper = new DatabaseHelper(); const databaseAPIRequests = new DatabaseAPIRequests(); @@ -15,7 +15,7 @@ fixture `Scripting area at Workbench` .beforeEach(async t => { await databaseHelper.acceptLicenseTermsAndAddDatabaseApi(ossStandaloneConfig); // Go to Workbench page - await t.click(myRedisDatabasePage.NavigationPanel.workbenchButton); + await browserPage.KeysInteractionPanel.setActiveTab(KeysInteractionTabs.Workbench); }) .afterEach(async() => { // Delete database From fbd5f305e46b536f3919586f27060c9806861772 Mon Sep 17 00:00:00 2001 From: mariasergeenko Date: Sat, 29 Jun 2024 14:13:14 +0200 Subject: [PATCH 009/256] fix tests #2 --- tests/e2e/tests/web/critical-path/monitor/monitor.e2e.ts | 2 +- tests/e2e/tests/web/regression/browser/onboarding.e2e.ts | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/tests/e2e/tests/web/critical-path/monitor/monitor.e2e.ts b/tests/e2e/tests/web/critical-path/monitor/monitor.e2e.ts index c9c1435170..24895ef253 100644 --- a/tests/e2e/tests/web/critical-path/monitor/monitor.e2e.ts +++ b/tests/e2e/tests/web/critical-path/monitor/monitor.e2e.ts @@ -46,7 +46,7 @@ test('Verify that user can work with Monitor', async t => { await browserPage.Cli.getSuccessCommandResultFromCli(`${command} ${keyName} ${keyValue}`); await browserPage.Profiler.checkCommandInMonitorResults(command, [keyName, keyValue]); }); -test.only('Verify that user can see the list of all commands from all clients ran for this Redis database in the list of results in Monitor', async t => { +test('Verify that user can see the list of all commands from all clients ran for this Redis database in the list of results in Monitor', async t => { //Define commands in different clients const cli_command = 'command'; const workbench_command = 'hello'; diff --git a/tests/e2e/tests/web/regression/browser/onboarding.e2e.ts b/tests/e2e/tests/web/regression/browser/onboarding.e2e.ts index e9f114f800..5ccf214dae 100644 --- a/tests/e2e/tests/web/regression/browser/onboarding.e2e.ts +++ b/tests/e2e/tests/web/regression/browser/onboarding.e2e.ts @@ -150,7 +150,7 @@ test('Verify onboard new user skip tour', async(t) => { await t.expect(browserPage.patternModeBtn.visible).ok('Browser page is not opened'); }); // https://redislabs.atlassian.net/browse/RI-4305 -test.requestHooks(logger)('Verify that the final onboarding step is closed when user opens another page', async(t) => { +test.only.requestHooks(logger)('Verify that the final onboarding step is closed when user opens another page', async(t) => { await t.click(myRedisDatabasePage.NavigationPanel.helpCenterButton); await t.click(onboardingCardsDialog.resetOnboardingBtn); await onboardingCardsDialog.startOnboarding(); @@ -158,6 +158,7 @@ test.requestHooks(logger)('Verify that the final onboarding step is closed when // Verify last step of onboarding process is visible await onboardingCardsDialog.verifyStepVisible('Great job!'); // Go to Workbench page + await t.click(myRedisDatabasePage.NavigationPanel.browserButton); await browserPage.KeysInteractionPanel.setActiveTab(KeysInteractionTabs.Workbench); // Verify that “ONBOARDING_TOUR_FINISHED” event is sent when user opens another page (or close the app) From 114da79a2f620a555aa564fa3a4727abf142d947 Mon Sep 17 00:00:00 2001 From: mariasergeenko Date: Sun, 30 Jun 2024 12:42:44 +0200 Subject: [PATCH 010/256] remove only --- tests/e2e/tests/web/regression/browser/onboarding.e2e.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/e2e/tests/web/regression/browser/onboarding.e2e.ts b/tests/e2e/tests/web/regression/browser/onboarding.e2e.ts index 5ccf214dae..80d3961e34 100644 --- a/tests/e2e/tests/web/regression/browser/onboarding.e2e.ts +++ b/tests/e2e/tests/web/regression/browser/onboarding.e2e.ts @@ -150,7 +150,7 @@ test('Verify onboard new user skip tour', async(t) => { await t.expect(browserPage.patternModeBtn.visible).ok('Browser page is not opened'); }); // https://redislabs.atlassian.net/browse/RI-4305 -test.only.requestHooks(logger)('Verify that the final onboarding step is closed when user opens another page', async(t) => { +test.requestHooks(logger)('Verify that the final onboarding step is closed when user opens another page', async(t) => { await t.click(myRedisDatabasePage.NavigationPanel.helpCenterButton); await t.click(onboardingCardsDialog.resetOnboardingBtn); await onboardingCardsDialog.startOnboarding(); From 7e67e9f44609813d77cf993384c5ffc5cd61cb2a Mon Sep 17 00:00:00 2001 From: Roman Sergeenko Date: Mon, 1 Jul 2024 10:52:51 +0200 Subject: [PATCH 011/256] #RI-5682 - fix tests --- .../workbench/components/wb-view/WBViewWrapper.spec.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/redisinsight/ui/src/pages/workbench/components/wb-view/WBViewWrapper.spec.tsx b/redisinsight/ui/src/pages/workbench/components/wb-view/WBViewWrapper.spec.tsx index c0d9cf9787..6703bb781c 100644 --- a/redisinsight/ui/src/pages/workbench/components/wb-view/WBViewWrapper.spec.tsx +++ b/redisinsight/ui/src/pages/workbench/components/wb-view/WBViewWrapper.spec.tsx @@ -10,8 +10,8 @@ import { screen, act, } from 'uiSrc/utils/test-utils' -import QueryWrapper from 'uiSrc/components/query' -import { Props as QueryProps } from 'uiSrc/components/query/QueryWrapper' +import QueryWrapper from 'uiSrc/pages/workbench/components/query' +import { Props as QueryProps } from 'uiSrc/pages/workbench/components/query/QueryWrapper' import { connectedInstanceSelector } from 'uiSrc/slices/instances/instances' import { clearWbResults, @@ -30,7 +30,7 @@ beforeEach(() => { store.clearActions() }) -jest.mock('uiSrc/components/query', () => ({ +jest.mock('uiSrc/pages/workbench/components/query', () => ({ __esModule: true, namedExport: jest.fn(), default: jest.fn(), From 6a576fb85f33ee3bfeeea8dbe1636fcff29f74ee Mon Sep 17 00:00:00 2001 From: Roman Sergeenko Date: Mon, 1 Jul 2024 16:06:43 +0200 Subject: [PATCH 012/256] #RI-5903 - fix suggestions for workbench editor #RI-5898 - fix nav meni redirect #RI-5899 - fix go to workbench button from recommendation --- .../ui/src/components/navigation-menu/NavigationMenu.tsx | 2 +- .../components/recommendation/Recommendation.tsx | 9 +++++++-- .../workbench/components/query/Query/styles.module.scss | 4 ++-- 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/redisinsight/ui/src/components/navigation-menu/NavigationMenu.tsx b/redisinsight/ui/src/components/navigation-menu/NavigationMenu.tsx index f77a84689f..b40e4924ba 100644 --- a/redisinsight/ui/src/components/navigation-menu/NavigationMenu.tsx +++ b/redisinsight/ui/src/components/navigation-menu/NavigationMenu.tsx @@ -117,7 +117,7 @@ const NavigationMenu = () => { pageName: PageNames.browser, isActivePage: isBrowserPath(activePage), ariaLabel: 'Browser page button', - onClick: () => handleGoPage(Pages.browser(connectedInstanceId)), + onClick: () => handleGoPage(Pages.keys(connectedInstanceId)), dataTestId: 'browser-page-btn', connectedInstanceId, getClassName() { diff --git a/redisinsight/ui/src/components/side-panels/panels/live-time-recommendations/components/recommendation/Recommendation.tsx b/redisinsight/ui/src/components/side-panels/panels/live-time-recommendations/components/recommendation/Recommendation.tsx index 5f46da2728..5cacae6882 100644 --- a/redisinsight/ui/src/components/side-panels/panels/live-time-recommendations/components/recommendation/Recommendation.tsx +++ b/redisinsight/ui/src/components/side-panels/panels/live-time-recommendations/components/recommendation/Recommendation.tsx @@ -17,7 +17,7 @@ import { isUndefined } from 'lodash' import cx from 'classnames' import { Nullable, Maybe, findTutorialPath } from 'uiSrc/utils' -import { Theme } from 'uiSrc/constants' +import { Pages, Theme } from 'uiSrc/constants' import { RecommendationVoting, RecommendationCopyComponent, RecommendationBody } from 'uiSrc/components' import { Vote } from 'uiSrc/constants/recommendations' import { sendEventTelemetry, TelemetryEvent } from 'uiSrc/telemetry' @@ -77,7 +77,12 @@ const Recommendation = ({ } }) - const tutorialPath = findTutorialPath({ id: tutorialId ?? '' }) + if (!tutorialId) { + history.push(Pages.workbench(instanceId)) + return + } + + const tutorialPath = findTutorialPath({ id: tutorialId }) dispatch(openTutorialByPath(tutorialPath ?? '', history)) } diff --git a/redisinsight/ui/src/pages/workbench/components/query/Query/styles.module.scss b/redisinsight/ui/src/pages/workbench/components/query/Query/styles.module.scss index 2213a8f856..18b46e1931 100644 --- a/redisinsight/ui/src/pages/workbench/components/query/Query/styles.module.scss +++ b/redisinsight/ui/src/pages/workbench/components/query/Query/styles.module.scss @@ -12,7 +12,6 @@ .container { display: flex; flex-direction: column; - overflow: hidden; padding: 8px 16px; width: 100%; height: 100%; @@ -50,7 +49,8 @@ } .input { - overflow: hidden; + // cannot use overflow since suggestions are absolute + max-height: calc(100% - 32px); flex-grow: 1; width: 100%; border: 1px solid var(--euiColorLightShade); From 8a8c3f2e2adf95404fda7deabe73ab2d20f948ec Mon Sep 17 00:00:00 2001 From: mariasergeenko Date: Tue, 2 Jul 2024 09:59:20 +0200 Subject: [PATCH 013/256] add new workbench tab test --- .../components/keys-interaction-panel.ts | 3 +++ tests/e2e/pageObjects/workbench-page.ts | 1 + .../web/critical-path/rdi/navigation.e2e.ts | 2 +- .../regression/workbench/workbench-tab.e2e.ts | 27 +++++++++++++++++++ 4 files changed, 32 insertions(+), 1 deletion(-) create mode 100644 tests/e2e/tests/web/regression/workbench/workbench-tab.e2e.ts diff --git a/tests/e2e/pageObjects/components/keys-interaction-panel.ts b/tests/e2e/pageObjects/components/keys-interaction-panel.ts index 6404d5a54c..6f2ef1276c 100644 --- a/tests/e2e/pageObjects/components/keys-interaction-panel.ts +++ b/tests/e2e/pageObjects/components/keys-interaction-panel.ts @@ -24,6 +24,9 @@ export class KeysInteractionPanel { * Click on Panel tab * @param type of the tab */ + async setActiveTab(type: KeysInteractionTabs.BrowserAndFilter): Promise + async setActiveTab(type: KeysInteractionTabs.SearchAndQuery): Promise + async setActiveTab(type: KeysInteractionTabs.Workbench): Promise async setActiveTab(type: KeysInteractionTabs): Promise { const activeTabName = await this.getActiveTabName(); diff --git a/tests/e2e/pageObjects/workbench-page.ts b/tests/e2e/pageObjects/workbench-page.ts index 2d75d37a6a..b4b7d0e3ad 100644 --- a/tests/e2e/pageObjects/workbench-page.ts +++ b/tests/e2e/pageObjects/workbench-page.ts @@ -47,6 +47,7 @@ export class WorkbenchPage extends InstancePage { copyCommand = Selector('[data-testid=copy-command]'); clearResultsBtn = Selector('[data-testid=clear-history-btn]'); exploreRedisBtn = Selector('[data-testid=no-results-explore-btn]'); + basicUseCaseTutorialsButton = Selector('[data-testid=wb-tutorials-link_redis_use_cases_basic]'); //ICONS noCommandHistoryIcon = Selector('[data-testid=wb_no-results__icon]'); parametersAnchor = Selector('[data-testid=parameters-anchor]'); diff --git a/tests/e2e/tests/web/critical-path/rdi/navigation.e2e.ts b/tests/e2e/tests/web/critical-path/rdi/navigation.e2e.ts index 9df133405a..a08d7799da 100644 --- a/tests/e2e/tests/web/critical-path/rdi/navigation.e2e.ts +++ b/tests/e2e/tests/web/critical-path/rdi/navigation.e2e.ts @@ -85,7 +85,7 @@ test('Verify that Insight and Sign in buttons are displayed ', async() => { await t.expect(rdiInstancePage.RdiHeader.InsightsPanel.getInsightsPanel().exists).ok('Insight panel is not exist'); await rdiInstancePage.RdiHeader.InsightsPanel.togglePanel(true); const tab = await rdiInstancePage.RdiHeader.InsightsPanel.getActiveTabName(); - await t.expect(tab).eql('Explore'); + await t.expect(tab).eql('Tutorials'); await t.expect(rdiInstancePage.RdiHeader.cloudSignInButton.exists).ok('sight in button is not exist'); }); diff --git a/tests/e2e/tests/web/regression/workbench/workbench-tab.e2e.ts b/tests/e2e/tests/web/regression/workbench/workbench-tab.e2e.ts new file mode 100644 index 0000000000..02f71ece03 --- /dev/null +++ b/tests/e2e/tests/web/regression/workbench/workbench-tab.e2e.ts @@ -0,0 +1,27 @@ +import { ExploreTabs, KeysInteractionTabs, rte } from '../../../../helpers/constants'; +import { DatabaseHelper } from '../../../../helpers/database'; +import { BrowserPage } from '../../../../pageObjects'; +import { commonUrl, ossStandaloneConfig } from '../../../../helpers/conf'; +import { DatabaseAPIRequests } from '../../../../helpers/api/api-database'; + +const databaseHelper = new DatabaseHelper(); +const databaseAPIRequests = new DatabaseAPIRequests(); +const browserPage = new BrowserPage(); + +fixture `Autocomplete for entered commands` + .meta({ type: 'regression', rte: rte.standalone }) + .page(commonUrl) + .beforeEach(async t => { + await databaseHelper.acceptLicenseTermsAndAddDatabaseApi(ossStandaloneConfig); + }) + .afterEach(async() => { + // Delete database + await databaseAPIRequests.deleteStandaloneDatabaseApi(ossStandaloneConfig); + }); +test.only('Verify that tutorials can be opened from Workbench"', async t => { + const workbench = await browserPage.KeysInteractionPanel.setActiveTab(KeysInteractionTabs.Workbench); + await t.click(workbench.basicUseCaseTutorialsButton); + await t.expect(workbench.InsightsPanel.sidePanel.exists).ok('Insight panel is not opened'); + const tab = await browserPage.InsightsPanel.setActiveTab(ExploreTabs.Tutorials); + await t.expect(tab.preselectArea.textContent).contains('BASIC REDIS USE CASES', 'the tutorial page is incorrect'); +}); From da577da1e6ba8cd405fc2623af2326456a08f86b Mon Sep 17 00:00:00 2001 From: mariasergeenko Date: Wed, 3 Jul 2024 10:57:26 +0200 Subject: [PATCH 014/256] fix per comments --- tests/e2e/tests/web/regression/workbench/workbench-tab.e2e.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/e2e/tests/web/regression/workbench/workbench-tab.e2e.ts b/tests/e2e/tests/web/regression/workbench/workbench-tab.e2e.ts index 02f71ece03..57c1898186 100644 --- a/tests/e2e/tests/web/regression/workbench/workbench-tab.e2e.ts +++ b/tests/e2e/tests/web/regression/workbench/workbench-tab.e2e.ts @@ -18,7 +18,7 @@ fixture `Autocomplete for entered commands` // Delete database await databaseAPIRequests.deleteStandaloneDatabaseApi(ossStandaloneConfig); }); -test.only('Verify that tutorials can be opened from Workbench"', async t => { +test('Verify that tutorials can be opened from Workbench', async t => { const workbench = await browserPage.KeysInteractionPanel.setActiveTab(KeysInteractionTabs.Workbench); await t.click(workbench.basicUseCaseTutorialsButton); await t.expect(workbench.InsightsPanel.sidePanel.exists).ok('Insight panel is not opened'); From 0f25ab6c1fbde92d4abdf12b2ef39d37268cca03 Mon Sep 17 00:00:00 2001 From: Roman Sergeenko Date: Fri, 26 Jul 2024 11:10:25 +0200 Subject: [PATCH 015/256] #RI-5683 - update search and query page --- redisinsight/ui/src/components/query/index.ts | 9 ++ .../query-actions/QueryActions.spec.tsx | 0 .../query}/query-actions/QueryActions.tsx | 86 ++++++------- .../query}/query-actions/index.ts | 0 .../query}/query-actions/styles.module.scss | 0 .../{ => query}/query-card/QueryCard.spec.tsx | 0 .../{ => query}/query-card/QueryCard.tsx | 0 .../QueryCardCliDefaultResult.spec.tsx | 0 .../QueryCardCliDefaultResult.tsx | 0 .../QueryCardCliDefaultResult/index.ts | 0 .../styles.module.scss | 0 .../QueryCardCliGroupResult.spec.tsx | 0 .../QueryCardCliGroupResult.tsx | 0 .../QueryCardCliGroupResult/index.ts | 0 .../QueryCardCliPlugin.spec.tsx | 0 .../QueryCardCliPlugin/QueryCardCliPlugin.tsx | 0 .../query-card/QueryCardCliPlugin/index.ts | 0 .../QueryCardCliPlugin/styles.module.scss | 0 .../QueryCardCliResultWrapper.spec.tsx | 0 .../QueryCardCliResultWrapper.tsx | 0 .../QueryCardCliResultWrapper/index.ts | 0 .../styles.module.scss | 0 .../QueryCardCommonResult.spec.tsx | 0 .../QueryCardCommonResult.tsx | 0 .../CommonErrorResponse.tsx | 0 .../components/CommonErrorResponse/index.ts | 0 .../query-card/QueryCardCommonResult/index.ts | 0 .../QueryCardCommonResult/styles.module.scss | 0 .../QueryCardHeader/QueryCardHeader.spec.tsx | 0 .../QueryCardHeader/QueryCardHeader.tsx | 0 .../query-card/QueryCardHeader/index.ts | 0 .../QueryCardHeader/styles.module.scss | 0 .../QueryCardTooltip.spec.tsx | 0 .../QueryCardTooltip/QueryCardTooltip.tsx | 0 .../query-card/QueryCardTooltip/index.ts | 0 .../QueryCardTooltip/styles.module.scss | 0 .../{ => query}/query-card/index.ts | 0 .../{ => query}/query-card/styles.module.scss | 0 .../query-tutorials/QueryTutorials.spec.tsx | 28 ++++- .../query}/query-tutorials/QueryTutorials.tsx | 30 ++--- .../query}/query-tutorials/index.ts | 0 .../query}/query-tutorials/styles.module.scss | 0 .../ui/src/constants/monaco/monaco.ts | 19 +++ redisinsight/ui/src/constants/storage.ts | 1 + redisinsight/ui/src/constants/tutorials.ts | 2 + .../ui/src/pages/search/SearchPage.tsx | 116 +++++++++++++++++- .../ui/src/pages/search/components/index.ts | 7 ++ .../search/components/query/Query.spec.tsx | 10 ++ .../pages/search/components/query/Query.tsx | 105 ++++++++++++++++ .../search/components/query/constants.ts | 16 +++ .../pages/search/components/query/index.ts | 3 + .../components/query/styles.module.scss | 76 ++++++++++++ .../results-history/ResultsHistory.spec.tsx | 10 ++ .../results-history/ResultsHistory.tsx | 87 +++++++++++++ .../components/results-history/index.ts | 3 + .../results-history/styles.module.scss | 33 +++++ .../ui/src/pages/search/styles.module.scss | 32 +++++ .../components/query/Query/Query.tsx | 39 ++---- .../components/query/Query/constants.ts | 24 ++++ .../wb-results/WBResults/WBResults.tsx | 2 +- redisinsight/ui/src/slices/app/context.ts | 16 +++ redisinsight/ui/src/slices/interfaces/app.ts | 8 ++ .../ui/src/slices/interfaces/index.ts | 3 +- .../src/slices/interfaces/searchAndQuery.ts | 11 ++ .../ui/src/slices/search/searchAndQuery.ts | 34 +++++ redisinsight/ui/src/slices/store.ts | 4 + redisinsight/ui/src/telemetry/events.ts | 2 + redisinsight/ui/src/telemetry/pageViews.ts | 1 + redisinsight/ui/src/utils/test-utils.tsx | 4 + 69 files changed, 720 insertions(+), 101 deletions(-) create mode 100644 redisinsight/ui/src/components/query/index.ts rename redisinsight/ui/src/{pages/workbench/components => components/query}/query-actions/QueryActions.spec.tsx (100%) rename redisinsight/ui/src/{pages/workbench/components => components/query}/query-actions/QueryActions.tsx (62%) rename redisinsight/ui/src/{pages/workbench/components => components/query}/query-actions/index.ts (100%) rename redisinsight/ui/src/{pages/workbench/components => components/query}/query-actions/styles.module.scss (100%) rename redisinsight/ui/src/components/{ => query}/query-card/QueryCard.spec.tsx (100%) rename redisinsight/ui/src/components/{ => query}/query-card/QueryCard.tsx (100%) rename redisinsight/ui/src/components/{ => query}/query-card/QueryCardCliDefaultResult/QueryCardCliDefaultResult.spec.tsx (100%) rename redisinsight/ui/src/components/{ => query}/query-card/QueryCardCliDefaultResult/QueryCardCliDefaultResult.tsx (100%) rename redisinsight/ui/src/components/{ => query}/query-card/QueryCardCliDefaultResult/index.ts (100%) rename redisinsight/ui/src/components/{ => query}/query-card/QueryCardCliDefaultResult/styles.module.scss (100%) rename redisinsight/ui/src/components/{ => query}/query-card/QueryCardCliGroupResult/QueryCardCliGroupResult.spec.tsx (100%) rename redisinsight/ui/src/components/{ => query}/query-card/QueryCardCliGroupResult/QueryCardCliGroupResult.tsx (100%) rename redisinsight/ui/src/components/{ => query}/query-card/QueryCardCliGroupResult/index.ts (100%) rename redisinsight/ui/src/components/{ => query}/query-card/QueryCardCliPlugin/QueryCardCliPlugin.spec.tsx (100%) rename redisinsight/ui/src/components/{ => query}/query-card/QueryCardCliPlugin/QueryCardCliPlugin.tsx (100%) rename redisinsight/ui/src/components/{ => query}/query-card/QueryCardCliPlugin/index.ts (100%) rename redisinsight/ui/src/components/{ => query}/query-card/QueryCardCliPlugin/styles.module.scss (100%) rename redisinsight/ui/src/components/{ => query}/query-card/QueryCardCliResultWrapper/QueryCardCliResultWrapper.spec.tsx (100%) rename redisinsight/ui/src/components/{ => query}/query-card/QueryCardCliResultWrapper/QueryCardCliResultWrapper.tsx (100%) rename redisinsight/ui/src/components/{ => query}/query-card/QueryCardCliResultWrapper/index.ts (100%) rename redisinsight/ui/src/components/{ => query}/query-card/QueryCardCliResultWrapper/styles.module.scss (100%) rename redisinsight/ui/src/components/{ => query}/query-card/QueryCardCommonResult/QueryCardCommonResult.spec.tsx (100%) rename redisinsight/ui/src/components/{ => query}/query-card/QueryCardCommonResult/QueryCardCommonResult.tsx (100%) rename redisinsight/ui/src/components/{ => query}/query-card/QueryCardCommonResult/components/CommonErrorResponse/CommonErrorResponse.tsx (100%) rename redisinsight/ui/src/components/{ => query}/query-card/QueryCardCommonResult/components/CommonErrorResponse/index.ts (100%) rename redisinsight/ui/src/components/{ => query}/query-card/QueryCardCommonResult/index.ts (100%) rename redisinsight/ui/src/components/{ => query}/query-card/QueryCardCommonResult/styles.module.scss (100%) rename redisinsight/ui/src/components/{ => query}/query-card/QueryCardHeader/QueryCardHeader.spec.tsx (100%) rename redisinsight/ui/src/components/{ => query}/query-card/QueryCardHeader/QueryCardHeader.tsx (100%) rename redisinsight/ui/src/components/{ => query}/query-card/QueryCardHeader/index.ts (100%) rename redisinsight/ui/src/components/{ => query}/query-card/QueryCardHeader/styles.module.scss (100%) rename redisinsight/ui/src/components/{ => query}/query-card/QueryCardTooltip/QueryCardTooltip.spec.tsx (100%) rename redisinsight/ui/src/components/{ => query}/query-card/QueryCardTooltip/QueryCardTooltip.tsx (100%) rename redisinsight/ui/src/components/{ => query}/query-card/QueryCardTooltip/index.ts (100%) rename redisinsight/ui/src/components/{ => query}/query-card/QueryCardTooltip/styles.module.scss (100%) rename redisinsight/ui/src/components/{ => query}/query-card/index.ts (100%) rename redisinsight/ui/src/components/{ => query}/query-card/styles.module.scss (100%) rename redisinsight/ui/src/{pages/workbench/components => components/query}/query-tutorials/QueryTutorials.spec.tsx (66%) rename redisinsight/ui/src/{pages/workbench/components => components/query}/query-tutorials/QueryTutorials.tsx (73%) rename redisinsight/ui/src/{pages/workbench/components => components/query}/query-tutorials/index.ts (100%) rename redisinsight/ui/src/{pages/workbench/components => components/query}/query-tutorials/styles.module.scss (100%) create mode 100644 redisinsight/ui/src/pages/search/components/index.ts create mode 100644 redisinsight/ui/src/pages/search/components/query/Query.spec.tsx create mode 100644 redisinsight/ui/src/pages/search/components/query/Query.tsx create mode 100644 redisinsight/ui/src/pages/search/components/query/constants.ts create mode 100644 redisinsight/ui/src/pages/search/components/query/index.ts create mode 100644 redisinsight/ui/src/pages/search/components/query/styles.module.scss create mode 100644 redisinsight/ui/src/pages/search/components/results-history/ResultsHistory.spec.tsx create mode 100644 redisinsight/ui/src/pages/search/components/results-history/ResultsHistory.tsx create mode 100644 redisinsight/ui/src/pages/search/components/results-history/index.ts create mode 100644 redisinsight/ui/src/pages/search/components/results-history/styles.module.scss create mode 100644 redisinsight/ui/src/pages/search/styles.module.scss create mode 100644 redisinsight/ui/src/pages/workbench/components/query/Query/constants.ts create mode 100644 redisinsight/ui/src/slices/interfaces/searchAndQuery.ts create mode 100644 redisinsight/ui/src/slices/search/searchAndQuery.ts diff --git a/redisinsight/ui/src/components/query/index.ts b/redisinsight/ui/src/components/query/index.ts new file mode 100644 index 0000000000..00c92dffa3 --- /dev/null +++ b/redisinsight/ui/src/components/query/index.ts @@ -0,0 +1,9 @@ +import QueryCard from './query-card' +import QueryActions from './query-actions' +import QueryTutorials from './query-tutorials' + +export { + QueryCard, + QueryActions, + QueryTutorials +} diff --git a/redisinsight/ui/src/pages/workbench/components/query-actions/QueryActions.spec.tsx b/redisinsight/ui/src/components/query/query-actions/QueryActions.spec.tsx similarity index 100% rename from redisinsight/ui/src/pages/workbench/components/query-actions/QueryActions.spec.tsx rename to redisinsight/ui/src/components/query/query-actions/QueryActions.spec.tsx diff --git a/redisinsight/ui/src/pages/workbench/components/query-actions/QueryActions.tsx b/redisinsight/ui/src/components/query/query-actions/QueryActions.tsx similarity index 62% rename from redisinsight/ui/src/pages/workbench/components/query-actions/QueryActions.tsx rename to redisinsight/ui/src/components/query/query-actions/QueryActions.tsx index 2650352ccd..b4764713a3 100644 --- a/redisinsight/ui/src/pages/workbench/components/query-actions/QueryActions.tsx +++ b/redisinsight/ui/src/components/query/query-actions/QueryActions.tsx @@ -14,8 +14,8 @@ import Divider from 'uiSrc/components/divider/Divider' import styles from './styles.module.scss' export interface Props { - onChangeMode: () => void - onChangeGroupMode: () => void + onChangeMode?: () => void + onChangeGroupMode?: () => void onSubmit: () => void activeMode: RunQueryMode resultsMode?: ResultsMode @@ -54,48 +54,52 @@ const QueryActions = (props: Props) => { return (
- - onChangeMode()} - iconType={RawModeIcon} - disabled={isLoading} - className={cx(styles.btn, styles.textBtn, { [styles.activeBtn]: activeMode === RunQueryMode.Raw })} - data-testid="btn-change-mode" + {onChangeMode && ( + - Raw mode - - - - Groups the command results into a single window. -
- When grouped, the results can be visualized only in the text format. - + onChangeMode()} + iconType={RawModeIcon} + disabled={isLoading} + className={cx(styles.btn, styles.textBtn, { [styles.activeBtn]: activeMode === RunQueryMode.Raw })} + data-testid="btn-change-mode" + > + Raw mode + +
+ )} + {onChangeGroupMode && ( + + Groups the command results into a single window. +
+ When grouped, the results can be visualized only in the text format. + )} - data-testid="group-results-tooltip" - > - onChangeGroupMode()} - disabled={isLoading} - iconType={GroupModeIcon} - className={cx(styles.btn, styles.textBtn, { [styles.activeBtn]: isGroupMode(resultsMode) })} - data-testid="btn-change-group-mode" + data-testid="group-results-tooltip" > - Group results - -
+ onChangeGroupMode()} + disabled={isLoading} + iconType={GroupModeIcon} + className={cx(styles.btn, styles.textBtn, { [styles.activeBtn]: isGroupMode(resultsMode) })} + data-testid="btn-change-group-mode" + > + Group results + + + )} ({ ...jest.requireActual('uiSrc/utils'), findTutorialPath: jest.fn(), @@ -20,7 +36,7 @@ jest.mock('uiSrc/telemetry', () => ({ describe('QueryTutorial', () => { it('should render', () => { - expect(render()).toBeTruthy() + expect(render()).toBeTruthy() }) it('should call proper history push after click on guide with tutorial', () => { @@ -28,9 +44,9 @@ describe('QueryTutorial', () => { reactRouterDom.useHistory = jest.fn().mockReturnValue({ push: pushMock }); (findTutorialPath as jest.Mock).mockImplementation(() => 'path') - render() + render() - fireEvent.click(screen.getByTestId('wb-tutorials-link_sq-intro')) + fireEvent.click(screen.getByTestId('query-tutorials-link_sq-intro')) expect(pushMock).toHaveBeenCalledWith({ search: 'path=tutorials/path' @@ -42,16 +58,16 @@ describe('QueryTutorial', () => { (sendEventTelemetry as jest.Mock).mockImplementation(() => sendEventTelemetryMock); (findTutorialPath as jest.Mock).mockImplementation(() => 'path') - render() + render() - fireEvent.click(screen.getByTestId('wb-tutorials-link_sq-intro')) + fireEvent.click(screen.getByTestId('query-tutorials-link_sq-intro')) expect(sendEventTelemetry).toBeCalledWith({ event: TelemetryEvent.EXPLORE_PANEL_TUTORIAL_OPENED, eventData: { path: 'path', databaseId: 'instanceId', - source: 'advanced_workbench_editor', + source: 'source', } }) }) diff --git a/redisinsight/ui/src/pages/workbench/components/query-tutorials/QueryTutorials.tsx b/redisinsight/ui/src/components/query/query-tutorials/QueryTutorials.tsx similarity index 73% rename from redisinsight/ui/src/pages/workbench/components/query-tutorials/QueryTutorials.tsx rename to redisinsight/ui/src/components/query/query-tutorials/QueryTutorials.tsx index 83e765da76..0fed95df93 100644 --- a/redisinsight/ui/src/pages/workbench/components/query-tutorials/QueryTutorials.tsx +++ b/redisinsight/ui/src/components/query/query-tutorials/QueryTutorials.tsx @@ -4,28 +4,20 @@ import { EuiLink, EuiText } from '@elastic/eui' import { useDispatch } from 'react-redux' import { useHistory, useParams } from 'react-router-dom' import { findTutorialPath } from 'uiSrc/utils' -import { TutorialsIds } from 'uiSrc/constants' import { openTutorialByPath } from 'uiSrc/slices/panels/sidePanels' import { sendEventTelemetry, TELEMETRY_EMPTY_VALUE, TelemetryEvent } from 'uiSrc/telemetry' import styles from './styles.module.scss' -const TUTORIALS = [ - { - id: TutorialsIds.IntroToSearch, - title: 'Intro to search' - }, - { - id: TutorialsIds.BasicRedisUseCases, - title: 'Basic use cases' - }, - { - id: TutorialsIds.IntroVectorSearch, - title: 'Intro to vector search' - }, -] +export interface Props { + tutorials: Array<{ + id: string + title: string + }> + source: string +} -const QueryTutorials = () => { +const QueryTutorials = ({ tutorials, source }: Props) => { const dispatch = useDispatch() const history = useHistory() const { instanceId } = useParams<{ instanceId: string }>() @@ -39,7 +31,7 @@ const QueryTutorials = () => { eventData: { path: tutorialPath, databaseId: instanceId || TELEMETRY_EMPTY_VALUE, - source: 'advanced_workbench_editor', + source, } }) } @@ -49,13 +41,13 @@ const QueryTutorials = () => { Tutorials: - {TUTORIALS.map(({ id, title }) => ( + {tutorials.map(({ id, title }) => ( handleClickTutorial(id)} - data-testid={`wb-tutorials-link_${id}`} + data-testid={`query-tutorials-link_${id}`} > {title} diff --git a/redisinsight/ui/src/pages/workbench/components/query-tutorials/index.ts b/redisinsight/ui/src/components/query/query-tutorials/index.ts similarity index 100% rename from redisinsight/ui/src/pages/workbench/components/query-tutorials/index.ts rename to redisinsight/ui/src/components/query/query-tutorials/index.ts diff --git a/redisinsight/ui/src/pages/workbench/components/query-tutorials/styles.module.scss b/redisinsight/ui/src/components/query/query-tutorials/styles.module.scss similarity index 100% rename from redisinsight/ui/src/pages/workbench/components/query-tutorials/styles.module.scss rename to redisinsight/ui/src/components/query/query-tutorials/styles.module.scss diff --git a/redisinsight/ui/src/constants/monaco/monaco.ts b/redisinsight/ui/src/constants/monaco/monaco.ts index a1ba8b1300..fad4f5528c 100644 --- a/redisinsight/ui/src/constants/monaco/monaco.ts +++ b/redisinsight/ui/src/constants/monaco/monaco.ts @@ -41,6 +41,25 @@ export enum MonacoLanguage { Text = 'text', } +export const defaultMonacoOptions: monacoEditor.editor.IStandaloneEditorConstructionOptions = { + tabCompletion: 'on', + wordWrap: 'on', + padding: { top: 10 }, + automaticLayout: true, + formatOnPaste: false, + glyphMargin: true, + stickyScroll: { + enabled: true, + defaultModel: 'indentationModel' + }, + suggest: { + preview: true, + showStatusBar: true, + showIcons: false, + }, + lineNumbersMinChars: 4 +} + export const DEFAULT_MONACO_YAML_URI = 'http://example.com/schema-name.json' export const DEFAULT_MONACO_FILE_MATCH = '*' diff --git a/redisinsight/ui/src/constants/storage.ts b/redisinsight/ui/src/constants/storage.ts index bd92ec4bf4..f0eb778d49 100644 --- a/redisinsight/ui/src/constants/storage.ts +++ b/redisinsight/ui/src/constants/storage.ts @@ -19,6 +19,7 @@ enum BrowserStorageItem { bulkActionDeleteId = 'bulkActionDeleteId', dbConfig = 'dbConfig_', RunQueryMode = 'RunQueryMode', + SQRunQueryMode = 'SQRunQueryMode', wbCleanUp = 'wbCleanUp', viewFormat = 'viewFormat', wbGroupMode = 'wbGroupMode', diff --git a/redisinsight/ui/src/constants/tutorials.ts b/redisinsight/ui/src/constants/tutorials.ts index 45c856417e..261e38c3f2 100644 --- a/redisinsight/ui/src/constants/tutorials.ts +++ b/redisinsight/ui/src/constants/tutorials.ts @@ -4,6 +4,8 @@ enum TutorialsIds { BasicRedisUseCases = 'redis_use_cases_basic', RedisUseCases = 'redis_use_cases', IntroVectorSearch = 'vss-intro', + ExactMatch = 'sq-exact-match', + FullTextSearch = 'sq-full-text', } export { diff --git a/redisinsight/ui/src/pages/search/SearchPage.tsx b/redisinsight/ui/src/pages/search/SearchPage.tsx index aef47b2781..c48219b554 100644 --- a/redisinsight/ui/src/pages/search/SearchPage.tsx +++ b/redisinsight/ui/src/pages/search/SearchPage.tsx @@ -1,13 +1,119 @@ -import React from 'react' +import React, { useCallback, useEffect, useRef, useState } from 'react' +import cx from 'classnames' +import { EuiResizableContainer } from '@elastic/eui' +import { useDispatch, useSelector } from 'react-redux' -export interface Props { +import { useParams } from 'react-router-dom' +import { + appContextSearchAndQuery, + setSQVerticalPanelSizes, +} from 'uiSrc/slices/app/context' +import { Query, ResultsHistory } from 'uiSrc/pages/search/components' +import { sendWbQueryAction } from 'uiSrc/slices/workbench/wb-results' +import { formatLongName, getDbIndex, Nullable, setTitle } from 'uiSrc/utils' + +import { connectedInstanceSelector } from 'uiSrc/slices/instances/instances' +import { sendPageViewTelemetry, TelemetryPageView } from 'uiSrc/telemetry' +import { CodeButtonParams } from 'uiSrc/constants' +import styles from './styles.module.scss' + +const verticalPanelIds = { + firstPanelId: 'scriptingArea', + secondPanelId: 'resultsArea' } -const SearchPage = (props: Props) => { - const {} = props +const SearchPage = () => { + const { name: connectedInstanceName, db } = useSelector(connectedInstanceSelector) + const { panelSizes: { vertical } } = useSelector(appContextSearchAndQuery) + const [isPageViewSent, setIsPageViewSent] = useState(false) + + const { instanceId } = useParams<{ instanceId: string }>() + const verticalSizesRef = useRef(vertical) + + const dispatch = useDispatch() + + setTitle(`${formatLongName(connectedInstanceName, 33, 0, '...')} ${getDbIndex(db)} - Search and Query`) + + useEffect(() => () => { + dispatch(setSQVerticalPanelSizes(verticalSizesRef.current)) + }, []) + + useEffect(() => { + if (connectedInstanceName && !isPageViewSent) { + sendPageView(instanceId) + } + }, [connectedInstanceName, isPageViewSent]) + + const onVerticalPanelWidthChange = useCallback((newSizes: any) => { + verticalSizesRef.current = newSizes + }, []) + + const sendPageView = (instanceId: string) => { + sendPageViewTelemetry({ + name: TelemetryPageView.SEARCH_AND_QUERY_PAGE, + databaseId: instanceId + }) + setIsPageViewSent(true) + } + + const handleSubmit = ( + commandInit: string, + commandId?: Nullable, + executeParams: CodeButtonParams = {} + ) => { + dispatch(sendWbQueryAction( + commandInit, + commandId, + { + ...executeParams, + results: 'single', + } + )) + } + return ( -
+
+
+
+ + {(EuiResizablePanel, EuiResizableButton) => ( + <> + + + + + + + + + + + )} + +
+
+
) } diff --git a/redisinsight/ui/src/pages/search/components/index.ts b/redisinsight/ui/src/pages/search/components/index.ts new file mode 100644 index 0000000000..704de0e116 --- /dev/null +++ b/redisinsight/ui/src/pages/search/components/index.ts @@ -0,0 +1,7 @@ +import Query from './query' +import ResultsHistory from './results-history' + +export { + Query, + ResultsHistory, +} diff --git a/redisinsight/ui/src/pages/search/components/query/Query.spec.tsx b/redisinsight/ui/src/pages/search/components/query/Query.spec.tsx new file mode 100644 index 0000000000..e87a00d627 --- /dev/null +++ b/redisinsight/ui/src/pages/search/components/query/Query.spec.tsx @@ -0,0 +1,10 @@ +import React from 'react' +import { render, screen } from 'uiSrc/utils/test-utils' + +import Query from './Query' + +describe('Query', () => { + it('should render', () => { + expect(render()).toBeTruthy() + }) +}) diff --git a/redisinsight/ui/src/pages/search/components/query/Query.tsx b/redisinsight/ui/src/pages/search/components/query/Query.tsx new file mode 100644 index 0000000000..f01c7ffe92 --- /dev/null +++ b/redisinsight/ui/src/pages/search/components/query/Query.tsx @@ -0,0 +1,105 @@ +import React, { useContext, useEffect, useRef, useState } from 'react' +import MonacoEditor from 'react-monaco-editor' +import { useDispatch, useSelector } from 'react-redux' +import { useParams } from 'react-router-dom' +import { QueryActions, QueryTutorials } from 'uiSrc/components/query' + +import { RunQueryMode } from 'uiSrc/slices/interfaces' +import { CodeButtonParams, defaultMonacoOptions, Theme } from 'uiSrc/constants' +import { ThemeContext } from 'uiSrc/contexts/themeContext' + +import { Nullable } from 'uiSrc/utils' +import { changeSQActiveRunQueryMode, searchAndQuerySelector } from 'uiSrc/slices/search/searchAndQuery' +import { appContextSearchAndQuery, setSQVerticalScript } from 'uiSrc/slices/app/context' +import { sendEventTelemetry, TelemetryEvent } from 'uiSrc/telemetry' +import { TUTORIALS } from './constants' + +import styles from './styles.module.scss' + +export interface Props { + onSubmit: ( + commandInit: string, + commandId?: Nullable, + executeParams?: CodeButtonParams + ) => void +} + +const options = { ...defaultMonacoOptions } + +const Query = (props: Props) => { + const { onSubmit } = props + + const { script: scriptContext } = useSelector(appContextSearchAndQuery) + const { activeRunQueryMode } = useSelector(searchAndQuerySelector) + const [value, setValue] = useState(scriptContext) + + const { theme } = useContext(ThemeContext) + const input = useRef(null) + const scriptRef = useRef('') + + const { instanceId } = useParams<{ instanceId: string }>() + + const dispatch = useDispatch() + + useEffect(() => () => { + dispatch(setSQVerticalScript(scriptRef.current)) + }, []) + + useEffect(() => { + scriptRef.current = value + }, [value]) + + const handleChangeQueryRunMode = () => { + dispatch(changeSQActiveRunQueryMode( + activeRunQueryMode === RunQueryMode.ASCII + ? RunQueryMode.Raw + : RunQueryMode.ASCII + )) + } + + const handleSubmit = () => { + onSubmit(value, undefined, { mode: activeRunQueryMode }) + sendEventTelemetry({ + event: TelemetryEvent.SEARCH_COMMAND_SUBMITTED, + eventData: { + databaseId: instanceId, + mode: activeRunQueryMode, + // TODO sanitize user query + command: value + } + }) + } + + return ( +
+
{}} + role="textbox" + tabIndex={0} + data-testid="main-input-container-area" + > +
+ setValue(val)} + language="RediSearch" + theme={theme === Theme.Dark ? 'dark' : 'light'} + options={options} + /> +
+
+ + +
+
+
+ ) +} + +export default Query diff --git a/redisinsight/ui/src/pages/search/components/query/constants.ts b/redisinsight/ui/src/pages/search/components/query/constants.ts new file mode 100644 index 0000000000..322307978f --- /dev/null +++ b/redisinsight/ui/src/pages/search/components/query/constants.ts @@ -0,0 +1,16 @@ +import { TutorialsIds } from 'uiSrc/constants' + +export const TUTORIALS = [ + { + id: TutorialsIds.ExactMatch, + title: 'Exact match' + }, + { + id: TutorialsIds.FullTextSearch, + title: 'Full-text search' + }, + { + id: TutorialsIds.IntroVectorSearch, + title: 'Intro to vector search' + }, +] diff --git a/redisinsight/ui/src/pages/search/components/query/index.ts b/redisinsight/ui/src/pages/search/components/query/index.ts new file mode 100644 index 0000000000..611583bbb6 --- /dev/null +++ b/redisinsight/ui/src/pages/search/components/query/index.ts @@ -0,0 +1,3 @@ +import Query from './Query' + +export default Query diff --git a/redisinsight/ui/src/pages/search/components/query/styles.module.scss b/redisinsight/ui/src/pages/search/components/query/styles.module.scss new file mode 100644 index 0000000000..18b46e1931 --- /dev/null +++ b/redisinsight/ui/src/pages/search/components/query/styles.module.scss @@ -0,0 +1,76 @@ +.wrapper { + position: relative; + height: 100%; + + :global(.editorBounder) { + bottom: 6px; + left: 18px; + right: 46px; + } +} + +.container { + display: flex; + flex-direction: column; + padding: 8px 16px; + width: 100%; + height: 100%; + word-break: break-word; + text-align: left; + letter-spacing: 0; + background-color: var(--rsInputWrapperColor); + color: var(--euiTextSubduedColor) !important; + border: 1px solid var(--euiColorLightShade); +} + +.disabled { + opacity: 0.8; +} + +.disabledActions { + pointer-events: none; + user-select: none; +} + +.containerPlaceholder { + display: flex; + padding: 8px 16px 8px 16px; + width: 100%; + height: 100%; + background-color: var(--rsInputWrapperColor); + color: var(--euiTextSubduedColor) !important; + border: 1px solid var(--euiColorLightShade); + > div { + border: 1px solid var(--euiColorLightShade); + background-color: var(--euiColorEmptyShade); + padding: 8px 20px; + width: 100%; + } +} + +.input { + // cannot use overflow since suggestions are absolute + max-height: calc(100% - 32px); + flex-grow: 1; + width: 100%; + border: 1px solid var(--euiColorLightShade); + background-color: var(--rsInputColor); +} + +.queryFooter { + display: flex; + align-items: center; + justify-content: space-between; + + margin-top: 8px; + flex-shrink: 0; +} + +#script { + font: normal normal bold 14px/17px Inconsolata !important; + color: var(--textColorShade); + caret-color: var(--euiColorFullShade); + min-width: 5px; + display: inline; +} + diff --git a/redisinsight/ui/src/pages/search/components/results-history/ResultsHistory.spec.tsx b/redisinsight/ui/src/pages/search/components/results-history/ResultsHistory.spec.tsx new file mode 100644 index 0000000000..21d2666793 --- /dev/null +++ b/redisinsight/ui/src/pages/search/components/results-history/ResultsHistory.spec.tsx @@ -0,0 +1,10 @@ +import React from 'react' +import { render, screen } from 'uiSrc/utils/test-utils' + +import ResultsHistory from './ResultsHistory' + +describe('ResultsHistory', () => { + it('should render', () => { + expect(render()).toBeTruthy() + }) +}) diff --git a/redisinsight/ui/src/pages/search/components/results-history/ResultsHistory.tsx b/redisinsight/ui/src/pages/search/components/results-history/ResultsHistory.tsx new file mode 100644 index 0000000000..b15b21dace --- /dev/null +++ b/redisinsight/ui/src/pages/search/components/results-history/ResultsHistory.tsx @@ -0,0 +1,87 @@ +import React, { useEffect } from 'react' +import cx from 'classnames' + +import { useDispatch, useSelector } from 'react-redux' +import { useParams } from 'react-router-dom' + +import { Nullable } from 'uiSrc/utils' +import { QueryCard } from 'uiSrc/components/query' +import { fetchWBCommandAction, fetchWBHistoryAction, workbenchResultsSelector } from 'uiSrc/slices/workbench/wb-results' +import { searchAndQuerySelector } from 'uiSrc/slices/search/searchAndQuery' + +import styles from './styles.module.scss' + +export interface Props { + onSubmit: ( + commandInit: string, + commandId?: Nullable, + ) => void +} + +const ResultsHistory = (props: Props) => { + const { onSubmit } = props + const { + items, + clearing, + } = useSelector(workbenchResultsSelector) + const { activeRunQueryMode } = useSelector(searchAndQuerySelector) + + const dispatch = useDispatch() + const { instanceId } = useParams<{ instanceId: string }>() + + useEffect(() => { + dispatch(fetchWBHistoryAction(instanceId)) + }, []) + + const handleQueryOpen = (commandId: string = '') => { + dispatch(fetchWBCommandAction(commandId)) + } + + return ( +
+
+
+ {items?.length ? items.map(( + { + command = '', + isOpen = false, + result = undefined, + summary = undefined, + id = '', + loading, + createdAt, + mode, + emptyCommand, + isNotStored, + executionTime, + db, + } + ) => ( + {}} + onQueryOpen={() => handleQueryOpen(id)} + onQueryReRun={() => onSubmit(command, id)} + onQueryDelete={() => {}} + /> + )) : null} +
+
+ ) +} + +export default ResultsHistory diff --git a/redisinsight/ui/src/pages/search/components/results-history/index.ts b/redisinsight/ui/src/pages/search/components/results-history/index.ts new file mode 100644 index 0000000000..a38f637f57 --- /dev/null +++ b/redisinsight/ui/src/pages/search/components/results-history/index.ts @@ -0,0 +1,3 @@ +import ResultsHistory from './ResultsHistory' + +export default ResultsHistory diff --git a/redisinsight/ui/src/pages/search/components/results-history/styles.module.scss b/redisinsight/ui/src/pages/search/components/results-history/styles.module.scss new file mode 100644 index 0000000000..7ea2ec299b --- /dev/null +++ b/redisinsight/ui/src/pages/search/components/results-history/styles.module.scss @@ -0,0 +1,33 @@ +.wrapper { + flex: 1; + height: 100%; + width: 100%; + background-color: var(--euiColorEmptyShade); + border: 1px solid var(--euiColorLightShade); + + display: flex; + flex-direction: column; + + position: relative; +} + +.container { + @include eui.scrollBar; + color: var(--euiTextSubduedColor) !important; + + flex: 1; + width: 100%; + overflow: auto; +} + +.header { + height: 42px; + display: flex; + align-items: center; + justify-content: flex-end; + padding: 0 12px; + + flex-shrink: 0; + border-bottom: 1px solid var(--tableDarkestBorderColor); +} + diff --git a/redisinsight/ui/src/pages/search/styles.module.scss b/redisinsight/ui/src/pages/search/styles.module.scss new file mode 100644 index 0000000000..e371f27293 --- /dev/null +++ b/redisinsight/ui/src/pages/search/styles.module.scss @@ -0,0 +1,32 @@ +.container { + min-height: 100%; + height: 1px !important; + display: flex; + flex-direction: column; +} + +.main { + display: flex; + flex: 1; + padding: 0 16px 0; + height: 100%; + width: 100%; +} + +.content { + display: flex; + flex-grow: 1; + width: 100%; +} + +.resizeButton { + z-index: 1 !important; +} + +.queryPanel { + padding-bottom: 8px; +} + +.queryResultsPanel { + padding-top: 8px; +} diff --git a/redisinsight/ui/src/pages/workbench/components/query/Query/Query.tsx b/redisinsight/ui/src/pages/workbench/components/query/Query/Query.tsx index 42ab11c6a0..f415fa85ca 100644 --- a/redisinsight/ui/src/pages/workbench/components/query/Query/Query.tsx +++ b/redisinsight/ui/src/pages/workbench/components/query/Query/Query.tsx @@ -32,9 +32,17 @@ import { RunQueryMode, ResultsMode } from 'uiSrc/slices/interfaces/workbench' import { sendEventTelemetry, TelemetryEvent } from 'uiSrc/telemetry' import { stopProcessing, workbenchResultsSelector } from 'uiSrc/slices/workbench/wb-results' import DedicatedEditor from 'uiSrc/components/monaco-editor/components/dedicated-editor' +import { QueryActions, QueryTutorials } from 'uiSrc/components/query' + +import { + aroundQuotesRegExp, + argInQuotesRegExp, + SYNTAX_CONTEXT_ID, + SYNTAX_WIDGET_ID, + options, + TUTORIALS +} from './constants' -import QueryActions from '../../query-actions' -import QueryTutorials from '../../query-tutorials' import styles from './styles.module.scss' export interface Props { @@ -49,12 +57,6 @@ export interface Props { onChangeGroupMode: () => void } -const SYNTAX_CONTEXT_ID = 'syntaxWidgetContext' -const SYNTAX_WIDGET_ID = 'syntax.content.widget' - -const argInQuotesRegExp = /^['"](.|[\r\n])*['"]$/ -const aroundQuotesRegExp = /(^["']|["']$)/g - let execHistoryPos: number = 0 let execHistory: CommandExecutionUI[] = [] let decorationCollection: Nullable = null @@ -426,25 +428,6 @@ const Query = (props: Props) => { ).dispose } - const options: monacoEditor.editor.IStandaloneEditorConstructionOptions = { - tabCompletion: 'on', - wordWrap: 'on', - padding: { top: 10 }, - automaticLayout: true, - formatOnPaste: false, - glyphMargin: true, - stickyScroll: { - enabled: true, - defaultModel: 'indentationModel' - }, - suggest: { - preview: true, - showStatusBar: true, - showIcons: false, - }, - lineNumbersMinChars: 4 - } - const isLoading = loading || processing return ( @@ -468,7 +451,7 @@ const Query = (props: Props) => { />
- + { state.workbench.panelSizes.vertical = payload }, + setSQVerticalPanelSizes: (state, { payload }: { payload: any }) => { + state.searchAndQuery.panelSizes.vertical = payload + }, + setSQVerticalScript: (state, { payload }: { payload: any }) => { + state.searchAndQuery.script = payload + }, setLastPageContext: (state, { payload }: { payload: string }) => { state.lastBrowserPage = payload }, @@ -248,6 +260,8 @@ export const { resetBrowserTree, setWorkbenchScript, setWorkbenchVerticalPanelSizes, + setSQVerticalPanelSizes, + setSQVerticalScript, setLastPageContext, setPubSubFieldsContext, setBrowserBulkActionOpen, @@ -276,6 +290,8 @@ export const appContextBrowserKeyDetails = (state: RootState) => state.app.context.browser.keyDetailsSizes export const appContextWorkbench = (state: RootState) => state.app.context.workbench +export const appContextSearchAndQuery = (state: RootState) => + state.app.context.searchAndQuery export const appContextSelectedKey = (state: RootState) => state.app.context.browser.keyList.selectedKey export const appContextPubSub = (state: RootState) => diff --git a/redisinsight/ui/src/slices/interfaces/app.ts b/redisinsight/ui/src/slices/interfaces/app.ts index 00cd49aa91..ba7602c322 100644 --- a/redisinsight/ui/src/slices/interfaces/app.ts +++ b/redisinsight/ui/src/slices/interfaces/app.ts @@ -106,6 +106,14 @@ export interface StateAppContext { } } } + searchAndQuery: { + script: string + panelSizes: { + vertical: { + [key: string]: number + } + } + } pubsub: { channel: string message: string diff --git a/redisinsight/ui/src/slices/interfaces/index.ts b/redisinsight/ui/src/slices/interfaces/index.ts index e3294a071d..052fd92082 100644 --- a/redisinsight/ui/src/slices/interfaces/index.ts +++ b/redisinsight/ui/src/slices/interfaces/index.ts @@ -2,9 +2,10 @@ export * from './instances' export * from './hash' export * from './app' export * from './workbench' +export * from './redisearch' export * from './monitor' export * from './api' export * from './bulkActions' -export * from './redisearch' +export * from './searchAndQuery' export * from './cloud' export * from './rdi' diff --git a/redisinsight/ui/src/slices/interfaces/searchAndQuery.ts b/redisinsight/ui/src/slices/interfaces/searchAndQuery.ts new file mode 100644 index 0000000000..dd75a9be03 --- /dev/null +++ b/redisinsight/ui/src/slices/interfaces/searchAndQuery.ts @@ -0,0 +1,11 @@ +import { CommandExecutionUI, RunQueryMode } from 'uiSrc/slices/interfaces/workbench' + +export interface StateSearchAndQuery { + isLoaded: boolean + loading: boolean + processing: boolean + clearing: boolean + error: string + items: CommandExecutionUI[] + activeRunQueryMode: RunQueryMode +} diff --git a/redisinsight/ui/src/slices/search/searchAndQuery.ts b/redisinsight/ui/src/slices/search/searchAndQuery.ts new file mode 100644 index 0000000000..76b3c147fd --- /dev/null +++ b/redisinsight/ui/src/slices/search/searchAndQuery.ts @@ -0,0 +1,34 @@ +import { createSlice } from '@reduxjs/toolkit' +import { RunQueryMode, StateSearchAndQuery } from 'uiSrc/slices/interfaces' +import { localStorageService } from 'uiSrc/services' +import { BrowserStorageItem } from 'uiSrc/constants' +import { RootState } from 'uiSrc/slices/store' + +export const initialState: StateSearchAndQuery = { + isLoaded: false, + loading: false, + processing: false, + clearing: false, + error: '', + items: [], + activeRunQueryMode: localStorageService?.get(BrowserStorageItem.SQRunQueryMode) ?? RunQueryMode.ASCII, +} + +const searchAndQuerySlice = createSlice({ + name: 'searchAndQuery', + initialState, + reducers: { + changeSQActiveRunQueryMode: (state, { payload }) => { + state.activeRunQueryMode = payload + localStorageService.set(BrowserStorageItem.SQRunQueryMode, payload) + }, + } +}) + +export const searchAndQuerySelector = (state: RootState) => state.search.query + +export default searchAndQuerySlice.reducer + +export const { + changeSQActiveRunQueryMode, +} = searchAndQuerySlice.actions diff --git a/redisinsight/ui/src/slices/store.ts b/redisinsight/ui/src/slices/store.ts index c7a3bbf4e4..89ede143e9 100644 --- a/redisinsight/ui/src/slices/store.ts +++ b/redisinsight/ui/src/slices/store.ts @@ -32,6 +32,7 @@ import appOauthReducer from './oauth/cloud' import workbenchResultsReducer from './workbench/wb-results' import workbenchTutorialsReducer from './workbench/wb-tutorials' import workbenchCustomTutorialsReducer from './workbench/wb-custom-tutorials' +import searchAndQueryReducer from './search/searchAndQuery' import contentCreateRedisButtonReducer from './content/create-redis-buttons' import contentGuideLinksReducer from './content/guide-links' import pubSubReducer from './pubsub/pubsub' @@ -95,6 +96,9 @@ export const rootReducer = combineReducers({ tutorials: workbenchTutorialsReducer, customTutorials: workbenchCustomTutorialsReducer, }), + search: combineReducers({ + query: searchAndQueryReducer, + }), content: combineReducers({ createRedisButtons: contentCreateRedisButtonReducer, guideLinks: contentGuideLinksReducer, diff --git a/redisinsight/ui/src/telemetry/events.ts b/redisinsight/ui/src/telemetry/events.ts index 31a3c90858..680cb5e3c9 100644 --- a/redisinsight/ui/src/telemetry/events.ts +++ b/redisinsight/ui/src/telemetry/events.ts @@ -124,6 +124,8 @@ export enum TelemetryEvent { WORKBENCH_CLEAR_RESULT_CLICKED = 'WORKBENCH_CLEAR_RESULT_CLICKED', WORKBENCH_CLEAR_ALL_RESULTS_CLICKED = 'WORKBENCH_CLEAR_ALL_RESULTS_CLICKED', + SEARCH_COMMAND_SUBMITTED = 'SEARCH_COMMAND_SUBMITTED', + PROFILER_OPENED = 'PROFILER_OPENED', PROFILER_STARTED = 'PROFILER_STARTED', PROFILER_STOPPED = 'PROFILER_STOPPED', diff --git a/redisinsight/ui/src/telemetry/pageViews.ts b/redisinsight/ui/src/telemetry/pageViews.ts index 9562baebc5..1d4960beb0 100644 --- a/redisinsight/ui/src/telemetry/pageViews.ts +++ b/redisinsight/ui/src/telemetry/pageViews.ts @@ -4,6 +4,7 @@ export enum TelemetryPageView { SETTINGS_PAGE = 'Settings', BROWSER_PAGE = 'Browser', WORKBENCH_PAGE = 'Workbench', + SEARCH_AND_QUERY_PAGE = 'Search and Query', SLOWLOG_PAGE = 'Slow Log', CLUSTER_DETAILS_PAGE = 'Overview', PUBSUB_PAGE = 'Pub/Sub', diff --git a/redisinsight/ui/src/utils/test-utils.tsx b/redisinsight/ui/src/utils/test-utils.tsx index ae0d35d545..f6464e8005 100644 --- a/redisinsight/ui/src/utils/test-utils.tsx +++ b/redisinsight/ui/src/utils/test-utils.tsx @@ -38,6 +38,7 @@ import { initialState as initialStateUserSettings } from 'uiSrc/slices/user/user import { initialState as initialStateWBResults } from 'uiSrc/slices/workbench/wb-results' import { initialState as initialStateWBETutorials } from 'uiSrc/slices/workbench/wb-tutorials' import { initialState as initialStateWBECustomTutorials } from 'uiSrc/slices/workbench/wb-custom-tutorials' +import { initialState as initialStateSearchAndQuery } from 'uiSrc/slices/search/searchAndQuery' import { initialState as initialStateCreateRedisButtons } from 'uiSrc/slices/content/create-redis-buttons' import { initialState as initialStateGuideLinks } from 'uiSrc/slices/content/guide-links' import { initialState as initialStateSlowLog } from 'uiSrc/slices/analytics/slowlog' @@ -110,6 +111,9 @@ const initialStateDefault: RootState = { tutorials: cloneDeep(initialStateWBETutorials), customTutorials: cloneDeep(initialStateWBECustomTutorials), }, + search: { + query: cloneDeep(initialStateSearchAndQuery), + }, content: { createRedisButtons: cloneDeep(initialStateCreateRedisButtons), guideLinks: cloneDeep(initialStateGuideLinks), From ba71e159544e5c449d56f3827784a569f4d4bfe8 Mon Sep 17 00:00:00 2001 From: mariasergeenko Date: Mon, 29 Jul 2024 14:49:42 +0200 Subject: [PATCH 016/256] create a base class for the pages --- .../e2e/pageObjects/base-run-commands-page.ts | 78 +++++++++++++++++++ .../e2e/pageObjects/search-and-query-page.ts | 5 +- tests/e2e/pageObjects/workbench-page.ts | 69 +--------------- .../search-and-query/search-and-query-tab.ts | 27 +++++++ .../regression/workbench/workbench-tab.e2e.ts | 2 +- 5 files changed, 112 insertions(+), 69 deletions(-) create mode 100644 tests/e2e/pageObjects/base-run-commands-page.ts create mode 100644 tests/e2e/tests/web/regression/search-and-query/search-and-query-tab.ts diff --git a/tests/e2e/pageObjects/base-run-commands-page.ts b/tests/e2e/pageObjects/base-run-commands-page.ts new file mode 100644 index 0000000000..becdb303b2 --- /dev/null +++ b/tests/e2e/pageObjects/base-run-commands-page.ts @@ -0,0 +1,78 @@ +import { Selector, t } from 'testcafe'; +import { InstancePage } from './instance-page'; + +export class BaseRunCommandsPage extends InstancePage { + + submitCommandButton = Selector('[data-testid=btn-submit]'); + queryInput = Selector('[data-testid=query-input-container]'); + + // History containers + queryCardCommand = Selector('[data-testid=query-card-command]'); + fullScreenButton = Selector('[data-testid=toggle-full-screen]'); + rawModeBtn = Selector('[data-testid="btn-change-mode"]'); + queryCardContainer = Selector('[data-testid^=query-card-container]'); + reRunCommandButton = Selector('[data-testid=re-run-command]'); + copyBtn = Selector('[data-testid^=copy-btn-]'); + copyCommand = Selector('[data-testid=copy-command]'); + + runButtonToolTip = Selector('[data-testid=run-query-tooltip]'); + loadedCommand = Selector('[class=euiLoadingContent__singleLine]'); + runButtonSpinner = Selector('[data-testid=loading-spinner]'); + commandExecutionDateAndTime = Selector('[data-testid=command-execution-date-time]'); + executionCommandTime = Selector('[data-testid=command-execution-time-value]'); + executionCommandIcon = Selector('[data-testid=command-execution-time-icon]'); + executedCommandTitle = Selector('[data-testid=query-card-tooltip-anchor]', { timeout: 500 }); + queryResult = Selector('[data-testid=query-common-result]'); + + cssQueryCardCommand = '[data-testid=query-card-command]'; + cssQueryTextResult = '[data-testid=query-cli-result]'; + cssReRunCommandButton = '[data-testid=re-run-command]'; + cssDeleteCommandButton = '[data-testid=delete-command]'; + + getTutorialLinkLocator = (tutorialName: string): Selector => + Selector(`[@data-testid="data-testid=query-tutorials-link_${tutorialName}"]`); + + /** + * Get card container by command + * @param command The command + */ + async getCardContainerByCommand(command: string): Promise { + return this.queryCardCommand.withExactText(command).parent('[data-testid^="query-card-container-"]'); + } + + /** + * Send a command in Workbench + * @param command The command + * @param speed The speed in seconds. Default is 1 + * @param paste + */ + async sendCommandInWorkbench(command: string, speed = 1, paste = true): Promise { + await t + .click(this.queryInput) + .typeText(this.queryInput, command, { replace: true, speed, paste }) + .click(this.submitCommandButton); + } + + /** + * Check the last command and result in workbench + * @param command The command to check + * @param result The result to check + * @param childNum Indicator which command result need to check + */ + async checkWorkbenchCommandResult(command: string, result: string, childNum = 0): Promise { + // Compare the command with executed command + const actualCommand = await this.queryCardContainer.nth(childNum).find(this.cssQueryCardCommand).textContent; + await t.expect(actualCommand).contains(command, 'Actual command is not equal to executed'); + // Compare the command result with executed command + const actualCommandResult = await this.queryCardContainer.nth(childNum).find(this.cssQueryTextResult).textContent; + await t.expect(actualCommandResult).contains(result, 'Actual command result is not equal to executed'); + } + + /** + * Get selector with tutorial name + * @param tutorialName name of the uploaded tutorial + */ + getAccordionButtonWithName(tutorialName: string): Selector { + return Selector(`[data-testid=accordion-button-${tutorialName}]`); + } +} diff --git a/tests/e2e/pageObjects/search-and-query-page.ts b/tests/e2e/pageObjects/search-and-query-page.ts index 289e8fb1ec..2b6ba80d21 100644 --- a/tests/e2e/pageObjects/search-and-query-page.ts +++ b/tests/e2e/pageObjects/search-and-query-page.ts @@ -1,4 +1,5 @@ -import { InstancePage } from './instance-page'; +import { BaseRunCommandsPage } from './base-run-commands-page'; + +export class SearchAndQueryPage extends BaseRunCommandsPage { -export class SearchAndQueryPage extends InstancePage { } diff --git a/tests/e2e/pageObjects/workbench-page.ts b/tests/e2e/pageObjects/workbench-page.ts index b4b7d0e3ad..196cf20339 100644 --- a/tests/e2e/pageObjects/workbench-page.ts +++ b/tests/e2e/pageObjects/workbench-page.ts @@ -1,17 +1,14 @@ import { Selector, t } from 'testcafe'; -import { InstancePage } from './instance-page'; +import { BaseRunCommandsPage } from './base-run-commands-page'; -export class WorkbenchPage extends InstancePage { +export class WorkbenchPage extends BaseRunCommandsPage { //CSS selectors cssSelectorPaginationButtonPrevious = '[data-test-subj=pagination-button-previous]'; cssSelectorPaginationButtonNext = '[data-test-subj=pagination-button-next]'; - cssReRunCommandButton = '[data-testid=re-run-command]'; - cssDeleteCommandButton = '[data-testid=delete-command]'; cssTableViewTypeOption = '[data-testid=view-type-selected-Plugin-redisearch__redisearch]'; cssClientListViewTypeOption = '[data-testid=view-type-selected-Plugin-client-list__clients-list]'; cssJsonViewTypeOption = '[data-testid=view-type-selected-Plugin-client-list__json-view]'; cssMonacoCommandPaletteLine = '[aria-label="Command Palette"]'; - cssQueryTextResult = '[data-testid=query-cli-result]'; cssWorkbenchCommandInHistory = '[data-testid=wb-command]'; cssQueryTableResult = '[data-testid^=query-table-result-]'; queryGraphContainer = '[data-testid=query-graph-container]'; @@ -25,7 +22,6 @@ export class WorkbenchPage extends InstancePage { //*The following categories are ordered alphabetically (Alerts, Buttons, Checkboxes, etc.). //------------------------------------------------------------------------------------------- //BUTTON - submitCommandButton = Selector('[data-testid=btn-submit]'); resizeButtonForScriptingAndResults = Selector('[data-test-subj=resize-btn-scripting-area-and-results]'); collapsePreselectAreaButton = Selector('[data-testid=collapse-enablement-area]'); expandPreselectAreaButton = Selector('[data-testid=expand-enablement-area]'); @@ -36,18 +32,12 @@ export class WorkbenchPage extends InstancePage { preselectCreateHashIndex = Selector('[data-testid="preselect-Create a hash index"]'); preselectGroupBy = Selector('[data-testid*=preselect-Group]'); preselectButtons = Selector('[data-testid^=preselect-]'); - copyBtn = Selector('[data-testid^=copy-btn-]'); - reRunCommandButton = Selector('[data-testid=re-run-command]'); preselectManual = Selector('[data-testid=preselect-Manual]'); - fullScreenButton = Selector('[data-testid=toggle-full-screen]'); queryCardNoModuleButton = Selector('[data-testid=query-card-no-module-button] a'); - rawModeBtn = Selector('[data-testid="btn-change-mode"]'); closeEnablementPage = Selector('[data-testid=enablement-area__page-close]'); groupMode = Selector('[data-testid=btn-change-group-mode]'); - copyCommand = Selector('[data-testid=copy-command]'); clearResultsBtn = Selector('[data-testid=clear-history-btn]'); exploreRedisBtn = Selector('[data-testid=no-results-explore-btn]'); - basicUseCaseTutorialsButton = Selector('[data-testid=wb-tutorials-link_redis_use_cases_basic]'); //ICONS noCommandHistoryIcon = Selector('[data-testid=wb_no-results__icon]'); parametersAnchor = Selector('[data-testid=parameters-anchor]'); @@ -56,15 +46,13 @@ export class WorkbenchPage extends InstancePage { silentModeIcon = Selector('[data-testid=silent-mode-tooltip]'); //LINKS //TEXT INPUTS (also referred to as 'Text fields') - queryInput = Selector('[data-testid=query-input-container]'); + iframe = Selector('[data-testid=pluginIframe]'); //TEXT ELEMENTS queryPluginResult = Selector('[data-testid=query-plugin-result]'); responseInfo = Selector('[class="responseInfo"]'); parsedRedisReply = Selector('[class="parsedRedisReply"]'); scriptsLines = Selector('[data-testid=query-input-container] .view-lines'); - queryCardContainer = Selector('[data-testid^=query-card-container]'); - queryCardCommand = Selector('[data-testid=query-card-command]'); queryTableResult = Selector('[data-testid^=query-table-result-]'); queryJsonResult = Selector('[data-testid=json-view]'); mainEditorArea = Selector('[data-testid=main-input-container-area]'); @@ -78,14 +66,6 @@ export class WorkbenchPage extends InstancePage { commandExecutionResult = Selector('[data-testid=welcome-page-title]'); commandExecutionResultFailed = Selector('[data-testid=cli-output-response-fail]'); chartViewTypeOptionSelected = Selector('[data-testid=view-type-selected-Plugin-redistimeseries__redistimeseries-chart]'); - runButtonToolTip = Selector('[data-testid=run-query-tooltip]'); - loadedCommand = Selector('[class=euiLoadingContent__singleLine]'); - runButtonSpinner = Selector('[data-testid=loading-spinner]'); - commandExecutionDateAndTime = Selector('[data-testid=command-execution-date-time]'); - executionCommandTime = Selector('[data-testid=command-execution-time-value]'); - executionCommandIcon = Selector('[data-testid=command-execution-time-icon]'); - executedCommandTitle = Selector('[data-testid=query-card-tooltip-anchor]', { timeout: 500 }); - queryResult = Selector('[data-testid=query-common-result]'); //OPTIONS selectViewType = Selector('[data-testid=select-view-type]'); textViewTypeOption = Selector('[data-test-subj^=view-type-option-Text]'); @@ -95,13 +75,6 @@ export class WorkbenchPage extends InstancePage { typeSelectedClientsList = Selector('[data-testid=view-type-selected-Plugin-client-list__clients-list]'); viewTypeOptionClientList = Selector('[data-test-subj=view-type-option-Plugin-client-list__clients-list]'); viewTypeOptionsText = Selector('[data-test-subj=view-type-option-Text-default__Text]'); - /** - * Get card container by command - * @param command The command - */ - async getCardContainerByCommand(command: string): Promise { - return this.queryCardCommand.withExactText(command).parent('[data-testid^="query-card-container-"]'); - } // Select Text view option in Workbench results async selectViewTypeText(): Promise { @@ -131,19 +104,6 @@ export class WorkbenchPage extends InstancePage { .click(this.graphViewTypeOption); } - /** - * Send a command in Workbench - * @param command The command - * @param speed The speed in seconds. Default is 1 - * @param paste - */ - async sendCommandInWorkbench(command: string, speed = 1, paste = true): Promise { - await t - .click(this.queryInput) - .typeText(this.queryInput, command, { replace: true, speed, paste }) - .click(this.submitCommandButton); - } - /** * Send multiple commands in Workbench * @param commands The commands @@ -167,29 +127,6 @@ export class WorkbenchPage extends InstancePage { } } - /** - * Check the last command and result in workbench - * @param command The command to check - * @param result The result to check - * @param childNum Indicator which command result need to check - */ - async checkWorkbenchCommandResult(command: string, result: string, childNum = 0): Promise { - // Compare the command with executed command - const actualCommand = await this.queryCardContainer.nth(childNum).find(this.cssQueryCardCommand).textContent; - await t.expect(actualCommand).contains(command, 'Actual command is not equal to executed'); - // Compare the command result with executed command - const actualCommandResult = await this.queryCardContainer.nth(childNum).find(this.cssQueryTextResult).textContent; - await t.expect(actualCommandResult).contains(result, 'Actual command result is not equal to executed'); - } - - /** - * Get selector with tutorial name - * @param tutorialName name of the uploaded tutorial - */ - getAccordionButtonWithName(tutorialName: string): Selector { - return Selector(`[data-testid=accordion-button-${tutorialName}]`); - } - /** * Get internal tutorial link with .md name * @param internalLink name of the .md file diff --git a/tests/e2e/tests/web/regression/search-and-query/search-and-query-tab.ts b/tests/e2e/tests/web/regression/search-and-query/search-and-query-tab.ts new file mode 100644 index 0000000000..9c5c4ec175 --- /dev/null +++ b/tests/e2e/tests/web/regression/search-and-query/search-and-query-tab.ts @@ -0,0 +1,27 @@ +import { DatabaseHelper } from '../../../../helpers'; +import { DatabaseAPIRequests } from '../../../../helpers/api/api-database'; +import { BrowserPage } from '../../../../pageObjects'; +import { ExploreTabs, KeysInteractionTabs, rte } from '../../../../helpers/constants'; +import { commonUrl, ossStandaloneConfig } from '../../../../helpers/conf'; + +const databaseHelper = new DatabaseHelper(); +const databaseAPIRequests = new DatabaseAPIRequests(); +const browserPage = new BrowserPage(); + +fixture `Autocomplete for entered commands` + .meta({ type: 'regression', rte: rte.standalone }) + .page(commonUrl) + .beforeEach(async t => { + await databaseHelper.acceptLicenseTermsAndAddDatabaseApi(ossStandaloneConfig); + }) + .afterEach(async() => { + // Delete database + await databaseAPIRequests.deleteStandaloneDatabaseApi(ossStandaloneConfig); + }); +test('Verify that tutorials can be opened from Workbench', async t => { + const search = await browserPage.KeysInteractionPanel.setActiveTab(KeysInteractionTabs.SearchAndQuery); + await t.click(search.getTutorialLinkLocator('sq-exact-match')); + await t.expect(search.InsightsPanel.sidePanel.exists).ok('Insight panel is not opened'); + const tab = await browserPage.InsightsPanel.setActiveTab(ExploreTabs.Tutorials); + await t.expect(tab.preselectArea.textContent).contains('EXACT MATCH', 'the tutorial page is incorrect'); +}); diff --git a/tests/e2e/tests/web/regression/workbench/workbench-tab.e2e.ts b/tests/e2e/tests/web/regression/workbench/workbench-tab.e2e.ts index 57c1898186..1091652ead 100644 --- a/tests/e2e/tests/web/regression/workbench/workbench-tab.e2e.ts +++ b/tests/e2e/tests/web/regression/workbench/workbench-tab.e2e.ts @@ -20,7 +20,7 @@ fixture `Autocomplete for entered commands` }); test('Verify that tutorials can be opened from Workbench', async t => { const workbench = await browserPage.KeysInteractionPanel.setActiveTab(KeysInteractionTabs.Workbench); - await t.click(workbench.basicUseCaseTutorialsButton); + await t.click(workbench.getTutorialLinkLocator('redis_use_cases_basic')); await t.expect(workbench.InsightsPanel.sidePanel.exists).ok('Insight panel is not opened'); const tab = await browserPage.InsightsPanel.setActiveTab(ExploreTabs.Tutorials); await t.expect(tab.preselectArea.textContent).contains('BASIC REDIS USE CASES', 'the tutorial page is incorrect'); From d594f280308a1d7f031f6f1c6f978b115dd226e9 Mon Sep 17 00:00:00 2001 From: kchepikava Date: Thu, 25 Jul 2024 19:02:41 +0200 Subject: [PATCH 017/256] RI-5888 added get info api on be --- redisinsight/api/src/__mocks__/redisearch.ts | 216 +++++++++ .../browser/redisearch/dto/index.info.dto.ts | 412 ++++++++++++++++++ .../modules/browser/redisearch/dto/index.ts | 1 + .../redisearch/redisearch.controller.ts | 13 + .../redisearch/redisearch.service.spec.ts | 30 ++ .../browser/redisearch/redisearch.service.ts | 35 ++ .../modules/browser/utils/redisIndexInfo.ts | 56 +++ .../POST-databases-id-redisearch-info.test.ts | 125 ++++++ 8 files changed, 888 insertions(+) create mode 100644 redisinsight/api/src/__mocks__/redisearch.ts create mode 100644 redisinsight/api/src/modules/browser/redisearch/dto/index.info.dto.ts create mode 100644 redisinsight/api/src/modules/browser/utils/redisIndexInfo.ts create mode 100644 redisinsight/api/test/api/redisearch/POST-databases-id-redisearch-info.test.ts diff --git a/redisinsight/api/src/__mocks__/redisearch.ts b/redisinsight/api/src/__mocks__/redisearch.ts new file mode 100644 index 0000000000..a23dc8c735 --- /dev/null +++ b/redisinsight/api/src/__mocks__/redisearch.ts @@ -0,0 +1,216 @@ +import { IndexInfoDto } from 'src/modules/browser/redisearch/dto'; + +export const mockIndexInfoRaw = [ + 'index_name', + 'idx:movie', + 'index_options', + [], + 'index_definition', + ['key_type', 'HASH', 'prefixes', ['movie:'], 'default_score', '1'], + 'attributes', + [ + ['identifier', 'title', 'attribute', 'title', 'type', 'TEXT', 'WEIGHT', '1', 'SORTABLE'], + ['identifier', 'release_year', 'attribute', 'release_year', 'type', 'NUMERIC', 'SORTABLE', 'UNF'], + ['identifier', 'rating', 'attribute', 'rating', 'type', 'NUMERIC', 'SORTABLE', 'UNF'], + ['identifier', 'genre', 'attribute', 'genre', 'type', 'TAG', 'SEPARATOR', ',', 'SORTABLE'], + ], + 'num_docs', + '2', + 'max_doc_id', + '2', + 'num_terms', + '13', + 'num_records', + '19', + 'inverted_sz_mb', + '0.0016384124755859375', + 'vector_index_sz_mb', + '0', + 'total_inverted_index_blocks', + '17', + 'offset_vectors_sz_mb', + '1.239776611328125e-5', + 'doc_table_size_mb', + '1.468658447265625e-4', + 'sortable_values_size_mb', + '2.498626708984375e-4', + 'key_table_size_mb', + '8.296966552734375e-5', + 'tag_overhead_sz_mb', + '5.53131103515625e-5', + 'text_overhead_sz_mb', + '4.3392181396484375e-4', + 'total_index_memory_sz_mb', + '0.0026903152465820313', + 'geoshapes_sz_mb', '0', + 'records_per_doc_avg', + '9.5', + 'bytes_per_record_avg', + '90.42105102539063', + 'offsets_per_term_avg', + '0.6842105388641357', + 'offset_bits_per_record_avg', + '8', 'hash_indexing_failures', + '0', 'total_indexing_time', '0.890999972820282', 'indexing', '0', + 'percent_indexed', '1', 'number_of_uses', 17, 'cleaning', 0, 'gc_stats', + ['bytes_collected', '0', 'total_ms_run', '0', 'total_cycles', '0', + 'average_cycle_time_ms', 'nan', 'last_run_time_ms', '0', + 'gc_numeric_trees_missed', '0', 'gc_blocks_denied', '0', + ], + 'cursor_stats', + ['global_idle', 0, 'global_total', 0, 'index_capacity', 128, 'index_total', 0], + 'dialect_stats', + ['dialect_1', 1, 'dialect_2', 0, 'dialect_3', 0, 'dialect_4', 0], + 'Index Errors', + ['indexing failures', 0, 'last indexing error', 'N/A', 'last indexing error key', 'N/A'], + 'field statistics', + [ + ['identifier', 'title', 'attribute', 'title', 'Index Errors', + ['indexing failures', 0, 'last indexing error', 'N/A', 'last indexing error key', 'N/A'], + ], + ['identifier', 'release_year', 'attribute', 'release_year', 'Index Errors', + ['indexing failures', 0, 'last indexing error', 'N/A', 'last indexing error key', 'N/A'], + ], + ['identifier', 'rating', 'attribute', 'rating', 'Index Errors', + ['indexing failures', 0, 'last indexing error', 'N/A', 'last indexing error key', 'N/A'], + ], + ['identifier', 'genre', 'attribute', 'genre', 'Index Errors', + ['indexing failures', 0, 'last indexing error', 'N/A', 'last indexing error key', 'N/A'], + ]]]; + +export const mockIndexInfoDto: IndexInfoDto = { + index_name: 'idx:movie', + index_options: {}, + index_definition: { key_type: 'HASH', prefixes: ['movie:'], default_score: '1' }, + attributes: [ + { + identifier: 'title', + attribute: 'title', + type: 'TEXT', + WEIGHT: '1', + SORTABLE: true, + NOINDEX: undefined, + CASESENSITIVE: undefined, + UNF: undefined, + NOSTEM: undefined, + }, + { + identifier: 'release_year', + attribute: 'release_year', + type: 'NUMERIC', + SORTABLE: true, + NOINDEX: undefined, + CASESENSITIVE: undefined, + UNF: true, + NOSTEM: undefined, + }, + { + identifier: 'rating', + attribute: 'rating', + type: 'NUMERIC', + SORTABLE: true, + NOINDEX: undefined, + CASESENSITIVE: undefined, + UNF: true, + NOSTEM: undefined, + }, + { + identifier: 'genre', + attribute: 'genre', + type: 'TAG', + SEPARATOR: ',', + SORTABLE: true, + NOINDEX: undefined, + CASESENSITIVE: undefined, + UNF: undefined, + NOSTEM: undefined, + }, + ], + num_docs: '2', + max_doc_id: '2', + num_terms: '13', + num_records: '19', + inverted_sz_mb: '0.0016384124755859375', + vector_index_sz_mb: '0', + total_inverted_index_blocks: '17', + offset_vectors_sz_mb: '1.239776611328125e-5', + doc_table_size_mb: '1.468658447265625e-4', + sortable_values_size_mb: '2.498626708984375e-4', + tag_overhead_sz_mb: '5.53131103515625e-5', + text_overhead_sz_mb: '4.3392181396484375e-4', + total_index_memory_sz_mb: '0.0026903152465820313', + + key_table_size_mb: '8.296966552734375e-5', + geoshapes_sz_mb: '0', + records_per_doc_avg: '9.5', + bytes_per_record_avg: '90.42105102539063', + offsets_per_term_avg: '0.6842105388641357', + offset_bits_per_record_avg: '8', + hash_indexing_failures: '0', + total_indexing_time: '0.890999972820282', + indexing: '0', + percent_indexed: '1', + number_of_uses: 17, + cleaning: 0, + gc_stats: { + bytes_collected: '0', + total_ms_run: '0', + total_cycles: '0', + average_cycle_time_ms: 'nan', + last_run_time_ms: '0', + gc_numeric_trees_missed: '0', + gc_blocks_denied: '0', + }, + cursor_stats: { + global_idle: 0, + global_total: 0, + index_capacity: 128, + index_total: 0, + }, + dialect_stats: { + dialect_1: 1, dialect_2: 0, dialect_3: 0, dialect_4: 0, + }, + 'Index Errors': { + 'indexing failures': 0, + 'last indexing error': 'N/A', + 'last indexing error key': 'N/A', + }, + 'field statistics': [ + { + identifier: 'title', + attribute: 'title', + 'Index Errors': { + 'indexing failures': 0, + 'last indexing error': 'N/A', + 'last indexing error key': 'N/A', + }, + }, + { + identifier: 'release_year', + attribute: 'release_year', + 'Index Errors': { + 'indexing failures': 0, + 'last indexing error': 'N/A', + 'last indexing error key': 'N/A', + }, + }, + { + identifier: 'rating', + attribute: 'rating', + 'Index Errors': { + 'indexing failures': 0, + 'last indexing error': 'N/A', + 'last indexing error key': 'N/A', + }, + }, + { + identifier: 'genre', + attribute: 'genre', + 'Index Errors': { + 'indexing failures': 0, + 'last indexing error': 'N/A', + 'last indexing error key': 'N/A', + }, + }, + ], +}; diff --git a/redisinsight/api/src/modules/browser/redisearch/dto/index.info.dto.ts b/redisinsight/api/src/modules/browser/redisearch/dto/index.info.dto.ts new file mode 100644 index 0000000000..2700275fec --- /dev/null +++ b/redisinsight/api/src/modules/browser/redisearch/dto/index.info.dto.ts @@ -0,0 +1,412 @@ +import { ApiProperty } from '@nestjs/swagger'; +import { + IsDefined, +} from 'class-validator'; +import { IsRedisString, RedisStringType } from 'src/common/decorators'; +import { RedisString } from 'src/common/constants'; +import { Expose } from 'class-transformer'; + +export class IndexInfoRequestBodyDto { + @ApiProperty({ + description: 'Index name', + type: String, + }) + @IsDefined() + @RedisStringType() + @IsRedisString() + index: RedisString; +} + +export class IndexOptionsDto { + @ApiProperty({ + description: 'is a filter expression with the full RediSearch aggregation expression language.', + type: String, + }) + @Expose() + filter?: string; + + @ApiProperty({ + description: 'if set, indicates the default language for documents in the index. Default is English.', + type: String, + }) + @Expose() + default_lang?: string; +} + +export class IndexDefinitionDto { + @ApiProperty({ + description: 'key_type, hash or JSON', + type: String, + }) + @Expose() + key_type: string; + + @ApiProperty({ + description: 'Index prefixes given during create', + type: String, + isArray: true, + }) + @Expose() + prefixes: Array; + + @ApiProperty({ + description: 'Index default_score', + type: String, + }) + @Expose() + default_score: string; +} + +export class IndexAttibuteDto { + @ApiProperty({ + description: 'Field identifier', + type: String, + }) + @Expose() + identifier: string; + + @ApiProperty({ + description: 'Field attribute', + type: String, + }) + @Expose() + attribute: string; + + @ApiProperty({ + description: 'Field type', + type: String, + }) + @Expose() + type: string; + + @ApiProperty({ + description: 'Field weight', + type: String, + }) + @Expose() + WEIGHT?: string; + + @ApiProperty({ + description: 'Field can be sorted', + type: Boolean, + }) + @Expose() + SORTABLE?: boolean; + + @ApiProperty({ + description: 'Attributes can have the NOINDEX option, which means they will not be indexed. ', + type: Boolean, + }) + @Expose() + NOINDEX?: boolean; + + @ApiProperty({ + description: 'Attribute is case sensitive', + type: Boolean, + }) + @Expose() + CASESENSITIVE?: boolean; + + @ApiProperty({ + description: `By default, for hashes (not with JSON) SORTABLE applies a normalization to the indexed value + (characters set to lowercase, removal of diacritics).`, + type: Boolean, + }) + @Expose() + UNF?: boolean; + + @ApiProperty({ + description: `Text attributes can have the NOSTEM argument that disables stemming when indexing its values. + This may be ideal for things like proper names.`, + type: Boolean, + }) + @Expose() + NOSTEM?: boolean; + + @ApiProperty({ + description: `Indicates how the text contained in the attribute is to be split into individual tags. + The default is ,. The value must be a single character.`, + type: String, + }) + @Expose() + SEPARATOR?: string; +} + +export class FieldStatisticsDto { + @ApiProperty({ + description: 'Field identifier', + type: String, + }) + @Expose() + identifier: string; + + @ApiProperty({ + description: 'Field attribute', + type: String, + }) + @Expose() + attribute: string; + + @ApiProperty({ + description: 'Field errors', + type: Object, + }) + @Expose() + [ 'Index Errors']: object; +} + +// The list of return fields from redis: https://redis.io/docs/latest/commands/ft.info/ + +export class IndexInfoDto { + // General + @ApiProperty({ + description: 'The index name that was defined when index was created', + type: String, + }) + @Expose() + @IsDefined() + index_name: string; + + @ApiProperty({ + description: 'The index options selected during FT.CREATE such as FILTER {filter}, LANGUAGE {default_lang}, etc.', + type: IndexOptionsDto, + }) + @Expose() + index_options: IndexOptionsDto; + + @ApiProperty({ + description: 'Includes key_type, hash or JSON; prefixes, if any; and default_score.', + type: IndexDefinitionDto, + }) + @Expose() + index_definition: IndexDefinitionDto; + + @ApiProperty({ + description: 'The index schema field names, types, and attributes.', + type: IndexAttibuteDto, + isArray: true, + }) + @Expose() + attributes: IndexAttibuteDto[]; + + @ApiProperty({ + description: 'The number of documents.', + type: String, + }) + @Expose() + num_docs: string; + + @ApiProperty({ + description: 'The maximum document ID.', + type: String, + }) + @Expose() + max_doc_id?: string; + + @ApiProperty({ + description: 'The number of distinct terms.', + type: String, + }) + @Expose() + num_terms?: string; + + @ApiProperty({ + description: 'The total number of records.', + type: String, + }) + @Expose() + num_records?: string; + + // Various size statistics + @ApiProperty({ + description: `The memory used by the inverted index, which is the core data structure + used for searching in RediSearch. The size is given in megabytes.`, + type: String, + }) + @Expose() + inverted_sz_mb?: string; + + @ApiProperty({ + description: `The memory used by the vector index, + which stores any vectors associated with each document.`, + type: String, + }) + @Expose() + vector_index_sz_mb?: string; + + @ApiProperty({ + description: 'The total number of blocks in the inverted index.', + type: String, + }) + @Expose() + total_inverted_index_blocks?: string; + + @ApiProperty({ + description: `The memory used by the offset vectors, + which store positional information for terms in documents.`, + type: String, + }) + @Expose() + offset_vectors_sz_mb?: string; + + @ApiProperty({ + description: `The memory used by the document table, + which contains metadata about each document in the index.`, + type: String, + }) + @Expose() + doc_table_size_mb?: string; + + @ApiProperty({ + description: `The memory used by sortable values, + which are values associated with documents and used for sorting purposes.`, + type: String, + }) + @Expose() + sortable_values_size_mb?: string; + + @ApiProperty({ + description: 'Tag overhead memory usage in mb', + type: String, + }) + @Expose() + tag_overhead_sz_mb?: string; + + @ApiProperty({ + description: 'Text overhead memory usage in mb', + type: String, + }) + @Expose() + text_overhead_sz_mb?: string; + + @ApiProperty({ + description: 'Total index memory size in mb', + type: String, + }) + @Expose() + total_index_memory_sz_mb?: string; + + @ApiProperty({ + description: `The memory used by the key table, + which stores the mapping between document IDs and Redis keys`, + type: String, + }) + @Expose() + key_table_size_mb?: string; + + @ApiProperty({ + description: 'The memory used by GEO-related fields.', + type: String, + }) + @Expose() + geoshapes_sz_mb?: string; + + @ApiProperty({ + description: 'The average number of records (including deletions) per document.', + type: String, + }) + @Expose() + records_per_doc_avg?: string; + + @ApiProperty({ + description: 'The average size of each record in bytes.', + type: String, + }) + @Expose() + bytes_per_record_avg?: string; + + @ApiProperty({ + description: 'The average number of offsets (position information) per term.', + type: String, + }) + @Expose() + offsets_per_term_avg?: string; + + @ApiProperty({ + description: 'The average number of bits used for offsets per record.', + type: String, + }) + @Expose() + offset_bits_per_record_avg?: string; + + // Indexing-related statistics + @ApiProperty({ + description: 'The number of failures encountered during indexing.', + type: String, + }) + @Expose() + hash_indexing_failures?: string; + + @ApiProperty({ + description: 'The total time taken for indexing in seconds.', + type: String, + }) + @Expose() + total_indexing_time?: string; + + @ApiProperty({ + description: 'Indicates whether the index is currently being generated.', + type: String, + }) + @Expose() + indexing?: string; + + @ApiProperty({ + description: 'The percentage of the index that has been successfully generated.', + type: String, + }) + @Expose() + percent_indexed?: string; + + @ApiProperty({ + description: 'The number of times the index has been used.', + type: Number, + }) + @Expose() + number_of_uses?: number; + + @ApiProperty({ + description: 'The index deletion flag. A value of 1 indicates index deletion is in progress.', + type: Number, + }) + @Expose() + cleaning?: number; + + // Other + @ApiProperty({ + description: 'Garbage collection statistics', + type: Object, + }) + @Expose() + gc_stats?: object; + + @ApiProperty({ + description: 'Cursor statistics', + type: Object, + }) + @Expose() + cursor_stats?: object; + + @ApiProperty({ + description: 'Dialect statistics: the number of times the index was searched using each DIALECT, 1 - 4.', + type: Object, + }) + @Expose() + dialect_stats?: object; + + @ApiProperty({ + description: `Index error statistics, including indexing failures, last indexing error, + and last indexing error key.`, + type: Object, + }) + @Expose() + ['Index Errors']?: object; + + @ApiProperty({ + description: 'Dialect statistics: the number of times the index was searched using each DIALECT, 1 - 4.', + type: FieldStatisticsDto, + isArray: true, + }) + @Expose() + ['field statistics']?: Array; +} diff --git a/redisinsight/api/src/modules/browser/redisearch/dto/index.ts b/redisinsight/api/src/modules/browser/redisearch/dto/index.ts index 2390227ecd..56e0b39d48 100644 --- a/redisinsight/api/src/modules/browser/redisearch/dto/index.ts +++ b/redisinsight/api/src/modules/browser/redisearch/dto/index.ts @@ -1,3 +1,4 @@ export * from './create.redisearch-index.dto'; export * from './search.redisearch.dto'; export * from './list.redisearch-indexes.response'; +export * from './index.info.dto'; diff --git a/redisinsight/api/src/modules/browser/redisearch/redisearch.controller.ts b/redisinsight/api/src/modules/browser/redisearch/redisearch.controller.ts index 7c3a9cdb55..7956f7445c 100644 --- a/redisinsight/api/src/modules/browser/redisearch/redisearch.controller.ts +++ b/redisinsight/api/src/modules/browser/redisearch/redisearch.controller.ts @@ -19,6 +19,8 @@ import { BrowserClientMetadata } from 'src/modules/browser/decorators/browser-cl import { ApiQueryRedisStringEncoding } from 'src/common/decorators'; import { CreateRedisearchIndexDto, + IndexInfoDto, + IndexInfoRequestBodyDto, ListRedisearchIndexesResponse, SearchRedisearchDto, } from 'src/modules/browser/redisearch/dto'; @@ -72,4 +74,15 @@ export class RedisearchController extends BrowserBaseController { ): Promise { return await this.service.search(clientMetadata, dto); } + + @Post('info') + @HttpCode(200) + @ApiOperation({ description: 'Get index info' }) + @ApiOkResponse({ type: IndexInfoDto }) + async info( + @BrowserClientMetadata() clientMetadata: ClientMetadata, + @Body() dto: IndexInfoRequestBodyDto, + ): Promise { + return await this.service.getInfo(clientMetadata, dto); + } } diff --git a/redisinsight/api/src/modules/browser/redisearch/redisearch.service.spec.ts b/redisinsight/api/src/modules/browser/redisearch/redisearch.service.spec.ts index 0a0910e660..5ce2d03d16 100644 --- a/redisinsight/api/src/modules/browser/redisearch/redisearch.service.spec.ts +++ b/redisinsight/api/src/modules/browser/redisearch/redisearch.service.spec.ts @@ -2,6 +2,7 @@ import { Test, TestingModule } from '@nestjs/testing'; import { ConflictException, ForbiddenException, + InternalServerErrorException, } from '@nestjs/common'; import { when } from 'jest-when'; import { @@ -20,6 +21,7 @@ import { } from 'src/modules/browser/redisearch/dto'; import { BrowserHistoryService } from 'src/modules/browser/browser-history/browser-history.service'; import { DatabaseClientFactory } from 'src/modules/database/providers/database.client.factory'; +import { mockIndexInfoDto, mockIndexInfoRaw } from 'src/__mocks__/redisearch'; const keyName1 = Buffer.from('keyName1'); const keyName2 = Buffer.from('keyName2'); @@ -368,4 +370,32 @@ describe('RedisearchService', () => { expect(browserHistory.create).toHaveBeenCalled(); }); }); + + describe('getInfo', () => { + it('should get indexInfo', async () => { + const mockIndexName = 'idx:movie'; + when(standaloneClient.sendCommand) + .calledWith(['FT.INFO', mockIndexName], { replyEncoding: 'utf8' }) + .mockResolvedValue(mockIndexInfoRaw); + + const res = await service.getInfo(mockBrowserClientMetadata, { index: mockIndexName }); + expect(standaloneClient.sendCommand).toHaveBeenCalledWith([ + 'FT.INFO', + mockIndexName, + ], { replyEncoding: 'utf8' }); + expect(res).toEqual(mockIndexInfoDto); + }); + + it('should throw error if index name was not provided', async () => { + await expect(service.getInfo(mockBrowserClientMetadata, { index: '' })).rejects.toThrow('Index was not provided'); + }); + + it('should throw error if client was not created', async () => { + const error = new Error('Client was not created'); + databaseClientFactory.getOrCreateClient = jest.fn().mockRejectedValue(error); + + await expect(service.getInfo(mockBrowserClientMetadata, + { index: 'indexName' })).rejects.toThrow(InternalServerErrorException); + }); + }); }); diff --git a/redisinsight/api/src/modules/browser/redisearch/redisearch.service.ts b/redisinsight/api/src/modules/browser/redisearch/redisearch.service.ts index 325b41b555..39f2d4a856 100644 --- a/redisinsight/api/src/modules/browser/redisearch/redisearch.service.ts +++ b/redisinsight/api/src/modules/browser/redisearch/redisearch.service.ts @@ -11,6 +11,8 @@ import { catchAclError } from 'src/utils'; import { ClientMetadata } from 'src/common/models'; import { CreateRedisearchIndexDto, + IndexInfoDto, + IndexInfoRequestBodyDto, ListRedisearchIndexesResponse, SearchRedisearchDto, } from 'src/modules/browser/redisearch/dto'; @@ -28,6 +30,7 @@ import { RedisClientConnectionType, RedisClientNodeRole, } from 'src/modules/redis/client'; +import { convertIndexInfoReply } from '../utils/redisIndexInfo'; @Injectable() export class RedisearchService { @@ -138,6 +141,38 @@ export class RedisearchService { } } + /** + * Gets the info of a given index + * @param clientMetadata + * @param dto + */ + public async getInfo( + clientMetadata: ClientMetadata, + dto: IndexInfoRequestBodyDto, + ): Promise { + this.logger.log('Getting index info'); + + try { + const { index } = dto; + + if (!index) { + throw new Error('Index was not provided'); + } + + const client: RedisClient = await this.databaseClientFactory.getOrCreateClient(clientMetadata); + + const infoReply = await client.sendCommand( + ['FT.INFO', index], + { replyEncoding: 'utf8' }, + ) as string[][]; + + return plainToClass(IndexInfoDto, convertIndexInfoReply(infoReply)); + } catch (e) { + this.logger.error('Failed to get index info', e); + throw catchAclError(e); + } + } + /** * Search for key names using RediSearch module * Response is the same as for keys "scan" to have the same behaviour in the browser diff --git a/redisinsight/api/src/modules/browser/utils/redisIndexInfo.ts b/redisinsight/api/src/modules/browser/utils/redisIndexInfo.ts new file mode 100644 index 0000000000..edf1440d5b --- /dev/null +++ b/redisinsight/api/src/modules/browser/utils/redisIndexInfo.ts @@ -0,0 +1,56 @@ +import { chunk, isArray } from 'lodash'; + +type ArrayReplyEntry = string | string[]; +const errorField = 'Index Errors'; + +const infoFieldsToConvert = [ + 'index_options', + 'index_definition', + 'gc_stats', + 'cursor_stats', + 'dialect_stats', + errorField, +]; + +export const convertArrayReplyToObject = ( + input: ArrayReplyEntry[], +): { [key: string]: any } => { + const obj = {}; + + chunk(input, 2).forEach(([key, value]) => { + obj[key as string] = value; + }); + + return obj; +}; + +export const convertIndexInfoAttributeReply = (input: string[]): object => { + const attribute = convertArrayReplyToObject(input); + + if (isArray(input)) { + attribute['SORTABLE'] = input.includes('SORTABLE') || undefined; + attribute['NOINDEX'] = input.includes('NOINDEX') || undefined; + attribute['CASESENSITIVE'] = input.includes('CASESENSITIVE') || undefined; + attribute['UNF'] = input.includes('UNF') || undefined; + attribute['NOSTEM'] = input.includes('NOSTEM') || undefined; + } + + return attribute; +}; + +export const convertIndexInfoReply = (input: ArrayReplyEntry[]): object => { + const infoReply = convertArrayReplyToObject(input); + infoFieldsToConvert.forEach((field) => { + infoReply[field] = convertArrayReplyToObject(infoReply[field]); + }); + + infoReply['attributes'] = infoReply['attributes']?.map?.(convertIndexInfoAttributeReply); + infoReply['field statistics'] = infoReply['field statistics']?.map?.((sField) => { + const convertedField = convertArrayReplyToObject(sField); + if (convertedField[errorField] && Array.isArray(convertedField[errorField])) { + convertedField[errorField] = convertArrayReplyToObject(convertedField[errorField]); + } + return convertedField; + }); + return infoReply; +}; diff --git a/redisinsight/api/test/api/redisearch/POST-databases-id-redisearch-info.test.ts b/redisinsight/api/test/api/redisearch/POST-databases-id-redisearch-info.test.ts new file mode 100644 index 0000000000..a70d92e566 --- /dev/null +++ b/redisinsight/api/test/api/redisearch/POST-databases-id-redisearch-info.test.ts @@ -0,0 +1,125 @@ +import { + expect, + describe, + before, + Joi, + deps, + requirements, + generateInvalidDataTestCases, + validateInvalidDataTestCase, + getMainCheckFn, +} from '../deps'; + +const { + server, request, constants, rte, localDb, +} = deps; + +// endpoint to test +const endpoint = (instanceId = constants.TEST_INSTANCE_ID) => request(server) + .post(`/${constants.API.DATABASES}/${instanceId}/redisearch/info`); + +// input data schema +const dataSchema = Joi.object({ + index: Joi.string().required(), +}).strict(); + +const validInputData = { + index: constants.TEST_SEARCH_HASH_INDEX_1, +}; + +const responseSchema = Joi.object({ + index_name: Joi.string().required(), + index_options: Joi.object({}), + index_definition: Joi.object({ + key_type: Joi.string(), + prefixes: Joi.array(), + default_score: Joi.string(), + }), + attributes: Joi.array().items({ + identifier: Joi.string(), + attribute: Joi.string(), + type: Joi.string(), + WEIGHT: Joi.string(), + SORTABLE: Joi.string(), + NOINDEX: Joi.string(), + CASESENSITIVE: Joi.string(), + UNF: Joi.string(), + NOSTEM: Joi.string(), + SEPARATOR: Joi.string(), + }), + num_docs: Joi.string(), + max_doc_id: Joi.string(), + num_terms: Joi.string(), + num_records: Joi.string(), + inverted_sz_mb: Joi.string(), + vector_index_sz_mb: Joi.string(), + total_inverted_index_blocks: Joi.string(), + offset_vectors_sz_mb: Joi.string(), + doc_table_size_mb: Joi.string(), + sortable_values_size_mb: Joi.string(), + tag_overhead_sz_mb: Joi.string(), + text_overhead_sz_mb: Joi.string(), + total_index_memory_sz_mb: Joi.string(), + key_table_size_mb: Joi.string(), + geoshapes_sz_mb: Joi.string(), + records_per_doc_avg: Joi.string(), + bytes_per_record_avg: Joi.string(), + offsets_per_term_avg: Joi.string(), + offset_bits_per_record_avg: Joi.string(), + hash_indexing_failures: Joi.string(), + total_indexing_time: Joi.string(), + indexing: Joi.string(), + percent_indexed: Joi.string(), + number_of_uses: Joi.number(), + cleaning: Joi.number(), + gc_stats: Joi.object(), + cursor_stats: Joi.object(), + dialect_stats: Joi.object(), + 'Index Errors': Joi.object(), + 'field statistics': Joi.array().items({ + identifier: Joi.string(), + attribute: Joi.string(), + 'Index Errors': Joi.object(), + }), +}).required().strict(); +const mainCheckFn = getMainCheckFn(endpoint); + +describe('POST /databases/:id/redisearch/info', () => { + requirements('!rte.bigData', 'rte.modules.search'); + before(async () => { + await rte.data.generateRedisearchIndexes(true); + await localDb.createTestDbInstance(rte, {}, { id: constants.TEST_INSTANCE_ID_2 }); + }); + + describe('Validation', () => { + generateInvalidDataTestCases(dataSchema, validInputData).forEach( + validateInvalidDataTestCase(endpoint, dataSchema), + ); + }); + + describe('Common', () => { + [ + { + name: 'Should get info index', + data: validInputData, + responseSchema, + checkFn: async ({ body }) => { + expect(body.index_name).to.eq(constants.TEST_SEARCH_HASH_INDEX_1); + expect(body.index_definition?.key_type).to.eq('HASH'); + }, + }, + { + name: 'Should throw error if non-existent index provided', + data: { + index: 'Invalid index', + }, + statusCode: 500, + responseBody: { + message: 'Unknown index name', + error: 'Internal Server Error', + statusCode: 500, + }, + }, + ].forEach(mainCheckFn); + }); +}); From c61e3f48f3b4e7a8671fb260664409d2b6fac602 Mon Sep 17 00:00:00 2001 From: Roman Sergeenko Date: Mon, 5 Aug 2024 11:48:13 +0200 Subject: [PATCH 018/256] #RI-5957 - integrate autocomplete to search and query --- .../ui/src/pages/search/SearchPage.tsx | 5 +- .../ui/src/pages/search/components/index.ts | 4 +- .../QueryWrapper.spec.tsx} | 4 +- .../components/query-wrapper/QueryWrapper.tsx | 111 ++++++ .../{query => query-wrapper}/constants.ts | 0 .../search/components/query-wrapper/index.ts | 3 + .../query-wrapper/styles.module.scss | 76 ++++ .../pages/search/components/query/Query.tsx | 346 +++++++++++++---- .../components/query/styles.module.scss | 76 ---- .../pages/search/components/query/types.ts | 22 ++ .../pages/search/components/query/utils.ts | 354 ++++++++++++++++++ 11 files changed, 839 insertions(+), 162 deletions(-) rename redisinsight/ui/src/pages/search/components/{query/Query.spec.tsx => query-wrapper/QueryWrapper.spec.tsx} (56%) create mode 100644 redisinsight/ui/src/pages/search/components/query-wrapper/QueryWrapper.tsx rename redisinsight/ui/src/pages/search/components/{query => query-wrapper}/constants.ts (100%) create mode 100644 redisinsight/ui/src/pages/search/components/query-wrapper/index.ts create mode 100644 redisinsight/ui/src/pages/search/components/query-wrapper/styles.module.scss create mode 100644 redisinsight/ui/src/pages/search/components/query/types.ts create mode 100644 redisinsight/ui/src/pages/search/components/query/utils.ts diff --git a/redisinsight/ui/src/pages/search/SearchPage.tsx b/redisinsight/ui/src/pages/search/SearchPage.tsx index c48219b554..bf6116641c 100644 --- a/redisinsight/ui/src/pages/search/SearchPage.tsx +++ b/redisinsight/ui/src/pages/search/SearchPage.tsx @@ -8,7 +8,7 @@ import { appContextSearchAndQuery, setSQVerticalPanelSizes, } from 'uiSrc/slices/app/context' -import { Query, ResultsHistory } from 'uiSrc/pages/search/components' +import { QueryWrapper, ResultsHistory } from 'uiSrc/pages/search/components' import { sendWbQueryAction } from 'uiSrc/slices/workbench/wb-results' import { formatLongName, getDbIndex, Nullable, setTitle } from 'uiSrc/utils' @@ -16,6 +16,7 @@ import { formatLongName, getDbIndex, Nullable, setTitle } from 'uiSrc/utils' import { connectedInstanceSelector } from 'uiSrc/slices/instances/instances' import { sendPageViewTelemetry, TelemetryPageView } from 'uiSrc/telemetry' import { CodeButtonParams } from 'uiSrc/constants' + import styles from './styles.module.scss' const verticalPanelIds = { @@ -88,7 +89,7 @@ const SearchPage = () => { initialSize={vertical[verticalPanelIds.firstPanelId] ?? 20} style={{ minHeight: '240px', zIndex: '8' }} > - + { it('should render', () => { - expect(render()).toBeTruthy() + expect(render()).toBeTruthy() }) }) diff --git a/redisinsight/ui/src/pages/search/components/query-wrapper/QueryWrapper.tsx b/redisinsight/ui/src/pages/search/components/query-wrapper/QueryWrapper.tsx new file mode 100644 index 0000000000..9850d79545 --- /dev/null +++ b/redisinsight/ui/src/pages/search/components/query-wrapper/QueryWrapper.tsx @@ -0,0 +1,111 @@ +import React, { useEffect, useRef, useState } from 'react' +import { useDispatch, useSelector } from 'react-redux' +import { useParams } from 'react-router-dom' +import { QueryActions, QueryTutorials } from 'uiSrc/components/query' + +import { RunQueryMode } from 'uiSrc/slices/interfaces' +import { CodeButtonParams } from 'uiSrc/constants' + +import { Nullable } from 'uiSrc/utils' +import { changeSQActiveRunQueryMode, searchAndQuerySelector } from 'uiSrc/slices/search/searchAndQuery' +import { appContextSearchAndQuery, setSQVerticalScript } from 'uiSrc/slices/app/context' +import { sendEventTelemetry, TelemetryEvent } from 'uiSrc/telemetry' +import { fetchRedisearchListAction, redisearchListSelector } from 'uiSrc/slices/browser/redisearch' +import { connectedInstanceSelector } from 'uiSrc/slices/instances/instances' +import { TUTORIALS } from './constants' + +import Query from '../query' + +import styles from './styles.module.scss' + +export interface Props { + onSubmit: ( + commandInit: string, + commandId?: Nullable, + executeParams?: CodeButtonParams + ) => void +} + +const QueryWrapper = (props: Props) => { + const { onSubmit } = props + + const { id: connectedIndstanceId } = useSelector(connectedInstanceSelector) + const { script: scriptContext } = useSelector(appContextSearchAndQuery) + const { activeRunQueryMode } = useSelector(searchAndQuerySelector) + const { data: indexes = [] } = useSelector(redisearchListSelector) + const [value, setValue] = useState(scriptContext) + + const input = useRef(null) + const scriptRef = useRef('') + + const { instanceId } = useParams<{ instanceId: string }>() + + const dispatch = useDispatch() + + useEffect(() => () => { + dispatch(setSQVerticalScript(scriptRef.current)) + }, []) + + useEffect(() => { + if (!connectedIndstanceId) return + + // fetch indexes + dispatch(fetchRedisearchListAction()) + }, [connectedIndstanceId]) + + useEffect(() => { + scriptRef.current = value + }, [value]) + + const handleChangeQueryRunMode = () => { + dispatch(changeSQActiveRunQueryMode( + activeRunQueryMode === RunQueryMode.ASCII + ? RunQueryMode.Raw + : RunQueryMode.ASCII + )) + } + + const handleSubmit = () => { + onSubmit(value.split('\n').join(' '), undefined, { mode: activeRunQueryMode }) + sendEventTelemetry({ + event: TelemetryEvent.SEARCH_COMMAND_SUBMITTED, + eventData: { + databaseId: instanceId, + mode: activeRunQueryMode, + // TODO sanitize user query + command: value + } + }) + } + + const handleChange = (val: string) => { + setValue(val) + } + + return ( +
+
{}} + role="textbox" + tabIndex={0} + data-testid="main-input-container-area" + > +
+ +
+
+ + +
+
+
+ ) +} + +export default React.memo(QueryWrapper) diff --git a/redisinsight/ui/src/pages/search/components/query/constants.ts b/redisinsight/ui/src/pages/search/components/query-wrapper/constants.ts similarity index 100% rename from redisinsight/ui/src/pages/search/components/query/constants.ts rename to redisinsight/ui/src/pages/search/components/query-wrapper/constants.ts diff --git a/redisinsight/ui/src/pages/search/components/query-wrapper/index.ts b/redisinsight/ui/src/pages/search/components/query-wrapper/index.ts new file mode 100644 index 0000000000..cf4185d43b --- /dev/null +++ b/redisinsight/ui/src/pages/search/components/query-wrapper/index.ts @@ -0,0 +1,3 @@ +import QueryWrapper from './QueryWrapper' + +export default QueryWrapper diff --git a/redisinsight/ui/src/pages/search/components/query-wrapper/styles.module.scss b/redisinsight/ui/src/pages/search/components/query-wrapper/styles.module.scss new file mode 100644 index 0000000000..18b46e1931 --- /dev/null +++ b/redisinsight/ui/src/pages/search/components/query-wrapper/styles.module.scss @@ -0,0 +1,76 @@ +.wrapper { + position: relative; + height: 100%; + + :global(.editorBounder) { + bottom: 6px; + left: 18px; + right: 46px; + } +} + +.container { + display: flex; + flex-direction: column; + padding: 8px 16px; + width: 100%; + height: 100%; + word-break: break-word; + text-align: left; + letter-spacing: 0; + background-color: var(--rsInputWrapperColor); + color: var(--euiTextSubduedColor) !important; + border: 1px solid var(--euiColorLightShade); +} + +.disabled { + opacity: 0.8; +} + +.disabledActions { + pointer-events: none; + user-select: none; +} + +.containerPlaceholder { + display: flex; + padding: 8px 16px 8px 16px; + width: 100%; + height: 100%; + background-color: var(--rsInputWrapperColor); + color: var(--euiTextSubduedColor) !important; + border: 1px solid var(--euiColorLightShade); + > div { + border: 1px solid var(--euiColorLightShade); + background-color: var(--euiColorEmptyShade); + padding: 8px 20px; + width: 100%; + } +} + +.input { + // cannot use overflow since suggestions are absolute + max-height: calc(100% - 32px); + flex-grow: 1; + width: 100%; + border: 1px solid var(--euiColorLightShade); + background-color: var(--rsInputColor); +} + +.queryFooter { + display: flex; + align-items: center; + justify-content: space-between; + + margin-top: 8px; + flex-shrink: 0; +} + +#script { + font: normal normal bold 14px/17px Inconsolata !important; + color: var(--textColorShade); + caret-color: var(--euiColorFullShade); + min-width: 5px; + display: inline; +} + diff --git a/redisinsight/ui/src/pages/search/components/query/Query.tsx b/redisinsight/ui/src/pages/search/components/query/Query.tsx index f01c7ffe92..ef9cc0768a 100644 --- a/redisinsight/ui/src/pages/search/components/query/Query.tsx +++ b/redisinsight/ui/src/pages/search/components/query/Query.tsx @@ -1,104 +1,290 @@ -import React, { useContext, useEffect, useRef, useState } from 'react' -import MonacoEditor from 'react-monaco-editor' -import { useDispatch, useSelector } from 'react-redux' -import { useParams } from 'react-router-dom' -import { QueryActions, QueryTutorials } from 'uiSrc/components/query' - -import { RunQueryMode } from 'uiSrc/slices/interfaces' -import { CodeButtonParams, defaultMonacoOptions, Theme } from 'uiSrc/constants' +import React, { useContext, useEffect, useRef } from 'react' +import MonacoEditor, { monaco } from 'react-monaco-editor' +import * as monacoEditor from 'monaco-editor' +import { useSelector } from 'react-redux' +import { merge } from 'lodash' +import { defaultMonacoOptions, Theme } from 'uiSrc/constants' import { ThemeContext } from 'uiSrc/contexts/themeContext' - -import { Nullable } from 'uiSrc/utils' -import { changeSQActiveRunQueryMode, searchAndQuerySelector } from 'uiSrc/slices/search/searchAndQuery' -import { appContextSearchAndQuery, setSQVerticalScript } from 'uiSrc/slices/app/context' -import { sendEventTelemetry, TelemetryEvent } from 'uiSrc/telemetry' -import { TUTORIALS } from './constants' - -import styles from './styles.module.scss' +import { appRedisCommandsSelector } from 'uiSrc/slices/app/redis-commands' +import { bufferToString, formatLongName, getCommandMarkdown, Nullable } from 'uiSrc/utils' +import { IEditorMount } from 'uiSrc/pages/workbench/interfaces' +import { + buildSuggestion, + findCurrentArgument, + generateDetail, + getRange, + splitQueryByArgs +} from 'uiSrc/pages/search/components/query/utils' +import { SearchCommand, TokenType } from 'uiSrc/pages/search/components/query/types' +import { RedisResponseBuffer } from 'uiSrc/slices/interfaces' export interface Props { - onSubmit: ( - commandInit: string, - commandId?: Nullable, - executeParams?: CodeButtonParams - ) => void + value: string + onChange: (val: string) => void + indexes: RedisResponseBuffer[] } -const options = { ...defaultMonacoOptions } +const options = merge(defaultMonacoOptions, + { + suggest: { + showWords: false, + showIcons: true + } + }) + +const SUPPORTED_COMMANDS_LIST = ['FT.SEARCH', 'FT.AGGREGATE'] const Query = (props: Props) => { - const { onSubmit } = props + const { value, onChange, indexes } = props + const { spec: REDIS_COMMANDS_SPEC } = useSelector(appRedisCommandsSelector) - const { script: scriptContext } = useSelector(appContextSearchAndQuery) - const { activeRunQueryMode } = useSelector(searchAndQuerySelector) - const [value, setValue] = useState(scriptContext) + const SUPPORTED_COMMANDS = SUPPORTED_COMMANDS_LIST.map((name) => ({ + ...REDIS_COMMANDS_SPEC[name], + name + })) as unknown as SearchCommand[] - const { theme } = useContext(ThemeContext) - const input = useRef(null) - const scriptRef = useRef('') + const monacoObjects = useRef>(null) + const disposeCompletionItemProvider = useRef(() => {}) + const disposeSignatureHelpProvider = useRef(() => {}) + const suggestionsRef = useRef([]) + const helpWidgetRef = useRef({ + isOpen: false, + parent: null, + currentArg: null + }) + const indexesRef = useRef([]) - const { instanceId } = useParams<{ instanceId: string }>() + const { theme } = useContext(ThemeContext) - const dispatch = useDispatch() + useEffect(() => { + monaco.languages.register({ id: 'RediSearch' }) - useEffect(() => () => { - dispatch(setSQVerticalScript(scriptRef.current)) + return () => { + disposeCompletionItemProvider.current?.() + disposeSignatureHelpProvider.current?.() + } }, []) useEffect(() => { - scriptRef.current = value - }, [value]) - - const handleChangeQueryRunMode = () => { - dispatch(changeSQActiveRunQueryMode( - activeRunQueryMode === RunQueryMode.ASCII - ? RunQueryMode.Raw - : RunQueryMode.ASCII - )) - } + indexesRef.current = indexes + }, [indexes]) + + const editorDidMount = ( + editor: monacoEditor.editor.IStandaloneCodeEditor, + monaco: typeof monacoEditor + ) => { + monacoObjects.current = { editor, monaco } + + suggestionsRef.current = getSuggestions(editor) + triggerSuggestions() + + disposeSignatureHelpProvider.current?.() + disposeSignatureHelpProvider.current = monaco.languages.registerSignatureHelpProvider( + 'RediSearch', + { + provideSignatureHelp: (): any => { + if (!helpWidgetRef.current?.isOpen) return null + + const { currentArg, parent } = helpWidgetRef.current + const label = generateDetail(parent) + const arg = currentArg?.type === TokenType.Block ? currentArg.arguments[0]?.name : (currentArg?.name || currentArg?.type || '') + + return { + dispose: () => {}, + value: { + activeParameter: 0, + activeSignature: 0, + signatures: [{ + label: label || '', + parameters: [{ label: arg }] + }] + } + } + } + } + ).dispose - const handleSubmit = () => { - onSubmit(value, undefined, { mode: activeRunQueryMode }) - sendEventTelemetry({ - event: TelemetryEvent.SEARCH_COMMAND_SUBMITTED, - eventData: { - databaseId: instanceId, - mode: activeRunQueryMode, - // TODO sanitize user query - command: value + disposeCompletionItemProvider.current?.() + disposeCompletionItemProvider.current = monaco.languages.registerCompletionItemProvider( + 'RediSearch', + { + provideCompletionItems: (): monacoEditor.languages.CompletionList => ({ suggestions: suggestionsRef.current }) } + ).dispose + + editor.onDidChangeCursorPosition(() => { + suggestionsRef.current = [] + + if (!editor.getSelection()?.isEmpty()) { + setTimeout(() => editor?.trigger('', 'hideSuggestWidget', null), 0) + return + } + + suggestionsRef.current = getSuggestions(editor) + + if (suggestionsRef.current?.length) { + triggerSuggestions() + helpWidgetRef.current.isOpen = false + return + } + + setTimeout(() => editor?.trigger('', 'hideSuggestWidget', null), 0) + editor?.trigger('', 'editor.action.triggerParameterHints', '') }) } + const getIndexesSuggestions = (range: monaco.IRange) => indexesRef.current.map((index) => { + const value = formatLongName(bufferToString(index)) + + return { + label: value, + kind: monacoEditor.languages.CompletionItemKind.Snippet, + insertText: `"${value}" "$1" `, + insertTextRules: monacoEditor.languages.CompletionItemInsertTextRule.InsertAsSnippet, + range, + } + }) + + const getFieldsSuggestions = (range: monaco.IRange, spaceAfter = false) => ['field1', 'field2'].map((field) => ({ + label: field, + kind: monacoEditor.languages.CompletionItemKind.Reference, + insertText: `${field}${spaceAfter ? ' ' : ''}`, + insertTextRules: monacoEditor.languages.CompletionItemInsertTextRule.InsertAsSnippet, + range, + })) + + const triggerSuggestions = () => { + const { monaco, editor } = monacoObjects.current || {} + if (!monaco) return + + setTimeout(() => editor?.trigger('', 'editor.action.triggerSuggest', { auto: false })) + } + + const getSuggestions = ( + editor: monacoEditor.editor.IStandaloneCodeEditor + ): monacoEditor.languages.CompletionItem[] => { + const position = editor.getPosition() + const model = editor.getModel() + + if (!position || !model) return [] + + const value = editor.getValue() + const offset = model.getOffsetAt(position) + const word = model.getWordUntilPosition(position) + const range = getRange(position, word) + + const { args, isCursorInArg, prevCursorChar, nextCursorChar } = splitQueryByArgs(value, offset) + const [beforeOffsetArgs] = args + const [firstArg, ...prevArgs] = beforeOffsetArgs + + const commandName = firstArg?.toUpperCase() + const command = REDIS_COMMANDS_SPEC[commandName] as unknown as SearchCommand + + if (!command && position.lineNumber === 1 && word.startColumn === 1) { + return SUPPORTED_COMMANDS.map((command) => buildSuggestion( + command, + range, + { + detail: generateDetail(command), + documentation: { + value: getCommandMarkdown(command as any) + }, + } + )) + } + + if (!command) return [] + + // cover query + if (command?.arguments?.[prevArgs.length]?.name === 'query') { + if (prevCursorChar === '@') { + return getFieldsSuggestions(range) + } + + return [] + } + + if (isCursorInArg || nextCursorChar?.trim()) return [] + + // just suggest indexes - in future get from BE + if (prevArgs.length === 0 && command?.arguments?.[0]?.name === 'index') { + return getIndexesSuggestions(range) + } + + if (prevArgs.length < 2) return [] + const foundArg = findCurrentArgument(command?.arguments || [], prevArgs) + + console.log('foundArg', foundArg) + helpWidgetRef.current = { + isOpen: !!foundArg?.stopArg, + parent: foundArg?.parent, + currentArg: foundArg?.stopArg + } + + // here we suggest arguments of argument + if (foundArg && !foundArg.isComplete) { + if (foundArg.stopArg?.name === 'field') { + return getFieldsSuggestions(range, true) + } + + if (foundArg.isBlocked) return [] + if (foundArg.append?.length) { + return foundArg.append.map((arg: any) => buildSuggestion( + arg, + range, + { + kind: monacoEditor.languages.CompletionItemKind.Property, + detail: generateDetail(foundArg?.parent) + } + )) + } + + return [] + } + + // the main list of arguments + optional from argument + // TODO: remove arguments which already used if they are not multiple + if (!foundArg || foundArg.isComplete) { + // here we can add append arguments + const appendCommands = foundArg?.append ?? [] + + return [ + ...appendCommands.map((arg: any) => buildSuggestion( + arg, + range, + { + sortText: 'a', + kind: monacoEditor.languages.CompletionItemKind.Property, + detail: generateDetail(foundArg?.parent) + } + )), + ...(command.arguments || []) + .filter((arg) => arg.optional) + .filter((arg) => arg.multiple || !args.flat().includes(arg.token || arg.arguments?.[0]?.token || '')) + .map((arg: any) => buildSuggestion( + arg, + range, + { + sortText: 'b', + kind: monacoEditor.languages.CompletionItemKind.Reference, + detail: generateDetail(arg) + } + )) + ] + } + + return [] + } + return ( -
-
{}} - role="textbox" - tabIndex={0} - data-testid="main-input-container-area" - > -
- setValue(val)} - language="RediSearch" - theme={theme === Theme.Dark ? 'dark' : 'light'} - options={options} - /> -
-
- - -
-
-
+ ) } diff --git a/redisinsight/ui/src/pages/search/components/query/styles.module.scss b/redisinsight/ui/src/pages/search/components/query/styles.module.scss index 18b46e1931..e69de29bb2 100644 --- a/redisinsight/ui/src/pages/search/components/query/styles.module.scss +++ b/redisinsight/ui/src/pages/search/components/query/styles.module.scss @@ -1,76 +0,0 @@ -.wrapper { - position: relative; - height: 100%; - - :global(.editorBounder) { - bottom: 6px; - left: 18px; - right: 46px; - } -} - -.container { - display: flex; - flex-direction: column; - padding: 8px 16px; - width: 100%; - height: 100%; - word-break: break-word; - text-align: left; - letter-spacing: 0; - background-color: var(--rsInputWrapperColor); - color: var(--euiTextSubduedColor) !important; - border: 1px solid var(--euiColorLightShade); -} - -.disabled { - opacity: 0.8; -} - -.disabledActions { - pointer-events: none; - user-select: none; -} - -.containerPlaceholder { - display: flex; - padding: 8px 16px 8px 16px; - width: 100%; - height: 100%; - background-color: var(--rsInputWrapperColor); - color: var(--euiTextSubduedColor) !important; - border: 1px solid var(--euiColorLightShade); - > div { - border: 1px solid var(--euiColorLightShade); - background-color: var(--euiColorEmptyShade); - padding: 8px 20px; - width: 100%; - } -} - -.input { - // cannot use overflow since suggestions are absolute - max-height: calc(100% - 32px); - flex-grow: 1; - width: 100%; - border: 1px solid var(--euiColorLightShade); - background-color: var(--rsInputColor); -} - -.queryFooter { - display: flex; - align-items: center; - justify-content: space-between; - - margin-top: 8px; - flex-shrink: 0; -} - -#script { - font: normal normal bold 14px/17px Inconsolata !important; - color: var(--textColorShade); - caret-color: var(--euiColorFullShade); - min-width: 5px; - display: inline; -} - diff --git a/redisinsight/ui/src/pages/search/components/query/types.ts b/redisinsight/ui/src/pages/search/components/query/types.ts new file mode 100644 index 0000000000..d1552818de --- /dev/null +++ b/redisinsight/ui/src/pages/search/components/query/types.ts @@ -0,0 +1,22 @@ +export enum TokenType { + PureToken = 'pure-token', + Block = 'block', + OneOf = 'oneof' +} + +export enum ArgName { + NArgs = 'nargs' +} + +export interface SearchCommand { + name?: string + type?: TokenType + token?: string + optional?: boolean + multiple?: boolean + arguments?: SearchCommand[] +} + +export interface SearchCommandTree extends SearchCommand { + parent?: SearchCommandTree +} diff --git a/redisinsight/ui/src/pages/search/components/query/utils.ts b/redisinsight/ui/src/pages/search/components/query/utils.ts new file mode 100644 index 0000000000..26e0436f72 --- /dev/null +++ b/redisinsight/ui/src/pages/search/components/query/utils.ts @@ -0,0 +1,354 @@ +/* eslint-disable no-continue */ + +import * as monacoEditor from 'monaco-editor' +import { monaco } from 'react-monaco-editor' +import { isString, toNumber } from 'lodash' +import { generateArgsNames, Maybe, Nullable } from 'uiSrc/utils' +import { CommandProvider } from 'uiSrc/constants' +import { ArgName, SearchCommand, SearchCommandTree, TokenType } from './types' + +export const buildSuggestion = (arg: SearchCommand, range: monaco.IRange, options: any = {}) => ({ + label: isString(arg) ? arg : arg.token || arg.arguments?.[0].token || arg.name || '', + insertText: `${arg.token || arg.arguments?.[0].token || arg.name?.toUpperCase() || ''} `, + insertTextRules: monacoEditor.languages.CompletionItemInsertTextRule.InsertAsSnippet, + range, + kind: options?.kind || monacoEditor.languages.CompletionItemKind.Function, + ...options, +}) + +export const splitQueryByArgs = (query: string, position: number = 0) => { + const args: [string[], string[]] = [[], []] + let arg = '' + let inQuotes = false + let escapeNextChar = false + let quoteChar = '' + const isCursorInArg = false + let lastArg = '' + + const pushToProperTuple = (isAfterOffset: boolean, arg: string) => { + lastArg = arg + isAfterOffset ? args[1].push(arg) : args[0].push(arg) + } + + const updateLastArgument = (isAfterOffset: boolean, arg: string) => { + const argsBySide = args[isAfterOffset ? 1 : 0] + argsBySide[argsBySide.length - 1] = `${argsBySide[argsBySide.length - 1]} ${arg}` + } + + for (let i = 0; i < query.length; i++) { + const char = query[i] + const isAfterOffset = i >= position + (inQuotes ? -1 : 0) + + if (escapeNextChar) { + arg += char + escapeNextChar = !quoteChar + } else if (char === '\\') { + escapeNextChar = true + } else if (inQuotes) { + if (char === quoteChar) { + inQuotes = false + const argWithChat = arg + char + + if (isCompositeArgument(argWithChat, lastArg)) { + updateLastArgument(isAfterOffset, argWithChat) + } else { + pushToProperTuple(isAfterOffset, argWithChat) + } + + arg = '' + } else { + arg += char + } + } else if (char === '"' || char === "'") { + inQuotes = true + quoteChar = char + arg += char + } else if (char === ' ' || char === '\n') { + if (arg.length > 0) { + if (isCompositeArgument(arg, lastArg)) { + updateLastArgument(isAfterOffset, arg) + } else { + pushToProperTuple(isAfterOffset, arg) + } + + arg = '' + } + } else { + arg += char + } + } + + if (arg.length > 0) { + pushToProperTuple(true, arg) + } + + return { args, isCursorInArg, prevCursorChar: query[position - 1], nextCursorChar: query[position] } +} + +export const getRange = (position: monaco.Position, word: monaco.editor.IWordAtPosition): monaco.IRange => ({ + startLineNumber: position.lineNumber, + endLineNumber: position.lineNumber, + endColumn: word.endColumn, + startColumn: word.startColumn, +}) + +export const findCurrentArgument = ( + args: SearchCommand[], + prev: string[], + parent?: SearchCommandTree +): Nullable<{ + isComplete: boolean + stopArg: Maybe, + isBlocked: boolean, + append: Maybe[], + parent: Maybe +}> => { + for (let i = prev.length - 1; i >= 0; i--) { + const arg = prev[i] + const currentArg = findArgByToken(args, arg) + const currentWithParent: SearchCommandTree = { ...currentArg, parent } + + if (currentArg?.arguments && currentArg?.type === TokenType.Block) { + return findCurrentArgument(currentArg.arguments, prev.slice(i), currentWithParent) + } + + const tokenIndex = args.findIndex((cArg) => + (cArg.type === TokenType.OneOf + ? cArg.arguments?.some((oneOfArg) => oneOfArg.token?.toLowerCase() === arg.toLowerCase()) + : cArg.token?.toLowerCase() === arg.toLowerCase())) + const token = args[tokenIndex] + + if (token) { + const pastArgs = prev.slice(i) + const commandArgs = parent ? args.slice(tokenIndex, args.length) : [token] + + // getArgByRest - here we preparing the list of arguments which can be inserted, + // this is the main function which creates the list of arguments + return { + ...getArgumentSuggestions(pastArgs, commandArgs, parent), + parent: parent || token + } + } + } + + return null +} + +const findStopArgumentInQuery = ( + queryArgs: string[], + restCommandArgs: Maybe = [], +): { + restArguments: SearchCommand[] + stopArgIndex: number + isBlocked: boolean +} => { + let currentCommandArgIndex = 0 + let isBlockedOnCommand = false + let multipleIndexStart = 0 + + const moveToNextCommandArg = () => currentCommandArgIndex++ + const blockCommand = () => { isBlockedOnCommand = true } + const unBlockCommand = () => { isBlockedOnCommand = false } + + const skipArg = () => { + moveToNextCommandArg() + unBlockCommand() + } + + for (let i = 0; i < queryArgs.length; i++) { + const arg = queryArgs[i] + const currentCommandArg = restCommandArgs[currentCommandArgIndex] + + if (currentCommandArg?.type === TokenType.PureToken) { + skipArg() + continue + } + + // if we are on token - that requires one more argument + if (currentCommandArg?.token === arg.toUpperCase()) { + blockCommand() + continue + } + + if (currentCommandArg?.type === TokenType.Block) { + // if block is multiple - we duplicate nArgs inner arguments + let blockArguments = currentCommandArg.arguments + + if (currentCommandArg?.multiple) { + const nArgs = toNumber(queryArgs[i - 1]) || 0 + blockArguments = Array(nArgs).fill(currentCommandArg.arguments).flat() + } + + const blockSuggestion = findStopArgumentInQuery(queryArgs.slice(i), blockArguments) + const stopArg = blockSuggestion.restArguments?.[blockSuggestion.stopArgIndex] + if (blockSuggestion.isBlocked || stopArg) return blockSuggestion + + i += queryArgs.slice(i).length - 1 + skipArg() + continue + } + + if (currentCommandArg?.name === ArgName.NArgs) { + const numberOfArgs = toNumber(arg) + + if (numberOfArgs === 0) { + moveToNextCommandArg() + skipArg() + continue + } + + moveToNextCommandArg() + blockCommand() + continue + } + + if (currentCommandArg?.type === TokenType.OneOf && currentCommandArg?.optional) { + // if oneof is optional then we can switch to another argument + if (!currentCommandArg?.arguments?.some(({ token }) => token === arg)) { + moveToNextCommandArg() + } + + skipArg() + continue + } + + if (currentCommandArg?.multiple) { + const numberOfArgs = toNumber(queryArgs[currentCommandArgIndex]) || 0 + + if (!multipleIndexStart) multipleIndexStart = currentCommandArgIndex + if (i - multipleIndexStart >= numberOfArgs) { + skipArg() + continue + } + + blockCommand() + continue + } + + moveToNextCommandArg() + + const nextCommand = restCommandArgs[currentCommandArgIndex + 1] + isBlockedOnCommand = (!!nextCommand && !nextCommand.optional) + } + + return { + restArguments: restCommandArgs, + stopArgIndex: currentCommandArgIndex, + isBlocked: isBlockedOnCommand + } +} + +export const getArgumentSuggestions = ( + pastStringArgs: string[], + pastCommandArgs: SearchCommand[], + current?: SearchCommandTree +): { + isComplete: boolean + stopArg: Maybe, + isBlocked: boolean, + append: Maybe[], +} => { + const { + restArguments, + stopArgIndex, + isBlocked: isWasBlocked + } = findStopArgumentInQuery(pastStringArgs, pastCommandArgs) + + // TODO refactor to early return related to where we stopped + + const stopArgument = restArguments[stopArgIndex] + const restNotFilledArgs = restArguments.slice(stopArgIndex) + const isBlocked = isWasBlocked || (stopArgument && !(stopArgument.token || stopArgument?.arguments?.length)) + const restParentOptionalSuggestions = !stopArgument || stopArgument?.optional + ? getRestParentArguments(current?.parent, current?.name, current?.multiple) + .filter((arg) => arg.optional) + .filter((arg) => arg.name !== current?.name) + : [] + + const restOptionalSuggestions = fillArgsByType([...restNotFilledArgs, ...restParentOptionalSuggestions]) + const isOneOfArgument = stopArgument?.type === TokenType.OneOf + || (stopArgument?.type === TokenType.PureToken && current?.parent?.type === TokenType.OneOf) + const isArgSuggestions = stopArgument && !stopArgument.optional && (stopArgument?.token || isOneOfArgument) + + const suggestions = isArgSuggestions + // only 1 suggestion since next arg is required + ? [isOneOfArgument ? stopArgument.arguments : stopArgument].flat() + : !isBlocked + ? restOptionalSuggestions + : [] + + const requiredArgsLength = restNotFilledArgs.filter((arg) => !arg.optional).length + + return { + isComplete: requiredArgsLength === 0 && !isBlocked, + stopArg: stopArgument, + isBlocked: isBlocked && !isOneOfArgument, + append: suggestions, + } +} + +export const getRestParentArguments = ( + parent?: SearchCommandTree, + currentArgName?: string, + isIncludeOwn: boolean = true, + prevArgs: SearchCommand[] = [] +): SearchCommand[] => { + if (!currentArgName) return [] + + const currentArgIndex = parent?.arguments?.findIndex((arg) => arg?.name === currentArgName) + if (!currentArgIndex) return prevArgs + + const currentRestArgs = parent?.arguments?.slice(currentArgIndex + (isIncludeOwn ? 0 : 1)) || [] + + if (parent?.parent) return getRestParentArguments(parent.parent, parent.name, true, currentRestArgs) + + return [...currentRestArgs, ...prevArgs] +} + +export const fillArgsByType = (args: SearchCommand[]) => { + const result = [] + + for (let i = 0; i < args.length; i++) { + const currentArg = args[i] + + if (currentArg.type === TokenType.OneOf) { + result.push(...(currentArg?.arguments || [])) + } + + if (currentArg.type === TokenType.Block) { + result.push(currentArg.arguments?.[0]) + } + + if (currentArg.token) { + result.push(currentArg) + } + } + + return result +} + +export const findArgByToken = (list: SearchCommand[], arg: string): Maybe => + list.find((cArg) => + (cArg.type === TokenType.OneOf + ? cArg.arguments?.some((oneOfArg) => oneOfArg?.token?.toLowerCase() === arg?.toLowerCase()) + : cArg.arguments?.[0]?.token?.toLowerCase() === arg.toLowerCase())) + +export const isCompositeArgument = (arg: string, prevArg?: string) => arg === '*' && prevArg === 'LOAD' + +export const generateDetail = (command: Maybe) => { + if (!command) return '' + + if (command.arguments) { + return generateArgsNames(CommandProvider.Main, command.arguments).join(' ') + } + + if (command.token) { + if (command.type === TokenType.PureToken) { + return command.token + } + + return `${command.token} ${command.name}` + } + + return '' +} From 00f546ad1df850a9b2a1ddcd211cdae08715b51f Mon Sep 17 00:00:00 2001 From: Roman Sergeenko Date: Mon, 5 Aug 2024 12:40:16 +0200 Subject: [PATCH 019/256] #RI-5957 - add monaco lang id --- redisinsight/ui/src/constants/monaco/monaco.ts | 1 + redisinsight/ui/src/pages/search/components/query/Query.tsx | 6 +++--- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/redisinsight/ui/src/constants/monaco/monaco.ts b/redisinsight/ui/src/constants/monaco/monaco.ts index fad4f5528c..a8eea653d4 100644 --- a/redisinsight/ui/src/constants/monaco/monaco.ts +++ b/redisinsight/ui/src/constants/monaco/monaco.ts @@ -39,6 +39,7 @@ export enum MonacoLanguage { JMESPath = 'jmespathLanguage', SQLiteFunctions = 'sqliteFunctions', Text = 'text', + RediSearch = 'redisearch', } export const defaultMonacoOptions: monacoEditor.editor.IStandaloneEditorConstructionOptions = { diff --git a/redisinsight/ui/src/pages/search/components/query/Query.tsx b/redisinsight/ui/src/pages/search/components/query/Query.tsx index ef9cc0768a..0b000a3452 100644 --- a/redisinsight/ui/src/pages/search/components/query/Query.tsx +++ b/redisinsight/ui/src/pages/search/components/query/Query.tsx @@ -3,7 +3,7 @@ import MonacoEditor, { monaco } from 'react-monaco-editor' import * as monacoEditor from 'monaco-editor' import { useSelector } from 'react-redux' import { merge } from 'lodash' -import { defaultMonacoOptions, Theme } from 'uiSrc/constants' +import { defaultMonacoOptions, MonacoLanguage, Theme } from 'uiSrc/constants' import { ThemeContext } from 'uiSrc/contexts/themeContext' import { appRedisCommandsSelector } from 'uiSrc/slices/app/redis-commands' import { bufferToString, formatLongName, getCommandMarkdown, Nullable } from 'uiSrc/utils' @@ -57,7 +57,7 @@ const Query = (props: Props) => { const { theme } = useContext(ThemeContext) useEffect(() => { - monaco.languages.register({ id: 'RediSearch' }) + monaco.languages.register({ id: MonacoLanguage.RediSearch }) return () => { disposeCompletionItemProvider.current?.() @@ -280,7 +280,7 @@ const Query = (props: Props) => { Date: Mon, 5 Aug 2024 13:46:09 +0200 Subject: [PATCH 020/256] #RI-5957 - refactor, fix tests --- .../pages/search/components/query/Query.tsx | 197 ++++++------------ .../search/components/query/constants.ts | 12 ++ .../search/{components/query => }/types.ts | 0 .../ui/src/pages/search/utils/index.ts | 2 + .../ui/src/pages/search/utils/monaco.ts | 74 +++++++ .../query/utils.ts => utils/query.ts} | 26 +-- 6 files changed, 155 insertions(+), 156 deletions(-) create mode 100644 redisinsight/ui/src/pages/search/components/query/constants.ts rename redisinsight/ui/src/pages/search/{components/query => }/types.ts (100%) create mode 100644 redisinsight/ui/src/pages/search/utils/index.ts create mode 100644 redisinsight/ui/src/pages/search/utils/monaco.ts rename redisinsight/ui/src/pages/search/{components/query/utils.ts => utils/query.ts} (90%) diff --git a/redisinsight/ui/src/pages/search/components/query/Query.tsx b/redisinsight/ui/src/pages/search/components/query/Query.tsx index 0b000a3452..dcd2d39352 100644 --- a/redisinsight/ui/src/pages/search/components/query/Query.tsx +++ b/redisinsight/ui/src/pages/search/components/query/Query.tsx @@ -1,22 +1,23 @@ import React, { useContext, useEffect, useRef } from 'react' -import MonacoEditor, { monaco } from 'react-monaco-editor' -import * as monacoEditor from 'monaco-editor' +import MonacoEditor, { monaco as monacoEditor } from 'react-monaco-editor' import { useSelector } from 'react-redux' -import { merge } from 'lodash' -import { defaultMonacoOptions, MonacoLanguage, Theme } from 'uiSrc/constants' + +import { MonacoLanguage, Theme } from 'uiSrc/constants' import { ThemeContext } from 'uiSrc/contexts/themeContext' import { appRedisCommandsSelector } from 'uiSrc/slices/app/redis-commands' -import { bufferToString, formatLongName, getCommandMarkdown, Nullable } from 'uiSrc/utils' +import { getCommandMarkdown, Nullable } from 'uiSrc/utils' import { IEditorMount } from 'uiSrc/pages/workbench/interfaces' import { buildSuggestion, findCurrentArgument, - generateDetail, + generateDetail, getFieldsSuggestions, getIndexesSuggestions, getRange, + getRediSearchSignutureProvider, splitQueryByArgs -} from 'uiSrc/pages/search/components/query/utils' -import { SearchCommand, TokenType } from 'uiSrc/pages/search/components/query/types' +} from 'uiSrc/pages/search/utils' +import { SearchCommand } from 'uiSrc/pages/search/types' import { RedisResponseBuffer } from 'uiSrc/slices/interfaces' +import { SUPPORTED_COMMANDS_LIST, options } from './constants' export interface Props { value: string @@ -24,16 +25,6 @@ export interface Props { indexes: RedisResponseBuffer[] } -const options = merge(defaultMonacoOptions, - { - suggest: { - showWords: false, - showIcons: true - } - }) - -const SUPPORTED_COMMANDS_LIST = ['FT.SEARCH', 'FT.AGGREGATE'] - const Query = (props: Props) => { const { value, onChange, indexes } = props const { spec: REDIS_COMMANDS_SPEC } = useSelector(appRedisCommandsSelector) @@ -56,13 +47,9 @@ const Query = (props: Props) => { const { theme } = useContext(ThemeContext) - useEffect(() => { - monaco.languages.register({ id: MonacoLanguage.RediSearch }) - - return () => { - disposeCompletionItemProvider.current?.() - disposeSignatureHelpProvider.current?.() - } + useEffect(() => () => { + disposeCompletionItemProvider.current?.() + disposeSignatureHelpProvider.current?.() }, []) useEffect(() => { @@ -73,85 +60,47 @@ const Query = (props: Props) => { editor: monacoEditor.editor.IStandaloneCodeEditor, monaco: typeof monacoEditor ) => { + monaco.languages.register({ id: MonacoLanguage.RediSearch }) monacoObjects.current = { editor, monaco } suggestionsRef.current = getSuggestions(editor) triggerSuggestions() disposeSignatureHelpProvider.current?.() - disposeSignatureHelpProvider.current = monaco.languages.registerSignatureHelpProvider( - 'RediSearch', - { - provideSignatureHelp: (): any => { - if (!helpWidgetRef.current?.isOpen) return null - - const { currentArg, parent } = helpWidgetRef.current - const label = generateDetail(parent) - const arg = currentArg?.type === TokenType.Block ? currentArg.arguments[0]?.name : (currentArg?.name || currentArg?.type || '') - - return { - dispose: () => {}, - value: { - activeParameter: 0, - activeSignature: 0, - signatures: [{ - label: label || '', - parameters: [{ label: arg }] - }] - } - } - } - } - ).dispose + disposeSignatureHelpProvider.current = monaco.languages.registerSignatureHelpProvider(MonacoLanguage.RediSearch, { + provideSignatureHelp: (): any => getRediSearchSignutureProvider(helpWidgetRef?.current) + }).dispose disposeCompletionItemProvider.current?.() - disposeCompletionItemProvider.current = monaco.languages.registerCompletionItemProvider( - 'RediSearch', - { - provideCompletionItems: (): monacoEditor.languages.CompletionList => ({ suggestions: suggestionsRef.current }) - } - ).dispose - - editor.onDidChangeCursorPosition(() => { - suggestionsRef.current = [] + disposeCompletionItemProvider.current = monaco.languages.registerCompletionItemProvider(MonacoLanguage.RediSearch, { + provideCompletionItems: (): monacoEditor.languages.CompletionList => ({ suggestions: suggestionsRef.current }) + }).dispose - if (!editor.getSelection()?.isEmpty()) { - setTimeout(() => editor?.trigger('', 'hideSuggestWidget', null), 0) - return - } + editor.onDidChangeCursorPosition(handleCursorChange) + } - suggestionsRef.current = getSuggestions(editor) + const handleCursorChange = () => { + const { editor } = monacoObjects.current || {} + suggestionsRef.current = [] - if (suggestionsRef.current?.length) { - triggerSuggestions() - helpWidgetRef.current.isOpen = false - return - } + if (!editor) return + if (!editor.getSelection()?.isEmpty()) { setTimeout(() => editor?.trigger('', 'hideSuggestWidget', null), 0) - editor?.trigger('', 'editor.action.triggerParameterHints', '') - }) - } + return + } - const getIndexesSuggestions = (range: monaco.IRange) => indexesRef.current.map((index) => { - const value = formatLongName(bufferToString(index)) + suggestionsRef.current = getSuggestions(editor) - return { - label: value, - kind: monacoEditor.languages.CompletionItemKind.Snippet, - insertText: `"${value}" "$1" `, - insertTextRules: monacoEditor.languages.CompletionItemInsertTextRule.InsertAsSnippet, - range, + if (suggestionsRef.current?.length) { + triggerSuggestions() + helpWidgetRef.current.isOpen = false + return } - }) - const getFieldsSuggestions = (range: monaco.IRange, spaceAfter = false) => ['field1', 'field2'].map((field) => ({ - label: field, - kind: monacoEditor.languages.CompletionItemKind.Reference, - insertText: `${field}${spaceAfter ? ' ' : ''}`, - insertTextRules: monacoEditor.languages.CompletionItemInsertTextRule.InsertAsSnippet, - range, - })) + setTimeout(() => editor?.trigger('', 'hideSuggestWidget', null), 0) + editor?.trigger('', 'editor.action.triggerParameterHints', '') + } const triggerSuggestions = () => { const { monaco, editor } = monacoObjects.current || {} @@ -181,16 +130,12 @@ const Query = (props: Props) => { const command = REDIS_COMMANDS_SPEC[commandName] as unknown as SearchCommand if (!command && position.lineNumber === 1 && word.startColumn === 1) { - return SUPPORTED_COMMANDS.map((command) => buildSuggestion( - command, - range, - { - detail: generateDetail(command), - documentation: { - value: getCommandMarkdown(command as any) - }, - } - )) + return SUPPORTED_COMMANDS.map((command) => buildSuggestion(command, range, { + detail: generateDetail(command), + documentation: { + value: getCommandMarkdown(command as any) + }, + })) } if (!command) return [] @@ -198,7 +143,7 @@ const Query = (props: Props) => { // cover query if (command?.arguments?.[prevArgs.length]?.name === 'query') { if (prevCursorChar === '@') { - return getFieldsSuggestions(range) + return getFieldsSuggestions(['field1', 'field2'], range) } return [] @@ -206,70 +151,54 @@ const Query = (props: Props) => { if (isCursorInArg || nextCursorChar?.trim()) return [] - // just suggest indexes - in future get from BE - if (prevArgs.length === 0 && command?.arguments?.[0]?.name === 'index') { - return getIndexesSuggestions(range) + // cover index field + if (command?.arguments?.[prevArgs.length]?.name === 'index') { + return getIndexesSuggestions(indexesRef.current, range) } if (prevArgs.length < 2) return [] const foundArg = findCurrentArgument(command?.arguments || [], prevArgs) - console.log('foundArg', foundArg) helpWidgetRef.current = { isOpen: !!foundArg?.stopArg, parent: foundArg?.parent, currentArg: foundArg?.stopArg } - // here we suggest arguments of argument + // suggest arguments of argument if (foundArg && !foundArg.isComplete) { if (foundArg.stopArg?.name === 'field') { - return getFieldsSuggestions(range, true) + return getFieldsSuggestions(['field1', 'field2'], range, true) } if (foundArg.isBlocked) return [] if (foundArg.append?.length) { - return foundArg.append.map((arg: any) => buildSuggestion( - arg, - range, - { - kind: monacoEditor.languages.CompletionItemKind.Property, - detail: generateDetail(foundArg?.parent) - } - )) + return foundArg.append.map((arg: any) => buildSuggestion(arg, range, { + kind: monacoEditor.languages.CompletionItemKind.Property, + detail: generateDetail(foundArg?.parent) + })) } return [] } - // the main list of arguments + optional from argument - // TODO: remove arguments which already used if they are not multiple if (!foundArg || foundArg.isComplete) { - // here we can add append arguments const appendCommands = foundArg?.append ?? [] return [ - ...appendCommands.map((arg: any) => buildSuggestion( - arg, - range, - { - sortText: 'a', - kind: monacoEditor.languages.CompletionItemKind.Property, - detail: generateDetail(foundArg?.parent) - } - )), - ...(command.arguments || []) + ...appendCommands.map((arg: any) => buildSuggestion(arg, range, { + sortText: 'a', + kind: monacoEditor.languages.CompletionItemKind.Property, + detail: generateDetail(foundArg?.parent) + })), + ...(command?.arguments || []) .filter((arg) => arg.optional) .filter((arg) => arg.multiple || !args.flat().includes(arg.token || arg.arguments?.[0]?.token || '')) - .map((arg: any) => buildSuggestion( - arg, - range, - { - sortText: 'b', - kind: monacoEditor.languages.CompletionItemKind.Reference, - detail: generateDetail(arg) - } - )) + .map((arg: any) => buildSuggestion(arg, range, { + sortText: 'b', + kind: monacoEditor.languages.CompletionItemKind.Reference, + detail: generateDetail(arg) + })) ] } diff --git a/redisinsight/ui/src/pages/search/components/query/constants.ts b/redisinsight/ui/src/pages/search/components/query/constants.ts new file mode 100644 index 0000000000..120ea9f891 --- /dev/null +++ b/redisinsight/ui/src/pages/search/components/query/constants.ts @@ -0,0 +1,12 @@ +import { merge } from 'lodash' +import { defaultMonacoOptions } from 'uiSrc/constants' + +export const options = merge(defaultMonacoOptions, + { + suggest: { + showWords: false, + showIcons: true + } + }) + +export const SUPPORTED_COMMANDS_LIST = ['FT.SEARCH', 'FT.AGGREGATE'] diff --git a/redisinsight/ui/src/pages/search/components/query/types.ts b/redisinsight/ui/src/pages/search/types.ts similarity index 100% rename from redisinsight/ui/src/pages/search/components/query/types.ts rename to redisinsight/ui/src/pages/search/types.ts diff --git a/redisinsight/ui/src/pages/search/utils/index.ts b/redisinsight/ui/src/pages/search/utils/index.ts new file mode 100644 index 0000000000..c820377353 --- /dev/null +++ b/redisinsight/ui/src/pages/search/utils/index.ts @@ -0,0 +1,2 @@ +export * from './query' +export * from './monaco' diff --git a/redisinsight/ui/src/pages/search/utils/monaco.ts b/redisinsight/ui/src/pages/search/utils/monaco.ts new file mode 100644 index 0000000000..cfdf1bb645 --- /dev/null +++ b/redisinsight/ui/src/pages/search/utils/monaco.ts @@ -0,0 +1,74 @@ +import { monaco } from 'react-monaco-editor' +import * as monacoEditor from 'monaco-editor' +import { isString } from 'lodash' +import { generateDetail } from 'uiSrc/pages/search/utils/query' +import { SearchCommand, TokenType } from 'uiSrc/pages/search/types' +import { bufferToString, formatLongName, Maybe } from 'uiSrc/utils' +import { RedisResponseBuffer } from 'uiSrc/slices/interfaces' + +export const getRange = (position: monaco.Position, word: monaco.editor.IWordAtPosition): monaco.IRange => ({ + startLineNumber: position.lineNumber, + endLineNumber: position.lineNumber, + endColumn: word.endColumn, + startColumn: word.startColumn, +}) + +export const buildSuggestion = (arg: SearchCommand, range: monaco.IRange, options: any = {}) => ({ + label: isString(arg) ? arg : arg.token || arg.arguments?.[0].token || arg.name || '', + insertText: `${arg.token || arg.arguments?.[0].token || arg.name?.toUpperCase() || ''} `, + insertTextRules: monacoEditor.languages.CompletionItemInsertTextRule.InsertAsSnippet, + range, + kind: options?.kind || monacoEditor.languages.CompletionItemKind.Function, + ...options, +}) + +export const getIndexesSuggestions = (indexes: RedisResponseBuffer[], range: monaco.IRange) => + indexes.map((index) => { + const value = formatLongName(bufferToString(index)) + + console.log(value) + + return { + label: value || ' ', + kind: monacoEditor.languages.CompletionItemKind.Snippet, + insertText: `"${value}" "$1" `, + insertTextRules: monacoEditor.languages.CompletionItemInsertTextRule.InsertAsSnippet, + range, + } + }) + +export const getFieldsSuggestions = (fields: string[], range: monaco.IRange, spaceAfter = false) => + fields.map((field) => ({ + label: field, + kind: monacoEditor.languages.CompletionItemKind.Reference, + insertText: `${field}${spaceAfter ? ' ' : ''}`, + insertTextRules: monacoEditor.languages.CompletionItemInsertTextRule.InsertAsSnippet, + range, + })) + +export const getRediSearchSignutureProvider = (options: Maybe<{ + isOpen: boolean + currentArg: SearchCommand + parent: Maybe +}>) => { + const { isOpen, currentArg, parent } = options || {} + + if (!isOpen) return null + + const label = generateDetail(parent) + const arg = currentArg?.type === TokenType.Block + ? currentArg?.arguments?.[0]?.name + : (currentArg?.name || currentArg?.type || '') + + return { + dispose: () => {}, + value: { + activeParameter: 0, + activeSignature: 0, + signatures: [{ + label: label || '', + parameters: [{ label: arg }] + }] + } + } +} diff --git a/redisinsight/ui/src/pages/search/components/query/utils.ts b/redisinsight/ui/src/pages/search/utils/query.ts similarity index 90% rename from redisinsight/ui/src/pages/search/components/query/utils.ts rename to redisinsight/ui/src/pages/search/utils/query.ts index 26e0436f72..58286b67b8 100644 --- a/redisinsight/ui/src/pages/search/components/query/utils.ts +++ b/redisinsight/ui/src/pages/search/utils/query.ts @@ -1,20 +1,9 @@ /* eslint-disable no-continue */ -import * as monacoEditor from 'monaco-editor' -import { monaco } from 'react-monaco-editor' -import { isString, toNumber } from 'lodash' +import { toNumber } from 'lodash' import { generateArgsNames, Maybe, Nullable } from 'uiSrc/utils' import { CommandProvider } from 'uiSrc/constants' -import { ArgName, SearchCommand, SearchCommandTree, TokenType } from './types' - -export const buildSuggestion = (arg: SearchCommand, range: monaco.IRange, options: any = {}) => ({ - label: isString(arg) ? arg : arg.token || arg.arguments?.[0].token || arg.name || '', - insertText: `${arg.token || arg.arguments?.[0].token || arg.name?.toUpperCase() || ''} `, - insertTextRules: monacoEditor.languages.CompletionItemInsertTextRule.InsertAsSnippet, - range, - kind: options?.kind || monacoEditor.languages.CompletionItemKind.Function, - ...options, -}) +import { ArgName, SearchCommand, SearchCommandTree, TokenType } from '../types' export const splitQueryByArgs = (query: string, position: number = 0) => { const args: [string[], string[]] = [[], []] @@ -85,13 +74,6 @@ export const splitQueryByArgs = (query: string, position: number = 0) => { return { args, isCursorInArg, prevCursorChar: query[position - 1], nextCursorChar: query[position] } } -export const getRange = (position: monaco.Position, word: monaco.editor.IWordAtPosition): monaco.IRange => ({ - startLineNumber: position.lineNumber, - endLineNumber: position.lineNumber, - endColumn: word.endColumn, - startColumn: word.startColumn, -}) - export const findCurrentArgument = ( args: SearchCommand[], prev: string[], @@ -114,7 +96,7 @@ export const findCurrentArgument = ( const tokenIndex = args.findIndex((cArg) => (cArg.type === TokenType.OneOf - ? cArg.arguments?.some((oneOfArg) => oneOfArg.token?.toLowerCase() === arg.toLowerCase()) + ? cArg.arguments?.some((oneOfArg: SearchCommand) => oneOfArg.token?.toLowerCase() === arg.toLowerCase()) : cArg.token?.toLowerCase() === arg.toLowerCase())) const token = args[tokenIndex] @@ -330,7 +312,7 @@ export const fillArgsByType = (args: SearchCommand[]) => { export const findArgByToken = (list: SearchCommand[], arg: string): Maybe => list.find((cArg) => (cArg.type === TokenType.OneOf - ? cArg.arguments?.some((oneOfArg) => oneOfArg?.token?.toLowerCase() === arg?.toLowerCase()) + ? cArg.arguments?.some((oneOfArg: SearchCommand) => oneOfArg?.token?.toLowerCase() === arg?.toLowerCase()) : cArg.arguments?.[0]?.token?.toLowerCase() === arg.toLowerCase())) export const isCompositeArgument = (arg: string, prevArg?: string) => arg === '*' && prevArg === 'LOAD' From 0c9a7976dd6f35a5835484a9871fc1ad17791298 Mon Sep 17 00:00:00 2001 From: Roman Sergeenko Date: Mon, 5 Aug 2024 13:46:31 +0200 Subject: [PATCH 021/256] #RI-5957 - remove console.log --- redisinsight/ui/src/pages/search/utils/monaco.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/redisinsight/ui/src/pages/search/utils/monaco.ts b/redisinsight/ui/src/pages/search/utils/monaco.ts index cfdf1bb645..924ea9ba1d 100644 --- a/redisinsight/ui/src/pages/search/utils/monaco.ts +++ b/redisinsight/ui/src/pages/search/utils/monaco.ts @@ -26,8 +26,6 @@ export const getIndexesSuggestions = (indexes: RedisResponseBuffer[], range: mon indexes.map((index) => { const value = formatLongName(bufferToString(index)) - console.log(value) - return { label: value || ' ', kind: monacoEditor.languages.CompletionItemKind.Snippet, From 827da349a8931c3ad9268c56aa788f4b4b8ecae6 Mon Sep 17 00:00:00 2001 From: mariasergeenko Date: Tue, 6 Aug 2024 10:34:36 +0200 Subject: [PATCH 022/256] fix per comments --- tests/e2e/pageObjects/base-run-commands-page.ts | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/tests/e2e/pageObjects/base-run-commands-page.ts b/tests/e2e/pageObjects/base-run-commands-page.ts index becdb303b2..cf7949b393 100644 --- a/tests/e2e/pageObjects/base-run-commands-page.ts +++ b/tests/e2e/pageObjects/base-run-commands-page.ts @@ -25,6 +25,7 @@ export class BaseRunCommandsPage extends InstancePage { queryResult = Selector('[data-testid=query-common-result]'); cssQueryCardCommand = '[data-testid=query-card-command]'; + cssQueryCardContainer = '[data-testid^="query-card-container-"]'; cssQueryTextResult = '[data-testid=query-cli-result]'; cssReRunCommandButton = '[data-testid=re-run-command]'; cssDeleteCommandButton = '[data-testid=delete-command]'; @@ -37,7 +38,7 @@ export class BaseRunCommandsPage extends InstancePage { * @param command The command */ async getCardContainerByCommand(command: string): Promise { - return this.queryCardCommand.withExactText(command).parent('[data-testid^="query-card-container-"]'); + return this.queryCardCommand.withExactText(command).parent(this.cssQueryCardContainer); } /** @@ -67,12 +68,4 @@ export class BaseRunCommandsPage extends InstancePage { const actualCommandResult = await this.queryCardContainer.nth(childNum).find(this.cssQueryTextResult).textContent; await t.expect(actualCommandResult).contains(result, 'Actual command result is not equal to executed'); } - - /** - * Get selector with tutorial name - * @param tutorialName name of the uploaded tutorial - */ - getAccordionButtonWithName(tutorialName: string): Selector { - return Selector(`[data-testid=accordion-button-${tutorialName}]`); - } } From a03732bd3fd982a2828f7cd37cc62410091c5dde Mon Sep 17 00:00:00 2001 From: Roman Sergeenko Date: Wed, 7 Aug 2024 18:07:28 +0200 Subject: [PATCH 023/256] #RI-5888 - add fields and indexes suggestions --- redisinsight/ui/src/constants/api.ts | 1 + .../pages/search/components/query/Query.tsx | 145 ++-- .../search/components/query/constants.ts | 6 + .../pages/search/components/query/utils.ts | 88 +++ redisinsight/ui/src/pages/search/types.ts | 10 + .../ui/src/pages/search/utils/monaco.ts | 38 +- .../ui/src/pages/search/utils/query.ts | 31 +- .../ui/src/pages/search/utils/tests/mocks.ts | 676 ++++++++++++++++++ .../pages/search/utils/tests/query.spec.ts | 351 +++++++++ .../ui/src/slices/browser/redisearch.ts | 27 + .../slices/tests/browser/redisearch.spec.ts | 37 +- 11 files changed, 1296 insertions(+), 114 deletions(-) create mode 100644 redisinsight/ui/src/pages/search/components/query/utils.ts create mode 100644 redisinsight/ui/src/pages/search/utils/tests/mocks.ts create mode 100644 redisinsight/ui/src/pages/search/utils/tests/query.spec.ts diff --git a/redisinsight/ui/src/constants/api.ts b/redisinsight/ui/src/constants/api.ts index a9d3453639..23ff703f82 100644 --- a/redisinsight/ui/src/constants/api.ts +++ b/redisinsight/ui/src/constants/api.ts @@ -113,6 +113,7 @@ enum ApiEndpoints { REDISEARCH = 'redisearch', REDISEARCH_SEARCH = 'redisearch/search', + REDISEARCH_INFO = 'redisearch/info', HISTORY = 'history', FEATURES = 'features', diff --git a/redisinsight/ui/src/pages/search/components/query/Query.tsx b/redisinsight/ui/src/pages/search/components/query/Query.tsx index dcd2d39352..e5be89b8ab 100644 --- a/redisinsight/ui/src/pages/search/components/query/Query.tsx +++ b/redisinsight/ui/src/pages/search/components/query/Query.tsx @@ -1,23 +1,28 @@ -import React, { useContext, useEffect, useRef } from 'react' +import React, { useContext, useEffect, useRef, useState } from 'react' import MonacoEditor, { monaco as monacoEditor } from 'react-monaco-editor' -import { useSelector } from 'react-redux' +import { useDispatch, useSelector } from 'react-redux' import { MonacoLanguage, Theme } from 'uiSrc/constants' import { ThemeContext } from 'uiSrc/contexts/themeContext' import { appRedisCommandsSelector } from 'uiSrc/slices/app/redis-commands' -import { getCommandMarkdown, Nullable } from 'uiSrc/utils' +import { Nullable } from 'uiSrc/utils' import { IEditorMount } from 'uiSrc/pages/workbench/interfaces' import { - buildSuggestion, findCurrentArgument, - generateDetail, getFieldsSuggestions, getIndexesSuggestions, getRange, - getRediSearchSignutureProvider, + getRediSearchSignutureProvider, setCursorPositionAtTheEnd, splitQueryByArgs } from 'uiSrc/pages/search/utils' import { SearchCommand } from 'uiSrc/pages/search/types' import { RedisResponseBuffer } from 'uiSrc/slices/interfaces' -import { SUPPORTED_COMMANDS_LIST, options } from './constants' +import { fetchRedisearchInfoAction } from 'uiSrc/slices/browser/redisearch' +import { SUPPORTED_COMMANDS_LIST, options, DefinedArgumentName } from './constants' +import { + getFieldsSuggestions, + getIndexesSuggestions, + asSuggestionsRef, + getMandatoryArgumentSuggestions, getOptionalSuggestions, getCommandsSuggestions +} from './utils' export interface Props { value: string @@ -29,6 +34,8 @@ const Query = (props: Props) => { const { value, onChange, indexes } = props const { spec: REDIS_COMMANDS_SPEC } = useSelector(appRedisCommandsSelector) + const [selectedIndex, setSelectedIndex] = useState('') + const SUPPORTED_COMMANDS = SUPPORTED_COMMANDS_LIST.map((name) => ({ ...REDIS_COMMANDS_SPEC[name], name @@ -37,15 +44,20 @@ const Query = (props: Props) => { const monacoObjects = useRef>(null) const disposeCompletionItemProvider = useRef(() => {}) const disposeSignatureHelpProvider = useRef(() => {}) - const suggestionsRef = useRef([]) + const suggestionsRef = useRef<{ + forceHide: boolean + data: monacoEditor.languages.CompletionItem[] + }>({ forceHide: false, data: [] }) const helpWidgetRef = useRef({ isOpen: false, parent: null, currentArg: null }) const indexesRef = useRef([]) + const attributesRef = useRef([]) const { theme } = useContext(ThemeContext) + const dispatch = useDispatch() useEffect(() => () => { disposeCompletionItemProvider.current?.() @@ -56,6 +68,18 @@ const Query = (props: Props) => { indexesRef.current = indexes }, [indexes]) + useEffect(() => { + if (!selectedIndex) return + + const index = selectedIndex.replace(/^(['"])(.*)\1$/, '$2') + + dispatch(fetchRedisearchInfoAction(index, + (data) => { + const { attributes } = data as any + attributesRef.current = attributes + })) + }, [selectedIndex]) + const editorDidMount = ( editor: monacoEditor.editor.IStandaloneCodeEditor, monaco: typeof monacoEditor @@ -63,8 +87,16 @@ const Query = (props: Props) => { monaco.languages.register({ id: MonacoLanguage.RediSearch }) monacoObjects.current = { editor, monaco } - suggestionsRef.current = getSuggestions(editor) - triggerSuggestions() + if (value) { + setCursorPositionAtTheEnd(editor) + } else { + const position = editor.getPosition() + + if (position?.column === 1 && position?.lineNumber === 1) { + suggestionsRef.current = getSuggestions(editor) + triggerSuggestions() + } + } disposeSignatureHelpProvider.current?.() disposeSignatureHelpProvider.current = monaco.languages.registerSignatureHelpProvider(MonacoLanguage.RediSearch, { @@ -73,7 +105,8 @@ const Query = (props: Props) => { disposeCompletionItemProvider.current?.() disposeCompletionItemProvider.current = monaco.languages.registerCompletionItemProvider(MonacoLanguage.RediSearch, { - provideCompletionItems: (): monacoEditor.languages.CompletionList => ({ suggestions: suggestionsRef.current }) + provideCompletionItems: (): monacoEditor.languages.CompletionList => + ({ suggestions: suggestionsRef.current.data }) }).dispose editor.onDidChangeCursorPosition(handleCursorChange) @@ -81,25 +114,25 @@ const Query = (props: Props) => { const handleCursorChange = () => { const { editor } = monacoObjects.current || {} - suggestionsRef.current = [] + suggestionsRef.current.data = [] if (!editor) return - if (!editor.getSelection()?.isEmpty()) { - setTimeout(() => editor?.trigger('', 'hideSuggestWidget', null), 0) + editor?.trigger('', 'hideSuggestWidget', null) return } suggestionsRef.current = getSuggestions(editor) - - if (suggestionsRef.current?.length) { + if (suggestionsRef.current.data.length) { triggerSuggestions() helpWidgetRef.current.isOpen = false return } - setTimeout(() => editor?.trigger('', 'hideSuggestWidget', null), 0) - editor?.trigger('', 'editor.action.triggerParameterHints', '') + if (suggestionsRef.current.forceHide) { + setTimeout(() => editor?.trigger('', 'hideSuggestWidget', null), 0) + editor?.trigger('', 'editor.action.triggerParameterHints', '') + } } const triggerSuggestions = () => { @@ -111,11 +144,14 @@ const Query = (props: Props) => { const getSuggestions = ( editor: monacoEditor.editor.IStandaloneCodeEditor - ): monacoEditor.languages.CompletionItem[] => { + ): { + forceHide: boolean + data: monacoEditor.languages.CompletionItem[] + } => { const position = editor.getPosition() const model = editor.getModel() - if (!position || !model) return [] + if (!position || !model) return asSuggestionsRef([]) const value = editor.getValue() const offset = model.getOffsetAt(position) @@ -123,6 +159,7 @@ const Query = (props: Props) => { const range = getRange(position, word) const { args, isCursorInArg, prevCursorChar, nextCursorChar } = splitQueryByArgs(value, offset) + const allArgs = args.flat() const [beforeOffsetArgs] = args const [firstArg, ...prevArgs] = beforeOffsetArgs @@ -130,33 +167,32 @@ const Query = (props: Props) => { const command = REDIS_COMMANDS_SPEC[commandName] as unknown as SearchCommand if (!command && position.lineNumber === 1 && word.startColumn === 1) { - return SUPPORTED_COMMANDS.map((command) => buildSuggestion(command, range, { - detail: generateDetail(command), - documentation: { - value: getCommandMarkdown(command as any) - }, - })) + return getCommandsSuggestions(SUPPORTED_COMMANDS, range) } - if (!command) return [] + if (!command) return asSuggestionsRef([]) + + setSelectedIndex(allArgs[1] || '') // cover query - if (command?.arguments?.[prevArgs.length]?.name === 'query') { + if (command?.arguments?.[prevArgs.length]?.name === DefinedArgumentName.query) { if (prevCursorChar === '@') { - return getFieldsSuggestions(['field1', 'field2'], range) + return asSuggestionsRef(getFieldsSuggestions(attributesRef.current, range), false) } - return [] + return asSuggestionsRef([]) } - if (isCursorInArg || nextCursorChar?.trim()) return [] + if (isCursorInArg || nextCursorChar?.trim()) return asSuggestionsRef([]) // cover index field - if (command?.arguments?.[prevArgs.length]?.name === 'index') { - return getIndexesSuggestions(indexesRef.current, range) + if (command?.arguments?.[prevArgs.length]?.name === DefinedArgumentName.index) { + if (prevCursorChar?.trim()) return asSuggestionsRef([], false) + return asSuggestionsRef(getIndexesSuggestions(indexesRef.current, range)) } - if (prevArgs.length < 2) return [] + if (prevArgs.length < 2) return asSuggestionsRef([]) + const foundArg = findCurrentArgument(command?.arguments || [], prevArgs) helpWidgetRef.current = { @@ -165,44 +201,9 @@ const Query = (props: Props) => { currentArg: foundArg?.stopArg } - // suggest arguments of argument - if (foundArg && !foundArg.isComplete) { - if (foundArg.stopArg?.name === 'field') { - return getFieldsSuggestions(['field1', 'field2'], range, true) - } - - if (foundArg.isBlocked) return [] - if (foundArg.append?.length) { - return foundArg.append.map((arg: any) => buildSuggestion(arg, range, { - kind: monacoEditor.languages.CompletionItemKind.Property, - detail: generateDetail(foundArg?.parent) - })) - } - - return [] - } - - if (!foundArg || foundArg.isComplete) { - const appendCommands = foundArg?.append ?? [] - - return [ - ...appendCommands.map((arg: any) => buildSuggestion(arg, range, { - sortText: 'a', - kind: monacoEditor.languages.CompletionItemKind.Property, - detail: generateDetail(foundArg?.parent) - })), - ...(command?.arguments || []) - .filter((arg) => arg.optional) - .filter((arg) => arg.multiple || !args.flat().includes(arg.token || arg.arguments?.[0]?.token || '')) - .map((arg: any) => buildSuggestion(arg, range, { - sortText: 'b', - kind: monacoEditor.languages.CompletionItemKind.Reference, - detail: generateDetail(arg) - })) - ] - } - - return [] + if (foundArg && !foundArg.isComplete) return getMandatoryArgumentSuggestions(foundArg, attributesRef.current, range) + if (!foundArg || foundArg.isComplete) return getOptionalSuggestions(command, foundArg, allArgs, range) + return asSuggestionsRef([]) } return ( diff --git a/redisinsight/ui/src/pages/search/components/query/constants.ts b/redisinsight/ui/src/pages/search/components/query/constants.ts index 120ea9f891..15556977d6 100644 --- a/redisinsight/ui/src/pages/search/components/query/constants.ts +++ b/redisinsight/ui/src/pages/search/components/query/constants.ts @@ -10,3 +10,9 @@ export const options = merge(defaultMonacoOptions, }) export const SUPPORTED_COMMANDS_LIST = ['FT.SEARCH', 'FT.AGGREGATE'] + +export enum DefinedArgumentName { + index = 'index', + query = 'query', + field = 'field', +} diff --git a/redisinsight/ui/src/pages/search/components/query/utils.ts b/redisinsight/ui/src/pages/search/components/query/utils.ts new file mode 100644 index 0000000000..24537cdb32 --- /dev/null +++ b/redisinsight/ui/src/pages/search/components/query/utils.ts @@ -0,0 +1,88 @@ +import { monaco } from 'react-monaco-editor' +import * as monacoEditor from 'monaco-editor' +import { RedisResponseBuffer } from 'uiSrc/slices/interfaces' +import { bufferToString, formatLongName, getCommandMarkdown, Nullable } from 'uiSrc/utils' +import { buildSuggestion, generateDetail } from 'uiSrc/pages/search/utils' +import { FoundCommandArgument, SearchCommand } from 'uiSrc/pages/search/types' +import { DefinedArgumentName } from 'uiSrc/pages/search/components/query/constants' + +export const asSuggestionsRef = (suggestions: monacoEditor.languages.CompletionItem[], forceHide = true) => ({ + data: suggestions, + forceHide +}) + +export const getIndexesSuggestions = (indexes: RedisResponseBuffer[], range: monaco.IRange) => + indexes.map((index) => { + const value = formatLongName(bufferToString(index)) + + return { + label: value || ' ', + kind: monacoEditor.languages.CompletionItemKind.Snippet, + insertText: `"${value}" "$1" `, + insertTextRules: monacoEditor.languages.CompletionItemInsertTextRule.InsertAsSnippet, + range, + } + }) + +export const getFieldsSuggestions = (fields: any[], range: monaco.IRange, spaceAfter = false) => + fields.map(({ attribute }) => ({ + label: attribute, + kind: monacoEditor.languages.CompletionItemKind.Reference, + insertText: `${attribute}${spaceAfter ? ' ' : ''}`, + insertTextRules: monacoEditor.languages.CompletionItemInsertTextRule.InsertAsSnippet, + range, + })) + +export const getCommandsSuggestions = (commands: SearchCommand[], range: monaco.IRange) => asSuggestionsRef( + commands.map((command) => buildSuggestion(command, range, { + detail: generateDetail(command), + documentation: { + value: getCommandMarkdown(command as any) + }, + })) +) + +export const getMandatoryArgumentSuggestions = ( + foundArg: FoundCommandArgument, + fields: any[], + range: monaco.IRange +) => { + if (foundArg.stopArg?.name === DefinedArgumentName.field) { + return asSuggestionsRef(getFieldsSuggestions(fields, range, true)) + } + + if (foundArg.isBlocked) return asSuggestionsRef([]) + if (foundArg.append?.length) { + return asSuggestionsRef(foundArg.append.map((arg: any) => buildSuggestion(arg, range, { + kind: monacoEditor.languages.CompletionItemKind.Property, + detail: generateDetail(foundArg?.parent) + }))) + } + + return asSuggestionsRef([]) +} + +export const getOptionalSuggestions = ( + command: SearchCommand, + foundArg: Nullable, + allArgs: string[], + range: monaco.IRange +) => { + const appendCommands = foundArg?.append ?? [] + + return asSuggestionsRef([ + ...appendCommands.map((arg) => buildSuggestion(arg, range, { + sortText: 'a', + kind: monacoEditor.languages.CompletionItemKind.Property, + detail: generateDetail(foundArg?.parent) + })), + ...(command?.arguments || []) + .filter((arg) => arg.optional) + .filter((arg) => arg.multiple || !allArgs.includes(arg.token || arg.arguments?.[0]?.token || '')) + .map((arg) => buildSuggestion(arg, range, { + sortText: 'b', + kind: monacoEditor.languages.CompletionItemKind.Reference, + detail: generateDetail(arg) + })) + ]) +} diff --git a/redisinsight/ui/src/pages/search/types.ts b/redisinsight/ui/src/pages/search/types.ts index d1552818de..d4973f1c0b 100644 --- a/redisinsight/ui/src/pages/search/types.ts +++ b/redisinsight/ui/src/pages/search/types.ts @@ -1,3 +1,5 @@ +import { Maybe } from 'uiSrc/utils' + export enum TokenType { PureToken = 'pure-token', Block = 'block', @@ -20,3 +22,11 @@ export interface SearchCommand { export interface SearchCommandTree extends SearchCommand { parent?: SearchCommandTree } + +export interface FoundCommandArgument { + isComplete: boolean + stopArg: Maybe + isBlocked: boolean + append: Maybe + parent: Maybe +} diff --git a/redisinsight/ui/src/pages/search/utils/monaco.ts b/redisinsight/ui/src/pages/search/utils/monaco.ts index 924ea9ba1d..41712e9568 100644 --- a/redisinsight/ui/src/pages/search/utils/monaco.ts +++ b/redisinsight/ui/src/pages/search/utils/monaco.ts @@ -3,8 +3,20 @@ import * as monacoEditor from 'monaco-editor' import { isString } from 'lodash' import { generateDetail } from 'uiSrc/pages/search/utils/query' import { SearchCommand, TokenType } from 'uiSrc/pages/search/types' -import { bufferToString, formatLongName, Maybe } from 'uiSrc/utils' -import { RedisResponseBuffer } from 'uiSrc/slices/interfaces' +import { Maybe } from 'uiSrc/utils' + +export const setCursorPositionAtTheEnd = (editor: monacoEditor.editor.IStandaloneCodeEditor) => { + if (!editor) return + + const rows = editor.getValue().split('\n') + + editor.setPosition({ + column: rows[rows.length - 1].trimEnd().length + 1, + lineNumber: rows.length + }) + + editor.focus() +} export const getRange = (position: monaco.Position, word: monaco.editor.IWordAtPosition): monaco.IRange => ({ startLineNumber: position.lineNumber, @@ -22,28 +34,6 @@ export const buildSuggestion = (arg: SearchCommand, range: monaco.IRange, option ...options, }) -export const getIndexesSuggestions = (indexes: RedisResponseBuffer[], range: monaco.IRange) => - indexes.map((index) => { - const value = formatLongName(bufferToString(index)) - - return { - label: value || ' ', - kind: monacoEditor.languages.CompletionItemKind.Snippet, - insertText: `"${value}" "$1" `, - insertTextRules: monacoEditor.languages.CompletionItemInsertTextRule.InsertAsSnippet, - range, - } - }) - -export const getFieldsSuggestions = (fields: string[], range: monaco.IRange, spaceAfter = false) => - fields.map((field) => ({ - label: field, - kind: monacoEditor.languages.CompletionItemKind.Reference, - insertText: `${field}${spaceAfter ? ' ' : ''}`, - insertTextRules: monacoEditor.languages.CompletionItemInsertTextRule.InsertAsSnippet, - range, - })) - export const getRediSearchSignutureProvider = (options: Maybe<{ isOpen: boolean currentArg: SearchCommand diff --git a/redisinsight/ui/src/pages/search/utils/query.ts b/redisinsight/ui/src/pages/search/utils/query.ts index 58286b67b8..0a5e269068 100644 --- a/redisinsight/ui/src/pages/search/utils/query.ts +++ b/redisinsight/ui/src/pages/search/utils/query.ts @@ -3,7 +3,7 @@ import { toNumber } from 'lodash' import { generateArgsNames, Maybe, Nullable } from 'uiSrc/utils' import { CommandProvider } from 'uiSrc/constants' -import { ArgName, SearchCommand, SearchCommandTree, TokenType } from '../types' +import { ArgName, FoundCommandArgument, SearchCommand, SearchCommandTree, TokenType } from '../types' export const splitQueryByArgs = (query: string, position: number = 0) => { const args: [string[], string[]] = [[], []] @@ -78,13 +78,7 @@ export const findCurrentArgument = ( args: SearchCommand[], prev: string[], parent?: SearchCommandTree -): Nullable<{ - isComplete: boolean - stopArg: Maybe, - isBlocked: boolean, - append: Maybe[], - parent: Maybe -}> => { +): Nullable => { for (let i = prev.length - 1; i >= 0; i--) { const arg = prev[i] const currentArg = findArgByToken(args, arg) @@ -228,7 +222,7 @@ export const getArgumentSuggestions = ( isComplete: boolean stopArg: Maybe, isBlocked: boolean, - append: Maybe[], + append: SearchCommand[], } => { const { restArguments, @@ -240,14 +234,19 @@ export const getArgumentSuggestions = ( const stopArgument = restArguments[stopArgIndex] const restNotFilledArgs = restArguments.slice(stopArgIndex) - const isBlocked = isWasBlocked || (stopArgument && !(stopArgument.token || stopArgument?.arguments?.length)) + const isStopArgumentCannotSuggest = Boolean(stopArgument && !(stopArgument.token || stopArgument?.arguments?.length)) + const isBlocked = isWasBlocked || isStopArgumentCannotSuggest + const restParentOptionalSuggestions = !stopArgument || stopArgument?.optional ? getRestParentArguments(current?.parent, current?.name, current?.multiple) - .filter((arg) => arg.optional) - .filter((arg) => arg.name !== current?.name) + .filter((arg) => + arg.optional && arg.name !== stopArgument?.name + && (current?.multiple || arg.name !== current?.name)) : [] - const restOptionalSuggestions = fillArgsByType([...restNotFilledArgs, ...restParentOptionalSuggestions]) + const restOptionalSuggestions = isBlocked + ? [] + : fillArgsByType([...restNotFilledArgs, ...restParentOptionalSuggestions]) const isOneOfArgument = stopArgument?.type === TokenType.OneOf || (stopArgument?.type === TokenType.PureToken && current?.parent?.type === TokenType.OneOf) const isArgSuggestions = stopArgument && !stopArgument.optional && (stopArgument?.token || isOneOfArgument) @@ -255,16 +254,14 @@ export const getArgumentSuggestions = ( const suggestions = isArgSuggestions // only 1 suggestion since next arg is required ? [isOneOfArgument ? stopArgument.arguments : stopArgument].flat() - : !isBlocked - ? restOptionalSuggestions - : [] + : restOptionalSuggestions const requiredArgsLength = restNotFilledArgs.filter((arg) => !arg.optional).length return { isComplete: requiredArgsLength === 0 && !isBlocked, stopArg: stopArgument, - isBlocked: isBlocked && !isOneOfArgument, + isBlocked, append: suggestions, } } diff --git a/redisinsight/ui/src/pages/search/utils/tests/mocks.ts b/redisinsight/ui/src/pages/search/utils/tests/mocks.ts new file mode 100644 index 0000000000..8125afa84c --- /dev/null +++ b/redisinsight/ui/src/pages/search/utils/tests/mocks.ts @@ -0,0 +1,676 @@ +export const MOCKED_SUPPORTED_COMMANDS = { + 'FT.SEARCH': { + summary: 'Searches the index with a textual query, returning either documents or just ids', + complexity: 'O(N)', + history: [ + [ + '2.0.0', + 'Deprecated `WITHPAYLOADS` and `PAYLOAD` arguments' + ] + ], + arguments: [ + { + name: 'index', + type: 'string' + }, + { + name: 'query', + type: 'string' + }, + { + name: 'nocontent', + type: 'pure-token', + token: 'NOCONTENT', + optional: true + }, + { + name: 'verbatim', + type: 'pure-token', + token: 'VERBATIM', + optional: true + }, + { + name: 'nostopwords', + type: 'pure-token', + token: 'NOSTOPWORDS', + optional: true + }, + { + name: 'withscores', + type: 'pure-token', + token: 'WITHSCORES', + optional: true + }, + { + name: 'withpayloads', + type: 'pure-token', + token: 'WITHPAYLOADS', + optional: true + }, + { + name: 'withsortkeys', + type: 'pure-token', + token: 'WITHSORTKEYS', + optional: true + }, + { + name: 'filter', + type: 'block', + optional: true, + multiple: true, + arguments: [ + { + name: 'numeric_field', + type: 'string', + token: 'FILTER' + }, + { + name: 'min', + type: 'double' + }, + { + name: 'max', + type: 'double' + } + ] + }, + { + name: 'geo_filter', + type: 'block', + optional: true, + multiple: true, + arguments: [ + { + name: 'geo_field', + type: 'string', + token: 'GEOFILTER' + }, + { + name: 'lon', + type: 'double' + }, + { + name: 'lat', + type: 'double' + }, + { + name: 'radius', + type: 'double' + }, + { + name: 'radius_type', + type: 'oneof', + arguments: [ + { + name: 'm', + type: 'pure-token', + token: 'm' + }, + { + name: 'km', + type: 'pure-token', + token: 'km' + }, + { + name: 'mi', + type: 'pure-token', + token: 'mi' + }, + { + name: 'ft', + type: 'pure-token', + token: 'ft' + } + ] + } + ] + }, + { + name: 'in_keys', + type: 'block', + optional: true, + arguments: [ + { + name: 'count', + type: 'string', + token: 'INKEYS' + }, + { + name: 'key', + type: 'string', + multiple: true + } + ] + }, + { + name: 'in_fields', + type: 'block', + optional: true, + arguments: [ + { + name: 'count', + type: 'string', + token: 'INFIELDS' + }, + { + name: 'field', + type: 'string', + multiple: true + } + ] + }, + { + name: 'return', + type: 'block', + optional: true, + arguments: [ + { + name: 'count', + type: 'string', + token: 'RETURN' + }, + { + name: 'identifiers', + type: 'block', + multiple: true, + arguments: [ + { + name: 'identifier', + type: 'string' + }, + { + name: 'property', + type: 'string', + token: 'AS', + optional: true + } + ] + } + ] + }, + { + name: 'summarize', + type: 'block', + optional: true, + arguments: [ + { + name: 'summarize', + type: 'pure-token', + token: 'SUMMARIZE' + }, + { + name: 'fields', + type: 'block', + optional: true, + arguments: [ + { + name: 'count', + type: 'string', + token: 'FIELDS' + }, + { + name: 'field', + type: 'string', + multiple: true + } + ] + }, + { + name: 'num', + type: 'integer', + token: 'FRAGS', + optional: true + }, + { + name: 'fragsize', + type: 'integer', + token: 'LEN', + optional: true + }, + { + name: 'separator', + type: 'string', + token: 'SEPARATOR', + optional: true + } + ] + }, + { + name: 'highlight', + type: 'block', + optional: true, + arguments: [ + { + name: 'highlight', + type: 'pure-token', + token: 'HIGHLIGHT' + }, + { + name: 'fields', + type: 'block', + optional: true, + arguments: [ + { + name: 'count', + type: 'string', + token: 'FIELDS' + }, + { + name: 'field', + type: 'string', + multiple: true + } + ] + }, + { + name: 'tags', + type: 'block', + optional: true, + arguments: [ + { + name: 'tags', + type: 'pure-token', + token: 'TAGS' + }, + { + name: 'open', + type: 'string' + }, + { + name: 'close', + type: 'string' + } + ] + } + ] + }, + { + name: 'slop', + type: 'integer', + optional: true, + token: 'SLOP' + }, + { + name: 'timeout', + type: 'integer', + optional: true, + token: 'TIMEOUT' + }, + { + name: 'inorder', + type: 'pure-token', + token: 'INORDER', + optional: true + }, + { + name: 'language', + type: 'string', + optional: true, + token: 'LANGUAGE' + }, + { + name: 'expander', + type: 'string', + optional: true, + token: 'EXPANDER' + }, + { + name: 'scorer', + type: 'string', + optional: true, + token: 'SCORER' + }, + { + name: 'explainscore', + type: 'pure-token', + token: 'EXPLAINSCORE', + optional: true + }, + { + name: 'payload', + type: 'string', + optional: true, + token: 'PAYLOAD' + }, + { + name: 'sortby', + type: 'block', + optional: true, + arguments: [ + { + name: 'sortby', + type: 'string', + token: 'SORTBY' + }, + { + name: 'order', + type: 'oneof', + optional: true, + arguments: [ + { + name: 'asc', + type: 'pure-token', + token: 'ASC' + }, + { + name: 'desc', + type: 'pure-token', + token: 'DESC' + } + ] + } + ] + }, + { + name: 'limit', + type: 'block', + optional: true, + arguments: [ + { + name: 'limit', + type: 'pure-token', + token: 'LIMIT' + }, + { + name: 'offset', + type: 'integer' + }, + { + name: 'num', + type: 'integer' + } + ] + }, + { + name: 'params', + type: 'block', + optional: true, + arguments: [ + { + name: 'params', + type: 'pure-token', + token: 'PARAMS' + }, + { + name: 'nargs', + type: 'integer' + }, + { + name: 'values', + type: 'block', + multiple: true, + arguments: [ + { + name: 'name', + type: 'string' + }, + { + name: 'value', + type: 'string' + } + ] + } + ] + }, + { + name: 'dialect', + type: 'integer', + optional: true, + token: 'DIALECT', + since: '2.4.3' + } + ], + since: '1.0.0', + group: 'search' + }, + + 'FT.AGGREGATE': { + summary: 'Run a search query on an index and perform aggregate transformations on the results', + complexity: 'O(1)', + arguments: [ + { + name: 'index', + type: 'string' + }, + { + name: 'query', + type: 'string' + }, + { + name: 'verbatim', + type: 'pure-token', + token: 'VERBATIM', + optional: true + }, + { + name: 'load', + type: 'block', + optional: true, + arguments: [ + { + name: 'count', + type: 'string', + token: 'LOAD' + }, + { + name: 'field', + type: 'string', + multiple: true + } + ] + }, + { + name: 'timeout', + type: 'integer', + optional: true, + token: 'TIMEOUT' + }, + { + name: 'loadall', + type: 'pure-token', + token: 'LOAD *', + optional: true + }, + { + name: 'groupby', + type: 'block', + optional: true, + multiple: true, + arguments: [ + { + name: 'nargs', + type: 'integer', + token: 'GROUPBY' + }, + { + name: 'property', + type: 'string', + multiple: true + }, + { + name: 'reduce', + type: 'block', + optional: true, + multiple: true, + arguments: [ + { + name: 'function', + type: 'string', + token: 'REDUCE' + }, + { + name: 'nargs', + type: 'integer' + }, + { + name: 'arg', + type: 'string', + multiple: true + }, + { + name: 'name', + type: 'string', + token: 'AS', + optional: true + } + ] + } + ] + }, + { + name: 'sortby', + type: 'block', + optional: true, + arguments: [ + { + name: 'nargs', + type: 'integer', + token: 'SORTBY' + }, + { + name: 'fields', + type: 'block', + optional: true, + multiple: true, + arguments: [ + { + name: 'property', + type: 'string' + }, + { + name: 'order', + type: 'oneof', + arguments: [ + { + name: 'asc', + type: 'pure-token', + token: 'ASC' + }, + { + name: 'desc', + type: 'pure-token', + token: 'DESC' + } + ] + } + ] + }, + { + name: 'num', + type: 'integer', + token: 'MAX', + optional: true + } + ] + }, + { + name: 'apply', + type: 'block', + optional: true, + multiple: true, + arguments: [ + { + name: 'expression', + type: 'string', + token: 'APPLY' + }, + { + name: 'name', + type: 'string', + token: 'AS' + } + ] + }, + { + name: 'limit', + type: 'block', + optional: true, + arguments: [ + { + name: 'limit', + type: 'pure-token', + token: 'LIMIT' + }, + { + name: 'offset', + type: 'integer' + }, + { + name: 'num', + type: 'integer' + } + ] + }, + { + name: 'filter', + type: 'string', + optional: true, + token: 'FILTER' + }, + { + name: 'cursor', + type: 'block', + optional: true, + arguments: [ + { + name: 'withcursor', + type: 'pure-token', + token: 'WITHCURSOR' + }, + { + name: 'read_size', + type: 'integer', + optional: true, + token: 'COUNT' + }, + { + name: 'idle_time', + type: 'integer', + optional: true, + token: 'MAXIDLE' + } + ] + }, + { + name: 'params', + type: 'block', + optional: true, + arguments: [ + { + name: 'params', + type: 'pure-token', + token: 'PARAMS' + }, + { + name: 'nargs', + type: 'integer' + }, + { + name: 'values', + type: 'block', + multiple: true, + arguments: [ + { + name: 'name', + type: 'string' + }, + { + name: 'value', + type: 'string' + } + ] + } + ] + }, + { + name: 'dialect', + type: 'integer', + optional: true, + token: 'DIALECT', + since: '2.4.3' + } + ], + since: '1.1.0', + group: 'search' + } +} diff --git a/redisinsight/ui/src/pages/search/utils/tests/query.spec.ts b/redisinsight/ui/src/pages/search/utils/tests/query.spec.ts new file mode 100644 index 0000000000..93bd7ea54e --- /dev/null +++ b/redisinsight/ui/src/pages/search/utils/tests/query.spec.ts @@ -0,0 +1,351 @@ +import { findCurrentArgument } from 'uiSrc/pages/search/utils' +import { SearchCommand } from 'uiSrc/pages/search/types' +import { MOCKED_SUPPORTED_COMMANDS } from './mocks' + +const ftSearchCommand = MOCKED_SUPPORTED_COMMANDS['FT.SEARCH'] +const ftAggregateCommand = MOCKED_SUPPORTED_COMMANDS['FT.AGGREGATE'] + +const ftAggreageTests = [ + { args: [''], result: null }, + { args: ['', ''], result: null }, + { + args: ['index', '"query"', 'APPLY'], + result: { + stopArg: { name: 'expression', token: 'APPLY', type: 'string' }, + append: [{ name: 'expression', token: 'APPLY', type: 'string' }], + isBlocked: true, + isComplete: false, + parent: expect.any(Object) + } + }, + { + args: ['index', '"query"', 'APPLY', 'expression'], + result: { + stopArg: { name: 'name', token: 'AS', type: 'string' }, + append: expect.any(Array), + isBlocked: false, + isComplete: false, + parent: expect.any(Object) + } + }, + { + args: ['index', '"query"', 'APPLY', 'expression', 'AS'], + result: { + stopArg: { name: 'name', token: 'AS', type: 'string' }, + append: expect.any(Array), + isBlocked: true, + isComplete: false, + parent: expect.any(Object) + } + }, + { + args: ['index', '"query"', 'APPLY', 'expression', 'AS', 'name'], + result: { + stopArg: undefined, + append: expect.any(Array), + isBlocked: false, + isComplete: true, + parent: expect.any(Object) + } + }, + { + args: ['""', '""', 'GROUPBY', '2', 'p1', 'p2', 'REDUCE', 'f'], + result: { + stopArg: { name: 'nargs', type: 'integer' }, + append: [], + isBlocked: true, + isComplete: false, + parent: expect.any(Object) + } + }, + { + args: ['""', '""', 'GROUPBY', '2', 'p1', 'p2', 'REDUCE', 'f', '0'], + result: { + stopArg: { + name: 'name', + type: 'string', + token: 'AS', + optional: true + }, + append: [ + { + name: 'name', + type: 'string', + token: 'AS', + optional: true + }, + { + name: 'function', + type: 'string', + token: 'REDUCE' + } + ], + isBlocked: false, + isComplete: true, + parent: expect.any(Object) + } + }, + { + args: ['index', '"query"', 'SORTBY'], + result: { + stopArg: { name: 'nargs', token: 'SORTBY', type: 'integer' }, + append: expect.any(Array), + isBlocked: true, + isComplete: false, + parent: expect.any(Object) + } + }, + { + args: ['index', '"query"', 'SORTBY', '1', 'p1'], + result: { + stopArg: { + name: 'order', + type: 'oneof', + arguments: [ + { + name: 'asc', + type: 'pure-token', + token: 'ASC' + }, + { + name: 'desc', + type: 'pure-token', + token: 'DESC' + } + ] + }, + append: [ + { + name: 'asc', + type: 'pure-token', + token: 'ASC' + }, + { + name: 'desc', + type: 'pure-token', + token: 'DESC' + } + ], + isBlocked: false, + isComplete: false, + parent: expect.any(Object) + } + }, + { + args: ['index', '"query"', 'SORTBY', '1', 'p1', 'ASC'], + result: { + stopArg: { + name: 'num', + type: 'integer', + token: 'MAX', + optional: true + }, + append: [ + { + name: 'num', + type: 'integer', + token: 'MAX', + optional: true + } + ], + isBlocked: false, + isComplete: true, + parent: expect.any(Object) + } + }, + { + args: ['index', '"query"', 'SORTBY', '0'], + result: { + stopArg: { + name: 'num', + type: 'integer', + token: 'MAX', + optional: true + }, + append: [ + { + name: 'num', + type: 'integer', + token: 'MAX', + optional: true + } + ], + isBlocked: false, + isComplete: true, + parent: expect.any(Object) + } + }, + { + args: ['index', '"query"', 'SORTBY', '1', 'p1', 'ASC', 'MAX'], + result: { + stopArg: { + name: 'num', + type: 'integer', + token: 'MAX', + optional: true + }, + append: [], + isBlocked: true, + isComplete: false, + parent: expect.any(Object) + } + }, +] + +const ftSearchTests = [ + { args: [''], result: null }, + { args: ['', ''], result: null }, + { + args: ['', '', 'SUMMARIZE'], + result: { + stopArg: { + name: 'fields', + type: 'block', + optional: true, + arguments: [ + { + name: 'count', + type: 'string', + token: 'FIELDS' + }, + { + name: 'field', + type: 'string', + multiple: true + } + ] + }, + append: [ + { + name: 'count', + type: 'string', + token: 'FIELDS' + }, + { + name: 'num', + type: 'integer', + token: 'FRAGS', + optional: true + }, + { + name: 'fragsize', + type: 'integer', + token: 'LEN', + optional: true + }, + { + name: 'separator', + type: 'string', + token: 'SEPARATOR', + optional: true + } + ], + isBlocked: false, + isComplete: true, + parent: expect.any(Object) + } + }, + { + args: ['', '', 'SUMMARIZE', 'FIELDS'], + result: { + stopArg: { + name: 'count', + type: 'string', + token: 'FIELDS' + }, + append: [ + { + name: 'count', + type: 'string', + token: 'FIELDS' + } + ], + isBlocked: true, + isComplete: false, + parent: expect.any(Object) + } + }, + { + args: ['', '', 'SUMMARIZE', 'FIELDS', '1'], + result: { + stopArg: { + name: 'field', + type: 'string', + multiple: true + }, + append: [], + isBlocked: true, + isComplete: false, + parent: expect.any(Object) + } + }, + { + args: ['', '', 'SUMMARIZE', 'FIELDS', '1', 'f', 'FRAGS'], + result: { + stopArg: { + name: 'num', + type: 'integer', + token: 'FRAGS', + optional: true + }, + append: [], + isBlocked: true, + isComplete: false, + parent: expect.any(Object) + } + }, + { + args: ['', '', 'SUMMARIZE', 'FIELDS', '1', 'f', 'FRAGS', '10'], + result: { + stopArg: { + name: 'fragsize', + type: 'integer', + token: 'LEN', + optional: true + }, + append: [ + { + name: 'fragsize', + type: 'integer', + token: 'LEN', + optional: true + }, + { + name: 'separator', + type: 'string', + token: 'SEPARATOR', + optional: true + } + ], + isBlocked: false, + isComplete: true, + parent: expect.any(Object) + } + }, +] + +describe('findCurrentArgument', () => { + describe('FT.AGGREGATE', () => { + ftAggreageTests.forEach(({ args, result: testResult }) => { + it(`should return proper suggestions for ${args.join(' ')}`, () => { + const result = findCurrentArgument( + ftAggregateCommand.arguments as SearchCommand[], + args + ) + expect(result).toEqual(testResult) + }) + }) + }) + + describe('FT.SEARCH', () => { + ftSearchTests.forEach(({ args, result: testResult }) => { + it(`should return proper suggestions for ${args.join(' ')}`, () => { + const result = findCurrentArgument( + ftSearchCommand.arguments as SearchCommand[], + args + ) + expect(result).toEqual(testResult) + }) + }) + }) +}) diff --git a/redisinsight/ui/src/slices/browser/redisearch.ts b/redisinsight/ui/src/slices/browser/redisearch.ts index 911497e8c6..10a3cb46be 100644 --- a/redisinsight/ui/src/slices/browser/redisearch.ts +++ b/redisinsight/ui/src/slices/browser/redisearch.ts @@ -532,3 +532,30 @@ export function deleteRedisearchHistoryAction( } } } + +export function fetchRedisearchInfoAction( + index: string, + onSuccess?: (value: RedisResponseBuffer[]) => void, + onFailed?: () => void, +) { + return async (_: AppDispatch, stateInit: () => RootState) => { + try { + const state = stateInit() + const { data, status } = await apiService.post( + getUrl( + state.connections.instances.connectedInstance?.id, + ApiEndpoints.REDISEARCH_INFO + ), + { + index + } + ) + + if (isStatusSuccessful(status)) { + onSuccess?.(data) + } + } catch (_err) { + onFailed?.() + } + } +} diff --git a/redisinsight/ui/src/slices/tests/browser/redisearch.spec.ts b/redisinsight/ui/src/slices/tests/browser/redisearch.spec.ts index 8df3a44642..295f812c9a 100644 --- a/redisinsight/ui/src/slices/tests/browser/redisearch.spec.ts +++ b/redisinsight/ui/src/slices/tests/browser/redisearch.spec.ts @@ -47,7 +47,7 @@ import reducer, { deleteRediSearchHistorySuccess, deleteRediSearchHistoryFailure, fetchRedisearchHistoryAction, - deleteRedisearchHistoryAction, + deleteRedisearchHistoryAction, fetchRedisearchInfoAction, } from '../../browser/redisearch' let store: typeof mockedStore @@ -1276,5 +1276,40 @@ describe('redisearch slice', () => { expect(store.getActions()).toEqual(expectedActions) }) }) + + describe('fetchRedisearchInfoAction', () => { + it('success fetch info', async () => { + // Arrange + const responsePayload = { status: 200 } + const onSuccess = jest.fn() + + apiService.post = jest.fn().mockResolvedValue(responsePayload) + + // Act + await store.dispatch(fetchRedisearchInfoAction('index', onSuccess)) + + expect(onSuccess).toBeCalled() + }) + + it('failed to delete history', async () => { + // Arrange + const onFailed = jest.fn() + const errorMessage = 'some error' + const responsePayload = { + response: { + status: 500, + data: { message: errorMessage }, + }, + } + + apiService.post = jest.fn().mockRejectedValue(responsePayload) + + // Act + await store.dispatch(fetchRedisearchInfoAction('index', undefined, onFailed)) + + // Assert + expect(onFailed).toBeCalled() + }) + }) }) }) From 4b0719a1537991870020fee37d2e8cf0daaf617a Mon Sep 17 00:00:00 2001 From: vlad-dargel Date: Fri, 9 Aug 2024 16:34:28 +0200 Subject: [PATCH 024/256] e2e/feature/RI-5957_integrate-autocomplete-in-search-and-query --- tests/e2e/package.json | 2 +- .../e2e/pageObjects/base-run-commands-page.ts | 2 + .../pageObjects/components/monaco-editor.ts | 1 + tests/e2e/pageObjects/workbench-page.ts | 1 - ...kbench.ts => cli-promote-workbench.e2e.ts} | 0 ...ster-7.ts => pub-sub-oss-cluster-7.e2e.ts} | 0 .../search-and-query-tab.e2e.ts | 176 ++++++++++++++++++ .../search-and-query/search-and-query-tab.ts | 27 --- tests/e2e/web.runner.ts | 4 +- 9 files changed, 182 insertions(+), 31 deletions(-) rename tests/e2e/tests/web/regression/cli/{cli-promote-workbench.ts => cli-promote-workbench.e2e.ts} (100%) rename tests/e2e/tests/web/regression/pub-sub/{pub-sub-oss-cluster-7.ts => pub-sub-oss-cluster-7.e2e.ts} (100%) create mode 100644 tests/e2e/tests/web/regression/search-and-query/search-and-query-tab.e2e.ts delete mode 100644 tests/e2e/tests/web/regression/search-and-query/search-and-query-tab.ts diff --git a/tests/e2e/package.json b/tests/e2e/package.json index 2f9490ab86..30f8986af4 100644 --- a/tests/e2e/package.json +++ b/tests/e2e/package.json @@ -13,7 +13,7 @@ "build:ui": "yarn --cwd ../../ build:ui", "redis:last": "docker run --name redis-last-version -p 7777:6379 -d redislabs/redismod", "start:app": "cross-env yarn start:api", - "test:chrome": "testcafe --compiler-options typescript.configPath=tsconfig.testcafe.json --cache --allow-insecure-localhost --disable-multiple-windows --concurrency 1 chrome tests/ -r html:./report/report.html,spec -e -s takeOnFails=true,path=report/screenshots/,pathPattern=${OS}_${BROWSER}/${DATE}_${TIME}/${FIXTURE}_${TEST}_${FILE_INDEX}.png", + "test:chrome": "testcafe --compiler-options typescript.configPath=tsconfig.testcafe.json --cache --disable-multiple-windows --disable-search-engine-choice-screen --concurrency 1 chrome tests/ -r html:./report/report.html,spec -e -s takeOnFails=true,path=report/screenshots/,pathPattern=${OS}_${BROWSER}/${DATE}_${TIME}/${FIXTURE}_${TEST}_${FILE_INDEX}.png", "test:chrome:ci": "ts-node ./web.runner.ts", "test": "yarn test:chrome", "lint": "eslint . --ext .ts,.js,.tsx,.jsx", diff --git a/tests/e2e/pageObjects/base-run-commands-page.ts b/tests/e2e/pageObjects/base-run-commands-page.ts index cf7949b393..885933dc38 100644 --- a/tests/e2e/pageObjects/base-run-commands-page.ts +++ b/tests/e2e/pageObjects/base-run-commands-page.ts @@ -5,6 +5,7 @@ export class BaseRunCommandsPage extends InstancePage { submitCommandButton = Selector('[data-testid=btn-submit]'); queryInput = Selector('[data-testid=query-input-container]'); + queryInputForText = Selector('[data-testid=query-input-container] .view-lines'); // History containers queryCardCommand = Selector('[data-testid=query-card-command]'); @@ -23,6 +24,7 @@ export class BaseRunCommandsPage extends InstancePage { executionCommandIcon = Selector('[data-testid=command-execution-time-icon]'); executedCommandTitle = Selector('[data-testid=query-card-tooltip-anchor]', { timeout: 500 }); queryResult = Selector('[data-testid=query-common-result]'); + queryInputScriptArea = Selector('[data-testid=query-input-container] .view-line'); cssQueryCardCommand = '[data-testid=query-card-command]'; cssQueryCardContainer = '[data-testid^="query-card-container-"]'; diff --git a/tests/e2e/pageObjects/components/monaco-editor.ts b/tests/e2e/pageObjects/components/monaco-editor.ts index 642920213f..007ebaf859 100644 --- a/tests/e2e/pageObjects/components/monaco-editor.ts +++ b/tests/e2e/pageObjects/components/monaco-editor.ts @@ -10,6 +10,7 @@ export class MonacoEditor { monacoHintWithArguments = Selector('[widgetid="editor.widget.parameterHintsWidget"]'); monacoCommandIndicator = Selector('div.monaco-glyph-run-command'); monacoWidget = Selector('[data-testid=monaco-widget]'); + monacoSuggestWidget = Selector('.suggest-widget'); nonRedisEditorResizeBottom = Selector('.t_resize-bottom'); nonRedisEditorResizeTop = Selector('.t_resize-top'); diff --git a/tests/e2e/pageObjects/workbench-page.ts b/tests/e2e/pageObjects/workbench-page.ts index 196cf20339..83e83e7640 100644 --- a/tests/e2e/pageObjects/workbench-page.ts +++ b/tests/e2e/pageObjects/workbench-page.ts @@ -58,7 +58,6 @@ export class WorkbenchPage extends BaseRunCommandsPage { mainEditorArea = Selector('[data-testid=main-input-container-area]'); queryTextResult = Selector(this.cssQueryTextResult); queryColumns = Selector('[data-testid*=query-column-]'); - queryInputScriptArea = Selector('[data-testid=query-input-container] .view-line'); noCommandHistorySection = Selector('[data-testid=wb_no-results]'); noCommandHistoryTitle = Selector('[data-testid=wb_no-results__title]'); noCommandHistoryText = Selector('[data-testid=wb_no-results__summary]'); diff --git a/tests/e2e/tests/web/regression/cli/cli-promote-workbench.ts b/tests/e2e/tests/web/regression/cli/cli-promote-workbench.e2e.ts similarity index 100% rename from tests/e2e/tests/web/regression/cli/cli-promote-workbench.ts rename to tests/e2e/tests/web/regression/cli/cli-promote-workbench.e2e.ts diff --git a/tests/e2e/tests/web/regression/pub-sub/pub-sub-oss-cluster-7.ts b/tests/e2e/tests/web/regression/pub-sub/pub-sub-oss-cluster-7.e2e.ts similarity index 100% rename from tests/e2e/tests/web/regression/pub-sub/pub-sub-oss-cluster-7.ts rename to tests/e2e/tests/web/regression/pub-sub/pub-sub-oss-cluster-7.e2e.ts diff --git a/tests/e2e/tests/web/regression/search-and-query/search-and-query-tab.e2e.ts b/tests/e2e/tests/web/regression/search-and-query/search-and-query-tab.e2e.ts new file mode 100644 index 0000000000..a719287a6d --- /dev/null +++ b/tests/e2e/tests/web/regression/search-and-query/search-and-query-tab.e2e.ts @@ -0,0 +1,176 @@ +import { Common, DatabaseHelper } from '../../../../helpers'; +import { DatabaseAPIRequests } from '../../../../helpers/api/api-database'; +import { BrowserPage } from '../../../../pageObjects'; +import { ExploreTabs, KeysInteractionTabs, rte } from '../../../../helpers/constants'; +import { commonUrl, ossStandaloneConfig } from '../../../../helpers/conf'; +import { SearchAndQueryPage } from '../../../../pageObjects/search-and-query-page'; +import { APIKeyRequests } from '../../../../helpers/api/api-keys'; + +const databaseHelper = new DatabaseHelper(); +const databaseAPIRequests = new DatabaseAPIRequests(); +const browserPage = new BrowserPage(); +const searchAndQueryPage = new SearchAndQueryPage(); +const apiKeyRequests = new APIKeyRequests(); + +const keyName = Common.generateWord(10); +let keyNames: string[]; +let indexName1: string; +let indexName2: string; + +fixture `Autocomplete for entered commands in search and query` + .meta({ type: 'regression', rte: rte.standalone }) + .page(commonUrl) + .beforeEach(async() => { + await databaseHelper.acceptLicenseTermsAndAddDatabaseApi(ossStandaloneConfig); + indexName1 = `idx1:${keyName}`; + indexName2 = `idx2:${keyName}`; + keyNames = [`${keyName}:1`, `${keyName}:2`, `${keyName}:3`]; + const commands = [ + `HSET ${keyNames[0]} "name" "Hall School" "description" " Spanning 10 states" "class" "independent" "type" "traditional" "address_city" "London" "address_street" "Manor Street" "students" 342 "location" "51.445417, -0.258352"`, + `HSET ${keyNames[1]} "name" "Garden School" "description" "Garden School is a new outdoor" "class" "state" "type" "forest; montessori;" "address_city" "London" "address_street" "Gordon Street" "students" 1452 "location" "51.402926, -0.321523"`, + `HSET ${keyNames[2]} "name" "Gillford School" "description" "Gillford School is a centre" "class" "private" "type" "democratic; waldorf" "address_city" "Goudhurst" "address_street" "Goudhurst" "students" 721 "location" "51.112685, 0.451076"`, + `FT.CREATE ${indexName1} ON HASH PREFIX 1 "${keyName}:" SCHEMA name TEXT NOSTEM description TEXT class TAG type TAG SEPARATOR ";" address_city AS city TAG address_street AS address TEXT NOSTEM students NUMERIC SORTABLE location GEO`, + `FT.CREATE ${indexName2} ON HASH PREFIX 1 "${keyName}:" SCHEMA name TEXT NOSTEM description TEXT class TAG type TAG SEPARATOR ";" address_city AS city TAG address_street AS address TEXT NOSTEM students NUMERIC SORTABLE location GEO` + ]; + + // Create 3 keys and index + await browserPage.Cli.sendCommandsInCli(commands); + }) + .afterEach(async() => { + // Clear and delete database + await apiKeyRequests.deleteKeyByNameApi(keyName, ossStandaloneConfig.databaseName); + await browserPage.Cli.sendCommandsInCli([`DEL ${keyNames.join(' ')}`, `FT.DROPINDEX ${indexName1}`]); + await browserPage.Cli.sendCommandsInCli([`DEL ${keyNames.join(' ')}`, `FT.DROPINDEX ${indexName2}`]); + await databaseAPIRequests.deleteStandaloneDatabaseApi(ossStandaloneConfig); + }); +test('Verify that tutorials can be opened from Workbench', async t => { + const search = await browserPage.KeysInteractionPanel.setActiveTab(KeysInteractionTabs.SearchAndQuery); + await t.click(search.getTutorialLinkLocator('sq-exact-match')); + await t.expect(search.InsightsPanel.sidePanel.exists).ok('Insight panel is not opened'); + const tab = await browserPage.InsightsPanel.setActiveTab(ExploreTabs.Tutorials); + await t.expect(tab.preselectArea.textContent).contains('EXACT MATCH', 'the tutorial page is incorrect'); +}); +test('Verify full commands suggestions with index and query for FT.AGGREGATE', async t => { + const groupByArgInfo = 'GROUPBY nargs property [property ...] [REDUCE function nargs arg [arg ...] [AS name] [REDUCE function nargs arg [arg ...] [AS name] ...]]'; + const indexFields = [ + 'address', + 'city', + 'class', + 'description', + 'location', + 'name', + 'students', + 'type' + ]; + const commandDetails = [ + 'index query [VERBATIM] [LOAD count field [field ...]]', + 'Run a search query on an index and perform aggregate transformations on the results', + 'Arguments:', + 'required index', + 'required query', + 'optional [verbatim]' + ]; + await browserPage.KeysInteractionPanel.setActiveTab(KeysInteractionTabs.SearchAndQuery); + + // Verify basic commands suggestions FT.SEARCH and FT.AGGREGATE + await t.typeText(searchAndQueryPage.queryInput, 'FT', { replace: true }); + // Verify that the list with FT.SEARCH and FT.AGGREGATE auto-suggestions is displayed + await t.expect(searchAndQueryPage.MonacoEditor.monacoSuggestion.count).eql(2, 'FT.SEARCH and FT.AGGREGATE auto-suggestions are not displayed'); + // Verify that user can use show more to see command fully in 2nd tooltip + await t.pressKey('ctrl+space'); + await t.expect(searchAndQueryPage.MonacoEditor.monacoCommandDetails.exists).ok('The "read more" about the command is not opened'); + for(const detail of commandDetails) { + await t.expect(searchAndQueryPage.MonacoEditor.monacoCommandDetails.textContent).contains(detail, `The ${detail} command detail is not displayed`); + } + // Verify that user can close show more tooltip by 'x' or 'Show less' + await t.pressKey('ctrl+space'); + await t.expect(searchAndQueryPage.MonacoEditor.monacoCommandDetails.exists).notOk('The "read more" about the command is not closed'); + // Select command and check result + await t.pressKey('enter'); + let script = await searchAndQueryPage.queryInputScriptArea.textContent; + await t.expect(script.replace(/\s/g, ' ')).contains('FT.AGGREGATE ', 'Result of sent command exists'); + + // Verify that user can see the list of all the indexes in database when put a space after only FT.SEARCH and FT.AGGREGATE commands + await t.expect(script.replace(/\s/g, ' ')).contains(`"${indexName1}" "" `, 'Index not suggested into input'); + await t.expect(searchAndQueryPage.MonacoEditor.monacoSuggestion.withExactText(indexName1).exists).ok('Index not auto-suggested'); + await t.expect(searchAndQueryPage.MonacoEditor.monacoSuggestion.withExactText(indexName2).exists).ok('All indexes not auto-suggested'); + + await t.pressKey('tab'); + await t.typeText(searchAndQueryPage.queryInput, '@', { replace: false }); + script = await searchAndQueryPage.queryInputScriptArea.textContent; + // Verify that user can see the list of fields from the index selected when type in “@” + await t.expect(script.replace(/\s/g, ' ')).contains('address', 'Index not suggested into input'); + for(const field of indexFields) { + await t.expect(searchAndQueryPage.MonacoEditor.monacoSuggestion.withExactText(field).exists).ok(`${field} Index field not auto-suggested`); + } + // Verify that user can use autosuggestions by typing fields from index after "@" + await t.typeText(searchAndQueryPage.queryInput, 'c', { replace: false }); + await t.expect(searchAndQueryPage.MonacoEditor.monacoSuggestion.withExactText('city').exists).ok('Index field not auto-suggested after starting typing'); + await t.expect(searchAndQueryPage.MonacoEditor.monacoSuggestion.count).eql(1, 'Wrong index fields suggested after typing first letter'); + + // Verify contextual suggestions after typing letters for commands + await t.pressKey('tab'); + await t.pressKey('right'); + await t.pressKey('space'); + await t.expect(searchAndQueryPage.MonacoEditor.monacoSuggestion.withExactText('APPLY').exists).ok('FT.AGGREGATE arguments not suggested'); + await t.typeText(searchAndQueryPage.queryInput, 'g', { replace: false }); + await t.expect(searchAndQueryPage.MonacoEditor.monacoSuggestion.nth(0).textContent).contains('GROUPBY', 'Argument not suggested after typing first letters'); + + await t.pressKey('tab'); + // Verify that user can see widget about entered argument + await t.expect(searchAndQueryPage.MonacoEditor.monacoHintWithArguments.withText(groupByArgInfo).exists).ok('Widget with info about entered argument not displayed'); + + await t.typeText(searchAndQueryPage.queryInput, '1 "London"', { replace: false }); + await t.pressKey('space'); + // Verify correct order of suggested arguments like LOAD, GROUPBY, SORTBY + await t.expect(searchAndQueryPage.MonacoEditor.monacoSuggestion.nth(0).textContent).contains('REDUCE', 'Incorrect order of suggested arguments'); + await t.pressKey('tab'); + await t.typeText(searchAndQueryPage.queryInput, 'SUM 1 @students', { replace: false }); + await t.pressKey('space'); + + // Verify expression and function suggestions like AS for APPLY/GROUPBY + await t.expect(searchAndQueryPage.MonacoEditor.monacoSuggestion.nth(0).textContent).contains('AS', 'Incorrect order of suggested arguments'); + await t.pressKey('tab'); + await t.typeText(searchAndQueryPage.queryInput, 'stud', { replace: false }); + + await t.pressKey('space'); + // Verify multiple argument option suggestions + await t.expect(searchAndQueryPage.MonacoEditor.monacoSuggestion.nth(0).textContent).contains('REDUCE', 'Incorrect order of suggested arguments'); + // Verify complex command sequences like nargs and properties are suggested accurately for GROUPBY + const expectedText = `FT.AGGREGATE "${indexName1}" "@city" GROUPBY 1 "London" REDUCE SUM 1 @students AS stud REDUCE`.trim().replace(/\s+/g, ' '); + await t.expect((await searchAndQueryPage.queryInputForText.innerText).trim().replace(/\s+/g, ' ')).contains(expectedText, 'Incorrect order of entered arguments'); +}); +test('Verify full commands suggestions with index and query for FT.SEARCH', async t => { + await browserPage.KeysInteractionPanel.setActiveTab(KeysInteractionTabs.SearchAndQuery); + await t.typeText(searchAndQueryPage.queryInput, 'FT', { replace: true }); + // Select command and check result + await t.pressKey('down'); + await t.pressKey('enter'); + const script = await searchAndQueryPage.queryInputScriptArea.textContent; + await t.expect(script.replace(/\s/g, ' ')).contains('FT.SEARCH ', 'Result of sent command exists'); + + await t.pressKey('tab'); + await t.typeText(searchAndQueryPage.queryInput, '@c', { replace: false }); + // Select '@city' field + await t.pressKey('down'); + await t.pressKey('tab'); + await t.pressKey('right'); + await t.pressKey('space'); + await t.expect(searchAndQueryPage.MonacoEditor.monacoSuggestion.withExactText('DIALECT').exists).ok('FT.SEARCH arguments not suggested'); + await t.typeText(searchAndQueryPage.queryInput, 'n', { replace: false }); + await t.expect(searchAndQueryPage.MonacoEditor.monacoSuggestion.nth(0).textContent).contains('NOCONTENT', 'Argument not suggested after typing first letters'); + await t.pressKey('tab'); + // Verify that FT.SEARCH and FT.AGGREGATE non-multiple arguments are suggested only once + await t.pressKey('space'); + await t.expect(searchAndQueryPage.MonacoEditor.monacoSuggestion.withText('NOCONTENT').exists).notOk('Non-multiple arguments are suggested not only once'); + + // Verify that suggestions correct to closest valid commands or options for invalid typing like WRONGCOMMAND + await t.typeText(searchAndQueryPage.queryInput, 'WRONGCOMMAND', { replace: false }); + await t.expect(searchAndQueryPage.MonacoEditor.monacoSuggestion.withExactText('WITHSORTKEYS').exists).ok('Closest suggestions not displayed'); + + await t.pressKey('space'); + await t.pressKey('backspace'); + await t.pressKey('backspace'); + // Verify that 'No suggestions' tooltip is displayed when returning to invalid typing like WRONGCOMMAND + await t.expect(searchAndQueryPage.MonacoEditor.monacoSuggestWidget.textContent).contains('No suggestions.', 'Index not auto-suggested'); +}); \ No newline at end of file diff --git a/tests/e2e/tests/web/regression/search-and-query/search-and-query-tab.ts b/tests/e2e/tests/web/regression/search-and-query/search-and-query-tab.ts deleted file mode 100644 index 9c5c4ec175..0000000000 --- a/tests/e2e/tests/web/regression/search-and-query/search-and-query-tab.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { DatabaseHelper } from '../../../../helpers'; -import { DatabaseAPIRequests } from '../../../../helpers/api/api-database'; -import { BrowserPage } from '../../../../pageObjects'; -import { ExploreTabs, KeysInteractionTabs, rte } from '../../../../helpers/constants'; -import { commonUrl, ossStandaloneConfig } from '../../../../helpers/conf'; - -const databaseHelper = new DatabaseHelper(); -const databaseAPIRequests = new DatabaseAPIRequests(); -const browserPage = new BrowserPage(); - -fixture `Autocomplete for entered commands` - .meta({ type: 'regression', rte: rte.standalone }) - .page(commonUrl) - .beforeEach(async t => { - await databaseHelper.acceptLicenseTermsAndAddDatabaseApi(ossStandaloneConfig); - }) - .afterEach(async() => { - // Delete database - await databaseAPIRequests.deleteStandaloneDatabaseApi(ossStandaloneConfig); - }); -test('Verify that tutorials can be opened from Workbench', async t => { - const search = await browserPage.KeysInteractionPanel.setActiveTab(KeysInteractionTabs.SearchAndQuery); - await t.click(search.getTutorialLinkLocator('sq-exact-match')); - await t.expect(search.InsightsPanel.sidePanel.exists).ok('Insight panel is not opened'); - const tab = await browserPage.InsightsPanel.setActiveTab(ExploreTabs.Tutorials); - await t.expect(tab.preselectArea.textContent).contains('EXACT MATCH', 'the tutorial page is incorrect'); -}); diff --git a/tests/e2e/web.runner.ts b/tests/e2e/web.runner.ts index e77ccc1030..8d0c83e7a9 100644 --- a/tests/e2e/web.runner.ts +++ b/tests/e2e/web.runner.ts @@ -11,7 +11,7 @@ import testcafe from 'testcafe'; experimentalDecorators: true } }) .src((process.env.TEST_FILES || 'tests/web/**/*.e2e.ts').split('\n')) - .browsers(['chromium:headless --cache --allow-insecure-localhost --ignore-certificate-errors']) + .browsers(['chromium:headless --cache --allow-insecure-localhost --disable-search-engine-choice-screen --ignore-certificate-errors']) .screenshots({ path: 'report/screenshots/', takeOnFails: true, @@ -38,7 +38,7 @@ import testcafe from 'testcafe'; selectorTimeout: 5000, assertionTimeout: 5000, speed: 1, - quarantineMode: { successThreshold: 1, attemptLimit: 3 }, + // quarantineMode: { successThreshold: 1, attemptLimit: 3 }, pageRequestTimeout: 8000, disableMultipleWindows: true }); From 3ffb4dda3a57b02af0bfb5cf66672ef5ee5f7514 Mon Sep 17 00:00:00 2001 From: vlad-dargel Date: Fri, 9 Aug 2024 16:38:22 +0200 Subject: [PATCH 025/256] uncomment row for web runner --- tests/e2e/web.runner.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/e2e/web.runner.ts b/tests/e2e/web.runner.ts index 8d0c83e7a9..cb090db3ae 100644 --- a/tests/e2e/web.runner.ts +++ b/tests/e2e/web.runner.ts @@ -38,7 +38,7 @@ import testcafe from 'testcafe'; selectorTimeout: 5000, assertionTimeout: 5000, speed: 1, - // quarantineMode: { successThreshold: 1, attemptLimit: 3 }, + quarantineMode: { successThreshold: 1, attemptLimit: 3 }, pageRequestTimeout: 8000, disableMultipleWindows: true }); From a58ec5988d59dbefa1a91d6b2ee3f31f95611e52 Mon Sep 17 00:00:00 2001 From: vlad-dargel Date: Mon, 12 Aug 2024 17:13:16 +0200 Subject: [PATCH 026/256] fix by pr comments and some updates --- tests/e2e/desktop.runner.ci.ts | 53 +++++++++++++++++++ tests/e2e/desktop.runner.ts | 1 - tests/e2e/package.json | 8 +-- .../e2e/pageObjects/base-run-commands-page.ts | 2 +- .../workbench/index-schema.e2e.ts | 2 +- .../regression/browser/key-messages.e2e.ts | 3 +- .../web/regression/browser/onboarding.e2e.ts | 2 + .../web/regression/browser/ttl-format.e2e.ts | 6 +-- .../search-and-query-tab.e2e.ts | 38 +++++++------ tests/e2e/web.runner.ci.ts | 53 +++++++++++++++++++ tests/e2e/web.runner.ts | 3 +- 11 files changed, 140 insertions(+), 31 deletions(-) create mode 100644 tests/e2e/desktop.runner.ci.ts create mode 100644 tests/e2e/web.runner.ci.ts diff --git a/tests/e2e/desktop.runner.ci.ts b/tests/e2e/desktop.runner.ci.ts new file mode 100644 index 0000000000..dfb4bcf3f2 --- /dev/null +++ b/tests/e2e/desktop.runner.ci.ts @@ -0,0 +1,53 @@ +import testcafe from 'testcafe'; + +(async(): Promise => { + await testcafe('localhost') + .then(t => { + return t + .createRunner() + .compilerOptions({ + 'typescript': { + configPath: 'tsconfig.testcafe.json', + experimentalDecorators: true + } }) + .src((process.env.TEST_FILES || 'tests/electron/**/*.e2e.ts').split('\n')) + .browsers(['electron']) + .screenshots({ + path: './report/screenshots/', + takeOnFails: true, + pathPattern: '${USERAGENT}/${DATE}_${TIME}/${FIXTURE}_${TEST}_${FILE_INDEX}.png' + }) + .reporter([ + 'spec', + { + name: 'xunit', + output: './results/results.xml' + }, + { + name: 'json', + output: './results/e2e.results.json' + }, + { + name: 'html', + output: './report/report.html' + } + ]) + .run({ + skipJsErrors: true, + browserInitTimeout: 60000, + selectorTimeout: 5000, + assertionTimeout: 5000, + speed: 1, + quarantineMode: { successThreshold: 1, attemptLimit: 3 }, + pageRequestTimeout: 8000, + disableMultipleWindows: true + }); + }) + .then((failedCount) => { + process.exit(failedCount); + }) + .catch((e) => { + console.error(e); + process.exit(1); + }); +})(); diff --git a/tests/e2e/desktop.runner.ts b/tests/e2e/desktop.runner.ts index dfb4bcf3f2..7afe4f0daf 100644 --- a/tests/e2e/desktop.runner.ts +++ b/tests/e2e/desktop.runner.ts @@ -38,7 +38,6 @@ import testcafe from 'testcafe'; selectorTimeout: 5000, assertionTimeout: 5000, speed: 1, - quarantineMode: { successThreshold: 1, attemptLimit: 3 }, pageRequestTimeout: 8000, disableMultipleWindows: true }); diff --git a/tests/e2e/package.json b/tests/e2e/package.json index 30f8986af4..8b6db4b9dc 100644 --- a/tests/e2e/package.json +++ b/tests/e2e/package.json @@ -13,13 +13,13 @@ "build:ui": "yarn --cwd ../../ build:ui", "redis:last": "docker run --name redis-last-version -p 7777:6379 -d redislabs/redismod", "start:app": "cross-env yarn start:api", - "test:chrome": "testcafe --compiler-options typescript.configPath=tsconfig.testcafe.json --cache --disable-multiple-windows --disable-search-engine-choice-screen --concurrency 1 chrome tests/ -r html:./report/report.html,spec -e -s takeOnFails=true,path=report/screenshots/,pathPattern=${OS}_${BROWSER}/${DATE}_${TIME}/${FIXTURE}_${TEST}_${FILE_INDEX}.png", - "test:chrome:ci": "ts-node ./web.runner.ts", + "test:chrome": "ts-node ./web.runner.ts", + "test:chrome:ci": "ts-node ./web.runner.ci.ts", "test": "yarn test:chrome", "lint": "eslint . --ext .ts,.js,.tsx,.jsx", - "test:desktop:ci": "ts-node ./desktop.runner.ts", + "test:desktop:ci": "ts-node ./desktop.runner.ci.ts", "test:desktop:ci:win": "ts-node ./desktop.runner.win.ts", - "test:desktop": "testcafe electron tests/ --compiler-options typescript.configPath=tsconfig.testcafe.json --browser-init-timeout 180000 -e -r html:./report/desktop-report.html,spec -s takeOnFails=true,path=report/screenshots/,pathPattern=${OS}_${BROWSER}/${DATE}_${TIME}/${FIXTURE}_${TEST}_${FILE_INDEX}.png" + "test:desktop": "ts-node ./desktop.runner.ts" }, "keywords": [], "author": "", diff --git a/tests/e2e/pageObjects/base-run-commands-page.ts b/tests/e2e/pageObjects/base-run-commands-page.ts index 885933dc38..b9c965ecfa 100644 --- a/tests/e2e/pageObjects/base-run-commands-page.ts +++ b/tests/e2e/pageObjects/base-run-commands-page.ts @@ -33,7 +33,7 @@ export class BaseRunCommandsPage extends InstancePage { cssDeleteCommandButton = '[data-testid=delete-command]'; getTutorialLinkLocator = (tutorialName: string): Selector => - Selector(`[@data-testid="data-testid=query-tutorials-link_${tutorialName}"]`); + Selector(`[data-testid=query-tutorials-link_${tutorialName}]`); /** * Get card container by command diff --git a/tests/e2e/tests/electron/critical-path/workbench/index-schema.e2e.ts b/tests/e2e/tests/electron/critical-path/workbench/index-schema.e2e.ts index 98e1f7f811..9f55e7f9f3 100644 --- a/tests/e2e/tests/electron/critical-path/workbench/index-schema.e2e.ts +++ b/tests/e2e/tests/electron/critical-path/workbench/index-schema.e2e.ts @@ -20,7 +20,7 @@ fixture `Index Schema at Workbench` await databaseHelper.acceptLicenseTermsAndAddDatabaseApi(ossStandaloneRedisearch); // Go to Workbench page await t.click(myRedisDatabasePage.NavigationPanel.browserButton); - await browserPage.KeysInteractionPanel.setActiveTab(KeysInteractionTabs.Workbench);; + await browserPage.KeysInteractionPanel.setActiveTab(KeysInteractionTabs.Workbench); }) .afterEach(async t => { // Drop index, documents and database diff --git a/tests/e2e/tests/web/regression/browser/key-messages.e2e.ts b/tests/e2e/tests/web/regression/browser/key-messages.e2e.ts index f000bc28af..867b8c6b86 100644 --- a/tests/e2e/tests/web/regression/browser/key-messages.e2e.ts +++ b/tests/e2e/tests/web/regression/browser/key-messages.e2e.ts @@ -1,4 +1,4 @@ -import { rte } from '../../../../helpers/constants'; +import { KeysInteractionTabs, rte } from '../../../../helpers/constants'; import { DatabaseHelper } from '../../../../helpers/database'; import { BrowserPage, MyRedisDatabasePage, WorkbenchPage } from '../../../../pageObjects'; import { commonUrl, ossStandaloneConfig } from '../../../../helpers/conf'; @@ -62,6 +62,7 @@ test('Verify that user can see link to Workbench under word “Workbench” in t // Add key and verify Workbench link await browserPage.Cli.sendCommandInCli(commands[i]); + await browserPage.KeysInteractionPanel.setActiveTab(KeysInteractionTabs.BrowserAndFilter); await browserPage.searchByKeyName(keyName); await t.click(browserPage.keyNameInTheList); await t.click(browserPage.internalLinkToWorkbench); diff --git a/tests/e2e/tests/web/regression/browser/onboarding.e2e.ts b/tests/e2e/tests/web/regression/browser/onboarding.e2e.ts index 80d3961e34..a38078a197 100644 --- a/tests/e2e/tests/web/regression/browser/onboarding.e2e.ts +++ b/tests/e2e/tests/web/regression/browser/onboarding.e2e.ts @@ -137,6 +137,7 @@ test('Verify onboard new user skip tour', async(t) => { await t.expect(myRedisDatabasePage.NavigationPanel.HelpCenter.helpCenterPanel.visible).ok('help center panel is not opened'); await t.click(onboardingCardsDialog.resetOnboardingBtn); await t.click(myRedisDatabasePage.NavigationPanel.browserButton); + await browserPage.KeysInteractionPanel.setActiveTab(KeysInteractionTabs.BrowserAndFilter); // Verify that when user reset onboarding, user can see the onboarding triggered when user open the Browser page. await t.expect(onboardingCardsDialog.showMeAroundButton.visible).ok('onboarding starting is not visible'); // click skip tour @@ -171,6 +172,7 @@ test.requestHooks(logger)('Verify that the final onboarding step is closed when await t.expect(onboardingCardsDialog.stepTitle.exists).notOk('Onboarding tooltip still visible'); // Go to Browser Page await t.click(myRedisDatabasePage.NavigationPanel.browserButton); + await browserPage.KeysInteractionPanel.setActiveTab(KeysInteractionTabs.BrowserAndFilter); // Verify onboarding completed successfully await onboardingCardsDialog.completeOnboarding(); await t.expect(browserPage.patternModeBtn.visible).ok('Browser page is not opened'); diff --git a/tests/e2e/tests/web/regression/browser/ttl-format.e2e.ts b/tests/e2e/tests/web/regression/browser/ttl-format.e2e.ts index ba39510384..8e91c20f0e 100644 --- a/tests/e2e/tests/web/regression/browser/ttl-format.e2e.ts +++ b/tests/e2e/tests/web/regression/browser/ttl-format.e2e.ts @@ -1,6 +1,6 @@ import { Selector } from 'testcafe'; import { DatabaseHelper } from '../../../../helpers/database'; -import { keyTypes } from '../../../../helpers/keys'; +import { deleteKeysViaCli, keyTypes } from '../../../../helpers/keys'; import { rte, COMMANDS_TO_CREATE_KEY, keyLength } from '../../../../helpers/constants'; import { BrowserPage } from '../../../../pageObjects'; import { commonUrl, ossStandaloneConfig } from '../../../../helpers/conf'; @@ -31,9 +31,7 @@ fixture `TTL values in Keys Table` }) .afterEach(async() => { // Clear and delete database - for (let i = 0; i < keysData.length; i++) { - await browserPage.deleteKey(); - } + await deleteKeysViaCli(keysData); await databaseAPIRequests.deleteStandaloneDatabaseApi(ossStandaloneConfig); }); test('Verify that user can see TTL in the list of keys rounded down to the nearest unit', async t => { diff --git a/tests/e2e/tests/web/regression/search-and-query/search-and-query-tab.e2e.ts b/tests/e2e/tests/web/regression/search-and-query/search-and-query-tab.e2e.ts index a719287a6d..ff3a339217 100644 --- a/tests/e2e/tests/web/regression/search-and-query/search-and-query-tab.e2e.ts +++ b/tests/e2e/tests/web/regression/search-and-query/search-and-query-tab.e2e.ts @@ -50,18 +50,7 @@ test('Verify that tutorials can be opened from Workbench', async t => { const tab = await browserPage.InsightsPanel.setActiveTab(ExploreTabs.Tutorials); await t.expect(tab.preselectArea.textContent).contains('EXACT MATCH', 'the tutorial page is incorrect'); }); -test('Verify full commands suggestions with index and query for FT.AGGREGATE', async t => { - const groupByArgInfo = 'GROUPBY nargs property [property ...] [REDUCE function nargs arg [arg ...] [AS name] [REDUCE function nargs arg [arg ...] [AS name] ...]]'; - const indexFields = [ - 'address', - 'city', - 'class', - 'description', - 'location', - 'name', - 'students', - 'type' - ]; +test('Verify that user can use show more to see command fully in 2nd tooltip', async t => { const commandDetails = [ 'index query [VERBATIM] [LOAD count field [field ...]]', 'Run a search query on an index and perform aggregate transformations on the results', @@ -71,11 +60,7 @@ test('Verify full commands suggestions with index and query for FT.AGGREGATE', a 'optional [verbatim]' ]; await browserPage.KeysInteractionPanel.setActiveTab(KeysInteractionTabs.SearchAndQuery); - - // Verify basic commands suggestions FT.SEARCH and FT.AGGREGATE await t.typeText(searchAndQueryPage.queryInput, 'FT', { replace: true }); - // Verify that the list with FT.SEARCH and FT.AGGREGATE auto-suggestions is displayed - await t.expect(searchAndQueryPage.MonacoEditor.monacoSuggestion.count).eql(2, 'FT.SEARCH and FT.AGGREGATE auto-suggestions are not displayed'); // Verify that user can use show more to see command fully in 2nd tooltip await t.pressKey('ctrl+space'); await t.expect(searchAndQueryPage.MonacoEditor.monacoCommandDetails.exists).ok('The "read more" about the command is not opened'); @@ -85,6 +70,25 @@ test('Verify full commands suggestions with index and query for FT.AGGREGATE', a // Verify that user can close show more tooltip by 'x' or 'Show less' await t.pressKey('ctrl+space'); await t.expect(searchAndQueryPage.MonacoEditor.monacoCommandDetails.exists).notOk('The "read more" about the command is not closed'); +}); +test('Verify full commands suggestions with index and query for FT.AGGREGATE', async t => { + const groupByArgInfo = 'GROUPBY nargs property [property ...] [REDUCE function nargs arg [arg ...] [AS name] [REDUCE function nargs arg [arg ...] [AS name] ...]]'; + const indexFields = [ + 'address', + 'city', + 'class', + 'description', + 'location', + 'name', + 'students', + 'type' + ]; + await browserPage.KeysInteractionPanel.setActiveTab(KeysInteractionTabs.SearchAndQuery); + + // Verify basic commands suggestions FT.SEARCH and FT.AGGREGATE + await t.typeText(searchAndQueryPage.queryInput, 'FT', { replace: true }); + // Verify that the list with FT.SEARCH and FT.AGGREGATE auto-suggestions is displayed + await t.expect(searchAndQueryPage.MonacoEditor.monacoSuggestion.count).eql(2, 'FT.SEARCH and FT.AGGREGATE auto-suggestions are not displayed'); // Select command and check result await t.pressKey('enter'); let script = await searchAndQueryPage.queryInputScriptArea.textContent; @@ -173,4 +177,4 @@ test('Verify full commands suggestions with index and query for FT.SEARCH', asyn await t.pressKey('backspace'); // Verify that 'No suggestions' tooltip is displayed when returning to invalid typing like WRONGCOMMAND await t.expect(searchAndQueryPage.MonacoEditor.monacoSuggestWidget.textContent).contains('No suggestions.', 'Index not auto-suggested'); -}); \ No newline at end of file +}); diff --git a/tests/e2e/web.runner.ci.ts b/tests/e2e/web.runner.ci.ts new file mode 100644 index 0000000000..cb090db3ae --- /dev/null +++ b/tests/e2e/web.runner.ci.ts @@ -0,0 +1,53 @@ +import testcafe from 'testcafe'; + +(async(): Promise => { + await testcafe() + .then(t => { + return t + .createRunner() + .compilerOptions({ + 'typescript': { + configPath: 'tsconfig.testcafe.json', + experimentalDecorators: true + } }) + .src((process.env.TEST_FILES || 'tests/web/**/*.e2e.ts').split('\n')) + .browsers(['chromium:headless --cache --allow-insecure-localhost --disable-search-engine-choice-screen --ignore-certificate-errors']) + .screenshots({ + path: 'report/screenshots/', + takeOnFails: true, + pathPattern: '${OS}_${BROWSER}/${DATE}_${TIME}/${FIXTURE}_${TEST}_${FILE_INDEX}.png' + }) + .reporter([ + 'spec', + { + name: 'xunit', + output: './results/results.xml' + }, + { + name: 'json', + output: './results/e2e.results.json' + }, + { + name: 'html', + output: './report/report.html' + } + ]) + .run({ + skipJsErrors: true, + browserInitTimeout: 60000, + selectorTimeout: 5000, + assertionTimeout: 5000, + speed: 1, + quarantineMode: { successThreshold: 1, attemptLimit: 3 }, + pageRequestTimeout: 8000, + disableMultipleWindows: true + }); + }) + .then((failedCount) => { + process.exit(failedCount); + }) + .catch((e) => { + console.error(e); + process.exit(1); + }); +})(); diff --git a/tests/e2e/web.runner.ts b/tests/e2e/web.runner.ts index cb090db3ae..a30406f2ce 100644 --- a/tests/e2e/web.runner.ts +++ b/tests/e2e/web.runner.ts @@ -11,7 +11,7 @@ import testcafe from 'testcafe'; experimentalDecorators: true } }) .src((process.env.TEST_FILES || 'tests/web/**/*.e2e.ts').split('\n')) - .browsers(['chromium:headless --cache --allow-insecure-localhost --disable-search-engine-choice-screen --ignore-certificate-errors']) + .browsers(['chrome --cache --allow-insecure-localhost --disable-search-engine-choice-screen --ignore-certificate-errors']) .screenshots({ path: 'report/screenshots/', takeOnFails: true, @@ -38,7 +38,6 @@ import testcafe from 'testcafe'; selectorTimeout: 5000, assertionTimeout: 5000, speed: 1, - quarantineMode: { successThreshold: 1, attemptLimit: 3 }, pageRequestTimeout: 8000, disableMultipleWindows: true }); From be0974047c1b1f5a50c4295db1ae92d446fbfeb5 Mon Sep 17 00:00:00 2001 From: vlad-dargel Date: Mon, 12 Aug 2024 20:46:37 +0200 Subject: [PATCH 027/256] fix for failed test --- .../web/critical-path/database-overview/database-index.e2e.ts | 2 +- .../tests/web/regression/insights/live-recommendations.e2e.ts | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/e2e/tests/web/critical-path/database-overview/database-index.e2e.ts b/tests/e2e/tests/web/critical-path/database-overview/database-index.e2e.ts index c87bbcb487..59a7c860e3 100644 --- a/tests/e2e/tests/web/critical-path/database-overview/database-index.e2e.ts +++ b/tests/e2e/tests/web/critical-path/database-overview/database-index.e2e.ts @@ -111,7 +111,7 @@ test('Switching between indexed databases', async t => { await workbenchPage.checkWorkbenchCommandResult(`[db1] ${command}`, '8'); // Open Browser page - await t.click(myRedisDatabasePage.NavigationPanel.browserButton); + await browserPage.KeysInteractionPanel.setActiveTab(KeysInteractionTabs.SearchAndQuery); // Clear filter await t.click(browserPage.clearFilterButton); // Verify that data changed for indexed db on Workbench page (on Search capability page) diff --git a/tests/e2e/tests/web/regression/insights/live-recommendations.e2e.ts b/tests/e2e/tests/web/regression/insights/live-recommendations.e2e.ts index 0a2b177e2b..30f2d00cfe 100644 --- a/tests/e2e/tests/web/regression/insights/live-recommendations.e2e.ts +++ b/tests/e2e/tests/web/regression/insights/live-recommendations.e2e.ts @@ -275,7 +275,6 @@ test await t.click(tab.analyzeDatabaseLink); await t.click(tab.analyzeTooltipButton); await t.click(memoryEfficiencyPage.recommendationsTab); - await memoryEfficiencyPage.getRecommendationButtonByName(RecommendationIds.searchJson); keyNameFromRecommendation = await tab.getRecommendationByName(RecommendationIds.searchJson) .find(tab.cssKeyName) .innerText; From 92db7cf11f7183b4e1f8cde4427030e8e8411e6d Mon Sep 17 00:00:00 2001 From: Roman Sergeenko Date: Tue, 13 Aug 2024 15:08:34 +0200 Subject: [PATCH 028/256] #RI-5982 - add tokenizer for search and query fix bugs --- .../pages/search/components/query/Query.tsx | 79 +++++++-- .../search/components/query/constants.ts | 2 +- .../pages/search/components/query/utils.ts | 10 +- .../monacoRedisMonarchTokensProvider.ts | 8 +- .../ui/src/utils/monaco/monacoThemes.ts | 43 +++++ .../monaco/monarchTokens/redisearchTokens.ts | 152 ++++++++++++++++++ 6 files changed, 270 insertions(+), 24 deletions(-) create mode 100644 redisinsight/ui/src/utils/monaco/monacoThemes.ts create mode 100644 redisinsight/ui/src/utils/monaco/monarchTokens/redisearchTokens.ts diff --git a/redisinsight/ui/src/pages/search/components/query/Query.tsx b/redisinsight/ui/src/pages/search/components/query/Query.tsx index e5be89b8ab..aace67a0f1 100644 --- a/redisinsight/ui/src/pages/search/components/query/Query.tsx +++ b/redisinsight/ui/src/pages/search/components/query/Query.tsx @@ -10,18 +10,24 @@ import { IEditorMount } from 'uiSrc/pages/workbench/interfaces' import { findCurrentArgument, getRange, - getRediSearchSignutureProvider, setCursorPositionAtTheEnd, + getRediSearchSignutureProvider, + setCursorPositionAtTheEnd, splitQueryByArgs } from 'uiSrc/pages/search/utils' -import { SearchCommand } from 'uiSrc/pages/search/types' +import { SearchCommand, TokenType } from 'uiSrc/pages/search/types' import { RedisResponseBuffer } from 'uiSrc/slices/interfaces' import { fetchRedisearchInfoAction } from 'uiSrc/slices/browser/redisearch' +import { getRediSearchMonarchTokensProvider } from 'uiSrc/utils/monaco/monarchTokens/redisearchTokens' +import { installRedisearchTheme, RedisearchMonacoTheme } from 'uiSrc/utils/monaco/monacoThemes' +import { useDebouncedEffect } from 'uiSrc/services' import { SUPPORTED_COMMANDS_LIST, options, DefinedArgumentName } from './constants' import { getFieldsSuggestions, getIndexesSuggestions, asSuggestionsRef, - getMandatoryArgumentSuggestions, getOptionalSuggestions, getCommandsSuggestions + getMandatoryArgumentSuggestions, + getOptionalSuggestions, + getCommandsSuggestions } from './utils' export interface Props { @@ -34,6 +40,7 @@ const Query = (props: Props) => { const { value, onChange, indexes } = props const { spec: REDIS_COMMANDS_SPEC } = useSelector(appRedisCommandsSelector) + const [selectedCommand, setSelectedCommand] = useState('') const [selectedIndex, setSelectedIndex] = useState('') const SUPPORTED_COMMANDS = SUPPORTED_COMMANDS_LIST.map((name) => ({ @@ -69,16 +76,23 @@ const Query = (props: Props) => { }, [indexes]) useEffect(() => { + monacoEditor.languages.setMonarchTokensProvider( + MonacoLanguage.RediSearch, + getRediSearchMonarchTokensProvider(SUPPORTED_COMMANDS, selectedCommand) + ) + }, [selectedCommand]) + + useDebouncedEffect(() => { if (!selectedIndex) return + // TODO: add check is selectedIndex is complete (", "\", "dwadawd) - do not request const index = selectedIndex.replace(/^(['"])(.*)\1$/, '$2') - dispatch(fetchRedisearchInfoAction(index, (data) => { const { attributes } = data as any attributesRef.current = attributes })) - }, [selectedIndex]) + }, 200, [selectedIndex]) const editorDidMount = ( editor: monacoEditor.editor.IStandaloneCodeEditor, @@ -93,11 +107,17 @@ const Query = (props: Props) => { const position = editor.getPosition() if (position?.column === 1 && position?.lineNumber === 1) { + editor.focus() suggestionsRef.current = getSuggestions(editor) triggerSuggestions() } } + monaco.languages.setMonarchTokensProvider( + MonacoLanguage.RediSearch, + getRediSearchMonarchTokensProvider(SUPPORTED_COMMANDS) + ) + disposeSignatureHelpProvider.current?.() disposeSignatureHelpProvider.current = monaco.languages.registerSignatureHelpProvider(MonacoLanguage.RediSearch, { provideSignatureHelp: (): any => getRediSearchSignutureProvider(helpWidgetRef?.current) @@ -109,6 +129,7 @@ const Query = (props: Props) => { ({ suggestions: suggestionsRef.current.data }) }).dispose + installRedisearchTheme() editor.onDidChangeCursorPosition(handleCursorChange) } @@ -123,15 +144,21 @@ const Query = (props: Props) => { } suggestionsRef.current = getSuggestions(editor) + if (suggestionsRef.current.data.length) { - triggerSuggestions() helpWidgetRef.current.isOpen = false + triggerSuggestions() return } + editor?.trigger('', 'editor.action.triggerParameterHints', '') + + const suggestController = editor.getContribution('editor.contrib.suggestController') + const suggestModel = suggestController?.model + helpWidgetRef.current.isOpen = suggestModel?.state === 0 && helpWidgetRef.current.isOpen + if (suggestionsRef.current.forceHide) { setTimeout(() => editor?.trigger('', 'hideSuggestWidget', null), 0) - editor?.trigger('', 'editor.action.triggerParameterHints', '') } } @@ -160,35 +187,53 @@ const Query = (props: Props) => { const { args, isCursorInArg, prevCursorChar, nextCursorChar } = splitQueryByArgs(value, offset) const allArgs = args.flat() - const [beforeOffsetArgs] = args + const [beforeOffsetArgs, [currentOffsetArg]] = args const [firstArg, ...prevArgs] = beforeOffsetArgs - const commandName = firstArg?.toUpperCase() + const commandName = (firstArg || currentOffsetArg)?.toUpperCase() const command = REDIS_COMMANDS_SPEC[commandName] as unknown as SearchCommand - if (!command && position.lineNumber === 1 && word.startColumn === 1) { + const isCommandSuppurted = SUPPORTED_COMMANDS + .some(({ name }) => commandName === name) + if (command && !isCommandSuppurted) return asSuggestionsRef([]) + + if (!command && position.lineNumber === 1 && position.column === 1) { return getCommandsSuggestions(SUPPORTED_COMMANDS, range) } - if (!command) return asSuggestionsRef([]) + if (!command) { + helpWidgetRef.current.isOpen = false + return asSuggestionsRef([], false) + } + + helpWidgetRef.current = { + isOpen: beforeOffsetArgs.length > 0, + parent: { command, arguments: [{ token: commandName, type: TokenType.PureToken }, ...command.arguments!] }, + currentArg: command?.arguments?.[prevArgs.length] + } setSelectedIndex(allArgs[1] || '') + setSelectedCommand(commandName) // cover query if (command?.arguments?.[prevArgs.length]?.name === DefinedArgumentName.query) { if (prevCursorChar === '@') { + helpWidgetRef.current.isOpen = false return asSuggestionsRef(getFieldsSuggestions(attributesRef.current, range), false) } - return asSuggestionsRef([]) + return asSuggestionsRef([], false) } if (isCursorInArg || nextCursorChar?.trim()) return asSuggestionsRef([]) // cover index field if (command?.arguments?.[prevArgs.length]?.name === DefinedArgumentName.index) { - if (prevCursorChar?.trim()) return asSuggestionsRef([], false) - return asSuggestionsRef(getIndexesSuggestions(indexesRef.current, range)) + if (currentOffsetArg) return asSuggestionsRef([], false) + if (indexesRef.current.length) { + return asSuggestionsRef(getIndexesSuggestions(indexesRef.current, range)) + } + return asSuggestionsRef([]) } if (prevArgs.length < 2) return asSuggestionsRef([]) @@ -202,7 +247,9 @@ const Query = (props: Props) => { } if (foundArg && !foundArg.isComplete) return getMandatoryArgumentSuggestions(foundArg, attributesRef.current, range) - if (!foundArg || foundArg.isComplete) return getOptionalSuggestions(command, foundArg, allArgs, range) + if (!foundArg || foundArg.isComplete) { + return getOptionalSuggestions(command, foundArg, allArgs, range, currentOffsetArg) + } return asSuggestionsRef([]) } @@ -211,7 +258,7 @@ const Query = (props: Props) => { value={value} onChange={onChange} language={MonacoLanguage.RediSearch} - theme={theme === Theme.Dark ? 'dark' : 'light'} + theme={theme === Theme.Dark ? RedisearchMonacoTheme.dark : RedisearchMonacoTheme.light} options={options} editorDidMount={editorDidMount} /> diff --git a/redisinsight/ui/src/pages/search/components/query/constants.ts b/redisinsight/ui/src/pages/search/components/query/constants.ts index 15556977d6..252d2a8de3 100644 --- a/redisinsight/ui/src/pages/search/components/query/constants.ts +++ b/redisinsight/ui/src/pages/search/components/query/constants.ts @@ -5,7 +5,7 @@ export const options = merge(defaultMonacoOptions, { suggest: { showWords: false, - showIcons: true + showIcons: true, } }) diff --git a/redisinsight/ui/src/pages/search/components/query/utils.ts b/redisinsight/ui/src/pages/search/components/query/utils.ts index 24537cdb32..d9c034f8a5 100644 --- a/redisinsight/ui/src/pages/search/components/query/utils.ts +++ b/redisinsight/ui/src/pages/search/components/query/utils.ts @@ -21,6 +21,7 @@ export const getIndexesSuggestions = (indexes: RedisResponseBuffer[], range: mon insertText: `"${value}" "$1" `, insertTextRules: monacoEditor.languages.CompletionItemInsertTextRule.InsertAsSnippet, range, + detail: value || ' ', } }) @@ -36,10 +37,11 @@ export const getFieldsSuggestions = (fields: any[], range: monaco.IRange, spaceA export const getCommandsSuggestions = (commands: SearchCommand[], range: monaco.IRange) => asSuggestionsRef( commands.map((command) => buildSuggestion(command, range, { detail: generateDetail(command), + insertTextRules: monacoEditor.languages.CompletionItemInsertTextRule.InsertAsSnippet, documentation: { value: getCommandMarkdown(command as any) }, - })) + })), false ) export const getMandatoryArgumentSuggestions = ( @@ -66,7 +68,8 @@ export const getOptionalSuggestions = ( command: SearchCommand, foundArg: Nullable, allArgs: string[], - range: monaco.IRange + range: monaco.IRange, + currentArg?: string ) => { const appendCommands = foundArg?.append ?? [] @@ -78,7 +81,8 @@ export const getOptionalSuggestions = ( })), ...(command?.arguments || []) .filter((arg) => arg.optional) - .filter((arg) => arg.multiple || !allArgs.includes(arg.token || arg.arguments?.[0]?.token || '')) + .filter((arg) => + arg.multiple || !(currentArg !== arg.token && allArgs.includes(arg.token || arg.arguments?.[0]?.token || ''))) .map((arg) => buildSuggestion(arg, range, { sortText: 'b', kind: monacoEditor.languages.CompletionItemKind.Reference, diff --git a/redisinsight/ui/src/utils/monaco/monacoRedisMonarchTokensProvider.ts b/redisinsight/ui/src/utils/monaco/monacoRedisMonarchTokensProvider.ts index a4a1ce63bd..9f41113289 100644 --- a/redisinsight/ui/src/utils/monaco/monacoRedisMonarchTokensProvider.ts +++ b/redisinsight/ui/src/utils/monaco/monacoRedisMonarchTokensProvider.ts @@ -79,14 +79,14 @@ export const getRedisMonarchTokensProvider = (commands: string[]): monacoEditor. [/"/, { token: STRING_DOUBLE, next: '@stringDouble' }], ], string: [ - [/[^']+/, 'string'], - [/''/, 'string'], + [/\\./, 'string'], [/'/, { token: 'string', next: '@pop' }], + [/[^\\']+/, 'string'], ], stringDouble: [ - [/[^"]+/, STRING_DOUBLE], - [/""/, STRING_DOUBLE], + [/\\./, STRING_DOUBLE], [/"/, { token: STRING_DOUBLE, next: '@pop' }], + [/[^\\"]+/, STRING_DOUBLE], ], scopes: [ // NOT SUPPORTED diff --git a/redisinsight/ui/src/utils/monaco/monacoThemes.ts b/redisinsight/ui/src/utils/monaco/monacoThemes.ts new file mode 100644 index 0000000000..0e7f41f56f --- /dev/null +++ b/redisinsight/ui/src/utils/monaco/monacoThemes.ts @@ -0,0 +1,43 @@ +import { monaco as monacoEditor } from 'react-monaco-editor' + +export enum RedisearchMonacoTheme { + dark = 'redisearchDarkTheme', + light = 'redisearchLightTheme' +} + +export const installRedisearchTheme = () => { + monacoEditor.editor.defineTheme(RedisearchMonacoTheme.dark, { + base: 'vs-dark', + inherit: true, + rules: [ + { token: 'keyword', foreground: '#569cd6', fontStyle: 'bold' }, + // { token: 'argument.token', foreground: '#6db9a2' }, + { token: 'argument.block.0', foreground: '#66ccaf' }, + { token: 'argument.block.1', foreground: '#459d7f' }, + { token: 'argument.block.2', foreground: '#3c816a' }, + { token: 'argument.block.3', foreground: '#28644f' }, + { token: 'loadAll', foreground: '#6db9a2' }, + { token: 'index', foreground: '#ce51cc' }, + { token: 'query', foreground: '#5183ce' }, + { token: 'field', foreground: '#c43265' }, + ], + colors: {} + }) + + monacoEditor.editor.defineTheme(RedisearchMonacoTheme.light, { + base: 'vs', + inherit: true, + rules: [ + { token: 'keyword', foreground: '#569cd6', fontStyle: 'bold' }, + { token: 'argument.block.0', foreground: '#66ccaf' }, + { token: 'argument.block.1', foreground: '#459d7f' }, + { token: 'argument.block.2', foreground: '#3c816a' }, + { token: 'argument.block.3', foreground: '#28644f' }, + { token: 'loadAll', foreground: '#6db9a2' }, + { token: 'index', foreground: '#ce51cc' }, + { token: 'field', foreground: '#5183ce' }, + { token: 'field', foreground: '#c43265' }, + ], + colors: {} + }) +} diff --git a/redisinsight/ui/src/utils/monaco/monarchTokens/redisearchTokens.ts b/redisinsight/ui/src/utils/monaco/monarchTokens/redisearchTokens.ts new file mode 100644 index 0000000000..2eb71dde4f --- /dev/null +++ b/redisinsight/ui/src/utils/monaco/monarchTokens/redisearchTokens.ts @@ -0,0 +1,152 @@ +import { monaco as monacoEditor } from 'react-monaco-editor' +import { SearchCommand, TokenType } from 'uiSrc/pages/search/types' + +const STRING_DOUBLE = 'string.double' + +const generateKeywords = (commands: SearchCommand[]) => commands.map(({ name }) => name) +const generateTokens = (command?: SearchCommand) => { + if (!command) return [] + const levels: Array> = [] + + function processArguments(args: SearchCommand[], level = 0) { + // Ensure the current level exists in the levels array + if (!levels[level]) { + levels[level] = [] + } + + args.forEach((arg) => { + if (arg.token) levels[level].push(arg.token) + + if (arg.type === TokenType.Block && arg.arguments) { + const blockToken = arg.arguments[0].token + const nextArgs = arg.arguments + if (blockToken) { + levels[level].push(blockToken) + } + processArguments(blockToken ? nextArgs.slice(1, nextArgs.length) : nextArgs, level + 1) + } + + if (arg.type === TokenType.OneOf && arg.arguments) { + arg.arguments.forEach((choice) => { + if (choice.token) levels[level].push(choice.token) + }) + } + }) + } + + if (command.arguments) { + processArguments(command.arguments, 0) + } + + return levels +} + +export const getRediSearchMonarchTokensProvider = ( + commands: SearchCommand[], + command?: string +): monacoEditor.languages.IMonarchLanguage => { + const currentCommand = commands.find(({ name }) => name === command) + + const keywords = generateKeywords(commands) + const argTokens = generateTokens(currentCommand) + + return ( + { + defaultToken: '', + tokenPostfix: '.redisearch', + ignoreCase: true, + brackets: [ + { open: '[', close: ']', token: 'delimiter.square' }, + { open: '(', close: ')', token: 'delimiter.parenthesis' }, + ], + keywords, + tokenizer: { + root: [ + { include: '@whitespace' }, + { include: '@numbers' }, + { include: '@strings' }, + { include: '@keyword' }, + [/LOAD\s+\*/, 'loadAll'], + { include: '@argument.block' }, + [/[;,.]/, 'delimiter'], + [/[()]/, '@brackets'], + [ + /[\w@#$]+/, + { + cases: { + '@keywords': 'keyword', + '@default': 'identifier', + }, + }, + ], + [/[<>=!%&+\-*/|~^]/, 'operator'], + ], + keyword: [ + [`(${keywords.join('|')})\\b`, { token: 'keyword', next: '@index' }] + ], + 'argument.block': argTokens.map((tokens, lvl) => [`(${tokens.join('|')})\\b`, `argument.block.${lvl}`]), + index: [ + [/"([^"\\]|\\.)*"/, { token: 'index', next: '@query' }], + [/'([^'\\]|\\.)*'/, { token: 'index', next: '@query' }], + [/[a-zA-Z_]\w*/, { token: 'index', next: '@query' }], + { include: 'root' } // Fallback to the root state if nothing matches + ], + query: [ + [/"/, { token: 'query', next: '@queryInsideDouble' }], + [/'/, { token: 'query', next: '@queryInsideSingle' }], + [/[a-zA-Z_]\w*/, { token: 'query', next: '@root' }], + { include: 'root' } // Fallback to the root state if nothing matches + ], + queryInsideDouble: [ + [/@/, { token: 'field', next: '@fieldInDouble' }], + [/\\"/, { token: 'query', next: 'queryInsideDouble' }], + [/"/, { token: 'query', next: '@root' }], + [/./, { token: 'query', next: '@queryInsideDouble' }], + { include: '@query' } // Fallback to the root state if nothing matches + ], + queryInsideSingle: [ + [/@/, { token: 'field', next: '@fieldInSingle' }], + [/\\'/, { token: 'query', next: 'queryInsideSingle' }], + [/'/, { token: 'query', next: '@root' }], + [/./, { token: 'query', next: '@queryInsideSingle' }], + { include: '@query' } // Fallback to the root state if nothing matches + ], + fieldInDouble: [ + [/\w+/, { token: 'field', next: '@queryInsideDouble' }], + [/\s+/, { token: '@rematch', next: '@queryInsideDouble' }], + [/"/, { token: 'query', next: '@root' }], + { include: '@query' } // Fallback to the root state if nothing matches + ], + fieldInSingle: [ + [/\w+/, { token: 'field', next: '@queryInsideSingle' }], + [/\s+/, { token: '@rematch', next: '@queryInsideSingle' }], + [/'/, { token: 'query', next: '@root' }], + { include: '@query' } // Fallback to the root state if nothing matches + ], + whitespace: [ + [/\s+/, 'white'], + [/\/\/.*$/, 'comment'], + ], + numbers: [ + [/0[xX][0-9a-fA-F]*/, 'number'], + [/[$][+-]*\d*(\.\d*)?/, 'number'], + [/((\d+(\.\d*)?)|(\.\d+))([eE][-+]?\d+)?/, 'number'], + ], + strings: [ + [/'/, { token: 'string', next: '@string' }], + [/"/, { token: STRING_DOUBLE, next: '@stringDouble' }], + ], + string: [ + [/\\./, 'string'], + [/'/, { token: 'string', next: '@pop' }], + [/[^\\']+/, 'string'], + ], + stringDouble: [ + [/\\./, STRING_DOUBLE], + [/"/, { token: STRING_DOUBLE, next: '@pop' }], + [/[^\\"]+/, STRING_DOUBLE], + ], + }, + } + ) +} From e16757fc8861175ea8164ca6cadc7ee7c280527b Mon Sep 17 00:00:00 2001 From: kchepikava Date: Wed, 14 Aug 2024 19:31:26 +0200 Subject: [PATCH 029/256] Updated circeci --- .circleci/config.yml | 73 +++++++++++++++++++++++--------------------- 1 file changed, 38 insertions(+), 35 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 57dc5c9390..6803342714 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -213,6 +213,9 @@ parameters: redis_client: type: string default: "" + env: + type: string + default: "stage" jobs: # Test jobs @@ -1351,24 +1354,24 @@ workflows: os: linux target: << pipeline.parameters.linux >> - setup-sign-certificates: - name: Setup sign certificates (stage) + name: Setup sign certificates (<< pipeline.parameters.env >>) requires: - Validating build parameters - setup-build: - name: Setup build (stage) - env: stage + name: Setup build (<< pipeline.parameters.env >>) + env: << pipeline.parameters.env >> requires: - - Setup sign certificates (stage) + - Setup sign certificates (<< pipeline.parameters.env >>) - linux: - name: Build app - Linux (stage) - env: stage + name: Build app - Linux (<< pipeline.parameters.env >>) + env: << pipeline.parameters.env >> target: << pipeline.parameters.linux >> requires: - - Setup build (stage) + - Setup build (<< pipeline.parameters.env >>) - store-build-artifacts: - name: Store build artifacts (stage) + name: Store build artifacts (<< pipeline.parameters.env >>) requires: - - Build app - Linux (stage) + - Build app - Linux (<< pipeline.parameters.env >>) manual-build-mac: when: << pipeline.parameters.mac >> jobs: @@ -1377,25 +1380,25 @@ workflows: os: mac target: << pipeline.parameters.mac >> - setup-sign-certificates: - name: Setup sign certificates (stage) + name: Setup sign certificates (<< pipeline.parameters.env >>) requires: - Validating build parameters - setup-build: - name: Setup build (stage) - env: stage + name: Setup build (<< pipeline.parameters.env >>) + env: << pipeline.parameters.env >> requires: - - Setup sign certificates (stage) + - Setup sign certificates (<< pipeline.parameters.env >>) - macosx: - name: Build app - MacOS (stage) - env: stage + name: Build app - MacOS (<< pipeline.parameters.env >>) + env: << pipeline.parameters.env >> redisstack: false target: << pipeline.parameters.mac >> requires: - - Setup build (stage) + - Setup build (<< pipeline.parameters.env >>) - store-build-artifacts: - name: Store build artifacts (stage) + name: Store build artifacts (<< pipeline.parameters.env >>) requires: - - Build app - MacOS (stage) + - Build app - MacOS (<< pipeline.parameters.env >>) manual-build-windows: when: << pipeline.parameters.windows >> jobs: @@ -1404,24 +1407,24 @@ workflows: os: windows target: << pipeline.parameters.windows >> - setup-sign-certificates: - name: Setup sign certificates (stage) + name: Setup sign certificates (<< pipeline.parameters.env >>) requires: - Validating build parameters - setup-build: - name: Setup build (stage) - env: stage + name: Setup build (<< pipeline.parameters.env >>) + env: << pipeline.parameters.env >> requires: - - Setup sign certificates (stage) + - Setup sign certificates (<< pipeline.parameters.env >>) - windows: - name: Build app - Windows (stage) - env: stage + name: Build app - Windows (<< pipeline.parameters.env >>) + env: << pipeline.parameters.env >> target: << pipeline.parameters.windows >> requires: - - Setup build (stage) + - Setup build (<< pipeline.parameters.env >>) - store-build-artifacts: - name: Store build artifacts (stage) + name: Store build artifacts (<< pipeline.parameters.env >>) requires: - - Build app - Windows (stage) + - Build app - Windows (<< pipeline.parameters.env >>) manual-build-docker: when: << pipeline.parameters.docker >> jobs: @@ -1430,22 +1433,22 @@ workflows: os: docker target: << pipeline.parameters.docker >> - setup-sign-certificates: - name: Setup sign certificates (stage) + name: Setup sign certificates (<< pipeline.parameters.env >>) requires: - Validating build parameters - setup-build: - name: Setup build (stage) - env: stage + name: Setup build (<< pipeline.parameters.env >>) + env: << pipeline.parameters.env >> requires: - - Setup sign certificates (stage) + - Setup sign certificates (<< pipeline.parameters.env >>) - docker: - name: Build docker images (stage) + name: Build docker images (<< pipeline.parameters.env >>) requires: - - Setup build (stage) + - Setup build (<< pipeline.parameters.env >>) - store-build-artifacts: - name: Store build artifacts (stage) + name: Store build artifacts (<< pipeline.parameters.env >>) requires: - - Build docker images (stage) + - Build docker images (<< pipeline.parameters.env >>) # build electron app (dev) from "build" branches build: From 6d0bf34b43df5568cfe7e3fb6b9e4f12c4ab81ac Mon Sep 17 00:00:00 2001 From: Roman Sergeenko Date: Thu, 15 Aug 2024 14:38:07 +0200 Subject: [PATCH 030/256] #RI-5988 - fix bugs, refactoring --- .../pages/search/components/query/Query.tsx | 60 +++++++------ .../pages/search/components/query/utils.ts | 36 ++++++-- .../ui/src/pages/search/utils/query.ts | 86 +++++++++---------- .../pages/search/utils/tests/query.spec.ts | 10 +-- 4 files changed, 105 insertions(+), 87 deletions(-) diff --git a/redisinsight/ui/src/pages/search/components/query/Query.tsx b/redisinsight/ui/src/pages/search/components/query/Query.tsx index aace67a0f1..a72ff71486 100644 --- a/redisinsight/ui/src/pages/search/components/query/Query.tsx +++ b/redisinsight/ui/src/pages/search/components/query/Query.tsx @@ -8,13 +8,14 @@ import { appRedisCommandsSelector } from 'uiSrc/slices/app/redis-commands' import { Nullable } from 'uiSrc/utils' import { IEditorMount } from 'uiSrc/pages/workbench/interfaces' import { + addOwnTokenToArgs, findCurrentArgument, getRange, getRediSearchSignutureProvider, setCursorPositionAtTheEnd, splitQueryByArgs } from 'uiSrc/pages/search/utils' -import { SearchCommand, TokenType } from 'uiSrc/pages/search/types' +import { SearchCommand } from 'uiSrc/pages/search/types' import { RedisResponseBuffer } from 'uiSrc/slices/interfaces' import { fetchRedisearchInfoAction } from 'uiSrc/slices/browser/redisearch' import { getRediSearchMonarchTokensProvider } from 'uiSrc/utils/monaco/monarchTokens/redisearchTokens' @@ -27,7 +28,7 @@ import { asSuggestionsRef, getMandatoryArgumentSuggestions, getOptionalSuggestions, - getCommandsSuggestions + getCommandsSuggestions, isIndexComplete } from './utils' export interface Props { @@ -83,8 +84,8 @@ const Query = (props: Props) => { }, [selectedCommand]) useDebouncedEffect(() => { - if (!selectedIndex) return - // TODO: add check is selectedIndex is complete (", "\", "dwadawd) - do not request + attributesRef.current = [] + if (!isIndexComplete(selectedIndex)) return const index = selectedIndex.replace(/^(['"])(.*)\1$/, '$2') dispatch(fetchRedisearchInfoAction(index, @@ -133,6 +134,16 @@ const Query = (props: Props) => { editor.onDidChangeCursorPosition(handleCursorChange) } + const isSuggestionsOpened = () => { + const { editor } = monacoObjects.current || {} + + if (!editor) return false + const suggestController = editor.getContribution('editor.contrib.suggestController') + const suggestModel = suggestController?.model + + return suggestModel?.state === 1 + } + const handleCursorChange = () => { const { editor } = monacoObjects.current || {} suggestionsRef.current.data = [] @@ -151,14 +162,12 @@ const Query = (props: Props) => { return } - editor?.trigger('', 'editor.action.triggerParameterHints', '') - - const suggestController = editor.getContribution('editor.contrib.suggestController') - const suggestModel = suggestController?.model - helpWidgetRef.current.isOpen = suggestModel?.state === 0 && helpWidgetRef.current.isOpen + editor.trigger('', 'editor.action.triggerParameterHints', '') if (suggestionsRef.current.forceHide) { setTimeout(() => editor?.trigger('', 'hideSuggestWidget', null), 0) + } else { + helpWidgetRef.current.isOpen = !isSuggestionsOpened() && helpWidgetRef.current.isOpen } } @@ -169,6 +178,12 @@ const Query = (props: Props) => { setTimeout(() => editor?.trigger('', 'editor.action.triggerSuggest', { auto: false })) } + const updateHelpWidget = (isOpen: boolean, parent?: SearchCommand, currentArg?: SearchCommand) => { + helpWidgetRef.current.isOpen = isOpen + helpWidgetRef.current.parent = parent + helpWidgetRef.current.currentArg = currentArg + } + const getSuggestions = ( editor: monacoEditor.editor.IStandaloneCodeEditor ): { @@ -193,10 +208,8 @@ const Query = (props: Props) => { const commandName = (firstArg || currentOffsetArg)?.toUpperCase() const command = REDIS_COMMANDS_SPEC[commandName] as unknown as SearchCommand - const isCommandSuppurted = SUPPORTED_COMMANDS - .some(({ name }) => commandName === name) + const isCommandSuppurted = SUPPORTED_COMMANDS.some(({ name }) => commandName === name) if (command && !isCommandSuppurted) return asSuggestionsRef([]) - if (!command && position.lineNumber === 1 && position.column === 1) { return getCommandsSuggestions(SUPPORTED_COMMANDS, range) } @@ -206,17 +219,13 @@ const Query = (props: Props) => { return asSuggestionsRef([], false) } - helpWidgetRef.current = { - isOpen: beforeOffsetArgs.length > 0, - parent: { command, arguments: [{ token: commandName, type: TokenType.PureToken }, ...command.arguments!] }, - currentArg: command?.arguments?.[prevArgs.length] - } - setSelectedIndex(allArgs[1] || '') setSelectedCommand(commandName) // cover query if (command?.arguments?.[prevArgs.length]?.name === DefinedArgumentName.query) { + updateHelpWidget(true, addOwnTokenToArgs(commandName, command), command?.arguments?.[prevArgs.length]) + if (prevCursorChar === '@') { helpWidgetRef.current.isOpen = false return asSuggestionsRef(getFieldsSuggestions(attributesRef.current, range), false) @@ -227,24 +236,19 @@ const Query = (props: Props) => { if (isCursorInArg || nextCursorChar?.trim()) return asSuggestionsRef([]) - // cover index field + // cover index if (command?.arguments?.[prevArgs.length]?.name === DefinedArgumentName.index) { + updateHelpWidget(true, addOwnTokenToArgs(commandName, command), command?.arguments?.[prevArgs.length]) + if (currentOffsetArg) return asSuggestionsRef([], false) - if (indexesRef.current.length) { - return asSuggestionsRef(getIndexesSuggestions(indexesRef.current, range)) - } + if (indexesRef.current.length) return asSuggestionsRef(getIndexesSuggestions(indexesRef.current, range)) return asSuggestionsRef([]) } if (prevArgs.length < 2) return asSuggestionsRef([]) const foundArg = findCurrentArgument(command?.arguments || [], prevArgs) - - helpWidgetRef.current = { - isOpen: !!foundArg?.stopArg, - parent: foundArg?.parent, - currentArg: foundArg?.stopArg - } + updateHelpWidget(!!foundArg?.stopArg, foundArg?.parent, foundArg?.stopArg) if (foundArg && !foundArg.isComplete) return getMandatoryArgumentSuggestions(foundArg, attributesRef.current, range) if (!foundArg || foundArg.isComplete) { diff --git a/redisinsight/ui/src/pages/search/components/query/utils.ts b/redisinsight/ui/src/pages/search/components/query/utils.ts index d9c034f8a5..1df71cd5a2 100644 --- a/redisinsight/ui/src/pages/search/components/query/utils.ts +++ b/redisinsight/ui/src/pages/search/components/query/utils.ts @@ -26,13 +26,17 @@ export const getIndexesSuggestions = (indexes: RedisResponseBuffer[], range: mon }) export const getFieldsSuggestions = (fields: any[], range: monaco.IRange, spaceAfter = false) => - fields.map(({ attribute }) => ({ - label: attribute, - kind: monacoEditor.languages.CompletionItemKind.Reference, - insertText: `${attribute}${spaceAfter ? ' ' : ''}`, - insertTextRules: monacoEditor.languages.CompletionItemInsertTextRule.InsertAsSnippet, - range, - })) + fields.map(({ attribute }) => { + const insertText = attribute.trim() ? attribute : `"${attribute}"` + return { + label: attribute || ' ', + kind: monacoEditor.languages.CompletionItemKind.Reference, + insertText: `${insertText}${spaceAfter ? ' ' : ''}`, + insertTextRules: monacoEditor.languages.CompletionItemInsertTextRule.InsertAsSnippet, + range, + detail: attribute || ' ', + } + }) export const getCommandsSuggestions = (commands: SearchCommand[], range: monaco.IRange) => asSuggestionsRef( commands.map((command) => buildSuggestion(command, range, { @@ -50,6 +54,7 @@ export const getMandatoryArgumentSuggestions = ( range: monaco.IRange ) => { if (foundArg.stopArg?.name === DefinedArgumentName.field) { + if (!fields.length) asSuggestionsRef([]) return asSuggestionsRef(getFieldsSuggestions(fields, range, true)) } @@ -90,3 +95,20 @@ export const getOptionalSuggestions = ( })) ]) } + +export const isIndexComplete = (index: string) => { + if (!index) return false + if (index.startsWith('"')) { + if (index.length < 2) return false + if (!index.endsWith('"')) return false + return !index.endsWith('\\', -1) + } + + if (index.startsWith("'")) { + if (index.length < 2) return false + if (!index.endsWith("'")) return false + return !index.endsWith('\\', -1) + } + + return true +} diff --git a/redisinsight/ui/src/pages/search/utils/query.ts b/redisinsight/ui/src/pages/search/utils/query.ts index 0a5e269068..4a04e391bb 100644 --- a/redisinsight/ui/src/pages/search/utils/query.ts +++ b/redisinsight/ui/src/pages/search/utils/query.ts @@ -230,39 +230,45 @@ export const getArgumentSuggestions = ( isBlocked: isWasBlocked } = findStopArgumentInQuery(pastStringArgs, pastCommandArgs) - // TODO refactor to early return related to where we stopped - const stopArgument = restArguments[stopArgIndex] const restNotFilledArgs = restArguments.slice(stopArgIndex) - const isStopArgumentCannotSuggest = Boolean(stopArgument && !(stopArgument.token || stopArgument?.arguments?.length)) - const isBlocked = isWasBlocked || isStopArgumentCannotSuggest - - const restParentOptionalSuggestions = !stopArgument || stopArgument?.optional - ? getRestParentArguments(current?.parent, current?.name, current?.multiple) - .filter((arg) => - arg.optional && arg.name !== stopArgument?.name - && (current?.multiple || arg.name !== current?.name)) - : [] - const restOptionalSuggestions = isBlocked - ? [] - : fillArgsByType([...restNotFilledArgs, ...restParentOptionalSuggestions]) const isOneOfArgument = stopArgument?.type === TokenType.OneOf || (stopArgument?.type === TokenType.PureToken && current?.parent?.type === TokenType.OneOf) - const isArgSuggestions = stopArgument && !stopArgument.optional && (stopArgument?.token || isOneOfArgument) - const suggestions = isArgSuggestions - // only 1 suggestion since next arg is required - ? [isOneOfArgument ? stopArgument.arguments : stopArgument].flat() - : restOptionalSuggestions + if (isWasBlocked) { + return { + isComplete: false, + stopArg: stopArgument, + isBlocked: !isOneOfArgument, + append: isOneOfArgument ? stopArgument.arguments! : [], + } + } + + if (stopArgument && !stopArgument.optional) { + const isCanAppend = stopArgument?.token || isOneOfArgument + const append = isCanAppend ? [isOneOfArgument ? stopArgument.arguments! : stopArgument].flat() : [] + return { + isComplete: false, + stopArg: stopArgument, + isBlocked: !isCanAppend, + append, + } + } + + const restParentOptionalSuggestions = getRestParentArguments(current?.parent, current?.name, current?.multiple) + .filter((arg) => arg.optional && arg.name !== stopArgument?.name + && (current?.multiple || arg.name !== current?.name)) + + const restOptionalSuggestions = fillArgsByType([...restNotFilledArgs, ...restParentOptionalSuggestions]) const requiredArgsLength = restNotFilledArgs.filter((arg) => !arg.optional).length return { - isComplete: requiredArgsLength === 0 && !isBlocked, + isComplete: requiredArgsLength === 0, stopArg: stopArgument, - isBlocked, - append: suggestions, + isBlocked: false, + append: restOptionalSuggestions, } } @@ -284,23 +290,15 @@ export const getRestParentArguments = ( return [...currentRestArgs, ...prevArgs] } -export const fillArgsByType = (args: SearchCommand[]) => { - const result = [] +export const fillArgsByType = (args: SearchCommand[]): SearchCommand[] => { + const result: SearchCommand[] = [] for (let i = 0; i < args.length; i++) { const currentArg = args[i] - if (currentArg.type === TokenType.OneOf) { - result.push(...(currentArg?.arguments || [])) - } - - if (currentArg.type === TokenType.Block) { - result.push(currentArg.arguments?.[0]) - } - - if (currentArg.token) { - result.push(currentArg) - } + if (currentArg.type === TokenType.OneOf) result.push(...(currentArg?.arguments || [])) + if (currentArg.type === TokenType.Block) result.push(currentArg.arguments?.[0] as SearchCommand) + if (currentArg.token) result.push(currentArg) } return result @@ -316,18 +314,18 @@ export const isCompositeArgument = (arg: string, prevArg?: string) => arg === '* export const generateDetail = (command: Maybe) => { if (!command) return '' - - if (command.arguments) { - return generateArgsNames(CommandProvider.Main, command.arguments).join(' ') - } - + if (command.arguments) return generateArgsNames(CommandProvider.Main, command.arguments).join(' ') if (command.token) { - if (command.type === TokenType.PureToken) { - return command.token - } - + if (command.type === TokenType.PureToken) return command.token return `${command.token} ${command.name}` } return '' } + +export const addOwnTokenToArgs = (token: string, command: SearchCommand) => { + if (command.arguments) { + return ({ ...command, arguments: [{ token, type: TokenType.PureToken }, ...command.arguments] }) + } + return command +} diff --git a/redisinsight/ui/src/pages/search/utils/tests/query.spec.ts b/redisinsight/ui/src/pages/search/utils/tests/query.spec.ts index 93bd7ea54e..f550210ed4 100644 --- a/redisinsight/ui/src/pages/search/utils/tests/query.spec.ts +++ b/redisinsight/ui/src/pages/search/utils/tests/query.spec.ts @@ -12,7 +12,7 @@ const ftAggreageTests = [ args: ['index', '"query"', 'APPLY'], result: { stopArg: { name: 'expression', token: 'APPLY', type: 'string' }, - append: [{ name: 'expression', token: 'APPLY', type: 'string' }], + append: [], isBlocked: true, isComplete: false, parent: expect.any(Object) @@ -253,13 +253,7 @@ const ftSearchTests = [ type: 'string', token: 'FIELDS' }, - append: [ - { - name: 'count', - type: 'string', - token: 'FIELDS' - } - ], + append: [], isBlocked: true, isComplete: false, parent: expect.any(Object) From 82a505f1747ea471cd1b7ab1896afaba00fdf001 Mon Sep 17 00:00:00 2001 From: Roman Sergeenko Date: Thu, 15 Aug 2024 14:40:46 +0200 Subject: [PATCH 031/256] #RI-5988 - fix tests --- redisinsight/__mocks__/monacoMock.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/redisinsight/__mocks__/monacoMock.js b/redisinsight/__mocks__/monacoMock.js index d26e492ffe..68045663d8 100644 --- a/redisinsight/__mocks__/monacoMock.js +++ b/redisinsight/__mocks__/monacoMock.js @@ -70,7 +70,8 @@ export const languages = { }, CompletionItemInsertTextRule: { InsertAsSnippet: 4 - } + }, + ...monacoEditor.languages } export const monaco = { From c4daceb8f831961f574ecabfbe0638ee06f44bc6 Mon Sep 17 00:00:00 2001 From: Roman Sergeenko Date: Fri, 16 Aug 2024 10:13:22 +0200 Subject: [PATCH 032/256] #RI-6008, #RI-6009 - fix bugs --- .../pages/search/components/query/Query.tsx | 18 ++++++++++--- .../search/components/query/constants.ts | 1 + .../ui/src/pages/search/utils/query.ts | 26 +++++++++++++++---- 3 files changed, 36 insertions(+), 9 deletions(-) diff --git a/redisinsight/ui/src/pages/search/components/query/Query.tsx b/redisinsight/ui/src/pages/search/components/query/Query.tsx index a72ff71486..6fc1fdd94b 100644 --- a/redisinsight/ui/src/pages/search/components/query/Query.tsx +++ b/redisinsight/ui/src/pages/search/components/query/Query.tsx @@ -63,6 +63,7 @@ const Query = (props: Props) => { }) const indexesRef = useRef([]) const attributesRef = useRef([]) + const isEscapedSuggestions = useRef(false) const { theme } = useContext(ThemeContext) const dispatch = useDispatch() @@ -102,6 +103,8 @@ const Query = (props: Props) => { monaco.languages.register({ id: MonacoLanguage.RediSearch }) monacoObjects.current = { editor, monaco } + suggestionsRef.current = getSuggestions(editor) + if (value) { setCursorPositionAtTheEnd(editor) } else { @@ -109,7 +112,6 @@ const Query = (props: Props) => { if (position?.column === 1 && position?.lineNumber === 1) { editor.focus() - suggestionsRef.current = getSuggestions(editor) triggerSuggestions() } } @@ -131,7 +133,13 @@ const Query = (props: Props) => { }).dispose installRedisearchTheme() + editor.onDidChangeCursorPosition(handleCursorChange) + editor.onKeyDown((e: monacoEditor.IKeyboardEvent) => { + if (e.keyCode === monacoEditor.KeyCode.Escape && isSuggestionsOpened()) { + isEscapedSuggestions.current = true + } + }) } const isSuggestionsOpened = () => { @@ -200,7 +208,7 @@ const Query = (props: Props) => { const word = model.getWordUntilPosition(position) const range = getRange(position, word) - const { args, isCursorInArg, prevCursorChar, nextCursorChar } = splitQueryByArgs(value, offset) + const { args, isCursorInQuotes, prevCursorChar, nextCursorChar } = splitQueryByArgs(value, offset) const allArgs = args.flat() const [beforeOffsetArgs, [currentOffsetArg]] = args const [firstArg, ...prevArgs] = beforeOffsetArgs @@ -234,18 +242,20 @@ const Query = (props: Props) => { return asSuggestionsRef([], false) } - if (isCursorInArg || nextCursorChar?.trim()) return asSuggestionsRef([]) - // cover index if (command?.arguments?.[prevArgs.length]?.name === DefinedArgumentName.index) { updateHelpWidget(true, addOwnTokenToArgs(commandName, command), command?.arguments?.[prevArgs.length]) + // we do not suggest indexes if there is something next if (currentOffsetArg) return asSuggestionsRef([], false) if (indexesRef.current.length) return asSuggestionsRef(getIndexesSuggestions(indexesRef.current, range)) return asSuggestionsRef([]) } + if (isCursorInQuotes || nextCursorChar?.trim()) return asSuggestionsRef([]) if (prevArgs.length < 2) return asSuggestionsRef([]) + if ((prevCursorChar?.trim() || isCursorInQuotes) && isEscapedSuggestions.current) return asSuggestionsRef([]) + isEscapedSuggestions.current = false const foundArg = findCurrentArgument(command?.arguments || [], prevArgs) updateHelpWidget(!!foundArg?.stopArg, foundArg?.parent, foundArg?.stopArg) diff --git a/redisinsight/ui/src/pages/search/components/query/constants.ts b/redisinsight/ui/src/pages/search/components/query/constants.ts index 252d2a8de3..437b0ae82c 100644 --- a/redisinsight/ui/src/pages/search/components/query/constants.ts +++ b/redisinsight/ui/src/pages/search/components/query/constants.ts @@ -6,6 +6,7 @@ export const options = merge(defaultMonacoOptions, suggest: { showWords: false, showIcons: true, + insertMode: 'replace', } }) diff --git a/redisinsight/ui/src/pages/search/utils/query.ts b/redisinsight/ui/src/pages/search/utils/query.ts index 4a04e391bb..703d651b31 100644 --- a/redisinsight/ui/src/pages/search/utils/query.ts +++ b/redisinsight/ui/src/pages/search/utils/query.ts @@ -1,6 +1,6 @@ /* eslint-disable no-continue */ -import { toNumber } from 'lodash' +import { toNumber, uniqBy } from 'lodash' import { generateArgsNames, Maybe, Nullable } from 'uiSrc/utils' import { CommandProvider } from 'uiSrc/constants' import { ArgName, FoundCommandArgument, SearchCommand, SearchCommandTree, TokenType } from '../types' @@ -11,7 +11,7 @@ export const splitQueryByArgs = (query: string, position: number = 0) => { let inQuotes = false let escapeNextChar = false let quoteChar = '' - const isCursorInArg = false + let isCursorInQuotes = false let lastArg = '' const pushToProperTuple = (isAfterOffset: boolean, arg: string) => { @@ -27,6 +27,7 @@ export const splitQueryByArgs = (query: string, position: number = 0) => { for (let i = 0; i < query.length; i++) { const char = query[i] const isAfterOffset = i >= position + (inQuotes ? -1 : 0) + if (i === position - 1) isCursorInQuotes = inQuotes if (escapeNextChar) { arg += char @@ -71,7 +72,7 @@ export const splitQueryByArgs = (query: string, position: number = 0) => { pushToProperTuple(true, arg) } - return { args, isCursorInArg, prevCursorChar: query[position - 1], nextCursorChar: query[position] } + return { args, isCursorInQuotes, prevCursorChar: query[position - 1], nextCursorChar: query[position] } } export const findCurrentArgument = ( @@ -140,6 +141,17 @@ const findStopArgumentInQuery = ( continue } + if ( + !isBlockedOnCommand + && currentCommandArg?.token + && currentCommandArg.optional + && currentCommandArg.token !== arg.toUpperCase() + ) { + moveToNextCommandArg() + skipArg() + continue + } + // if we are on token - that requires one more argument if (currentCommandArg?.token === arg.toUpperCase()) { blockCommand() @@ -204,7 +216,8 @@ const findStopArgumentInQuery = ( moveToNextCommandArg() const nextCommand = restCommandArgs[currentCommandArgIndex + 1] - isBlockedOnCommand = (!!nextCommand && !nextCommand.optional) + const currentCommand = restCommandArgs[currentCommandArgIndex] + isBlockedOnCommand = [currentCommand, nextCommand].every((arg) => arg && !arg.optional) } return { @@ -261,7 +274,10 @@ export const getArgumentSuggestions = ( .filter((arg) => arg.optional && arg.name !== stopArgument?.name && (current?.multiple || arg.name !== current?.name)) - const restOptionalSuggestions = fillArgsByType([...restNotFilledArgs, ...restParentOptionalSuggestions]) + const restOptionalSuggestions = uniqBy( + fillArgsByType([...restNotFilledArgs, ...restParentOptionalSuggestions]), + 'token' + ) const requiredArgsLength = restNotFilledArgs.filter((arg) => !arg.optional).length return { From f0c0cb653944e5ec8d0fb71aa8cc8b0a5af75764 Mon Sep 17 00:00:00 2001 From: Roman Sergeenko Date: Mon, 19 Aug 2024 16:15:45 +0200 Subject: [PATCH 033/256] #RI-5993 - add tests --- redisinsight/__mocks__/monacoMock.js | 11 +- .../ui/src/pages/search/SearchPage.spec.tsx | 68 ++++- .../ui/src/pages/search/SearchPage.tsx | 4 +- .../query-wrapper/QueryWrapper.spec.tsx | 70 +++++- .../components/query-wrapper/QueryWrapper.tsx | 27 +- .../search/components/query/Query.spec.tsx | 10 + .../pages/search/components/query/Query.tsx | 28 +-- .../pages/search/utils/tests/monaco.spec.ts | 60 +++++ .../pages/search/utils/tests/query.spec.ts | 235 +++++++++++++++++- .../tests/search/searchAndQuery.spec.ts | 58 +++++ 10 files changed, 542 insertions(+), 29 deletions(-) create mode 100644 redisinsight/ui/src/pages/search/components/query/Query.spec.tsx create mode 100644 redisinsight/ui/src/pages/search/utils/tests/monaco.spec.ts create mode 100644 redisinsight/ui/src/slices/tests/search/searchAndQuery.spec.ts diff --git a/redisinsight/__mocks__/monacoMock.js b/redisinsight/__mocks__/monacoMock.js index 68045663d8..63b6eae71b 100644 --- a/redisinsight/__mocks__/monacoMock.js +++ b/redisinsight/__mocks__/monacoMock.js @@ -15,10 +15,14 @@ const editor = { executeEdits: jest.fn(), updateOptions: jest.fn(), setSelection: jest.fn(), + setPosition: jest.fn(), createDecorationsCollection: jest.fn(), getValue: jest.fn().mockReturnValue(''), - getModel: jest.fn().mockReturnValue({}), - getPosition: jest.fn(), + getModel: jest.fn().mockReturnValue({ + getOffsetAt: jest.fn().mockReturnValue(0), + getWordUntilPosition: jest.fn().mockReturnValue(''), + }), + getPosition: jest.fn().mockReturnValue({}), trigger: jest.fn(), } @@ -78,9 +82,10 @@ export const monaco = { languages, Selection: jest.fn().mockImplementation(() => ({})), editor: { + ...editor, colorize: jest.fn().mockImplementation((data) => Promise.resolve(data)), defineTheme: jest.fn(), - setTheme: jest.fn() + setTheme: jest.fn(), }, Range: monacoEditor.Range } diff --git a/redisinsight/ui/src/pages/search/SearchPage.spec.tsx b/redisinsight/ui/src/pages/search/SearchPage.spec.tsx index f48f5729ff..50a53c0b27 100644 --- a/redisinsight/ui/src/pages/search/SearchPage.spec.tsx +++ b/redisinsight/ui/src/pages/search/SearchPage.spec.tsx @@ -1,10 +1,76 @@ import React from 'react' -import { render, screen } from 'uiSrc/utils/test-utils' +import { cloneDeep } from 'lodash' +import { cleanup, fireEvent, mockedStore, render, screen } from 'uiSrc/utils/test-utils' +import { loadWBHistory, sendWBCommand } from 'uiSrc/slices/workbench/wb-results' +import { setDbIndexState } from 'uiSrc/slices/app/context' +import { sendPageViewTelemetry, TelemetryPageView } from 'uiSrc/telemetry' import SearchPage from './SearchPage' +jest.mock('uiSrc/slices/app/context', () => ({ + ...jest.requireActual('uiSrc/slices/app/context'), + appContextSearchAndQuery: jest.fn().mockReturnValue({ + script: 'value', + panelSizes: { vertical: 100 } + }) +})) + +jest.mock('uiSrc/slices/instances/instances', () => ({ + ...jest.requireActual('uiSrc/slices/instances/instances'), + connectedInstanceSelector: jest.fn().mockReturnValue({ + name: 'db_name', + }), +})) + +jest.mock('uiSrc/telemetry', () => ({ + ...jest.requireActual('uiSrc/telemetry'), + sendEventTelemetry: jest.fn(), + sendPageViewTelemetry: jest.fn() +})) + +let store: typeof mockedStore +beforeEach(() => { + cleanup() + store = cloneDeep(mockedStore) + store.clearActions() +}) + +/** + * SearchPage tests + * + * @group component + */ describe('SearchPage', () => { it('should render', () => { expect(render()).toBeTruthy() }) + + it('should send page event', () => { + const sendPageViewTelemetryMock = jest.fn(); + (sendPageViewTelemetry as jest.Mock).mockImplementation(() => sendPageViewTelemetryMock) + + render() + + expect(sendPageViewTelemetry).toBeCalledWith({ + name: TelemetryPageView.SEARCH_AND_QUERY_PAGE, + eventData: { + databaseId: 'instanceId' + } + }) + }) + + it('should call proper actions on submit', () => { + render() + + fireEvent.click(screen.getByTestId('btn-submit')) + + expect(store.getActions()).toEqual([ + loadWBHistory(), + sendWBCommand({ + commandId: expect.any(String), + commands: ['value'] + }), + setDbIndexState(true) + ]) + }) }) diff --git a/redisinsight/ui/src/pages/search/SearchPage.tsx b/redisinsight/ui/src/pages/search/SearchPage.tsx index bf6116641c..f4e2562541 100644 --- a/redisinsight/ui/src/pages/search/SearchPage.tsx +++ b/redisinsight/ui/src/pages/search/SearchPage.tsx @@ -53,7 +53,9 @@ const SearchPage = () => { const sendPageView = (instanceId: string) => { sendPageViewTelemetry({ name: TelemetryPageView.SEARCH_AND_QUERY_PAGE, - databaseId: instanceId + eventData: { + databaseId: instanceId + } }) setIsPageViewSent(true) } diff --git a/redisinsight/ui/src/pages/search/components/query-wrapper/QueryWrapper.spec.tsx b/redisinsight/ui/src/pages/search/components/query-wrapper/QueryWrapper.spec.tsx index a0635f0dde..7c3eb91e4c 100644 --- a/redisinsight/ui/src/pages/search/components/query-wrapper/QueryWrapper.spec.tsx +++ b/redisinsight/ui/src/pages/search/components/query-wrapper/QueryWrapper.spec.tsx @@ -1,10 +1,78 @@ import React from 'react' -import { render, screen } from 'uiSrc/utils/test-utils' +import { cloneDeep } from 'lodash' +import { cleanup, mockedStore, render, fireEvent, screen } from 'uiSrc/utils/test-utils' +import { loadList } from 'uiSrc/slices/browser/redisearch' +import { changeSQActiveRunQueryMode } from 'uiSrc/slices/search/searchAndQuery' +import { RunQueryMode } from 'uiSrc/slices/interfaces' +import { sendEventTelemetry, TelemetryEvent } from 'uiSrc/telemetry' import QueryWrapper from './QueryWrapper' +jest.mock('uiSrc/slices/instances/instances', () => ({ + ...jest.requireActual('uiSrc/slices/instances/instances'), + connectedInstanceSelector: jest.fn().mockReturnValue({ + id: '123', + connectionType: 'STANDALONE', + db: 0, + }), +})) + +jest.mock('uiSrc/slices/app/context', () => ({ + ...jest.requireActual('uiSrc/slices/app/context'), + appContextSearchAndQuery: jest.fn().mockReturnValue({ + script: 'value' + }) +})) + +jest.mock('uiSrc/telemetry', () => ({ + ...jest.requireActual('uiSrc/telemetry'), + sendEventTelemetry: jest.fn(), +})) + +let store: typeof mockedStore +beforeEach(() => { + cleanup() + store = cloneDeep(mockedStore) + store.clearActions() +}) + describe('Query', () => { it('should render', () => { expect(render()).toBeTruthy() }) + + it('should fetch list of indexes', () => { + render() + + expect(store.getActions()).toEqual([loadList()]) + }) + + it('should call proper actions after change mode', () => { + render() + + fireEvent.click(screen.getByTestId('btn-change-mode')) + + expect(store.getActions()).toEqual([loadList(), changeSQActiveRunQueryMode(RunQueryMode.Raw)]) + }) + + it('should call proper actions after submit', () => { + const sendEventTelemetryMock = jest.fn(); + (sendEventTelemetry as jest.Mock).mockImplementation(() => sendEventTelemetryMock) + + const onSubmit = jest.fn() + render() + + fireEvent.click(screen.getByTestId('btn-submit')) + + expect(onSubmit).toBeCalledWith('value', undefined, { mode: RunQueryMode.ASCII }) + + expect(sendEventTelemetry).toBeCalledWith({ + event: TelemetryEvent.SEARCH_COMMAND_SUBMITTED, + eventData: { + databaseId: 'instanceId', + mode: RunQueryMode.ASCII, + command: 'value' + } + }) + }) }) diff --git a/redisinsight/ui/src/pages/search/components/query-wrapper/QueryWrapper.tsx b/redisinsight/ui/src/pages/search/components/query-wrapper/QueryWrapper.tsx index 9850d79545..a52d5e7768 100644 --- a/redisinsight/ui/src/pages/search/components/query-wrapper/QueryWrapper.tsx +++ b/redisinsight/ui/src/pages/search/components/query-wrapper/QueryWrapper.tsx @@ -6,12 +6,15 @@ import { QueryActions, QueryTutorials } from 'uiSrc/components/query' import { RunQueryMode } from 'uiSrc/slices/interfaces' import { CodeButtonParams } from 'uiSrc/constants' -import { Nullable } from 'uiSrc/utils' +import { getCommandsFromQuery, Nullable } from 'uiSrc/utils' import { changeSQActiveRunQueryMode, searchAndQuerySelector } from 'uiSrc/slices/search/searchAndQuery' import { appContextSearchAndQuery, setSQVerticalScript } from 'uiSrc/slices/app/context' import { sendEventTelemetry, TelemetryEvent } from 'uiSrc/telemetry' import { fetchRedisearchListAction, redisearchListSelector } from 'uiSrc/slices/browser/redisearch' import { connectedInstanceSelector } from 'uiSrc/slices/instances/instances' +import { appRedisCommandsSelector } from 'uiSrc/slices/app/redis-commands' +import { SUPPORTED_COMMANDS_LIST } from 'uiSrc/pages/search/components/query/constants' +import { SearchCommand } from 'uiSrc/pages/search/types' import { TUTORIALS } from './constants' import Query from '../query' @@ -33,11 +36,18 @@ const QueryWrapper = (props: Props) => { const { script: scriptContext } = useSelector(appContextSearchAndQuery) const { activeRunQueryMode } = useSelector(searchAndQuerySelector) const { data: indexes = [] } = useSelector(redisearchListSelector) + const { spec: REDIS_COMMANDS_SPEC, commandsArray } = useSelector(appRedisCommandsSelector) + const [value, setValue] = useState(scriptContext) const input = useRef(null) const scriptRef = useRef('') + const SUPPORTED_COMMANDS = SUPPORTED_COMMANDS_LIST.map((name) => ({ + ...REDIS_COMMANDS_SPEC[name], + name + })) as unknown as SearchCommand[] + const { instanceId } = useParams<{ instanceId: string }>() const dispatch = useDispatch() @@ -66,14 +76,17 @@ const QueryWrapper = (props: Props) => { } const handleSubmit = () => { - onSubmit(value.split('\n').join(' '), undefined, { mode: activeRunQueryMode }) + const val = value.split('\n').join(' ') + if (!val) return + + onSubmit(val, undefined, { mode: activeRunQueryMode }) sendEventTelemetry({ event: TelemetryEvent.SEARCH_COMMAND_SUBMITTED, eventData: { databaseId: instanceId, mode: activeRunQueryMode, // TODO sanitize user query - command: value + command: getCommandsFromQuery(value, commandsArray) || '' } }) } @@ -92,7 +105,13 @@ const QueryWrapper = (props: Props) => { data-testid="main-input-container-area" >
- +
diff --git a/redisinsight/ui/src/pages/search/components/query/Query.spec.tsx b/redisinsight/ui/src/pages/search/components/query/Query.spec.tsx new file mode 100644 index 0000000000..1f57ca4c4a --- /dev/null +++ b/redisinsight/ui/src/pages/search/components/query/Query.spec.tsx @@ -0,0 +1,10 @@ +import React from 'react' +import { render } from 'uiSrc/utils/test-utils' + +import Query from './Query' + +describe('Query', () => { + it('should render', () => { + expect(render()).toBeTruthy() + }) +}) diff --git a/redisinsight/ui/src/pages/search/components/query/Query.tsx b/redisinsight/ui/src/pages/search/components/query/Query.tsx index 6fc1fdd94b..81b309baaf 100644 --- a/redisinsight/ui/src/pages/search/components/query/Query.tsx +++ b/redisinsight/ui/src/pages/search/components/query/Query.tsx @@ -1,10 +1,9 @@ import React, { useContext, useEffect, useRef, useState } from 'react' import MonacoEditor, { monaco as monacoEditor } from 'react-monaco-editor' -import { useDispatch, useSelector } from 'react-redux' +import { useDispatch } from 'react-redux' -import { MonacoLanguage, Theme } from 'uiSrc/constants' +import { ICommands, MonacoLanguage, Theme } from 'uiSrc/constants' import { ThemeContext } from 'uiSrc/contexts/themeContext' -import { appRedisCommandsSelector } from 'uiSrc/slices/app/redis-commands' import { Nullable } from 'uiSrc/utils' import { IEditorMount } from 'uiSrc/pages/workbench/interfaces' import { @@ -21,7 +20,7 @@ import { fetchRedisearchInfoAction } from 'uiSrc/slices/browser/redisearch' import { getRediSearchMonarchTokensProvider } from 'uiSrc/utils/monaco/monarchTokens/redisearchTokens' import { installRedisearchTheme, RedisearchMonacoTheme } from 'uiSrc/utils/monaco/monacoThemes' import { useDebouncedEffect } from 'uiSrc/services' -import { SUPPORTED_COMMANDS_LIST, options, DefinedArgumentName } from './constants' +import { options, DefinedArgumentName } from './constants' import { getFieldsSuggestions, getIndexesSuggestions, @@ -35,20 +34,16 @@ export interface Props { value: string onChange: (val: string) => void indexes: RedisResponseBuffer[] + supportedCommands?: SearchCommand[] + commandsSpec?: ICommands } const Query = (props: Props) => { - const { value, onChange, indexes } = props - const { spec: REDIS_COMMANDS_SPEC } = useSelector(appRedisCommandsSelector) + const { value, onChange, indexes, supportedCommands = [], commandsSpec } = props const [selectedCommand, setSelectedCommand] = useState('') const [selectedIndex, setSelectedIndex] = useState('') - const SUPPORTED_COMMANDS = SUPPORTED_COMMANDS_LIST.map((name) => ({ - ...REDIS_COMMANDS_SPEC[name], - name - })) as unknown as SearchCommand[] - const monacoObjects = useRef>(null) const disposeCompletionItemProvider = useRef(() => {}) const disposeSignatureHelpProvider = useRef(() => {}) @@ -80,7 +75,7 @@ const Query = (props: Props) => { useEffect(() => { monacoEditor.languages.setMonarchTokensProvider( MonacoLanguage.RediSearch, - getRediSearchMonarchTokensProvider(SUPPORTED_COMMANDS, selectedCommand) + getRediSearchMonarchTokensProvider(supportedCommands, selectedCommand) ) }, [selectedCommand]) @@ -118,7 +113,7 @@ const Query = (props: Props) => { monaco.languages.setMonarchTokensProvider( MonacoLanguage.RediSearch, - getRediSearchMonarchTokensProvider(SUPPORTED_COMMANDS) + getRediSearchMonarchTokensProvider(supportedCommands) ) disposeSignatureHelpProvider.current?.() @@ -209,17 +204,18 @@ const Query = (props: Props) => { const range = getRange(position, word) const { args, isCursorInQuotes, prevCursorChar, nextCursorChar } = splitQueryByArgs(value, offset) + const allArgs = args.flat() const [beforeOffsetArgs, [currentOffsetArg]] = args const [firstArg, ...prevArgs] = beforeOffsetArgs const commandName = (firstArg || currentOffsetArg)?.toUpperCase() - const command = REDIS_COMMANDS_SPEC[commandName] as unknown as SearchCommand + const command = commandsSpec?.[commandName] as unknown as SearchCommand - const isCommandSuppurted = SUPPORTED_COMMANDS.some(({ name }) => commandName === name) + const isCommandSuppurted = supportedCommands.some(({ name }) => commandName === name) if (command && !isCommandSuppurted) return asSuggestionsRef([]) if (!command && position.lineNumber === 1 && position.column === 1) { - return getCommandsSuggestions(SUPPORTED_COMMANDS, range) + return getCommandsSuggestions(supportedCommands, range) } if (!command) { diff --git a/redisinsight/ui/src/pages/search/utils/tests/monaco.spec.ts b/redisinsight/ui/src/pages/search/utils/tests/monaco.spec.ts new file mode 100644 index 0000000000..70dc43d5ad --- /dev/null +++ b/redisinsight/ui/src/pages/search/utils/tests/monaco.spec.ts @@ -0,0 +1,60 @@ +import { getRediSearchSignutureProvider } from 'uiSrc/pages/search/utils' +import { MOCKED_SUPPORTED_COMMANDS } from 'uiSrc/pages/search/utils/tests/mocks' +import { SearchCommand } from 'uiSrc/pages/search/types' + +const ftAggregateCommand = MOCKED_SUPPORTED_COMMANDS['FT.AGGREGATE'] + +const getRediSearchSignutureProviderTests = [ + { + input: { + isOpen: false, + currentArg: {}, + parent: {} + }, + result: null + }, + { + input: { + isOpen: true, + currentArg: ftAggregateCommand.arguments.find(({ name }) => name === 'groupby') as SearchCommand, + parent: null + }, + result: { + dispose: expect.any(Function), + value: { + activeParameter: 0, + activeSignature: 0, + signatures: [{ + label: '', + parameters: [{ label: 'nargs' }] + }] + } + } + }, + { + input: { + isOpen: true, + currentArg: { name: 'expression' }, + parent: ftAggregateCommand.arguments.find(({ name }) => name === 'apply') as SearchCommand + }, + result: { + dispose: expect.any(Function), + value: { + activeParameter: 0, + activeSignature: 0, + signatures: [{ + label: 'APPLY expression AS name', + parameters: [{ label: 'expression' }] + }] + } + } + } +] + +describe('getRediSearchSignutureProvider', () => { + it.each(getRediSearchSignutureProviderTests)('should properly return result', ({ input, result }) => { + const testResult = getRediSearchSignutureProvider(input) + + expect(result).toEqual(testResult) + }) +}) diff --git a/redisinsight/ui/src/pages/search/utils/tests/query.spec.ts b/redisinsight/ui/src/pages/search/utils/tests/query.spec.ts index f550210ed4..584a587222 100644 --- a/redisinsight/ui/src/pages/search/utils/tests/query.spec.ts +++ b/redisinsight/ui/src/pages/search/utils/tests/query.spec.ts @@ -1,5 +1,6 @@ -import { findCurrentArgument } from 'uiSrc/pages/search/utils' +import { addOwnTokenToArgs, findCurrentArgument, generateDetail, splitQueryByArgs } from 'uiSrc/pages/search/utils' import { SearchCommand } from 'uiSrc/pages/search/types' +import { Maybe } from 'uiSrc/utils' import { MOCKED_SUPPORTED_COMMANDS } from './mocks' const ftSearchCommand = MOCKED_SUPPORTED_COMMANDS['FT.SEARCH'] @@ -190,6 +191,36 @@ const ftAggreageTests = [ parent: expect.any(Object) } }, + { + args: ['index', '"query"', 'LOAD', '4'], + result: { + stopArg: { multiple: true, name: 'field', type: 'string' }, + append: [], + isBlocked: true, + isComplete: false, + parent: expect.any(Object) + } + }, + { + args: ['index', '"query"', 'LOAD', '4', '1', '2', '3'], + result: { + stopArg: { multiple: true, name: 'field', type: 'string' }, + append: [], + isBlocked: true, + isComplete: false, + parent: expect.any(Object) + } + }, + { + args: ['index', '"query"', 'LOAD', '4', '1', '2', '3', '4'], + result: { + stopArg: undefined, + append: [], + isBlocked: false, + isComplete: true, + parent: expect.any(Object) + } + }, ] const ftSearchTests = [ @@ -316,6 +347,112 @@ const ftSearchTests = [ parent: expect.any(Object) } }, + { + args: ['', '', 'RETURN', '2', 'iden'], + result: { + stopArg: { + name: 'property', + type: 'string', + token: 'AS', + optional: true + }, + append: [ + { + name: 'property', + type: 'string', + token: 'AS', + optional: true + } + ], + isBlocked: false, + isComplete: false, + parent: expect.any(Object) + } + }, + { + args: ['', '', 'RETURN', '2', 'iden', 'iden'], + result: { + stopArg: { + name: 'property', + type: 'string', + token: 'AS', + optional: true + }, + append: [ + { + name: 'property', + type: 'string', + token: 'AS', + optional: true + } + ], + isBlocked: false, + isComplete: true, + parent: expect.any(Object) + } + }, + { + args: ['', '', 'RETURN', '2', 'iden', 'iden', 'AS'], + result: { + stopArg: { + name: 'property', + type: 'string', + token: 'AS', + optional: true + }, + append: [], + isBlocked: true, + isComplete: false, + parent: expect.any(Object) + } + }, + { + args: ['', '', 'SORTBY', 'f'], + result: { + stopArg: { + name: 'order', + type: 'oneof', + optional: true, + arguments: [ + { + name: 'asc', + type: 'pure-token', + token: 'ASC' + }, + { + name: 'desc', + type: 'pure-token', + token: 'DESC' + } + ] + }, + append: [ + { + name: 'asc', + type: 'pure-token', + token: 'ASC' + }, + { + name: 'desc', + type: 'pure-token', + token: 'DESC' + } + ], + isBlocked: false, + isComplete: true, + parent: expect.any(Object) + } + }, + { + args: ['', '', 'SORTBY', 'f', 'DESC'], + result: { + stopArg: undefined, + append: [], + isBlocked: false, + isComplete: true, + parent: expect.any(Object) + } + }, ] describe('findCurrentArgument', () => { @@ -326,7 +463,7 @@ describe('findCurrentArgument', () => { ftAggregateCommand.arguments as SearchCommand[], args ) - expect(result).toEqual(testResult) + expect(testResult).toEqual(result) }) }) }) @@ -338,8 +475,100 @@ describe('findCurrentArgument', () => { ftSearchCommand.arguments as SearchCommand[], args ) - expect(result).toEqual(testResult) + expect(testResult).toEqual(result) }) }) }) }) + +const splitQueryByArgsTests: Array<{ + input: [string, number?] + result: any +}> = [ + { + input: ['FT.SEARCH "idx:bicycle" "" WITHSORTKEYS'], + result: { + args: [[], ['FT.SEARCH', '"idx:bicycle"', '""', 'WITHSORTKEYS']], + isCursorInQuotes: false, + nextCursorChar: 'F', + prevCursorChar: undefined + } + }, + { + input: ['FT.SEARCH "idx:bicycle" "" WITHSORTKEYS', 17], + result: { + args: [['FT.SEARCH'], ['"idx:bicycle"', '""', 'WITHSORTKEYS']], + isCursorInQuotes: true, + nextCursorChar: 'c', + prevCursorChar: 'i' + } + }, + { + input: ['FT.SEARCH "idx:bicycle" "" WITHSORTKEYS', 39], + result: { + args: [['FT.SEARCH', '"idx:bicycle"', '""'], ['WITHSORTKEYS']], + isCursorInQuotes: false, + nextCursorChar: undefined, + prevCursorChar: 'S' + } + }, + { + input: ['FT.SEARCH "idx:bicycle" "" WITHSORTKEYS ', 40], + result: { + args: [['FT.SEARCH', '"idx:bicycle"', '""', 'WITHSORTKEYS'], []], + isCursorInQuotes: false, + nextCursorChar: undefined, + prevCursorChar: ' ' + } + }, + { + input: ['FT.SEARCH "idx:bicycle \\" \\"" "" WITHSORTKEYS ', 46], + result: { + args: [['FT.SEARCH', '"idx:bicycle " ""', '""', 'WITHSORTKEYS'], []], + isCursorInQuotes: false, + nextCursorChar: undefined, + prevCursorChar: ' ' + } + } +] + +describe('splitQueryByArgs', () => { + it.each(splitQueryByArgsTests)('should return for %input proper result', ({ input, result }) => { + const testResult = splitQueryByArgs(...input) + expect(testResult).toEqual(result) + }) +}) + +const generateDetailTests: Array<{ input: Maybe, result: any }> = [ + { + input: ftSearchCommand.arguments.find(({ name }) => name === 'nocontent') as SearchCommand, + result: 'NOCONTENT' + }, + { + input: ftSearchCommand.arguments.find(({ name }) => name === 'filter') as SearchCommand, + result: 'FILTER numeric_field min max' + }, + { + input: ftSearchCommand.arguments.find(({ name }) => name === 'geo_filter') as SearchCommand, + result: 'GEOFILTER geo_field lon lat radius m | km | mi | ft' + }, + { + input: ftAggregateCommand.arguments.find(({ name }) => name === 'groupby') as SearchCommand, + result: 'GROUPBY nargs property [property ...] [REDUCE function nargs arg [arg ...] [AS name] [REDUCE function nargs arg [arg ...] [AS name] ...]]' + }, +] + +describe('generateDetail', () => { + it.each(generateDetailTests)('should return for %input proper result', ({ input, result }) => { + const testResult = generateDetail(input) + expect(testResult).toEqual(result) + }) +}) + +describe('addOwnTokenToArgs', () => { + it('should add FT.SEARCH to args', () => { + const result = addOwnTokenToArgs('FT.SEARCH', { arguments: [] }) + + expect({ arguments: [{ token: 'FT.SEARCH', type: 'pure-token' }] }).toEqual(result) + }) +}) diff --git a/redisinsight/ui/src/slices/tests/search/searchAndQuery.spec.ts b/redisinsight/ui/src/slices/tests/search/searchAndQuery.spec.ts new file mode 100644 index 0000000000..29af826a88 --- /dev/null +++ b/redisinsight/ui/src/slices/tests/search/searchAndQuery.spec.ts @@ -0,0 +1,58 @@ +import { cloneDeep } from 'lodash' + +import { + cleanup, + initialStateDefault, + mockedStore, +} from 'uiSrc/utils/test-utils' + +import { RunQueryMode } from 'uiSrc/slices/interfaces' +import reducer, { + initialState, + searchAndQuerySelector, + changeSQActiveRunQueryMode +} from '../../search/searchAndQuery' + +jest.mock('uiSrc/services', () => ({ + ...jest.requireActual('uiSrc/services'), +})) + +let store: typeof mockedStore +beforeEach(() => { + cleanup() + store = cloneDeep(mockedStore) + store.clearActions() +}) + +describe('slices', () => { + describe('reducer, actions and selectors', () => { + it('should return the initial state on first run', () => { + // Arrange + const nextState = initialState + + // Act + const result = reducer(undefined, {} as any) + + // Assert + expect(result).toEqual(nextState) + }) + }) + + describe('changeSQActiveRunQueryMode', () => { + it('should properly set mode', () => { + const state = { + ...initialState, + activeRunQueryMode: RunQueryMode.Raw + } + + const nextState = reducer(initialState, changeSQActiveRunQueryMode(RunQueryMode.Raw)) + + // Assert + const rootState = Object.assign(initialStateDefault, { + search: { query: nextState }, + }) + + expect(searchAndQuerySelector(rootState)).toEqual(state) + }) + }) +}) From 93c0e5ce3c235659021c1ec13b76a26173a23946 Mon Sep 17 00:00:00 2001 From: Roman Sergeenko Date: Thu, 22 Aug 2024 11:03:01 +0200 Subject: [PATCH 034/256] #RI-5684 - add ft.profile and ft.explain to supported commands --- .../pages/search/components/query/Query.tsx | 75 ++++++++----- .../search/components/query/constants.ts | 2 +- .../search/components/query/utils.spec.ts | 39 +++++++ .../pages/search/components/query/utils.ts | 103 +++++++++++++++--- .../search/{utils/tests => mocks}/mocks.ts | 0 redisinsight/ui/src/pages/search/types.ts | 19 +++- .../ui/src/pages/search/utils/query.ts | 25 +++++ .../pages/search/utils/tests/query.spec.ts | 23 +++- .../monaco/monarchTokens/redisearchTokens.ts | 15 ++- 9 files changed, 249 insertions(+), 52 deletions(-) create mode 100644 redisinsight/ui/src/pages/search/components/query/utils.spec.ts rename redisinsight/ui/src/pages/search/{utils/tests => mocks}/mocks.ts (100%) diff --git a/redisinsight/ui/src/pages/search/components/query/Query.tsx b/redisinsight/ui/src/pages/search/components/query/Query.tsx index 81b309baaf..9db6aabfb3 100644 --- a/redisinsight/ui/src/pages/search/components/query/Query.tsx +++ b/redisinsight/ui/src/pages/search/components/query/Query.tsx @@ -8,13 +8,13 @@ import { Nullable } from 'uiSrc/utils' import { IEditorMount } from 'uiSrc/pages/workbench/interfaces' import { addOwnTokenToArgs, - findCurrentArgument, + findCurrentArgInQuery, findCurrentArgument, getRange, getRediSearchSignutureProvider, setCursorPositionAtTheEnd, splitQueryByArgs } from 'uiSrc/pages/search/utils' -import { SearchCommand } from 'uiSrc/pages/search/types' +import { CommandContext, CursorContext, SearchCommand } from 'uiSrc/pages/search/types' import { RedisResponseBuffer } from 'uiSrc/slices/interfaces' import { fetchRedisearchInfoAction } from 'uiSrc/slices/browser/redisearch' import { getRediSearchMonarchTokensProvider } from 'uiSrc/utils/monaco/monarchTokens/redisearchTokens' @@ -25,9 +25,9 @@ import { getFieldsSuggestions, getIndexesSuggestions, asSuggestionsRef, - getMandatoryArgumentSuggestions, - getOptionalSuggestions, - getCommandsSuggestions, isIndexComplete + getCommandsSuggestions, + isIndexComplete, + getGeneralSuggestions } from './utils' export interface Props { @@ -226,43 +226,64 @@ const Query = (props: Props) => { setSelectedIndex(allArgs[1] || '') setSelectedCommand(commandName) - // cover query - if (command?.arguments?.[prevArgs.length]?.name === DefinedArgumentName.query) { - updateHelpWidget(true, addOwnTokenToArgs(commandName, command), command?.arguments?.[prevArgs.length]) - - if (prevCursorChar === '@') { - helpWidgetRef.current.isOpen = false - return asSuggestionsRef(getFieldsSuggestions(attributesRef.current, range), false) - } + const currentCommandArg = findCurrentArgInQuery(prevArgs, command) - return asSuggestionsRef([], false) + // cover index + if (currentCommandArg?.name === DefinedArgumentName.index) { + updateHelpWidget(true, addOwnTokenToArgs(commandName, command), currentCommandArg) + return getIndexSuggestions(command, prevArgs.length, currentOffsetArg, range) } - // cover index - if (command?.arguments?.[prevArgs.length]?.name === DefinedArgumentName.index) { - updateHelpWidget(true, addOwnTokenToArgs(commandName, command), command?.arguments?.[prevArgs.length]) + // cover query + if (currentCommandArg?.name === DefinedArgumentName.query) { + updateHelpWidget(true, addOwnTokenToArgs(commandName, command), currentCommandArg) - // we do not suggest indexes if there is something next - if (currentOffsetArg) return asSuggestionsRef([], false) - if (indexesRef.current.length) return asSuggestionsRef(getIndexesSuggestions(indexesRef.current, range)) - return asSuggestionsRef([]) + return getQuerySuggestions(prevCursorChar, range) } if (isCursorInQuotes || nextCursorChar?.trim()) return asSuggestionsRef([]) - if (prevArgs.length < 2) return asSuggestionsRef([]) if ((prevCursorChar?.trim() || isCursorInQuotes) && isEscapedSuggestions.current) return asSuggestionsRef([]) isEscapedSuggestions.current = false - const foundArg = findCurrentArgument(command?.arguments || [], prevArgs) - updateHelpWidget(!!foundArg?.stopArg, foundArg?.parent, foundArg?.stopArg) + const cursorContext: CursorContext = { isCursorInQuotes, prevCursorChar, nextCursorChar, currentOffsetArg, range } + const commandContext: CommandContext = { commandName, command, prevArgs, allArgs, currentCommandArg } + + const { suggestions, forceHide, helpWidgetData } = getGeneralSuggestions( + commandContext, + cursorContext, + attributesRef.current + ) + + if (helpWidgetData) updateHelpWidget(helpWidgetData.isOpen, helpWidgetData.parent, helpWidgetData.currentArg) + return asSuggestionsRef(suggestions, forceHide) + } - if (foundArg && !foundArg.isComplete) return getMandatoryArgumentSuggestions(foundArg, attributesRef.current, range) - if (!foundArg || foundArg.isComplete) { - return getOptionalSuggestions(command, foundArg, allArgs, range, currentOffsetArg) + const getIndexSuggestions = ( + command: SearchCommand, + prevArgsLength: number, + currentOffsetArg: Nullable, + range: monacoEditor.IRange + ) => { + if (currentOffsetArg) return asSuggestionsRef([], false) + if (indexesRef.current.length) { + const isNextArgQuery = command?.arguments?.[prevArgsLength + 1]?.name === DefinedArgumentName.query + return asSuggestionsRef(getIndexesSuggestions(indexesRef.current, range, isNextArgQuery)) } return asSuggestionsRef([]) } + const getQuerySuggestions = ( + prevCursorChar: string, + range: monacoEditor.IRange + ) => { + if (prevCursorChar === '@') { + helpWidgetRef.current.isOpen = false + return asSuggestionsRef(getFieldsSuggestions(attributesRef.current, range), false) + } + + return asSuggestionsRef([], false) + } + return ( ({ + currentOffsetArg: undefined, + isCursorInQuotes: false, + nextCursorChar: undefined, + prevCursorChar: ' ', + range: {} +}) + +const getGeneralSuggestionsTests = [ + { + input: { + commandContext: { + allArgs: ['FT.AGGREGATE', '""', '""'], + command: ftAggregate, + commandName: 'FT.AGGREGATE', + currentCommandArg: null, + prevArgs: ['""', '""'] + }, + cursorContext: getCursorContext() + }, + result: { + helpWidgetData: expect.any(Object), + suggestions: expect.any(Array) + } + } +] + +describe('getGeneralSuggestions', () => { + it.each(getGeneralSuggestionsTests)('dawd', ({ input, result }) => { + const testResult = getGeneralSuggestions(input.commandContext, input.cursorContext, []) + + expect(testResult).toEqual(result) + }) +}) diff --git a/redisinsight/ui/src/pages/search/components/query/utils.ts b/redisinsight/ui/src/pages/search/components/query/utils.ts index 1df71cd5a2..ba133ec57f 100644 --- a/redisinsight/ui/src/pages/search/components/query/utils.ts +++ b/redisinsight/ui/src/pages/search/components/query/utils.ts @@ -2,8 +2,8 @@ import { monaco } from 'react-monaco-editor' import * as monacoEditor from 'monaco-editor' import { RedisResponseBuffer } from 'uiSrc/slices/interfaces' import { bufferToString, formatLongName, getCommandMarkdown, Nullable } from 'uiSrc/utils' -import { buildSuggestion, generateDetail } from 'uiSrc/pages/search/utils' -import { FoundCommandArgument, SearchCommand } from 'uiSrc/pages/search/types' +import { addOwnTokenToArgs, buildSuggestion, findCurrentArgument, generateDetail } from 'uiSrc/pages/search/utils' +import { CommandContext, CursorContext, FoundCommandArgument, SearchCommand } from 'uiSrc/pages/search/types' import { DefinedArgumentName } from 'uiSrc/pages/search/components/query/constants' export const asSuggestionsRef = (suggestions: monacoEditor.languages.CompletionItem[], forceHide = true) => ({ @@ -11,14 +11,15 @@ export const asSuggestionsRef = (suggestions: monacoEditor.languages.CompletionI forceHide }) -export const getIndexesSuggestions = (indexes: RedisResponseBuffer[], range: monaco.IRange) => +export const getIndexesSuggestions = (indexes: RedisResponseBuffer[], range: monaco.IRange, nextQoutes = true) => indexes.map((index) => { const value = formatLongName(bufferToString(index)) + const insertQueryQuotes = nextQoutes ? ' "$1"' : '' return { label: value || ' ', kind: monacoEditor.languages.CompletionItemKind.Snippet, - insertText: `"${value}" "$1" `, + insertText: `"${value}"${insertQueryQuotes} `, insertTextRules: monacoEditor.languages.CompletionItemInsertTextRule.InsertAsSnippet, range, detail: value || ' ', @@ -52,25 +53,25 @@ export const getMandatoryArgumentSuggestions = ( foundArg: FoundCommandArgument, fields: any[], range: monaco.IRange -) => { +): monacoEditor.languages.CompletionItem[] => { if (foundArg.stopArg?.name === DefinedArgumentName.field) { - if (!fields.length) asSuggestionsRef([]) - return asSuggestionsRef(getFieldsSuggestions(fields, range, true)) + if (!fields.length) return [] + return getFieldsSuggestions(fields, range, true) } - if (foundArg.isBlocked) return asSuggestionsRef([]) + if (foundArg.isBlocked) return [] if (foundArg.append?.length) { - return asSuggestionsRef(foundArg.append.map((arg: any) => buildSuggestion(arg, range, { + return foundArg.append.map((arg: any) => buildSuggestion(arg, range, { kind: monacoEditor.languages.CompletionItemKind.Property, detail: generateDetail(foundArg?.parent) - }))) + })) } - return asSuggestionsRef([]) + return [] } -export const getOptionalSuggestions = ( - command: SearchCommand, +export const getCommandSuggestions = ( + firstLevelArgs: SearchCommand[], foundArg: Nullable, allArgs: string[], range: monaco.IRange, @@ -78,14 +79,13 @@ export const getOptionalSuggestions = ( ) => { const appendCommands = foundArg?.append ?? [] - return asSuggestionsRef([ + return [ ...appendCommands.map((arg) => buildSuggestion(arg, range, { sortText: 'a', kind: monacoEditor.languages.CompletionItemKind.Property, detail: generateDetail(foundArg?.parent) })), - ...(command?.arguments || []) - .filter((arg) => arg.optional) + ...firstLevelArgs .filter((arg) => arg.multiple || !(currentArg !== arg.token && allArgs.includes(arg.token || arg.arguments?.[0]?.token || ''))) .map((arg) => buildSuggestion(arg, range, { @@ -93,7 +93,76 @@ export const getOptionalSuggestions = ( kind: monacoEditor.languages.CompletionItemKind.Reference, detail: generateDetail(arg) })) - ]) + ] +} + +export const getGeneralSuggestions = ( + commandContext: CommandContext, + cursorContext: CursorContext, + fields: any[], +): { + suggestions: monacoEditor.languages.CompletionItem[], + forceHide?: boolean + helpWidgetData?: any +} => { + const { command, prevArgs } = commandContext + const { range } = cursorContext + const foundArg = findCurrentArgument(command?.arguments || [], prevArgs) + + if (foundArg && !foundArg.isComplete) { + return { + suggestions: getMandatoryArgumentSuggestions(foundArg, fields, range), + helpWidgetData: { + isOpen: !!foundArg?.stopArg, + parent: foundArg?.parent, + currentArg: foundArg?.stopArg + } + } + } + + return getNextSuggestions(commandContext, cursorContext, foundArg) +} + +export const getNextSuggestions = ( + { command, currentCommandArg, prevArgs, allArgs }: CommandContext, + { currentOffsetArg, range }: CursorContext, + foundArg: Nullable +) => { + if (!command) return { suggestions: [] } + if (foundArg && !foundArg.isComplete) return { suggestions: [], helpWidgetData: { isOpen: false } } + + const parentArgIndex = command.arguments + ?.findIndex(({ name }) => name === foundArg?.parent?.name) || -1 + const currentArgIndex = parentArgIndex > -1 ? parentArgIndex : prevArgs.length - 1 + const nextMandatoryIndex = command.arguments + ?.findIndex(({ optional }, i) => !optional && i > currentArgIndex) || -1 + + const nextOptionalArgs = ( + nextMandatoryIndex > -1 + ? command.arguments?.slice(currentArgIndex + 1, nextMandatoryIndex) + : command.arguments?.filter(({ optional }) => optional) + ) || [] + const nextMandatoryArg = command.arguments?.[nextMandatoryIndex] + + if (nextMandatoryArg?.token) { + nextOptionalArgs.unshift(nextMandatoryArg) + } + + if (nextMandatoryArg && !nextMandatoryArg.token) { + return { + helpWidgetData: { + isOpen: !!currentCommandArg, + parent: addOwnTokenToArgs(command.name!, command), + currentArg: nextMandatoryArg + }, + suggestions: [] + } + } + + return { + suggestions: getCommandSuggestions(nextOptionalArgs, foundArg, allArgs, range, currentOffsetArg), + helpWidgetData: { isOpen: false } + } } export const isIndexComplete = (index: string) => { diff --git a/redisinsight/ui/src/pages/search/utils/tests/mocks.ts b/redisinsight/ui/src/pages/search/mocks/mocks.ts similarity index 100% rename from redisinsight/ui/src/pages/search/utils/tests/mocks.ts rename to redisinsight/ui/src/pages/search/mocks/mocks.ts diff --git a/redisinsight/ui/src/pages/search/types.ts b/redisinsight/ui/src/pages/search/types.ts index d4973f1c0b..d4eca49253 100644 --- a/redisinsight/ui/src/pages/search/types.ts +++ b/redisinsight/ui/src/pages/search/types.ts @@ -1,4 +1,5 @@ -import { Maybe } from 'uiSrc/utils' +import { monaco as monacoEditor } from 'react-monaco-editor' +import { Maybe, Nullable } from 'uiSrc/utils' export enum TokenType { PureToken = 'pure-token', @@ -30,3 +31,19 @@ export interface FoundCommandArgument { append: Maybe parent: Maybe } + +export interface CommandContext { + commandName: string + command: Maybe + prevArgs: string[] + allArgs: string[] + currentCommandArg: Nullable +} + +export interface CursorContext { + isCursorInQuotes: boolean + prevCursorChar: string + nextCursorChar: string + currentOffsetArg: any + range: monacoEditor.IRange +} diff --git a/redisinsight/ui/src/pages/search/utils/query.ts b/redisinsight/ui/src/pages/search/utils/query.ts index 703d651b31..17a8ad5ef2 100644 --- a/redisinsight/ui/src/pages/search/utils/query.ts +++ b/redisinsight/ui/src/pages/search/utils/query.ts @@ -108,6 +108,13 @@ export const findCurrentArgument = ( } } + if (args[prev.length] && !args[prev.length].optional) { + return { + ...getArgumentSuggestions([], args.slice(prev.length)), + parent: undefined + } + } + return null } @@ -345,3 +352,21 @@ export const addOwnTokenToArgs = (token: string, command: SearchCommand) => { } return command } + +export const findCurrentArgInQuery = (args: string[], command: SearchCommand) => { + if (!command.arguments || !command.arguments.length) return null + + let argIndex = 0 + args.forEach((arg) => { + for (let i = argIndex; i < command.arguments!.length; i++) { + if (command.arguments![i]?.optional && command.arguments![i]?.token?.toUpperCase() !== arg?.toUpperCase()) { + continue + } + + argIndex = i + 1 + break + } + }) + + return command.arguments[argIndex] +} diff --git a/redisinsight/ui/src/pages/search/utils/tests/query.spec.ts b/redisinsight/ui/src/pages/search/utils/tests/query.spec.ts index 584a587222..bff290b4da 100644 --- a/redisinsight/ui/src/pages/search/utils/tests/query.spec.ts +++ b/redisinsight/ui/src/pages/search/utils/tests/query.spec.ts @@ -1,13 +1,22 @@ import { addOwnTokenToArgs, findCurrentArgument, generateDetail, splitQueryByArgs } from 'uiSrc/pages/search/utils' import { SearchCommand } from 'uiSrc/pages/search/types' import { Maybe } from 'uiSrc/utils' -import { MOCKED_SUPPORTED_COMMANDS } from './mocks' +import { MOCKED_SUPPORTED_COMMANDS } from '../../mocks/mocks' const ftSearchCommand = MOCKED_SUPPORTED_COMMANDS['FT.SEARCH'] const ftAggregateCommand = MOCKED_SUPPORTED_COMMANDS['FT.AGGREGATE'] const ftAggreageTests = [ - { args: [''], result: null }, + { + args: [''], + result: { + append: [], + isBlocked: true, + isComplete: false, + parent: undefined, + stopArg: { name: 'query', type: 'string' } + } + }, { args: ['', ''], result: null }, { args: ['index', '"query"', 'APPLY'], @@ -224,7 +233,15 @@ const ftAggreageTests = [ ] const ftSearchTests = [ - { args: [''], result: null }, + { + args: [''], + result: { + append: [], + isBlocked: true, + isComplete: false, + parent: undefined, + stopArg: { name: 'query', type: 'string' } } + }, { args: ['', ''], result: null }, { args: ['', '', 'SUMMARIZE'], diff --git a/redisinsight/ui/src/utils/monaco/monarchTokens/redisearchTokens.ts b/redisinsight/ui/src/utils/monaco/monarchTokens/redisearchTokens.ts index 2eb71dde4f..9d91952d2d 100644 --- a/redisinsight/ui/src/utils/monaco/monarchTokens/redisearchTokens.ts +++ b/redisinsight/ui/src/utils/monaco/monarchTokens/redisearchTokens.ts @@ -1,5 +1,6 @@ import { monaco as monacoEditor } from 'react-monaco-editor' import { SearchCommand, TokenType } from 'uiSrc/pages/search/types' +import { DefinedArgumentName } from 'uiSrc/pages/search/components/query/constants' const STRING_DOUBLE = 'string.double' @@ -41,6 +42,13 @@ const generateTokens = (command?: SearchCommand) => { return levels } +const isQueryAfterIndex = (command?: SearchCommand) => { + if (!command) return false + + const index = command.arguments?.findIndex(({ name }) => name === DefinedArgumentName.index) || -2 + return command.arguments?.[index + 1]?.name === DefinedArgumentName.query +} + export const getRediSearchMonarchTokensProvider = ( commands: SearchCommand[], command?: string @@ -49,6 +57,7 @@ export const getRediSearchMonarchTokensProvider = ( const keywords = generateKeywords(commands) const argTokens = generateTokens(currentCommand) + const isHighlightQuery = isQueryAfterIndex(currentCommand) return ( { @@ -86,9 +95,9 @@ export const getRediSearchMonarchTokensProvider = ( ], 'argument.block': argTokens.map((tokens, lvl) => [`(${tokens.join('|')})\\b`, `argument.block.${lvl}`]), index: [ - [/"([^"\\]|\\.)*"/, { token: 'index', next: '@query' }], - [/'([^'\\]|\\.)*'/, { token: 'index', next: '@query' }], - [/[a-zA-Z_]\w*/, { token: 'index', next: '@query' }], + [/"([^"\\]|\\.)*"/, { token: 'index', next: isHighlightQuery ? '@query' : '@root' }], + [/'([^'\\]|\\.)*'/, { token: 'index', next: isHighlightQuery ? '@query' : '@root' }], + [/[a-zA-Z_]\w*/, { token: 'index', next: isHighlightQuery ? '@query' : '@root' }], { include: 'root' } // Fallback to the root state if nothing matches ], query: [ From a70b25f1592d7452dd96aa0a878f3f1b5088ef5a Mon Sep 17 00:00:00 2001 From: Roman Sergeenko Date: Thu, 22 Aug 2024 11:54:25 +0200 Subject: [PATCH 035/256] #RI-5684 - start refactoring --- .../pages/search/components/query/Query.tsx | 100 +++++++++++++----- .../pages/search/components/query/utils.ts | 5 +- 2 files changed, 74 insertions(+), 31 deletions(-) diff --git a/redisinsight/ui/src/pages/search/components/query/Query.tsx b/redisinsight/ui/src/pages/search/components/query/Query.tsx index 9db6aabfb3..063511a729 100644 --- a/redisinsight/ui/src/pages/search/components/query/Query.tsx +++ b/redisinsight/ui/src/pages/search/components/query/Query.tsx @@ -14,7 +14,7 @@ import { setCursorPositionAtTheEnd, splitQueryByArgs } from 'uiSrc/pages/search/utils' -import { CommandContext, CursorContext, SearchCommand } from 'uiSrc/pages/search/types' +import { CommandContext, CursorContext, SearchCommand, TokenType } from 'uiSrc/pages/search/types' import { RedisResponseBuffer } from 'uiSrc/slices/interfaces' import { fetchRedisearchInfoAction } from 'uiSrc/slices/browser/redisearch' import { getRediSearchMonarchTokensProvider } from 'uiSrc/utils/monaco/monarchTokens/redisearchTokens' @@ -27,7 +27,7 @@ import { asSuggestionsRef, getCommandsSuggestions, isIndexComplete, - getGeneralSuggestions + getGeneralSuggestions, } from './utils' export interface Props { @@ -60,6 +60,12 @@ const Query = (props: Props) => { const attributesRef = useRef([]) const isEscapedSuggestions = useRef(false) + const COMMANDS_LIST = supportedCommands.map((command) => ({ + ...addOwnTokenToArgs(command.name!, command), + token: command.name!, + type: TokenType.Block + })) + const { theme } = useContext(ThemeContext) const dispatch = useDispatch() @@ -227,35 +233,73 @@ const Query = (props: Props) => { setSelectedCommand(commandName) const currentCommandArg = findCurrentArgInQuery(prevArgs, command) + const foundArg = findCurrentArgument(COMMANDS_LIST, beforeOffsetArgs) - // cover index - if (currentCommandArg?.name === DefinedArgumentName.index) { - updateHelpWidget(true, addOwnTokenToArgs(commandName, command), currentCommandArg) - return getIndexSuggestions(command, prevArgs.length, currentOffsetArg, range) - } - - // cover query - if (currentCommandArg?.name === DefinedArgumentName.query) { - updateHelpWidget(true, addOwnTokenToArgs(commandName, command), currentCommandArg) + console.log(foundArg) - return getQuerySuggestions(prevCursorChar, range) + switch (foundArg?.stopArg?.name) { + case DefinedArgumentName.index: { + updateHelpWidget(true, command, foundArg?.stopArg) + return getIndexSuggestions(command, prevArgs.length, currentOffsetArg, range) + } + case DefinedArgumentName.query: { + updateHelpWidget(true, command, foundArg?.stopArg) + return getQuerySuggestions(prevCursorChar, range) + } + default: { + console.log(foundArg) + const cursorContext: CursorContext = { isCursorInQuotes, prevCursorChar, nextCursorChar, currentOffsetArg, range } + const commandContext: CommandContext = { + commands: COMMANDS_LIST, + commandName, + command, + prevArgs: beforeOffsetArgs, + allArgs, + currentCommandArg: foundArg?.stopArg + } + + const { suggestions, forceHide, helpWidgetData } = getGeneralSuggestions( + foundArg, + commandContext, + cursorContext, + attributesRef.current + ) + + console.log(suggestions) + console.log(helpWidgetData) + + if (helpWidgetData) updateHelpWidget(helpWidgetData.isOpen, helpWidgetData.parent, helpWidgetData.currentArg) + return asSuggestionsRef(suggestions, forceHide) + } } - - if (isCursorInQuotes || nextCursorChar?.trim()) return asSuggestionsRef([]) - if ((prevCursorChar?.trim() || isCursorInQuotes) && isEscapedSuggestions.current) return asSuggestionsRef([]) - isEscapedSuggestions.current = false - - const cursorContext: CursorContext = { isCursorInQuotes, prevCursorChar, nextCursorChar, currentOffsetArg, range } - const commandContext: CommandContext = { commandName, command, prevArgs, allArgs, currentCommandArg } - - const { suggestions, forceHide, helpWidgetData } = getGeneralSuggestions( - commandContext, - cursorContext, - attributesRef.current - ) - - if (helpWidgetData) updateHelpWidget(helpWidgetData.isOpen, helpWidgetData.parent, helpWidgetData.currentArg) - return asSuggestionsRef(suggestions, forceHide) + // // cover index + // if (currentCommandArg?.name === DefinedArgumentName.index) { + // updateHelpWidget(true, addOwnTokenToArgs(commandName, command), currentCommandArg) + // return getIndexSuggestions(command, prevArgs.length, currentOffsetArg, range) + // } + // + // // cover query + // if (currentCommandArg?.name === DefinedArgumentName.query) { + // updateHelpWidget(true, addOwnTokenToArgs(commandName, command), currentCommandArg) + // + // return getQuerySuggestions(prevCursorChar, range) + // } + // + // if (isCursorInQuotes || nextCursorChar?.trim()) return asSuggestionsRef([]) + // if ((prevCursorChar?.trim() || isCursorInQuotes) && isEscapedSuggestions.current) return asSuggestionsRef([]) + // isEscapedSuggestions.current = false + // + // const cursorContext: CursorContext = { isCursorInQuotes, prevCursorChar, nextCursorChar, currentOffsetArg, range } + // const commandContext: CommandContext = { commandName, command, prevArgs, allArgs, currentCommandArg } + // + // const { suggestions, forceHide, helpWidgetData } = getGeneralSuggestions( + // commandContext, + // cursorContext, + // attributesRef.current + // ) + // + // if (helpWidgetData) updateHelpWidget(helpWidgetData.isOpen, helpWidgetData.parent, helpWidgetData.currentArg) + // return asSuggestionsRef(suggestions, forceHide) } const getIndexSuggestions = ( diff --git a/redisinsight/ui/src/pages/search/components/query/utils.ts b/redisinsight/ui/src/pages/search/components/query/utils.ts index ba133ec57f..65a1380efe 100644 --- a/redisinsight/ui/src/pages/search/components/query/utils.ts +++ b/redisinsight/ui/src/pages/search/components/query/utils.ts @@ -97,6 +97,7 @@ export const getCommandSuggestions = ( } export const getGeneralSuggestions = ( + foundArg: any, commandContext: CommandContext, cursorContext: CursorContext, fields: any[], @@ -105,9 +106,7 @@ export const getGeneralSuggestions = ( forceHide?: boolean helpWidgetData?: any } => { - const { command, prevArgs } = commandContext const { range } = cursorContext - const foundArg = findCurrentArgument(command?.arguments || [], prevArgs) if (foundArg && !foundArg.isComplete) { return { @@ -152,7 +151,7 @@ export const getNextSuggestions = ( return { helpWidgetData: { isOpen: !!currentCommandArg, - parent: addOwnTokenToArgs(command.name!, command), + parent: foundArg?.stopArg, currentArg: nextMandatoryArg }, suggestions: [] From 3d8d242582bad7d99ee258d289fcaca24b092259 Mon Sep 17 00:00:00 2001 From: Roman Sergeenko Date: Fri, 23 Aug 2024 09:03:49 +0200 Subject: [PATCH 036/256] #RI-5684 - udd tests --- .../pages/search/components/query/Query.tsx | 3 +- .../search/components/query/utils.spec.ts | 97 ++++++++++++++++++- .../pages/search/components/query/utils.ts | 23 ++--- .../ui/src/pages/search/mocks/mocks.ts | 45 +++++++++ .../pages/search/utils/tests/monaco.spec.ts | 2 +- 5 files changed, 153 insertions(+), 17 deletions(-) diff --git a/redisinsight/ui/src/pages/search/components/query/Query.tsx b/redisinsight/ui/src/pages/search/components/query/Query.tsx index 9db6aabfb3..e3b605b7a1 100644 --- a/redisinsight/ui/src/pages/search/components/query/Query.tsx +++ b/redisinsight/ui/src/pages/search/components/query/Query.tsx @@ -8,7 +8,7 @@ import { Nullable } from 'uiSrc/utils' import { IEditorMount } from 'uiSrc/pages/workbench/interfaces' import { addOwnTokenToArgs, - findCurrentArgInQuery, findCurrentArgument, + findCurrentArgInQuery, getRange, getRediSearchSignutureProvider, setCursorPositionAtTheEnd, @@ -223,6 +223,7 @@ const Query = (props: Props) => { return asSuggestionsRef([], false) } + // TODO: change to more generic logic setSelectedIndex(allArgs[1] || '') setSelectedCommand(commandName) diff --git a/redisinsight/ui/src/pages/search/components/query/utils.spec.ts b/redisinsight/ui/src/pages/search/components/query/utils.spec.ts index 2b917ec384..bb71924265 100644 --- a/redisinsight/ui/src/pages/search/components/query/utils.spec.ts +++ b/redisinsight/ui/src/pages/search/components/query/utils.spec.ts @@ -1,7 +1,10 @@ -import { getGeneralSuggestions } from 'uiSrc/pages/search/components/query/utils' +import { getGeneralSuggestions, isIndexComplete } from 'uiSrc/pages/search/components/query/utils' import { MOCKED_SUPPORTED_COMMANDS } from 'uiSrc/pages/search/mocks/mocks' +import { buildSuggestion } from 'uiSrc/pages/search/utils' +import { SearchCommand } from 'uiSrc/pages/search/types' -const ftAggregate = MOCKED_SUPPORTED_COMMANDS['FT.SEARCH'] +const ftAggregate = MOCKED_SUPPORTED_COMMANDS['FT.AGGREGATE'] +const ftProfile = MOCKED_SUPPORTED_COMMANDS['FT.PROFILE'] const getCursorContext = () => ({ currentOffsetArg: undefined, @@ -25,15 +28,101 @@ const getGeneralSuggestionsTests = [ }, result: { helpWidgetData: expect.any(Object), - suggestions: expect.any(Array) + suggestions: ftAggregate.arguments + .slice(2) + .map((arg) => ({ + ...buildSuggestion(arg as SearchCommand, {} as any), + sortText: expect.any(String), + kind: undefined, + detail: expect.any(String) + })) + } + }, + { + input: { + commandContext: { + allArgs: ['FT.AGGREGATE', '""', '""', 'APPLY', 'expression'], + command: ftAggregate, + commandName: 'FT.AGGREGATE', + currentCommandArg: null, + prevArgs: ['""', '""', 'APPLY', 'expression'] + }, + cursorContext: getCursorContext() + }, + result: { + helpWidgetData: expect.any(Object), + suggestions: [ + { + label: 'AS', + insertText: 'AS ', + insertTextRules: 4, + range: expect.any(Object), + kind: undefined, + detail: 'APPLY expression AS name', + } + ] + } + }, + { + input: { + commandContext: { + allArgs: ['FT.PROFILE', '""'], + command: ftProfile, + commandName: 'FT.PROFILE', + currentCommandArg: null, + prevArgs: ['""'] + }, + cursorContext: getCursorContext() + }, + result: { + helpWidgetData: expect.any(Object), + suggestions: [ + { + label: 'SEARCH', + insertText: 'SEARCH ', + insertTextRules: 4, + range: expect.any(Object), + kind: undefined, + detail: '', + }, + { + label: 'AGGREGATE', + insertText: 'AGGREGATE ', + insertTextRules: 4, + range: expect.any(Object), + kind: undefined, + detail: '', + } + ] } } ] describe('getGeneralSuggestions', () => { - it.each(getGeneralSuggestionsTests)('dawd', ({ input, result }) => { + it.each(getGeneralSuggestionsTests)('should properly return suggestions', ({ input, result }) => { const testResult = getGeneralSuggestions(input.commandContext, input.cursorContext, []) expect(testResult).toEqual(result) }) }) + +const isIndexCompleteTests: Array<[string, boolean]> = [ + ['', false], + ['"', false], + ['\"\\"', false], + ['""', true], + ["'", false], + ["''", true], + ["'index\\'", false], + ["'index'", true], + ['"index \\\\"', true], + ['index', true], +] + +describe('isIndexComplete', () => { + it.each(isIndexCompleteTests)('should properly return value for %s', (index, result) => { + const testResult = isIndexComplete(index) + + expect(testResult).toEqual(result) + }) +}) diff --git a/redisinsight/ui/src/pages/search/components/query/utils.ts b/redisinsight/ui/src/pages/search/components/query/utils.ts index ba133ec57f..a22e1b1d6c 100644 --- a/redisinsight/ui/src/pages/search/components/query/utils.ts +++ b/redisinsight/ui/src/pages/search/components/query/utils.ts @@ -166,18 +166,19 @@ export const getNextSuggestions = ( } export const isIndexComplete = (index: string) => { - if (!index) return false - if (index.startsWith('"')) { - if (index.length < 2) return false - if (!index.endsWith('"')) return false - return !index.endsWith('\\', -1) - } + if (index.length === 0) return false + + const firstChar = index[0] + const lastChar = index[index.length - 1] + + if (firstChar !== '"' && firstChar !== "'") return true + if (index.length === 1 && (firstChar === '"' || firstChar === "'")) return false + if (firstChar !== lastChar) return false - if (index.startsWith("'")) { - if (index.length < 2) return false - if (!index.endsWith("'")) return false - return !index.endsWith('\\', -1) + let escape = false + for (let i = 1; i < index.length - 1; i++) { + escape = index[i] === '\\' && !escape } - return true + return !escape } diff --git a/redisinsight/ui/src/pages/search/mocks/mocks.ts b/redisinsight/ui/src/pages/search/mocks/mocks.ts index 8125afa84c..01a67f5c19 100644 --- a/redisinsight/ui/src/pages/search/mocks/mocks.ts +++ b/redisinsight/ui/src/pages/search/mocks/mocks.ts @@ -672,5 +672,50 @@ export const MOCKED_SUPPORTED_COMMANDS = { ], since: '1.1.0', group: 'search' + }, + + 'FT.PROFILE': { + summary: 'Performs a `FT.SEARCH` or `FT.AGGREGATE` command and collects performance information', + complexity: 'O(N)', + arguments: [ + { + name: 'index', + type: 'string' + }, + { + name: 'querytype', + type: 'oneof', + arguments: [ + { + name: 'search', + type: 'pure-token', + token: 'SEARCH' + }, + { + name: 'aggregate', + type: 'pure-token', + token: 'AGGREGATE' + } + ] + }, + { + name: 'limited', + type: 'pure-token', + token: 'LIMITED', + optional: true + }, + { + name: 'queryword', + type: 'pure-token', + token: 'QUERY' + }, + { + name: 'query', + type: 'string' + } + ], + since: '2.2.0', + group: 'search', + provider: 'redisearch' } } diff --git a/redisinsight/ui/src/pages/search/utils/tests/monaco.spec.ts b/redisinsight/ui/src/pages/search/utils/tests/monaco.spec.ts index 70dc43d5ad..48b9ff5c3e 100644 --- a/redisinsight/ui/src/pages/search/utils/tests/monaco.spec.ts +++ b/redisinsight/ui/src/pages/search/utils/tests/monaco.spec.ts @@ -1,5 +1,5 @@ import { getRediSearchSignutureProvider } from 'uiSrc/pages/search/utils' -import { MOCKED_SUPPORTED_COMMANDS } from 'uiSrc/pages/search/utils/tests/mocks' +import { MOCKED_SUPPORTED_COMMANDS } from 'uiSrc/pages/search/mocks/mocks' import { SearchCommand } from 'uiSrc/pages/search/types' const ftAggregateCommand = MOCKED_SUPPORTED_COMMANDS['FT.AGGREGATE'] From 283c3a459da3ff7de93ab5f550dcb18852d7af25 Mon Sep 17 00:00:00 2001 From: Roman Sergeenko Date: Sat, 24 Aug 2024 14:53:15 +0200 Subject: [PATCH 037/256] refactoring --- .../pages/search/components/query/Query.tsx | 55 ++------- .../pages/search/components/query/utils.ts | 90 +++++--------- redisinsight/ui/src/pages/search/types.ts | 21 +--- .../ui/src/pages/search/utils/query.ts | 116 ++++++++++-------- 4 files changed, 105 insertions(+), 177 deletions(-) diff --git a/redisinsight/ui/src/pages/search/components/query/Query.tsx b/redisinsight/ui/src/pages/search/components/query/Query.tsx index 7f742e5df7..21cbfa6f2e 100644 --- a/redisinsight/ui/src/pages/search/components/query/Query.tsx +++ b/redisinsight/ui/src/pages/search/components/query/Query.tsx @@ -8,13 +8,13 @@ import { Nullable } from 'uiSrc/utils' import { IEditorMount } from 'uiSrc/pages/workbench/interfaces' import { addOwnTokenToArgs, - findCurrentArgInQuery, + findCurrentArgument, getRange, getRediSearchSignutureProvider, setCursorPositionAtTheEnd, splitQueryByArgs } from 'uiSrc/pages/search/utils' -import { CommandContext, CursorContext, SearchCommand, TokenType } from 'uiSrc/pages/search/types' +import { SearchCommand, TokenType } from 'uiSrc/pages/search/types' import { RedisResponseBuffer } from 'uiSrc/slices/interfaces' import { fetchRedisearchInfoAction } from 'uiSrc/slices/browser/redisearch' import { getRediSearchMonarchTokensProvider } from 'uiSrc/utils/monaco/monarchTokens/redisearchTokens' @@ -233,11 +233,8 @@ const Query = (props: Props) => { setSelectedIndex(allArgs[1] || '') setSelectedCommand(commandName) - const currentCommandArg = findCurrentArgInQuery(prevArgs, command) const foundArg = findCurrentArgument(COMMANDS_LIST, beforeOffsetArgs) - console.log(foundArg) - switch (foundArg?.stopArg?.name) { case DefinedArgumentName.index: { updateHelpWidget(true, command, foundArg?.stopArg) @@ -248,59 +245,21 @@ const Query = (props: Props) => { return getQuerySuggestions(prevCursorChar, range) } default: { - console.log(foundArg) - const cursorContext: CursorContext = { isCursorInQuotes, prevCursorChar, nextCursorChar, currentOffsetArg, range } - const commandContext: CommandContext = { - commands: COMMANDS_LIST, - commandName, - command, - prevArgs: beforeOffsetArgs, - allArgs, - currentCommandArg: foundArg?.stopArg - } + if (isCursorInQuotes || nextCursorChar?.trim()) return asSuggestionsRef([]) + if ((prevCursorChar?.trim() || isCursorInQuotes) && isEscapedSuggestions.current) return asSuggestionsRef([]) + isEscapedSuggestions.current = false const { suggestions, forceHide, helpWidgetData } = getGeneralSuggestions( foundArg, - commandContext, - cursorContext, + allArgs, + range, attributesRef.current ) - console.log(suggestions) - console.log(helpWidgetData) - if (helpWidgetData) updateHelpWidget(helpWidgetData.isOpen, helpWidgetData.parent, helpWidgetData.currentArg) return asSuggestionsRef(suggestions, forceHide) } } - // // cover index - // if (currentCommandArg?.name === DefinedArgumentName.index) { - // updateHelpWidget(true, addOwnTokenToArgs(commandName, command), currentCommandArg) - // return getIndexSuggestions(command, prevArgs.length, currentOffsetArg, range) - // } - // - // // cover query - // if (currentCommandArg?.name === DefinedArgumentName.query) { - // updateHelpWidget(true, addOwnTokenToArgs(commandName, command), currentCommandArg) - // - // return getQuerySuggestions(prevCursorChar, range) - // } - // - // if (isCursorInQuotes || nextCursorChar?.trim()) return asSuggestionsRef([]) - // if ((prevCursorChar?.trim() || isCursorInQuotes) && isEscapedSuggestions.current) return asSuggestionsRef([]) - // isEscapedSuggestions.current = false - // - // const cursorContext: CursorContext = { isCursorInQuotes, prevCursorChar, nextCursorChar, currentOffsetArg, range } - // const commandContext: CommandContext = { commandName, command, prevArgs, allArgs, currentCommandArg } - // - // const { suggestions, forceHide, helpWidgetData } = getGeneralSuggestions( - // commandContext, - // cursorContext, - // attributesRef.current - // ) - // - // if (helpWidgetData) updateHelpWidget(helpWidgetData.isOpen, helpWidgetData.parent, helpWidgetData.currentArg) - // return asSuggestionsRef(suggestions, forceHide) } const getIndexSuggestions = ( diff --git a/redisinsight/ui/src/pages/search/components/query/utils.ts b/redisinsight/ui/src/pages/search/components/query/utils.ts index 8dae0dea29..10f1527fb2 100644 --- a/redisinsight/ui/src/pages/search/components/query/utils.ts +++ b/redisinsight/ui/src/pages/search/components/query/utils.ts @@ -2,8 +2,12 @@ import { monaco } from 'react-monaco-editor' import * as monacoEditor from 'monaco-editor' import { RedisResponseBuffer } from 'uiSrc/slices/interfaces' import { bufferToString, formatLongName, getCommandMarkdown, Nullable } from 'uiSrc/utils' -import { addOwnTokenToArgs, buildSuggestion, findCurrentArgument, generateDetail } from 'uiSrc/pages/search/utils' -import { CommandContext, CursorContext, FoundCommandArgument, SearchCommand } from 'uiSrc/pages/search/types' +import { + buildSuggestion, + generateDetail, + removeNotSuggestedArgs +} from 'uiSrc/pages/search/utils' +import { FoundCommandArgument, SearchCommand } from 'uiSrc/pages/search/types' import { DefinedArgumentName } from 'uiSrc/pages/search/components/query/constants' export const asSuggestionsRef = (suggestions: monacoEditor.languages.CompletionItem[], forceHide = true) => ({ @@ -61,7 +65,7 @@ export const getMandatoryArgumentSuggestions = ( if (foundArg.isBlocked) return [] if (foundArg.append?.length) { - return foundArg.append.map((arg: any) => buildSuggestion(arg, range, { + return foundArg.append.flat().map((arg: any) => buildSuggestion(arg, range, { kind: monacoEditor.languages.CompletionItemKind.Property, detail: generateDetail(foundArg?.parent) })) @@ -71,43 +75,44 @@ export const getMandatoryArgumentSuggestions = ( } export const getCommandSuggestions = ( - firstLevelArgs: SearchCommand[], foundArg: Nullable, allArgs: string[], range: monaco.IRange, - currentArg?: string ) => { const appendCommands = foundArg?.append ?? [] + const suggestions = [] - return [ - ...appendCommands.map((arg) => buildSuggestion(arg, range, { - sortText: 'a', - kind: monacoEditor.languages.CompletionItemKind.Property, - detail: generateDetail(foundArg?.parent) - })), - ...firstLevelArgs - .filter((arg) => - arg.multiple || !(currentArg !== arg.token && allArgs.includes(arg.token || arg.arguments?.[0]?.token || ''))) + for (let i = 0; i < appendCommands.length; i++) { + const isLastLevel = i === appendCommands.length - 1 + const filteredFileldArgs = isLastLevel + ? removeNotSuggestedArgs(allArgs, appendCommands[i]) + : appendCommands[i] + + const leveledSuggestions = filteredFileldArgs .map((arg) => buildSuggestion(arg, range, { - sortText: 'b', - kind: monacoEditor.languages.CompletionItemKind.Reference, - detail: generateDetail(arg) + sortText: `${i}`, + kind: isLastLevel + ? monacoEditor.languages.CompletionItemKind.Reference + : monacoEditor.languages.CompletionItemKind.Property, + detail: generateDetail(arg?.parent) })) - ] + + suggestions.push(leveledSuggestions) + } + + return suggestions.flat() } export const getGeneralSuggestions = ( - foundArg: any, - commandContext: CommandContext, - cursorContext: CursorContext, + foundArg: Nullable, + allArgs: string[], + range: monacoEditor.IRange, fields: any[], ): { suggestions: monacoEditor.languages.CompletionItem[], forceHide?: boolean helpWidgetData?: any } => { - const { range } = cursorContext - if (foundArg && !foundArg.isComplete) { return { suggestions: getMandatoryArgumentSuggestions(foundArg, fields, range), @@ -119,47 +124,18 @@ export const getGeneralSuggestions = ( } } - return getNextSuggestions(commandContext, cursorContext, foundArg) + return getNextSuggestions(foundArg, allArgs, range) } export const getNextSuggestions = ( - { command, currentCommandArg, prevArgs, allArgs }: CommandContext, - { currentOffsetArg, range }: CursorContext, - foundArg: Nullable + foundArg: Nullable, + allArgs: string[], + range: monacoEditor.IRange ) => { - if (!command) return { suggestions: [] } if (foundArg && !foundArg.isComplete) return { suggestions: [], helpWidgetData: { isOpen: false } } - const parentArgIndex = command.arguments - ?.findIndex(({ name }) => name === foundArg?.parent?.name) || -1 - const currentArgIndex = parentArgIndex > -1 ? parentArgIndex : prevArgs.length - 1 - const nextMandatoryIndex = command.arguments - ?.findIndex(({ optional }, i) => !optional && i > currentArgIndex) || -1 - - const nextOptionalArgs = ( - nextMandatoryIndex > -1 - ? command.arguments?.slice(currentArgIndex + 1, nextMandatoryIndex) - : command.arguments?.filter(({ optional }) => optional) - ) || [] - const nextMandatoryArg = command.arguments?.[nextMandatoryIndex] - - if (nextMandatoryArg?.token) { - nextOptionalArgs.unshift(nextMandatoryArg) - } - - if (nextMandatoryArg && !nextMandatoryArg.token) { - return { - helpWidgetData: { - isOpen: !!currentCommandArg, - parent: foundArg?.stopArg, - currentArg: nextMandatoryArg - }, - suggestions: [] - } - } - return { - suggestions: getCommandSuggestions(nextOptionalArgs, foundArg, allArgs, range, currentOffsetArg), + suggestions: getCommandSuggestions(foundArg, allArgs, range), helpWidgetData: { isOpen: false } } } diff --git a/redisinsight/ui/src/pages/search/types.ts b/redisinsight/ui/src/pages/search/types.ts index d4eca49253..a2d96a5a4d 100644 --- a/redisinsight/ui/src/pages/search/types.ts +++ b/redisinsight/ui/src/pages/search/types.ts @@ -1,5 +1,4 @@ -import { monaco as monacoEditor } from 'react-monaco-editor' -import { Maybe, Nullable } from 'uiSrc/utils' +import { Maybe } from 'uiSrc/utils' export enum TokenType { PureToken = 'pure-token', @@ -28,22 +27,6 @@ export interface FoundCommandArgument { isComplete: boolean stopArg: Maybe isBlocked: boolean - append: Maybe + append: Maybe> parent: Maybe } - -export interface CommandContext { - commandName: string - command: Maybe - prevArgs: string[] - allArgs: string[] - currentCommandArg: Nullable -} - -export interface CursorContext { - isCursorInQuotes: boolean - prevCursorChar: string - nextCursorChar: string - currentOffsetArg: any - range: monacoEditor.IRange -} diff --git a/redisinsight/ui/src/pages/search/utils/query.ts b/redisinsight/ui/src/pages/search/utils/query.ts index 17a8ad5ef2..89178a4fcf 100644 --- a/redisinsight/ui/src/pages/search/utils/query.ts +++ b/redisinsight/ui/src/pages/search/utils/query.ts @@ -1,6 +1,6 @@ /* eslint-disable no-continue */ -import { toNumber, uniqBy } from 'lodash' +import { toNumber } from 'lodash' import { generateArgsNames, Maybe, Nullable } from 'uiSrc/utils' import { CommandProvider } from 'uiSrc/constants' import { ArgName, FoundCommandArgument, SearchCommand, SearchCommandTree, TokenType } from '../types' @@ -27,7 +27,6 @@ export const splitQueryByArgs = (query: string, position: number = 0) => { for (let i = 0; i < query.length; i++) { const char = query[i] const isAfterOffset = i >= position + (inQuotes ? -1 : 0) - if (i === position - 1) isCursorInQuotes = inQuotes if (escapeNextChar) { arg += char @@ -66,6 +65,8 @@ export const splitQueryByArgs = (query: string, position: number = 0) => { } else { arg += char } + + if (i === position - 1) isCursorInQuotes = inQuotes } if (arg.length > 0) { @@ -108,13 +109,6 @@ export const findCurrentArgument = ( } } - if (args[prev.length] && !args[prev.length].optional) { - return { - ...getArgumentSuggestions([], args.slice(prev.length)), - parent: undefined - } - } - return null } @@ -242,7 +236,7 @@ export const getArgumentSuggestions = ( isComplete: boolean stopArg: Maybe, isBlocked: boolean, - append: SearchCommand[], + append: Array, } => { const { restArguments, @@ -261,13 +255,13 @@ export const getArgumentSuggestions = ( isComplete: false, stopArg: stopArgument, isBlocked: !isOneOfArgument, - append: isOneOfArgument ? stopArgument.arguments! : [], + append: isOneOfArgument ? [stopArgument.arguments!] : [], } } if (stopArgument && !stopArgument.optional) { const isCanAppend = stopArgument?.token || isOneOfArgument - const append = isCanAppend ? [isOneOfArgument ? stopArgument.arguments! : stopArgument].flat() : [] + const append = isCanAppend ? [[isOneOfArgument ? stopArgument.arguments! : stopArgument].flat()] : [] return { isComplete: false, @@ -277,49 +271,83 @@ export const getArgumentSuggestions = ( } } - const restParentOptionalSuggestions = getRestParentArguments(current?.parent, current?.name, current?.multiple) - .filter((arg) => arg.optional && arg.name !== stopArgument?.name - && (current?.multiple || arg.name !== current?.name)) - - const restOptionalSuggestions = uniqBy( - fillArgsByType([...restNotFilledArgs, ...restParentOptionalSuggestions]), - 'token' - ) + const beforeMandatoryOptionalArgs = getAllRestArguments(current, stopArgument, pastStringArgs) const requiredArgsLength = restNotFilledArgs.filter((arg) => !arg.optional).length return { isComplete: requiredArgsLength === 0, stopArg: stopArgument, isBlocked: false, - append: restOptionalSuggestions, + append: beforeMandatoryOptionalArgs, } } -export const getRestParentArguments = ( - parent?: SearchCommandTree, - currentArgName?: string, - isIncludeOwn: boolean = true, - prevArgs: SearchCommand[] = [] -): SearchCommand[] => { - if (!currentArgName) return [] +export const getRestArguments = ( + current: Maybe, + stopArgument: Nullable +): SearchCommandTree[] => { + if (!stopArgument) return [] + + const argumentIndexInArg = current?.arguments + ?.findIndex(({ name }) => name === stopArgument?.name) || -1 + const nextMandatoryIndex = current?.arguments + ?.findIndex(({ optional }, i) => !optional && i > argumentIndexInArg) || -1 - const currentArgIndex = parent?.arguments?.findIndex((arg) => arg?.name === currentArgName) - if (!currentArgIndex) return prevArgs + const beforeMandatoryOptionalArgs = ( + nextMandatoryIndex > -1 + ? current?.arguments?.slice(argumentIndexInArg, nextMandatoryIndex) + : current?.arguments?.filter(({ optional }) => optional) + ) || [] - const currentRestArgs = parent?.arguments?.slice(currentArgIndex + (isIncludeOwn ? 0 : 1)) || [] + const nextMandatoryArg = current?.arguments?.[nextMandatoryIndex] - if (parent?.parent) return getRestParentArguments(parent.parent, parent.name, true, currentRestArgs) + if (nextMandatoryArg?.token) { + beforeMandatoryOptionalArgs.unshift(nextMandatoryArg) + } - return [...currentRestArgs, ...prevArgs] + return fillArgsByType(beforeMandatoryOptionalArgs) + .map((arg) => ({ + ...arg, + parent: current + })) } -export const fillArgsByType = (args: SearchCommand[]): SearchCommand[] => { +export const getAllRestArguments = ( + current: Maybe, + stopArgument: Nullable, + prevStringArgs: string[] = [], +) => { + const appendArgs: Array = [] + const currentLvlNextArgs = removeNotSuggestedArgs( + prevStringArgs, + getRestArguments(current, stopArgument) + ) + + if (currentLvlNextArgs.length) { + appendArgs.push(currentLvlNextArgs) + } + + if (current?.parent) { + const parentArgs = getAllRestArguments(current.parent, current, []) + if (parentArgs?.length) { + appendArgs.push(...parentArgs) + } + } + + return appendArgs +} + +export const removeNotSuggestedArgs = (args: string[], commandArgs: SearchCommandTree[]) => + commandArgs.filter((arg) => arg.token + && (arg.multiple || !args.some((queryArg) => queryArg.toUpperCase() === arg.token?.toUpperCase()))) + +export const fillArgsByType = (args: SearchCommand[], expandBlock = true): SearchCommand[] => { const result: SearchCommand[] = [] for (let i = 0; i < args.length; i++) { const currentArg = args[i] - if (currentArg.type === TokenType.OneOf) result.push(...(currentArg?.arguments || [])) + if (expandBlock && currentArg.type === TokenType.OneOf) result.push(...(currentArg?.arguments || [])) if (currentArg.type === TokenType.Block) result.push(currentArg.arguments?.[0] as SearchCommand) if (currentArg.token) result.push(currentArg) } @@ -352,21 +380,3 @@ export const addOwnTokenToArgs = (token: string, command: SearchCommand) => { } return command } - -export const findCurrentArgInQuery = (args: string[], command: SearchCommand) => { - if (!command.arguments || !command.arguments.length) return null - - let argIndex = 0 - args.forEach((arg) => { - for (let i = argIndex; i < command.arguments!.length; i++) { - if (command.arguments![i]?.optional && command.arguments![i]?.token?.toUpperCase() !== arg?.toUpperCase()) { - continue - } - - argIndex = i + 1 - break - } - }) - - return command.arguments[argIndex] -} From 354b6148a27cee31b288f18d6bb799dec0f31467 Mon Sep 17 00:00:00 2001 From: Roman Sergeenko Date: Mon, 26 Aug 2024 09:27:36 +0200 Subject: [PATCH 038/256] #RI-6061 - fix overflow --- redisinsight/ui/src/pages/search/styles.module.scss | 4 ++-- .../workbench/components/wb-view/WBView/styles.module.scss | 4 ++-- .../ui/src/templates/explore-panel/styles.module.scss | 1 - 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/redisinsight/ui/src/pages/search/styles.module.scss b/redisinsight/ui/src/pages/search/styles.module.scss index e371f27293..359b2462eb 100644 --- a/redisinsight/ui/src/pages/search/styles.module.scss +++ b/redisinsight/ui/src/pages/search/styles.module.scss @@ -1,8 +1,8 @@ .container { - min-height: 100%; - height: 1px !important; + flex-grow: 1; display: flex; flex-direction: column; + max-height: calc(100% - 50px); } .main { diff --git a/redisinsight/ui/src/pages/workbench/components/wb-view/WBView/styles.module.scss b/redisinsight/ui/src/pages/workbench/components/wb-view/WBView/styles.module.scss index eff58ba867..cea9ac8893 100644 --- a/redisinsight/ui/src/pages/workbench/components/wb-view/WBView/styles.module.scss +++ b/redisinsight/ui/src/pages/workbench/components/wb-view/WBView/styles.module.scss @@ -1,8 +1,8 @@ .container { - min-height: 100%; - height: 1px !important; display: flex; + flex-grow: 1; flex-direction: column; + max-height: calc(100% - 50px); } .main { diff --git a/redisinsight/ui/src/templates/explore-panel/styles.module.scss b/redisinsight/ui/src/templates/explore-panel/styles.module.scss index 49cef4b420..9f5842eadc 100644 --- a/redisinsight/ui/src/templates/explore-panel/styles.module.scss +++ b/redisinsight/ui/src/templates/explore-panel/styles.module.scss @@ -4,7 +4,6 @@ height: 100%; width: 100%; position: relative; - overflow: hidden; } .mainPanel { From b24377cc3db1fff3f515a0b5329f5deb1fe22f29 Mon Sep 17 00:00:00 2001 From: Roman Sergeenko Date: Mon, 26 Aug 2024 09:56:01 +0200 Subject: [PATCH 039/256] #RI-6062 - add initial commands json --- .../constants/supported_commands.json | 745 ++++++++++++++++++ 1 file changed, 745 insertions(+) create mode 100644 redisinsight/ui/src/pages/search/components/constants/supported_commands.json diff --git a/redisinsight/ui/src/pages/search/components/constants/supported_commands.json b/redisinsight/ui/src/pages/search/components/constants/supported_commands.json new file mode 100644 index 0000000000..4eb75226c2 --- /dev/null +++ b/redisinsight/ui/src/pages/search/components/constants/supported_commands.json @@ -0,0 +1,745 @@ +{ + "FT.AGGREGATE": { + "summary": "Run a search query on an index and perform aggregate transformations on the results", + "complexity": "O(1)", + "arguments": [ + { + "name": "index", + "type": "string" + }, + { + "name": "query", + "type": "string" + }, + { + "name": "verbatim", + "type": "pure-token", + "token": "VERBATIM", + "optional": true + }, + { + "name": "load", + "type": "block", + "optional": true, + "arguments": [ + { + "name": "count", + "type": "string", + "token": "LOAD" + }, + { + "name": "field", + "type": "string", + "multiple": true + } + ] + }, + { + "name": "timeout", + "type": "integer", + "optional": true, + "token": "TIMEOUT" + }, + { + "name": "loadall", + "type": "pure-token", + "token": "LOAD *", + "optional": true + }, + { + "name": "groupby", + "type": "block", + "optional": true, + "multiple": true, + "arguments": [ + { + "name": "nargs", + "type": "integer", + "token": "GROUPBY" + }, + { + "name": "property", + "type": "string", + "multiple": true + }, + { + "name": "reduce", + "type": "block", + "optional": true, + "multiple": true, + "arguments": [ + { + "name": "function", + "type": "string", + "token": "REDUCE" + }, + { + "name": "nargs", + "type": "integer" + }, + { + "name": "arg", + "type": "string", + "multiple": true + }, + { + "name": "name", + "type": "string", + "token": "AS", + "optional": true + } + ] + } + ] + }, + { + "name": "sortby", + "type": "block", + "optional": true, + "arguments": [ + { + "name": "nargs", + "type": "integer", + "token": "SORTBY" + }, + { + "name": "fields", + "type": "block", + "optional": true, + "multiple": true, + "arguments": [ + { + "name": "property", + "type": "string" + }, + { + "name": "order", + "type": "oneof", + "arguments": [ + { + "name": "asc", + "type": "pure-token", + "token": "ASC" + }, + { + "name": "desc", + "type": "pure-token", + "token": "DESC" + } + ] + } + ] + }, + { + "name": "num", + "type": "integer", + "token": "MAX", + "optional": true + } + ] + }, + { + "name": "apply", + "type": "block", + "optional": true, + "multiple": true, + "arguments": [ + { + "name": "expression", + "type": "string", + "token": "APPLY" + }, + { + "name": "name", + "type": "string", + "token": "AS" + } + ] + }, + { + "name": "limit", + "type": "block", + "optional": true, + "arguments": [ + { + "name": "limit", + "type": "pure-token", + "token": "LIMIT" + }, + { + "name": "offset", + "type": "integer" + }, + { + "name": "num", + "type": "integer" + } + ] + }, + { + "name": "filter", + "type": "string", + "optional": true, + "token": "FILTER" + }, + { + "name": "cursor", + "type": "block", + "optional": true, + "arguments": [ + { + "name": "withcursor", + "type": "pure-token", + "token": "WITHCURSOR" + }, + { + "name": "read_size", + "type": "integer", + "optional": true, + "token": "COUNT" + }, + { + "name": "idle_time", + "type": "integer", + "optional": true, + "token": "MAXIDLE" + } + ] + }, + { + "name": "params", + "type": "block", + "optional": true, + "arguments": [ + { + "name": "params", + "type": "pure-token", + "token": "PARAMS" + }, + { + "name": "nargs", + "type": "integer" + }, + { + "name": "values", + "type": "block", + "multiple": true, + "arguments": [ + { + "name": "name", + "type": "string" + }, + { + "name": "value", + "type": "string" + } + ] + } + ] + }, + { + "name": "dialect", + "type": "integer", + "optional": true, + "token": "DIALECT", + "since": "2.4.3" + } + ], + "since": "1.1.0", + "group": "search", + "provider": "redisearch" + }, + "FT.EXPLAIN": { + "summary": "Returns the execution plan for a complex query", + "complexity": "O(1)", + "arguments": [ + { + "name": "index", + "type": "string" + }, + { + "name": "query", + "type": "string" + }, + { + "name": "dialect", + "type": "integer", + "optional": true, + "token": "DIALECT", + "since": "2.4.3" + } + ], + "since": "1.0.0", + "group": "search", + "provider": "redisearch" + }, + "FT.PROFILE": { + "summary": "Performs a `FT.SEARCH` or `FT.AGGREGATE` command and collects performance information", + "complexity": "O(N)", + "arguments": [ + { + "name": "index", + "type": "string" + }, + { + "name": "querytype", + "type": "oneof", + "arguments": [ + { + "name": "search", + "type": "pure-token", + "token": "SEARCH" + }, + { + "name": "aggregate", + "type": "pure-token", + "token": "AGGREGATE" + } + ] + }, + { + "name": "limited", + "type": "pure-token", + "token": "LIMITED", + "optional": true + }, + { + "name": "queryword", + "type": "pure-token", + "token": "QUERY" + }, + { + "name": "query", + "type": "string" + } + ], + "since": "2.2.0", + "group": "search", + "provider": "redisearch" + }, + "FT.SEARCH": { + "summary": "Searches the index with a textual query, returning either documents or just ids", + "complexity": "O(N)", + "history": [ + [ + "2.0.0", + "Deprecated `WITHPAYLOADS` and `PAYLOAD` arguments" + ] + ], + "arguments": [ + { + "name": "index", + "type": "string" + }, + { + "name": "query", + "type": "string" + }, + { + "name": "nocontent", + "type": "pure-token", + "token": "NOCONTENT", + "optional": true + }, + { + "name": "verbatim", + "type": "pure-token", + "token": "VERBATIM", + "optional": true + }, + { + "name": "nostopwords", + "type": "pure-token", + "token": "NOSTOPWORDS", + "optional": true + }, + { + "name": "withscores", + "type": "pure-token", + "token": "WITHSCORES", + "optional": true + }, + { + "name": "withpayloads", + "type": "pure-token", + "token": "WITHPAYLOADS", + "optional": true + }, + { + "name": "withsortkeys", + "type": "pure-token", + "token": "WITHSORTKEYS", + "optional": true + }, + { + "name": "filter", + "type": "block", + "optional": true, + "multiple": true, + "arguments": [ + { + "name": "numeric_field", + "type": "string", + "token": "FILTER" + }, + { + "name": "min", + "type": "double" + }, + { + "name": "max", + "type": "double" + } + ] + }, + { + "name": "geo_filter", + "type": "block", + "optional": true, + "multiple": true, + "arguments": [ + { + "name": "geo_field", + "type": "string", + "token": "GEOFILTER" + }, + { + "name": "lon", + "type": "double" + }, + { + "name": "lat", + "type": "double" + }, + { + "name": "radius", + "type": "double" + }, + { + "name": "radius_type", + "type": "oneof", + "arguments": [ + { + "name": "m", + "type": "pure-token", + "token": "m" + }, + { + "name": "km", + "type": "pure-token", + "token": "km" + }, + { + "name": "mi", + "type": "pure-token", + "token": "mi" + }, + { + "name": "ft", + "type": "pure-token", + "token": "ft" + } + ] + } + ] + }, + { + "name": "in_keys", + "type": "block", + "optional": true, + "arguments": [ + { + "name": "count", + "type": "string", + "token": "INKEYS" + }, + { + "name": "key", + "type": "string", + "multiple": true + } + ] + }, + { + "name": "in_fields", + "type": "block", + "optional": true, + "arguments": [ + { + "name": "count", + "type": "string", + "token": "INFIELDS" + }, + { + "name": "field", + "type": "string", + "multiple": true + } + ] + }, + { + "name": "return", + "type": "block", + "optional": true, + "arguments": [ + { + "name": "count", + "type": "string", + "token": "RETURN" + }, + { + "name": "identifiers", + "type": "block", + "multiple": true, + "arguments": [ + { + "name": "identifier", + "type": "string" + }, + { + "name": "property", + "type": "string", + "token": "AS", + "optional": true + } + ] + } + ] + }, + { + "name": "summarize", + "type": "block", + "optional": true, + "arguments": [ + { + "name": "summarize", + "type": "pure-token", + "token": "SUMMARIZE" + }, + { + "name": "fields", + "type": "block", + "optional": true, + "arguments": [ + { + "name": "count", + "type": "string", + "token": "FIELDS" + }, + { + "name": "field", + "type": "string", + "multiple": true + } + ] + }, + { + "name": "num", + "type": "integer", + "token": "FRAGS", + "optional": true + }, + { + "name": "fragsize", + "type": "integer", + "token": "LEN", + "optional": true + }, + { + "name": "separator", + "type": "string", + "token": "SEPARATOR", + "optional": true + } + ] + }, + { + "name": "highlight", + "type": "block", + "optional": true, + "arguments": [ + { + "name": "highlight", + "type": "pure-token", + "token": "HIGHLIGHT" + }, + { + "name": "fields", + "type": "block", + "optional": true, + "arguments": [ + { + "name": "count", + "type": "string", + "token": "FIELDS" + }, + { + "name": "field", + "type": "string", + "multiple": true + } + ] + }, + { + "name": "tags", + "type": "block", + "optional": true, + "arguments": [ + { + "name": "tags", + "type": "pure-token", + "token": "TAGS" + }, + { + "name": "open", + "type": "string" + }, + { + "name": "close", + "type": "string" + } + ] + } + ] + }, + { + "name": "slop", + "type": "integer", + "optional": true, + "token": "SLOP" + }, + { + "name": "timeout", + "type": "integer", + "optional": true, + "token": "TIMEOUT" + }, + { + "name": "inorder", + "type": "pure-token", + "token": "INORDER", + "optional": true + }, + { + "name": "language", + "type": "string", + "optional": true, + "token": "LANGUAGE" + }, + { + "name": "expander", + "type": "string", + "optional": true, + "token": "EXPANDER" + }, + { + "name": "scorer", + "type": "string", + "optional": true, + "token": "SCORER" + }, + { + "name": "explainscore", + "type": "pure-token", + "token": "EXPLAINSCORE", + "optional": true + }, + { + "name": "payload", + "type": "string", + "optional": true, + "token": "PAYLOAD" + }, + { + "name": "sortby", + "type": "block", + "optional": true, + "arguments": [ + { + "name": "sortby", + "type": "string", + "token": "SORTBY" + }, + { + "name": "order", + "type": "oneof", + "optional": true, + "arguments": [ + { + "name": "asc", + "type": "pure-token", + "token": "ASC" + }, + { + "name": "desc", + "type": "pure-token", + "token": "DESC" + } + ] + } + ] + }, + { + "name": "limit", + "type": "block", + "optional": true, + "arguments": [ + { + "name": "limit", + "type": "pure-token", + "token": "LIMIT" + }, + { + "name": "offset", + "type": "integer" + }, + { + "name": "num", + "type": "integer" + } + ] + }, + { + "name": "params", + "type": "block", + "optional": true, + "arguments": [ + { + "name": "params", + "type": "pure-token", + "token": "PARAMS" + }, + { + "name": "nargs", + "type": "integer" + }, + { + "name": "values", + "type": "block", + "multiple": true, + "arguments": [ + { + "name": "name", + "type": "string" + }, + { + "name": "value", + "type": "string" + } + ] + } + ] + }, + { + "name": "dialect", + "type": "integer", + "optional": true, + "token": "DIALECT", + "since": "2.4.3" + } + ], + "since": "1.0.0", + "group": "search", + "provider": "redisearch" + } +} From f6a8d05cae9b24a85b520e1b0dd76eb4a28a3179 Mon Sep 17 00:00:00 2001 From: vlad-dargel Date: Tue, 27 Aug 2024 13:38:58 +0200 Subject: [PATCH 040/256] changes from main --- .../navigation-menu/NavigationMenu.spec.tsx | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/redisinsight/ui/src/components/navigation-menu/NavigationMenu.spec.tsx b/redisinsight/ui/src/components/navigation-menu/NavigationMenu.spec.tsx index 2dfa3c3e57..bcdba4a63d 100644 --- a/redisinsight/ui/src/components/navigation-menu/NavigationMenu.spec.tsx +++ b/redisinsight/ui/src/components/navigation-menu/NavigationMenu.spec.tsx @@ -28,7 +28,16 @@ jest.mock('uiSrc/slices/instances/instances', () => ({ ...jest.requireActual('uiSrc/slices/instances/instances'), connectedInstanceSelector: jest.fn().mockReturnValue({ id: '' - }) + }), +})) + +jest.mock('uiSrc/slices/app/features', () => ({ + ...jest.requireActual('uiSrc/slices/app/features'), + appFeatureFlagsFeaturesSelector: jest.fn().mockReturnValue({ + appSettings: { + flag: true, + }, + }), })) describe('NavigationMenu', () => { From 865bb59d29c72b5282f0624169af1e007b02fcfe Mon Sep 17 00:00:00 2001 From: Roman Sergeenko Date: Fri, 30 Aug 2024 15:46:42 +0200 Subject: [PATCH 041/256] #RI-6026 - support apply functions, filter expressions, reducer functions --- .../constants/supported_commands.json | 419 +++++++++++++++++- .../components/query-wrapper/QueryWrapper.tsx | 4 +- .../pages/search/components/query/Query.tsx | 108 +++-- .../search/components/query/constants.ts | 3 + .../pages/search/components/query/utils.ts | 27 +- redisinsight/ui/src/pages/search/types.ts | 15 +- .../ui/src/pages/search/utils/monaco.ts | 19 +- .../ui/src/pages/search/utils/query.ts | 58 ++- .../ui/src/utils/monaco/monacoThemes.ts | 13 +- .../monaco/monarchTokens/redisearchTokens.ts | 93 +--- .../redisearchTokensTemplates.ts | 104 +++++ .../ui/src/utils/monaco/redisearch/utils.ts | 136 ++++++ 12 files changed, 854 insertions(+), 145 deletions(-) create mode 100644 redisinsight/ui/src/utils/monaco/monarchTokens/redisearchTokensTemplates.ts create mode 100644 redisinsight/ui/src/utils/monaco/redisearch/utils.ts diff --git a/redisinsight/ui/src/pages/search/components/constants/supported_commands.json b/redisinsight/ui/src/pages/search/components/constants/supported_commands.json index 4eb75226c2..fa08d11556 100644 --- a/redisinsight/ui/src/pages/search/components/constants/supported_commands.json +++ b/redisinsight/ui/src/pages/search/components/constants/supported_commands.json @@ -68,10 +68,76 @@ "optional": true, "multiple": true, "arguments": [ + { + "name": "reduce", + "token": "REDUCE", + "type": "pure-token" + }, { "name": "function", - "type": "string", - "token": "REDUCE" + "type": "oneof", + "arguments": [ + { + "name": "count", + "type": "pure-token", + "token": "COUNT" + }, + { + "name": "count_distinct", + "type": "pure-token", + "token": "COUNT_DISTINCT" + }, + { + "name": "count_distinctish", + "type": "pure-token", + "token": "COUNT_DISTINCTISH" + }, + { + "name": "sum", + "type": "pure-token", + "token": "SUM" + }, + { + "name": "min", + "type": "pure-token", + "token": "MIN" + }, + { + "name": "max", + "type": "pure-token", + "token": "MAX" + }, + { + "name": "avg", + "type": "pure-token", + "token": "AVG" + }, + { + "name": "stddev", + "type": "pure-token", + "token": "STDDEV" + }, + { + "name": "quantile", + "type": "pure-token", + "token": "QUANTILE" + }, + { + "name": "tolist", + "type": "pure-token", + "token": "TOLIST" + }, + { + "name": "first_value", + "type": "pure-token", + "token": "FIRST_VALUE" + }, + { + "name": "random_sample", + "type": "pure-token", + "token": "RANDOM_SAMPLE" + } + ] }, { "name": "nargs", @@ -147,7 +213,350 @@ { "name": "expression", "type": "string", - "token": "APPLY" + "expression": true, + "token": "APPLY", + "arguments": [ + { + "name": "exists", + "token": "exists", + "type": "function", + "summary": "Checks whether a field exists in a document.", + "arguments": [ + { + "token": "s" + } + ] + }, + { + "name": "log", + "token": "log", + "type": "function", + "summary": "Return the logarithm of a number, property or subexpression", + "arguments": [ + { + "token": "x" + } + ] + }, + { + "name": "abs", + "token": "abs", + "type": "function", + "summary": "Return the absolute number of a numeric expression", + "arguments": [ + { + "token": "x" + } + ] + }, + { + "name": "ceil", + "token": "ceil", + "type": "function", + "summary": "Round to the smallest value not less than x", + "arguments": [ + { + "token": "x" + } + ] + }, + { + "name": "floor", + "token": "floor", + "type": "function", + "summary": "Round to largest value not greater than x", + "arguments": [ + { + "token": "x" + } + ] + }, + { + "name": "log2", + "token": "log2", + "type": "function", + "summary": "Return the logarithm of x to base 2", + "arguments": [ + { + "token": "x" + } + ] + }, + { + "name": "exp", + "token": "exp", + "type": "function", + "summary": "Return the exponent of x, e.g., e^x", + "arguments": [ + { + "token": "x" + } + ] + }, + { + "name": "sqrt", + "token": "sqrt", + "type": "function", + "summary": "Return the square root of x", + "arguments": [ + { + "token": "x" + } + ] + }, + { + "name": "upper", + "token": "upper", + "type": "function", + "summary": "Return the uppercase conversion of s", + "arguments": [ + { + "token": "s" + } + ] + }, + { + "name": "lower", + "token": "lower", + "type": "function", + "summary": "Return the lowercase conversion of s", + "arguments": [ + { + "token": "s" + } + ] + }, + { + "name": "startswith", + "token": "startswith", + "type": "function", + "summary": "Return 1 if s2 is the prefix of s1, 0 otherwise.", + "arguments": [ + { + "token": "s1" + }, + { + "token": "s2" + } + ] + }, + { + "name": "contains", + "token": "contains", + "type": "function", + "summary": "Return the number of occurrences of s2 in s1, 0 otherwise. If s2 is an empty string, return length(s1) + 1.", + "arguments": [ + { + "token": "s1" + }, + { + "token": "s2" + } + ] + }, + { + "name": "strlen", + "token": "strlen", + "type": "function", + "summary": "Return the length of s", + "arguments": [ + { + "token": "s" + } + ] + }, + { + "name": "substr", + "token": "substr", + "type": "function", + "summary": "Return the substring of s, starting at offset and having count characters.If offset is negative, it represents the distance from the end of the string.If count is -1, it means \"the rest of the string starting at offset\".", + "arguments": [ + { + "token": "s" + }, + { + "token": "offset" + }, + { + "token": "count" + } + ] + }, + { + "name": "format", + "token": "format", + "type": "function", + "summary": "Use the arguments following fmt to format a string.Currently the only format argument supported is %s and it applies to all types of arguments.", + "arguments": [ + { + "token": "fmt" + } + ] + }, + { + "name": "matched_terms", + "token": "matched_terms", + "type": "function", + "summary": "Return the query terms that matched for each record (up to 100), as a list. If a limit is specified, Redis will return the first N matches found, based on query order.", + "arguments": [ + { + "token": "max_terms=100", + "optional": true + } + ] + }, + { + "name": "split", + "token": "split", + "type": "function", + "summary": "Split a string by any character in the string sep, and strip any characters in strip. If only s is specified, it is split by commas and spaces are stripped. The output is an array.", + "arguments": [ + { + "token": "s" + } + ] + }, + { + "name": "timefmt", + "token": "timefmt", + "type": "function", + "summary": "Return a formatted time string based on a numeric timestamp value x.", + "arguments": [ + { + "token": "x" + }, + { + "token": "fmt", + "optional": true + } + ] + }, + { + "name": "parsetime", + "token": "parsetime", + "type": "function", + "summary": "The opposite of timefmt() - parse a time format using a given format string", + "arguments": [ + { + "token": "timesharing" + }, + { + "token": "fmt", + "optional": true + } + ] + }, + { + "name": "day", + "token": "day", + "type": "function", + "summary": "Round a Unix timestamp to midnight (00:00) start of the current day.", + "arguments": [ + { + "token": "timestamp" + } + ] + }, + { + "name": "hour", + "token": "hour", + "type": "function", + "summary": "Round a Unix timestamp to the beginning of the current hour.", + "arguments": [ + { + "token": "timestamp" + } + ] + }, + { + "name": "minute", + "token": "minute", + "type": "function", + "summary": "Round a Unix timestamp to the beginning of the current minute.", + "arguments": [ + { + "token": "timestamp" + } + ] + }, + { + "name": "month", + "token": "month", + "type": "function", + "summary": "Round a unix timestamp to the beginning of the current month.", + "arguments": [ + { + "token": "timestamp" + } + ] + }, + { + "name": "dayofweek", + "token": "dayofweek", + "type": "function", + "summary": "Convert a Unix timestamp to the day number (Sunday = 0).", + "arguments": [ + { + "token": "timestamp" + } + ] + }, + { + "name": "dayofmonth", + "token": "dayofmonth", + "type": "function", + "summary": "Convert a Unix timestamp to the day of month number (1 .. 31).", + "arguments": [ + { + "token": "timestamp" + } + ] + }, + { + "name": "dayofyear", + "token": "dayofyear", + "type": "function", + "summary": "Convert a Unix timestamp to the day of year number (0 .. 365).", + "arguments": [ + { + "token": "timestamp" + } + ] + }, + { + "name": "year", + "token": "year", + "type": "function", + "summary": "Convert a Unix timestamp to the current year (e.g. 2018).", + "arguments": [ + { + "token": "timestamp" + } + ] + }, + { + "name": "monthofyear", + "token": "monthofyear", + "type": "function", + "summary": "Convert a Unix timestamp to the current month (0 .. 11).", + "arguments": [ + { + "token": "timestamp" + } + ] + }, + { + "name": "geodistance", + "token": "geodistance", + "type": "function", + "summary": "Return distance in meters.", + "arguments": [ + { + "token": "" + } + ] + } + ] }, { "name": "name", @@ -180,6 +589,7 @@ "name": "filter", "type": "string", "optional": true, + "expression": true, "token": "FILTER" }, { @@ -306,7 +716,8 @@ { "name": "queryword", "type": "pure-token", - "token": "QUERY" + "token": "QUERY", + "expression": true }, { "name": "query", diff --git a/redisinsight/ui/src/pages/search/components/query-wrapper/QueryWrapper.tsx b/redisinsight/ui/src/pages/search/components/query-wrapper/QueryWrapper.tsx index a52d5e7768..2d47aeaa91 100644 --- a/redisinsight/ui/src/pages/search/components/query-wrapper/QueryWrapper.tsx +++ b/redisinsight/ui/src/pages/search/components/query-wrapper/QueryWrapper.tsx @@ -17,6 +17,8 @@ import { SUPPORTED_COMMANDS_LIST } from 'uiSrc/pages/search/components/query/con import { SearchCommand } from 'uiSrc/pages/search/types' import { TUTORIALS } from './constants' +import REDIS_COMMANDS_SPEC from '../constants/supported_commands.json' + import Query from '../query' import styles from './styles.module.scss' @@ -36,7 +38,7 @@ const QueryWrapper = (props: Props) => { const { script: scriptContext } = useSelector(appContextSearchAndQuery) const { activeRunQueryMode } = useSelector(searchAndQuerySelector) const { data: indexes = [] } = useSelector(redisearchListSelector) - const { spec: REDIS_COMMANDS_SPEC, commandsArray } = useSelector(appRedisCommandsSelector) + const { commandsArray } = useSelector(appRedisCommandsSelector) const [value, setValue] = useState(scriptContext) diff --git a/redisinsight/ui/src/pages/search/components/query/Query.tsx b/redisinsight/ui/src/pages/search/components/query/Query.tsx index 21cbfa6f2e..dc8ce60263 100644 --- a/redisinsight/ui/src/pages/search/components/query/Query.tsx +++ b/redisinsight/ui/src/pages/search/components/query/Query.tsx @@ -14,13 +14,13 @@ import { setCursorPositionAtTheEnd, splitQueryByArgs } from 'uiSrc/pages/search/utils' -import { SearchCommand, TokenType } from 'uiSrc/pages/search/types' +import { CursorContext, FoundCommandArgument, SearchCommand, TokenType } from 'uiSrc/pages/search/types' import { RedisResponseBuffer } from 'uiSrc/slices/interfaces' import { fetchRedisearchInfoAction } from 'uiSrc/slices/browser/redisearch' import { getRediSearchMonarchTokensProvider } from 'uiSrc/utils/monaco/monarchTokens/redisearchTokens' import { installRedisearchTheme, RedisearchMonacoTheme } from 'uiSrc/utils/monaco/monacoThemes' import { useDebouncedEffect } from 'uiSrc/services' -import { options, DefinedArgumentName } from './constants' +import { options, DefinedArgumentName, FIELD_START_SYMBOL } from './constants' import { getFieldsSuggestions, getIndexesSuggestions, @@ -28,6 +28,7 @@ import { getCommandsSuggestions, isIndexComplete, getGeneralSuggestions, + getFunctionsSuggestions, } from './utils' export interface Props { @@ -48,6 +49,7 @@ const Query = (props: Props) => { const disposeCompletionItemProvider = useRef(() => {}) const disposeSignatureHelpProvider = useRef(() => {}) const suggestionsRef = useRef<{ + forceShow?: boolean forceHide: boolean data: monacoEditor.languages.CompletionItem[] }>({ forceHide: false, data: [] }) @@ -145,12 +147,9 @@ const Query = (props: Props) => { const isSuggestionsOpened = () => { const { editor } = monacoObjects.current || {} - if (!editor) return false const suggestController = editor.getContribution('editor.contrib.suggestController') - const suggestModel = suggestController?.model - - return suggestModel?.state === 1 + return suggestController?.model?.state === 1 } const handleCursorChange = () => { @@ -165,6 +164,11 @@ const Query = (props: Props) => { suggestionsRef.current = getSuggestions(editor) + if (!suggestionsRef.current.forceShow) { + editor.trigger('', 'editor.action.triggerParameterHints', '') + return + } + if (suggestionsRef.current.data.length) { helpWidgetRef.current.isOpen = false triggerSuggestions() @@ -209,7 +213,8 @@ const Query = (props: Props) => { const word = model.getWordUntilPosition(position) const range = getRange(position, word) - const { args, isCursorInQuotes, prevCursorChar, nextCursorChar } = splitQueryByArgs(value, offset) + const { args, cursor } = splitQueryByArgs(value, offset) + const { prevCursorChar } = cursor const allArgs = args.flat() const [beforeOffsetArgs, [currentOffsetArg]] = args @@ -233,41 +238,35 @@ const Query = (props: Props) => { setSelectedIndex(allArgs[1] || '') setSelectedCommand(commandName) + if (prevCursorChar === FIELD_START_SYMBOL) { + helpWidgetRef.current.isOpen = false + return asSuggestionsRef(getFieldsSuggestions(attributesRef.current, range), false) + } + + const cursorContext: CursorContext = { ...cursor, currentOffsetArg, offset } const foundArg = findCurrentArgument(COMMANDS_LIST, beforeOffsetArgs) switch (foundArg?.stopArg?.name) { case DefinedArgumentName.index: { - updateHelpWidget(true, command, foundArg?.stopArg) - return getIndexSuggestions(command, prevArgs.length, currentOffsetArg, range) + return handleIndexSuggestions(command, foundArg, prevArgs.length, currentOffsetArg, range) } case DefinedArgumentName.query: { - updateHelpWidget(true, command, foundArg?.stopArg) - return getQuerySuggestions(prevCursorChar, range) + return handleQuerySuggestions(command, foundArg) } default: { - if (isCursorInQuotes || nextCursorChar?.trim()) return asSuggestionsRef([]) - if ((prevCursorChar?.trim() || isCursorInQuotes) && isEscapedSuggestions.current) return asSuggestionsRef([]) - isEscapedSuggestions.current = false - - const { suggestions, forceHide, helpWidgetData } = getGeneralSuggestions( - foundArg, - allArgs, - range, - attributesRef.current - ) - - if (helpWidgetData) updateHelpWidget(helpWidgetData.isOpen, helpWidgetData.parent, helpWidgetData.currentArg) - return asSuggestionsRef(suggestions, forceHide) + return handleCommonSuggestions(value, foundArg, allArgs, cursorContext, range) } } } - const getIndexSuggestions = ( + const handleIndexSuggestions = ( command: SearchCommand, + foundArg: FoundCommandArgument, prevArgsLength: number, currentOffsetArg: Nullable, range: monacoEditor.IRange ) => { + updateHelpWidget(true, command, foundArg?.stopArg) if (currentOffsetArg) return asSuggestionsRef([], false) if (indexesRef.current.length) { const isNextArgQuery = command?.arguments?.[prevArgsLength + 1]?.name === DefinedArgumentName.query @@ -276,16 +275,61 @@ const Query = (props: Props) => { return asSuggestionsRef([]) } - const getQuerySuggestions = ( - prevCursorChar: string, + const handleQuerySuggestions = ( + command: SearchCommand, + foundArg: FoundCommandArgument, + ) => { + updateHelpWidget(true, command, foundArg?.stopArg) + return asSuggestionsRef([], false) + } + + const handleExpressionSuggestions = ( + value: string, + foundArg: FoundCommandArgument, + cursorContext: CursorContext, range: monacoEditor.IRange ) => { - if (prevCursorChar === '@') { - helpWidgetRef.current.isOpen = false - return asSuggestionsRef(getFieldsSuggestions(attributesRef.current, range), false) - } + updateHelpWidget(true, foundArg?.parent, foundArg?.stopArg) - return asSuggestionsRef([], false) + const { isCursorInQuotes, offset, argLeftOffset } = cursorContext + if (!isCursorInQuotes) return asSuggestionsRef([]) + + const stringBeforeCursor = value.substring(argLeftOffset, offset) || '' + const { args } = splitQueryByArgs( + stringBeforeCursor.replace(/^["']|["']$/g, ''), + offset - argLeftOffset + ) + const [, [currentArg]] = args + + const functions = foundArg?.stopArg?.arguments ?? [] + + const suggestions = getFunctionsSuggestions(functions, range) + const isStartsWithFunction = functions.some(({ token }) => token?.startsWith(currentArg)) + return asSuggestionsRef(suggestions, true, isStartsWithFunction) + } + + const handleCommonSuggestions = ( + value: string, + foundArg: Nullable, + allArgs: string[], + cursorContext: CursorContext, + range: monacoEditor.IRange + ) => { + if (foundArg?.stopArg?.expression) return handleExpressionSuggestions(value, foundArg, cursorContext, range) + + const { prevCursorChar, nextCursorChar, isCursorInQuotes } = cursorContext + if (isCursorInQuotes || nextCursorChar?.trim()) return asSuggestionsRef([]) + if ((prevCursorChar?.trim() || isCursorInQuotes) && isEscapedSuggestions.current) return asSuggestionsRef([]) + + const { suggestions, forceHide, helpWidgetData } = getGeneralSuggestions( + foundArg, + allArgs, + range, + attributesRef.current + ) + + if (helpWidgetData) updateHelpWidget(helpWidgetData.isOpen, helpWidgetData.parent, helpWidgetData.currentArg) + return asSuggestionsRef(suggestions, forceHide) } return ( diff --git a/redisinsight/ui/src/pages/search/components/query/constants.ts b/redisinsight/ui/src/pages/search/components/query/constants.ts index f06c41a66c..22dcf561d6 100644 --- a/redisinsight/ui/src/pages/search/components/query/constants.ts +++ b/redisinsight/ui/src/pages/search/components/query/constants.ts @@ -16,4 +16,7 @@ export enum DefinedArgumentName { index = 'index', query = 'query', field = 'field', + expression = 'expression' } + +export const FIELD_START_SYMBOL = '@' diff --git a/redisinsight/ui/src/pages/search/components/query/utils.ts b/redisinsight/ui/src/pages/search/components/query/utils.ts index 10f1527fb2..4e7964b2c2 100644 --- a/redisinsight/ui/src/pages/search/components/query/utils.ts +++ b/redisinsight/ui/src/pages/search/components/query/utils.ts @@ -1,7 +1,7 @@ import { monaco } from 'react-monaco-editor' import * as monacoEditor from 'monaco-editor' import { RedisResponseBuffer } from 'uiSrc/slices/interfaces' -import { bufferToString, formatLongName, getCommandMarkdown, Nullable } from 'uiSrc/utils' +import { bufferToString, formatLongName, generateArgsForInsertText, getCommandMarkdown, Nullable } from 'uiSrc/utils' import { buildSuggestion, generateDetail, @@ -10,9 +10,14 @@ import { import { FoundCommandArgument, SearchCommand } from 'uiSrc/pages/search/types' import { DefinedArgumentName } from 'uiSrc/pages/search/components/query/constants' -export const asSuggestionsRef = (suggestions: monacoEditor.languages.CompletionItem[], forceHide = true) => ({ +export const asSuggestionsRef = ( + suggestions: monacoEditor.languages.CompletionItem[], + forceHide = true, + forceShow = true +) => ({ data: suggestions, - forceHide + forceHide, + forceShow }) export const getIndexesSuggestions = (indexes: RedisResponseBuffer[], range: monaco.IRange, nextQoutes = true) => @@ -43,6 +48,22 @@ export const getFieldsSuggestions = (fields: any[], range: monaco.IRange, spaceA } }) +const insertFunctionArguments = (args: SearchCommand[]) => + generateArgsForInsertText( + args.map(({ token, optional }) => (optional ? `[${token}]` : (token || ''))) as string[], + ', ' + ) + +export const getFunctionsSuggestions = (functions: SearchCommand[], range: monaco.IRange) => functions + .map(({ token, summary, arguments: args }) => ({ + label: token || '', + insertText: `${token}(${insertFunctionArguments(args || [])})`, + insertTextRules: monacoEditor.languages.CompletionItemInsertTextRule.InsertAsSnippet, + range, + kind: monacoEditor.languages.CompletionItemKind.Function, + detail: summary + })) + export const getCommandsSuggestions = (commands: SearchCommand[], range: monaco.IRange) => asSuggestionsRef( commands.map((command) => buildSuggestion(command, range, { detail: generateDetail(command), diff --git a/redisinsight/ui/src/pages/search/types.ts b/redisinsight/ui/src/pages/search/types.ts index a2d96a5a4d..f1d9287048 100644 --- a/redisinsight/ui/src/pages/search/types.ts +++ b/redisinsight/ui/src/pages/search/types.ts @@ -3,7 +3,8 @@ import { Maybe } from 'uiSrc/utils' export enum TokenType { PureToken = 'pure-token', Block = 'block', - OneOf = 'oneof' + OneOf = 'oneof', + String = 'string', } export enum ArgName { @@ -12,6 +13,8 @@ export enum ArgName { export interface SearchCommand { name?: string + summary?: string + expression?: boolean type?: TokenType token?: string optional?: boolean @@ -30,3 +33,13 @@ export interface FoundCommandArgument { append: Maybe> parent: Maybe } + +export interface CursorContext { + prevCursorChar: string + nextCursorChar: string + isCursorInQuotes: boolean + currentOffsetArg: string + offset: number + argLeftOffset: number + argRightOffset: number +} diff --git a/redisinsight/ui/src/pages/search/utils/monaco.ts b/redisinsight/ui/src/pages/search/utils/monaco.ts index 41712e9568..bfc1d6ea08 100644 --- a/redisinsight/ui/src/pages/search/utils/monaco.ts +++ b/redisinsight/ui/src/pages/search/utils/monaco.ts @@ -25,14 +25,17 @@ export const getRange = (position: monaco.Position, word: monaco.editor.IWordAtP startColumn: word.startColumn, }) -export const buildSuggestion = (arg: SearchCommand, range: monaco.IRange, options: any = {}) => ({ - label: isString(arg) ? arg : arg.token || arg.arguments?.[0].token || arg.name || '', - insertText: `${arg.token || arg.arguments?.[0].token || arg.name?.toUpperCase() || ''} `, - insertTextRules: monacoEditor.languages.CompletionItemInsertTextRule.InsertAsSnippet, - range, - kind: options?.kind || monacoEditor.languages.CompletionItemKind.Function, - ...options, -}) +export const buildSuggestion = (arg: SearchCommand, range: monaco.IRange, options: any = {}) => { + const extraQuotes = arg.expression ? '"$1"' : '' + return { + label: isString(arg) ? arg : arg.token || arg.arguments?.[0].token || arg.name || '', + insertText: `${arg.token || arg.arguments?.[0].token || arg.name?.toUpperCase() || ''} ${extraQuotes}`, + insertTextRules: monacoEditor.languages.CompletionItemInsertTextRule.InsertAsSnippet, + range, + kind: options?.kind || monacoEditor.languages.CompletionItemKind.Function, + ...options, + } +} export const getRediSearchSignutureProvider = (options: Maybe<{ isOpen: boolean diff --git a/redisinsight/ui/src/pages/search/utils/query.ts b/redisinsight/ui/src/pages/search/utils/query.ts index 89178a4fcf..a66bdb2596 100644 --- a/redisinsight/ui/src/pages/search/utils/query.ts +++ b/redisinsight/ui/src/pages/search/utils/query.ts @@ -13,6 +13,8 @@ export const splitQueryByArgs = (query: string, position: number = 0) => { let quoteChar = '' let isCursorInQuotes = false let lastArg = '' + let argLeftOffset = 0 + let argRightOffset = 0 const pushToProperTuple = (isAfterOffset: boolean, arg: string) => { lastArg = arg @@ -24,6 +26,11 @@ export const splitQueryByArgs = (query: string, position: number = 0) => { argsBySide[argsBySide.length - 1] = `${argsBySide[argsBySide.length - 1]} ${arg}` } + const updateArgOffsets = (left: number, right: number) => { + argLeftOffset = left + argRightOffset = right + } + for (let i = 0; i < query.length; i++) { const char = query[i] const isAfterOffset = i >= position + (inQuotes ? -1 : 0) @@ -38,6 +45,10 @@ export const splitQueryByArgs = (query: string, position: number = 0) => { inQuotes = false const argWithChat = arg + char + if (isAfterOffset && !argLeftOffset) { + updateArgOffsets(i - arg.length, i + 1) + } + if (isCompositeArgument(argWithChat, lastArg)) { updateLastArgument(isAfterOffset, argWithChat) } else { @@ -54,6 +65,10 @@ export const splitQueryByArgs = (query: string, position: number = 0) => { arg += char } else if (char === ' ' || char === '\n') { if (arg.length > 0) { + if (isAfterOffset && !argLeftOffset) { + updateArgOffsets(i - arg.length, i) + } + if (isCompositeArgument(arg, lastArg)) { updateLastArgument(isAfterOffset, arg) } else { @@ -70,10 +85,19 @@ export const splitQueryByArgs = (query: string, position: number = 0) => { } if (arg.length > 0) { + if (!argLeftOffset) updateArgOffsets(query.length - arg.length, query.length) pushToProperTuple(true, arg) } - return { args, isCursorInQuotes, prevCursorChar: query[position - 1], nextCursorChar: query[position] } + const cursor = { + isCursorInQuotes, + prevCursorChar: query[position - 1], + nextCursorChar: query[position], + argLeftOffset, + argRightOffset + } + + return { args, cursor } } export const findCurrentArgument = ( @@ -91,9 +115,7 @@ export const findCurrentArgument = ( } const tokenIndex = args.findIndex((cArg) => - (cArg.type === TokenType.OneOf - ? cArg.arguments?.some((oneOfArg: SearchCommand) => oneOfArg.token?.toLowerCase() === arg.toLowerCase()) - : cArg.token?.toLowerCase() === arg.toLowerCase())) + cArg.token?.toLowerCase() === arg.toLowerCase()) const token = args[tokenIndex] if (token) { @@ -123,6 +145,7 @@ const findStopArgumentInQuery = ( let currentCommandArgIndex = 0 let isBlockedOnCommand = false let multipleIndexStart = 0 + let multipleCountNumber = 0 const moveToNextCommandArg = () => currentCommandArgIndex++ const blockCommand = () => { isBlockedOnCommand = true } @@ -202,11 +225,14 @@ const findStopArgumentInQuery = ( } if (currentCommandArg?.multiple) { - const numberOfArgs = toNumber(queryArgs[currentCommandArgIndex]) || 0 + if (!multipleIndexStart) { + multipleCountNumber = toNumber(queryArgs[i - 1]) + multipleIndexStart = i - 1 + } - if (!multipleIndexStart) multipleIndexStart = currentCommandArgIndex - if (i - multipleIndexStart >= numberOfArgs) { + if (i - multipleIndexStart >= multipleCountNumber) { skipArg() + multipleIndexStart = 0 continue } @@ -271,7 +297,9 @@ export const getArgumentSuggestions = ( } } - const beforeMandatoryOptionalArgs = getAllRestArguments(current, stopArgument, pastStringArgs) + // if we finished argument - stopArgument will be undefined, then we get it as token + const lastArgument = stopArgument ?? restArguments[0] + const beforeMandatoryOptionalArgs = getAllRestArguments(current, lastArgument, pastStringArgs) const requiredArgsLength = restNotFilledArgs.filter((arg) => !arg.optional).length return { @@ -286,20 +314,20 @@ export const getRestArguments = ( current: Maybe, stopArgument: Nullable ): SearchCommandTree[] => { - if (!stopArgument) return [] - const argumentIndexInArg = current?.arguments - ?.findIndex(({ name }) => name === stopArgument?.name) || -1 - const nextMandatoryIndex = current?.arguments - ?.findIndex(({ optional }, i) => !optional && i > argumentIndexInArg) || -1 + ?.findIndex(({ name }) => name === stopArgument?.name) + const nextMandatoryIndex = argumentIndexInArg && argumentIndexInArg > -1 ? current?.arguments + ?.findIndex(({ optional }, i) => !optional && i > argumentIndexInArg) : -1 const beforeMandatoryOptionalArgs = ( - nextMandatoryIndex > -1 + nextMandatoryIndex && nextMandatoryIndex > -1 ? current?.arguments?.slice(argumentIndexInArg, nextMandatoryIndex) : current?.arguments?.filter(({ optional }) => optional) ) || [] - const nextMandatoryArg = current?.arguments?.[nextMandatoryIndex] + const nextMandatoryArg = nextMandatoryIndex && nextMandatoryIndex > -1 + ? current?.arguments?.[nextMandatoryIndex] + : undefined if (nextMandatoryArg?.token) { beforeMandatoryOptionalArgs.unshift(nextMandatoryArg) diff --git a/redisinsight/ui/src/utils/monaco/monacoThemes.ts b/redisinsight/ui/src/utils/monaco/monacoThemes.ts index 0e7f41f56f..3982d4e651 100644 --- a/redisinsight/ui/src/utils/monaco/monacoThemes.ts +++ b/redisinsight/ui/src/utils/monaco/monacoThemes.ts @@ -11,15 +11,20 @@ export const installRedisearchTheme = () => { inherit: true, rules: [ { token: 'keyword', foreground: '#569cd6', fontStyle: 'bold' }, - // { token: 'argument.token', foreground: '#6db9a2' }, { token: 'argument.block.0', foreground: '#66ccaf' }, { token: 'argument.block.1', foreground: '#459d7f' }, { token: 'argument.block.2', foreground: '#3c816a' }, { token: 'argument.block.3', foreground: '#28644f' }, + { token: 'argument.block.withToken.0', foreground: '#66ccaf' }, + { token: 'argument.block.withToken.1', foreground: '#459d7f' }, + { token: 'argument.block.withToken.2', foreground: '#3c816a' }, + { token: 'argument.block.withToken.3', foreground: '#28644f' }, { token: 'loadAll', foreground: '#6db9a2' }, { token: 'index', foreground: '#ce51cc' }, { token: 'query', foreground: '#5183ce' }, { token: 'field', foreground: '#c43265' }, + { token: 'query.operator', foreground: '#a4e7df' }, + { token: 'function', foreground: '#aa58d2' }, ], colors: {} }) @@ -33,10 +38,16 @@ export const installRedisearchTheme = () => { { token: 'argument.block.1', foreground: '#459d7f' }, { token: 'argument.block.2', foreground: '#3c816a' }, { token: 'argument.block.3', foreground: '#28644f' }, + { token: 'argument.block.withToken.0', foreground: '#66ccaf' }, + { token: 'argument.block.withToken.1', foreground: '#459d7f' }, + { token: 'argument.block.withToken.2', foreground: '#3c816a' }, + { token: 'argument.block.withToken.3', foreground: '#28644f' }, { token: 'loadAll', foreground: '#6db9a2' }, { token: 'index', foreground: '#ce51cc' }, { token: 'field', foreground: '#5183ce' }, { token: 'field', foreground: '#c43265' }, + { token: 'query.operator', foreground: '#a4e7df' }, + { token: 'function', foreground: '#aa58d2' }, ], colors: {} }) diff --git a/redisinsight/ui/src/utils/monaco/monarchTokens/redisearchTokens.ts b/redisinsight/ui/src/utils/monaco/monarchTokens/redisearchTokens.ts index 9d91952d2d..a4814e00c3 100644 --- a/redisinsight/ui/src/utils/monaco/monarchTokens/redisearchTokens.ts +++ b/redisinsight/ui/src/utils/monaco/monarchTokens/redisearchTokens.ts @@ -1,54 +1,16 @@ import { monaco as monacoEditor } from 'react-monaco-editor' -import { SearchCommand, TokenType } from 'uiSrc/pages/search/types' -import { DefinedArgumentName } from 'uiSrc/pages/search/components/query/constants' +import { SearchCommand } from 'uiSrc/pages/search/types' +import { + generateKeywords, + generateTokens, + generateTokensWithFunctions, + getBlockTokens, + isQueryAfterIndex +} from 'uiSrc/utils/monaco/redisearch/utils' +import { generateQuery } from 'uiSrc/utils/monaco/monarchTokens/redisearchTokensTemplates' const STRING_DOUBLE = 'string.double' -const generateKeywords = (commands: SearchCommand[]) => commands.map(({ name }) => name) -const generateTokens = (command?: SearchCommand) => { - if (!command) return [] - const levels: Array> = [] - - function processArguments(args: SearchCommand[], level = 0) { - // Ensure the current level exists in the levels array - if (!levels[level]) { - levels[level] = [] - } - - args.forEach((arg) => { - if (arg.token) levels[level].push(arg.token) - - if (arg.type === TokenType.Block && arg.arguments) { - const blockToken = arg.arguments[0].token - const nextArgs = arg.arguments - if (blockToken) { - levels[level].push(blockToken) - } - processArguments(blockToken ? nextArgs.slice(1, nextArgs.length) : nextArgs, level + 1) - } - - if (arg.type === TokenType.OneOf && arg.arguments) { - arg.arguments.forEach((choice) => { - if (choice.token) levels[level].push(choice.token) - }) - } - }) - } - - if (command.arguments) { - processArguments(command.arguments, 0) - } - - return levels -} - -const isQueryAfterIndex = (command?: SearchCommand) => { - if (!command) return false - - const index = command.arguments?.findIndex(({ name }) => name === DefinedArgumentName.index) || -2 - return command.arguments?.[index + 1]?.name === DefinedArgumentName.query -} - export const getRediSearchMonarchTokensProvider = ( commands: SearchCommand[], command?: string @@ -77,6 +39,7 @@ export const getRediSearchMonarchTokensProvider = ( { include: '@keyword' }, [/LOAD\s+\*/, 'loadAll'], { include: '@argument.block' }, + { include: '@argument.block.withFunctions' }, [/[;,.]/, 'delimiter'], [/[()]/, '@brackets'], [ @@ -93,45 +56,15 @@ export const getRediSearchMonarchTokensProvider = ( keyword: [ [`(${keywords.join('|')})\\b`, { token: 'keyword', next: '@index' }] ], - 'argument.block': argTokens.map((tokens, lvl) => [`(${tokens.join('|')})\\b`, `argument.block.${lvl}`]), + 'argument.block': getBlockTokens(argTokens?.pureTokens), + ...generateTokensWithFunctions(argTokens?.tokensWithQueryAfter), index: [ [/"([^"\\]|\\.)*"/, { token: 'index', next: isHighlightQuery ? '@query' : '@root' }], [/'([^'\\]|\\.)*'/, { token: 'index', next: isHighlightQuery ? '@query' : '@root' }], [/[a-zA-Z_]\w*/, { token: 'index', next: isHighlightQuery ? '@query' : '@root' }], { include: 'root' } // Fallback to the root state if nothing matches ], - query: [ - [/"/, { token: 'query', next: '@queryInsideDouble' }], - [/'/, { token: 'query', next: '@queryInsideSingle' }], - [/[a-zA-Z_]\w*/, { token: 'query', next: '@root' }], - { include: 'root' } // Fallback to the root state if nothing matches - ], - queryInsideDouble: [ - [/@/, { token: 'field', next: '@fieldInDouble' }], - [/\\"/, { token: 'query', next: 'queryInsideDouble' }], - [/"/, { token: 'query', next: '@root' }], - [/./, { token: 'query', next: '@queryInsideDouble' }], - { include: '@query' } // Fallback to the root state if nothing matches - ], - queryInsideSingle: [ - [/@/, { token: 'field', next: '@fieldInSingle' }], - [/\\'/, { token: 'query', next: 'queryInsideSingle' }], - [/'/, { token: 'query', next: '@root' }], - [/./, { token: 'query', next: '@queryInsideSingle' }], - { include: '@query' } // Fallback to the root state if nothing matches - ], - fieldInDouble: [ - [/\w+/, { token: 'field', next: '@queryInsideDouble' }], - [/\s+/, { token: '@rematch', next: '@queryInsideDouble' }], - [/"/, { token: 'query', next: '@root' }], - { include: '@query' } // Fallback to the root state if nothing matches - ], - fieldInSingle: [ - [/\w+/, { token: 'field', next: '@queryInsideSingle' }], - [/\s+/, { token: '@rematch', next: '@queryInsideSingle' }], - [/'/, { token: 'query', next: '@root' }], - { include: '@query' } // Fallback to the root state if nothing matches - ], + ...generateQuery(), whitespace: [ [/\s+/, 'white'], [/\/\/.*$/, 'comment'], diff --git a/redisinsight/ui/src/utils/monaco/monarchTokens/redisearchTokensTemplates.ts b/redisinsight/ui/src/utils/monaco/monarchTokens/redisearchTokensTemplates.ts new file mode 100644 index 0000000000..9c2901029f --- /dev/null +++ b/redisinsight/ui/src/utils/monaco/monarchTokens/redisearchTokensTemplates.ts @@ -0,0 +1,104 @@ +import { languages } from 'monaco-editor' +import { curryRight } from 'lodash' +import { SearchCommand } from 'uiSrc/pages/search/types' +import { Maybe } from 'uiSrc/utils' + +const appendToken = (token: string, name: Maybe) => (name ? `${token}.${name}` : token) +export const generateQuery = ( + argToken?: SearchCommand, + args?: SearchCommand[] +): { [name: string]: languages.IMonarchLanguageRule[] } => { + const curriedAppendToken = curryRight(appendToken) + const appendTokenName = curriedAppendToken(argToken?.token) + + const getFunctionsTokens = (tokenName: string): languages.IMonarchLanguageRule => (args?.length ? [ + `(${args?.map(({ token }) => token).join('|')})\\b`, { token: 'function', next: appendTokenName(tokenName) } + ] : [/_/, '']) + + return { + [appendTokenName('query')]: [ + [/"/, { token: appendTokenName('query'), next: appendTokenName('@query.inside.double') }], + [/'/, { token: appendTokenName('query'), next: appendTokenName('@query.inside.single') }], + [/[a-zA-Z_]\w*/, { token: appendTokenName('query'), next: '@root' }], + { include: 'root' } // Fallback to the root state if nothing matches + ], + [appendTokenName('query.inside.double')]: [ + [/@/, { token: 'field', next: appendTokenName('@field.inside.double') }], + [/\\"/, { token: 'query', next: appendTokenName('@query.inside.double') }], + [/==|!=|<=|>=|<|>/, { token: 'query.operator' }], + [/&&|\|\|/, { token: 'query.operator' }], + getFunctionsTokens('@function.inside.double'), + [/"/, { token: appendTokenName('query'), next: '@root' }], + [/./, { token: appendTokenName('query'), next: appendTokenName('@query.inside.double') }], + { include: '@query' } // Fallback to the root state if nothing matches + ], + [appendTokenName('query.inside.single')]: [ + [/@/, { token: 'field', next: appendTokenName('@field.inside.single') }], + [/\\'/, { token: appendTokenName('query'), next: appendTokenName('query.inside.single') }], + [/==|!=|<=|>=|<|>/, { token: 'query.operator' }], + [/&&|\|\|/, { token: 'query.operator' }], + getFunctionsTokens('@function.inside.single'), + [/'/, { token: appendTokenName('query'), next: '@root' }], + [/./, { token: appendTokenName('query'), next: appendTokenName('@query.inside.single') }], + { include: appendTokenName('@query') } // Fallback to the root state if nothing matches + ], + [appendTokenName('field.inside.double')]: [ + [/\w+/, { token: 'field', next: appendTokenName('@query.inside.double') }], + [/\s+/, { token: '@rematch', next: appendTokenName('@query.inside.double') }], + [/"/, { token: appendTokenName('query'), next: '@root' }], + { include: appendTokenName('@query') } // Fallback to the root state if nothing matches + ], + [appendTokenName('field.inside.single')]: [ + [/\w+/, { token: 'field', next: appendTokenName('@query.inside.single') }], + [/\s+/, { token: '@rematch', next: appendTokenName('@query.inside.single') }], + [/'/, { token: appendTokenName('query'), next: '@root' }], + + { include: appendTokenName('@query') } + ], + [appendTokenName('function.inside.double')]: [ + [/\s+/, 'white'], // Handle whitespace + [/\(/, { token: 'delimiter.parenthesis', next: appendTokenName('@function.args.double') }], + { include: appendTokenName('@query') } + ], + [appendTokenName('function.inside.double')]: [ + [/\s+/, 'white'], // Handle whitespace + [/\(/, { token: 'delimiter.parenthesis', next: appendTokenName('@function.args.double') }], + { include: appendTokenName('@query') } + ], + [appendTokenName('function.args.double')]: [ + [/\)/, { token: 'delimiter.parenthesis', next: appendTokenName('@query.inside.double') }], + [/,/, 'delimiter.comma'], // Match commas between arguments + getFunctionsTokens('@function.inside.double'), + [/[a-zA-Z_]\w*/, { token: 'parameter' }], // Highlight parameters + [/\s+/, 'white'], // Handle whitespace + [/@\w+/, { token: 'field' }], + + // // Handle strings with escaped quotes + [/\\"/, 'parameter'], // Match escaped double quote + [/\\'/, 'parameter'], // Match escaped single quote + [/'/, 'parameter'], // Match escaped single quote + + { include: appendTokenName('@query') } // Fallback to root state + ], + [appendTokenName('function.inside.single')]: [ + [/\s+/, 'white'], // Handle whitespace + [/\(/, { token: 'delimiter.parenthesis', next: appendTokenName('@function.args.single') }], + { include: appendTokenName('@query') } + ], + [appendTokenName('function.args.single')]: [ + [/\)/, { token: 'delimiter.parenthesis', next: appendTokenName('@query.inside.single') }], + [/,/, 'delimiter.comma'], // Match commas between arguments + getFunctionsTokens('@function.inside.single'), + [/[a-zA-Z_]\w*/, { token: 'parameter' }], // Highlight parameters + [/\s+/, 'white'], // Handle whitespace + [/@\w+/, { token: 'field' }], + + [/"/, 'parameter'], // Match escaped double quote + // // Handle strings with escaped quotes + [/\\"/, 'parameter'], // Match escaped double quote + [/\\'/, 'parameter'], // Match escaped single quote + + { include: appendTokenName('@query') } // Fallback to root state + ] + } +} diff --git a/redisinsight/ui/src/utils/monaco/redisearch/utils.ts b/redisinsight/ui/src/utils/monaco/redisearch/utils.ts new file mode 100644 index 0000000000..c65b4bb80a --- /dev/null +++ b/redisinsight/ui/src/utils/monaco/redisearch/utils.ts @@ -0,0 +1,136 @@ +import { isNumber, remove } from 'lodash' +import { languages } from 'monaco-editor' +import { SearchCommand, TokenType } from 'uiSrc/pages/search/types' +import { Maybe, Nullable } from 'uiSrc/utils' +import { DefinedArgumentName } from 'uiSrc/pages/search/components/query/constants' +import { generateQuery } from 'uiSrc/utils/monaco/monarchTokens/redisearchTokensTemplates' + +export const generateKeywords = (commands: SearchCommand[]) => commands.map(({ name }) => name) +export const generateTokens = (command?: SearchCommand): Nullable<{ + pureTokens: Array> + tokensWithQueryAfter: Array> +}> => { + if (!command) return null + const pureTokens: Array> = [] + const tokensWithQueryAfter: Array> = [] + + function processArguments(args: SearchCommand[], level = 0) { + if (!pureTokens[level]) pureTokens[level] = [] + if (!tokensWithQueryAfter[level]) tokensWithQueryAfter[level] = [] + + args.forEach((arg) => { + if (arg.token) pureTokens[level].push(arg) + + if (arg.type === TokenType.Block && arg.arguments) { + const blockToken = arg.arguments[0] + const nextArgs = arg.arguments + const isArgHasOwnSyntax = arg.arguments[0].expression && !!arg.arguments[0].arguments?.length + + if (blockToken?.token) { + if (isArgHasOwnSyntax) { + tokensWithQueryAfter[level].push({ + token: blockToken, + arguments: arg.arguments[0].arguments as SearchCommand[] + }) + } else { + pureTokens[level].push(blockToken) + } + } + + processArguments(blockToken ? nextArgs.slice(1, nextArgs.length) : nextArgs, level + 1) + } + + if (arg.type === TokenType.OneOf && arg.arguments) { + arg.arguments.forEach((choice) => { + if (choice?.token) pureTokens[level].push(choice) + }) + } + }) + } + + if (command.arguments) { + processArguments(command.arguments, 0) + } + + return { pureTokens, tokensWithQueryAfter } +} + +export const isQueryAfterIndex = (command?: SearchCommand) => { + if (!command) return false + + const index = command.arguments?.findIndex(({ name }) => name === DefinedArgumentName.index) + return isNumber(index) && index > -1 ? command.arguments?.[index + 1]?.name === DefinedArgumentName.query : false +} + +export const appendTokenWithQuery = ( + args: Array<{ token: SearchCommand, arguments: SearchCommand[] }>, + level: number +): languages.IMonarchLanguageRule[] => + args.map(({ token }) => [`(${token.token})\\b`, { token: `argument.block.${level}`, next: `@query.${token.token}` }]) + +export const appendQueryWithNextFunctions = (tokens: Array<{ token: SearchCommand, arguments: SearchCommand[] }>): { + [name: string]: languages.IMonarchLanguageRule[] +} => { + let result: { [name: string]: languages.IMonarchLanguageRule[] } = {} + + tokens.forEach(({ token, arguments: args }) => { + result = { + ...result, + ...generateQuery(token, args) + } + }) + + return result +} + +export const generateTokensWithFunctions = ( + tokens?: Array> +): { + [name: string]: languages.IMonarchLanguageRule[] +} => { + if (!tokens) return { 'argument.block.withFunctions': [] } + + const actualTokens = tokens.filter((tokens) => tokens.length) + + return { + 'argument.block.withFunctions': [ + ...actualTokens + .map((tokens, lvl) => appendTokenWithQuery(tokens, lvl)) + .flat() + ], + ...appendQueryWithNextFunctions(actualTokens.flat()) + } +} + +export const getBlockTokens = ( + pureTokens: Maybe[]> +): languages.IMonarchLanguageRule[] => { + if (!pureTokens) return [] + + const getLeveledToken = ( + tokens: SearchCommand[], + lvl: number + ): languages.IMonarchLanguageRule[] => { + const result: languages.IMonarchLanguageRule[] = [] + const restTokens = [...tokens] + const tokensWithNextExpression = remove(restTokens, (({ expression }) => expression)) + + if (tokensWithNextExpression.length) { + result.push([ + `(${tokensWithNextExpression.map(({ token }) => token).join('|')})\\b`, + { + token: `argument.block.${lvl}`, + next: '@query' + }, + ]) + } + + if (restTokens.length) { + result.push([`(${restTokens.map(({ token }) => token).join('|')})\\b`, { token: `argument.block.${lvl}`, next: '@root' }]) + } + + return result + } + + return pureTokens.map((tokens, lvl) => getLeveledToken(tokens, lvl)).flat() +} From 063e093023bbf7d3f53f7bce4afba3a43cfa5ec0 Mon Sep 17 00:00:00 2001 From: Roman Sergeenko Date: Tue, 3 Sep 2024 18:26:33 +0200 Subject: [PATCH 042/256] #RI-6026 - add tests, fix tests --- .../search/components/query/utils.spec.ts | 81 +++--- .../pages/search/components/query/utils.ts | 2 +- .../ui/src/pages/search/utils/query.ts | 21 +- .../pages/search/utils/tests/query.spec.ts | 246 +++++++++++------- .../cyber/monarchTokensProvider.spec.ts | 17 ++ 5 files changed, 225 insertions(+), 142 deletions(-) diff --git a/redisinsight/ui/src/pages/search/components/query/utils.spec.ts b/redisinsight/ui/src/pages/search/components/query/utils.spec.ts index bb71924265..ded3afcccd 100644 --- a/redisinsight/ui/src/pages/search/components/query/utils.spec.ts +++ b/redisinsight/ui/src/pages/search/components/query/utils.spec.ts @@ -1,35 +1,32 @@ import { getGeneralSuggestions, isIndexComplete } from 'uiSrc/pages/search/components/query/utils' import { MOCKED_SUPPORTED_COMMANDS } from 'uiSrc/pages/search/mocks/mocks' -import { buildSuggestion } from 'uiSrc/pages/search/utils' -import { SearchCommand } from 'uiSrc/pages/search/types' +import { addOwnTokenToArgs, buildSuggestion, findCurrentArgument } from 'uiSrc/pages/search/utils' +import { SearchCommand, TokenType } from 'uiSrc/pages/search/types' const ftAggregate = MOCKED_SUPPORTED_COMMANDS['FT.AGGREGATE'] -const ftProfile = MOCKED_SUPPORTED_COMMANDS['FT.PROFILE'] -const getCursorContext = () => ({ - currentOffsetArg: undefined, - isCursorInQuotes: false, - nextCursorChar: undefined, - prevCursorChar: ' ', - range: {} -}) +const commands = Object.keys(MOCKED_SUPPORTED_COMMANDS) + .map((key) => ({ + ...addOwnTokenToArgs(key, MOCKED_SUPPORTED_COMMANDS[key]), + token: key, + type: TokenType.Block + })) + +const ftAggregateAppend = ftAggregate.arguments.slice(2) + .map((arg) => ({ ...arg, parent: ftAggregate })) const getGeneralSuggestionsTests = [ { input: { - commandContext: { - allArgs: ['FT.AGGREGATE', '""', '""'], - command: ftAggregate, - commandName: 'FT.AGGREGATE', - currentCommandArg: null, - prevArgs: ['""', '""'] - }, - cursorContext: getCursorContext() + foundArg: findCurrentArgument( + commands, + ['FT.AGGREGATE', '""', '""'] + ), + allArgs: ['FT.AGGREGATE', '""', '""'] }, result: { helpWidgetData: expect.any(Object), - suggestions: ftAggregate.arguments - .slice(2) + suggestions: ftAggregateAppend .map((arg) => ({ ...buildSuggestion(arg as SearchCommand, {} as any), sortText: expect.any(String), @@ -40,14 +37,11 @@ const getGeneralSuggestionsTests = [ }, { input: { - commandContext: { - allArgs: ['FT.AGGREGATE', '""', '""', 'APPLY', 'expression'], - command: ftAggregate, - commandName: 'FT.AGGREGATE', - currentCommandArg: null, - prevArgs: ['""', '""', 'APPLY', 'expression'] - }, - cursorContext: getCursorContext() + foundArg: findCurrentArgument( + commands, + ['FT.AGGREGATE', '""', '""', 'APPLY', 'expression'] + ), + allArgs: ['FT.AGGREGATE', '""', '""', 'APPLY', 'expression'] }, result: { helpWidgetData: expect.any(Object), @@ -65,14 +59,11 @@ const getGeneralSuggestionsTests = [ }, { input: { - commandContext: { - allArgs: ['FT.PROFILE', '""'], - command: ftProfile, - commandName: 'FT.PROFILE', - currentCommandArg: null, - prevArgs: ['""'] - }, - cursorContext: getCursorContext() + foundArg: findCurrentArgument( + commands, + ['FT.PROFILE', '""'] + ), + allArgs: ['FT.PROFILE', '""'] }, result: { helpWidgetData: expect.any(Object), @@ -83,7 +74,7 @@ const getGeneralSuggestionsTests = [ insertTextRules: 4, range: expect.any(Object), kind: undefined, - detail: '', + detail: expect.any(String), }, { label: 'AGGREGATE', @@ -91,16 +82,26 @@ const getGeneralSuggestionsTests = [ insertTextRules: 4, range: expect.any(Object), kind: undefined, - detail: '', + detail: expect.any(String), } ] } - } + }, ] describe('getGeneralSuggestions', () => { it.each(getGeneralSuggestionsTests)('should properly return suggestions', ({ input, result }) => { - const testResult = getGeneralSuggestions(input.commandContext, input.cursorContext, []) + const testResult = getGeneralSuggestions( + input.foundArg as any, + input.allArgs, + {} as any, + [] + ) + + console.log(findCurrentArgument( + commands, + ['FT.AGGREGATE', '""', '""'] + )) expect(testResult).toEqual(result) }) diff --git a/redisinsight/ui/src/pages/search/components/query/utils.ts b/redisinsight/ui/src/pages/search/components/query/utils.ts index 4e7964b2c2..3c3def04ed 100644 --- a/redisinsight/ui/src/pages/search/components/query/utils.ts +++ b/redisinsight/ui/src/pages/search/components/query/utils.ts @@ -86,7 +86,7 @@ export const getMandatoryArgumentSuggestions = ( if (foundArg.isBlocked) return [] if (foundArg.append?.length) { - return foundArg.append.flat().map((arg: any) => buildSuggestion(arg, range, { + return foundArg.append[0].map((arg: any) => buildSuggestion(arg, range, { kind: monacoEditor.languages.CompletionItemKind.Property, detail: generateDetail(foundArg?.parent) })) diff --git a/redisinsight/ui/src/pages/search/utils/query.ts b/redisinsight/ui/src/pages/search/utils/query.ts index a66bdb2596..921c1f5674 100644 --- a/redisinsight/ui/src/pages/search/utils/query.ts +++ b/redisinsight/ui/src/pages/search/utils/query.ts @@ -125,7 +125,7 @@ export const findCurrentArgument = ( // getArgByRest - here we preparing the list of arguments which can be inserted, // this is the main function which creates the list of arguments return { - ...getArgumentSuggestions(pastArgs, commandArgs, parent), + ...getArgumentSuggestions({ tokenArgs: pastArgs, levelArgs: prev }, commandArgs, parent), parent: parent || token } } @@ -242,9 +242,7 @@ const findStopArgumentInQuery = ( moveToNextCommandArg() - const nextCommand = restCommandArgs[currentCommandArgIndex + 1] - const currentCommand = restCommandArgs[currentCommandArgIndex] - isBlockedOnCommand = [currentCommand, nextCommand].every((arg) => arg && !arg.optional) + isBlockedOnCommand = false } return { @@ -255,7 +253,10 @@ const findStopArgumentInQuery = ( } export const getArgumentSuggestions = ( - pastStringArgs: string[], + { tokenArgs, levelArgs }: { + tokenArgs: string[], + levelArgs: string[] + }, pastCommandArgs: SearchCommand[], current?: SearchCommandTree ): { @@ -268,7 +269,7 @@ export const getArgumentSuggestions = ( restArguments, stopArgIndex, isBlocked: isWasBlocked - } = findStopArgumentInQuery(pastStringArgs, pastCommandArgs) + } = findStopArgumentInQuery(tokenArgs, pastCommandArgs) const stopArgument = restArguments[stopArgIndex] const restNotFilledArgs = restArguments.slice(stopArgIndex) @@ -299,7 +300,7 @@ export const getArgumentSuggestions = ( // if we finished argument - stopArgument will be undefined, then we get it as token const lastArgument = stopArgument ?? restArguments[0] - const beforeMandatoryOptionalArgs = getAllRestArguments(current, lastArgument, pastStringArgs) + const beforeMandatoryOptionalArgs = getAllRestArguments(current, lastArgument, levelArgs, !stopArgument) const requiredArgsLength = restNotFilledArgs.filter((arg) => !arg.optional).length return { @@ -344,19 +345,21 @@ export const getAllRestArguments = ( current: Maybe, stopArgument: Nullable, prevStringArgs: string[] = [], + skipLevel = false ) => { const appendArgs: Array = [] + const currentLvlNextArgs = removeNotSuggestedArgs( prevStringArgs, getRestArguments(current, stopArgument) ) - if (currentLvlNextArgs.length) { + if (!skipLevel) { appendArgs.push(currentLvlNextArgs) } if (current?.parent) { - const parentArgs = getAllRestArguments(current.parent, current, []) + const parentArgs = getAllRestArguments(current.parent, current, skipLevel ? prevStringArgs : []) if (parentArgs?.length) { appendArgs.push(...parentArgs) } diff --git a/redisinsight/ui/src/pages/search/utils/tests/query.spec.ts b/redisinsight/ui/src/pages/search/utils/tests/query.spec.ts index bff290b4da..f356961a93 100644 --- a/redisinsight/ui/src/pages/search/utils/tests/query.spec.ts +++ b/redisinsight/ui/src/pages/search/utils/tests/query.spec.ts @@ -7,16 +7,7 @@ const ftSearchCommand = MOCKED_SUPPORTED_COMMANDS['FT.SEARCH'] const ftAggregateCommand = MOCKED_SUPPORTED_COMMANDS['FT.AGGREGATE'] const ftAggreageTests = [ - { - args: [''], - result: { - append: [], - isBlocked: true, - isComplete: false, - parent: undefined, - stopArg: { name: 'query', type: 'string' } - } - }, + { args: [''], result: null }, { args: ['', ''], result: null }, { args: ['index', '"query"', 'APPLY'], @@ -78,17 +69,75 @@ const ftAggreageTests = [ optional: true }, append: [ - { - name: 'name', - type: 'string', - token: 'AS', - optional: true - }, - { - name: 'function', - type: 'string', - token: 'REDUCE' - } + [ + { + name: 'name', + type: 'string', + token: 'AS', + optional: true, + parent: { + name: 'reduce', + type: 'block', + optional: true, + multiple: true, + arguments: [ + { + name: 'function', + token: 'REDUCE', + type: 'string' + }, + { + name: 'nargs', + type: 'integer' + }, + { + name: 'arg', + type: 'string', + multiple: true + }, + { + name: 'name', + type: 'string', + token: 'AS', + optional: true + } + ], + parent: expect.any(Object) + } + } + ], + [ + { + name: 'function', + token: 'REDUCE', + type: 'string', + parent: { + name: 'groupby', + type: 'block', + optional: true, + multiple: true, + arguments: [ + { + name: 'nargs', + type: 'integer', + token: 'GROUPBY' + }, + { + name: 'property', + type: 'string', + multiple: true + }, + { + name: 'reduce', + type: 'block', + optional: true, + multiple: true, + arguments: expect.any(Array) + } + ] + } + } + ] ], isBlocked: false, isComplete: true, @@ -124,7 +173,7 @@ const ftAggreageTests = [ } ] }, - append: [ + append: [[ { name: 'asc', type: 'pure-token', @@ -135,7 +184,7 @@ const ftAggreageTests = [ type: 'pure-token', token: 'DESC' } - ], + ]], isBlocked: false, isComplete: false, parent: expect.any(Object) @@ -151,12 +200,15 @@ const ftAggreageTests = [ optional: true }, append: [ - { - name: 'num', - type: 'integer', - token: 'MAX', - optional: true - } + [ + { + name: 'num', + type: 'integer', + token: 'MAX', + optional: true, + parent: expect.any(Object) + } + ] ], isBlocked: false, isComplete: true, @@ -173,12 +225,13 @@ const ftAggreageTests = [ optional: true }, append: [ - { + [{ name: 'num', type: 'integer', token: 'MAX', - optional: true - } + optional: true, + parent: expect.any(Object) + }] ], isBlocked: false, isComplete: true, @@ -233,15 +286,7 @@ const ftAggreageTests = [ ] const ftSearchTests = [ - { - args: [''], - result: { - append: [], - isBlocked: true, - isComplete: false, - parent: undefined, - stopArg: { name: 'query', type: 'string' } } - }, + { args: [''], result: null }, { args: ['', ''], result: null }, { args: ['', '', 'SUMMARIZE'], @@ -263,31 +308,35 @@ const ftSearchTests = [ } ] }, - append: [ + append: [[ { name: 'count', type: 'string', - token: 'FIELDS' + token: 'FIELDS', + parent: expect.any(Object) }, { name: 'num', type: 'integer', token: 'FRAGS', - optional: true + optional: true, + parent: expect.any(Object) }, { name: 'fragsize', type: 'integer', token: 'LEN', - optional: true + optional: true, + parent: expect.any(Object) }, { name: 'separator', type: 'string', token: 'SEPARATOR', - optional: true + optional: true, + parent: expect.any(Object) } - ], + ]], isBlocked: false, isComplete: true, parent: expect.any(Object) @@ -345,20 +394,22 @@ const ftSearchTests = [ token: 'LEN', optional: true }, - append: [ + append: [[ { name: 'fragsize', type: 'integer', token: 'LEN', - optional: true + optional: true, + parent: expect.any(Object) }, { name: 'separator', type: 'string', token: 'SEPARATOR', - optional: true + optional: true, + parent: expect.any(Object) } - ], + ]], isBlocked: false, isComplete: true, parent: expect.any(Object) @@ -373,14 +424,8 @@ const ftSearchTests = [ token: 'AS', optional: true }, - append: [ - { - name: 'property', - type: 'string', - token: 'AS', - optional: true - } - ], + // TODO: append may have AS token, since it is optional - we skip for now + append: [[]], isBlocked: false, isComplete: false, parent: expect.any(Object) @@ -395,14 +440,7 @@ const ftSearchTests = [ token: 'AS', optional: true }, - append: [ - { - name: 'property', - type: 'string', - token: 'AS', - optional: true - } - ], + append: [[]], isBlocked: false, isComplete: true, parent: expect.any(Object) @@ -444,16 +482,20 @@ const ftSearchTests = [ ] }, append: [ - { - name: 'asc', - type: 'pure-token', - token: 'ASC' - }, - { - name: 'desc', - type: 'pure-token', - token: 'DESC' - } + [ + { + name: 'asc', + type: 'pure-token', + token: 'ASC', + parent: expect.any(Object) + }, + { + name: 'desc', + type: 'pure-token', + token: 'DESC', + parent: expect.any(Object) + } + ] ], isBlocked: false, isComplete: true, @@ -506,45 +548,65 @@ const splitQueryByArgsTests: Array<{ input: ['FT.SEARCH "idx:bicycle" "" WITHSORTKEYS'], result: { args: [[], ['FT.SEARCH', '"idx:bicycle"', '""', 'WITHSORTKEYS']], - isCursorInQuotes: false, - nextCursorChar: 'F', - prevCursorChar: undefined + cursor: { + argLeftOffset: 10, + argRightOffset: 23, + isCursorInQuotes: false, + nextCursorChar: 'F', + prevCursorChar: undefined + } } }, { input: ['FT.SEARCH "idx:bicycle" "" WITHSORTKEYS', 17], result: { args: [['FT.SEARCH'], ['"idx:bicycle"', '""', 'WITHSORTKEYS']], - isCursorInQuotes: true, - nextCursorChar: 'c', - prevCursorChar: 'i' + cursor: { + argLeftOffset: 10, + argRightOffset: 23, + isCursorInQuotes: true, + nextCursorChar: 'c', + prevCursorChar: 'i' + } } }, { input: ['FT.SEARCH "idx:bicycle" "" WITHSORTKEYS', 39], result: { args: [['FT.SEARCH', '"idx:bicycle"', '""'], ['WITHSORTKEYS']], - isCursorInQuotes: false, - nextCursorChar: undefined, - prevCursorChar: 'S' + cursor: { + argLeftOffset: 27, + argRightOffset: 39, + isCursorInQuotes: false, + nextCursorChar: undefined, + prevCursorChar: 'S' + } } }, { input: ['FT.SEARCH "idx:bicycle" "" WITHSORTKEYS ', 40], result: { args: [['FT.SEARCH', '"idx:bicycle"', '""', 'WITHSORTKEYS'], []], - isCursorInQuotes: false, - nextCursorChar: undefined, - prevCursorChar: ' ' + cursor: { + argLeftOffset: 0, + argRightOffset: 0, + isCursorInQuotes: false, + nextCursorChar: undefined, + prevCursorChar: ' ' + } } }, { input: ['FT.SEARCH "idx:bicycle \\" \\"" "" WITHSORTKEYS ', 46], result: { args: [['FT.SEARCH', '"idx:bicycle " ""', '""', 'WITHSORTKEYS'], []], - isCursorInQuotes: false, - nextCursorChar: undefined, - prevCursorChar: ' ' + cursor: { + argLeftOffset: 0, + argRightOffset: 0, + isCursorInQuotes: false, + nextCursorChar: undefined, + prevCursorChar: ' ' + } } } ] diff --git a/redisinsight/ui/src/utils/tests/monaco/cyber/monarchTokensProvider.spec.ts b/redisinsight/ui/src/utils/tests/monaco/cyber/monarchTokensProvider.spec.ts index caaedee9a4..711e7bba49 100644 --- a/redisinsight/ui/src/utils/tests/monaco/cyber/monarchTokensProvider.spec.ts +++ b/redisinsight/ui/src/utils/tests/monaco/cyber/monarchTokensProvider.spec.ts @@ -1,6 +1,8 @@ import { getCypherMonarchTokensProvider } from 'uiSrc/utils/monaco/monarchTokens/cypherTokens' import { getJmespathMonarchTokensProvider } from 'uiSrc/utils/monaco/monarchTokens/jmespathTokens' import { getSqliteFunctionsMonarchTokensProvider } from 'uiSrc/utils/monaco/monarchTokens/sqliteFunctionsTokens' +import { getRediSearchMonarchTokensProvider } from 'uiSrc/utils/monaco/monarchTokens/redisearchTokens' +import { MOCKED_SUPPORTED_COMMANDS } from 'uiSrc/pages/search/mocks/mocks' describe('getCypherMonarchTokensProvider', () => { it('should be truthy', () => { @@ -19,3 +21,18 @@ describe('getSqliteFunctionsMonarchTokensProvider', () => { expect(getSqliteFunctionsMonarchTokensProvider([])).toBeTruthy() }) }) + +describe('getRediSearchMonarchTokensProvider', () => { + it('should be truthy', () => { + expect(getRediSearchMonarchTokensProvider([])).toBeTruthy() + }) + + it('should be truthy with command', () => { + const commands = Object.keys(MOCKED_SUPPORTED_COMMANDS) + .map((key) => ({ + ...MOCKED_SUPPORTED_COMMANDS[key], + name: key + })) + expect(getRediSearchMonarchTokensProvider(commands, 'FT.AGGREGATE')).toBeTruthy() + }) +}) From bd3402cb955566272a9211cb1ce0074c956f5025 Mon Sep 17 00:00:00 2001 From: Roman Sergeenko Date: Tue, 3 Sep 2024 18:27:33 +0200 Subject: [PATCH 043/256] #RI-6026 - remove console.log --- .../ui/src/pages/search/components/query/utils.spec.ts | 5 ----- 1 file changed, 5 deletions(-) diff --git a/redisinsight/ui/src/pages/search/components/query/utils.spec.ts b/redisinsight/ui/src/pages/search/components/query/utils.spec.ts index ded3afcccd..43b8d04254 100644 --- a/redisinsight/ui/src/pages/search/components/query/utils.spec.ts +++ b/redisinsight/ui/src/pages/search/components/query/utils.spec.ts @@ -98,11 +98,6 @@ describe('getGeneralSuggestions', () => { [] ) - console.log(findCurrentArgument( - commands, - ['FT.AGGREGATE', '""', '""'] - )) - expect(testResult).toEqual(result) }) }) From 187b6eacfcb606d8390c1606c608a1785d232bb7 Mon Sep 17 00:00:00 2001 From: Roman Sergeenko Date: Wed, 4 Sep 2024 19:18:55 +0200 Subject: [PATCH 044/256] #RI-6027 - add completion types for query fields --- .../pages/search/components/query/Query.tsx | 13 +++-- .../search/components/query/utils.spec.ts | 51 ++++++++++++++++++- .../pages/search/components/query/utils.ts | 25 +++++++-- 3 files changed, 82 insertions(+), 7 deletions(-) diff --git a/redisinsight/ui/src/pages/search/components/query/Query.tsx b/redisinsight/ui/src/pages/search/components/query/Query.tsx index dc8ce60263..5e7daef53e 100644 --- a/redisinsight/ui/src/pages/search/components/query/Query.tsx +++ b/redisinsight/ui/src/pages/search/components/query/Query.tsx @@ -238,14 +238,21 @@ const Query = (props: Props) => { setSelectedIndex(allArgs[1] || '') setSelectedCommand(commandName) + const foundArg = findCurrentArgument(COMMANDS_LIST, beforeOffsetArgs) if (prevCursorChar === FIELD_START_SYMBOL) { helpWidgetRef.current.isOpen = false - return asSuggestionsRef(getFieldsSuggestions(attributesRef.current, range), false) + return asSuggestionsRef( + getFieldsSuggestions( + attributesRef.current, + range, + false, + foundArg?.stopArg?.name === DefinedArgumentName.query + ), + false + ) } const cursorContext: CursorContext = { ...cursor, currentOffsetArg, offset } - const foundArg = findCurrentArgument(COMMANDS_LIST, beforeOffsetArgs) - switch (foundArg?.stopArg?.name) { case DefinedArgumentName.index: { return handleIndexSuggestions(command, foundArg, prevArgs.length, currentOffsetArg, range) diff --git a/redisinsight/ui/src/pages/search/components/query/utils.spec.ts b/redisinsight/ui/src/pages/search/components/query/utils.spec.ts index 43b8d04254..9e08a40283 100644 --- a/redisinsight/ui/src/pages/search/components/query/utils.spec.ts +++ b/redisinsight/ui/src/pages/search/components/query/utils.spec.ts @@ -1,4 +1,9 @@ -import { getGeneralSuggestions, isIndexComplete } from 'uiSrc/pages/search/components/query/utils' +import { + addFieldAttribute, + getFieldsSuggestions, + getGeneralSuggestions, + isIndexComplete +} from 'uiSrc/pages/search/components/query/utils' import { MOCKED_SUPPORTED_COMMANDS } from 'uiSrc/pages/search/mocks/mocks' import { addOwnTokenToArgs, buildSuggestion, findCurrentArgument } from 'uiSrc/pages/search/utils' import { SearchCommand, TokenType } from 'uiSrc/pages/search/types' @@ -122,3 +127,47 @@ describe('isIndexComplete', () => { expect(testResult).toEqual(result) }) }) + +const mockedFields = [ + { identifier: 'name', attribute: 'name', type: 'TEXT', WEIGHT: '1', SORTABLE: true, NOSTEM: true }, + { identifier: 'description', attribute: 'description', type: 'TEXT', WEIGHT: '1' }, + { identifier: 'class', attribute: 'class', type: 'TAG', SEPARATOR: ',' }, + { identifier: 'type', attribute: 'type', type: 'TAG', SEPARATOR: ';' }, + { identifier: 'address_city', attribute: 'city', type: 'TAG', SEPARATOR: ',' }, + { identifier: 'address_street', attribute: 'address', type: 'TEXT', WEIGHT: '1', NOSTEM: true }, + { identifier: 'students', attribute: 'students', type: 'NUMERIC', SORTABLE: true }, + { identifier: 'location', attribute: 'location', type: 'GEO' } +] + +const getFieldsSuggestionsTests = [ + [ + [mockedFields, {}], + mockedFields.map((field) => ({ + detail: field.attribute, + insertText: field.attribute, + insertTextRules: 4, + kind: undefined, + label: field.attribute, + range: expect.any(Object), + })) + ], + [ + [mockedFields, {}, false, true], + mockedFields.map((field) => ({ + detail: field.attribute, + insertText: addFieldAttribute(field.attribute, field.type), + insertTextRules: 4, + kind: undefined, + label: field.attribute, + range: expect.any(Object), + })) + ], +] + +describe('getFieldsSuggestions', () => { + it.each(getFieldsSuggestionsTests)('should properly return value for %s', (input, result) => { + const testResult = getFieldsSuggestions(...input) + + expect(testResult).toEqual(result) + }) +}) diff --git a/redisinsight/ui/src/pages/search/components/query/utils.ts b/redisinsight/ui/src/pages/search/components/query/utils.ts index 3c3def04ed..16035f2641 100644 --- a/redisinsight/ui/src/pages/search/components/query/utils.ts +++ b/redisinsight/ui/src/pages/search/components/query/utils.ts @@ -35,9 +35,28 @@ export const getIndexesSuggestions = (indexes: RedisResponseBuffer[], range: mon } }) -export const getFieldsSuggestions = (fields: any[], range: monaco.IRange, spaceAfter = false) => - fields.map(({ attribute }) => { - const insertText = attribute.trim() ? attribute : `"${attribute}"` +export const addFieldAttribute = (attribute: string, type: string) => { + switch (type) { + case 'TAG': return `${attribute}:{\${1:tag}}` + case 'TEXT': return `${attribute}:(\${1:term})` + case 'NUMERIC': return `${attribute}:[\${1:range}]` + case 'GEO': return `${attribute}:[\${1:lon} \${2:lat} \${3:radius} \${4:unit}]` + case 'VECTOR': return `${attribute} \${1:vector}` + default: return attribute + } +} + +export const getFieldsSuggestions = ( + fields: any[], + range: monaco.IRange, + spaceAfter = false, + withType = false +) => + fields.map((field) => { + const { attribute, type } = field + const attibuteText = attribute.trim() ? attribute : `\\"${attribute}\\"` + const insertText = withType ? addFieldAttribute(attibuteText, type) : attibuteText + // const insertText = attibuteText return { label: attribute || ' ', kind: monacoEditor.languages.CompletionItemKind.Reference, From 083adc3d783377c647eb6df8b8d3258f69c6d785 Mon Sep 17 00:00:00 2001 From: Roman Sergeenko Date: Wed, 4 Sep 2024 19:20:24 +0200 Subject: [PATCH 045/256] #RI-6027 - remove commented code --- redisinsight/ui/src/pages/search/components/query/utils.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/redisinsight/ui/src/pages/search/components/query/utils.ts b/redisinsight/ui/src/pages/search/components/query/utils.ts index 16035f2641..6519932cbc 100644 --- a/redisinsight/ui/src/pages/search/components/query/utils.ts +++ b/redisinsight/ui/src/pages/search/components/query/utils.ts @@ -56,7 +56,7 @@ export const getFieldsSuggestions = ( const { attribute, type } = field const attibuteText = attribute.trim() ? attribute : `\\"${attribute}\\"` const insertText = withType ? addFieldAttribute(attibuteText, type) : attibuteText - // const insertText = attibuteText + return { label: attribute || ' ', kind: monacoEditor.languages.CompletionItemKind.Reference, From 3e9bf7bb07770c0b299ac9e0a813f81afb9d913b Mon Sep 17 00:00:00 2001 From: vlad-dargel Date: Fri, 6 Sep 2024 18:13:40 +0200 Subject: [PATCH 046/256] add profile and explain tests --- .../search-and-query-tab.e2e.ts | 92 ++++++++++++++++++- 1 file changed, 89 insertions(+), 3 deletions(-) diff --git a/tests/e2e/tests/web/regression/search-and-query/search-and-query-tab.e2e.ts b/tests/e2e/tests/web/regression/search-and-query/search-and-query-tab.e2e.ts index ff3a339217..abdbdd2930 100644 --- a/tests/e2e/tests/web/regression/search-and-query/search-and-query-tab.e2e.ts +++ b/tests/e2e/tests/web/regression/search-and-query/search-and-query-tab.e2e.ts @@ -88,7 +88,9 @@ test('Verify full commands suggestions with index and query for FT.AGGREGATE', a // Verify basic commands suggestions FT.SEARCH and FT.AGGREGATE await t.typeText(searchAndQueryPage.queryInput, 'FT', { replace: true }); // Verify that the list with FT.SEARCH and FT.AGGREGATE auto-suggestions is displayed - await t.expect(searchAndQueryPage.MonacoEditor.monacoSuggestion.count).eql(2, 'FT.SEARCH and FT.AGGREGATE auto-suggestions are not displayed'); + await t.expect(searchAndQueryPage.MonacoEditor.monacoSuggestion.withText('FT.SEARCH').exists).ok('FT.SEARCH auto-suggestions are not displayed'); + await t.expect(searchAndQueryPage.MonacoEditor.monacoSuggestion.withText('FT.AGGREGATE').exists).ok('FT.AGGREGATE auto-suggestions are not displayed'); + // Select command and check result await t.pressKey('enter'); let script = await searchAndQueryPage.queryInputScriptArea.textContent; @@ -146,9 +148,8 @@ test('Verify full commands suggestions with index and query for FT.AGGREGATE', a }); test('Verify full commands suggestions with index and query for FT.SEARCH', async t => { await browserPage.KeysInteractionPanel.setActiveTab(KeysInteractionTabs.SearchAndQuery); - await t.typeText(searchAndQueryPage.queryInput, 'FT', { replace: true }); + await t.typeText(searchAndQueryPage.queryInput, 'FT.SE', { replace: true }); // Select command and check result - await t.pressKey('down'); await t.pressKey('enter'); const script = await searchAndQueryPage.queryInputScriptArea.textContent; await t.expect(script.replace(/\s/g, ' ')).contains('FT.SEARCH ', 'Result of sent command exists'); @@ -178,3 +179,88 @@ test('Verify full commands suggestions with index and query for FT.SEARCH', asyn // Verify that 'No suggestions' tooltip is displayed when returning to invalid typing like WRONGCOMMAND await t.expect(searchAndQueryPage.MonacoEditor.monacoSuggestWidget.textContent).contains('No suggestions.', 'Index not auto-suggested'); }); +test('Verify full commands suggestions with index and query for FT.PROFILE(SEARCH)', async t => { + await browserPage.KeysInteractionPanel.setActiveTab(KeysInteractionTabs.SearchAndQuery); + await t.typeText(searchAndQueryPage.queryInput, 'FT.PR', { replace: true }); + // Select command and check result + await t.pressKey('enter'); + const script = await searchAndQueryPage.queryInputScriptArea.textContent; + await t.expect(script.replace(/\s/g, ' ')).contains('FT.PROFILE ', 'Result of sent command exists'); + + await t.pressKey('tab'); + await t.expect(searchAndQueryPage.MonacoEditor.monacoSuggestion.withExactText('AGGREGATE').exists).ok('FT.PROFILE aggregate argument not suggested'); + await t.expect(searchAndQueryPage.MonacoEditor.monacoSuggestion.withExactText('SEARCH').exists).ok('FT.PROFILE search argument not suggested'); + + // Select SEARCH command + await t.typeText(searchAndQueryPage.queryInput, 'SEA', { replace: false }); + await t.pressKey('enter'); + await t.expect(searchAndQueryPage.MonacoEditor.monacoSuggestion.withExactText('LIMITED').exists).ok('FT.PROFILE SEARCH arguments not suggested'); + await t.expect(searchAndQueryPage.MonacoEditor.monacoSuggestion.withExactText('QUERY').exists).ok('FT.PROFILE SEARCH arguments not suggested'); + + // Select QUERY + await t.typeText(searchAndQueryPage.queryInput, 'QUE', { replace: false }); + await t.pressKey('enter'); + await t.typeText(searchAndQueryPage.queryInput, '@c', { replace: false }); + // Select '@city' field + await t.pressKey('down'); + await t.pressKey('tab'); + await t.pressKey('right'); + await t.pressKey('space'); + // Verify that there are no more suggestions + await t.expect(searchAndQueryPage.MonacoEditor.monacoSuggestion.exists).notOk('Additional invalid commands suggested'); + const expectedText = `FT.PROFILE "${indexName1}" SEARCH QUERY "@city"`.trim().replace(/\s+/g, ' '); + // Verify command entered correctly + await t.expect((await searchAndQueryPage.queryInputForText.innerText).trim().replace(/\s+/g, ' ')).contains(expectedText, 'Incorrect order of entered arguments'); +}); +test('Verify full commands suggestions with index and query for FT.PROFILE(AGGREGATE)', async t => { + await browserPage.KeysInteractionPanel.setActiveTab(KeysInteractionTabs.SearchAndQuery); + await t.typeText(searchAndQueryPage.queryInput, 'FT.PR', { replace: true }); + // Select command and check result + await t.pressKey('enter'); + await t.pressKey('tab'); + // Select AGGREGATE command + await t.typeText(searchAndQueryPage.queryInput, 'AGG', { replace: false }); + await t.pressKey('enter'); + await t.expect(searchAndQueryPage.MonacoEditor.monacoSuggestion.withExactText('LIMITED').exists).ok('FT.PROFILE AGGREGATE arguments not suggested'); + await t.expect(searchAndQueryPage.MonacoEditor.monacoSuggestion.withExactText('QUERY').exists).ok('FT.PROFILE AGGREGATE arguments not suggested'); + + // Select QUERY + await t.typeText(searchAndQueryPage.queryInput, 'QUE', { replace: false }); + await t.pressKey('enter'); + await t.typeText(searchAndQueryPage.queryInput, '@c', { replace: false }); + // Select '@city' field + await t.pressKey('down'); + await t.pressKey('tab'); + await t.pressKey('right'); + await t.pressKey('space'); + // Verify that there are no more suggestions + await t.expect(searchAndQueryPage.MonacoEditor.monacoSuggestion.exists).notOk('Additional invalid commands suggested'); + const expectedText = `FT.PROFILE "${indexName1}" AGGREGATE QUERY "@city"`.trim().replace(/\s+/g, ' '); + // Verify command entered correctly + await t.expect((await searchAndQueryPage.queryInputForText.innerText).trim().replace(/\s+/g, ' ')).contains(expectedText, 'Incorrect order of entered arguments'); +}); +test('Verify full commands suggestions with index and query for FT.EXPLAIN', async t => { + await browserPage.KeysInteractionPanel.setActiveTab(KeysInteractionTabs.SearchAndQuery); + await t.typeText(searchAndQueryPage.queryInput, 'FT.EX', { replace: true }); + // Select command and check result + await t.pressKey('enter'); + await t.pressKey('tab'); + + await t.typeText(searchAndQueryPage.queryInput, '@c', { replace: false }); + // Select '@city' field + await t.pressKey('down'); + await t.pressKey('tab'); + await t.pressKey('right'); + await t.pressKey('space'); + + await t.expect(searchAndQueryPage.MonacoEditor.monacoSuggestion.withExactText('DIALECT').exists).ok('FT.EXPLAIN arguments not suggested'); + // Add DIALECT + await t.pressKey('enter'); + await t.typeText(searchAndQueryPage.queryInput, 'dialectTest', { replace: false }); + // Verify that there are no more suggestions + await t.pressKey('space'); + await t.expect(searchAndQueryPage.MonacoEditor.monacoSuggestion.exists).notOk('Additional invalid commands suggested'); + const expectedText = `FT.EXPLAIN "${indexName1}" "@city" DIALECT dialectTest`.trim().replace(/\s+/g, ' '); + // Verify command entered correctly + await t.expect((await searchAndQueryPage.queryInputForText.innerText).trim().replace(/\s+/g, ' ')).contains(expectedText, 'Incorrect order of entered arguments'); +}); From 8754910e35ffc88dc4eae86870d7e0da8f62e6c0 Mon Sep 17 00:00:00 2001 From: vlad-dargel Date: Mon, 9 Sep 2024 09:40:01 +0200 Subject: [PATCH 047/256] fixes --- .../search-and-query-tab.e2e.ts | 30 +++++++++++-------- 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/tests/e2e/tests/web/regression/search-and-query/search-and-query-tab.e2e.ts b/tests/e2e/tests/web/regression/search-and-query/search-and-query-tab.e2e.ts index abdbdd2930..b51b417049 100644 --- a/tests/e2e/tests/web/regression/search-and-query/search-and-query-tab.e2e.ts +++ b/tests/e2e/tests/web/regression/search-and-query/search-and-query-tab.e2e.ts @@ -72,7 +72,7 @@ test('Verify that user can use show more to see command fully in 2nd tooltip', a await t.expect(searchAndQueryPage.MonacoEditor.monacoCommandDetails.exists).notOk('The "read more" about the command is not closed'); }); test('Verify full commands suggestions with index and query for FT.AGGREGATE', async t => { - const groupByArgInfo = 'GROUPBY nargs property [property ...] [REDUCE function nargs arg [arg ...] [AS name] [REDUCE function nargs arg [arg ...] [AS name] ...]]'; + const groupByArgInfo = 'GROUPBY nargs property [property ...] [REDUCE '; const indexFields = [ 'address', 'city', @@ -102,6 +102,7 @@ test('Verify full commands suggestions with index and query for FT.AGGREGATE', a await t.expect(searchAndQueryPage.MonacoEditor.monacoSuggestion.withExactText(indexName2).exists).ok('All indexes not auto-suggested'); await t.pressKey('tab'); + await t.wait(200); await t.typeText(searchAndQueryPage.queryInput, '@', { replace: false }); script = await searchAndQueryPage.queryInputScriptArea.textContent; // Verify that user can see the list of fields from the index selected when type in “@” @@ -110,7 +111,7 @@ test('Verify full commands suggestions with index and query for FT.AGGREGATE', a await t.expect(searchAndQueryPage.MonacoEditor.monacoSuggestion.withExactText(field).exists).ok(`${field} Index field not auto-suggested`); } // Verify that user can use autosuggestions by typing fields from index after "@" - await t.typeText(searchAndQueryPage.queryInput, 'c', { replace: false }); + await t.typeText(searchAndQueryPage.queryInput, 'ci', { replace: false }); await t.expect(searchAndQueryPage.MonacoEditor.monacoSuggestion.withExactText('city').exists).ok('Index field not auto-suggested after starting typing'); await t.expect(searchAndQueryPage.MonacoEditor.monacoSuggestion.count).eql(1, 'Wrong index fields suggested after typing first letter'); @@ -124,7 +125,7 @@ test('Verify full commands suggestions with index and query for FT.AGGREGATE', a await t.pressKey('tab'); // Verify that user can see widget about entered argument - await t.expect(searchAndQueryPage.MonacoEditor.monacoHintWithArguments.withText(groupByArgInfo).exists).ok('Widget with info about entered argument not displayed'); + await t.expect(searchAndQueryPage.MonacoEditor.monacoHintWithArguments.textContent).contains(groupByArgInfo, 'Widget with info about entered argument not displayed'); await t.typeText(searchAndQueryPage.queryInput, '1 "London"', { replace: false }); await t.pressKey('space'); @@ -140,6 +141,7 @@ test('Verify full commands suggestions with index and query for FT.AGGREGATE', a await t.typeText(searchAndQueryPage.queryInput, 'stud', { replace: false }); await t.pressKey('space'); + await t.debug(); // Verify multiple argument option suggestions await t.expect(searchAndQueryPage.MonacoEditor.monacoSuggestion.nth(0).textContent).contains('REDUCE', 'Incorrect order of suggested arguments'); // Verify complex command sequences like nargs and properties are suggested accurately for GROUPBY @@ -155,9 +157,11 @@ test('Verify full commands suggestions with index and query for FT.SEARCH', asyn await t.expect(script.replace(/\s/g, ' ')).contains('FT.SEARCH ', 'Result of sent command exists'); await t.pressKey('tab'); - await t.typeText(searchAndQueryPage.queryInput, '@c', { replace: false }); + await t.wait(200); + await t.typeText(searchAndQueryPage.queryInput, '@', { replace: false }); + await t.expect(searchAndQueryPage.MonacoEditor.monacoSuggestion.visible).ok('Suggestions not displayed'); + await t.typeText(searchAndQueryPage.queryInput, 'ci', { replace: false }); // Select '@city' field - await t.pressKey('down'); await t.pressKey('tab'); await t.pressKey('right'); await t.pressKey('space'); @@ -200,9 +204,10 @@ test('Verify full commands suggestions with index and query for FT.PROFILE(SEARC // Select QUERY await t.typeText(searchAndQueryPage.queryInput, 'QUE', { replace: false }); await t.pressKey('enter'); - await t.typeText(searchAndQueryPage.queryInput, '@c', { replace: false }); + await t.typeText(searchAndQueryPage.queryInput, '@', { replace: false }); + await t.expect(searchAndQueryPage.MonacoEditor.monacoSuggestion.visible).ok('Suggestions not displayed'); + await t.typeText(searchAndQueryPage.queryInput, 'ci', { replace: false }); // Select '@city' field - await t.pressKey('down'); await t.pressKey('tab'); await t.pressKey('right'); await t.pressKey('space'); @@ -227,9 +232,10 @@ test('Verify full commands suggestions with index and query for FT.PROFILE(AGGRE // Select QUERY await t.typeText(searchAndQueryPage.queryInput, 'QUE', { replace: false }); await t.pressKey('enter'); - await t.typeText(searchAndQueryPage.queryInput, '@c', { replace: false }); + await t.typeText(searchAndQueryPage.queryInput, '@', { replace: false }); + await t.expect(searchAndQueryPage.MonacoEditor.monacoSuggestion.visible).ok('Suggestions not displayed'); + await t.typeText(searchAndQueryPage.queryInput, 'ci', { replace: false }); // Select '@city' field - await t.pressKey('down'); await t.pressKey('tab'); await t.pressKey('right'); await t.pressKey('space'); @@ -245,10 +251,10 @@ test('Verify full commands suggestions with index and query for FT.EXPLAIN', asy // Select command and check result await t.pressKey('enter'); await t.pressKey('tab'); - - await t.typeText(searchAndQueryPage.queryInput, '@c', { replace: false }); + await t.typeText(searchAndQueryPage.queryInput, '@', { replace: false }); + await t.expect(searchAndQueryPage.MonacoEditor.monacoSuggestion.visible).ok('Suggestions not displayed'); + await t.typeText(searchAndQueryPage.queryInput, 'ci', { replace: false }); // Select '@city' field - await t.pressKey('down'); await t.pressKey('tab'); await t.pressKey('right'); await t.pressKey('space'); From e687014db99a151e3a4dccb7f4d78a3d74943af3 Mon Sep 17 00:00:00 2001 From: vlad-dargel Date: Mon, 9 Sep 2024 10:27:07 +0200 Subject: [PATCH 048/256] add waiter because of slow work of suggestions --- .../regression/search-and-query/search-and-query-tab.e2e.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/e2e/tests/web/regression/search-and-query/search-and-query-tab.e2e.ts b/tests/e2e/tests/web/regression/search-and-query/search-and-query-tab.e2e.ts index b51b417049..088674bcf4 100644 --- a/tests/e2e/tests/web/regression/search-and-query/search-and-query-tab.e2e.ts +++ b/tests/e2e/tests/web/regression/search-and-query/search-and-query-tab.e2e.ts @@ -204,6 +204,7 @@ test('Verify full commands suggestions with index and query for FT.PROFILE(SEARC // Select QUERY await t.typeText(searchAndQueryPage.queryInput, 'QUE', { replace: false }); await t.pressKey('enter'); + await t.wait(200); await t.typeText(searchAndQueryPage.queryInput, '@', { replace: false }); await t.expect(searchAndQueryPage.MonacoEditor.monacoSuggestion.visible).ok('Suggestions not displayed'); await t.typeText(searchAndQueryPage.queryInput, 'ci', { replace: false }); @@ -232,6 +233,7 @@ test('Verify full commands suggestions with index and query for FT.PROFILE(AGGRE // Select QUERY await t.typeText(searchAndQueryPage.queryInput, 'QUE', { replace: false }); await t.pressKey('enter'); + await t.wait(200); await t.typeText(searchAndQueryPage.queryInput, '@', { replace: false }); await t.expect(searchAndQueryPage.MonacoEditor.monacoSuggestion.visible).ok('Suggestions not displayed'); await t.typeText(searchAndQueryPage.queryInput, 'ci', { replace: false }); @@ -251,6 +253,7 @@ test('Verify full commands suggestions with index and query for FT.EXPLAIN', asy // Select command and check result await t.pressKey('enter'); await t.pressKey('tab'); + await t.wait(200); await t.typeText(searchAndQueryPage.queryInput, '@', { replace: false }); await t.expect(searchAndQueryPage.MonacoEditor.monacoSuggestion.visible).ok('Suggestions not displayed'); await t.typeText(searchAndQueryPage.queryInput, 'ci', { replace: false }); From b782852e9501c0031f8369c041714aed9dfcc087 Mon Sep 17 00:00:00 2001 From: vlad-dargel Date: Mon, 9 Sep 2024 11:59:56 +0200 Subject: [PATCH 049/256] add env variable for local --- tests/e2e/local.web.docker-compose.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/e2e/local.web.docker-compose.yml b/tests/e2e/local.web.docker-compose.yml index 69db32bc4a..788a88304e 100644 --- a/tests/e2e/local.web.docker-compose.yml +++ b/tests/e2e/local.web.docker-compose.yml @@ -43,9 +43,10 @@ services: env_file: - ./.env environment: - RI_ENCRYPTION_KEY: $E2E_RI_ENCRYPTION_KEY + RI_ENCRYPTION_KEY: $RI_ENCRYPTION_KEY RI_SERVER_TLS_CERT: $RI_SERVER_TLS_CERT RI_SERVER_TLS_KEY: $RI_SERVER_TLS_KEY + BUILD_TYPE: DOCKER_ON_PREMISE volumes: - ./rihomedir:/data - tmp:/tmp From ed29703fe491bf1afd5d58e5a8ee3c471e79d44e Mon Sep 17 00:00:00 2001 From: vlad-dargel Date: Mon, 9 Sep 2024 12:00:38 +0200 Subject: [PATCH 050/256] add env --- tests/e2e/.env | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/e2e/.env b/tests/e2e/.env index 509b8704a1..9242dec68e 100644 --- a/tests/e2e/.env +++ b/tests/e2e/.env @@ -1,5 +1,6 @@ COMMON_URL=https://app:5540 API_URL=https://app:5540/api +BUILD_TYPE=DOCKER_ON_PREMISE OSS_SENTINEL_PASSWORD=password RI_NOTIFICATION_UPDATE_URL=https://s3.amazonaws.com/redisinsight.test/public/tests/e2e/notifications.json RI_NOTIFICATION_SYNC_INTERVAL=30000 From 6698ebef0251b6f7d10d6deaa5eb8602c8c962ac Mon Sep 17 00:00:00 2001 From: vlad-dargel Date: Mon, 9 Sep 2024 12:13:50 +0200 Subject: [PATCH 051/256] add method for selecting query --- .../e2e/pageObjects/search-and-query-page.ts | 15 ++++++++ .../search-and-query-tab.e2e.ts | 35 +++---------------- 2 files changed, 19 insertions(+), 31 deletions(-) diff --git a/tests/e2e/pageObjects/search-and-query-page.ts b/tests/e2e/pageObjects/search-and-query-page.ts index 2b6ba80d21..7943ca5131 100644 --- a/tests/e2e/pageObjects/search-and-query-page.ts +++ b/tests/e2e/pageObjects/search-and-query-page.ts @@ -1,5 +1,20 @@ +import { t } from 'testcafe'; import { BaseRunCommandsPage } from './base-run-commands-page'; export class SearchAndQueryPage extends BaseRunCommandsPage { + /** + * Select query using autosuggest + * @param query Value of query + */ + async selectQueryUsingAutosuggest(value: string): Promise { + await t.wait(200); + await t.typeText(this.queryInput, '@', { replace: false }); + await t.expect(this.MonacoEditor.monacoSuggestion.visible).ok('Suggestions not displayed'); + await t.typeText(this.queryInput, value, { replace: false }); + // Select query option into autosuggest and go out of quotes + await t.pressKey('tab'); + await t.pressKey('right'); + await t.pressKey('space'); + } } diff --git a/tests/e2e/tests/web/regression/search-and-query/search-and-query-tab.e2e.ts b/tests/e2e/tests/web/regression/search-and-query/search-and-query-tab.e2e.ts index 088674bcf4..1b50e224be 100644 --- a/tests/e2e/tests/web/regression/search-and-query/search-and-query-tab.e2e.ts +++ b/tests/e2e/tests/web/regression/search-and-query/search-and-query-tab.e2e.ts @@ -157,14 +157,8 @@ test('Verify full commands suggestions with index and query for FT.SEARCH', asyn await t.expect(script.replace(/\s/g, ' ')).contains('FT.SEARCH ', 'Result of sent command exists'); await t.pressKey('tab'); - await t.wait(200); - await t.typeText(searchAndQueryPage.queryInput, '@', { replace: false }); - await t.expect(searchAndQueryPage.MonacoEditor.monacoSuggestion.visible).ok('Suggestions not displayed'); - await t.typeText(searchAndQueryPage.queryInput, 'ci', { replace: false }); // Select '@city' field - await t.pressKey('tab'); - await t.pressKey('right'); - await t.pressKey('space'); + await searchAndQueryPage.selectQueryUsingAutosuggest('city'); await t.expect(searchAndQueryPage.MonacoEditor.monacoSuggestion.withExactText('DIALECT').exists).ok('FT.SEARCH arguments not suggested'); await t.typeText(searchAndQueryPage.queryInput, 'n', { replace: false }); await t.expect(searchAndQueryPage.MonacoEditor.monacoSuggestion.nth(0).textContent).contains('NOCONTENT', 'Argument not suggested after typing first letters'); @@ -204,14 +198,7 @@ test('Verify full commands suggestions with index and query for FT.PROFILE(SEARC // Select QUERY await t.typeText(searchAndQueryPage.queryInput, 'QUE', { replace: false }); await t.pressKey('enter'); - await t.wait(200); - await t.typeText(searchAndQueryPage.queryInput, '@', { replace: false }); - await t.expect(searchAndQueryPage.MonacoEditor.monacoSuggestion.visible).ok('Suggestions not displayed'); - await t.typeText(searchAndQueryPage.queryInput, 'ci', { replace: false }); - // Select '@city' field - await t.pressKey('tab'); - await t.pressKey('right'); - await t.pressKey('space'); + await searchAndQueryPage.selectQueryUsingAutosuggest('city'); // Verify that there are no more suggestions await t.expect(searchAndQueryPage.MonacoEditor.monacoSuggestion.exists).notOk('Additional invalid commands suggested'); const expectedText = `FT.PROFILE "${indexName1}" SEARCH QUERY "@city"`.trim().replace(/\s+/g, ' '); @@ -233,14 +220,7 @@ test('Verify full commands suggestions with index and query for FT.PROFILE(AGGRE // Select QUERY await t.typeText(searchAndQueryPage.queryInput, 'QUE', { replace: false }); await t.pressKey('enter'); - await t.wait(200); - await t.typeText(searchAndQueryPage.queryInput, '@', { replace: false }); - await t.expect(searchAndQueryPage.MonacoEditor.monacoSuggestion.visible).ok('Suggestions not displayed'); - await t.typeText(searchAndQueryPage.queryInput, 'ci', { replace: false }); - // Select '@city' field - await t.pressKey('tab'); - await t.pressKey('right'); - await t.pressKey('space'); + await searchAndQueryPage.selectQueryUsingAutosuggest('city'); // Verify that there are no more suggestions await t.expect(searchAndQueryPage.MonacoEditor.monacoSuggestion.exists).notOk('Additional invalid commands suggested'); const expectedText = `FT.PROFILE "${indexName1}" AGGREGATE QUERY "@city"`.trim().replace(/\s+/g, ' '); @@ -253,14 +233,7 @@ test('Verify full commands suggestions with index and query for FT.EXPLAIN', asy // Select command and check result await t.pressKey('enter'); await t.pressKey('tab'); - await t.wait(200); - await t.typeText(searchAndQueryPage.queryInput, '@', { replace: false }); - await t.expect(searchAndQueryPage.MonacoEditor.monacoSuggestion.visible).ok('Suggestions not displayed'); - await t.typeText(searchAndQueryPage.queryInput, 'ci', { replace: false }); - // Select '@city' field - await t.pressKey('tab'); - await t.pressKey('right'); - await t.pressKey('space'); + await searchAndQueryPage.selectQueryUsingAutosuggest('city'); await t.expect(searchAndQueryPage.MonacoEditor.monacoSuggestion.withExactText('DIALECT').exists).ok('FT.EXPLAIN arguments not suggested'); // Add DIALECT From e9bf2ee1f6796d8a874f5a33df214bdb90c1bab3 Mon Sep 17 00:00:00 2001 From: Roman Sergeenko Date: Mon, 9 Sep 2024 12:14:04 +0200 Subject: [PATCH 052/256] #RI-6091 - fix highlighting #RI-6093 - fix expression suggestions --- redisinsight/ui/src/pages/search/components/query/Query.tsx | 4 +++- .../ui/src/utils/monaco/monarchTokens/redisearchTokens.ts | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/redisinsight/ui/src/pages/search/components/query/Query.tsx b/redisinsight/ui/src/pages/search/components/query/Query.tsx index dc8ce60263..c9ceeb1c83 100644 --- a/redisinsight/ui/src/pages/search/components/query/Query.tsx +++ b/redisinsight/ui/src/pages/search/components/query/Query.tsx @@ -315,7 +315,9 @@ const Query = (props: Props) => { cursorContext: CursorContext, range: monacoEditor.IRange ) => { - if (foundArg?.stopArg?.expression) return handleExpressionSuggestions(value, foundArg, cursorContext, range) + if (foundArg?.isBlocked && foundArg?.stopArg?.expression) { + return handleExpressionSuggestions(value, foundArg, cursorContext, range) + } const { prevCursorChar, nextCursorChar, isCursorInQuotes } = cursorContext if (isCursorInQuotes || nextCursorChar?.trim()) return asSuggestionsRef([]) diff --git a/redisinsight/ui/src/utils/monaco/monarchTokens/redisearchTokens.ts b/redisinsight/ui/src/utils/monaco/monarchTokens/redisearchTokens.ts index a4814e00c3..323a7be11d 100644 --- a/redisinsight/ui/src/utils/monaco/monarchTokens/redisearchTokens.ts +++ b/redisinsight/ui/src/utils/monaco/monarchTokens/redisearchTokens.ts @@ -61,7 +61,7 @@ export const getRediSearchMonarchTokensProvider = ( index: [ [/"([^"\\]|\\.)*"/, { token: 'index', next: isHighlightQuery ? '@query' : '@root' }], [/'([^'\\]|\\.)*'/, { token: 'index', next: isHighlightQuery ? '@query' : '@root' }], - [/[a-zA-Z_]\w*/, { token: 'index', next: isHighlightQuery ? '@query' : '@root' }], + [/[\w:]+/, { token: 'index', next: isHighlightQuery ? '@query' : '@root' }], { include: 'root' } // Fallback to the root state if nothing matches ], ...generateQuery(), From 7f7b2efa868318d00d7bd104c199a65b903980a3 Mon Sep 17 00:00:00 2001 From: ArtemHoruzhenko Date: Mon, 9 Sep 2024 13:43:20 +0300 Subject: [PATCH 053/256] init implementation --- .../dto/create-command-execution.dto.ts | 56 ++----------- .../dto/create-command-executions.dto.ts | 34 ++------ .../entities/command-execution.entity.ts | 45 +++------- .../models/command-execution-result.ts | 7 +- .../workbench/models/command-execution.ts | 64 ++++++++++++-- .../models/command-executions.filter.ts | 4 + .../src/modules/workbench/plugins.service.ts | 2 +- .../providers/workbench-commands.executor.ts | 3 +- .../command-execution.repository.ts | 51 +++++++++++- .../local-command-execution.repository.ts | 83 ++++++++----------- .../modules/workbench/workbench.controller.ts | 8 +- .../modules/workbench/workbench.service.ts | 18 ++-- 12 files changed, 195 insertions(+), 180 deletions(-) create mode 100644 redisinsight/api/src/modules/workbench/models/command-executions.filter.ts diff --git a/redisinsight/api/src/modules/workbench/dto/create-command-execution.dto.ts b/redisinsight/api/src/modules/workbench/dto/create-command-execution.dto.ts index 50e7388163..9664a64e97 100644 --- a/redisinsight/api/src/modules/workbench/dto/create-command-execution.dto.ts +++ b/redisinsight/api/src/modules/workbench/dto/create-command-execution.dto.ts @@ -1,51 +1,7 @@ -import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger'; -import { - IsEnum, IsNotEmpty, IsOptional, IsString, -} from 'class-validator'; +import { PickType } from '@nestjs/swagger'; +import { CommandExecution } from 'src/modules/workbench/models/command-execution'; -export enum RunQueryMode { - Raw = 'RAW', - ASCII = 'ASCII', -} - -export enum ResultsMode { - Default = 'DEFAULT', - GroupMode = 'GROUP_MODE', - Silent = 'SILENT', -} - -export class CreateCommandExecutionDto { - @ApiProperty({ - type: String, - description: 'Redis command', - }) - @IsString() - @IsNotEmpty() - command: string; - - @ApiPropertyOptional({ - description: 'Workbench mode', - default: RunQueryMode.ASCII, - enum: RunQueryMode, - }) - @IsOptional() - @IsEnum(RunQueryMode, { - message: `mode must be a valid enum value. Valid values: ${Object.values( - RunQueryMode, - )}.`, - }) - mode?: RunQueryMode = RunQueryMode.ASCII; - - @ApiPropertyOptional({ - description: 'Workbench group mode', - default: ResultsMode.Default, - enum: ResultsMode, - }) - @IsOptional() - @IsEnum(ResultsMode, { - message: `resultsMode must be a valid enum value. Valid values: ${Object.values( - ResultsMode, - )}.`, - }) - resultsMode?: ResultsMode; -} +export class CreateCommandExecutionDto extends PickType( + CommandExecution, + ['command', 'mode', 'resultsMode', 'type'] as const, +) {} diff --git a/redisinsight/api/src/modules/workbench/dto/create-command-executions.dto.ts b/redisinsight/api/src/modules/workbench/dto/create-command-executions.dto.ts index f8749e20cd..9ca21174ba 100644 --- a/redisinsight/api/src/modules/workbench/dto/create-command-executions.dto.ts +++ b/redisinsight/api/src/modules/workbench/dto/create-command-executions.dto.ts @@ -1,39 +1,23 @@ -import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger'; +import { ApiProperty, PickType } from '@nestjs/swagger'; import { - IsEnum, IsArray, IsDefined, IsOptional, IsString, ArrayNotEmpty, + IsArray, IsDefined, IsString, ArrayNotEmpty, } from 'class-validator'; -import { RunQueryMode, ResultsMode } from './create-command-execution.dto'; +import { CommandExecution } from 'src/modules/workbench/models/command-execution'; +import { Expose } from 'class-transformer'; -export class CreateCommandExecutionsDto { +export class CreateCommandExecutionsDto extends PickType( + CommandExecution, + ['mode', 'resultsMode', 'type'] as const, +) { @ApiProperty({ isArray: true, type: String, description: 'Redis commands', }) + @Expose() @IsArray() @ArrayNotEmpty() @IsDefined() @IsString({ each: true }) commands: string[]; - - @ApiPropertyOptional({ - description: 'Workbench mode', - default: RunQueryMode.ASCII, - enum: RunQueryMode, - }) - @IsOptional() - @IsEnum(RunQueryMode, { - message: `mode must be a valid enum value. Valid values: ${Object.values( - RunQueryMode, - )}.`, - }) - mode?: RunQueryMode = RunQueryMode.ASCII; - - @IsOptional() - @IsEnum(ResultsMode, { - message: `resultsMode must be a valid enum value. Valid values: ${Object.values( - ResultsMode, - )}.`, - }) - resultsMode?: ResultsMode; } diff --git a/redisinsight/api/src/modules/workbench/entities/command-execution.entity.ts b/redisinsight/api/src/modules/workbench/entities/command-execution.entity.ts index ec060896a1..09e56ba76f 100644 --- a/redisinsight/api/src/modules/workbench/entities/command-execution.entity.ts +++ b/redisinsight/api/src/modules/workbench/entities/command-execution.entity.ts @@ -2,9 +2,10 @@ import { Column, CreateDateColumn, Entity, ManyToOne, PrimaryGeneratedColumn, JoinColumn, Index, } from 'typeorm'; import { DatabaseEntity } from 'src/modules/database/entities/database.entity'; -import { RunQueryMode, ResultsMode } from 'src/modules/workbench/dto/create-command-execution.dto'; -import { Expose, Transform } from 'class-transformer'; +import { Expose } from 'class-transformer'; import { IsInt, Min } from 'class-validator'; +import { CommandExecutionType, ResultsMode, RunQueryMode } from 'src/modules/workbench/models/command-execution'; +import { DataAsJsonString } from 'src/common/decorators'; @Entity('command_execution') export class CommandExecutionEntity { @@ -24,6 +25,7 @@ export class CommandExecutionEntity { }, ) @JoinColumn({ name: 'databaseId' }) + @Expose() database: DatabaseEntity; @Column({ nullable: false, type: 'text' }) @@ -35,48 +37,27 @@ export class CommandExecutionEntity { mode?: string = RunQueryMode.ASCII; @Column({ nullable: false, type: 'text' }) - @Transform((object) => JSON.stringify(object), { toClassOnly: true }) - @Transform((string) => { - try { - return JSON.parse(string); - } catch (e) { - return undefined; - } - }, { toPlainOnly: true }) + @DataAsJsonString() @Expose() result: string; @Column({ nullable: true }) @Expose() - role?: string = null; + role?: string; @Column({ nullable: true }) @Expose() resultsMode?: string = ResultsMode.Default; @Column({ nullable: true }) - @Transform((object) => JSON.stringify(object), { toClassOnly: true }) - @Transform((string) => { - try { - return JSON.parse(string); - } catch (e) { - return undefined; - } - }, { toPlainOnly: true }) + @DataAsJsonString() @Expose() summary?: string; @Column({ nullable: true }) - @Transform((object) => JSON.stringify(object), { toClassOnly: true }) - @Transform((string) => { - try { - return JSON.parse(string); - } catch (e) { - return undefined; - } - }, { toPlainOnly: true }) + @DataAsJsonString() @Expose() - nodeOptions?: string = null; + nodeOptions?: string; @Column({ nullable: true }) encryption: string; @@ -91,12 +72,12 @@ export class CommandExecutionEntity { @Min(0) db?: number; + @Column({ nullable: false, default: CommandExecutionType.Workbench }) + @Expose() + type?: string = CommandExecutionType.Workbench; + @CreateDateColumn() @Index() @Expose() createdAt: Date; - - constructor(entity: Partial) { - Object.assign(this, entity); - } } diff --git a/redisinsight/api/src/modules/workbench/models/command-execution-result.ts b/redisinsight/api/src/modules/workbench/models/command-execution-result.ts index 2ba5d706a8..51852ef731 100644 --- a/redisinsight/api/src/modules/workbench/models/command-execution-result.ts +++ b/redisinsight/api/src/modules/workbench/models/command-execution-result.ts @@ -1,5 +1,6 @@ import { ApiProperty } from '@nestjs/swagger'; import { CommandExecutionStatus } from 'src/modules/cli/dto/cli.dto'; +import { Expose } from 'class-transformer'; export class CommandExecutionResult { @ApiProperty({ @@ -7,15 +8,13 @@ export class CommandExecutionResult { default: CommandExecutionStatus.Success, enum: CommandExecutionStatus, }) + @Expose() status: CommandExecutionStatus; @ApiProperty({ type: String, description: 'Redis response', }) + @Expose() response: any; - - constructor(partial: Partial = {}) { - Object.assign(this, partial); - } } diff --git a/redisinsight/api/src/modules/workbench/models/command-execution.ts b/redisinsight/api/src/modules/workbench/models/command-execution.ts index d7c0da3041..37d9fafa09 100644 --- a/redisinsight/api/src/modules/workbench/models/command-execution.ts +++ b/redisinsight/api/src/modules/workbench/models/command-execution.ts @@ -1,10 +1,32 @@ import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger'; import { - IsDefined, IsInt, IsOptional, Min, + IsDefined, + IsEnum, + IsInt, + IsNotEmpty, + IsOptional, + IsString, + Min, } from 'class-validator'; import { CommandExecutionResult } from 'src/modules/workbench/models/command-execution-result'; -import { RunQueryMode, ResultsMode } from 'src/modules/workbench/dto/create-command-execution.dto'; -import { Expose } from 'class-transformer'; +import { Expose, Type } from 'class-transformer'; +import { Default } from 'src/common/decorators'; + +export enum RunQueryMode { + Raw = 'RAW', + ASCII = 'ASCII', +} + +export enum ResultsMode { + Default = 'DEFAULT', + GroupMode = 'GROUP_MODE', + Silent = 'SILENT', +} + +export enum CommandExecutionType { + Workbench = 'WORKBENCH', + Search = 'SEARCH', +} export class ResultsSummary { @ApiProperty({ @@ -45,9 +67,11 @@ export class CommandExecution { databaseId: string; @ApiProperty({ - description: 'Redis command executed', + description: 'Redis command', type: String, }) + @IsString() + @IsNotEmpty() @Expose() command: string; @@ -57,7 +81,14 @@ export class CommandExecution { enum: RunQueryMode, }) @Expose() - mode?: RunQueryMode = RunQueryMode.ASCII; + @IsOptional() + @IsEnum(RunQueryMode, { + message: `mode must be a valid enum value. Valid values: ${Object.values( + RunQueryMode, + )}.`, + }) + @Default(RunQueryMode.ASCII) + mode?: RunQueryMode; @ApiPropertyOptional({ description: 'Workbench result mode', @@ -65,7 +96,14 @@ export class CommandExecution { enum: ResultsMode, }) @Expose() - resultsMode?: ResultsMode = ResultsMode.Default; + @IsOptional() + @IsEnum(ResultsMode, { + message: `resultsMode must be a valid enum value. Valid values: ${Object.values( + ResultsMode, + )}.`, + }) + @Default(ResultsMode.Default) + resultsMode?: ResultsMode; @ApiPropertyOptional({ description: 'Workbench executions summary', @@ -79,6 +117,7 @@ export class CommandExecution { type: () => CommandExecutionResult, isArray: true, }) + @Type(() => CommandExecutionResult) @Expose() result: CommandExecutionResult[]; @@ -113,7 +152,14 @@ export class CommandExecution { @IsOptional() db?: number; - constructor(partial: Partial = {}) { - Object.assign(this, partial); - } + @ApiPropertyOptional({ + description: 'Command execution type. Used to distinguish between search and workbench', + default: CommandExecutionType.Workbench, + enum: CommandExecutionType, + }) + @Expose() + @IsOptional() + @IsEnum(CommandExecutionType) + @Default(CommandExecutionType.Workbench) + type?: CommandExecutionType; } diff --git a/redisinsight/api/src/modules/workbench/models/command-executions.filter.ts b/redisinsight/api/src/modules/workbench/models/command-executions.filter.ts new file mode 100644 index 0000000000..0cc3dccbe9 --- /dev/null +++ b/redisinsight/api/src/modules/workbench/models/command-executions.filter.ts @@ -0,0 +1,4 @@ +import { PickType } from '@nestjs/swagger'; +import { CommandExecution } from 'src/modules/workbench/models/command-execution'; + +export class CommandExecutionFilter extends PickType(CommandExecution, ['type'] as const) {} diff --git a/redisinsight/api/src/modules/workbench/plugins.service.ts b/redisinsight/api/src/modules/workbench/plugins.service.ts index dda9d1b02b..8e05865d92 100644 --- a/redisinsight/api/src/modules/workbench/plugins.service.ts +++ b/redisinsight/api/src/modules/workbench/plugins.service.ts @@ -52,7 +52,7 @@ export class PluginsService { return new PluginCommandExecution({ ...dto, databaseId: clientMetadata.databaseId, - result: [new CommandExecutionResult({ + result: [plainToClass(CommandExecutionResult, { response: error.message, status: CommandExecutionStatus.Fail, })], diff --git a/redisinsight/api/src/modules/workbench/providers/workbench-commands.executor.ts b/redisinsight/api/src/modules/workbench/providers/workbench-commands.executor.ts index 1228edbbf9..8f6a30684d 100644 --- a/redisinsight/api/src/modules/workbench/providers/workbench-commands.executor.ts +++ b/redisinsight/api/src/modules/workbench/providers/workbench-commands.executor.ts @@ -11,7 +11,7 @@ import { } from 'src/modules/cli/constants/errors'; import { unknownCommand } from 'src/constants'; import { CommandExecutionResult } from 'src/modules/workbench/models/command-execution-result'; -import { CreateCommandExecutionDto, RunQueryMode } from 'src/modules/workbench/dto/create-command-execution.dto'; +import { CreateCommandExecutionDto } from 'src/modules/workbench/dto/create-command-execution.dto'; import { FormatterManager, FormatterTypes, @@ -20,6 +20,7 @@ import { } from 'src/common/transformers'; import { RedisClient } from 'src/modules/redis/client'; import { getAnalyticsDataFromIndexInfo } from 'src/utils'; +import { RunQueryMode } from 'src/modules/workbench/models/command-execution'; import { WorkbenchAnalyticsService } from '../services/workbench-analytics/workbench-analytics.service'; @Injectable() diff --git a/redisinsight/api/src/modules/workbench/repositories/command-execution.repository.ts b/redisinsight/api/src/modules/workbench/repositories/command-execution.repository.ts index ab13569de4..0125933cab 100644 --- a/redisinsight/api/src/modules/workbench/repositories/command-execution.repository.ts +++ b/redisinsight/api/src/modules/workbench/repositories/command-execution.repository.ts @@ -1,14 +1,61 @@ import { CommandExecution } from 'src/modules/workbench/models/command-execution'; import { ShortCommandExecution } from 'src/modules/workbench/models/short-command-execution'; import { SessionMetadata } from 'src/common/models'; +import { CommandExecutionFilter } from 'src/modules/workbench/models/command-executions.filter'; export abstract class CommandExecutionRepository { + /** + * Create multiple entities + * + * @param sessionMetadata + * @param commandExecutions + */ abstract createMany( sessionMetadata: SessionMetadata, commandExecutions: Partial[], ): Promise; - abstract getList(sessionMetadata: SessionMetadata, databaseId: string): Promise; + + /** + * Fetch only needed fields to show in list to avoid huge decryption work + * + * @param sessionMetadata + * @param databaseId + * @param filter + */ + abstract getList( + sessionMetadata: SessionMetadata, + databaseId: string, + filter: CommandExecutionFilter, + ): Promise; + + /** + * Get single command execution entity, decrypt and convert to model + * + * @param sessionMetadata + * @param databaseId + * @param id + */ abstract getOne(sessionMetadata: SessionMetadata, databaseId: string, id: string): Promise; + + /** + * Delete single item + * + * @param sessionMetadata + * @param databaseId + * @param id + */ abstract delete(sessionMetadata: SessionMetadata, databaseId: string, id: string): Promise; - abstract deleteAll(sessionMetadata: SessionMetadata, databaseId: string): Promise; + + /** + * Delete all items + * + * @param sessionMetadata + * @param databaseId + * @param filter + */ + abstract deleteAll( + sessionMetadata: SessionMetadata, + databaseId: string, + filter: CommandExecutionFilter, + ): Promise; } diff --git a/redisinsight/api/src/modules/workbench/repositories/local-command-execution.repository.ts b/redisinsight/api/src/modules/workbench/repositories/local-command-execution.repository.ts index be0f4c6e05..499ab942bd 100644 --- a/redisinsight/api/src/modules/workbench/repositories/local-command-execution.repository.ts +++ b/redisinsight/api/src/modules/workbench/repositories/local-command-execution.repository.ts @@ -14,6 +14,7 @@ import { CommandExecutionStatus } from 'src/modules/cli/dto/cli.dto'; import { CommandExecutionRepository } from 'src/modules/workbench/repositories/command-execution.repository'; import config from 'src/utils/config'; import { SessionMetadata } from 'src/common/models'; +import { CommandExecutionFilter } from 'src/modules/workbench/models/command-executions.filter'; const WORKBENCH_CONFIG = config.get('workbench'); @@ -29,19 +30,20 @@ export class LocalCommandExecutionRepository extends CommandExecutionRepository private readonly encryptionService: EncryptionService, ) { super(); - this.modelEncryptor = new ModelEncryptor(encryptionService, ['command', 'result']); + this.modelEncryptor = new ModelEncryptor(this.encryptionService, ['command', 'result']); } /** - * Encrypt command executions and save entire entities + * @inheritDoc + * ___ + * Should encrypt command executions * Should always throw and error in case when unable to encrypt for some reason - * @param _ - * @param commandExecutions */ async createMany(_: SessionMetadata, commandExecutions: Partial[]): Promise { // todo: limit by 30 max to insert - let entities = await Promise.all(commandExecutions.map(async (commandExecution) => { + const response = await Promise.all(commandExecutions.map(async (commandExecution, idx) => { const entity = plainToClass(CommandExecutionEntity, commandExecution); + let isNotStored = false; // Do not store command execution result that exceeded limitation if (JSON.stringify(entity.result).length > WORKBENCH_CONFIG.maxResultSize) { @@ -52,31 +54,23 @@ export class LocalCommandExecutionRepository extends CommandExecutionRepository }, ]); // Hack, do not store isNotStored. Send once to show warning - entity['isNotStored'] = true; + isNotStored = true; } - return this.modelEncryptor.encryptEntity(entity); + return classToClass(CommandExecution, { + ...(await this.commandExecutionRepository.save(await this.modelEncryptor.encryptEntity(entity))), + command: commandExecutions[idx].command, // avoid decryption + mode: commandExecutions[idx].mode, + result: commandExecutions[idx].result, // avoid decryption + show original response when it was huge + summary: commandExecutions[idx].summary, + executionTime: commandExecutions[idx].executionTime, + isNotStored, + }); })); - entities = await this.commandExecutionRepository.save(entities); - - const response = await Promise.all( - entities.map((entity, idx) => classToClass( - CommandExecution, - { - ...entity, - command: commandExecutions[idx].command, - mode: commandExecutions[idx].mode, - result: commandExecutions[idx].result, - summary: commandExecutions[idx].summary, - executionTime: commandExecutions[idx].executionTime, - }, - )), - ); - // cleanup history and ignore error if any try { - await this.cleanupDatabaseHistory(entities[0].databaseId); + await this.cleanupDatabaseHistory(response[0].databaseId, { type: commandExecutions[0].type }); } catch (e) { this.logger.error('Error when trying to cleanup history after insert', e); } @@ -85,15 +79,17 @@ export class LocalCommandExecutionRepository extends CommandExecutionRepository } /** - * Fetch only needed fields to show in list to avoid huge decryption work - * @param _ - * @param databaseId + * @inheritDoc */ - async getList(_: SessionMetadata, databaseId: string): Promise { + async getList( + _: SessionMetadata, + databaseId: string, + queryFilter: CommandExecutionFilter, + ): Promise { this.logger.log('Getting command executions'); const entities = await this.commandExecutionRepository .createQueryBuilder('e') - .where({ databaseId }) + .where({ databaseId, type: queryFilter.type }) .select([ 'e.id', 'e.command', @@ -105,6 +101,7 @@ export class LocalCommandExecutionRepository extends CommandExecutionRepository 'e.resultsMode', 'e.executionTime', 'e.db', + 'e.type', ]) .orderBy('e.createdAt', 'DESC') .limit(WORKBENCH_CONFIG.maxItemsPerDb) @@ -127,11 +124,7 @@ export class LocalCommandExecutionRepository extends CommandExecutionRepository } /** - * Get single command execution entity, decrypt and convert to model - * - * @param _ - * @param databaseId - * @param id + * @inheritDoc */ async getOne(_: SessionMetadata, databaseId: string, id: string): Promise { this.logger.log('Getting command executions'); @@ -151,11 +144,7 @@ export class LocalCommandExecutionRepository extends CommandExecutionRepository } /** - * Delete single item - * - * @param _ - * @param databaseId - * @param id + * @inheritDoc */ async delete(_: SessionMetadata, databaseId: string, id: string): Promise { this.logger.log('Delete command execution'); @@ -166,28 +155,26 @@ export class LocalCommandExecutionRepository extends CommandExecutionRepository } /** - * Delete all items - * - * @param _ - * @param databaseId + * @inheritDoc */ - async deleteAll(_: SessionMetadata, databaseId: string): Promise { + async deleteAll(_: SessionMetadata, databaseId: string, queryFilter: CommandExecutionFilter): Promise { this.logger.log('Delete all command executions'); - await this.commandExecutionRepository.delete({ databaseId }); + await this.commandExecutionRepository.delete({ databaseId, type: queryFilter.type }); this.logger.log('Command executions deleted'); } /** - * Clean history for particular database to fit 30 items limitation + * Clean history for particular database to fit N items limitation * @param databaseId + * @param queryFilter */ - private async cleanupDatabaseHistory(databaseId: string): Promise { + private async cleanupDatabaseHistory(databaseId: string, queryFilter: CommandExecutionFilter): Promise { // todo: investigate why delete with sub-query doesn't works const idsToDelete = (await this.commandExecutionRepository .createQueryBuilder() - .where({ databaseId }) + .where({ databaseId, type: queryFilter.type }) .select('id') .orderBy('createdAt', 'DESC') .offset(WORKBENCH_CONFIG.maxItemsPerDb) diff --git a/redisinsight/api/src/modules/workbench/workbench.controller.ts b/redisinsight/api/src/modules/workbench/workbench.controller.ts index 1ba53775df..5803864756 100644 --- a/redisinsight/api/src/modules/workbench/workbench.controller.ts +++ b/redisinsight/api/src/modules/workbench/workbench.controller.ts @@ -6,6 +6,7 @@ import { Get, Param, Post, + Query, UseInterceptors, UsePipes, ValidationPipe, @@ -19,6 +20,7 @@ import { CreateCommandExecutionsDto } from 'src/modules/workbench/dto/create-com import { ShortCommandExecution } from 'src/modules/workbench/models/short-command-execution'; import { ClientMetadata } from 'src/common/models'; import { WorkbenchClientMetadata } from 'src/modules/workbench/decorators/workbench-client-metadata.decorator'; +import { CommandExecutionFilter } from 'src/modules/workbench/models/command-executions.filter'; @ApiTags('Workbench') @UsePipes(new ValidationPipe({ transform: true })) @@ -62,8 +64,9 @@ export class WorkbenchController { @ApiRedisParams() async listCommandExecutions( @WorkbenchClientMetadata() clientMetadata: ClientMetadata, + @Query() filter: CommandExecutionFilter, ): Promise { - return this.service.listCommandExecutions(clientMetadata); + return this.service.listCommandExecutions(clientMetadata, filter); } @ApiEndpoint({ @@ -107,7 +110,8 @@ export class WorkbenchController { @ApiRedisParams() async deleteCommandExecutions( @WorkbenchClientMetadata() clientMetadata: ClientMetadata, + @Body() filter: CommandExecutionFilter, ): Promise { - return this.service.deleteCommandExecutions(clientMetadata); + return this.service.deleteCommandExecutions(clientMetadata, filter); } } diff --git a/redisinsight/api/src/modules/workbench/workbench.service.ts b/redisinsight/api/src/modules/workbench/workbench.service.ts index 2a4a972995..30142a1c8d 100644 --- a/redisinsight/api/src/modules/workbench/workbench.service.ts +++ b/redisinsight/api/src/modules/workbench/workbench.service.ts @@ -2,8 +2,8 @@ import { Injectable } from '@nestjs/common'; import { omit } from 'lodash'; import { ClientMetadata } from 'src/common/models'; import { WorkbenchCommandsExecutor } from 'src/modules/workbench/providers/workbench-commands.executor'; -import { CommandExecution } from 'src/modules/workbench/models/command-execution'; -import { CreateCommandExecutionDto, ResultsMode } from 'src/modules/workbench/dto/create-command-execution.dto'; +import { CommandExecution, ResultsMode } from 'src/modules/workbench/models/command-execution'; +import { CreateCommandExecutionDto } from 'src/modules/workbench/dto/create-command-execution.dto'; import { CreateCommandExecutionsDto } from 'src/modules/workbench/dto/create-command-executions.dto'; import { getBlockingCommands, multilineCommandToOneLine } from 'src/utils/cli-helper'; import ERROR_MESSAGES from 'src/constants/error-messages'; @@ -12,6 +12,7 @@ import { CommandExecutionStatus } from 'src/modules/cli/dto/cli.dto'; import { CommandExecutionRepository } from 'src/modules/workbench/repositories/command-execution.repository'; import { DatabaseClientFactory } from 'src/modules/database/providers/database.client.factory'; import { RedisClient } from 'src/modules/redis/client'; +import { CommandExecutionFilter } from 'src/modules/workbench/models/command-executions.filter'; import { getUnsupportedCommands } from './utils/getUnsupportedCommands'; import { WorkbenchAnalyticsService } from './services/workbench-analytics/workbench-analytics.service'; @@ -160,9 +161,13 @@ export class WorkbenchService { * Get list command execution history per instance (last 30 items) * * @param clientMetadata + * @param filter */ - async listCommandExecutions(clientMetadata: ClientMetadata): Promise { - return this.commandExecutionRepository.getList(clientMetadata.sessionMetadata, clientMetadata.databaseId); + async listCommandExecutions( + clientMetadata: ClientMetadata, + filter: CommandExecutionFilter, + ): Promise { + return this.commandExecutionRepository.getList(clientMetadata.sessionMetadata, clientMetadata.databaseId, filter); } /** @@ -190,9 +195,10 @@ export class WorkbenchService { * Delete command executions by databaseId * * @param clientMetadata + * @param filter */ - async deleteCommandExecutions(clientMetadata: ClientMetadata): Promise { - await this.commandExecutionRepository.deleteAll(clientMetadata.sessionMetadata, clientMetadata.databaseId); + async deleteCommandExecutions(clientMetadata: ClientMetadata, filter: CommandExecutionFilter): Promise { + await this.commandExecutionRepository.deleteAll(clientMetadata.sessionMetadata, clientMetadata.databaseId, filter); } /** From 3ba5eb6dccd6f5cf5b4803cdc8e10ff67ae8a9cc Mon Sep 17 00:00:00 2001 From: Roman Sergeenko Date: Mon, 9 Sep 2024 16:00:10 +0200 Subject: [PATCH 054/256] #RI-6079 - update colors --- redisinsight/ui/src/constants/monaco/theme.ts | 36 ++++++++++++++++++ .../ui/src/utils/monaco/monacoThemes.ts | 37 ++----------------- 2 files changed, 39 insertions(+), 34 deletions(-) diff --git a/redisinsight/ui/src/constants/monaco/theme.ts b/redisinsight/ui/src/constants/monaco/theme.ts index bdfcbe0d29..0a48b48ded 100644 --- a/redisinsight/ui/src/constants/monaco/theme.ts +++ b/redisinsight/ui/src/constants/monaco/theme.ts @@ -26,3 +26,39 @@ export const lightTheme: monaco.editor.IStandaloneThemeData = { rules: lightThemeRules, colors: {} } + +export const redisearchDarKThemeRules = [ + { token: 'keyword', foreground: '#8094B1', fontStyle: 'bold' }, + { token: 'argument.block.0', foreground: '#BDE8D7' }, + { token: 'argument.block.1', foreground: '#8CD7B9' }, + { token: 'argument.block.2', foreground: '#5BC69B' }, + { token: 'argument.block.3', foreground: '#3A8365' }, + { token: 'argument.block.withToken.0', foreground: '#BDE8D7' }, + { token: 'argument.block.withToken.1', foreground: '#8CD7B9' }, + { token: 'argument.block.withToken.2', foreground: '#5BC69B' }, + { token: 'argument.block.withToken.3', foreground: '#3A8365' }, + { token: 'loadAll', foreground: '#BDE8D7' }, + { token: 'index', foreground: '#DE47BB' }, + { token: 'query', foreground: '#7B90E0' }, + { token: 'field', foreground: '#B02C30' }, + { token: 'query.operator', foreground: '#B9F0F3' }, + { token: 'function', foreground: '#9E7EE8' }, +] + +export const redisearchLightThemeRules = [ + { token: 'keyword', foreground: '#8094B1', fontStyle: 'bold' }, + { token: 'argument.block.0', foreground: '#BDE8D7' }, + { token: 'argument.block.1', foreground: '#8CD7B9' }, + { token: 'argument.block.2', foreground: '#5BC69B' }, + { token: 'argument.block.3', foreground: '#3A8365' }, + { token: 'argument.block.withToken.0', foreground: '#BDE8D7' }, + { token: 'argument.block.withToken.1', foreground: '#8CD7B9' }, + { token: 'argument.block.withToken.2', foreground: '#5BC69B' }, + { token: 'argument.block.withToken.3', foreground: '#3A8365' }, + { token: 'loadAll', foreground: '#BDE8D7' }, + { token: 'index', foreground: '#DE47BB' }, + { token: 'query', foreground: '#7B90E0' }, + { token: 'field', foreground: '#B02C30' }, + { token: 'query.operator', foreground: '#B9F0F3' }, + { token: 'function', foreground: '#9E7EE8' }, +] diff --git a/redisinsight/ui/src/utils/monaco/monacoThemes.ts b/redisinsight/ui/src/utils/monaco/monacoThemes.ts index 3982d4e651..c3fd5313a3 100644 --- a/redisinsight/ui/src/utils/monaco/monacoThemes.ts +++ b/redisinsight/ui/src/utils/monaco/monacoThemes.ts @@ -1,4 +1,5 @@ import { monaco as monacoEditor } from 'react-monaco-editor' +import { redisearchDarKThemeRules, redisearchLightThemeRules } from 'uiSrc/constants/monaco' export enum RedisearchMonacoTheme { dark = 'redisearchDarkTheme', @@ -9,46 +10,14 @@ export const installRedisearchTheme = () => { monacoEditor.editor.defineTheme(RedisearchMonacoTheme.dark, { base: 'vs-dark', inherit: true, - rules: [ - { token: 'keyword', foreground: '#569cd6', fontStyle: 'bold' }, - { token: 'argument.block.0', foreground: '#66ccaf' }, - { token: 'argument.block.1', foreground: '#459d7f' }, - { token: 'argument.block.2', foreground: '#3c816a' }, - { token: 'argument.block.3', foreground: '#28644f' }, - { token: 'argument.block.withToken.0', foreground: '#66ccaf' }, - { token: 'argument.block.withToken.1', foreground: '#459d7f' }, - { token: 'argument.block.withToken.2', foreground: '#3c816a' }, - { token: 'argument.block.withToken.3', foreground: '#28644f' }, - { token: 'loadAll', foreground: '#6db9a2' }, - { token: 'index', foreground: '#ce51cc' }, - { token: 'query', foreground: '#5183ce' }, - { token: 'field', foreground: '#c43265' }, - { token: 'query.operator', foreground: '#a4e7df' }, - { token: 'function', foreground: '#aa58d2' }, - ], + rules: redisearchDarKThemeRules, colors: {} }) monacoEditor.editor.defineTheme(RedisearchMonacoTheme.light, { base: 'vs', inherit: true, - rules: [ - { token: 'keyword', foreground: '#569cd6', fontStyle: 'bold' }, - { token: 'argument.block.0', foreground: '#66ccaf' }, - { token: 'argument.block.1', foreground: '#459d7f' }, - { token: 'argument.block.2', foreground: '#3c816a' }, - { token: 'argument.block.3', foreground: '#28644f' }, - { token: 'argument.block.withToken.0', foreground: '#66ccaf' }, - { token: 'argument.block.withToken.1', foreground: '#459d7f' }, - { token: 'argument.block.withToken.2', foreground: '#3c816a' }, - { token: 'argument.block.withToken.3', foreground: '#28644f' }, - { token: 'loadAll', foreground: '#6db9a2' }, - { token: 'index', foreground: '#ce51cc' }, - { token: 'field', foreground: '#5183ce' }, - { token: 'field', foreground: '#c43265' }, - { token: 'query.operator', foreground: '#a4e7df' }, - { token: 'function', foreground: '#aa58d2' }, - ], + rules: redisearchLightThemeRules, colors: {} }) } From 829d39ede830171ea506a451e56f1ffa04535558 Mon Sep 17 00:00:00 2001 From: mariasergeenko Date: Tue, 10 Sep 2024 11:31:02 +0200 Subject: [PATCH 055/256] test for APPLY, FILTER and REDUCE --- .../e2e/pageObjects/search-and-query-page.ts | 2 +- .../search-and-query-tab.e2e.ts | 93 ++++++++++++++++--- 2 files changed, 80 insertions(+), 15 deletions(-) diff --git a/tests/e2e/pageObjects/search-and-query-page.ts b/tests/e2e/pageObjects/search-and-query-page.ts index 7943ca5131..b4fa96b8e0 100644 --- a/tests/e2e/pageObjects/search-and-query-page.ts +++ b/tests/e2e/pageObjects/search-and-query-page.ts @@ -7,7 +7,7 @@ export class SearchAndQueryPage extends BaseRunCommandsPage { * Select query using autosuggest * @param query Value of query */ - async selectQueryUsingAutosuggest(value: string): Promise { + async selectFieldUsingAutosuggest(value: string): Promise { await t.wait(200); await t.typeText(this.queryInput, '@', { replace: false }); await t.expect(this.MonacoEditor.monacoSuggestion.visible).ok('Suggestions not displayed'); diff --git a/tests/e2e/tests/web/regression/search-and-query/search-and-query-tab.e2e.ts b/tests/e2e/tests/web/regression/search-and-query/search-and-query-tab.e2e.ts index 1b50e224be..cc334fa495 100644 --- a/tests/e2e/tests/web/regression/search-and-query/search-and-query-tab.e2e.ts +++ b/tests/e2e/tests/web/regression/search-and-query/search-and-query-tab.e2e.ts @@ -35,6 +35,7 @@ fixture `Autocomplete for entered commands in search and query` // Create 3 keys and index await browserPage.Cli.sendCommandsInCli(commands); + await browserPage.KeysInteractionPanel.setActiveTab(KeysInteractionTabs.SearchAndQuery); }) .afterEach(async() => { // Clear and delete database @@ -44,9 +45,9 @@ fixture `Autocomplete for entered commands in search and query` await databaseAPIRequests.deleteStandaloneDatabaseApi(ossStandaloneConfig); }); test('Verify that tutorials can be opened from Workbench', async t => { - const search = await browserPage.KeysInteractionPanel.setActiveTab(KeysInteractionTabs.SearchAndQuery); - await t.click(search.getTutorialLinkLocator('sq-exact-match')); - await t.expect(search.InsightsPanel.sidePanel.exists).ok('Insight panel is not opened'); + await browserPage.KeysInteractionPanel.setActiveTab(KeysInteractionTabs.SearchAndQuery); + await t.click(searchAndQueryPage.getTutorialLinkLocator('sq-exact-match')); + await t.expect(searchAndQueryPage.InsightsPanel.sidePanel.exists).ok('Insight panel is not opened'); const tab = await browserPage.InsightsPanel.setActiveTab(ExploreTabs.Tutorials); await t.expect(tab.preselectArea.textContent).contains('EXACT MATCH', 'the tutorial page is incorrect'); }); @@ -59,7 +60,6 @@ test('Verify that user can use show more to see command fully in 2nd tooltip', a 'required query', 'optional [verbatim]' ]; - await browserPage.KeysInteractionPanel.setActiveTab(KeysInteractionTabs.SearchAndQuery); await t.typeText(searchAndQueryPage.queryInput, 'FT', { replace: true }); // Verify that user can use show more to see command fully in 2nd tooltip await t.pressKey('ctrl+space'); @@ -83,8 +83,6 @@ test('Verify full commands suggestions with index and query for FT.AGGREGATE', a 'students', 'type' ]; - await browserPage.KeysInteractionPanel.setActiveTab(KeysInteractionTabs.SearchAndQuery); - // Verify basic commands suggestions FT.SEARCH and FT.AGGREGATE await t.typeText(searchAndQueryPage.queryInput, 'FT', { replace: true }); // Verify that the list with FT.SEARCH and FT.AGGREGATE auto-suggestions is displayed @@ -149,7 +147,6 @@ test('Verify full commands suggestions with index and query for FT.AGGREGATE', a await t.expect((await searchAndQueryPage.queryInputForText.innerText).trim().replace(/\s+/g, ' ')).contains(expectedText, 'Incorrect order of entered arguments'); }); test('Verify full commands suggestions with index and query for FT.SEARCH', async t => { - await browserPage.KeysInteractionPanel.setActiveTab(KeysInteractionTabs.SearchAndQuery); await t.typeText(searchAndQueryPage.queryInput, 'FT.SE', { replace: true }); // Select command and check result await t.pressKey('enter'); @@ -158,7 +155,7 @@ test('Verify full commands suggestions with index and query for FT.SEARCH', asyn await t.pressKey('tab'); // Select '@city' field - await searchAndQueryPage.selectQueryUsingAutosuggest('city'); + await searchAndQueryPage.selectFieldUsingAutosuggest('city'); await t.expect(searchAndQueryPage.MonacoEditor.monacoSuggestion.withExactText('DIALECT').exists).ok('FT.SEARCH arguments not suggested'); await t.typeText(searchAndQueryPage.queryInput, 'n', { replace: false }); await t.expect(searchAndQueryPage.MonacoEditor.monacoSuggestion.nth(0).textContent).contains('NOCONTENT', 'Argument not suggested after typing first letters'); @@ -178,7 +175,6 @@ test('Verify full commands suggestions with index and query for FT.SEARCH', asyn await t.expect(searchAndQueryPage.MonacoEditor.monacoSuggestWidget.textContent).contains('No suggestions.', 'Index not auto-suggested'); }); test('Verify full commands suggestions with index and query for FT.PROFILE(SEARCH)', async t => { - await browserPage.KeysInteractionPanel.setActiveTab(KeysInteractionTabs.SearchAndQuery); await t.typeText(searchAndQueryPage.queryInput, 'FT.PR', { replace: true }); // Select command and check result await t.pressKey('enter'); @@ -198,7 +194,7 @@ test('Verify full commands suggestions with index and query for FT.PROFILE(SEARC // Select QUERY await t.typeText(searchAndQueryPage.queryInput, 'QUE', { replace: false }); await t.pressKey('enter'); - await searchAndQueryPage.selectQueryUsingAutosuggest('city'); + await searchAndQueryPage.selectFieldUsingAutosuggest('city'); // Verify that there are no more suggestions await t.expect(searchAndQueryPage.MonacoEditor.monacoSuggestion.exists).notOk('Additional invalid commands suggested'); const expectedText = `FT.PROFILE "${indexName1}" SEARCH QUERY "@city"`.trim().replace(/\s+/g, ' '); @@ -206,7 +202,6 @@ test('Verify full commands suggestions with index and query for FT.PROFILE(SEARC await t.expect((await searchAndQueryPage.queryInputForText.innerText).trim().replace(/\s+/g, ' ')).contains(expectedText, 'Incorrect order of entered arguments'); }); test('Verify full commands suggestions with index and query for FT.PROFILE(AGGREGATE)', async t => { - await browserPage.KeysInteractionPanel.setActiveTab(KeysInteractionTabs.SearchAndQuery); await t.typeText(searchAndQueryPage.queryInput, 'FT.PR', { replace: true }); // Select command and check result await t.pressKey('enter'); @@ -220,7 +215,7 @@ test('Verify full commands suggestions with index and query for FT.PROFILE(AGGRE // Select QUERY await t.typeText(searchAndQueryPage.queryInput, 'QUE', { replace: false }); await t.pressKey('enter'); - await searchAndQueryPage.selectQueryUsingAutosuggest('city'); + await searchAndQueryPage.selectFieldUsingAutosuggest('city'); // Verify that there are no more suggestions await t.expect(searchAndQueryPage.MonacoEditor.monacoSuggestion.exists).notOk('Additional invalid commands suggested'); const expectedText = `FT.PROFILE "${indexName1}" AGGREGATE QUERY "@city"`.trim().replace(/\s+/g, ' '); @@ -228,12 +223,11 @@ test('Verify full commands suggestions with index and query for FT.PROFILE(AGGRE await t.expect((await searchAndQueryPage.queryInputForText.innerText).trim().replace(/\s+/g, ' ')).contains(expectedText, 'Incorrect order of entered arguments'); }); test('Verify full commands suggestions with index and query for FT.EXPLAIN', async t => { - await browserPage.KeysInteractionPanel.setActiveTab(KeysInteractionTabs.SearchAndQuery); await t.typeText(searchAndQueryPage.queryInput, 'FT.EX', { replace: true }); // Select command and check result await t.pressKey('enter'); await t.pressKey('tab'); - await searchAndQueryPage.selectQueryUsingAutosuggest('city'); + await searchAndQueryPage.selectFieldUsingAutosuggest('city'); await t.expect(searchAndQueryPage.MonacoEditor.monacoSuggestion.withExactText('DIALECT').exists).ok('FT.EXPLAIN arguments not suggested'); // Add DIALECT @@ -246,3 +240,74 @@ test('Verify full commands suggestions with index and query for FT.EXPLAIN', asy // Verify command entered correctly await t.expect((await searchAndQueryPage.queryInputForText.innerText).trim().replace(/\s+/g, ' ')).contains(expectedText, 'Incorrect order of entered arguments'); }); +test('Verify commands suggestions for APPLY and FILTER', async t => { + await t.typeText(searchAndQueryPage.queryInput, 'FT.AGGREGATE ', { replace: true }); + await t.pressKey('enter'); + + await t.typeText(searchAndQueryPage.queryInput, '*'); + await t.pressKey('right'); + await t.pressKey('space'); + //Verify APPLY command + await t.expect(searchAndQueryPage.MonacoEditor.monacoSuggestion.withExactText('APPLY').exists).ok('Apply is not suggested'); + await t.pressKey('enter'); + + await t.typeText(searchAndQueryPage.queryInput, 'g'); + await t.expect(searchAndQueryPage.MonacoEditor.monacoSuggestion.exists).ok('commands is not suggested'); + await t.pressKey('enter'); + await t.typeText(searchAndQueryPage.queryInput, '@', { replace: false }); + await t.expect(searchAndQueryPage.MonacoEditor.monacoSuggestion.visible).ok('Suggestions not displayed'); + await t.typeText(searchAndQueryPage.queryInput, 'location', { replace: false }); + await t.typeText(searchAndQueryPage.queryInput, ', \'40.7128,-74.0060\''); + for (let i = 0; i < 3; i++) { + await t.pressKey('right'); + } + await t.pressKey('space'); + await t.pressKey('tab'); + await t.typeText(searchAndQueryPage.queryInput, 'apply_key', { replace: false }); + + await t.pressKey('space'); + //Verify Filter command + await t.typeText(searchAndQueryPage.queryInput, 'F'); + await t.expect(searchAndQueryPage.MonacoEditor.monacoSuggestion.withExactText('FILTER').exists).ok('FILTER is not suggested'); + await t.pressKey('enter'); + await t.typeText(searchAndQueryPage.queryInput, 'apply_key < 5000', { replace: false }); + await t.pressKey('right'); + await t.pressKey('space'); + await t.expect(searchAndQueryPage.MonacoEditor.monacoSuggestion.withExactText('GROUPBY').exists).ok('query can not be prolong'); +}); + +test('Verify REDUCE commands', async t => { + await t.typeText(searchAndQueryPage.queryInput, `FT.AGGREGATE ${indexName1} "*" GROUPBY 1 @location`, { replace: true }); + await t.pressKey('space'); + // select Reduce + await t.expect(searchAndQueryPage.MonacoEditor.monacoSuggestion.withExactText('REDUCE').exists).ok('REDUCE is not suggested'); + await t.typeText(searchAndQueryPage.queryInput, 'R'); + await t.pressKey('enter'); + + // set value of reduce + await t.expect(searchAndQueryPage.MonacoEditor.monacoSuggestion.visible).ok('Suggestions not displayed'); + await t.typeText(searchAndQueryPage.queryInput, 'CO'); + await t.pressKey('enter'); + await t.typeText(searchAndQueryPage.queryInput, '0'); + + // verify that count of nargs is correct + await t.pressKey('space'); + await t.expect(searchAndQueryPage.MonacoEditor.monacoSuggestion.withExactText('AS').exists).ok('AS is not suggested'); + await t.pressKey('enter'); + await t.typeText(searchAndQueryPage.queryInput, 'item_count '); + + //add additional reduce + await t.expect(searchAndQueryPage.MonacoEditor.monacoSuggestion.withExactText('REDUCE').exists).ok('Apply is not suggested'); + await t.typeText(searchAndQueryPage.queryInput, 'R'); + await t.pressKey('enter'); + await t.typeText(searchAndQueryPage.queryInput, 'SUM'); + await t.pressKey('enter'); + await t.typeText(searchAndQueryPage.queryInput, '1 '); + + await t.typeText(searchAndQueryPage.queryInput, '@', { replace: false }); + await t.expect(searchAndQueryPage.MonacoEditor.monacoSuggestion.visible).ok('Suggestions not displayed'); + await t.typeText(searchAndQueryPage.queryInput, 'students ', { replace: false }); + await t.expect(searchAndQueryPage.MonacoEditor.monacoSuggestion.withExactText('AS').exists).ok('AS is not suggested'); + await t.pressKey('enter'); + await t.typeText(searchAndQueryPage.queryInput, 'total_students'); +}); From ce73e8274aacf16a98886d4ebb16c23476578201 Mon Sep 17 00:00:00 2001 From: ArtemHoruzhenko Date: Tue, 10 Sep 2024 14:27:21 +0300 Subject: [PATCH 056/256] fix tests + small rework --- redisinsight/api/src/__mocks__/common.ts | 3 +- redisinsight/api/src/__mocks__/index.ts | 1 + redisinsight/api/src/__mocks__/workbench.ts | 100 ++++++ .../workbench/models/command-execution.ts | 6 +- .../models/plugin-command-execution.ts | 7 +- .../modules/workbench/plugins.service.spec.ts | 43 +-- .../workbench-commands.executor.spec.ts | 2 +- .../providers/workbench-commands.executor.ts | 2 +- ...local-command-execution.repository.spec.ts | 288 ++++++++---------- .../local-command-execution.repository.ts | 2 +- .../workbench/workbench.service.spec.ts | 135 ++++---- ...id-workbench-command_executions-id.test.ts | 24 +- ...es-id-workbench-command_executions.test.ts | 91 ++++-- ...id-workbench-command_executions-id.test.ts | 3 +- ...es-id-workbench-command_executions.test.ts | 80 +++-- ...es-id-workbench-command_executions.test.ts | 25 +- 16 files changed, 437 insertions(+), 375 deletions(-) create mode 100644 redisinsight/api/src/__mocks__/workbench.ts diff --git a/redisinsight/api/src/__mocks__/common.ts b/redisinsight/api/src/__mocks__/common.ts index 2e3e86348a..874e8a0c79 100644 --- a/redisinsight/api/src/__mocks__/common.ts +++ b/redisinsight/api/src/__mocks__/common.ts @@ -8,6 +8,7 @@ export type MockType = { }; export const mockQueryBuilderWhere = jest.fn().mockReturnThis(); +export const mockQueryBuilderWhereInIds = jest.fn().mockReturnThis(); export const mockQueryBuilderSelect = jest.fn().mockReturnThis(); export const mockQueryBuilderGetOne = jest.fn(); export const mockQueryBuilderGetMany = jest.fn(); @@ -17,6 +18,7 @@ export const mockQueryBuilderExecute = jest.fn(); export const mockCreateQueryBuilder = jest.fn(() => ({ // where: jest.fn().mockReturnThis(), where: mockQueryBuilderWhere, + whereInIds: mockQueryBuilderWhereInIds, orWhere: mockQueryBuilderWhere, update: jest.fn().mockReturnThis(), select: mockQueryBuilderSelect, @@ -29,7 +31,6 @@ export const mockCreateQueryBuilder = jest.fn(() => ({ leftJoinAndSelect: jest.fn().mockReturnThis(), offset: jest.fn().mockReturnThis(), delete: jest.fn().mockReturnThis(), - whereInIds: jest.fn().mockReturnThis(), execute: mockQueryBuilderExecute, getCount: mockQueryBuilderGetCount, getRawMany: mockQueryBuilderGetManyRaw, diff --git a/redisinsight/api/src/__mocks__/index.ts b/redisinsight/api/src/__mocks__/index.ts index 8999864e19..19a2c1aad5 100644 --- a/redisinsight/api/src/__mocks__/index.ts +++ b/redisinsight/api/src/__mocks__/index.ts @@ -41,3 +41,4 @@ export * from './cloud-session'; export * from './database-info'; export * from './cloud-job'; export * from './rdi'; +export * from './workbench'; diff --git a/redisinsight/api/src/__mocks__/workbench.ts b/redisinsight/api/src/__mocks__/workbench.ts new file mode 100644 index 0000000000..c5b94301e5 --- /dev/null +++ b/redisinsight/api/src/__mocks__/workbench.ts @@ -0,0 +1,100 @@ +import { v4 as uuidv4 } from 'uuid'; +import { + CommandExecution, + CommandExecutionType, + ResultsMode, + RunQueryMode, +} from 'src/modules/workbench/models/command-execution'; +import { CommandExecutionEntity } from 'src/modules/workbench/entities/command-execution.entity'; +import { mockDatabase } from 'src/__mocks__/databases'; +import { CommandExecutionResult } from 'src/modules/workbench/models/command-execution-result'; +import { CommandExecutionStatus } from 'src/modules/cli/dto/cli.dto'; +import { CreateCommandExecutionDto } from 'src/modules/workbench/dto/create-command-execution.dto'; +import { ShortCommandExecution } from 'src/modules/workbench/models/short-command-execution'; +import { CommandExecutionFilter } from 'src/modules/workbench/models/command-executions.filter'; +import ERROR_MESSAGES from 'src/constants/error-messages'; +import { PluginCommandExecution } from 'src/modules/workbench/models/plugin-command-execution'; + +export const mockCommandExecutionUnsupportedCommandResult = Object.assign(new CommandExecutionResult(), { + response: ERROR_MESSAGES.PLUGIN_COMMAND_NOT_SUPPORTED('subscribe'.toUpperCase()), + status: CommandExecutionStatus.Fail, +}); + +export const mockCommandExecutionSuccessResult = Object.assign(new CommandExecutionResult(), { + status: CommandExecutionStatus.Success, + response: 'bar', +}); + +export const mockCommendExecutionHugeResultPlaceholder = Object.assign(new CommandExecutionResult(), { + status: CommandExecutionStatus.Success, + response: 'Results have been deleted since they exceed 1 MB. Re-run the command to see new results.', +}); + +export const mockCommendExecutionHugeResultPlaceholderEncrypted = 'huge_result_placeholder_encrypted'; + +export const mockCommandExecution = Object.assign(new CommandExecution(), { + id: uuidv4(), + databaseId: mockDatabase.id, + command: 'get foo', + mode: RunQueryMode.ASCII, + resultsMode: ResultsMode.Default, + type: CommandExecutionType.Workbench, + result: [mockCommandExecutionSuccessResult], + createdAt: new Date(), + db: 0, +}); + +export const mockCommandExecutionEntity = Object.assign(new CommandExecutionEntity(), { + ...mockCommandExecution, + command: 'encrypted_command', + result: `${JSON.stringify([mockCommandExecutionSuccessResult])}_encrypted`, + encryption: 'KEYTAR', +}); + +export const mockShortCommandExecution = Object.assign(new ShortCommandExecution(), { + id: mockCommandExecution.id, + databaseId: mockCommandExecution.id, + command: mockCommandExecution.command, + createdAt: mockCommandExecution.createdAt, + mode: mockCommandExecution.mode, + summary: mockCommandExecution.summary, + resultsMode: mockCommandExecution.resultsMode, + executionTime: mockCommandExecution.executionTime, + db: mockCommandExecution.db, + type: mockCommandExecution.type, +}); + +export const mockShortCommandExecutionEntity = Object.assign(new CommandExecutionEntity(), { + ...mockShortCommandExecution, + command: mockCommandExecutionEntity.command, + encryption: mockCommandExecutionEntity.encryption, +}); + +export const mockCreateCommandExecutionDto = Object.assign(new CreateCommandExecutionDto(), { + command: mockCommandExecution.command, + mode: mockCommandExecution.mode, + resultsMode: mockCommandExecution.resultsMode, + type: mockCommandExecution.type, +}); + +export const mockCommandExecutionFilter = Object.assign(new CommandExecutionFilter(), { + type: mockCommandExecution.type, +}); + +export const mockPluginCommandExecution = Object.assign(new PluginCommandExecution(), { + ...mockCreateCommandExecutionDto, + databaseId: mockDatabase.id, + result: [mockCommandExecutionSuccessResult], +}); + +export const mockWorkbenchCommandsExecutor = () => ({ + sendCommand: jest.fn().mockResolvedValue([mockCommandExecutionSuccessResult]), +}); + +export const mockCommandExecutionRepository = () => ({ + createMany: jest.fn().mockResolvedValue([mockCommandExecution]), + getList: jest.fn().mockResolvedValue([mockCommandExecution]), + getOne: jest.fn().mockResolvedValue(mockCommandExecution), + delete: jest.fn(), + deleteAll: jest.fn(), +}); diff --git a/redisinsight/api/src/modules/workbench/models/command-execution.ts b/redisinsight/api/src/modules/workbench/models/command-execution.ts index 37d9fafa09..f22b9beb3f 100644 --- a/redisinsight/api/src/modules/workbench/models/command-execution.ts +++ b/redisinsight/api/src/modules/workbench/models/command-execution.ts @@ -159,7 +159,11 @@ export class CommandExecution { }) @Expose() @IsOptional() - @IsEnum(CommandExecutionType) + @IsEnum(CommandExecutionType, { + message: `type must be a valid enum value. Valid values: ${Object.values( + CommandExecutionType, + )}.`, + }) @Default(CommandExecutionType.Workbench) type?: CommandExecutionType; } diff --git a/redisinsight/api/src/modules/workbench/models/plugin-command-execution.ts b/redisinsight/api/src/modules/workbench/models/plugin-command-execution.ts index 8dc38bb30f..94add4f14d 100644 --- a/redisinsight/api/src/modules/workbench/models/plugin-command-execution.ts +++ b/redisinsight/api/src/modules/workbench/models/plugin-command-execution.ts @@ -3,9 +3,4 @@ import { OmitType, PartialType } from '@nestjs/swagger'; export class PluginCommandExecution extends PartialType( OmitType(CommandExecution, ['createdAt', 'id'] as const), -) { - constructor(partial: Partial) { - super(); - Object.assign(this, partial); - } -} +) {} diff --git a/redisinsight/api/src/modules/workbench/plugins.service.spec.ts b/redisinsight/api/src/modules/workbench/plugins.service.spec.ts index ea1580cf60..4f75731fdf 100644 --- a/redisinsight/api/src/modules/workbench/plugins.service.spec.ts +++ b/redisinsight/api/src/modules/workbench/plugins.service.spec.ts @@ -1,20 +1,16 @@ import { Test, TestingModule } from '@nestjs/testing'; import { mockClientMetadata, - mockDatabase, + mockCommandExecutionUnsupportedCommandResult, + mockCreateCommandExecutionDto, mockDatabaseClientFactory, + mockPluginCommandExecution, mockWhitelistCommandsResponse, mockWorkbenchClientMetadata, + mockWorkbenchCommandsExecutor, } from 'src/__mocks__'; import { v4 as uuidv4 } from 'uuid'; import { WorkbenchCommandsExecutor } from 'src/modules/workbench/providers/workbench-commands.executor'; -import { - CreateCommandExecutionDto, - ResultsMode, - RunQueryMode, -} from 'src/modules/workbench/dto/create-command-execution.dto'; -import { CommandExecutionResult } from 'src/modules/workbench/models/command-execution-result'; -import { CommandExecutionStatus } from 'src/modules/cli/dto/cli.dto'; import { BadRequestException } from '@nestjs/common'; import ERROR_MESSAGES from 'src/constants/error-messages'; import { PluginsService } from 'src/modules/workbench/plugins.service'; @@ -24,27 +20,10 @@ import { PluginStateRepository } from 'src/modules/workbench/repositories/plugin import { PluginState } from 'src/modules/workbench/models/plugin-state'; import config from 'src/utils/config'; import { DatabaseClientFactory } from 'src/modules/database/providers/database.client.factory'; +import { RunQueryMode } from 'src/modules/workbench/models/command-execution'; const PLUGINS_CONFIG = config.get('plugins'); -const mockCreateCommandExecutionDto: CreateCommandExecutionDto = { - command: 'get foo', - mode: RunQueryMode.ASCII, - resultsMode: ResultsMode.Default, -}; - -const mockCommandExecutionResults: CommandExecutionResult[] = [ - new CommandExecutionResult({ - status: CommandExecutionStatus.Success, - response: 'OK', - }), -]; -const mockPluginCommandExecution = new PluginCommandExecution({ - ...mockCreateCommandExecutionDto, - databaseId: mockDatabase.id, - result: mockCommandExecutionResults, -}); - const mockVisualizationId = 'pluginName_visualizationName'; const mockCommandExecutionId = uuidv4(); const mockState = { @@ -80,9 +59,7 @@ describe('PluginsService', () => { PluginsService, { provide: WorkbenchCommandsExecutor, - useFactory: () => ({ - sendCommand: jest.fn(), - }), + useFactory: mockWorkbenchCommandsExecutor, }, { provide: PluginCommandsWhitelistProvider, @@ -107,7 +84,6 @@ describe('PluginsService', () => { describe('sendCommand', () => { it('should successfully execute command', async () => { - workbenchCommandsExecutor.sendCommand.mockResolvedValueOnce(mockCommandExecutionResults); pluginsCommandsWhitelistProvider.getWhitelistCommands.mockResolvedValueOnce(mockWhitelistCommandsResponse); const result = await service.sendCommand(mockWorkbenchClientMetadata, mockCreateCommandExecutionDto); @@ -128,10 +104,7 @@ describe('PluginsService', () => { expect(result).toEqual(new PluginCommandExecution({ ...dto, databaseId: mockWorkbenchClientMetadata.databaseId, - result: [new CommandExecutionResult({ - response: ERROR_MESSAGES.PLUGIN_COMMAND_NOT_SUPPORTED('subscribe'.toUpperCase()), - status: CommandExecutionStatus.Fail, - })], + result: [mockCommandExecutionUnsupportedCommandResult], })); expect(workbenchCommandsExecutor.sendCommand).not.toHaveBeenCalled(); }); @@ -140,7 +113,6 @@ describe('PluginsService', () => { workbenchCommandsExecutor.sendCommand.mockRejectedValueOnce(new BadRequestException('error')); const dto = { - ...mockCommandExecutionResults, command: 'get foo', mode: RunQueryMode.ASCII, }; @@ -155,7 +127,6 @@ describe('PluginsService', () => { }); describe('getWhitelistCommands', () => { it('should successfully return whitelisted commands', async () => { - workbenchCommandsExecutor.sendCommand.mockResolvedValueOnce(mockCommandExecutionResults); pluginsCommandsWhitelistProvider.getWhitelistCommands.mockResolvedValueOnce(mockWhitelistCommandsResponse); const result = await service.getWhitelistCommands(mockWorkbenchClientMetadata); diff --git a/redisinsight/api/src/modules/workbench/providers/workbench-commands.executor.spec.ts b/redisinsight/api/src/modules/workbench/providers/workbench-commands.executor.spec.ts index 741b61d50b..4db9dc9cd6 100644 --- a/redisinsight/api/src/modules/workbench/providers/workbench-commands.executor.spec.ts +++ b/redisinsight/api/src/modules/workbench/providers/workbench-commands.executor.spec.ts @@ -11,7 +11,6 @@ import { unknownCommand } from 'src/constants'; import { WorkbenchCommandsExecutor } from 'src/modules/workbench/providers/workbench-commands.executor'; import { CreateCommandExecutionDto, - RunQueryMode, } from 'src/modules/workbench/dto/create-command-execution.dto'; import { CommandExecutionResult } from 'src/modules/workbench/models/command-execution-result'; import { CommandExecutionStatus } from 'src/modules/cli/dto/cli.dto'; @@ -19,6 +18,7 @@ import { ServiceUnavailableException } from '@nestjs/common'; import { CommandNotSupportedError, CommandParsingError } from 'src/modules/cli/constants/errors'; import { FormatterManager, IFormatterStrategy, FormatterTypes } from 'src/common/transformers'; import { DatabaseClientFactory } from 'src/modules/database/providers/database.client.factory'; +import { RunQueryMode } from 'src/modules/workbench/models/command-execution'; import { WorkbenchAnalyticsService } from '../services/workbench-analytics/workbench-analytics.service'; const MOCK_ERROR_MESSAGE = 'Some error'; diff --git a/redisinsight/api/src/modules/workbench/providers/workbench-commands.executor.ts b/redisinsight/api/src/modules/workbench/providers/workbench-commands.executor.ts index 8f6a30684d..223da5efcf 100644 --- a/redisinsight/api/src/modules/workbench/providers/workbench-commands.executor.ts +++ b/redisinsight/api/src/modules/workbench/providers/workbench-commands.executor.ts @@ -45,7 +45,7 @@ export class WorkbenchCommandsExecutor { /** * Entrypoint for any CommandExecution - * Will determine type of a command (standalone, per node(s)) and format, and execute it + * Will determine type of command (standalone, per node(s)) and format, and execute it * Also sis a single place of analytics events invocation * @param client * @param dto diff --git a/redisinsight/api/src/modules/workbench/repositories/local-command-execution.repository.spec.ts b/redisinsight/api/src/modules/workbench/repositories/local-command-execution.repository.spec.ts index 10703459f9..3769d6bd0a 100644 --- a/redisinsight/api/src/modules/workbench/repositories/local-command-execution.repository.spec.ts +++ b/redisinsight/api/src/modules/workbench/repositories/local-command-execution.repository.spec.ts @@ -1,23 +1,19 @@ import { Test, TestingModule } from '@nestjs/testing'; -import { v4 as uuidv4 } from 'uuid'; +import { when } from 'jest-when'; import { mockEncryptionService, - mockEncryptResult, - mockQueryBuilderGetMany, - mockQueryBuilderGetManyRaw, mockRepository, - mockDatabase, MockType, mockSessionMetadata, + mockCommandExecutionEntity, + mockCommandExecution, + mockCommendExecutionHugeResultPlaceholder, + mockCommendExecutionHugeResultPlaceholderEncrypted, + mockShortCommandExecutionEntity, + mockShortCommandExecution, + mockCommandExecutionFilter, } from 'src/__mocks__'; -import { omit } from 'lodash'; -import { - CreateCommandExecutionDto, - RunQueryMode, -} from 'src/modules/workbench/dto/create-command-execution.dto'; -import { CommandExecution } from 'src/modules/workbench/models/command-execution'; -import { CommandExecutionResult } from 'src/modules/workbench/models/command-execution-result'; -import { CommandExecutionStatus, ICliExecResultFromNode } from 'src/modules/cli/dto/cli.dto'; +import { CommandExecutionStatus } from 'src/modules/cli/dto/cli.dto'; import { NotFoundException } from '@nestjs/common'; import { EncryptionService } from 'src/modules/encryption/encryption.service'; import { Repository } from 'typeorm'; @@ -30,49 +26,14 @@ import { LocalCommandExecutionRepository } from 'src/modules/workbench/repositor const WORKBENCH_CONFIG = config.get('workbench'); -const mockNodeEndpoint = { - host: '127.0.0.1', - port: 6379, -}; - -const mockCliNodeResponse: ICliExecResultFromNode = { - ...mockNodeEndpoint, - response: 'OK', - status: CommandExecutionStatus.Success, -}; - -const mockCreateCommandExecutionDto: CreateCommandExecutionDto = { - command: 'set foo bar', - mode: RunQueryMode.ASCII, -}; - -const mockCommandExecutionEntity = new CommandExecutionEntity({ - id: uuidv4(), - databaseId: mockDatabase.id, - command: mockEncryptResult.data, - result: mockEncryptResult.data, - mode: mockCreateCommandExecutionDto.mode, - encryption: 'KEYTAR', - createdAt: new Date(), -}); - -const mockCommandExecutionResult: CommandExecutionResult = { - status: mockCliNodeResponse.status, - response: mockCliNodeResponse.response, -}; - -const mockCommandExecutionPartial: Partial = new CommandExecution({ - ...mockCreateCommandExecutionDto, - databaseId: mockDatabase.id, - result: [mockCommandExecutionResult], -}); - describe('LocalCommandExecutionRepository', () => { let service: LocalCommandExecutionRepository; let repository: MockType>; - let encryptionService; + let encryptionService: MockType; beforeEach(async () => { + jest.clearAllMocks(); + const module: TestingModule = await Test.createTestingModule({ providers: [ LocalCommandExecutionRepository, @@ -89,177 +50,178 @@ describe('LocalCommandExecutionRepository', () => { service = module.get(LocalCommandExecutionRepository); repository = module.get(getRepositoryToken(CommandExecutionEntity)); - encryptionService = module.get(EncryptionService); + encryptionService = module.get(EncryptionService); + + when(encryptionService.encrypt) + .calledWith(mockCommandExecution.command) + .mockResolvedValue({ + data: mockCommandExecutionEntity.command, + encryption: mockCommandExecutionEntity.encryption, + }) + .calledWith(JSON.stringify(mockCommandExecution.result)) + .mockResolvedValue({ + data: mockCommandExecutionEntity.result, + encryption: mockCommandExecutionEntity.encryption, + }) + .calledWith(JSON.stringify([mockCommendExecutionHugeResultPlaceholder])) + .mockResolvedValue({ + data: mockCommendExecutionHugeResultPlaceholderEncrypted, + encryption: mockCommandExecutionEntity.encryption, + }); + + when(encryptionService.decrypt) + .calledWith(mockCommandExecutionEntity.command, jasmine.anything()) + .mockResolvedValue(mockCommandExecution.command) + .calledWith(mockCommandExecutionEntity.result, jasmine.anything()) + .mockResolvedValue(JSON.stringify(mockCommandExecution.result)); + + repository.save.mockReturnValue(mockCommandExecutionEntity); + repository.findOneBy.mockReturnValue(mockCommandExecutionEntity); }); describe('create', () => { - it('should process new entity', async () => { - repository.save.mockReturnValueOnce([mockCommandExecutionEntity]); - encryptionService.encrypt.mockReturnValue(mockEncryptResult); + let cleanupSpy: jest.SpyInstance; - expect(await service.createMany(mockSessionMetadata, [mockCommandExecutionPartial])).toEqual([{ - ...mockCommandExecutionPartial, - id: mockCommandExecutionEntity.id, - createdAt: mockCommandExecutionEntity.createdAt, - }]); + beforeEach(() => { + cleanupSpy = jest.spyOn(service as any, 'cleanupDatabaseHistory'); }); - it('should return full result even if size limit exceeded', async () => { - repository.save.mockReturnValueOnce([mockCommandExecutionEntity]); - encryptionService.encrypt.mockReturnValue(mockEncryptResult); - - const executionResult = [{ - status: CommandExecutionStatus.Success, - response: `${Buffer.alloc(WORKBENCH_CONFIG.maxResultSize, 'a').toString()}`, - }]; + it('should process new entity', async () => { expect(await service.createMany(mockSessionMetadata, [{ - ...mockCommandExecutionPartial, - result: executionResult, - }])).toEqual([{ - ...mockCommandExecutionPartial, - id: mockCommandExecutionEntity.id, - createdAt: mockCommandExecutionEntity.createdAt, - result: executionResult, - }]); - - expect(encryptionService.encrypt).toHaveBeenLastCalledWith(JSON.stringify([{ - status: CommandExecutionStatus.Success, - response: 'Results have been deleted since they exceed 1 MB. Re-run the command to see new results.', - }])); + ...mockCommandExecution, + id: undefined, + createdAt: undefined, + }])).toEqual([mockCommandExecution]); + expect(repository.save).toHaveBeenCalledWith({ + ...mockCommandExecutionEntity, + id: undefined, + createdAt: undefined, + }); + expect(cleanupSpy).toBeCalledTimes(1); + expect(cleanupSpy).toHaveBeenCalledWith(mockCommandExecution.databaseId, { type: mockCommandExecution.type }); }); - it('should return with flag isNotStored="true" even if size limit exceeded', async () => { - repository.save.mockReturnValueOnce([{ ...mockCommandExecutionEntity, isNotStored: true }]); - encryptionService.encrypt.mockReturnValue(mockEncryptResult); - + it('should return full result even if size limit exceeded', async () => { const executionResult = [{ status: CommandExecutionStatus.Success, response: `${Buffer.alloc(WORKBENCH_CONFIG.maxResultSize, 'a').toString()}`, }]; expect(await service.createMany(mockSessionMetadata, [{ - ...mockCommandExecutionPartial, + ...mockCommandExecution, result: executionResult, }])).toEqual([{ - ...mockCommandExecutionPartial, - id: mockCommandExecutionEntity.id, - createdAt: mockCommandExecutionEntity.createdAt, + ...mockCommandExecution, result: executionResult, - isNotStored: true, + isNotStored: true, // double check that for such cases special flag returned }]); - - expect(encryptionService.encrypt).toHaveBeenLastCalledWith(JSON.stringify([ - new CommandExecutionResult({ - status: CommandExecutionStatus.Success, - response: 'Results have been deleted since they exceed 1 MB. Re-run the command to see new results.', - }), - ])); + expect(repository.save).toHaveBeenCalledWith({ + ...mockCommandExecutionEntity, + command: mockCommandExecutionEntity.command, + result: mockCommendExecutionHugeResultPlaceholderEncrypted, + }); }); }); describe('getList', () => { it('should return list (2) of command execution', async () => { - const entityResponse = new CommandExecutionEntity({ ...omit(mockCommandExecutionEntity, 'result') }); - mockQueryBuilderGetMany.mockReturnValueOnce([entityResponse, entityResponse]); - encryptionService.decrypt.mockReturnValueOnce(mockCreateCommandExecutionDto.command); - encryptionService.decrypt.mockReturnValueOnce(mockCreateCommandExecutionDto.command); - - const commandExecution = new CommandExecution({ - ...omit(mockCommandExecutionPartial, ['result']), - id: mockCommandExecutionEntity.id, - createdAt: mockCommandExecutionEntity.createdAt, - }); - - expect(await service.getList(mockSessionMetadata, mockCommandExecutionEntity.databaseId)).toEqual([ - commandExecution, - commandExecution, + repository.createQueryBuilder() + .getMany.mockReturnValueOnce([mockShortCommandExecutionEntity, mockShortCommandExecutionEntity]); + + expect(await service.getList( + mockSessionMetadata, + mockCommandExecutionEntity.databaseId, + mockCommandExecutionFilter, + )).toEqual([ + mockShortCommandExecution, + mockShortCommandExecution, ]); + expect(repository.createQueryBuilder().where).toHaveBeenCalledWith({ + databaseId: mockCommandExecution.databaseId, + type: mockCommandExecutionFilter.type, + }); }); it('should return list (1) of command execution without failed decrypted item', async () => { - const entityResponse = new CommandExecutionEntity({ ...omit(mockCommandExecutionEntity, 'result') }); - mockQueryBuilderGetMany.mockReturnValueOnce([entityResponse, entityResponse]); - encryptionService.decrypt.mockReturnValueOnce(mockCreateCommandExecutionDto.command); + repository.createQueryBuilder().getMany.mockResolvedValueOnce([ + mockShortCommandExecutionEntity, + { + ...mockShortCommandExecutionEntity, + command: 'something that can not be decrypted', + }, + ]); + encryptionService.decrypt.mockResolvedValueOnce(mockShortCommandExecution.command); encryptionService.decrypt.mockRejectedValueOnce(new KeytarDecryptionErrorException()); - const commandExecution = new CommandExecution({ - ...omit(mockCommandExecutionPartial, ['result']), - id: mockCommandExecutionEntity.id, - createdAt: mockCommandExecutionEntity.createdAt, - }); - - expect(await service.getList(mockSessionMetadata, mockCommandExecutionEntity.databaseId)).toEqual([ - commandExecution, + expect(await service.getList( + mockSessionMetadata, + mockCommandExecution.databaseId, + mockCommandExecutionFilter, + )).toEqual([ + mockShortCommandExecution, ]); }); }); describe('getOne', () => { it('should return decrypted and transformed command execution', async () => { - repository.findOneBy.mockResolvedValueOnce(mockCommandExecutionEntity); - encryptionService.decrypt.mockReturnValueOnce(mockCreateCommandExecutionDto.command); - encryptionService.decrypt.mockReturnValueOnce(JSON.stringify([mockCommandExecutionResult])); - - const commandExecution = new CommandExecution({ - ...mockCommandExecutionPartial, - id: mockCommandExecutionEntity.id, - createdAt: mockCommandExecutionEntity.createdAt, + expect(await service.getOne(mockSessionMetadata, mockCommandExecution.databaseId, mockCommandExecution.id)) + .toEqual(mockCommandExecution); + expect(repository.findOneBy).toHaveBeenCalledWith({ + id: mockCommandExecution.id, + databaseId: mockCommandExecution.databaseId, }); - - expect(await service.getOne(mockSessionMetadata, mockDatabase.id, mockCommandExecutionEntity.id)).toEqual( - commandExecution, - ); }); it('should return null fields in case of decryption errors', async () => { - repository.findOneBy.mockResolvedValueOnce(mockCommandExecutionEntity); - encryptionService.decrypt.mockReturnValueOnce(mockCreateCommandExecutionDto.command); + encryptionService.decrypt.mockReturnValueOnce(mockCommandExecution.command); encryptionService.decrypt.mockRejectedValueOnce(new KeytarDecryptionErrorException()); - const commandExecution = new CommandExecution({ - ...mockCommandExecutionPartial, - id: mockCommandExecutionEntity.id, - createdAt: mockCommandExecutionEntity.createdAt, - result: null, - }); - - expect(await service.getOne(mockSessionMetadata, mockDatabase.id, mockCommandExecutionEntity.id)).toEqual( - commandExecution, - ); + expect(await service.getOne(mockSessionMetadata, mockCommandExecution.databaseId, mockCommandExecution.id)) + .toEqual({ + ...mockCommandExecution, + result: null, + }); }); it('should return not found exception', async () => { repository.findOneBy.mockResolvedValueOnce(null); - try { - await service.getOne(mockSessionMetadata, mockDatabase.id, mockCommandExecutionEntity.id); - fail(); - } catch (e) { - expect(e).toBeInstanceOf(NotFoundException); - expect(e.message).toEqual(ERROR_MESSAGES.COMMAND_EXECUTION_NOT_FOUND); - } + await expect(service.getOne(mockSessionMetadata, mockCommandExecution.databaseId, mockCommandExecution.id)) + .rejects.toEqual(new NotFoundException(ERROR_MESSAGES.COMMAND_EXECUTION_NOT_FOUND)); }); }); describe('delete', () => { it('Should not return anything on delete', async () => { repository.delete.mockResolvedValueOnce(1); - expect(await service.delete(mockSessionMetadata, mockDatabase.id, mockCommandExecutionEntity.id)).toEqual( - undefined, - ); + expect(await service.delete(mockSessionMetadata, mockCommandExecution.databaseId, mockCommandExecution.id)) + .toEqual(undefined); + expect(repository.delete).toHaveBeenCalledWith({ + id: mockCommandExecution.id, + databaseId: mockCommandExecution.databaseId, + }); }); }); describe('deleteAll', () => { it('Should not return anything on delete', async () => { repository.delete.mockResolvedValueOnce(1); - expect(await service.deleteAll(mockSessionMetadata, mockDatabase.id)).toEqual( - undefined, - ); + expect(await service.deleteAll(mockSessionMetadata, mockCommandExecution.databaseId, mockCommandExecutionFilter)) + .toEqual(undefined); + expect(repository.delete).toHaveBeenCalledWith({ + databaseId: mockCommandExecution.databaseId, + type: mockCommandExecutionFilter.type, + }); }); }); describe('cleanupDatabaseHistory', () => { it('Should should not return anything on cleanup', async () => { - mockQueryBuilderGetManyRaw.mockReturnValueOnce([ + repository.createQueryBuilder().getRawMany.mockReturnValueOnce([ { id: mockCommandExecutionEntity.id }, { id: mockCommandExecutionEntity.id }, ]); - expect(await service['cleanupDatabaseHistory'](mockDatabase.id)).toEqual( - undefined, - ); + expect(await service['cleanupDatabaseHistory'](mockCommandExecution.databaseId, mockCommandExecutionFilter)) + .toEqual(undefined); + expect(repository.createQueryBuilder().where).toHaveBeenCalledWith({ + databaseId: mockCommandExecution.databaseId, + type: mockCommandExecutionFilter.type, + }); + expect(repository.createQueryBuilder().whereInIds) + .toHaveBeenCalledWith([mockCommandExecutionEntity.id, mockCommandExecutionEntity.id]); }); }); }); diff --git a/redisinsight/api/src/modules/workbench/repositories/local-command-execution.repository.ts b/redisinsight/api/src/modules/workbench/repositories/local-command-execution.repository.ts index 499ab942bd..5207b41cd3 100644 --- a/redisinsight/api/src/modules/workbench/repositories/local-command-execution.repository.ts +++ b/redisinsight/api/src/modules/workbench/repositories/local-command-execution.repository.ts @@ -43,7 +43,7 @@ export class LocalCommandExecutionRepository extends CommandExecutionRepository // todo: limit by 30 max to insert const response = await Promise.all(commandExecutions.map(async (commandExecution, idx) => { const entity = plainToClass(CommandExecutionEntity, commandExecution); - let isNotStored = false; + let isNotStored: undefined | boolean; // Do not store command execution result that exceeded limitation if (JSON.stringify(entity.result).length > WORKBENCH_CONFIG.maxResultSize) { diff --git a/redisinsight/api/src/modules/workbench/workbench.service.spec.ts b/redisinsight/api/src/modules/workbench/workbench.service.spec.ts index b4a056b520..aabd4d6611 100644 --- a/redisinsight/api/src/modules/workbench/workbench.service.spec.ts +++ b/redisinsight/api/src/modules/workbench/workbench.service.spec.ts @@ -1,22 +1,18 @@ import { Test, TestingModule } from '@nestjs/testing'; -import { v4 as uuidv4 } from 'uuid'; import { when } from 'jest-when'; import { - mockDatabase, + mockCommandExecution, mockCommandExecutionFilter, mockCommandExecutionRepository, + mockCommandExecutionSuccessResult, + mockCreateCommandExecutionDto, mockDatabaseClientFactory, - mockStandaloneRedisClient, + mockStandaloneRedisClient, MockType, mockWorkbenchAnalyticsService, - mockWorkbenchClientMetadata, + mockWorkbenchClientMetadata, mockWorkbenchCommandsExecutor, } from 'src/__mocks__'; import { WorkbenchService } from 'src/modules/workbench/workbench.service'; import { WorkbenchCommandsExecutor } from 'src/modules/workbench/providers/workbench-commands.executor'; import { CommandExecutionRepository } from 'src/modules/workbench/repositories/command-execution.repository'; -import { - CreateCommandExecutionDto, - RunQueryMode, - ResultsMode, -} from 'src/modules/workbench/dto/create-command-execution.dto'; -import { CommandExecution } from 'src/modules/workbench/models/command-execution'; +import { ResultsMode, RunQueryMode } from 'src/modules/workbench/models/command-execution'; import { CommandExecutionResult } from 'src/modules/workbench/models/command-execution-result'; import { CommandExecutionStatus } from 'src/modules/cli/dto/cli.dto'; import { BadRequestException, InternalServerErrorException } from '@nestjs/common'; @@ -25,12 +21,6 @@ import { CreateCommandExecutionsDto } from 'src/modules/workbench/dto/create-com import { DatabaseClientFactory } from 'src/modules/database/providers/database.client.factory'; import { WorkbenchAnalyticsService } from './services/workbench-analytics/workbench-analytics.service'; -const mockCreateCommandExecutionDto: CreateCommandExecutionDto = { - command: 'set foo bar', - mode: RunQueryMode.ASCII, - resultsMode: ResultsMode.Default, -}; - const mockCommands = ['set 1 1', 'get 1']; const mockCreateCommandExecutionDtoWithGroupMode: CreateCommandExecutionsDto = { @@ -54,23 +44,8 @@ const mockCreateCommandExecutionsDto: CreateCommandExecutionsDto = { }; const mockCommandExecutionResults: CommandExecutionResult[] = [ - new CommandExecutionResult({ - status: CommandExecutionStatus.Success, - response: 'OK', - }), + mockCommandExecutionSuccessResult, ]; -const mockCommandExecutionToRun: CommandExecution = new CommandExecution({ - ...mockCreateCommandExecutionDto, - databaseId: mockDatabase.id, - db: 0, -}); - -const mockCommandExecution: CommandExecution = new CommandExecution({ - ...mockCommandExecutionToRun, - id: uuidv4(), - createdAt: new Date(), - result: mockCommandExecutionResults, -}); const mockSendCommandResultSuccess = { response: '1', status: 'success' }; const mockSendCommandResultFail = { response: 'error', status: 'fail' }; @@ -106,19 +81,10 @@ const mockCommandExecutionWithSilentMode = { }], }; -const mockCommandExecutionRepository = () => ({ - createMany: jest.fn(), - getList: jest.fn(), - getOne: jest.fn(), - delete: jest.fn(), - deleteAll: jest.fn(), -}); - describe('WorkbenchService', () => { - const client = mockStandaloneRedisClient; let service: WorkbenchService; - let workbenchCommandsExecutor; - let commandExecutionProvider; + let workbenchCommandsExecutor: MockType; + let commandExecutionRepository: MockType; beforeEach(async () => { const module: TestingModule = await Test.createTestingModule({ @@ -130,9 +96,7 @@ describe('WorkbenchService', () => { }, { provide: WorkbenchCommandsExecutor, - useFactory: () => ({ - sendCommand: jest.fn(), - }), + useFactory: mockWorkbenchCommandsExecutor, }, { provide: CommandExecutionRepository, @@ -145,30 +109,38 @@ describe('WorkbenchService', () => { ], }).compile(); - service = module.get(WorkbenchService); - workbenchCommandsExecutor = module.get(WorkbenchCommandsExecutor); - commandExecutionProvider = module.get(CommandExecutionRepository); + service = module.get(WorkbenchService); + workbenchCommandsExecutor = module.get(WorkbenchCommandsExecutor); + commandExecutionRepository = module.get(CommandExecutionRepository); }); describe('createCommandExecution', () => { it('should successfully execute command and save it', async () => { - const result = await service.createCommandExecution(client, mockCreateCommandExecutionDto); - // can't predict execution time - expect(result).toMatchObject(mockCommandExecutionToRun); - expect(result.executionTime).toBeGreaterThan(0); + const result = await service.createCommandExecution(mockStandaloneRedisClient, mockCreateCommandExecutionDto); + expect(result).toEqual({ + ...mockCommandExecution, + executionTime: result.executionTime, + id: undefined, // result was not saved yet + createdAt: undefined, // result was not saved yet + }); }); it('should save db index', async () => { const db = 2; - client.getCurrentDbIndex = jest.fn().mockResolvedValueOnce(db); + mockStandaloneRedisClient.getCurrentDbIndex.mockResolvedValueOnce(db); const result = await service.createCommandExecution( - client, + mockStandaloneRedisClient, mockCreateCommandExecutionDto, ); - expect(result).toMatchObject({ ...mockCommandExecutionToRun, db }); - expect(result.db).toBe(db); + expect(result).toEqual({ + ...mockCommandExecution, + executionTime: result.executionTime, + id: undefined, // result was not saved yet + createdAt: undefined, // result was not saved yet + db, + }); }); it('should save result as unsupported command message', async () => { - client.getCurrentDbIndex = jest.fn().mockResolvedValueOnce(0); + mockStandaloneRedisClient.getCurrentDbIndex = jest.fn().mockResolvedValueOnce(0); workbenchCommandsExecutor.sendCommand.mockResolvedValueOnce(mockCommandExecutionResults); const dto = { @@ -177,7 +149,7 @@ describe('WorkbenchService', () => { mode: RunQueryMode.ASCII, }; - expect(await service.createCommandExecution(client, dto)).toEqual({ + expect(await service.createCommandExecution(mockStandaloneRedisClient, dto)).toEqual({ ...dto, db: 0, databaseId: mockWorkbenchClientMetadata.databaseId, @@ -199,7 +171,7 @@ describe('WorkbenchService', () => { }; try { - await service.createCommandExecution(client, dto); + await service.createCommandExecution(mockStandaloneRedisClient, dto); fail(); } catch (e) { expect(e).toBeInstanceOf(BadRequestException); @@ -211,19 +183,18 @@ describe('WorkbenchService', () => { workbenchCommandsExecutor.sendCommand.mockResolvedValueOnce( [mockCommandExecutionResults, mockCommandExecutionResults], ); - commandExecutionProvider.createMany.mockResolvedValueOnce([mockCommandExecution, mockCommandExecution]); + commandExecutionRepository.createMany.mockResolvedValueOnce([mockCommandExecution, mockCommandExecution]); const result = await service.createCommandExecutions(mockWorkbenchClientMetadata, mockCreateCommandExecutionsDto); expect(result).toEqual([mockCommandExecution, mockCommandExecution]); }); - it('should successfully execute commands and save in group mode view', async () => { when(workbenchCommandsExecutor.sendCommand) - .calledWith(client, expect.anything()) + .calledWith(mockStandaloneRedisClient, expect.anything()) .mockResolvedValue([mockSendCommandResultSuccess]); - commandExecutionProvider.createMany.mockResolvedValueOnce([mockCommandExecutionWithGroupMode]); + commandExecutionRepository.createMany.mockResolvedValueOnce([mockCommandExecutionWithGroupMode]); const result = await service.createCommandExecutions( mockWorkbenchClientMetadata, @@ -232,13 +203,12 @@ describe('WorkbenchService', () => { expect(result).toEqual([mockCommandExecutionWithGroupMode]); }); - it('should successfully execute commands and save in silent mode view', async () => { when(workbenchCommandsExecutor.sendCommand) - .calledWith(client, expect.anything()) + .calledWith(mockStandaloneRedisClient, expect.anything()) .mockResolvedValue([mockSendCommandResultSuccess]); - commandExecutionProvider.createMany.mockResolvedValueOnce([mockCommandExecutionWithSilentMode]); + commandExecutionRepository.createMany.mockResolvedValueOnce([mockCommandExecutionWithSilentMode]); const result = await service.createCommandExecutions( mockWorkbenchClientMetadata, @@ -250,20 +220,20 @@ describe('WorkbenchService', () => { it('should successfully execute commands with error and save summary', async () => { when(workbenchCommandsExecutor.sendCommand) - .calledWith(client, { + .calledWith(mockStandaloneRedisClient, { ...mockCreateCommandExecutionDtoWithGroupMode, command: mockCommands[0], }) .mockResolvedValue([mockSendCommandResultSuccess]); when(workbenchCommandsExecutor.sendCommand) - .calledWith(client, { + .calledWith(mockStandaloneRedisClient, { ...mockCreateCommandExecutionDtoWithGroupMode, command: mockCommands[1], }) .mockResolvedValue([mockSendCommandResultFail]); - commandExecutionProvider.createMany.mockResolvedValueOnce([mockCommandExecutionWithGroupMode]); + commandExecutionRepository.createMany.mockResolvedValueOnce([mockCommandExecutionWithGroupMode]); const result = await service.createCommandExecutions( mockWorkbenchClientMetadata, @@ -275,20 +245,20 @@ describe('WorkbenchService', () => { it('should successfully execute commands with error and save summary in silent mode view', async () => { when(workbenchCommandsExecutor.sendCommand) - .calledWith(client, { + .calledWith(mockStandaloneRedisClient, { ...mockCreateCommandExecutionDtoWithSilentMode, command: mockCommands[0], }) .mockResolvedValue([mockSendCommandResultSuccess]); when(workbenchCommandsExecutor.sendCommand) - .calledWith(client, { + .calledWith(mockStandaloneRedisClient, { ...mockCreateCommandExecutionDtoWithSilentMode, command: mockCommands[1], }) .mockResolvedValue([mockSendCommandResultFail]); - commandExecutionProvider.createMany.mockResolvedValueOnce([mockCommandExecutionWithSilentMode]); + commandExecutionRepository.createMany.mockResolvedValueOnce([mockCommandExecutionWithSilentMode]); const result = await service.createCommandExecutions( mockWorkbenchClientMetadata, @@ -310,7 +280,7 @@ describe('WorkbenchService', () => { }); it('should throw an error from command execution provider (create)', async () => { workbenchCommandsExecutor.sendCommand.mockResolvedValueOnce([mockCommandExecutionResults]); - commandExecutionProvider.createMany.mockRejectedValueOnce(new InternalServerErrorException('db error')); + commandExecutionRepository.createMany.mockRejectedValueOnce(new InternalServerErrorException('db error')); try { await service.createCommandExecutions(mockWorkbenchClientMetadata, mockCreateCommandExecutionsDto); @@ -322,17 +292,17 @@ describe('WorkbenchService', () => { }); describe('listCommandExecutions', () => { it('should return list of command executions', async () => { - commandExecutionProvider.getList.mockResolvedValueOnce([mockCommandExecution, mockCommandExecution]); + commandExecutionRepository.getList.mockResolvedValueOnce([mockCommandExecution, mockCommandExecution]); - const result = await service.listCommandExecutions(mockWorkbenchClientMetadata); + const result = await service.listCommandExecutions(mockWorkbenchClientMetadata, mockCommandExecutionFilter); expect(result).toEqual([mockCommandExecution, mockCommandExecution]); }); it('should throw an error from command execution provider (getList)', async () => { - commandExecutionProvider.getList.mockRejectedValueOnce(new InternalServerErrorException()); + commandExecutionRepository.getList.mockRejectedValueOnce(new InternalServerErrorException()); try { - await service.listCommandExecutions(mockWorkbenchClientMetadata); + await service.listCommandExecutions(mockWorkbenchClientMetadata, mockCommandExecutionFilter); fail(); } catch (e) { expect(e).toBeInstanceOf(InternalServerErrorException); @@ -341,14 +311,14 @@ describe('WorkbenchService', () => { }); describe('getCommandExecution', () => { it('should return full command executions', async () => { - commandExecutionProvider.getOne.mockResolvedValueOnce(mockCommandExecution); + commandExecutionRepository.getOne.mockResolvedValueOnce(mockCommandExecution); const result = await service.getCommandExecution(mockWorkbenchClientMetadata, mockCommandExecution.id); expect(result).toEqual(mockCommandExecution); }); it('should throw an error from command execution provider (getOne)', async () => { - commandExecutionProvider.getOne.mockRejectedValueOnce(new InternalServerErrorException()); + commandExecutionRepository.getOne.mockRejectedValueOnce(new InternalServerErrorException()); try { await service.getCommandExecution(mockWorkbenchClientMetadata, mockCommandExecution.id); @@ -360,7 +330,7 @@ describe('WorkbenchService', () => { }); describe('deleteCommandExecution', () => { it('should not return anything on delete', async () => { - commandExecutionProvider.delete.mockResolvedValueOnce('some response'); + commandExecutionRepository.delete.mockResolvedValueOnce('some response'); const result = await service.deleteCommandExecution( mockWorkbenchClientMetadata, @@ -372,10 +342,11 @@ describe('WorkbenchService', () => { }); describe('deleteCommandExecutions', () => { it('should not return anything on delete', async () => { - commandExecutionProvider.deleteAll.mockResolvedValueOnce('some response'); + commandExecutionRepository.deleteAll.mockResolvedValueOnce('some response'); const result = await service.deleteCommandExecutions( mockWorkbenchClientMetadata, + mockCommandExecutionFilter, ); expect(result).toEqual(undefined); diff --git a/redisinsight/api/test/api/workbench/DELETE-databases-id-workbench-command_executions-id.test.ts b/redisinsight/api/test/api/workbench/DELETE-databases-id-workbench-command_executions-id.test.ts index 1aac29ec4f..193fa3aa5b 100644 --- a/redisinsight/api/test/api/workbench/DELETE-databases-id-workbench-command_executions-id.test.ts +++ b/redisinsight/api/test/api/workbench/DELETE-databases-id-workbench-command_executions-id.test.ts @@ -1,10 +1,9 @@ import { expect, describe, - it, deps, - validateApiCall, -} from '../deps'; + getMainCheckFn, +} from '../deps' const { server, request, constants, rte, localDb } = deps; // endpoint to test @@ -14,24 +13,7 @@ const endpoint = ( ) => request(server).delete(`/${constants.API.DATABASES}/${instanceId}/workbench/command-executions/${id}`); -const mainCheckFn = async (testCase) => { - it(testCase.name, async () => { - // additional checks before test run - if (testCase.before) { - await testCase.before(); - } - - await validateApiCall({ - endpoint, - ...testCase, - }); - - // additional checks after test pass - if (testCase.after) { - await testCase.after(); - } - }); -}; +const mainCheckFn = getMainCheckFn(endpoint); describe('DELETE /databases/:instanceId/workbench/command-executions/:commandExecutionId', () => { describe('Common', () => { diff --git a/redisinsight/api/test/api/workbench/DELETE-databases-id-workbench-command_executions.test.ts b/redisinsight/api/test/api/workbench/DELETE-databases-id-workbench-command_executions.test.ts index 671a25b733..81a9fb05fa 100644 --- a/redisinsight/api/test/api/workbench/DELETE-databases-id-workbench-command_executions.test.ts +++ b/redisinsight/api/test/api/workbench/DELETE-databases-id-workbench-command_executions.test.ts @@ -1,11 +1,11 @@ import { expect, describe, - it, deps, - validateApiCall, -} from '../deps'; -const { server, request, constants, rte, localDb } = deps; + getMainCheckFn, + Joi, generateInvalidDataTestCases, validateInvalidDataTestCase, +} from '../deps' +const { server, request, constants, localDb } = deps; // endpoint to test const endpoint = ( @@ -13,26 +13,26 @@ const endpoint = ( ) => request(server).delete(`/${constants.API.DATABASES}/${instanceId}/workbench/command-executions`); -const mainCheckFn = async (testCase) => { - it(testCase.name, async () => { - // additional checks before test run - if (testCase.before) { - await testCase.before(); - } +// input data schema +const dataSchema = Joi.object({ + type: Joi.string().valid('WORKBENCH', 'SEARCH').allow(null), +}).messages({ + 'any.required': '{#label} should not be empty', +}).strict(); - await validateApiCall({ - endpoint, - ...testCase, - }); - - // additional checks after test pass - if (testCase.after) { - await testCase.after(); - } - }); +const validInputData = { + type: 'WORKBENCH', }; +const mainCheckFn = getMainCheckFn(endpoint); + describe('DELETE /databases/:instanceId/workbench/command-executions', () => { + describe('Validation', () => { + generateInvalidDataTestCases(dataSchema, validInputData).map( + validateInvalidDataTestCase(endpoint, dataSchema), + ); + }); + describe('Common', () => { [ { @@ -61,4 +61,55 @@ describe('DELETE /databases/:instanceId/workbench/command-executions', () => { }, ].map(mainCheckFn); }); + describe('Filter', () => { + beforeEach(async () => { + await localDb.generateNCommandExecutions({ + databaseId: constants.TEST_INSTANCE_ID, + type: 'WORKBENCH', + }, 20, true); + await localDb.generateNCommandExecutions({ + databaseId: constants.TEST_INSTANCE_ID, + type: 'SEARCH', + }, 10, false); + }); + + [ + { + name: 'Should return 404 not found when incorrect instance', + endpoint: () => endpoint( + constants.TEST_NOT_EXISTED_INSTANCE_ID, + ), + statusCode: 404, + responseBody: { + statusCode: 404, + message: 'Invalid database instance id.', + error: 'Not Found' + }, + }, + { + name: 'Should return remove only WORKBENCH items (by default)', + after: async () => { + expect(await (await localDb.getRepository(localDb.repositories.COMMAND_EXECUTION)).count({})).to.eq(10) + }, + }, + { + name: 'Should return remove only WORKBENCH items', + data: { + type: 'WORKBENCH', + }, + after: async () => { + expect(await (await localDb.getRepository(localDb.repositories.COMMAND_EXECUTION)).count({})).to.eq(10) + }, + }, + { + name: 'Should return remove only SEARCH items', + data: { + type: 'SEARCH', + }, + after: async () => { + expect(await (await localDb.getRepository(localDb.repositories.COMMAND_EXECUTION)).count({})).to.eq(20) + }, + }, + ].map(mainCheckFn); + }); }); diff --git a/redisinsight/api/test/api/workbench/GET-databases-id-workbench-command_executions-id.test.ts b/redisinsight/api/test/api/workbench/GET-databases-id-workbench-command_executions-id.test.ts index c50e1324b0..62878b5b99 100644 --- a/redisinsight/api/test/api/workbench/GET-databases-id-workbench-command_executions-id.test.ts +++ b/redisinsight/api/test/api/workbench/GET-databases-id-workbench-command_executions-id.test.ts @@ -6,7 +6,7 @@ import { deps, validateApiCall, } from '../deps'; -const { server, request, constants, rte, localDb } = deps; +const { server, request, constants, localDb } = deps; // endpoint to test const endpoint = ( @@ -29,6 +29,7 @@ const responseSchema = Joi.object().keys({ executionTime: Joi.number().required(), db: Joi.number().integer().allow(null), createdAt: Joi.date().required(), + type: Joi.string().valid('WORKBENCH', 'SEARCH').required(), }).required(); const mainCheckFn = async (testCase) => { diff --git a/redisinsight/api/test/api/workbench/GET-databases-id-workbench-command_executions.test.ts b/redisinsight/api/test/api/workbench/GET-databases-id-workbench-command_executions.test.ts index f705326087..32fc90b682 100644 --- a/redisinsight/api/test/api/workbench/GET-databases-id-workbench-command_executions.test.ts +++ b/redisinsight/api/test/api/workbench/GET-databases-id-workbench-command_executions.test.ts @@ -1,11 +1,11 @@ import { expect, describe, - it, + before, Joi, deps, - validateApiCall, -} from '../deps'; + getMainCheckFn, +} from '../deps' const { server, request, constants, localDb } = deps; // endpoint to test @@ -28,26 +28,10 @@ const responseSchema = Joi.array().items(Joi.object().keys({ }).allow(null), db: Joi.number().integer().allow(null), createdAt: Joi.date().required(), + type: Joi.string().valid('WORKBENCH', 'SEARCH').required(), })).required().max(30); -const mainCheckFn = async (testCase) => { - it(testCase.name, async () => { - // additional checks before test run - if (testCase.before) { - await testCase.before(); - } - - await validateApiCall({ - endpoint, - ...testCase, - }); - - // additional checks after test pass - if (testCase.after) { - await testCase.after(); - } - }); -}; +const mainCheckFn = getMainCheckFn(endpoint); describe('GET /databases/:instanceId/workbench/command-executions', () => { describe('Common', () => { @@ -110,4 +94,58 @@ describe('GET /databases/:instanceId/workbench/command-executions', () => { }, ].map(mainCheckFn); }); + describe('Filter', () => { + before(async () => { + await localDb.generateNCommandExecutions({ + databaseId: constants.TEST_INSTANCE_ID, + type: 'WORKBENCH', + }, 20, true); + await localDb.generateNCommandExecutions({ + databaseId: constants.TEST_INSTANCE_ID, + type: 'SEARCH', + }, 10, false); + }); + + [ + { + name: 'Should get only 20 items (workbench by default)', + responseSchema, + checkFn: async ({ body }) => { + expect(body.length).to.eql(20); + for (let i = 0; i < 20; i ++) { + expect(body[i].command).to.eql('set foo bar'); + expect(body[i].type).to.eql('WORKBENCH'); + } + }, + }, + { + name: 'Should get only 20 items filtered by type (WORKBENCH)', + query: { + type: 'WORKBENCH', + }, + responseSchema, + checkFn: async ({ body }) => { + expect(body.length).to.eql(20); + for (let i = 0; i < 20; i ++) { + expect(body[i].command).to.eql('set foo bar'); + expect(body[i].type).to.eql('WORKBENCH'); + } + }, + }, + { + name: 'Should get only 10 items filtered by type (SEARCH)', + responseSchema, + query: { + type: 'SEARCH', + }, + checkFn: async ({ body }) => { + expect(body.length).to.eql(10); + for (let i = 0; i < 10; i ++) { + expect(body[i].command).to.eql('set foo bar'); + expect(body[i].type).to.eql('SEARCH'); + } + }, + }, + ].map(mainCheckFn); + }); }); diff --git a/redisinsight/api/test/api/workbench/POST-databases-id-workbench-command_executions.test.ts b/redisinsight/api/test/api/workbench/POST-databases-id-workbench-command_executions.test.ts index a98a551fc5..5fd42e4bcc 100644 --- a/redisinsight/api/test/api/workbench/POST-databases-id-workbench-command_executions.test.ts +++ b/redisinsight/api/test/api/workbench/POST-databases-id-workbench-command_executions.test.ts @@ -9,8 +9,8 @@ import { generateInvalidDataTestCases, validateInvalidDataTestCase, validateApiCall, - requirements, -} from '../deps'; + requirements, getMainCheckFn, +} from '../deps' import { convertArrayReplyToObject } from 'src/modules/redis/utils'; const { server, request, constants, rte, localDb } = deps; @@ -25,6 +25,7 @@ const dataSchema = Joi.object({ }), mode: Joi.string().valid('RAW', 'ASCII').allow(null), resultsMode: Joi.string().valid('DEFAULT', 'GROUP_MODE').allow(null), + type: Joi.string().valid('WORKBENCH', 'SEARCH').allow(null), }).messages({ 'any.required': '{#label} should not be empty', }).strict(); @@ -54,26 +55,10 @@ const responseSchema = Joi.array().items(Joi.object().keys({ success: Joi.number(), fail: Joi.number(), }), + type: Joi.string().valid('WORKBENCH', 'SEARCH').required(), })).required(); -const mainCheckFn = async (testCase) => { - it(testCase.name, async () => { - // additional checks before test run - if (testCase.before) { - await testCase.before(); - } - - await validateApiCall({ - endpoint, - ...testCase, - }); - - // additional checks after test pass - if (testCase.after) { - await testCase.after(); - } - }); -}; +const mainCheckFn = getMainCheckFn(endpoint); describe('POST /databases/:instanceId/workbench/command-executions', () => { before(rte.data.truncate); From 25792fa5710d13dc4d7e681e7e765c279f998b6e Mon Sep 17 00:00:00 2001 From: ArtemHoruzhenko Date: Tue, 10 Sep 2024 18:55:35 +0300 Subject: [PATCH 057/256] fix tests --- .../src/modules/workbench/plugins.service.ts | 6 ++--- ...ases-id-plugins-command_executions.test.ts | 24 ++++--------------- ...es-id-workbench-command_executions.test.ts | 10 ++++---- 3 files changed, 12 insertions(+), 28 deletions(-) diff --git a/redisinsight/api/src/modules/workbench/plugins.service.ts b/redisinsight/api/src/modules/workbench/plugins.service.ts index 8e05865d92..8ca00e88ba 100644 --- a/redisinsight/api/src/modules/workbench/plugins.service.ts +++ b/redisinsight/api/src/modules/workbench/plugins.service.ts @@ -49,13 +49,13 @@ export class PluginsService { }); } catch (error) { if (error instanceof CommandNotSupportedError) { - return new PluginCommandExecution({ + return plainToClass(PluginCommandExecution, { ...dto, databaseId: clientMetadata.databaseId, - result: [plainToClass(CommandExecutionResult, { + result: [{ response: error.message, status: CommandExecutionStatus.Fail, - })], + }], }); } diff --git a/redisinsight/api/test/api/plugins/POST-databases-id-plugins-command_executions.test.ts b/redisinsight/api/test/api/plugins/POST-databases-id-plugins-command_executions.test.ts index 0526aae7b4..2a8e9a6e20 100644 --- a/redisinsight/api/test/api/plugins/POST-databases-id-plugins-command_executions.test.ts +++ b/redisinsight/api/test/api/plugins/POST-databases-id-plugins-command_executions.test.ts @@ -8,8 +8,8 @@ import { generateInvalidDataTestCases, validateInvalidDataTestCase, validateApiCall, - requirements, -} from '../deps'; + requirements, getMainCheckFn, +} from '../deps' const { server, request, constants, rte, localDb } = deps; // endpoint to test @@ -40,26 +40,10 @@ const responseSchema = Joi.object().keys({ })), mode: Joi.string().required(), resultsMode: Joi.string().required(), + type: Joi.string().valid('WORKBENCH', 'SEARCH').required(), }).required(); -const mainCheckFn = async (testCase) => { - it(testCase.name, async () => { - // additional checks before test run - if (testCase.before) { - await testCase.before(); - } - - await validateApiCall({ - endpoint, - ...testCase, - }); - - // additional checks after test pass - if (testCase.after) { - await testCase.after(); - } - }); -}; +const mainCheckFn = getMainCheckFn(endpoint); describe('POST /databases/:instanceId/plugins/command-executions', () => { before(rte.data.truncate); diff --git a/redisinsight/api/test/api/workbench/POST-databases-id-workbench-command_executions.test.ts b/redisinsight/api/test/api/workbench/POST-databases-id-workbench-command_executions.test.ts index 5fd42e4bcc..e337f46ca1 100644 --- a/redisinsight/api/test/api/workbench/POST-databases-id-workbench-command_executions.test.ts +++ b/redisinsight/api/test/api/workbench/POST-databases-id-workbench-command_executions.test.ts @@ -71,7 +71,7 @@ describe('POST /databases/:instanceId/workbench/command-executions', () => { describe('Common', () => { describe('String', () => { - const bigStringValue = Buffer.alloc(1023 * 1024, 'a').toString(); + const bigStringValue = Buffer.alloc(10, 'a').toString(); [ { @@ -103,8 +103,8 @@ describe('POST /databases/:instanceId/workbench/command-executions', () => { }); expect(entity.encryption).to.eql(constants.TEST_ENCRYPTION_STRATEGY); - expect(localDb.encryptData(body[0].command)).to.eql(entity.command); - expect(localDb.encryptData(JSON.stringify(body[0].result))).to.eql(entity.result); + expect(body[0].command).to.eql(localDb.decryptData(entity.command)); + expect(body[0].result).to.eql(JSON.parse(localDb.decryptData(entity.result))); }, before: async () => { expect(await rte.client.set(constants.TEST_STRING_KEY_1, bigStringValue)); @@ -215,8 +215,8 @@ describe('POST /databases/:instanceId/workbench/command-executions', () => { }); expect(entity.encryption).to.eql(constants.TEST_ENCRYPTION_STRATEGY); - expect(localDb.encryptData(body[0].command)).to.eql(entity.command); - expect(localDb.encryptData(JSON.stringify(body[0].result))).to.eql(entity.result); + expect(body[0].command).to.eql(localDb.decryptData(entity.command)); + expect(body[0].result).to.eql(JSON.parse(localDb.decryptData(entity.result))); } }, { From 054a7e70ae051e4d54a878b98922e2878926a64a Mon Sep 17 00:00:00 2001 From: ArtemHoruzhenko Date: Tue, 10 Sep 2024 19:03:57 +0300 Subject: [PATCH 058/256] fix tests --- .../api/src/modules/workbench/plugins.service.spec.ts | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/redisinsight/api/src/modules/workbench/plugins.service.spec.ts b/redisinsight/api/src/modules/workbench/plugins.service.spec.ts index 4f75731fdf..89358ff46f 100644 --- a/redisinsight/api/src/modules/workbench/plugins.service.spec.ts +++ b/redisinsight/api/src/modules/workbench/plugins.service.spec.ts @@ -20,7 +20,7 @@ import { PluginStateRepository } from 'src/modules/workbench/repositories/plugin import { PluginState } from 'src/modules/workbench/models/plugin-state'; import config from 'src/utils/config'; import { DatabaseClientFactory } from 'src/modules/database/providers/database.client.factory'; -import { RunQueryMode } from 'src/modules/workbench/models/command-execution'; +import {CommandExecutionType, ResultsMode, RunQueryMode} from 'src/modules/workbench/models/command-execution' const PLUGINS_CONFIG = config.get('plugins'); @@ -101,11 +101,13 @@ describe('PluginsService', () => { const result = await service.sendCommand(mockWorkbenchClientMetadata, dto); - expect(result).toEqual(new PluginCommandExecution({ + expect(result).toEqual({ ...dto, databaseId: mockWorkbenchClientMetadata.databaseId, result: [mockCommandExecutionUnsupportedCommandResult], - })); + resultsMode: ResultsMode.Default, + type: CommandExecutionType.Workbench, + }); expect(workbenchCommandsExecutor.sendCommand).not.toHaveBeenCalled(); }); it('should throw an error when command execution failed', async () => { From efc04c7a4bb67427d10821d4333ed982a0a491df Mon Sep 17 00:00:00 2001 From: mariasergeenko Date: Wed, 11 Sep 2024 10:14:20 +0200 Subject: [PATCH 059/256] test for suggestions for fields --- .../search-and-query-tab.e2e.ts | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/tests/e2e/tests/web/regression/search-and-query/search-and-query-tab.e2e.ts b/tests/e2e/tests/web/regression/search-and-query/search-and-query-tab.e2e.ts index cc334fa495..e2be296bf2 100644 --- a/tests/e2e/tests/web/regression/search-and-query/search-and-query-tab.e2e.ts +++ b/tests/e2e/tests/web/regression/search-and-query/search-and-query-tab.e2e.ts @@ -311,3 +311,28 @@ test('Verify REDUCE commands', async t => { await t.pressKey('enter'); await t.typeText(searchAndQueryPage.queryInput, 'total_students'); }); +test('Verify suggestions for fields', async t => { + await t.typeText(searchAndQueryPage.queryInput, 'FT.AGGREGATE ', { replace: true }); + await t.typeText(searchAndQueryPage.queryInput, 'idx1'); + await t.pressKey('enter'); + await t.wait(200); + + await t.typeText(searchAndQueryPage.queryInput, '@'); + await t.expect(searchAndQueryPage.MonacoEditor.monacoSuggestion.visible).ok('Suggestions not displayed'); + + //verify suggestions for geo + await t.typeText(searchAndQueryPage.queryInput, 'l'); + await t.pressKey('tab'); + await t.expect((await searchAndQueryPage.MonacoEditor.getTextFromMonaco()).trim()).eql(`FT.AGGREGATE "${indexName1}" "@location:[lon lat radius unit]"`); + + //verify for numeric + await t.typeText(searchAndQueryPage.queryInput, 'FT.AGGREGATE ', { replace: true }); + await t.typeText(searchAndQueryPage.queryInput, 'idx1'); + await t.pressKey('enter'); + await t.wait(200); + + await t.typeText(searchAndQueryPage.queryInput, '@'); + await t.typeText(searchAndQueryPage.queryInput, 's'); + await t.pressKey('tab'); + await t.expect((await searchAndQueryPage.MonacoEditor.getTextFromMonaco()).trim()).eql(`FT.AGGREGATE "${indexName1}" "@students:[range]"`); +}); From 77b0a6297431d630113c2d3a1b9d91811e148837 Mon Sep 17 00:00:00 2001 From: ArtemHoruzhenko Date: Wed, 11 Sep 2024 15:44:55 +0300 Subject: [PATCH 060/256] add migrations --- .../1726058563737-command-execution.ts | 24 +++++++++++++++++++ redisinsight/api/migration/index.ts | 2 ++ 2 files changed, 26 insertions(+) create mode 100644 redisinsight/api/migration/1726058563737-command-execution.ts diff --git a/redisinsight/api/migration/1726058563737-command-execution.ts b/redisinsight/api/migration/1726058563737-command-execution.ts new file mode 100644 index 0000000000..e8df57332b --- /dev/null +++ b/redisinsight/api/migration/1726058563737-command-execution.ts @@ -0,0 +1,24 @@ +import { MigrationInterface, QueryRunner } from "typeorm"; + +export class CommandExecution1726058563737 implements MigrationInterface { + name = 'CommandExecution1726058563737' + + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query(`DROP INDEX "IDX_5cd90dd6def1fd7c521e53fb2c"`); + await queryRunner.query(`CREATE TABLE "temporary_command_execution" ("id" varchar PRIMARY KEY NOT NULL, "databaseId" varchar NOT NULL, "command" text NOT NULL, "result" text NOT NULL, "role" varchar, "nodeOptions" varchar, "encryption" varchar, "createdAt" datetime NOT NULL DEFAULT (datetime('now')), "mode" varchar, "resultsMode" varchar, "summary" varchar, "executionTime" integer, "db" integer, "type" varchar NOT NULL DEFAULT ('WORKBENCH'), CONSTRAINT "FK_ea8adfe9aceceb79212142206b8" FOREIGN KEY ("databaseId") REFERENCES "database_instance" ("id") ON DELETE CASCADE ON UPDATE NO ACTION)`); + await queryRunner.query(`INSERT INTO "temporary_command_execution"("id", "databaseId", "command", "result", "role", "nodeOptions", "encryption", "createdAt", "mode", "resultsMode", "summary", "executionTime", "db") SELECT "id", "databaseId", "command", "result", "role", "nodeOptions", "encryption", "createdAt", "mode", "resultsMode", "summary", "executionTime", "db" FROM "command_execution"`); + await queryRunner.query(`DROP TABLE "command_execution"`); + await queryRunner.query(`ALTER TABLE "temporary_command_execution" RENAME TO "command_execution"`); + await queryRunner.query(`CREATE INDEX "IDX_5cd90dd6def1fd7c521e53fb2c" ON "command_execution" ("createdAt") `); + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query(`DROP INDEX "IDX_5cd90dd6def1fd7c521e53fb2c"`); + await queryRunner.query(`ALTER TABLE "command_execution" RENAME TO "temporary_command_execution"`); + await queryRunner.query(`CREATE TABLE "command_execution" ("id" varchar PRIMARY KEY NOT NULL, "databaseId" varchar NOT NULL, "command" text NOT NULL, "result" text NOT NULL, "role" varchar, "nodeOptions" varchar, "encryption" varchar, "createdAt" datetime NOT NULL DEFAULT (datetime('now')), "mode" varchar, "resultsMode" varchar, "summary" varchar, "executionTime" integer, "db" integer, CONSTRAINT "FK_ea8adfe9aceceb79212142206b8" FOREIGN KEY ("databaseId") REFERENCES "database_instance" ("id") ON DELETE CASCADE ON UPDATE NO ACTION)`); + await queryRunner.query(`INSERT INTO "command_execution"("id", "databaseId", "command", "result", "role", "nodeOptions", "encryption", "createdAt", "mode", "resultsMode", "summary", "executionTime", "db") SELECT "id", "databaseId", "command", "result", "role", "nodeOptions", "encryption", "createdAt", "mode", "resultsMode", "summary", "executionTime", "db" FROM "temporary_command_execution"`); + await queryRunner.query(`DROP TABLE "temporary_command_execution"`); + await queryRunner.query(`CREATE INDEX "IDX_5cd90dd6def1fd7c521e53fb2c" ON "command_execution" ("createdAt") `); + } + +} diff --git a/redisinsight/api/migration/index.ts b/redisinsight/api/migration/index.ts index 621b74750d..60f4bda910 100644 --- a/redisinsight/api/migration/index.ts +++ b/redisinsight/api/migration/index.ts @@ -42,6 +42,7 @@ import { AiHistory1713515657364 } from './1713515657364-ai-history'; import { AiHistorySteps1714501203616 } from './1714501203616-ai-history-steps'; import { Rdi1716370509836 } from './1716370509836-rdi'; import { AiHistory1718260230164 } from './1718260230164-ai-history'; +import { CommandExecution1726058563737 } from './1726058563737-command-execution'; export default [ initialMigration1614164490968, @@ -88,4 +89,5 @@ export default [ AiHistorySteps1714501203616, Rdi1716370509836, AiHistory1718260230164, + CommandExecution1726058563737, ]; From 3928bf4ef5f55ca56c56564859f284187c1841b9 Mon Sep 17 00:00:00 2001 From: Roman Sergeenko Date: Wed, 11 Sep 2024 18:57:18 +0200 Subject: [PATCH 061/256] #RI-5992 - update search and query history --- .../components/query/query-card/QueryCard.tsx | 20 +-- .../QueryCardCliPlugin/QueryCardCliPlugin.tsx | 14 +- .../QueryCardHeader/QueryCardHeader.tsx | 69 +++++--- .../components/code-block/CodeBlock.tsx | 10 +- .../enablement-area/EnablementAreaWrapper.tsx | 10 +- .../src/pages/instance/InstancePage.spec.tsx | 2 + .../ui/src/pages/instance/InstancePage.tsx | 5 + .../ui/src/pages/search/SearchPage.tsx | 16 +- .../components/query-wrapper/QueryWrapper.tsx | 10 +- .../results-history/ResultsHistory.spec.tsx | 149 +++++++++++++++++- .../results-history/ResultsHistory.tsx | 99 +++++++++++- .../results-history/styles.module.scss | 11 ++ .../ui/src/pages/workbench/WorkbenchPage.tsx | 8 +- .../components/wb-view/WBViewWrapper.tsx | 22 ++- redisinsight/ui/src/slices/app/context.ts | 4 +- redisinsight/ui/src/slices/app/plugins.ts | 23 ++- .../ui/src/slices/interfaces/workbench.ts | 5 + .../ui/src/slices/workbench/wb-results.ts | 25 ++- redisinsight/ui/src/telemetry/events.ts | 10 ++ 19 files changed, 427 insertions(+), 85 deletions(-) diff --git a/redisinsight/ui/src/components/query/query-card/QueryCard.tsx b/redisinsight/ui/src/components/query/query-card/QueryCard.tsx index d1890eaada..29b9192bbe 100644 --- a/redisinsight/ui/src/components/query/query-card/QueryCard.tsx +++ b/redisinsight/ui/src/components/query/query-card/QueryCard.tsx @@ -5,15 +5,9 @@ import { EuiLoadingContent, keys } from '@elastic/eui' import { useParams } from 'react-router-dom' import { isNull } from 'lodash' -import { WBQueryType, ProfileQueryType, DEFAULT_TEXT_VIEW_TYPE } from 'uiSrc/pages/workbench/constants' -import { RunQueryMode, ResultsMode, ResultsSummary } from 'uiSrc/slices/interfaces/workbench' -import { - getWBQueryType, - getVisualizationsByCommand, - Maybe, - isGroupResults, - isSilentModeWithoutError, -} from 'uiSrc/utils' +import { DEFAULT_TEXT_VIEW_TYPE, ProfileQueryType, WBQueryType } from 'uiSrc/pages/workbench/constants' +import { CommandExecutionType, ResultsMode, ResultsSummary, RunQueryMode } from 'uiSrc/slices/interfaces/workbench' +import { getVisualizationsByCommand, getWBQueryType, isGroupResults, isSilentModeWithoutError, Maybe, } from 'uiSrc/utils' import { appPluginsSelector } from 'uiSrc/slices/app/plugins' import { CommandExecutionResult, IPluginVisualization } from 'uiSrc/slices/interfaces' import { sendEventTelemetry, TelemetryEvent } from 'uiSrc/telemetry' @@ -36,6 +30,7 @@ export interface Props { activeResultsMode?: ResultsMode resultsMode?: ResultsMode emptyCommand?: boolean + executionType?: CommandExecutionType summary?: ResultsSummary createdAt?: Date loading?: boolean @@ -73,6 +68,7 @@ const QueryCard = (props: Props) => { mode, activeResultsMode, resultsMode, + executionType = CommandExecutionType.Workbench, summary, isOpen, createdAt, @@ -117,7 +113,9 @@ const QueryCard = (props: Props) => { const toggleFullScreen = () => { setIsFullScreen((isFull) => { sendEventTelemetry({ - event: TelemetryEvent.WORKBENCH_RESULTS_IN_FULL_SCREEN, + event: executionType === CommandExecutionType.Search + ? TelemetryEvent.SEARCH_RESULTS_IN_FULL_SCREEN + : TelemetryEvent.WORKBENCH_RESULTS_IN_FULL_SCREEN, eventData: { databaseId: instanceId, state: isFull ? 'Close' : 'Open' @@ -184,6 +182,7 @@ const QueryCard = (props: Props) => { mode={mode} resultsMode={resultsMode} activeResultsMode={activeResultsMode} + executionType={executionType} emptyCommand={emptyCommand} summary={summary} summaryText={getSummaryText(summary, resultsMode)} @@ -224,6 +223,7 @@ const QueryCard = (props: Props) => { result={result} query={command} mode={mode} + executionType={executionType} setMessage={setMessage} commandId={id} /> diff --git a/redisinsight/ui/src/components/query/query-card/QueryCardCliPlugin/QueryCardCliPlugin.tsx b/redisinsight/ui/src/components/query/query-card/QueryCardCliPlugin/QueryCardCliPlugin.tsx index 0b07487bca..629b849408 100644 --- a/redisinsight/ui/src/components/query/query-card/QueryCardCliPlugin/QueryCardCliPlugin.tsx +++ b/redisinsight/ui/src/components/query/query-card/QueryCardCliPlugin/QueryCardCliPlugin.tsx @@ -7,7 +7,7 @@ import { pluginApi } from 'uiSrc/services/PluginAPI' import { ThemeContext } from 'uiSrc/contexts/themeContext' import { getBaseApiUrl, Nullable, formatToText, replaceEmptyValue } from 'uiSrc/utils' import { Theme } from 'uiSrc/constants' -import { CommandExecutionResult, IPluginVisualization, RunQueryMode } from 'uiSrc/slices/interfaces' +import { CommandExecutionResult, CommandExecutionType, IPluginVisualization, RunQueryMode } from 'uiSrc/slices/interfaces' import { PluginEvents } from 'uiSrc/plugins/pluginEvents' import { prepareIframeHtml } from 'uiSrc/plugins/pluginImport' import { @@ -28,6 +28,7 @@ export interface Props { setMessage: (text: string) => void commandId: string mode?: RunQueryMode + executionType?: CommandExecutionType } enum StylesNamePostfix { @@ -44,7 +45,15 @@ enum ActionTypes { const baseUrl = getBaseApiUrl() const QueryCardCliPlugin = (props: Props) => { - const { query, id, result, setMessage, commandId, mode = RunQueryMode.Raw } = props + const { + query, + id, + result, + setMessage, + commandId, + mode = RunQueryMode.Raw, + executionType + } = props const { visualizations = [], staticPath } = useSelector(appPluginsSelector) const { modules = [] } = useSelector(connectedInstanceSelector) const serverInfo = useSelector(appServerInfoSelector) @@ -84,6 +93,7 @@ const QueryCardCliPlugin = (props: Props) => { dispatch( sendPluginCommandAction({ command, + executionType, onSuccessAction: (response) => { sendMessageToPlugin({ ...commonOptions, diff --git a/redisinsight/ui/src/components/query/query-card/QueryCardHeader/QueryCardHeader.tsx b/redisinsight/ui/src/components/query/query-card/QueryCardHeader/QueryCardHeader.tsx index f2de4c4f30..fe9d8b4b6d 100644 --- a/redisinsight/ui/src/components/query/query-card/QueryCardHeader/QueryCardHeader.tsx +++ b/redisinsight/ui/src/components/query/query-card/QueryCardHeader/QueryCardHeader.tsx @@ -19,21 +19,27 @@ import { getCommandNameFromQuery, getVisualizationsByCommand, isGroupMode, - truncateText, - urlForAsset, - truncateMilliseconds, + isGroupResults, isRawMode, isSilentMode, isSilentModeWithoutError, - isGroupResults, + truncateMilliseconds, + truncateText, + urlForAsset, } from 'uiSrc/utils' import { numberWithSpaces } from 'uiSrc/utils/numbers' import { ThemeContext } from 'uiSrc/contexts/themeContext' import { appPluginsSelector } from 'uiSrc/slices/app/plugins' import { sendEventTelemetry, TelemetryEvent } from 'uiSrc/telemetry' -import { getViewTypeOptions, WBQueryType, getProfileViewTypeOptions, ProfileQueryType, isCommandAllowedForProfile } from 'uiSrc/pages/workbench/constants' -import { IPluginVisualization } from 'uiSrc/slices/interfaces' -import { RunQueryMode, ResultsMode, ResultsSummary } from 'uiSrc/slices/interfaces/workbench' +import { + getProfileViewTypeOptions, + getViewTypeOptions, + isCommandAllowedForProfile, + ProfileQueryType, + WBQueryType +} from 'uiSrc/pages/workbench/constants' +import { CommandExecutionType, IPluginVisualization } from 'uiSrc/slices/interfaces' +import { ResultsMode, ResultsSummary, RunQueryMode } from 'uiSrc/slices/interfaces/workbench' import { appRedisCommandsSelector } from 'uiSrc/slices/app/redis-commands' import { FormatedDate, FullScreen } from 'uiSrc/components' @@ -57,6 +63,7 @@ export interface Props { mode?: RunQueryMode resultsMode?: ResultsMode activeResultsMode?: ResultsMode + executionType?: CommandExecutionType summary?: ResultsSummary summaryText?: string queryType: WBQueryType @@ -102,6 +109,7 @@ const QueryCardHeader = (props: Props) => { createdAt, mode, resultsMode, + executionType, summary, activeResultsMode, summaryText, @@ -121,6 +129,7 @@ const QueryCardHeader = (props: Props) => { const { instanceId = '' } = useParams<{ instanceId: string }>() const { theme } = useContext(ThemeContext) + const isExecuteTypeSearch = executionType === CommandExecutionType.Search const eventStop = (event: React.MouseEvent) => { event.preventDefault() @@ -139,7 +148,12 @@ const QueryCardHeader = (props: Props) => { } const handleCopy = (event: React.MouseEvent, query: string) => { - sendEvent(TelemetryEvent.WORKBENCH_COMMAND_COPIED, query) + sendEvent( + isExecuteTypeSearch + ? TelemetryEvent.SEARCH_COMMAND_COPIED + : TelemetryEvent.WORKBENCH_COMMAND_COPIED, + query + ) eventStop(event) navigator.clipboard?.writeText?.(query) } @@ -154,24 +168,29 @@ const QueryCardHeader = (props: Props) => { const previousView = options.find(({ id }) => id === selectedValue) const type = currentView.value setSelectedValue(type as WBQueryType, initValue) - sendEvent( - TelemetryEvent.WORKBENCH_RESULT_VIEW_CHANGED, - query, - { - rawMode: isRawMode(activeMode), - group: isGroupMode(activeResultsMode), - previousView: previousView?.name, - isPreviousViewInternal: !!previousView?.internal, - currentView: currentView?.name, - isCurrentViewInternal: !!currentView?.internal, - } - ) + sendEvent(isExecuteTypeSearch + ? TelemetryEvent.SEARCH_RESULT_VIEW_CHANGED + : TelemetryEvent.WORKBENCH_RESULT_VIEW_CHANGED, + query, + { + rawMode: isRawMode(activeMode), + group: isGroupMode(activeResultsMode), + previousView: previousView?.name, + isPreviousViewInternal: !!previousView?.internal, + currentView: currentView?.name, + isCurrentViewInternal: !!currentView?.internal, + }) } const handleQueryDelete = (event: React.MouseEvent) => { eventStop(event) onQueryDelete() - sendEvent(TelemetryEvent.WORKBENCH_CLEAR_RESULT_CLICKED, query) + sendEvent( + isExecuteTypeSearch + ? TelemetryEvent.SEARCH_CLEAR_RESULT_CLICKED + : TelemetryEvent.WORKBENCH_CLEAR_RESULT_CLICKED, + query + ) } const handleQueryReRun = (event: React.MouseEvent) => { @@ -181,8 +200,14 @@ const QueryCardHeader = (props: Props) => { const handleToggleOpen = () => { if (!isFullScreen && !isSilentModeWithoutError(resultsMode, summary?.fail)) { + const collapsedEventName = isExecuteTypeSearch + ? TelemetryEvent.SEARCH_RESULTS_COLLAPSED + : TelemetryEvent.WORKBENCH_RESULTS_COLLAPSED + const expandedEventName = isExecuteTypeSearch + ? TelemetryEvent.SEARCH_RESULTS_EXPANDED + : TelemetryEvent.WORKBENCH_RESULTS_EXPANDED sendEvent( - isOpen ? TelemetryEvent.WORKBENCH_RESULTS_COLLAPSED : TelemetryEvent.WORKBENCH_RESULTS_EXPANDED, + isOpen ? collapsedEventName : expandedEventName, query ) } diff --git a/redisinsight/ui/src/components/side-panels/panels/ai-assistant/components/shared/markdown-message/components/code-block/CodeBlock.tsx b/redisinsight/ui/src/components/side-panels/panels/ai-assistant/components/shared/markdown-message/components/code-block/CodeBlock.tsx index 30b51199a4..582e9b94c8 100644 --- a/redisinsight/ui/src/components/side-panels/panels/ai-assistant/components/shared/markdown-message/components/code-block/CodeBlock.tsx +++ b/redisinsight/ui/src/components/side-panels/panels/ai-assistant/components/shared/markdown-message/components/code-block/CodeBlock.tsx @@ -4,6 +4,7 @@ import { CodeButtonParams } from 'uiSrc/constants' import { sendWbQueryAction } from 'uiSrc/slices/workbench/wb-results' import { CodeButtonBlock } from 'uiSrc/components/markdown' import { ButtonLang } from 'uiSrc/utils/formatters/markdown/remarkCode' +import { CommandExecutionType } from 'uiSrc/slices/interfaces' import { AdditionalRedisModule } from 'apiSrc/modules/database/models/additional.redis.module' export interface Props { @@ -20,7 +21,14 @@ const CodeBlock = (props: Props) => { const handleApply = (params?: CodeButtonParams, onFinish?: () => void) => { onRunCommand?.(children) - dispatch(sendWbQueryAction(children, null, params, { afterAll: onFinish }, onFinish)) + dispatch(sendWbQueryAction( + children, + null, + params, + CommandExecutionType.Workbench, + { afterAll: onFinish }, + onFinish + )) } return ( diff --git a/redisinsight/ui/src/components/side-panels/panels/enablement-area/EnablementAreaWrapper.tsx b/redisinsight/ui/src/components/side-panels/panels/enablement-area/EnablementAreaWrapper.tsx index 72acc86174..e94b0ee661 100644 --- a/redisinsight/ui/src/components/side-panels/panels/enablement-area/EnablementAreaWrapper.tsx +++ b/redisinsight/ui/src/components/side-panels/panels/enablement-area/EnablementAreaWrapper.tsx @@ -7,6 +7,7 @@ import { workbenchCustomTutorialsSelector } from 'uiSrc/slices/workbench/wb-cust import { sendEventTelemetry, TELEMETRY_EMPTY_VALUE, TelemetryEvent } from 'uiSrc/telemetry' import { CodeButtonParams } from 'uiSrc/constants' import { sendWbQueryAction } from 'uiSrc/slices/workbench/wb-results' +import { CommandExecutionType } from 'uiSrc/slices/interfaces' import { getTutorialSection } from './EnablementArea/utils' import EnablementArea from './EnablementArea' @@ -26,7 +27,14 @@ const EnablementAreaWrapper = () => { params?: CodeButtonParams, onFinish?: () => void ) => { - dispatch(sendWbQueryAction(script, null, params, { afterAll: onFinish }, onFinish)) + dispatch(sendWbQueryAction( + script, + null, + params, + CommandExecutionType.Workbench, + { afterAll: onFinish }, + onFinish + )) } const onOpenInternalPage = ({ path, manifestPath }: IInternalPage) => { diff --git a/redisinsight/ui/src/pages/instance/InstancePage.spec.tsx b/redisinsight/ui/src/pages/instance/InstancePage.spec.tsx index bf183f94a8..e8f2b7fb53 100644 --- a/redisinsight/ui/src/pages/instance/InstancePage.spec.tsx +++ b/redisinsight/ui/src/pages/instance/InstancePage.spec.tsx @@ -28,6 +28,7 @@ import { } from 'uiSrc/slices/instances/instances' import { resetConnectedInstance as resetRdiConnectedInstance } from 'uiSrc/slices/rdi/instances' import { clearExpertChatHistory } from 'uiSrc/slices/panels/aiAssistant' +import { getAllPlugins } from 'uiSrc/slices/app/plugins' import InstancePage, { Props } from './InstancePage' const INSTANCE_ID_MOCK = 'instanceId' @@ -119,6 +120,7 @@ describe('InstancePage', () => { ] const expectedActions = [ + getAllPlugins(), setDefaultInstance(), setConnectedInstance(), getDatabaseConfigInfo(), diff --git a/redisinsight/ui/src/pages/instance/InstancePage.tsx b/redisinsight/ui/src/pages/instance/InstancePage.tsx index 220d238588..7f71ad7b49 100644 --- a/redisinsight/ui/src/pages/instance/InstancePage.tsx +++ b/redisinsight/ui/src/pages/instance/InstancePage.tsx @@ -23,6 +23,7 @@ import { localStorageService } from 'uiSrc/services' import { InstancePageTemplate } from 'uiSrc/templates' import { getPageName } from 'uiSrc/utils/routing' import { resetConnectedInstance as resetRdiConnectedInstance } from 'uiSrc/slices/rdi/instances' +import { loadPluginsAction } from 'uiSrc/slices/app/plugins' import InstancePageRouter from './InstancePageRouter' export interface Props { @@ -41,6 +42,10 @@ const InstancePage = ({ routes = [] }: Props) => { const lastPageRef = useRef() + useEffect(() => { + dispatch(loadPluginsAction()) + }, []) + useEffect(() => { dispatch(fetchConnectedInstanceAction(connectionInstanceId, () => { !modulesData.length && dispatch(fetchInstancesAction()) diff --git a/redisinsight/ui/src/pages/search/SearchPage.tsx b/redisinsight/ui/src/pages/search/SearchPage.tsx index f4e2562541..10c267ec84 100644 --- a/redisinsight/ui/src/pages/search/SearchPage.tsx +++ b/redisinsight/ui/src/pages/search/SearchPage.tsx @@ -4,10 +4,7 @@ import { EuiResizableContainer } from '@elastic/eui' import { useDispatch, useSelector } from 'react-redux' import { useParams } from 'react-router-dom' -import { - appContextSearchAndQuery, - setSQVerticalPanelSizes, -} from 'uiSrc/slices/app/context' +import { appContextSearchAndQuery, setSQVerticalPanelSizes, } from 'uiSrc/slices/app/context' import { QueryWrapper, ResultsHistory } from 'uiSrc/pages/search/components' import { sendWbQueryAction } from 'uiSrc/slices/workbench/wb-results' @@ -17,6 +14,8 @@ import { connectedInstanceSelector } from 'uiSrc/slices/instances/instances' import { sendPageViewTelemetry, TelemetryPageView } from 'uiSrc/telemetry' import { CodeButtonParams } from 'uiSrc/constants' +import { CommandExecutionType } from 'uiSrc/slices/interfaces' +import { appRedisCommandsSelector } from 'uiSrc/slices/app/redis-commands' import styles from './styles.module.scss' const verticalPanelIds = { @@ -26,6 +25,8 @@ const verticalPanelIds = { const SearchPage = () => { const { name: connectedInstanceName, db } = useSelector(connectedInstanceSelector) + const { commandsArray } = useSelector(appRedisCommandsSelector) + const { panelSizes: { vertical } } = useSelector(appContextSearchAndQuery) const [isPageViewSent, setIsPageViewSent] = useState(false) @@ -71,7 +72,8 @@ const SearchPage = () => { { ...executeParams, results: 'single', - } + }, + CommandExecutionType.Search )) } @@ -91,7 +93,7 @@ const SearchPage = () => { initialSize={vertical[verticalPanelIds.firstPanelId] ?? 20} style={{ minHeight: '240px', zIndex: '8' }} > - + { // Fix scroll on low height - 140px (queryPanel) style={{ maxHeight: 'calc(100% - 240px)' }} > - + )} diff --git a/redisinsight/ui/src/pages/search/components/query-wrapper/QueryWrapper.tsx b/redisinsight/ui/src/pages/search/components/query-wrapper/QueryWrapper.tsx index 2d47aeaa91..1db85cde05 100644 --- a/redisinsight/ui/src/pages/search/components/query-wrapper/QueryWrapper.tsx +++ b/redisinsight/ui/src/pages/search/components/query-wrapper/QueryWrapper.tsx @@ -8,11 +8,10 @@ import { CodeButtonParams } from 'uiSrc/constants' import { getCommandsFromQuery, Nullable } from 'uiSrc/utils' import { changeSQActiveRunQueryMode, searchAndQuerySelector } from 'uiSrc/slices/search/searchAndQuery' -import { appContextSearchAndQuery, setSQVerticalScript } from 'uiSrc/slices/app/context' +import { appContextSearchAndQuery, setSQScript } from 'uiSrc/slices/app/context' import { sendEventTelemetry, TelemetryEvent } from 'uiSrc/telemetry' import { fetchRedisearchListAction, redisearchListSelector } from 'uiSrc/slices/browser/redisearch' import { connectedInstanceSelector } from 'uiSrc/slices/instances/instances' -import { appRedisCommandsSelector } from 'uiSrc/slices/app/redis-commands' import { SUPPORTED_COMMANDS_LIST } from 'uiSrc/pages/search/components/query/constants' import { SearchCommand } from 'uiSrc/pages/search/types' import { TUTORIALS } from './constants' @@ -24,6 +23,7 @@ import Query from '../query' import styles from './styles.module.scss' export interface Props { + commandsArray?: string[] onSubmit: ( commandInit: string, commandId?: Nullable, @@ -32,13 +32,12 @@ export interface Props { } const QueryWrapper = (props: Props) => { - const { onSubmit } = props + const { commandsArray = [], onSubmit } = props const { id: connectedIndstanceId } = useSelector(connectedInstanceSelector) const { script: scriptContext } = useSelector(appContextSearchAndQuery) const { activeRunQueryMode } = useSelector(searchAndQuerySelector) const { data: indexes = [] } = useSelector(redisearchListSelector) - const { commandsArray } = useSelector(appRedisCommandsSelector) const [value, setValue] = useState(scriptContext) @@ -55,7 +54,7 @@ const QueryWrapper = (props: Props) => { const dispatch = useDispatch() useEffect(() => () => { - dispatch(setSQVerticalScript(scriptRef.current)) + dispatch(setSQScript(scriptRef.current)) }, []) useEffect(() => { @@ -87,7 +86,6 @@ const QueryWrapper = (props: Props) => { eventData: { databaseId: instanceId, mode: activeRunQueryMode, - // TODO sanitize user query command: getCommandsFromQuery(value, commandsArray) || '' } }) diff --git a/redisinsight/ui/src/pages/search/components/results-history/ResultsHistory.spec.tsx b/redisinsight/ui/src/pages/search/components/results-history/ResultsHistory.spec.tsx index 21d2666793..a152317088 100644 --- a/redisinsight/ui/src/pages/search/components/results-history/ResultsHistory.spec.tsx +++ b/redisinsight/ui/src/pages/search/components/results-history/ResultsHistory.spec.tsx @@ -1,10 +1,157 @@ import React from 'react' -import { render, screen } from 'uiSrc/utils/test-utils' +import { cloneDeep } from 'lodash' +import { cleanup, fireEvent, mockedStore, render, screen } from 'uiSrc/utils/test-utils' +import { sendEventTelemetry, TelemetryEvent } from 'uiSrc/telemetry' +import { INSTANCE_ID_MOCK } from 'uiSrc/mocks/handlers/analytics/clusterDetailsHandlers' +import { + clearWbResults, + loadWBHistory, + processWBCommand, + workbenchResultsSelector +} from 'uiSrc/slices/workbench/wb-results' import ResultsHistory from './ResultsHistory' +jest.mock('uiSrc/telemetry', () => ({ + ...jest.requireActual('uiSrc/telemetry'), + sendEventTelemetry: jest.fn(), +})) + +jest.mock('uiSrc/slices/workbench/wb-results', () => ({ + ...jest.requireActual('uiSrc/slices/workbench/wb-results'), + workbenchResultsSelector: jest.fn().mockReturnValue({ + loading: false, + items: [] + }) +})) + +let store: typeof mockedStore +beforeEach(() => { + cleanup() + store = cloneDeep(mockedStore) + store.clearActions() +}) + describe('ResultsHistory', () => { it('should render', () => { expect(render()).toBeTruthy() }) + + it('should call proper actions on rerun', async () => { + const onSubmit = jest.fn() + const sendEventTelemetryMock = jest.fn(); + (sendEventTelemetry as jest.Mock).mockImplementation(() => sendEventTelemetryMock); + + (workbenchResultsSelector as jest.Mock).mockReturnValue({ + items: [ + { + mode: 'RAW', + resultsMode: 'DEFAULT', + id: '9dda0f6d-9265-4b15-b627-82d2eb867605', + databaseId: '18c37d1d-bc25-4e46-a20d-a1f9bf228946', + command: 'info', + summary: null, + createdAt: '2022-09-28T18:04:46.000Z', + emptyCommand: false + } + ] + }) + + render() + + fireEvent.click(screen.getByTestId('re-run-command')) + + expect(sendEventTelemetry).toBeCalledWith({ + event: TelemetryEvent.SEARCH_COMMAND_RUN_AGAIN, + eventData: { + command: 'INFO', + databaseId: INSTANCE_ID_MOCK, + mode: 'RAW' + } + }); + (sendEventTelemetry as jest.Mock).mockRestore() + + expect(onSubmit).toBeCalledWith( + 'info', + '9dda0f6d-9265-4b15-b627-82d2eb867605', + { mode: 'RAW' } + ) + }) + + it('should call proper actions on delete', async () => { + const onSubmit = jest.fn() + const sendEventTelemetryMock = jest.fn(); + (sendEventTelemetry as jest.Mock).mockImplementation(() => sendEventTelemetryMock); + + (workbenchResultsSelector as jest.Mock).mockReturnValue({ + items: [ + { + mode: 'RAW', + resultsMode: 'DEFAULT', + id: '9dda0f6d-9265-4b15-b627-82d2eb867605', + databaseId: '18c37d1d-bc25-4e46-a20d-a1f9bf228946', + command: 'info', + summary: null, + createdAt: '2022-09-28T18:04:46.000Z', + emptyCommand: false + } + ] + }) + + render() + + fireEvent.click(screen.getByTestId('delete-command')) + + expect(sendEventTelemetry).toBeCalledWith({ + event: TelemetryEvent.SEARCH_CLEAR_RESULT_CLICKED, + eventData: { + command: 'info', + databaseId: INSTANCE_ID_MOCK, + } + }); + (sendEventTelemetry as jest.Mock).mockRestore() + + expect(store.getActions()).toEqual([ + loadWBHistory(), + processWBCommand('9dda0f6d-9265-4b15-b627-82d2eb867605') + ]) + }) + + it('should call proper actions on clear all commands', async () => { + const onSubmit = jest.fn() + const sendEventTelemetryMock = jest.fn(); + (sendEventTelemetry as jest.Mock).mockImplementation(() => sendEventTelemetryMock); + + (workbenchResultsSelector as jest.Mock).mockReturnValue({ + items: [ + { + mode: 'RAW', + resultsMode: 'DEFAULT', + id: '9dda0f6d-9265-4b15-b627-82d2eb867605', + databaseId: '18c37d1d-bc25-4e46-a20d-a1f9bf228946', + command: 'info', + summary: null, + createdAt: '2022-09-28T18:04:46.000Z', + emptyCommand: false + } + ] + }) + + render() + + fireEvent.click(screen.getByTestId('clear-history-btn')) + + expect(sendEventTelemetry).toBeCalledWith({ + event: TelemetryEvent.SEARCH_CLEAR_ALL_RESULTS_CLICKED, + eventData: { + databaseId: INSTANCE_ID_MOCK, + } + }); + (sendEventTelemetry as jest.Mock).mockRestore() + + expect(store.getActions()).toEqual([ + loadWBHistory(), + clearWbResults() + ]) + }) }) diff --git a/redisinsight/ui/src/pages/search/components/results-history/ResultsHistory.tsx b/redisinsight/ui/src/pages/search/components/results-history/ResultsHistory.tsx index b15b21dace..d03724bf7c 100644 --- a/redisinsight/ui/src/pages/search/components/results-history/ResultsHistory.tsx +++ b/redisinsight/ui/src/pages/search/components/results-history/ResultsHistory.tsx @@ -4,25 +4,41 @@ import cx from 'classnames' import { useDispatch, useSelector } from 'react-redux' import { useParams } from 'react-router-dom' -import { Nullable } from 'uiSrc/utils' +import { EuiButtonEmpty, EuiProgress } from '@elastic/eui' +import { getCommandsFromQuery, Nullable } from 'uiSrc/utils' import { QueryCard } from 'uiSrc/components/query' -import { fetchWBCommandAction, fetchWBHistoryAction, workbenchResultsSelector } from 'uiSrc/slices/workbench/wb-results' +import { + clearWbResultsAction, + deleteWBCommandAction, + fetchWBCommandAction, + fetchWBHistoryAction, + resetWBHistoryItems, + workbenchResultsSelector +} from 'uiSrc/slices/workbench/wb-results' import { searchAndQuerySelector } from 'uiSrc/slices/search/searchAndQuery' +import { CommandExecutionType, RunQueryMode } from 'uiSrc/slices/interfaces' +import { sendEventTelemetry, TelemetryEvent } from 'uiSrc/telemetry' +import { ProfileQueryType } from 'uiSrc/pages/workbench/constants' +import { generateProfileQueryForCommand } from 'uiSrc/pages/workbench/utils' +import { CodeButtonParams } from 'uiSrc/constants' import styles from './styles.module.scss' export interface Props { + commandsArray?: string[] onSubmit: ( commandInit: string, commandId?: Nullable, + executeParams?: CodeButtonParams ) => void } const ResultsHistory = (props: Props) => { - const { onSubmit } = props + const { commandsArray = [], onSubmit } = props const { items, clearing, + isLoaded } = useSelector(workbenchResultsSelector) const { activeRunQueryMode } = useSelector(searchAndQuerySelector) @@ -30,15 +46,82 @@ const ResultsHistory = (props: Props) => { const { instanceId } = useParams<{ instanceId: string }>() useEffect(() => { - dispatch(fetchWBHistoryAction(instanceId)) + dispatch(fetchWBHistoryAction(instanceId, CommandExecutionType.Search)) + + return () => { + dispatch(resetWBHistoryItems()) + } }, []) const handleQueryOpen = (commandId: string = '') => { dispatch(fetchWBCommandAction(commandId)) } + const handleQueryDelete = (commandId: string) => { + dispatch(deleteWBCommandAction(commandId)) + } + + const handleAllQueriesDelete = () => { + dispatch(clearWbResultsAction(CommandExecutionType.Search)) + sendEventTelemetry({ + event: TelemetryEvent.SEARCH_CLEAR_ALL_RESULTS_CLICKED, + eventData: { + databaseId: instanceId, + } + }) + } + + const handleQueryReRun = ( + query: string, + commandId?: Nullable, + mode?: RunQueryMode + ) => { + sendEventTelemetry({ + event: TelemetryEvent.SEARCH_COMMAND_RUN_AGAIN, + eventData: { + databaseId: instanceId, + command: getCommandsFromQuery(query, commandsArray) || '', + mode + } + }) + onSubmit(query, commandId, { mode }) + } + + const handleQueryProfile = ( + profileType: ProfileQueryType, + commandExecution: { command: string, mode?: RunQueryMode } + ) => { + const { command, mode } = commandExecution + const profileQuery = generateProfileQueryForCommand(command, profileType) + if (profileQuery) { + onSubmit(command, null, { mode }) + } + } + return (
+ {!isLoaded && ( + + )} + {!!items?.length && ( +
+ + Clear Results + +
+ )}
{items?.length ? items.map(( @@ -72,11 +155,13 @@ const ResultsHistory = (props: Props) => { executionTime={executionTime} mode={mode} activeMode={activeRunQueryMode} + executionType={CommandExecutionType.Search} db={db} - onQueryProfile={() => {}} + onQueryProfile={(profileType) => + handleQueryProfile(profileType, { command, mode })} onQueryOpen={() => handleQueryOpen(id)} - onQueryReRun={() => onSubmit(command, id)} - onQueryDelete={() => {}} + onQueryReRun={() => handleQueryReRun(command, id, mode)} + onQueryDelete={() => handleQueryDelete(id)} /> )) : null}
diff --git a/redisinsight/ui/src/pages/search/components/results-history/styles.module.scss b/redisinsight/ui/src/pages/search/components/results-history/styles.module.scss index 7ea2ec299b..84827c7662 100644 --- a/redisinsight/ui/src/pages/search/components/results-history/styles.module.scss +++ b/redisinsight/ui/src/pages/search/components/results-history/styles.module.scss @@ -31,3 +31,14 @@ border-bottom: 1px solid var(--tableDarkestBorderColor); } +.clearAllBtn { + font-size: 14px !important; + + :global { + .euiIcon { + width: 14px !important; + height: 14px !important; + } + } +} + diff --git a/redisinsight/ui/src/pages/workbench/WorkbenchPage.tsx b/redisinsight/ui/src/pages/workbench/WorkbenchPage.tsx index 455dd9ca5f..2e92e9c76b 100644 --- a/redisinsight/ui/src/pages/workbench/WorkbenchPage.tsx +++ b/redisinsight/ui/src/pages/workbench/WorkbenchPage.tsx @@ -1,10 +1,9 @@ import React, { useEffect, useState } from 'react' -import { useDispatch, useSelector } from 'react-redux' +import { useSelector } from 'react-redux' import { useParams } from 'react-router-dom' import { formatLongName, getDbIndex, setTitle } from 'uiSrc/utils' import { connectedInstanceSelector } from 'uiSrc/slices/instances/instances' -import { loadPluginsAction } from 'uiSrc/slices/app/plugins' import { sendPageViewTelemetry, TelemetryPageView } from 'uiSrc/telemetry' import WBViewWrapper from './components/wb-view' @@ -15,7 +14,6 @@ const WorkbenchPage = () => { const { instanceId } = useParams<{ instanceId: string }>() - const dispatch = useDispatch() setTitle(`${formatLongName(connectedInstanceName, 33, 0, '...')} ${getDbIndex(db)} - Workbench`) useEffect(() => { @@ -34,10 +32,6 @@ const WorkbenchPage = () => { setIsPageViewSent(true) } - useEffect(() => { - dispatch(loadPluginsAction()) - }, []) - return () } diff --git a/redisinsight/ui/src/pages/workbench/components/wb-view/WBViewWrapper.tsx b/redisinsight/ui/src/pages/workbench/components/wb-view/WBViewWrapper.tsx index e484b25f28..bb050d7f89 100644 --- a/redisinsight/ui/src/pages/workbench/components/wb-view/WBViewWrapper.tsx +++ b/redisinsight/ui/src/pages/workbench/components/wb-view/WBViewWrapper.tsx @@ -15,7 +15,7 @@ import { sendWbQueryAction, workbenchResultsSelector, } from 'uiSrc/slices/workbench/wb-results' -import { Instance, IPluginVisualization } from 'uiSrc/slices/interfaces' +import { CommandExecutionType, Instance, IPluginVisualization } from 'uiSrc/slices/interfaces' import { connectedInstanceSelector, initialState as instanceInitState } from 'uiSrc/slices/instances/instances' import { ResultsMode, RunQueryMode } from 'uiSrc/slices/interfaces/workbench' import { cliSettingsSelector, fetchBlockingCliCommandsAction } from 'uiSrc/slices/cli/cli-settings' @@ -161,13 +161,19 @@ const WBViewWrapper = () => { ) => { if (!commandInit?.length) return - dispatch(sendWbQueryAction(commandInit, commandId, executeParams, { - afterEach: () => { - const isNewCommand = !commandId - isNewCommand && scrollResults('start') - }, - afterAll: updateOnboardingOnSubmit - })) + dispatch(sendWbQueryAction( + commandInit, + commandId, + executeParams, + CommandExecutionType.Workbench, + { + afterEach: () => { + const isNewCommand = !commandId + isNewCommand && scrollResults('start') + }, + afterAll: updateOnboardingOnSubmit + } + )) } const scrollResults = (inline: ScrollLogicalPosition = 'start') => { diff --git a/redisinsight/ui/src/slices/app/context.ts b/redisinsight/ui/src/slices/app/context.ts index 07ca089c37..4fce0714a5 100644 --- a/redisinsight/ui/src/slices/app/context.ts +++ b/redisinsight/ui/src/slices/app/context.ts @@ -187,7 +187,7 @@ const appContextSlice = createSlice({ setSQVerticalPanelSizes: (state, { payload }: { payload: any }) => { state.searchAndQuery.panelSizes.vertical = payload }, - setSQVerticalScript: (state, { payload }: { payload: any }) => { + setSQScript: (state, { payload }: { payload: any }) => { state.searchAndQuery.script = payload }, setLastPageContext: (state, { payload }: { payload: string }) => { @@ -261,7 +261,7 @@ export const { setWorkbenchScript, setWorkbenchVerticalPanelSizes, setSQVerticalPanelSizes, - setSQVerticalScript, + setSQScript, setLastPageContext, setPubSubFieldsContext, setBrowserBulkActionOpen, diff --git a/redisinsight/ui/src/slices/app/plugins.ts b/redisinsight/ui/src/slices/app/plugins.ts index 77c248067c..1f30dea8a5 100644 --- a/redisinsight/ui/src/slices/app/plugins.ts +++ b/redisinsight/ui/src/slices/app/plugins.ts @@ -9,7 +9,7 @@ import { } from 'uiSrc/utils' import { apiService } from 'uiSrc/services' import { ApiEndpoints } from 'uiSrc/constants' -import { IPlugin, PluginsResponse, StateAppPlugins } from 'uiSrc/slices/interfaces' +import { CommandExecutionType, IPlugin, PluginsResponse, StateAppPlugins } from 'uiSrc/slices/interfaces' import { SendCommandResponse } from 'apiSrc/modules/cli/dto/cli.dto' import { PluginState } from 'apiSrc/modules/workbench/models/plugin-state' @@ -95,11 +95,19 @@ export function loadPluginsAction() { } // Asynchronous thunk action -export function sendPluginCommandAction({ command = '', onSuccessAction, onFailAction }: { - command: string - onSuccessAction?: (responseData: any) => void - onFailAction?: (error: any) => void -}) { +export function sendPluginCommandAction( + { + command = '', + executionType = CommandExecutionType.Workbench, + onSuccessAction, + onFailAction + }: { + command: string + executionType?: CommandExecutionType + onSuccessAction?: (responseData: any) => void + onFailAction?: (error: any) => void + } +) { return async (_dispatch: AppDispatch, stateInit: () => RootState) => { try { const state = stateInit() @@ -112,7 +120,8 @@ export function sendPluginCommandAction({ command = '', onSuccessAction, onFailA ApiEndpoints.COMMAND_EXECUTIONS ), { - command: multilineCommandToOneLine(command) + command: multilineCommandToOneLine(command), + type: executionType } ) diff --git a/redisinsight/ui/src/slices/interfaces/workbench.ts b/redisinsight/ui/src/slices/interfaces/workbench.ts index 0dafcdb0ec..94652c9768 100644 --- a/redisinsight/ui/src/slices/interfaces/workbench.ts +++ b/redisinsight/ui/src/slices/interfaces/workbench.ts @@ -69,6 +69,11 @@ export enum ResultsMode { GroupMode = 'GROUP_MODE', } +export enum CommandExecutionType { + Workbench = 'WORKBENCH', + Search = 'SEARCH', +} + export interface ResultsSummary { total: number success: number diff --git a/redisinsight/ui/src/slices/workbench/wb-results.ts b/redisinsight/ui/src/slices/workbench/wb-results.ts index 7c1c570ebd..3939291d3b 100644 --- a/redisinsight/ui/src/slices/workbench/wb-results.ts +++ b/redisinsight/ui/src/slices/workbench/wb-results.ts @@ -5,7 +5,7 @@ import { apiService, localStorageService } from 'uiSrc/services' import { ApiEndpoints, BrowserStorageItem, CodeButtonParams, EMPTY_COMMAND } from 'uiSrc/constants' import { addErrorNotification } from 'uiSrc/slices/app/notifications' import { CliOutputFormatterType } from 'uiSrc/constants/cliOutput' -import { RunQueryMode, ResultsMode } from 'uiSrc/slices/interfaces/workbench' +import { RunQueryMode, ResultsMode, CommandExecutionType } from 'uiSrc/slices/interfaces/workbench' import { getApiErrorMessage, getCommandsForExecution, getExecuteParams, @@ -242,7 +242,10 @@ export const workbenchResultsSelector = (state: RootState) => state.workbench.re export default workbenchResultsSlice.reducer // Asynchronous thunk actions -export function fetchWBHistoryAction(instanceId: string) { +export function fetchWBHistoryAction( + instanceId: string, + executionType = CommandExecutionType.Workbench, +) { return async (dispatch: AppDispatch) => { dispatch(loadWBHistory()) @@ -251,7 +254,8 @@ export function fetchWBHistoryAction(instanceId: string) { getUrl( instanceId, ApiEndpoints.WORKBENCH_COMMAND_EXECUTIONS, - ) + ), + { params: { type: executionType } } ) if (isStatusSuccessful(status)) { @@ -273,6 +277,7 @@ export function sendWBCommandAction({ mode = RunQueryMode.ASCII, resultsMode = ResultsMode.Default, commandId = `${Date.now()}`, + executionType = CommandExecutionType.Workbench, onSuccessAction, onFailAction, }: { @@ -281,6 +286,7 @@ export function sendWBCommandAction({ commandId?: string mode: RunQueryMode resultsMode?: ResultsMode + executionType?: CommandExecutionType onSuccessAction?: (multiCommands: string[]) => void onFailAction?: () => void }) { @@ -304,7 +310,8 @@ export function sendWBCommandAction({ { commands, mode, - resultsMode + resultsMode, + type: executionType } ) @@ -335,6 +342,7 @@ export function sendWBCommandClusterAction({ mode = RunQueryMode.ASCII, resultsMode = ResultsMode.Default, commandId = `${Date.now()}`, + executionType = CommandExecutionType.Workbench, onSuccessAction, onFailAction, }: { @@ -344,6 +352,7 @@ export function sendWBCommandClusterAction({ multiCommands?: string[] mode?: RunQueryMode, resultsMode?: ResultsMode + executionType?: CommandExecutionType onSuccessAction?: (multiCommands: string[]) => void onFailAction?: () => void }) { @@ -367,6 +376,7 @@ export function sendWBCommandClusterAction({ commands, mode, resultsMode, + type: executionType, outputFormat: CliOutputFormatterType.Raw } ) @@ -462,6 +472,7 @@ export function deleteWBCommandAction( // Asynchronous thunk action export function clearWbResultsAction( + executionType = CommandExecutionType.Workbench, onSuccessAction?: () => void, onFailAction?: () => void, ) { @@ -477,6 +488,9 @@ export function clearWbResultsAction( id, ApiEndpoints.WORKBENCH_COMMAND_EXECUTIONS, ), + { + params: { type: executionType } + } ) if (isStatusSuccessful(status)) { @@ -498,6 +512,7 @@ export function sendWbQueryAction( queryInit: string, commandId?: Nullable, executeParams: CodeButtonParams = {}, + executionType?: CommandExecutionType, onSuccessAction?: { afterEach?: () => void, afterAll?: () => void @@ -533,6 +548,7 @@ export function sendWbQueryAction( commands, multiCommands, mode: activeRunQueryMode, + executionType, onSuccessAction: onSuccess, onFailAction: onFail })) @@ -555,6 +571,7 @@ export function sendWbQueryAction( mode: activeRunQueryMode, resultsMode, multiCommands, + executionType, onSuccessAction: onSuccess, onFailAction: onFail }) diff --git a/redisinsight/ui/src/telemetry/events.ts b/redisinsight/ui/src/telemetry/events.ts index 9b379e999b..b82ee884b3 100644 --- a/redisinsight/ui/src/telemetry/events.ts +++ b/redisinsight/ui/src/telemetry/events.ts @@ -127,6 +127,16 @@ export enum TelemetryEvent { WORKBENCH_CLEAR_ALL_RESULTS_CLICKED = 'WORKBENCH_CLEAR_ALL_RESULTS_CLICKED', SEARCH_COMMAND_SUBMITTED = 'SEARCH_COMMAND_SUBMITTED', + SEARCH_RESULT_VIEW_CHANGED = 'SEARCH_RESULT_VIEW_CHANGED', + SEARCH_COMMAND_COPIED = 'SEARCH_COMMAND_COPIED', + SEARCH_COMMAND_RUN_AGAIN = 'SEARCH_COMMAND_RUN_AGAIN', + SEARCH_RESULTS_IN_FULL_SCREEN = 'SEARCH_RESULTS_IN_FULL_SCREEN', + SEARCH_RESULTS_COLLAPSED = 'SEARCH_RESULTS_COLLAPSED', + SEARCH_RESULTS_EXPANDED = 'SEARCH_RESULTS_EXPANDED', + SEARCH_CLEAR_RESULT_CLICKED = 'SEARCH_CLEAR_RESULT_CLICKED', + SEARCH_CLEAR_ALL_RESULTS_CLICKED = 'SEARCH_CLEAR_ALL_RESULTS_CLICKED', + SEARCH_EXPAND_ALL_RESULTS = 'SEARCH_EXPAND_ALL_RESULTS', + SEARCH_FORMATTER_CHANGED = 'SEARCH_FORMATTER_CHANGED', PROFILER_OPENED = 'PROFILER_OPENED', PROFILER_STARTED = 'PROFILER_STARTED', From 6e1cad4ae23ced3133504992fe771be271e36f7c Mon Sep 17 00:00:00 2001 From: Roman Sergeenko Date: Thu, 12 Sep 2024 11:28:59 +0200 Subject: [PATCH 062/256] #RI-6079 - update colors #RI-6099 - highlight fields --- redisinsight/ui/src/constants/monaco/theme.ts | 18 +++++++++--------- .../monaco/monarchTokens/redisearchTokens.ts | 4 ++++ 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/redisinsight/ui/src/constants/monaco/theme.ts b/redisinsight/ui/src/constants/monaco/theme.ts index 0a48b48ded..f7f69e1887 100644 --- a/redisinsight/ui/src/constants/monaco/theme.ts +++ b/redisinsight/ui/src/constants/monaco/theme.ts @@ -47,15 +47,15 @@ export const redisearchDarKThemeRules = [ export const redisearchLightThemeRules = [ { token: 'keyword', foreground: '#8094B1', fontStyle: 'bold' }, - { token: 'argument.block.0', foreground: '#BDE8D7' }, - { token: 'argument.block.1', foreground: '#8CD7B9' }, - { token: 'argument.block.2', foreground: '#5BC69B' }, - { token: 'argument.block.3', foreground: '#3A8365' }, - { token: 'argument.block.withToken.0', foreground: '#BDE8D7' }, - { token: 'argument.block.withToken.1', foreground: '#8CD7B9' }, - { token: 'argument.block.withToken.2', foreground: '#5BC69B' }, - { token: 'argument.block.withToken.3', foreground: '#3A8365' }, - { token: 'loadAll', foreground: '#BDE8D7' }, + { token: 'argument.block.0', foreground: '#8CD7B9' }, + { token: 'argument.block.1', foreground: '#5BC69B' }, + { token: 'argument.block.2', foreground: '#3A8365' }, + { token: 'argument.block.3', foreground: '#244F3E' }, + { token: 'argument.block.withToken.0', foreground: '#8CD7B9' }, + { token: 'argument.block.withToken.1', foreground: '#5BC69B' }, + { token: 'argument.block.withToken.2', foreground: '#3A8365' }, + { token: 'argument.block.withToken.3', foreground: '#244F3E' }, + { token: 'loadAll', foreground: '#8CD7B9' }, { token: 'index', foreground: '#DE47BB' }, { token: 'query', foreground: '#7B90E0' }, { token: 'field', foreground: '#B02C30' }, diff --git a/redisinsight/ui/src/utils/monaco/monarchTokens/redisearchTokens.ts b/redisinsight/ui/src/utils/monaco/monarchTokens/redisearchTokens.ts index 323a7be11d..187fe305fe 100644 --- a/redisinsight/ui/src/utils/monaco/monarchTokens/redisearchTokens.ts +++ b/redisinsight/ui/src/utils/monaco/monarchTokens/redisearchTokens.ts @@ -33,6 +33,7 @@ export const getRediSearchMonarchTokensProvider = ( keywords, tokenizer: { root: [ + { include: '@fields' }, { include: '@whitespace' }, { include: '@numbers' }, { include: '@strings' }, @@ -65,6 +66,9 @@ export const getRediSearchMonarchTokensProvider = ( { include: 'root' } // Fallback to the root state if nothing matches ], ...generateQuery(), + fields: [ + [/@\w+/, { token: 'field', }] + ], whitespace: [ [/\s+/, 'white'], [/\/\/.*$/, 'comment'], From 5a019a6f34c29ebe776af088f631ca8009f495a7 Mon Sep 17 00:00:00 2001 From: Roman Sergeenko Date: Thu, 12 Sep 2024 14:13:48 +0200 Subject: [PATCH 063/256] #RI-6108 - fix clear results #RI-6109 - fix history #RI-6110 - fix profile/explain --- .../components/code-block/CodeBlock.spec.tsx | 4 ++- .../ui/src/pages/search/SearchPage.spec.tsx | 7 +++-- .../ui/src/pages/search/SearchPage.tsx | 9 ++++-- .../results-history/ResultsHistory.tsx | 2 +- .../ui/src/pages/workbench/WorkbenchPage.tsx | 9 +++++- .../ui/src/slices/interfaces/workbench.ts | 1 + .../slices/tests/workbench/wb-results.spec.ts | 31 +++++++++++++++++-- .../ui/src/slices/workbench/wb-results.ts | 27 ++++++++++++---- 8 files changed, 74 insertions(+), 16 deletions(-) diff --git a/redisinsight/ui/src/components/side-panels/panels/ai-assistant/components/shared/markdown-message/components/code-block/CodeBlock.spec.tsx b/redisinsight/ui/src/components/side-panels/panels/ai-assistant/components/shared/markdown-message/components/code-block/CodeBlock.spec.tsx index 7d1502fda6..98bbebd6a9 100644 --- a/redisinsight/ui/src/components/side-panels/panels/ai-assistant/components/shared/markdown-message/components/code-block/CodeBlock.spec.tsx +++ b/redisinsight/ui/src/components/side-panels/panels/ai-assistant/components/shared/markdown-message/components/code-block/CodeBlock.spec.tsx @@ -5,6 +5,7 @@ import { ButtonLang } from 'uiSrc/utils/formatters/markdown/remarkCode' import { sendWBCommand } from 'uiSrc/slices/workbench/wb-results' import { setDbIndexState } from 'uiSrc/slices/app/context' +import { CommandExecutionType } from 'uiSrc/slices/interfaces' import CodeBlock from './CodeBlock' let store: typeof mockedStore @@ -27,7 +28,8 @@ describe('CodeBlock', () => { expect(store.getActions()).toEqual([ sendWBCommand({ commandId: expect.any(String), - commands: ['info'] + commands: ['info'], + executionType: CommandExecutionType.Workbench }), setDbIndexState(true) ]) diff --git a/redisinsight/ui/src/pages/search/SearchPage.spec.tsx b/redisinsight/ui/src/pages/search/SearchPage.spec.tsx index 50a53c0b27..c160ed2a87 100644 --- a/redisinsight/ui/src/pages/search/SearchPage.spec.tsx +++ b/redisinsight/ui/src/pages/search/SearchPage.spec.tsx @@ -2,9 +2,10 @@ import React from 'react' import { cloneDeep } from 'lodash' import { cleanup, fireEvent, mockedStore, render, screen } from 'uiSrc/utils/test-utils' -import { loadWBHistory, sendWBCommand } from 'uiSrc/slices/workbench/wb-results' +import { loadWBHistory, sendWBCommand, setExecutionType } from 'uiSrc/slices/workbench/wb-results' import { setDbIndexState } from 'uiSrc/slices/app/context' import { sendPageViewTelemetry, TelemetryPageView } from 'uiSrc/telemetry' +import { CommandExecutionType } from 'uiSrc/slices/interfaces' import SearchPage from './SearchPage' jest.mock('uiSrc/slices/app/context', () => ({ @@ -66,9 +67,11 @@ describe('SearchPage', () => { expect(store.getActions()).toEqual([ loadWBHistory(), + setExecutionType(CommandExecutionType.Search), sendWBCommand({ commandId: expect.any(String), - commands: ['value'] + commands: ['value'], + executionType: CommandExecutionType.Search }), setDbIndexState(true) ]) diff --git a/redisinsight/ui/src/pages/search/SearchPage.tsx b/redisinsight/ui/src/pages/search/SearchPage.tsx index 10c267ec84..e69dd222fd 100644 --- a/redisinsight/ui/src/pages/search/SearchPage.tsx +++ b/redisinsight/ui/src/pages/search/SearchPage.tsx @@ -7,7 +7,7 @@ import { useParams } from 'react-router-dom' import { appContextSearchAndQuery, setSQVerticalPanelSizes, } from 'uiSrc/slices/app/context' import { QueryWrapper, ResultsHistory } from 'uiSrc/pages/search/components' -import { sendWbQueryAction } from 'uiSrc/slices/workbench/wb-results' +import { sendWbQueryAction, setExecutionType } from 'uiSrc/slices/workbench/wb-results' import { formatLongName, getDbIndex, Nullable, setTitle } from 'uiSrc/utils' import { connectedInstanceSelector } from 'uiSrc/slices/instances/instances' @@ -37,8 +37,11 @@ const SearchPage = () => { setTitle(`${formatLongName(connectedInstanceName, 33, 0, '...')} ${getDbIndex(db)} - Search and Query`) - useEffect(() => () => { - dispatch(setSQVerticalPanelSizes(verticalSizesRef.current)) + useEffect(() => { + dispatch(setExecutionType(CommandExecutionType.Search)) + return () => { + dispatch(setSQVerticalPanelSizes(verticalSizesRef.current)) + } }, []) useEffect(() => { diff --git a/redisinsight/ui/src/pages/search/components/results-history/ResultsHistory.tsx b/redisinsight/ui/src/pages/search/components/results-history/ResultsHistory.tsx index d03724bf7c..9d05a11205 100644 --- a/redisinsight/ui/src/pages/search/components/results-history/ResultsHistory.tsx +++ b/redisinsight/ui/src/pages/search/components/results-history/ResultsHistory.tsx @@ -94,7 +94,7 @@ const ResultsHistory = (props: Props) => { const { command, mode } = commandExecution const profileQuery = generateProfileQueryForCommand(command, profileType) if (profileQuery) { - onSubmit(command, null, { mode }) + onSubmit(profileQuery, null, { mode }) } } diff --git a/redisinsight/ui/src/pages/workbench/WorkbenchPage.tsx b/redisinsight/ui/src/pages/workbench/WorkbenchPage.tsx index 2e92e9c76b..bdd0a14058 100644 --- a/redisinsight/ui/src/pages/workbench/WorkbenchPage.tsx +++ b/redisinsight/ui/src/pages/workbench/WorkbenchPage.tsx @@ -1,10 +1,12 @@ import React, { useEffect, useState } from 'react' -import { useSelector } from 'react-redux' +import { useDispatch, useSelector } from 'react-redux' import { useParams } from 'react-router-dom' import { formatLongName, getDbIndex, setTitle } from 'uiSrc/utils' import { connectedInstanceSelector } from 'uiSrc/slices/instances/instances' import { sendPageViewTelemetry, TelemetryPageView } from 'uiSrc/telemetry' +import { CommandExecutionType } from 'uiSrc/slices/interfaces' +import { setExecutionType } from 'uiSrc/slices/workbench/wb-results' import WBViewWrapper from './components/wb-view' const WorkbenchPage = () => { @@ -13,9 +15,14 @@ const WorkbenchPage = () => { const { name: connectedInstanceName, db } = useSelector(connectedInstanceSelector) const { instanceId } = useParams<{ instanceId: string }>() + const dispatch = useDispatch() setTitle(`${formatLongName(connectedInstanceName, 33, 0, '...')} ${getDbIndex(db)} - Workbench`) + useEffect(() => { + dispatch(setExecutionType(CommandExecutionType.Workbench)) + }, []) + useEffect(() => { if (connectedInstanceName && !isPageViewSent) { sendPageView(instanceId) diff --git a/redisinsight/ui/src/slices/interfaces/workbench.ts b/redisinsight/ui/src/slices/interfaces/workbench.ts index 94652c9768..4bb7378e84 100644 --- a/redisinsight/ui/src/slices/interfaces/workbench.ts +++ b/redisinsight/ui/src/slices/interfaces/workbench.ts @@ -9,6 +9,7 @@ export interface StateWorkbenchSettings { } export interface StateWorkbenchResults { + type: CommandExecutionType isLoaded: boolean loading: boolean processing: boolean diff --git a/redisinsight/ui/src/slices/tests/workbench/wb-results.spec.ts b/redisinsight/ui/src/slices/tests/workbench/wb-results.spec.ts index c9d9669382..e5338ed994 100644 --- a/redisinsight/ui/src/slices/tests/workbench/wb-results.spec.ts +++ b/redisinsight/ui/src/slices/tests/workbench/wb-results.spec.ts @@ -12,7 +12,7 @@ import { apiService } from 'uiSrc/services' import { addErrorNotification } from 'uiSrc/slices/app/notifications' import { ClusterNodeRole, CommandExecutionStatus } from 'uiSrc/slices/interfaces/cli' import { EMPTY_COMMAND } from 'uiSrc/constants' -import { ResultsMode } from 'uiSrc/slices/interfaces' +import { CommandExecutionType, ResultsMode } from 'uiSrc/slices/interfaces' import { setDbIndexState } from 'uiSrc/slices/app/context' import { SendClusterCommandDto } from 'apiSrc/modules/cli/dto/cli.dto' import reducer, { @@ -67,7 +67,8 @@ describe('workbench results slice', () => { // Arrange const mockPayload = { commands: ['command', 'command2'], - commandId: '123' + commandId: '123', + executionType: CommandExecutionType.Workbench } const state = { ...initialState, @@ -95,6 +96,32 @@ describe('workbench results slice', () => { }) }) + describe('sendWBCommand with another type', () => { + it('should properly set state', () => { + // Arrange + const mockPayload = { + commands: ['command', 'command2'], + commandId: '123', + executionType: CommandExecutionType.Search + } + const state = { + ...initialState, + items: [] + } + + // Act + const nextState = reducer(initialState, sendWBCommand(mockPayload)) + + // Assert + const rootState = Object.assign(initialStateDefault, { + workbench: { + results: nextState, + }, + }) + expect(workbenchResultsSelector(rootState)).toEqual(state) + }) + }) + describe('toggleOpenWBResult', () => { it('should properly set isOpen = true', () => { // Arrange diff --git a/redisinsight/ui/src/slices/workbench/wb-results.ts b/redisinsight/ui/src/slices/workbench/wb-results.ts index 3939291d3b..f3a9d177f8 100644 --- a/redisinsight/ui/src/slices/workbench/wb-results.ts +++ b/redisinsight/ui/src/slices/workbench/wb-results.ts @@ -1,4 +1,4 @@ -import { createSlice } from '@reduxjs/toolkit' +import { createSlice, PayloadAction } from '@reduxjs/toolkit' import { AxiosError } from 'axios' import { chunk, reverse } from 'lodash' import { apiService, localStorageService } from 'uiSrc/services' @@ -29,6 +29,7 @@ import { } from '../interfaces' export const initialState: StateWorkbenchResults = { + type: CommandExecutionType.Workbench, isLoaded: false, loading: false, processing: false, @@ -46,6 +47,10 @@ const workbenchResultsSlice = createSlice({ reducers: { setWBResultsInitialState: () => initialState, + setExecutionType: (state, { payload }: PayloadAction) => { + state.type = payload + }, + // Fetch Workbench history loadWBHistory: (state) => { state.loading = true @@ -110,8 +115,15 @@ const workbenchResultsSlice = createSlice({ state.processing = false }, - sendWBCommand: (state, { payload: { commands, commandId } }: - { payload: { commands: string[], commandId: string } }) => { + sendWBCommand: ( + state, + { + payload: { commands, commandId, executionType } + }: + PayloadAction<{ commands: string[], commandId: string, executionType: CommandExecutionType }> + ) => { + if (executionType !== state.type) return + let newItems = [ ...commands.map((command, i) => ({ command, @@ -215,6 +227,7 @@ const workbenchResultsSlice = createSlice({ // Actions generated from the slice export const { setWBResultsInitialState, + setExecutionType, loadWBHistory, loadWBHistorySuccess, loadWBHistoryFailure, @@ -297,7 +310,8 @@ export function sendWBCommandAction({ dispatch(sendWBCommand({ commands: isGroupResults(resultsMode) ? [`${commands.length} - Command(s)`] : commands, - commandId + commandId, + executionType })) dispatch(setDbIndexState(true)) @@ -363,7 +377,8 @@ export function sendWBCommandClusterAction({ dispatch(sendWBCommand({ commands: isGroupResults(resultsMode) ? [`${commands.length} - Commands`] : commands, - commandId + commandId, + executionType })) const { data, status } = await apiService.post( @@ -489,7 +504,7 @@ export function clearWbResultsAction( ApiEndpoints.WORKBENCH_COMMAND_EXECUTIONS, ), { - params: { type: executionType } + data: { type: executionType } } ) From cb75d3a2ac7856809554cdf73896dc8839a30193 Mon Sep 17 00:00:00 2001 From: mariasergeenko Date: Fri, 13 Sep 2024 11:45:32 +0200 Subject: [PATCH 064/256] add tests for search history --- .../e2e/pageObjects/base-run-commands-page.ts | 32 ++++ tests/e2e/pageObjects/workbench-page.ts | 52 ++---- .../search-and-query/commands-history.e2e.ts | 164 ++++++++++++++++++ .../search-and-query/raw-mode.e2e.ts | 69 ++++++++ .../workbench/command-results.e2e.ts | 3 +- 5 files changed, 278 insertions(+), 42 deletions(-) create mode 100644 tests/e2e/tests/web/regression/search-and-query/commands-history.e2e.ts create mode 100644 tests/e2e/tests/web/regression/search-and-query/raw-mode.e2e.ts diff --git a/tests/e2e/pageObjects/base-run-commands-page.ts b/tests/e2e/pageObjects/base-run-commands-page.ts index b9c965ecfa..d40b647560 100644 --- a/tests/e2e/pageObjects/base-run-commands-page.ts +++ b/tests/e2e/pageObjects/base-run-commands-page.ts @@ -25,12 +25,30 @@ export class BaseRunCommandsPage extends InstancePage { executedCommandTitle = Selector('[data-testid=query-card-tooltip-anchor]', { timeout: 500 }); queryResult = Selector('[data-testid=query-common-result]'); queryInputScriptArea = Selector('[data-testid=query-input-container] .view-line'); + parametersAnchor = Selector('[data-testid=parameters-anchor]'); + + iframe = Selector('[data-testid=pluginIframe]'); + + //OPTIONS + selectViewType = Selector('[data-testid=select-view-type]'); + queryTableResult = Selector('[data-testid^=query-table-result-]'); + textViewTypeOption = Selector('[data-test-subj^=view-type-option-Text]'); + tableViewTypeOption = Selector('[data-test-subj^=view-type-option-Plugin]'); + + clearResultsBtn = Selector('[data-testid=clear-history-btn]'); + rawModeIcon = Selector('[data-testid=raw-mode-tooltip]'); cssQueryCardCommand = '[data-testid=query-card-command]'; cssQueryCardContainer = '[data-testid^="query-card-container-"]'; cssQueryTextResult = '[data-testid=query-cli-result]'; cssReRunCommandButton = '[data-testid=re-run-command]'; cssDeleteCommandButton = '[data-testid=delete-command]'; + cssJsonViewTypeOption = '[data-testid=view-type-selected-Plugin-client-list__json-view]'; + cssQueryTableResult = '[data-testid^=query-table-result-]'; + cssTableViewTypeOption = '[data-testid=view-type-selected-Plugin-redisearch__redisearch]'; + cssCommandExecutionDateTime = '[data-testid=command-execution-date-time]'; + + queryTextResult = Selector(this.cssQueryTextResult); getTutorialLinkLocator = (tutorialName: string): Selector => Selector(`[data-testid=query-tutorials-link_${tutorialName}]`); @@ -70,4 +88,18 @@ export class BaseRunCommandsPage extends InstancePage { const actualCommandResult = await this.queryCardContainer.nth(childNum).find(this.cssQueryTextResult).textContent; await t.expect(actualCommandResult).contains(result, 'Actual command result is not equal to executed'); } + + // Select Text view option in Workbench results + async selectViewTypeText(): Promise { + await t + .click(this.selectViewType) + .click(this.textViewTypeOption); + } + + // Select Table view option in Workbench results + async selectViewTypeTable(): Promise { + await t + .click(this.selectViewType) + .doubleClick(this.tableViewTypeOption); + } } diff --git a/tests/e2e/pageObjects/workbench-page.ts b/tests/e2e/pageObjects/workbench-page.ts index bf30d3938d..3d4987677d 100644 --- a/tests/e2e/pageObjects/workbench-page.ts +++ b/tests/e2e/pageObjects/workbench-page.ts @@ -5,16 +5,12 @@ export class WorkbenchPage extends BaseRunCommandsPage { //CSS selectors cssSelectorPaginationButtonPrevious = '[data-test-subj=pagination-button-previous]'; cssSelectorPaginationButtonNext = '[data-test-subj=pagination-button-next]'; - cssTableViewTypeOption = '[data-testid=view-type-selected-Plugin-redisearch__redisearch]'; - cssClientListViewTypeOption = '[data-testid=view-type-selected-Plugin-client-list__clients-list]'; - cssJsonViewTypeOption = '[data-testid=view-type-selected-Plugin-client-list__json-view]'; cssMonacoCommandPaletteLine = '[aria-label="Command Palette"]'; cssWorkbenchCommandInHistory = '[data-testid=wb-command]'; - cssQueryTableResult = '[data-testid^=query-table-result-]'; queryGraphContainer = '[data-testid=query-graph-container]'; cssQueryCardCommand = '[data-testid=query-card-command]'; - cssCommandExecutionDateTime = '[data-testid=command-execution-date-time]'; cssRowInVirtualizedTable = '[data-testid^=row-]'; + cssClientListViewTypeOption = '[data-testid=view-type-selected-Plugin-client-list__clients-list]'; //------------------------------------------------------------------------------------------- //DECLARATION OF SELECTORS //*Declare all elements/components of the relevant page. @@ -36,26 +32,17 @@ export class WorkbenchPage extends BaseRunCommandsPage { queryCardNoModuleButton = Selector('[data-testid=query-card-no-module-button] a'); closeEnablementPage = Selector('[data-testid=enablement-area__page-close]'); groupMode = Selector('[data-testid=btn-change-group-mode]'); - clearResultsBtn = Selector('[data-testid=clear-history-btn]'); + //ICONS noCommandHistoryIcon = Selector('[data-testid=wb_no-results__icon]'); - parametersAnchor = Selector('[data-testid=parameters-anchor]'); groupModeIcon = Selector('[data-testid=group-mode-tooltip]'); - rawModeIcon = Selector('[data-testid=raw-mode-tooltip]'); silentModeIcon = Selector('[data-testid=silent-mode-tooltip]'); - //LINKS - //TEXT INPUTS (also referred to as 'Text fields') - iframe = Selector('[data-testid=pluginIframe]'); //TEXT ELEMENTS queryPluginResult = Selector('[data-testid=query-plugin-result]'); responseInfo = Selector('[class="responseInfo"]'); parsedRedisReply = Selector('[class="parsedRedisReply"]'); - scriptsLines = Selector('[data-testid=query-input-container] .view-lines'); - queryTableResult = Selector('[data-testid^=query-table-result-]'); - queryJsonResult = Selector('[data-testid=json-view]'); mainEditorArea = Selector('[data-testid=main-input-container-area]'); - queryTextResult = Selector(this.cssQueryTextResult); queryColumns = Selector('[data-testid*=query-column-]'); noCommandHistorySection = Selector('[data-testid=wb_no-results]'); noCommandHistoryTitle = Selector('[data-testid=wb_no-results__title]'); @@ -64,37 +51,15 @@ export class WorkbenchPage extends BaseRunCommandsPage { commandExecutionResult = Selector('[data-testid=welcome-page-title]'); commandExecutionResultFailed = Selector('[data-testid=cli-output-response-fail]'); chartViewTypeOptionSelected = Selector('[data-testid=view-type-selected-Plugin-redistimeseries__redistimeseries-chart]'); - //OPTIONS - selectViewType = Selector('[data-testid=select-view-type]'); - textViewTypeOption = Selector('[data-test-subj^=view-type-option-Text]'); + scriptsLines = Selector('[data-testid=query-input-container] .view-lines'); + queryJsonResult = Selector('[data-testid=json-view]'); jsonStringViewTypeOption = Selector('[data-test-subj=view-type-option-Plugin-client-list__json-string-view]'); - tableViewTypeOption = Selector('[data-test-subj^=view-type-option-Plugin]'); + graphViewTypeOption = Selector('[data-test-subj^=view-type-option-Plugin-graph]'); typeSelectedClientsList = Selector('[data-testid=view-type-selected-Plugin-client-list__clients-list]'); viewTypeOptionClientList = Selector('[data-test-subj=view-type-option-Plugin-client-list__clients-list]'); viewTypeOptionsText = Selector('[data-test-subj=view-type-option-Text-default__Text]'); - // Select Text view option in Workbench results - async selectViewTypeText(): Promise { - await t - .click(this.selectViewType) - .click(this.textViewTypeOption); - } - - // Select Json view option in Workbench results - async selectViewTypeJson(): Promise { - await t - .click(this.selectViewType) - .click(this.jsonStringViewTypeOption); - } - - // Select Table view option in Workbench results - async selectViewTypeTable(): Promise { - await t - .click(this.selectViewType) - .doubleClick(this.tableViewTypeOption); - } - // Select view option in Workbench results async selectViewTypeGraph(): Promise { await t @@ -140,4 +105,11 @@ export class WorkbenchPage extends BaseRunCommandsPage { getInternalLinkWithoutManifest(internalLink: string): Selector { return Selector(`[data-testid="internal-link-${internalLink}"]`); } + + // Select Json view option in Workbench results + async selectViewTypeJson(): Promise { + await t + .click(this.selectViewType) + .click(this.jsonStringViewTypeOption); + } } diff --git a/tests/e2e/tests/web/regression/search-and-query/commands-history.e2e.ts b/tests/e2e/tests/web/regression/search-and-query/commands-history.e2e.ts new file mode 100644 index 0000000000..c0dc5acf22 --- /dev/null +++ b/tests/e2e/tests/web/regression/search-and-query/commands-history.e2e.ts @@ -0,0 +1,164 @@ +import { KeysInteractionTabs, rte } from '../../../../helpers/constants'; +import { DatabaseHelper } from '../../../../helpers/database'; +import { BrowserPage, MyRedisDatabasePage, WorkbenchPage } from '../../../../pageObjects'; +import { SearchAndQueryPage } from '../../../../pageObjects/search-and-query-page'; +import { commonUrl, ossClusterConfig } from '../../../../helpers/conf'; +import { DatabaseAPIRequests } from '../../../../helpers/api/api-database'; +import { Common } from '../../../../helpers/common'; + +const myRedisDatabasePage = new MyRedisDatabasePage(); +const searchAndQueryPage = new SearchAndQueryPage(); +const databaseHelper = new DatabaseHelper(); +const databaseAPIRequests = new DatabaseAPIRequests(); +const browserPage = new BrowserPage(); +const workbenchPage = new WorkbenchPage(); + +const commandForSend1 = 'FT.INFO'; +const commandForSend2 = 'FT._LIST'; +let indexName = Common.generateWord(5); + +const commandsForIndex = [ + `FT.CREATE ${indexName} ON HASH PREFIX 1 product: SCHEMA price NUMERIC SORTABLE`, + 'HMSET product:1 price 20', + 'HMSET product:2 price 100' +]; + +fixture `Command results at Search and Query` + .meta({ type: 'critical_path', rte: rte.standalone }) + .page(commonUrl) + .beforeEach(async t => { + await databaseHelper.acceptLicenseTermsAndAddOSSClusterDatabase(ossClusterConfig); + // Go to Workbench page + await t.click(myRedisDatabasePage.NavigationPanel.browserButton); + await browserPage.KeysInteractionPanel.setActiveTab(KeysInteractionTabs.SearchAndQuery); + }) + .afterEach(async t => { + await t.switchToMainWindow(); + await workbenchPage.sendCommandInWorkbench(`FT.DROPINDEX ${indexName} DD`); + await databaseAPIRequests.deleteOSSClusterDatabaseApi(ossClusterConfig); + }); +test('Verify that user can see re-run icon near the already executed command and re-execute the command by clicking on the icon in Workbench page', async t => { + // Send commands + await searchAndQueryPage.sendCommandInWorkbench(commandForSend1); + await searchAndQueryPage.sendCommandInWorkbench(commandForSend2); + const containerOfCommand = await searchAndQueryPage.getCardContainerByCommand(commandForSend1); + const containerOfCommand2 = await searchAndQueryPage.getCardContainerByCommand(commandForSend2); + // Verify that re-run icon is displayed + await t.expect(await searchAndQueryPage.reRunCommandButton.visible).ok('Re-run icon is not displayed'); + // Re-run the last command in results + await t.click(containerOfCommand.find(searchAndQueryPage.cssReRunCommandButton)); + // Verify that command is re-executed + await t.expect(searchAndQueryPage.queryCardCommand.textContent).eql(commandForSend1, 'The command is not re-executed'); + + // Verify that user can see expanded result after command re-run at the top of results table in Workbench + await t.expect(await searchAndQueryPage.queryCardContainer.nth(0).find(searchAndQueryPage.cssQueryTextResult).visible) + .ok('Re-executed command is not expanded'); + await t.expect(searchAndQueryPage.queryCardCommand.nth(0).textContent).eql(commandForSend1, 'The re-executed command is not at the top of results table'); + + // Delete the command from results + await t.click(containerOfCommand2.find(searchAndQueryPage.cssDeleteCommandButton)); + // Verify that user can delete command with result from table with results in Workbench + await t.expect(searchAndQueryPage.queryCardCommand.withExactText(commandForSend2).exists).notOk(`Command ${commandForSend2} is not deleted from table with results`); +}); +test('Verify that user can see the results found in the table view by default for FT.INFO, FT.SEARCH and FT.AGGREGATE', async t => { + const commands = [ + 'FT.INFO', + 'FT.SEARCH', + 'FT.AGGREGATE' + ]; + // Send commands and check table view is default + for(const command of commands) { + await searchAndQueryPage.sendCommandInWorkbench(command); + await t.expect(searchAndQueryPage.queryCardContainer.nth(0).find(searchAndQueryPage.cssTableViewTypeOption).exists).ok(`The table view is not selected by default for command ${command}`); + } +}); +test + .after(async() => { + await searchAndQueryPage.sendCommandInWorkbench(`FT.DROPINDEX ${indexName} DD`); + })('Verify that user can switches between views and see results according to the view rules in Workbench in results', async t => { + indexName = Common.generateWord(5); + const commands = [ + 'hset doc:10 title "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud" url "redis.io" author "Test" rate "undefined" review "0" comment "Test comment"', + `FT.CREATE ${indexName} ON HASH PREFIX 1 doc: SCHEMA title TEXT WEIGHT 5.0 body TEXT url TEXT author TEXT rate TEXT review TEXT comment TEXT`, + `FT.SEARCH ${indexName} * limit 0 10000` + ]; + // Send commands and check table view is default for Search command + for (const command of commands) { + await searchAndQueryPage.sendCommandInWorkbench(command); + } + await t.expect(await searchAndQueryPage.queryCardContainer.nth(0).find(searchAndQueryPage.cssTableViewTypeOption).exists) + .ok('The table view is not selected by default for command FT.SEARCH'); + await t.switchToIframe(searchAndQueryPage.iframe); + await t.expect(await searchAndQueryPage.queryTableResult.visible).ok('The table result is not displayed for command FT.SEARCH'); + // Select Text view and check result + await t.switchToMainWindow(); + await searchAndQueryPage.selectViewTypeText(); + await t.expect(await searchAndQueryPage.queryCardContainer.nth(0).find(searchAndQueryPage.cssQueryTextResult).visible).ok('The result is not displayed in Text view'); + }); + +test('Verify that user can clear all results at once.', async t => { + await t.click(searchAndQueryPage.clearResultsBtn); + await t.expect(searchAndQueryPage.queryTextResult.exists).notOk('Clear all button does not remove commands'); +}); + +test('Verify that user can switches between Table and Text for FT.AGGREGATE and see results corresponding to their views', async t => { + + await browserPage.KeysInteractionPanel.setActiveTab(KeysInteractionTabs.Workbench); + await workbenchPage.sendCommandsArrayInWorkbench(commandsForIndex); + await browserPage.KeysInteractionPanel.setActiveTab(KeysInteractionTabs.SearchAndQuery); + const aggregateCommand = `FT.Aggregate ${indexName} * GROUPBY 0 REDUCE MAX 1 @price AS max_price`; + + // Send FT.AGGREGATE and switch to Text view + await searchAndQueryPage.sendCommandInWorkbench(aggregateCommand); + await searchAndQueryPage.selectViewTypeText(); + await t.expect(searchAndQueryPage.queryCardContainer.nth(0).find(searchAndQueryPage.cssQueryTextResult).visible).ok('The text view is not switched for command FT.AGGREGATE'); + // Switch to Table view and check result + await searchAndQueryPage.selectViewTypeTable(); + await t.switchToIframe(searchAndQueryPage.iframe); + await t.expect(searchAndQueryPage.queryTableResult.exists).ok('The table view is not switched for command FT.AGGREGATE'); +}); + +test('Verify that user can switches between Table and Text for FT.SEARCH and see results corresponding to their views', async t => { + await browserPage.KeysInteractionPanel.setActiveTab(KeysInteractionTabs.Workbench); + await workbenchPage.sendCommandsArrayInWorkbench(commandsForIndex); + await browserPage.KeysInteractionPanel.setActiveTab(KeysInteractionTabs.SearchAndQuery); + const searchCommand = `FT.SEARCH ${indexName} *`; + + // Send FT.SEARCH and switch to Text view + await searchAndQueryPage.sendCommandInWorkbench(searchCommand); + await searchAndQueryPage.selectViewTypeText(); + await t.expect(searchAndQueryPage.queryCardContainer.nth(0).find(searchAndQueryPage.cssQueryTextResult).visible).ok('The text view is not switched for command FT.SEARCH'); + // Switch to Table view and check result + await searchAndQueryPage.selectViewTypeTable(); + await t.switchToIframe(searchAndQueryPage.iframe); + await t.expect(searchAndQueryPage.queryTableResult.exists).ok('The table view is not switched for command FT.SEARCH'); +}); +test('Verify that user can switches between Table and Text for FT.INFO and see results corresponding to their views', async t => { + await browserPage.KeysInteractionPanel.setActiveTab(KeysInteractionTabs.Workbench); + await workbenchPage.sendCommandsArrayInWorkbench(commandsForIndex); + await browserPage.KeysInteractionPanel.setActiveTab(KeysInteractionTabs.SearchAndQuery); + const infoCommand = `FT.INFO ${indexName}`; + + // Send FT.INFO and switch to Text view + await searchAndQueryPage.sendCommandInWorkbench(infoCommand); + await searchAndQueryPage.selectViewTypeText(); + await t.expect(searchAndQueryPage.queryCardContainer.nth(0).find(searchAndQueryPage.cssQueryTextResult).exists).ok('The text view is not switched for command FT.INFO'); + // Switch to Table view and check result + await searchAndQueryPage.selectViewTypeTable(); + await t.switchToIframe(searchAndQueryPage.iframe); + await t.expect(searchAndQueryPage.queryTableResult.exists).ok('The table view is not switched for command FT.INFO'); +}); +test + .meta({ rte: rte.standalone })('Verify that user can see original date and time of command execution in Workbench history after the page update', async t => { + const keyName = Common.generateWord(5); + const command = `set ${keyName} test`; + + // Send command and remember the time + await searchAndQueryPage.sendCommandInWorkbench(command); + const dateTime = await searchAndQueryPage.queryCardContainer.nth(0).find(searchAndQueryPage.cssCommandExecutionDateTime).textContent; + // Wait fo 1 minute, refresh page and check results + await t.wait(60000); + await searchAndQueryPage.reloadPage(); + await t.expect(searchAndQueryPage.queryCardContainer.nth(0).find(searchAndQueryPage.cssCommandExecutionDateTime).textContent).eql(dateTime, 'The original date and time of command execution is not saved after the page update'); + }); + diff --git a/tests/e2e/tests/web/regression/search-and-query/raw-mode.e2e.ts b/tests/e2e/tests/web/regression/search-and-query/raw-mode.e2e.ts new file mode 100644 index 0000000000..32d7ed7a05 --- /dev/null +++ b/tests/e2e/tests/web/regression/search-and-query/raw-mode.e2e.ts @@ -0,0 +1,69 @@ +import { DatabaseHelper } from '../../../../helpers/database'; +import { WorkbenchPage, MyRedisDatabasePage, BrowserPage } from '../../../../pageObjects'; +import { KeysInteractionTabs, rte } from '../../../../helpers/constants'; +import { commonUrl, ossStandaloneConfig, ossStandaloneRedisearch } from '../../../../helpers/conf'; +import { DatabaseAPIRequests } from '../../../../helpers/api/api-database'; +import { Common } from '../../../../helpers/common'; +import { SearchAndQueryPage } from '../../../../pageObjects/search-and-query-page'; + +const myRedisDatabasePage = new MyRedisDatabasePage(); +const workbenchPage = new WorkbenchPage(); +const browserPage = new BrowserPage(); +const databaseHelper = new DatabaseHelper(); +const databaseAPIRequests = new DatabaseAPIRequests(); +const searchAndQueryPage = new SearchAndQueryPage(); + +const indexName = Common.generateWord(5); +const unicodeValue = '山女馬 / 马目 abc 123'; + +const databasesForAdding = + { host: ossStandaloneConfig.host, port: ossStandaloneConfig.port, databaseName: 'testDB2' }; + +fixture `Search and Query Raw mode` + .meta({ type: 'critical_path', rte: rte.standalone }) + .page(commonUrl); + +test + .before(async t => { + await databaseHelper.acceptLicenseTerms(); + await databaseAPIRequests.addNewStandaloneDatabaseApi( + databasesForAdding); + await databaseHelper.acceptLicenseTermsAndAddDatabaseApi(ossStandaloneRedisearch); + // Go to Workbench page + await browserPage.KeysInteractionPanel.setActiveTab(KeysInteractionTabs.Workbench); + }) + .after(async t => { + // Drop index, documents and database + await t.switchToMainWindow(); + await workbenchPage.sendCommandInWorkbench(`FT.DROPINDEX ${indexName} DD`); + await databaseAPIRequests.deleteStandaloneDatabaseApi(ossStandaloneRedisearch); + + })('Display Raw mode for plugins and save state', async t => { + const commandsForSend = [ + `FT.CREATE ${indexName} ON HASH PREFIX 1 product: SCHEMA name TEXT`, + `HMSET product:1 name "${unicodeValue}"` + ]; + const commandSearch = `FT.SEARCH ${indexName} "${unicodeValue}"`; + + await workbenchPage.sendCommandsArrayInWorkbench(commandsForSend); + await browserPage.KeysInteractionPanel.setActiveTab(KeysInteractionTabs.SearchAndQuery); + // Send command in raw mode + await t.click(searchAndQueryPage.rawModeBtn); + await searchAndQueryPage.sendCommandInWorkbench(commandSearch); + // Check the FT.SEARCH result + await t.switchToIframe(workbenchPage.iframe); + let name = workbenchPage.queryTableResult.withText(unicodeValue); + await t.expect(name.exists).ok('The added key name field is not converted to Unicode'); + await t.switchToMainWindow(); + await t.click(myRedisDatabasePage.NavigationPanel.myRedisDBButton); + await myRedisDatabasePage.clickOnDBByName(databasesForAdding.databaseName); + await browserPage.KeysInteractionPanel.setActiveTab(KeysInteractionTabs.Workbench); + + await workbenchPage.sendCommandsArrayInWorkbench(commandsForSend); + await browserPage.KeysInteractionPanel.setActiveTab(KeysInteractionTabs.SearchAndQuery); + await searchAndQueryPage.sendCommandInWorkbench(commandSearch); + // Check the FT.SEARCH result + await t.switchToIframe(workbenchPage.iframe); + name = workbenchPage.queryTableResult.withText(unicodeValue); + await t.expect(name.exists).ok('The added key name field is not converted to Unicode'); + }); diff --git a/tests/e2e/tests/web/regression/workbench/command-results.e2e.ts b/tests/e2e/tests/web/regression/workbench/command-results.e2e.ts index 40b725c1e4..88b58e051e 100644 --- a/tests/e2e/tests/web/regression/workbench/command-results.e2e.ts +++ b/tests/e2e/tests/web/regression/workbench/command-results.e2e.ts @@ -1,12 +1,11 @@ import { DatabaseHelper } from '../../../../helpers/database'; -import { WorkbenchPage, MyRedisDatabasePage, BrowserPage } from '../../../../pageObjects'; +import { WorkbenchPage, BrowserPage } from '../../../../pageObjects'; import { commonUrl, ossStandaloneRedisearch } from '../../../../helpers/conf'; import { KeysInteractionTabs, rte } from '../../../../helpers/constants'; import { DatabaseAPIRequests } from '../../../../helpers/api/api-database'; import { Common } from '../../../../helpers/common'; import { WorkbenchActions } from '../../../../common-actions/workbench-actions'; -const myRedisDatabasePage = new MyRedisDatabasePage(); const workbenchPage = new WorkbenchPage(); const workBenchActions = new WorkbenchActions(); const databaseHelper = new DatabaseHelper(); From 55a8abba039feaca4a4754b2ca11cf8707c1caa9 Mon Sep 17 00:00:00 2001 From: mariasergeenko Date: Fri, 13 Sep 2024 11:49:04 +0200 Subject: [PATCH 065/256] remove unused meta --- .../search-and-query/commands-history.e2e.ts | 23 +++++++++---------- 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/tests/e2e/tests/web/regression/search-and-query/commands-history.e2e.ts b/tests/e2e/tests/web/regression/search-and-query/commands-history.e2e.ts index c0dc5acf22..f41f2daea5 100644 --- a/tests/e2e/tests/web/regression/search-and-query/commands-history.e2e.ts +++ b/tests/e2e/tests/web/regression/search-and-query/commands-history.e2e.ts @@ -148,17 +148,16 @@ test('Verify that user can switches between Table and Text for FT.INFO and see r await t.switchToIframe(searchAndQueryPage.iframe); await t.expect(searchAndQueryPage.queryTableResult.exists).ok('The table view is not switched for command FT.INFO'); }); -test - .meta({ rte: rte.standalone })('Verify that user can see original date and time of command execution in Workbench history after the page update', async t => { - const keyName = Common.generateWord(5); - const command = `set ${keyName} test`; +test('Verify that user can see original date and time of command execution in Workbench history after the page update', async t => { + const keyName = Common.generateWord(5); + const command = `set ${keyName} test`; - // Send command and remember the time - await searchAndQueryPage.sendCommandInWorkbench(command); - const dateTime = await searchAndQueryPage.queryCardContainer.nth(0).find(searchAndQueryPage.cssCommandExecutionDateTime).textContent; - // Wait fo 1 minute, refresh page and check results - await t.wait(60000); - await searchAndQueryPage.reloadPage(); - await t.expect(searchAndQueryPage.queryCardContainer.nth(0).find(searchAndQueryPage.cssCommandExecutionDateTime).textContent).eql(dateTime, 'The original date and time of command execution is not saved after the page update'); - }); + // Send command and remember the time + await searchAndQueryPage.sendCommandInWorkbench(command); + const dateTime = await searchAndQueryPage.queryCardContainer.nth(0).find(searchAndQueryPage.cssCommandExecutionDateTime).textContent; + // Wait fo 1 minute, refresh page and check results + await t.wait(60000); + await searchAndQueryPage.reloadPage(); + await t.expect(searchAndQueryPage.queryCardContainer.nth(0).find(searchAndQueryPage.cssCommandExecutionDateTime).textContent).eql(dateTime, 'The original date and time of command execution is not saved after the page update'); +}); From 2499a3df25b8342430f32ef804976f3a877fcc4f Mon Sep 17 00:00:00 2001 From: Roman Sergeenko Date: Fri, 13 Sep 2024 17:03:37 +0200 Subject: [PATCH 066/256] #RI-6086 - fix number of args next to count #RI-6088 - fix multiple arguments --- .../pages/search/components/query/Query.tsx | 4 +- .../ui/src/pages/search/utils/query.ts | 51 ++++++--- .../pages/search/utils/tests/query.spec.ts | 106 +++++++++++------- 3 files changed, 105 insertions(+), 56 deletions(-) diff --git a/redisinsight/ui/src/pages/search/components/query/Query.tsx b/redisinsight/ui/src/pages/search/components/query/Query.tsx index 96f613b1e3..28c0e1a582 100644 --- a/redisinsight/ui/src/pages/search/components/query/Query.tsx +++ b/redisinsight/ui/src/pages/search/components/query/Query.tsx @@ -18,7 +18,7 @@ import { CursorContext, FoundCommandArgument, SearchCommand, TokenType } from 'u import { RedisResponseBuffer } from 'uiSrc/slices/interfaces' import { fetchRedisearchInfoAction } from 'uiSrc/slices/browser/redisearch' import { getRediSearchMonarchTokensProvider } from 'uiSrc/utils/monaco/monarchTokens/redisearchTokens' -import { installRedisearchTheme, RedisearchMonacoTheme } from 'uiSrc/utils/monaco/monacoThemes' +import { installRedisearchTheme } from 'uiSrc/utils/monaco/monacoThemes' import { useDebouncedEffect } from 'uiSrc/services' import { options, DefinedArgumentName, FIELD_START_SYMBOL } from './constants' import { @@ -346,7 +346,7 @@ const Query = (props: Props) => { value={value} onChange={onChange} language={MonacoLanguage.RediSearch} - theme={theme === Theme.Dark ? RedisearchMonacoTheme.dark : RedisearchMonacoTheme.light} + theme={theme === Theme.Dark ? 'dark' : 'light'} options={options} editorDidMount={editorDidMount} /> diff --git a/redisinsight/ui/src/pages/search/utils/query.ts b/redisinsight/ui/src/pages/search/utils/query.ts index 921c1f5674..ab6a1ae2a6 100644 --- a/redisinsight/ui/src/pages/search/utils/query.ts +++ b/redisinsight/ui/src/pages/search/utils/query.ts @@ -1,6 +1,6 @@ /* eslint-disable no-continue */ -import { toNumber } from 'lodash' +import { isNumber, toNumber } from 'lodash' import { generateArgsNames, Maybe, Nullable } from 'uiSrc/utils' import { CommandProvider } from 'uiSrc/constants' import { ArgName, FoundCommandArgument, SearchCommand, SearchCommandTree, TokenType } from '../types' @@ -140,18 +140,24 @@ const findStopArgumentInQuery = ( ): { restArguments: SearchCommand[] stopArgIndex: number + argumentsIntered?: number isBlocked: boolean } => { let currentCommandArgIndex = 0 + let argumentsIntered = 0 let isBlockedOnCommand = false let multipleIndexStart = 0 let multipleCountNumber = 0 - const moveToNextCommandArg = () => currentCommandArgIndex++ + const moveToNextCommandArg = () => { + currentCommandArgIndex++ + argumentsIntered++ + } const blockCommand = () => { isBlockedOnCommand = true } const unBlockCommand = () => { isBlockedOnCommand = false } const skipArg = () => { + argumentsIntered -= 1 moveToNextCommandArg() unBlockCommand() } @@ -165,15 +171,16 @@ const findStopArgumentInQuery = ( continue } - if ( - !isBlockedOnCommand - && currentCommandArg?.token - && currentCommandArg.optional - && currentCommandArg.token !== arg.toUpperCase() - ) { - moveToNextCommandArg() - skipArg() - continue + if (!isBlockedOnCommand && currentCommandArg.optional) { + const isNotToken = currentCommandArg?.token && currentCommandArg.token !== arg.toUpperCase() + const isNotOneOfToken = currentCommandArg?.type === TokenType.OneOf + && currentCommandArg?.arguments?.every(({ token }) => token !== arg.toUpperCase()) + + if (isNotToken || isNotOneOfToken) { + moveToNextCommandArg() + skipArg() + continue + } } // if we are on token - that requires one more argument @@ -183,16 +190,23 @@ const findStopArgumentInQuery = ( } if (currentCommandArg?.type === TokenType.Block) { - // if block is multiple - we duplicate nArgs inner arguments let blockArguments = currentCommandArg.arguments - + const nArgs = toNumber(queryArgs[i - 1]) || 0 + // if block is multiple - we duplicate nArgs inner arguments if (currentCommandArg?.multiple) { - const nArgs = toNumber(queryArgs[i - 1]) || 0 blockArguments = Array(nArgs).fill(currentCommandArg.arguments).flat() } const blockSuggestion = findStopArgumentInQuery(queryArgs.slice(i), blockArguments) const stopArg = blockSuggestion.restArguments?.[blockSuggestion.stopArgIndex] + const { argumentsIntered } = blockSuggestion + + if (isNumber(argumentsIntered) && argumentsIntered >= nArgs) { + i += queryArgs.slice(i).length - 1 + skipArg() + continue + } + if (blockSuggestion.isBlocked || stopArg) return blockSuggestion i += queryArgs.slice(i).length - 1 @@ -248,6 +262,7 @@ const findStopArgumentInQuery = ( return { restArguments: restCommandArgs, stopArgIndex: currentCommandArgIndex, + argumentsIntered, isBlocked: isBlockedOnCommand } } @@ -379,7 +394,13 @@ export const fillArgsByType = (args: SearchCommand[], expandBlock = true): Searc const currentArg = args[i] if (expandBlock && currentArg.type === TokenType.OneOf) result.push(...(currentArg?.arguments || [])) - if (currentArg.type === TokenType.Block) result.push(currentArg.arguments?.[0] as SearchCommand) + if (currentArg.type === TokenType.Block) { + result.push({ + multiple: currentArg.multiple, + optional: currentArg.optional, + ...(currentArg?.arguments?.[0] as SearchCommand || {}), + }) + } if (currentArg.token) result.push(currentArg) } diff --git a/redisinsight/ui/src/pages/search/utils/tests/query.spec.ts b/redisinsight/ui/src/pages/search/utils/tests/query.spec.ts index f356961a93..8dc839f048 100644 --- a/redisinsight/ui/src/pages/search/utils/tests/query.spec.ts +++ b/redisinsight/ui/src/pages/search/utils/tests/query.spec.ts @@ -111,6 +111,8 @@ const ftAggreageTests = [ name: 'function', token: 'REDUCE', type: 'string', + multiple: true, + optional: true, parent: { name: 'groupby', type: 'block', @@ -144,6 +146,27 @@ const ftAggreageTests = [ parent: expect.any(Object) } }, + { + args: ['""', '""', 'GROUPBY', '2', 'p1', 'p2', 'REDUCE', 'f', '1', 'AS', 'name'], + result: { + stopArg: undefined, + append: [ + [ + { + name: 'function', + token: 'REDUCE', + type: 'string', + multiple: true, + optional: true, + parent: expect.any(Object) + } + ] + ], + isBlocked: false, + isComplete: true, + parent: expect.any(Object) + } + }, { args: ['index', '"query"', 'SORTBY'], result: { @@ -158,40 +181,29 @@ const ftAggreageTests = [ args: ['index', '"query"', 'SORTBY', '1', 'p1'], result: { stopArg: { - name: 'order', - type: 'oneof', - arguments: [ - { - name: 'asc', - type: 'pure-token', - token: 'ASC' - }, + name: 'num', + type: 'integer', + token: 'MAX', + optional: true + }, + append: [ + [ { - name: 'desc', - type: 'pure-token', - token: 'DESC' + name: 'num', + type: 'integer', + token: 'MAX', + optional: true, + parent: expect.any(Object) } ] - }, - append: [[ - { - name: 'asc', - type: 'pure-token', - token: 'ASC' - }, - { - name: 'desc', - type: 'pure-token', - token: 'DESC' - } - ]], + ], isBlocked: false, - isComplete: false, + isComplete: true, parent: expect.any(Object) } }, { - args: ['index', '"query"', 'SORTBY', '1', 'p1', 'ASC'], + args: ['index', '"query"', 'SORTBY', '2', 'p1', 'ASC'], result: { stopArg: { name: 'num', @@ -239,7 +251,7 @@ const ftAggreageTests = [ } }, { - args: ['index', '"query"', 'SORTBY', '1', 'p1', 'ASC', 'MAX'], + args: ['index', '"query"', 'SORTBY', '2', 'p1', 'ASC', 'MAX'], result: { stopArg: { name: 'num', @@ -313,7 +325,8 @@ const ftSearchTests = [ name: 'count', type: 'string', token: 'FIELDS', - parent: expect.any(Object) + parent: expect.any(Object), + optional: true }, { name: 'num', @@ -415,6 +428,17 @@ const ftSearchTests = [ parent: expect.any(Object) } }, + { + args: ['', '', 'RETURN', '1', 'iden'], + result: { + stopArg: undefined, + // TODO: append may have AS token, since it is optional - we skip for now + append: [], + isBlocked: false, + isComplete: true, + parent: expect.any(Object) + } + }, { args: ['', '', 'RETURN', '2', 'iden'], result: { @@ -424,7 +448,6 @@ const ftSearchTests = [ token: 'AS', optional: true }, - // TODO: append may have AS token, since it is optional - we skip for now append: [[]], isBlocked: false, isComplete: false, @@ -434,20 +457,15 @@ const ftSearchTests = [ { args: ['', '', 'RETURN', '2', 'iden', 'iden'], result: { - stopArg: { - name: 'property', - type: 'string', - token: 'AS', - optional: true - }, - append: [[]], + stopArg: undefined, + append: [], isBlocked: false, isComplete: true, parent: expect.any(Object) } }, { - args: ['', '', 'RETURN', '2', 'iden', 'iden', 'AS'], + args: ['', '', 'RETURN', '3', 'iden', 'iden'], result: { stopArg: { name: 'property', @@ -455,12 +473,22 @@ const ftSearchTests = [ token: 'AS', optional: true }, - append: [], - isBlocked: true, + append: [[]], + isBlocked: false, isComplete: false, parent: expect.any(Object) } }, + { + args: ['', '', 'RETURN', '3', 'iden', 'iden', 'AS', 'iden2'], + result: { + stopArg: undefined, + append: [], + isBlocked: false, + isComplete: true, + parent: expect.any(Object) + } + }, { args: ['', '', 'SORTBY', 'f'], result: { From 8ade5c89d026f5ca120a37aa23200fcd2bed4da4 Mon Sep 17 00:00:00 2001 From: Roman Sergeenko Date: Sat, 14 Sep 2024 17:03:48 +0200 Subject: [PATCH 067/256] revert theme --- redisinsight/ui/src/pages/search/components/query/Query.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/redisinsight/ui/src/pages/search/components/query/Query.tsx b/redisinsight/ui/src/pages/search/components/query/Query.tsx index 28c0e1a582..96f613b1e3 100644 --- a/redisinsight/ui/src/pages/search/components/query/Query.tsx +++ b/redisinsight/ui/src/pages/search/components/query/Query.tsx @@ -18,7 +18,7 @@ import { CursorContext, FoundCommandArgument, SearchCommand, TokenType } from 'u import { RedisResponseBuffer } from 'uiSrc/slices/interfaces' import { fetchRedisearchInfoAction } from 'uiSrc/slices/browser/redisearch' import { getRediSearchMonarchTokensProvider } from 'uiSrc/utils/monaco/monarchTokens/redisearchTokens' -import { installRedisearchTheme } from 'uiSrc/utils/monaco/monacoThemes' +import { installRedisearchTheme, RedisearchMonacoTheme } from 'uiSrc/utils/monaco/monacoThemes' import { useDebouncedEffect } from 'uiSrc/services' import { options, DefinedArgumentName, FIELD_START_SYMBOL } from './constants' import { @@ -346,7 +346,7 @@ const Query = (props: Props) => { value={value} onChange={onChange} language={MonacoLanguage.RediSearch} - theme={theme === Theme.Dark ? 'dark' : 'light'} + theme={theme === Theme.Dark ? RedisearchMonacoTheme.dark : RedisearchMonacoTheme.light} options={options} editorDidMount={editorDidMount} /> From 2140499be63f996464a50c4f917f0758438f5212 Mon Sep 17 00:00:00 2001 From: Gnanesh Date: Sun, 15 Sep 2024 13:30:45 +0530 Subject: [PATCH 068/256] Dynamically show multiple byte formats --- .../OverviewMetrics/OverviewMetrics.tsx | 33 +++++++++++-------- 1 file changed, 19 insertions(+), 14 deletions(-) diff --git a/redisinsight/ui/src/components/database-overview/components/OverviewMetrics/OverviewMetrics.tsx b/redisinsight/ui/src/components/database-overview/components/OverviewMetrics/OverviewMetrics.tsx index 932a9ce341..864dbfe4d1 100644 --- a/redisinsight/ui/src/components/database-overview/components/OverviewMetrics/OverviewMetrics.tsx +++ b/redisinsight/ui/src/components/database-overview/components/OverviewMetrics/OverviewMetrics.tsx @@ -119,16 +119,21 @@ export const getOverviewMetrics = ({ theme, items, db = 0 }: Props): Array - {networkInKbps} -  kb/s + {networkIn} +  {networkInUnit} ), unavailableText: 'Network Input is not available', @@ -137,23 +142,23 @@ export const getOverviewMetrics = ({ theme, items, db = 0 }: Props): Array - {networkInKbps} -  kb/s + {networkIn} +  {networkInUnit} ), }, } - const networkOutKbpsItem = { + const networkOutItem = { id: 'network-output-tip', groupId: opsPerSecItem.id, title: 'Network Output', icon: theme === Theme.Dark ? OutputDarkIcon : OutputLightIcon, - value: networkOutKbps, + value: networkOut, content: ( <> - {networkOutKbps} -  kb/s + {networkOut} +  {networkOutUnit} ), unavailableText: 'Network Output is not available', @@ -162,8 +167,8 @@ export const getOverviewMetrics = ({ theme, items, db = 0 }: Props): Array - {networkOutKbps} -  kb/s + {networkOut} +  {networkOutUnit} ), }, @@ -179,8 +184,8 @@ export const getOverviewMetrics = ({ theme, items, db = 0 }: Props): Array Date: Mon, 16 Sep 2024 13:53:52 +0200 Subject: [PATCH 069/256] #RI-6100 - merge colors --- redisinsight/ui/src/constants/monaco/theme.ts | 62 +++++++++++-------- .../pages/search/components/query/Query.tsx | 5 +- .../ui/src/utils/monaco/monacoThemes.ts | 23 ------- 3 files changed, 36 insertions(+), 54 deletions(-) delete mode 100644 redisinsight/ui/src/utils/monaco/monacoThemes.ts diff --git a/redisinsight/ui/src/constants/monaco/theme.ts b/redisinsight/ui/src/constants/monaco/theme.ts index f7f69e1887..db0e6521fa 100644 --- a/redisinsight/ui/src/constants/monaco/theme.ts +++ b/redisinsight/ui/src/constants/monaco/theme.ts @@ -1,32 +1,5 @@ import { monaco } from 'react-monaco-editor' -export const darkThemeRules = [ - { token: 'function', foreground: 'BFBC4E' } -] - -export const lightThemeRules = [ - { token: 'function', foreground: '795E26' } -] - -export enum MonacoThemes { - Dark = 'dark', - Light = 'light' -} - -export const darkTheme: monaco.editor.IStandaloneThemeData = { - base: 'vs-dark', - inherit: true, - rules: darkThemeRules, - colors: {} -} - -export const lightTheme: monaco.editor.IStandaloneThemeData = { - base: 'vs', - inherit: true, - rules: lightThemeRules, - colors: {} -} - export const redisearchDarKThemeRules = [ { token: 'keyword', foreground: '#8094B1', fontStyle: 'bold' }, { token: 'argument.block.0', foreground: '#BDE8D7' }, @@ -62,3 +35,38 @@ export const redisearchLightThemeRules = [ { token: 'query.operator', foreground: '#B9F0F3' }, { token: 'function', foreground: '#9E7EE8' }, ] + +export const darkThemeRules = [ + { token: 'function', foreground: 'BFBC4E' }, + ...redisearchDarKThemeRules.map((rule) => ({ + ...rule, + token: `${rule.token}.redisearch` + })) +] + +export const lightThemeRules = [ + { token: 'function', foreground: '795E26' }, + ...redisearchLightThemeRules.map((rule) => ({ + ...rule, + token: `${rule.token}.redisearch` + })) +] + +export enum MonacoThemes { + Dark = 'dark', + Light = 'light' +} + +export const darkTheme: monaco.editor.IStandaloneThemeData = { + base: 'vs-dark', + inherit: true, + rules: darkThemeRules, + colors: {} +} + +export const lightTheme: monaco.editor.IStandaloneThemeData = { + base: 'vs', + inherit: true, + rules: lightThemeRules, + colors: {} +} diff --git a/redisinsight/ui/src/pages/search/components/query/Query.tsx b/redisinsight/ui/src/pages/search/components/query/Query.tsx index 96f613b1e3..f08e55d688 100644 --- a/redisinsight/ui/src/pages/search/components/query/Query.tsx +++ b/redisinsight/ui/src/pages/search/components/query/Query.tsx @@ -18,7 +18,6 @@ import { CursorContext, FoundCommandArgument, SearchCommand, TokenType } from 'u import { RedisResponseBuffer } from 'uiSrc/slices/interfaces' import { fetchRedisearchInfoAction } from 'uiSrc/slices/browser/redisearch' import { getRediSearchMonarchTokensProvider } from 'uiSrc/utils/monaco/monarchTokens/redisearchTokens' -import { installRedisearchTheme, RedisearchMonacoTheme } from 'uiSrc/utils/monaco/monacoThemes' import { useDebouncedEffect } from 'uiSrc/services' import { options, DefinedArgumentName, FIELD_START_SYMBOL } from './constants' import { @@ -135,8 +134,6 @@ const Query = (props: Props) => { ({ suggestions: suggestionsRef.current.data }) }).dispose - installRedisearchTheme() - editor.onDidChangeCursorPosition(handleCursorChange) editor.onKeyDown((e: monacoEditor.IKeyboardEvent) => { if (e.keyCode === monacoEditor.KeyCode.Escape && isSuggestionsOpened()) { @@ -346,7 +343,7 @@ const Query = (props: Props) => { value={value} onChange={onChange} language={MonacoLanguage.RediSearch} - theme={theme === Theme.Dark ? RedisearchMonacoTheme.dark : RedisearchMonacoTheme.light} + theme={theme === Theme.Dark ? 'dark' : 'light'} options={options} editorDidMount={editorDidMount} /> diff --git a/redisinsight/ui/src/utils/monaco/monacoThemes.ts b/redisinsight/ui/src/utils/monaco/monacoThemes.ts deleted file mode 100644 index c3fd5313a3..0000000000 --- a/redisinsight/ui/src/utils/monaco/monacoThemes.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { monaco as monacoEditor } from 'react-monaco-editor' -import { redisearchDarKThemeRules, redisearchLightThemeRules } from 'uiSrc/constants/monaco' - -export enum RedisearchMonacoTheme { - dark = 'redisearchDarkTheme', - light = 'redisearchLightTheme' -} - -export const installRedisearchTheme = () => { - monacoEditor.editor.defineTheme(RedisearchMonacoTheme.dark, { - base: 'vs-dark', - inherit: true, - rules: redisearchDarKThemeRules, - colors: {} - }) - - monacoEditor.editor.defineTheme(RedisearchMonacoTheme.light, { - base: 'vs', - inherit: true, - rules: redisearchLightThemeRules, - colors: {} - }) -} From bb11155b1c4f38256952e65d1c85d6bd7dbd699e Mon Sep 17 00:00:00 2001 From: Roman Sergeenko Date: Mon, 16 Sep 2024 16:11:40 +0200 Subject: [PATCH 070/256] #RI-6111 - fix suggestions --- .../ui/src/pages/search/utils/query.ts | 5 +- .../pages/search/utils/tests/query.spec.ts | 96 ++++++++++++++++++- 2 files changed, 94 insertions(+), 7 deletions(-) diff --git a/redisinsight/ui/src/pages/search/utils/query.ts b/redisinsight/ui/src/pages/search/utils/query.ts index ab6a1ae2a6..2d3a030449 100644 --- a/redisinsight/ui/src/pages/search/utils/query.ts +++ b/redisinsight/ui/src/pages/search/utils/query.ts @@ -171,7 +171,7 @@ const findStopArgumentInQuery = ( continue } - if (!isBlockedOnCommand && currentCommandArg.optional) { + if (!isBlockedOnCommand && currentCommandArg?.optional) { const isNotToken = currentCommandArg?.token && currentCommandArg.token !== arg.toUpperCase() const isNotOneOfToken = currentCommandArg?.type === TokenType.OneOf && currentCommandArg?.arguments?.every(({ token }) => token !== arg.toUpperCase()) @@ -315,7 +315,8 @@ export const getArgumentSuggestions = ( // if we finished argument - stopArgument will be undefined, then we get it as token const lastArgument = stopArgument ?? restArguments[0] - const beforeMandatoryOptionalArgs = getAllRestArguments(current, lastArgument, levelArgs, !stopArgument) + const isBlockComplete = !stopArgument && current?.name === lastArgument?.name + const beforeMandatoryOptionalArgs = getAllRestArguments(current, lastArgument, levelArgs, isBlockComplete) const requiredArgsLength = restNotFilledArgs.filter((arg) => !arg.optional).length return { diff --git a/redisinsight/ui/src/pages/search/utils/tests/query.spec.ts b/redisinsight/ui/src/pages/search/utils/tests/query.spec.ts index 8dc839f048..48ea441b65 100644 --- a/redisinsight/ui/src/pages/search/utils/tests/query.spec.ts +++ b/redisinsight/ui/src/pages/search/utils/tests/query.spec.ts @@ -1,10 +1,20 @@ import { addOwnTokenToArgs, findCurrentArgument, generateDetail, splitQueryByArgs } from 'uiSrc/pages/search/utils' -import { SearchCommand } from 'uiSrc/pages/search/types' +import { SearchCommand, TokenType } from 'uiSrc/pages/search/types' import { Maybe } from 'uiSrc/utils' import { MOCKED_SUPPORTED_COMMANDS } from '../../mocks/mocks' const ftSearchCommand = MOCKED_SUPPORTED_COMMANDS['FT.SEARCH'] const ftAggregateCommand = MOCKED_SUPPORTED_COMMANDS['FT.AGGREGATE'] +const COMMANDS = [ + { + name: 'FT.SEARCH', + ...ftSearchCommand + }, + { + name: 'FT.AGGREGATE', + ...ftAggregateCommand + } +] const ftAggreageTests = [ { args: [''], result: null }, @@ -151,6 +161,7 @@ const ftAggreageTests = [ result: { stopArg: undefined, append: [ + [], [ { name: 'function', @@ -289,7 +300,7 @@ const ftAggreageTests = [ args: ['index', '"query"', 'LOAD', '4', '1', '2', '3', '4'], result: { stopArg: undefined, - append: [], + append: [[]], isBlocked: false, isComplete: true, parent: expect.any(Object) @@ -433,7 +444,9 @@ const ftSearchTests = [ result: { stopArg: undefined, // TODO: append may have AS token, since it is optional - we skip for now - append: [], + append: [ + [] + ], isBlocked: false, isComplete: true, parent: expect.any(Object) @@ -458,7 +471,9 @@ const ftSearchTests = [ args: ['', '', 'RETURN', '2', 'iden', 'iden'], result: { stopArg: undefined, - append: [], + append: [ + [] + ], isBlocked: false, isComplete: true, parent: expect.any(Object) @@ -483,7 +498,9 @@ const ftSearchTests = [ args: ['', '', 'RETURN', '3', 'iden', 'iden', 'AS', 'iden2'], result: { stopArg: undefined, - append: [], + append: [ + [] + ], isBlocked: false, isComplete: true, parent: expect.any(Object) @@ -540,9 +557,78 @@ const ftSearchTests = [ parent: expect.any(Object) } }, + { + args: ['', '', 'DIALECT', '1'], + result: { + stopArg: undefined, + append: [ + [] + ], + isBlocked: false, + isComplete: true, + parent: expect.any(Object) + } + }, +] + +// Common test cases - provides list of suggestions +const commonfindCurrentArgumentCases = [ + { + input: 'FT.SEARCH index "" DIALECT 1', + result: { + stopArg: undefined, + append: expect.any(Array), + isBlocked: false, + isComplete: true, + parent: expect.any(Object) + }, + appendIncludes: ['WITHSCORES', 'VERBATIM', 'FILTER', 'SORTBY', 'RETURN'], + appendNotIncludes: ['DIALECT'] + }, + { + input: 'FT.AGGREGATE "idx:schools" "" GROUPBY 1 p REDUCE AVG 1 a1 AS name ', + result: { + stopArg: undefined, + append: expect.any(Array), + isBlocked: false, + isComplete: true, + parent: expect.any(Object) + }, + appendIncludes: ['REDUCE', 'APPLY', 'SORTBY', 'GROUPBY'], + appendNotIncludes: ['AS'], + }, ] describe('findCurrentArgument', () => { + describe('with list of commands', () => { + commonfindCurrentArgumentCases.forEach(({ input, result, appendIncludes, appendNotIncludes }) => { + it(`should return proper suggestions for ${input}`, () => { + const { args } = splitQueryByArgs(input) + const COMMANDS_LIST = COMMANDS.map((command) => ({ + ...addOwnTokenToArgs(command.name!, command), + token: command.name!, + type: TokenType.Block + })) + + const testResult = findCurrentArgument( + COMMANDS_LIST, + args.flat() + ) + expect(testResult).toEqual(result) + expect( + testResult?.append?.flat()?.map((arg) => arg.token) + ).toEqual( + expect.arrayContaining(appendIncludes) + ) + expect( + testResult?.append?.flat()?.map((arg) => arg.token) + ).toEqual( + expect.not.arrayContaining(appendNotIncludes) + ) + }) + }) + }) + describe('FT.AGGREGATE', () => { ftAggreageTests.forEach(({ args, result: testResult }) => { it(`should return proper suggestions for ${args.join(' ')}`, () => { From c005b70cc11b059f73442e9988946ed25b6ef0a7 Mon Sep 17 00:00:00 2001 From: mariasergeenko Date: Wed, 18 Sep 2024 14:05:02 +0200 Subject: [PATCH 071/256] fix vector --- redisinsight/ui/src/pages/search/components/query/utils.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/redisinsight/ui/src/pages/search/components/query/utils.ts b/redisinsight/ui/src/pages/search/components/query/utils.ts index 6519932cbc..c2503e6d0b 100644 --- a/redisinsight/ui/src/pages/search/components/query/utils.ts +++ b/redisinsight/ui/src/pages/search/components/query/utils.ts @@ -41,7 +41,7 @@ export const addFieldAttribute = (attribute: string, type: string) => { case 'TEXT': return `${attribute}:(\${1:term})` case 'NUMERIC': return `${attribute}:[\${1:range}]` case 'GEO': return `${attribute}:[\${1:lon} \${2:lat} \${3:radius} \${4:unit}]` - case 'VECTOR': return `${attribute} \${1:vector}` + case 'VECTOR': return `${attribute} \\$\${1:vector}` default: return attribute } } From 75a5208c0f397d25910e6af8a9b13baccdb9ae08 Mon Sep 17 00:00:00 2001 From: Roman Sergeenko Date: Thu, 19 Sep 2024 10:26:12 +0200 Subject: [PATCH 072/256] #RI-6119 - move browser pages from tabs to menu --- .../ui/src/assets/img/sidebar/search.svg | 3 + .../src/assets/img/sidebar/search_active.svg | 3 + .../main-router/constants/defaultRoutes.ts | 27 +++--- .../main-router/constants/redisStackRoutes.ts | 46 ++++------ .../constants/sub-routes/browserRoutes.ts | 22 ----- .../main-router/constants/sub-routes/index.ts | 2 - .../navigation-menu/NavigationMenu.spec.tsx | 4 +- .../navigation-menu/NavigationMenu.tsx | 46 ++++++++-- redisinsight/ui/src/constants/pages.ts | 7 +- .../top-namespace/TopNamespace.spec.tsx | 2 +- .../database-alias/DatabaseAlias.tsx | 2 +- .../DatabasesListWrapper.tsx | 2 +- .../ui/src/pages/keys/KeysPage.spec.tsx | 85 ------------------- redisinsight/ui/src/pages/keys/KeysPage.tsx | 62 -------------- .../browser-tabs/BrowserTabs.spec.tsx | 40 --------- .../components/browser-tabs/BrowserTabs.tsx | 67 --------------- .../keys/components/browser-tabs/index.ts | 3 - .../browser-tabs/styles.module.scss | 44 ---------- redisinsight/ui/src/pages/keys/index.ts | 3 - .../ui/src/pages/search/styles.module.scss | 2 +- .../wb-view/WBView/styles.module.scss | 2 +- redisinsight/ui/src/utils/routing.ts | 7 +- .../ui/src/utils/tests/routing.spec.ts | 8 +- 23 files changed, 93 insertions(+), 396 deletions(-) create mode 100644 redisinsight/ui/src/assets/img/sidebar/search.svg create mode 100644 redisinsight/ui/src/assets/img/sidebar/search_active.svg delete mode 100644 redisinsight/ui/src/components/main-router/constants/sub-routes/browserRoutes.ts delete mode 100644 redisinsight/ui/src/pages/keys/KeysPage.spec.tsx delete mode 100644 redisinsight/ui/src/pages/keys/KeysPage.tsx delete mode 100644 redisinsight/ui/src/pages/keys/components/browser-tabs/BrowserTabs.spec.tsx delete mode 100644 redisinsight/ui/src/pages/keys/components/browser-tabs/BrowserTabs.tsx delete mode 100644 redisinsight/ui/src/pages/keys/components/browser-tabs/index.ts delete mode 100644 redisinsight/ui/src/pages/keys/components/browser-tabs/styles.module.scss delete mode 100644 redisinsight/ui/src/pages/keys/index.ts diff --git a/redisinsight/ui/src/assets/img/sidebar/search.svg b/redisinsight/ui/src/assets/img/sidebar/search.svg new file mode 100644 index 0000000000..5fe15b2504 --- /dev/null +++ b/redisinsight/ui/src/assets/img/sidebar/search.svg @@ -0,0 +1,3 @@ + + + diff --git a/redisinsight/ui/src/assets/img/sidebar/search_active.svg b/redisinsight/ui/src/assets/img/sidebar/search_active.svg new file mode 100644 index 0000000000..fd5f5821e4 --- /dev/null +++ b/redisinsight/ui/src/assets/img/sidebar/search_active.svg @@ -0,0 +1,3 @@ + + + diff --git a/redisinsight/ui/src/components/main-router/constants/defaultRoutes.ts b/redisinsight/ui/src/components/main-router/constants/defaultRoutes.ts index 3e42509952..600f89c5e5 100644 --- a/redisinsight/ui/src/components/main-router/constants/defaultRoutes.ts +++ b/redisinsight/ui/src/components/main-router/constants/defaultRoutes.ts @@ -1,5 +1,6 @@ import { IRoute, FeatureFlags, PageNames, Pages } from 'uiSrc/constants' import { + BrowserPage, HomePage, InstancePage, RedisCloudDatabasesPage, @@ -8,23 +9,33 @@ import { RedisCloudSubscriptionsPage, RedisClusterDatabasesPage, } from 'uiSrc/pages' -import KeysPage from 'uiSrc/pages/keys' +import WorkbenchPage from 'uiSrc/pages/workbench' import PubSubPage from 'uiSrc/pages/pub-sub' import AnalyticsPage from 'uiSrc/pages/analytics' import RdiPage from 'uiSrc/pages/rdi/home' import RdiInstancePage from 'uiSrc/pages/rdi/instance' import RdiStatisticsPage from 'uiSrc/pages/rdi/statistics' import PipelineManagementPage from 'uiSrc/pages/rdi/pipeline-management' - -import { ANALYTICS_ROUTES, RDI_PIPELINE_MANAGEMENT_ROUTES, BROWSER_ROUTES } from './sub-routes' +import SearchPage from 'uiSrc/pages/search' +import { ANALYTICS_ROUTES, RDI_PIPELINE_MANAGEMENT_ROUTES } from './sub-routes' import COMMON_ROUTES from './commonRoutes' const INSTANCE_ROUTES: IRoute[] = [ { - path: Pages.keys(':instanceId'), - component: KeysPage, - routes: BROWSER_ROUTES, + pageName: PageNames.browser, + path: Pages.browser(':instanceId'), + component: BrowserPage, + }, + { + pageName: PageNames.workbench, + path: Pages.workbench(':instanceId'), + component: WorkbenchPage, + }, + { + pageName: PageNames.search, + path: Pages.search(':instanceId'), + component: SearchPage, }, { pageName: PageNames.pubSub, @@ -36,10 +47,6 @@ const INSTANCE_ROUTES: IRoute[] = [ component: AnalyticsPage, routes: ANALYTICS_ROUTES, }, - { - path: '/:instanceId/workbench', - redirect: (params) => Pages.workbench(params?.instanceId || '') - } ] const RDI_INSTANCE_ROUTES: IRoute[] = [ diff --git a/redisinsight/ui/src/components/main-router/constants/redisStackRoutes.ts b/redisinsight/ui/src/components/main-router/constants/redisStackRoutes.ts index 043937c1ca..9697c50110 100644 --- a/redisinsight/ui/src/components/main-router/constants/redisStackRoutes.ts +++ b/redisinsight/ui/src/components/main-router/constants/redisStackRoutes.ts @@ -2,7 +2,6 @@ import { PageNames, Pages, IRoute } from 'uiSrc/constants' import { BrowserPage, InstancePage, } from 'uiSrc/pages' -import KeysPage from 'uiSrc/pages/keys' import WorkbenchPage from 'uiSrc/pages/workbench' import SlowLogPage from 'uiSrc/pages/slow-log' import PubSubPage from 'uiSrc/pages/pub-sub' @@ -13,27 +12,6 @@ import DatabaseAnalysisPage from 'uiSrc/pages/database-analysis' import SearchPage from 'uiSrc/pages/search' import COMMON_ROUTES from './commonRoutes' -const BROWSER_ROUTES: IRoute[] = [ - { - pageName: PageNames.browser, - protected: true, - path: Pages.browser(':instanceId'), - component: BrowserPage, - }, - { - pageName: PageNames.search, - protected: true, - path: Pages.search(':instanceId'), - component: SearchPage, - }, - { - pageName: PageNames.workbench, - protected: true, - path: Pages.workbench(':instanceId'), - component: WorkbenchPage, - }, -] - const ANALYTICS_ROUTES: IRoute[] = [ { pageName: PageNames.slowLog, @@ -57,9 +35,22 @@ const ANALYTICS_ROUTES: IRoute[] = [ const INSTANCE_ROUTES: IRoute[] = [ { - path: Pages.keys(':instanceId'), - component: KeysPage, - routes: BROWSER_ROUTES, + pageName: PageNames.browser, + protected: true, + path: Pages.browser(':instanceId'), + component: BrowserPage, + }, + { + pageName: PageNames.workbench, + protected: true, + path: Pages.workbench(':instanceId'), + component: WorkbenchPage, + }, + { + pageName: PageNames.search, + protected: true, + path: Pages.search(':instanceId'), + component: SearchPage, }, { pageName: PageNames.pubSub, @@ -73,11 +64,6 @@ const INSTANCE_ROUTES: IRoute[] = [ component: AnalyticsPage, routes: ANALYTICS_ROUTES, }, - // redirect to the new workbench path - { - path: ':instanceId/workbench', - redirect: (params) => Pages.workbench(params?.instanceId || '') - } ] const ROUTES: IRoute[] = [ diff --git a/redisinsight/ui/src/components/main-router/constants/sub-routes/browserRoutes.ts b/redisinsight/ui/src/components/main-router/constants/sub-routes/browserRoutes.ts deleted file mode 100644 index 16c739a1be..0000000000 --- a/redisinsight/ui/src/components/main-router/constants/sub-routes/browserRoutes.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { IRoute, PageNames, Pages } from 'uiSrc/constants' -import BrowserPage from 'uiSrc/pages/browser' -import SearchPage from 'uiSrc/pages/search' -import WorkbenchPage from 'uiSrc/pages/workbench' - -export const BROWSER_ROUTES: IRoute[] = [ - { - pageName: PageNames.browser, - path: Pages.browser(':instanceId'), - component: BrowserPage, - }, - { - pageName: PageNames.search, - path: Pages.search(':instanceId'), - component: SearchPage, - }, - { - pageName: PageNames.workbench, - path: Pages.workbench(':instanceId'), - component: WorkbenchPage, - } -] diff --git a/redisinsight/ui/src/components/main-router/constants/sub-routes/index.ts b/redisinsight/ui/src/components/main-router/constants/sub-routes/index.ts index 5770a6d4ed..68a3732539 100644 --- a/redisinsight/ui/src/components/main-router/constants/sub-routes/index.ts +++ b/redisinsight/ui/src/components/main-router/constants/sub-routes/index.ts @@ -1,9 +1,7 @@ import { ANALYTICS_ROUTES } from './analyticsRoutes' import { RDI_PIPELINE_MANAGEMENT_ROUTES } from './rdiPipelineManagementRoutes' -import { BROWSER_ROUTES } from './browserRoutes' export { ANALYTICS_ROUTES, RDI_PIPELINE_MANAGEMENT_ROUTES, - BROWSER_ROUTES } diff --git a/redisinsight/ui/src/components/navigation-menu/NavigationMenu.spec.tsx b/redisinsight/ui/src/components/navigation-menu/NavigationMenu.spec.tsx index bcdba4a63d..c8a07c32a4 100644 --- a/redisinsight/ui/src/components/navigation-menu/NavigationMenu.spec.tsx +++ b/redisinsight/ui/src/components/navigation-menu/NavigationMenu.spec.tsx @@ -127,9 +127,9 @@ describe('NavigationMenu', () => { })) render() - screen.debug(undefined, 100_000) - expect(screen.getByTestId('browser-page-btn')).toBeTruthy() + expect(screen.getByTestId('workbench-page-btn')).toBeTruthy() + expect(screen.getByTestId('search-page-btn')).toBeTruthy() }) it('should render public routes', () => { diff --git a/redisinsight/ui/src/components/navigation-menu/NavigationMenu.tsx b/redisinsight/ui/src/components/navigation-menu/NavigationMenu.tsx index 0e03a29009..ef97859d0d 100644 --- a/redisinsight/ui/src/components/navigation-menu/NavigationMenu.tsx +++ b/redisinsight/ui/src/components/navigation-menu/NavigationMenu.tsx @@ -13,7 +13,7 @@ import { EuiToolTip } from '@elastic/eui' import HighlightedFeature, { Props as HighlightedFeatureProps } from 'uiSrc/components/hightlighted-feature/HighlightedFeature' -import { ANALYTICS_ROUTES, BROWSER_ROUTES } from 'uiSrc/components/main-router/constants/sub-routes' +import { ANALYTICS_ROUTES } from 'uiSrc/components/main-router/constants/sub-routes' import { FeatureFlags, PageNames, Pages } from 'uiSrc/constants' import { EXTERNAL_LINKS } from 'uiSrc/constants/links' @@ -24,6 +24,10 @@ import SettingsSVG from 'uiSrc/assets/img/sidebar/settings.svg' import SettingsActiveSVG from 'uiSrc/assets/img/sidebar/settings_active.svg' import BrowserSVG from 'uiSrc/assets/img/sidebar/browser.svg' import BrowserActiveSVG from 'uiSrc/assets/img/sidebar/browser_active.svg' +import WorkbenchSVG from 'uiSrc/assets/img/sidebar/workbench.svg' +import WorkbenchActiveSVG from 'uiSrc/assets/img/sidebar/workbench_active.svg' +import SearchSVG from 'uiSrc/assets/img/sidebar/search.svg' +import SearchActiveSVG from 'uiSrc/assets/img/sidebar/search_active.svg' import SlowLogSVG from 'uiSrc/assets/img/sidebar/slowlog.svg' import SlowLogActiveSVG from 'uiSrc/assets/img/sidebar/slowlog_active.svg' import PubSubSVG from 'uiSrc/assets/img/sidebar/pubsub.svg' @@ -88,10 +92,6 @@ const NavigationMenu = () => { ({ path }) => (`/${last(path.split('/'))}` === activePage) ) - const isBrowserPath = (activePage: string) => !!BROWSER_ROUTES.find( - ({ path }) => (`/${last(path.split('/'))}` === activePage) - ) - const isPipelineManagementPath = () => location.pathname?.startsWith(Pages.rdiPipelineManagement(connectedRdiInstanceId)) @@ -111,9 +111,9 @@ const NavigationMenu = () => { { tooltipText: 'Browser', pageName: PageNames.browser, - isActivePage: isBrowserPath(activePage), + isActivePage: activePage === `/${PageNames.browser}`, ariaLabel: 'Browser page button', - onClick: () => handleGoPage(Pages.keys(connectedInstanceId)), + onClick: () => handleGoPage(Pages.browser(connectedInstanceId)), dataTestId: 'browser-page-btn', connectedInstanceId, getClassName() { @@ -122,6 +122,38 @@ const NavigationMenu = () => { getIconType() { return this.isActivePage ? BrowserSVG : BrowserActiveSVG }, + onboard: ONBOARDING_FEATURES.BROWSER_PAGE + }, + { + tooltipText: 'Search and Query', + pageName: PageNames.search, + ariaLabel: 'Search and Query page button', + onClick: () => handleGoPage(Pages.search(connectedInstanceId)), + dataTestId: 'search-page-btn', + connectedInstanceId, + isActivePage: activePage === `/${PageNames.search}`, + getClassName() { + return cx(styles.navigationButton, { [styles.active]: this.isActivePage }) + }, + getIconType() { + return this.isActivePage ? SearchSVG : SearchActiveSVG + }, + }, + { + tooltipText: 'Workbench', + pageName: PageNames.workbench, + ariaLabel: 'Workbench page button', + onClick: () => handleGoPage(Pages.workbench(connectedInstanceId)), + dataTestId: 'workbench-page-btn', + connectedInstanceId, + isActivePage: activePage === `/${PageNames.workbench}`, + getClassName() { + return cx(styles.navigationButton, { [styles.active]: this.isActivePage }) + }, + getIconType() { + return this.isActivePage ? WorkbenchSVG : WorkbenchActiveSVG + }, + onboard: ONBOARDING_FEATURES.WORKBENCH_PAGE }, { tooltipText: 'Analysis Tools', diff --git a/redisinsight/ui/src/constants/pages.ts b/redisinsight/ui/src/constants/pages.ts index 17b6d7a35c..b063b6cc68 100644 --- a/redisinsight/ui/src/constants/pages.ts +++ b/redisinsight/ui/src/constants/pages.ts @@ -47,10 +47,9 @@ export const Pages = { sentinel, sentinelDatabases: `${sentinel}/databases`, sentinelDatabasesResult: `${sentinel}/databases-result`, - keys: (instanceId: string) => `/${instanceId}/${PageNames.browser}`, - browser: (instanceId: string) => `/${instanceId}/${PageNames.browser}/${PageNames.browser}`, - search: (instanceId: string) => `/${instanceId}/${PageNames.browser}/${PageNames.search}`, - workbench: (instanceId: string) => `/${instanceId}/${PageNames.browser}/${PageNames.workbench}`, + browser: (instanceId: string) => `/${instanceId}/${PageNames.browser}`, + workbench: (instanceId: string) => `/${instanceId}/${PageNames.workbench}`, + search: (instanceId: string) => `/${instanceId}/${PageNames.search}`, pubSub: (instanceId: string) => `/${instanceId}/${PageNames.pubSub}`, analytics: (instanceId: string) => `/${instanceId}/${PageNames.analytics}`, slowLog: (instanceId: string) => `/${instanceId}/${PageNames.analytics}/${PageNames.slowLog}`, diff --git a/redisinsight/ui/src/pages/database-analysis/components/top-namespace/TopNamespace.spec.tsx b/redisinsight/ui/src/pages/database-analysis/components/top-namespace/TopNamespace.spec.tsx index 88d050d31e..9a8a0c1c14 100644 --- a/redisinsight/ui/src/pages/database-analysis/components/top-namespace/TopNamespace.spec.tsx +++ b/redisinsight/ui/src/pages/database-analysis/components/top-namespace/TopNamespace.spec.tsx @@ -166,6 +166,6 @@ describe('TopNamespace', () => { expect(store.getActions()).toEqual(expectedActions) expect(pushMock).toHaveBeenCalledTimes(1) - expect(pushMock).toHaveBeenCalledWith('/instanceId/browser/browser') + expect(pushMock).toHaveBeenCalledWith('/instanceId/browser') }) }) diff --git a/redisinsight/ui/src/pages/home/components/database-alias/DatabaseAlias.tsx b/redisinsight/ui/src/pages/home/components/database-alias/DatabaseAlias.tsx index c3510d03ee..5018d2061e 100644 --- a/redisinsight/ui/src/pages/home/components/database-alias/DatabaseAlias.tsx +++ b/redisinsight/ui/src/pages/home/components/database-alias/DatabaseAlias.tsx @@ -95,7 +95,7 @@ const DatabaseAlias = (props: Props) => { dispatch(setAppContextInitialState()) } dispatch(setConnectedInstanceId(id ?? '')) - history.push(Pages.keys(id ?? '')) + history.push(Pages.browser(id ?? '')) } const handleOpen = (event: any) => { diff --git a/redisinsight/ui/src/pages/home/components/database-list-component/DatabasesListWrapper.tsx b/redisinsight/ui/src/pages/home/components/database-list-component/DatabasesListWrapper.tsx index e413acf9f9..03898384bf 100644 --- a/redisinsight/ui/src/pages/home/components/database-list-component/DatabasesListWrapper.tsx +++ b/redisinsight/ui/src/pages/home/components/database-list-component/DatabasesListWrapper.tsx @@ -125,7 +125,7 @@ const DatabasesListWrapper = ({ width, onEditInstance, editedInstance, onDeleteI } dispatch(setConnectedInstanceId(id)) - history.push(Pages.keys(id)) + history.push(Pages.browser(id)) } const handleCheckConnectToInstance = ( event: React.MouseEvent | React.KeyboardEvent, diff --git a/redisinsight/ui/src/pages/keys/KeysPage.spec.tsx b/redisinsight/ui/src/pages/keys/KeysPage.spec.tsx deleted file mode 100644 index b3b4982efe..0000000000 --- a/redisinsight/ui/src/pages/keys/KeysPage.spec.tsx +++ /dev/null @@ -1,85 +0,0 @@ -import React from 'react' -import reactRouterDom, { BrowserRouter } from 'react-router-dom' -import { cleanup } from '@testing-library/react' -import { cloneDeep } from 'lodash' -import { mockedStore, render } from 'uiSrc/utils/test-utils' - -import { Pages } from 'uiSrc/constants' -import { appContextSelector, setLastPageContext } from 'uiSrc/slices/app/context' -import KeysPage from './KeysPage' - -jest.mock('uiSrc/slices/app/context', () => ({ - ...jest.requireActual('uiSrc/slices/app/context'), - appContextSelector: jest.fn().mockReturnValue({ - lastBrowserPage: '', - }), -})) - -let store: typeof mockedStore -beforeEach(() => { - cleanup() - store = cloneDeep(mockedStore) - store.clearActions() -}) - -const mockedRoutes = [ - { - path: '/123/browser', - }, -] - -describe('KeysPage', () => { - it('should render', () => { - expect( - render( - - - - ) - ).toBeTruthy() - }) - - it('should redirect to the browser by default', () => { - const pushMock = jest.fn() - reactRouterDom.useHistory = jest.fn().mockReturnValue({ push: pushMock }) - reactRouterDom.useLocation = jest.fn().mockReturnValue({ pathname: Pages.keys('instanceId') }) - - render( - - - - ) - - expect(pushMock).toBeCalledWith(Pages.browser('instanceId')) - }) - - it('should redirect to the prev page from context', () => { - (appContextSelector as jest.Mock).mockReturnValueOnce({ - lastBrowserPage: Pages.workbench('instanceId') - }) - const pushMock = jest.fn() - reactRouterDom.useHistory = jest.fn().mockReturnValue({ push: pushMock }) - reactRouterDom.useLocation = jest.fn().mockReturnValue({ pathname: Pages.keys('instanceId') }) - - render( - - - - ) - - expect(pushMock).toBeCalledWith(Pages.workbench('instanceId')) - }) - - it('should save proper page on unmount', () => { - reactRouterDom.useLocation = jest.fn().mockReturnValue({ pathname: Pages.workbench('instanceId') }) - - const { unmount } = render( - - - - ) - - unmount() - expect(store.getActions()).toEqual([setLastPageContext('/instanceId/browser/workbench')]) - }) -}) diff --git a/redisinsight/ui/src/pages/keys/KeysPage.tsx b/redisinsight/ui/src/pages/keys/KeysPage.tsx deleted file mode 100644 index 9ac514c88d..0000000000 --- a/redisinsight/ui/src/pages/keys/KeysPage.tsx +++ /dev/null @@ -1,62 +0,0 @@ -import React, { useEffect, useRef } from 'react' -import { Switch, useHistory, useLocation, useParams } from 'react-router-dom' -import { useDispatch, useSelector } from 'react-redux' -import { IRoute, Pages } from 'uiSrc/constants' -import { appContextSelector, setLastPageContext } from 'uiSrc/slices/app/context' -import RouteWithSubRoutes from 'uiSrc/utils/routerWithSubRoutes' - -import BrowserTabs from './components/browser-tabs' - -export interface Props { - routes: IRoute[] -} - -const KeysPage = (props: Props) => { - const { routes } = props - - const { lastBrowserPage } = useSelector(appContextSelector) - const { instanceId } = useParams<{ instanceId: string }>() - const { pathname } = useLocation() - const pathnameRef = useRef('') - - const history = useHistory() - const dispatch = useDispatch() - - useEffect(() => () => { - dispatch(setLastPageContext(pathnameRef.current)) - }, []) - - useEffect(() => { - if (pathname === Pages.keys(instanceId)) { - // restore current inner page and ignore context (as we store context on unmount) - if (pathnameRef.current && pathnameRef.current !== lastBrowserPage) { - history.push(pathnameRef.current) - return - } - - // restore from context - if (lastBrowserPage) { - history.push(lastBrowserPage) - return - } - - history.push(Pages.browser(instanceId)) - } - - pathnameRef.current = pathname === Pages.keys(instanceId) ? '' : pathname - }, [pathname]) - - return ( - <> - - - {routes.map((route, i) => ( - // eslint-disable-next-line react/no-array-index-key - - ))} - - - ) -} - -export default KeysPage diff --git a/redisinsight/ui/src/pages/keys/components/browser-tabs/BrowserTabs.spec.tsx b/redisinsight/ui/src/pages/keys/components/browser-tabs/BrowserTabs.spec.tsx deleted file mode 100644 index a85228d2e4..0000000000 --- a/redisinsight/ui/src/pages/keys/components/browser-tabs/BrowserTabs.spec.tsx +++ /dev/null @@ -1,40 +0,0 @@ -import React from 'react' -import reactRouterDom from 'react-router-dom' -import { render, screen, fireEvent } from 'uiSrc/utils/test-utils' - -import BrowserTabs from './BrowserTabs' - -jest.mock('uiSrc/telemetry', () => ({ - ...jest.requireActual('uiSrc/telemetry'), - sendEventTelemetry: jest.fn(), -})) - -jest.mock('react-router-dom', () => ({ - ...jest.requireActual('react-router-dom'), - useHistory: () => ({ - push: jest.fn, - }), -})) - -const MOCKED_INSTANCE_ID = 'instanceId' - -describe('BrowserTabs', () => { - it('should render', () => { - expect(render()).toBeTruthy() - }) - - it('should call proper history push after click on tabs', () => { - const pushMock = jest.fn() - reactRouterDom.useHistory = jest.fn().mockReturnValue({ push: pushMock }) - - render() - - fireEvent.click(screen.getByTestId('browser-tab-workbench')) - expect(pushMock).toBeCalledWith('/instanceId/browser/workbench') - - pushMock.mockRestore() - - fireEvent.click(screen.getByTestId('browser-tab-browser')) - expect(pushMock).toBeCalledWith('/instanceId/browser/browser') - }) -}) diff --git a/redisinsight/ui/src/pages/keys/components/browser-tabs/BrowserTabs.tsx b/redisinsight/ui/src/pages/keys/components/browser-tabs/BrowserTabs.tsx deleted file mode 100644 index 4799a72bf5..0000000000 --- a/redisinsight/ui/src/pages/keys/components/browser-tabs/BrowserTabs.tsx +++ /dev/null @@ -1,67 +0,0 @@ -import React from 'react' -import { EuiBadge, EuiTab, EuiTabs } from '@elastic/eui' -import { useHistory } from 'react-router-dom' -import { Pages } from 'uiSrc/constants/pages' - -import { renderOnboardingTourWithChild } from 'uiSrc/utils/onboarding' -import { ONBOARDING_FEATURES } from 'uiSrc/components/onboarding-features' -import styles from './styles.module.scss' - -export interface Props { - instanceId: string - pathname: string -} - -const BrowserTabs = (props: Props) => { - const { instanceId, pathname } = props - - const history = useHistory() - - const tabs = [ - { - id: 'browser', - title: 'Browse and filter', - page: Pages.browser(instanceId), - onboard: ONBOARDING_FEATURES.BROWSER_PAGE - }, - { - id: 'search', - title: 'Search and query', - page: Pages.search(instanceId), - isBeta: true - }, - { - id: 'workbench', - title: 'Workbench', - page: Pages.workbench(instanceId), - onboard: ONBOARDING_FEATURES.WORKBENCH_PAGE, - } - ] - - const onClickTab = (page: string) => { - history.push(page) - } - - return ( - - {tabs.map(({ id, title, page, onboard, isBeta }) => renderOnboardingTourWithChild( - ( - onClickTab(page)} - data-testid={`browser-tab-${id}`} - > - {title} - {isBeta && ((New!))} - - ), - { options: onboard, anchorPosition: 'downLeft' }, - pathname === page - ))} - - ) -} - -export default BrowserTabs diff --git a/redisinsight/ui/src/pages/keys/components/browser-tabs/index.ts b/redisinsight/ui/src/pages/keys/components/browser-tabs/index.ts deleted file mode 100644 index e1617ed596..0000000000 --- a/redisinsight/ui/src/pages/keys/components/browser-tabs/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -import BrowserTabs from './BrowserTabs' - -export default BrowserTabs diff --git a/redisinsight/ui/src/pages/keys/components/browser-tabs/styles.module.scss b/redisinsight/ui/src/pages/keys/components/browser-tabs/styles.module.scss deleted file mode 100644 index 3072523b71..0000000000 --- a/redisinsight/ui/src/pages/keys/components/browser-tabs/styles.module.scss +++ /dev/null @@ -1,44 +0,0 @@ -.tabs { - margin: 0 16px 16px; - background: var(--euiColorEmptyShade); - - .tab { - padding: 8px 16px !important; - margin: 0 !important; - border-radius: 0 !important; - color: var(--euiTextSubduedColor) !important; - border-right: 1px solid var(--separatorColor); - - &:hover { - background: var(--tableLightBorderColor); - } - - &:global(.euiTab-isSelected) { - color: var(--euiTextColor) !important; - background: var(--insightsTriggerBgColor) !important; - } - - &:after { - display: none !important; - } - } - - .betaLabel { - margin-left: 12px; - font-size: 8px !important; - line-height: 12px !important; - background-color: var(--recommendationLiveBorderColor) !important; - border: 1px solid var(--triggerIconActiveColor) !important; - color: #FFF7EA !important; - border-radius: 2px !important; - padding: 0 3px !important; - margin-bottom: 2px; - - transition: transform 250ms ease-in-out; - pointer-events: none; - - :global(.euiBadge__content) { - min-height: 12px !important; - } - } -} diff --git a/redisinsight/ui/src/pages/keys/index.ts b/redisinsight/ui/src/pages/keys/index.ts deleted file mode 100644 index 06362669d9..0000000000 --- a/redisinsight/ui/src/pages/keys/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -import KeysPage from './KeysPage' - -export default KeysPage diff --git a/redisinsight/ui/src/pages/search/styles.module.scss b/redisinsight/ui/src/pages/search/styles.module.scss index 359b2462eb..160dcb9b75 100644 --- a/redisinsight/ui/src/pages/search/styles.module.scss +++ b/redisinsight/ui/src/pages/search/styles.module.scss @@ -2,7 +2,7 @@ flex-grow: 1; display: flex; flex-direction: column; - max-height: calc(100% - 50px); + max-height: 100%; } .main { diff --git a/redisinsight/ui/src/pages/workbench/components/wb-view/WBView/styles.module.scss b/redisinsight/ui/src/pages/workbench/components/wb-view/WBView/styles.module.scss index cea9ac8893..5d5312b271 100644 --- a/redisinsight/ui/src/pages/workbench/components/wb-view/WBView/styles.module.scss +++ b/redisinsight/ui/src/pages/workbench/components/wb-view/WBView/styles.module.scss @@ -2,7 +2,7 @@ display: flex; flex-grow: 1; flex-direction: column; - max-height: calc(100% - 50px); + max-height: 100%; } .main { diff --git a/redisinsight/ui/src/utils/routing.ts b/redisinsight/ui/src/utils/routing.ts index 341b33e01a..78ea0d2ec2 100644 --- a/redisinsight/ui/src/utils/routing.ts +++ b/redisinsight/ui/src/utils/routing.ts @@ -1,4 +1,4 @@ -import { IRoute, Pages } from 'uiSrc/constants' +import { IRoute } from 'uiSrc/constants' import { Maybe, Nullable } from 'uiSrc/utils' import DEFAULT_ROUTES from 'uiSrc/components/main-router/constants/defaultRoutes' @@ -43,11 +43,6 @@ export const getRedirectionPage = ( page += '&insights=open' } - // old page - temp redirection - if (page === 'workbench' && databaseId) { - return `${Pages.keys(databaseId)}/${page}` - } - const foundRoute = findRouteByPathname(DEFAULT_ROUTES, pathname) if (!foundRoute) return undefined diff --git a/redisinsight/ui/src/utils/tests/routing.spec.ts b/redisinsight/ui/src/utils/tests/routing.spec.ts index ab019d61b5..adc3a1a3b3 100644 --- a/redisinsight/ui/src/utils/tests/routing.spec.ts +++ b/redisinsight/ui/src/utils/tests/routing.spec.ts @@ -14,10 +14,10 @@ Object.defineProperty(window, 'location', { const databaseId = '1' const getRedirectionPageTests = [ { input: ['settings'], expected: '/settings' }, - { input: ['workbench', databaseId], expected: '/1/browser/workbench' }, - { input: ['/workbench', databaseId], expected: '/1/browser/workbench' }, - { input: ['browser/workbench', databaseId], expected: '/1/browser/workbench' }, - { input: ['/browser/workbench', databaseId], expected: '/1/browser/workbench' }, + { input: ['workbench', databaseId], expected: '/1/workbench' }, + { input: ['/workbench', databaseId], expected: '/1/workbench' }, + { input: ['browser', databaseId], expected: '/1/browser' }, + { input: ['/browser', databaseId], expected: '/1/browser' }, { input: ['/analytics/slowlog', databaseId], expected: '/1/analytics/slowlog' }, { input: ['/analytics/slowlog'], expected: null }, { input: ['/analytics', databaseId], expected: '/1/analytics' }, From e345e8181e03b4c7e01543ae37a88d4ad3c63959 Mon Sep 17 00:00:00 2001 From: Roman Sergeenko Date: Thu, 19 Sep 2024 10:46:19 +0200 Subject: [PATCH 073/256] #RI-6119 - add tests, fix test --- .../triggers/insights-trigger/InsightsTrigger.spec.tsx | 2 +- redisinsight/ui/src/utils/tests/routing.spec.ts | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/redisinsight/ui/src/components/triggers/insights-trigger/InsightsTrigger.spec.tsx b/redisinsight/ui/src/components/triggers/insights-trigger/InsightsTrigger.spec.tsx index 2619b6a388..2c4dc23b9f 100644 --- a/redisinsight/ui/src/components/triggers/insights-trigger/InsightsTrigger.spec.tsx +++ b/redisinsight/ui/src/components/triggers/insights-trigger/InsightsTrigger.spec.tsx @@ -86,7 +86,7 @@ describe('InsightsTrigger', () => { databaseId: 'instanceId', provider: 'RE_CLOUD', source: 'overview', - page: '/browser/browser', + page: '/browser', tab: 'tips' }, }); diff --git a/redisinsight/ui/src/utils/tests/routing.spec.ts b/redisinsight/ui/src/utils/tests/routing.spec.ts index adc3a1a3b3..6f11ef1ae2 100644 --- a/redisinsight/ui/src/utils/tests/routing.spec.ts +++ b/redisinsight/ui/src/utils/tests/routing.spec.ts @@ -18,6 +18,8 @@ const getRedirectionPageTests = [ { input: ['/workbench', databaseId], expected: '/1/workbench' }, { input: ['browser', databaseId], expected: '/1/browser' }, { input: ['/browser', databaseId], expected: '/1/browser' }, + { input: ['search', databaseId], expected: '/1/search' }, + { input: ['/search', databaseId], expected: '/1/search' }, { input: ['/analytics/slowlog', databaseId], expected: '/1/analytics/slowlog' }, { input: ['/analytics/slowlog'], expected: null }, { input: ['/analytics', databaseId], expected: '/1/analytics' }, From 2c711998abde002285b40b735739cb3c931ba77a Mon Sep 17 00:00:00 2001 From: Gnanesh Date: Thu, 19 Sep 2024 20:16:36 +0530 Subject: [PATCH 074/256] Add support for 1000 base which is used for network metrics --- .../components/OverviewMetrics/OverviewMetrics.tsx | 9 +++++---- .../ui/src/utils/tests/transformers/formatBytes.spec.ts | 5 +++++ redisinsight/ui/src/utils/transformers/formatBytes.ts | 5 +++-- 3 files changed, 13 insertions(+), 6 deletions(-) diff --git a/redisinsight/ui/src/components/database-overview/components/OverviewMetrics/OverviewMetrics.tsx b/redisinsight/ui/src/components/database-overview/components/OverviewMetrics/OverviewMetrics.tsx index 864dbfe4d1..68ae57d115 100644 --- a/redisinsight/ui/src/components/database-overview/components/OverviewMetrics/OverviewMetrics.tsx +++ b/redisinsight/ui/src/components/database-overview/components/OverviewMetrics/OverviewMetrics.tsx @@ -119,10 +119,11 @@ export const getOverviewMetrics = ({ theme, items, db = 0 }: Props): Array { expect(formatBytes(1572864, 0, true)).toEqual([2, 'MB']) expect(formatBytes(1347545989, 3, true)).toEqual([1.255, 'GB']) }) + + it('should properly set the baseK', () => { + expect(formatBytes(1347545989, 3, true)).toEqual([1.255, 'GB']) // default uses 1024 + expect(formatBytes(1347545989, 3, true, 1000)).toEqual([1.348, 'GB']) + }) }) const toBytesTests: any[] = [ diff --git a/redisinsight/ui/src/utils/transformers/formatBytes.ts b/redisinsight/ui/src/utils/transformers/formatBytes.ts index 9739fd4b32..51afb53172 100644 --- a/redisinsight/ui/src/utils/transformers/formatBytes.ts +++ b/redisinsight/ui/src/utils/transformers/formatBytes.ts @@ -3,11 +3,12 @@ const SIZES = ['B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'] export const formatBytes = ( input: number, decimals: number = 3, - splitResult: boolean = false + splitResult: boolean = false, + baseK = 1024, ): string | [number, string] => { try { const bytes = parseFloat(String(input)) - const k = 1024 + const k = baseK const dm = decimals < 0 ? 0 : decimals if (Number.isNaN(bytes) || bytes < 0) return '-' if (bytes === 0) return `0 ${SIZES[0]}` From 6244234b32b6c5184d76c0df1a1fdd9870ca6832 Mon Sep 17 00:00:00 2001 From: Gnanesh Date: Thu, 19 Sep 2024 20:19:36 +0530 Subject: [PATCH 075/256] Remove console log --- .../components/OverviewMetrics/OverviewMetrics.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/redisinsight/ui/src/components/database-overview/components/OverviewMetrics/OverviewMetrics.tsx b/redisinsight/ui/src/components/database-overview/components/OverviewMetrics/OverviewMetrics.tsx index 68ae57d115..857c0a5876 100644 --- a/redisinsight/ui/src/components/database-overview/components/OverviewMetrics/OverviewMetrics.tsx +++ b/redisinsight/ui/src/components/database-overview/components/OverviewMetrics/OverviewMetrics.tsx @@ -120,7 +120,6 @@ export const getOverviewMetrics = ({ theme, items, db = 0 }: Props): Array Date: Fri, 20 Sep 2024 12:56:46 +0200 Subject: [PATCH 076/256] RI-6101 fix styling od time column in workbench --- .../query-card/QueryCardHeader/QueryCardHeader.tsx | 2 +- .../query-card/QueryCardHeader/styles.module.scss | 7 +------ 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/redisinsight/ui/src/components/query-card/QueryCardHeader/QueryCardHeader.tsx b/redisinsight/ui/src/components/query-card/QueryCardHeader/QueryCardHeader.tsx index f2de4c4f30..23a0fe5eb9 100644 --- a/redisinsight/ui/src/components/query-card/QueryCardHeader/QueryCardHeader.tsx +++ b/redisinsight/ui/src/components/query-card/QueryCardHeader/QueryCardHeader.tsx @@ -308,7 +308,7 @@ const QueryCardHeader = (props: Props) => { - + {!!createdAt && ( diff --git a/redisinsight/ui/src/components/query-card/QueryCardHeader/styles.module.scss b/redisinsight/ui/src/components/query-card/QueryCardHeader/styles.module.scss index 14c7e1faf5..6e7f6c4746 100644 --- a/redisinsight/ui/src/components/query-card/QueryCardHeader/styles.module.scss +++ b/redisinsight/ui/src/components/query-card/QueryCardHeader/styles.module.scss @@ -61,8 +61,7 @@ $marginIcon: 12px; } .time { - max-width: 90px; - position: relative; + max-width: 126px; } .mode + .mode { @@ -77,10 +76,6 @@ $marginIcon: 12px; text-align: left; } -.timeText { - min-width: 126px; -} - .summaryTextWrapper { min-width: 86px; } From 50746e3d01404f02d154a846500108b14a6601e1 Mon Sep 17 00:00:00 2001 From: Roman Sergeenko Date: Mon, 23 Sep 2024 09:31:40 +0200 Subject: [PATCH 077/256] refactoring --- .../pages/search/components/query/Query.tsx | 148 ++++++++---------- .../search/components/query/constants.ts | 2 + .../pages/search/components/query/utils.ts | 27 +--- .../ui/src/pages/search/utils/query.ts | 4 +- .../pages/search/utils/tests/query.spec.ts | 12 +- 5 files changed, 81 insertions(+), 112 deletions(-) diff --git a/redisinsight/ui/src/pages/search/components/query/Query.tsx b/redisinsight/ui/src/pages/search/components/query/Query.tsx index f08e55d688..d4b1f0c92e 100644 --- a/redisinsight/ui/src/pages/search/components/query/Query.tsx +++ b/redisinsight/ui/src/pages/search/components/query/Query.tsx @@ -47,11 +47,7 @@ const Query = (props: Props) => { const monacoObjects = useRef>(null) const disposeCompletionItemProvider = useRef(() => {}) const disposeSignatureHelpProvider = useRef(() => {}) - const suggestionsRef = useRef<{ - forceShow?: boolean - forceHide: boolean - data: monacoEditor.languages.CompletionItem[] - }>({ forceHide: false, data: [] }) + const suggestionsRef = useRef([]) const helpWidgetRef = useRef({ isOpen: false, parent: null, @@ -92,9 +88,8 @@ const Query = (props: Props) => { const index = selectedIndex.replace(/^(['"])(.*)\1$/, '$2') dispatch(fetchRedisearchInfoAction(index, - (data) => { - const { attributes } = data as any - attributesRef.current = attributes + (data: any) => { + attributesRef.current = data?.attributes || [] })) }, 200, [selectedIndex]) @@ -105,19 +100,6 @@ const Query = (props: Props) => { monaco.languages.register({ id: MonacoLanguage.RediSearch }) monacoObjects.current = { editor, monaco } - suggestionsRef.current = getSuggestions(editor) - - if (value) { - setCursorPositionAtTheEnd(editor) - } else { - const position = editor.getPosition() - - if (position?.column === 1 && position?.lineNumber === 1) { - editor.focus() - triggerSuggestions() - } - } - monaco.languages.setMonarchTokensProvider( MonacoLanguage.RediSearch, getRediSearchMonarchTokensProvider(supportedCommands) @@ -131,7 +113,7 @@ const Query = (props: Props) => { disposeCompletionItemProvider.current?.() disposeCompletionItemProvider.current = monaco.languages.registerCompletionItemProvider(MonacoLanguage.RediSearch, { provideCompletionItems: (): monacoEditor.languages.CompletionList => - ({ suggestions: suggestionsRef.current.data }) + ({ suggestions: suggestionsRef.current }) }).dispose editor.onDidChangeCursorPosition(handleCursorChange) @@ -140,6 +122,18 @@ const Query = (props: Props) => { isEscapedSuggestions.current = true } }) + + suggestionsRef.current = getSuggestions(editor).data + if (value) { + setCursorPositionAtTheEnd(editor) + return + } + + const position = editor.getPosition() + if (position?.column === 1 && position?.lineNumber === 1) { + editor.focus() + triggerSuggestions() + } } const isSuggestionsOpened = () => { @@ -151,7 +145,7 @@ const Query = (props: Props) => { const handleCursorChange = () => { const { editor } = monacoObjects.current || {} - suggestionsRef.current.data = [] + suggestionsRef.current = [] if (!editor) return if (!editor.getSelection()?.isEmpty()) { @@ -159,14 +153,15 @@ const Query = (props: Props) => { return } - suggestionsRef.current = getSuggestions(editor) + const { data, forceHide, forceShow } = getSuggestions(editor) + suggestionsRef.current = data - if (!suggestionsRef.current.forceShow) { + if (!forceShow) { editor.trigger('', 'editor.action.triggerParameterHints', '') return } - if (suggestionsRef.current.data.length) { + if (data.length) { helpWidgetRef.current.isOpen = false triggerSuggestions() return @@ -174,7 +169,7 @@ const Query = (props: Props) => { editor.trigger('', 'editor.action.triggerParameterHints', '') - if (suggestionsRef.current.forceHide) { + if (forceHide) { setTimeout(() => editor?.trigger('', 'hideSuggestWidget', null), 0) } else { helpWidgetRef.current.isOpen = !isSuggestionsOpened() && helpWidgetRef.current.isOpen @@ -182,22 +177,20 @@ const Query = (props: Props) => { } const triggerSuggestions = () => { - const { monaco, editor } = monacoObjects.current || {} - if (!monaco) return - + const { editor } = monacoObjects.current || {} + isEscapedSuggestions.current = false setTimeout(() => editor?.trigger('', 'editor.action.triggerSuggest', { auto: false })) } const updateHelpWidget = (isOpen: boolean, parent?: SearchCommand, currentArg?: SearchCommand) => { - helpWidgetRef.current.isOpen = isOpen - helpWidgetRef.current.parent = parent - helpWidgetRef.current.currentArg = currentArg + helpWidgetRef.current = { isOpen, parent, currentArg } } const getSuggestions = ( editor: monacoEditor.editor.IStandaloneCodeEditor ): { forceHide: boolean + forceShow: boolean data: monacoEditor.languages.CompletionItem[] } => { const position = editor.getPosition() @@ -211,22 +204,23 @@ const Query = (props: Props) => { const range = getRange(position, word) const { args, cursor } = splitQueryByArgs(value, offset) - const { prevCursorChar } = cursor + const { argLeftOffset, prevCursorChar } = cursor + const argBeforeCursor = prevCursorChar ?? (value.substring(argLeftOffset, offset) || '') const allArgs = args.flat() const [beforeOffsetArgs, [currentOffsetArg]] = args - const [firstArg, ...prevArgs] = beforeOffsetArgs + const [firstArg] = beforeOffsetArgs const commandName = (firstArg || currentOffsetArg)?.toUpperCase() const command = commandsSpec?.[commandName] as unknown as SearchCommand + const isCommandSupported = supportedCommands.some(({ name }) => commandName === name) - const isCommandSuppurted = supportedCommands.some(({ name }) => commandName === name) - if (command && !isCommandSuppurted) return asSuggestionsRef([]) - if (!command && position.lineNumber === 1 && position.column === 1) { - return getCommandsSuggestions(supportedCommands, range) - } - + if (command && !isCommandSupported) return asSuggestionsRef([]) if (!command) { + if (position.lineNumber === 1 && position.column === 1) { + return asSuggestionsRef(getCommandsSuggestions(supportedCommands, range), false) + } + helpWidgetRef.current.isOpen = false return asSuggestionsRef([], false) } @@ -235,24 +229,14 @@ const Query = (props: Props) => { setSelectedIndex(allArgs[1] || '') setSelectedCommand(commandName) + const cursorContext: CursorContext = { ...cursor, currentOffsetArg, offset } const foundArg = findCurrentArgument(COMMANDS_LIST, beforeOffsetArgs) - if (prevCursorChar === FIELD_START_SYMBOL) { - helpWidgetRef.current.isOpen = false - return asSuggestionsRef( - getFieldsSuggestions( - attributesRef.current, - range, - false, - foundArg?.stopArg?.name === DefinedArgumentName.query - ), - false - ) - } - const cursorContext: CursorContext = { ...cursor, currentOffsetArg, offset } + if (argBeforeCursor.startsWith(FIELD_START_SYMBOL)) return handleFieldSuggestions(foundArg, range) + switch (foundArg?.stopArg?.name) { case DefinedArgumentName.index: { - return handleIndexSuggestions(command, foundArg, prevArgs.length, currentOffsetArg, range) + return handleIndexSuggestions(command, foundArg, beforeOffsetArgs.length, currentOffsetArg, range) } case DefinedArgumentName.query: { return handleQuerySuggestions(command, foundArg) @@ -263,26 +247,29 @@ const Query = (props: Props) => { } } + const handleFieldSuggestions = (foundArg: Nullable, range: monacoEditor.IRange) => { + const isInQuery = foundArg?.stopArg?.name === DefinedArgumentName.query + const fieldSuggestions = getFieldsSuggestions(attributesRef.current, range, true, isInQuery) + return asSuggestionsRef(fieldSuggestions, true) + } + const handleIndexSuggestions = ( command: SearchCommand, foundArg: FoundCommandArgument, - prevArgsLength: number, + lastArgIndex: number, currentOffsetArg: Nullable, range: monacoEditor.IRange ) => { updateHelpWidget(true, command, foundArg?.stopArg) - if (currentOffsetArg) return asSuggestionsRef([], false) - if (indexesRef.current.length) { - const isNextArgQuery = command?.arguments?.[prevArgsLength + 1]?.name === DefinedArgumentName.query - return asSuggestionsRef(getIndexesSuggestions(indexesRef.current, range, isNextArgQuery)) - } - return asSuggestionsRef([]) + + const isIndex = indexesRef.current.length > 0 + if (!isIndex || currentOffsetArg) return asSuggestionsRef([], !currentOffsetArg) + + const isNextArgQuery = command?.arguments?.[lastArgIndex]?.name === DefinedArgumentName.query + return asSuggestionsRef(getIndexesSuggestions(indexesRef.current, range, isNextArgQuery)) } - const handleQuerySuggestions = ( - command: SearchCommand, - foundArg: FoundCommandArgument, - ) => { + const handleQuerySuggestions = (command: SearchCommand, foundArg: FoundCommandArgument) => { updateHelpWidget(true, command, foundArg?.stopArg) return asSuggestionsRef([], false) } @@ -299,16 +286,14 @@ const Query = (props: Props) => { if (!isCursorInQuotes) return asSuggestionsRef([]) const stringBeforeCursor = value.substring(argLeftOffset, offset) || '' - const { args } = splitQueryByArgs( - stringBeforeCursor.replace(/^["']|["']$/g, ''), - offset - argLeftOffset - ) + const expression = stringBeforeCursor.replace(/^["']|["']$/g, '') + const { args } = splitQueryByArgs(expression, offset - argLeftOffset) const [, [currentArg]] = args const functions = foundArg?.stopArg?.arguments ?? [] - const suggestions = getFunctionsSuggestions(functions, range) const isStartsWithFunction = functions.some(({ token }) => token?.startsWith(currentArg)) + return asSuggestionsRef(suggestions, true, isStartsWithFunction) } @@ -319,20 +304,17 @@ const Query = (props: Props) => { cursorContext: CursorContext, range: monacoEditor.IRange ) => { - if (foundArg?.isBlocked && foundArg?.stopArg?.expression) { - return handleExpressionSuggestions(value, foundArg, cursorContext, range) - } + if (foundArg?.stopArg?.expression) return handleExpressionSuggestions(value, foundArg, cursorContext, range) const { prevCursorChar, nextCursorChar, isCursorInQuotes } = cursorContext - if (isCursorInQuotes || nextCursorChar?.trim()) return asSuggestionsRef([]) - if ((prevCursorChar?.trim() || isCursorInQuotes) && isEscapedSuggestions.current) return asSuggestionsRef([]) - - const { suggestions, forceHide, helpWidgetData } = getGeneralSuggestions( - foundArg, - allArgs, - range, - attributesRef.current - ) + const shouldHideSuggestions = isCursorInQuotes || nextCursorChar || (prevCursorChar && isEscapedSuggestions.current) + if (shouldHideSuggestions) return asSuggestionsRef([]) + + const { + suggestions, + forceHide, + helpWidgetData + } = getGeneralSuggestions(foundArg, allArgs, range, attributesRef.current) if (helpWidgetData) updateHelpWidget(helpWidgetData.isOpen, helpWidgetData.parent, helpWidgetData.currentArg) return asSuggestionsRef(suggestions, forceHide) diff --git a/redisinsight/ui/src/pages/search/components/query/constants.ts b/redisinsight/ui/src/pages/search/components/query/constants.ts index 22dcf561d6..589f6f1484 100644 --- a/redisinsight/ui/src/pages/search/components/query/constants.ts +++ b/redisinsight/ui/src/pages/search/components/query/constants.ts @@ -7,6 +7,8 @@ export const options = merge(defaultMonacoOptions, showWords: false, showIcons: true, insertMode: 'replace', + filterGraceful: false, + matchOnWordStartOnly: true } }) diff --git a/redisinsight/ui/src/pages/search/components/query/utils.ts b/redisinsight/ui/src/pages/search/components/query/utils.ts index c2503e6d0b..581b85c2d2 100644 --- a/redisinsight/ui/src/pages/search/components/query/utils.ts +++ b/redisinsight/ui/src/pages/search/components/query/utils.ts @@ -20,10 +20,10 @@ export const asSuggestionsRef = ( forceShow }) -export const getIndexesSuggestions = (indexes: RedisResponseBuffer[], range: monaco.IRange, nextQoutes = true) => +export const getIndexesSuggestions = (indexes: RedisResponseBuffer[], range: monaco.IRange, nextQuotes = true) => indexes.map((index) => { const value = formatLongName(bufferToString(index)) - const insertQueryQuotes = nextQoutes ? ' "$1"' : '' + const insertQueryQuotes = nextQuotes ? ' "$1"' : '' return { label: value || ' ', @@ -83,15 +83,14 @@ export const getFunctionsSuggestions = (functions: SearchCommand[], range: monac detail: summary })) -export const getCommandsSuggestions = (commands: SearchCommand[], range: monaco.IRange) => asSuggestionsRef( +export const getCommandsSuggestions = (commands: SearchCommand[], range: monaco.IRange) => commands.map((command) => buildSuggestion(command, range, { detail: generateDetail(command), insertTextRules: monacoEditor.languages.CompletionItemInsertTextRule.InsertAsSnippet, documentation: { value: getCommandMarkdown(command as any) }, - })), false -) + })) export const getMandatoryArgumentSuggestions = ( foundArg: FoundCommandArgument, @@ -147,7 +146,7 @@ export const getGeneralSuggestions = ( foundArg: Nullable, allArgs: string[], range: monacoEditor.IRange, - fields: any[], + fields: any[] ): { suggestions: monacoEditor.languages.CompletionItem[], forceHide?: boolean @@ -156,24 +155,10 @@ export const getGeneralSuggestions = ( if (foundArg && !foundArg.isComplete) { return { suggestions: getMandatoryArgumentSuggestions(foundArg, fields, range), - helpWidgetData: { - isOpen: !!foundArg?.stopArg, - parent: foundArg?.parent, - currentArg: foundArg?.stopArg - } + helpWidgetData: { isOpen: !!foundArg?.stopArg, parent: foundArg?.parent, currentArg: foundArg?.stopArg } } } - return getNextSuggestions(foundArg, allArgs, range) -} - -export const getNextSuggestions = ( - foundArg: Nullable, - allArgs: string[], - range: monacoEditor.IRange -) => { - if (foundArg && !foundArg.isComplete) return { suggestions: [], helpWidgetData: { isOpen: false } } - return { suggestions: getCommandSuggestions(foundArg, allArgs, range), helpWidgetData: { isOpen: false } diff --git a/redisinsight/ui/src/pages/search/utils/query.ts b/redisinsight/ui/src/pages/search/utils/query.ts index 2d3a030449..17fbffcb53 100644 --- a/redisinsight/ui/src/pages/search/utils/query.ts +++ b/redisinsight/ui/src/pages/search/utils/query.ts @@ -91,8 +91,8 @@ export const splitQueryByArgs = (query: string, position: number = 0) => { const cursor = { isCursorInQuotes, - prevCursorChar: query[position - 1], - nextCursorChar: query[position], + prevCursorChar: query[position - 1]?.trim() || '', + nextCursorChar: query[position]?.trim() || '', argLeftOffset, argRightOffset } diff --git a/redisinsight/ui/src/pages/search/utils/tests/query.spec.ts b/redisinsight/ui/src/pages/search/utils/tests/query.spec.ts index 48ea441b65..b6b4a49991 100644 --- a/redisinsight/ui/src/pages/search/utils/tests/query.spec.ts +++ b/redisinsight/ui/src/pages/search/utils/tests/query.spec.ts @@ -667,7 +667,7 @@ const splitQueryByArgsTests: Array<{ argRightOffset: 23, isCursorInQuotes: false, nextCursorChar: 'F', - prevCursorChar: undefined + prevCursorChar: '' } } }, @@ -692,7 +692,7 @@ const splitQueryByArgsTests: Array<{ argLeftOffset: 27, argRightOffset: 39, isCursorInQuotes: false, - nextCursorChar: undefined, + nextCursorChar: '', prevCursorChar: 'S' } } @@ -705,8 +705,8 @@ const splitQueryByArgsTests: Array<{ argLeftOffset: 0, argRightOffset: 0, isCursorInQuotes: false, - nextCursorChar: undefined, - prevCursorChar: ' ' + nextCursorChar: '', + prevCursorChar: '' } } }, @@ -718,8 +718,8 @@ const splitQueryByArgsTests: Array<{ argLeftOffset: 0, argRightOffset: 0, isCursorInQuotes: false, - nextCursorChar: undefined, - prevCursorChar: ' ' + nextCursorChar: '', + prevCursorChar: '' } } } From 05b1c4b9fd081bfb5679f0d23b1dd2bc35a92b1e Mon Sep 17 00:00:00 2001 From: Roman Sergeenko Date: Mon, 23 Sep 2024 10:53:28 +0200 Subject: [PATCH 078/256] fix some issues --- .../ui/src/pages/search/components/query/Query.tsx | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/redisinsight/ui/src/pages/search/components/query/Query.tsx b/redisinsight/ui/src/pages/search/components/query/Query.tsx index d4b1f0c92e..5dff9067c1 100644 --- a/redisinsight/ui/src/pages/search/components/query/Query.tsx +++ b/redisinsight/ui/src/pages/search/components/query/Query.tsx @@ -178,7 +178,6 @@ const Query = (props: Props) => { const triggerSuggestions = () => { const { editor } = monacoObjects.current || {} - isEscapedSuggestions.current = false setTimeout(() => editor?.trigger('', 'editor.action.triggerSuggest', { auto: false })) } @@ -204,9 +203,8 @@ const Query = (props: Props) => { const range = getRange(position, word) const { args, cursor } = splitQueryByArgs(value, offset) - const { argLeftOffset, prevCursorChar } = cursor + const { prevCursorChar } = cursor - const argBeforeCursor = prevCursorChar ?? (value.substring(argLeftOffset, offset) || '') const allArgs = args.flat() const [beforeOffsetArgs, [currentOffsetArg]] = args const [firstArg] = beforeOffsetArgs @@ -217,7 +215,7 @@ const Query = (props: Props) => { if (command && !isCommandSupported) return asSuggestionsRef([]) if (!command) { - if (position.lineNumber === 1 && position.column === 1) { + if ((position.lineNumber === 1 && position.column === 1) || beforeOffsetArgs.length === 0) { return asSuggestionsRef(getCommandsSuggestions(supportedCommands, range), false) } @@ -232,7 +230,7 @@ const Query = (props: Props) => { const cursorContext: CursorContext = { ...cursor, currentOffsetArg, offset } const foundArg = findCurrentArgument(COMMANDS_LIST, beforeOffsetArgs) - if (argBeforeCursor.startsWith(FIELD_START_SYMBOL)) return handleFieldSuggestions(foundArg, range) + if (prevCursorChar === FIELD_START_SYMBOL) return handleFieldSuggestions(foundArg, range) switch (foundArg?.stopArg?.name) { case DefinedArgumentName.index: { From 813f4d9f255ceab64ad8a7d84c986c1bd5627bde Mon Sep 17 00:00:00 2001 From: Roman Sergeenko Date: Mon, 23 Sep 2024 13:19:39 +0200 Subject: [PATCH 079/256] #RI-6085 - fix sending query --- .../components/query-wrapper/QueryWrapper.spec.tsx | 13 +++++++++++++ .../components/query-wrapper/QueryWrapper.tsx | 4 +++- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/redisinsight/ui/src/pages/search/components/query-wrapper/QueryWrapper.spec.tsx b/redisinsight/ui/src/pages/search/components/query-wrapper/QueryWrapper.spec.tsx index 7c3eb91e4c..cb604dcca3 100644 --- a/redisinsight/ui/src/pages/search/components/query-wrapper/QueryWrapper.spec.tsx +++ b/redisinsight/ui/src/pages/search/components/query-wrapper/QueryWrapper.spec.tsx @@ -75,4 +75,17 @@ describe('Query', () => { } }) }) + + it('should call onSubmit with proper value', () => { + const sendEventTelemetryMock = jest.fn(); + (sendEventTelemetry as jest.Mock).mockImplementation(() => sendEventTelemetryMock) + + const onSubmit = jest.fn() + render() + + fireEvent.change(screen.getByTestId('monaco'), { target: { value: 'set\ra\rb\n\nc \nd' } }) + fireEvent.click(screen.getByTestId('btn-submit')) + + expect(onSubmit).toBeCalledWith('set a b c d', undefined, { mode: RunQueryMode.ASCII }) + }) }) diff --git a/redisinsight/ui/src/pages/search/components/query-wrapper/QueryWrapper.tsx b/redisinsight/ui/src/pages/search/components/query-wrapper/QueryWrapper.tsx index 1db85cde05..93d2c1e3ff 100644 --- a/redisinsight/ui/src/pages/search/components/query-wrapper/QueryWrapper.tsx +++ b/redisinsight/ui/src/pages/search/components/query-wrapper/QueryWrapper.tsx @@ -77,7 +77,9 @@ const QueryWrapper = (props: Props) => { } const handleSubmit = () => { - const val = value.split('\n').join(' ') + const val = value + .replace(/[\r\n?]{2}|\n\n/g, ' ') + .replace(/\n/g, ' ') if (!val) return onSubmit(val, undefined, { mode: activeRunQueryMode }) From 30bc43222716f703aba137e6b3732489cf599951 Mon Sep 17 00:00:00 2001 From: Gnanesh Date: Sun, 29 Sep 2024 20:34:50 +0530 Subject: [PATCH 080/256] Disconnect redis client for the database after certificate removal --- .../certificate/ca-certificate.controller.ts | 9 +++++++-- .../certificate/ca-certificate.service.spec.ts | 7 ++++--- .../certificate/ca-certificate.service.ts | 17 ++++++++++++++--- .../client-certificate.controller.ts | 9 +++++++-- .../client-certificate.service.spec.ts | 7 ++++--- .../certificate/client-certificate.service.ts | 15 ++++++++++++++- 6 files changed, 50 insertions(+), 14 deletions(-) diff --git a/redisinsight/api/src/modules/certificate/ca-certificate.controller.ts b/redisinsight/api/src/modules/certificate/ca-certificate.controller.ts index 692eba98c4..a356cc5280 100644 --- a/redisinsight/api/src/modules/certificate/ca-certificate.controller.ts +++ b/redisinsight/api/src/modules/certificate/ca-certificate.controller.ts @@ -14,6 +14,8 @@ import { } from '@nestjs/swagger'; import { CaCertificate } from 'src/modules/certificate/models/ca-certificate'; import { CaCertificateService } from 'src/modules/certificate/ca-certificate.service'; +import { RequestSessionMetadata } from 'src/common/decorators'; +import { SessionMetadata } from 'src/common/models'; @ApiTags('TLS Certificates') @Controller('certificates/ca') @@ -38,7 +40,10 @@ export class CaCertificateController { @Delete(':id') @ApiOperation({ description: 'Delete Ca Certificate by id' }) @ApiParam({ name: 'id', type: String }) - async delete(@Param('id') id: string): Promise { - await this.service.delete(id); + async delete( + @RequestSessionMetadata() sessionMetadata: SessionMetadata, + @Param('id') id: string, + ): Promise { + await this.service.delete(sessionMetadata, id); } } diff --git a/redisinsight/api/src/modules/certificate/ca-certificate.service.spec.ts b/redisinsight/api/src/modules/certificate/ca-certificate.service.spec.ts index 0a9a4dad57..fb77ed8bc2 100644 --- a/redisinsight/api/src/modules/certificate/ca-certificate.service.spec.ts +++ b/redisinsight/api/src/modules/certificate/ca-certificate.service.spec.ts @@ -5,6 +5,7 @@ import { mockCaCertificate, mockCaCertificateRepository, mockCreateCaCertificateDto, MockType, + mockSessionMetadata, } from 'src/__mocks__'; import { CaCertificateRepository } from 'src/modules/certificate/repositories/ca-certificate.repository'; import { pick } from 'lodash'; @@ -88,13 +89,13 @@ describe('CaCertificateService', () => { describe('delete', () => { it('should delete ca certificate', async () => { - expect(await service.delete(mockCaCertificate.id)).toEqual(undefined); + expect(await service.delete(mockSessionMetadata, mockCaCertificate.id)).toEqual(undefined); }); it('should throw encryption error', async () => { repository.delete.mockRejectedValueOnce(new KeytarEncryptionErrorException()); try { - await service.delete(mockCaCertificate.id); + await service.delete(mockSessionMetadata, mockCaCertificate.id); fail(); } catch (e) { expect(e).toBeInstanceOf(KeytarEncryptionErrorException); @@ -104,7 +105,7 @@ describe('CaCertificateService', () => { repository.delete.mockRejectedValueOnce(new Error()); try { - await service.delete(mockCaCertificate.id); + await service.delete(mockSessionMetadata, mockCaCertificate.id); fail(); } catch (e) { expect(e).toBeInstanceOf(InternalServerErrorException); diff --git a/redisinsight/api/src/modules/certificate/ca-certificate.service.ts b/redisinsight/api/src/modules/certificate/ca-certificate.service.ts index 8986efe33b..fa2d837a15 100644 --- a/redisinsight/api/src/modules/certificate/ca-certificate.service.ts +++ b/redisinsight/api/src/modules/certificate/ca-certificate.service.ts @@ -12,6 +12,9 @@ import { CaCertificateRepository } from 'src/modules/certificate/repositories/ca import { CaCertificate } from 'src/modules/certificate/models/ca-certificate'; import { CreateCaCertificateDto } from 'src/modules/certificate/dto/create.ca-certificate.dto'; import { classToClass } from 'src/utils'; +import { SessionMetadata } from 'src/common/models'; +import { DatabaseRepository } from 'src/modules/database/repositories/database.repository'; +import { RedisClientStorage } from 'src/modules/redis/redis.client.storage'; @Injectable() export class CaCertificateService { @@ -19,6 +22,8 @@ export class CaCertificateService { constructor( private readonly repository: CaCertificateRepository, + private readonly databaseRepository: DatabaseRepository, + private redisClientStorage: RedisClientStorage, ) {} async get(id: string): Promise { @@ -55,10 +60,16 @@ export class CaCertificateService { } } - async delete(id: string): Promise { - this.logger.log(`Deleting certificate. id: ${id}`); - + async delete(sessionMetadata: SessionMetadata, id: string): Promise { try { + const databases = await this.databaseRepository.list(sessionMetadata); + await Promise.all(databases.map(async (database) => { + const db = await this.databaseRepository.get(sessionMetadata, database.id); + if (db.caCert?.id === id) { + // If the certificate is used by the database, remove the client + await this.redisClientStorage.removeManyByMetadata({ databaseId: db.id }); + } + })); await this.repository.delete(id); } catch (error) { this.logger.error(`Failed to delete certificate ${id}`, error); diff --git a/redisinsight/api/src/modules/certificate/client-certificate.controller.ts b/redisinsight/api/src/modules/certificate/client-certificate.controller.ts index dfaaf5b365..70db6ebdfb 100644 --- a/redisinsight/api/src/modules/certificate/client-certificate.controller.ts +++ b/redisinsight/api/src/modules/certificate/client-certificate.controller.ts @@ -12,6 +12,8 @@ import { ApiParam, ApiTags, } from '@nestjs/swagger'; +import { RequestSessionMetadata } from 'src/common/decorators'; +import { SessionMetadata } from 'src/common/models'; import { ClientCertificateService } from 'src/modules/certificate/client-certificate.service'; import { ClientCertificate } from 'src/modules/certificate/models/client-certificate'; @@ -39,7 +41,10 @@ export class ClientCertificateController { @Delete(':id') @ApiOperation({ description: 'Delete Client Certificate pair by id' }) @ApiParam({ name: 'id', type: String }) - async deleteClientCertificatePair(@Param('id') id: string): Promise { - await this.service.delete(id); + async deleteClientCertificatePair( + @RequestSessionMetadata() sessionMetadata: SessionMetadata, + @Param('id') id: string, + ): Promise { + await this.service.delete(sessionMetadata, id); } } diff --git a/redisinsight/api/src/modules/certificate/client-certificate.service.spec.ts b/redisinsight/api/src/modules/certificate/client-certificate.service.spec.ts index b3e8b05160..6c57b4be28 100644 --- a/redisinsight/api/src/modules/certificate/client-certificate.service.spec.ts +++ b/redisinsight/api/src/modules/certificate/client-certificate.service.spec.ts @@ -6,6 +6,7 @@ import { mockClientCertificate, mockClientCertificateRepository, mockCreateClientCertificateDto, MockType, + mockSessionMetadata, } from 'src/__mocks__'; import { KeytarEncryptionErrorException } from 'src/modules/encryption/exceptions'; import { ClientCertificateService } from 'src/modules/certificate/client-certificate.service'; @@ -88,13 +89,13 @@ describe('ClientCertificateService', () => { describe('delete', () => { it('should delete client certificate', async () => { - expect(await service.delete(mockClientCertificate.id)).toEqual(undefined); + expect(await service.delete(mockSessionMetadata, mockClientCertificate.id)).toEqual(undefined); }); it('should throw encryption error', async () => { repository.delete.mockRejectedValueOnce(new KeytarEncryptionErrorException()); try { - await service.delete(mockClientCertificate.id); + await service.delete(mockSessionMetadata, mockClientCertificate.id); fail(); } catch (e) { expect(e).toBeInstanceOf(KeytarEncryptionErrorException); @@ -104,7 +105,7 @@ describe('ClientCertificateService', () => { repository.delete.mockRejectedValueOnce(new Error()); try { - await service.delete(mockClientCertificate.id); + await service.delete(mockSessionMetadata, mockClientCertificate.id); fail(); } catch (e) { expect(e).toBeInstanceOf(InternalServerErrorException); diff --git a/redisinsight/api/src/modules/certificate/client-certificate.service.ts b/redisinsight/api/src/modules/certificate/client-certificate.service.ts index c4ff16573c..614c36f09d 100644 --- a/redisinsight/api/src/modules/certificate/client-certificate.service.ts +++ b/redisinsight/api/src/modules/certificate/client-certificate.service.ts @@ -12,6 +12,9 @@ import { ClientCertificateRepository } from 'src/modules/certificate/repositorie import { ClientCertificate } from 'src/modules/certificate/models/client-certificate'; import { CreateClientCertificateDto } from 'src/modules/certificate/dto/create.client-certificate.dto'; import { classToClass } from 'src/utils'; +import { SessionMetadata } from 'src/common/models'; +import { DatabaseRepository } from 'src/modules/database/repositories/database.repository'; +import { RedisClientStorage } from 'src/modules/redis/redis.client.storage'; @Injectable() export class ClientCertificateService { @@ -19,6 +22,8 @@ export class ClientCertificateService { constructor( private readonly repository: ClientCertificateRepository, + private readonly databaseRepository: DatabaseRepository, + private redisClientStorage: RedisClientStorage, ) {} /** @@ -63,10 +68,18 @@ export class ClientCertificateService { } } - async delete(id: string): Promise { + async delete(sessionMetadata: SessionMetadata, id: string): Promise { this.logger.log(`Deleting client certificate. id: ${id}`); try { + const databases = await this.databaseRepository.list(sessionMetadata); + await Promise.all(databases.map(async (database) => { + const db = await this.databaseRepository.get(sessionMetadata, database.id); + if (db.clientCert?.id === id) { + // If the certificate is used by the database, remove the client + await this.redisClientStorage.removeManyByMetadata({ databaseId: db.id }); + } + })); await this.repository.delete(id); } catch (error) { this.logger.error(`Failed to delete certificate ${id}`, error); From 3abc70e8988865c11a1202791cb4188c1ac46e66 Mon Sep 17 00:00:00 2001 From: Gnanesh Date: Sun, 29 Sep 2024 20:47:15 +0530 Subject: [PATCH 081/256] Load mock database repository and redis client storage --- .../certificate/ca-certificate.service.spec.ts | 12 ++++++++++++ .../certificate/client-certificate.service.spec.ts | 12 ++++++++++++ 2 files changed, 24 insertions(+) diff --git a/redisinsight/api/src/modules/certificate/ca-certificate.service.spec.ts b/redisinsight/api/src/modules/certificate/ca-certificate.service.spec.ts index fb77ed8bc2..1722a91049 100644 --- a/redisinsight/api/src/modules/certificate/ca-certificate.service.spec.ts +++ b/redisinsight/api/src/modules/certificate/ca-certificate.service.spec.ts @@ -6,8 +6,12 @@ import { mockCaCertificateRepository, mockCreateCaCertificateDto, MockType, mockSessionMetadata, + mockDatabaseRepository, + mockRedisClientStorage, } from 'src/__mocks__'; import { CaCertificateRepository } from 'src/modules/certificate/repositories/ca-certificate.repository'; +import { DatabaseRepository } from 'src/modules/database/repositories/database.repository'; +import { RedisClientStorage } from 'src/modules/redis/redis.client.storage'; import { pick } from 'lodash'; import { KeytarEncryptionErrorException } from 'src/modules/encryption/exceptions'; import { CaCertificateService } from './ca-certificate.service'; @@ -25,6 +29,14 @@ describe('CaCertificateService', () => { provide: CaCertificateRepository, useFactory: mockCaCertificateRepository, }, + { + provide: DatabaseRepository, + useFactory: mockDatabaseRepository, + }, + { + provide: RedisClientStorage, + useFactory: mockRedisClientStorage, + }, ], }).compile(); diff --git a/redisinsight/api/src/modules/certificate/client-certificate.service.spec.ts b/redisinsight/api/src/modules/certificate/client-certificate.service.spec.ts index 6c57b4be28..d2c15d3f05 100644 --- a/redisinsight/api/src/modules/certificate/client-certificate.service.spec.ts +++ b/redisinsight/api/src/modules/certificate/client-certificate.service.spec.ts @@ -7,10 +7,14 @@ import { mockClientCertificateRepository, mockCreateClientCertificateDto, MockType, mockSessionMetadata, + mockDatabaseRepository, + mockRedisClientStorage, } from 'src/__mocks__'; import { KeytarEncryptionErrorException } from 'src/modules/encryption/exceptions'; import { ClientCertificateService } from 'src/modules/certificate/client-certificate.service'; import { ClientCertificateRepository } from 'src/modules/certificate/repositories/client-certificate.repository'; +import { DatabaseRepository } from 'src/modules/database/repositories/database.repository'; +import { RedisClientStorage } from 'src/modules/redis/redis.client.storage'; describe('ClientCertificateService', () => { let service: ClientCertificateService; @@ -25,6 +29,14 @@ describe('ClientCertificateService', () => { provide: ClientCertificateRepository, useFactory: mockClientCertificateRepository, }, + { + provide: DatabaseRepository, + useFactory: mockDatabaseRepository, + }, + { + provide: RedisClientStorage, + useFactory: mockRedisClientStorage, + }, ], }).compile(); From e0dd0964e07c31a52f02cd08b0eac64b49121df2 Mon Sep 17 00:00:00 2001 From: ArtemHoruzhenko Date: Mon, 30 Sep 2024 13:35:32 +0300 Subject: [PATCH 082/256] rework bugfix to be more performant and compatible with other app parts --- .../certificate/ca-certificate.controller.ts | 7 ++----- .../certificate/ca-certificate.service.ts | 18 ++++++------------ .../client-certificate.controller.ts | 7 ++----- .../certificate/client-certificate.service.ts | 18 ++++++------------ .../repositories/ca-certificate.repository.ts | 2 +- .../client-certificate.repository.ts | 2 +- .../local.ca-certificate.repository.ts | 14 +++++++++++++- .../local.client-certificate.repository.ts | 14 +++++++++++++- 8 files changed, 44 insertions(+), 38 deletions(-) diff --git a/redisinsight/api/src/modules/certificate/ca-certificate.controller.ts b/redisinsight/api/src/modules/certificate/ca-certificate.controller.ts index a356cc5280..bfe43bc7f4 100644 --- a/redisinsight/api/src/modules/certificate/ca-certificate.controller.ts +++ b/redisinsight/api/src/modules/certificate/ca-certificate.controller.ts @@ -14,8 +14,6 @@ import { } from '@nestjs/swagger'; import { CaCertificate } from 'src/modules/certificate/models/ca-certificate'; import { CaCertificateService } from 'src/modules/certificate/ca-certificate.service'; -import { RequestSessionMetadata } from 'src/common/decorators'; -import { SessionMetadata } from 'src/common/models'; @ApiTags('TLS Certificates') @Controller('certificates/ca') @@ -41,9 +39,8 @@ export class CaCertificateController { @ApiOperation({ description: 'Delete Ca Certificate by id' }) @ApiParam({ name: 'id', type: String }) async delete( - @RequestSessionMetadata() sessionMetadata: SessionMetadata, - @Param('id') id: string, + @Param('id') id: string, ): Promise { - await this.service.delete(sessionMetadata, id); + await this.service.delete(id); } } diff --git a/redisinsight/api/src/modules/certificate/ca-certificate.service.ts b/redisinsight/api/src/modules/certificate/ca-certificate.service.ts index fa2d837a15..6bbe8c211e 100644 --- a/redisinsight/api/src/modules/certificate/ca-certificate.service.ts +++ b/redisinsight/api/src/modules/certificate/ca-certificate.service.ts @@ -12,8 +12,6 @@ import { CaCertificateRepository } from 'src/modules/certificate/repositories/ca import { CaCertificate } from 'src/modules/certificate/models/ca-certificate'; import { CreateCaCertificateDto } from 'src/modules/certificate/dto/create.ca-certificate.dto'; import { classToClass } from 'src/utils'; -import { SessionMetadata } from 'src/common/models'; -import { DatabaseRepository } from 'src/modules/database/repositories/database.repository'; import { RedisClientStorage } from 'src/modules/redis/redis.client.storage'; @Injectable() @@ -22,7 +20,6 @@ export class CaCertificateService { constructor( private readonly repository: CaCertificateRepository, - private readonly databaseRepository: DatabaseRepository, private redisClientStorage: RedisClientStorage, ) {} @@ -60,17 +57,14 @@ export class CaCertificateService { } } - async delete(sessionMetadata: SessionMetadata, id: string): Promise { + async delete(id: string): Promise { try { - const databases = await this.databaseRepository.list(sessionMetadata); - await Promise.all(databases.map(async (database) => { - const db = await this.databaseRepository.get(sessionMetadata, database.id); - if (db.caCert?.id === id) { - // If the certificate is used by the database, remove the client - await this.redisClientStorage.removeManyByMetadata({ databaseId: db.id }); - } + const { affectedDatabases } = await this.repository.delete(id); + + await Promise.all(affectedDatabases.map(async (databaseId) => { + // If the certificate is used by the database, remove the client + await this.redisClientStorage.removeManyByMetadata({ databaseId }); })); - await this.repository.delete(id); } catch (error) { this.logger.error(`Failed to delete certificate ${id}`, error); diff --git a/redisinsight/api/src/modules/certificate/client-certificate.controller.ts b/redisinsight/api/src/modules/certificate/client-certificate.controller.ts index 70db6ebdfb..2c45bb7db0 100644 --- a/redisinsight/api/src/modules/certificate/client-certificate.controller.ts +++ b/redisinsight/api/src/modules/certificate/client-certificate.controller.ts @@ -12,8 +12,6 @@ import { ApiParam, ApiTags, } from '@nestjs/swagger'; -import { RequestSessionMetadata } from 'src/common/decorators'; -import { SessionMetadata } from 'src/common/models'; import { ClientCertificateService } from 'src/modules/certificate/client-certificate.service'; import { ClientCertificate } from 'src/modules/certificate/models/client-certificate'; @@ -42,9 +40,8 @@ export class ClientCertificateController { @ApiOperation({ description: 'Delete Client Certificate pair by id' }) @ApiParam({ name: 'id', type: String }) async deleteClientCertificatePair( - @RequestSessionMetadata() sessionMetadata: SessionMetadata, - @Param('id') id: string, + @Param('id') id: string, ): Promise { - await this.service.delete(sessionMetadata, id); + await this.service.delete(id); } } diff --git a/redisinsight/api/src/modules/certificate/client-certificate.service.ts b/redisinsight/api/src/modules/certificate/client-certificate.service.ts index 614c36f09d..1de5cd7dca 100644 --- a/redisinsight/api/src/modules/certificate/client-certificate.service.ts +++ b/redisinsight/api/src/modules/certificate/client-certificate.service.ts @@ -12,8 +12,6 @@ import { ClientCertificateRepository } from 'src/modules/certificate/repositorie import { ClientCertificate } from 'src/modules/certificate/models/client-certificate'; import { CreateClientCertificateDto } from 'src/modules/certificate/dto/create.client-certificate.dto'; import { classToClass } from 'src/utils'; -import { SessionMetadata } from 'src/common/models'; -import { DatabaseRepository } from 'src/modules/database/repositories/database.repository'; import { RedisClientStorage } from 'src/modules/redis/redis.client.storage'; @Injectable() @@ -22,7 +20,6 @@ export class ClientCertificateService { constructor( private readonly repository: ClientCertificateRepository, - private readonly databaseRepository: DatabaseRepository, private redisClientStorage: RedisClientStorage, ) {} @@ -68,19 +65,16 @@ export class ClientCertificateService { } } - async delete(sessionMetadata: SessionMetadata, id: string): Promise { + async delete(id: string): Promise { this.logger.log(`Deleting client certificate. id: ${id}`); try { - const databases = await this.databaseRepository.list(sessionMetadata); - await Promise.all(databases.map(async (database) => { - const db = await this.databaseRepository.get(sessionMetadata, database.id); - if (db.clientCert?.id === id) { - // If the certificate is used by the database, remove the client - await this.redisClientStorage.removeManyByMetadata({ databaseId: db.id }); - } + const { affectedDatabases } = await this.repository.delete(id); + + await Promise.all(affectedDatabases.map(async (databaseId) => { + // If the certificate is used by the database, remove the client + await this.redisClientStorage.removeManyByMetadata({ databaseId }); })); - await this.repository.delete(id); } catch (error) { this.logger.error(`Failed to delete certificate ${id}`, error); diff --git a/redisinsight/api/src/modules/certificate/repositories/ca-certificate.repository.ts b/redisinsight/api/src/modules/certificate/repositories/ca-certificate.repository.ts index bb1109dfcc..6ad4409dc8 100644 --- a/redisinsight/api/src/modules/certificate/repositories/ca-certificate.repository.ts +++ b/redisinsight/api/src/modules/certificate/repositories/ca-certificate.repository.ts @@ -26,5 +26,5 @@ export abstract class CaCertificateRepository { * @param id * @throws NotFoundException in case when try to delete not existing cert (?) */ - abstract delete(id: string): Promise; + abstract delete(id: string): Promise<{ affectedDatabases: string[] }>; } diff --git a/redisinsight/api/src/modules/certificate/repositories/client-certificate.repository.ts b/redisinsight/api/src/modules/certificate/repositories/client-certificate.repository.ts index 9072dfcd6d..3e37273af7 100644 --- a/redisinsight/api/src/modules/certificate/repositories/client-certificate.repository.ts +++ b/redisinsight/api/src/modules/certificate/repositories/client-certificate.repository.ts @@ -24,5 +24,5 @@ export abstract class ClientCertificateRepository { * @param id * @throws NotFoundException in case when try to delete not existing cert (?) */ - abstract delete(id: string): Promise; + abstract delete(id: string): Promise<{ affectedDatabases: string[] }>; } diff --git a/redisinsight/api/src/modules/certificate/repositories/local.ca-certificate.repository.ts b/redisinsight/api/src/modules/certificate/repositories/local.ca-certificate.repository.ts index c2330c7292..0aa083c1ee 100644 --- a/redisinsight/api/src/modules/certificate/repositories/local.ca-certificate.repository.ts +++ b/redisinsight/api/src/modules/certificate/repositories/local.ca-certificate.repository.ts @@ -13,6 +13,7 @@ import ERROR_MESSAGES from 'src/constants/error-messages'; import { classToClass } from 'src/utils'; import { EncryptionService } from 'src/modules/encryption/encryption.service'; import { ModelEncryptor } from 'src/modules/encryption/model.encryptor'; +import { DatabaseEntity } from 'src/modules/database/entities/database.entity'; @Injectable() export class LocalCaCertificateRepository extends CaCertificateRepository { @@ -23,6 +24,8 @@ export class LocalCaCertificateRepository extends CaCertificateRepository { constructor( @InjectRepository(CaCertificateEntity) private readonly repository: Repository, + @InjectRepository(DatabaseEntity) + private readonly databaseRepository: Repository, private readonly encryptionService: EncryptionService, ) { super(); @@ -71,7 +74,7 @@ export class LocalCaCertificateRepository extends CaCertificateRepository { /** * @inheritDoc */ - async delete(id: string): Promise { + async delete(id: string): Promise<{ affectedDatabases: string[] }> { this.logger.log(`Deleting certificate. id: ${id}`); // todo: 1. why we need to check if entity exists? @@ -84,7 +87,16 @@ export class LocalCaCertificateRepository extends CaCertificateRepository { throw new NotFoundException(); } + const affectedDatabases = (await this.databaseRepository + .createQueryBuilder('d') + .leftJoinAndSelect('d.caCert', 'c') + .where({ caCert: id }) + .select(['d.id']) + .getMany()).map((e) => e.id); + await this.repository.delete(id); this.logger.log(`Succeed to delete ca certificate: ${id}`); + + return { affectedDatabases }; } } diff --git a/redisinsight/api/src/modules/certificate/repositories/local.client-certificate.repository.ts b/redisinsight/api/src/modules/certificate/repositories/local.client-certificate.repository.ts index 21bd9e86ca..f48d560a54 100644 --- a/redisinsight/api/src/modules/certificate/repositories/local.client-certificate.repository.ts +++ b/redisinsight/api/src/modules/certificate/repositories/local.client-certificate.repository.ts @@ -13,6 +13,7 @@ import { ModelEncryptor } from 'src/modules/encryption/model.encryptor'; import { ClientCertificateRepository } from 'src/modules/certificate/repositories/client-certificate.repository'; import { ClientCertificateEntity } from 'src/modules/certificate/entities/client-certificate.entity'; import { ClientCertificate } from 'src/modules/certificate/models/client-certificate'; +import { DatabaseEntity } from 'src/modules/database/entities/database.entity'; @Injectable() export class LocalClientCertificateRepository extends ClientCertificateRepository { @@ -23,6 +24,8 @@ export class LocalClientCertificateRepository extends ClientCertificateRepositor constructor( @InjectRepository(ClientCertificateEntity) private readonly repository: Repository, + @InjectRepository(DatabaseEntity) + private readonly databaseRepository: Repository, private readonly encryptionService: EncryptionService, ) { super(); @@ -71,7 +74,7 @@ export class LocalClientCertificateRepository extends ClientCertificateRepositor /** * @inheritDoc */ - async delete(id: string): Promise { + async delete(id: string): Promise<{ affectedDatabases: string[] }> { this.logger.log(`Deleting certificate. id: ${id}`); // todo: 1. why we need to check if entity exists? @@ -83,7 +86,16 @@ export class LocalClientCertificateRepository extends ClientCertificateRepositor throw new NotFoundException(); } + const affectedDatabases = (await this.databaseRepository + .createQueryBuilder('d') + .leftJoinAndSelect('d.clientCert', 'c') + .where({ clientCert: id }) + .select(['d.id']) + .getMany()).map((e) => e.id); + await this.repository.delete(id); this.logger.log(`Succeed to delete client certificate: ${id}`); + + return { affectedDatabases }; } } From bb373c6f86c92650cd1d3d1cfc873d6f9c670b1d Mon Sep 17 00:00:00 2001 From: Roman Sergeenko Date: Tue, 1 Oct 2024 11:56:50 +0200 Subject: [PATCH 083/256] #RI-6089 - add support ft commands --- .../ui/src/pages/search/SearchPage.tsx | 4 +- .../components/query-wrapper/QueryWrapper.tsx | 15 +- .../pages/search/components/query/Query.tsx | 38 +- .../search/components/query/constants.ts | 39 +- .../ui/src/pages/search/mocks/mocks.ts | 806 +++++++++++++++++- .../ui/src/pages/search/utils/query.ts | 72 +- .../pages/search/utils/tests/query.spec.ts | 619 +------------- .../search/utils/tests/test-cases/common.ts | 177 ++++ .../utils/tests/test-cases/ft-aggregate.ts | 291 +++++++ .../utils/tests/test-cases/ft-search.ts | 283 ++++++ .../search/utils/tests/test-cases/index.ts | 3 + .../monaco/monarchTokens/redisearchTokens.ts | 5 +- .../ui/src/utils/monaco/redisearch/utils.ts | 7 + 13 files changed, 1708 insertions(+), 651 deletions(-) create mode 100644 redisinsight/ui/src/pages/search/utils/tests/test-cases/common.ts create mode 100644 redisinsight/ui/src/pages/search/utils/tests/test-cases/ft-aggregate.ts create mode 100644 redisinsight/ui/src/pages/search/utils/tests/test-cases/ft-search.ts create mode 100644 redisinsight/ui/src/pages/search/utils/tests/test-cases/index.ts diff --git a/redisinsight/ui/src/pages/search/SearchPage.tsx b/redisinsight/ui/src/pages/search/SearchPage.tsx index e69dd222fd..2ff8291b8a 100644 --- a/redisinsight/ui/src/pages/search/SearchPage.tsx +++ b/redisinsight/ui/src/pages/search/SearchPage.tsx @@ -25,7 +25,7 @@ const verticalPanelIds = { const SearchPage = () => { const { name: connectedInstanceName, db } = useSelector(connectedInstanceSelector) - const { commandsArray } = useSelector(appRedisCommandsSelector) + const { commandsArray, spec } = useSelector(appRedisCommandsSelector) const { panelSizes: { vertical } } = useSelector(appContextSearchAndQuery) const [isPageViewSent, setIsPageViewSent] = useState(false) @@ -96,7 +96,7 @@ const SearchPage = () => { initialSize={vertical[verticalPanelIds.firstPanelId] ?? 20} style={{ minHeight: '240px', zIndex: '8' }} > - + , @@ -32,7 +33,7 @@ export interface Props { } const QueryWrapper = (props: Props) => { - const { commandsArray = [], onSubmit } = props + const { commandsArray = [], spec = {}, onSubmit } = props const { id: connectedIndstanceId } = useSelector(connectedInstanceSelector) const { script: scriptContext } = useSelector(appContextSearchAndQuery) @@ -44,10 +45,12 @@ const QueryWrapper = (props: Props) => { const input = useRef(null) const scriptRef = useRef('') - const SUPPORTED_COMMANDS = SUPPORTED_COMMANDS_LIST.map((name) => ({ - ...REDIS_COMMANDS_SPEC[name], - name - })) as unknown as SearchCommand[] + const getCommandByName = (name: string) => + (name in REDIS_COMMANDS_SPEC ? REDIS_COMMANDS_SPEC[name] : (spec[name] || {})) + + const SUPPORTED_COMMANDS = commandsArray + .filter((item) => item.startsWith('FT.')) + .map((name) => ({ ...getCommandByName(name), name })) as unknown as SearchCommand[] const { instanceId } = useParams<{ instanceId: string }>() diff --git a/redisinsight/ui/src/pages/search/components/query/Query.tsx b/redisinsight/ui/src/pages/search/components/query/Query.tsx index 5dff9067c1..0e73ae51bc 100644 --- a/redisinsight/ui/src/pages/search/components/query/Query.tsx +++ b/redisinsight/ui/src/pages/search/components/query/Query.tsx @@ -2,7 +2,8 @@ import React, { useContext, useEffect, useRef, useState } from 'react' import MonacoEditor, { monaco as monacoEditor } from 'react-monaco-editor' import { useDispatch } from 'react-redux' -import { ICommands, MonacoLanguage, Theme } from 'uiSrc/constants' +import { isNumber } from 'lodash' +import { MonacoLanguage, Theme } from 'uiSrc/constants' import { ThemeContext } from 'uiSrc/contexts/themeContext' import { Nullable } from 'uiSrc/utils' import { IEditorMount } from 'uiSrc/pages/workbench/interfaces' @@ -19,7 +20,7 @@ import { RedisResponseBuffer } from 'uiSrc/slices/interfaces' import { fetchRedisearchInfoAction } from 'uiSrc/slices/browser/redisearch' import { getRediSearchMonarchTokensProvider } from 'uiSrc/utils/monaco/monarchTokens/redisearchTokens' import { useDebouncedEffect } from 'uiSrc/services' -import { options, DefinedArgumentName, FIELD_START_SYMBOL } from './constants' +import { options, DefinedArgumentName, FIELD_START_SYMBOL, COMMANDS_TO_GET_INDEX_INFO } from './constants' import { getFieldsSuggestions, getIndexesSuggestions, @@ -35,11 +36,10 @@ export interface Props { onChange: (val: string) => void indexes: RedisResponseBuffer[] supportedCommands?: SearchCommand[] - commandsSpec?: ICommands } const Query = (props: Props) => { - const { value, onChange, indexes, supportedCommands = [], commandsSpec } = props + const { value, onChange, indexes, supportedCommands = [] } = props const [selectedCommand, setSelectedCommand] = useState('') const [selectedIndex, setSelectedIndex] = useState('') @@ -209,22 +209,21 @@ const Query = (props: Props) => { const [beforeOffsetArgs, [currentOffsetArg]] = args const [firstArg] = beforeOffsetArgs - const commandName = (firstArg || currentOffsetArg)?.toUpperCase() - const command = commandsSpec?.[commandName] as unknown as SearchCommand - const isCommandSupported = supportedCommands.some(({ name }) => commandName === name) + if ((position.lineNumber === 1 && position.column === 1) || beforeOffsetArgs.length === 0) { + return asSuggestionsRef(getCommandsSuggestions(COMMANDS_LIST, range), false) + } - if (command && !isCommandSupported) return asSuggestionsRef([]) + const commandName = (firstArg || currentOffsetArg)?.toUpperCase() + const command = COMMANDS_LIST.find(({ name }) => commandName === name) if (!command) { - if ((position.lineNumber === 1 && position.column === 1) || beforeOffsetArgs.length === 0) { - return asSuggestionsRef(getCommandsSuggestions(supportedCommands, range), false) - } - helpWidgetRef.current.isOpen = false - return asSuggestionsRef([], false) + return asSuggestionsRef([]) + } + + if (COMMANDS_TO_GET_INDEX_INFO.some((name) => name === commandName)) { + setSelectedIndex(allArgs[1] || '') } - // TODO: change to more generic logic - setSelectedIndex(allArgs[1] || '') setSelectedCommand(commandName) const cursorContext: CursorContext = { ...cursor, currentOffsetArg, offset } @@ -234,7 +233,7 @@ const Query = (props: Props) => { switch (foundArg?.stopArg?.name) { case DefinedArgumentName.index: { - return handleIndexSuggestions(command, foundArg, beforeOffsetArgs.length, currentOffsetArg, range) + return handleIndexSuggestions(command, foundArg, currentOffsetArg, range) } case DefinedArgumentName.query: { return handleQuerySuggestions(command, foundArg) @@ -254,7 +253,6 @@ const Query = (props: Props) => { const handleIndexSuggestions = ( command: SearchCommand, foundArg: FoundCommandArgument, - lastArgIndex: number, currentOffsetArg: Nullable, range: monacoEditor.IRange ) => { @@ -263,7 +261,11 @@ const Query = (props: Props) => { const isIndex = indexesRef.current.length > 0 if (!isIndex || currentOffsetArg) return asSuggestionsRef([], !currentOffsetArg) - const isNextArgQuery = command?.arguments?.[lastArgIndex]?.name === DefinedArgumentName.query + const argumentIndex = command?.arguments + ?.findIndex(({ name }) => foundArg?.stopArg?.name === name) + const isNextArgQuery = isNumber(argumentIndex) + && command?.arguments?.[argumentIndex + 1]?.name === DefinedArgumentName.query + return asSuggestionsRef(getIndexesSuggestions(indexesRef.current, range, isNextArgQuery)) } diff --git a/redisinsight/ui/src/pages/search/components/query/constants.ts b/redisinsight/ui/src/pages/search/components/query/constants.ts index 589f6f1484..53d83e8e3f 100644 --- a/redisinsight/ui/src/pages/search/components/query/constants.ts +++ b/redisinsight/ui/src/pages/search/components/query/constants.ts @@ -12,7 +12,44 @@ export const options = merge(defaultMonacoOptions, } }) -export const SUPPORTED_COMMANDS_LIST = ['FT.SEARCH', 'FT.AGGREGATE', 'FT.PROFILE', 'FT.EXPLAIN'] +export const SUPPORTED_COMMANDS_LIST = [ + 'FT.SEARCH', + 'FT.AGGREGATE', + 'FT.PROFILE', + 'FT.EXPLAIN', + 'FT.INFO', + 'FT._LIST', + 'FT.ALIASADD', + 'FT.ALIASDEL', + 'FT.ALIASUPDATE', + 'FT.ALTER', + 'FT.CONFIG GET', + 'FT.CONFIG SET', + 'FT.CURSOR DEL', + 'FT.CURSOR READ', + 'FT.DICTADD', + 'FT.DICTDEL', +] + +export const COMMANDS_TO_GET_INDEX_INFO = [ + 'FT.SEARCH', + 'FT.AGGREGATE', + 'FT.EXPLAIN', + 'FT.EXPLAINCLI', + 'FT.PROFILE', + 'FT.SPELLCHECK', + 'FT.TAGVALS', + 'FT.ALTER', + 'FT.CREATE' +] + +export const COMPOSITE_ARGS = [ + 'LOAD *', + 'FT.CONFIG GET', + 'FT.CONFIG SET', + 'FT.CURSOR DEL', + 'FT.CURSOR READ', +] export enum DefinedArgumentName { index = 'index', diff --git a/redisinsight/ui/src/pages/search/mocks/mocks.ts b/redisinsight/ui/src/pages/search/mocks/mocks.ts index 01a67f5c19..9ebacd0a47 100644 --- a/redisinsight/ui/src/pages/search/mocks/mocks.ts +++ b/redisinsight/ui/src/pages/search/mocks/mocks.ts @@ -423,7 +423,6 @@ export const MOCKED_SUPPORTED_COMMANDS = { since: '1.0.0', group: 'search' }, - 'FT.AGGREGATE': { summary: 'Run a search query on an index and perform aggregate transformations on the results', complexity: 'O(1)', @@ -673,7 +672,6 @@ export const MOCKED_SUPPORTED_COMMANDS = { since: '1.1.0', group: 'search' }, - 'FT.PROFILE': { summary: 'Performs a `FT.SEARCH` or `FT.AGGREGATE` command and collects performance information', complexity: 'O(N)', @@ -717,5 +715,807 @@ export const MOCKED_SUPPORTED_COMMANDS = { since: '2.2.0', group: 'search', provider: 'redisearch' - } + }, + 'FT.ALIASADD': { + summary: 'Adds an alias to the index', + complexity: 'O(1)', + arguments: [ + { + name: 'alias', + type: 'string' + }, + { + name: 'index', + type: 'string' + } + ], + since: '1.0.0', + group: 'search', + provider: 'redisearch' + }, + 'FT.ALIASDEL': { + summary: 'Deletes an alias from the index', + complexity: 'O(1)', + arguments: [ + { + name: 'alias', + type: 'string' + } + ], + since: '1.0.0', + group: 'search', + provider: 'redisearch' + }, + 'FT.ALIASUPDATE': { + summary: 'Adds or updates an alias to the index', + complexity: 'O(1)', + arguments: [ + { + name: 'alias', + type: 'string' + }, + { + name: 'index', + type: 'string' + } + ], + since: '1.0.0', + group: 'search', + provider: 'redisearch' + }, + 'FT.ALTER': { + summary: 'Adds a new field to the index', + complexity: 'O(N) where N is the number of keys in the keyspace', + arguments: [ + { + name: 'index', + type: 'string' + }, + { + name: 'skipinitialscan', + type: 'pure-token', + token: 'SKIPINITIALSCAN', + optional: true + }, + { + name: 'schema', + type: 'pure-token', + token: 'SCHEMA' + }, + { + name: 'add', + type: 'pure-token', + token: 'ADD' + }, + { + name: 'field', + type: 'string' + }, + { + name: 'options', + type: 'string' + } + ], + since: '1.0.0', + group: 'search', + provider: 'redisearch' + }, + 'FT.CONFIG GET': { + summary: 'Retrieves runtime configuration options', + complexity: 'O(1)', + arguments: [ + { + name: 'option', + type: 'string' + } + ], + since: '1.0.0', + group: 'search', + provider: 'redisearch' + }, + 'FT.CONFIG HELP': { + summary: 'Help description of runtime configuration options', + complexity: 'O(1)', + arguments: [ + { + name: 'option', + type: 'string' + } + ], + since: '1.0.0', + group: 'search', + provider: 'redisearch' + }, + 'FT.CONFIG SET': { + summary: 'Sets runtime configuration options', + complexity: 'O(1)', + arguments: [ + { + name: 'option', + type: 'string' + }, + { + name: 'value', + type: 'string' + } + ], + since: '1.0.0', + group: 'search', + provider: 'redisearch' + }, + 'FT.CREATE': { + summary: 'Creates an index with the given spec', + complexity: 'O(K) at creation where K is the number of fields, O(N) if scanning the keyspace is triggered, where N is the number of keys in the keyspace', + history: [ + [ + '2.0.0', + 'Added `PAYLOAD_FIELD` argument for backward support of `FT.SEARCH` deprecated `WITHPAYLOADS` argument' + ], + [ + '2.0.0', + 'Deprecated `PAYLOAD_FIELD` argument' + ] + ], + arguments: [ + { + name: 'index', + type: 'string' + }, + { + name: 'data_type', + token: 'ON', + type: 'oneof', + arguments: [ + { + name: 'hash', + type: 'pure-token', + token: 'HASH' + }, + { + name: 'json', + type: 'pure-token', + token: 'JSON' + } + ], + optional: true + }, + { + name: 'prefix', + type: 'block', + optional: true, + arguments: [ + { + name: 'count', + type: 'integer', + token: 'PREFIX' + }, + { + name: 'prefix', + type: 'string', + multiple: true + } + ] + }, + { + name: 'filter', + type: 'string', + optional: true, + token: 'FILTER' + }, + { + name: 'default_lang', + type: 'string', + token: 'LANGUAGE', + optional: true + }, + { + name: 'lang_attribute', + type: 'string', + token: 'LANGUAGE_FIELD', + optional: true + }, + { + name: 'default_score', + type: 'double', + token: 'SCORE', + optional: true + }, + { + name: 'score_attribute', + type: 'string', + token: 'SCORE_FIELD', + optional: true + }, + { + name: 'payload_attribute', + type: 'string', + token: 'PAYLOAD_FIELD', + optional: true + }, + { + name: 'maxtextfields', + type: 'pure-token', + token: 'MAXTEXTFIELDS', + optional: true + }, + { + name: 'seconds', + type: 'double', + token: 'TEMPORARY', + optional: true + }, + { + name: 'nooffsets', + type: 'pure-token', + token: 'NOOFFSETS', + optional: true + }, + { + name: 'nohl', + type: 'pure-token', + token: 'NOHL', + optional: true + }, + { + name: 'nofields', + type: 'pure-token', + token: 'NOFIELDS', + optional: true + }, + { + name: 'nofreqs', + type: 'pure-token', + token: 'NOFREQS', + optional: true + }, + { + name: 'stopwords', + type: 'block', + optional: true, + token: 'STOPWORDS', + arguments: [ + { + name: 'count', + type: 'integer' + }, + { + name: 'stopword', + type: 'string', + multiple: true, + optional: true + } + ] + }, + { + name: 'skipinitialscan', + type: 'pure-token', + token: 'SKIPINITIALSCAN', + optional: true + }, + { + name: 'schema', + type: 'pure-token', + token: 'SCHEMA' + }, + { + name: 'field', + type: 'block', + multiple: true, + arguments: [ + { + name: 'field_name', + type: 'string' + }, + { + name: 'alias', + type: 'string', + token: 'AS', + optional: true + }, + { + name: 'field_type', + type: 'oneof', + arguments: [ + { + name: 'text', + type: 'pure-token', + token: 'TEXT' + }, + { + name: 'tag', + type: 'pure-token', + token: 'TAG' + }, + { + name: 'numeric', + type: 'pure-token', + token: 'NUMERIC' + }, + { + name: 'geo', + type: 'pure-token', + token: 'GEO' + }, + { + name: 'vector', + type: 'pure-token', + token: 'VECTOR' + } + ] + }, + { + name: 'withsuffixtrie', + type: 'pure-token', + token: 'WITHSUFFIXTRIE', + optional: true + }, + { + name: 'INDEXEMPTY', + type: 'pure-token', + token: 'INDEXEMPTY', + optional: true + }, + { + name: 'indexmissing', + type: 'pure-token', + token: 'INDEXMISSING', + optional: true + }, + { + name: 'sortable', + type: 'block', + optional: true, + arguments: [ + { + name: 'sortable', + type: 'pure-token', + token: 'SORTABLE' + }, + { + name: 'UNF', + type: 'pure-token', + token: 'UNF', + optional: true + } + ] + }, + { + name: 'noindex', + type: 'pure-token', + token: 'NOINDEX', + optional: true + } + ] + } + ], + since: '1.0.0', + group: 'search', + provider: 'redisearch' + }, + 'FT.CURSOR DEL': { + summary: 'Deletes a cursor', + complexity: 'O(1)', + arguments: [ + { + name: 'index', + type: 'string' + }, + { + name: 'cursor_id', + type: 'integer' + } + ], + since: '1.1.0', + group: 'search', + provider: 'redisearch' + }, + 'FT.CURSOR READ': { + summary: 'Reads from a cursor', + complexity: 'O(1)', + arguments: [ + { + name: 'index', + type: 'string' + }, + { + name: 'cursor_id', + type: 'integer' + }, + { + name: 'read size', + type: 'integer', + optional: true, + token: 'COUNT' + } + ], + since: '1.1.0', + group: 'search', + provider: 'redisearch' + }, + 'FT.DICTADD': { + summary: 'Adds terms to a dictionary', + complexity: 'O(1)', + arguments: [ + { + name: 'dict', + type: 'string' + }, + { + name: 'term', + type: 'string', + multiple: true + } + ], + since: '1.4.0', + group: 'search', + provider: 'redisearch' + }, + 'FT.DICTDEL': { + summary: 'Deletes terms from a dictionary', + complexity: 'O(1)', + arguments: [ + { + name: 'dict', + type: 'string' + }, + { + name: 'term', + type: 'string', + multiple: true + } + ], + since: '1.4.0', + group: 'search', + provider: 'redisearch' + }, + 'FT.DICTDUMP': { + summary: 'Dumps all terms in the given dictionary', + complexity: 'O(N), where N is the size of the dictionary', + arguments: [ + { + name: 'dict', + type: 'string' + } + ], + since: '1.4.0', + group: 'search', + provider: 'redisearch' + }, + 'FT.DROPINDEX': { + summary: 'Deletes the index', + complexity: 'O(1) or O(N) if documents are deleted, where N is the number of keys in the keyspace', + arguments: [ + { + name: 'index', + type: 'string' + }, + { + name: 'delete docs', + type: 'oneof', + arguments: [ + { + name: 'delete docs', + type: 'pure-token', + token: 'DD' + } + ], + optional: true + } + ], + since: '2.0.0', + group: 'search', + provider: 'redisearch' + }, + 'FT.EXPLAIN': { + summary: 'Returns the execution plan for a complex query', + complexity: 'O(1)', + arguments: [ + { + name: 'index', + type: 'string' + }, + { + name: 'query', + type: 'string' + }, + { + name: 'dialect', + type: 'integer', + optional: true, + token: 'DIALECT', + since: '2.4.3' + } + ], + since: '1.0.0', + group: 'search', + provider: 'redisearch' + }, + 'FT.EXPLAINCLI': { + summary: 'Returns the execution plan for a complex query', + complexity: 'O(1)', + arguments: [ + { + name: 'index', + type: 'string' + }, + { + name: 'query', + type: 'string' + }, + { + name: 'dialect', + type: 'integer', + optional: true, + token: 'DIALECT', + since: '2.4.3' + } + ], + since: '1.0.0', + group: 'search', + provider: 'redisearch' + }, + 'FT.INFO': { + summary: 'Returns information and statistics on the index', + complexity: 'O(1)', + arguments: [ + { + name: 'index', + type: 'string' + } + ], + since: '1.0.0', + group: 'search', + provider: 'redisearch' + }, + 'FT.SPELLCHECK': { + summary: 'Performs spelling correction on a query, returning suggestions for misspelled terms', + complexity: 'O(1)', + arguments: [ + { + name: 'index', + type: 'string' + }, + { + name: 'query', + type: 'string' + }, + { + name: 'distance', + token: 'DISTANCE', + type: 'integer', + optional: true + }, + { + name: 'terms', + token: 'TERMS', + type: 'block', + optional: true, + arguments: [ + { + name: 'inclusion', + type: 'oneof', + arguments: [ + { + name: 'include', + type: 'pure-token', + token: 'INCLUDE' + }, + { + name: 'exclude', + type: 'pure-token', + token: 'EXCLUDE' + } + ] + }, + { + name: 'dictionary', + type: 'string' + }, + { + name: 'terms', + type: 'string', + multiple: true, + optional: true + } + ] + }, + { + name: 'dialect', + type: 'integer', + optional: true, + token: 'DIALECT', + since: '2.4.3' + } + ], + since: '1.4.0', + group: 'search', + provider: 'redisearch' + }, + 'FT.SUGADD': { + summary: 'Adds a suggestion string to an auto-complete suggestion dictionary', + complexity: 'O(1)', + history: [ + [ + '2.0.0', + 'Deprecated `PAYLOAD` argument' + ] + ], + arguments: [ + { + name: 'key', + type: 'string' + }, + { + name: 'string', + type: 'string' + }, + { + name: 'score', + type: 'double' + }, + { + name: 'increment score', + type: 'oneof', + arguments: [ + { + name: 'incr', + type: 'pure-token', + token: 'INCR' + } + ], + optional: true + }, + { + name: 'payload', + token: 'PAYLOAD', + type: 'string', + optional: true + } + ], + since: '1.0.0', + group: 'suggestion', + provider: 'redisearch' + }, + 'FT.SUGDEL': { + summary: 'Deletes a string from a suggestion index', + complexity: 'O(1)', + arguments: [ + { + name: 'key', + type: 'string' + }, + { + name: 'string', + type: 'string' + } + ], + since: '1.0.0', + group: 'suggestion', + provider: 'redisearch' + }, + 'FT.SUGGET': { + summary: 'Gets completion suggestions for a prefix', + complexity: 'O(1)', + history: [ + [ + '2.0.0', + 'Deprecated `WITHPAYLOADS` argument' + ] + ], + arguments: [ + { + name: 'key', + type: 'string' + }, + { + name: 'prefix', + type: 'string' + }, + { + name: 'fuzzy', + type: 'pure-token', + token: 'FUZZY', + optional: true + }, + { + name: 'withscores', + type: 'pure-token', + token: 'WITHSCORES', + optional: true + }, + { + name: 'withpayloads', + type: 'pure-token', + token: 'WITHPAYLOADS', + optional: true + }, + { + name: 'max', + token: 'MAX', + type: 'integer', + optional: true + } + ], + since: '1.0.0', + group: 'suggestion', + provider: 'redisearch' + }, + 'FT.SUGLEN': { + summary: 'Gets the size of an auto-complete suggestion dictionary', + complexity: 'O(1)', + arguments: [ + { + name: 'key', + type: 'string' + } + ], + since: '1.0.0', + group: 'suggestion', + provider: 'redisearch' + }, + 'FT.SYNDUMP': { + summary: 'Dumps the contents of a synonym group', + complexity: 'O(1)', + arguments: [ + { + name: 'index', + type: 'string' + } + ], + since: '1.2.0', + group: 'search', + provider: 'redisearch' + }, + 'FT.SYNUPDATE': { + summary: 'Creates or updates a synonym group with additional terms', + complexity: 'O(1)', + arguments: [ + { + name: 'index', + type: 'string' + }, + { + name: 'synonym_group_id', + type: 'string' + }, + { + name: 'skipinitialscan', + type: 'pure-token', + token: 'SKIPINITIALSCAN', + optional: true + }, + { + name: 'term', + type: 'string', + multiple: true + } + ], + since: '1.2.0', + group: 'search', + provider: 'redisearch' + }, + 'FT.TAGVALS': { + summary: 'Returns the distinct tags indexed in a Tag field', + complexity: 'O(N)', + arguments: [ + { + name: 'index', + type: 'string' + }, + { + name: 'field_name', + type: 'string' + } + ], + since: '1.0.0', + group: 'search', + provider: 'redisearch' + }, + 'FT._LIST': { + summary: 'Returns a list of all existing indexes', + complexity: 'O(1)', + since: '2.0.0', + group: 'search', + provider: 'redisearch' + }, } diff --git a/redisinsight/ui/src/pages/search/utils/query.ts b/redisinsight/ui/src/pages/search/utils/query.ts index 17fbffcb53..2b50127bc6 100644 --- a/redisinsight/ui/src/pages/search/utils/query.ts +++ b/redisinsight/ui/src/pages/search/utils/query.ts @@ -3,6 +3,7 @@ import { isNumber, toNumber } from 'lodash' import { generateArgsNames, Maybe, Nullable } from 'uiSrc/utils' import { CommandProvider } from 'uiSrc/constants' +import { COMPOSITE_ARGS } from 'uiSrc/pages/search/components/query/constants' import { ArgName, FoundCommandArgument, SearchCommand, SearchCommandTree, TokenType } from '../types' export const splitQueryByArgs = (query: string, position: number = 0) => { @@ -142,6 +143,7 @@ const findStopArgumentInQuery = ( stopArgIndex: number argumentsIntered?: number isBlocked: boolean + parent?: SearchCommand } => { let currentCommandArgIndex = 0 let argumentsIntered = 0 @@ -173,7 +175,7 @@ const findStopArgumentInQuery = ( if (!isBlockedOnCommand && currentCommandArg?.optional) { const isNotToken = currentCommandArg?.token && currentCommandArg.token !== arg.toUpperCase() - const isNotOneOfToken = currentCommandArg?.type === TokenType.OneOf + const isNotOneOfToken = !currentCommandArg?.token && currentCommandArg?.type === TokenType.OneOf && currentCommandArg?.arguments?.every(({ token }) => token !== arg.toUpperCase()) if (isNotToken || isNotOneOfToken) { @@ -183,37 +185,53 @@ const findStopArgumentInQuery = ( } } - // if we are on token - that requires one more argument - if (currentCommandArg?.token === arg.toUpperCase()) { - blockCommand() - continue - } - if (currentCommandArg?.type === TokenType.Block) { - let blockArguments = currentCommandArg.arguments + let blockArguments = currentCommandArg.arguments ? [...currentCommandArg.arguments] : [] const nArgs = toNumber(queryArgs[i - 1]) || 0 + // if block is multiple - we duplicate nArgs inner arguments - if (currentCommandArg?.multiple) { + if (currentCommandArg?.multiple && nArgs) { blockArguments = Array(nArgs).fill(currentCommandArg.arguments).flat() } + const currentQueryArg = queryArgs.slice(i)?.[0]?.toUpperCase() + const isBlockHasToken = blockArguments?.[0]?.token === currentQueryArg + + if (currentCommandArg.token && !isBlockHasToken && currentQueryArg) { + blockArguments.unshift({ + type: TokenType.PureToken, + token: currentQueryArg + }) + } + const blockSuggestion = findStopArgumentInQuery(queryArgs.slice(i), blockArguments) const stopArg = blockSuggestion.restArguments?.[blockSuggestion.stopArgIndex] const { argumentsIntered } = blockSuggestion - if (isNumber(argumentsIntered) && argumentsIntered >= nArgs) { + if (nArgs && currentCommandArg?.multiple && isNumber(argumentsIntered) && argumentsIntered >= nArgs) { i += queryArgs.slice(i).length - 1 skipArg() continue } - if (blockSuggestion.isBlocked || stopArg) return blockSuggestion + if (blockSuggestion.isBlocked || stopArg) { + return { + ...blockSuggestion, + parent: currentCommandArg + } + } i += queryArgs.slice(i).length - 1 skipArg() continue } + // if we are on token - that requires one more argument + if (currentCommandArg?.token === arg.toUpperCase()) { + blockCommand() + continue + } + if (currentCommandArg?.name === ArgName.NArgs) { const numberOfArgs = toNumber(arg) @@ -283,9 +301,11 @@ export const getArgumentSuggestions = ( const { restArguments, stopArgIndex, - isBlocked: isWasBlocked + isBlocked: isWasBlocked, + parent } = findStopArgumentInQuery(tokenArgs, pastCommandArgs) + const prevArg = restArguments[stopArgIndex - 1] const stopArgument = restArguments[stopArgIndex] const restNotFilledArgs = restArguments.slice(stopArgIndex) @@ -301,7 +321,8 @@ export const getArgumentSuggestions = ( } } - if (stopArgument && !stopArgument.optional) { + const isPrevArgWasMandatory = prevArg && !prevArg.optional + if (isPrevArgWasMandatory && stopArgument && !stopArgument.optional) { const isCanAppend = stopArgument?.token || isOneOfArgument const append = isCanAppend ? [[isOneOfArgument ? stopArgument.arguments! : stopArgument].flat()] : [] @@ -315,8 +336,11 @@ export const getArgumentSuggestions = ( // if we finished argument - stopArgument will be undefined, then we get it as token const lastArgument = stopArgument ?? restArguments[0] + const isBlockHasParent = current?.arguments?.some(({ name }) => parent?.name && name === parent?.name) + const foundParent = isBlockHasParent ? { ...parent, parent: current } : (parent || current) + const isBlockComplete = !stopArgument && current?.name === lastArgument?.name - const beforeMandatoryOptionalArgs = getAllRestArguments(current, lastArgument, levelArgs, isBlockComplete) + const beforeMandatoryOptionalArgs = getAllRestArguments(foundParent, lastArgument, levelArgs, isBlockComplete) const requiredArgsLength = restNotFilledArgs.filter((arg) => !arg.optional).length return { @@ -335,11 +359,14 @@ export const getRestArguments = ( ?.findIndex(({ name }) => name === stopArgument?.name) const nextMandatoryIndex = argumentIndexInArg && argumentIndexInArg > -1 ? current?.arguments ?.findIndex(({ optional }, i) => !optional && i > argumentIndexInArg) : -1 + const prevMandatory = current?.arguments?.slice(0, argumentIndexInArg).reverse() + .find(({ optional }) => !optional) + const prevMandatoryIndex = current?.arguments?.findIndex(({ name }) => name === prevMandatory?.name) const beforeMandatoryOptionalArgs = ( nextMandatoryIndex && nextMandatoryIndex > -1 - ? current?.arguments?.slice(argumentIndexInArg, nextMandatoryIndex) - : current?.arguments?.filter(({ optional }) => optional) + ? current?.arguments?.slice(prevMandatoryIndex, nextMandatoryIndex) + : current?.arguments?.slice((prevMandatoryIndex || 0) + 1) ) || [] const nextMandatoryArg = nextMandatoryIndex && nextMandatoryIndex > -1 @@ -350,6 +377,10 @@ export const getRestArguments = ( beforeMandatoryOptionalArgs.unshift(nextMandatoryArg) } + if (nextMandatoryArg?.type === TokenType.OneOf) { + beforeMandatoryOptionalArgs.unshift(...(nextMandatoryArg.arguments || [])) + } + return fillArgsByType(beforeMandatoryOptionalArgs) .map((arg) => ({ ...arg, @@ -364,7 +395,6 @@ export const getAllRestArguments = ( skipLevel = false ) => { const appendArgs: Array = [] - const currentLvlNextArgs = removeNotSuggestedArgs( prevStringArgs, getRestArguments(current, stopArgument) @@ -394,7 +424,10 @@ export const fillArgsByType = (args: SearchCommand[], expandBlock = true): Searc for (let i = 0; i < args.length; i++) { const currentArg = args[i] - if (expandBlock && currentArg.type === TokenType.OneOf) result.push(...(currentArg?.arguments || [])) + if (expandBlock && currentArg.type === TokenType.OneOf && !currentArg.token) { + result.push(...(currentArg?.arguments || [])) + } + if (currentArg.type === TokenType.Block) { result.push({ multiple: currentArg.multiple, @@ -414,7 +447,8 @@ export const findArgByToken = (list: SearchCommand[], arg: string): Maybe oneOfArg?.token?.toLowerCase() === arg?.toLowerCase()) : cArg.arguments?.[0]?.token?.toLowerCase() === arg.toLowerCase())) -export const isCompositeArgument = (arg: string, prevArg?: string) => arg === '*' && prevArg === 'LOAD' +export const isCompositeArgument = (arg: string, prevArg?: string) => + COMPOSITE_ARGS.includes([prevArg?.toUpperCase(), arg?.toUpperCase()].join(' ')) export const generateDetail = (command: Maybe) => { if (!command) return '' diff --git a/redisinsight/ui/src/pages/search/utils/tests/query.spec.ts b/redisinsight/ui/src/pages/search/utils/tests/query.spec.ts index b6b4a49991..ccd15cc8a2 100644 --- a/redisinsight/ui/src/pages/search/utils/tests/query.spec.ts +++ b/redisinsight/ui/src/pages/search/utils/tests/query.spec.ts @@ -1,603 +1,19 @@ import { addOwnTokenToArgs, findCurrentArgument, generateDetail, splitQueryByArgs } from 'uiSrc/pages/search/utils' import { SearchCommand, TokenType } from 'uiSrc/pages/search/types' import { Maybe } from 'uiSrc/utils' +import { + commonfindCurrentArgumentCases, + findArgumentftAggreageTests, + findArgumentftSearchTests +} from './test-cases' import { MOCKED_SUPPORTED_COMMANDS } from '../../mocks/mocks' const ftSearchCommand = MOCKED_SUPPORTED_COMMANDS['FT.SEARCH'] const ftAggregateCommand = MOCKED_SUPPORTED_COMMANDS['FT.AGGREGATE'] -const COMMANDS = [ - { - name: 'FT.SEARCH', - ...ftSearchCommand - }, - { - name: 'FT.AGGREGATE', - ...ftAggregateCommand - } -] - -const ftAggreageTests = [ - { args: [''], result: null }, - { args: ['', ''], result: null }, - { - args: ['index', '"query"', 'APPLY'], - result: { - stopArg: { name: 'expression', token: 'APPLY', type: 'string' }, - append: [], - isBlocked: true, - isComplete: false, - parent: expect.any(Object) - } - }, - { - args: ['index', '"query"', 'APPLY', 'expression'], - result: { - stopArg: { name: 'name', token: 'AS', type: 'string' }, - append: expect.any(Array), - isBlocked: false, - isComplete: false, - parent: expect.any(Object) - } - }, - { - args: ['index', '"query"', 'APPLY', 'expression', 'AS'], - result: { - stopArg: { name: 'name', token: 'AS', type: 'string' }, - append: expect.any(Array), - isBlocked: true, - isComplete: false, - parent: expect.any(Object) - } - }, - { - args: ['index', '"query"', 'APPLY', 'expression', 'AS', 'name'], - result: { - stopArg: undefined, - append: expect.any(Array), - isBlocked: false, - isComplete: true, - parent: expect.any(Object) - } - }, - { - args: ['""', '""', 'GROUPBY', '2', 'p1', 'p2', 'REDUCE', 'f'], - result: { - stopArg: { name: 'nargs', type: 'integer' }, - append: [], - isBlocked: true, - isComplete: false, - parent: expect.any(Object) - } - }, - { - args: ['""', '""', 'GROUPBY', '2', 'p1', 'p2', 'REDUCE', 'f', '0'], - result: { - stopArg: { - name: 'name', - type: 'string', - token: 'AS', - optional: true - }, - append: [ - [ - { - name: 'name', - type: 'string', - token: 'AS', - optional: true, - parent: { - name: 'reduce', - type: 'block', - optional: true, - multiple: true, - arguments: [ - { - name: 'function', - token: 'REDUCE', - type: 'string' - }, - { - name: 'nargs', - type: 'integer' - }, - { - name: 'arg', - type: 'string', - multiple: true - }, - { - name: 'name', - type: 'string', - token: 'AS', - optional: true - } - ], - parent: expect.any(Object) - } - } - ], - [ - { - name: 'function', - token: 'REDUCE', - type: 'string', - multiple: true, - optional: true, - parent: { - name: 'groupby', - type: 'block', - optional: true, - multiple: true, - arguments: [ - { - name: 'nargs', - type: 'integer', - token: 'GROUPBY' - }, - { - name: 'property', - type: 'string', - multiple: true - }, - { - name: 'reduce', - type: 'block', - optional: true, - multiple: true, - arguments: expect.any(Array) - } - ] - } - } - ] - ], - isBlocked: false, - isComplete: true, - parent: expect.any(Object) - } - }, - { - args: ['""', '""', 'GROUPBY', '2', 'p1', 'p2', 'REDUCE', 'f', '1', 'AS', 'name'], - result: { - stopArg: undefined, - append: [ - [], - [ - { - name: 'function', - token: 'REDUCE', - type: 'string', - multiple: true, - optional: true, - parent: expect.any(Object) - } - ] - ], - isBlocked: false, - isComplete: true, - parent: expect.any(Object) - } - }, - { - args: ['index', '"query"', 'SORTBY'], - result: { - stopArg: { name: 'nargs', token: 'SORTBY', type: 'integer' }, - append: expect.any(Array), - isBlocked: true, - isComplete: false, - parent: expect.any(Object) - } - }, - { - args: ['index', '"query"', 'SORTBY', '1', 'p1'], - result: { - stopArg: { - name: 'num', - type: 'integer', - token: 'MAX', - optional: true - }, - append: [ - [ - { - name: 'num', - type: 'integer', - token: 'MAX', - optional: true, - parent: expect.any(Object) - } - ] - ], - isBlocked: false, - isComplete: true, - parent: expect.any(Object) - } - }, - { - args: ['index', '"query"', 'SORTBY', '2', 'p1', 'ASC'], - result: { - stopArg: { - name: 'num', - type: 'integer', - token: 'MAX', - optional: true - }, - append: [ - [ - { - name: 'num', - type: 'integer', - token: 'MAX', - optional: true, - parent: expect.any(Object) - } - ] - ], - isBlocked: false, - isComplete: true, - parent: expect.any(Object) - } - }, - { - args: ['index', '"query"', 'SORTBY', '0'], - result: { - stopArg: { - name: 'num', - type: 'integer', - token: 'MAX', - optional: true - }, - append: [ - [{ - name: 'num', - type: 'integer', - token: 'MAX', - optional: true, - parent: expect.any(Object) - }] - ], - isBlocked: false, - isComplete: true, - parent: expect.any(Object) - } - }, - { - args: ['index', '"query"', 'SORTBY', '2', 'p1', 'ASC', 'MAX'], - result: { - stopArg: { - name: 'num', - type: 'integer', - token: 'MAX', - optional: true - }, - append: [], - isBlocked: true, - isComplete: false, - parent: expect.any(Object) - } - }, - { - args: ['index', '"query"', 'LOAD', '4'], - result: { - stopArg: { multiple: true, name: 'field', type: 'string' }, - append: [], - isBlocked: true, - isComplete: false, - parent: expect.any(Object) - } - }, - { - args: ['index', '"query"', 'LOAD', '4', '1', '2', '3'], - result: { - stopArg: { multiple: true, name: 'field', type: 'string' }, - append: [], - isBlocked: true, - isComplete: false, - parent: expect.any(Object) - } - }, - { - args: ['index', '"query"', 'LOAD', '4', '1', '2', '3', '4'], - result: { - stopArg: undefined, - append: [[]], - isBlocked: false, - isComplete: true, - parent: expect.any(Object) - } - }, -] - -const ftSearchTests = [ - { args: [''], result: null }, - { args: ['', ''], result: null }, - { - args: ['', '', 'SUMMARIZE'], - result: { - stopArg: { - name: 'fields', - type: 'block', - optional: true, - arguments: [ - { - name: 'count', - type: 'string', - token: 'FIELDS' - }, - { - name: 'field', - type: 'string', - multiple: true - } - ] - }, - append: [[ - { - name: 'count', - type: 'string', - token: 'FIELDS', - parent: expect.any(Object), - optional: true - }, - { - name: 'num', - type: 'integer', - token: 'FRAGS', - optional: true, - parent: expect.any(Object) - }, - { - name: 'fragsize', - type: 'integer', - token: 'LEN', - optional: true, - parent: expect.any(Object) - }, - { - name: 'separator', - type: 'string', - token: 'SEPARATOR', - optional: true, - parent: expect.any(Object) - } - ]], - isBlocked: false, - isComplete: true, - parent: expect.any(Object) - } - }, - { - args: ['', '', 'SUMMARIZE', 'FIELDS'], - result: { - stopArg: { - name: 'count', - type: 'string', - token: 'FIELDS' - }, - append: [], - isBlocked: true, - isComplete: false, - parent: expect.any(Object) - } - }, - { - args: ['', '', 'SUMMARIZE', 'FIELDS', '1'], - result: { - stopArg: { - name: 'field', - type: 'string', - multiple: true - }, - append: [], - isBlocked: true, - isComplete: false, - parent: expect.any(Object) - } - }, - { - args: ['', '', 'SUMMARIZE', 'FIELDS', '1', 'f', 'FRAGS'], - result: { - stopArg: { - name: 'num', - type: 'integer', - token: 'FRAGS', - optional: true - }, - append: [], - isBlocked: true, - isComplete: false, - parent: expect.any(Object) - } - }, - { - args: ['', '', 'SUMMARIZE', 'FIELDS', '1', 'f', 'FRAGS', '10'], - result: { - stopArg: { - name: 'fragsize', - type: 'integer', - token: 'LEN', - optional: true - }, - append: [[ - { - name: 'fragsize', - type: 'integer', - token: 'LEN', - optional: true, - parent: expect.any(Object) - }, - { - name: 'separator', - type: 'string', - token: 'SEPARATOR', - optional: true, - parent: expect.any(Object) - } - ]], - isBlocked: false, - isComplete: true, - parent: expect.any(Object) - } - }, - { - args: ['', '', 'RETURN', '1', 'iden'], - result: { - stopArg: undefined, - // TODO: append may have AS token, since it is optional - we skip for now - append: [ - [] - ], - isBlocked: false, - isComplete: true, - parent: expect.any(Object) - } - }, - { - args: ['', '', 'RETURN', '2', 'iden'], - result: { - stopArg: { - name: 'property', - type: 'string', - token: 'AS', - optional: true - }, - append: [[]], - isBlocked: false, - isComplete: false, - parent: expect.any(Object) - } - }, - { - args: ['', '', 'RETURN', '2', 'iden', 'iden'], - result: { - stopArg: undefined, - append: [ - [] - ], - isBlocked: false, - isComplete: true, - parent: expect.any(Object) - } - }, - { - args: ['', '', 'RETURN', '3', 'iden', 'iden'], - result: { - stopArg: { - name: 'property', - type: 'string', - token: 'AS', - optional: true - }, - append: [[]], - isBlocked: false, - isComplete: false, - parent: expect.any(Object) - } - }, - { - args: ['', '', 'RETURN', '3', 'iden', 'iden', 'AS', 'iden2'], - result: { - stopArg: undefined, - append: [ - [] - ], - isBlocked: false, - isComplete: true, - parent: expect.any(Object) - } - }, - { - args: ['', '', 'SORTBY', 'f'], - result: { - stopArg: { - name: 'order', - type: 'oneof', - optional: true, - arguments: [ - { - name: 'asc', - type: 'pure-token', - token: 'ASC' - }, - { - name: 'desc', - type: 'pure-token', - token: 'DESC' - } - ] - }, - append: [ - [ - { - name: 'asc', - type: 'pure-token', - token: 'ASC', - parent: expect.any(Object) - }, - { - name: 'desc', - type: 'pure-token', - token: 'DESC', - parent: expect.any(Object) - } - ] - ], - isBlocked: false, - isComplete: true, - parent: expect.any(Object) - } - }, - { - args: ['', '', 'SORTBY', 'f', 'DESC'], - result: { - stopArg: undefined, - append: [], - isBlocked: false, - isComplete: true, - parent: expect.any(Object) - } - }, - { - args: ['', '', 'DIALECT', '1'], - result: { - stopArg: undefined, - append: [ - [] - ], - isBlocked: false, - isComplete: true, - parent: expect.any(Object) - } - }, -] - -// Common test cases - provides list of suggestions -const commonfindCurrentArgumentCases = [ - { - input: 'FT.SEARCH index "" DIALECT 1', - result: { - stopArg: undefined, - append: expect.any(Array), - isBlocked: false, - isComplete: true, - parent: expect.any(Object) - }, - appendIncludes: ['WITHSCORES', 'VERBATIM', 'FILTER', 'SORTBY', 'RETURN'], - appendNotIncludes: ['DIALECT'] - }, - { - input: 'FT.AGGREGATE "idx:schools" "" GROUPBY 1 p REDUCE AVG 1 a1 AS name ', - result: { - stopArg: undefined, - append: expect.any(Array), - isBlocked: false, - isComplete: true, - parent: expect.any(Object) - }, - appendIncludes: ['REDUCE', 'APPLY', 'SORTBY', 'GROUPBY'], - appendNotIncludes: ['AS'], - }, -] +const COMMANDS = Object.keys(MOCKED_SUPPORTED_COMMANDS).map((name) => ({ + name, + ...MOCKED_SUPPORTED_COMMANDS[name] +})) describe('findCurrentArgument', () => { describe('with list of commands', () => { @@ -620,17 +36,20 @@ describe('findCurrentArgument', () => { ).toEqual( expect.arrayContaining(appendIncludes) ) - expect( - testResult?.append?.flat()?.map((arg) => arg.token) - ).toEqual( - expect.not.arrayContaining(appendNotIncludes) - ) + + if (appendNotIncludes) { + expect( + testResult?.append?.flat()?.map((arg) => arg.token) + ).toEqual( + expect.not.arrayContaining(appendNotIncludes) + ) + } }) }) }) describe('FT.AGGREGATE', () => { - ftAggreageTests.forEach(({ args, result: testResult }) => { + findArgumentftAggreageTests.forEach(({ args, result: testResult }) => { it(`should return proper suggestions for ${args.join(' ')}`, () => { const result = findCurrentArgument( ftAggregateCommand.arguments as SearchCommand[], @@ -642,7 +61,7 @@ describe('findCurrentArgument', () => { }) describe('FT.SEARCH', () => { - ftSearchTests.forEach(({ args, result: testResult }) => { + findArgumentftSearchTests.forEach(({ args, result: testResult }) => { it(`should return proper suggestions for ${args.join(' ')}`, () => { const result = findCurrentArgument( ftSearchCommand.arguments as SearchCommand[], diff --git a/redisinsight/ui/src/pages/search/utils/tests/test-cases/common.ts b/redisinsight/ui/src/pages/search/utils/tests/test-cases/common.ts new file mode 100644 index 0000000000..3322cb9cc9 --- /dev/null +++ b/redisinsight/ui/src/pages/search/utils/tests/test-cases/common.ts @@ -0,0 +1,177 @@ +// Common test cases +export const commonfindCurrentArgumentCases = [ + { + input: 'FT.SEARCH index "" DIALECT 1', + result: { + stopArg: undefined, + append: expect.any(Array), + isBlocked: false, + isComplete: true, + parent: expect.any(Object) + }, + appendIncludes: ['WITHSCORES', 'VERBATIM', 'FILTER', 'SORTBY', 'RETURN'], + appendNotIncludes: ['DIALECT'] + }, + { + input: 'FT.AGGREGATE "idx:schools" "" GROUPBY 1 p REDUCE AVG 1 a1 AS name ', + result: { + stopArg: undefined, + append: expect.any(Array), + isBlocked: false, + isComplete: true, + parent: expect.any(Object) + }, + appendIncludes: ['REDUCE', 'APPLY', 'SORTBY', 'GROUPBY'], + appendNotIncludes: ['AS'], + }, + { + input: 'FT.SEARCH "idx:bicycle" "*" ', + result: { + stopArg: expect.any(Object), + append: expect.any(Array), + isBlocked: false, + isComplete: true, + parent: expect.any(Object) + }, + appendIncludes: ['DIALECT', 'EXPANDER', 'INKEYS', 'LIMIT'], + appendNotIncludes: ['ASC'], + }, + { + input: 'FT.SEARCH "idx:bicycle" "*" DIALECT 2', + result: expect.any(Object), + appendIncludes: ['EXPANDER', 'INKEYS', 'LIMIT'], + appendNotIncludes: ['DIALECT'], + }, + { + input: 'FT.CREATE "idx:schools" ', + result: expect.any(Object), + appendIncludes: ['FILTER', 'ON', 'SCHEMA', 'SCORE', 'NOHL'], + appendNotIncludes: ['HASH', 'JSON'], + }, + { + input: 'FT.CREATE "idx:schools" ON', + result: expect.any(Object), + appendIncludes: ['HASH', 'JSON'], + appendNotIncludes: ['SCHEMA', 'SCORE', 'NOHL'], + }, + { + input: 'FT.CREATE "idx:schools" ON JSON NOFREQS', + result: expect.any(Object), + appendIncludes: ['TEMPORARY', 'NOFIELDS', 'PAYLOAD_FIELD', 'MAXTEXTFIELDS', 'PREFIX', 'SKIPINITIALSCAN'], + appendNotIncludes: ['ON', 'JSON', 'NOFREQS'], + }, + { + input: 'FT.CREATE "idx:schools" ON JSON NOFREQS SKIPINITIALSCAN', + result: expect.any(Object), + appendIncludes: ['TEMPORARY', 'NOFIELDS', 'PAYLOAD_FIELD', 'MAXTEXTFIELDS', 'PREFIX'], + appendNotIncludes: ['ON', 'JSON', 'NOFREQS', 'SKIPINITIALSCAN'], + }, + { + input: 'FT.CREATE "idx:schools" ON JSON SCHEMA address ', + result: { + stopArg: expect.any(Object), + append: expect.any(Array), + isBlocked: false, + isComplete: false, + parent: expect.any(Object) + }, + appendIncludes: ['AS', 'GEO', 'TEXT', 'VECTOR'], + appendNotIncludes: ['SCHEMA', 'SCORE', 'NOHL'], + }, + { + input: 'FT.CREATE "idx:schools" ON JSON SCHEMA address TEXT NOINDEX INDEXMISSING ', + result: { + stopArg: expect.any(Object), + append: expect.any(Array), + isBlocked: false, + isComplete: true, + parent: expect.any(Object) + }, + appendIncludes: ['INDEXEMPTY', 'SORTABLE', 'WITHSUFFIXTRIE'], + appendNotIncludes: ['SCHEMA', 'SCORE', 'NOHL'], + }, + { + input: 'FT.ALTER "idx:schools" ', + result: { + stopArg: expect.any(Object), + append: expect.any(Array), + isBlocked: false, + isComplete: false, + parent: expect.any(Object) + }, + appendIncludes: ['SCHEMA', 'SKIPINITIALSCAN'], + appendNotIncludes: ['ADD'], + }, + { + input: 'FT.ALTER "idx:schools" SCHEMA', + result: expect.any(Object), + appendIncludes: ['ADD'], + appendNotIncludes: ['SKIPINITIALSCAN'], + }, + { + input: 'FT.CONFIG SET ', + result: { + stopArg: { + name: 'option', + type: 'string' + }, + append: [], + isBlocked: true, + isComplete: false, + parent: expect.any(Object) + }, + appendIncludes: [], + appendNotIncludes: [expect.any(String)], + }, + { + input: 'FT.CURSOR READ "idx:schools" 1 ', + result: expect.any(Object), + appendIncludes: ['COUNT'], + }, + { + input: 'FT.DICTADD dict term1 ', + result: { + append: [], + isBlocked: true, + isComplete: false, + parent: expect.any(Object), + stopArg: { + multiple: true, + name: 'term', + type: 'string' + } + }, + appendIncludes: [], + }, + { + input: 'FT.SUGADD key string ', + result: { + append: [], + isBlocked: true, + isComplete: false, + parent: expect.any(Object), + stopArg: { + name: 'score', + type: 'double' + } + }, + appendIncludes: [], + }, + { + input: 'FT.SUGADD key string 1.0 ', + result: expect.any(Object), + appendIncludes: ['INCR', 'PAYLOAD'], + }, + { + input: 'FT.SUGADD key string 1.0 PAYLOAD 1 ', + result: expect.any(Object), + appendIncludes: ['INCR'], + appendNotIncludes: ['PAYLOAD'], + }, + { + input: 'FT.SUGGET k p FUZZY MAX 2 ', + result: expect.any(Object), + appendIncludes: ['WITHPAYLOADS', 'WITHSCORES'], + appendNotIncludes: ['FUZZY', 'MAX'], + }, +] diff --git a/redisinsight/ui/src/pages/search/utils/tests/test-cases/ft-aggregate.ts b/redisinsight/ui/src/pages/search/utils/tests/test-cases/ft-aggregate.ts new file mode 100644 index 0000000000..7601af7b29 --- /dev/null +++ b/redisinsight/ui/src/pages/search/utils/tests/test-cases/ft-aggregate.ts @@ -0,0 +1,291 @@ +export const findArgumentftAggreageTests = [ + { args: [''], result: null }, + { args: ['', ''], result: null }, + { + args: ['index', '"query"', 'APPLY'], + result: { + stopArg: { name: 'expression', token: 'APPLY', type: 'string' }, + append: [], + isBlocked: true, + isComplete: false, + parent: expect.any(Object) + } + }, + { + args: ['index', '"query"', 'APPLY', 'expression'], + result: { + stopArg: { name: 'name', token: 'AS', type: 'string' }, + append: expect.any(Array), + isBlocked: false, + isComplete: false, + parent: expect.any(Object) + } + }, + { + args: ['index', '"query"', 'APPLY', 'expression', 'AS'], + result: { + stopArg: { name: 'name', token: 'AS', type: 'string' }, + append: expect.any(Array), + isBlocked: true, + isComplete: false, + parent: expect.any(Object) + } + }, + { + args: ['index', '"query"', 'APPLY', 'expression', 'AS', 'name'], + result: { + stopArg: undefined, + append: expect.any(Array), + isBlocked: false, + isComplete: true, + parent: expect.any(Object) + } + }, + { + args: ['""', '""', 'GROUPBY', '2', 'p1', 'p2', 'REDUCE', 'f'], + result: { + stopArg: { name: 'nargs', type: 'integer' }, + append: [], + isBlocked: true, + isComplete: false, + parent: expect.any(Object) + } + }, + { + args: ['""', '""', 'GROUPBY', '2', 'p1', 'p2', 'REDUCE', 'f', '0'], + result: { + stopArg: { + name: 'name', + type: 'string', + token: 'AS', + optional: true + }, + append: [ + [ + { + name: 'name', + type: 'string', + token: 'AS', + optional: true, + parent: { + name: 'reduce', + type: 'block', + optional: true, + multiple: true, + arguments: [ + { + name: 'function', + token: 'REDUCE', + type: 'string' + }, + { + name: 'nargs', + type: 'integer' + }, + { + name: 'arg', + type: 'string', + multiple: true + }, + { + name: 'name', + type: 'string', + token: 'AS', + optional: true + } + ], + parent: expect.any(Object) + } + } + ], + [ + { + name: 'function', + token: 'REDUCE', + type: 'string', + multiple: true, + optional: true, + parent: { + name: 'groupby', + type: 'block', + optional: true, + multiple: true, + arguments: [ + { + name: 'nargs', + type: 'integer', + token: 'GROUPBY' + }, + { + name: 'property', + type: 'string', + multiple: true + }, + { + name: 'reduce', + type: 'block', + optional: true, + multiple: true, + arguments: expect.any(Array) + } + ] + } + } + ] + ], + isBlocked: false, + isComplete: true, + parent: expect.any(Object) + } + }, + { + args: ['""', '""', 'GROUPBY', '2', 'p1', 'p2', 'REDUCE', 'f', '1', 'AS', 'name'], + result: { + stopArg: undefined, + append: [ + [], + [ + { + name: 'function', + token: 'REDUCE', + type: 'string', + multiple: true, + optional: true, + parent: expect.any(Object) + } + ] + ], + isBlocked: false, + isComplete: true, + parent: expect.any(Object) + } + }, + { + args: ['index', '"query"', 'SORTBY'], + result: { + stopArg: { name: 'nargs', token: 'SORTBY', type: 'integer' }, + append: expect.any(Array), + isBlocked: true, + isComplete: false, + parent: expect.any(Object) + } + }, + { + args: ['index', '"query"', 'SORTBY', '1', 'p1'], + result: { + stopArg: { + name: 'num', + type: 'integer', + token: 'MAX', + optional: true + }, + append: [ + [ + { + name: 'num', + type: 'integer', + token: 'MAX', + optional: true, + parent: expect.any(Object) + } + ] + ], + isBlocked: false, + isComplete: true, + parent: expect.any(Object) + } + }, + { + args: ['index', '"query"', 'SORTBY', '2', 'p1', 'ASC'], + result: { + stopArg: { + name: 'num', + type: 'integer', + token: 'MAX', + optional: true + }, + append: [ + [ + { + name: 'num', + type: 'integer', + token: 'MAX', + optional: true, + parent: expect.any(Object) + } + ] + ], + isBlocked: false, + isComplete: true, + parent: expect.any(Object) + } + }, + { + args: ['index', '"query"', 'SORTBY', '0'], + result: { + stopArg: { + name: 'num', + type: 'integer', + token: 'MAX', + optional: true + }, + append: [ + [{ + name: 'num', + type: 'integer', + token: 'MAX', + optional: true, + parent: expect.any(Object) + }] + ], + isBlocked: false, + isComplete: true, + parent: expect.any(Object) + } + }, + { + args: ['index', '"query"', 'SORTBY', '2', 'p1', 'ASC', 'MAX'], + result: { + stopArg: { + name: 'num', + type: 'integer', + token: 'MAX', + optional: true + }, + append: [], + isBlocked: true, + isComplete: false, + parent: expect.any(Object) + } + }, + { + args: ['index', '"query"', 'LOAD', '4'], + result: { + stopArg: { multiple: true, name: 'field', type: 'string' }, + append: [], + isBlocked: true, + isComplete: false, + parent: expect.any(Object) + } + }, + { + args: ['index', '"query"', 'LOAD', '4', '1', '2', '3'], + result: { + stopArg: { multiple: true, name: 'field', type: 'string' }, + append: [], + isBlocked: true, + isComplete: false, + parent: expect.any(Object) + } + }, + { + args: ['index', '"query"', 'LOAD', '4', '1', '2', '3', '4'], + result: { + stopArg: undefined, + append: [[]], + isBlocked: false, + isComplete: true, + parent: expect.any(Object) + } + }, +] diff --git a/redisinsight/ui/src/pages/search/utils/tests/test-cases/ft-search.ts b/redisinsight/ui/src/pages/search/utils/tests/test-cases/ft-search.ts new file mode 100644 index 0000000000..0e7650f5ad --- /dev/null +++ b/redisinsight/ui/src/pages/search/utils/tests/test-cases/ft-search.ts @@ -0,0 +1,283 @@ +export const findArgumentftSearchTests = [ + { args: [''], result: null }, + { args: ['', ''], result: null }, + { + args: ['', '', 'SUMMARIZE'], + result: { + stopArg: { + name: 'fields', + type: 'block', + optional: true, + arguments: [ + { + name: 'count', + type: 'string', + token: 'FIELDS' + }, + { + name: 'field', + type: 'string', + multiple: true + } + ] + }, + append: [[ + { + name: 'count', + type: 'string', + token: 'FIELDS', + parent: expect.any(Object), + optional: true + }, + { + name: 'num', + type: 'integer', + token: 'FRAGS', + optional: true, + parent: expect.any(Object) + }, + { + name: 'fragsize', + type: 'integer', + token: 'LEN', + optional: true, + parent: expect.any(Object) + }, + { + name: 'separator', + type: 'string', + token: 'SEPARATOR', + optional: true, + parent: expect.any(Object) + } + ]], + isBlocked: false, + isComplete: true, + parent: expect.any(Object) + } + }, + { + args: ['', '', 'SUMMARIZE', 'FIELDS'], + result: { + stopArg: { + name: 'count', + type: 'string', + token: 'FIELDS' + }, + append: [], + isBlocked: true, + isComplete: false, + parent: expect.any(Object) + } + }, + { + args: ['', '', 'SUMMARIZE', 'FIELDS', '1'], + result: { + stopArg: { + name: 'field', + type: 'string', + multiple: true + }, + append: [], + isBlocked: true, + isComplete: false, + parent: expect.any(Object) + } + }, + { + args: ['', '', 'SUMMARIZE', 'FIELDS', '1', 'f', 'FRAGS'], + result: { + stopArg: { + name: 'num', + type: 'integer', + token: 'FRAGS', + optional: true + }, + append: [], + isBlocked: true, + isComplete: false, + parent: expect.any(Object) + } + }, + { + args: ['', '', 'SUMMARIZE', 'FIELDS', '1', 'f', 'FRAGS', '10'], + result: { + stopArg: { + name: 'fragsize', + type: 'integer', + token: 'LEN', + optional: true + }, + append: [[ + { + name: 'fragsize', + type: 'integer', + token: 'LEN', + optional: true, + parent: expect.any(Object) + }, + { + name: 'separator', + type: 'string', + token: 'SEPARATOR', + optional: true, + parent: expect.any(Object) + } + ]], + isBlocked: false, + isComplete: true, + parent: expect.any(Object) + } + }, + { + args: ['', '', 'RETURN', '1', 'iden'], + result: { + stopArg: undefined, + append: [ + [] + ], + isBlocked: false, + isComplete: true, + parent: expect.any(Object) + } + }, + { + args: ['', '', 'RETURN', '2', 'iden'], + result: { + stopArg: { + name: 'property', + type: 'string', + token: 'AS', + optional: true + }, + append: [ + [ + { + name: 'property', + type: 'string', + token: 'AS', + optional: true, + parent: expect.any(Object) + } + ], + [] + ], + isBlocked: false, + isComplete: false, + parent: expect.any(Object) + } + }, + { + args: ['', '', 'RETURN', '2', 'iden', 'iden'], + result: { + stopArg: undefined, + append: [ + [] + ], + isBlocked: false, + isComplete: true, + parent: expect.any(Object) + } + }, + { + args: ['', '', 'RETURN', '3', 'iden', 'iden'], + result: { + stopArg: { + name: 'property', + type: 'string', + token: 'AS', + optional: true + }, + append: [ + [ + { + name: 'property', + type: 'string', + token: 'AS', + optional: true, + parent: expect.any(Object) + } + ], + [] + ], + isBlocked: false, + isComplete: false, + parent: expect.any(Object) + } + }, + { + args: ['', '', 'RETURN', '3', 'iden', 'iden', 'AS', 'iden2'], + result: { + stopArg: undefined, + append: [ + [] + ], + isBlocked: false, + isComplete: true, + parent: expect.any(Object) + } + }, + { + args: ['', '', 'SORTBY', 'f'], + result: { + stopArg: { + name: 'order', + type: 'oneof', + optional: true, + arguments: [ + { + name: 'asc', + type: 'pure-token', + token: 'ASC' + }, + { + name: 'desc', + type: 'pure-token', + token: 'DESC' + } + ] + }, + append: [ + [ + { + name: 'asc', + type: 'pure-token', + token: 'ASC', + parent: expect.any(Object) + }, + { + name: 'desc', + type: 'pure-token', + token: 'DESC', + parent: expect.any(Object) + } + ] + ], + isBlocked: false, + isComplete: true, + parent: expect.any(Object) + } + }, + { + args: ['', '', 'SORTBY', 'f', 'DESC'], + result: { + stopArg: undefined, + append: [], + isBlocked: false, + isComplete: true, + parent: expect.any(Object) + } + }, + { + args: ['', '', 'DIALECT', '1'], + result: { + stopArg: undefined, + append: [ + [] + ], + isBlocked: false, + isComplete: true, + parent: expect.any(Object) + } + }, +] diff --git a/redisinsight/ui/src/pages/search/utils/tests/test-cases/index.ts b/redisinsight/ui/src/pages/search/utils/tests/test-cases/index.ts new file mode 100644 index 0000000000..42889e7be5 --- /dev/null +++ b/redisinsight/ui/src/pages/search/utils/tests/test-cases/index.ts @@ -0,0 +1,3 @@ +export * from './ft-aggregate' +export * from './ft-search' +export * from './common' diff --git a/redisinsight/ui/src/utils/monaco/monarchTokens/redisearchTokens.ts b/redisinsight/ui/src/utils/monaco/monarchTokens/redisearchTokens.ts index 187fe305fe..d9c1c3b881 100644 --- a/redisinsight/ui/src/utils/monaco/monarchTokens/redisearchTokens.ts +++ b/redisinsight/ui/src/utils/monaco/monarchTokens/redisearchTokens.ts @@ -4,7 +4,7 @@ import { generateKeywords, generateTokens, generateTokensWithFunctions, - getBlockTokens, + getBlockTokens, isIndexAfterKeyword, isQueryAfterIndex } from 'uiSrc/utils/monaco/redisearch/utils' import { generateQuery } from 'uiSrc/utils/monaco/monarchTokens/redisearchTokensTemplates' @@ -18,6 +18,7 @@ export const getRediSearchMonarchTokensProvider = ( const currentCommand = commands.find(({ name }) => name === command) const keywords = generateKeywords(commands) + const isHighlightIndex = isIndexAfterKeyword(currentCommand) const argTokens = generateTokens(currentCommand) const isHighlightQuery = isQueryAfterIndex(currentCommand) @@ -55,7 +56,7 @@ export const getRediSearchMonarchTokensProvider = ( [/[<>=!%&+\-*/|~^]/, 'operator'], ], keyword: [ - [`(${keywords.join('|')})\\b`, { token: 'keyword', next: '@index' }] + [`(${keywords.join('|')})\\b`, { token: 'keyword', next: isHighlightIndex ? '@index' : '@root' }] ], 'argument.block': getBlockTokens(argTokens?.pureTokens), ...generateTokensWithFunctions(argTokens?.tokensWithQueryAfter), diff --git a/redisinsight/ui/src/utils/monaco/redisearch/utils.ts b/redisinsight/ui/src/utils/monaco/redisearch/utils.ts index c65b4bb80a..d04f47a717 100644 --- a/redisinsight/ui/src/utils/monaco/redisearch/utils.ts +++ b/redisinsight/ui/src/utils/monaco/redisearch/utils.ts @@ -55,6 +55,13 @@ export const generateTokens = (command?: SearchCommand): Nullable<{ return { pureTokens, tokensWithQueryAfter } } +export const isIndexAfterKeyword = (command?: SearchCommand) => { + if (!command) return false + + const index = command.arguments?.findIndex(({ name }) => name === DefinedArgumentName.index) + return isNumber(index) && index === 0 +} + export const isQueryAfterIndex = (command?: SearchCommand) => { if (!command) return false From a9b72cec4590f85abee540668aae680039df6745 Mon Sep 17 00:00:00 2001 From: Roman Sergeenko Date: Tue, 1 Oct 2024 15:07:40 +0200 Subject: [PATCH 084/256] #RI-6089 - fix suggestions --- .../ui/src/pages/search/utils/query.ts | 32 ++++++++++++------- .../pages/search/utils/tests/query.spec.ts | 12 ++++--- .../search/utils/tests/test-cases/common.ts | 6 ++++ .../utils/tests/test-cases/ft-aggregate.ts | 26 +-------------- .../utils/tests/test-cases/ft-search.ts | 2 +- 5 files changed, 36 insertions(+), 42 deletions(-) diff --git a/redisinsight/ui/src/pages/search/utils/query.ts b/redisinsight/ui/src/pages/search/utils/query.ts index 2b50127bc6..92bc72179e 100644 --- a/redisinsight/ui/src/pages/search/utils/query.ts +++ b/redisinsight/ui/src/pages/search/utils/query.ts @@ -381,11 +381,7 @@ export const getRestArguments = ( beforeMandatoryOptionalArgs.unshift(...(nextMandatoryArg.arguments || [])) } - return fillArgsByType(beforeMandatoryOptionalArgs) - .map((arg) => ({ - ...arg, - parent: current - })) + return beforeMandatoryOptionalArgs.map((arg) => ({ ...arg, parent: current })) } export const getAllRestArguments = ( @@ -401,7 +397,7 @@ export const getAllRestArguments = ( ) if (!skipLevel) { - appendArgs.push(currentLvlNextArgs) + appendArgs.push(fillArgsByType(currentLvlNextArgs)) } if (current?.parent) { @@ -415,23 +411,37 @@ export const getAllRestArguments = ( } export const removeNotSuggestedArgs = (args: string[], commandArgs: SearchCommandTree[]) => - commandArgs.filter((arg) => arg.token - && (arg.multiple || !args.some((queryArg) => queryArg.toUpperCase() === arg.token?.toUpperCase()))) + commandArgs.filter((arg) => { + if (arg.token && arg.multiple) return true -export const fillArgsByType = (args: SearchCommand[], expandBlock = true): SearchCommand[] => { - const result: SearchCommand[] = [] + if (arg.type === TokenType.OneOf) { + return !args + .some((queryArg) => arg.arguments + ?.some((oneOfArg) => oneOfArg.token?.toUpperCase() === queryArg.toUpperCase())) + } + + if (arg.type === TokenType.Block) { + return arg.arguments?.[0]?.token && !args.includes(arg.arguments?.[0]?.token?.toUpperCase()) + } + + return arg.token && !args.includes(arg.token) + }) + +export const fillArgsByType = (args: SearchCommand[], expandBlock = true): SearchCommandTree[] => { + const result: SearchCommandTree[] = [] for (let i = 0; i < args.length; i++) { const currentArg = args[i] if (expandBlock && currentArg.type === TokenType.OneOf && !currentArg.token) { - result.push(...(currentArg?.arguments || [])) + result.push(...(currentArg?.arguments?.map((arg) => ({ ...arg, parent: currentArg })) || [])) } if (currentArg.type === TokenType.Block) { result.push({ multiple: currentArg.multiple, optional: currentArg.optional, + parent: currentArg, ...(currentArg?.arguments?.[0] as SearchCommand || {}), }) } diff --git a/redisinsight/ui/src/pages/search/utils/tests/query.spec.ts b/redisinsight/ui/src/pages/search/utils/tests/query.spec.ts index ccd15cc8a2..0c3fcd858d 100644 --- a/redisinsight/ui/src/pages/search/utils/tests/query.spec.ts +++ b/redisinsight/ui/src/pages/search/utils/tests/query.spec.ts @@ -38,11 +38,13 @@ describe('findCurrentArgument', () => { ) if (appendNotIncludes) { - expect( - testResult?.append?.flat()?.map((arg) => arg.token) - ).toEqual( - expect.not.arrayContaining(appendNotIncludes) - ) + appendNotIncludes.forEach((token) => { + expect( + testResult?.append?.flat()?.map((arg) => arg.token) + ).not.toEqual( + expect.arrayContaining([token]) + ) + }) } }) }) diff --git a/redisinsight/ui/src/pages/search/utils/tests/test-cases/common.ts b/redisinsight/ui/src/pages/search/utils/tests/test-cases/common.ts index 3322cb9cc9..7946e4baa6 100644 --- a/redisinsight/ui/src/pages/search/utils/tests/test-cases/common.ts +++ b/redisinsight/ui/src/pages/search/utils/tests/test-cases/common.ts @@ -42,6 +42,12 @@ export const commonfindCurrentArgumentCases = [ appendIncludes: ['EXPANDER', 'INKEYS', 'LIMIT'], appendNotIncludes: ['DIALECT'], }, + { + input: 'FT.PROFILE \'idx:schools\' SEARCH ', + result: expect.any(Object), + appendIncludes: ['LIMITED', 'QUERY'], + appendNotIncludes: ['AGGREGATE', 'SEARCH'], + }, { input: 'FT.CREATE "idx:schools" ', result: expect.any(Object), diff --git a/redisinsight/ui/src/pages/search/utils/tests/test-cases/ft-aggregate.ts b/redisinsight/ui/src/pages/search/utils/tests/test-cases/ft-aggregate.ts index 7601af7b29..e1411809a9 100644 --- a/redisinsight/ui/src/pages/search/utils/tests/test-cases/ft-aggregate.ts +++ b/redisinsight/ui/src/pages/search/utils/tests/test-cases/ft-aggregate.ts @@ -105,31 +105,7 @@ export const findArgumentftAggreageTests = [ type: 'string', multiple: true, optional: true, - parent: { - name: 'groupby', - type: 'block', - optional: true, - multiple: true, - arguments: [ - { - name: 'nargs', - type: 'integer', - token: 'GROUPBY' - }, - { - name: 'property', - type: 'string', - multiple: true - }, - { - name: 'reduce', - type: 'block', - optional: true, - multiple: true, - arguments: expect.any(Array) - } - ] - } + parent: expect.any(Object) } ] ], diff --git a/redisinsight/ui/src/pages/search/utils/tests/test-cases/ft-search.ts b/redisinsight/ui/src/pages/search/utils/tests/test-cases/ft-search.ts index 0e7650f5ad..28137bf8e9 100644 --- a/redisinsight/ui/src/pages/search/utils/tests/test-cases/ft-search.ts +++ b/redisinsight/ui/src/pages/search/utils/tests/test-cases/ft-search.ts @@ -26,8 +26,8 @@ export const findArgumentftSearchTests = [ name: 'count', type: 'string', token: 'FIELDS', + optional: true, parent: expect.any(Object), - optional: true }, { name: 'num', From 76663e99c47dea6e6a8fa67089145e4355310215 Mon Sep 17 00:00:00 2001 From: Gnanesh Date: Wed, 2 Oct 2024 13:14:27 +0530 Subject: [PATCH 085/256] Rework the test cases to be compatible with the latest bugfix suggestion --- .../certificate/ca-certificate.controller.ts | 4 +--- .../certificate/ca-certificate.service.spec.ts | 13 +++---------- .../certificate/client-certificate.controller.ts | 4 +--- .../certificate/client-certificate.service.spec.ts | 13 +++---------- 4 files changed, 8 insertions(+), 26 deletions(-) diff --git a/redisinsight/api/src/modules/certificate/ca-certificate.controller.ts b/redisinsight/api/src/modules/certificate/ca-certificate.controller.ts index bfe43bc7f4..692eba98c4 100644 --- a/redisinsight/api/src/modules/certificate/ca-certificate.controller.ts +++ b/redisinsight/api/src/modules/certificate/ca-certificate.controller.ts @@ -38,9 +38,7 @@ export class CaCertificateController { @Delete(':id') @ApiOperation({ description: 'Delete Ca Certificate by id' }) @ApiParam({ name: 'id', type: String }) - async delete( - @Param('id') id: string, - ): Promise { + async delete(@Param('id') id: string): Promise { await this.service.delete(id); } } diff --git a/redisinsight/api/src/modules/certificate/ca-certificate.service.spec.ts b/redisinsight/api/src/modules/certificate/ca-certificate.service.spec.ts index 1722a91049..fdf372cb18 100644 --- a/redisinsight/api/src/modules/certificate/ca-certificate.service.spec.ts +++ b/redisinsight/api/src/modules/certificate/ca-certificate.service.spec.ts @@ -5,12 +5,9 @@ import { mockCaCertificate, mockCaCertificateRepository, mockCreateCaCertificateDto, MockType, - mockSessionMetadata, - mockDatabaseRepository, mockRedisClientStorage, } from 'src/__mocks__'; import { CaCertificateRepository } from 'src/modules/certificate/repositories/ca-certificate.repository'; -import { DatabaseRepository } from 'src/modules/database/repositories/database.repository'; import { RedisClientStorage } from 'src/modules/redis/redis.client.storage'; import { pick } from 'lodash'; import { KeytarEncryptionErrorException } from 'src/modules/encryption/exceptions'; @@ -29,10 +26,6 @@ describe('CaCertificateService', () => { provide: CaCertificateRepository, useFactory: mockCaCertificateRepository, }, - { - provide: DatabaseRepository, - useFactory: mockDatabaseRepository, - }, { provide: RedisClientStorage, useFactory: mockRedisClientStorage, @@ -101,13 +94,13 @@ describe('CaCertificateService', () => { describe('delete', () => { it('should delete ca certificate', async () => { - expect(await service.delete(mockSessionMetadata, mockCaCertificate.id)).toEqual(undefined); + expect(await service.delete(mockCaCertificate.id)).toEqual(undefined); }); it('should throw encryption error', async () => { repository.delete.mockRejectedValueOnce(new KeytarEncryptionErrorException()); try { - await service.delete(mockSessionMetadata, mockCaCertificate.id); + await service.delete(mockCaCertificate.id); fail(); } catch (e) { expect(e).toBeInstanceOf(KeytarEncryptionErrorException); @@ -117,7 +110,7 @@ describe('CaCertificateService', () => { repository.delete.mockRejectedValueOnce(new Error()); try { - await service.delete(mockSessionMetadata, mockCaCertificate.id); + await service.delete(mockCaCertificate.id); fail(); } catch (e) { expect(e).toBeInstanceOf(InternalServerErrorException); diff --git a/redisinsight/api/src/modules/certificate/client-certificate.controller.ts b/redisinsight/api/src/modules/certificate/client-certificate.controller.ts index 2c45bb7db0..dfaaf5b365 100644 --- a/redisinsight/api/src/modules/certificate/client-certificate.controller.ts +++ b/redisinsight/api/src/modules/certificate/client-certificate.controller.ts @@ -39,9 +39,7 @@ export class ClientCertificateController { @Delete(':id') @ApiOperation({ description: 'Delete Client Certificate pair by id' }) @ApiParam({ name: 'id', type: String }) - async deleteClientCertificatePair( - @Param('id') id: string, - ): Promise { + async deleteClientCertificatePair(@Param('id') id: string): Promise { await this.service.delete(id); } } diff --git a/redisinsight/api/src/modules/certificate/client-certificate.service.spec.ts b/redisinsight/api/src/modules/certificate/client-certificate.service.spec.ts index d2c15d3f05..1291d700d2 100644 --- a/redisinsight/api/src/modules/certificate/client-certificate.service.spec.ts +++ b/redisinsight/api/src/modules/certificate/client-certificate.service.spec.ts @@ -6,14 +6,11 @@ import { mockClientCertificate, mockClientCertificateRepository, mockCreateClientCertificateDto, MockType, - mockSessionMetadata, - mockDatabaseRepository, mockRedisClientStorage, } from 'src/__mocks__'; import { KeytarEncryptionErrorException } from 'src/modules/encryption/exceptions'; import { ClientCertificateService } from 'src/modules/certificate/client-certificate.service'; import { ClientCertificateRepository } from 'src/modules/certificate/repositories/client-certificate.repository'; -import { DatabaseRepository } from 'src/modules/database/repositories/database.repository'; import { RedisClientStorage } from 'src/modules/redis/redis.client.storage'; describe('ClientCertificateService', () => { @@ -29,10 +26,6 @@ describe('ClientCertificateService', () => { provide: ClientCertificateRepository, useFactory: mockClientCertificateRepository, }, - { - provide: DatabaseRepository, - useFactory: mockDatabaseRepository, - }, { provide: RedisClientStorage, useFactory: mockRedisClientStorage, @@ -101,13 +94,13 @@ describe('ClientCertificateService', () => { describe('delete', () => { it('should delete client certificate', async () => { - expect(await service.delete(mockSessionMetadata, mockClientCertificate.id)).toEqual(undefined); + expect(await service.delete(mockClientCertificate.id)).toEqual(undefined); }); it('should throw encryption error', async () => { repository.delete.mockRejectedValueOnce(new KeytarEncryptionErrorException()); try { - await service.delete(mockSessionMetadata, mockClientCertificate.id); + await service.delete(mockClientCertificate.id); fail(); } catch (e) { expect(e).toBeInstanceOf(KeytarEncryptionErrorException); @@ -117,7 +110,7 @@ describe('ClientCertificateService', () => { repository.delete.mockRejectedValueOnce(new Error()); try { - await service.delete(mockSessionMetadata, mockClientCertificate.id); + await service.delete(mockClientCertificate.id); fail(); } catch (e) { expect(e).toBeInstanceOf(InternalServerErrorException); From 80c2de1b690006e1c2bce81c7d469bb1164a3ec4 Mon Sep 17 00:00:00 2001 From: Gnanesh Date: Wed, 2 Oct 2024 13:49:07 +0530 Subject: [PATCH 086/256] Fix tests for local ca and client cert repository --- .../repositories/local.ca-certificate.repository.spec.ts | 9 ++++++++- .../local.client-certificate.repository.spec.ts | 6 ++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/redisinsight/api/src/modules/certificate/repositories/local.ca-certificate.repository.spec.ts b/redisinsight/api/src/modules/certificate/repositories/local.ca-certificate.repository.spec.ts index 7d34aed57b..fc156803d8 100644 --- a/redisinsight/api/src/modules/certificate/repositories/local.ca-certificate.repository.spec.ts +++ b/redisinsight/api/src/modules/certificate/repositories/local.ca-certificate.repository.spec.ts @@ -5,7 +5,9 @@ import { getRepositoryToken } from '@nestjs/typeorm'; import { Repository } from 'typeorm'; import { mockCaCertificate, mockCaCertificateCertificateEncrypted, mockCaCertificateCertificatePlain, mockCaCertificateEntity, - mockCaCertificateId, mockEncryptionService, + mockCaCertificateId, + mockDatabaseRepository, + mockEncryptionService, mockRepository, MockType, } from 'src/__mocks__'; @@ -14,6 +16,7 @@ import { CaCertificateEntity } from 'src/modules/certificate/entities/ca-certifi import { EncryptionService } from 'src/modules/encryption/encryption.service'; import { BadRequestException, NotFoundException } from '@nestjs/common'; import ERROR_MESSAGES from 'src/constants/error-messages'; +import { DatabaseRepository } from 'src/modules/database/repositories/database.repository'; describe('LocalCaCertificateRepository', () => { let service: LocalCaCertificateRepository; @@ -34,6 +37,10 @@ describe('LocalCaCertificateRepository', () => { provide: EncryptionService, useFactory: mockEncryptionService, }, + { + provide: DatabaseRepository, + useFactory: mockDatabaseRepository, + }, ], }).compile(); diff --git a/redisinsight/api/src/modules/certificate/repositories/local.client-certificate.repository.spec.ts b/redisinsight/api/src/modules/certificate/repositories/local.client-certificate.repository.spec.ts index 6847becd99..a747fe1a3b 100644 --- a/redisinsight/api/src/modules/certificate/repositories/local.client-certificate.repository.spec.ts +++ b/redisinsight/api/src/modules/certificate/repositories/local.client-certificate.repository.spec.ts @@ -11,6 +11,7 @@ import { mockClientCertificateId, mockClientCertificateKeyEncrypted, mockClientCertificateKeyPlain, + mockDatabaseRepository, mockEncryptionService, mockRepository, MockType, @@ -22,6 +23,7 @@ import { LocalClientCertificateRepository, } from 'src/modules/certificate/repositories/local.client-certificate.repository'; import { ClientCertificateEntity } from 'src/modules/certificate/entities/client-certificate.entity'; +import { DatabaseRepository } from 'src/modules/database/repositories/database.repository'; describe('LocalClientCertificateRepository', () => { let service: LocalClientCertificateRepository; @@ -38,6 +40,10 @@ describe('LocalClientCertificateRepository', () => { provide: getRepositoryToken(ClientCertificateEntity), useFactory: mockRepository, }, + { + provide: DatabaseRepository, + useFactory: mockDatabaseRepository, + }, { provide: EncryptionService, useFactory: mockEncryptionService, From 6e936b866f4670200cd49df898eece590267afbd Mon Sep 17 00:00:00 2001 From: Roman Sergeenko Date: Wed, 2 Oct 2024 10:28:21 +0200 Subject: [PATCH 087/256] #RI-6137 - update quotes and colors --- redisinsight/ui/src/constants/monaco/theme.ts | 26 +++++++++---------- .../pages/search/components/query/utils.ts | 8 +++--- .../ui/src/pages/search/utils/monaco.ts | 2 +- 3 files changed, 18 insertions(+), 18 deletions(-) diff --git a/redisinsight/ui/src/constants/monaco/theme.ts b/redisinsight/ui/src/constants/monaco/theme.ts index db0e6521fa..b3ac2f83cb 100644 --- a/redisinsight/ui/src/constants/monaco/theme.ts +++ b/redisinsight/ui/src/constants/monaco/theme.ts @@ -1,16 +1,16 @@ import { monaco } from 'react-monaco-editor' export const redisearchDarKThemeRules = [ - { token: 'keyword', foreground: '#8094B1', fontStyle: 'bold' }, - { token: 'argument.block.0', foreground: '#BDE8D7' }, - { token: 'argument.block.1', foreground: '#8CD7B9' }, - { token: 'argument.block.2', foreground: '#5BC69B' }, - { token: 'argument.block.3', foreground: '#3A8365' }, - { token: 'argument.block.withToken.0', foreground: '#BDE8D7' }, - { token: 'argument.block.withToken.1', foreground: '#8CD7B9' }, - { token: 'argument.block.withToken.2', foreground: '#5BC69B' }, - { token: 'argument.block.withToken.3', foreground: '#3A8365' }, - { token: 'loadAll', foreground: '#BDE8D7' }, + { token: 'keyword', foreground: '#C8B5F2' }, + { token: 'argument.block.0', foreground: '#8CD7B9' }, + { token: 'argument.block.1', foreground: '#72B59B' }, + { token: 'argument.block.2', foreground: '#3A8365' }, + { token: 'argument.block.3', foreground: '#244F3E' }, + { token: 'argument.block.withToken.0', foreground: '#8CD7B9' }, + { token: 'argument.block.withToken.1', foreground: '#72B59B' }, + { token: 'argument.block.withToken.2', foreground: '#3A8365' }, + { token: 'argument.block.withToken.3', foreground: '#244F3E' }, + { token: 'loadAll', foreground: '#8CD7B9' }, { token: 'index', foreground: '#DE47BB' }, { token: 'query', foreground: '#7B90E0' }, { token: 'field', foreground: '#B02C30' }, @@ -19,13 +19,13 @@ export const redisearchDarKThemeRules = [ ] export const redisearchLightThemeRules = [ - { token: 'keyword', foreground: '#8094B1', fontStyle: 'bold' }, + { token: 'keyword', foreground: '#7547DE' }, { token: 'argument.block.0', foreground: '#8CD7B9' }, - { token: 'argument.block.1', foreground: '#5BC69B' }, + { token: 'argument.block.1', foreground: '#72B59B' }, { token: 'argument.block.2', foreground: '#3A8365' }, { token: 'argument.block.3', foreground: '#244F3E' }, { token: 'argument.block.withToken.0', foreground: '#8CD7B9' }, - { token: 'argument.block.withToken.1', foreground: '#5BC69B' }, + { token: 'argument.block.withToken.1', foreground: '#72B59B' }, { token: 'argument.block.withToken.2', foreground: '#3A8365' }, { token: 'argument.block.withToken.3', foreground: '#244F3E' }, { token: 'loadAll', foreground: '#8CD7B9' }, diff --git a/redisinsight/ui/src/pages/search/components/query/utils.ts b/redisinsight/ui/src/pages/search/components/query/utils.ts index 581b85c2d2..49d7976cde 100644 --- a/redisinsight/ui/src/pages/search/components/query/utils.ts +++ b/redisinsight/ui/src/pages/search/components/query/utils.ts @@ -20,15 +20,15 @@ export const asSuggestionsRef = ( forceShow }) -export const getIndexesSuggestions = (indexes: RedisResponseBuffer[], range: monaco.IRange, nextQuotes = true) => +export const getIndexesSuggestions = (indexes: RedisResponseBuffer[], range: monaco.IRange, isNextArgQuery = true) => indexes.map((index) => { const value = formatLongName(bufferToString(index)) - const insertQueryQuotes = nextQuotes ? ' "$1"' : '' + const insertQueryQuotes = isNextArgQuery ? " '\${1:query to search}'" : '' return { label: value || ' ', kind: monacoEditor.languages.CompletionItemKind.Snippet, - insertText: `"${value}"${insertQueryQuotes} `, + insertText: `'${value}'${insertQueryQuotes} `, insertTextRules: monacoEditor.languages.CompletionItemInsertTextRule.InsertAsSnippet, range, detail: value || ' ', @@ -54,7 +54,7 @@ export const getFieldsSuggestions = ( ) => fields.map((field) => { const { attribute, type } = field - const attibuteText = attribute.trim() ? attribute : `\\"${attribute}\\"` + const attibuteText = attribute.trim() ? attribute : `\\'${attribute}\\'` const insertText = withType ? addFieldAttribute(attibuteText, type) : attibuteText return { diff --git a/redisinsight/ui/src/pages/search/utils/monaco.ts b/redisinsight/ui/src/pages/search/utils/monaco.ts index bfc1d6ea08..2f8c713e78 100644 --- a/redisinsight/ui/src/pages/search/utils/monaco.ts +++ b/redisinsight/ui/src/pages/search/utils/monaco.ts @@ -26,7 +26,7 @@ export const getRange = (position: monaco.Position, word: monaco.editor.IWordAtP }) export const buildSuggestion = (arg: SearchCommand, range: monaco.IRange, options: any = {}) => { - const extraQuotes = arg.expression ? '"$1"' : '' + const extraQuotes = arg.expression ? '\'$1\'' : '' return { label: isString(arg) ? arg : arg.token || arg.arguments?.[0].token || arg.name || '', insertText: `${arg.token || arg.arguments?.[0].token || arg.name?.toUpperCase() || ''} ${extraQuotes}`, From 9ce24ce5ed582d275688386273d3cf40d1cc8393 Mon Sep 17 00:00:00 2001 From: Gnanesh Date: Wed, 2 Oct 2024 14:01:55 +0530 Subject: [PATCH 088/256] Use the getRepositoryToken to inject the databae --- .../repositories/local.ca-certificate.repository.spec.ts | 9 ++++----- .../local.client-certificate.repository.spec.ts | 3 +-- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/redisinsight/api/src/modules/certificate/repositories/local.ca-certificate.repository.spec.ts b/redisinsight/api/src/modules/certificate/repositories/local.ca-certificate.repository.spec.ts index fc156803d8..839d9c5eb3 100644 --- a/redisinsight/api/src/modules/certificate/repositories/local.ca-certificate.repository.spec.ts +++ b/redisinsight/api/src/modules/certificate/repositories/local.ca-certificate.repository.spec.ts @@ -16,7 +16,6 @@ import { CaCertificateEntity } from 'src/modules/certificate/entities/ca-certifi import { EncryptionService } from 'src/modules/encryption/encryption.service'; import { BadRequestException, NotFoundException } from '@nestjs/common'; import ERROR_MESSAGES from 'src/constants/error-messages'; -import { DatabaseRepository } from 'src/modules/database/repositories/database.repository'; describe('LocalCaCertificateRepository', () => { let service: LocalCaCertificateRepository; @@ -34,12 +33,12 @@ describe('LocalCaCertificateRepository', () => { useFactory: mockRepository, }, { - provide: EncryptionService, - useFactory: mockEncryptionService, + provide: getRepositoryToken(DatabaseRepository), + useFactory: mockDatabaseRepository, }, { - provide: DatabaseRepository, - useFactory: mockDatabaseRepository, + provide: EncryptionService, + useFactory: mockEncryptionService, }, ], }).compile(); diff --git a/redisinsight/api/src/modules/certificate/repositories/local.client-certificate.repository.spec.ts b/redisinsight/api/src/modules/certificate/repositories/local.client-certificate.repository.spec.ts index a747fe1a3b..807127e39a 100644 --- a/redisinsight/api/src/modules/certificate/repositories/local.client-certificate.repository.spec.ts +++ b/redisinsight/api/src/modules/certificate/repositories/local.client-certificate.repository.spec.ts @@ -23,7 +23,6 @@ import { LocalClientCertificateRepository, } from 'src/modules/certificate/repositories/local.client-certificate.repository'; import { ClientCertificateEntity } from 'src/modules/certificate/entities/client-certificate.entity'; -import { DatabaseRepository } from 'src/modules/database/repositories/database.repository'; describe('LocalClientCertificateRepository', () => { let service: LocalClientCertificateRepository; @@ -41,7 +40,7 @@ describe('LocalClientCertificateRepository', () => { useFactory: mockRepository, }, { - provide: DatabaseRepository, + provide: getRepositoryToken(DatabaseEntity), useFactory: mockDatabaseRepository, }, { From 9b1f814782399be19e9e54f50b8eb913fb8df538 Mon Sep 17 00:00:00 2001 From: Gnanesh Date: Wed, 2 Oct 2024 14:11:17 +0530 Subject: [PATCH 089/256] Fix database entity import --- .../repositories/local.ca-certificate.repository.spec.ts | 3 ++- .../repositories/local.client-certificate.repository.spec.ts | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/redisinsight/api/src/modules/certificate/repositories/local.ca-certificate.repository.spec.ts b/redisinsight/api/src/modules/certificate/repositories/local.ca-certificate.repository.spec.ts index 839d9c5eb3..598b69d089 100644 --- a/redisinsight/api/src/modules/certificate/repositories/local.ca-certificate.repository.spec.ts +++ b/redisinsight/api/src/modules/certificate/repositories/local.ca-certificate.repository.spec.ts @@ -16,6 +16,7 @@ import { CaCertificateEntity } from 'src/modules/certificate/entities/ca-certifi import { EncryptionService } from 'src/modules/encryption/encryption.service'; import { BadRequestException, NotFoundException } from '@nestjs/common'; import ERROR_MESSAGES from 'src/constants/error-messages'; +import { DatabaseEntity } from 'src/modules/database/entities/database.entity'; describe('LocalCaCertificateRepository', () => { let service: LocalCaCertificateRepository; @@ -33,7 +34,7 @@ describe('LocalCaCertificateRepository', () => { useFactory: mockRepository, }, { - provide: getRepositoryToken(DatabaseRepository), + provide: getRepositoryToken(DatabaseEntity), useFactory: mockDatabaseRepository, }, { diff --git a/redisinsight/api/src/modules/certificate/repositories/local.client-certificate.repository.spec.ts b/redisinsight/api/src/modules/certificate/repositories/local.client-certificate.repository.spec.ts index 807127e39a..7353bb53c6 100644 --- a/redisinsight/api/src/modules/certificate/repositories/local.client-certificate.repository.spec.ts +++ b/redisinsight/api/src/modules/certificate/repositories/local.client-certificate.repository.spec.ts @@ -23,6 +23,7 @@ import { LocalClientCertificateRepository, } from 'src/modules/certificate/repositories/local.client-certificate.repository'; import { ClientCertificateEntity } from 'src/modules/certificate/entities/client-certificate.entity'; +import { DatabaseEntity } from 'src/modules/database/entities/database.entity'; describe('LocalClientCertificateRepository', () => { let service: LocalClientCertificateRepository; From b15bd83fb8d2b735c4827d0a553e783b494142fb Mon Sep 17 00:00:00 2001 From: Gnanesh Date: Wed, 2 Oct 2024 14:59:53 +0530 Subject: [PATCH 090/256] Mock db methods to test the service's delete method --- redisinsight/api/src/__mocks__/databases.ts | 6 +++ .../local.ca-certificate.repository.spec.ts | 51 +++++++++++++------ ...ocal.client-certificate.repository.spec.ts | 47 ++++++++++++----- 3 files changed, 75 insertions(+), 29 deletions(-) diff --git a/redisinsight/api/src/__mocks__/databases.ts b/redisinsight/api/src/__mocks__/databases.ts index ffd848dc0c..e4d69da655 100644 --- a/redisinsight/api/src/__mocks__/databases.ts +++ b/redisinsight/api/src/__mocks__/databases.ts @@ -251,6 +251,12 @@ export const mockDatabaseRepository = jest.fn(() => ({ pick(mockDatabase, 'id', 'name'), pick(mockDatabase, 'id', 'name'), ]), + createQueryBuilder: jest.fn().mockReturnThis(), + leftJoinAndSelect: jest.fn().mockReturnThis(), + where: jest.fn().mockReturnThis(), + select: jest.fn().mockReturnThis(), + getMany: jest.fn().mockResolvedValue([]), + findOneBy: jest.fn().mockResolvedValue(mockDatabase), })); export const mockDatabaseService = jest.fn(() => ({ diff --git a/redisinsight/api/src/modules/certificate/repositories/local.ca-certificate.repository.spec.ts b/redisinsight/api/src/modules/certificate/repositories/local.ca-certificate.repository.spec.ts index 598b69d089..67449eb7f9 100644 --- a/redisinsight/api/src/modules/certificate/repositories/local.ca-certificate.repository.spec.ts +++ b/redisinsight/api/src/modules/certificate/repositories/local.ca-certificate.repository.spec.ts @@ -107,24 +107,45 @@ describe('LocalCaCertificateRepository', () => { }); describe('delete', () => { - it('should delete ca certificate', async () => { - const result = await service.delete(mockCaCertificate.id); - - expect(result).toEqual(undefined); + it('should delete ca certificate and return affected databases', async () => { + const mockId = 'mock-ca-cert-id'; + const mockAffectedDatabases = ['db1', 'db2']; + + // Mock findOneBy to return a certificate + repository.findOneBy.mockResolvedValue(mockCaCertificate); + + // Mock getMany to return affected databases + const mockQueryBuilder = { + leftJoinAndSelect: jest.fn().mockReturnThis(), + where: jest.fn().mockReturnThis(), + select: jest.fn().mockReturnThis(), + getMany: jest.fn().mockResolvedValue(mockAffectedDatabases.map((id) => ({ id }))), + }; + jest.spyOn(service['databaseRepository'], 'createQueryBuilder').mockReturnValue(mockQueryBuilder as any); + + // Mock delete operation + repository.delete.mockResolvedValue(undefined); + + const result = await service.delete(mockId); + + expect(result).toEqual({ affectedDatabases: mockAffectedDatabases }); + expect(repository.findOneBy).toHaveBeenCalledWith({ id: mockId }); + expect(service['databaseRepository'].createQueryBuilder).toHaveBeenCalledWith('d'); + expect(mockQueryBuilder.leftJoinAndSelect).toHaveBeenCalledWith('d.caCert', 'c'); + expect(mockQueryBuilder.where).toHaveBeenCalledWith({ caCert: mockId }); + expect(mockQueryBuilder.select).toHaveBeenCalledWith(['d.id']); + expect(repository.delete).toHaveBeenCalledWith(mockId); }); - it('should throw an error when trying to delete non-existing ca certificate', async () => { - repository.findOneBy.mockResolvedValueOnce(null); + it('should throw NotFoundException when trying to delete non-existing ca certificate', async () => { + const mockId = 'non-existent-id'; - try { - await service.delete(mockCaCertificate.id); - fail(); - } catch (e) { - expect(e).toBeInstanceOf(NotFoundException); - // todo: why such message? - expect(e.message).toEqual('Not Found'); - expect(repository.delete).not.toHaveBeenCalled(); - } + // Mock findOneBy to return null (certificate not found) + repository.findOneBy.mockResolvedValue(null); + + await expect(service.delete(mockId)).rejects.toThrow(NotFoundException); + expect(repository.findOneBy).toHaveBeenCalledWith({ id: mockId }); + expect(repository.delete).not.toHaveBeenCalled(); }); }); }); diff --git a/redisinsight/api/src/modules/certificate/repositories/local.client-certificate.repository.spec.ts b/redisinsight/api/src/modules/certificate/repositories/local.client-certificate.repository.spec.ts index 7353bb53c6..ce3a843db9 100644 --- a/redisinsight/api/src/modules/certificate/repositories/local.client-certificate.repository.spec.ts +++ b/redisinsight/api/src/modules/certificate/repositories/local.client-certificate.repository.spec.ts @@ -123,24 +123,43 @@ describe('LocalClientCertificateRepository', () => { }); describe('delete', () => { - it('should delete client certificate', async () => { - const result = await service.delete(mockClientCertificate.id); + const mockId = 'mock-client-cert-id'; + const mockAffectedDatabases = ['db1', 'db2']; - expect(result).toEqual(undefined); + beforeEach(() => { + jest.clearAllMocks(); }); - it('should throw an error when trying to delete non-existing client certificate', async () => { - repository.findOneBy.mockResolvedValueOnce(null); + it('should delete client certificate and return affected databases', async () => { + jest.spyOn(repository, 'findOneBy').mockResolvedValue(mockClientCertificate); - try { - await service.delete(mockClientCertificate.id); - fail(); - } catch (e) { - expect(e).toBeInstanceOf(NotFoundException); - // todo: why such message? - expect(e.message).toEqual('Not Found'); - expect(repository.delete).not.toHaveBeenCalled(); - } + const mockQueryBuilder = { + leftJoinAndSelect: jest.fn().mockReturnThis(), + where: jest.fn().mockReturnThis(), + select: jest.fn().mockReturnThis(), + getMany: jest.fn().mockResolvedValue(mockAffectedDatabases.map((id) => ({ id }))) + }; + jest.spyOn(service['databaseRepository'], 'createQueryBuilder').mockReturnValue(mockQueryBuilder as any); + + jest.spyOn(repository, 'delete').mockResolvedValue(undefined); + + const result = await service.delete(mockId); + + expect(result).toEqual({ affectedDatabases: mockAffectedDatabases }); + expect(repository.findOneBy).toHaveBeenCalledWith({ id: mockId }); + expect(service['databaseRepository'].createQueryBuilder).toHaveBeenCalledWith('d'); + expect(mockQueryBuilder.leftJoinAndSelect).toHaveBeenCalledWith('d.clientCert', 'c'); + expect(mockQueryBuilder.where).toHaveBeenCalledWith({ clientCert: mockId }); + expect(mockQueryBuilder.select).toHaveBeenCalledWith(['d.id']); + expect(repository.delete).toHaveBeenCalledWith(mockId); + }); + + it('should throw NotFoundException when trying to delete non-existing client certificate', async () => { + jest.spyOn(repository, 'findOneBy').mockResolvedValue(null); + + await expect(service.delete(mockId)).rejects.toThrow(NotFoundException); + expect(repository.findOneBy).toHaveBeenCalledWith({ id: mockId }); + expect(repository.delete).not.toHaveBeenCalled(); }); }); }); From d9bd880f00f1050ff861476ce108b72a06c57782 Mon Sep 17 00:00:00 2001 From: Gnanesh Date: Wed, 2 Oct 2024 15:13:41 +0530 Subject: [PATCH 091/256] Fix CA and client certificate service tests --- .../ca-certificate.service.spec.ts | 21 +++++++++++++++++-- .../client-certificate.service.spec.ts | 21 +++++++++++++++++-- 2 files changed, 38 insertions(+), 4 deletions(-) diff --git a/redisinsight/api/src/modules/certificate/ca-certificate.service.spec.ts b/redisinsight/api/src/modules/certificate/ca-certificate.service.spec.ts index fdf372cb18..981e48d36e 100644 --- a/redisinsight/api/src/modules/certificate/ca-certificate.service.spec.ts +++ b/redisinsight/api/src/modules/certificate/ca-certificate.service.spec.ts @@ -93,9 +93,26 @@ describe('CaCertificateService', () => { }); describe('delete', () => { - it('should delete ca certificate', async () => { - expect(await service.delete(mockCaCertificate.id)).toEqual(undefined); + const mockId = 'mock-ca-cert-id'; + const mockAffectedDatabases = ['db1', 'db2']; + + beforeEach(() => { + jest.clearAllMocks(); + }); + + it('should delete CA certificate and remove affected database clients', async () => { + jest.spyOn(repository, 'delete').mockResolvedValue({ affectedDatabases: mockAffectedDatabases }); + jest.spyOn(service['redisClientStorage'], 'removeManyByMetadata').mockResolvedValue(undefined); + + await service.delete(mockId); + + expect(repository.delete).toHaveBeenCalledWith(mockId); + expect(service['redisClientStorage'].removeManyByMetadata).toHaveBeenCalledTimes(mockAffectedDatabases.length); + mockAffectedDatabases.forEach((databaseId) => { + expect(service['redisClientStorage'].removeManyByMetadata).toHaveBeenCalledWith({ databaseId }); + }); }); + it('should throw encryption error', async () => { repository.delete.mockRejectedValueOnce(new KeytarEncryptionErrorException()); diff --git a/redisinsight/api/src/modules/certificate/client-certificate.service.spec.ts b/redisinsight/api/src/modules/certificate/client-certificate.service.spec.ts index 1291d700d2..d59065c1b5 100644 --- a/redisinsight/api/src/modules/certificate/client-certificate.service.spec.ts +++ b/redisinsight/api/src/modules/certificate/client-certificate.service.spec.ts @@ -93,9 +93,26 @@ describe('ClientCertificateService', () => { }); describe('delete', () => { - it('should delete client certificate', async () => { - expect(await service.delete(mockClientCertificate.id)).toEqual(undefined); + const mockId = 'mock-client-cert-id'; + const mockAffectedDatabases = ['db1', 'db2']; + + beforeEach(() => { + jest.clearAllMocks(); + }); + + it('should delete client certificate and remove affected database clients', async () => { + jest.spyOn(repository, 'delete').mockResolvedValue({ affectedDatabases: mockAffectedDatabases }); + jest.spyOn(service['redisClientStorage'], 'removeManyByMetadata').mockResolvedValue(undefined); + + await service.delete(mockId); + + expect(repository.delete).toHaveBeenCalledWith(mockId); + expect(service['redisClientStorage'].removeManyByMetadata).toHaveBeenCalledTimes(mockAffectedDatabases.length); + mockAffectedDatabases.forEach((databaseId) => { + expect(service['redisClientStorage'].removeManyByMetadata).toHaveBeenCalledWith({ databaseId }); + }); }); + it('should throw encryption error', async () => { repository.delete.mockRejectedValueOnce(new KeytarEncryptionErrorException()); From 987fdd8453f035477199073ef9f17c63b401c395 Mon Sep 17 00:00:00 2001 From: mariasergeenko Date: Wed, 2 Oct 2024 15:46:53 +0200 Subject: [PATCH 092/256] add brotli --- .../e2e/helpers/brotli-database-populator.ts | 155 +++ tests/e2e/package.json | 8 +- .../e2e/test-data/decompressors/awesome.proto | 26 + .../decompressors/pickleFile1.pickle | 7 + .../decompressors/test_annotated_obj.ser | Bin 0 -> 66 bytes .../decompressors/test_serialised_obj.ser | Bin 0 -> 125 bytes tests/e2e/test-data/decompressors/vector.json | 978 ++++++++++++++++++ tests/e2e/yarn.lock | 184 +++- 8 files changed, 1354 insertions(+), 4 deletions(-) create mode 100644 tests/e2e/helpers/brotli-database-populator.ts create mode 100644 tests/e2e/test-data/decompressors/awesome.proto create mode 100644 tests/e2e/test-data/decompressors/pickleFile1.pickle create mode 100644 tests/e2e/test-data/decompressors/test_annotated_obj.ser create mode 100644 tests/e2e/test-data/decompressors/test_serialised_obj.ser create mode 100644 tests/e2e/test-data/decompressors/vector.json diff --git a/tests/e2e/helpers/brotli-database-populator.ts b/tests/e2e/helpers/brotli-database-populator.ts new file mode 100644 index 0000000000..4f5a4f9f13 --- /dev/null +++ b/tests/e2e/helpers/brotli-database-populator.ts @@ -0,0 +1,155 @@ +import { createClient } from 'redis'; +import * as proto from 'protobufjs'; +import { pack as msgpackrPack } from 'msgpackr'; +import * as brotli from 'brotli-unicode'; +import * as fflate from 'fflate'; +import * as fs from 'fs'; + +const COMPRESSED_PREFIX = 'Comp'; +const BROTLI_PREFIX = 'BROTLI'; + +export class BrotliDatabasePopulator { + private client: ReturnType; + + constructor(private host: string, private port: string) { + const dbConf = { port: Number.parseInt(port), host, username: 'default' }; + this.client = createClient(dbConf); + + this.client.on('error', (error: string) => { + throw new Error(`Redis connection error: ${error}`); + }); + } + + public async populateDB(): Promise { + this.client.on('connect', async () => { + console.log('Connected to Redis'); + + try { + await this.createBrotliCompressedKeys(); + } catch (error) { + console.error('Error during key creation:', error); + } finally { + await this.client.quit(); + } + }); + } + + private async createBrotliCompressedKeys(): Promise { + await this.createBrotliUnicodeKeys(); + await this.createBrotliASCIIKeys(); + await this.createBrotliVectorKeys(); + await this.createBrotliJSONKeys(); + await this.createBrotliPHPUnserializedJSONKeys(); + await this.createBrotliJavaSerializedObjectKeys(); + await this.createBrotliMsgpackKeys(); + await this.createBrotliProtobufKeys(); + await this.createBrotliPickleKeys(); + } + + private async createBrotliUnicodeKeys() { + const encoder = new TextEncoder(); + const prefix = `${COMPRESSED_PREFIX}:${BROTLI_PREFIX}:Unicode`; + const rawValue = '漢字'; + const buf = encoder.encode(rawValue); + const value = Buffer.from(await brotli.compress(buf)); + this.createString(prefix, value); + } + + private async createBrotliASCIIKeys() { + const prefix = `${COMPRESSED_PREFIX}:${BROTLI_PREFIX}:ASCII`; + const rawValue = '\xac\xed\x00\x05t\x0a4102'; + const buf = fflate.strToU8(rawValue); + const value = Buffer.from(await brotli.compress(buf)); + this.createString(prefix, value); + } + + private async createBrotliVectorKeys() { + const prefix = `${COMPRESSED_PREFIX}:${BROTLI_PREFIX}:Vector`; + const rawValue = JSON.parse(fs.readFileSync('./test-data/decompressors/vector.json', 'utf8')); + const buf = fflate.strToU8(rawValue); + const value = Buffer.from(await brotli.compress(buf)); + this.createString(prefix, value); + } + + private async createBrotliJSONKeys() { + const prefix = `${COMPRESSED_PREFIX}:${BROTLI_PREFIX}:JSON`; + const rawValue = '{"test":"test"}'; + const buf = fflate.strToU8(rawValue); + const value = Buffer.from(await brotli.compress(buf)); + this.createString(prefix, value); + } + + private async createBrotliPHPUnserializedJSONKeys() { + const prefix = `${COMPRESSED_PREFIX}:${BROTLI_PREFIX}:PHP`; + const rawValue = 'a:2:{i:0;s:12:"Sample array";i:1;a:2:{i:0;s:5:"Apple";i:1;s:6:"Orange";}}'; + const buf = fflate.strToU8(rawValue); + const value = Buffer.from(await brotli.compress(buf)); + this.createString(prefix, value); + } + + private async createBrotliPickleKeys() { + const prefix = `${COMPRESSED_PREFIX}:${BROTLI_PREFIX}:Pickle`; + const rawValue = fs.readFileSync('./test-data/decompressors/pickleFile1.pickle'); + const value = Buffer.from(await brotli.compress(rawValue)); + this.createString(prefix, value); +}; + + private async createBrotliJavaSerializedObjectKeys() { + const prefix = `${COMPRESSED_PREFIX}:${BROTLI_PREFIX}:Java`; + const rawValue = fs.readFileSync('./test-data/decompressors/test_serialised_obj.ser'); + const rawValue2 = fs.readFileSync('./test-data/decompressors/test_annotated_obj.ser'); + + const value = Buffer.from(await brotli.compress(rawValue)); + const value2 = Buffer.from(await brotli.compress(rawValue2)); + + this.createString(prefix, value); + this.createString(prefix, value2); + } + + private async createBrotliMsgpackKeys(): Promise { + const prefix = `${COMPRESSED_PREFIX}:${BROTLI_PREFIX}:Msgpack`; + const rawValue = msgpackrPack({ + hello: 'World', + array: [1, 2], + obj: { test: 'test' }, + boolean: false, + }); + const value = Buffer.from(await brotli.compress(rawValue)); + this.createString(prefix, value); + } + + private createBrotliProtobufKeys(): Promise { + return new Promise((resolve, reject) => { + const prefix = `${COMPRESSED_PREFIX}:${BROTLI_PREFIX}:Proto`; + proto.load('./test-data/decompressors/awesome.proto', async (err, root) => { + if (err || !root) { + console.error('Error loading protobuf:', err); + return reject(err); + } + + try { + const Book = root.lookupType('com.book.BookStore'); + const payload = { name: 'Test name', books: { 0: 'book 1', 1: 'book 2' } }; + const message = Book.create(payload); + const rawValue = Book.encode(message).finish(); + + const value = Buffer.from(await brotli.compress(rawValue)); + this.createString(prefix, value); + resolve(); + } catch (error) { + reject(error); + } + }); + }); + } + + private createString(prefix: string, value: Buffer): void { + this.client.set(`${prefix}:string`, value, (error: Error | null) => { + if (error) { + console.error(`Error saving key ${prefix}:`, error); + throw error; + } + console.log(`Key ${prefix} successfully saved.`); + }); + } +} diff --git a/tests/e2e/package.json b/tests/e2e/package.json index 37a83d21ac..9d3c1e7b20 100644 --- a/tests/e2e/package.json +++ b/tests/e2e/package.json @@ -13,7 +13,7 @@ "build:ui": "yarn --cwd ../../ build:ui", "redis:last": "docker run --name redis-last-version -p 7777:6379 -d redislabs/redismod", "start:app": "cross-env yarn start:api", - "test:chrome": "testcafe --compiler-options typescript.configPath=tsconfig.testcafe.json --cache --allow-insecure-localhost --disable-multiple-windows --concurrency 1 chrome tests/ -r html:./report/report.html,spec -e -s takeOnFails=true,path=report/screenshots/,pathPattern=${OS}_${BROWSER}/${DATE}_${TIME}/${FIXTURE}_${TEST}_${FILE_INDEX}.png", + "test:chrome": "testcafe --compiler-options typescript.configPath=tsconfig.testcafe.json --cache --disable-multiple-windows --concurrency 1 chrome:--disable-search-engine-choice-screen tests/ -r html:./report/report.html,spec -e -s takeOnFails=true,path=report/screenshots/,pathPattern=${OS}_${BROWSER}/${DATE}_${TIME}/${FIXTURE}_${TEST}_${FILE_INDEX}.png", "test:chrome:ci": "ts-node ./web.runner.ts", "test": "yarn test:chrome", "lint": "eslint . --ext .ts,.js,.tsx,.jsx", @@ -25,8 +25,12 @@ "author": "", "dependencies": { "axios": "^1.6.0", + "brotli-unicode": "^1.0.2", "cli-argument-parser": "0.4.5", - "js-yaml": "^4.1.0" + "fflate": "^0.8.2", + "js-yaml": "^4.1.0", + "msgpackr": "^1.11.0", + "protobufjs": "^7.4.0" }, "resolutions": { "@types/lodash": "4.14.192", diff --git a/tests/e2e/test-data/decompressors/awesome.proto b/tests/e2e/test-data/decompressors/awesome.proto new file mode 100644 index 0000000000..3c2ba30775 --- /dev/null +++ b/tests/e2e/test-data/decompressors/awesome.proto @@ -0,0 +1,26 @@ +syntax = "proto3"; + +package com.book; + +message Book { + int64 isbn = 1; + string title = 2; + string author = 3; +} + + +message GetBookViaAuthor { + string author = 1; +} + +service BookService { + rpc GetBook (GetBookRequest) returns (Book) {} + rpc GetBooksViaAuthor (GetBookViaAuthor) returns (stream Book) {} + rpc GetGreatestBook (stream GetBookRequest) returns (Book) {} + rpc GetBooks (stream GetBookRequest) returns (stream Book) {} +} + +message BookStore { + string name = 1; + map books = 2; +} diff --git a/tests/e2e/test-data/decompressors/pickleFile1.pickle b/tests/e2e/test-data/decompressors/pickleFile1.pickle new file mode 100644 index 0000000000..15b18437ef --- /dev/null +++ b/tests/e2e/test-data/decompressors/pickleFile1.pickle @@ -0,0 +1,7 @@ +(lp0 +S'Привет 漢字' +p1 +aI23123 +aS'\xae\xae' +p2 +a. \ No newline at end of file diff --git a/tests/e2e/test-data/decompressors/test_annotated_obj.ser b/tests/e2e/test-data/decompressors/test_annotated_obj.ser new file mode 100644 index 0000000000000000000000000000000000000000..25aa1b7b340f9f1a2244ec49f70d329b7b0a8a37 GIT binary patch literal 66 zcmZ4UmVvdnh(Vz^wJ0+&C$lQCBr`wHB{er+&oM7AzXZ$;Ni8m6fB+^Y21ZW?w!G5Z Mq|~B{0-#_N0PwmKuK)l5 literal 0 HcmV?d00001 diff --git a/tests/e2e/test-data/decompressors/test_serialised_obj.ser b/tests/e2e/test-data/decompressors/test_serialised_obj.ser new file mode 100644 index 0000000000000000000000000000000000000000..8a6f0d999c6f799c2288340c199a2acd0ac1db2a GIT binary patch literal 125 zcmZ4UmVvdnh=Id3w;(6KGBuScuEZq$n2-$<1G6UsTV82yQfiS81AAghN>OTYaS4Nv zPgY`CqJB%nMt*j7qJnp6VxEqI bBhZwLl0=1o)YPI92F{?=%EUYc$DB+6iLNHE literal 0 HcmV?d00001 diff --git a/tests/e2e/test-data/decompressors/vector.json b/tests/e2e/test-data/decompressors/vector.json new file mode 100644 index 0000000000..11cc8c140d --- /dev/null +++ b/tests/e2e/test-data/decompressors/vector.json @@ -0,0 +1,978 @@ +[ + 8, + 61, + 76, + 188, + 93, + 150, + 56, + 188, + 206, + 238, + 71, + 60, + 76, + 184, + 215, + 188, + 60, + 42, + 181, + 187, + 187, + 82, + 208, + 60, + 208, + 184, + 35, + 60, + 247, + 94, + 235, + 188, + 2, + 247, + 66, + 188, + 175, + 91, + 237, + 188, + 171, + 101, + 162, + 60, + 2, + 247, + 194, + 58, + 172, + 169, + 27, + 188, + 124, + 56, + 96, + 187, + 242, + 104, + 32, + 187, + 97, + 152, + 72, + 188, + 20, + 201, + 222, + 60, + 249, + 40, + 199, + 188, + 180, + 185, + 128, + 60, + 108, + 48, + 160, + 188, + 42, + 249, + 141, + 60, + 124, + 41, + 147, + 59, + 211, + 91, + 40, + 188, + 9, + 22, + 117, + 60, + 125, + 163, + 176, + 60, + 9, + 156, + 215, + 60, + 97, + 152, + 200, + 60, + 145, + 24, + 81, + 188, + 131, + 84, + 10, + 60, + 26, + 244, + 213, + 187, + 70, + 141, + 96, + 59, + 101, + 154, + 88, + 60, + 28, + 41, + 130, + 187, + 170, + 128, + 52, + 188, + 39, + 86, + 9, + 189, + 129, + 16, + 17, + 189, + 193, + 30, + 188, + 187, + 41, + 154, + 2, + 189, + 143, + 197, + 10, + 60, + 143, + 224, + 28, + 188, + 177, + 10, + 183, + 60, + 101, + 154, + 88, + 60, + 1, + 152, + 55, + 186, + 223, + 204, + 40, + 188, + 213, + 25, + 63, + 187, + 109, + 21, + 142, + 60, + 203, + 209, + 37, + 60, + 168, + 167, + 139, + 188, + 212, + 64, + 150, + 188, + 247, + 228, + 205, + 60, + 211, + 225, + 138, + 60, + 152, + 67, + 200, + 59, + 139, + 222, + 140, + 188, + 57, + 13, + 19, + 189, + 138, + 115, + 188, + 59, + 68, + 180, + 55, + 188, + 168, + 167, + 139, + 60, + 236, + 61, + 169, + 59, + 13, + 158, + 231, + 59, + 231, + 208, + 200, + 187, + 56, + 55, + 242, + 59, + 113, + 157, + 0, + 187, + 125, + 163, + 176, + 188, + 255, + 95, + 131, + 60, + 247, + 79, + 158, + 59, + 106, + 7, + 185, + 58, + 150, + 121, + 236, + 187, + 16, + 184, + 129, + 187, + 169, + 48, + 118, + 185, + 7, + 88, + 222, + 60, + 19, + 228, + 112, + 60, + 124, + 148, + 60, + 136, + 59, + 8, + 60, + 3, + 220, + 48, + 60, + 122, + 244, + 230, + 58, + 194, + 3, + 170, + 60, + 122, + 122, + 201, + 60, + 77, + 35, + 40, + 59, + 25, + 161, + 143, + 60, + 3, + 235, + 253, + 188, + 201, + 19, + 143, + 60, + 30, + 124, + 200, + 187, + 9, + 7, + 40, + 60, + 221, + 29, + 223, + 188, + 148, + 65, + 184, + 60, + 171, + 211, + 250, + 188, + 157, + 164, + 227, + 59, + 59, + 96, + 89, + 60, + 242, + 131, + 178, + 60, + 240, + 63, + 57, + 188, + 123, + 217, + 84, + 58, + 60, + 176, + 23, + 188, + 172, + 169, + 155, + 60, + 241, + 9, + 149, + 187, + 126, + 124, + 217, + 59, + 66, + 124, + 131, + 188, + 108, + 48, + 160, + 186, + 149, + 148, + 254, + 59, + 170, + 235, + 4, + 189, + 182, + 134, + 228, + 59, + 226, + 111, + 173, + 60, + 96, + 57, + 189, + 59, + 11, + 224, + 80, + 188, + 195, + 71, + 35, + 186, + 19, + 91, + 6, + 189, + 158, + 110, + 63, + 59, + 118, + 254, + 155, + 188, + 131, + 221, + 244, + 187, + 197, + 166, + 174, + 60, + 58, + 135, + 176, + 60, + 103, + 100, + 52, + 189, + 218, + 244, + 247, + 188, + 56, + 55, + 114, + 59, + 212, + 186, + 179, + 187, + 36, + 179, + 132, + 188, + 201, + 19, + 59, + 245, + 17, + 145, + 42, + 189, + 107, + 224, + 225, + 187, + 136, + 59, + 136, + 184, + 207, + 211, + 181, + 188, + 63, + 98, + 105, + 186, + 75, + 223, + 174, + 187, + 213, + 159, + 161, + 188, + 235, + 222, + 157, + 60, + 165, + 31, + 25, + 60, + 254, + 122, + 21, + 61, + 177, + 37, + 73, + 188, + 15, + 104, + 67, + 59, + 233, + 20, + 66, + 189, + 3, + 86, + 78, + 59, + 166, + 126, + 164, + 60, + 147, + 92, + 74, + 188, + 195, + 71, + 163, + 59, + 138, + 8, + 236, + 60, + 166, + 248, + 193, + 187, + 96, + 191, + 159, + 188, + 71, + 221, + 30, + 188, + 58, + 135, + 48, + 190, + 216, + 188, + 195, + 60, + 184, + 175, + 203, + 59, + 78, + 237, + 131, + 188, + 240, + 63, + 57, + 60, + 33, + 138, + 157, + 59, + 171, + 89, + 93, + 60, + 207, + 211, + 181, + 60, + 202, + 7, + 202, + 188, + 185, + 41, + 105, + 188, + 240, + 63, + 185, + 186, + 206, + 9, + 218, + 59, + 75, + 211, + 233, + 188, + 166, + 141, + 241, + 187, + 134, + 247, + 142, + 60, + 48, + 51, + 33, + 188, + 4, + 208, + 107, + 188, + 104, + 46, + 144, + 186, + 29, + 151, + 90, + 60, + 91, + 216, + 33, + 188, + 209, + 145, + 76, + 188, + 221, + 29, + 223, + 60, + 187, + 235, + 195, + 139, + 187, + 162, + 124, + 20, + 189, + 169, + 33, + 41, + 60, + 66, + 124, + 131, + 188, + 241, + 158, + 68, + 188, + 169, + 21, + 100, + 188, + 137, + 35, + 126, + 187, + 151, + 228, + 188, + 60, + 211, + 91, + 40, + 187, + 115, + 213, + 52, + 187, + 71, + 87, + 188, + 59, + 235, + 237, + 234, + 188, + 43, + 210, + 54, + 60, + 96, + 57, + 61, + 60, + 143, + 90, + 186, + 188, + 231, + 86, + 171, + 188, + 202, + 7, + 74, + 60, + 131, + 84, + 138, + 59, + 96, + 191, + 31, + 187, + 204, + 197, + 96, + 60, + 125, + 178, + 125, + 187, + 189, + 162, + 14, + 61, + 122, + 244, + 230, + 59, + 169, + 21, + 228, + 59, + 27, + 217, + 195, + 188, + 122, + 244, + 230, + 188, + 40, + 62, + 255, + 187, + 70, + 99, + 1, + 60, + 81, + 10, + 166, + 188, + 197, + 32, + 76, + 189, + 24, + 66, + 132, + 187, + 66, + 124, + 3, + 188, + 1, + 30, + 26, + 188, + 34, + 233, + 40, + 188, + 217, + 27, + 207, + 60, + 64, + 44, + 69, + 188, + 226, + 245, + 143, + 61, + 7, + 73, + 17, + 61, + 36, + 72, + 52, + 187, + 95, + 96, + 20, + 59, + 251, + 81, + 174, + 59, + 74, + 116, + 222, + 59, + 97, + 18, + 230, + 59, + 228, + 179, + 166, + 188, + 102, + 5, + 169, + 188, + 64, + 44, + 197, + 59, + 60, + 42, + 181, + 60, + 180, + 51, + 158, + 188, + 247, + 228, + 205, + 60, + 231, + 220, + 141, + 188, + 192, + 191, + 176, + 188, + 158, + 110, + 191, + 188, + 118, + 227, + 9, + 188, + 161, + 44, + 214, + 60, + 239, + 90, + 75, + 188, + 31, + 85, + 113, + 188, + 73, + 6, + 6, + 60, + 143, + 197, + 138, + 59, + 122, + 15, + 121, + 60, + 25, + 161, + 15, + 188, + 80, + 198, + 44, + 188, + 199, + 73, + 179, + 187, + 250, + 120, + 133, + 186, + 132, + 179, + 21, + 188, + 24, + 176, + 220, + 187, + 106, + 236, + 38, + 189, + 29, + 136, + 141, + 60, + 149, + 148, + 126, + 188, + 91, + 216, + 161, + 60, + 78, + 130, + 179, + 188, + 35, + 221, + 227, + 60, + 171, + 101, + 34, + 187, + 85, + 12, + 182, + 59, + 103, + 73, + 34, + 59, + 199, + 100, + 69, + 60, + 17, + 23, + 141, + 60, + 171, + 101, + 34, + 189, + 3, + 86, + 206, + 187, + 20, + 186, + 17, + 189, + 112, + 65, + 253, + 188, + 246, + 240, + 18, + 61, + 246, + 121, + 253, + 60, + 225, + 165, + 209, + 188, + 49, + 24, + 192, + 188, + 170, + 250, + 81, + 59 +] \ No newline at end of file diff --git a/tests/e2e/yarn.lock b/tests/e2e/yarn.lock index 9f36c7bd4e..6b9cb54120 100644 --- a/tests/e2e/yarn.lock +++ b/tests/e2e/yarn.lock @@ -1377,6 +1377,36 @@ "@jridgewell/resolve-uri" "^3.1.0" "@jridgewell/sourcemap-codec" "^1.4.14" +"@msgpackr-extract/msgpackr-extract-darwin-arm64@3.0.3": + version "3.0.3" + resolved "https://registry.yarnpkg.com/@msgpackr-extract/msgpackr-extract-darwin-arm64/-/msgpackr-extract-darwin-arm64-3.0.3.tgz#9edec61b22c3082018a79f6d1c30289ddf3d9d11" + integrity sha512-QZHtlVgbAdy2zAqNA9Gu1UpIuI8Xvsd1v8ic6B2pZmeFnFcMWiPLfWXh7TVw4eGEZ/C9TH281KwhVoeQUKbyjw== + +"@msgpackr-extract/msgpackr-extract-darwin-x64@3.0.3": + version "3.0.3" + resolved "https://registry.yarnpkg.com/@msgpackr-extract/msgpackr-extract-darwin-x64/-/msgpackr-extract-darwin-x64-3.0.3.tgz#33677a275204898ad8acbf62734fc4dc0b6a4855" + integrity sha512-mdzd3AVzYKuUmiWOQ8GNhl64/IoFGol569zNRdkLReh6LRLHOXxU4U8eq0JwaD8iFHdVGqSy4IjFL4reoWCDFw== + +"@msgpackr-extract/msgpackr-extract-linux-arm64@3.0.3": + version "3.0.3" + resolved "https://registry.yarnpkg.com/@msgpackr-extract/msgpackr-extract-linux-arm64/-/msgpackr-extract-linux-arm64-3.0.3.tgz#19edf7cdc2e7063ee328403c1d895a86dd28f4bb" + integrity sha512-YxQL+ax0XqBJDZiKimS2XQaf+2wDGVa1enVRGzEvLLVFeqa5kx2bWbtcSXgsxjQB7nRqqIGFIcLteF/sHeVtQg== + +"@msgpackr-extract/msgpackr-extract-linux-arm@3.0.3": + version "3.0.3" + resolved "https://registry.yarnpkg.com/@msgpackr-extract/msgpackr-extract-linux-arm/-/msgpackr-extract-linux-arm-3.0.3.tgz#94fb0543ba2e28766c3fc439cabbe0440ae70159" + integrity sha512-fg0uy/dG/nZEXfYilKoRe7yALaNmHoYeIoJuJ7KJ+YyU2bvY8vPv27f7UKhGRpY6euFYqEVhxCFZgAUNQBM3nw== + +"@msgpackr-extract/msgpackr-extract-linux-x64@3.0.3": + version "3.0.3" + resolved "https://registry.yarnpkg.com/@msgpackr-extract/msgpackr-extract-linux-x64/-/msgpackr-extract-linux-x64-3.0.3.tgz#4a0609ab5fe44d07c9c60a11e4484d3c38bbd6e3" + integrity sha512-cvwNfbP07pKUfq1uH+S6KJ7dT9K8WOE4ZiAcsrSes+UY55E/0jLYc+vq+DO7jlmqRb5zAggExKm0H7O/CBaesg== + +"@msgpackr-extract/msgpackr-extract-win32-x64@3.0.3": + version "3.0.3" + resolved "https://registry.yarnpkg.com/@msgpackr-extract/msgpackr-extract-win32-x64/-/msgpackr-extract-win32-x64-3.0.3.tgz#0aa5502d547b57abfc4ac492de68e2006e417242" + integrity sha512-x0fWaQtYp4E6sktbsdAqnehxDgEc/VwM7uLsRCYWaiGu0ykYdZPiS8zCWdnjHwyiumousxfBm4SO31eXqwEZhQ== + "@nodelib/fs.scandir@2.1.5": version "2.1.5" resolved "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz" @@ -1414,6 +1444,59 @@ mkdirp "^1.0.4" rimraf "^3.0.2" +"@protobufjs/aspromise@^1.1.1", "@protobufjs/aspromise@^1.1.2": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@protobufjs/aspromise/-/aspromise-1.1.2.tgz#9b8b0cc663d669a7d8f6f5d0893a14d348f30fbf" + integrity sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ== + +"@protobufjs/base64@^1.1.2": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@protobufjs/base64/-/base64-1.1.2.tgz#4c85730e59b9a1f1f349047dbf24296034bb2735" + integrity sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg== + +"@protobufjs/codegen@^2.0.4": + version "2.0.4" + resolved "https://registry.yarnpkg.com/@protobufjs/codegen/-/codegen-2.0.4.tgz#7ef37f0d010fb028ad1ad59722e506d9262815cb" + integrity sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg== + +"@protobufjs/eventemitter@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz#355cbc98bafad5978f9ed095f397621f1d066b70" + integrity sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q== + +"@protobufjs/fetch@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@protobufjs/fetch/-/fetch-1.1.0.tgz#ba99fb598614af65700c1619ff06d454b0d84c45" + integrity sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ== + dependencies: + "@protobufjs/aspromise" "^1.1.1" + "@protobufjs/inquire" "^1.1.0" + +"@protobufjs/float@^1.0.2": + version "1.0.2" + resolved "https://registry.yarnpkg.com/@protobufjs/float/-/float-1.0.2.tgz#5e9e1abdcb73fc0a7cb8b291df78c8cbd97b87d1" + integrity sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ== + +"@protobufjs/inquire@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@protobufjs/inquire/-/inquire-1.1.0.tgz#ff200e3e7cf2429e2dcafc1140828e8cc638f089" + integrity sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q== + +"@protobufjs/path@^1.1.2": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@protobufjs/path/-/path-1.1.2.tgz#6cc2b20c5c9ad6ad0dccfd21ca7673d8d7fbf68d" + integrity sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA== + +"@protobufjs/pool@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@protobufjs/pool/-/pool-1.1.0.tgz#09fd15f2d6d3abfa9b65bc366506d6ad7846ff54" + integrity sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw== + +"@protobufjs/utf8@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@protobufjs/utf8/-/utf8-1.1.0.tgz#a777360b5b39a1a2e5106f8e858f2fd2d060c570" + integrity sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw== + "@testim/chrome-version@^1.1.4": version "1.1.4" resolved "https://registry.npmjs.org/@testim/chrome-version/-/chrome-version-1.1.4.tgz" @@ -1514,7 +1597,7 @@ resolved "https://registry.npmjs.org/@types/minimatch/-/minimatch-5.1.2.tgz" integrity sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA== -"@types/node@*", "@types/node@20.3.1", "@types/node@^20.14.5": +"@types/node@*", "@types/node@20.3.1", "@types/node@>=13.7.0", "@types/node@^17.0.40", "@types/node@^20.14.5": version "20.3.1" resolved "https://registry.yarnpkg.com/@types/node/-/node-20.3.1.tgz#e8a83f1aa8b649377bb1fb5d7bac5cb90e784dfe" integrity sha512-EhcH/wvidPy1WeML3TtYFGR83UzjxeWRen9V402T8aUGYsCHOmfoisV3ZSg03gAFIbLq8TnWOJ0f4cALtnSEUg== @@ -1995,6 +2078,13 @@ balanced-match@^1.0.0: resolved "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz" integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== +base-unicode@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/base-unicode/-/base-unicode-1.0.0.tgz#44b61fd4460b18f6d47ae6f5ea95a45b16a4885a" + integrity sha512-9y/0iVN7k3NyH0E4oYD/1qZceUVE180YcRRqhsQVNzazPcuRjr67SjUzl/wdhLaVmzjIMEjE5pDH7xb6X9kBFA== + dependencies: + buffer "^6.0.3" + base64-js@^1.3.1: version "1.5.1" resolved "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz" @@ -2053,6 +2143,27 @@ braces@^3.0.2: dependencies: fill-range "^7.0.1" +brotli-compress@^1.3.3: + version "1.3.3" + resolved "https://registry.yarnpkg.com/brotli-compress/-/brotli-compress-1.3.3.tgz#fe3b50b6234bfbc8e26a137bffff2a07e2a4efe9" + integrity sha512-cwKOmzEuKqUmRxXDdZimiNoXRRr7AQKMSubJSbYA9FXk+LTPT3fBGpHU8VZRZZctAJ5OCeXGK9PzPpZ1vD0pDA== + dependencies: + "@types/node" "^17.0.40" + brotli-wasm "1.2.0" + +brotli-unicode@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/brotli-unicode/-/brotli-unicode-1.0.2.tgz#25e53a7fdc543337768e90fd59a94b6eb55ea6cc" + integrity sha512-eqO2kauz48Raqi0I8c4WOhvfr5GAtpHhCvegHRTY00zyn6pEP8jo5nHrwtAJKO68j1ZFi4zel6JrwBz60Z5d3g== + dependencies: + base-unicode "^1.0.0" + brotli-compress "^1.3.3" + +brotli-wasm@1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/brotli-wasm/-/brotli-wasm-1.2.0.tgz#0f99b97b0020c8152308c277388aecf2a06b6e32" + integrity sha512-PdDi7awF36zFujZyFJb9UNrP1l+If7iCgXhLKE1SpwqFQSK2yc7w2dysOmME7p325yQaZNvae7ruzypB3YhFxA== + browserslist@^4.22.2, browserslist@^4.22.3, browserslist@^4.23.0: version "4.23.0" resolved "https://registry.npmjs.org/browserslist/-/browserslist-4.23.0.tgz" @@ -2081,6 +2192,14 @@ buffer@^5.5.0: base64-js "^1.3.1" ieee754 "^1.1.13" +buffer@^6.0.3: + version "6.0.3" + resolved "https://registry.yarnpkg.com/buffer/-/buffer-6.0.3.tgz#2ace578459cc8fbe2a70aaa8f52ee63b6a74c6c6" + integrity sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA== + dependencies: + base64-js "^1.3.1" + ieee754 "^1.2.1" + cacache@^15.2.0: version "15.3.0" resolved "https://registry.npmjs.org/cacache/-/cacache-15.3.0.tgz" @@ -2527,6 +2646,11 @@ detect-libc@^2.0.0: resolved "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.2.tgz" integrity sha512-UX6sGumvvqSaXgdKGUsgZWqcUyIXZ/vZTrlRT/iobiKhGL0zL4d3osHj3uqllWJK+i+sixDS/3COVEOFbupFyw== +detect-libc@^2.0.1: + version "2.0.3" + resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-2.0.3.tgz#f0cd503b40f9939b894697d19ad50895e30cf700" + integrity sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw== + device-specs@^1.0.0: version "1.0.1" resolved "https://registry.npmjs.org/device-specs/-/device-specs-1.0.1.tgz" @@ -3056,6 +3180,11 @@ fd-slicer@~1.1.0: dependencies: pend "~1.2.0" +fflate@^0.8.2: + version "0.8.2" + resolved "https://registry.yarnpkg.com/fflate/-/fflate-0.8.2.tgz#fc8631f5347812ad6028bbe4a2308b2792aa1dea" + integrity sha512-cPJU47OaAoCbg0pBvzsgpTPhmhqI5eJjh/JIu8tPj5q+T7iLvW/JAYUqmE7KOB4R1ZyEhzBaIQpQpardBF5z8A== + file-entry-cache@^6.0.1: version "6.0.1" resolved "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz" @@ -3595,7 +3724,7 @@ iconv-lite@^0.6.2: dependencies: safer-buffer ">= 2.1.2 < 3.0.0" -ieee754@^1.1.13: +ieee754@^1.1.13, ieee754@^1.2.1: version "1.2.1" resolved "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz" integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA== @@ -4202,6 +4331,11 @@ log-update-async-hook@^2.0.7: onetime "^2.0.1" wrap-ansi "^7.0.0" +long@^5.0.0: + version "5.2.3" + resolved "https://registry.yarnpkg.com/long/-/long-5.2.3.tgz#a3ba97f3877cf1d778eccbcb048525ebb77499e1" + integrity sha512-lcHwpNoggQTObv5apGNCTdJrO69eHOZMi4BNC+rTLER8iHAqGrUVeLh/irVIM7zTw2bOXA8T6uNPeujwOLg/2Q== + lru-cache@2.6.3: version "2.6.3" resolved "https://registry.npmjs.org/lru-cache/-/lru-cache-2.6.3.tgz" @@ -4474,6 +4608,27 @@ ms@^2.0.0, ms@^2.1.1: resolved "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz" integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== +msgpackr-extract@^3.0.2: + version "3.0.3" + resolved "https://registry.yarnpkg.com/msgpackr-extract/-/msgpackr-extract-3.0.3.tgz#e9d87023de39ce714872f9e9504e3c1996d61012" + integrity sha512-P0efT1C9jIdVRefqjzOQ9Xml57zpOXnIuS+csaB4MdZbTdmGDLo8XhzBG1N7aO11gKDDkJvBLULeFTo46wwreA== + dependencies: + node-gyp-build-optional-packages "5.2.2" + optionalDependencies: + "@msgpackr-extract/msgpackr-extract-darwin-arm64" "3.0.3" + "@msgpackr-extract/msgpackr-extract-darwin-x64" "3.0.3" + "@msgpackr-extract/msgpackr-extract-linux-arm" "3.0.3" + "@msgpackr-extract/msgpackr-extract-linux-arm64" "3.0.3" + "@msgpackr-extract/msgpackr-extract-linux-x64" "3.0.3" + "@msgpackr-extract/msgpackr-extract-win32-x64" "3.0.3" + +msgpackr@^1.11.0: + version "1.11.0" + resolved "https://registry.yarnpkg.com/msgpackr/-/msgpackr-1.11.0.tgz#8321d52333048cadc749f56385e3231e65337091" + integrity sha512-I8qXuuALqJe5laEBYoFykChhSXLikZmUhccjGsPuSJ/7uPip2TJ7lwdIQwWSAi0jGZDXv4WOP8Qg65QZRuXxXw== + optionalDependencies: + msgpackr-extract "^3.0.2" + mustache@^2.1.1, mustache@^2.1.2, mustache@^2.2.1, mustache@^2.3.0: version "2.3.2" resolved "https://registry.npmjs.org/mustache/-/mustache-2.3.2.tgz" @@ -4516,6 +4671,13 @@ node-addon-api@^7.0.0: resolved "https://registry.npmjs.org/node-addon-api/-/node-addon-api-7.1.0.tgz" integrity sha512-mNcltoe1R8o7STTegSOHdnJNN7s5EUvhoS7ShnTHDyOSd+8H+UdWODq6qSv67PjC8Zc5JRT8+oLAMCr0SIXw7g== +node-gyp-build-optional-packages@5.2.2: + version "5.2.2" + resolved "https://registry.yarnpkg.com/node-gyp-build-optional-packages/-/node-gyp-build-optional-packages-5.2.2.tgz#522f50c2d53134d7f3a76cd7255de4ab6c96a3a4" + integrity sha512-s+w+rBWnpTMwSFbaE0UXsRlg7hU4FjekKU4eyAih5T8nJuNZT1nNsskXpxmeqSK9UzkBl6UgRlnKc8hz8IEqOw== + dependencies: + detect-libc "^2.0.1" + node-gyp@8.x: version "8.4.1" resolved "https://registry.npmjs.org/node-gyp/-/node-gyp-8.4.1.tgz" @@ -4973,6 +5135,24 @@ prompts@^2.4.2: kleur "^3.0.3" sisteransi "^1.0.5" +protobufjs@^7.4.0: + version "7.4.0" + resolved "https://registry.yarnpkg.com/protobufjs/-/protobufjs-7.4.0.tgz#7efe324ce9b3b61c82aae5de810d287bc08a248a" + integrity sha512-mRUWCc3KUU4w1jU8sGxICXH/gNS94DvI1gxqDvBzhj1JpcsimQkYiOJfwsPUykUI5ZaspFbSgmBLER8IrQ3tqw== + dependencies: + "@protobufjs/aspromise" "^1.1.2" + "@protobufjs/base64" "^1.1.2" + "@protobufjs/codegen" "^2.0.4" + "@protobufjs/eventemitter" "^1.1.0" + "@protobufjs/fetch" "^1.1.0" + "@protobufjs/float" "^1.0.2" + "@protobufjs/inquire" "^1.1.0" + "@protobufjs/path" "^1.1.2" + "@protobufjs/pool" "^1.1.0" + "@protobufjs/utf8" "^1.1.0" + "@types/node" ">=13.7.0" + long "^5.0.0" + proxy-agent@^6.4.0: version "6.4.0" resolved "https://registry.npmjs.org/proxy-agent/-/proxy-agent-6.4.0.tgz" From 57f4249bbc758b196937c42e29491e7affe665b4 Mon Sep 17 00:00:00 2001 From: mariasergeenko Date: Thu, 3 Oct 2024 11:55:07 +0200 Subject: [PATCH 093/256] add gzip and lz4 --- .../base-decompressors-populator.ts | 64 +++++++++ .../brotli-database-populator.ts | 73 +++------- .../decompressors/gzip-database-populator.ts | 129 ++++++++++++++++++ .../decompressors/lz4-database-populator.ts | 116 ++++++++++++++++ tests/e2e/package.json | 1 + tests/e2e/yarn.lock | 5 + 6 files changed, 335 insertions(+), 53 deletions(-) create mode 100644 tests/e2e/helpers/decompressors/base-decompressors-populator.ts rename tests/e2e/helpers/{ => decompressors}/brotli-database-populator.ts (65%) create mode 100644 tests/e2e/helpers/decompressors/gzip-database-populator.ts create mode 100644 tests/e2e/helpers/decompressors/lz4-database-populator.ts diff --git a/tests/e2e/helpers/decompressors/base-decompressors-populator.ts b/tests/e2e/helpers/decompressors/base-decompressors-populator.ts new file mode 100644 index 0000000000..a003ff695d --- /dev/null +++ b/tests/e2e/helpers/decompressors/base-decompressors-populator.ts @@ -0,0 +1,64 @@ +import { createClient } from 'redis'; + +export abstract class BaseDatabasePopulator { + private client: ReturnType; + + protected abstract createCompressedKeys(): Promise; + + constructor(private host: string, private port: string) { + const dbConf = { port: Number.parseInt(port), host, username: 'default' }; + this.client = createClient(dbConf); + + this.client.on('error', (error: string) => { + throw new Error(`Redis connection error: ${error}`); + }); + } + + public async populateDB(): Promise { + this.client.on('connect', async () => { + console.log('Connected to Redis'); + try { + await this.createCompressedKeys(); + } catch (error) { + console.error('Error during key creation:', error); + } finally { + await this.client.quit(); + } + }); + } + + protected async createHash(prefix: string, value: Buffer, onlyOneItem = false, value2 = ''): Promise { + let fields: string[] = []; + + const randomNumber = Array.from({ length: 5 }).map(() => Math.random()); + const field = `${value.toString()}:${randomNumber.toString()}`; + const fieldValue = `${value.toString()}:${randomNumber.toString()}`; + fields.push(field, fieldValue); + + if (onlyOneItem) { + fields = [value.toString(), value.toString()]; + } + + if (value2) { + fields.push(value2, value2); + } + + try { + await this.client.hset(`${prefix}:hash`, ...fields); + console.log(`Hash created with prefix: ${prefix}`); + } catch (error) { + console.error(`Error creating hash with prefix ${prefix}:`, error); + throw error; + } + } + + protected async createString(prefix: string, value: Buffer): Promise { + this.client.set(`${prefix}:string`, value, (error: Error | null) => { + if (error) { + console.error(`Error saving key ${prefix}:`, error); + throw error; + } + console.log(`Key ${prefix} successfully saved.`); + }); + } +} diff --git a/tests/e2e/helpers/brotli-database-populator.ts b/tests/e2e/helpers/decompressors/brotli-database-populator.ts similarity index 65% rename from tests/e2e/helpers/brotli-database-populator.ts rename to tests/e2e/helpers/decompressors/brotli-database-populator.ts index 4f5a4f9f13..970fa8a9b3 100644 --- a/tests/e2e/helpers/brotli-database-populator.ts +++ b/tests/e2e/helpers/decompressors/brotli-database-populator.ts @@ -1,40 +1,16 @@ -import { createClient } from 'redis'; import * as proto from 'protobufjs'; import { pack as msgpackrPack } from 'msgpackr'; import * as brotli from 'brotli-unicode'; import * as fflate from 'fflate'; import * as fs from 'fs'; +import { BaseDatabasePopulator } from './base-decompressors-populator'; const COMPRESSED_PREFIX = 'Comp'; const BROTLI_PREFIX = 'BROTLI'; -export class BrotliDatabasePopulator { - private client: ReturnType; +export class BrotliDatabasePopulator extends BaseDatabasePopulator { - constructor(private host: string, private port: string) { - const dbConf = { port: Number.parseInt(port), host, username: 'default' }; - this.client = createClient(dbConf); - - this.client.on('error', (error: string) => { - throw new Error(`Redis connection error: ${error}`); - }); - } - - public async populateDB(): Promise { - this.client.on('connect', async () => { - console.log('Connected to Redis'); - - try { - await this.createBrotliCompressedKeys(); - } catch (error) { - console.error('Error during key creation:', error); - } finally { - await this.client.quit(); - } - }); - } - - private async createBrotliCompressedKeys(): Promise { + protected async createCompressedKeys(): Promise { await this.createBrotliUnicodeKeys(); await this.createBrotliASCIIKeys(); await this.createBrotliVectorKeys(); @@ -52,7 +28,7 @@ export class BrotliDatabasePopulator { const rawValue = '漢字'; const buf = encoder.encode(rawValue); const value = Buffer.from(await brotli.compress(buf)); - this.createString(prefix, value); + await this.createString(prefix, value); } private async createBrotliASCIIKeys() { @@ -60,7 +36,7 @@ export class BrotliDatabasePopulator { const rawValue = '\xac\xed\x00\x05t\x0a4102'; const buf = fflate.strToU8(rawValue); const value = Buffer.from(await brotli.compress(buf)); - this.createString(prefix, value); + await this.createString(prefix, value); } private async createBrotliVectorKeys() { @@ -68,7 +44,7 @@ export class BrotliDatabasePopulator { const rawValue = JSON.parse(fs.readFileSync('./test-data/decompressors/vector.json', 'utf8')); const buf = fflate.strToU8(rawValue); const value = Buffer.from(await brotli.compress(buf)); - this.createString(prefix, value); + await this.createString(prefix, value); } private async createBrotliJSONKeys() { @@ -76,7 +52,7 @@ export class BrotliDatabasePopulator { const rawValue = '{"test":"test"}'; const buf = fflate.strToU8(rawValue); const value = Buffer.from(await brotli.compress(buf)); - this.createString(prefix, value); + await this.createString(prefix, value); } private async createBrotliPHPUnserializedJSONKeys() { @@ -84,15 +60,15 @@ export class BrotliDatabasePopulator { const rawValue = 'a:2:{i:0;s:12:"Sample array";i:1;a:2:{i:0;s:5:"Apple";i:1;s:6:"Orange";}}'; const buf = fflate.strToU8(rawValue); const value = Buffer.from(await brotli.compress(buf)); - this.createString(prefix, value); + await this.createString(prefix, value); } private async createBrotliPickleKeys() { - const prefix = `${COMPRESSED_PREFIX}:${BROTLI_PREFIX}:Pickle`; - const rawValue = fs.readFileSync('./test-data/decompressors/pickleFile1.pickle'); - const value = Buffer.from(await brotli.compress(rawValue)); - this.createString(prefix, value); -}; + const prefix = `${COMPRESSED_PREFIX}:${BROTLI_PREFIX}:Pickle`; + const rawValue = fs.readFileSync('./test-data/decompressors/pickleFile1.pickle'); + const value = Buffer.from(await brotli.compress(rawValue)); + await this.createString(prefix, value); + }; private async createBrotliJavaSerializedObjectKeys() { const prefix = `${COMPRESSED_PREFIX}:${BROTLI_PREFIX}:Java`; @@ -102,8 +78,8 @@ export class BrotliDatabasePopulator { const value = Buffer.from(await brotli.compress(rawValue)); const value2 = Buffer.from(await brotli.compress(rawValue2)); - this.createString(prefix, value); - this.createString(prefix, value2); + await this.createString(prefix, value); + await this.createString(prefix, value2); } private async createBrotliMsgpackKeys(): Promise { @@ -111,11 +87,11 @@ export class BrotliDatabasePopulator { const rawValue = msgpackrPack({ hello: 'World', array: [1, 2], - obj: { test: 'test' }, + obj: {test: 'test'}, boolean: false, }); const value = Buffer.from(await brotli.compress(rawValue)); - this.createString(prefix, value); + await this.createString(prefix, value); } private createBrotliProtobufKeys(): Promise { @@ -129,12 +105,12 @@ export class BrotliDatabasePopulator { try { const Book = root.lookupType('com.book.BookStore'); - const payload = { name: 'Test name', books: { 0: 'book 1', 1: 'book 2' } }; + const payload = {name: 'Test name', books: {0: 'book 1', 1: 'book 2'}}; const message = Book.create(payload); const rawValue = Book.encode(message).finish(); const value = Buffer.from(await brotli.compress(rawValue)); - this.createString(prefix, value); + await this.createString(prefix, value); resolve(); } catch (error) { reject(error); @@ -142,14 +118,5 @@ export class BrotliDatabasePopulator { }); }); } - - private createString(prefix: string, value: Buffer): void { - this.client.set(`${prefix}:string`, value, (error: Error | null) => { - if (error) { - console.error(`Error saving key ${prefix}:`, error); - throw error; - } - console.log(`Key ${prefix} successfully saved.`); - }); - } } + diff --git a/tests/e2e/helpers/decompressors/gzip-database-populator.ts b/tests/e2e/helpers/decompressors/gzip-database-populator.ts new file mode 100644 index 0000000000..c2459dd68f --- /dev/null +++ b/tests/e2e/helpers/decompressors/gzip-database-populator.ts @@ -0,0 +1,129 @@ +import { pack as msgpackrPack } from 'msgpackr'; +import * as fs from 'fs'; +import * as fflate from 'fflate'; +import * as proto from 'protobufjs'; +import { BaseDatabasePopulator } from './base-decompressors-populator'; + + +const COMPRESSED_PREFIX = 'Comp'; +const GZIP_PREFIX = 'GZIP'; + +export class GzipDatabasePopulator extends BaseDatabasePopulator { + + protected async createCompressedKeys(): Promise { + await this.createGZIPUnicodeKeys(); + await this.createGZIPASCIIKeys(); + await this.createGZIPJSONKeys(); + await this.createGZIPPHPUnserializedJSONKeys(); + await this.createGZIPMsgpackKeys(); + await this.createGZIPProtobufKeys(); + await this.createGZIPPickleKeys(); + await this.createGZIPJavaSerializedObjectKeys(); + await this.createGZIPVectorKeys(); + } + + private async createGZIPUnicodeKeys(): Promise { + const prefix = `${COMPRESSED_PREFIX}:${GZIP_PREFIX}:Unicode`; + const rawValue = '漢字'; + const buf = fflate.strToU8(rawValue); + const value = Buffer.from(fflate.compressSync(buf)); + + await this.createString(prefix, value); + } + + private async createGZIPASCIIKeys(): Promise { + const prefix = `${COMPRESSED_PREFIX}:${GZIP_PREFIX}:ASCII`; + const rawValue = '\xac\xed\x00\x05t\x0a4102'; + const buf = fflate.strToU8(rawValue); + const value = Buffer.from(fflate.compressSync(buf)); + + await this.createString(prefix, value); + } + + private async createGZIPJSONKeys(): Promise { + const prefix = `${COMPRESSED_PREFIX}:${GZIP_PREFIX}:JSON`; + const rawValue = '{"test":"test"}'; + const buf = fflate.strToU8(rawValue); + const value = Buffer.from(fflate.compressSync(buf)); + + await this.createString(prefix, value); + } + + private async createGZIPPHPUnserializedJSONKeys(): Promise { + const prefix = `${COMPRESSED_PREFIX}:${GZIP_PREFIX}:PHP`; + const rawValue = + 'a:2:{i:0;s:12:"Sample array";i:1;a:2:{i:0;s:5:"Apple";i:1;s:6:"Orange";}}'; + const buf = fflate.strToU8(rawValue); + const value = Buffer.from(fflate.compressSync(buf)); + + await this.createString(prefix, value); + } + + private async createGZIPJavaSerializedObjectKeys(): Promise { + const prefix = `${COMPRESSED_PREFIX}:${GZIP_PREFIX}:Java`; + const rawValue = fs.readFileSync('./test-data/decompressors/test_serialised_obj.ser'); + const rawValue2 = fs.readFileSync('./test-data/decompressors/test_annotated_obj.ser'); + + const value = Buffer.from(fflate.compressSync(rawValue)); + const value2 = Buffer.from(fflate.compressSync(rawValue2)); + + await this.createString(prefix, value); + await this.createString(prefix, value2); + } + + private async createGZIPMsgpackKeys(): Promise { + const prefix = `${COMPRESSED_PREFIX}:${GZIP_PREFIX}:Msgpack`; + const rawValue = msgpackrPack({ + hello: 'World', + array: [1, 2], + obj: {test: 'test'}, + boolean: false, + }); + + const value = Buffer.from(fflate.compressSync(rawValue)); + + await this.createString(prefix, value); + } + + private async createGZIPVectorKeys(): Promise { + const prefix = `${COMPRESSED_PREFIX}:${GZIP_PREFIX}:Vector`; + const rawValue = JSON.parse(fs.readFileSync('./test-data/decompressors/vector.json', 'utf8')); + const value = Buffer.from(fflate.compressSync(rawValue)); + + await this.createString(prefix, value); + } + + private createGZIPProtobufKeys(): Promise { + const prefix = `${COMPRESSED_PREFIX}:${GZIP_PREFIX}:Proto`; + + return new Promise((resolve, reject) => { + proto.load('./test-data/decompressors/awesome.proto', async (err, root) => { + if (err || !root) { + console.error('Error loading protobuf:', err); + return reject(err); + } + + const Book = root.lookupType('com.book.BookStore'); + const payloadBookStore = { + name: 'Test name', + books: {0: 'book 1', 1: 'book 2'}, + }; + const message = Book.create(payloadBookStore); + const rawValue = Book.encode(message).finish(); + const value = Buffer.from(fflate.compressSync(rawValue)); + + await this.createString(prefix, value); + + resolve(); + }); + }); + } + + private async createGZIPPickleKeys(): Promise { + const prefix = `${COMPRESSED_PREFIX}:${GZIP_PREFIX}:Pickle`; + const rawValue = fs.readFileSync('./test-data/decompressors/pickleFile1.pickle'); + const value = Buffer.from(fflate.compressSync(rawValue)); + + await this.createString(prefix, value); + } +} diff --git a/tests/e2e/helpers/decompressors/lz4-database-populator.ts b/tests/e2e/helpers/decompressors/lz4-database-populator.ts new file mode 100644 index 0000000000..dc23646a71 --- /dev/null +++ b/tests/e2e/helpers/decompressors/lz4-database-populator.ts @@ -0,0 +1,116 @@ +import { pack as msgpackrPack } from 'msgpackr'; +import * as fflate from 'fflate'; +import * as fs from 'fs'; +import * as lz4js from 'lz4js'; +import * as proto from 'protobufjs'; +import { BaseDatabasePopulator } from './base-decompressors-populator'; + +const COMPRESSED_PREFIX = 'Comp'; +const LZ4_PREFIX = 'LZ4'; + +export class LZ4DatabasePopulator extends BaseDatabasePopulator{ + + protected async createCompressedKeys(): Promise { + await this.createLZ4UnicodeKeys(); + await this.createLZ4ASCIIKeys(); + await this.createLZ4JSONKeys(); + await this.createLZ4PHPUnserializedJSONKeys(); + await this.createLZ4MsgpackKeys(); + await this.createLZ4ProtobufKeys(); + await this.createLZ4PickleKeys(); + await this.createLZ4JavaSerializedObjectKeys(); + await this.createLZ4VectorKeys(); + } + + private async createLZ4UnicodeKeys() { + const prefix = `${COMPRESSED_PREFIX}:${LZ4_PREFIX}:Unicode`; + const rawValue = '漢字'; + const buf = new TextEncoder().encode(rawValue); + const value = Buffer.from(lz4js.compress(buf)); + await this.createHash(prefix, value); + } + + private async createLZ4ASCIIKeys() { + const prefix = `${COMPRESSED_PREFIX}:${LZ4_PREFIX}:ASCII`; + const rawValue = '\xac\xed\x00\x05t\x0a4102'; + const buf = fflate.strToU8(rawValue); + const value = Buffer.from(lz4js.compress(buf)); + await this.createHash(prefix, value); + } + + private async createLZ4JSONKeys() { + const prefix = `${COMPRESSED_PREFIX}:${LZ4_PREFIX}:JSON`; + const rawValue = '{"test":"test"}'; + const buf = fflate.strToU8(rawValue); + const value = Buffer.from(lz4js.compress(buf)); + await this.createHash(prefix, value); + } + + private async createLZ4PHPUnserializedJSONKeys() { + const prefix = `${COMPRESSED_PREFIX}:${LZ4_PREFIX}:PHP`; + const rawValue = 'a:2:{i:0;s:12:"Sample array";i:1;a:2:{i:0;s:5:"Apple";i:1;s:6:"Orange";}}'; + const buf = fflate.strToU8(rawValue); + const value = Buffer.from(lz4js.compress(buf)); + await this.createHash(prefix, value); + } + + private async createLZ4JavaSerializedObjectKeys() { + const prefix = `${COMPRESSED_PREFIX}:${LZ4_PREFIX}:Java`; + const rawValue = fs.readFileSync('./test-data/decompressors/test_serialised_obj.ser'); + const rawValue2 = fs.readFileSync('./test-data/decompressors/test_annotated_obj.ser'); + const value = Buffer.from(lz4js.compress(rawValue)); + const value2 = Buffer.from(lz4js.compress(rawValue2)); + await this.createHash(prefix, value); + await this.createHash(prefix, value2); + } + + private async createLZ4MsgpackKeys(): Promise { + const prefix = `${COMPRESSED_PREFIX}:${LZ4_PREFIX}:Msgpack`; + const rawValue = msgpackrPack({ + hello: 'World', + array: [1, 2], + obj: { test: 'test' }, + boolean: false, + }); + const value = Buffer.from(lz4js.compress(rawValue)); + await this.createHash(prefix, value); + } + + private createLZ4ProtobufKeys(): Promise { + return new Promise((resolve, reject) => { + const prefix = `${COMPRESSED_PREFIX}:${LZ4_PREFIX}:Proto`; + proto.load('./test-data/decompressors/awesome.proto', async (err, root) => { + if (err || !root) { + console.error('Error loading protobuf:', err); + return reject(err); + } + try { + const Book = root.lookupType('com.book.BookStore'); + const payload = { name: 'Test name', books: { 0: 'book 1', 1: 'book 2' } }; + const message = Book.create(payload); + const rawValue = Book.encode(message).finish(); + const value = Buffer.from(lz4js.compress(rawValue)); + this.createHash(prefix, value); + resolve(); + } catch (error) { + reject(error); + } + }); + }); + } + + private async createLZ4PickleKeys() { + const prefix = `${COMPRESSED_PREFIX}:${LZ4_PREFIX}:Pickle`; + const rawValue = fs.readFileSync('./test-data/decompressors/pickleFile1.pickle'); + const value = Buffer.from(lz4js.compress(rawValue)); + await this.createHash(prefix, value); + } + + private async createLZ4VectorKeys() { + const prefix = `${COMPRESSED_PREFIX}:${LZ4_PREFIX}:Vector`; + const rawValue = JSON.parse(fs.readFileSync('./test-data/decompressors/vector.json', 'utf8')); + const value = Buffer.from(lz4js.compress(rawValue)); + await this.createHash(prefix, value); + } + +} diff --git a/tests/e2e/package.json b/tests/e2e/package.json index 9d3c1e7b20..91fe92eca8 100644 --- a/tests/e2e/package.json +++ b/tests/e2e/package.json @@ -29,6 +29,7 @@ "cli-argument-parser": "0.4.5", "fflate": "^0.8.2", "js-yaml": "^4.1.0", + "lz4js": "^0.2.0", "msgpackr": "^1.11.0", "protobufjs": "^7.4.0" }, diff --git a/tests/e2e/yarn.lock b/tests/e2e/yarn.lock index 6b9cb54120..620ef8ec53 100644 --- a/tests/e2e/yarn.lock +++ b/tests/e2e/yarn.lock @@ -4360,6 +4360,11 @@ lru-cache@^7.14.1: resolved "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz" integrity sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA== +lz4js@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/lz4js/-/lz4js-0.2.0.tgz#09f1a397cb2158f675146c3351dde85058cb322f" + integrity sha512-gY2Ia9Lm7Ep8qMiuGRhvUq0Q7qUereeldZPP1PMEJxPtEWHJLqw9pgX68oHajBH0nzJK4MaZEA/YNV3jT8u8Bg== + macos-release@^3.0.1: version "3.2.0" resolved "https://registry.npmjs.org/macos-release/-/macos-release-3.2.0.tgz" From 9febe2276bae14afa82aa70641eb29b2eaf0ce44 Mon Sep 17 00:00:00 2001 From: Roman Sergeenko Date: Thu, 3 Oct 2024 13:57:15 +0200 Subject: [PATCH 094/256] #RI-6135 - cover no indexes case * fix last page context --- .../pages/search/components/query/Query.tsx | 32 ++++++++++++++++--- .../search/components/query/constants.ts | 3 ++ .../pages/search/components/query/utils.ts | 17 +++++++++- .../ui/src/pages/search/utils/query.ts | 2 +- redisinsight/ui/src/slices/app/context.ts | 4 +-- redisinsight/ui/src/slices/interfaces/app.ts | 2 +- .../ui/src/slices/tests/app/context.spec.ts | 2 +- 7 files changed, 52 insertions(+), 10 deletions(-) diff --git a/redisinsight/ui/src/pages/search/components/query/Query.tsx b/redisinsight/ui/src/pages/search/components/query/Query.tsx index 0e73ae51bc..32e992a49f 100644 --- a/redisinsight/ui/src/pages/search/components/query/Query.tsx +++ b/redisinsight/ui/src/pages/search/components/query/Query.tsx @@ -20,7 +20,13 @@ import { RedisResponseBuffer } from 'uiSrc/slices/interfaces' import { fetchRedisearchInfoAction } from 'uiSrc/slices/browser/redisearch' import { getRediSearchMonarchTokensProvider } from 'uiSrc/utils/monaco/monarchTokens/redisearchTokens' import { useDebouncedEffect } from 'uiSrc/services' -import { options, DefinedArgumentName, FIELD_START_SYMBOL, COMMANDS_TO_GET_INDEX_INFO } from './constants' +import { + options, + DefinedArgumentName, + FIELD_START_SYMBOL, + COMMANDS_TO_GET_INDEX_INFO, + EmptySuggestionsIds +} from './constants' import { getFieldsSuggestions, getIndexesSuggestions, @@ -29,6 +35,7 @@ import { isIndexComplete, getGeneralSuggestions, getFunctionsSuggestions, + getNoIndexesSuggestion, } from './utils' export interface Props { @@ -123,6 +130,15 @@ const Query = (props: Props) => { } }) + const suggestionWidget = editor.getContribution('editor.contrib.suggestController') + suggestionWidget.onWillInsertSuggestItem(({ item }: Record<'item', any>) => { + if (item.completion.id === EmptySuggestionsIds.NoIndexes) { + updateHelpWidget(true) + editor.trigger('', 'hideSuggestWidget', null) + editor.trigger('', 'editor.action.triggerParameterHints', '') + } + }) + suggestionsRef.current = getSuggestions(editor).data if (value) { setCursorPositionAtTheEnd(editor) @@ -182,7 +198,10 @@ const Query = (props: Props) => { } const updateHelpWidget = (isOpen: boolean, parent?: SearchCommand, currentArg?: SearchCommand) => { - helpWidgetRef.current = { isOpen, parent, currentArg } + helpWidgetRef.current = { + isOpen, + parent: parent || helpWidgetRef.current.parent, + currentArg: currentArg || helpWidgetRef.current.currentArg } } const getSuggestions = ( @@ -256,9 +275,14 @@ const Query = (props: Props) => { currentOffsetArg: Nullable, range: monacoEditor.IRange ) => { - updateHelpWidget(true, command, foundArg?.stopArg) - const isIndex = indexesRef.current.length > 0 + updateHelpWidget(isIndex, command, foundArg?.stopArg) + + if (!isIndex) { + updateHelpWidget(!!currentOffsetArg) + return asSuggestionsRef(!currentOffsetArg ? getNoIndexesSuggestion(range) : [], true) + } + if (!isIndex || currentOffsetArg) return asSuggestionsRef([], !currentOffsetArg) const argumentIndex = command?.arguments diff --git a/redisinsight/ui/src/pages/search/components/query/constants.ts b/redisinsight/ui/src/pages/search/components/query/constants.ts index 53d83e8e3f..e3c7be2574 100644 --- a/redisinsight/ui/src/pages/search/components/query/constants.ts +++ b/redisinsight/ui/src/pages/search/components/query/constants.ts @@ -59,3 +59,6 @@ export enum DefinedArgumentName { } export const FIELD_START_SYMBOL = '@' +export enum EmptySuggestionsIds { + NoIndexes = 'no-indexes' +} diff --git a/redisinsight/ui/src/pages/search/components/query/utils.ts b/redisinsight/ui/src/pages/search/components/query/utils.ts index 49d7976cde..1ae87452be 100644 --- a/redisinsight/ui/src/pages/search/components/query/utils.ts +++ b/redisinsight/ui/src/pages/search/components/query/utils.ts @@ -8,7 +8,7 @@ import { removeNotSuggestedArgs } from 'uiSrc/pages/search/utils' import { FoundCommandArgument, SearchCommand } from 'uiSrc/pages/search/types' -import { DefinedArgumentName } from 'uiSrc/pages/search/components/query/constants' +import { DefinedArgumentName, EmptySuggestionsIds } from 'uiSrc/pages/search/components/query/constants' export const asSuggestionsRef = ( suggestions: monacoEditor.languages.CompletionItem[], @@ -20,6 +20,21 @@ export const asSuggestionsRef = ( forceShow }) +export const getNoIndexesSuggestion = (range: monaco.IRange) => [ + { + id: EmptySuggestionsIds.NoIndexes, + label: 'No indexes to display', + kind: monacoEditor.languages.CompletionItemKind.Issue, + insertText: '', + insertTextRules: monacoEditor.languages.CompletionItemInsertTextRule.InsertAsSnippet, + range, + detail: 'Create an index', + documentation: { + value: 'See the [documentation](https://redis.io/docs/latest/commands/ft.create/?utm_source=redisinsight&utm_medium=app&utm_campaign=workbench) for detailed instructions on how to create an index.', + } + } +] + export const getIndexesSuggestions = (indexes: RedisResponseBuffer[], range: monaco.IRange, isNextArgQuery = true) => indexes.map((index) => { const value = formatLongName(bufferToString(index)) diff --git a/redisinsight/ui/src/pages/search/utils/query.ts b/redisinsight/ui/src/pages/search/utils/query.ts index 92bc72179e..a18498d5d5 100644 --- a/redisinsight/ui/src/pages/search/utils/query.ts +++ b/redisinsight/ui/src/pages/search/utils/query.ts @@ -465,7 +465,7 @@ export const generateDetail = (command: Maybe) => { if (command.arguments) return generateArgsNames(CommandProvider.Main, command.arguments).join(' ') if (command.token) { if (command.type === TokenType.PureToken) return command.token - return `${command.token} ${command.name}` + return `${command.token}` } return '' diff --git a/redisinsight/ui/src/slices/app/context.ts b/redisinsight/ui/src/slices/app/context.ts index 4fce0714a5..4421886dff 100644 --- a/redisinsight/ui/src/slices/app/context.ts +++ b/redisinsight/ui/src/slices/app/context.ts @@ -35,7 +35,7 @@ export const initialState: StateAppContext = { : AppWorkspace.Databases, contextInstanceId: '', contextRdiInstanceId: '', - lastBrowserPage: '', + lastPage: '', dbConfig: { treeViewDelimiter: DEFAULT_DELIMITER, treeViewSort: DEFAULT_TREE_SORTING, @@ -191,7 +191,7 @@ const appContextSlice = createSlice({ state.searchAndQuery.script = payload }, setLastPageContext: (state, { payload }: { payload: string }) => { - state.lastBrowserPage = payload + state.lastPage = payload }, resetBrowserTree: (state) => { state.browser.tree.selectedLeaf = null diff --git a/redisinsight/ui/src/slices/interfaces/app.ts b/redisinsight/ui/src/slices/interfaces/app.ts index ba7602c322..994b3c41e2 100644 --- a/redisinsight/ui/src/slices/interfaces/app.ts +++ b/redisinsight/ui/src/slices/interfaces/app.ts @@ -62,7 +62,7 @@ export interface StateAppContext { workspace: AppWorkspace contextInstanceId: string contextRdiInstanceId: string - lastBrowserPage: string + lastPage: string dbConfig: { treeViewDelimiter: string treeViewSort: SortOrder diff --git a/redisinsight/ui/src/slices/tests/app/context.spec.ts b/redisinsight/ui/src/slices/tests/app/context.spec.ts index 91b8898d17..874ac9da0b 100644 --- a/redisinsight/ui/src/slices/tests/app/context.spec.ts +++ b/redisinsight/ui/src/slices/tests/app/context.spec.ts @@ -370,7 +370,7 @@ describe('slices', () => { const lastPage = 'workbench' const state = { ...initialState, - lastBrowserPage: lastPage + lastPage } // Act From ef19afe7ae9958b1ad3bc55f3ef8a99027fb65bf Mon Sep 17 00:00:00 2001 From: Roman Sergeenko Date: Thu, 3 Oct 2024 14:00:11 +0200 Subject: [PATCH 095/256] #RI-6135 - update link --- redisinsight/ui/src/pages/search/components/query/utils.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/redisinsight/ui/src/pages/search/components/query/utils.ts b/redisinsight/ui/src/pages/search/components/query/utils.ts index 1ae87452be..5ec9f867aa 100644 --- a/redisinsight/ui/src/pages/search/components/query/utils.ts +++ b/redisinsight/ui/src/pages/search/components/query/utils.ts @@ -9,6 +9,7 @@ import { } from 'uiSrc/pages/search/utils' import { FoundCommandArgument, SearchCommand } from 'uiSrc/pages/search/types' import { DefinedArgumentName, EmptySuggestionsIds } from 'uiSrc/pages/search/components/query/constants' +import { getUtmExternalLink } from 'uiSrc/utils/links' export const asSuggestionsRef = ( suggestions: monacoEditor.languages.CompletionItem[], @@ -20,6 +21,7 @@ export const asSuggestionsRef = ( forceShow }) +const NO_INDEXES_DOC_LINK = getUtmExternalLink('https://redis.io/docs/latest/commands/ft.create/', { campaign: 'workbench' }) export const getNoIndexesSuggestion = (range: monaco.IRange) => [ { id: EmptySuggestionsIds.NoIndexes, @@ -30,7 +32,7 @@ export const getNoIndexesSuggestion = (range: monaco.IRange) => [ range, detail: 'Create an index', documentation: { - value: 'See the [documentation](https://redis.io/docs/latest/commands/ft.create/?utm_source=redisinsight&utm_medium=app&utm_campaign=workbench) for detailed instructions on how to create an index.', + value: `See the [documentation](${NO_INDEXES_DOC_LINK}) for detailed instructions on how to create an index.`, } } ] From 077369ae12f57de91e4b0078ff0c797bc2912786 Mon Sep 17 00:00:00 2001 From: Kristiyan Ivanov Date: Thu, 3 Oct 2024 15:02:31 +0300 Subject: [PATCH 096/256] RI-6160 Add a list data type with multiple elements --- .../api/src/modules/browser/__mocks__/list.ts | 4 +- .../list/dto/push.element-to-list.dto.ts | 12 +-- .../modules/browser/list/list.service.spec.ts | 44 ++++----- .../src/modules/browser/list/list.service.ts | 32 +++---- .../add-key/AddKeyList/AddKeyList.spec.tsx | 29 +++++- .../add-key/AddKeyList/AddKeyList.tsx | 68 ++++++++----- .../AddMultipleFields.spec.tsx | 2 +- .../add-multiple-fields/AddMultipleFields.tsx | 12 +-- .../AddListElements.spec.tsx | 23 +++++ .../add-list-elements/AddListElements.tsx | 95 +++++++++++-------- 10 files changed, 200 insertions(+), 121 deletions(-) diff --git a/redisinsight/api/src/modules/browser/__mocks__/list.ts b/redisinsight/api/src/modules/browser/__mocks__/list.ts index ba1263add7..52d3c6f4b3 100644 --- a/redisinsight/api/src/modules/browser/__mocks__/list.ts +++ b/redisinsight/api/src/modules/browser/__mocks__/list.ts @@ -1,3 +1,4 @@ +import { mockKeyDto } from 'src/modules/browser/__mocks__/keys'; import { DeleteListElementsDto, GetListElementResponse, @@ -7,7 +8,6 @@ import { PushElementToListDto, SetListElementDto, } from 'src/modules/browser/list/dto'; -import { mockKeyDto } from 'src/modules/browser/__mocks__/keys'; export const mockIndex: number = 0; export const mockListElement = Buffer.from('Lorem ipsum dolor sit amet.'); @@ -15,7 +15,7 @@ export const mockListElement2 = Buffer.from('Lorem ipsum dolor sit amet2.'); export const mockListElements = [mockListElement]; export const mockPushElementDto: PushElementToListDto = { keyName: mockKeyDto.keyName, - element: mockListElement, + elements: mockListElements, destination: ListElementDestination.Tail, }; export const mockGetListElementsDto: GetListElementsDto = { diff --git a/redisinsight/api/src/modules/browser/list/dto/push.element-to-list.dto.ts b/redisinsight/api/src/modules/browser/list/dto/push.element-to-list.dto.ts index df97403a33..bca6a07c0b 100644 --- a/redisinsight/api/src/modules/browser/list/dto/push.element-to-list.dto.ts +++ b/redisinsight/api/src/modules/browser/list/dto/push.element-to-list.dto.ts @@ -1,8 +1,8 @@ -import { KeyDto } from 'src/modules/browser/keys/dto'; import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger'; import { IsDefined, IsEnum } from 'class-validator'; -import { IsRedisString, RedisStringType } from 'src/common/decorators'; import { RedisString } from 'src/common/constants'; +import { RedisStringType } from 'src/common/decorators'; +import { KeyDto } from 'src/modules/browser/keys/dto'; export enum ListElementDestination { Tail = 'TAIL', @@ -11,13 +11,13 @@ export enum ListElementDestination { export class PushElementToListDto extends KeyDto { @ApiProperty({ - description: 'List element', + description: 'List elements', + isArray: true, type: String, }) @IsDefined() - @IsRedisString() - @RedisStringType() - element: RedisString; + @RedisStringType({ each: true }) + elements: RedisString[]; @ApiPropertyOptional({ description: diff --git a/redisinsight/api/src/modules/browser/list/list.service.spec.ts b/redisinsight/api/src/modules/browser/list/list.service.spec.ts index 2f1a8ea192..d1383058ad 100644 --- a/redisinsight/api/src/modules/browser/list/list.service.spec.ts +++ b/redisinsight/api/src/modules/browser/list/list.service.spec.ts @@ -1,26 +1,21 @@ -import { Test, TestingModule } from '@nestjs/testing'; import { BadRequestException, ConflictException, ForbiddenException, NotFoundException, } from '@nestjs/common'; +import { Test, TestingModule } from '@nestjs/testing'; import { when } from 'jest-when'; -import { ReplyError } from 'src/models/redis-client'; import { + mockBrowserClientMetadata, mockRedisNoPermError, mockRedisWrongNumberOfArgumentsError, mockRedisWrongTypeError, - mockBrowserClientMetadata, } from 'src/__mocks__'; -import { - CreateListWithExpireDto, - ListElementDestination, -} from 'src/modules/browser/list/dto'; -import { - BrowserToolKeysCommands, - BrowserToolListCommands, -} from 'src/modules/browser/constants/browser-tool-commands'; +import { mockDatabaseClientFactory } from 'src/__mocks__/databases-client'; +import { mockStandaloneRedisClient } from 'src/__mocks__/redis-client'; +import ERROR_MESSAGES from 'src/constants/error-messages'; +import { ReplyError } from 'src/models/redis-client'; import { mockDeleteElementsDto, mockGetListElementResponse, @@ -34,10 +29,15 @@ import { mockPushElementDto, mockSetListElementDto, } from 'src/modules/browser/__mocks__'; +import { + BrowserToolKeysCommands, + BrowserToolListCommands, +} from 'src/modules/browser/constants/browser-tool-commands'; +import { + CreateListWithExpireDto, + ListElementDestination, +} from 'src/modules/browser/list/dto'; import { DatabaseClientFactory } from 'src/modules/database/providers/database.client.factory'; -import { mockDatabaseClientFactory } from 'src/__mocks__/databases-client'; -import { mockStandaloneRedisClient } from 'src/__mocks__/redis-client'; -import ERROR_MESSAGES from 'src/constants/error-messages'; import { ListService } from './list.service'; describe('ListService', () => { @@ -84,7 +84,7 @@ describe('ListService', () => { .calledWith([ BrowserToolListCommands.LPush, mockPushElementDto.keyName, - mockPushElementDto.element, + mockPushElementDto.elements, ]) .mockResolvedValue(1); @@ -120,12 +120,12 @@ describe('ListService', () => { }); describe('pushElement', () => { - it('succeed to insert element at the tail of the list data type', async () => { + it('succeed to insert element(s) at the tail of the list data type', async () => { when(mockStandaloneRedisClient.sendCommand) .calledWith([ BrowserToolListCommands.RPushX, mockPushElementDto.keyName, - mockPushElementDto.element, + mockPushElementDto.elements, ]) .mockResolvedValue(1); @@ -133,12 +133,12 @@ describe('ListService', () => { service.pushElement(mockBrowserClientMetadata, mockPushElementDto), ).resolves.not.toThrow(); }); - it('succeed to insert element at the head of the list data type', async () => { + it('succeed to insert element(s) at the head of the list data type', async () => { when(mockStandaloneRedisClient.sendCommand) .calledWith([ BrowserToolListCommands.LPushX, mockPushElementDto.keyName, - mockPushElementDto.element, + mockPushElementDto.elements, ]) .mockResolvedValue(12); @@ -154,7 +154,7 @@ describe('ListService', () => { .calledWith([ BrowserToolListCommands.RPushX, mockPushElementDto.keyName, - mockPushElementDto.element, + mockPushElementDto.elements, ]) .mockResolvedValue(0); @@ -475,7 +475,7 @@ describe('ListService', () => { it("shouldn't throw error", async () => { when(mockStandaloneRedisClient.sendPipeline) .calledWith([ - [BrowserToolListCommands.LPush, dto.keyName, dto.element], + [BrowserToolListCommands.LPush, dto.keyName, dto.elements], [BrowserToolKeysCommands.Expire, dto.keyName, dto.expire], ]) .mockResolvedValue([ @@ -494,7 +494,7 @@ describe('ListService', () => { }; when(mockStandaloneRedisClient.sendPipeline) .calledWith([ - [BrowserToolListCommands.LPush, dto.keyName, dto.element], + [BrowserToolListCommands.LPush, dto.keyName, dto.elements], [BrowserToolKeysCommands.Expire, dto.keyName, dto.expire], ]) .mockResolvedValue([[replyError, []]]); diff --git a/redisinsight/api/src/modules/browser/list/list.service.ts b/redisinsight/api/src/modules/browser/list/list.service.ts index 0b8add517f..522b21094e 100644 --- a/redisinsight/api/src/modules/browser/list/list.service.ts +++ b/redisinsight/api/src/modules/browser/list/list.service.ts @@ -4,11 +4,16 @@ import { Logger, NotFoundException, } from '@nestjs/common'; -import { isNull, isArray } from 'lodash'; +import { plainToClass } from 'class-transformer'; +import { isArray, isNull } from 'lodash'; +import { ClientMetadata } from 'src/common/models'; import { RedisErrorCodes } from 'src/constants'; import ERROR_MESSAGES from 'src/constants/error-messages'; -import { catchAclError, catchMultiTransactionError } from 'src/utils'; -import { ClientMetadata } from 'src/common/models'; +import { + BrowserToolKeysCommands, + BrowserToolListCommands, +} from 'src/modules/browser/constants/browser-tool-commands'; +import { KeyDto } from 'src/modules/browser/keys/dto'; import { CreateListWithExpireDto, DeleteListElementsDto, @@ -22,15 +27,10 @@ import { SetListElementDto, SetListElementResponse, } from 'src/modules/browser/list/dto'; -import { KeyDto } from 'src/modules/browser/keys/dto'; -import { - BrowserToolKeysCommands, - BrowserToolListCommands, -} from 'src/modules/browser/constants/browser-tool-commands'; -import { plainToClass } from 'class-transformer'; +import { checkIfKeyExists, checkIfKeyNotExists } from 'src/modules/browser/utils'; import { DatabaseClientFactory } from 'src/modules/database/providers/database.client.factory'; import { RedisClient, RedisClientCommandReply } from 'src/modules/redis/client'; -import { checkIfKeyExists, checkIfKeyNotExists } from 'src/modules/browser/utils'; +import { catchAclError, catchMultiTransactionError } from 'src/utils'; @Injectable() export class ListService { @@ -69,13 +69,13 @@ export class ListService { ): Promise { try { this.logger.log('Insert element at the tail/head of the list data type.'); - const { keyName, element, destination } = dto; + const { keyName, elements, destination } = dto; const client: RedisClient = await this.databaseClientFactory.getOrCreateClient(clientMetadata); const total: RedisClientCommandReply = await client.sendCommand([ BrowserToolListCommands[destination === ListElementDestination.Tail ? 'RPushX' : 'LPushX'], keyName, - element, + ...elements, ]); if (!total) { this.logger.error( @@ -234,17 +234,17 @@ export class ListService { client: RedisClient, dto: PushElementToListDto, ): Promise { - const { keyName, element } = dto; - await client.sendCommand([BrowserToolListCommands.LPush, keyName, element]); + const { keyName, elements } = dto; + await client.sendCommand([BrowserToolListCommands.LPush, keyName, ...elements]); } public async createListWithExpiration( client: RedisClient, dto: CreateListWithExpireDto, ): Promise { - const { keyName, element, expire } = dto; + const { keyName, elements, expire } = dto; const transactionResults = await client.sendPipeline([ - [BrowserToolListCommands.LPush, keyName, element], + [BrowserToolListCommands.LPush, keyName, ...elements], [BrowserToolKeysCommands.Expire, keyName, expire], ]); catchMultiTransactionError(transactionResults); diff --git a/redisinsight/ui/src/pages/browser/components/add-key/AddKeyList/AddKeyList.spec.tsx b/redisinsight/ui/src/pages/browser/components/add-key/AddKeyList/AddKeyList.spec.tsx index 1e2e319de1..7ba3d8a222 100644 --- a/redisinsight/ui/src/pages/browser/components/add-key/AddKeyList/AddKeyList.spec.tsx +++ b/redisinsight/ui/src/pages/browser/components/add-key/AddKeyList/AddKeyList.spec.tsx @@ -1,11 +1,13 @@ import React from 'react' import { instance, mock } from 'ts-mockito' -import { render, screen, fireEvent } from 'uiSrc/utils/test-utils' -import AddKeyList, { Props } from './AddKeyList' +import { fireEvent, render, screen } from 'uiSrc/utils/test-utils' import AddKeyFooter from '../AddKeyFooter/AddKeyFooter' +import AddKeyList, { Props } from './AddKeyList' const mockedProps = mock() +const elementFindingRegex = /^element-\d+$/ + jest.mock('../AddKeyFooter/AddKeyFooter', () => ({ __esModule: true, namedExport: jest.fn(), @@ -25,7 +27,7 @@ describe('AddKeyList', () => { it('should set value properly', () => { render() - const valueInput = screen.getByTestId('element') + const valueInput = screen.getByTestId(elementFindingRegex) const value = 'list list list list list list ' fireEvent.change(valueInput, { target: { value } }) expect(valueInput).toHaveValue(value) @@ -40,4 +42,25 @@ describe('AddKeyList', () => { const { container } = render() expect(container.querySelector('.btn-add')).not.toBeDisabled() }) + + it('should allow for adding multiple elements', () => { + render() + fireEvent.click(screen.getByTestId('add-item')) + const valueInputs = screen.getAllByTestId(elementFindingRegex) + expect([...valueInputs].length).toBe(2) + }) + + it('should not allow deleting the last element', () => { + render() + fireEvent.click(screen.getByTestId('add-item')) + const deleteButtons = screen.getAllByTestId('remove-item') + expect(deleteButtons[0]).toBeDisabled() + }) + + it('should allow deleting of the elements after the first one', () => { + render() + fireEvent.click(screen.getByTestId('add-item')) + const deleteButtons = screen.getAllByTestId('remove-item') + expect(deleteButtons[1]).not.toBeDisabled() + }) }) diff --git a/redisinsight/ui/src/pages/browser/components/add-key/AddKeyList/AddKeyList.tsx b/redisinsight/ui/src/pages/browser/components/add-key/AddKeyList/AddKeyList.tsx index 86814688e7..afa9ced56c 100644 --- a/redisinsight/ui/src/pages/browser/components/add-key/AddKeyList/AddKeyList.tsx +++ b/redisinsight/ui/src/pages/browser/components/add-key/AddKeyList/AddKeyList.tsx @@ -1,25 +1,25 @@ -import React, { ChangeEvent, FormEvent, useState, useEffect } from 'react' +import React, { ChangeEvent, FormEvent, useEffect, useState } from 'react' import { useDispatch, useSelector } from 'react-redux' import { EuiButton, - EuiFormRow, - EuiTextColor, - EuiForm, + EuiFieldText, EuiFlexGroup, EuiFlexItem, + EuiForm, EuiPanel, - EuiFieldText, + EuiTextColor } from '@elastic/eui' -import { Maybe, stringToBuffer } from 'uiSrc/utils' -import { addKeyStateSelector, addListKey } from 'uiSrc/slices/browser/keys' import { CreateListWithExpireDto } from 'apiSrc/modules/browser/list/dto' +import { addKeyStateSelector, addListKey } from 'uiSrc/slices/browser/keys' +import { Maybe, stringToBuffer } from 'uiSrc/utils' +import AddMultipleFields from '../../add-multiple-fields' +import AddKeyFooter from '../AddKeyFooter/AddKeyFooter' import { AddListFormConfig as config, } from '../constants/fields-config' -import AddKeyFooter from '../AddKeyFooter/AddKeyFooter' export interface Props { keyName: string @@ -29,7 +29,8 @@ export interface Props { const AddKeyList = (props: Props) => { const { keyName = '', keyTTL, onCancel } = props - const [element, setElement] = useState('') + const [elements, setElements] = useState(['']) + const [isFormValid, setIsFormValid] = useState(false) const { loading } = useSelector(addKeyStateSelector) @@ -46,11 +47,25 @@ const AddKeyList = (props: Props) => { submitData() } } + const addField = () => { + setElements([...elements, '']) + } + const onClickRemove = (_item: string, index?: number) => { + setElements(elements.filter((_el, i) => i !== index)) + } + + const isClearDisabled = (_element:string, index?: number) => index === 0 + + const handleElementChange = (value: string, index: number) => { + const newElements = [...elements] + newElements[index] = value + setElements(newElements) + } const submitData = (): void => { const data: CreateListWithExpireDto = { keyName: stringToBuffer(keyName), - element: stringToBuffer(element), + elements: elements.map((el) => stringToBuffer(el)), } if (keyTTL !== undefined) { data.expire = keyTTL @@ -60,19 +75,26 @@ const AddKeyList = (props: Props) => { return ( - - ) => - setElement(e.target.value)} - disabled={loading} - data-testid="element" - /> - + + {(item, index) => ( + ) => + handleElementChange(e.target.value, index)} + data-testid={`element-${index}`} + /> + )} + Submit diff --git a/redisinsight/ui/src/pages/browser/components/add-multiple-fields/AddMultipleFields.spec.tsx b/redisinsight/ui/src/pages/browser/components/add-multiple-fields/AddMultipleFields.spec.tsx index 62f8f1a366..82f3d011b6 100644 --- a/redisinsight/ui/src/pages/browser/components/add-multiple-fields/AddMultipleFields.spec.tsx +++ b/redisinsight/ui/src/pages/browser/components/add-multiple-fields/AddMultipleFields.spec.tsx @@ -1,5 +1,5 @@ import React from 'react' -import { render, screen } from 'uiSrc/utils/test-utils' +import { render } from 'uiSrc/utils/test-utils' import AddMultipleFields from './AddMultipleFields' diff --git a/redisinsight/ui/src/pages/browser/components/add-multiple-fields/AddMultipleFields.tsx b/redisinsight/ui/src/pages/browser/components/add-multiple-fields/AddMultipleFields.tsx index 46a99d80e8..5806c60c0c 100644 --- a/redisinsight/ui/src/pages/browser/components/add-multiple-fields/AddMultipleFields.tsx +++ b/redisinsight/ui/src/pages/browser/components/add-multiple-fields/AddMultipleFields.tsx @@ -1,6 +1,6 @@ -import React from 'react' -import cx from 'classnames' import { EuiButtonIcon, EuiFlexGroup, EuiFlexItem, EuiSpacer, EuiToolTip } from '@elastic/eui' +import cx from 'classnames' +import React from 'react' import styles from './styles.module.scss' @@ -10,8 +10,8 @@ export interface Props { item: T, index: number ) => React.ReactNode - isClearDisabled: (item: T) => boolean - onClickRemove: (item: T) => void + isClearDisabled: (item: T, index?: number) => boolean + onClickRemove: (item: T, index?: number) => void onClickAdd: () => void } @@ -41,10 +41,10 @@ const AddMultipleFields = (props: Props) => { > onClickRemove(item)} + onClick={() => onClickRemove(item, index)} data-testid="remove-item" /> diff --git a/redisinsight/ui/src/pages/browser/modules/key-details/components/list-details/add-list-elements/AddListElements.spec.tsx b/redisinsight/ui/src/pages/browser/modules/key-details/components/list-details/add-list-elements/AddListElements.spec.tsx index 564750e0d4..4209a6bae0 100644 --- a/redisinsight/ui/src/pages/browser/modules/key-details/components/list-details/add-list-elements/AddListElements.spec.tsx +++ b/redisinsight/ui/src/pages/browser/modules/key-details/components/list-details/add-list-elements/AddListElements.spec.tsx @@ -5,6 +5,8 @@ import AddListElements, { HEAD_DESTINATION, Props } from './AddListElements' const mockedProps = mock() +const elementFindingRegex = /^element-\d+$/ + describe('AddListElements', () => { it('should render', () => { expect(render()).toBeTruthy() @@ -29,4 +31,25 @@ describe('AddListElements', () => { ) expect(destinationSelect).toHaveValue(HEAD_DESTINATION) }) + + it('should allow for adding multiple elements', () => { + render() + fireEvent.click(screen.getByTestId('add-item')) + const valueInputs = screen.getAllByTestId(elementFindingRegex) + expect([...valueInputs].length).toBe(2) + }) + + it('should not allow deleting the last element', () => { + render() + fireEvent.click(screen.getByTestId('add-item')) + const deleteButtons = screen.getAllByTestId('remove-item') + expect(deleteButtons[0]).toBeDisabled() + }) + + it('should allow deleting of the elements after the first one', () => { + render() + fireEvent.click(screen.getByTestId('add-item')) + const deleteButtons = screen.getAllByTestId('remove-item') + expect(deleteButtons[1]).not.toBeDisabled() + }) }) diff --git a/redisinsight/ui/src/pages/browser/modules/key-details/components/list-details/add-list-elements/AddListElements.tsx b/redisinsight/ui/src/pages/browser/modules/key-details/components/list-details/add-list-elements/AddListElements.tsx index 39cd89ce42..efd2a55c1d 100644 --- a/redisinsight/ui/src/pages/browser/modules/key-details/components/list-details/add-list-elements/AddListElements.tsx +++ b/redisinsight/ui/src/pages/browser/modules/key-details/components/list-details/add-list-elements/AddListElements.tsx @@ -1,27 +1,27 @@ -import React, { ChangeEvent, useEffect, useRef, useState } from 'react' -import { useDispatch, useSelector } from 'react-redux' -import cx from 'classnames' import { EuiButton, - EuiTextColor, + EuiFieldText, EuiFlexGroup, EuiFlexItem, - EuiFormRow, - EuiFieldText, EuiPanel, EuiSuperSelect, EuiSuperSelectOption, + EuiTextColor } from '@elastic/eui' +import cx from 'classnames' +import React, { ChangeEvent, useEffect, useRef, useState } from 'react' +import { useDispatch, useSelector } from 'react-redux' -import { selectedKeyDataSelector, keysSelector } from 'uiSrc/slices/browser/keys' -import { connectedInstanceSelector } from 'uiSrc/slices/instances/instances' +import { PushElementToListDto } from 'apiSrc/modules/browser/list/dto' +import { KeyTypes } from 'uiSrc/constants' +import { AddListFormConfig as config } from 'uiSrc/pages/browser/components/add-key/constants/fields-config' +import { keysSelector, selectedKeyDataSelector } from 'uiSrc/slices/browser/keys' import { insertListElementsAction } from 'uiSrc/slices/browser/list' +import { connectedInstanceSelector } from 'uiSrc/slices/instances/instances' import { getBasedOnViewTypeEvent, sendEventTelemetry, TelemetryEvent } from 'uiSrc/telemetry' -import { KeyTypes } from 'uiSrc/constants' import { stringToBuffer } from 'uiSrc/utils' -import { AddListFormConfig as config } from 'uiSrc/pages/browser/components/add-key/constants/fields-config' -import { PushElementToListDto } from 'apiSrc/modules/browser/list/dto' +import AddMultipleFields from 'uiSrc/pages/browser/components/add-multiple-fields' import styles from '../styles.module.scss' export interface Props { @@ -50,7 +50,7 @@ const optionsDestinations: EuiSuperSelectOption[] = [ const AddListElements = (props: Props) => { const { closePanel } = props - const [element, setElement] = useState('') + const [elements, setElements] = useState(['']) const [destination, setDestination] = useState(TAIL_DESTINATION) const { name: selectedKey = '' } = useSelector(selectedKeyDataSelector) ?? { name: undefined } const { viewType } = useSelector(keysSelector) @@ -81,10 +81,25 @@ const AddListElements = (props: Props) => { }) } + const addField = () => { + setElements([...elements, '']) + } + const onClickRemove = (_item: string, index?: number) => { + setElements(elements.filter((_el, i) => i !== index)) + } + + const isClearDisabled = (_element:string, index?: number) => index === 0 + + const handleElementChange = (value: string, index: number) => { + const newElements = [...elements] + newElements[index] = value + setElements(newElements) + } + const submitData = (): void => { const data: PushElementToListDto = { keyName: selectedKey, - element: stringToBuffer(element), + elements: elements.map((el) => stringToBuffer(el)), destination, } dispatch(insertListElementsAction(data, onSuccessAdded)) @@ -99,35 +114,31 @@ const AddListElements = (props: Props) => { data-test-subj="add-list-field-panel" className={cx(styles.content, 'eui-yScroll', 'flexItemNoFullWidth', 'inlineFieldsNoSpace')} > - - - - - setDestination(value as ListElementDestination)} - data-testid="destination-select" - /> - - - - - ) => setElement(e.target.value)} - data-testid="elements-input" - inputRef={elementInput} - /> - - - - + setDestination(value as ListElementDestination)} + data-testid="destination-select" + /> + + {(item, index) => ( + ) => + handleElementChange(e.target.value, index)} + data-testid={`element-${index}`} + /> + )} + Date: Thu, 3 Oct 2024 14:06:42 +0200 Subject: [PATCH 097/256] add php-gzc --- .../base-decompressors-populator.ts | 9 +- .../php-gzcompress-database-populator.ts | 138 ++++++++++++++++++ 2 files changed, 145 insertions(+), 2 deletions(-) create mode 100644 tests/e2e/helpers/decompressors/php-gzcompress-database-populator.ts diff --git a/tests/e2e/helpers/decompressors/base-decompressors-populator.ts b/tests/e2e/helpers/decompressors/base-decompressors-populator.ts index a003ff695d..535d786171 100644 --- a/tests/e2e/helpers/decompressors/base-decompressors-populator.ts +++ b/tests/e2e/helpers/decompressors/base-decompressors-populator.ts @@ -27,7 +27,12 @@ export abstract class BaseDatabasePopulator { }); } - protected async createHash(prefix: string, value: Buffer, onlyOneItem = false, value2 = ''): Promise { + protected async createHash( + prefix: string, + value: Buffer, + onlyOneItem = false, + value2: Buffer = Buffer.from('') + ): Promise { let fields: string[] = []; const randomNumber = Array.from({ length: 5 }).map(() => Math.random()); @@ -40,7 +45,7 @@ export abstract class BaseDatabasePopulator { } if (value2) { - fields.push(value2, value2); + fields.push(value2.toString(), value2.toString()); } try { diff --git a/tests/e2e/helpers/decompressors/php-gzcompress-database-populator.ts b/tests/e2e/helpers/decompressors/php-gzcompress-database-populator.ts new file mode 100644 index 0000000000..ede4f7e93f --- /dev/null +++ b/tests/e2e/helpers/decompressors/php-gzcompress-database-populator.ts @@ -0,0 +1,138 @@ +import { pack as msgpackrPack } from 'msgpackr'; +import * as fflate from 'fflate'; +import * as fs from 'fs'; +import * as proto from 'protobufjs'; +import { BaseDatabasePopulator } from './base-decompressors-populator'; + +const COMPRESSED_PREFIX = 'Comp'; +const GZLIB_PREFIX = 'GZLIB'; + +export class PhpGzcompressDatabasePopulator extends BaseDatabasePopulator { + + protected async createCompressedKeys(): Promise { + await this.createGZCompressUnicodeKeys(); + await this.createGZCompressASCIIKeys(); + await this.createGZCompressJSONKeys(); + await this.createGZCompressPHPUnserializedJSONKeys(); + await this.createGZCompressMsgpackKeys(); + await this.createGZCompressProtobufKeys(); + await this.createGZCompressPickleKeys(); + await this.createGZCompressJavaSerializedObjectKeys(); + await this.createGZCompressVectorKeys(); + }; + + private async createGZCompressUnicodeKeys() { + const prefix = `${COMPRESSED_PREFIX}:${GZLIB_PREFIX}:Unicode`; + const rawValue = '漢字'; + + const buf = fflate.strToU8(rawValue); + const value = Buffer.from(fflate.zlibSync(buf)); + + await this.createHash(prefix, value, true); + }; + + private async createGZCompressASCIIKeys() { + const prefix = `${COMPRESSED_PREFIX}:${GZLIB_PREFIX}:ASCII`; + const rawValue = '\xac\xed\x00\x05t\x0a4102'; + const buf = fflate.strToU8(rawValue); + const value = Buffer.from(fflate.zlibSync(buf)); + + await this.createHash(prefix, value, true); + }; + + private async createGZCompressJSONKeys() { + const prefix = `${COMPRESSED_PREFIX}:${GZLIB_PREFIX}:JSON`; + const rawValue = '{"test":"test"}'; + + const buf = fflate.strToU8(rawValue); + const value = Buffer.from(fflate.zlibSync(buf)); + + await this.createHash(prefix, value, true); + }; + + private async createGZCompressPHPUnserializedJSONKeys() { + const prefix = `${COMPRESSED_PREFIX}:${GZLIB_PREFIX}:PHP`; + const rawValue = 'a:2:{i:0;s:12:"Sample array";i:1;a:2:{i:0;s:5:"Apple";i:1;s:6:"Orange";}}'; + + const buf = fflate.strToU8(rawValue); + const value = Buffer.from(fflate.zlibSync(buf)); + + await this.createHash(prefix, value, true); + }; + + private async createGZCompressJavaSerializedObjectKeys() { + const prefix = `${COMPRESSED_PREFIX}:${GZLIB_PREFIX}:Java`; + const rawValue = fs.readFileSync('./test-data/decompressors/test_serialised_obj.ser'); + const rawValue2 = fs.readFileSync('./test-data/decompressors/test_annotated_obj.ser'); + + const value = Buffer.from(fflate.zlibSync(rawValue)); + const value2 = Buffer.from(fflate.zlibSync(rawValue2)); + + await this.createHash(prefix, value, true, value2); + }; + + private async createGZCompressMsgpackKeys() { + const prefix = `${COMPRESSED_PREFIX}:${GZLIB_PREFIX}:Msgpack`; + const rawValue = msgpackrPack({ + hello: 'World', + array: [1, 2], + obj: {test: 'test'}, + boolean: false, + }); + + const value = Buffer.from(fflate.zlibSync(rawValue)); + + await this.createHash(prefix, value, true); + }; + + private async createGZCompressVectorKeys() { + const prefix = `${COMPRESSED_PREFIX}:${GZLIB_PREFIX}:Vector`; + const rawValue = JSON.parse(fs.readFileSync('./test-data/decompressors/vector.json', 'utf8')); + + const value = Buffer.from(fflate.zlibSync(rawValue)); + + await this.createHash(prefix, value, true); + }; + + private createGZCompressProtobufKeys() : Promise { + return new Promise((resolve, reject) => { + const prefix = `${COMPRESSED_PREFIX}:${GZLIB_PREFIX}:Proto`; + + proto.load('./test-data/decompressors/awesome.proto', async (err, root) => { + if (err || !root) { + console.error('Error loading protobuf:', err); + return reject(err); + } + try { + const Book = root.lookupType('com.book.BookStore') + const payloadBookStore = { + name: 'Test name', + books: { 0: 'book 1', 1: 'book 2' }, + }; + const message = Book.create(payloadBookStore); // or use .fromObject if conversion is necessary + + // Encode a message to an Uint8Array (browser) or Buffer (node) + const rawValue = Book.encode(message).finish(); + + const value = Buffer.from(fflate.zlibSync(rawValue)); + await this.createHash(prefix, value); + resolve(); + } catch (error) { + reject(error); + } + }); + }); + }; + + private async createGZCompressPickleKeys() { + const prefix = `${COMPRESSED_PREFIX}:${GZLIB_PREFIX}:Pickle`; + + const rawValue = fs.readFileSync('./test-data/decompressors/test_serialised_obj.ser'); + const rawValue2 = fs.readFileSync('./test-data/decompressors/test_annotated_obj.ser'); + + const value = Buffer.from(fflate.zlibSync(rawValue)); + const value2 = Buffer.from(fflate.zlibSync(rawValue2)); + await this.createHash(prefix, value, true,value2); + }; +} + From 8c9123ce2574b52b1e3621ed15ef45f0b1692db7 Mon Sep 17 00:00:00 2001 From: mariasergeenko Date: Thu, 3 Oct 2024 15:05:57 +0200 Subject: [PATCH 098/256] update package.json --- tests/e2e/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/e2e/package.json b/tests/e2e/package.json index 91fe92eca8..6844badc51 100644 --- a/tests/e2e/package.json +++ b/tests/e2e/package.json @@ -13,7 +13,7 @@ "build:ui": "yarn --cwd ../../ build:ui", "redis:last": "docker run --name redis-last-version -p 7777:6379 -d redislabs/redismod", "start:app": "cross-env yarn start:api", - "test:chrome": "testcafe --compiler-options typescript.configPath=tsconfig.testcafe.json --cache --disable-multiple-windows --concurrency 1 chrome:--disable-search-engine-choice-screen tests/ -r html:./report/report.html,spec -e -s takeOnFails=true,path=report/screenshots/,pathPattern=${OS}_${BROWSER}/${DATE}_${TIME}/${FIXTURE}_${TEST}_${FILE_INDEX}.png", + "test:chrome": "testcafe --compiler-options typescript.configPath=tsconfig.testcafe.json --cache --allow-insecure-localhost --disable-multiple-windows --concurrency 1 chrome tests/ -r html:./report/report.html,spec -e -s takeOnFails=true,path=report/screenshots/,pathPattern=${OS}_${BROWSER}/${DATE}_${TIME}/${FIXTURE}_${TEST}_${FILE_INDEX}.png", "test:chrome:ci": "ts-node ./web.runner.ts", "test": "yarn test:chrome", "lint": "eslint . --ext .ts,.js,.tsx,.jsx", From 2b79713d57f4b4e6dec61deb6dc61ad36c2bf07c Mon Sep 17 00:00:00 2001 From: Roman Sergeenko Date: Thu, 3 Oct 2024 15:31:05 +0200 Subject: [PATCH 099/256] #RI-6135 - fix tests --- redisinsight/ui/src/pages/search/components/query/Query.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/redisinsight/ui/src/pages/search/components/query/Query.tsx b/redisinsight/ui/src/pages/search/components/query/Query.tsx index 32e992a49f..20aae087c4 100644 --- a/redisinsight/ui/src/pages/search/components/query/Query.tsx +++ b/redisinsight/ui/src/pages/search/components/query/Query.tsx @@ -131,7 +131,7 @@ const Query = (props: Props) => { }) const suggestionWidget = editor.getContribution('editor.contrib.suggestController') - suggestionWidget.onWillInsertSuggestItem(({ item }: Record<'item', any>) => { + suggestionWidget?.onWillInsertSuggestItem(({ item }: Record<'item', any>) => { if (item.completion.id === EmptySuggestionsIds.NoIndexes) { updateHelpWidget(true) editor.trigger('', 'hideSuggestWidget', null) From 3d51076b3c9f8c08f676933e8f8ef46c8c23f908 Mon Sep 17 00:00:00 2001 From: Kristiyan Ivanov Date: Thu, 3 Oct 2024 18:32:29 +0300 Subject: [PATCH 100/256] RI-6160 fixed UI test --- .../list-details/add-list-elements/AddListElements.spec.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/redisinsight/ui/src/pages/browser/modules/key-details/components/list-details/add-list-elements/AddListElements.spec.tsx b/redisinsight/ui/src/pages/browser/modules/key-details/components/list-details/add-list-elements/AddListElements.spec.tsx index 4209a6bae0..25a2534cc7 100644 --- a/redisinsight/ui/src/pages/browser/modules/key-details/components/list-details/add-list-elements/AddListElements.spec.tsx +++ b/redisinsight/ui/src/pages/browser/modules/key-details/components/list-details/add-list-elements/AddListElements.spec.tsx @@ -14,7 +14,7 @@ describe('AddListElements', () => { it('should set elements input properly', () => { render() - const elementsInput = screen.getByTestId('elements-input') + const elementsInput = screen.getByTestId(elementFindingRegex) fireEvent.change( elementsInput, { target: { value: '123' } } From e63b3fbde86752aaf52d170a7e0adcdb5f4c5dbc Mon Sep 17 00:00:00 2001 From: mariasergeenko Date: Fri, 4 Oct 2024 09:37:18 +0200 Subject: [PATCH 101/256] add test when there is no index --- .../no-indexes-suggestions.e2e.ts | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 tests/e2e/tests/web/regression/search-and-query/no-indexes-suggestions.e2e.ts diff --git a/tests/e2e/tests/web/regression/search-and-query/no-indexes-suggestions.e2e.ts b/tests/e2e/tests/web/regression/search-and-query/no-indexes-suggestions.e2e.ts new file mode 100644 index 0000000000..b076bd565c --- /dev/null +++ b/tests/e2e/tests/web/regression/search-and-query/no-indexes-suggestions.e2e.ts @@ -0,0 +1,36 @@ +import { DatabaseHelper } from '../../../../helpers/database'; +import { BrowserPage } from '../../../../pageObjects'; +import { rte } from '../../../../helpers/constants'; +import { commonUrl, ossClusterConfig, ossStandaloneConfig, ossStandaloneRedisearch } from '../../../../helpers/conf'; +import { DatabaseAPIRequests } from '../../../../helpers/api/api-database'; +import { SearchAndQueryPage } from '../../../../pageObjects/search-and-query-page'; + +const browserPage = new BrowserPage(); +const databaseHelper = new DatabaseHelper(); +const databaseAPIRequests = new DatabaseAPIRequests(); +const searchAndQueryPage = new SearchAndQueryPage(); + +fixture `Search and Query Raw mode` + .meta({ type: 'critical_path', rte: rte.standalone }) + .page(commonUrl); + +test + .before(async t => { + await databaseHelper.acceptLicenseTermsAndAddOSSClusterDatabase(ossClusterConfig); + await browserPage.Cli.sendCommandInCli('flushdb'); + }) + .after(async t => { + await databaseAPIRequests.deleteOSSClusterDatabaseApi(ossClusterConfig); + + })('Verify suggestions when there are no indexes', async t => { + + // TODO add navigation to search and query Monaco + + await t.typeText(searchAndQueryPage.queryInput, 'FT.SE', { replace: true }); + await t.pressKey('enter'); + + await t.expect(searchAndQueryPage.MonacoEditor.monacoSuggestion.withExactText('No indexes to display').exists).ok('info text is not displayed'); + + await t.pressKey('ctrl+space'); + await t.expect(await searchAndQueryPage.MonacoEditor.monacoCommandDetails.find('a').exists).ok('no link in the details') + }); From d49c34c9ab629e1f0daff5cb041511ecd165c551 Mon Sep 17 00:00:00 2001 From: Kristiyan Ivanov Date: Fri, 4 Oct 2024 10:40:16 +0300 Subject: [PATCH 102/256] RI-6160 fixed api test --- .../src/modules/browser/list/list.service.spec.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/redisinsight/api/src/modules/browser/list/list.service.spec.ts b/redisinsight/api/src/modules/browser/list/list.service.spec.ts index d1383058ad..c8726bff08 100644 --- a/redisinsight/api/src/modules/browser/list/list.service.spec.ts +++ b/redisinsight/api/src/modules/browser/list/list.service.spec.ts @@ -84,7 +84,7 @@ describe('ListService', () => { .calledWith([ BrowserToolListCommands.LPush, mockPushElementDto.keyName, - mockPushElementDto.elements, + ...mockPushElementDto.elements, ]) .mockResolvedValue(1); @@ -125,7 +125,7 @@ describe('ListService', () => { .calledWith([ BrowserToolListCommands.RPushX, mockPushElementDto.keyName, - mockPushElementDto.elements, + ...mockPushElementDto.elements, ]) .mockResolvedValue(1); @@ -138,7 +138,7 @@ describe('ListService', () => { .calledWith([ BrowserToolListCommands.LPushX, mockPushElementDto.keyName, - mockPushElementDto.elements, + ...mockPushElementDto.elements, ]) .mockResolvedValue(12); @@ -154,7 +154,7 @@ describe('ListService', () => { .calledWith([ BrowserToolListCommands.RPushX, mockPushElementDto.keyName, - mockPushElementDto.elements, + ...mockPushElementDto.elements, ]) .mockResolvedValue(0); @@ -475,7 +475,7 @@ describe('ListService', () => { it("shouldn't throw error", async () => { when(mockStandaloneRedisClient.sendPipeline) .calledWith([ - [BrowserToolListCommands.LPush, dto.keyName, dto.elements], + [BrowserToolListCommands.LPush, dto.keyName, ...dto.elements], [BrowserToolKeysCommands.Expire, dto.keyName, dto.expire], ]) .mockResolvedValue([ @@ -494,7 +494,7 @@ describe('ListService', () => { }; when(mockStandaloneRedisClient.sendPipeline) .calledWith([ - [BrowserToolListCommands.LPush, dto.keyName, dto.elements], + [BrowserToolListCommands.LPush, dto.keyName, ...dto.elements], [BrowserToolKeysCommands.Expire, dto.keyName, dto.expire], ]) .mockResolvedValue([[replyError, []]]); From 5a060be79d7e36343311eae5b536366e9f1e6ab6 Mon Sep 17 00:00:00 2001 From: mariasergeenko Date: Fri, 4 Oct 2024 12:08:55 +0200 Subject: [PATCH 103/256] fix per comments --- .../base-decompressors-populator.ts | 22 ++++++++----------- .../brotli-database-populator.ts | 9 ++++++++ .../decompressors/gzip-database-populator.ts | 9 ++++++++ .../decompressors/lz4-database-populator.ts | 19 ++++++++-------- .../php-gzcompress-database-populator.ts | 16 +++++++------- 5 files changed, 44 insertions(+), 31 deletions(-) diff --git a/tests/e2e/helpers/decompressors/base-decompressors-populator.ts b/tests/e2e/helpers/decompressors/base-decompressors-populator.ts index 535d786171..e25a7fabac 100644 --- a/tests/e2e/helpers/decompressors/base-decompressors-populator.ts +++ b/tests/e2e/helpers/decompressors/base-decompressors-populator.ts @@ -14,6 +14,9 @@ export abstract class BaseDatabasePopulator { }); } + /** + * Populate db with compressed keys + */ public async populateDB(): Promise { this.client.on('connect', async () => { console.log('Connected to Redis'); @@ -29,24 +32,17 @@ export abstract class BaseDatabasePopulator { protected async createHash( prefix: string, - value: Buffer, - onlyOneItem = false, - value2: Buffer = Buffer.from('') + values: Buffer[] ): Promise { let fields: string[] = []; const randomNumber = Array.from({ length: 5 }).map(() => Math.random()); - const field = `${value.toString()}:${randomNumber.toString()}`; - const fieldValue = `${value.toString()}:${randomNumber.toString()}`; - fields.push(field, fieldValue); - if (onlyOneItem) { - fields = [value.toString(), value.toString()]; - } - - if (value2) { - fields.push(value2.toString(), value2.toString()); - } + values.forEach((value) => { + const field = `${value.toString()}:${randomNumber.toString()}`; + const fieldValue = `${value.toString()}:${randomNumber.toString()}`; + fields.push(field, fieldValue); + }); try { await this.client.hset(`${prefix}:hash`, ...fields); diff --git a/tests/e2e/helpers/decompressors/brotli-database-populator.ts b/tests/e2e/helpers/decompressors/brotli-database-populator.ts index 970fa8a9b3..41499288e8 100644 --- a/tests/e2e/helpers/decompressors/brotli-database-populator.ts +++ b/tests/e2e/helpers/decompressors/brotli-database-populator.ts @@ -29,6 +29,7 @@ export class BrotliDatabasePopulator extends BaseDatabasePopulator { const buf = encoder.encode(rawValue); const value = Buffer.from(await brotli.compress(buf)); await this.createString(prefix, value); + await this.createHash(prefix, [value]); } private async createBrotliASCIIKeys() { @@ -37,6 +38,7 @@ export class BrotliDatabasePopulator extends BaseDatabasePopulator { const buf = fflate.strToU8(rawValue); const value = Buffer.from(await brotli.compress(buf)); await this.createString(prefix, value); + await this.createHash(prefix, [value]); } private async createBrotliVectorKeys() { @@ -45,6 +47,7 @@ export class BrotliDatabasePopulator extends BaseDatabasePopulator { const buf = fflate.strToU8(rawValue); const value = Buffer.from(await brotli.compress(buf)); await this.createString(prefix, value); + await this.createHash(prefix, [value]); } private async createBrotliJSONKeys() { @@ -53,6 +56,7 @@ export class BrotliDatabasePopulator extends BaseDatabasePopulator { const buf = fflate.strToU8(rawValue); const value = Buffer.from(await brotli.compress(buf)); await this.createString(prefix, value); + await this.createHash(prefix, [value]); } private async createBrotliPHPUnserializedJSONKeys() { @@ -61,6 +65,7 @@ export class BrotliDatabasePopulator extends BaseDatabasePopulator { const buf = fflate.strToU8(rawValue); const value = Buffer.from(await brotli.compress(buf)); await this.createString(prefix, value); + await this.createHash(prefix, [value]); } private async createBrotliPickleKeys() { @@ -68,6 +73,7 @@ export class BrotliDatabasePopulator extends BaseDatabasePopulator { const rawValue = fs.readFileSync('./test-data/decompressors/pickleFile1.pickle'); const value = Buffer.from(await brotli.compress(rawValue)); await this.createString(prefix, value); + await this.createHash(prefix, [value]); }; private async createBrotliJavaSerializedObjectKeys() { @@ -80,6 +86,7 @@ export class BrotliDatabasePopulator extends BaseDatabasePopulator { await this.createString(prefix, value); await this.createString(prefix, value2); + await this.createHash(prefix, [value,value2]); } private async createBrotliMsgpackKeys(): Promise { @@ -92,6 +99,7 @@ export class BrotliDatabasePopulator extends BaseDatabasePopulator { }); const value = Buffer.from(await brotli.compress(rawValue)); await this.createString(prefix, value); + await this.createHash(prefix, [value]); } private createBrotliProtobufKeys(): Promise { @@ -111,6 +119,7 @@ export class BrotliDatabasePopulator extends BaseDatabasePopulator { const value = Buffer.from(await brotli.compress(rawValue)); await this.createString(prefix, value); + await this.createHash(prefix, [value]); resolve(); } catch (error) { reject(error); diff --git a/tests/e2e/helpers/decompressors/gzip-database-populator.ts b/tests/e2e/helpers/decompressors/gzip-database-populator.ts index c2459dd68f..948eba5642 100644 --- a/tests/e2e/helpers/decompressors/gzip-database-populator.ts +++ b/tests/e2e/helpers/decompressors/gzip-database-populator.ts @@ -29,6 +29,7 @@ export class GzipDatabasePopulator extends BaseDatabasePopulator { const value = Buffer.from(fflate.compressSync(buf)); await this.createString(prefix, value); + await this.createHash(prefix, [value]); } private async createGZIPASCIIKeys(): Promise { @@ -38,6 +39,7 @@ export class GzipDatabasePopulator extends BaseDatabasePopulator { const value = Buffer.from(fflate.compressSync(buf)); await this.createString(prefix, value); + await this.createHash(prefix, [value]); } private async createGZIPJSONKeys(): Promise { @@ -47,6 +49,7 @@ export class GzipDatabasePopulator extends BaseDatabasePopulator { const value = Buffer.from(fflate.compressSync(buf)); await this.createString(prefix, value); + await this.createHash(prefix, [value]); } private async createGZIPPHPUnserializedJSONKeys(): Promise { @@ -57,6 +60,7 @@ export class GzipDatabasePopulator extends BaseDatabasePopulator { const value = Buffer.from(fflate.compressSync(buf)); await this.createString(prefix, value); + await this.createHash(prefix, [value]); } private async createGZIPJavaSerializedObjectKeys(): Promise { @@ -69,6 +73,7 @@ export class GzipDatabasePopulator extends BaseDatabasePopulator { await this.createString(prefix, value); await this.createString(prefix, value2); + await this.createHash(prefix, [value,value2]); } private async createGZIPMsgpackKeys(): Promise { @@ -83,6 +88,7 @@ export class GzipDatabasePopulator extends BaseDatabasePopulator { const value = Buffer.from(fflate.compressSync(rawValue)); await this.createString(prefix, value); + await this.createHash(prefix, [value]); } private async createGZIPVectorKeys(): Promise { @@ -91,6 +97,7 @@ export class GzipDatabasePopulator extends BaseDatabasePopulator { const value = Buffer.from(fflate.compressSync(rawValue)); await this.createString(prefix, value); + await this.createHash(prefix, [value]); } private createGZIPProtobufKeys(): Promise { @@ -113,6 +120,7 @@ export class GzipDatabasePopulator extends BaseDatabasePopulator { const value = Buffer.from(fflate.compressSync(rawValue)); await this.createString(prefix, value); + await this.createHash(prefix, [value]); resolve(); }); @@ -125,5 +133,6 @@ export class GzipDatabasePopulator extends BaseDatabasePopulator { const value = Buffer.from(fflate.compressSync(rawValue)); await this.createString(prefix, value); + await this.createHash(prefix, [value]); } } diff --git a/tests/e2e/helpers/decompressors/lz4-database-populator.ts b/tests/e2e/helpers/decompressors/lz4-database-populator.ts index dc23646a71..71aa8f4eca 100644 --- a/tests/e2e/helpers/decompressors/lz4-database-populator.ts +++ b/tests/e2e/helpers/decompressors/lz4-database-populator.ts @@ -27,7 +27,7 @@ export class LZ4DatabasePopulator extends BaseDatabasePopulator{ const rawValue = '漢字'; const buf = new TextEncoder().encode(rawValue); const value = Buffer.from(lz4js.compress(buf)); - await this.createHash(prefix, value); + await this.createHash(prefix, [value]); } private async createLZ4ASCIIKeys() { @@ -35,7 +35,7 @@ export class LZ4DatabasePopulator extends BaseDatabasePopulator{ const rawValue = '\xac\xed\x00\x05t\x0a4102'; const buf = fflate.strToU8(rawValue); const value = Buffer.from(lz4js.compress(buf)); - await this.createHash(prefix, value); + await this.createHash(prefix, [value]); } private async createLZ4JSONKeys() { @@ -43,7 +43,7 @@ export class LZ4DatabasePopulator extends BaseDatabasePopulator{ const rawValue = '{"test":"test"}'; const buf = fflate.strToU8(rawValue); const value = Buffer.from(lz4js.compress(buf)); - await this.createHash(prefix, value); + await this.createHash(prefix, [value]); } private async createLZ4PHPUnserializedJSONKeys() { @@ -51,7 +51,7 @@ export class LZ4DatabasePopulator extends BaseDatabasePopulator{ const rawValue = 'a:2:{i:0;s:12:"Sample array";i:1;a:2:{i:0;s:5:"Apple";i:1;s:6:"Orange";}}'; const buf = fflate.strToU8(rawValue); const value = Buffer.from(lz4js.compress(buf)); - await this.createHash(prefix, value); + await this.createHash(prefix, [value]); } private async createLZ4JavaSerializedObjectKeys() { @@ -60,8 +60,7 @@ export class LZ4DatabasePopulator extends BaseDatabasePopulator{ const rawValue2 = fs.readFileSync('./test-data/decompressors/test_annotated_obj.ser'); const value = Buffer.from(lz4js.compress(rawValue)); const value2 = Buffer.from(lz4js.compress(rawValue2)); - await this.createHash(prefix, value); - await this.createHash(prefix, value2); + await this.createHash(prefix, [value,value2]); } private async createLZ4MsgpackKeys(): Promise { @@ -73,7 +72,7 @@ export class LZ4DatabasePopulator extends BaseDatabasePopulator{ boolean: false, }); const value = Buffer.from(lz4js.compress(rawValue)); - await this.createHash(prefix, value); + await this.createHash(prefix, [value]); } private createLZ4ProtobufKeys(): Promise { @@ -90,7 +89,7 @@ export class LZ4DatabasePopulator extends BaseDatabasePopulator{ const message = Book.create(payload); const rawValue = Book.encode(message).finish(); const value = Buffer.from(lz4js.compress(rawValue)); - this.createHash(prefix, value); + await this.createHash(prefix, [value]); resolve(); } catch (error) { reject(error); @@ -103,14 +102,14 @@ export class LZ4DatabasePopulator extends BaseDatabasePopulator{ const prefix = `${COMPRESSED_PREFIX}:${LZ4_PREFIX}:Pickle`; const rawValue = fs.readFileSync('./test-data/decompressors/pickleFile1.pickle'); const value = Buffer.from(lz4js.compress(rawValue)); - await this.createHash(prefix, value); + await this.createHash(prefix, [value]); } private async createLZ4VectorKeys() { const prefix = `${COMPRESSED_PREFIX}:${LZ4_PREFIX}:Vector`; const rawValue = JSON.parse(fs.readFileSync('./test-data/decompressors/vector.json', 'utf8')); const value = Buffer.from(lz4js.compress(rawValue)); - await this.createHash(prefix, value); + await this.createHash(prefix, [value]); } } diff --git a/tests/e2e/helpers/decompressors/php-gzcompress-database-populator.ts b/tests/e2e/helpers/decompressors/php-gzcompress-database-populator.ts index ede4f7e93f..97bb2cc279 100644 --- a/tests/e2e/helpers/decompressors/php-gzcompress-database-populator.ts +++ b/tests/e2e/helpers/decompressors/php-gzcompress-database-populator.ts @@ -37,7 +37,7 @@ export class PhpGzcompressDatabasePopulator extends BaseDatabasePopulator { const buf = fflate.strToU8(rawValue); const value = Buffer.from(fflate.zlibSync(buf)); - await this.createHash(prefix, value, true); + await this.createHash(prefix, [value]); }; private async createGZCompressJSONKeys() { @@ -47,7 +47,7 @@ export class PhpGzcompressDatabasePopulator extends BaseDatabasePopulator { const buf = fflate.strToU8(rawValue); const value = Buffer.from(fflate.zlibSync(buf)); - await this.createHash(prefix, value, true); + await this.createHash(prefix, [value]); }; private async createGZCompressPHPUnserializedJSONKeys() { @@ -57,7 +57,7 @@ export class PhpGzcompressDatabasePopulator extends BaseDatabasePopulator { const buf = fflate.strToU8(rawValue); const value = Buffer.from(fflate.zlibSync(buf)); - await this.createHash(prefix, value, true); + await this.createHash(prefix, [value]); }; private async createGZCompressJavaSerializedObjectKeys() { @@ -68,7 +68,7 @@ export class PhpGzcompressDatabasePopulator extends BaseDatabasePopulator { const value = Buffer.from(fflate.zlibSync(rawValue)); const value2 = Buffer.from(fflate.zlibSync(rawValue2)); - await this.createHash(prefix, value, true, value2); + await this.createHash(prefix, [value,value2]); }; private async createGZCompressMsgpackKeys() { @@ -82,7 +82,7 @@ export class PhpGzcompressDatabasePopulator extends BaseDatabasePopulator { const value = Buffer.from(fflate.zlibSync(rawValue)); - await this.createHash(prefix, value, true); + await this.createHash(prefix, [value]); }; private async createGZCompressVectorKeys() { @@ -91,7 +91,7 @@ export class PhpGzcompressDatabasePopulator extends BaseDatabasePopulator { const value = Buffer.from(fflate.zlibSync(rawValue)); - await this.createHash(prefix, value, true); + await this.createHash(prefix, [value]); }; private createGZCompressProtobufKeys() : Promise { @@ -115,7 +115,7 @@ export class PhpGzcompressDatabasePopulator extends BaseDatabasePopulator { const rawValue = Book.encode(message).finish(); const value = Buffer.from(fflate.zlibSync(rawValue)); - await this.createHash(prefix, value); + await this.createHash(prefix, [value]); resolve(); } catch (error) { reject(error); @@ -132,7 +132,7 @@ export class PhpGzcompressDatabasePopulator extends BaseDatabasePopulator { const value = Buffer.from(fflate.zlibSync(rawValue)); const value2 = Buffer.from(fflate.zlibSync(rawValue2)); - await this.createHash(prefix, value, true,value2); + await this.createHash(prefix, [value,value2]); }; } From 071248dc4fdb25fe63c67ce493cf9fe094d728da Mon Sep 17 00:00:00 2001 From: mariasergeenko Date: Fri, 4 Oct 2024 12:38:37 +0200 Subject: [PATCH 104/256] unskip links --- .../critical-path/browser/bulk-upload.e2e.ts | 4 +- .../browser/search-capabilities.e2e.ts | 24 +++++----- .../cli/cli-command-helper.e2e.ts | 3 +- .../database/connecting-to-the-db.e2e.ts | 12 ++--- .../database/import-databases.e2e.ts | 4 +- .../web/regression/browser/survey-link.e2e.ts | 10 ++-- .../regression/cli/cli-command-helper.e2e.ts | 46 +++++++++---------- .../web/regression/database/github.e2e.ts | 4 +- .../web/regression/shortcuts/shortcuts.e2e.ts | 12 ++--- .../workbench/workbench-pipeline.e2e.ts | 8 ++-- 10 files changed, 63 insertions(+), 64 deletions(-) diff --git a/tests/e2e/tests/web/critical-path/browser/bulk-upload.e2e.ts b/tests/e2e/tests/web/critical-path/browser/bulk-upload.e2e.ts index 1bf6fef7ee..8d9da86f23 100644 --- a/tests/e2e/tests/web/critical-path/browser/bulk-upload.e2e.ts +++ b/tests/e2e/tests/web/critical-path/browser/bulk-upload.e2e.ts @@ -61,8 +61,8 @@ test('Verify bulk upload of different text docs formats', async t => { // Verify that user can remove uploaded file await t.setFilesToUpload(browserPage.BulkActions.bulkUploadInput, [filePathes.bigDataFile]); - // Unskip after updating testcafe with opening links support https://redislabs.atlassian.net/browse/RI-5565 - // await t.expect(browserPage.BulkActions.bulkUploadContainer.textContent).contains(filesToUpload[1], 'Filename not displayed in upload input'); + + await t.expect(browserPage.BulkActions.bulkUploadContainer.textContent).contains(filesToUpload[1], 'Filename not displayed in upload input'); await t.click(browserPage.BulkActions.removeFileBtn); await t.expect(browserPage.BulkActions.bulkUploadContainer.textContent).contains(defaultText, 'File not removed from upload input'); diff --git a/tests/e2e/tests/web/critical-path/browser/search-capabilities.e2e.ts b/tests/e2e/tests/web/critical-path/browser/search-capabilities.e2e.ts index 1728346db0..7d9efa1c66 100644 --- a/tests/e2e/tests/web/critical-path/browser/search-capabilities.e2e.ts +++ b/tests/e2e/tests/web/critical-path/browser/search-capabilities.e2e.ts @@ -155,17 +155,17 @@ test await databaseAPIRequests.deleteStandaloneDatabaseApi(ossStandaloneV5Config); })('No RediSearch module message', async t => { const noRedisearchMessage = 'RediSearch is not available for this database'; - // const externalPageLinkFirst = 'https://redis.io/try-free'; - // const externalPageLinkSecond = '?utm_source=redisinsight&utm_medium=app&utm_campaign=redisinsight_browser_search' + const externalPageLinkFirst = 'https://redis.io/try-free'; + const externalPageLinkSecond = '?utm_source=redisinsight&utm_medium=app&utm_campaign=redisinsight_browser_search' await t.click(browserPage.redisearchModeBtn); // Verify that user can see message in the dialog when he doesn't have RediSearch module await t.expect(browserPage.noReadySearchDialogTitle.textContent).contains(noRedisearchMessage, 'Invalid text in no redisearch popover'); - // Unskip after updating testcafe with opening links support https://redislabs.atlassian.net/browse/RI-5565 - // // Verify that user can navigate by link to create a Redis db - // await t.click(browserPage.redisearchFreeLink); - // await Common.checkURLContainsText(externalPageLinkFirst); - // await Common.checkURLContainsText(externalPageLinkSecond); + + // Verify that user can navigate by link to create a Redis db + await t.click(browserPage.redisearchFreeLink); + await Common.checkURLContainsText(externalPageLinkFirst); + await Common.checkURLContainsText(externalPageLinkSecond); }); test .before(async() => { @@ -190,11 +190,11 @@ test await t.click(browserPage.selectIndexDdn); await t.click(browserPage.createIndexBtn); await t.expect(browserPage.newIndexPanel.exists).ok('New Index panel is not displayed'); - // Unskip after updating testcafe with opening links support https://redislabs.atlassian.net/browse/RI-5565 - // // Verify that user can see a link to create a profound index and navigate - // await t.click(browserPage.newIndexPanel.find('a')); - // await Common.checkURL(createIndexLink); - // await goBackHistory(); + + // Verify that user can see a link to create a profound index and navigate + await t.click(browserPage.newIndexPanel.find('a')); + await Common.checkURL(createIndexLink); + await goBackHistory(); // Verify that user can create an index with multiple prefixes // await t.click(browserPage.selectIndexDdn); diff --git a/tests/e2e/tests/web/critical-path/cli/cli-command-helper.e2e.ts b/tests/e2e/tests/web/critical-path/cli/cli-command-helper.e2e.ts index 5247abc12e..3c6300d885 100644 --- a/tests/e2e/tests/web/critical-path/cli/cli-command-helper.e2e.ts +++ b/tests/e2e/tests/web/critical-path/cli/cli-command-helper.e2e.ts @@ -91,8 +91,7 @@ test('Verify that user can type TS. in Command helper and see commands from Redi // Search per part of command and check all opened commands await browserPage.CommandHelper.checkSearchedCommandInCommandHelper(commandForSearch, timeSeriesCommands); // Check the first command documentation url - // Unskip after updating testcafe with opening links support https://redislabs.atlassian.net/browse/RI-5565 - // await browserPage.CommandHelper.checkURLCommand(timeSeriesCommands[0], `https://redis.io/docs/latest/commands/${timeSeriesCommands[0].toLowerCase()}/?utm_source=redisinsight&utm_medium=app&utm_campaign=redisinsight_command_helper`); + await browserPage.CommandHelper.checkURLCommand(timeSeriesCommands[0], `https://redis.io/docs/latest/commands/${timeSeriesCommands[0].toLowerCase()}/?utm_source=redisinsight&utm_medium=app&utm_campaign=redisinsight_command_helper`); }); // outdated after https://redislabs.atlassian.net/browse/RI-4608 test.skip('Verify that user can type GRAPH. in Command helper and see auto-suggestions from RedisGraph commands.json', async t => { diff --git a/tests/e2e/tests/web/critical-path/database/connecting-to-the-db.e2e.ts b/tests/e2e/tests/web/critical-path/database/connecting-to-the-db.e2e.ts index 47c970752f..fa0be017ea 100644 --- a/tests/e2e/tests/web/critical-path/database/connecting-to-the-db.e2e.ts +++ b/tests/e2e/tests/web/critical-path/database/connecting-to-the-db.e2e.ts @@ -6,6 +6,7 @@ import { DatabaseAPIRequests } from '../../../../helpers/api/api-database'; import { sshPrivateKey, sshPrivateKeyWithPasscode } from '../../../../test-data/sshPrivateKeys'; import { Common } from '../../../../helpers/common'; import { BrowserActions } from '../../../../common-actions/browser-actions'; +import { goBackHistory } from '../../../../helpers/utils'; const myRedisDatabasePage = new MyRedisDatabasePage(); const browserPage = new BrowserPage(); @@ -181,14 +182,14 @@ test await myRedisDatabasePage.clickOnDBByName(sshDbPass.databaseName); await Common.checkURLContainsText('browser'); }); -test +test.only .meta({ rte: rte.none }) .before(async() => { await databaseAPIRequests.deleteAllDatabasesApi(); await databaseHelper.acceptLicenseTerms(); })('Verify that user can see the No databases message on the empty databases list', async t => { const noDatabasesMessage = 'No databases yet, let\'s add one!'; - // const externalPageLink = 'https://redis.io/try-free/?utm_source=redisinsight&utm_medium=main&utm_campaign=main' + const externalPageLink = 'https://redis.io/try-free/?utm_source=redisinsight&utm_medium=main&utm_campaign=empty_db_list' await t.expect(myRedisDatabasePage.emptyListMessage.withText(noDatabasesMessage).exists).ok('Empty databases list message not displayed'); @@ -196,8 +197,7 @@ test await t.expect(myRedisDatabasePage.AddRedisDatabase.testConnectionBtn.exists).ok('Add database form not opened'); await t.click(myRedisDatabasePage.AddRedisDatabase.cancelButton); - // Unskip after updating testcafe with opening links support https://redislabs.atlassian.net/browse/RI-5565 - // await t.click(myRedisDatabasePage.emptyDbCloudBtn); - // await Common.checkURL(externalPageLink); - // await goBackHistory(); + await t.click(myRedisDatabasePage.emptyDbCloudBtn); + await Common.checkURL(externalPageLink); + await goBackHistory(); }); diff --git a/tests/e2e/tests/web/critical-path/database/import-databases.e2e.ts b/tests/e2e/tests/web/critical-path/database/import-databases.e2e.ts index e58cd53cf9..4744232112 100644 --- a/tests/e2e/tests/web/critical-path/database/import-databases.e2e.ts +++ b/tests/e2e/tests/web/critical-path/database/import-databases.e2e.ts @@ -125,8 +125,8 @@ test.before(async() => { await t.click(myRedisDatabasePage.Modal.closeModalButton); await t.click(myRedisDatabasePage.importDatabasesBtn); await t.setFilesToUpload(myRedisDatabasePage.importDatabaseInput, [rdmData.path]); - // Unskip after updating testcafe with opening links support https://redislabs.atlassian.net/browse/RI-5565 - // await t.expect(myRedisDatabasePage.importDbDialog.textContent).contains(fileNames.rdmFullJson, 'Filename not displayed in import input'); + + await t.expect(myRedisDatabasePage.importDbDialog.textContent).contains(fileNames.rdmFullJson, 'Filename not displayed in import input'); // Click on remove button await t.click(myRedisDatabasePage.removeImportedFileBtn); await t.expect(myRedisDatabasePage.importDbDialog.textContent).contains(defaultText, 'File not removed from import input'); diff --git a/tests/e2e/tests/web/regression/browser/survey-link.e2e.ts b/tests/e2e/tests/web/regression/browser/survey-link.e2e.ts index 23176285e8..bf4a0debf7 100644 --- a/tests/e2e/tests/web/regression/browser/survey-link.e2e.ts +++ b/tests/e2e/tests/web/regression/browser/survey-link.e2e.ts @@ -26,11 +26,11 @@ test('Verify that user can use survey link', async t => { // Verify that user can see survey link on any page inside of DB // Browser page await t.expect(browserPage.userSurveyLink.visible).ok('Survey Link is not displayed'); - // Unskip after updating testcafe with opening links support https://redislabs.atlassian.net/browse/RI-5565 - // await t.click(browserPage.userSurveyLink); - // // Verify that when users click on RI survey, they are redirected to https://www.surveymonkey.com/r/redisinsight - // await Common.checkURL(externalPageLink); - // await goBackHistory(); + + await t.click(browserPage.userSurveyLink); + // Verify that when users click on RI survey, they are redirected to https://www.surveymonkey.com/r/redisinsight + await Common.checkURL(externalPageLink); + await goBackHistory(); // Workbench page await t.click(myRedisDatabasePage.NavigationPanel.workbenchButton); await t.expect(browserPage.userSurveyLink.visible).ok('Survey Link is not displayed'); diff --git a/tests/e2e/tests/web/regression/cli/cli-command-helper.e2e.ts b/tests/e2e/tests/web/regression/cli/cli-command-helper.e2e.ts index e4432f25ce..2f05bb5e19 100644 --- a/tests/e2e/tests/web/regression/cli/cli-command-helper.e2e.ts +++ b/tests/e2e/tests/web/regression/cli/cli-command-helper.e2e.ts @@ -90,11 +90,11 @@ test('Verify that user can see in Command helper and click on new group "JSON", await t.click(browserPage.CommandHelper.cliHelperOutputTitles.withExactText(commandToCheck)); // Verify results of opened command await t.expect(browserPage.CommandHelper.cliHelperTitleArgs.textContent).eql(commandArgumentsToCheck, 'Selected command title not correct'); - // Unskip after updating testcafe with opening links support https://redislabs.atlassian.net/browse/RI-5565 - // // Click on Read More link for selected command - // await t.click(browserPage.CommandHelper.readMoreButton); - // // Check new opened window page with the correct URL - // await Common.checkURL(externalPageLink); + + // Click on Read More link for selected command + await t.click(browserPage.CommandHelper.readMoreButton); + // Check new opened window page with the correct URL + await Common.checkURL(externalPageLink); }); test('Verify that user can see in Command helper and click on new group "Search", can choose it and see list of commands in the group', async t => { filteringGroup = 'Search'; @@ -109,11 +109,11 @@ test('Verify that user can see in Command helper and click on new group "Search" await t.click(browserPage.CommandHelper.cliHelperOutputTitles.withExactText(commandToCheck)); // Verify results of opened command await t.expect(browserPage.CommandHelper.cliHelperTitleArgs.textContent).eql(commandArgumentsToCheck, 'Selected command title not correct'); - // Unskip after updating testcafe with opening links support https://redislabs.atlassian.net/browse/RI-5565 - // // Click on Read More link for selected command - // await t.click(browserPage.CommandHelper.readMoreButton); - // // Check new opened window page with the correct URL - // await Common.checkURL(externalPageLink); + + // Click on Read More link for selected command + await t.click(browserPage.CommandHelper.readMoreButton); + // Check new opened window page with the correct URL + await Common.checkURL(externalPageLink); }); test('Verify that user can see HyperLogLog title in Command Helper for this command group', async t => { filteringGroup = 'HyperLogLog'; @@ -128,11 +128,11 @@ test('Verify that user can see HyperLogLog title in Command Helper for this comm await t.click(browserPage.CommandHelper.cliHelperOutputTitles.withExactText(commandToCheck)); // Verify results of opened command await t.expect(browserPage.CommandHelper.cliHelperTitleArgs.textContent).eql(commandArgumentsToCheck, 'Selected command title not correct'); - // Unskip after updating testcafe with opening links support https://redislabs.atlassian.net/browse/RI-5565 - // // Click on Read More link for selected command - // await t.click(browserPage.CommandHelper.readMoreButton); - // // Check new opened window page with the correct URL - // await Common.checkURL(externalPageLink); + + // Click on Read More link for selected command + await t.click(browserPage.CommandHelper.readMoreButton); + // Check new opened window page with the correct URL + await Common.checkURL(externalPageLink); }); test('Verify that user can see all separated groups for AI json file (model, tensor, inference, script)', async t => { filteringGroups = ['Model', 'Script', 'Inference', 'Tensor']; @@ -230,14 +230,14 @@ test('Verify that user can work with Bloom groups in Command Helper (RedisBloom await t.click(browserPage.CommandHelper.cliHelperOutputTitles.withExactText(commandsToCheck[i])); // Verify results of opened command await t.expect(browserPage.CommandHelper.cliHelperTitleArgs.textContent).eql(commandsArgumentsToCheck[i], 'Selected command title not correct'); - // Unskip after updating testcafe with opening links support https://redislabs.atlassian.net/browse/RI-5565 - // // Verify that user can use Read More link for Bloom, Cuckoo, CMS, TDigest, TopK groups in Command Helper (RedisBloom module). - // await t.click(browserPage.CommandHelper.readMoreButton); - // // Check new opened window page with the correct URL - // await Common.checkURL(externalPageLinks[i]); - // // Close the window with external link to switch to the application window - // await goBackHistory(); - // await t.click(browserPage.CommandHelper.expandCommandHelperButton); + + // Verify that user can use Read More link for Bloom, Cuckoo, CMS, TDigest, TopK groups in Command Helper (RedisBloom module). + await t.click(browserPage.CommandHelper.readMoreButton); + // Check new opened window page with the correct URL + await Common.checkURL(externalPageLinks[i]); + // Close the window with external link to switch to the application window + await goBackHistory(); + await t.click(browserPage.CommandHelper.expandCommandHelperButton); i++; } }); diff --git a/tests/e2e/tests/web/regression/database/github.e2e.ts b/tests/e2e/tests/web/regression/database/github.e2e.ts index 2a05263539..997533ceee 100644 --- a/tests/e2e/tests/web/regression/database/github.e2e.ts +++ b/tests/e2e/tests/web/regression/database/github.e2e.ts @@ -33,6 +33,6 @@ test('Verify that user can work with Github link in the application', async t => await t.expect(myRedisDatabasePage.NavigationPanel.githubButton.visible).ok('Github button'); // Verify that when user clicks on Github icon he redirects to the URL: https://github.com/RedisInsight/RedisInsight await t.click(myRedisDatabasePage.NavigationPanel.githubButton); - // Unskip after updating testcafe with opening links support https://redislabs.atlassian.net/browse/RI-5565 - // await Common.checkURLContainsText('https://github.com/RedisInsight/RedisInsight'); + + await Common.checkURLContainsText('https://github.com/RedisInsight/RedisInsight'); }); diff --git a/tests/e2e/tests/web/regression/shortcuts/shortcuts.e2e.ts b/tests/e2e/tests/web/regression/shortcuts/shortcuts.e2e.ts index ff3c9f49d3..af12390894 100644 --- a/tests/e2e/tests/web/regression/shortcuts/shortcuts.e2e.ts +++ b/tests/e2e/tests/web/regression/shortcuts/shortcuts.e2e.ts @@ -31,12 +31,12 @@ test('Verify that user can see a summary of Shortcuts by clicking "Keyboard Shor // Verify that user can close the Shortcuts await t.click(myRedisDatabasePage.ShortcutsPanel.shortcutsCloseButton); await t.expect(myRedisDatabasePage.ShortcutsPanel.shortcutsPanel.exists).notOk('Shortcuts panel is not displayed'); - // Unskip after updating testcafe with opening links support https://redislabs.atlassian.net/browse/RI-5565 - // // Click on the Release Notes in Help Center - // await t.click(myRedisDatabasePage.NavigationPanel.helpCenterButton); - // await t.click(myRedisDatabasePage.NavigationPanel.HelpCenter.helpCenterReleaseNotesButton); - // // Verify redirected link opening Release Notes in Help Center - // await Common.checkURL('https://github.com/RedisInsight/RedisInsight/releases'); + + // Click on the Release Notes in Help Center + await t.click(myRedisDatabasePage.NavigationPanel.helpCenterButton); + await t.click(myRedisDatabasePage.NavigationPanel.HelpCenter.helpCenterReleaseNotesButton); + // Verify redirected link opening Release Notes in Help Center + await Common.checkURL('https://github.com/RedisInsight/RedisInsight/releases'); }); test('Verify that user can see description of the “up” shortcut in the Help Center > Keyboard Shortcuts > Workbench table', async t => { const description = [ diff --git a/tests/e2e/tests/web/regression/workbench/workbench-pipeline.e2e.ts b/tests/e2e/tests/web/regression/workbench/workbench-pipeline.e2e.ts index a78097f21e..6256bed78a 100644 --- a/tests/e2e/tests/web/regression/workbench/workbench-pipeline.e2e.ts +++ b/tests/e2e/tests/web/regression/workbench/workbench-pipeline.e2e.ts @@ -41,10 +41,10 @@ test('Verify that user can see the text in settings for pipeline with link', asy // Verify text in setting for pipeline await t.expect(settingsPage.accordionWorkbenchSettings.textContent).contains(pipelineText, 'Text is incorrect'); - // Unskip after updating testcafe with opening links support https://redislabs.atlassian.net/browse/RI-5565 - // await t.click(settingsPage.pipelineLink); - // // Check new opened window page with the correct URL - // await Common.checkURL(externalPageLink); + + await t.click(settingsPage.pipelineLink); + // Check new opened window page with the correct URL + await Common.checkURL(externalPageLink); }); test.skip('Verify that only chosen in pipeline number of commands is loading at the same time in Workbench', async t => { await settingsPage.changeCommandsInPipeline(pipelineValues[1]); From a8fe546b3a6fb0d21c6007253ce94184ebcbcf77 Mon Sep 17 00:00:00 2001 From: mariasergeenko Date: Fri, 4 Oct 2024 13:52:32 +0200 Subject: [PATCH 105/256] text fix --- .../web/critical-path/database/connecting-to-the-db.e2e.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/e2e/tests/web/critical-path/database/connecting-to-the-db.e2e.ts b/tests/e2e/tests/web/critical-path/database/connecting-to-the-db.e2e.ts index fa0be017ea..e725fc8b60 100644 --- a/tests/e2e/tests/web/critical-path/database/connecting-to-the-db.e2e.ts +++ b/tests/e2e/tests/web/critical-path/database/connecting-to-the-db.e2e.ts @@ -182,14 +182,14 @@ test await myRedisDatabasePage.clickOnDBByName(sshDbPass.databaseName); await Common.checkURLContainsText('browser'); }); -test.only +test .meta({ rte: rte.none }) .before(async() => { await databaseAPIRequests.deleteAllDatabasesApi(); await databaseHelper.acceptLicenseTerms(); })('Verify that user can see the No databases message on the empty databases list', async t => { const noDatabasesMessage = 'No databases yet, let\'s add one!'; - const externalPageLink = 'https://redis.io/try-free/?utm_source=redisinsight&utm_medium=main&utm_campaign=empty_db_list' + const externalPageLink = 'https://redis.io/try-free?utm_source=redisinsight&utm_medium=main&utm_campaign=empty_db_list' await t.expect(myRedisDatabasePage.emptyListMessage.withText(noDatabasesMessage).exists).ok('Empty databases list message not displayed'); From fb773904f0b29b9c52e05a4cd0b48e8d3cf6556c Mon Sep 17 00:00:00 2001 From: mariasergeenko Date: Fri, 4 Oct 2024 18:12:15 +0200 Subject: [PATCH 106/256] text fix#2 --- .../decompressors/base-decompressors-populator.ts | 10 ++++++++++ .../decompressors/brotli-database-populator.ts | 5 ++++- .../decompressors/gzip-database-populator.ts | 3 +++ .../decompressors/lz4-database-populator.ts | 13 ++++++++++++- .../php-gzcompress-database-populator.ts | 15 ++++++++++++++- 5 files changed, 43 insertions(+), 3 deletions(-) diff --git a/tests/e2e/helpers/decompressors/base-decompressors-populator.ts b/tests/e2e/helpers/decompressors/base-decompressors-populator.ts index e25a7fabac..5db1cddbf3 100644 --- a/tests/e2e/helpers/decompressors/base-decompressors-populator.ts +++ b/tests/e2e/helpers/decompressors/base-decompressors-populator.ts @@ -30,6 +30,11 @@ export abstract class BaseDatabasePopulator { }); } + /** + * create a hash + * @param prefix prefix of the key name + * @param values values of the hash + */ protected async createHash( prefix: string, values: Buffer[] @@ -53,6 +58,11 @@ export abstract class BaseDatabasePopulator { } } + /** + * create a string + * @param prefix prefix of the key name + * @param value values of the string + */ protected async createString(prefix: string, value: Buffer): Promise { this.client.set(`${prefix}:string`, value, (error: Error | null) => { if (error) { diff --git a/tests/e2e/helpers/decompressors/brotli-database-populator.ts b/tests/e2e/helpers/decompressors/brotli-database-populator.ts index 41499288e8..8f33d7d027 100644 --- a/tests/e2e/helpers/decompressors/brotli-database-populator.ts +++ b/tests/e2e/helpers/decompressors/brotli-database-populator.ts @@ -10,7 +10,10 @@ const BROTLI_PREFIX = 'BROTLI'; export class BrotliDatabasePopulator extends BaseDatabasePopulator { - protected async createCompressedKeys(): Promise { + /** + * Create keys with all types of Bolti compression + */ + protected async createCompressedKeys(): Promise { await this.createBrotliUnicodeKeys(); await this.createBrotliASCIIKeys(); await this.createBrotliVectorKeys(); diff --git a/tests/e2e/helpers/decompressors/gzip-database-populator.ts b/tests/e2e/helpers/decompressors/gzip-database-populator.ts index 948eba5642..35dba0199e 100644 --- a/tests/e2e/helpers/decompressors/gzip-database-populator.ts +++ b/tests/e2e/helpers/decompressors/gzip-database-populator.ts @@ -10,6 +10,9 @@ const GZIP_PREFIX = 'GZIP'; export class GzipDatabasePopulator extends BaseDatabasePopulator { + /** + * Create keys with all types of Gzip compression + */ protected async createCompressedKeys(): Promise { await this.createGZIPUnicodeKeys(); await this.createGZIPASCIIKeys(); diff --git a/tests/e2e/helpers/decompressors/lz4-database-populator.ts b/tests/e2e/helpers/decompressors/lz4-database-populator.ts index 71aa8f4eca..633ca58398 100644 --- a/tests/e2e/helpers/decompressors/lz4-database-populator.ts +++ b/tests/e2e/helpers/decompressors/lz4-database-populator.ts @@ -10,6 +10,9 @@ const LZ4_PREFIX = 'LZ4'; export class LZ4DatabasePopulator extends BaseDatabasePopulator{ + /** + * Create keys with all types of LZ4 compression + */ protected async createCompressedKeys(): Promise { await this.createLZ4UnicodeKeys(); await this.createLZ4ASCIIKeys(); @@ -28,6 +31,7 @@ export class LZ4DatabasePopulator extends BaseDatabasePopulator{ const buf = new TextEncoder().encode(rawValue); const value = Buffer.from(lz4js.compress(buf)); await this.createHash(prefix, [value]); + await this.createString(prefix, value); } private async createLZ4ASCIIKeys() { @@ -36,6 +40,7 @@ export class LZ4DatabasePopulator extends BaseDatabasePopulator{ const buf = fflate.strToU8(rawValue); const value = Buffer.from(lz4js.compress(buf)); await this.createHash(prefix, [value]); + await this.createString(prefix, value); } private async createLZ4JSONKeys() { @@ -44,6 +49,7 @@ export class LZ4DatabasePopulator extends BaseDatabasePopulator{ const buf = fflate.strToU8(rawValue); const value = Buffer.from(lz4js.compress(buf)); await this.createHash(prefix, [value]); + await this.createString(prefix, value); } private async createLZ4PHPUnserializedJSONKeys() { @@ -52,6 +58,7 @@ export class LZ4DatabasePopulator extends BaseDatabasePopulator{ const buf = fflate.strToU8(rawValue); const value = Buffer.from(lz4js.compress(buf)); await this.createHash(prefix, [value]); + await this.createString(prefix, value); } private async createLZ4JavaSerializedObjectKeys() { @@ -61,6 +68,7 @@ export class LZ4DatabasePopulator extends BaseDatabasePopulator{ const value = Buffer.from(lz4js.compress(rawValue)); const value2 = Buffer.from(lz4js.compress(rawValue2)); await this.createHash(prefix, [value,value2]); + await this.createString(prefix, value); } private async createLZ4MsgpackKeys(): Promise { @@ -73,6 +81,7 @@ export class LZ4DatabasePopulator extends BaseDatabasePopulator{ }); const value = Buffer.from(lz4js.compress(rawValue)); await this.createHash(prefix, [value]); + await this.createString(prefix, value); } private createLZ4ProtobufKeys(): Promise { @@ -90,6 +99,7 @@ export class LZ4DatabasePopulator extends BaseDatabasePopulator{ const rawValue = Book.encode(message).finish(); const value = Buffer.from(lz4js.compress(rawValue)); await this.createHash(prefix, [value]); + await this.createString(prefix, value); resolve(); } catch (error) { reject(error); @@ -103,6 +113,7 @@ export class LZ4DatabasePopulator extends BaseDatabasePopulator{ const rawValue = fs.readFileSync('./test-data/decompressors/pickleFile1.pickle'); const value = Buffer.from(lz4js.compress(rawValue)); await this.createHash(prefix, [value]); + await this.createString(prefix, value); } private async createLZ4VectorKeys() { @@ -110,6 +121,6 @@ export class LZ4DatabasePopulator extends BaseDatabasePopulator{ const rawValue = JSON.parse(fs.readFileSync('./test-data/decompressors/vector.json', 'utf8')); const value = Buffer.from(lz4js.compress(rawValue)); await this.createHash(prefix, [value]); + await this.createString(prefix, value); } - } diff --git a/tests/e2e/helpers/decompressors/php-gzcompress-database-populator.ts b/tests/e2e/helpers/decompressors/php-gzcompress-database-populator.ts index 97bb2cc279..6a7d4af6cd 100644 --- a/tests/e2e/helpers/decompressors/php-gzcompress-database-populator.ts +++ b/tests/e2e/helpers/decompressors/php-gzcompress-database-populator.ts @@ -9,6 +9,10 @@ const GZLIB_PREFIX = 'GZLIB'; export class PhpGzcompressDatabasePopulator extends BaseDatabasePopulator { + /** + * Create keys with all types of LZ4 compression + */ + protected async createCompressedKeys(): Promise { await this.createGZCompressUnicodeKeys(); await this.createGZCompressASCIIKeys(); @@ -28,7 +32,8 @@ export class PhpGzcompressDatabasePopulator extends BaseDatabasePopulator { const buf = fflate.strToU8(rawValue); const value = Buffer.from(fflate.zlibSync(buf)); - await this.createHash(prefix, value, true); + await this.createHash(prefix, [value]); + await this.createString(prefix, value); }; private async createGZCompressASCIIKeys() { @@ -38,6 +43,7 @@ export class PhpGzcompressDatabasePopulator extends BaseDatabasePopulator { const value = Buffer.from(fflate.zlibSync(buf)); await this.createHash(prefix, [value]); + await this.createString(prefix, value); }; private async createGZCompressJSONKeys() { @@ -48,6 +54,7 @@ export class PhpGzcompressDatabasePopulator extends BaseDatabasePopulator { const value = Buffer.from(fflate.zlibSync(buf)); await this.createHash(prefix, [value]); + await this.createString(prefix, value); }; private async createGZCompressPHPUnserializedJSONKeys() { @@ -58,6 +65,7 @@ export class PhpGzcompressDatabasePopulator extends BaseDatabasePopulator { const value = Buffer.from(fflate.zlibSync(buf)); await this.createHash(prefix, [value]); + await this.createString(prefix, value); }; private async createGZCompressJavaSerializedObjectKeys() { @@ -69,6 +77,7 @@ export class PhpGzcompressDatabasePopulator extends BaseDatabasePopulator { const value2 = Buffer.from(fflate.zlibSync(rawValue2)); await this.createHash(prefix, [value,value2]); + await this.createString(prefix, value); }; private async createGZCompressMsgpackKeys() { @@ -83,6 +92,7 @@ export class PhpGzcompressDatabasePopulator extends BaseDatabasePopulator { const value = Buffer.from(fflate.zlibSync(rawValue)); await this.createHash(prefix, [value]); + await this.createString(prefix, value); }; private async createGZCompressVectorKeys() { @@ -92,6 +102,7 @@ export class PhpGzcompressDatabasePopulator extends BaseDatabasePopulator { const value = Buffer.from(fflate.zlibSync(rawValue)); await this.createHash(prefix, [value]); + await this.createString(prefix, value); }; private createGZCompressProtobufKeys() : Promise { @@ -116,6 +127,7 @@ export class PhpGzcompressDatabasePopulator extends BaseDatabasePopulator { const value = Buffer.from(fflate.zlibSync(rawValue)); await this.createHash(prefix, [value]); + await this.createString(prefix, value); resolve(); } catch (error) { reject(error); @@ -133,6 +145,7 @@ export class PhpGzcompressDatabasePopulator extends BaseDatabasePopulator { const value = Buffer.from(fflate.zlibSync(rawValue)); const value2 = Buffer.from(fflate.zlibSync(rawValue2)); await this.createHash(prefix, [value,value2]); + await this.createString(prefix, value); }; } From 9b8039a03ac36913527b3615771279afeaa55ae8 Mon Sep 17 00:00:00 2001 From: Gnanesh Date: Sat, 5 Oct 2024 16:44:53 +0530 Subject: [PATCH 107/256] Bump socket.io-client to ^4.8.0 --- package.json | 2 +- yarn.lock | 48 ++++++++++++++++++++++++------------------------ 2 files changed, 25 insertions(+), 25 deletions(-) diff --git a/package.json b/package.json index 8ef5a28899..d2b6383bcc 100644 --- a/package.json +++ b/package.json @@ -266,7 +266,7 @@ "remark-gfm": "^3.0.1", "remark-parse": "^10.0.1", "remark-rehype": "^10.0.1", - "socket.io-client": "^4.4.0", + "socket.io-client": "^4.8.0", "unified": "^10.1.1", "unist-util-visit": "^4.1.0", "url-parse": "^1.5.10", diff --git a/yarn.lock b/yarn.lock index bebb660129..2f58e7dfdf 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6182,21 +6182,21 @@ end-of-stream@^1.0.0, end-of-stream@^1.1.0: dependencies: once "^1.4.0" -engine.io-client@~6.5.1: - version "6.5.1" - resolved "https://registry.yarnpkg.com/engine.io-client/-/engine.io-client-6.5.1.tgz#1735fb8ae3bae5ae13115e18d2f484daf005dd9c" - integrity sha512-hE5wKXH8Ru4L19MbM1GgYV/2Qo54JSMh1rlJbfpa40bEWkCKNo3ol2eOtGmowcr+ysgbI7+SGL+by42Q3pt/Ng== +engine.io-client@~6.6.1: + version "6.6.1" + resolved "https://registry.yarnpkg.com/engine.io-client/-/engine.io-client-6.6.1.tgz#28a9cc4e90d448e1d0ba9369ad08a7af82f9956a" + integrity sha512-aYuoak7I+R83M/BBPIOs2to51BmFIpC1wZe6zZzMrT2llVsHy5cvcmdsJgP2Qz6smHu+sD9oexiSUAVd8OfBPw== dependencies: "@socket.io/component-emitter" "~3.1.0" debug "~4.3.1" - engine.io-parser "~5.1.0" - ws "~8.11.0" - xmlhttprequest-ssl "~2.0.0" + engine.io-parser "~5.2.1" + ws "~8.17.1" + xmlhttprequest-ssl "~2.1.1" -engine.io-parser@~5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/engine.io-parser/-/engine.io-parser-5.1.0.tgz#d593d6372d7f79212df48f807b8cace1ea1cb1b8" - integrity sha512-enySgNiK5tyZFynt3z7iqBR+Bto9EVVVvDFuTT0ioHCGbzirZVGDGiQjZzEp8hWl6hd5FSVytJGuScX1C1C35w== +engine.io-parser@~5.2.1: + version "5.2.3" + resolved "https://registry.yarnpkg.com/engine.io-parser/-/engine.io-parser-5.2.3.tgz#00dc5b97b1f233a23c9398d0209504cf5f94d92f" + integrity sha512-HqD3yTBfnBxIrbnM1DoD6Pcq8NECnh8d4As1Qgh0z5Gg3jRRIqijury0CL3ghu/edArpUYiYqQiDUQBIs4np3Q== enhanced-resolve@^0.9.1: version "0.9.1" @@ -13053,14 +13053,14 @@ snake-case@^3.0.4: dot-case "^3.0.4" tslib "^2.0.3" -socket.io-client@^4.4.0: - version "4.7.1" - resolved "https://registry.yarnpkg.com/socket.io-client/-/socket.io-client-4.7.1.tgz#48e5f703abe4fb0402182bcf9c06b7820fb3453b" - integrity sha512-Qk3Xj8ekbnzKu3faejo4wk2MzXA029XppiXtTF/PkbTg+fcwaTw1PlDrTrrrU4mKoYC4dvlApOnSeyLCKwek2w== +socket.io-client@^4.8.0: + version "4.8.0" + resolved "https://registry.yarnpkg.com/socket.io-client/-/socket.io-client-4.8.0.tgz#2ea0302d0032d23422bd2860f78127a800cad6a2" + integrity sha512-C0jdhD5yQahMws9alf/yvtsMGTaIDBnZ8Rb5HU56svyq0l5LIrGzIDZZD5pHQlmzxLuU91Gz+VpQMKgCTNYtkw== dependencies: "@socket.io/component-emitter" "~3.1.0" debug "~4.3.2" - engine.io-client "~6.5.1" + engine.io-client "~6.6.1" socket.io-parser "~4.2.4" socket.io-mock@^1.3.2: @@ -14944,10 +14944,10 @@ ws@^8.11.0, ws@^8.16.0: resolved "https://registry.yarnpkg.com/ws/-/ws-8.16.0.tgz#d1cd774f36fbc07165066a60e40323eab6446fd4" integrity sha512-HS0c//TP7Ina87TfiPUz1rQzMhHrl/SG2guqRcTOIUYD2q8uhUdNHZYJUaQ8aTGPzCh+c6oawMKW35nFl1dxyQ== -ws@~8.11.0: - version "8.11.0" - resolved "https://registry.yarnpkg.com/ws/-/ws-8.11.0.tgz#6a0d36b8edfd9f96d8b25683db2f8d7de6e8e143" - integrity sha512-HPG3wQd9sNQoT9xHyNCXoDUa+Xw/VevmY9FoHyQ+g+rrMn4j6FB4np7Z0OhdTgjx6MgQLK7jwSy1YecU1+4Asg== +ws@~8.17.1: + version "8.17.1" + resolved "https://registry.yarnpkg.com/ws/-/ws-8.17.1.tgz#9293da530bb548febc95371d90f9c878727d919b" + integrity sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ== xml-name-validator@^4.0.0: version "4.0.0" @@ -14964,10 +14964,10 @@ xmlchars@^2.2.0: resolved "https://registry.yarnpkg.com/xmlchars/-/xmlchars-2.2.0.tgz#060fe1bcb7f9c76fe2a17db86a9bc3ab894210cb" integrity sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw== -xmlhttprequest-ssl@~2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/xmlhttprequest-ssl/-/xmlhttprequest-ssl-2.0.0.tgz#91360c86b914e67f44dce769180027c0da618c67" - integrity sha512-QKxVRxiRACQcVuQEYFsI1hhkrMlrXHPegbbd1yn9UHOmRxY+si12nQYzri3vbzt8VdTTRviqcKxcyllFas5z2A== +xmlhttprequest-ssl@~2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/xmlhttprequest-ssl/-/xmlhttprequest-ssl-2.1.1.tgz#0d045c3b2babad8e7db1af5af093f5d0d60df99a" + integrity sha512-ptjR8YSJIXoA3Mbv5po7RtSYHO6mZr8s7i5VGmEk7QY2pQWyT1o0N+W1gKbOyJPUCGXGnuw0wqe8f0L6Y0ny7g== xtend@^4.0.0, xtend@^4.0.1, xtend@~4.0.1: version "4.0.2" From 138120f268820ad319a4a05505cde74980145c22 Mon Sep 17 00:00:00 2001 From: Gnanesh Date: Sat, 5 Oct 2024 17:02:27 +0530 Subject: [PATCH 108/256] Bump socket.io-client in api --- redisinsight/api/package.json | 2 +- redisinsight/api/yarn.lock | 35 ++++++++++++++++++++--------------- yarn.lock | 7 +------ 3 files changed, 22 insertions(+), 22 deletions(-) diff --git a/redisinsight/api/package.json b/redisinsight/api/package.json index ef95267875..9505fc0bcd 100644 --- a/redisinsight/api/package.json +++ b/redisinsight/api/package.json @@ -85,7 +85,7 @@ "reflect-metadata": "^0.1.13", "rxjs": "^7.5.6", "socket.io": "^4.6.2", - "socket.io-client": "^4.7.5", + "socket.io-client": "^4.8.0", "source-map-support": "^0.5.19", "sqlite3": "5.1.7", "swagger-ui-express": "^4.1.4", diff --git a/redisinsight/api/yarn.lock b/redisinsight/api/yarn.lock index fdecc94fe1..133eb68752 100644 --- a/redisinsight/api/yarn.lock +++ b/redisinsight/api/yarn.lock @@ -3292,16 +3292,16 @@ end-of-stream@^1.1.0, end-of-stream@^1.4.1: dependencies: once "^1.4.0" -engine.io-client@~6.5.2: - version "6.5.3" - resolved "https://registry.yarnpkg.com/engine.io-client/-/engine.io-client-6.5.3.tgz#4cf6fa24845029b238f83c628916d9149c399bc5" - integrity sha512-9Z0qLB0NIisTRt1DZ/8U2k12RJn8yls/nXMZLn+/N8hANT3TcYjKFKcwbw5zFQiN4NTde3TSY9zb79e1ij6j9Q== +engine.io-client@~6.6.1: + version "6.6.1" + resolved "https://registry.yarnpkg.com/engine.io-client/-/engine.io-client-6.6.1.tgz#28a9cc4e90d448e1d0ba9369ad08a7af82f9956a" + integrity sha512-aYuoak7I+R83M/BBPIOs2to51BmFIpC1wZe6zZzMrT2llVsHy5cvcmdsJgP2Qz6smHu+sD9oexiSUAVd8OfBPw== dependencies: "@socket.io/component-emitter" "~3.1.0" debug "~4.3.1" engine.io-parser "~5.2.1" - ws "~8.11.0" - xmlhttprequest-ssl "~2.0.0" + ws "~8.17.1" + xmlhttprequest-ssl "~2.1.1" engine.io-parser@~5.1.0: version "5.1.0" @@ -7894,14 +7894,14 @@ socket.io-adapter@~2.5.2: dependencies: ws "~8.11.0" -socket.io-client@^4.7.5: - version "4.7.5" - resolved "https://registry.yarnpkg.com/socket.io-client/-/socket.io-client-4.7.5.tgz#919be76916989758bdc20eec63f7ee0ae45c05b7" - integrity sha512-sJ/tqHOCe7Z50JCBCXrsY3I2k03iOiUe+tj1OmKeD2lXPiGH/RUCdTZFoqVyN7l1MnpIzPrGtLcijffmeouNlQ== +socket.io-client@^4.8.0: + version "4.8.0" + resolved "https://registry.yarnpkg.com/socket.io-client/-/socket.io-client-4.8.0.tgz#2ea0302d0032d23422bd2860f78127a800cad6a2" + integrity sha512-C0jdhD5yQahMws9alf/yvtsMGTaIDBnZ8Rb5HU56svyq0l5LIrGzIDZZD5pHQlmzxLuU91Gz+VpQMKgCTNYtkw== dependencies: "@socket.io/component-emitter" "~3.1.0" debug "~4.3.2" - engine.io-client "~6.5.2" + engine.io-client "~6.6.1" socket.io-parser "~4.2.4" socket.io-mock@^1.3.2: @@ -9308,6 +9308,11 @@ ws@~8.11.0: resolved "https://registry.yarnpkg.com/ws/-/ws-8.11.0.tgz#6a0d36b8edfd9f96d8b25683db2f8d7de6e8e143" integrity sha512-HPG3wQd9sNQoT9xHyNCXoDUa+Xw/VevmY9FoHyQ+g+rrMn4j6FB4np7Z0OhdTgjx6MgQLK7jwSy1YecU1+4Asg== +ws@~8.17.1: + version "8.17.1" + resolved "https://registry.yarnpkg.com/ws/-/ws-8.17.1.tgz#9293da530bb548febc95371d90f9c878727d919b" + integrity sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ== + xhr2@0.1.3: version "0.1.3" resolved "https://registry.yarnpkg.com/xhr2/-/xhr2-0.1.3.tgz#cbfc4759a69b4a888e78cf4f20b051038757bd11" @@ -9328,10 +9333,10 @@ xmlchars@^2.2.0: resolved "https://registry.yarnpkg.com/xmlchars/-/xmlchars-2.2.0.tgz#060fe1bcb7f9c76fe2a17db86a9bc3ab894210cb" integrity sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw== -xmlhttprequest-ssl@~2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/xmlhttprequest-ssl/-/xmlhttprequest-ssl-2.0.0.tgz#91360c86b914e67f44dce769180027c0da618c67" - integrity sha512-QKxVRxiRACQcVuQEYFsI1hhkrMlrXHPegbbd1yn9UHOmRxY+si12nQYzri3vbzt8VdTTRviqcKxcyllFas5z2A== +xmlhttprequest-ssl@~2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/xmlhttprequest-ssl/-/xmlhttprequest-ssl-2.1.1.tgz#0d045c3b2babad8e7db1af5af093f5d0d60df99a" + integrity sha512-ptjR8YSJIXoA3Mbv5po7RtSYHO6mZr8s7i5VGmEk7QY2pQWyT1o0N+W1gKbOyJPUCGXGnuw0wqe8f0L6Y0ny7g== xtend@^4.0.0: version "4.0.2" diff --git a/yarn.lock b/yarn.lock index 2f58e7dfdf..e291ca425f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -14939,12 +14939,7 @@ ws@^7.3.1: resolved "https://registry.yarnpkg.com/ws/-/ws-7.5.9.tgz#54fa7db29f4c7cec68b1ddd3a89de099942bb591" integrity sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q== -ws@^8.11.0, ws@^8.16.0: - version "8.16.0" - resolved "https://registry.yarnpkg.com/ws/-/ws-8.16.0.tgz#d1cd774f36fbc07165066a60e40323eab6446fd4" - integrity sha512-HS0c//TP7Ina87TfiPUz1rQzMhHrl/SG2guqRcTOIUYD2q8uhUdNHZYJUaQ8aTGPzCh+c6oawMKW35nFl1dxyQ== - -ws@~8.17.1: +ws@^8.11.0, ws@^8.16.0, ws@~8.17.1: version "8.17.1" resolved "https://registry.yarnpkg.com/ws/-/ws-8.17.1.tgz#9293da530bb548febc95371d90f9c878727d919b" integrity sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ== From 147204912f178d75dfcc5bda8e2db8dfba637e1d Mon Sep 17 00:00:00 2001 From: Gnanesh Date: Sat, 5 Oct 2024 17:27:48 +0530 Subject: [PATCH 109/256] Bump API's socket.io packages --- redisinsight/api/package.json | 6 ++--- redisinsight/api/yarn.lock | 46 ++++++++++++++++++++++++++++++----- 2 files changed, 43 insertions(+), 9 deletions(-) diff --git a/redisinsight/api/package.json b/redisinsight/api/package.json index 9505fc0bcd..61af6b0864 100644 --- a/redisinsight/api/package.json +++ b/redisinsight/api/package.json @@ -43,7 +43,7 @@ "nanoid": "^3.1.31", "word-wrap": "1.2.4", "mocha/minimatch": "^3.0.5", - "@nestjs/platform-socket.io/socket.io": "^4.7.1", + "@nestjs/platform-socket.io/socket.io": "^4.8.0", "**/semver": "^7.5.2", "winston-daily-rotate-file/**/file-stream-rotator": "^1.0.0" }, @@ -52,7 +52,7 @@ "@nestjs/core": "^10.3.7", "@nestjs/event-emitter": "^2.0.4", "@nestjs/platform-express": "^10.3.7", - "@nestjs/platform-socket.io": "^10.3.7", + "@nestjs/platform-socket.io": "^10.4.4", "@nestjs/serve-static": "^3.0.0", "@nestjs/swagger": "^7.3.1", "@nestjs/typeorm": "^9.0.1", @@ -84,7 +84,7 @@ "redis": "^4.6.10", "reflect-metadata": "^0.1.13", "rxjs": "^7.5.6", - "socket.io": "^4.6.2", + "socket.io": "^4.8.0", "socket.io-client": "^4.8.0", "source-map-support": "^0.5.19", "sqlite3": "5.1.7", diff --git a/redisinsight/api/yarn.lock b/redisinsight/api/yarn.lock index 133eb68752..0f2328a052 100644 --- a/redisinsight/api/yarn.lock +++ b/redisinsight/api/yarn.lock @@ -903,13 +903,13 @@ multer "1.4.4-lts.1" tslib "2.6.2" -"@nestjs/platform-socket.io@^10.3.7": - version "10.3.7" - resolved "https://registry.yarnpkg.com/@nestjs/platform-socket.io/-/platform-socket.io-10.3.7.tgz#d814da88f289f32d07d84db8a7e838c4f9cc5ef2" - integrity sha512-T9VbVgEUnbid/RiywN9/8YQ8pAGDP++0nX73l4kIWeDWkz5DEh4aLB7O/JvLA3/xRHdjTZ4RiRZazwqSWi1Sog== +"@nestjs/platform-socket.io@^10.4.4": + version "10.4.4" + resolved "https://registry.yarnpkg.com/@nestjs/platform-socket.io/-/platform-socket.io-10.4.4.tgz#ee505767102ab85890fdc3a7b0a7407f4b8b59a9" + integrity sha512-5GEYUA3sNbX2jOBP6FmrIK/zv9VCdvpdr4Sef1OKvt1U0qsV1YgmWPWDPumZM77n5DI0VHSJPyo7yjZaEKWOiQ== dependencies: socket.io "4.7.5" - tslib "2.6.2" + tslib "2.7.0" "@nestjs/schematics@^9.0.3", "@nestjs/schematics@^9.0.4": version "9.1.0" @@ -3329,6 +3329,22 @@ engine.io@~6.5.0: engine.io-parser "~5.1.0" ws "~8.11.0" +engine.io@~6.6.0: + version "6.6.1" + resolved "https://registry.yarnpkg.com/engine.io/-/engine.io-6.6.1.tgz#a82b1e5511239a0e95fac14516870ee9138febc8" + integrity sha512-NEpDCw9hrvBW+hVEOK4T7v0jFJ++KgtPl4jKFwsZVfG1XhS0dCrSb3VMb9gPAd7VAdW52VT1EnaNiU2vM8C0og== + dependencies: + "@types/cookie" "^0.4.1" + "@types/cors" "^2.8.12" + "@types/node" ">=10.0.0" + accepts "~1.3.4" + base64id "2.0.0" + cookie "~0.4.1" + cors "~2.8.5" + debug "~4.3.1" + engine.io-parser "~5.2.1" + ws "~8.17.1" + enhanced-resolve@^4.0.0: version "4.5.0" resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-4.5.0.tgz#2f3cfd84dbe3b487f18f2db2ef1e064a571ca5ec" @@ -7919,7 +7935,7 @@ socket.io-parser@~4.2.4: "@socket.io/component-emitter" "~3.1.0" debug "~4.3.1" -socket.io@*, socket.io@4.7.5, socket.io@^4.6.2, socket.io@^4.7.1: +socket.io@*: version "4.7.1" resolved "https://registry.yarnpkg.com/socket.io/-/socket.io-4.7.1.tgz#9009f31bf7be25478895145e92fbc972ad1db900" integrity sha512-W+utHys2w//dhFjy7iQQu9sGd3eokCjGbl2r59tyLqNiJJBdIebn3GAKEXBr3osqHTObJi2die/25bCx2zsaaw== @@ -7932,6 +7948,19 @@ socket.io@*, socket.io@4.7.5, socket.io@^4.6.2, socket.io@^4.7.1: socket.io-adapter "~2.5.2" socket.io-parser "~4.2.4" +socket.io@4.7.5, socket.io@^4.8.0: + version "4.8.0" + resolved "https://registry.yarnpkg.com/socket.io/-/socket.io-4.8.0.tgz#33d05ae0915fad1670bd0c4efcc07ccfabebe3b1" + integrity sha512-8U6BEgGjQOfGz3HHTYaC/L1GaxDCJ/KM0XTkJly0EhZ5U/du9uNEZy4ZgYzEzIqlx2CMm25CrCqr1ck899eLNA== + dependencies: + accepts "~1.3.4" + base64id "~2.0.0" + cors "~2.8.5" + debug "~4.3.2" + engine.io "~6.6.0" + socket.io-adapter "~2.5.2" + socket.io-parser "~4.2.4" + socks-proxy-agent@^6.0.0: version "6.2.1" resolved "https://registry.yarnpkg.com/socks-proxy-agent/-/socks-proxy-agent-6.2.1.tgz#2687a31f9d7185e38d530bef1944fe1f1496d6ce" @@ -8688,6 +8717,11 @@ tslib@2.6.2: resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.6.2.tgz#703ac29425e7b37cd6fd456e92404d46d1f3e4ae" integrity sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q== +tslib@2.7.0: + version "2.7.0" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.7.0.tgz#d9b40c5c40ab59e8738f297df3087bf1a2690c01" + integrity sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA== + tslib@^1.8.1, tslib@^1.9.0: version "1.14.1" resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" From 04309399695cf93ff54de84a155269e407eb3305 Mon Sep 17 00:00:00 2001 From: Gnanesh Date: Sat, 5 Oct 2024 17:35:32 +0530 Subject: [PATCH 110/256] Bump express and body parser packages --- redisinsight/api/package.json | 8 +- redisinsight/api/yarn.lock | 214 +++++++++++++++++++++++----------- 2 files changed, 152 insertions(+), 70 deletions(-) diff --git a/redisinsight/api/package.json b/redisinsight/api/package.json index 61af6b0864..932f697517 100644 --- a/redisinsight/api/package.json +++ b/redisinsight/api/package.json @@ -51,17 +51,17 @@ "@nestjs/common": "^10.3.7", "@nestjs/core": "^10.3.7", "@nestjs/event-emitter": "^2.0.4", - "@nestjs/platform-express": "^10.3.7", + "@nestjs/platform-express": "^10.4.4", "@nestjs/platform-socket.io": "^10.4.4", "@nestjs/serve-static": "^3.0.0", "@nestjs/swagger": "^7.3.1", "@nestjs/typeorm": "^9.0.1", "@nestjs/websockets": "^10.3.7", "@okta/okta-auth-js": "^7.3.0", - "@segment/analytics-node": "^2.1.2", + "@segment/analytics-node": "^2.1.3", "adm-zip": "^0.5.9", "axios": "^1.6.0", - "body-parser": "^1.19.0", + "body-parser": "^1.20.3", "busboy": "^1.6.0", "class-transformer": "^0.2.3", "class-validator": "^0.14.0", @@ -70,7 +70,7 @@ "date-fns": "^2.29.3", "detect-port": "^1.5.1", "dotenv": "^16.0.0", - "express": "^4.19.2", + "express": "^4.21.0", "fs-extra": "^10.0.0", "ioredis": "^5.2.2", "is-glob": "^4.0.1", diff --git a/redisinsight/api/yarn.lock b/redisinsight/api/yarn.lock index 0f2328a052..39cc84c493 100644 --- a/redisinsight/api/yarn.lock +++ b/redisinsight/api/yarn.lock @@ -892,16 +892,16 @@ resolved "https://registry.yarnpkg.com/@nestjs/mapped-types/-/mapped-types-2.0.5.tgz#485d6b44e19779c98d04e52bd1d2bcc7001df0ea" integrity sha512-bSJv4pd6EY99NX9CjBIyn4TVDoSit82DUZlL4I3bqNfy5Gt+gXTa86i3I/i0iIV9P4hntcGM5GyO+FhZAhxtyg== -"@nestjs/platform-express@^10.3.7": - version "10.3.7" - resolved "https://registry.yarnpkg.com/@nestjs/platform-express/-/platform-express-10.3.7.tgz#ae3fc59609bdc0ffc5029a6e74d59a5d1e257eef" - integrity sha512-noNJ+PyIxQJLCKfuXz0tcQtlVAynfLIuKy62g70lEZ86UrIqSrZFqvWs/rFUgkbT6J8H7Rmv11hASOnX+7M2rA== +"@nestjs/platform-express@^10.4.4": + version "10.4.4" + resolved "https://registry.yarnpkg.com/@nestjs/platform-express/-/platform-express-10.4.4.tgz#582d375272207f8d1528f77ff470ba815d9d9846" + integrity sha512-y52q1MxhbHaT3vAgWd08RgiYon0lJgtTa8U6g6gV0KI0IygwZhDQFJVxnrRDUdxQGIP5CKHmfQu3sk9gTNFoEA== dependencies: - body-parser "1.20.2" + body-parser "1.20.3" cors "2.8.5" - express "4.19.2" + express "4.21.0" multer "1.4.4-lts.1" - tslib "2.6.2" + tslib "2.7.0" "@nestjs/platform-socket.io@^10.4.4": version "10.4.4" @@ -1092,14 +1092,14 @@ resolved "https://registry.yarnpkg.com/@redis/time-series/-/time-series-1.0.5.tgz#a6d70ef7a0e71e083ea09b967df0a0ed742bc6ad" integrity sha512-IFjIgTusQym2B5IZJG3XKr5llka7ey84fw/NOYqESP5WUfQs9zz1ww/9+qoz4ka/S6KcGBodzlCeZ5UImKbscg== -"@segment/analytics-core@1.6.0": - version "1.6.0" - resolved "https://registry.yarnpkg.com/@segment/analytics-core/-/analytics-core-1.6.0.tgz#f59cdc45a4408a09fdae77910f5a0b43833e8af8" - integrity sha512-bn9X++IScUfpT7aJGjKU/yJAu/Ko2sYD6HsKA70Z2560E89x30pqgqboVKY8kootvQnT4UKCJiUr5NDMgjmWdQ== +"@segment/analytics-core@1.8.0": + version "1.8.0" + resolved "https://registry.yarnpkg.com/@segment/analytics-core/-/analytics-core-1.8.0.tgz#7189b79c21b8c41ec7d3dd10b158a756b034f206" + integrity sha512-6CrccsYRY33I3mONN2ZW8SdBpbLtu1Ict3xR+n0FemYF5RB/jG7pW6jOvDXULR8kuYMzMmGOP4HvlyUmf3qLpg== dependencies: "@lukeed/uuid" "^2.0.0" "@segment/analytics-generic-utils" "1.2.0" - dset "^3.1.2" + dset "^3.1.4" tslib "^2.4.1" "@segment/analytics-generic-utils@1.2.0": @@ -1109,13 +1109,13 @@ dependencies: tslib "^2.4.1" -"@segment/analytics-node@^2.1.2": - version "2.1.2" - resolved "https://registry.yarnpkg.com/@segment/analytics-node/-/analytics-node-2.1.2.tgz#ff1b913f23f6fbb9654a01154f33af56af6095fe" - integrity sha512-CIqWH5G0pB/LAFAZEZtntAxujiYIpdk0F+YGhfM6N/qt4/VLWjFcd4VZXVLW7xqaxig64UKWGQhe8bszXDRXXw== +"@segment/analytics-node@^2.1.3": + version "2.2.0" + resolved "https://registry.yarnpkg.com/@segment/analytics-node/-/analytics-node-2.2.0.tgz#e8fd59fb15757261156c1a36a60130b440fd8be5" + integrity sha512-mPFTSBr9CrkFBdgr7KU/YD8V/25P8vPb/hVvVHYKwEdHRovlizZ34ENgQlvqeRuamQiXD3RLM8pcWX+WxPz3lQ== dependencies: "@lukeed/uuid" "^2.0.0" - "@segment/analytics-core" "1.6.0" + "@segment/analytics-core" "1.8.0" "@segment/analytics-generic-utils" "1.2.0" buffer "^6.0.3" jose "^5.1.0" @@ -2175,10 +2175,10 @@ bl@^4.0.3, bl@^4.1.0: inherits "^2.0.4" readable-stream "^3.4.0" -body-parser@1.20.2, body-parser@^1.19.0: - version "1.20.2" - resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.20.2.tgz#6feb0e21c4724d06de7ff38da36dad4f57a747fd" - integrity sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA== +body-parser@1.20.3, body-parser@^1.20.3: + version "1.20.3" + resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.20.3.tgz#1953431221c6fb5cd63c4b36d53fab0928e548c6" + integrity sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g== dependencies: bytes "3.1.2" content-type "~1.0.5" @@ -2188,7 +2188,7 @@ body-parser@1.20.2, body-parser@^1.19.0: http-errors "2.0.0" iconv-lite "0.4.24" on-finished "2.4.1" - qs "6.11.0" + qs "6.13.0" raw-body "2.5.2" type-is "~1.6.18" unpipe "1.0.0" @@ -2396,6 +2396,17 @@ call-bind@^1.0.0, call-bind@^1.0.2: function-bind "^1.1.1" get-intrinsic "^1.0.2" +call-bind@^1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.7.tgz#06016599c40c56498c18769d2730be242b6fa3b9" + integrity sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w== + dependencies: + es-define-property "^1.0.0" + es-errors "^1.3.0" + function-bind "^1.1.2" + get-intrinsic "^1.2.4" + set-function-length "^1.2.1" + callsites@^3.0.0: version "3.1.0" resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" @@ -3085,6 +3096,15 @@ defaults@^1.0.3: dependencies: clone "^1.0.2" +define-data-property@^1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/define-data-property/-/define-data-property-1.1.4.tgz#894dc141bb7d3060ae4366f6a0107e68fbe48c5e" + integrity sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A== + dependencies: + es-define-property "^1.0.0" + es-errors "^1.3.0" + gopd "^1.0.1" + define-properties@^1.1.3, define-properties@^1.1.4, define-properties@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.2.0.tgz#52988570670c9eacedd8064f4a990f2405849bd5" @@ -3221,10 +3241,10 @@ dotenv@^16.0.0, dotenv@^16.0.3: resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-16.0.3.tgz#115aec42bac5053db3c456db30cc243a5a836a07" integrity sha512-7GO6HghkA5fYG9TYnNxi14/7K9f5occMlp3zXAuSxn7CKCxt9xbNWG7yF8hTCSUchlfWSe3uLmlPfigevRItzQ== -dset@^3.1.2: - version "3.1.3" - resolved "https://registry.yarnpkg.com/dset/-/dset-3.1.3.tgz#c194147f159841148e8e34ca41f638556d9542d2" - integrity sha512-20TuZZHCEZ2O71q9/+8BwKwZ0QtD9D8ObhrihJPr+vLLYlSuAU3/zL4cSlgbfeoGHTjCSJBa7NGcrF9/Bx/WJQ== +dset@^3.1.4: + version "3.1.4" + resolved "https://registry.yarnpkg.com/dset/-/dset-3.1.4.tgz#f8eaf5f023f068a036d08cd07dc9ffb7d0065248" + integrity sha512-2QF/g9/zTaPDc3BjNcVTGoBbXBgYfMTTceLaYcFJ/W9kggFUkhxD/hMEeuLKbugyef9SqAx8cpgwlIP/jinUTA== ecdsa-sig-formatter@1.0.11: version "1.0.11" @@ -3278,6 +3298,11 @@ encodeurl@~1.0.2: resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" integrity sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w== +encodeurl@~2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-2.0.0.tgz#7b8ea898077d7e409d3ac45474ea38eaf0857a58" + integrity sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg== + encoding@^0.1.12: version "0.1.13" resolved "https://registry.yarnpkg.com/encoding/-/encoding-0.1.13.tgz#56574afdd791f54a8e9b2785c0582a2d26210fa9" @@ -3433,6 +3458,18 @@ es-abstract@^1.19.0, es-abstract@^1.20.4: unbox-primitive "^1.0.2" which-typed-array "^1.1.9" +es-define-property@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/es-define-property/-/es-define-property-1.0.0.tgz#c7faefbdff8b2696cf5f46921edfb77cc4ba3845" + integrity sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ== + dependencies: + get-intrinsic "^1.2.4" + +es-errors@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/es-errors/-/es-errors-1.3.0.tgz#05f75a25dab98e4fb1dcd5e1472c0546d5057c8f" + integrity sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw== + es-module-lexer@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/es-module-lexer/-/es-module-lexer-1.2.1.tgz#ba303831f63e6a394983fde2f97ad77b22324527" @@ -3824,37 +3861,37 @@ expect@^26.6.2: jest-message-util "^26.6.2" jest-regex-util "^26.0.0" -express@4.19.2, express@^4.19.2: - version "4.19.2" - resolved "https://registry.yarnpkg.com/express/-/express-4.19.2.tgz#e25437827a3aa7f2a827bc8171bbbb664a356465" - integrity sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q== +express@4.21.0, express@^4.21.0: + version "4.21.0" + resolved "https://registry.yarnpkg.com/express/-/express-4.21.0.tgz#d57cb706d49623d4ac27833f1cbc466b668eb915" + integrity sha512-VqcNGcj/Id5ZT1LZ/cfihi3ttTn+NJmkli2eZADigjq29qTlWi/hAQ43t/VLPq8+UX06FCEx3ByOYet6ZFblng== dependencies: accepts "~1.3.8" array-flatten "1.1.1" - body-parser "1.20.2" + body-parser "1.20.3" content-disposition "0.5.4" content-type "~1.0.4" cookie "0.6.0" cookie-signature "1.0.6" debug "2.6.9" depd "2.0.0" - encodeurl "~1.0.2" + encodeurl "~2.0.0" escape-html "~1.0.3" etag "~1.8.1" - finalhandler "1.2.0" + finalhandler "1.3.1" fresh "0.5.2" http-errors "2.0.0" - merge-descriptors "1.0.1" + merge-descriptors "1.0.3" methods "~1.1.2" on-finished "2.4.1" parseurl "~1.3.3" - path-to-regexp "0.1.7" + path-to-regexp "0.1.10" proxy-addr "~2.0.7" - qs "6.11.0" + qs "6.13.0" range-parser "~1.2.1" safe-buffer "5.2.1" - send "0.18.0" - serve-static "1.15.0" + send "0.19.0" + serve-static "1.16.2" setprototypeof "1.2.0" statuses "2.0.1" type-is "~1.6.18" @@ -4023,13 +4060,13 @@ fill-range@^7.0.1: dependencies: to-regex-range "^5.0.1" -finalhandler@1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.2.0.tgz#7d23fe5731b207b4640e4fcd00aec1f9207a7b32" - integrity sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg== +finalhandler@1.3.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.3.1.tgz#0c575f1d1d324ddd1da35ad7ece3df7d19088019" + integrity sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ== dependencies: debug "2.6.9" - encodeurl "~1.0.2" + encodeurl "~2.0.0" escape-html "~1.0.3" on-finished "2.4.1" parseurl "~1.3.3" @@ -4302,6 +4339,17 @@ get-intrinsic@^1.0.2, get-intrinsic@^1.1.1, get-intrinsic@^1.1.3, get-intrinsic@ has "^1.0.3" has-symbols "^1.0.3" +get-intrinsic@^1.2.4: + version "1.2.4" + resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.2.4.tgz#e385f5a4b5227d449c3eabbad05494ef0abbeadd" + integrity sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ== + dependencies: + es-errors "^1.3.0" + function-bind "^1.1.2" + has-proto "^1.0.1" + has-symbols "^1.0.3" + hasown "^2.0.0" + get-package-type@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/get-package-type/-/get-package-type-0.1.0.tgz#8de2d803cff44df3bc6c456e6668b36c3926e11a" @@ -4476,6 +4524,13 @@ has-property-descriptors@^1.0.0: dependencies: get-intrinsic "^1.1.1" +has-property-descriptors@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz#963ed7d071dc7bf5f084c5bfbe0d1b6222586854" + integrity sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg== + dependencies: + es-define-property "^1.0.0" + has-proto@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/has-proto/-/has-proto-1.0.1.tgz#1885c1305538958aff469fef37937c22795408e0" @@ -6089,10 +6144,10 @@ memory-fs@^0.5.0: errno "^0.1.3" readable-stream "^2.0.1" -merge-descriptors@1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61" - integrity sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w== +merge-descriptors@1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.3.tgz#d80319a65f3c7935351e5cfdac8f9318504dbed5" + integrity sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ== merge-stream@^2.0.0: version "2.0.0" @@ -6699,6 +6754,11 @@ object-inspect@^1.12.3, object-inspect@^1.9.0: resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.12.3.tgz#ba62dffd67ee256c8c086dfae69e016cd1f198b9" integrity sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g== +object-inspect@^1.13.1: + version "1.13.2" + resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.13.2.tgz#dea0088467fb991e67af4058147a24824a3043ff" + integrity sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g== + object-keys@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e" @@ -7025,10 +7085,10 @@ path-scurry@^1.6.1: lru-cache "^9.0.0" minipass "^5.0.0" -path-to-regexp@0.1.7: - version "0.1.7" - resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c" - integrity sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ== +path-to-regexp@0.1.10: + version "0.1.10" + resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.10.tgz#67e9108c5c0551b9e5326064387de4763c4d5f8b" + integrity sha512-7lf7qcQidTku0Gu3YDPc8DJ1q7OOucfa/BSsIwjuh56VU7katFvuM8hULfkwB3Fns/rsVF7PwPKVw1sl5KQS9w== path-to-regexp@0.2.5: version "0.2.5" @@ -7244,12 +7304,12 @@ pvutils@^1.1.3: resolved "https://registry.yarnpkg.com/pvutils/-/pvutils-1.1.3.tgz#f35fc1d27e7cd3dfbd39c0826d173e806a03f5a3" integrity sha512-pMpnA0qRdFp32b1sJl1wOJNxZLQ2cbQx+k6tjNtZ8CpvVhNqEPRgivZ2WOUev2YMajecdH7ctUPDvEe87nariQ== -qs@6.11.0: - version "6.11.0" - resolved "https://registry.yarnpkg.com/qs/-/qs-6.11.0.tgz#fd0d963446f7a65e1367e01abd85429453f0c37a" - integrity sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q== +qs@6.13.0: + version "6.13.0" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.13.0.tgz#6ca3bd58439f7e245655798997787b0d88a51906" + integrity sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg== dependencies: - side-channel "^1.0.4" + side-channel "^1.0.6" qs@^6.5.1: version "6.11.1" @@ -7700,10 +7760,10 @@ schema-utils@^3.1.1, schema-utils@^3.1.2: dependencies: lru-cache "^6.0.0" -send@0.18.0: - version "0.18.0" - resolved "https://registry.yarnpkg.com/send/-/send-0.18.0.tgz#670167cc654b05f5aa4a767f9113bb371bc706be" - integrity sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg== +send@0.19.0: + version "0.19.0" + resolved "https://registry.yarnpkg.com/send/-/send-0.19.0.tgz#bbc5a388c8ea6c048967049dbeac0e4a3f09d7f8" + integrity sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw== dependencies: debug "2.6.9" depd "2.0.0" @@ -7733,21 +7793,33 @@ serialize-javascript@^6.0.1: dependencies: randombytes "^2.1.0" -serve-static@1.15.0: - version "1.15.0" - resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.15.0.tgz#faaef08cffe0a1a62f60cad0c4e513cff0ac9540" - integrity sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g== +serve-static@1.16.2: + version "1.16.2" + resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.16.2.tgz#b6a5343da47f6bdd2673848bf45754941e803296" + integrity sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw== dependencies: - encodeurl "~1.0.2" + encodeurl "~2.0.0" escape-html "~1.0.3" parseurl "~1.3.3" - send "0.18.0" + send "0.19.0" set-blocking@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" integrity sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw== +set-function-length@^1.2.1: + version "1.2.2" + resolved "https://registry.yarnpkg.com/set-function-length/-/set-function-length-1.2.2.tgz#aac72314198eaed975cf77b2c3b6b880695e5449" + integrity sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg== + dependencies: + define-data-property "^1.1.4" + es-errors "^1.3.0" + function-bind "^1.1.2" + get-intrinsic "^1.2.4" + gopd "^1.0.1" + has-property-descriptors "^1.0.2" + set-value@^2.0.0, set-value@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/set-value/-/set-value-2.0.1.tgz#a18d40530e6f07de4228c7defe4227af8cad005b" @@ -7823,6 +7895,16 @@ side-channel@^1.0.4: get-intrinsic "^1.0.2" object-inspect "^1.9.0" +side-channel@^1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.6.tgz#abd25fb7cd24baf45466406b1096b7831c9215f2" + integrity sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA== + dependencies: + call-bind "^1.0.7" + es-errors "^1.3.0" + get-intrinsic "^1.2.4" + object-inspect "^1.13.1" + signal-exit@^3.0.0, signal-exit@^3.0.2, signal-exit@^3.0.7: version "3.0.7" resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9" From 7a45d2019f74152822be4aaecf189c56fbd20f98 Mon Sep 17 00:00:00 2001 From: Gnanesh Date: Sat, 5 Oct 2024 18:32:07 +0530 Subject: [PATCH 111/256] Bump axios package for UI and API --- package.json | 2 +- redisinsight/api/package.json | 2 +- redisinsight/api/yarn.lock | 8 ++++---- yarn.lock | 8 ++++---- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/package.json b/package.json index d2b6383bcc..37c48a2078 100644 --- a/package.json +++ b/package.json @@ -215,7 +215,7 @@ "@elastic/eui": "34.6.0", "@reduxjs/toolkit": "^1.6.2", "@stablelib/snappy": "^1.0.2", - "axios": "^1.6.0", + "axios": "^1.7.4", "brotli-unicode": "^1.0.2", "buffer": "^6.0.3", "classnames": "^2.3.1", diff --git a/redisinsight/api/package.json b/redisinsight/api/package.json index 932f697517..b89633e836 100644 --- a/redisinsight/api/package.json +++ b/redisinsight/api/package.json @@ -60,7 +60,7 @@ "@okta/okta-auth-js": "^7.3.0", "@segment/analytics-node": "^2.1.3", "adm-zip": "^0.5.9", - "axios": "^1.6.0", + "axios": "^1.7.4", "body-parser": "^1.20.3", "busboy": "^1.6.0", "class-transformer": "^0.2.3", diff --git a/redisinsight/api/yarn.lock b/redisinsight/api/yarn.lock index 39cc84c493..011481f835 100644 --- a/redisinsight/api/yarn.lock +++ b/redisinsight/api/yarn.lock @@ -2044,10 +2044,10 @@ available-typed-arrays@^1.0.5: resolved "https://registry.yarnpkg.com/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz#92f95616501069d07d10edb2fc37d3e1c65123b7" integrity sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw== -axios@^1.6.0: - version "1.6.8" - resolved "https://registry.yarnpkg.com/axios/-/axios-1.6.8.tgz#66d294951f5d988a00e87a0ffb955316a619ea66" - integrity sha512-v/ZHtJDU39mDpyBoFVkETcd/uNdxrWRrg3bKpOKzXFA6Bvqopts6ALSMU3y6ijYxbw2B+wPrIv46egTzJXCLGQ== +axios@^1.7.4: + version "1.7.7" + resolved "https://registry.yarnpkg.com/axios/-/axios-1.7.7.tgz#2f554296f9892a72ac8d8e4c5b79c14a91d0a47f" + integrity sha512-S4kL7XrjgBmvdGut0sN3yJxqYzrDOnivkBiN0OFs6hLiUam3UPvswUo0kqGyhqUZGEOytHyumEdXsAkgCOUf3Q== dependencies: follow-redirects "^1.15.6" form-data "^4.0.0" diff --git a/yarn.lock b/yarn.lock index e291ca425f..39aa0b1a2c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3977,10 +3977,10 @@ axe-core@^4.0.2: resolved "https://registry.yarnpkg.com/axe-core/-/axe-core-4.7.0.tgz#34ba5a48a8b564f67e103f0aa5768d76e15bbbbf" integrity sha512-M0JtH+hlOL5pLQwHOLNYZaXuhqmvS8oExsqB1SBYgA4Dk7u/xx+YdGHXaK5pyUfed5mYXdlYiphWq3G8cRi5JQ== -axios@^1.6.0: - version "1.6.8" - resolved "https://registry.yarnpkg.com/axios/-/axios-1.6.8.tgz#66d294951f5d988a00e87a0ffb955316a619ea66" - integrity sha512-v/ZHtJDU39mDpyBoFVkETcd/uNdxrWRrg3bKpOKzXFA6Bvqopts6ALSMU3y6ijYxbw2B+wPrIv46egTzJXCLGQ== +axios@^1.7.4: + version "1.7.7" + resolved "https://registry.yarnpkg.com/axios/-/axios-1.7.7.tgz#2f554296f9892a72ac8d8e4c5b79c14a91d0a47f" + integrity sha512-S4kL7XrjgBmvdGut0sN3yJxqYzrDOnivkBiN0OFs6hLiUam3UPvswUo0kqGyhqUZGEOytHyumEdXsAkgCOUf3Q== dependencies: follow-redirects "^1.15.6" form-data "^4.0.0" From f64520c9aaa6846ee62bfba50156ad748b9995f1 Mon Sep 17 00:00:00 2001 From: Kristiyan Ivanov Date: Sat, 5 Oct 2024 18:16:36 +0300 Subject: [PATCH 112/256] RI-6160 Add a list data type with multiple elements - resovled tests --- .../list/dto/push.element-to-list.dto.ts | 10 ++-- .../api/list/POST-databases-id-list.test.ts | 35 +++++++++----- .../api/list/PUT-databases-id-list.test.ts | 47 +++++++++++-------- .../ui/src/slices/tests/browser/keys.spec.ts | 2 +- 4 files changed, 57 insertions(+), 37 deletions(-) diff --git a/redisinsight/api/src/modules/browser/list/dto/push.element-to-list.dto.ts b/redisinsight/api/src/modules/browser/list/dto/push.element-to-list.dto.ts index bca6a07c0b..567c26a048 100644 --- a/redisinsight/api/src/modules/browser/list/dto/push.element-to-list.dto.ts +++ b/redisinsight/api/src/modules/browser/list/dto/push.element-to-list.dto.ts @@ -1,7 +1,7 @@ import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger'; -import { IsDefined, IsEnum } from 'class-validator'; +import { IsArray, IsDefined, IsEnum } from 'class-validator'; import { RedisString } from 'src/common/constants'; -import { RedisStringType } from 'src/common/decorators'; +import { IsRedisString, RedisStringType } from 'src/common/decorators'; import { KeyDto } from 'src/modules/browser/keys/dto'; export enum ListElementDestination { @@ -11,11 +11,13 @@ export enum ListElementDestination { export class PushElementToListDto extends KeyDto { @ApiProperty({ - description: 'List elements', - isArray: true, + description: 'List element(s)', type: String, + isArray: true, }) @IsDefined() + @IsArray() + @IsRedisString({ each: true }) @RedisStringType({ each: true }) elements: RedisString[]; diff --git a/redisinsight/api/test/api/list/POST-databases-id-list.test.ts b/redisinsight/api/test/api/list/POST-databases-id-list.test.ts index 7f89cf77d8..e4aa6db890 100644 --- a/redisinsight/api/test/api/list/POST-databases-id-list.test.ts +++ b/redisinsight/api/test/api/list/POST-databases-id-list.test.ts @@ -19,13 +19,22 @@ const endpoint = (instanceId = constants.TEST_INSTANCE_ID) => // input data schema const dataSchema = Joi.object({ keyName: Joi.string().allow('').required(), - element: Joi.string().required(), + elements: Joi.array().items( + Joi.custom((value, helpers) => { + if (typeof value === 'string' || Buffer.isBuffer(value)) { + return value; + } + return helpers.error('any.invalid'); + }).messages({ + 'any.invalid': 'elements must be a string or a Buffer', + }) + ).required(), expire: Joi.number().integer().allow(null).min(1).max(2147483647), }).strict(); const validInputData = { keyName: constants.TEST_LIST_KEY_1, - element: constants.TEST_LIST_ELEMENT_1, + elements: [constants.TEST_LIST_ELEMENT_1], expire: constants.TEST_LIST_EXPIRE_1, }; @@ -53,7 +62,7 @@ const createCheckFn = async (testCase) => { } else { if (testCase.statusCode === 201) { expect(await rte.client.exists(testCase.data.keyName)).to.eql(1); - expect(await rte.client.lrange(testCase.data.keyName, 0, 100)).to.eql([testCase.data.element]); + expect(await rte.client.lrange(testCase.data.keyName, 0, 100)).to.eql(testCase.data.elements); if (testCase.data.expire) { expect(await rte.client.ttl(testCase.data.keyName)).to.gte(testCase.data.expire - 5); } else { @@ -74,7 +83,7 @@ describe('POST /databases/:databases/list', () => { name: 'Should create list from buff', data: { keyName: constants.TEST_LIST_KEY_BIN_BUF_OBJ_1, - element: constants.TEST_LIST_ELEMENT_BIN_BUF_OBJ_1, + elements: [constants.TEST_LIST_ELEMENT_BIN_BUF_OBJ_1], }, statusCode: 201, after: async () => { @@ -88,7 +97,7 @@ describe('POST /databases/:databases/list', () => { name: 'Should create list from ascii', data: { keyName: constants.TEST_LIST_KEY_BIN_ASCII_1, - element: constants.TEST_LIST_ELEMENT_BIN_ASCII_1, + elements: [constants.TEST_LIST_ELEMENT_BIN_ASCII_1], }, statusCode: 201, after: async () => { @@ -116,7 +125,7 @@ describe('POST /databases/:databases/list', () => { name: 'Should create item with empty value', data: { keyName: constants.getRandomString(), - element: '', + elements: [''], }, statusCode: 201, }, @@ -124,7 +133,7 @@ describe('POST /databases/:databases/list', () => { name: 'Should create item with key ttl', data: { keyName: constants.getRandomString(), - element: constants.getRandomString(), + elements: [constants.getRandomString()], expire: constants.TEST_STRING_EXPIRE_1, }, statusCode: 201, @@ -133,7 +142,7 @@ describe('POST /databases/:databases/list', () => { name: 'Should create regular item', data: { keyName: constants.TEST_LIST_KEY_1, - element: constants.TEST_LIST_ELEMENT_1, + elements: [constants.TEST_LIST_ELEMENT_1], }, statusCode: 201, }, @@ -141,7 +150,7 @@ describe('POST /databases/:databases/list', () => { name: 'Should return conflict error if key already exists', data: { keyName: constants.TEST_LIST_KEY_1, - element: constants.getRandomString(), + elements: [constants.getRandomString()], }, statusCode: 409, responseBody: { @@ -158,7 +167,7 @@ describe('POST /databases/:databases/list', () => { endpoint: () => endpoint(constants.TEST_NOT_EXISTED_INSTANCE_ID), data: { keyName: constants.TEST_LIST_KEY_1, - element: constants.getRandomString(), + elements: [constants.getRandomString()], }, statusCode: 404, responseBody: { @@ -183,7 +192,7 @@ describe('POST /databases/:databases/list', () => { endpoint: () => endpoint(constants.TEST_INSTANCE_ACL_ID), data: { keyName: constants.getRandomString(), - element: constants.TEST_LIST_ELEMENT_1, + elements: [constants.TEST_LIST_ELEMENT_1], }, statusCode: 201, }, @@ -192,7 +201,7 @@ describe('POST /databases/:databases/list', () => { endpoint: () => endpoint(constants.TEST_INSTANCE_ACL_ID), data: { keyName: constants.getRandomString(), - element: constants.getRandomString(), + elements: [constants.getRandomString()], }, statusCode: 403, responseBody: { @@ -206,7 +215,7 @@ describe('POST /databases/:databases/list', () => { endpoint: () => endpoint(constants.TEST_INSTANCE_ACL_ID), data: { keyName: constants.getRandomString(), - element: constants.getRandomString(), + elements: [constants.getRandomString()], }, statusCode: 403, responseBody: { diff --git a/redisinsight/api/test/api/list/PUT-databases-id-list.test.ts b/redisinsight/api/test/api/list/PUT-databases-id-list.test.ts index f6e42fd153..d4143e7678 100644 --- a/redisinsight/api/test/api/list/PUT-databases-id-list.test.ts +++ b/redisinsight/api/test/api/list/PUT-databases-id-list.test.ts @@ -8,7 +8,8 @@ import { requirements, generateInvalidDataTestCases, validateInvalidDataTestCase, - validateApiCall, getMainCheckFn + validateApiCall, getMainCheckFn, + JoiRedisString } from '../deps'; const { server, request, constants, rte } = deps; @@ -19,13 +20,22 @@ const endpoint = (instanceId = constants.TEST_INSTANCE_ID) => // input data schema const dataSchema = Joi.object({ keyName: Joi.string().allow('').required(), - element: Joi.string().required(), - destination: Joi.string().valid('HEAD', 'TAIL'), + elements: Joi.array().items( + Joi.custom((value, helpers) => { + if (typeof value === 'string' || Buffer.isBuffer(value)) { + return value; + } + return helpers.error('any.invalid'); + }).messages({ + 'any.invalid': 'elements must be a string or a Buffer', + }) + ).required(), + destination: Joi.string().valid('HEAD', 'TAIL').default('TAIL'), }).strict(); const validInputData = { keyName: constants.getRandomString(), - element: constants.getRandomString(), + elements: [constants.getRandomString()], destination: 'TAIL', }; @@ -49,7 +59,7 @@ describe('PUT /databases/:instanceId/list', () => { }, data: { keyName: constants.TEST_LIST_KEY_BIN_BUF_OBJ_1, - element: constants.TEST_LIST_ELEMENT_BIN_BUF_OBJ_1, + elements: [constants.TEST_LIST_ELEMENT_BIN_BUF_OBJ_1], }, responseBody: { keyName: constants.TEST_LIST_KEY_BIN_UTF8_1, @@ -69,7 +79,7 @@ describe('PUT /databases/:instanceId/list', () => { }, data: { keyName: constants.TEST_LIST_KEY_BIN_BUF_OBJ_1, - element: constants.TEST_LIST_ELEMENT_BIN_BUF_OBJ_1, + elements: [constants.TEST_LIST_ELEMENT_BIN_BUF_OBJ_1], }, responseBody: { keyName: constants.TEST_LIST_KEY_BIN_BUF_OBJ_1, @@ -90,7 +100,7 @@ describe('PUT /databases/:instanceId/list', () => { }, data: { keyName: constants.TEST_LIST_KEY_BIN_ASCII_1, - element: constants.TEST_LIST_ELEMENT_BIN_ASCII_1, + elements: [constants.TEST_LIST_ELEMENT_BIN_ASCII_1], }, responseBody: { keyName: constants.TEST_LIST_KEY_BIN_ASCII_1, @@ -126,8 +136,7 @@ describe('PUT /databases/:instanceId/list', () => { name: 'Should insert 1 element to the tail (by default)', data: { keyName: constants.TEST_LIST_KEY_1, - element: constants.getRandomString(), - destination: 'TAIL', + elements: [constants.getRandomString()], }, responseSchema, responseBody: { @@ -136,14 +145,14 @@ describe('PUT /databases/:instanceId/list', () => { }, after: async function () { const elements = await rte.client.lrange(constants.TEST_LIST_KEY_1, 0, 1000); - expect(elements[2]).to.eql(this.data.element); + expect(elements[2]).to.eql(this.data.elements[0]); }, }, { name: 'Should insert 1 element to the tail', data: { keyName: constants.TEST_LIST_KEY_1, - element: constants.getRandomString(), + elements: [constants.getRandomString()], destination: 'TAIL', }, responseSchema, @@ -153,14 +162,14 @@ describe('PUT /databases/:instanceId/list', () => { }, after: async function () { const elements = await rte.client.lrange(constants.TEST_LIST_KEY_1, 0, 1000); - expect(elements[3]).to.eql(this.data.element); + expect(elements[3]).to.eql(this.data.elements[0]); }, }, { name: 'Should insert 1 element to the head', data: { keyName: constants.TEST_LIST_KEY_1, - element: constants.getRandomString(), + elements: [constants.getRandomString()], destination: 'HEAD', }, responseSchema, @@ -170,14 +179,14 @@ describe('PUT /databases/:instanceId/list', () => { }, after: async function () { const elements = await rte.client.lrange(constants.TEST_LIST_KEY_1, 0, 1000); - expect(elements[0]).to.eql(this.data.element); + expect(elements[0]).to.eql(this.data.elements[0]); }, }, { name: 'Should return NotFound error if key does not exists', data: { keyName: constants.getRandomString(), - element: constants.getRandomString(), + elements: [constants.getRandomString()], destination: 'HEAD', }, statusCode: 404, @@ -192,7 +201,7 @@ describe('PUT /databases/:instanceId/list', () => { endpoint: () => endpoint(constants.TEST_NOT_EXISTED_INSTANCE_ID), data: { keyName: constants.TEST_LIST_KEY_1, - element: constants.getRandomString(), + elements: [constants.getRandomString()], destination: 'HEAD', }, statusCode: 404, @@ -215,7 +224,7 @@ describe('PUT /databases/:instanceId/list', () => { endpoint: () => endpoint(constants.TEST_INSTANCE_ACL_ID), data: { keyName: constants.TEST_LIST_KEY_1, - element: constants.getRandomString(), + elements: [constants.getRandomString()], destination: 'TAIL', }, responseSchema, @@ -225,7 +234,7 @@ describe('PUT /databases/:instanceId/list', () => { endpoint: () => endpoint(constants.TEST_INSTANCE_ACL_ID), data: { keyName: constants.TEST_LIST_KEY_1, - element: constants.getRandomString(), + elements: [constants.getRandomString()], destination: 'HEAD', }, statusCode: 403, @@ -240,7 +249,7 @@ describe('PUT /databases/:instanceId/list', () => { endpoint: () => endpoint(constants.TEST_INSTANCE_ACL_ID), data: { keyName: constants.TEST_LIST_KEY_1, - element: constants.getRandomString(), + elements: [constants.getRandomString()], destination: 'TAIL', }, statusCode: 403, diff --git a/redisinsight/ui/src/slices/tests/browser/keys.spec.ts b/redisinsight/ui/src/slices/tests/browser/keys.spec.ts index ed14b7e52b..96b8ca3c8c 100644 --- a/redisinsight/ui/src/slices/tests/browser/keys.spec.ts +++ b/redisinsight/ui/src/slices/tests/browser/keys.spec.ts @@ -1448,7 +1448,7 @@ describe('keys slice', () => { const data: CreateListWithExpireDto = { keyName: 'keyName', destination: 'TAIL' as ListElementDestination, - element: '1', + elements: ['1'], } const responsePayload = { data, status: 200 } From a9eb3e895005a089745ef0bdcdf326a14caf8160 Mon Sep 17 00:00:00 2001 From: Kristiyan Ivanov Date: Sat, 5 Oct 2024 18:23:37 +0300 Subject: [PATCH 113/256] RI-6160 Add a list data type with multiple elements - reverted order import changes --- .../api/src/modules/browser/__mocks__/list.ts | 2 +- .../list/dto/push.element-to-list.dto.ts | 6 ++-- .../modules/browser/list/list.service.spec.ts | 28 +++++++++---------- .../src/modules/browser/list/list.service.ts | 20 ++++++------- .../add-key/AddKeyList/AddKeyList.spec.tsx | 4 +-- .../add-key/AddKeyList/AddKeyList.tsx | 15 +++++----- .../add-multiple-fields/AddMultipleFields.tsx | 4 +-- .../add-list-elements/AddListElements.tsx | 21 +++++++------- 8 files changed, 49 insertions(+), 51 deletions(-) diff --git a/redisinsight/api/src/modules/browser/__mocks__/list.ts b/redisinsight/api/src/modules/browser/__mocks__/list.ts index 52d3c6f4b3..16316a6d9c 100644 --- a/redisinsight/api/src/modules/browser/__mocks__/list.ts +++ b/redisinsight/api/src/modules/browser/__mocks__/list.ts @@ -1,4 +1,3 @@ -import { mockKeyDto } from 'src/modules/browser/__mocks__/keys'; import { DeleteListElementsDto, GetListElementResponse, @@ -8,6 +7,7 @@ import { PushElementToListDto, SetListElementDto, } from 'src/modules/browser/list/dto'; +import { mockKeyDto } from 'src/modules/browser/__mocks__/keys'; export const mockIndex: number = 0; export const mockListElement = Buffer.from('Lorem ipsum dolor sit amet.'); diff --git a/redisinsight/api/src/modules/browser/list/dto/push.element-to-list.dto.ts b/redisinsight/api/src/modules/browser/list/dto/push.element-to-list.dto.ts index 567c26a048..1ce88c3e94 100644 --- a/redisinsight/api/src/modules/browser/list/dto/push.element-to-list.dto.ts +++ b/redisinsight/api/src/modules/browser/list/dto/push.element-to-list.dto.ts @@ -1,8 +1,8 @@ +import { KeyDto } from 'src/modules/browser/keys/dto'; import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger'; -import { IsArray, IsDefined, IsEnum } from 'class-validator'; -import { RedisString } from 'src/common/constants'; +import { IsDefined, IsEnum } from 'class-validator'; import { IsRedisString, RedisStringType } from 'src/common/decorators'; -import { KeyDto } from 'src/modules/browser/keys/dto'; +import { RedisString } from 'src/common/constants'; export enum ListElementDestination { Tail = 'TAIL', diff --git a/redisinsight/api/src/modules/browser/list/list.service.spec.ts b/redisinsight/api/src/modules/browser/list/list.service.spec.ts index c8726bff08..28b9e11980 100644 --- a/redisinsight/api/src/modules/browser/list/list.service.spec.ts +++ b/redisinsight/api/src/modules/browser/list/list.service.spec.ts @@ -1,21 +1,26 @@ +import { Test, TestingModule } from '@nestjs/testing'; import { BadRequestException, ConflictException, ForbiddenException, NotFoundException, } from '@nestjs/common'; -import { Test, TestingModule } from '@nestjs/testing'; import { when } from 'jest-when'; +import { ReplyError } from 'src/models/redis-client'; import { - mockBrowserClientMetadata, mockRedisNoPermError, mockRedisWrongNumberOfArgumentsError, mockRedisWrongTypeError, + mockBrowserClientMetadata, } from 'src/__mocks__'; -import { mockDatabaseClientFactory } from 'src/__mocks__/databases-client'; -import { mockStandaloneRedisClient } from 'src/__mocks__/redis-client'; -import ERROR_MESSAGES from 'src/constants/error-messages'; -import { ReplyError } from 'src/models/redis-client'; +import { + CreateListWithExpireDto, + ListElementDestination, +} from 'src/modules/browser/list/dto'; +import { + BrowserToolKeysCommands, + BrowserToolListCommands, +} from 'src/modules/browser/constants/browser-tool-commands'; import { mockDeleteElementsDto, mockGetListElementResponse, @@ -29,15 +34,10 @@ import { mockPushElementDto, mockSetListElementDto, } from 'src/modules/browser/__mocks__'; -import { - BrowserToolKeysCommands, - BrowserToolListCommands, -} from 'src/modules/browser/constants/browser-tool-commands'; -import { - CreateListWithExpireDto, - ListElementDestination, -} from 'src/modules/browser/list/dto'; import { DatabaseClientFactory } from 'src/modules/database/providers/database.client.factory'; +import { mockDatabaseClientFactory } from 'src/__mocks__/databases-client'; +import { mockStandaloneRedisClient } from 'src/__mocks__/redis-client'; +import ERROR_MESSAGES from 'src/constants/error-messages'; import { ListService } from './list.service'; describe('ListService', () => { diff --git a/redisinsight/api/src/modules/browser/list/list.service.ts b/redisinsight/api/src/modules/browser/list/list.service.ts index 522b21094e..d2b14d2f56 100644 --- a/redisinsight/api/src/modules/browser/list/list.service.ts +++ b/redisinsight/api/src/modules/browser/list/list.service.ts @@ -4,16 +4,11 @@ import { Logger, NotFoundException, } from '@nestjs/common'; -import { plainToClass } from 'class-transformer'; -import { isArray, isNull } from 'lodash'; -import { ClientMetadata } from 'src/common/models'; +import { isNull, isArray } from 'lodash'; import { RedisErrorCodes } from 'src/constants'; import ERROR_MESSAGES from 'src/constants/error-messages'; -import { - BrowserToolKeysCommands, - BrowserToolListCommands, -} from 'src/modules/browser/constants/browser-tool-commands'; -import { KeyDto } from 'src/modules/browser/keys/dto'; +import { catchAclError, catchMultiTransactionError } from 'src/utils'; +import { ClientMetadata } from 'src/common/models'; import { CreateListWithExpireDto, DeleteListElementsDto, @@ -27,10 +22,15 @@ import { SetListElementDto, SetListElementResponse, } from 'src/modules/browser/list/dto'; -import { checkIfKeyExists, checkIfKeyNotExists } from 'src/modules/browser/utils'; +import { KeyDto } from 'src/modules/browser/keys/dto'; +import { + BrowserToolKeysCommands, + BrowserToolListCommands, +} from 'src/modules/browser/constants/browser-tool-commands'; +import { plainToClass } from 'class-transformer'; import { DatabaseClientFactory } from 'src/modules/database/providers/database.client.factory'; import { RedisClient, RedisClientCommandReply } from 'src/modules/redis/client'; -import { catchAclError, catchMultiTransactionError } from 'src/utils'; +import { checkIfKeyExists, checkIfKeyNotExists } from 'src/modules/browser/utils'; @Injectable() export class ListService { diff --git a/redisinsight/ui/src/pages/browser/components/add-key/AddKeyList/AddKeyList.spec.tsx b/redisinsight/ui/src/pages/browser/components/add-key/AddKeyList/AddKeyList.spec.tsx index 7ba3d8a222..f93254b0ef 100644 --- a/redisinsight/ui/src/pages/browser/components/add-key/AddKeyList/AddKeyList.spec.tsx +++ b/redisinsight/ui/src/pages/browser/components/add-key/AddKeyList/AddKeyList.spec.tsx @@ -1,8 +1,8 @@ import React from 'react' import { instance, mock } from 'ts-mockito' -import { fireEvent, render, screen } from 'uiSrc/utils/test-utils' -import AddKeyFooter from '../AddKeyFooter/AddKeyFooter' +import { render, screen, fireEvent } from 'uiSrc/utils/test-utils' import AddKeyList, { Props } from './AddKeyList' +import AddKeyFooter from '../AddKeyFooter/AddKeyFooter' const mockedProps = mock() diff --git a/redisinsight/ui/src/pages/browser/components/add-key/AddKeyList/AddKeyList.tsx b/redisinsight/ui/src/pages/browser/components/add-key/AddKeyList/AddKeyList.tsx index afa9ced56c..dcbfcbdfe5 100644 --- a/redisinsight/ui/src/pages/browser/components/add-key/AddKeyList/AddKeyList.tsx +++ b/redisinsight/ui/src/pages/browser/components/add-key/AddKeyList/AddKeyList.tsx @@ -1,25 +1,24 @@ -import React, { ChangeEvent, FormEvent, useEffect, useState } from 'react' +import React, { ChangeEvent, FormEvent, useState, useEffect } from 'react' import { useDispatch, useSelector } from 'react-redux' import { EuiButton, - EuiFieldText, + EuiTextColor, + EuiForm, EuiFlexGroup, EuiFlexItem, - EuiForm, EuiPanel, - EuiTextColor + EuiFieldText, } from '@elastic/eui' -import { CreateListWithExpireDto } from 'apiSrc/modules/browser/list/dto' -import { addKeyStateSelector, addListKey } from 'uiSrc/slices/browser/keys' import { Maybe, stringToBuffer } from 'uiSrc/utils' +import { addKeyStateSelector, addListKey } from 'uiSrc/slices/browser/keys' +import { CreateListWithExpireDto } from 'apiSrc/modules/browser/list/dto' -import AddMultipleFields from '../../add-multiple-fields' -import AddKeyFooter from '../AddKeyFooter/AddKeyFooter' import { AddListFormConfig as config, } from '../constants/fields-config' +import AddKeyFooter from '../AddKeyFooter/AddKeyFooter' export interface Props { keyName: string diff --git a/redisinsight/ui/src/pages/browser/components/add-multiple-fields/AddMultipleFields.tsx b/redisinsight/ui/src/pages/browser/components/add-multiple-fields/AddMultipleFields.tsx index 5806c60c0c..9345f69486 100644 --- a/redisinsight/ui/src/pages/browser/components/add-multiple-fields/AddMultipleFields.tsx +++ b/redisinsight/ui/src/pages/browser/components/add-multiple-fields/AddMultipleFields.tsx @@ -1,6 +1,6 @@ -import { EuiButtonIcon, EuiFlexGroup, EuiFlexItem, EuiSpacer, EuiToolTip } from '@elastic/eui' -import cx from 'classnames' import React from 'react' +import cx from 'classnames' +import { EuiButtonIcon, EuiFlexGroup, EuiFlexItem, EuiSpacer, EuiToolTip } from '@elastic/eui' import styles from './styles.module.scss' diff --git a/redisinsight/ui/src/pages/browser/modules/key-details/components/list-details/add-list-elements/AddListElements.tsx b/redisinsight/ui/src/pages/browser/modules/key-details/components/list-details/add-list-elements/AddListElements.tsx index efd2a55c1d..adbf425463 100644 --- a/redisinsight/ui/src/pages/browser/modules/key-details/components/list-details/add-list-elements/AddListElements.tsx +++ b/redisinsight/ui/src/pages/browser/modules/key-details/components/list-details/add-list-elements/AddListElements.tsx @@ -1,27 +1,26 @@ +import React, { ChangeEvent, useEffect, useRef, useState } from 'react' +import { useDispatch, useSelector } from 'react-redux' +import cx from 'classnames' import { EuiButton, - EuiFieldText, + EuiTextColor, EuiFlexGroup, EuiFlexItem, + EuiFieldText, EuiPanel, EuiSuperSelect, EuiSuperSelectOption, - EuiTextColor } from '@elastic/eui' -import cx from 'classnames' -import React, { ChangeEvent, useEffect, useRef, useState } from 'react' -import { useDispatch, useSelector } from 'react-redux' -import { PushElementToListDto } from 'apiSrc/modules/browser/list/dto' -import { KeyTypes } from 'uiSrc/constants' -import { AddListFormConfig as config } from 'uiSrc/pages/browser/components/add-key/constants/fields-config' -import { keysSelector, selectedKeyDataSelector } from 'uiSrc/slices/browser/keys' -import { insertListElementsAction } from 'uiSrc/slices/browser/list' +import { selectedKeyDataSelector, keysSelector } from 'uiSrc/slices/browser/keys' import { connectedInstanceSelector } from 'uiSrc/slices/instances/instances' +import { insertListElementsAction } from 'uiSrc/slices/browser/list' import { getBasedOnViewTypeEvent, sendEventTelemetry, TelemetryEvent } from 'uiSrc/telemetry' +import { KeyTypes } from 'uiSrc/constants' import { stringToBuffer } from 'uiSrc/utils' +import { AddListFormConfig as config } from 'uiSrc/pages/browser/components/add-key/constants/fields-config' +import { PushElementToListDto } from 'apiSrc/modules/browser/list/dto' -import AddMultipleFields from 'uiSrc/pages/browser/components/add-multiple-fields' import styles from '../styles.module.scss' export interface Props { From 3358f6703663d8fcfe0ef51cfe60784cc8e4a619 Mon Sep 17 00:00:00 2001 From: Kristiyan Ivanov Date: Sat, 5 Oct 2024 18:24:48 +0300 Subject: [PATCH 114/256] RI-6160 Add a list data type with multiple elements - reverted order import changes --- .../src/modules/browser/list/dto/push.element-to-list.dto.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/redisinsight/api/src/modules/browser/list/dto/push.element-to-list.dto.ts b/redisinsight/api/src/modules/browser/list/dto/push.element-to-list.dto.ts index 1ce88c3e94..07eef57d87 100644 --- a/redisinsight/api/src/modules/browser/list/dto/push.element-to-list.dto.ts +++ b/redisinsight/api/src/modules/browser/list/dto/push.element-to-list.dto.ts @@ -1,6 +1,6 @@ import { KeyDto } from 'src/modules/browser/keys/dto'; import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger'; -import { IsDefined, IsEnum } from 'class-validator'; +import { IsArray, IsDefined, IsEnum } from 'class-validator'; import { IsRedisString, RedisStringType } from 'src/common/decorators'; import { RedisString } from 'src/common/constants'; From cd1feb5b364547afde0c217cf01836f99e2617f0 Mon Sep 17 00:00:00 2001 From: Kristiyan Ivanov Date: Sat, 5 Oct 2024 18:28:16 +0300 Subject: [PATCH 115/256] RI-6160 Add a list data type with multiple elements - reverted order import changes --- .../pages/browser/components/add-key/AddKeyList/AddKeyList.tsx | 1 + .../list-details/add-list-elements/AddListElements.tsx | 1 + 2 files changed, 2 insertions(+) diff --git a/redisinsight/ui/src/pages/browser/components/add-key/AddKeyList/AddKeyList.tsx b/redisinsight/ui/src/pages/browser/components/add-key/AddKeyList/AddKeyList.tsx index dcbfcbdfe5..a365d7a162 100644 --- a/redisinsight/ui/src/pages/browser/components/add-key/AddKeyList/AddKeyList.tsx +++ b/redisinsight/ui/src/pages/browser/components/add-key/AddKeyList/AddKeyList.tsx @@ -19,6 +19,7 @@ import { AddListFormConfig as config, } from '../constants/fields-config' import AddKeyFooter from '../AddKeyFooter/AddKeyFooter' +import AddMultipleFields from '../../add-multiple-fields' export interface Props { keyName: string diff --git a/redisinsight/ui/src/pages/browser/modules/key-details/components/list-details/add-list-elements/AddListElements.tsx b/redisinsight/ui/src/pages/browser/modules/key-details/components/list-details/add-list-elements/AddListElements.tsx index adbf425463..9e5ca1d365 100644 --- a/redisinsight/ui/src/pages/browser/modules/key-details/components/list-details/add-list-elements/AddListElements.tsx +++ b/redisinsight/ui/src/pages/browser/modules/key-details/components/list-details/add-list-elements/AddListElements.tsx @@ -15,6 +15,7 @@ import { import { selectedKeyDataSelector, keysSelector } from 'uiSrc/slices/browser/keys' import { connectedInstanceSelector } from 'uiSrc/slices/instances/instances' import { insertListElementsAction } from 'uiSrc/slices/browser/list' +import AddMultipleFields from 'uiSrc/pages/browser/components/add-multiple-fields' import { getBasedOnViewTypeEvent, sendEventTelemetry, TelemetryEvent } from 'uiSrc/telemetry' import { KeyTypes } from 'uiSrc/constants' import { stringToBuffer } from 'uiSrc/utils' From 1359d7d1b702d02a149af0a6c23a8853f111209d Mon Sep 17 00:00:00 2001 From: vlad-dargel Date: Mon, 7 Oct 2024 11:54:31 +0200 Subject: [PATCH 116/256] RI-6089_support-ft-commands --- .../search-and-query-tab.e2e.ts | 52 +++++++++++++++++-- 1 file changed, 47 insertions(+), 5 deletions(-) diff --git a/tests/e2e/tests/web/regression/search-and-query/search-and-query-tab.e2e.ts b/tests/e2e/tests/web/regression/search-and-query/search-and-query-tab.e2e.ts index e2be296bf2..6050175477 100644 --- a/tests/e2e/tests/web/regression/search-and-query/search-and-query-tab.e2e.ts +++ b/tests/e2e/tests/web/regression/search-and-query/search-and-query-tab.e2e.ts @@ -16,6 +16,7 @@ const keyName = Common.generateWord(10); let keyNames: string[]; let indexName1: string; let indexName2: string; +let indexName3: string; fixture `Autocomplete for entered commands in search and query` .meta({ type: 'regression', rte: rte.standalone }) @@ -24,6 +25,7 @@ fixture `Autocomplete for entered commands in search and query` await databaseHelper.acceptLicenseTermsAndAddDatabaseApi(ossStandaloneConfig); indexName1 = `idx1:${keyName}`; indexName2 = `idx2:${keyName}`; + indexName3 = `idx3:${keyName}`; keyNames = [`${keyName}:1`, `${keyName}:2`, `${keyName}:3`]; const commands = [ `HSET ${keyNames[0]} "name" "Hall School" "description" " Spanning 10 states" "class" "independent" "type" "traditional" "address_city" "London" "address_street" "Manor Street" "students" 342 "location" "51.445417, -0.258352"`, @@ -247,7 +249,7 @@ test('Verify commands suggestions for APPLY and FILTER', async t => { await t.typeText(searchAndQueryPage.queryInput, '*'); await t.pressKey('right'); await t.pressKey('space'); - //Verify APPLY command + // Verify APPLY command await t.expect(searchAndQueryPage.MonacoEditor.monacoSuggestion.withExactText('APPLY').exists).ok('Apply is not suggested'); await t.pressKey('enter'); @@ -266,7 +268,7 @@ test('Verify commands suggestions for APPLY and FILTER', async t => { await t.typeText(searchAndQueryPage.queryInput, 'apply_key', { replace: false }); await t.pressKey('space'); - //Verify Filter command + // Verify Filter command await t.typeText(searchAndQueryPage.queryInput, 'F'); await t.expect(searchAndQueryPage.MonacoEditor.monacoSuggestion.withExactText('FILTER').exists).ok('FILTER is not suggested'); await t.pressKey('enter'); @@ -296,7 +298,7 @@ test('Verify REDUCE commands', async t => { await t.pressKey('enter'); await t.typeText(searchAndQueryPage.queryInput, 'item_count '); - //add additional reduce + // add additional reduce await t.expect(searchAndQueryPage.MonacoEditor.monacoSuggestion.withExactText('REDUCE').exists).ok('Apply is not suggested'); await t.typeText(searchAndQueryPage.queryInput, 'R'); await t.pressKey('enter'); @@ -320,12 +322,12 @@ test('Verify suggestions for fields', async t => { await t.typeText(searchAndQueryPage.queryInput, '@'); await t.expect(searchAndQueryPage.MonacoEditor.monacoSuggestion.visible).ok('Suggestions not displayed'); - //verify suggestions for geo + // verify suggestions for geo await t.typeText(searchAndQueryPage.queryInput, 'l'); await t.pressKey('tab'); await t.expect((await searchAndQueryPage.MonacoEditor.getTextFromMonaco()).trim()).eql(`FT.AGGREGATE "${indexName1}" "@location:[lon lat radius unit]"`); - //verify for numeric + // verify for numeric await t.typeText(searchAndQueryPage.queryInput, 'FT.AGGREGATE ', { replace: true }); await t.typeText(searchAndQueryPage.queryInput, 'idx1'); await t.pressKey('enter'); @@ -336,3 +338,43 @@ test('Verify suggestions for fields', async t => { await t.pressKey('tab'); await t.expect((await searchAndQueryPage.MonacoEditor.getTextFromMonaco()).trim()).eql(`FT.AGGREGATE "${indexName1}" "@students:[range]"`); }); + +test + .after(async() => { + // Clear and delete database + await apiKeyRequests.deleteKeyByNameApi(keyName, ossStandaloneConfig.databaseName); + await browserPage.Cli.sendCommandsInCli([`DEL ${keyNames.join(' ')}`, `FT.DROPINDEX ${indexName1}`]); + await browserPage.Cli.sendCommandsInCli([`DEL ${keyNames.join(' ')}`, `FT.DROPINDEX ${indexName2}`]); + await browserPage.Cli.sendCommandsInCli([`DEL ${keyNames.join(' ')}`, `FT.DROPINDEX ${indexName3}`]); + await databaseAPIRequests.deleteStandaloneDatabaseApi(ossStandaloneConfig); + })('Verify commands suggestions for CREATE', async t => { + await t.typeText(searchAndQueryPage.queryInput, 'FT.CREATE ', { replace: true }); + await t.pressKey('enter'); + // Verify that indexes are not suggested for FT.CREATE + await t.expect(searchAndQueryPage.MonacoEditor.monacoSuggestion.exists).notOk('Existing index suggested'); + + // Enter index name + await t.typeText(searchAndQueryPage.queryInput, indexName3); + await t.pressKey('space'); + + // Select FILTER keyword + await t.typeText(searchAndQueryPage.queryInput, 'FI'); + await t.pressKey('tab'); + await t.typeText(searchAndQueryPage.queryInput, 'filterNew', { replace: false }); + await t.pressKey('space'); + + // Select SCHEMA keyword + await t.typeText(searchAndQueryPage.queryInput, 'SCH'); + await t.pressKey('tab'); + await t.typeText(searchAndQueryPage.queryInput, 'field_name', { replace: false }); + await t.pressKey('space'); + + // Select TEXT keyword + await t.typeText(searchAndQueryPage.queryInput, 'te', { replace: false }); + await t.pressKey('tab'); + + // Select SORTABLE + await t.typeText(searchAndQueryPage.queryInput, 'so', { replace: false }); + await t.pressKey('tab'); + await t.expect((await searchAndQueryPage.MonacoEditor.getTextFromMonaco()).trim()).eql(`FT.CREATE ${indexName3} FILTER filterNew SCHEMA field_name TEXT SORTABLE`); + }); From 386b2b3a2610143bc9ad8723055951d45f583186 Mon Sep 17 00:00:00 2001 From: mariasergeenko Date: Mon, 7 Oct 2024 12:20:49 +0200 Subject: [PATCH 117/256] add TREE_VIEW_KEY_VALUE_VIEWED --- tests/e2e/pageObjects/browser-page.ts | 3 ++- .../web/regression/tree-view/tree-view.e2e.ts | 20 ++++++++++++++++--- 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/tests/e2e/pageObjects/browser-page.ts b/tests/e2e/pageObjects/browser-page.ts index 297bdded5f..55c8acc5ed 100644 --- a/tests/e2e/pageObjects/browser-page.ts +++ b/tests/e2e/pageObjects/browser-page.ts @@ -107,7 +107,8 @@ export class BrowserPage extends InstancePage { backToBrowserBtn = Selector('[data-testid=back-right-panel-btn]'); loadAllBtn = Selector('[data-testid=load-all-value-btn]'); downloadAllValueBtn = Selector('[data-testid=download-all-value-btn]'); - openTutorialsBtn = Selector('[data-testid=explore-msg-btn]'); + openTutorialsBtn = Selector('[data-testid=explore-msg-btn]') + keyItem = Selector('[data-testid*="node-item"][data-testid*="keys:"]'); //CONTAINERS streamGroupsContainer = Selector('[data-testid=stream-groups-container]'); streamConsumersContainer = Selector('[data-testid=stream-consumers-container]'); diff --git a/tests/e2e/tests/web/regression/tree-view/tree-view.e2e.ts b/tests/e2e/tests/web/regression/tree-view/tree-view.e2e.ts index 0cbe19e549..08be4a8c69 100644 --- a/tests/e2e/tests/web/regression/tree-view/tree-view.e2e.ts +++ b/tests/e2e/tests/web/regression/tree-view/tree-view.e2e.ts @@ -1,5 +1,6 @@ import { DatabaseHelper } from '../../../../helpers/database'; import { BrowserPage, WorkbenchPage } from '../../../../pageObjects'; +import { Telemetry } from '../../../../helpers/telemetry'; import { commonUrl, ossStandaloneBigConfig, @@ -16,8 +17,17 @@ const browserPage = new BrowserPage(); const workbenchPage = new WorkbenchPage(); const databaseHelper = new DatabaseHelper(); const databaseAPIRequests = new DatabaseAPIRequests(); +const telemetry = new Telemetry(); let keyNames: string[] = []; +const telemetryEvent = 'TREE_VIEW_KEY_VALUE_VIEWED'; +const logger = telemetry.createLogger(); + +const expectedProperties = [ + 'databaseId', + 'keyType', + 'provider' +]; fixture `Tree view verifications` .meta({ type: 'regression', rte: rte.standalone }) @@ -101,17 +111,21 @@ test await t.expect(totalKeysValue).gte(10, 'the info message after upload does not appear'); }); -test('Verify that user can see the total number of keys, the number of keys scanned, the “Scan more” control displayed at the top of Tree view and Browser view', async t => { - await browserPage.selectFilterGroupType(KeyTypesTexts.Hash); +test.requestHooks(logger)('Verify that user can see the total number of keys, the number of keys scanned, the “Scan more” control displayed at the top of Tree view and Browser view', async t => { + await browserPage.selectFilterGroupType(KeyTypesTexts.ReJSON); // Verify the controls on the Browser view await t.expect(browserPage.totalKeysNumber.visible).ok('The total number of keys is not displayed on the Browser view'); await t.expect(browserPage.scannedValue.visible).ok('The number of keys scanned is not displayed on the Browser view'); await t.expect(browserPage.scanMoreButton.visible).ok('The scan more button is not displayed on the Browser view'); - // Verify the controls on the Tree view + //Verify the controls on the Tree view await t.click(browserPage.treeViewButton); await t.expect(browserPage.totalKeysNumber.visible).ok('The total number of keys is not displayed on the Tree view'); await t.expect(browserPage.scannedValue.visible).ok('The number of keys scanned is not displayed on the Tree view'); await t.expect(browserPage.scanMoreButton.visible).ok('The scan more button is not displayed on the Tree view'); + + // Verify that telemetry event 'TREE_VIEW_KEY_VALUE_VIEWED' sent + await t.click(browserPage.keyItem); + await telemetry.verifyEventHasProperties(telemetryEvent, expectedProperties, logger); }); test('Verify that when user deletes the key he can see the key is removed from the folder, the number of keys is reduced, the percentage is recalculated', async t => { const mainFolder = browserPage.TreeView.getFolderSelectorByName('device'); From fe9f51e863bf81a021bfd554c760dc37448964aa Mon Sep 17 00:00:00 2001 From: ArtemHoruzhenko Date: Mon, 7 Oct 2024 13:27:22 +0300 Subject: [PATCH 118/256] fix tests repo --- redisinsight/api/src/__mocks__/common.ts | 3 ++- redisinsight/api/src/__mocks__/databases.ts | 6 ----- .../local.ca-certificate.repository.spec.ts | 23 +++++++------------ ...ocal.client-certificate.repository.spec.ts | 19 ++++++--------- 4 files changed, 17 insertions(+), 34 deletions(-) diff --git a/redisinsight/api/src/__mocks__/common.ts b/redisinsight/api/src/__mocks__/common.ts index 2e3e86348a..85eee7e4ca 100644 --- a/redisinsight/api/src/__mocks__/common.ts +++ b/redisinsight/api/src/__mocks__/common.ts @@ -9,6 +9,7 @@ export type MockType = { export const mockQueryBuilderWhere = jest.fn().mockReturnThis(); export const mockQueryBuilderSelect = jest.fn().mockReturnThis(); +export const mockQueryBuilderLeftJoinAndSelect = jest.fn().mockReturnThis(); export const mockQueryBuilderGetOne = jest.fn(); export const mockQueryBuilderGetMany = jest.fn(); export const mockQueryBuilderGetManyRaw = jest.fn(); @@ -26,7 +27,7 @@ export const mockCreateQueryBuilder = jest.fn(() => ({ having: jest.fn().mockReturnThis(), limit: jest.fn().mockReturnThis(), leftJoin: jest.fn().mockReturnThis(), - leftJoinAndSelect: jest.fn().mockReturnThis(), + leftJoinAndSelect: mockQueryBuilderLeftJoinAndSelect, offset: jest.fn().mockReturnThis(), delete: jest.fn().mockReturnThis(), whereInIds: jest.fn().mockReturnThis(), diff --git a/redisinsight/api/src/__mocks__/databases.ts b/redisinsight/api/src/__mocks__/databases.ts index e4d69da655..ffd848dc0c 100644 --- a/redisinsight/api/src/__mocks__/databases.ts +++ b/redisinsight/api/src/__mocks__/databases.ts @@ -251,12 +251,6 @@ export const mockDatabaseRepository = jest.fn(() => ({ pick(mockDatabase, 'id', 'name'), pick(mockDatabase, 'id', 'name'), ]), - createQueryBuilder: jest.fn().mockReturnThis(), - leftJoinAndSelect: jest.fn().mockReturnThis(), - where: jest.fn().mockReturnThis(), - select: jest.fn().mockReturnThis(), - getMany: jest.fn().mockResolvedValue([]), - findOneBy: jest.fn().mockResolvedValue(mockDatabase), })); export const mockDatabaseService = jest.fn(() => ({ diff --git a/redisinsight/api/src/modules/certificate/repositories/local.ca-certificate.repository.spec.ts b/redisinsight/api/src/modules/certificate/repositories/local.ca-certificate.repository.spec.ts index 67449eb7f9..baf4791bf4 100644 --- a/redisinsight/api/src/modules/certificate/repositories/local.ca-certificate.repository.spec.ts +++ b/redisinsight/api/src/modules/certificate/repositories/local.ca-certificate.repository.spec.ts @@ -6,7 +6,6 @@ import { Repository } from 'typeorm'; import { mockCaCertificate, mockCaCertificateCertificateEncrypted, mockCaCertificateCertificatePlain, mockCaCertificateEntity, mockCaCertificateId, - mockDatabaseRepository, mockEncryptionService, mockRepository, MockType, @@ -22,6 +21,7 @@ describe('LocalCaCertificateRepository', () => { let service: LocalCaCertificateRepository; let encryptionService: MockType; let repository: MockType>; + let databaseRepository: MockType>; beforeEach(async () => { jest.clearAllMocks(); @@ -35,7 +35,7 @@ describe('LocalCaCertificateRepository', () => { }, { provide: getRepositoryToken(DatabaseEntity), - useFactory: mockDatabaseRepository, + useFactory: mockRepository, }, { provide: EncryptionService, @@ -45,6 +45,7 @@ describe('LocalCaCertificateRepository', () => { }).compile(); repository = await module.get(getRepositoryToken(CaCertificateEntity)); + databaseRepository = await module.get(getRepositoryToken(DatabaseEntity)); encryptionService = await module.get(EncryptionService); service = await module.get(LocalCaCertificateRepository); @@ -113,15 +114,7 @@ describe('LocalCaCertificateRepository', () => { // Mock findOneBy to return a certificate repository.findOneBy.mockResolvedValue(mockCaCertificate); - - // Mock getMany to return affected databases - const mockQueryBuilder = { - leftJoinAndSelect: jest.fn().mockReturnThis(), - where: jest.fn().mockReturnThis(), - select: jest.fn().mockReturnThis(), - getMany: jest.fn().mockResolvedValue(mockAffectedDatabases.map((id) => ({ id }))), - }; - jest.spyOn(service['databaseRepository'], 'createQueryBuilder').mockReturnValue(mockQueryBuilder as any); + databaseRepository.createQueryBuilder().getMany.mockResolvedValue(mockAffectedDatabases.map((id) => ({ id }))); // Mock delete operation repository.delete.mockResolvedValue(undefined); @@ -130,10 +123,10 @@ describe('LocalCaCertificateRepository', () => { expect(result).toEqual({ affectedDatabases: mockAffectedDatabases }); expect(repository.findOneBy).toHaveBeenCalledWith({ id: mockId }); - expect(service['databaseRepository'].createQueryBuilder).toHaveBeenCalledWith('d'); - expect(mockQueryBuilder.leftJoinAndSelect).toHaveBeenCalledWith('d.caCert', 'c'); - expect(mockQueryBuilder.where).toHaveBeenCalledWith({ caCert: mockId }); - expect(mockQueryBuilder.select).toHaveBeenCalledWith(['d.id']); + expect(databaseRepository.createQueryBuilder).toHaveBeenCalledWith('d'); + expect(databaseRepository.createQueryBuilder().leftJoinAndSelect).toHaveBeenCalledWith('d.caCert', 'c'); + expect(databaseRepository.createQueryBuilder().where).toHaveBeenCalledWith({ caCert: mockId }); + expect(databaseRepository.createQueryBuilder().select).toHaveBeenCalledWith(['d.id']); expect(repository.delete).toHaveBeenCalledWith(mockId); }); diff --git a/redisinsight/api/src/modules/certificate/repositories/local.client-certificate.repository.spec.ts b/redisinsight/api/src/modules/certificate/repositories/local.client-certificate.repository.spec.ts index ce3a843db9..79aa19387b 100644 --- a/redisinsight/api/src/modules/certificate/repositories/local.client-certificate.repository.spec.ts +++ b/redisinsight/api/src/modules/certificate/repositories/local.client-certificate.repository.spec.ts @@ -11,7 +11,6 @@ import { mockClientCertificateId, mockClientCertificateKeyEncrypted, mockClientCertificateKeyPlain, - mockDatabaseRepository, mockEncryptionService, mockRepository, MockType, @@ -29,6 +28,7 @@ describe('LocalClientCertificateRepository', () => { let service: LocalClientCertificateRepository; let encryptionService: MockType; let repository: MockType>; + let databaseRepository: MockType>; beforeEach(async () => { jest.clearAllMocks(); @@ -42,7 +42,7 @@ describe('LocalClientCertificateRepository', () => { }, { provide: getRepositoryToken(DatabaseEntity), - useFactory: mockDatabaseRepository, + useFactory: mockRepository, }, { provide: EncryptionService, @@ -52,6 +52,7 @@ describe('LocalClientCertificateRepository', () => { }).compile(); repository = await module.get(getRepositoryToken(ClientCertificateEntity)); + databaseRepository = await module.get(getRepositoryToken(DatabaseEntity)); encryptionService = await module.get(EncryptionService); service = await module.get(LocalClientCertificateRepository); @@ -133,13 +134,7 @@ describe('LocalClientCertificateRepository', () => { it('should delete client certificate and return affected databases', async () => { jest.spyOn(repository, 'findOneBy').mockResolvedValue(mockClientCertificate); - const mockQueryBuilder = { - leftJoinAndSelect: jest.fn().mockReturnThis(), - where: jest.fn().mockReturnThis(), - select: jest.fn().mockReturnThis(), - getMany: jest.fn().mockResolvedValue(mockAffectedDatabases.map((id) => ({ id }))) - }; - jest.spyOn(service['databaseRepository'], 'createQueryBuilder').mockReturnValue(mockQueryBuilder as any); + databaseRepository.createQueryBuilder().getMany.mockResolvedValue(mockAffectedDatabases.map((id) => ({ id }))); jest.spyOn(repository, 'delete').mockResolvedValue(undefined); @@ -148,9 +143,9 @@ describe('LocalClientCertificateRepository', () => { expect(result).toEqual({ affectedDatabases: mockAffectedDatabases }); expect(repository.findOneBy).toHaveBeenCalledWith({ id: mockId }); expect(service['databaseRepository'].createQueryBuilder).toHaveBeenCalledWith('d'); - expect(mockQueryBuilder.leftJoinAndSelect).toHaveBeenCalledWith('d.clientCert', 'c'); - expect(mockQueryBuilder.where).toHaveBeenCalledWith({ clientCert: mockId }); - expect(mockQueryBuilder.select).toHaveBeenCalledWith(['d.id']); + expect(databaseRepository.createQueryBuilder().leftJoinAndSelect).toHaveBeenCalledWith('d.clientCert', 'c'); + expect(databaseRepository.createQueryBuilder().where).toHaveBeenCalledWith({ clientCert: mockId }); + expect(databaseRepository.createQueryBuilder().select).toHaveBeenCalledWith(['d.id']); expect(repository.delete).toHaveBeenCalledWith(mockId); }); From 324fc7fcf5b2bb547996d46d08088e4e25d3b74f Mon Sep 17 00:00:00 2001 From: mariasergeenko Date: Mon, 7 Oct 2024 13:32:26 +0200 Subject: [PATCH 119/256] add more telemetry events --- .../browser/search-capabilities.e2e.ts | 46 +++++++++++++++++-- .../web/regression/browser/list-key.e2e.ts | 17 ++++++- 2 files changed, 58 insertions(+), 5 deletions(-) diff --git a/tests/e2e/tests/web/critical-path/browser/search-capabilities.e2e.ts b/tests/e2e/tests/web/critical-path/browser/search-capabilities.e2e.ts index 7d9efa1c66..15810f2507 100644 --- a/tests/e2e/tests/web/critical-path/browser/search-capabilities.e2e.ts +++ b/tests/e2e/tests/web/critical-path/browser/search-capabilities.e2e.ts @@ -1,6 +1,7 @@ import { Selector, t } from 'testcafe'; import { DatabaseHelper } from '../../../../helpers/database'; import { BrowserPage, MyRedisDatabasePage } from '../../../../pageObjects'; +import { Telemetry } from '../../../../helpers/telemetry'; import { commonUrl, ossStandaloneBigConfig, @@ -19,6 +20,32 @@ const myRedisDatabasePage = new MyRedisDatabasePage(); const databaseHelper = new DatabaseHelper(); const databaseAPIRequests = new DatabaseAPIRequests(); const apiKeyRequests = new APIKeyRequests(); +const telemetry = new Telemetry(); + +const telemetryEvents = ['SEARCH_MODE_CHANGED', 'SEARCH_INDEX_ADD_BUTTON_CLICKED', 'SEARCH_INDEX_ADDED']; +const logger = telemetry.createLogger(); +const expectedPropertiesMode = [ + 'current', + 'databaseId', + 'previous', + 'provider', + 'view' +]; + +const expectedPropertiesCreateIndex = [ + 'databaseId', + 'provider', + 'view' +]; + +const expectedPropertiesAddedIndex = [ + 'countOfFieldNames', + 'countOfPrefixes', + 'dataType', + 'databaseId', + 'provider', + 'view' +]; const patternModeTooltipText = 'Filter by Key Name or Pattern'; const redisearchModeTooltipText = 'Search by Values of Keys'; @@ -167,7 +194,7 @@ test await Common.checkURLContainsText(externalPageLinkFirst); await Common.checkURLContainsText(externalPageLinkSecond); }); -test +test.requestHooks(logger) .before(async() => { await databaseHelper.acceptLicenseTermsAndAddDatabaseApi(ossStandaloneBigConfig); }) @@ -177,10 +204,17 @@ test })('Index creation', async t => { const createIndexLink = 'https://redis.io/docs/latest/commands/ft.create/?utm_source=redisinsight&utm_medium=app&utm_campaign=browser_search'; - // Verify that user can cancel index creation + // Verify that telemetry event 'SEARCH_MODE_CHANGED' sent await t.click(browserPage.redisearchModeBtn); + await telemetry.verifyEventHasProperties(telemetryEvents[0], expectedPropertiesMode, logger); + + // Verify that user can cancel index creation await t.click(browserPage.selectIndexDdn); await t.click(browserPage.createIndexBtn); + + // Verify that telemetry event 'SEARCH_INDEX_ADD_BUTTON_CLICKED' sent + await telemetry.verifyEventHasProperties(telemetryEvents[1], expectedPropertiesCreateIndex, logger); + await t.expect(browserPage.newIndexPanel.exists).ok('New Index panel is not displayed'); await t.click(browserPage.cancelIndexCreationBtn); await t.expect(browserPage.newIndexPanel.exists).notOk('New Index panel is displayed'); @@ -197,8 +231,8 @@ test await goBackHistory(); // Verify that user can create an index with multiple prefixes - // await t.click(browserPage.selectIndexDdn); - // await t.click(browserPage.createIndexBtn); + await t.click(browserPage.selectIndexDdn); + await t.click(browserPage.createIndexBtn); await t.click(browserPage.indexNameInput); await t.typeText(browserPage.indexNameInput, indexName); await t.click(browserPage.prefixFieldInput); @@ -214,6 +248,10 @@ test await t.click(browserPage.indexIdentifierInput); await t.typeText(browserPage.indexIdentifierInput, 'k0'); await t.click(browserPage.confirmIndexCreationBtn); + + await telemetry.verifyEventHasProperties(telemetryEvents[2], expectedPropertiesAddedIndex, logger); + await telemetry.verifyEventPropertyValue(telemetryEvents[2], 'countOfPrefixes', '3', logger); + await t.expect(browserPage.newIndexPanel.exists).notOk('New Index panel is displayed'); await t.click(browserPage.selectIndexDdn); await browserPage.selectIndexByName(indexName); diff --git a/tests/e2e/tests/web/regression/browser/list-key.e2e.ts b/tests/e2e/tests/web/regression/browser/list-key.e2e.ts index 2ea70f9b64..33cfd76167 100644 --- a/tests/e2e/tests/web/regression/browser/list-key.e2e.ts +++ b/tests/e2e/tests/web/regression/browser/list-key.e2e.ts @@ -6,17 +6,27 @@ import { DatabaseAPIRequests } from '../../../../helpers/api/api-database'; import { populateListWithElements } from '../../../../helpers/keys'; import { Common } from '../../../../helpers/common'; import { APIKeyRequests } from '../../../../helpers/api/api-keys'; +import { Telemetry } from '../../../../helpers/telemetry'; const browserPage = new BrowserPage(); const databaseHelper = new DatabaseHelper(); const databaseAPIRequests = new DatabaseAPIRequests(); const apiKeyRequests = new APIKeyRequests(); +const telemetry = new Telemetry(); const dbParameters = { host: ossStandaloneConfig.host, port: ossStandaloneConfig.port }; const keyName = `TestListKey-${ Common.generateWord(10) }`; const elementForSearch = `SearchField-${ Common.generateWord(5) }`; const keyToAddParameters = { elementsCount: 500000, keyName, elementStartWith: 'listElement' }; +const telemetryEvent = 'LIST_VIEW_OPENED'; +const logger = telemetry.createLogger(); + +const expectedProperties = [ + 'databaseId', + 'provider' +]; + fixture `List Key verification` .meta({ type: 'regression' }) .page(commonUrl) @@ -29,11 +39,16 @@ fixture `List Key verification` await apiKeyRequests.deleteKeyByNameApi(keyName, ossStandaloneConfig.databaseName); await databaseAPIRequests.deleteStandaloneDatabaseApi(ossStandaloneConfig); }); -test +test.requestHooks(logger) .meta({ rte: rte.standalone })('Verify that user can search per exact element index in List key in DB with 1 million of fields', async t => { // Add 1000000 elements to the list key await populateListWithElements(dbParameters.host, dbParameters.port, keyToAddParameters); await populateListWithElements(dbParameters.host, dbParameters.port, keyToAddParameters); + + // Verify that telemetry event 'TREE_VIEW_KEY_VALUE_VIEWED' sent + await telemetry.verifyEventHasProperties(telemetryEvent, expectedProperties, logger); + + await t.click(browserPage.browserViewButton); // Add custom element to the list key await browserPage.openKeyDetails(keyName); await browserPage.addElementToList(elementForSearch); From 1fc1bd2e27b17e8647911dabb3614ac83578448b Mon Sep 17 00:00:00 2001 From: mariasergeenko Date: Mon, 7 Oct 2024 14:29:39 +0200 Subject: [PATCH 120/256] fix --- tests/e2e/helpers/telemetry.ts | 2 +- tests/e2e/tests/web/regression/browser/list-key.e2e.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/e2e/helpers/telemetry.ts b/tests/e2e/helpers/telemetry.ts index a71057d1ba..bdc2e6e971 100644 --- a/tests/e2e/helpers/telemetry.ts +++ b/tests/e2e/helpers/telemetry.ts @@ -65,6 +65,6 @@ export class Telemetry { const requestBody = JSON.parse(request.request.body.toString()); // Verify that event has correct property value - await t.expect(requestBody.eventData[property]).eql(value); + await t.expect(String(requestBody.eventData[property])).eql(value); } } diff --git a/tests/e2e/tests/web/regression/browser/list-key.e2e.ts b/tests/e2e/tests/web/regression/browser/list-key.e2e.ts index 33cfd76167..1c29dc39fd 100644 --- a/tests/e2e/tests/web/regression/browser/list-key.e2e.ts +++ b/tests/e2e/tests/web/regression/browser/list-key.e2e.ts @@ -46,9 +46,9 @@ test.requestHooks(logger) await populateListWithElements(dbParameters.host, dbParameters.port, keyToAddParameters); // Verify that telemetry event 'TREE_VIEW_KEY_VALUE_VIEWED' sent + await t.click(browserPage.browserViewButton); await telemetry.verifyEventHasProperties(telemetryEvent, expectedProperties, logger); - await t.click(browserPage.browserViewButton); // Add custom element to the list key await browserPage.openKeyDetails(keyName); await browserPage.addElementToList(elementForSearch); From 0b1621da5dc64568d2db6c453c1d607f77fff564 Mon Sep 17 00:00:00 2001 From: mariasergeenko Date: Mon, 7 Oct 2024 16:00:26 +0200 Subject: [PATCH 121/256] fix for regression tests --- tests/e2e/pageObjects/browser-page.ts | 19 +++++++++++++------ .../web/critical-path/browser/list-key.e2e.ts | 2 +- .../browser/large-key-details-values.e2e.ts | 4 ++-- .../web/regression/browser/list-key.e2e.ts | 2 +- .../regression/browser/resize-columns.e2e.ts | 2 +- .../web/smoke/browser/edit-key-value.e2e.ts | 2 +- .../tests/web/smoke/browser/list-key.e2e.ts | 2 +- 7 files changed, 20 insertions(+), 13 deletions(-) diff --git a/tests/e2e/pageObjects/browser-page.ts b/tests/e2e/pageObjects/browser-page.ts index 297bdded5f..e3facd8dff 100644 --- a/tests/e2e/pageObjects/browser-page.ts +++ b/tests/e2e/pageObjects/browser-page.ts @@ -162,7 +162,6 @@ export class BrowserPage extends InstancePage { hashFieldNameInput = Selector('[data-testid=field-name]'); hashFieldValueEditor = Selector('[data-testid^=hash_value-editor]'); hashTtlFieldInput = Selector('[data-testid=hash-ttl]'); - listKeyElementInput = Selector('[data-testid=element]'); listKeyElementEditorInput = Selector('[data-testid^=list_value-editor-]'); stringKeyValueInput = Selector('[data-testid=string-value]'); jsonKeyValueInput = Selector('[data-mode-id=json]'); @@ -265,12 +264,14 @@ export class BrowserPage extends InstancePage { keyListItem = Selector('[role=rowgroup] [role=row]'); // Dialog noReadySearchDialogTitle = Selector('[data-testid=welcome-page-title]'); + //checkbox + showTtlCheckbox = Selector('[data-testid=test-check-ttl]~label'); //Get Hash key field ttl value //for Redis databases 7.4 and higher getHashTtlFieldInput = (fieldName: string): Selector => (Selector(`[data-testid=hash-ttl_content-value-${fieldName}]`)); - //checkbox - showTtlCheckbox = Selector('[data-testid=test-check-ttl]~label'); + getListElementInput = (count: number): Selector => (Selector(`[data-testid*=element-${count}]`)); + /** * Common part for Add any new key @@ -385,7 +386,7 @@ export class BrowserPage extends InstancePage { * @param TTL The Time to live value of the key * @param element The key element */ - async addListKey(keyName: string, TTL = ' ', element = ' '): Promise { + async addListKey(keyName: string, TTL = ' ', element = [' ']): Promise { await Common.waitForElementNotVisible(this.progressLine); await Common.waitForElementNotVisible(this.loader); await t.click(this.plusAddKeyButton); @@ -395,8 +396,14 @@ export class BrowserPage extends InstancePage { await t.typeText(this.addKeyNameInput, keyName, { replace: true, paste: true }); await t.click(this.keyTTLInput); await t.typeText(this.keyTTLInput, TTL, { replace: true, paste: true }); - await t.click(this.listKeyElementInput); - await t.typeText(this.listKeyElementInput, element, { replace: true, paste: true }); + for(let i = 0; i < element.length; i++ ) { + await t.click(this.getListElementInput(i)); + await t.typeText(this.getListElementInput(i), element[i], { replace: true, paste: true }); + // If there's more than one element and it's not the last element, add a new row + if (element.length > 1 && i < element.length - 1) { + await t.click(this.addStreamRow); + } + } await t.click(this.addKeyButton); } diff --git a/tests/e2e/tests/web/critical-path/browser/list-key.e2e.ts b/tests/e2e/tests/web/critical-path/browser/list-key.e2e.ts index 0fe2cce93e..15d29061f5 100644 --- a/tests/e2e/tests/web/critical-path/browser/list-key.e2e.ts +++ b/tests/e2e/tests/web/critical-path/browser/list-key.e2e.ts @@ -33,7 +33,7 @@ fixture `List Key verification` }); test('Verify that user can search List element by index', async t => { keyName = Common.generateWord(10); - await browserPage.addListKey(keyName, keyTTL, elements[0]); + await browserPage.addListKey(keyName, keyTTL, [elements[0]]); // Add few elements to the List key await browserPage.addElementToList(elements[1]); await browserPage.addElementToList(elements[2]); diff --git a/tests/e2e/tests/web/regression/browser/large-key-details-values.e2e.ts b/tests/e2e/tests/web/regression/browser/large-key-details-values.e2e.ts index 8d3614486e..2c1c853715 100644 --- a/tests/e2e/tests/web/regression/browser/large-key-details-values.e2e.ts +++ b/tests/e2e/tests/web/regression/browser/large-key-details-values.e2e.ts @@ -94,7 +94,7 @@ test('Verify that user can expand/collapse for sorted set data type', async t => test('Verify that user can expand/collapse for list data type', async t => { const elementValueCell = browserPage.listElementsList.parent(2); // Create list key - await browserPage.addListKey(keyName, keyTTL, value); + await browserPage.addListKey(keyName, keyTTL, [value]); // Remember height of the cell with long value const startLongCellHeight = await elementValueCell.clientHeight; // Verify that user can expand a row of list data type @@ -107,7 +107,7 @@ test('Verify that user can expand/collapse for list data type', async t => { test('Verify that user can work in full mode with expanded/collapsed value', async t => { const elementValueCell = browserPage.listElementsList.parent(2); // Create list key - await browserPage.addListKey(keyName, keyTTL, value); + await browserPage.addListKey(keyName, keyTTL, [value]); // Open full mode for key details await t.click(browserPage.fullScreenModeButton); // Remember height of the cell with long value diff --git a/tests/e2e/tests/web/regression/browser/list-key.e2e.ts b/tests/e2e/tests/web/regression/browser/list-key.e2e.ts index 2ea70f9b64..76a7b88929 100644 --- a/tests/e2e/tests/web/regression/browser/list-key.e2e.ts +++ b/tests/e2e/tests/web/regression/browser/list-key.e2e.ts @@ -22,7 +22,7 @@ fixture `List Key verification` .page(commonUrl) .beforeEach(async() => { await databaseHelper.acceptLicenseTermsAndAddDatabaseApi(ossStandaloneConfig); - await browserPage.addListKey(keyName, '2147476121', 'testElement'); + await browserPage.addListKey(keyName, '2147476121', ['testElement']); }) .afterEach(async() => { // Clear and delete database diff --git a/tests/e2e/tests/web/regression/browser/resize-columns.e2e.ts b/tests/e2e/tests/web/regression/browser/resize-columns.e2e.ts index 5f86ecff1c..76a9780f4a 100644 --- a/tests/e2e/tests/web/regression/browser/resize-columns.e2e.ts +++ b/tests/e2e/tests/web/regression/browser/resize-columns.e2e.ts @@ -54,7 +54,7 @@ fixture `Resize columns in Key details` await databaseHelper.acceptLicenseTermsAndAddDatabaseApi(databasesForAdding[0]); await databaseAPIRequests.addNewStandaloneDatabaseApi(databasesForAdding[1]); await browserPage.addHashKey(keys[0].name, '2147476121', longFieldName, longFieldName); - await browserPage.addListKey(keys[1].name, '2147476121', 'element'); + await browserPage.addListKey(keys[1].name, '2147476121', ['element']); await browserPage.addZSetKey(keys[2].name, '1', '2147476121', 'member'); }) .afterEach(async() => { diff --git a/tests/e2e/tests/web/smoke/browser/edit-key-value.e2e.ts b/tests/e2e/tests/web/smoke/browser/edit-key-value.e2e.ts index 6d45f90585..df86fbd2a4 100644 --- a/tests/e2e/tests/web/smoke/browser/edit-key-value.e2e.ts +++ b/tests/e2e/tests/web/smoke/browser/edit-key-value.e2e.ts @@ -93,7 +93,7 @@ test('Verify that user can edit List Key element', async t => { keyName = Common.generateWord(10); // Add List key - await browserPage.addListKey(keyName, keyTTL, keyValueBefore); + await browserPage.addListKey(keyName, keyTTL, [keyValueBefore]); // Check the key value before edit let keyValue = await browserPage.getListKeyValue(); await t.expect(keyValue).eql(keyValueBefore, 'The List value is incorrect'); diff --git a/tests/e2e/tests/web/smoke/browser/list-key.e2e.ts b/tests/e2e/tests/web/smoke/browser/list-key.e2e.ts index 9dcf5e31ef..5c038069e7 100644 --- a/tests/e2e/tests/web/smoke/browser/list-key.e2e.ts +++ b/tests/e2e/tests/web/smoke/browser/list-key.e2e.ts @@ -48,7 +48,7 @@ test('Verify that user can select remove List element position: from tail', asyn }); test('Verify that user can select remove List element position: from head', async t => { keyName = Common.generateWord(10); - await browserPage.addListKey(keyName, keyTTL, element); + await browserPage.addListKey(keyName, keyTTL, [element]); // Add few elements to the List key await browserPage.addElementToList(element2); await browserPage.addElementToList(element3); From 8e94a0d3b156114c53b02ef78c71c174975a16ea Mon Sep 17 00:00:00 2001 From: mariasergeenko Date: Tue, 8 Oct 2024 11:04:55 +0200 Subject: [PATCH 122/256] add test for list keys --- tests/e2e/helpers/constants.ts | 5 + tests/e2e/pageObjects/browser-page.ts | 114 +++++------------- .../web/critical-path/browser/list-key.e2e.ts | 4 +- .../critical-path/browser/stream-key.e2e.ts | 2 +- .../web/regression/browser/list-key.e2e.ts | 71 +++++++++-- .../tests/web/smoke/browser/list-key.e2e.ts | 8 +- .../tests/web/smoke/browser/zset-key.e2e.ts | 4 +- 7 files changed, 107 insertions(+), 101 deletions(-) diff --git a/tests/e2e/helpers/constants.ts b/tests/e2e/helpers/constants.ts index b447dfdc96..b1b2ddb2fa 100644 --- a/tests/e2e/helpers/constants.ts +++ b/tests/e2e/helpers/constants.ts @@ -126,3 +126,8 @@ export enum TlsCertificates { Client = 'client', } +export enum AddElementInList { + Head , + Tail, +} + diff --git a/tests/e2e/pageObjects/browser-page.ts b/tests/e2e/pageObjects/browser-page.ts index e3facd8dff..4cfb68bd09 100644 --- a/tests/e2e/pageObjects/browser-page.ts +++ b/tests/e2e/pageObjects/browser-page.ts @@ -1,7 +1,8 @@ -import { t, Selector } from 'testcafe'; +import { Selector, t } from 'testcafe'; import { Common } from '../helpers/common'; import { InstancePage } from './instance-page'; import { BulkActions, TreeView } from './components/browser'; +import { AddElementInList } from '../helpers/constants'; export class BrowserPage extends InstancePage { BulkActions = new BulkActions(); @@ -12,7 +13,6 @@ export class BrowserPage extends InstancePage { cssSelectorRows = '[aria-label="row"]'; cssSelectorKey = '[data-testid^=key-]'; cssFilteringLabel = '[data-testid=multi-search]'; - cssPrimitiveJsonValue = '[data-testid=json-primitive-value]'; cssJsonValue = '[data-testid=value-as-json]'; cssRowInVirtualizedTable = '[role=gridcell]'; cssVirtualTableRow = '[aria-label=row]'; @@ -20,23 +20,13 @@ export class BrowserPage extends InstancePage { cssKeyTtl = '[data-testid^=ttl-]'; cssKeySize = '[data-testid^=size-]'; cssRemoveSuggestionItem = '[data-testid^=remove-suggestion-item-]'; - //------------------------------------------------------------------------------------------- - //DECLARATION OF SELECTORS - //*Declare all elements/components of the relevant page. - //*Target any element/component via data-id, if possible! - //*The following categories are ordered alphabetically (Alerts, Buttons, Checkboxes, etc.). - //------------------------------------------------------------------------------------------- + //BUTTONS - hashDeleteButton = Selector('[data-testid=hash-delete-btn]'); - setDeleteButton = Selector('[data-testid=set-delete-btn]'); - streamDeleteButton = Selector('[data-testid=stream-delete-btn]'); applyButton = Selector('[data-testid=apply-btn]'); deleteKeyButton = Selector('[data-testid=delete-key-btn]'); submitDeleteKeyButton = Selector('[data-testid=submit-delete-key]'); confirmDeleteKeyButton = Selector('[data-testid=delete-key-confirm-btn]'); editKeyTTLButton = Selector('[data-testid=edit-ttl-btn]'); - closeEditTTL = Selector('[data-testid=cancel-btn]'); - saveTTLValue = Selector('[data-testid=apply-btn]'); refreshKeysButton = Selector('[data-testid=keys-refresh-btn]'); refreshKeyButton = Selector('[data-testid=key-refresh-btn]'); editKeyNameButton = Selector('[data-testid=edit-key-btn]'); @@ -52,9 +42,9 @@ export class BrowserPage extends InstancePage { confirmRemoveHashFieldButton = Selector('[data-testid^=remove-hash-button-] span'); removeSetMemberButton = Selector('[data-testid^=set-remove-btn]'); removeHashFieldButton = Selector('[data-testid^=remove-hash-button]'); - removeZserMemberButton = Selector('[data-testid^=zset-remove-button]'); + removeZsetMemberButton = Selector('[data-testid^=zset-remove-button]'); confirmRemoveSetMemberButton = Selector('[data-testid^=set-remove-btn-] span'); - confirmRemovZSetMemberButton = Selector('[data-testid^=zset-remove-button-] span'); + confirmRemoveZSetMemberButton = Selector('[data-testid^=zset-remove-button-] span'); saveElementButton = Selector('[data-testid=save-elements-btn]'); removeElementFromListIconButton = Selector('[data-testid=remove-key-value-items-btn]'); removeElementFromListButton = Selector('[data-testid=remove-elements-btn]'); @@ -73,7 +63,6 @@ export class BrowserPage extends InstancePage { browserViewButton = Selector('[data-testid=view-type-browser-btn]'); searchButton = Selector('[data-testid=search-btn]'); clearFilterButton = Selector('[data-testid=reset-filter-btn]'); - clearSelectionButton = Selector('[data-testid=clear-selection-btn]'); fullScreenModeButton = Selector('[data-testid=toggle-full-screen]'); closeRightPanel = Selector('[data-testid=close-right-panel-btn]'); addNewStreamEntry = Selector('[data-testid=add-key-value-items-btn]'); @@ -172,17 +161,15 @@ export class BrowserPage extends InstancePage { hashFieldInput = Selector('[data-testid=hash-field]'); hashValueInput = Selector('[data-testid=hash-value]'); searchInput = Selector('[data-testid=search]'); - addListKeyElementInput = Selector('[data-testid=elements-input]'); jsonKeyInput = Selector('[data-testid=json-key]'); jsonValueInput = Selector('[data-testid=json-value]'); countInput = Selector('[data-testid=count-input]'); streamEntryId = Selector('[data-testid=entryId]'); streamField = Selector('[data-testid=field-name]'); streamValue = Selector('[data-testid=field-value]'); - addStreamRow = Selector('[data-testid=add-item]'); + addAdditionalElement = Selector('[data-testid=add-item]'); streamFieldsValues = Selector('[data-testid^=stream-entry-field-]'); streamEntryIDDateValue = Selector('[data-testid^=stream-entry-][data-testid$=date]'); - streamRangeEndInput = Selector('[data-testid=range-end-input]'); groupNameInput = Selector('[data-testid=group-name-field]'); consumerIdInput = Selector('[data-testid=id-field]'); streamMinIdleTimeInput = Selector('[data-testid=min-idle-time]'); @@ -193,7 +180,6 @@ export class BrowserPage extends InstancePage { indexNameInput = Selector('[data-testid=index-name]'); prefixFieldInput = Selector('[data-test-subj=comboBoxInput]'); indexIdentifierInput = Selector('[data-testid^=identifier-]'); - indexFieldType = Selector('[data-testid^=field-type-]'); //TEXT ELEMENTS keySizeDetails = Selector('[data-testid=key-size-text]'); keyLengthDetails = Selector('[data-testid=key-length-text]'); @@ -216,9 +202,6 @@ export class BrowserPage extends InstancePage { keysNumberOfResults = Selector('[data-testid=keys-number-of-results]'); scannedValue = Selector('[data-testid=keys-number-of-scanned]'); totalKeysNumber = Selector('[data-testid=keys-total]'); - databaseInfoToolTip = Selector('[data-testid=db-info-tooltip]'); - ttlValueInKeysTable = Selector('[data-testid^=ttl-]'); - stringKeyValue = Selector('.key-details-body pre'); keyDetailsBadge = Selector('.key-details-header .euiBadge__text'); modulesTypeDetails = Selector('[data-testid=modules-type-details]'); filteringLabel = Selector('[data-testid^=badge-]'); @@ -234,16 +217,12 @@ export class BrowserPage extends InstancePage { progressKeyList = Selector('[data-testid=progress-key-list]'); jsonScalarValue = Selector('[data-testid=json-scalar-value]'); noKeysToDisplayText = Selector('[data-testid=no-result-found-msg]'); - streamEntryColumns = Selector(this.streamEntriesContainer.find('[aria-colcount]')); - streamEntryRows = Selector(this.streamEntriesContainer.find('[aria-rowcount]')); streamEntryDate = Selector('[data-testid*=-date][data-testid*=stream-entry]'); streamEntryIdValue = Selector('.streamItemId[data-testid*=stream-entry]'); streamFields = Selector('[data-testid=stream-entries-container] .truncateText'); streamVirtualContainer = Selector('[data-testid=virtual-grid-container] div div').nth(0); streamEntryFields = Selector('[data-testid^=stream-entry-field]'); confirmationMessagePopover = Selector('div.euiPopover__panel .euiText '); - streamRangeLeftTimestamp = Selector('[data-testid=range-left-timestamp]'); - streamRangeRightTimestamp = Selector('[data-testid=range-right-timestamp]'); streamGroupId = Selector('.streamItemId[data-testid^=stream-group-id]'); streamGroupName = Selector('[data-testid^=stream-group-name]'); streamMessage = Selector('[data-testid*=-date][data-testid^=stream-message]'); @@ -252,7 +231,6 @@ export class BrowserPage extends InstancePage { entryIdInfoIcon = Selector('[data-testid=entry-id-info-icon]'); entryIdError = Selector('[data-testid=id-error]'); pendingCount = Selector('[data-testid=pending-count]'); - lastRefreshMessage = Selector('[data-testid=refresh-message]'); streamRangeBar = Selector('[data-testid=mock-fill-range]'); rangeLeftTimestamp = Selector('[data-testid=range-left-timestamp]'); rangeRightTimestamp = Selector('[data-testid=range-right-timestamp]'); @@ -386,7 +364,7 @@ export class BrowserPage extends InstancePage { * @param TTL The Time to live value of the key * @param element The key element */ - async addListKey(keyName: string, TTL = ' ', element = [' ']): Promise { + async addListKey(keyName: string, TTL = ' ', element: string[] = [' '], position: AddElementInList = AddElementInList.Tail): Promise { await Common.waitForElementNotVisible(this.progressLine); await Common.waitForElementNotVisible(this.loader); await t.click(this.plusAddKeyButton); @@ -396,12 +374,19 @@ export class BrowserPage extends InstancePage { await t.typeText(this.addKeyNameInput, keyName, { replace: true, paste: true }); await t.click(this.keyTTLInput); await t.typeText(this.keyTTLInput, TTL, { replace: true, paste: true }); + + if(position === AddElementInList.Head){ + await t.click(this.removeElementFromListSelect); + await t.click(this.removeFromHeadSelection); + await t.expect(this.removeFromHeadSelection.exists).notOk(); + } + for(let i = 0; i < element.length; i++ ) { await t.click(this.getListElementInput(i)); await t.typeText(this.getListElementInput(i), element[i], { replace: true, paste: true }); // If there's more than one element and it's not the last element, add a new row if (element.length > 1 && i < element.length - 1) { - await t.click(this.addStreamRow); + await t.click(this.addAdditionalElement); } } await t.click(this.addKeyButton); @@ -487,7 +472,7 @@ export class BrowserPage extends InstancePage { await t.typeText(this.streamField.nth(-1), fields[i], { replace: true, paste: true }) .typeText(this.streamValue.nth(-1), values[i], { replace: true, paste: true }); if (i < fields.length - 1) { - await t.click(this.addStreamRow); + await t.click(this.addAdditionalElement); } } if (entryId !== undefined) { @@ -524,24 +509,6 @@ export class BrowserPage extends InstancePage { await t.pressKey('enter'); } - /** - * Searching by Key name in the list and clicking Scan More until find - * @param searchPattern Search pattern to enter - * @param keyName The name of the key - */ - async searchByKeyNameWithScanMore(searchPattern: string, keyName: string): Promise { - await this.searchByKeyName(searchPattern); - const scannedValueText = Number(await this.scannedValue.textContent); - const totalKeysValue = Number(await this.totalKeysNumber.textContent); - // Scan until finding element or all keys scanned - while (true) { - await t.click(this.scanMoreButton); - if (await this.isKeyIsDisplayedInTheList(keyName) || scannedValueText === totalKeysValue) { - break; - } - } - } - /** * Get selector by key name * @param keyName The name of the key @@ -630,18 +597,6 @@ export class BrowserPage extends InstancePage { return this.stringKeyValueInput.textContent; } - /** - * Edit Zset key the firstscore from details - * @param value The new value of the key - */ - async editZsetKeyScore(value: string): Promise { - await t - .hover(this.zsetScoresList) - .click(this.editZsetButton) - .typeText(this.inlineItemEditor, value, { replace: true, paste: true }) - .click(this.EditorButton.applyBtn); - } - //Get Zset key score from details async getZsetKeyScore(): Promise { return this.zsetScoresList.textContent; @@ -713,17 +668,6 @@ export class BrowserPage extends InstancePage { return this.listElementsList.textContent; } - /** - * Edit JSON key value from details - * @param value The value of the key - */ - async editJsonKeyValue(value: string): Promise { - await t - .click(this.jsonScalarValue) - .typeText(this.inlineItemEditor, value, { replace: true, paste: true }) - .click(this.EditorButton.applyBtn); - } - //Get JSON key value from details async getJsonKeyValue(): Promise { return this.jsonKeyValue.textContent; @@ -813,23 +757,25 @@ export class BrowserPage extends InstancePage { * Add element to the List key * @param element The value of the list element */ - async addElementToList(element: string): Promise { + async addElementToList(element: string[], position: AddElementInList = AddElementInList.Tail ): Promise { if (await this.Toast.toastCloseButton.exists) { await t.click(this.Toast.toastCloseButton); } await t .click(this.addKeyValueItemsButton) - .typeText(this.addListKeyElementInput, element, { replace: true, paste: true }) - .click(this.saveElementButton); - } - - //Remove List element from tail for Redis databases less then v. 6.2. - async removeListElementFromTailOld(): Promise { - await t - .click(this.removeElementFromListIconButton) - .expect(this.countInput.withAttribute('disabled').exists).ok('Input field not disabled') - .click(this.removeElementFromListButton) - .click(this.confirmRemoveListElementButton); + if(position === AddElementInList.Head){ + await t.click(this.removeElementFromListSelect); + await t.click(this.removeFromHeadSelection); + await t.expect(this.removeFromHeadSelection.exists).notOk(); + } + for (let i = 0; i < element.length; i ++){ + await t.typeText(this.getListElementInput(i), element[i], { replace: true, paste: true }); + // If there's more than one element and it's not the last element, add a new row + if (element.length > 1 && i < element.length - 1) { + await t.click(this.addAdditionalElement); + } + } + await t.click(this.saveElementButton); } //Remove List element from head for Redis databases less then v. 6.2. diff --git a/tests/e2e/tests/web/critical-path/browser/list-key.e2e.ts b/tests/e2e/tests/web/critical-path/browser/list-key.e2e.ts index 15d29061f5..f1bdc8c165 100644 --- a/tests/e2e/tests/web/critical-path/browser/list-key.e2e.ts +++ b/tests/e2e/tests/web/critical-path/browser/list-key.e2e.ts @@ -35,8 +35,8 @@ test('Verify that user can search List element by index', async t => { keyName = Common.generateWord(10); await browserPage.addListKey(keyName, keyTTL, [elements[0]]); // Add few elements to the List key - await browserPage.addElementToList(elements[1]); - await browserPage.addElementToList(elements[2]); + await browserPage.addElementToList([elements[1]]); + await browserPage.addElementToList([elements[2]]); // Search List element by index await browserPage.searchByTheValueInKeyDetails('1'); // Check the search result diff --git a/tests/e2e/tests/web/critical-path/browser/stream-key.e2e.ts b/tests/e2e/tests/web/critical-path/browser/stream-key.e2e.ts index 2771935808..9d2e605aa5 100644 --- a/tests/e2e/tests/web/critical-path/browser/stream-key.e2e.ts +++ b/tests/e2e/tests/web/critical-path/browser/stream-key.e2e.ts @@ -63,7 +63,7 @@ test('Verify that user can add several fields and values during Stream key creat await t.scroll(scrollSelector, 'bottom'); await t.expect(browserPage.streamField.count).eql(i + 1, 'Number of added fields not correct'); if (i < Object.keys(streamData).length - 1) { - await t.click(browserPage.addStreamRow); + await t.click(browserPage.addAdditionalElement); } } await t.expect(browserPage.addKeyButton.withAttribute('disabled').exists).notOk('Clickable Add Key button'); diff --git a/tests/e2e/tests/web/regression/browser/list-key.e2e.ts b/tests/e2e/tests/web/regression/browser/list-key.e2e.ts index 76a7b88929..ec2fa863e5 100644 --- a/tests/e2e/tests/web/regression/browser/list-key.e2e.ts +++ b/tests/e2e/tests/web/regression/browser/list-key.e2e.ts @@ -1,7 +1,7 @@ -import { rte } from '../../../../helpers/constants'; +import { AddElementInList, rte } from '../../../../helpers/constants'; import { DatabaseHelper } from '../../../../helpers/database'; import { BrowserPage } from '../../../../pageObjects'; -import { commonUrl, ossStandaloneConfig } from '../../../../helpers/conf'; +import { commonUrl, ossStandaloneConfig, redisEnterpriseClusterConfig } from '../../../../helpers/conf'; import { DatabaseAPIRequests } from '../../../../helpers/api/api-database'; import { populateListWithElements } from '../../../../helpers/keys'; import { Common } from '../../../../helpers/common'; @@ -21,13 +21,12 @@ fixture `List Key verification` .meta({ type: 'regression' }) .page(commonUrl) .beforeEach(async() => { - await databaseHelper.acceptLicenseTermsAndAddDatabaseApi(ossStandaloneConfig); + await databaseHelper.acceptLicenseTermsAndAddREClusterDatabase(redisEnterpriseClusterConfig); await browserPage.addListKey(keyName, '2147476121', ['testElement']); }) .afterEach(async() => { - // Clear and delete database - await apiKeyRequests.deleteKeyByNameApi(keyName, ossStandaloneConfig.databaseName); - await databaseAPIRequests.deleteStandaloneDatabaseApi(ossStandaloneConfig); + await apiKeyRequests.deleteKeyByNameApi(keyName, redisEnterpriseClusterConfig.databaseName); + await databaseHelper.deleteDatabase(redisEnterpriseClusterConfig.databaseName); }); test .meta({ rte: rte.standalone })('Verify that user can search per exact element index in List key in DB with 1 million of fields', async t => { @@ -36,10 +35,68 @@ test await populateListWithElements(dbParameters.host, dbParameters.port, keyToAddParameters); // Add custom element to the list key await browserPage.openKeyDetails(keyName); - await browserPage.addElementToList(elementForSearch); + await browserPage.addElementToList([elementForSearch]); // Search by element index await browserPage.searchByTheValueInKeyDetails('1000001'); // Check the search result const result = await browserPage.listElementsList.nth(0).textContent; await t.expect(result).eql(elementForSearch, 'List element not found'); }); + +// TODO unskip when the bug is fixed https://redislabs.atlassian.net/browse/RI-6188 +test.skip + .before(async() => { + await databaseHelper.acceptLicenseTermsAndAddREClusterDatabase(redisEnterpriseClusterConfig); + + }) + .after(async() => { + await browserPage.Cli.sendCommandInCli('flushdb'); + await databaseHelper.deleteDatabase(redisEnterpriseClusterConfig.databaseName); + }) + ('Verify that user can add a multiple fields', async t => { + + const tailKeyName = 'tailListKey'; + const headKeyName = 'headKeyName'; + + const elementsValue = [ + 'element1', + 'element2', + 'element3', + 'element4' + ] + + await browserPage.addListKey(tailKeyName, '2147476121', [elementsValue[0],elementsValue[1], elementsValue[2]]); + await browserPage.openKeyDetails(tailKeyName); + + await t.expect(browserPage.listElementsList.nth(0).textContent).eql(elementsValue[0], 'the first element is not corrected for add in tail'); + let count = await browserPage.listElementsList.count; + await t.expect(browserPage.listElementsList.nth(count - 1).textContent).eql(elementsValue[2], 'the last element is not corrected for add in tail'); + + await browserPage.addListKey(headKeyName, '2147476121', [elementsValue[0],elementsValue[1], elementsValue[2]], AddElementInList.Head); + await browserPage.openKeyDetails(headKeyName); + + await t.expect(browserPage.listElementsList.nth(0).textContent).eql(elementsValue[2], 'the first element is not corrected for add in tail'); + count = await browserPage.listElementsList.count; + await t.expect(browserPage.listElementsList.nth(count - 1).textContent).eql(elementsValue[0], 'the last element is not corrected for add in tail'); + + }); +test + .meta({ rte: rte.reCluster })('Verify that user can edit a multiple fields', async t => { + const elementsValue = [ + 'element1', + 'element2', + 'element3', + 'element4' + ] + await browserPage.openKeyDetails(keyName); + + await browserPage.addElementToList([elementsValue[0], elementsValue[1]]); + await t.expect(browserPage.listElementsList.nth(0).textContent).eql('testElement', 'the first element is not corrected for add in tail'); + let count = await browserPage.listElementsList.count; + await t.expect(browserPage.listElementsList.nth(count - 1).textContent).eql(elementsValue[1], 'the last element is not corrected for add in tail'); + + await browserPage.addElementToList([elementsValue[2], elementsValue[3]], AddElementInList.Head); + await t.expect(browserPage.listElementsList.nth(0).textContent).eql(elementsValue[3], 'the first element is not corrected for add in head'); + count = await browserPage.listElementsList.count; + await t.expect(browserPage.listElementsList.nth(count - 1).textContent).eql(elementsValue[1], 'the last element is not corrected for add in head'); + }); diff --git a/tests/e2e/tests/web/smoke/browser/list-key.e2e.ts b/tests/e2e/tests/web/smoke/browser/list-key.e2e.ts index 5c038069e7..a1d539cf41 100644 --- a/tests/e2e/tests/web/smoke/browser/list-key.e2e.ts +++ b/tests/e2e/tests/web/smoke/browser/list-key.e2e.ts @@ -32,12 +32,11 @@ test('Verify that user can select remove List element position: from tail', asyn keyName = Common.generateWord(10); await browserPage.addListKey(keyName, keyTTL); // Add few elements to the List key - await browserPage.addElementToList(element); + await browserPage.addElementToList([element]); // Verify that user can add element to List await t.expect(browserPage.listElementsList.withExactText(element).exists).ok('The list element not added', { timeout: 10000 }); - await browserPage.addElementToList(element2); - await browserPage.addElementToList(element3); + await browserPage.addElementToList([element2,element3]); // Remove element from the key await browserPage.removeListElementFromTail('1'); // Check the notification message @@ -50,8 +49,7 @@ test('Verify that user can select remove List element position: from head', asyn keyName = Common.generateWord(10); await browserPage.addListKey(keyName, keyTTL, [element]); // Add few elements to the List key - await browserPage.addElementToList(element2); - await browserPage.addElementToList(element3); + await browserPage.addElementToList([element2,element3]); // Remove element from the key await browserPage.removeListElementFromHead('1'); // Check the notification message diff --git a/tests/e2e/tests/web/smoke/browser/zset-key.e2e.ts b/tests/e2e/tests/web/smoke/browser/zset-key.e2e.ts index 3552eaeb1b..71d53a5464 100644 --- a/tests/e2e/tests/web/smoke/browser/zset-key.e2e.ts +++ b/tests/e2e/tests/web/smoke/browser/zset-key.e2e.ts @@ -37,8 +37,8 @@ test('Verify that user can remove member from ZSet', async t => { await t.expect(browserPage.zsetScoresList.withExactText(score).exists).ok('The Zset score not found', { timeout: 10000 }); // Remove member from the key - await t.click(browserPage.removeZserMemberButton); - await t.click(browserPage.confirmRemovZSetMemberButton); + await t.click(browserPage.removeZsetMemberButton); + await t.click(browserPage.confirmRemoveZSetMemberButton); // Check the notification message const notification = browserPage.Toast.toastHeader.textContent; await t.expect(notification).contains('Member has been removed', 'The notification not found'); From c4b297f461057145894848936f5c4fcefada617e Mon Sep 17 00:00:00 2001 From: mariasergeenko Date: Tue, 8 Oct 2024 11:52:59 +0200 Subject: [PATCH 123/256] fix db --- .../web/regression/browser/list-key.e2e.ts | 24 ++++++++++--------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/tests/e2e/tests/web/regression/browser/list-key.e2e.ts b/tests/e2e/tests/web/regression/browser/list-key.e2e.ts index ec2fa863e5..a2a95f9603 100644 --- a/tests/e2e/tests/web/regression/browser/list-key.e2e.ts +++ b/tests/e2e/tests/web/regression/browser/list-key.e2e.ts @@ -1,7 +1,10 @@ import { AddElementInList, rte } from '../../../../helpers/constants'; import { DatabaseHelper } from '../../../../helpers/database'; import { BrowserPage } from '../../../../pageObjects'; -import { commonUrl, ossStandaloneConfig, redisEnterpriseClusterConfig } from '../../../../helpers/conf'; +import { + commonUrl, + ossStandaloneV8Config, +} from '../../../../helpers/conf'; import { DatabaseAPIRequests } from '../../../../helpers/api/api-database'; import { populateListWithElements } from '../../../../helpers/keys'; import { Common } from '../../../../helpers/common'; @@ -12,24 +15,24 @@ const databaseHelper = new DatabaseHelper(); const databaseAPIRequests = new DatabaseAPIRequests(); const apiKeyRequests = new APIKeyRequests(); -const dbParameters = { host: ossStandaloneConfig.host, port: ossStandaloneConfig.port }; +const dbParameters = { host: ossStandaloneV8Config.host, port: ossStandaloneV8Config.port }; const keyName = `TestListKey-${ Common.generateWord(10) }`; const elementForSearch = `SearchField-${ Common.generateWord(5) }`; const keyToAddParameters = { elementsCount: 500000, keyName, elementStartWith: 'listElement' }; fixture `List Key verification` - .meta({ type: 'regression' }) + .meta({ type: 'regression', rte: rte.standalone }) .page(commonUrl) .beforeEach(async() => { - await databaseHelper.acceptLicenseTermsAndAddREClusterDatabase(redisEnterpriseClusterConfig); + await databaseHelper.acceptLicenseTermsAndAddDatabaseApi(ossStandaloneV8Config); await browserPage.addListKey(keyName, '2147476121', ['testElement']); }) .afterEach(async() => { - await apiKeyRequests.deleteKeyByNameApi(keyName, redisEnterpriseClusterConfig.databaseName); - await databaseHelper.deleteDatabase(redisEnterpriseClusterConfig.databaseName); + await apiKeyRequests.deleteKeyByNameApi(keyName, ossStandaloneV8Config.databaseName); + await databaseAPIRequests.deleteStandaloneDatabaseApi(ossStandaloneV8Config); }); test - .meta({ rte: rte.standalone })('Verify that user can search per exact element index in List key in DB with 1 million of fields', async t => { + ('Verify that user can search per exact element index in List key in DB with 1 million of fields', async t => { // Add 1000000 elements to the list key await populateListWithElements(dbParameters.host, dbParameters.port, keyToAddParameters); await populateListWithElements(dbParameters.host, dbParameters.port, keyToAddParameters); @@ -46,12 +49,12 @@ test // TODO unskip when the bug is fixed https://redislabs.atlassian.net/browse/RI-6188 test.skip .before(async() => { - await databaseHelper.acceptLicenseTermsAndAddREClusterDatabase(redisEnterpriseClusterConfig); + await databaseHelper.acceptLicenseTermsAndAddDatabaseApi(ossStandaloneV8Config); }) .after(async() => { await browserPage.Cli.sendCommandInCli('flushdb'); - await databaseHelper.deleteDatabase(redisEnterpriseClusterConfig.databaseName); + await databaseAPIRequests.deleteStandaloneDatabaseApi(ossStandaloneV8Config); }) ('Verify that user can add a multiple fields', async t => { @@ -80,8 +83,7 @@ test.skip await t.expect(browserPage.listElementsList.nth(count - 1).textContent).eql(elementsValue[0], 'the last element is not corrected for add in tail'); }); -test - .meta({ rte: rte.reCluster })('Verify that user can edit a multiple fields', async t => { +test('Verify that user can edit a multiple fields', async t => { const elementsValue = [ 'element1', 'element2', From 353cb85a8f305f314163b5d9b2901e161a748327 Mon Sep 17 00:00:00 2001 From: kchepikava Date: Tue, 8 Oct 2024 17:04:13 +0200 Subject: [PATCH 124/256] RI-6161 replace tooltip with popover in pubsub textarea append icon --- redisinsight/ui/src/constants/links.ts | 2 + .../subscription-panel/SubscriptionPanel.tsx | 4 +- .../append-info/AppendInfo.spec.tsx | 21 -------- .../components/append-info/AppendInfo.tsx | 23 -------- .../components/append-info/index.ts | 3 -- .../ClickableAppendInfo.spec.tsx | 19 +++++++ .../ClickableAppendInfo.tsx | 53 +++++++++++++++++++ .../components/clickable-append-info/index.ts | 3 ++ .../clickable-append-info/styles.module.scss | 15 ++++++ 9 files changed, 94 insertions(+), 49 deletions(-) delete mode 100644 redisinsight/ui/src/pages/pub-sub/components/subscription-panel/components/append-info/AppendInfo.spec.tsx delete mode 100644 redisinsight/ui/src/pages/pub-sub/components/subscription-panel/components/append-info/AppendInfo.tsx delete mode 100644 redisinsight/ui/src/pages/pub-sub/components/subscription-panel/components/append-info/index.ts create mode 100644 redisinsight/ui/src/pages/pub-sub/components/subscription-panel/components/clickable-append-info/ClickableAppendInfo.spec.tsx create mode 100644 redisinsight/ui/src/pages/pub-sub/components/subscription-panel/components/clickable-append-info/ClickableAppendInfo.tsx create mode 100644 redisinsight/ui/src/pages/pub-sub/components/subscription-panel/components/clickable-append-info/index.ts create mode 100644 redisinsight/ui/src/pages/pub-sub/components/subscription-panel/components/clickable-append-info/styles.module.scss diff --git a/redisinsight/ui/src/constants/links.ts b/redisinsight/ui/src/constants/links.ts index bf032c1c51..ad53464d86 100644 --- a/redisinsight/ui/src/constants/links.ts +++ b/redisinsight/ui/src/constants/links.ts @@ -15,6 +15,7 @@ export const EXTERNAL_LINKS = { rdiQuickStart: 'https://redis.io/docs/latest/integrate/redis-data-integration/ingest/quick-start-guide/', rdiPipeline: 'https://redis.io/docs/latest/integrate/redis-data-integration/ingest/data-pipelines/data-pipelines/', rdiPipelineTransforms: 'https://redis.io/docs/latest/integrate/redis-data-integration/ingest/data-pipelines/transform-examples/', + pubSub: 'https://redis.io/docs/latest/commands/psubscribe/', } export const UTM_CAMPAINGS: Record = { @@ -23,6 +24,7 @@ export const UTM_CAMPAINGS: Record = { [OAuthSocialSource.Workbench]: 'redisinsight_workbench', [CloudSsoUtmCampaign.BrowserFilter]: 'browser_filter', [OAuthSocialSource.EmptyDatabasesList]: 'empty_db_list', + PubSub: 'pub_sub', Main: 'main', } diff --git a/redisinsight/ui/src/pages/pub-sub/components/subscription-panel/SubscriptionPanel.tsx b/redisinsight/ui/src/pages/pub-sub/components/subscription-panel/SubscriptionPanel.tsx index a252bd7a12..7ce8aa500f 100644 --- a/redisinsight/ui/src/pages/pub-sub/components/subscription-panel/SubscriptionPanel.tsx +++ b/redisinsight/ui/src/pages/pub-sub/components/subscription-panel/SubscriptionPanel.tsx @@ -16,7 +16,7 @@ import NotSubscribedIconLight from 'uiSrc/assets/img/pub-sub/not-subscribed-lt.s import { DEFAULT_SEARCH_MATCH } from 'uiSrc/constants/api' import PatternsInfo from './components/patternsInfo' -import AppendInfo from './components/append-info' +import ClickableAppendInfo from './components/clickable-append-info' import styles from './styles.module.scss' const SubscriptionPanel = () => { @@ -95,7 +95,7 @@ const SubscriptionPanel = () => { placeholder="Enter Pattern" aria-label="channel names for filtering" data-testid="channels-input" - append={} + append={} /> diff --git a/redisinsight/ui/src/pages/pub-sub/components/subscription-panel/components/append-info/AppendInfo.spec.tsx b/redisinsight/ui/src/pages/pub-sub/components/subscription-panel/components/append-info/AppendInfo.spec.tsx deleted file mode 100644 index c248a42239..0000000000 --- a/redisinsight/ui/src/pages/pub-sub/components/subscription-panel/components/append-info/AppendInfo.spec.tsx +++ /dev/null @@ -1,21 +0,0 @@ -import React from 'react' -import { fireEvent, render, screen, waitFor } from 'uiSrc/utils/test-utils' -import AppendInfo from './AppendInfo' - -describe('AppendInfo', () => { - it('should render', () => { - expect( - render( - - ) - ).toBeTruthy() - }) - - it('should show info text on hover', async () => { - const content = 'Some content' - render() - fireEvent.mouseOver(screen.getByTestId('append-info-icon')) - await waitFor(() => screen.getByText(content)) - expect(screen.getByText(content)).toBeInTheDocument() - }) -}) diff --git a/redisinsight/ui/src/pages/pub-sub/components/subscription-panel/components/append-info/AppendInfo.tsx b/redisinsight/ui/src/pages/pub-sub/components/subscription-panel/components/append-info/AppendInfo.tsx deleted file mode 100644 index 0717a8080d..0000000000 --- a/redisinsight/ui/src/pages/pub-sub/components/subscription-panel/components/append-info/AppendInfo.tsx +++ /dev/null @@ -1,23 +0,0 @@ -import React from 'react' -import { EuiIcon, EuiToolTip, EuiToolTipProps, ToolTipPositions } from '@elastic/eui' - -export interface AppendInfoProps extends Omit { - position?: ToolTipPositions -} -const AppendInfo = ({ title, content, ...rest }: AppendInfoProps) => ( - - - -) - -export default AppendInfo diff --git a/redisinsight/ui/src/pages/pub-sub/components/subscription-panel/components/append-info/index.ts b/redisinsight/ui/src/pages/pub-sub/components/subscription-panel/components/append-info/index.ts deleted file mode 100644 index 4079128fcd..0000000000 --- a/redisinsight/ui/src/pages/pub-sub/components/subscription-panel/components/append-info/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -import AppendInfo from './AppendInfo' - -export default AppendInfo diff --git a/redisinsight/ui/src/pages/pub-sub/components/subscription-panel/components/clickable-append-info/ClickableAppendInfo.spec.tsx b/redisinsight/ui/src/pages/pub-sub/components/subscription-panel/components/clickable-append-info/ClickableAppendInfo.spec.tsx new file mode 100644 index 0000000000..e176e02254 --- /dev/null +++ b/redisinsight/ui/src/pages/pub-sub/components/subscription-panel/components/clickable-append-info/ClickableAppendInfo.spec.tsx @@ -0,0 +1,19 @@ +import React from 'react' +import { fireEvent, render, screen } from 'uiSrc/utils/test-utils' +import ClickableAppendInfo from './ClickableAppendInfo' + +describe('ClickableAppendInfo', () => { + it('should render', () => { + expect( + render( + + ) + ).toBeTruthy() + }) + + it('should open popover on click', async () => { + render() + fireEvent.click(screen.getByTestId('append-info-icon')) + expect(screen.getByTestId('pub-sub-examples')).toBeInTheDocument() + }) +}) diff --git a/redisinsight/ui/src/pages/pub-sub/components/subscription-panel/components/clickable-append-info/ClickableAppendInfo.tsx b/redisinsight/ui/src/pages/pub-sub/components/subscription-panel/components/clickable-append-info/ClickableAppendInfo.tsx new file mode 100644 index 0000000000..954948e489 --- /dev/null +++ b/redisinsight/ui/src/pages/pub-sub/components/subscription-panel/components/clickable-append-info/ClickableAppendInfo.tsx @@ -0,0 +1,53 @@ +import React, { useState } from 'react' +import { EuiIcon, EuiLink, EuiPopover, EuiText } from '@elastic/eui' +import { getUtmExternalLink } from 'uiSrc/utils/links' +import { EXTERNAL_LINKS, UTM_CAMPAINGS, UTM_MEDIUMS } from 'uiSrc/constants/links' +import styles from './styles.module.scss' + +const ClickableAppendInfo = () => { + const [open, setOpen] = useState(false) + + const onClick = () => { + const newVal = !open + setOpen(newVal) + } + + return ( + + )} + isOpen={open} + panelClassName={styles.popover} + anchorClassName={styles.infoIcon} + panelPaddingSize="s" + data-testid="pub-sub-examples" + > + + Supported glob-style patterns are described  + here. + + + + ) +} + +export default ClickableAppendInfo diff --git a/redisinsight/ui/src/pages/pub-sub/components/subscription-panel/components/clickable-append-info/index.ts b/redisinsight/ui/src/pages/pub-sub/components/subscription-panel/components/clickable-append-info/index.ts new file mode 100644 index 0000000000..89e433f906 --- /dev/null +++ b/redisinsight/ui/src/pages/pub-sub/components/subscription-panel/components/clickable-append-info/index.ts @@ -0,0 +1,3 @@ +import ClickableAppendInfo from './ClickableAppendInfo' + +export default ClickableAppendInfo diff --git a/redisinsight/ui/src/pages/pub-sub/components/subscription-panel/components/clickable-append-info/styles.module.scss b/redisinsight/ui/src/pages/pub-sub/components/subscription-panel/components/clickable-append-info/styles.module.scss new file mode 100644 index 0000000000..f23dd1d537 --- /dev/null +++ b/redisinsight/ui/src/pages/pub-sub/components/subscription-panel/components/clickable-append-info/styles.module.scss @@ -0,0 +1,15 @@ +.infoIcon { + display: flex !important; + align-items: center; + justify-content: center; + width: 34px; + color: var(--iconsDefaultColor) !important; + background-color: var(--browserTableRowEven) !important; +} + +.popover { + max-width: 200px !important; + background-color: var(--euiTooltipBackgroundColor) !important; + color: var(--euiTooltipTitleTextColor) !important; + border-radius: 4px; +} From d54a28047e1cd88e61ec033d459b99f20069b6be Mon Sep 17 00:00:00 2001 From: mariasergeenko Date: Tue, 8 Oct 2024 17:26:40 +0200 Subject: [PATCH 125/256] remove skip --- tests/e2e/tests/web/regression/browser/list-key.e2e.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/e2e/tests/web/regression/browser/list-key.e2e.ts b/tests/e2e/tests/web/regression/browser/list-key.e2e.ts index a2a95f9603..91181c055b 100644 --- a/tests/e2e/tests/web/regression/browser/list-key.e2e.ts +++ b/tests/e2e/tests/web/regression/browser/list-key.e2e.ts @@ -46,8 +46,7 @@ test await t.expect(result).eql(elementForSearch, 'List element not found'); }); -// TODO unskip when the bug is fixed https://redislabs.atlassian.net/browse/RI-6188 -test.skip +test .before(async() => { await databaseHelper.acceptLicenseTermsAndAddDatabaseApi(ossStandaloneV8Config); From 59b0968a6f1e67a305f6148b2f96dd71f556b1ea Mon Sep 17 00:00:00 2001 From: kchepikava Date: Tue, 8 Oct 2024 20:36:16 +0200 Subject: [PATCH 126/256] RI-6141 update rdi last connection on each connect --- .../rdi/providers/rdi.client.provider.spec.ts | 15 +++++++++++++++ .../rdi/providers/rdi.client.provider.ts | 17 +++++++++++++++-- .../rdi/repository/local.rdi.repository.ts | 3 +-- 3 files changed, 31 insertions(+), 4 deletions(-) diff --git a/redisinsight/api/src/modules/rdi/providers/rdi.client.provider.spec.ts b/redisinsight/api/src/modules/rdi/providers/rdi.client.provider.spec.ts index 3b269258a9..9a4368ad4b 100644 --- a/redisinsight/api/src/modules/rdi/providers/rdi.client.provider.spec.ts +++ b/redisinsight/api/src/modules/rdi/providers/rdi.client.provider.spec.ts @@ -46,11 +46,13 @@ describe('RdiClientProvider', () => { const metadata: RdiClientMetadata = { id: '123', sessionMetadata: undefined }; const client: RdiClient = generateMockRdiClient(metadata); rdiClientStorage.getByMetadata.mockResolvedValue(client); + repository.update.mockResolvedValue(mockRdi); const result = await provider.getOrCreate(metadata); expect(rdiClientStorage.getByMetadata).toHaveBeenCalledWith(metadata); expect(client.ensureAuth).toHaveBeenCalled(); + expect(repository.update).toHaveBeenCalled(); expect(result).toEqual(client); }); @@ -84,11 +86,13 @@ describe('RdiClientProvider', () => { const client: RdiClient = generateMockRdiClient(metadata); repository.get.mockResolvedValue(mockRdi); rdiClientFactory.createClient.mockResolvedValue(client); + repository.update.mockResolvedValue(mockRdi); const result = await provider.create(metadata); expect(repository.get).toHaveBeenCalledWith(metadata.id); expect(rdiClientFactory.createClient).toHaveBeenCalledWith(metadata, mockRdi); + expect(repository.update).toHaveBeenCalled(); expect(result).toEqual(client); }); }); @@ -128,4 +132,15 @@ describe('RdiClientProvider', () => { expect(result).toEqual(2); }); }); + + describe('updateLastConnection', () => { + it('should update rdi lastConnection', async () => { + const metadata: RdiClientMetadata = { id: '123', sessionMetadata: undefined }; + repository.update.mockResolvedValue(mockRdi); + + await provider['updateLastConnection'](metadata); + + expect(repository.update).toHaveBeenCalled(); + }); + }); }); diff --git a/redisinsight/api/src/modules/rdi/providers/rdi.client.provider.ts b/redisinsight/api/src/modules/rdi/providers/rdi.client.provider.ts index fb0f6fa204..9b5a9ca863 100644 --- a/redisinsight/api/src/modules/rdi/providers/rdi.client.provider.ts +++ b/redisinsight/api/src/modules/rdi/providers/rdi.client.provider.ts @@ -1,6 +1,6 @@ import { RdiClient } from 'src/modules/rdi/client/rdi.client'; import { Injectable, Logger, NotFoundException } from '@nestjs/common'; -import { RdiClientMetadata } from 'src/modules/rdi/models'; +import { Rdi, RdiClientMetadata } from 'src/modules/rdi/models'; import { RdiClientStorage } from 'src/modules/rdi/providers/rdi.client.storage'; import { RdiClientFactory } from 'src/modules/rdi/providers/rdi.client.factory'; import { RdiRepository } from 'src/modules/rdi/repository/rdi.repository'; @@ -20,6 +20,7 @@ export class RdiClientProvider { let client = await this.rdiClientStorage.getByMetadata(rdiClientMetadata); if (client) { await client.ensureAuth(); + this.updateLastConnection(rdiClientMetadata); return client; } @@ -35,7 +36,11 @@ export class RdiClientProvider { this.logger.error(`RDI with ${clientMetadata.id} was not Found`); throw new NotFoundException(ERROR_MESSAGES.INVALID_RDI_INSTANCE_ID); } - return this.rdiClientFactory.createClient(clientMetadata, rdi); + const rdiClient = this.rdiClientFactory.createClient(clientMetadata, rdi); + if (rdiClient) { + this.updateLastConnection(clientMetadata); + } + return rdiClient; } async delete(rdiClientMetadata: RdiClientMetadata): Promise { @@ -49,4 +54,12 @@ export class RdiClientProvider { async deleteManyByRdiId(id: string): Promise { return this.rdiClientStorage.deleteManyByRdiId(id); } + + private async updateLastConnection(rdiClientMetadata: RdiClientMetadata): Promise { + try { + await this.repository.update(rdiClientMetadata.id, { lastConnection: new Date() }); + } catch (e) { + // ignore the error + } + } } diff --git a/redisinsight/api/src/modules/rdi/repository/local.rdi.repository.ts b/redisinsight/api/src/modules/rdi/repository/local.rdi.repository.ts index f041581e7b..90bff4550d 100644 --- a/redisinsight/api/src/modules/rdi/repository/local.rdi.repository.ts +++ b/redisinsight/api/src/modules/rdi/repository/local.rdi.repository.ts @@ -75,9 +75,8 @@ export class LocalRdiRepository extends RdiRepository { const newEntity = classToClass(RdiEntity, rdi); const encrypted = await this.modelEncryptor.encryptEntity(this.repository.merge(oldEntity, newEntity)); - await this.repository.save(encrypted); - return this.get(id); + return classToClass(Rdi, await this.modelEncryptor.decryptEntity(await this.repository.save(encrypted))); } /** From 1178771ce592c1f424efd1dcb1eadfff91f3dea8 Mon Sep 17 00:00:00 2001 From: Kristiyan Ivanov Date: Wed, 9 Oct 2024 09:54:43 +0300 Subject: [PATCH 127/256] RI-6186 The first item can't be removed --- .../browser/components/add-key/AddKeyList/AddKeyList.tsx | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/redisinsight/ui/src/pages/browser/components/add-key/AddKeyList/AddKeyList.tsx b/redisinsight/ui/src/pages/browser/components/add-key/AddKeyList/AddKeyList.tsx index a365d7a162..9fbc3c61ad 100644 --- a/redisinsight/ui/src/pages/browser/components/add-key/AddKeyList/AddKeyList.tsx +++ b/redisinsight/ui/src/pages/browser/components/add-key/AddKeyList/AddKeyList.tsx @@ -51,10 +51,14 @@ const AddKeyList = (props: Props) => { setElements([...elements, '']) } const onClickRemove = (_item: string, index?: number) => { - setElements(elements.filter((_el, i) => i !== index)) + if (elements.length === 1) { + setElements(['']) + } else { + setElements(elements.filter((_el, i) => i !== index)) + } } - const isClearDisabled = (_element:string, index?: number) => index === 0 + const isClearDisabled = (element:string, index?: number) => index === 0 && !element.length const handleElementChange = (value: string, index: number) => { const newElements = [...elements] From bb559285ddbf591a42006ba8a39662a6b951c7d6 Mon Sep 17 00:00:00 2001 From: Kristiyan Ivanov Date: Wed, 9 Oct 2024 10:41:38 +0300 Subject: [PATCH 128/256] RI-6187 Save and Cancel button are scrollable --- .../list-details/add-list-elements/AddListElements.tsx | 2 +- .../key-details/components/list-details/styles.module.scss | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/redisinsight/ui/src/pages/browser/modules/key-details/components/list-details/add-list-elements/AddListElements.tsx b/redisinsight/ui/src/pages/browser/modules/key-details/components/list-details/add-list-elements/AddListElements.tsx index 9e5ca1d365..8de109e7dc 100644 --- a/redisinsight/ui/src/pages/browser/modules/key-details/components/list-details/add-list-elements/AddListElements.tsx +++ b/redisinsight/ui/src/pages/browser/modules/key-details/components/list-details/add-list-elements/AddListElements.tsx @@ -112,7 +112,7 @@ const AddListElements = (props: Props) => { hasShadow={false} borderRadius="none" data-test-subj="add-list-field-panel" - className={cx(styles.content, 'eui-yScroll', 'flexItemNoFullWidth', 'inlineFieldsNoSpace')} + className={cx(styles.container, 'eui-yScroll', 'flexItemNoFullWidth', 'inlineFieldsNoSpace')} > Date: Wed, 9 Oct 2024 10:47:55 +0300 Subject: [PATCH 129/256] RI-6184 BROWSER_KEY_ADDED and TREE_VIEW_KEY_ADDED contain incorrect length --- redisinsight/ui/src/telemetry/telemetryUtils.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/redisinsight/ui/src/telemetry/telemetryUtils.ts b/redisinsight/ui/src/telemetry/telemetryUtils.ts index c62e103163..2dee25b10e 100644 --- a/redisinsight/ui/src/telemetry/telemetryUtils.ts +++ b/redisinsight/ui/src/telemetry/telemetryUtils.ts @@ -119,7 +119,7 @@ const getAdditionalAddedEventData = (endpoint: ApiEndpoints, data: any) => { case ApiEndpoints.LIST: return { keyType: KeyTypes.List, - length: 1, + length: data.elements?.length, TTL: data.expire || -1 } case ApiEndpoints.REJSON: From 8a2933682623ca4097f9fdd80485e005141d11d8 Mon Sep 17 00:00:00 2001 From: Kristiyan Ivanov Date: Wed, 9 Oct 2024 10:49:20 +0300 Subject: [PATCH 130/256] RI-6185 BROWSER_KEY_VALUE_ADDED and TREE_VIEW_KEY_VALUE_ADDED contain incorrect number of added elements --- .../list-details/add-list-elements/AddListElements.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/redisinsight/ui/src/pages/browser/modules/key-details/components/list-details/add-list-elements/AddListElements.tsx b/redisinsight/ui/src/pages/browser/modules/key-details/components/list-details/add-list-elements/AddListElements.tsx index 8de109e7dc..8e352871ba 100644 --- a/redisinsight/ui/src/pages/browser/modules/key-details/components/list-details/add-list-elements/AddListElements.tsx +++ b/redisinsight/ui/src/pages/browser/modules/key-details/components/list-details/add-list-elements/AddListElements.tsx @@ -76,7 +76,7 @@ const AddListElements = (props: Props) => { eventData: { databaseId: instanceId, keyType: KeyTypes.List, - numberOfAdded: 1, + numberOfAdded: elements.length, } }) } From e70808cbfb73aee4cc865e201c675cda40795286 Mon Sep 17 00:00:00 2001 From: Roman Sergeenko Date: Wed, 9 Oct 2024 13:30:31 +0200 Subject: [PATCH 131/256] #RI-6151 - initial implementation of search suggestions in the workbench --- .../monaco-laguages/MonacoLanguages.tsx | 20 +- redisinsight/ui/src/constants/monaco/theme.ts | 4 +- .../ui/src/pages/search/utils/monaco.ts | 1 - .../components/query/Query/Query.tsx | 320 ++++- .../components/query/Query/constants.ts | 12 +- .../components/query/QueryWrapper.tsx | 22 +- .../ui/src/pages/workbench/constants.ts | 51 + .../workbench/data/supported_commands.json | 1156 +++++++++++++++++ redisinsight/ui/src/pages/workbench/types.ts | 45 + .../ui/src/pages/workbench/utils/monaco.ts | 64 + .../ui/src/pages/workbench/utils/profile.ts | 40 + .../ui/src/pages/workbench/utils/query.ts | 479 +++++++ .../src/pages/workbench/utils/suggestions.ts | 198 +++ .../ui/src/utils/monaco/monacoInterfaces.ts | 10 +- .../monacoRedisMonarchTokensProvider.ts | 56 +- .../ui/src/utils/monaco/monacoUtils.ts | 102 +- .../monaco/monarchTokens/redisearchTokens.ts | 2 +- .../monarchTokens/redisearchTokensSubRedis.ts | 121 ++ .../ui/src/utils/monaco/redisearch/utils.ts | 16 +- .../src/utils/monaco/redisearch/utils_old.ts | 143 ++ .../monaco/subTokens/redisearchSubTokens.ts | 0 21 files changed, 2772 insertions(+), 90 deletions(-) create mode 100644 redisinsight/ui/src/pages/workbench/data/supported_commands.json create mode 100644 redisinsight/ui/src/pages/workbench/types.ts create mode 100644 redisinsight/ui/src/pages/workbench/utils/monaco.ts create mode 100644 redisinsight/ui/src/pages/workbench/utils/profile.ts create mode 100644 redisinsight/ui/src/pages/workbench/utils/query.ts create mode 100644 redisinsight/ui/src/pages/workbench/utils/suggestions.ts create mode 100644 redisinsight/ui/src/utils/monaco/monarchTokens/redisearchTokensSubRedis.ts create mode 100644 redisinsight/ui/src/utils/monaco/redisearch/utils_old.ts create mode 100644 redisinsight/ui/src/utils/monaco/subTokens/redisearchSubTokens.ts diff --git a/redisinsight/ui/src/components/monaco-laguages/MonacoLanguages.tsx b/redisinsight/ui/src/components/monaco-laguages/MonacoLanguages.tsx index e87c71dba4..db84c5556f 100644 --- a/redisinsight/ui/src/components/monaco-laguages/MonacoLanguages.tsx +++ b/redisinsight/ui/src/components/monaco-laguages/MonacoLanguages.tsx @@ -7,10 +7,14 @@ import { MonacoLanguage, redisLanguageConfig, Theme } from 'uiSrc/constants' import { getRedisMonarchTokensProvider } from 'uiSrc/utils' import { darkTheme, lightTheme, MonacoThemes } from 'uiSrc/constants/monaco' import { ThemeContext } from 'uiSrc/contexts/themeContext' +import { TokenType } from 'uiSrc/pages/workbench/types' + +import { getRediSearchSubRedisMonarchTokensProvider } from 'uiSrc/utils/monaco/monarchTokens/redisearchTokensSubRedis' +import SEARCH_COMMANDS_SPEC from 'uiSrc/pages/workbench/data/supported_commands.json' const MonacoLanguages = () => { const { theme } = useContext(ThemeContext) - const { commandsArray: REDIS_COMMANDS_ARRAY } = useSelector(appRedisCommandsSelector) + const { commandsArray: REDIS_COMMANDS_ARRAY, spec: COMMANDS_SPEC } = useSelector(appRedisCommandsSelector) useEffect(() => { if (monaco?.editor) { @@ -34,12 +38,24 @@ const MonacoLanguages = () => { const isRedisLangRegistered = findIndex(languages, { id: MonacoLanguage.Redis }) > -1 if (!isRedisLangRegistered) { monaco.languages.register({ id: MonacoLanguage.Redis }) + monaco.languages.register({ id: MonacoLanguage.RediSearch }) } monaco.languages.setLanguageConfiguration(MonacoLanguage.Redis, redisLanguageConfig) + const REDIS_COMMANDS = Object.keys(COMMANDS_SPEC).map((name) => ({ + ...(name in SEARCH_COMMANDS_SPEC ? SEARCH_COMMANDS_SPEC[name] : (COMMANDS_SPEC[name] || {})), + name, + token: name, + type: TokenType.Block + })) + + monaco.languages.setMonarchTokensProvider( + MonacoLanguage.RediSearch, + getRediSearchSubRedisMonarchTokensProvider(REDIS_COMMANDS.filter(({ name }) => name.startsWith('FT.'))) + ) monaco.languages.setMonarchTokensProvider( MonacoLanguage.Redis, - getRedisMonarchTokensProvider(REDIS_COMMANDS_ARRAY) + getRedisMonarchTokensProvider(REDIS_COMMANDS) ) } diff --git a/redisinsight/ui/src/constants/monaco/theme.ts b/redisinsight/ui/src/constants/monaco/theme.ts index b3ac2f83cb..9cb3e860af 100644 --- a/redisinsight/ui/src/constants/monaco/theme.ts +++ b/redisinsight/ui/src/constants/monaco/theme.ts @@ -10,7 +10,6 @@ export const redisearchDarKThemeRules = [ { token: 'argument.block.withToken.1', foreground: '#72B59B' }, { token: 'argument.block.withToken.2', foreground: '#3A8365' }, { token: 'argument.block.withToken.3', foreground: '#244F3E' }, - { token: 'loadAll', foreground: '#8CD7B9' }, { token: 'index', foreground: '#DE47BB' }, { token: 'query', foreground: '#7B90E0' }, { token: 'field', foreground: '#B02C30' }, @@ -28,7 +27,6 @@ export const redisearchLightThemeRules = [ { token: 'argument.block.withToken.1', foreground: '#72B59B' }, { token: 'argument.block.withToken.2', foreground: '#3A8365' }, { token: 'argument.block.withToken.3', foreground: '#244F3E' }, - { token: 'loadAll', foreground: '#8CD7B9' }, { token: 'index', foreground: '#DE47BB' }, { token: 'query', foreground: '#7B90E0' }, { token: 'field', foreground: '#B02C30' }, @@ -40,7 +38,7 @@ export const darkThemeRules = [ { token: 'function', foreground: 'BFBC4E' }, ...redisearchDarKThemeRules.map((rule) => ({ ...rule, - token: `${rule.token}.redisearch` + token: `${rule.token}` })) ] diff --git a/redisinsight/ui/src/pages/search/utils/monaco.ts b/redisinsight/ui/src/pages/search/utils/monaco.ts index 2f8c713e78..4eda87a868 100644 --- a/redisinsight/ui/src/pages/search/utils/monaco.ts +++ b/redisinsight/ui/src/pages/search/utils/monaco.ts @@ -43,7 +43,6 @@ export const getRediSearchSignutureProvider = (options: Maybe<{ parent: Maybe }>) => { const { isOpen, currentArg, parent } = options || {} - if (!isOpen) return null const label = generateDetail(parent) diff --git a/redisinsight/ui/src/pages/workbench/components/query/Query/Query.tsx b/redisinsight/ui/src/pages/workbench/components/query/Query/Query.tsx index f415fa85ca..440dd63215 100644 --- a/redisinsight/ui/src/pages/workbench/components/query/Query/Query.tsx +++ b/redisinsight/ui/src/pages/workbench/components/query/Query/Query.tsx @@ -1,6 +1,6 @@ import React, { useContext, useEffect, useRef, useState } from 'react' import { useDispatch, useSelector } from 'react-redux' -import { compact, first } from 'lodash' +import { compact, first, isNumber } from 'lodash' import cx from 'classnames' import MonacoEditor, { monaco as monacoEditor } from 'react-monaco-editor' import { useParams } from 'react-router-dom' @@ -17,8 +17,7 @@ import { findArgIndexByCursor, findCompleteQuery, getMonacoAction, - getRedisCompletionProvider, - getRedisSignatureHelpProvider, + IMonacoQuery, isParamsLine, MonacoAction, Nullable, @@ -27,13 +26,39 @@ import { import { ThemeContext } from 'uiSrc/contexts/themeContext' import { appRedisCommandsSelector } from 'uiSrc/slices/app/redis-commands' import { IEditorMount, ISnippetController } from 'uiSrc/pages/workbench/interfaces' -import { CommandExecutionUI } from 'uiSrc/slices/interfaces' +import { CommandExecutionUI, RedisResponseBuffer } from 'uiSrc/slices/interfaces' import { RunQueryMode, ResultsMode } from 'uiSrc/slices/interfaces/workbench' import { sendEventTelemetry, TelemetryEvent } from 'uiSrc/telemetry' import { stopProcessing, workbenchResultsSelector } from 'uiSrc/slices/workbench/wb-results' import DedicatedEditor from 'uiSrc/components/monaco-editor/components/dedicated-editor' import { QueryActions, QueryTutorials } from 'uiSrc/components/query' +import { + addOwnTokenToArgs, + findCurrentArgument, + splitQueryByArgs +} from 'uiSrc/pages/workbench/utils/query' +import { getRange, getRediSearchSignutureProvider, } from 'uiSrc/pages/workbench/utils/monaco' +import { CursorContext, FoundCommandArgument, SearchCommand, TokenType } from 'uiSrc/pages/workbench/types' +import SEARCH_COMMANDS_SPEC from 'uiSrc/pages/workbench/data/supported_commands.json' +import { + asSuggestionsRef, + getCommandsSuggestions, + getFieldsSuggestions, + getFunctionsSuggestions, + getGeneralSuggestions, + getIndexesSuggestions, + getNoIndexesSuggestion, + isIndexComplete +} from 'uiSrc/pages/workbench/utils/suggestions' +import { + COMMANDS_TO_GET_INDEX_INFO, + DefinedArgumentName, + EmptySuggestionsIds, + FIELD_START_SYMBOL +} from 'uiSrc/pages/workbench/constants' +import { useDebouncedEffect } from 'uiSrc/services' +import { fetchRedisearchInfoAction } from 'uiSrc/slices/browser/redisearch' import { aroundQuotesRegExp, argInQuotesRegExp, @@ -42,11 +67,11 @@ import { options, TUTORIALS } from './constants' - import styles from './styles.module.scss' export interface Props { query: string + indexes: RedisResponseBuffer[] activeMode: RunQueryMode resultsMode?: ResultsMode setQueryEl: Function @@ -64,6 +89,7 @@ let decorationCollection: Nullable { const { query = '', + indexes = [], activeMode, resultsMode, setQuery = () => {}, @@ -75,6 +101,17 @@ const Query = (props: Props) => { } = props let contribution: Nullable = null const [isDedicatedEditorOpen, setIsDedicatedEditorOpen] = useState(false) + const [selectedIndex, setSelectedIndex] = useState('') + + const suggestionsRef = useRef([]) + const helpWidgetRef = useRef({ + isOpen: false, + parent: null, + currentArg: null + }) + const indexesRef = useRef([]) + const attributesRef = useRef([]) + const isWidgetOpen = useRef(false) const input = useRef(null) const isWidgetEscaped = useRef(false) @@ -88,6 +125,17 @@ const Query = (props: Props) => { const { theme } = useContext(ThemeContext) const monacoObjects = useRef>(null) + const getCommandByName = (name: string) => + (name in SEARCH_COMMANDS_SPEC ? SEARCH_COMMANDS_SPEC[name] : (REDIS_COMMANDS_SPEC[name] || {})) + + const REDIS_COMMANDS = REDIS_COMMANDS_ARRAY + .map((name) => ({ ...getCommandByName(name), name })) + .map((command) => ({ + ...addOwnTokenToArgs(command.name!, command), + token: command.name!, + type: TokenType.Block + })) + const { instanceId = '' } = useParams<{ instanceId: string }>() const dispatch = useDispatch() @@ -104,6 +152,10 @@ const Query = (props: Props) => { disposeSignatureHelpProvider() }, []) + useEffect(() => { + indexesRef.current = indexes + }, [indexes]) + useEffect(() => { // HACK: The Monaco editor memoize the state and ignores updates to it execHistory = execHistoryItems @@ -141,6 +193,17 @@ const Query = (props: Props) => { isDedicatedEditorOpenRef.current = isDedicatedEditorOpen }, [isDedicatedEditorOpen]) + useDebouncedEffect(() => { + attributesRef.current = [] + if (!isIndexComplete(selectedIndex)) return + + const index = selectedIndex.replace(/^(['"])(.*)\1$/, '$2') + dispatch(fetchRedisearchInfoAction(index, + (data: any) => { + attributesRef.current = data?.attributes || [] + })) + }, 200, [selectedIndex]) + const triggerUpdateCursorPosition = (editor: monacoEditor.editor.IStandaloneCodeEditor) => { const position = editor.getPosition() isDedicatedEditorOpenRef.current = false @@ -251,37 +314,31 @@ const Query = (props: Props) => { } } - const onKeyChangeCursorMonaco = (e: monacoEditor.editor.ICursorPositionChangedEvent) => { - if (!monacoObjects.current) return - const { editor } = monacoObjects?.current - const model = editor.getModel() - - isWidgetOpen.current && hideSyntaxWidget(editor) - - if (!model || isDedicatedEditorOpenRef.current) { - return - } - - const command = findCompleteQuery(model, e.position, REDIS_COMMANDS_SPEC, REDIS_COMMANDS_ARRAY) - if (!command) { + const handleDslSyntax = ( + e: monacoEditor.editor.ICursorPositionChangedEvent, + command: Nullable + ) => { + const { editor } = monacoObjects?.current || {} + if (!command || !editor) { isWidgetEscaped.current = false return } const queryArgIndex = command.info?.arguments?.findIndex((arg) => arg.dsl) || -1 const cursorPosition = command.commandCursorPosition || 0 - if (!command.args?.length || queryArgIndex < 0) { + const { allArgs } = command || {} + if (!allArgs.length || queryArgIndex < 0) { isWidgetEscaped.current = false return } - const argIndex = findArgIndexByCursor(command.args, command.fullQuery, cursorPosition) + const argIndex = findArgIndexByCursor(allArgs, command.fullQuery, cursorPosition) if (argIndex === null) { isWidgetEscaped.current = false return } - const queryArg = command.args[argIndex] + const queryArg = allArgs[argIndex] const argDSL = command.info?.arguments?.[argIndex]?.dsl || '' if (queryArgIndex === argIndex && argInQuotesRegExp.test(queryArg)) { @@ -297,6 +354,57 @@ const Query = (props: Props) => { } } + const isSuggestionsOpened = () => { + const { editor } = monacoObjects.current || {} + if (!editor) return false + const suggestController = editor.getContribution('editor.contrib.suggestController') + return suggestController?.model?.state === 1 + } + + const onKeyChangeCursorMonaco = (e: monacoEditor.editor.ICursorPositionChangedEvent) => { + if (!monacoObjects.current) return + const { editor } = monacoObjects?.current + const model = editor.getModel() + + isWidgetOpen.current && hideSyntaxWidget(editor) + + if (!model || isDedicatedEditorOpenRef.current) { + return + } + + const command = findCompleteQuery(model, e.position, REDIS_COMMANDS_SPEC, REDIS_COMMANDS_ARRAY) + + const { data, forceHide, forceShow } = getSuggestions(editor, command) + + suggestionsRef.current = data + + if (!forceShow) { + editor.trigger('', 'editor.action.triggerParameterHints', '') + return + } + + if (data.length) { + helpWidgetRef.current.isOpen = false + triggerSuggestions() + return + } + + editor.trigger('', 'editor.action.triggerParameterHints', '') + + if (forceHide) { + setTimeout(() => editor?.trigger('', 'hideSuggestWidget', null), 0) + } else { + helpWidgetRef.current.isOpen = !isSuggestionsOpened() && helpWidgetRef.current.isOpen + } + + handleDslSyntax(e, command) + } + + const triggerSuggestions = () => { + const { editor } = monacoObjects.current || {} + setTimeout(() => editor?.trigger('', 'editor.action.triggerSuggest', { auto: false })) + } + const onExitSnippetMode = () => { if (!monacoObjects.current) return const { editor } = monacoObjects?.current @@ -414,18 +522,170 @@ const Query = (props: Props) => { }, SYNTAX_CONTEXT_ID) decorationCollection = editor.createDecorationsCollection() + + const suggestionWidget = editor.getContribution('editor.contrib.suggestController') + suggestionWidget?.onWillInsertSuggestItem(({ item }: Record<'item', any>) => { + if (item.completion.id === EmptySuggestionsIds.NoIndexes) { + updateHelpWidget(true) + editor.trigger('', 'hideSuggestWidget', null) + editor.trigger('', 'editor.action.triggerParameterHints', '') + } + }) + suggestionsRef.current = getSuggestions(editor).data } const setupMonacoRedisLang = (monaco: typeof monacoEditor) => { - disposeCompletionItemProvider = monaco.languages.registerCompletionItemProvider( - MonacoLanguage.Redis, - getRedisCompletionProvider(REDIS_COMMANDS_SPEC) - ).dispose - - disposeSignatureHelpProvider = monaco.languages.registerSignatureHelpProvider( - MonacoLanguage.Redis, - getRedisSignatureHelpProvider(REDIS_COMMANDS_SPEC, REDIS_COMMANDS_ARRAY, isWidgetOpen) - ).dispose + disposeCompletionItemProvider = monaco.languages.registerCompletionItemProvider(MonacoLanguage.Redis, { + provideCompletionItems: (): monacoEditor.languages.CompletionList => ({ suggestions: suggestionsRef.current }) + }).dispose + + disposeSignatureHelpProvider = monaco.languages.registerSignatureHelpProvider(MonacoLanguage.Redis, { + provideSignatureHelp: (): any => getRediSearchSignutureProvider(helpWidgetRef?.current) + }).dispose + } + + const updateHelpWidget = (isOpen: boolean, parent?: SearchCommand, currentArg?: SearchCommand) => { + helpWidgetRef.current = { + isOpen, + parent: parent || helpWidgetRef.current.parent, + currentArg: currentArg || helpWidgetRef.current.currentArg } + } + + const getSuggestions = ( + editor: monacoEditor.editor.IStandaloneCodeEditor, + command?: Nullable + ): { + forceHide: boolean + forceShow: boolean + data: monacoEditor.languages.CompletionItem[] + } => { + const position = editor.getPosition() + const model = editor.getModel() + + if (!position || !model) return asSuggestionsRef([]) + const word = model.getWordUntilPosition(position) + const range = getRange(position, word) + + if (position.column === 1) { + if (command) return asSuggestionsRef([]) + + return asSuggestionsRef(getCommandsSuggestions(REDIS_COMMANDS, range), false) + } + + if (!command) { + return asSuggestionsRef([], false) + } + + const { allArgs, args, cursor } = command + const { prevCursorChar } = cursor + const [beforeOffsetArgs, [currentOffsetArg]] = args + + if (COMMANDS_TO_GET_INDEX_INFO.some((name) => name === command.name)) { + setSelectedIndex(allArgs[1] || '') + } + + const cursorContext: CursorContext = { ...cursor, currentOffsetArg, offset: command.commandCursorPosition || 0 } + const foundArg = findCurrentArgument(REDIS_COMMANDS, beforeOffsetArgs) + + if (!command.name.startsWith('FT.')) { + updateHelpWidget(true, foundArg?.parent, foundArg?.stopArg) + return asSuggestionsRef([]) + } + + if (prevCursorChar === FIELD_START_SYMBOL) return handleFieldSuggestions(foundArg, range) + + switch (foundArg?.stopArg?.name) { + case DefinedArgumentName.index: { + return handleIndexSuggestions(command.info as SearchCommand, foundArg, currentOffsetArg, range) + } + case DefinedArgumentName.query: { + return handleQuerySuggestions(command.info as SearchCommand, foundArg) + } + default: { + return handleCommonSuggestions(command.fullQuery, foundArg, allArgs, cursorContext, range) + } + } + } + + const handleFieldSuggestions = (foundArg: Nullable, range: monacoEditor.IRange) => { + const isInQuery = foundArg?.stopArg?.name === DefinedArgumentName.query + const fieldSuggestions = getFieldsSuggestions(attributesRef.current, range, true, isInQuery) + return asSuggestionsRef(fieldSuggestions, true) + } + + const handleIndexSuggestions = ( + command: SearchCommand, + foundArg: FoundCommandArgument, + currentOffsetArg: Nullable, + range: monacoEditor.IRange + ) => { + const isIndex = indexesRef.current.length > 0 + updateHelpWidget(isIndex, command, foundArg?.stopArg) + + if (!isIndex) { + updateHelpWidget(!!currentOffsetArg) + return asSuggestionsRef(!currentOffsetArg ? getNoIndexesSuggestion(range) : [], true) + } + + if (!isIndex || currentOffsetArg) return asSuggestionsRef([], !currentOffsetArg) + + const argumentIndex = command?.arguments + ?.findIndex(({ name }) => foundArg?.stopArg?.name === name) + const isNextArgQuery = isNumber(argumentIndex) + && command?.arguments?.[argumentIndex + 1]?.name === DefinedArgumentName.query + + return asSuggestionsRef(getIndexesSuggestions(indexesRef.current, range, isNextArgQuery)) + } + + const handleQuerySuggestions = (command: SearchCommand, foundArg: FoundCommandArgument) => { + updateHelpWidget(true, command, foundArg?.stopArg) + return asSuggestionsRef([], false) + } + + const handleExpressionSuggestions = ( + value: string, + foundArg: FoundCommandArgument, + cursorContext: CursorContext, + range: monacoEditor.IRange + ) => { + updateHelpWidget(true, foundArg?.parent, foundArg?.stopArg) + + const { isCursorInQuotes, offset, argLeftOffset } = cursorContext + if (!isCursorInQuotes) return asSuggestionsRef([]) + + const stringBeforeCursor = value.substring(argLeftOffset, offset) || '' + const expression = stringBeforeCursor.replace(/^["']|["']$/g, '') + const { args } = splitQueryByArgs(expression, offset - argLeftOffset) + const [, [currentArg]] = args + + const functions = foundArg?.stopArg?.arguments ?? [] + const suggestions = getFunctionsSuggestions(functions, range) + const isStartsWithFunction = functions.some(({ token }) => token?.startsWith(currentArg)) + + return asSuggestionsRef(suggestions, true, isStartsWithFunction) + } + + const handleCommonSuggestions = ( + value: string, + foundArg: Nullable, + allArgs: string[], + cursorContext: CursorContext, + range: monacoEditor.IRange + ) => { + if (foundArg?.stopArg?.expression) return handleExpressionSuggestions(value, foundArg, cursorContext, range) + + const { prevCursorChar, nextCursorChar, isCursorInQuotes } = cursorContext + const shouldHideSuggestions = isCursorInQuotes || nextCursorChar || (prevCursorChar) + if (shouldHideSuggestions) return asSuggestionsRef([]) + + const { + suggestions, + forceHide, + helpWidgetData + } = getGeneralSuggestions(foundArg, allArgs, range, attributesRef.current) + + if (helpWidgetData) updateHelpWidget(helpWidgetData.isOpen, helpWidgetData.parent, helpWidgetData.currentArg) + return asSuggestionsRef(suggestions, forceHide) } const isLoading = loading || processing diff --git a/redisinsight/ui/src/pages/workbench/components/query/Query/constants.ts b/redisinsight/ui/src/pages/workbench/components/query/Query/constants.ts index 3b5e92e88b..eb3b518284 100644 --- a/redisinsight/ui/src/pages/workbench/components/query/Query/constants.ts +++ b/redisinsight/ui/src/pages/workbench/components/query/Query/constants.ts @@ -1,3 +1,4 @@ +import { merge } from 'lodash' import { defaultMonacoOptions, TutorialsIds } from 'uiSrc/constants' export const argInQuotesRegExp = /^['"](.|[\r\n])*['"]$/ @@ -6,7 +7,16 @@ export const aroundQuotesRegExp = /(^["']|["']$)/g export const SYNTAX_CONTEXT_ID = 'syntaxWidgetContext' export const SYNTAX_WIDGET_ID = 'syntax.content.widget' -export const options = { ...defaultMonacoOptions } +export const options = merge(defaultMonacoOptions, + { + suggest: { + showWords: false, + showIcons: true, + insertMode: 'replace', + filterGraceful: false, + matchOnWordStartOnly: true + } + }) export const TUTORIALS = [ { diff --git a/redisinsight/ui/src/pages/workbench/components/query/QueryWrapper.tsx b/redisinsight/ui/src/pages/workbench/components/query/QueryWrapper.tsx index 56a7d9e974..d6e1d2f351 100644 --- a/redisinsight/ui/src/pages/workbench/components/query/QueryWrapper.tsx +++ b/redisinsight/ui/src/pages/workbench/components/query/QueryWrapper.tsx @@ -1,9 +1,11 @@ -import React from 'react' -import { useSelector } from 'react-redux' +import React, { useEffect } from 'react' +import { useDispatch, useSelector } from 'react-redux' import { EuiLoadingContent } from '@elastic/eui' import { appRedisCommandsSelector } from 'uiSrc/slices/app/redis-commands' import { RunQueryMode, ResultsMode } from 'uiSrc/slices/interfaces/workbench' +import { fetchRedisearchListAction, redisearchListSelector } from 'uiSrc/slices/browser/redisearch' +import { connectedInstanceSelector } from 'uiSrc/slices/instances/instances' import Query from './Query' import styles from './Query/styles.module.scss' @@ -31,9 +33,18 @@ const QueryWrapper = (props: Props) => { onQueryChangeMode, onChangeGroupMode } = props - const { - loading: isCommandsLoading, - } = useSelector(appRedisCommandsSelector) + const { loading: isCommandsLoading, } = useSelector(appRedisCommandsSelector) + const { id: connectedIndstanceId } = useSelector(connectedInstanceSelector) + const { data: indexes = [] } = useSelector(redisearchListSelector) + + const dispatch = useDispatch() + + useEffect(() => { + if (!connectedIndstanceId) return + + // fetch indexes + dispatch(fetchRedisearchListAction()) + }, [connectedIndstanceId]) const Placeholder = (
@@ -47,6 +58,7 @@ const QueryWrapper = (props: Props) => { ) : ( + isBlocked: boolean + append: Maybe> + parent: Maybe +} + +export interface CursorContext { + prevCursorChar: string + nextCursorChar: string + isCursorInQuotes: boolean + currentOffsetArg: string + offset: number + argLeftOffset: number + argRightOffset: number +} diff --git a/redisinsight/ui/src/pages/workbench/utils/monaco.ts b/redisinsight/ui/src/pages/workbench/utils/monaco.ts new file mode 100644 index 0000000000..3bce209dd4 --- /dev/null +++ b/redisinsight/ui/src/pages/workbench/utils/monaco.ts @@ -0,0 +1,64 @@ +import { monaco } from 'react-monaco-editor' +import * as monacoEditor from 'monaco-editor' +import { isString } from 'lodash' +import { generateDetail } from 'uiSrc/pages/workbench/utils/query' +import { SearchCommand, TokenType } from 'uiSrc/pages/workbench/types' +import { Maybe } from 'uiSrc/utils' + +export const setCursorPositionAtTheEnd = (editor: monacoEditor.editor.IStandaloneCodeEditor) => { + if (!editor) return + + const rows = editor.getValue().split('\n') + + editor.setPosition({ + column: rows[rows.length - 1].trimEnd().length + 1, + lineNumber: rows.length + }) + + editor.focus() +} + +export const getRange = (position: monaco.Position, word: monaco.editor.IWordAtPosition): monaco.IRange => ({ + startLineNumber: position.lineNumber, + endLineNumber: position.lineNumber, + endColumn: word.endColumn, + startColumn: word.startColumn, +}) + +export const buildSuggestion = (arg: SearchCommand, range: monaco.IRange, options: any = {}) => { + const extraQuotes = arg.expression ? '\'$1\'' : '' + return { + label: isString(arg) ? arg : arg.token || arg.arguments?.[0].token || arg.name || '', + insertText: `${arg.token || arg.arguments?.[0].token || arg.name?.toUpperCase() || ''} ${extraQuotes}`, + insertTextRules: monacoEditor.languages.CompletionItemInsertTextRule.InsertAsSnippet, + range, + kind: options?.kind || monacoEditor.languages.CompletionItemKind.Function, + ...options, + } +} + +export const getRediSearchSignutureProvider = (options: Maybe<{ + isOpen: boolean + currentArg: SearchCommand + parent: Maybe +}>) => { + const { isOpen, currentArg, parent } = options || {} + if (!isOpen) return null + + const label = generateDetail(parent) + const arg = currentArg?.type === TokenType.Block + ? currentArg?.arguments?.[0]?.name + : (currentArg?.name || currentArg?.type || '') + + return { + dispose: () => {}, + value: { + activeParameter: 0, + activeSignature: 0, + signatures: [{ + label: label || '', + parameters: [{ label: arg }] + }] + } + } +} diff --git a/redisinsight/ui/src/pages/workbench/utils/profile.ts b/redisinsight/ui/src/pages/workbench/utils/profile.ts new file mode 100644 index 0000000000..5ba0ae140c --- /dev/null +++ b/redisinsight/ui/src/pages/workbench/utils/profile.ts @@ -0,0 +1,40 @@ +import { ProfileQueryType, SEARCH_COMMANDS, GRAPH_COMMANDS } from '../constants' + +export const generateGraphProfileQuery = (query: string, type: ProfileQueryType) => { + const q = query?.split(' ')?.slice(1) + + if (q) { + return [`graph.${type.toLowerCase()}`, ...q].join(' ') + } + + return null +} + +export const generateSearchProfileQuery = (query: string, type: ProfileQueryType) => { + const commandSplit = query?.split(' ') + const cmd = commandSplit?.[0] + + if (!commandSplit || !cmd) { + return null + } + + if (type === ProfileQueryType.Explain) { + return [`ft.${type.toLowerCase()}`, ...commandSplit?.slice(1)].join(' ') + } + const index = commandSplit?.[1] + + const queryType = cmd.split('.')?.[1] // SEARCH / AGGREGATE + return [`ft.${type.toLowerCase()}`, index, queryType, 'QUERY', ...commandSplit?.slice(2)].join(' ') +} + +export const generateProfileQueryForCommand = (query: string, type: ProfileQueryType) => { + const cmd = query?.split(' ')?.[0]?.toLowerCase() + + if (GRAPH_COMMANDS.includes(cmd)) { + return generateGraphProfileQuery(query, type) + } if (SEARCH_COMMANDS.includes(cmd)) { + return generateSearchProfileQuery(query, type) + } + + return null +} diff --git a/redisinsight/ui/src/pages/workbench/utils/query.ts b/redisinsight/ui/src/pages/workbench/utils/query.ts new file mode 100644 index 0000000000..c87887fbb8 --- /dev/null +++ b/redisinsight/ui/src/pages/workbench/utils/query.ts @@ -0,0 +1,479 @@ +/* eslint-disable no-continue */ + +import { isNumber, toNumber } from 'lodash' +import { generateArgsNames, Maybe, Nullable } from 'uiSrc/utils' +import { CommandProvider } from 'uiSrc/constants' +import { COMPOSITE_ARGS } from 'uiSrc/pages/workbench/constants' +import { ArgName, FoundCommandArgument, SearchCommand, SearchCommandTree, TokenType } from '../types' + +export const splitQueryByArgs = (query: string, position: number = 0) => { + const args: [string[], string[]] = [[], []] + let arg = '' + let inQuotes = false + let escapeNextChar = false + let quoteChar = '' + let isCursorInQuotes = false + let lastArg = '' + let argLeftOffset = 0 + let argRightOffset = 0 + + const pushToProperTuple = (isAfterOffset: boolean, arg: string) => { + lastArg = arg + isAfterOffset ? args[1].push(arg) : args[0].push(arg) + } + + const updateLastArgument = (isAfterOffset: boolean, arg: string) => { + const argsBySide = args[isAfterOffset ? 1 : 0] + argsBySide[argsBySide.length - 1] = `${argsBySide[argsBySide.length - 1]} ${arg}` + } + + const updateArgOffsets = (left: number, right: number) => { + argLeftOffset = left + argRightOffset = right + } + + for (let i = 0; i < query.length; i++) { + const char = query[i] + const isAfterOffset = i >= position + (inQuotes ? -1 : 0) + + if (escapeNextChar) { + arg += char + escapeNextChar = !quoteChar + } else if (char === '\\') { + escapeNextChar = true + } else if (inQuotes) { + if (char === quoteChar) { + inQuotes = false + const argWithChat = arg + char + + if (isAfterOffset && !argLeftOffset) { + updateArgOffsets(i - arg.length, i + 1) + } + + if (isCompositeArgument(argWithChat, lastArg)) { + updateLastArgument(isAfterOffset, argWithChat) + } else { + pushToProperTuple(isAfterOffset, argWithChat) + } + + arg = '' + } else { + arg += char + } + } else if (char === '"' || char === "'") { + inQuotes = true + quoteChar = char + arg += char + } else if (char === ' ' || char === '\n') { + if (arg.length > 0) { + if (isAfterOffset && !argLeftOffset) { + updateArgOffsets(i - arg.length, i) + } + + if (isCompositeArgument(arg, lastArg)) { + updateLastArgument(isAfterOffset, arg) + } else { + pushToProperTuple(isAfterOffset, arg) + } + + arg = '' + } + } else { + arg += char + } + + if (i === position - 1) isCursorInQuotes = inQuotes + } + + if (arg.length > 0) { + if (!argLeftOffset) updateArgOffsets(query.length - arg.length, query.length) + pushToProperTuple(true, arg) + } + + const cursor = { + isCursorInQuotes, + prevCursorChar: query[position - 1]?.trim() || '', + nextCursorChar: query[position]?.trim() || '', + argLeftOffset, + argRightOffset + } + + return { args, cursor } +} + +export const findCurrentArgument = ( + args: SearchCommand[], + prev: string[], + parent?: SearchCommandTree +): Nullable => { + for (let i = prev.length - 1; i >= 0; i--) { + const arg = prev[i] + const currentArg = findArgByToken(args, arg) + const currentWithParent: SearchCommandTree = { ...currentArg, parent } + + if (currentArg?.arguments && currentArg?.type === TokenType.Block) { + return findCurrentArgument(currentArg.arguments, prev.slice(i), currentWithParent) + } + + const tokenIndex = args.findIndex((cArg) => + cArg.token?.toLowerCase() === arg.toLowerCase()) + const token = args[tokenIndex] + + if (token) { + const pastArgs = prev.slice(i) + const commandArgs = parent ? args.slice(tokenIndex, args.length) : [token] + + // getArgByRest - here we preparing the list of arguments which can be inserted, + // this is the main function which creates the list of arguments + return { + ...getArgumentSuggestions({ tokenArgs: pastArgs, levelArgs: prev }, commandArgs, parent), + parent: parent || token + } + } + } + + return null +} + +const findStopArgumentInQuery = ( + queryArgs: string[], + restCommandArgs: Maybe = [], +): { + restArguments: SearchCommand[] + stopArgIndex: number + argumentsIntered?: number + isBlocked: boolean + parent?: SearchCommand +} => { + let currentCommandArgIndex = 0 + let argumentsIntered = 0 + let isBlockedOnCommand = false + let multipleIndexStart = 0 + let multipleCountNumber = 0 + + const moveToNextCommandArg = () => { + currentCommandArgIndex++ + argumentsIntered++ + } + const blockCommand = () => { isBlockedOnCommand = true } + const unBlockCommand = () => { isBlockedOnCommand = false } + + const skipArg = () => { + argumentsIntered -= 1 + moveToNextCommandArg() + unBlockCommand() + } + + for (let i = 0; i < queryArgs.length; i++) { + const arg = queryArgs[i] + const currentCommandArg = restCommandArgs[currentCommandArgIndex] + + if (currentCommandArg?.type === TokenType.PureToken) { + skipArg() + continue + } + + if (!isBlockedOnCommand && currentCommandArg?.optional) { + const isNotToken = currentCommandArg?.token && currentCommandArg.token !== arg.toUpperCase() + const isNotOneOfToken = !currentCommandArg?.token && currentCommandArg?.type === TokenType.OneOf + && currentCommandArg?.arguments?.every(({ token }) => token !== arg.toUpperCase()) + + if (isNotToken || isNotOneOfToken) { + moveToNextCommandArg() + skipArg() + continue + } + } + + if (currentCommandArg?.type === TokenType.Block) { + let blockArguments = currentCommandArg.arguments ? [...currentCommandArg.arguments] : [] + const nArgs = toNumber(queryArgs[i - 1]) || 0 + + // if block is multiple - we duplicate nArgs inner arguments + if (currentCommandArg?.multiple && nArgs) { + blockArguments = Array(nArgs).fill(currentCommandArg.arguments).flat() + } + + const currentQueryArg = queryArgs.slice(i)?.[0]?.toUpperCase() + const isBlockHasToken = blockArguments?.[0]?.token === currentQueryArg + + if (currentCommandArg.token && !isBlockHasToken && currentQueryArg) { + blockArguments.unshift({ + type: TokenType.PureToken, + token: currentQueryArg + }) + } + + const blockSuggestion = findStopArgumentInQuery(queryArgs.slice(i), blockArguments) + const stopArg = blockSuggestion.restArguments?.[blockSuggestion.stopArgIndex] + const { argumentsIntered } = blockSuggestion + + if (nArgs && currentCommandArg?.multiple && isNumber(argumentsIntered) && argumentsIntered >= nArgs) { + i += queryArgs.slice(i).length - 1 + skipArg() + continue + } + + if (blockSuggestion.isBlocked || stopArg) { + return { + ...blockSuggestion, + parent: currentCommandArg + } + } + + i += queryArgs.slice(i).length - 1 + skipArg() + continue + } + + // if we are on token - that requires one more argument + if (currentCommandArg?.token === arg.toUpperCase()) { + blockCommand() + continue + } + + if (currentCommandArg?.name === ArgName.NArgs) { + const numberOfArgs = toNumber(arg) + + if (numberOfArgs === 0) { + moveToNextCommandArg() + skipArg() + continue + } + + moveToNextCommandArg() + blockCommand() + continue + } + + if (currentCommandArg?.type === TokenType.OneOf && currentCommandArg?.optional) { + // if oneof is optional then we can switch to another argument + if (!currentCommandArg?.arguments?.some(({ token }) => token === arg)) { + moveToNextCommandArg() + } + + skipArg() + continue + } + + if (currentCommandArg?.multiple) { + if (!multipleIndexStart) { + multipleCountNumber = toNumber(queryArgs[i - 1]) + multipleIndexStart = i - 1 + } + + if (i - multipleIndexStart >= multipleCountNumber) { + skipArg() + multipleIndexStart = 0 + continue + } + + blockCommand() + continue + } + + moveToNextCommandArg() + + isBlockedOnCommand = false + } + + return { + restArguments: restCommandArgs, + stopArgIndex: currentCommandArgIndex, + argumentsIntered, + isBlocked: isBlockedOnCommand + } +} + +export const getArgumentSuggestions = ( + { tokenArgs, levelArgs }: { + tokenArgs: string[], + levelArgs: string[] + }, + pastCommandArgs: SearchCommand[], + current?: SearchCommandTree +): { + isComplete: boolean + stopArg: Maybe, + isBlocked: boolean, + append: Array, +} => { + const { + restArguments, + stopArgIndex, + isBlocked: isWasBlocked, + parent + } = findStopArgumentInQuery(tokenArgs, pastCommandArgs) + + const prevArg = restArguments[stopArgIndex - 1] + const stopArgument = restArguments[stopArgIndex] + const restNotFilledArgs = restArguments.slice(stopArgIndex) + + const isOneOfArgument = stopArgument?.type === TokenType.OneOf + || (stopArgument?.type === TokenType.PureToken && current?.parent?.type === TokenType.OneOf) + + if (isWasBlocked) { + return { + isComplete: false, + stopArg: stopArgument, + isBlocked: !isOneOfArgument, + append: isOneOfArgument ? [stopArgument.arguments!] : [], + } + } + + const isPrevArgWasMandatory = prevArg && !prevArg.optional + if (isPrevArgWasMandatory && stopArgument && !stopArgument.optional) { + const isCanAppend = stopArgument?.token || isOneOfArgument + const append = isCanAppend ? [[isOneOfArgument ? stopArgument.arguments! : stopArgument].flat()] : [] + + return { + isComplete: false, + stopArg: stopArgument, + isBlocked: !isCanAppend, + append, + } + } + + // if we finished argument - stopArgument will be undefined, then we get it as token + const lastArgument = stopArgument ?? restArguments[0] + const isBlockHasParent = current?.arguments?.some(({ name }) => parent?.name && name === parent?.name) + const foundParent = isBlockHasParent ? { ...parent, parent: current } : (parent || current) + + const isBlockComplete = !stopArgument && current?.name === lastArgument?.name + const beforeMandatoryOptionalArgs = getAllRestArguments(foundParent, lastArgument, levelArgs, isBlockComplete) + const requiredArgsLength = restNotFilledArgs.filter((arg) => !arg.optional).length + + return { + isComplete: requiredArgsLength === 0, + stopArg: stopArgument, + isBlocked: false, + append: beforeMandatoryOptionalArgs, + } +} + +export const getRestArguments = ( + current: Maybe, + stopArgument: Nullable +): SearchCommandTree[] => { + const argumentIndexInArg = current?.arguments + ?.findIndex(({ name }) => name === stopArgument?.name) + const nextMandatoryIndex = argumentIndexInArg && argumentIndexInArg > -1 ? current?.arguments + ?.findIndex(({ optional }, i) => !optional && i > argumentIndexInArg) : -1 + const prevMandatory = current?.arguments?.slice(0, argumentIndexInArg).reverse() + .find(({ optional }) => !optional) + const prevMandatoryIndex = current?.arguments?.findIndex(({ name }) => name === prevMandatory?.name) + + const beforeMandatoryOptionalArgs = ( + nextMandatoryIndex && nextMandatoryIndex > -1 + ? current?.arguments?.slice(prevMandatoryIndex, nextMandatoryIndex) + : current?.arguments?.slice((prevMandatoryIndex || 0) + 1) + ) || [] + + const nextMandatoryArg = nextMandatoryIndex && nextMandatoryIndex > -1 + ? current?.arguments?.[nextMandatoryIndex] + : undefined + + if (nextMandatoryArg?.token) { + beforeMandatoryOptionalArgs.unshift(nextMandatoryArg) + } + + if (nextMandatoryArg?.type === TokenType.OneOf) { + beforeMandatoryOptionalArgs.unshift(...(nextMandatoryArg.arguments || [])) + } + + return beforeMandatoryOptionalArgs.map((arg) => ({ ...arg, parent: current })) +} + +export const getAllRestArguments = ( + current: Maybe, + stopArgument: Nullable, + prevStringArgs: string[] = [], + skipLevel = false +) => { + const appendArgs: Array = [] + const currentLvlNextArgs = removeNotSuggestedArgs( + prevStringArgs, + getRestArguments(current, stopArgument) + ) + + if (!skipLevel) { + appendArgs.push(fillArgsByType(currentLvlNextArgs)) + } + + if (current?.parent) { + const parentArgs = getAllRestArguments(current.parent, current, skipLevel ? prevStringArgs : []) + if (parentArgs?.length) { + appendArgs.push(...parentArgs) + } + } + + return appendArgs +} + +export const removeNotSuggestedArgs = (args: string[], commandArgs: SearchCommandTree[]) => + commandArgs.filter((arg) => { + if (arg.token && arg.multiple) return true + + if (arg.type === TokenType.OneOf) { + return !args + .some((queryArg) => arg.arguments + ?.some((oneOfArg) => oneOfArg.token?.toUpperCase() === queryArg.toUpperCase())) + } + + if (arg.type === TokenType.Block) { + return arg.arguments?.[0]?.token && !args.includes(arg.arguments?.[0]?.token?.toUpperCase()) + } + + return arg.token && !args.includes(arg.token) + }) + +export const fillArgsByType = (args: SearchCommand[], expandBlock = true): SearchCommandTree[] => { + const result: SearchCommandTree[] = [] + + for (let i = 0; i < args.length; i++) { + const currentArg = args[i] + + if (expandBlock && currentArg.type === TokenType.OneOf && !currentArg.token) { + result.push(...(currentArg?.arguments?.map((arg) => ({ ...arg, parent: currentArg })) || [])) + } + + if (currentArg.type === TokenType.Block) { + result.push({ + multiple: currentArg.multiple, + optional: currentArg.optional, + parent: currentArg, + ...(currentArg?.arguments?.[0] as SearchCommand || {}), + }) + } + if (currentArg.token) result.push(currentArg) + } + + return result +} + +export const findArgByToken = (list: SearchCommand[], arg: string): Maybe => + list.find((cArg) => + (cArg.type === TokenType.OneOf + ? cArg.arguments?.some((oneOfArg: SearchCommand) => oneOfArg?.token?.toLowerCase() === arg?.toLowerCase()) + : cArg.arguments?.[0]?.token?.toLowerCase() === arg.toLowerCase())) + +export const isCompositeArgument = (arg: string, prevArg?: string) => + COMPOSITE_ARGS.includes([prevArg?.toUpperCase(), arg?.toUpperCase()].join(' ')) + +export const generateDetail = (command: Maybe) => { + if (!command) return '' + if (command.arguments) return generateArgsNames(CommandProvider.Main, command.arguments).join(' ') + if (command.token) { + if (command.type === TokenType.PureToken) return command.token + return `${command.token}` + } + + return '' +} + +export const addOwnTokenToArgs = (token: string, command: SearchCommand) => { + if (command.arguments) { + return ({ ...command, arguments: [{ token, type: TokenType.PureToken }, ...command.arguments] }) + } + return command +} diff --git a/redisinsight/ui/src/pages/workbench/utils/suggestions.ts b/redisinsight/ui/src/pages/workbench/utils/suggestions.ts new file mode 100644 index 0000000000..288ae6dc69 --- /dev/null +++ b/redisinsight/ui/src/pages/workbench/utils/suggestions.ts @@ -0,0 +1,198 @@ +import { monaco } from 'react-monaco-editor' +import * as monacoEditor from 'monaco-editor' +import { RedisResponseBuffer } from 'uiSrc/slices/interfaces' +import { bufferToString, formatLongName, generateArgsForInsertText, getCommandMarkdown, Nullable } from 'uiSrc/utils' +import { FoundCommandArgument, SearchCommand } from 'uiSrc/pages/workbench/types' +import { DefinedArgumentName, EmptySuggestionsIds } from 'uiSrc/pages/workbench/constants' +import { getUtmExternalLink } from 'uiSrc/utils/links' +import { removeNotSuggestedArgs, generateDetail } from './query' +import { buildSuggestion, } from './monaco' + +export const asSuggestionsRef = ( + suggestions: monacoEditor.languages.CompletionItem[], + forceHide = true, + forceShow = true +) => ({ + data: suggestions, + forceHide, + forceShow +}) + +const NO_INDEXES_DOC_LINK = getUtmExternalLink('https://redis.io/docs/latest/commands/ft.create/', { campaign: 'workbench' }) +export const getNoIndexesSuggestion = (range: monaco.IRange) => [ + { + id: EmptySuggestionsIds.NoIndexes, + label: 'No indexes to display', + kind: monacoEditor.languages.CompletionItemKind.Issue, + insertText: '', + insertTextRules: monacoEditor.languages.CompletionItemInsertTextRule.InsertAsSnippet, + range, + detail: 'Create an index', + documentation: { + value: `See the [documentation](${NO_INDEXES_DOC_LINK}) for detailed instructions on how to create an index.`, + } + } +] + +export const getIndexesSuggestions = (indexes: RedisResponseBuffer[], range: monaco.IRange, isNextArgQuery = true) => + indexes.map((index) => { + const value = formatLongName(bufferToString(index)) + const insertQueryQuotes = isNextArgQuery ? " '\${1:query to search}'" : '' + + return { + label: value || ' ', + kind: monacoEditor.languages.CompletionItemKind.Snippet, + insertText: `'${value}'${insertQueryQuotes} `, + insertTextRules: monacoEditor.languages.CompletionItemInsertTextRule.InsertAsSnippet, + range, + detail: value || ' ', + } + }) + +export const addFieldAttribute = (attribute: string, type: string) => { + switch (type) { + case 'TAG': return `${attribute}:{\${1:tag}}` + case 'TEXT': return `${attribute}:(\${1:term})` + case 'NUMERIC': return `${attribute}:[\${1:range}]` + case 'GEO': return `${attribute}:[\${1:lon} \${2:lat} \${3:radius} \${4:unit}]` + case 'VECTOR': return `${attribute} \\$\${1:vector}` + default: return attribute + } +} + +export const getFieldsSuggestions = ( + fields: any[], + range: monaco.IRange, + spaceAfter = false, + withType = false +) => + fields.map((field) => { + const { attribute, type } = field + const attibuteText = attribute.trim() ? attribute : `\\'${attribute}\\'` + const insertText = withType ? addFieldAttribute(attibuteText, type) : attibuteText + + return { + label: attribute || ' ', + kind: monacoEditor.languages.CompletionItemKind.Reference, + insertText: `${insertText}${spaceAfter ? ' ' : ''}`, + insertTextRules: monacoEditor.languages.CompletionItemInsertTextRule.InsertAsSnippet, + range, + detail: attribute || ' ', + } + }) + +const insertFunctionArguments = (args: SearchCommand[]) => + generateArgsForInsertText( + args.map(({ token, optional }) => (optional ? `[${token}]` : (token || ''))) as string[], + ', ' + ) + +export const getFunctionsSuggestions = (functions: SearchCommand[], range: monaco.IRange) => functions + .map(({ token, summary, arguments: args }) => ({ + label: token || '', + insertText: `${token}(${insertFunctionArguments(args || [])})`, + insertTextRules: monacoEditor.languages.CompletionItemInsertTextRule.InsertAsSnippet, + range, + kind: monacoEditor.languages.CompletionItemKind.Function, + detail: summary + })) + +export const getCommandsSuggestions = (commands: SearchCommand[], range: monaco.IRange) => + commands.map((command) => buildSuggestion(command, range, { + detail: generateDetail(command), + insertTextRules: monacoEditor.languages.CompletionItemInsertTextRule.InsertAsSnippet, + documentation: { + value: getCommandMarkdown(command as any) + }, + })) + +export const getMandatoryArgumentSuggestions = ( + foundArg: FoundCommandArgument, + fields: any[], + range: monaco.IRange +): monacoEditor.languages.CompletionItem[] => { + if (foundArg.stopArg?.name === DefinedArgumentName.field) { + if (!fields.length) return [] + return getFieldsSuggestions(fields, range, true) + } + + if (foundArg.isBlocked) return [] + if (foundArg.append?.length) { + return foundArg.append[0].map((arg: any) => buildSuggestion(arg, range, { + kind: monacoEditor.languages.CompletionItemKind.Property, + detail: generateDetail(foundArg?.parent) + })) + } + + return [] +} + +export const getCommandSuggestions = ( + foundArg: Nullable, + allArgs: string[], + range: monaco.IRange, +) => { + const appendCommands = foundArg?.append ?? [] + const suggestions = [] + + for (let i = 0; i < appendCommands.length; i++) { + const isLastLevel = i === appendCommands.length - 1 + const filteredFileldArgs = isLastLevel + ? removeNotSuggestedArgs(allArgs, appendCommands[i]) + : appendCommands[i] + + const leveledSuggestions = filteredFileldArgs + .map((arg) => buildSuggestion(arg, range, { + sortText: `${i}`, + kind: isLastLevel + ? monacoEditor.languages.CompletionItemKind.Reference + : monacoEditor.languages.CompletionItemKind.Property, + detail: generateDetail(arg?.parent) + })) + + suggestions.push(leveledSuggestions) + } + + return suggestions.flat() +} + +export const getGeneralSuggestions = ( + foundArg: Nullable, + allArgs: string[], + range: monacoEditor.IRange, + fields: any[] +): { + suggestions: monacoEditor.languages.CompletionItem[], + forceHide?: boolean + helpWidgetData?: any +} => { + if (foundArg && !foundArg.isComplete) { + return { + suggestions: getMandatoryArgumentSuggestions(foundArg, fields, range), + helpWidgetData: { isOpen: !!foundArg?.stopArg, parent: foundArg?.parent, currentArg: foundArg?.stopArg } + } + } + + return { + suggestions: getCommandSuggestions(foundArg, allArgs, range), + helpWidgetData: { isOpen: false } + } +} + +export const isIndexComplete = (index: string) => { + if (index.length === 0) return false + + const firstChar = index[0] + const lastChar = index[index.length - 1] + + if (firstChar !== '"' && firstChar !== "'") return true + if (index.length === 1 && (firstChar === '"' || firstChar === "'")) return false + if (firstChar !== lastChar) return false + + let escape = false + for (let i = 1; i < index.length - 1; i++) { + escape = index[i] === '\\' && !escape + } + + return !escape +} diff --git a/redisinsight/ui/src/utils/monaco/monacoInterfaces.ts b/redisinsight/ui/src/utils/monaco/monacoInterfaces.ts index fac8c23166..e092777374 100644 --- a/redisinsight/ui/src/utils/monaco/monacoInterfaces.ts +++ b/redisinsight/ui/src/utils/monaco/monacoInterfaces.ts @@ -10,7 +10,15 @@ export interface IMonacoCommand { export interface IMonacoQuery { name: string fullQuery: string - args?: string[] + args: [string[], string[]], + cursor: { + isCursorInQuotes: boolean, + prevCursorChar: string, + nextCursorChar: string, + argLeftOffset: number, + argRightOffset: number + } + allArgs: string[] info?: ICommand commandPosition: any position?: monacoEditor.Position diff --git a/redisinsight/ui/src/utils/monaco/monacoRedisMonarchTokensProvider.ts b/redisinsight/ui/src/utils/monaco/monacoRedisMonarchTokensProvider.ts index 9f41113289..a007c4cf3c 100644 --- a/redisinsight/ui/src/utils/monaco/monacoRedisMonarchTokensProvider.ts +++ b/redisinsight/ui/src/utils/monaco/monacoRedisMonarchTokensProvider.ts @@ -1,9 +1,16 @@ import { monaco as monacoEditor } from 'react-monaco-editor' +import { remove } from 'lodash' +import { SearchCommand } from 'uiSrc/pages/workbench/types' const STRING_DOUBLE = 'string.double' -export const getRedisMonarchTokensProvider = (commands: string[]): monacoEditor.languages.IMonarchLanguage => ( - { +export const getRedisMonarchTokensProvider = (commands: SearchCommand[]): monacoEditor.languages.IMonarchLanguage => { + const commandRedisCommands = [...commands] + const searchCommands = remove(commandRedisCommands, ({ token }) => token?.startsWith('FT.')) + const COMMON_COMMANDS_REGEX = `(${commandRedisCommands.map(({ token }) => token).join('|')})\\b` + const SEARCH_COMMANDS_REGEX = `(${searchCommands.map(({ token }) => token).join('|')})\\b` + + return { defaultToken: '', tokenPostfix: '.redis', ignoreCase: true, @@ -11,26 +18,13 @@ export const getRedisMonarchTokensProvider = (commands: string[]): monacoEditor. { open: '[', close: ']', token: 'delimiter.square' }, { open: '(', close: ')', token: 'delimiter.parenthesis' }, ], - keywords: commands, - operators: [ - // NOT SUPPORTED - ], - builtinFunctions: [ - // NOT SUPPORTED - ], - builtinVariables: [ - // NOT SUPPORTED - ], - pseudoColumns: [ - // NOT SUPPORTED - ], + keywords: commands.map(({ token }) => token), + operators: [], tokenizer: { root: [ { include: '@whitespace' }, - { include: '@pseudoColumns' }, { include: '@numbers' }, { include: '@strings' }, - { include: '@scopes' }, { include: '@keyword' }, [/[;,.]/, 'delimiter'], [/[()]/, '@brackets'], @@ -40,8 +34,6 @@ export const getRedisMonarchTokensProvider = (commands: string[]): monacoEditor. cases: { '@keywords': 'keyword', '@operators': 'operator', - '@builtinVariables': 'predefined', - '@builtinFunctions': 'predefined', '@default': 'identifier', }, }, @@ -49,26 +41,13 @@ export const getRedisMonarchTokensProvider = (commands: string[]): monacoEditor. [/[<>=!%&+\-*/|~^]/, 'operator'], ], keyword: [ - [ - `(${commands.join('|')})\\b`, - 'keyword' - ] + [COMMON_COMMANDS_REGEX, { token: 'keyword' }], + [SEARCH_COMMANDS_REGEX, { token: '@rematch', nextEmbedded: 'redisearch', next: '@endRedisearch' }], ], whitespace: [ [/\s+/, 'white'], [/\/\/.*$/, 'comment'], ], - pseudoColumns: [ - [ - /[$][A-Za-z_][\w@#$]*/, - { - cases: { - '@pseudoColumns': 'predefined', - '@default': 'identifier', - }, - }, - ], - ], numbers: [ [/0[xX][0-9a-fA-F]*/, 'number'], [/[$][+-]*\d*(\.\d*)?/, 'number'], @@ -88,9 +67,10 @@ export const getRedisMonarchTokensProvider = (commands: string[]): monacoEditor. [/"/, { token: STRING_DOUBLE, next: '@pop' }], [/[^\\"]+/, STRING_DOUBLE], ], - scopes: [ - // NOT SUPPORTED - ], + // TODO: can be tokens or functions the same - need to think how to avoid wrong ending + endRedisearch: [ + [`^\\s*${COMMON_COMMANDS_REGEX}`, { token: '@rematch', next: '@root', nextEmbedded: '@pop', log: 'end' }], + ] }, } -) +} diff --git a/redisinsight/ui/src/utils/monaco/monacoUtils.ts b/redisinsight/ui/src/utils/monaco/monacoUtils.ts index dadcb5234d..4ff48b893e 100644 --- a/redisinsight/ui/src/utils/monaco/monacoUtils.ts +++ b/redisinsight/ui/src/utils/monaco/monacoUtils.ts @@ -10,6 +10,7 @@ import { IMonacoQuery } from 'uiSrc/utils' import { TJMESPathFunctions } from 'uiSrc/slices/interfaces' +import { isCompositeArgument } from 'uiSrc/pages/search/utils' import { Nullable } from '../types' import { getCommandRepeat, isRepeatCountCorrect } from '../commands' @@ -105,6 +106,101 @@ export const findCommandEarlier = ( return command } +export const splitQueryByArgs = (query: string, position: number = 0) => { + const args: [string[], string[]] = [[], []] + let arg = '' + let inQuotes = false + let escapeNextChar = false + let quoteChar = '' + let isCursorInQuotes = false + let lastArg = '' + let argLeftOffset = 0 + let argRightOffset = 0 + + const pushToProperTuple = (isAfterOffset: boolean, arg: string) => { + lastArg = arg + isAfterOffset ? args[1].push(arg) : args[0].push(arg) + } + + const updateLastArgument = (isAfterOffset: boolean, arg: string) => { + const argsBySide = args[isAfterOffset ? 1 : 0] + argsBySide[argsBySide.length - 1] = `${argsBySide[argsBySide.length - 1]} ${arg}` + } + + const updateArgOffsets = (left: number, right: number) => { + argLeftOffset = left + argRightOffset = right + } + + for (let i = 0; i < query.length; i++) { + const char = query[i] + const isAfterOffset = i >= position + (inQuotes ? -1 : 0) + + if (escapeNextChar) { + arg += char + escapeNextChar = !quoteChar + } else if (char === '\\') { + escapeNextChar = true + } else if (inQuotes) { + if (char === quoteChar) { + inQuotes = false + const argWithChat = arg + char + + if (isAfterOffset && !argLeftOffset) { + updateArgOffsets(i - arg.length, i + 1) + } + + if (isCompositeArgument(argWithChat, lastArg)) { + updateLastArgument(isAfterOffset, argWithChat) + } else { + pushToProperTuple(isAfterOffset, argWithChat) + } + + arg = '' + } else { + arg += char + } + } else if (char === '"' || char === "'") { + inQuotes = true + quoteChar = char + arg += char + } else if (char === ' ' || char === '\n') { + if (arg.length > 0) { + if (isAfterOffset && !argLeftOffset) { + updateArgOffsets(i - arg.length, i) + } + + if (isCompositeArgument(arg, lastArg)) { + updateLastArgument(isAfterOffset, arg) + } else { + pushToProperTuple(isAfterOffset, arg) + } + + arg = '' + } + } else { + arg += char + } + + if (i === position - 1) isCursorInQuotes = inQuotes + } + + if (arg.length > 0) { + if (!argLeftOffset) updateArgOffsets(query.length - arg.length, query.length) + pushToProperTuple(true, arg) + } + + const cursor = { + isCursorInQuotes, + prevCursorChar: query[position - 1]?.trim() || '', + nextCursorChar: query[position]?.trim() || '', + argLeftOffset, + argRightOffset + } + + return { args, cursor } +} + export const findCompleteQuery = ( model: monacoEditor.editor.ITextModel, position: monacoEditor.Position, @@ -166,9 +262,7 @@ export const findCompleteQuery = ( fullQuery += lineAfterPosition } - const args = fullQuery - .replace(matchedCommand, '') - .match(/(?:[^\s"']+|["][^"]*["]|['][^']*['])+/g) + const { args, cursor } = splitQueryByArgs(fullQuery, commandCursorPosition) return { position, @@ -176,6 +270,8 @@ export const findCompleteQuery = ( commandCursorPosition, fullQuery, args, + cursor, + allArgs: args.flat(), name: matchedCommand, info: commandsSpec[matchedCommand] } as IMonacoQuery diff --git a/redisinsight/ui/src/utils/monaco/monarchTokens/redisearchTokens.ts b/redisinsight/ui/src/utils/monaco/monarchTokens/redisearchTokens.ts index d9c1c3b881..e73734b113 100644 --- a/redisinsight/ui/src/utils/monaco/monarchTokens/redisearchTokens.ts +++ b/redisinsight/ui/src/utils/monaco/monarchTokens/redisearchTokens.ts @@ -6,7 +6,7 @@ import { generateTokensWithFunctions, getBlockTokens, isIndexAfterKeyword, isQueryAfterIndex -} from 'uiSrc/utils/monaco/redisearch/utils' +} from 'uiSrc/utils/monaco/redisearch/utils_old' import { generateQuery } from 'uiSrc/utils/monaco/monarchTokens/redisearchTokensTemplates' const STRING_DOUBLE = 'string.double' diff --git a/redisinsight/ui/src/utils/monaco/monarchTokens/redisearchTokensSubRedis.ts b/redisinsight/ui/src/utils/monaco/monarchTokens/redisearchTokensSubRedis.ts new file mode 100644 index 0000000000..9be0444673 --- /dev/null +++ b/redisinsight/ui/src/utils/monaco/monarchTokens/redisearchTokensSubRedis.ts @@ -0,0 +1,121 @@ +import { monaco as monacoEditor } from 'react-monaco-editor' +import { remove } from 'lodash' +import { SearchCommand } from 'uiSrc/pages/search/types' +import { + generateKeywords, + generateTokens, + generateTokensWithFunctions, + getBlockTokens, isIndexAfterKeyword, + isQueryAfterIndex +} from 'uiSrc/utils/monaco/redisearch/utils' +import { generateQuery } from 'uiSrc/utils/monaco/monarchTokens/redisearchTokensTemplates' + +const STRING_DOUBLE = 'string.double' + +export const getRediSearchSubRedisMonarchTokensProvider = ( + commands: SearchCommand[], +): monacoEditor.languages.IMonarchLanguage => { + const withoutIndexSuggestions = [...commands] + const withNextIndexSuggestions = remove(withoutIndexSuggestions, isIndexAfterKeyword) + const withNextQueryIndexSuggestions = remove([...withNextIndexSuggestions], isQueryAfterIndex) + + const generateTokensForCommands = () => { + let commandTokens: any = {} + + withNextIndexSuggestions.forEach((command) => { + const isIndexAfterCommand = isIndexAfterKeyword(command) + const argTokens = generateTokens(command) + const tokenName = command.token?.replace(/(\.| )/g, '_') + + if (isIndexAfterCommand) { + commandTokens[`argument.block.${tokenName}`] = getBlockTokens(tokenName, argTokens?.pureTokens) + commandTokens = { + ...commandTokens, + ...generateTokensWithFunctions(tokenName, argTokens?.tokensWithQueryAfter) + } + } + }) + + return commandTokens + } + + const keywords = generateKeywords(commands) + const tokens = generateTokensForCommands() + + const includeTokens = () => { + const tokensToInclude = Object.keys(tokens).filter((name) => name.startsWith('argument.block')) + return tokensToInclude.map((include) => ({ include: `@${include}` })) + } + + return ( + { + defaultToken: '', + tokenPostfix: '.redisearch', + ignoreCase: true, + brackets: [ + { open: '[', close: ']', token: 'delimiter.square' }, + { open: '(', close: ')', token: 'delimiter.parenthesis' }, + ], + keywords, + tokenizer: { + root: [ + { include: '@keywords' }, + ...includeTokens(), + { include: '@fields' }, + { include: '@whitespace' }, + { include: '@numbers' }, + { include: '@strings' }, + [/[;,.]/, 'delimiter'], + [/[()]/, '@brackets'], + [/[<>=!%&+\-*/|~^]/, 'operator'], + [/[\w@#$.]+/, 'identifier'] + ], + keywords: [ + [`(${generateKeywords(withNextQueryIndexSuggestions).join('|')})\\b`, { token: 'keyword', next: '@index.query' }], + [`(${generateKeywords(withNextIndexSuggestions).join('|')})\\b`, { token: 'keyword', next: '@index' }], + [`(${generateKeywords(withoutIndexSuggestions).join('|')})\\b`, { token: 'keyword', next: '@root' }], + ], + ...tokens, + ...generateQuery(), + index: [ + [/"([^"\\]|\\.)*"/, { token: 'index', next: '@root' }], + [/'([^'\\]|\\.)*'/, { token: 'index', next: '@root' }], + [/[\w:]+/, { token: 'index', next: '@root' }], + { include: 'root' } // Fallback to the root state if nothing matches + ], + 'index.query': [ + [/"([^"\\]|\\.)*"/, { token: 'index', next: '@query' }], + [/'([^'\\]|\\.)*'/, { token: 'index', next: '@query' }], + [/[\w:]+/, { token: 'index', next: '@query' }], + { include: 'root' } // Fallback to the root state if nothing matches + ], + fields: [ + [/@\w+/, { token: 'field' }] + ], + whitespace: [ + [/\s+/, 'white'], + [/\/\/.*$/, 'comment'], + ], + numbers: [ + [/0[xX][0-9a-fA-F]*/, 'number'], + [/[$][+-]*\d*(\.\d*)?/, 'number'], + [/((\d+(\.\d*)?)|(\.\d+))([eE][-+]?\d+)?/, 'number'], + ], + strings: [ + [/'/, { token: 'string', next: '@string' }], + [/"/, { token: STRING_DOUBLE, next: '@stringDouble' }], + ], + string: [ + [/\\./, 'string'], + [/'/, { token: 'string', next: '@pop' }], + [/[^\\']+/, 'string'], + ], + stringDouble: [ + [/\\./, STRING_DOUBLE], + [/"/, { token: STRING_DOUBLE, next: '@pop' }], + [/[^\\"]+/, STRING_DOUBLE], + ] + }, + } + ) +} diff --git a/redisinsight/ui/src/utils/monaco/redisearch/utils.ts b/redisinsight/ui/src/utils/monaco/redisearch/utils.ts index d04f47a717..25b0fd0b19 100644 --- a/redisinsight/ui/src/utils/monaco/redisearch/utils.ts +++ b/redisinsight/ui/src/utils/monaco/redisearch/utils.ts @@ -75,7 +75,9 @@ export const appendTokenWithQuery = ( ): languages.IMonarchLanguageRule[] => args.map(({ token }) => [`(${token.token})\\b`, { token: `argument.block.${level}`, next: `@query.${token.token}` }]) -export const appendQueryWithNextFunctions = (tokens: Array<{ token: SearchCommand, arguments: SearchCommand[] }>): { +export const appendQueryWithNextFunctions = ( + tokens: Array<{ token: SearchCommand, arguments: SearchCommand[] }> +): { [name: string]: languages.IMonarchLanguageRule[] } => { let result: { [name: string]: languages.IMonarchLanguageRule[] } = {} @@ -91,16 +93,19 @@ export const appendQueryWithNextFunctions = (tokens: Array<{ token: SearchComman } export const generateTokensWithFunctions = ( + name: string = '', tokens?: Array> ): { [name: string]: languages.IMonarchLanguageRule[] } => { - if (!tokens) return { 'argument.block.withFunctions': [] } + if (!tokens) return {} const actualTokens = tokens.filter((tokens) => tokens.length) + if (!actualTokens.length) return {} + return { - 'argument.block.withFunctions': [ + [`argument.block.${name}.withFunctions`]: [ ...actualTokens .map((tokens, lvl) => appendTokenWithQuery(tokens, lvl)) .flat() @@ -110,6 +115,7 @@ export const generateTokensWithFunctions = ( } export const getBlockTokens = ( + name: string = '', pureTokens: Maybe[]> ): languages.IMonarchLanguageRule[] => { if (!pureTokens) return [] @@ -126,14 +132,14 @@ export const getBlockTokens = ( result.push([ `(${tokensWithNextExpression.map(({ token }) => token).join('|')})\\b`, { - token: `argument.block.${lvl}`, + token: `argument.block.${lvl}.${name}`, next: '@query' }, ]) } if (restTokens.length) { - result.push([`(${restTokens.map(({ token }) => token).join('|')})\\b`, { token: `argument.block.${lvl}`, next: '@root' }]) + result.push([`(${restTokens.map(({ token }) => token).join('|')})\\b`, { token: `argument.block.${lvl}.${name}`, next: '@root' }]) } return result diff --git a/redisinsight/ui/src/utils/monaco/redisearch/utils_old.ts b/redisinsight/ui/src/utils/monaco/redisearch/utils_old.ts new file mode 100644 index 0000000000..d04f47a717 --- /dev/null +++ b/redisinsight/ui/src/utils/monaco/redisearch/utils_old.ts @@ -0,0 +1,143 @@ +import { isNumber, remove } from 'lodash' +import { languages } from 'monaco-editor' +import { SearchCommand, TokenType } from 'uiSrc/pages/search/types' +import { Maybe, Nullable } from 'uiSrc/utils' +import { DefinedArgumentName } from 'uiSrc/pages/search/components/query/constants' +import { generateQuery } from 'uiSrc/utils/monaco/monarchTokens/redisearchTokensTemplates' + +export const generateKeywords = (commands: SearchCommand[]) => commands.map(({ name }) => name) +export const generateTokens = (command?: SearchCommand): Nullable<{ + pureTokens: Array> + tokensWithQueryAfter: Array> +}> => { + if (!command) return null + const pureTokens: Array> = [] + const tokensWithQueryAfter: Array> = [] + + function processArguments(args: SearchCommand[], level = 0) { + if (!pureTokens[level]) pureTokens[level] = [] + if (!tokensWithQueryAfter[level]) tokensWithQueryAfter[level] = [] + + args.forEach((arg) => { + if (arg.token) pureTokens[level].push(arg) + + if (arg.type === TokenType.Block && arg.arguments) { + const blockToken = arg.arguments[0] + const nextArgs = arg.arguments + const isArgHasOwnSyntax = arg.arguments[0].expression && !!arg.arguments[0].arguments?.length + + if (blockToken?.token) { + if (isArgHasOwnSyntax) { + tokensWithQueryAfter[level].push({ + token: blockToken, + arguments: arg.arguments[0].arguments as SearchCommand[] + }) + } else { + pureTokens[level].push(blockToken) + } + } + + processArguments(blockToken ? nextArgs.slice(1, nextArgs.length) : nextArgs, level + 1) + } + + if (arg.type === TokenType.OneOf && arg.arguments) { + arg.arguments.forEach((choice) => { + if (choice?.token) pureTokens[level].push(choice) + }) + } + }) + } + + if (command.arguments) { + processArguments(command.arguments, 0) + } + + return { pureTokens, tokensWithQueryAfter } +} + +export const isIndexAfterKeyword = (command?: SearchCommand) => { + if (!command) return false + + const index = command.arguments?.findIndex(({ name }) => name === DefinedArgumentName.index) + return isNumber(index) && index === 0 +} + +export const isQueryAfterIndex = (command?: SearchCommand) => { + if (!command) return false + + const index = command.arguments?.findIndex(({ name }) => name === DefinedArgumentName.index) + return isNumber(index) && index > -1 ? command.arguments?.[index + 1]?.name === DefinedArgumentName.query : false +} + +export const appendTokenWithQuery = ( + args: Array<{ token: SearchCommand, arguments: SearchCommand[] }>, + level: number +): languages.IMonarchLanguageRule[] => + args.map(({ token }) => [`(${token.token})\\b`, { token: `argument.block.${level}`, next: `@query.${token.token}` }]) + +export const appendQueryWithNextFunctions = (tokens: Array<{ token: SearchCommand, arguments: SearchCommand[] }>): { + [name: string]: languages.IMonarchLanguageRule[] +} => { + let result: { [name: string]: languages.IMonarchLanguageRule[] } = {} + + tokens.forEach(({ token, arguments: args }) => { + result = { + ...result, + ...generateQuery(token, args) + } + }) + + return result +} + +export const generateTokensWithFunctions = ( + tokens?: Array> +): { + [name: string]: languages.IMonarchLanguageRule[] +} => { + if (!tokens) return { 'argument.block.withFunctions': [] } + + const actualTokens = tokens.filter((tokens) => tokens.length) + + return { + 'argument.block.withFunctions': [ + ...actualTokens + .map((tokens, lvl) => appendTokenWithQuery(tokens, lvl)) + .flat() + ], + ...appendQueryWithNextFunctions(actualTokens.flat()) + } +} + +export const getBlockTokens = ( + pureTokens: Maybe[]> +): languages.IMonarchLanguageRule[] => { + if (!pureTokens) return [] + + const getLeveledToken = ( + tokens: SearchCommand[], + lvl: number + ): languages.IMonarchLanguageRule[] => { + const result: languages.IMonarchLanguageRule[] = [] + const restTokens = [...tokens] + const tokensWithNextExpression = remove(restTokens, (({ expression }) => expression)) + + if (tokensWithNextExpression.length) { + result.push([ + `(${tokensWithNextExpression.map(({ token }) => token).join('|')})\\b`, + { + token: `argument.block.${lvl}`, + next: '@query' + }, + ]) + } + + if (restTokens.length) { + result.push([`(${restTokens.map(({ token }) => token).join('|')})\\b`, { token: `argument.block.${lvl}`, next: '@root' }]) + } + + return result + } + + return pureTokens.map((tokens, lvl) => getLeveledToken(tokens, lvl)).flat() +} diff --git a/redisinsight/ui/src/utils/monaco/subTokens/redisearchSubTokens.ts b/redisinsight/ui/src/utils/monaco/subTokens/redisearchSubTokens.ts new file mode 100644 index 0000000000..e69de29bb2 From 4b845e31ef040628c6e109d82e13e856deacfe34 Mon Sep 17 00:00:00 2001 From: kchepikava Date: Wed, 9 Oct 2024 16:21:22 +0200 Subject: [PATCH 132/256] RI-6191 fixed text --- .../components/clickable-append-info/ClickableAppendInfo.tsx | 3 +++ .../components/clickable-append-info/styles.module.scss | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/redisinsight/ui/src/pages/pub-sub/components/subscription-panel/components/clickable-append-info/ClickableAppendInfo.tsx b/redisinsight/ui/src/pages/pub-sub/components/subscription-panel/components/clickable-append-info/ClickableAppendInfo.tsx index 954948e489..921467da76 100644 --- a/redisinsight/ui/src/pages/pub-sub/components/subscription-panel/components/clickable-append-info/ClickableAppendInfo.tsx +++ b/redisinsight/ui/src/pages/pub-sub/components/subscription-panel/components/clickable-append-info/ClickableAppendInfo.tsx @@ -26,6 +26,7 @@ const ClickableAppendInfo = () => { /> )} isOpen={open} + closePopover={() => setOpen(false)} panelClassName={styles.popover} anchorClassName={styles.infoIcon} panelPaddingSize="s" @@ -35,6 +36,8 @@ const ClickableAppendInfo = () => { color="subdued" size="s" > + Subscribe to one or more channels or patterns by entering them, separated by spaces. +
Supported glob-style patterns are described  Date: Wed, 9 Oct 2024 18:23:26 +0300 Subject: [PATCH 133/256] RI-6186 The first item can't be removed --- .../browser/components/add-key/AddKeyList/AddKeyList.tsx | 4 +++- .../list-details/add-list-elements/AddListElements.tsx | 9 +++++++-- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/redisinsight/ui/src/pages/browser/components/add-key/AddKeyList/AddKeyList.tsx b/redisinsight/ui/src/pages/browser/components/add-key/AddKeyList/AddKeyList.tsx index 9fbc3c61ad..f0365b33ec 100644 --- a/redisinsight/ui/src/pages/browser/components/add-key/AddKeyList/AddKeyList.tsx +++ b/redisinsight/ui/src/pages/browser/components/add-key/AddKeyList/AddKeyList.tsx @@ -47,9 +47,11 @@ const AddKeyList = (props: Props) => { submitData() } } + const addField = () => { setElements([...elements, '']) } + const onClickRemove = (_item: string, index?: number) => { if (elements.length === 1) { setElements(['']) @@ -58,7 +60,7 @@ const AddKeyList = (props: Props) => { } } - const isClearDisabled = (element:string, index?: number) => index === 0 && !element.length + const isClearDisabled = (element:string) => elements.length === 1 && !element.length const handleElementChange = (value: string, index: number) => { const newElements = [...elements] diff --git a/redisinsight/ui/src/pages/browser/modules/key-details/components/list-details/add-list-elements/AddListElements.tsx b/redisinsight/ui/src/pages/browser/modules/key-details/components/list-details/add-list-elements/AddListElements.tsx index 8e352871ba..3be07f1f84 100644 --- a/redisinsight/ui/src/pages/browser/modules/key-details/components/list-details/add-list-elements/AddListElements.tsx +++ b/redisinsight/ui/src/pages/browser/modules/key-details/components/list-details/add-list-elements/AddListElements.tsx @@ -84,11 +84,16 @@ const AddListElements = (props: Props) => { const addField = () => { setElements([...elements, '']) } + const onClickRemove = (_item: string, index?: number) => { - setElements(elements.filter((_el, i) => i !== index)) + if (elements.length === 1) { + setElements(['']) + } else { + setElements(elements.filter((_el, i) => i !== index)) + } } - const isClearDisabled = (_element:string, index?: number) => index === 0 + const isClearDisabled = (element:string) => elements.length === 1 && !element.length const handleElementChange = (value: string, index: number) => { const newElements = [...elements] From 41df850833c628d33a502774bfe74064c4463ad8 Mon Sep 17 00:00:00 2001 From: Kristiyan Ivanov Date: Wed, 9 Oct 2024 18:45:06 +0300 Subject: [PATCH 134/256] RI-6186 The first item can't be removed --- .../pages/browser/components/add-key/AddKeyList/AddKeyList.tsx | 2 +- .../list-details/add-list-elements/AddListElements.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/redisinsight/ui/src/pages/browser/components/add-key/AddKeyList/AddKeyList.tsx b/redisinsight/ui/src/pages/browser/components/add-key/AddKeyList/AddKeyList.tsx index f0365b33ec..086d492ef1 100644 --- a/redisinsight/ui/src/pages/browser/components/add-key/AddKeyList/AddKeyList.tsx +++ b/redisinsight/ui/src/pages/browser/components/add-key/AddKeyList/AddKeyList.tsx @@ -60,7 +60,7 @@ const AddKeyList = (props: Props) => { } } - const isClearDisabled = (element:string) => elements.length === 1 && !element.length + const isClearDisabled = (item:string) => elements.length === 1 && !item.length const handleElementChange = (value: string, index: number) => { const newElements = [...elements] diff --git a/redisinsight/ui/src/pages/browser/modules/key-details/components/list-details/add-list-elements/AddListElements.tsx b/redisinsight/ui/src/pages/browser/modules/key-details/components/list-details/add-list-elements/AddListElements.tsx index 3be07f1f84..b0d2b07ca1 100644 --- a/redisinsight/ui/src/pages/browser/modules/key-details/components/list-details/add-list-elements/AddListElements.tsx +++ b/redisinsight/ui/src/pages/browser/modules/key-details/components/list-details/add-list-elements/AddListElements.tsx @@ -93,7 +93,7 @@ const AddListElements = (props: Props) => { } } - const isClearDisabled = (element:string) => elements.length === 1 && !element.length + const isClearDisabled = (item:string) => elements.length === 1 && !item.length const handleElementChange = (value: string, index: number) => { const newElements = [...elements] From 40624f4f44dd90b2a456f4a843d29399f3a09daf Mon Sep 17 00:00:00 2001 From: kchepikava Date: Wed, 9 Oct 2024 21:15:49 +0200 Subject: [PATCH 135/256] RI-6153 renamed and added tooltips to dry-run panel tabs --- .../components/jobs-panel/Panel.tsx | 29 +++++++++++++++---- .../components/jobs-panel/styles.module.scss | 2 +- 2 files changed, 25 insertions(+), 6 deletions(-) diff --git a/redisinsight/ui/src/pages/rdi/pipeline-management/components/jobs-panel/Panel.tsx b/redisinsight/ui/src/pages/rdi/pipeline-management/components/jobs-panel/Panel.tsx index 0b5bde9cec..6835c5c972 100644 --- a/redisinsight/ui/src/pages/rdi/pipeline-management/components/jobs-panel/Panel.tsx +++ b/redisinsight/ui/src/pages/rdi/pipeline-management/components/jobs-panel/Panel.tsx @@ -144,7 +144,18 @@ const DryRunJobPanel = (props: Props) => { className={styles.tab} data-testid="transformations-tab" > - Transformations + + Displays the results of the transformations you defined. The data is presented in JSON format. +
+ No data is written to the target database. + + )} + data-testid="transformation-output-tooltip" + > + Transformation output +
{ className={styles.tab} data-testid="output-tab" > - <> - Output - + + Displays the list of Redis commands that will be generated based on your job details. +
+ No data is written to the target database. + + )} + data-testid="job-output-tooltip" + > + Job output +
), [selectedTab, isFullScreen]) @@ -223,7 +243,6 @@ const DryRunJobPanel = (props: Props) => {
- Results {isSelectAvailable && ( Date: Thu, 10 Oct 2024 09:48:58 +0300 Subject: [PATCH 136/256] fix plugins deps --- .../ui/src/packages/clients-list/package.json | 8 +- .../ui/src/packages/clients-list/yarn.lock | 1254 ++++++------ .../ui/src/packages/redisearch/package.json | 2 + .../ui/src/packages/redisearch/yarn.lock | 28 +- .../ui/src/packages/redisgraph/package.json | 2 + .../ui/src/packages/redisgraph/yarn.lock | 28 +- .../packages/redistimeseries-app/package.json | 7 +- .../packages/redistimeseries-app/yarn.lock | 1741 ++++++++--------- .../ui/src/packages/ri-explain/package.json | 2 + .../ui/src/packages/ri-explain/yarn.lock | 28 +- 10 files changed, 1578 insertions(+), 1522 deletions(-) diff --git a/redisinsight/ui/src/packages/clients-list/package.json b/redisinsight/ui/src/packages/clients-list/package.json index 2b0517fae2..a5c7635e61 100644 --- a/redisinsight/ui/src/packages/clients-list/package.json +++ b/redisinsight/ui/src/packages/clients-list/package.json @@ -69,14 +69,15 @@ ], "devDependencies": { "@babel/core": "^7.12.0", - "@parcel/transformer-sass": "2.8.3", + "@parcel/transformer-sass": "^2.12.0", "@types/json-bigint": "^1.0.1", "@types/node": "^17.0.21", "@types/react": "^17.0.40", "@types/react-dom": "^17.0.13", "concurrently": "^7.6.0", "cross-env": "^7.0.3", - "parcel": "2.8.3", + "parcel": "^2.12.0", + "process": "^0.11.10", "rimraf": "^3.0.2", "terser": "^5.16.6", "typescript": ">=3.0.0" @@ -88,12 +89,13 @@ "classnames": "^2.3.1", "json-bigint": "^1.0.0", "lodash": "^4.17.21", - "moment": "^2.29.1", "react": "^17.0.2", "react-dom": "^17.0.2", "redisinsight-plugin-sdk": "^1.1.0" }, "resolutions": { + "@parcel/**/micromatch": "^4.0.8", + "@parcel/**/braces": "^3.0.3", "trim": "0.0.3", "**/semver": "^7.5.2" } diff --git a/redisinsight/ui/src/packages/clients-list/yarn.lock b/redisinsight/ui/src/packages/clients-list/yarn.lock index 1fad35c726..352bac1755 100644 --- a/redisinsight/ui/src/packages/clients-list/yarn.lock +++ b/redisinsight/ui/src/packages/clients-list/yarn.lock @@ -296,14 +296,6 @@ "@jridgewell/gen-mapping" "^0.3.0" "@jridgewell/trace-mapping" "^0.3.9" -"@jridgewell/source-map@^0.3.3": - version "0.3.5" - resolved "https://registry.yarnpkg.com/@jridgewell/source-map/-/source-map-0.3.5.tgz#a3bb4d5c6825aab0d281268f47f6ad5853431e91" - integrity sha512-UTYAUj/wviwdsMfzoSJspJxbkH5o1snzwX0//0ENX1u/55kkZZkcTZP6u9bwKGkv+dkk9at4m1Cpt0uY80kcpQ== - dependencies: - "@jridgewell/gen-mapping" "^0.3.0" - "@jridgewell/trace-mapping" "^0.3.9" - "@jridgewell/sourcemap-codec@1.4.14": version "1.4.14" resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz#add4c98d341472a289190b424efbdb096991bb24" @@ -342,35 +334,35 @@ dependencies: "@lezer/common" "^1.0.0" -"@lmdb/lmdb-darwin-arm64@2.5.2": - version "2.5.2" - resolved "https://registry.yarnpkg.com/@lmdb/lmdb-darwin-arm64/-/lmdb-darwin-arm64-2.5.2.tgz#bc66fa43286b5c082e8fee0eacc17995806b6fbe" - integrity sha512-+F8ioQIUN68B4UFiIBYu0QQvgb9FmlKw2ctQMSBfW2QBrZIxz9vD9jCGqTCPqZBRbPHAS/vG1zSXnKqnS2ch/A== +"@lmdb/lmdb-darwin-arm64@2.8.5": + version "2.8.5" + resolved "https://registry.yarnpkg.com/@lmdb/lmdb-darwin-arm64/-/lmdb-darwin-arm64-2.8.5.tgz#895d8cb16a9d709ce5fedd8b60022903b875e08e" + integrity sha512-KPDeVScZgA1oq0CiPBcOa3kHIqU+pTOwRFDIhxvmf8CTNvqdZQYp5cCKW0bUk69VygB2PuTiINFWbY78aR2pQw== -"@lmdb/lmdb-darwin-x64@2.5.2": - version "2.5.2" - resolved "https://registry.yarnpkg.com/@lmdb/lmdb-darwin-x64/-/lmdb-darwin-x64-2.5.2.tgz#89d8390041bce6bab24a82a20392be22faf54ffc" - integrity sha512-KvPH56KRLLx4KSfKBx0m1r7GGGUMXm0jrKmNE7plbHlesZMuPJICtn07HYgQhj1LNsK7Yqwuvnqh1QxhJnF1EA== +"@lmdb/lmdb-darwin-x64@2.8.5": + version "2.8.5" + resolved "https://registry.yarnpkg.com/@lmdb/lmdb-darwin-x64/-/lmdb-darwin-x64-2.8.5.tgz#ca243534c8b37d5516c557e4624256d18dd63184" + integrity sha512-w/sLhN4T7MW1nB3R/U8WK5BgQLz904wh+/SmA2jD8NnF7BLLoUgflCNxOeSPOWp8geP6nP/+VjWzZVip7rZ1ug== -"@lmdb/lmdb-linux-arm64@2.5.2": - version "2.5.2" - resolved "https://registry.yarnpkg.com/@lmdb/lmdb-linux-arm64/-/lmdb-linux-arm64-2.5.2.tgz#14fe4c96c2bb1285f93797f45915fa35ee047268" - integrity sha512-aLl89VHL/wjhievEOlPocoefUyWdvzVrcQ/MHQYZm2JfV1jUsrbr/ZfkPPUFvZBf+VSE+Q0clWs9l29PCX1hTQ== +"@lmdb/lmdb-linux-arm64@2.8.5": + version "2.8.5" + resolved "https://registry.yarnpkg.com/@lmdb/lmdb-linux-arm64/-/lmdb-linux-arm64-2.8.5.tgz#b44a8023057e21512eefb9f6120096843b531c1e" + integrity sha512-vtbZRHH5UDlL01TT5jB576Zox3+hdyogvpcbvVJlmU5PdL3c5V7cj1EODdh1CHPksRl+cws/58ugEHi8bcj4Ww== -"@lmdb/lmdb-linux-arm@2.5.2": - version "2.5.2" - resolved "https://registry.yarnpkg.com/@lmdb/lmdb-linux-arm/-/lmdb-linux-arm-2.5.2.tgz#05bde4573ab10cf21827339fe687148f2590cfa1" - integrity sha512-5kQAP21hAkfW5Bl+e0P57dV4dGYnkNIpR7f/GAh6QHlgXx+vp/teVj4PGRZaKAvt0GX6++N6hF8NnGElLDuIDw== +"@lmdb/lmdb-linux-arm@2.8.5": + version "2.8.5" + resolved "https://registry.yarnpkg.com/@lmdb/lmdb-linux-arm/-/lmdb-linux-arm-2.8.5.tgz#17bd54740779c3e4324e78e8f747c21416a84b3d" + integrity sha512-c0TGMbm2M55pwTDIfkDLB6BpIsgxV4PjYck2HiOX+cy/JWiBXz32lYbarPqejKs9Flm7YVAKSILUducU9g2RVg== -"@lmdb/lmdb-linux-x64@2.5.2": - version "2.5.2" - resolved "https://registry.yarnpkg.com/@lmdb/lmdb-linux-x64/-/lmdb-linux-x64-2.5.2.tgz#d2f85afd857d2c33d2caa5b057944574edafcfee" - integrity sha512-xUdUfwDJLGjOUPH3BuPBt0NlIrR7f/QHKgu3GZIXswMMIihAekj2i97oI0iWG5Bok/b+OBjHPfa8IU9velnP/Q== +"@lmdb/lmdb-linux-x64@2.8.5": + version "2.8.5" + resolved "https://registry.yarnpkg.com/@lmdb/lmdb-linux-x64/-/lmdb-linux-x64-2.8.5.tgz#6c61835b6cc58efdf79dbd5e8c72a38300a90302" + integrity sha512-Xkc8IUx9aEhP0zvgeKy7IQ3ReX2N8N1L0WPcQwnZweWmOuKfwpS3GRIYqLtK5za/w3E60zhFfNdS+3pBZPytqQ== -"@lmdb/lmdb-win32-x64@2.5.2": - version "2.5.2" - resolved "https://registry.yarnpkg.com/@lmdb/lmdb-win32-x64/-/lmdb-win32-x64-2.5.2.tgz#28f643fbc0bec30b07fbe95b137879b6b4d1c9c5" - integrity sha512-zrBczSbXKxEyK2ijtbRdICDygRqWSRPpZMN5dD1T8VMEW5RIhIbwFWw2phDRXuBQdVDpSjalCIUMWMV2h3JaZA== +"@lmdb/lmdb-win32-x64@2.8.5": + version "2.8.5" + resolved "https://registry.yarnpkg.com/@lmdb/lmdb-win32-x64/-/lmdb-win32-x64-2.8.5.tgz#8233e8762440b0f4632c47a09b1b6f23de8b934c" + integrity sha512-4wvrf5BgnR8RpogHhtpCPJMKBmvyZPhhUtEwMJbXh0ni2BucpfF07jlmyM11zRqQ2XIq6PbC2j7W7UCCcm1rRQ== "@mapbox/hast-util-table-cell-style@^0.2.0": version "0.2.0" @@ -418,97 +410,99 @@ resolved "https://registry.yarnpkg.com/@msgpackr-extract/msgpackr-extract-win32-x64/-/msgpackr-extract-win32-x64-3.0.2.tgz#0f164b726869f71da3c594171df5ebc1c4b0a407" integrity sha512-O+6Gs8UeDbyFpbSh2CPEz/UOrrdWPTBYNblZK5CxxLisYt4kGX3Sc+czffFonyjiGSq3jWLwJS/CCJc7tBr4sQ== -"@parcel/bundler-default@2.8.3": - version "2.8.3" - resolved "https://registry.yarnpkg.com/@parcel/bundler-default/-/bundler-default-2.8.3.tgz#d64739dbc2dbd59d6629861bf77a8083aced5229" - integrity sha512-yJvRsNWWu5fVydsWk3O2L4yIy3UZiKWO2cPDukGOIWMgp/Vbpp+2Ct5IygVRtE22bnseW/E/oe0PV3d2IkEJGg== +"@parcel/bundler-default@2.12.0": + version "2.12.0" + resolved "https://registry.yarnpkg.com/@parcel/bundler-default/-/bundler-default-2.12.0.tgz#b8f6f3fc3f497714bd54e19882aaa116e97df4a4" + integrity sha512-3ybN74oYNMKyjD6V20c9Gerdbh7teeNvVMwIoHIQMzuIFT6IGX53PyOLlOKRLbjxMc0TMimQQxIt2eQqxR5LsA== dependencies: - "@parcel/diagnostic" "2.8.3" - "@parcel/graph" "2.8.3" - "@parcel/hash" "2.8.3" - "@parcel/plugin" "2.8.3" - "@parcel/utils" "2.8.3" + "@parcel/diagnostic" "2.12.0" + "@parcel/graph" "3.2.0" + "@parcel/plugin" "2.12.0" + "@parcel/rust" "2.12.0" + "@parcel/utils" "2.12.0" nullthrows "^1.1.1" -"@parcel/cache@2.8.3": - version "2.8.3" - resolved "https://registry.yarnpkg.com/@parcel/cache/-/cache-2.8.3.tgz#169e130cf59913c0ed9fadce1a450e68f710e16f" - integrity sha512-k7xv5vSQrJLdXuglo+Hv3yF4BCSs1tQ/8Vbd6CHTkOhf7LcGg6CPtLw053R/KdMpd/4GPn0QrAsOLdATm1ELtQ== +"@parcel/cache@2.12.0": + version "2.12.0" + resolved "https://registry.yarnpkg.com/@parcel/cache/-/cache-2.12.0.tgz#b8fd2ea2bc7a2353a9b20344cc191bfb4f8284f3" + integrity sha512-FX5ZpTEkxvq/yvWklRHDESVRz+c7sLTXgFuzz6uEnBcXV38j6dMSikflNpHA6q/L4GKkCqRywm9R6XQwhwIMyw== dependencies: - "@parcel/fs" "2.8.3" - "@parcel/logger" "2.8.3" - "@parcel/utils" "2.8.3" - lmdb "2.5.2" + "@parcel/fs" "2.12.0" + "@parcel/logger" "2.12.0" + "@parcel/utils" "2.12.0" + lmdb "2.8.5" -"@parcel/codeframe@2.8.3": - version "2.8.3" - resolved "https://registry.yarnpkg.com/@parcel/codeframe/-/codeframe-2.8.3.tgz#84fb529ef70def7f5bc64f6c59b18d24826f5fcc" - integrity sha512-FE7sY53D6n/+2Pgg6M9iuEC6F5fvmyBkRE4d9VdnOoxhTXtkEqpqYgX7RJ12FAQwNlxKq4suBJQMgQHMF2Kjeg== +"@parcel/codeframe@2.12.0": + version "2.12.0" + resolved "https://registry.yarnpkg.com/@parcel/codeframe/-/codeframe-2.12.0.tgz#9ea75bd7ae6c5f7fadf42a5e64657cf88fdcb29e" + integrity sha512-v2VmneILFiHZJTxPiR7GEF1wey1/IXPdZMcUlNXBiPZyWDfcuNgGGVQkx/xW561rULLIvDPharOMdxz5oHOKQg== dependencies: chalk "^4.1.0" -"@parcel/compressor-raw@2.8.3": - version "2.8.3" - resolved "https://registry.yarnpkg.com/@parcel/compressor-raw/-/compressor-raw-2.8.3.tgz#301753df8c6de967553149639e8a4179b88f0c95" - integrity sha512-bVDsqleBUxRdKMakWSlWC9ZjOcqDKE60BE+Gh3JSN6WJrycJ02P5wxjTVF4CStNP/G7X17U+nkENxSlMG77ySg== - dependencies: - "@parcel/plugin" "2.8.3" - -"@parcel/config-default@2.8.3": - version "2.8.3" - resolved "https://registry.yarnpkg.com/@parcel/config-default/-/config-default-2.8.3.tgz#9a43486e7c702e96c68052c37b79098d7240e35b" - integrity sha512-o/A/mbrO6X/BfGS65Sib8d6SSG45NYrNooNBkH/o7zbOBSRQxwyTlysleK1/3Wa35YpvFyLOwgfakqCtbGy4fw== - dependencies: - "@parcel/bundler-default" "2.8.3" - "@parcel/compressor-raw" "2.8.3" - "@parcel/namer-default" "2.8.3" - "@parcel/optimizer-css" "2.8.3" - "@parcel/optimizer-htmlnano" "2.8.3" - "@parcel/optimizer-image" "2.8.3" - "@parcel/optimizer-svgo" "2.8.3" - "@parcel/optimizer-terser" "2.8.3" - "@parcel/packager-css" "2.8.3" - "@parcel/packager-html" "2.8.3" - "@parcel/packager-js" "2.8.3" - "@parcel/packager-raw" "2.8.3" - "@parcel/packager-svg" "2.8.3" - "@parcel/reporter-dev-server" "2.8.3" - "@parcel/resolver-default" "2.8.3" - "@parcel/runtime-browser-hmr" "2.8.3" - "@parcel/runtime-js" "2.8.3" - "@parcel/runtime-react-refresh" "2.8.3" - "@parcel/runtime-service-worker" "2.8.3" - "@parcel/transformer-babel" "2.8.3" - "@parcel/transformer-css" "2.8.3" - "@parcel/transformer-html" "2.8.3" - "@parcel/transformer-image" "2.8.3" - "@parcel/transformer-js" "2.8.3" - "@parcel/transformer-json" "2.8.3" - "@parcel/transformer-postcss" "2.8.3" - "@parcel/transformer-posthtml" "2.8.3" - "@parcel/transformer-raw" "2.8.3" - "@parcel/transformer-react-refresh-wrap" "2.8.3" - "@parcel/transformer-svg" "2.8.3" - -"@parcel/core@2.8.3": - version "2.8.3" - resolved "https://registry.yarnpkg.com/@parcel/core/-/core-2.8.3.tgz#22a69f36095d53736ab10bf42697d9aa5f4e382b" - integrity sha512-Euf/un4ZAiClnlUXqPB9phQlKbveU+2CotZv7m7i+qkgvFn5nAGnrV4h1OzQU42j9dpgOxWi7AttUDMrvkbhCQ== +"@parcel/compressor-raw@2.12.0": + version "2.12.0" + resolved "https://registry.yarnpkg.com/@parcel/compressor-raw/-/compressor-raw-2.12.0.tgz#71012b695c870f1d26bfd8d56983c14bf13fd996" + integrity sha512-h41Q3X7ZAQ9wbQ2csP8QGrwepasLZdXiuEdpUryDce6rF9ZiHoJ97MRpdLxOhOPyASTw/xDgE1xyaPQr0Q3f5A== + dependencies: + "@parcel/plugin" "2.12.0" + +"@parcel/config-default@2.12.0": + version "2.12.0" + resolved "https://registry.yarnpkg.com/@parcel/config-default/-/config-default-2.12.0.tgz#7b213348db349c6042a80dfd4a7eab707a1dfbfa" + integrity sha512-dPNe2n9eEsKRc1soWIY0yToMUPirPIa2QhxcCB3Z5RjpDGIXm0pds+BaiqY6uGLEEzsjhRO0ujd4v2Rmm0vuFg== + dependencies: + "@parcel/bundler-default" "2.12.0" + "@parcel/compressor-raw" "2.12.0" + "@parcel/namer-default" "2.12.0" + "@parcel/optimizer-css" "2.12.0" + "@parcel/optimizer-htmlnano" "2.12.0" + "@parcel/optimizer-image" "2.12.0" + "@parcel/optimizer-svgo" "2.12.0" + "@parcel/optimizer-swc" "2.12.0" + "@parcel/packager-css" "2.12.0" + "@parcel/packager-html" "2.12.0" + "@parcel/packager-js" "2.12.0" + "@parcel/packager-raw" "2.12.0" + "@parcel/packager-svg" "2.12.0" + "@parcel/packager-wasm" "2.12.0" + "@parcel/reporter-dev-server" "2.12.0" + "@parcel/resolver-default" "2.12.0" + "@parcel/runtime-browser-hmr" "2.12.0" + "@parcel/runtime-js" "2.12.0" + "@parcel/runtime-react-refresh" "2.12.0" + "@parcel/runtime-service-worker" "2.12.0" + "@parcel/transformer-babel" "2.12.0" + "@parcel/transformer-css" "2.12.0" + "@parcel/transformer-html" "2.12.0" + "@parcel/transformer-image" "2.12.0" + "@parcel/transformer-js" "2.12.0" + "@parcel/transformer-json" "2.12.0" + "@parcel/transformer-postcss" "2.12.0" + "@parcel/transformer-posthtml" "2.12.0" + "@parcel/transformer-raw" "2.12.0" + "@parcel/transformer-react-refresh-wrap" "2.12.0" + "@parcel/transformer-svg" "2.12.0" + +"@parcel/core@2.12.0": + version "2.12.0" + resolved "https://registry.yarnpkg.com/@parcel/core/-/core-2.12.0.tgz#ea5734f008300bc57aaff2ba0f7949724c93b56d" + integrity sha512-s+6pwEj+GfKf7vqGUzN9iSEPueUssCCQrCBUlcAfKrJe0a22hTUCjewpB0I7lNrCIULt8dkndD+sMdOrXsRl6Q== dependencies: "@mischnic/json-sourcemap" "^0.1.0" - "@parcel/cache" "2.8.3" - "@parcel/diagnostic" "2.8.3" - "@parcel/events" "2.8.3" - "@parcel/fs" "2.8.3" - "@parcel/graph" "2.8.3" - "@parcel/hash" "2.8.3" - "@parcel/logger" "2.8.3" - "@parcel/package-manager" "2.8.3" - "@parcel/plugin" "2.8.3" + "@parcel/cache" "2.12.0" + "@parcel/diagnostic" "2.12.0" + "@parcel/events" "2.12.0" + "@parcel/fs" "2.12.0" + "@parcel/graph" "3.2.0" + "@parcel/logger" "2.12.0" + "@parcel/package-manager" "2.12.0" + "@parcel/plugin" "2.12.0" + "@parcel/profiler" "2.12.0" + "@parcel/rust" "2.12.0" "@parcel/source-map" "^2.1.1" - "@parcel/types" "2.8.3" - "@parcel/utils" "2.8.3" - "@parcel/workers" "2.8.3" + "@parcel/types" "2.12.0" + "@parcel/utils" "2.12.0" + "@parcel/workers" "2.12.0" abortcontroller-polyfill "^1.1.9" base-x "^3.0.8" browserslist "^4.6.6" @@ -516,281 +510,306 @@ dotenv "^7.0.0" dotenv-expand "^5.1.0" json5 "^2.2.0" - msgpackr "^1.5.4" + msgpackr "^1.9.9" nullthrows "^1.1.1" - semver "^5.7.1" + semver "^7.5.2" -"@parcel/diagnostic@2.8.3": - version "2.8.3" - resolved "https://registry.yarnpkg.com/@parcel/diagnostic/-/diagnostic-2.8.3.tgz#d560276d5d2804b48beafa1feaf3fc6b2ac5e39d" - integrity sha512-u7wSzuMhLGWZjVNYJZq/SOViS3uFG0xwIcqXw12w54Uozd6BH8JlhVtVyAsq9kqnn7YFkw6pXHqAo5Tzh4FqsQ== +"@parcel/diagnostic@2.12.0": + version "2.12.0" + resolved "https://registry.yarnpkg.com/@parcel/diagnostic/-/diagnostic-2.12.0.tgz#b38057d819ea2edc32018a1d51df434f07840be9" + integrity sha512-8f1NOsSFK+F4AwFCKynyIu9Kr/uWHC+SywAv4oS6Bv3Acig0gtwUjugk0C9UaB8ztBZiW5TQZhw+uPZn9T/lJA== dependencies: "@mischnic/json-sourcemap" "^0.1.0" nullthrows "^1.1.1" -"@parcel/events@2.8.3": - version "2.8.3" - resolved "https://registry.yarnpkg.com/@parcel/events/-/events-2.8.3.tgz#205f8d874e6ecc2cbdb941bf8d54bae669e571af" - integrity sha512-hoIS4tAxWp8FJk3628bsgKxEvR7bq2scCVYHSqZ4fTi/s0+VymEATrRCUqf+12e5H47uw1/ZjoqrGtBI02pz4w== - -"@parcel/fs-search@2.8.3": - version "2.8.3" - resolved "https://registry.yarnpkg.com/@parcel/fs-search/-/fs-search-2.8.3.tgz#1c7d812c110b808758f44c56e61dfffdb09e9451" - integrity sha512-DJBT2N8knfN7Na6PP2mett3spQLTqxFrvl0gv+TJRp61T8Ljc4VuUTb0hqBj+belaASIp3Q+e8+SgaFQu7wLiQ== - dependencies: - detect-libc "^1.0.3" +"@parcel/events@2.12.0": + version "2.12.0" + resolved "https://registry.yarnpkg.com/@parcel/events/-/events-2.12.0.tgz#ef67e3fbb96806b3531a37bcf95e8fbb3818ffa2" + integrity sha512-nmAAEIKLjW1kB2cUbCYSmZOGbnGj8wCzhqnK727zCCWaA25ogzAtt657GPOeFyqW77KyosU728Tl63Fc8hphIA== -"@parcel/fs@2.8.3": - version "2.8.3" - resolved "https://registry.yarnpkg.com/@parcel/fs/-/fs-2.8.3.tgz#80536afe877fc8a2bd26be5576b9ba27bb4c5754" - integrity sha512-y+i+oXbT7lP0e0pJZi/YSm1vg0LDsbycFuHZIL80pNwdEppUAtibfJZCp606B7HOjMAlNZOBo48e3hPG3d8jgQ== +"@parcel/fs@2.12.0": + version "2.12.0" + resolved "https://registry.yarnpkg.com/@parcel/fs/-/fs-2.12.0.tgz#8c9029353888311ba2e9e2198dbe6c7c1da635c0" + integrity sha512-NnFkuvou1YBtPOhTdZr44WN7I60cGyly2wpHzqRl62yhObyi1KvW0SjwOMa0QGNcBOIzp4G0CapoZ93hD0RG5Q== dependencies: - "@parcel/fs-search" "2.8.3" - "@parcel/types" "2.8.3" - "@parcel/utils" "2.8.3" + "@parcel/rust" "2.12.0" + "@parcel/types" "2.12.0" + "@parcel/utils" "2.12.0" "@parcel/watcher" "^2.0.7" - "@parcel/workers" "2.8.3" + "@parcel/workers" "2.12.0" -"@parcel/graph@2.8.3": - version "2.8.3" - resolved "https://registry.yarnpkg.com/@parcel/graph/-/graph-2.8.3.tgz#00ffe8ec032e74fee57199e54529f1da7322571d" - integrity sha512-26GL8fYZPdsRhSXCZ0ZWliloK6DHlMJPWh6Z+3VVZ5mnDSbYg/rRKWmrkhnr99ZWmL9rJsv4G74ZwvDEXTMPBg== +"@parcel/graph@3.2.0": + version "3.2.0" + resolved "https://registry.yarnpkg.com/@parcel/graph/-/graph-3.2.0.tgz#309e6e3f19ef4ea7f71b2341ec1bcc08e7c43523" + integrity sha512-xlrmCPqy58D4Fg5umV7bpwDx5Vyt7MlnQPxW68vae5+BA4GSWetfZt+Cs5dtotMG2oCHzZxhIPt7YZ7NRyQzLA== dependencies: nullthrows "^1.1.1" -"@parcel/hash@2.8.3": - version "2.8.3" - resolved "https://registry.yarnpkg.com/@parcel/hash/-/hash-2.8.3.tgz#bc2499a27395169616cad2a99e19e69b9098f6e9" - integrity sha512-FVItqzjWmnyP4ZsVgX+G00+6U2IzOvqDtdwQIWisCcVoXJFCqZJDy6oa2qDDFz96xCCCynjRjPdQx2jYBCpfYw== - dependencies: - detect-libc "^1.0.3" - xxhash-wasm "^0.4.2" - -"@parcel/logger@2.8.3": - version "2.8.3" - resolved "https://registry.yarnpkg.com/@parcel/logger/-/logger-2.8.3.tgz#e14e4debafb3ca9e87c07c06780f9afc38b2712c" - integrity sha512-Kpxd3O/Vs7nYJIzkdmB6Bvp3l/85ydIxaZaPfGSGTYOfaffSOTkhcW9l6WemsxUrlts4za6CaEWcc4DOvaMOPA== +"@parcel/logger@2.12.0": + version "2.12.0" + resolved "https://registry.yarnpkg.com/@parcel/logger/-/logger-2.12.0.tgz#0b866b7aee8a0a462596a80cd46bd8b29c318758" + integrity sha512-cJ7Paqa7/9VJ7C+KwgJlwMqTQBOjjn71FbKk0G07hydUEBISU2aDfmc/52o60ErL9l+vXB26zTrIBanbxS8rVg== dependencies: - "@parcel/diagnostic" "2.8.3" - "@parcel/events" "2.8.3" + "@parcel/diagnostic" "2.12.0" + "@parcel/events" "2.12.0" -"@parcel/markdown-ansi@2.8.3": - version "2.8.3" - resolved "https://registry.yarnpkg.com/@parcel/markdown-ansi/-/markdown-ansi-2.8.3.tgz#1337d421bb1133ad178f386a8e1b746631bba4a1" - integrity sha512-4v+pjyoh9f5zuU/gJlNvNFGEAb6J90sOBwpKJYJhdWXLZMNFCVzSigxrYO+vCsi8G4rl6/B2c0LcwIMjGPHmFQ== +"@parcel/markdown-ansi@2.12.0": + version "2.12.0" + resolved "https://registry.yarnpkg.com/@parcel/markdown-ansi/-/markdown-ansi-2.12.0.tgz#a4301321fa784a28ba817e65e41432fe8b3b3192" + integrity sha512-WZz3rzL8k0H3WR4qTHX6Ic8DlEs17keO9gtD4MNGyMNQbqQEvQ61lWJaIH0nAtgEetu0SOITiVqdZrb8zx/M7w== dependencies: chalk "^4.1.0" -"@parcel/namer-default@2.8.3": - version "2.8.3" - resolved "https://registry.yarnpkg.com/@parcel/namer-default/-/namer-default-2.8.3.tgz#5304bee74beb4b9c1880781bdbe35be0656372f4" - integrity sha512-tJ7JehZviS5QwnxbARd8Uh63rkikZdZs1QOyivUhEvhN+DddSAVEdQLHGPzkl3YRk0tjFhbqo+Jci7TpezuAMw== +"@parcel/namer-default@2.12.0": + version "2.12.0" + resolved "https://registry.yarnpkg.com/@parcel/namer-default/-/namer-default-2.12.0.tgz#f9903da8e4c5c3e33fc8ab70b222be520a46da5d" + integrity sha512-9DNKPDHWgMnMtqqZIMiEj/R9PNWW16lpnlHjwK3ciRlMPgjPJ8+UNc255teZODhX0T17GOzPdGbU/O/xbxVPzA== dependencies: - "@parcel/diagnostic" "2.8.3" - "@parcel/plugin" "2.8.3" + "@parcel/diagnostic" "2.12.0" + "@parcel/plugin" "2.12.0" nullthrows "^1.1.1" -"@parcel/node-resolver-core@2.8.3": - version "2.8.3" - resolved "https://registry.yarnpkg.com/@parcel/node-resolver-core/-/node-resolver-core-2.8.3.tgz#581df074a27646400b3fed9da95297b616a7db8f" - integrity sha512-12YryWcA5Iw2WNoEVr/t2HDjYR1iEzbjEcxfh1vaVDdZ020PiGw67g5hyIE/tsnG7SRJ0xdRx1fQ2hDgED+0Ww== +"@parcel/node-resolver-core@3.3.0": + version "3.3.0" + resolved "https://registry.yarnpkg.com/@parcel/node-resolver-core/-/node-resolver-core-3.3.0.tgz#f40d80de800baa7cf230406b7122c8711ac4cdc8" + integrity sha512-rhPW9DYPEIqQBSlYzz3S0AjXxjN6Ub2yS6tzzsW/4S3Gpsgk/uEq4ZfxPvoPf/6TgZndVxmKwpmxaKtGMmf3cA== dependencies: - "@parcel/diagnostic" "2.8.3" - "@parcel/utils" "2.8.3" + "@mischnic/json-sourcemap" "^0.1.0" + "@parcel/diagnostic" "2.12.0" + "@parcel/fs" "2.12.0" + "@parcel/rust" "2.12.0" + "@parcel/utils" "2.12.0" nullthrows "^1.1.1" - semver "^5.7.1" + semver "^7.5.2" -"@parcel/optimizer-css@2.8.3": - version "2.8.3" - resolved "https://registry.yarnpkg.com/@parcel/optimizer-css/-/optimizer-css-2.8.3.tgz#420a333f4b78f7ff15e69217dfed34421b1143ee" - integrity sha512-JotGAWo8JhuXsQDK0UkzeQB0UR5hDAKvAviXrjqB4KM9wZNLhLleeEAW4Hk8R9smCeQFP6Xg/N/NkLDpqMwT3g== +"@parcel/optimizer-css@2.12.0": + version "2.12.0" + resolved "https://registry.yarnpkg.com/@parcel/optimizer-css/-/optimizer-css-2.12.0.tgz#f44f38dc7136b511a849343eea04714a42e1ba5f" + integrity sha512-ifbcC97fRzpruTjaa8axIFeX4MjjSIlQfem3EJug3L2AVqQUXnM1XO8L0NaXGNLTW2qnh1ZjIJ7vXT/QhsphsA== dependencies: - "@parcel/diagnostic" "2.8.3" - "@parcel/plugin" "2.8.3" + "@parcel/diagnostic" "2.12.0" + "@parcel/plugin" "2.12.0" "@parcel/source-map" "^2.1.1" - "@parcel/utils" "2.8.3" + "@parcel/utils" "2.12.0" browserslist "^4.6.6" - lightningcss "^1.16.1" + lightningcss "^1.22.1" nullthrows "^1.1.1" -"@parcel/optimizer-htmlnano@2.8.3": - version "2.8.3" - resolved "https://registry.yarnpkg.com/@parcel/optimizer-htmlnano/-/optimizer-htmlnano-2.8.3.tgz#a71ab6f0f24160ef9f573266064438eff65e96d0" - integrity sha512-L8/fHbEy8Id2a2E0fwR5eKGlv9VYDjrH9PwdJE9Za9v1O/vEsfl/0T/79/x129l5O0yB6EFQkFa20MiK3b+vOg== +"@parcel/optimizer-htmlnano@2.12.0": + version "2.12.0" + resolved "https://registry.yarnpkg.com/@parcel/optimizer-htmlnano/-/optimizer-htmlnano-2.12.0.tgz#e389d56d3f5cd2f6dd464a756a0704a65e527a9b" + integrity sha512-MfPMeCrT8FYiOrpFHVR+NcZQlXAptK2r4nGJjfT+ndPBhEEZp4yyL7n1y7HfX9geg5altc4WTb4Gug7rCoW8VQ== dependencies: - "@parcel/plugin" "2.8.3" + "@parcel/plugin" "2.12.0" htmlnano "^2.0.0" nullthrows "^1.1.1" posthtml "^0.16.5" svgo "^2.4.0" -"@parcel/optimizer-image@2.8.3": - version "2.8.3" - resolved "https://registry.yarnpkg.com/@parcel/optimizer-image/-/optimizer-image-2.8.3.tgz#ea49b4245b4f7d60b38c7585c6311fb21d341baa" - integrity sha512-SD71sSH27SkCDNUNx9A3jizqB/WIJr3dsfp+JZGZC42tpD/Siim6Rqy9M4To/BpMMQIIiEXa5ofwS+DgTEiEHQ== - dependencies: - "@parcel/diagnostic" "2.8.3" - "@parcel/plugin" "2.8.3" - "@parcel/utils" "2.8.3" - "@parcel/workers" "2.8.3" - detect-libc "^1.0.3" - -"@parcel/optimizer-svgo@2.8.3": - version "2.8.3" - resolved "https://registry.yarnpkg.com/@parcel/optimizer-svgo/-/optimizer-svgo-2.8.3.tgz#04da4efec6b623679539a84961bff6998034ba8a" - integrity sha512-9KQed99NZnQw3/W4qBYVQ7212rzA9EqrQG019TIWJzkA9tjGBMIm2c/nXpK1tc3hQ3e7KkXkFCQ3C+ibVUnHNA== - dependencies: - "@parcel/diagnostic" "2.8.3" - "@parcel/plugin" "2.8.3" - "@parcel/utils" "2.8.3" +"@parcel/optimizer-image@2.12.0": + version "2.12.0" + resolved "https://registry.yarnpkg.com/@parcel/optimizer-image/-/optimizer-image-2.12.0.tgz#46dd3c2a871700076c17376d27f6d46d030a0717" + integrity sha512-bo1O7raeAIbRU5nmNVtx8divLW9Xqn0c57GVNGeAK4mygnQoqHqRZ0mR9uboh64pxv6ijXZHPhKvU9HEpjPjBQ== + dependencies: + "@parcel/diagnostic" "2.12.0" + "@parcel/plugin" "2.12.0" + "@parcel/rust" "2.12.0" + "@parcel/utils" "2.12.0" + "@parcel/workers" "2.12.0" + +"@parcel/optimizer-svgo@2.12.0": + version "2.12.0" + resolved "https://registry.yarnpkg.com/@parcel/optimizer-svgo/-/optimizer-svgo-2.12.0.tgz#f1e411cbc3a3c56e05aa5fb2e1edd1ecc7016378" + integrity sha512-Kyli+ZZXnoonnbeRQdoWwee9Bk2jm/49xvnfb+2OO8NN0d41lblBoRhOyFiScRnJrw7eVl1Xrz7NTkXCIO7XFQ== + dependencies: + "@parcel/diagnostic" "2.12.0" + "@parcel/plugin" "2.12.0" + "@parcel/utils" "2.12.0" svgo "^2.4.0" -"@parcel/optimizer-terser@2.8.3": - version "2.8.3" - resolved "https://registry.yarnpkg.com/@parcel/optimizer-terser/-/optimizer-terser-2.8.3.tgz#3a06d98d09386a1a0ae1be85376a8739bfba9618" - integrity sha512-9EeQlN6zIeUWwzrzu6Q2pQSaYsYGah8MtiQ/hog9KEPlYTP60hBv/+utDyYEHSQhL7y5ym08tPX5GzBvwAD/dA== +"@parcel/optimizer-swc@2.12.0": + version "2.12.0" + resolved "https://registry.yarnpkg.com/@parcel/optimizer-swc/-/optimizer-swc-2.12.0.tgz#bacbdb4f6f4a7e0b7086f30b683e3f3f2f980c96" + integrity sha512-iBi6LZB3lm6WmbXfzi8J3DCVPmn4FN2lw7DGXxUXu7MouDPVWfTsM6U/5TkSHJRNRogZ2gqy5q9g34NPxHbJcw== dependencies: - "@parcel/diagnostic" "2.8.3" - "@parcel/plugin" "2.8.3" + "@parcel/diagnostic" "2.12.0" + "@parcel/plugin" "2.12.0" "@parcel/source-map" "^2.1.1" - "@parcel/utils" "2.8.3" + "@parcel/utils" "2.12.0" + "@swc/core" "^1.3.36" nullthrows "^1.1.1" - terser "^5.2.0" - -"@parcel/package-manager@2.8.3": - version "2.8.3" - resolved "https://registry.yarnpkg.com/@parcel/package-manager/-/package-manager-2.8.3.tgz#ddd0d62feae3cf0fb6cc0537791b3a16296ad458" - integrity sha512-tIpY5pD2lH53p9hpi++GsODy6V3khSTX4pLEGuMpeSYbHthnOViobqIlFLsjni+QA1pfc8NNNIQwSNdGjYflVA== - dependencies: - "@parcel/diagnostic" "2.8.3" - "@parcel/fs" "2.8.3" - "@parcel/logger" "2.8.3" - "@parcel/types" "2.8.3" - "@parcel/utils" "2.8.3" - "@parcel/workers" "2.8.3" - semver "^5.7.1" - -"@parcel/packager-css@2.8.3": - version "2.8.3" - resolved "https://registry.yarnpkg.com/@parcel/packager-css/-/packager-css-2.8.3.tgz#0eff34268cb4f5dfb53c1bbca85f5567aeb1835a" - integrity sha512-WyvkMmsurlHG8d8oUVm7S+D+cC/T3qGeqogb7sTI52gB6uiywU7lRCizLNqGFyFGIxcVTVHWnSHqItBcLN76lA== - dependencies: - "@parcel/plugin" "2.8.3" + +"@parcel/package-manager@2.12.0": + version "2.12.0" + resolved "https://registry.yarnpkg.com/@parcel/package-manager/-/package-manager-2.12.0.tgz#7e1eb5f652544e045f7240fa6cf92e5ff1627624" + integrity sha512-0nvAezcjPx9FT+hIL+LS1jb0aohwLZXct7jAh7i0MLMtehOi0z1Sau+QpgMlA9rfEZZ1LIeFdnZZwqSy7Ccspw== + dependencies: + "@parcel/diagnostic" "2.12.0" + "@parcel/fs" "2.12.0" + "@parcel/logger" "2.12.0" + "@parcel/node-resolver-core" "3.3.0" + "@parcel/types" "2.12.0" + "@parcel/utils" "2.12.0" + "@parcel/workers" "2.12.0" + "@swc/core" "^1.3.36" + semver "^7.5.2" + +"@parcel/packager-css@2.12.0": + version "2.12.0" + resolved "https://registry.yarnpkg.com/@parcel/packager-css/-/packager-css-2.12.0.tgz#bee2908608f306186695c6505c3303548751a7b8" + integrity sha512-j3a/ODciaNKD19IYdWJT+TP+tnhhn5koBGBWWtrKSu0UxWpnezIGZetit3eE+Y9+NTePalMkvpIlit2eDhvfJA== + dependencies: + "@parcel/diagnostic" "2.12.0" + "@parcel/plugin" "2.12.0" "@parcel/source-map" "^2.1.1" - "@parcel/utils" "2.8.3" + "@parcel/utils" "2.12.0" + lightningcss "^1.22.1" nullthrows "^1.1.1" -"@parcel/packager-html@2.8.3": - version "2.8.3" - resolved "https://registry.yarnpkg.com/@parcel/packager-html/-/packager-html-2.8.3.tgz#f9263b891aa4dd46c6e2fa2b07025a482132fff1" - integrity sha512-OhPu1Hx1RRKJodpiu86ZqL8el2Aa4uhBHF6RAL1Pcrh2EhRRlPf70Sk0tC22zUpYL7es+iNKZ/n0Rl+OWSHWEw== +"@parcel/packager-html@2.12.0": + version "2.12.0" + resolved "https://registry.yarnpkg.com/@parcel/packager-html/-/packager-html-2.12.0.tgz#dd62a483043982880a63e68ce8d8132f60becd3d" + integrity sha512-PpvGB9hFFe+19NXGz2ApvPrkA9GwEqaDAninT+3pJD57OVBaxB8U+HN4a5LICKxjUppPPqmrLb6YPbD65IX4RA== dependencies: - "@parcel/plugin" "2.8.3" - "@parcel/types" "2.8.3" - "@parcel/utils" "2.8.3" + "@parcel/plugin" "2.12.0" + "@parcel/types" "2.12.0" + "@parcel/utils" "2.12.0" nullthrows "^1.1.1" posthtml "^0.16.5" -"@parcel/packager-js@2.8.3": - version "2.8.3" - resolved "https://registry.yarnpkg.com/@parcel/packager-js/-/packager-js-2.8.3.tgz#3ed11565915d73d12192b6901c75a6b820e4a83a" - integrity sha512-0pGKC3Ax5vFuxuZCRB+nBucRfFRz4ioie19BbDxYnvBxrd4M3FIu45njf6zbBYsI9eXqaDnL1b3DcZJfYqtIzw== +"@parcel/packager-js@2.12.0": + version "2.12.0" + resolved "https://registry.yarnpkg.com/@parcel/packager-js/-/packager-js-2.12.0.tgz#f81f64d16560b97e70bbb4cf568555f990afa2f6" + integrity sha512-viMF+FszITRRr8+2iJyk+4ruGiL27Y6AF7hQ3xbJfzqnmbOhGFtLTQwuwhOLqN/mWR2VKdgbLpZSarWaO3yAMg== dependencies: - "@parcel/diagnostic" "2.8.3" - "@parcel/hash" "2.8.3" - "@parcel/plugin" "2.8.3" + "@parcel/diagnostic" "2.12.0" + "@parcel/plugin" "2.12.0" + "@parcel/rust" "2.12.0" "@parcel/source-map" "^2.1.1" - "@parcel/utils" "2.8.3" + "@parcel/types" "2.12.0" + "@parcel/utils" "2.12.0" globals "^13.2.0" nullthrows "^1.1.1" -"@parcel/packager-raw@2.8.3": - version "2.8.3" - resolved "https://registry.yarnpkg.com/@parcel/packager-raw/-/packager-raw-2.8.3.tgz#bdec826df991e186cb58691cc45d12ad5c06676e" - integrity sha512-BA6enNQo1RCnco9MhkxGrjOk59O71IZ9DPKu3lCtqqYEVd823tXff2clDKHK25i6cChmeHu6oB1Rb73hlPqhUA== +"@parcel/packager-raw@2.12.0": + version "2.12.0" + resolved "https://registry.yarnpkg.com/@parcel/packager-raw/-/packager-raw-2.12.0.tgz#043b704814ff2bcc884cf33e6542f72e246367e0" + integrity sha512-tJZqFbHqP24aq1F+OojFbQIc09P/u8HAW5xfndCrFnXpW4wTgM3p03P0xfw3gnNq+TtxHJ8c3UFE5LnXNNKhYA== dependencies: - "@parcel/plugin" "2.8.3" + "@parcel/plugin" "2.12.0" -"@parcel/packager-svg@2.8.3": - version "2.8.3" - resolved "https://registry.yarnpkg.com/@parcel/packager-svg/-/packager-svg-2.8.3.tgz#7233315296001c531cb55ca96b5f2ef672343630" - integrity sha512-mvIoHpmv5yzl36OjrklTDFShLUfPFTwrmp1eIwiszGdEBuQaX7JVI3Oo2jbVQgcN4W7J6SENzGQ3Q5hPTW3pMw== +"@parcel/packager-svg@2.12.0": + version "2.12.0" + resolved "https://registry.yarnpkg.com/@parcel/packager-svg/-/packager-svg-2.12.0.tgz#2c392243373d60fc834a08d15003f239c34f39a7" + integrity sha512-ldaGiacGb2lLqcXas97k8JiZRbAnNREmcvoY2W2dvW4loVuDT9B9fU777mbV6zODpcgcHWsLL3lYbJ5Lt3y9cg== dependencies: - "@parcel/plugin" "2.8.3" - "@parcel/types" "2.8.3" - "@parcel/utils" "2.8.3" + "@parcel/plugin" "2.12.0" + "@parcel/types" "2.12.0" + "@parcel/utils" "2.12.0" posthtml "^0.16.4" -"@parcel/plugin@2.8.3": - version "2.8.3" - resolved "https://registry.yarnpkg.com/@parcel/plugin/-/plugin-2.8.3.tgz#7bb30a5775eaa6473c27f002a0a3ee7308d6d669" - integrity sha512-jZ6mnsS4D9X9GaNnvrixDQwlUQJCohDX2hGyM0U0bY2NWU8Km97SjtoCpWjq+XBCx/gpC4g58+fk9VQeZq2vlw== +"@parcel/packager-wasm@2.12.0": + version "2.12.0" + resolved "https://registry.yarnpkg.com/@parcel/packager-wasm/-/packager-wasm-2.12.0.tgz#39dbd91e7bf68456dbc9d19a412017e2b513736f" + integrity sha512-fYqZzIqO9fGYveeImzF8ll6KRo2LrOXfD+2Y5U3BiX/wp9wv17dz50QLDQm9hmTcKGWxK4yWqKQh+Evp/fae7A== + dependencies: + "@parcel/plugin" "2.12.0" + +"@parcel/plugin@2.12.0": + version "2.12.0" + resolved "https://registry.yarnpkg.com/@parcel/plugin/-/plugin-2.12.0.tgz#3db4237e8977ef5b5378b65eaffb809d2026431a" + integrity sha512-nc/uRA8DiMoe4neBbzV6kDndh/58a4wQuGKw5oEoIwBCHUvE2W8ZFSu7ollSXUGRzfacTt4NdY8TwS73ScWZ+g== dependencies: - "@parcel/types" "2.8.3" + "@parcel/types" "2.12.0" -"@parcel/reporter-cli@2.8.3": - version "2.8.3" - resolved "https://registry.yarnpkg.com/@parcel/reporter-cli/-/reporter-cli-2.8.3.tgz#12a4743b51b8fe6837f53c20e01bbf1f7336e8e4" - integrity sha512-3sJkS6tFFzgIOz3u3IpD/RsmRxvOKKiQHOTkiiqRt1l44mMDGKS7zANRnJYsQzdCsgwc9SOP30XFgJwtoVlMbw== +"@parcel/profiler@2.12.0": + version "2.12.0" + resolved "https://registry.yarnpkg.com/@parcel/profiler/-/profiler-2.12.0.tgz#8541ca5d27500aebc843b1de081734442e5ee054" + integrity sha512-q53fvl5LDcFYzMUtSusUBZSjQrKjMlLEBgKeQHFwkimwR1mgoseaDBDuNz0XvmzDzF1UelJ02TUKCGacU8W2qA== dependencies: - "@parcel/plugin" "2.8.3" - "@parcel/types" "2.8.3" - "@parcel/utils" "2.8.3" + "@parcel/diagnostic" "2.12.0" + "@parcel/events" "2.12.0" + chrome-trace-event "^1.0.2" + +"@parcel/reporter-cli@2.12.0": + version "2.12.0" + resolved "https://registry.yarnpkg.com/@parcel/reporter-cli/-/reporter-cli-2.12.0.tgz#e067b4eeca49c7120d3455d99810bed5bc825920" + integrity sha512-TqKsH4GVOLPSCanZ6tcTPj+rdVHERnt5y4bwTM82cajM21bCX1Ruwp8xOKU+03091oV2pv5ieB18pJyRF7IpIw== + dependencies: + "@parcel/plugin" "2.12.0" + "@parcel/types" "2.12.0" + "@parcel/utils" "2.12.0" chalk "^4.1.0" term-size "^2.2.1" -"@parcel/reporter-dev-server@2.8.3": - version "2.8.3" - resolved "https://registry.yarnpkg.com/@parcel/reporter-dev-server/-/reporter-dev-server-2.8.3.tgz#a0daa5cc015642684cea561f4e0e7116bbffdc1c" - integrity sha512-Y8C8hzgzTd13IoWTj+COYXEyCkXfmVJs3//GDBsH22pbtSFMuzAZd+8J9qsCo0EWpiDow7V9f1LischvEh3FbQ== +"@parcel/reporter-dev-server@2.12.0": + version "2.12.0" + resolved "https://registry.yarnpkg.com/@parcel/reporter-dev-server/-/reporter-dev-server-2.12.0.tgz#bd4c9e3d6dc8d8b178564a336f46b4f70acf3e79" + integrity sha512-tIcDqRvAPAttRlTV28dHcbWT5K2r/MBFks7nM4nrEDHWtnrCwimkDmZTc1kD8QOCCjGVwRHcQybpHvxfwol6GA== dependencies: - "@parcel/plugin" "2.8.3" - "@parcel/utils" "2.8.3" + "@parcel/plugin" "2.12.0" + "@parcel/utils" "2.12.0" -"@parcel/resolver-default@2.8.3": - version "2.8.3" - resolved "https://registry.yarnpkg.com/@parcel/resolver-default/-/resolver-default-2.8.3.tgz#5ae41e537ae4a793c1abb47f094482b9e2ac3535" - integrity sha512-k0B5M/PJ+3rFbNj4xZSBr6d6HVIe6DH/P3dClLcgBYSXAvElNDfXgtIimbjCyItFkW9/BfcgOVKEEIZOeySH/A== +"@parcel/reporter-tracer@2.12.0": + version "2.12.0" + resolved "https://registry.yarnpkg.com/@parcel/reporter-tracer/-/reporter-tracer-2.12.0.tgz#680e8be677277318c656c1825dbe98a8bfb64e16" + integrity sha512-g8rlu9GxB8Ut/F8WGx4zidIPQ4pcYFjU9bZO+fyRIPrSUFH2bKijCnbZcr4ntqzDGx74hwD6cCG4DBoleq2UlQ== dependencies: - "@parcel/node-resolver-core" "2.8.3" - "@parcel/plugin" "2.8.3" + "@parcel/plugin" "2.12.0" + "@parcel/utils" "2.12.0" + chrome-trace-event "^1.0.3" + nullthrows "^1.1.1" -"@parcel/runtime-browser-hmr@2.8.3": - version "2.8.3" - resolved "https://registry.yarnpkg.com/@parcel/runtime-browser-hmr/-/runtime-browser-hmr-2.8.3.tgz#1fa74e1fbd1030b0a920c58afa3a9eb7dc4bcd1e" - integrity sha512-2O1PYi2j/Q0lTyGNV3JdBYwg4rKo6TEVFlYGdd5wCYU9ZIN9RRuoCnWWH2qCPj3pjIVtBeppYxzfVjPEHINWVg== +"@parcel/resolver-default@2.12.0": + version "2.12.0" + resolved "https://registry.yarnpkg.com/@parcel/resolver-default/-/resolver-default-2.12.0.tgz#005b6bc01de9d166a97d7ef30daf339973c4898a" + integrity sha512-uuhbajTax37TwCxu7V98JtRLiT6hzE4VYSu5B7Qkauy14/WFt2dz6GOUXPgVsED569/hkxebPx3KCMtZW6cHHA== dependencies: - "@parcel/plugin" "2.8.3" - "@parcel/utils" "2.8.3" + "@parcel/node-resolver-core" "3.3.0" + "@parcel/plugin" "2.12.0" -"@parcel/runtime-js@2.8.3": - version "2.8.3" - resolved "https://registry.yarnpkg.com/@parcel/runtime-js/-/runtime-js-2.8.3.tgz#0baa4c8fbf77eabce05d01ccc186614968ffc0cd" - integrity sha512-IRja0vNKwvMtPgIqkBQh0QtRn0XcxNC8HU1jrgWGRckzu10qJWO+5ULgtOeR4pv9krffmMPqywGXw6l/gvJKYQ== +"@parcel/runtime-browser-hmr@2.12.0": + version "2.12.0" + resolved "https://registry.yarnpkg.com/@parcel/runtime-browser-hmr/-/runtime-browser-hmr-2.12.0.tgz#9d045785b83760e305c9efd3d6300a9ff73bcfaf" + integrity sha512-4ZLp2FWyD32r0GlTulO3+jxgsA3oO1P1b5oO2IWuWilfhcJH5LTiazpL5YdusUjtNn9PGN6QLAWfxmzRIfM+Ow== dependencies: - "@parcel/plugin" "2.8.3" - "@parcel/utils" "2.8.3" + "@parcel/plugin" "2.12.0" + "@parcel/utils" "2.12.0" + +"@parcel/runtime-js@2.12.0": + version "2.12.0" + resolved "https://registry.yarnpkg.com/@parcel/runtime-js/-/runtime-js-2.12.0.tgz#da6f7da041cb157556822ad60fefcdbc790dda9c" + integrity sha512-sBerP32Z1crX5PfLNGDSXSdqzlllM++GVnVQVeM7DgMKS8JIFG3VLi28YkX+dYYGtPypm01JoIHCkvwiZEcQJg== + dependencies: + "@parcel/diagnostic" "2.12.0" + "@parcel/plugin" "2.12.0" + "@parcel/utils" "2.12.0" nullthrows "^1.1.1" -"@parcel/runtime-react-refresh@2.8.3": - version "2.8.3" - resolved "https://registry.yarnpkg.com/@parcel/runtime-react-refresh/-/runtime-react-refresh-2.8.3.tgz#381a942fb81e8f5ac6c7e0ee1b91dbf34763c3f8" - integrity sha512-2v/qFKp00MfG0234OdOgQNAo6TLENpFYZMbVbAsPMY9ITiqG73MrEsrGXVoGbYiGTMB/Toer/lSWlJxtacOCuA== +"@parcel/runtime-react-refresh@2.12.0": + version "2.12.0" + resolved "https://registry.yarnpkg.com/@parcel/runtime-react-refresh/-/runtime-react-refresh-2.12.0.tgz#58c17552766492ec2005ffedfa04ecb29386dd8b" + integrity sha512-SCHkcczJIDFTFdLTzrHTkQ0aTrX3xH6jrA4UsCBL6ji61+w+ohy4jEEe9qCgJVXhnJfGLE43HNXek+0MStX+Mw== dependencies: - "@parcel/plugin" "2.8.3" - "@parcel/utils" "2.8.3" + "@parcel/plugin" "2.12.0" + "@parcel/utils" "2.12.0" react-error-overlay "6.0.9" react-refresh "^0.9.0" -"@parcel/runtime-service-worker@2.8.3": - version "2.8.3" - resolved "https://registry.yarnpkg.com/@parcel/runtime-service-worker/-/runtime-service-worker-2.8.3.tgz#54d92da9ff1dfbd27db0e84164a22fa59e99b348" - integrity sha512-/Skkw+EeRiwzOJso5fQtK8c9b452uWLNhQH1ISTodbmlcyB4YalAiSsyHCtMYD0c3/t5Sx4ZS7vxBAtQd0RvOw== +"@parcel/runtime-service-worker@2.12.0": + version "2.12.0" + resolved "https://registry.yarnpkg.com/@parcel/runtime-service-worker/-/runtime-service-worker-2.12.0.tgz#67ee1e6dbc5441651fed04ecb2bd7ebe1e362679" + integrity sha512-BXuMBsfiwpIEnssn+jqfC3jkgbS8oxeo3C7xhSQsuSv+AF2FwY3O3AO1c1RBskEW3XrBLNINOJujroNw80VTKA== dependencies: - "@parcel/plugin" "2.8.3" - "@parcel/utils" "2.8.3" + "@parcel/plugin" "2.12.0" + "@parcel/utils" "2.12.0" nullthrows "^1.1.1" +"@parcel/rust@2.12.0": + version "2.12.0" + resolved "https://registry.yarnpkg.com/@parcel/rust/-/rust-2.12.0.tgz#135df4dd8c63d97720379777c5bb4a2680a201cd" + integrity sha512-005cldMdFZFDPOjbDVEXcINQ3wT4vrxvSavRWI3Az0e3E18exO/x/mW9f648KtXugOXMAqCEqhFHcXECL9nmMw== + "@parcel/source-map@^2.1.1": version "2.1.1" resolved "https://registry.yarnpkg.com/@parcel/source-map/-/source-map-2.1.1.tgz#fb193b82dba6dd62cc7a76b326f57bb35000a782" @@ -798,174 +817,175 @@ dependencies: detect-libc "^1.0.3" -"@parcel/transformer-babel@2.8.3": - version "2.8.3" - resolved "https://registry.yarnpkg.com/@parcel/transformer-babel/-/transformer-babel-2.8.3.tgz#286bc6cb9afe4c0259f0b28e0f2f47322a24b130" - integrity sha512-L6lExfpvvC7T/g3pxf3CIJRouQl+sgrSzuWQ0fD4PemUDHvHchSP4SNUVnd6gOytF3Y1KpnEZIunQGi5xVqQCQ== +"@parcel/transformer-babel@2.12.0": + version "2.12.0" + resolved "https://registry.yarnpkg.com/@parcel/transformer-babel/-/transformer-babel-2.12.0.tgz#29be68f2fad4688b33ef3f03ef2b8c3e9928b87f" + integrity sha512-zQaBfOnf/l8rPxYGnsk/ufh/0EuqvmnxafjBIpKZ//j6rGylw5JCqXSb1QvvAqRYruKeccxGv7+HrxpqKU6V4A== dependencies: - "@parcel/diagnostic" "2.8.3" - "@parcel/plugin" "2.8.3" + "@parcel/diagnostic" "2.12.0" + "@parcel/plugin" "2.12.0" "@parcel/source-map" "^2.1.1" - "@parcel/utils" "2.8.3" + "@parcel/utils" "2.12.0" browserslist "^4.6.6" json5 "^2.2.0" nullthrows "^1.1.1" - semver "^5.7.0" + semver "^7.5.2" -"@parcel/transformer-css@2.8.3": - version "2.8.3" - resolved "https://registry.yarnpkg.com/@parcel/transformer-css/-/transformer-css-2.8.3.tgz#d6c44100204e73841ad8e0f90472172ea8b9120c" - integrity sha512-xTqFwlSXtnaYen9ivAgz+xPW7yRl/u4QxtnDyDpz5dr8gSeOpQYRcjkd4RsYzKsWzZcGtB5EofEk8ayUbWKEUg== +"@parcel/transformer-css@2.12.0": + version "2.12.0" + resolved "https://registry.yarnpkg.com/@parcel/transformer-css/-/transformer-css-2.12.0.tgz#218a98948c9410c17287183d80ca9bd9943cc9e9" + integrity sha512-vXhOqoAlQGATYyQ433Z1DXKmiKmzOAUmKysbYH3FD+LKEKLMEl/pA14goqp00TW+A/EjtSKKyeMyHlMIIUqj4Q== dependencies: - "@parcel/diagnostic" "2.8.3" - "@parcel/plugin" "2.8.3" + "@parcel/diagnostic" "2.12.0" + "@parcel/plugin" "2.12.0" "@parcel/source-map" "^2.1.1" - "@parcel/utils" "2.8.3" + "@parcel/utils" "2.12.0" browserslist "^4.6.6" - lightningcss "^1.16.1" + lightningcss "^1.22.1" nullthrows "^1.1.1" -"@parcel/transformer-html@2.8.3": - version "2.8.3" - resolved "https://registry.yarnpkg.com/@parcel/transformer-html/-/transformer-html-2.8.3.tgz#5c68b28ee6b8c7a13b8aee87f7957ad3227bd83f" - integrity sha512-kIZO3qsMYTbSnSpl9cnZog+SwL517ffWH54JeB410OSAYF1ouf4n5v9qBnALZbuCCmPwJRGs4jUtE452hxwN4g== +"@parcel/transformer-html@2.12.0": + version "2.12.0" + resolved "https://registry.yarnpkg.com/@parcel/transformer-html/-/transformer-html-2.12.0.tgz#8681b089e2b20c5fda1c966cefb8de4d8fb2ce80" + integrity sha512-5jW4dFFBlYBvIQk4nrH62rfA/G/KzVzEDa6S+Nne0xXhglLjkm64Ci9b/d4tKZfuGWUbpm2ASAq8skti/nfpXw== dependencies: - "@parcel/diagnostic" "2.8.3" - "@parcel/hash" "2.8.3" - "@parcel/plugin" "2.8.3" + "@parcel/diagnostic" "2.12.0" + "@parcel/plugin" "2.12.0" + "@parcel/rust" "2.12.0" nullthrows "^1.1.1" posthtml "^0.16.5" posthtml-parser "^0.10.1" posthtml-render "^3.0.0" - semver "^5.7.1" + semver "^7.5.2" srcset "4" -"@parcel/transformer-image@2.8.3": - version "2.8.3" - resolved "https://registry.yarnpkg.com/@parcel/transformer-image/-/transformer-image-2.8.3.tgz#73805b2bfc3c8919d7737544e5f8be39e3f303fe" - integrity sha512-cO4uptcCGTi5H6bvTrAWEFUsTNhA4kCo8BSvRSCHA2sf/4C5tGQPHt3JhdO0GQLPwZRCh/R41EkJs5HZ8A8DAg== +"@parcel/transformer-image@2.12.0": + version "2.12.0" + resolved "https://registry.yarnpkg.com/@parcel/transformer-image/-/transformer-image-2.12.0.tgz#8ba2ca3b5d88287bf38c8244b2714158c9d34b2e" + integrity sha512-8hXrGm2IRII49R7lZ0RpmNk27EhcsH+uNKsvxuMpXPuEnWgC/ha/IrjaI29xCng1uGur74bJF43NUSQhR4aTdw== dependencies: - "@parcel/plugin" "2.8.3" - "@parcel/utils" "2.8.3" - "@parcel/workers" "2.8.3" + "@parcel/plugin" "2.12.0" + "@parcel/utils" "2.12.0" + "@parcel/workers" "2.12.0" nullthrows "^1.1.1" -"@parcel/transformer-js@2.8.3": - version "2.8.3" - resolved "https://registry.yarnpkg.com/@parcel/transformer-js/-/transformer-js-2.8.3.tgz#fe400df428394d1e7fe5afb6dea5c7c858e44f03" - integrity sha512-9Qd6bib+sWRcpovvzvxwy/PdFrLUXGfmSW9XcVVG8pvgXsZPFaNjnNT8stzGQj1pQiougCoxMY4aTM5p1lGHEQ== +"@parcel/transformer-js@2.12.0": + version "2.12.0" + resolved "https://registry.yarnpkg.com/@parcel/transformer-js/-/transformer-js-2.12.0.tgz#e6bf0c312f78603faf98ce546086898506e3811f" + integrity sha512-OSZpOu+FGDbC/xivu24v092D9w6EGytB3vidwbdiJ2FaPgfV7rxS0WIUjH4I0OcvHAcitArRXL0a3+HrNTdQQw== dependencies: - "@parcel/diagnostic" "2.8.3" - "@parcel/plugin" "2.8.3" + "@parcel/diagnostic" "2.12.0" + "@parcel/plugin" "2.12.0" + "@parcel/rust" "2.12.0" "@parcel/source-map" "^2.1.1" - "@parcel/utils" "2.8.3" - "@parcel/workers" "2.8.3" - "@swc/helpers" "^0.4.12" + "@parcel/utils" "2.12.0" + "@parcel/workers" "2.12.0" + "@swc/helpers" "^0.5.0" browserslist "^4.6.6" - detect-libc "^1.0.3" nullthrows "^1.1.1" regenerator-runtime "^0.13.7" - semver "^5.7.1" + semver "^7.5.2" -"@parcel/transformer-json@2.8.3": - version "2.8.3" - resolved "https://registry.yarnpkg.com/@parcel/transformer-json/-/transformer-json-2.8.3.tgz#25deb3a5138cc70a83269fc5d39d564609354d36" - integrity sha512-B7LmVq5Q7bZO4ERb6NHtRuUKWGysEeaj9H4zelnyBv+wLgpo4f5FCxSE1/rTNmP9u1qHvQ3scGdK6EdSSokGPg== +"@parcel/transformer-json@2.12.0": + version "2.12.0" + resolved "https://registry.yarnpkg.com/@parcel/transformer-json/-/transformer-json-2.12.0.tgz#16cc0454e4862350b605a5e2009d050c676c6ea5" + integrity sha512-Utv64GLRCQILK5r0KFs4o7I41ixMPllwOLOhkdjJKvf1hZmN6WqfOmB1YLbWS/y5Zb/iB52DU2pWZm96vLFQZQ== dependencies: - "@parcel/plugin" "2.8.3" + "@parcel/plugin" "2.12.0" json5 "^2.2.0" -"@parcel/transformer-postcss@2.8.3": - version "2.8.3" - resolved "https://registry.yarnpkg.com/@parcel/transformer-postcss/-/transformer-postcss-2.8.3.tgz#df4fdc1c90893823445f2a8eb8e2bdd0349ccc58" - integrity sha512-e8luB/poIlz6jBsD1Izms+6ElbyzuoFVa4lFVLZnTAChI3UxPdt9p/uTsIO46HyBps/Bk8ocvt3J4YF84jzmvg== +"@parcel/transformer-postcss@2.12.0": + version "2.12.0" + resolved "https://registry.yarnpkg.com/@parcel/transformer-postcss/-/transformer-postcss-2.12.0.tgz#195f4fb86f36f42b5de82076ea36b9d850f4832e" + integrity sha512-FZqn+oUtiLfPOn67EZxPpBkfdFiTnF4iwiXPqvst3XI8H+iC+yNgzmtJkunOOuylpYY6NOU5jT8d7saqWSDv2Q== dependencies: - "@parcel/diagnostic" "2.8.3" - "@parcel/hash" "2.8.3" - "@parcel/plugin" "2.8.3" - "@parcel/utils" "2.8.3" + "@parcel/diagnostic" "2.12.0" + "@parcel/plugin" "2.12.0" + "@parcel/rust" "2.12.0" + "@parcel/utils" "2.12.0" clone "^2.1.1" nullthrows "^1.1.1" postcss-value-parser "^4.2.0" - semver "^5.7.1" + semver "^7.5.2" -"@parcel/transformer-posthtml@2.8.3": - version "2.8.3" - resolved "https://registry.yarnpkg.com/@parcel/transformer-posthtml/-/transformer-posthtml-2.8.3.tgz#7c3912a5a631cb26485f6464e0d6eeabb6f1e718" - integrity sha512-pkzf9Smyeaw4uaRLsT41RGrPLT5Aip8ZPcntawAfIo+KivBQUV0erY1IvHYjyfFzq1ld/Fo2Ith9He6mxpPifA== +"@parcel/transformer-posthtml@2.12.0": + version "2.12.0" + resolved "https://registry.yarnpkg.com/@parcel/transformer-posthtml/-/transformer-posthtml-2.12.0.tgz#a906c26278e03455f6186b7dbd9f5b63eaa26948" + integrity sha512-z6Z7rav/pcaWdeD+2sDUcd0mmNZRUvtHaUGa50Y2mr+poxrKilpsnFMSiWBT+oOqPt7j71jzDvrdnAF4XkCljg== dependencies: - "@parcel/plugin" "2.8.3" - "@parcel/utils" "2.8.3" + "@parcel/plugin" "2.12.0" + "@parcel/utils" "2.12.0" nullthrows "^1.1.1" posthtml "^0.16.5" posthtml-parser "^0.10.1" posthtml-render "^3.0.0" - semver "^5.7.1" + semver "^7.5.2" -"@parcel/transformer-raw@2.8.3": - version "2.8.3" - resolved "https://registry.yarnpkg.com/@parcel/transformer-raw/-/transformer-raw-2.8.3.tgz#3a22213fe18a5f83fd78889cb49f06e059cfead7" - integrity sha512-G+5cXnd2/1O3nV/pgRxVKZY/HcGSseuhAe71gQdSQftb8uJEURyUHoQ9Eh0JUD3MgWh9V+nIKoyFEZdf9T0sUQ== +"@parcel/transformer-raw@2.12.0": + version "2.12.0" + resolved "https://registry.yarnpkg.com/@parcel/transformer-raw/-/transformer-raw-2.12.0.tgz#1ee7e02214f777cf3a5bf53580ee4dadfaf8a44c" + integrity sha512-Ht1fQvXxix0NncdnmnXZsa6hra20RXYh1VqhBYZLsDfkvGGFnXIgO03Jqn4Z8MkKoa0tiNbDhpKIeTjyclbBxQ== dependencies: - "@parcel/plugin" "2.8.3" + "@parcel/plugin" "2.12.0" -"@parcel/transformer-react-refresh-wrap@2.8.3": - version "2.8.3" - resolved "https://registry.yarnpkg.com/@parcel/transformer-react-refresh-wrap/-/transformer-react-refresh-wrap-2.8.3.tgz#8b0392638405dd470a886002229f7889d5464822" - integrity sha512-q8AAoEvBnCf/nPvgOwFwKZfEl/thwq7c2duxXkhl+tTLDRN2vGmyz4355IxCkavSX+pLWSQ5MexklSEeMkgthg== +"@parcel/transformer-react-refresh-wrap@2.12.0": + version "2.12.0" + resolved "https://registry.yarnpkg.com/@parcel/transformer-react-refresh-wrap/-/transformer-react-refresh-wrap-2.12.0.tgz#cf079353126f2bb820209736a75f868d0df58d92" + integrity sha512-GE8gmP2AZtkpBIV5vSCVhewgOFRhqwdM5Q9jNPOY5PKcM3/Ff0qCqDiTzzGLhk0/VMBrdjssrfZkVx6S/lHdJw== dependencies: - "@parcel/plugin" "2.8.3" - "@parcel/utils" "2.8.3" + "@parcel/plugin" "2.12.0" + "@parcel/utils" "2.12.0" react-refresh "^0.9.0" -"@parcel/transformer-sass@2.8.3": - version "2.8.3" - resolved "https://registry.yarnpkg.com/@parcel/transformer-sass/-/transformer-sass-2.8.3.tgz#d3a0388e77c1e6279b488ccd0abf612d3a0897ff" - integrity sha512-ak196rjvXdsBOGi5aTkBEKv6i4LKQgOkHuaKEjeT8g2a3CU6Z36J+j2GbZzsznfws/hH+CRTf8bAsbkxtKlkjQ== +"@parcel/transformer-sass@^2.12.0": + version "2.12.0" + resolved "https://registry.yarnpkg.com/@parcel/transformer-sass/-/transformer-sass-2.12.0.tgz#9132ee78197db04baf51d3024a1bf3c35f1df5ef" + integrity sha512-xLLoSLPST+2AHJwFRLl4foArDjjy6P1RChP3TxMU2MVS1sbKGJnfFhFpHAacH8ASjuGtu5rbpfpHRZePlvoZxw== dependencies: - "@parcel/plugin" "2.8.3" + "@parcel/plugin" "2.12.0" "@parcel/source-map" "^2.1.1" sass "^1.38.0" -"@parcel/transformer-svg@2.8.3": - version "2.8.3" - resolved "https://registry.yarnpkg.com/@parcel/transformer-svg/-/transformer-svg-2.8.3.tgz#4df959cba4ebf45d7aaddd540f752e6e84df38b2" - integrity sha512-3Zr/gBzxi1ZH1fftH/+KsZU7w5GqkmxlB0ZM8ovS5E/Pl1lq1t0xvGJue9m2VuQqP8Mxfpl5qLFmsKlhaZdMIQ== +"@parcel/transformer-svg@2.12.0": + version "2.12.0" + resolved "https://registry.yarnpkg.com/@parcel/transformer-svg/-/transformer-svg-2.12.0.tgz#0281e89bf0f438ec161c19b59a8a8978434a3621" + integrity sha512-cZJqGRJ4JNdYcb+vj94J7PdOuTnwyy45dM9xqbIMH+HSiiIkfrMsdEwYft0GTyFTdsnf+hdHn3tau7Qa5hhX+A== dependencies: - "@parcel/diagnostic" "2.8.3" - "@parcel/hash" "2.8.3" - "@parcel/plugin" "2.8.3" + "@parcel/diagnostic" "2.12.0" + "@parcel/plugin" "2.12.0" + "@parcel/rust" "2.12.0" nullthrows "^1.1.1" posthtml "^0.16.5" posthtml-parser "^0.10.1" posthtml-render "^3.0.0" - semver "^5.7.1" + semver "^7.5.2" -"@parcel/types@2.8.3": - version "2.8.3" - resolved "https://registry.yarnpkg.com/@parcel/types/-/types-2.8.3.tgz#3306bc5391b6913bd619914894b8cd84a24b30fa" - integrity sha512-FECA1FB7+0UpITKU0D6TgGBpGxYpVSMNEENZbSJxFSajNy3wrko+zwBKQmFOLOiPcEtnGikxNs+jkFWbPlUAtw== +"@parcel/types@2.12.0": + version "2.12.0" + resolved "https://registry.yarnpkg.com/@parcel/types/-/types-2.12.0.tgz#caf0af00ee0c7228b350eca5f4d3a5b85ce457ad" + integrity sha512-8zAFiYNCwNTQcglIObyNwKfRYQK5ELlL13GuBOrSMxueUiI5ylgsGbTS1N7J3dAGZixHO8KhHGv5a71FILn9rQ== dependencies: - "@parcel/cache" "2.8.3" - "@parcel/diagnostic" "2.8.3" - "@parcel/fs" "2.8.3" - "@parcel/package-manager" "2.8.3" + "@parcel/cache" "2.12.0" + "@parcel/diagnostic" "2.12.0" + "@parcel/fs" "2.12.0" + "@parcel/package-manager" "2.12.0" "@parcel/source-map" "^2.1.1" - "@parcel/workers" "2.8.3" + "@parcel/workers" "2.12.0" utility-types "^3.10.0" -"@parcel/utils@2.8.3": - version "2.8.3" - resolved "https://registry.yarnpkg.com/@parcel/utils/-/utils-2.8.3.tgz#0d56c9e8e22c119590a5e044a0e01031965da40e" - integrity sha512-IhVrmNiJ+LOKHcCivG5dnuLGjhPYxQ/IzbnF2DKNQXWBTsYlHkJZpmz7THoeLtLliGmSOZ3ZCsbR8/tJJKmxjA== +"@parcel/utils@2.12.0": + version "2.12.0" + resolved "https://registry.yarnpkg.com/@parcel/utils/-/utils-2.12.0.tgz#ac900726e7cb12a9e6392081fa05b756183f65fd" + integrity sha512-z1JhLuZ8QmDaYoEIuUCVZlhcFrS7LMfHrb2OCRui5SQFntRWBH2fNM6H/fXXUkT9SkxcuFP2DUA6/m4+Gkz72g== dependencies: - "@parcel/codeframe" "2.8.3" - "@parcel/diagnostic" "2.8.3" - "@parcel/hash" "2.8.3" - "@parcel/logger" "2.8.3" - "@parcel/markdown-ansi" "2.8.3" + "@parcel/codeframe" "2.12.0" + "@parcel/diagnostic" "2.12.0" + "@parcel/logger" "2.12.0" + "@parcel/markdown-ansi" "2.12.0" + "@parcel/rust" "2.12.0" "@parcel/source-map" "^2.1.1" chalk "^4.1.0" + nullthrows "^1.1.1" "@parcel/watcher-android-arm64@2.4.0": version "2.4.0" @@ -1050,26 +1070,106 @@ "@parcel/watcher-win32-ia32" "2.4.0" "@parcel/watcher-win32-x64" "2.4.0" -"@parcel/workers@2.8.3": - version "2.8.3" - resolved "https://registry.yarnpkg.com/@parcel/workers/-/workers-2.8.3.tgz#255450ccf4db234082407e4ddda5fd575f08c235" - integrity sha512-+AxBnKgjqVpUHBcHLWIHcjYgKIvHIpZjN33mG5LG9XXvrZiqdWvouEzqEXlVLq5VzzVbKIQQcmsvRy138YErkg== +"@parcel/workers@2.12.0": + version "2.12.0" + resolved "https://registry.yarnpkg.com/@parcel/workers/-/workers-2.12.0.tgz#773182b5006741102de8ae36d18a5a9e3320ebd1" + integrity sha512-zv5We5Jmb+ZWXlU6A+AufyjY4oZckkxsZ8J4dvyWL0W8IQvGO1JB4FGeryyttzQv3RM3OxcN/BpTGPiDG6keBw== dependencies: - "@parcel/diagnostic" "2.8.3" - "@parcel/logger" "2.8.3" - "@parcel/types" "2.8.3" - "@parcel/utils" "2.8.3" - chrome-trace-event "^1.0.2" + "@parcel/diagnostic" "2.12.0" + "@parcel/logger" "2.12.0" + "@parcel/profiler" "2.12.0" + "@parcel/types" "2.12.0" + "@parcel/utils" "2.12.0" nullthrows "^1.1.1" -"@swc/helpers@^0.4.12": - version "0.4.36" - resolved "https://registry.yarnpkg.com/@swc/helpers/-/helpers-0.4.36.tgz#fcfff76ed52c214f357e8e9d3f37b568908072d9" - integrity sha512-5lxnyLEYFskErRPenYItLRSge5DjrJngYKdVjRSrWfza9G6KkgHEXi0vUZiyUeMU5JfXH1YnvXZzSp8ul88o2Q== +"@swc/core-darwin-arm64@1.7.26": + version "1.7.26" + resolved "https://registry.yarnpkg.com/@swc/core-darwin-arm64/-/core-darwin-arm64-1.7.26.tgz#5f4096c00e71771ca1b18c824f0c92a052c70760" + integrity sha512-FF3CRYTg6a7ZVW4yT9mesxoVVZTrcSWtmZhxKCYJX9brH4CS/7PRPjAKNk6kzWgWuRoglP7hkjQcd6EpMcZEAw== + +"@swc/core-darwin-x64@1.7.26": + version "1.7.26" + resolved "https://registry.yarnpkg.com/@swc/core-darwin-x64/-/core-darwin-x64-1.7.26.tgz#867b7a4f094e6b64201090ca5fcbf3da7d0f3e22" + integrity sha512-az3cibZdsay2HNKmc4bjf62QVukuiMRh5sfM5kHR/JMTrLyS6vSw7Ihs3UTkZjUxkLTT8ro54LI6sV6sUQUbLQ== + +"@swc/core-linux-arm-gnueabihf@1.7.26": + version "1.7.26" + resolved "https://registry.yarnpkg.com/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.7.26.tgz#35bb43894def296d92aaa2cc9372d48042f37777" + integrity sha512-VYPFVJDO5zT5U3RpCdHE5v1gz4mmR8BfHecUZTmD2v1JeFY6fv9KArJUpjrHEEsjK/ucXkQFmJ0jaiWXmpOV9Q== + +"@swc/core-linux-arm64-gnu@1.7.26": + version "1.7.26" + resolved "https://registry.yarnpkg.com/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.7.26.tgz#8e2321cc4ec84cbfed8f8e16ff1ed7b854450443" + integrity sha512-YKevOV7abpjcAzXrhsl+W48Z9mZvgoVs2eP5nY+uoMAdP2b3GxC0Df1Co0I90o2lkzO4jYBpTMcZlmUXLdXn+Q== + +"@swc/core-linux-arm64-musl@1.7.26": + version "1.7.26" + resolved "https://registry.yarnpkg.com/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.7.26.tgz#b1c16e4b23ffa9ff19973eda6ffee35d2a7de7b0" + integrity sha512-3w8iZICMkQQON0uIcvz7+Q1MPOW6hJ4O5ETjA0LSP/tuKqx30hIniCGOgPDnv3UTMruLUnQbtBwVCZTBKR3Rkg== + +"@swc/core-linux-x64-gnu@1.7.26": + version "1.7.26" + resolved "https://registry.yarnpkg.com/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.7.26.tgz#388e2cc13a010cd28787aead2cecf31eb491836d" + integrity sha512-c+pp9Zkk2lqb06bNGkR2Looxrs7FtGDMA4/aHjZcCqATgp348hOKH5WPvNLBl+yPrISuWjbKDVn3NgAvfvpH4w== + +"@swc/core-linux-x64-musl@1.7.26": + version "1.7.26" + resolved "https://registry.yarnpkg.com/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.7.26.tgz#51e0ff30981f26d7a5b97a7a7b5b291bad050d1a" + integrity sha512-PgtyfHBF6xG87dUSSdTJHwZ3/8vWZfNIXQV2GlwEpslrOkGqy+WaiiyE7Of7z9AvDILfBBBcJvJ/r8u980wAfQ== + +"@swc/core-win32-arm64-msvc@1.7.26": + version "1.7.26" + resolved "https://registry.yarnpkg.com/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.7.26.tgz#a7fdcc4074c34ee6a026506b594d00323383c11f" + integrity sha512-9TNXPIJqFynlAOrRD6tUQjMq7KApSklK3R/tXgIxc7Qx+lWu8hlDQ/kVPLpU7PWvMMwC/3hKBW+p5f+Tms1hmA== + +"@swc/core-win32-ia32-msvc@1.7.26": + version "1.7.26" + resolved "https://registry.yarnpkg.com/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.7.26.tgz#ae7be6dde798eebee2000b8fd84e01a439b5bd6a" + integrity sha512-9YngxNcG3177GYdsTum4V98Re+TlCeJEP4kEwEg9EagT5s3YejYdKwVAkAsJszzkXuyRDdnHUpYbTrPG6FiXrQ== + +"@swc/core-win32-x64-msvc@1.7.26": + version "1.7.26" + resolved "https://registry.yarnpkg.com/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.7.26.tgz#310d607004d7319085a4dec20c0c38c3405cc05b" + integrity sha512-VR+hzg9XqucgLjXxA13MtV5O3C0bK0ywtLIBw/+a+O+Oc6mxFWHtdUeXDbIi5AiPbn0fjgVJMqYnyjGyyX8u0w== + +"@swc/core@^1.3.36": + version "1.7.26" + resolved "https://registry.yarnpkg.com/@swc/core/-/core-1.7.26.tgz#beda9b82063fcec7b56c958804a4d175aecf9a9d" + integrity sha512-f5uYFf+TmMQyYIoxkn/evWhNGuUzC730dFwAKGwBVHHVoPyak1/GvJUm6i1SKl+2Hrj9oN0i3WSoWWZ4pgI8lw== + dependencies: + "@swc/counter" "^0.1.3" + "@swc/types" "^0.1.12" + optionalDependencies: + "@swc/core-darwin-arm64" "1.7.26" + "@swc/core-darwin-x64" "1.7.26" + "@swc/core-linux-arm-gnueabihf" "1.7.26" + "@swc/core-linux-arm64-gnu" "1.7.26" + "@swc/core-linux-arm64-musl" "1.7.26" + "@swc/core-linux-x64-gnu" "1.7.26" + "@swc/core-linux-x64-musl" "1.7.26" + "@swc/core-win32-arm64-msvc" "1.7.26" + "@swc/core-win32-ia32-msvc" "1.7.26" + "@swc/core-win32-x64-msvc" "1.7.26" + +"@swc/counter@^0.1.3": + version "0.1.3" + resolved "https://registry.yarnpkg.com/@swc/counter/-/counter-0.1.3.tgz#cc7463bd02949611c6329596fccd2b0ec782b0e9" + integrity sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ== + +"@swc/helpers@^0.5.0": + version "0.5.13" + resolved "https://registry.yarnpkg.com/@swc/helpers/-/helpers-0.5.13.tgz#33e63ff3cd0cade557672bd7888a39ce7d115a8c" + integrity sha512-UoKGxQ3r5kYI9dALKJapMmuK+1zWM/H17Z1+iwnNmzcJRnfFuevZs375TA5rW31pu4BS4NoSy1fRsexDXfWn5w== dependencies: - legacy-swc-helpers "npm:@swc/helpers@=0.4.14" tslib "^2.4.0" +"@swc/types@^0.1.12": + version "0.1.12" + resolved "https://registry.yarnpkg.com/@swc/types/-/types-0.1.12.tgz#7f632c06ab4092ce0ebd046ed77ff7557442282f" + integrity sha512-wBJA+SdtkbFhHjTMYH+dEH1y4VpfGdAc2Kw/LK09i9bXd/K6j6PkDcFCEzb6iVfZMkPRrl/q0e3toqTAJdkIVA== + dependencies: + "@swc/counter" "^0.1.3" + "@trysound/sax@0.2.0": version "0.2.0" resolved "https://registry.yarnpkg.com/@trysound/sax/-/sax-0.2.0.tgz#cccaab758af56761eb7bf37af6f03f326dd798ad" @@ -1239,11 +1339,6 @@ acorn@^8.5.0: resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.8.2.tgz#1b2f25db02af965399b9776b0c2c391276d37c4a" integrity sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw== -acorn@^8.8.2: - version "8.11.3" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.11.3.tgz#71e0b14e13a4ec160724b38fb7b0f233b1b81d7a" - integrity sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg== - ansi-regex@^5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" @@ -1338,12 +1433,12 @@ brace@^0.11.1: resolved "https://registry.yarnpkg.com/brace/-/brace-0.11.1.tgz#4896fcc9d544eef45f4bb7660db320d3b379fe58" integrity sha512-Fc8Ne62jJlKHiG/ajlonC4Sd66Pq68fFwK4ihJGNZpGqboc324SQk+lRvMzpPRuJOmfrJefdG8/7JdWX4bzJ2Q== -braces@^3.0.2, braces@~3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" - integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A== +braces@^3.0.3, braces@~3.0.2: + version "3.0.3" + resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.3.tgz#490332f40919452272d55a8480adc0c441358789" + integrity sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA== dependencies: - fill-range "^7.0.1" + fill-range "^7.1.1" browserslist@^4.21.9: version "4.22.1" @@ -1460,6 +1555,11 @@ chrome-trace-event@^1.0.2: resolved "https://registry.yarnpkg.com/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz#1015eced4741e15d06664a957dbbf50d041e26ac" integrity sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg== +chrome-trace-event@^1.0.3: + version "1.0.4" + resolved "https://registry.yarnpkg.com/chrome-trace-event/-/chrome-trace-event-1.0.4.tgz#05bffd7ff928465093314708c93bdfa9bd1f0f5b" + integrity sha512-rNjApaLzuwaOTjCiT8lSDdGN1APCiqkChLMJxJPWLunPAt5fy8xgU9/jNOchV84wfIxrA0lRQB7oCT8jrn/wrQ== + classnames@^2.2.6, classnames@^2.3.1: version "2.3.2" resolved "https://registry.yarnpkg.com/classnames/-/classnames-2.3.2.tgz#351d813bf0137fcc6a76a16b88208d2560a0d924" @@ -1634,6 +1734,11 @@ detect-libc@^1.0.3: resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b" integrity sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg== +detect-libc@^2.0.1: + version "2.0.3" + resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-2.0.3.tgz#f0cd503b40f9939b894697d19ad50895e30cf700" + integrity sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw== + detect-node-es@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/detect-node-es/-/detect-node-es-1.1.0.tgz#163acdf643330caa0b4cd7c21e7ee7755d6fa493" @@ -1743,10 +1848,10 @@ file-selector@^0.4.0: dependencies: tslib "^2.0.3" -fill-range@^7.0.1: - version "7.0.1" - resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40" - integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ== +fill-range@^7.1.1: + version "7.1.1" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.1.1.tgz#44265d3cac07e3ea7dc247516380643754a05292" + integrity sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg== dependencies: to-regex-range "^5.0.1" @@ -2118,97 +2223,96 @@ json5@^2.2.0, json5@^2.2.1, json5@^2.2.3: resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.3.tgz#78cd6f1a19bdc12b73db5ad0c61efd66c1e29283" integrity sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg== -"legacy-swc-helpers@npm:@swc/helpers@=0.4.14": - version "0.4.14" - resolved "https://registry.yarnpkg.com/@swc/helpers/-/helpers-0.4.14.tgz#1352ac6d95e3617ccb7c1498ff019654f1e12a74" - integrity sha512-4C7nX/dvpzB7za4Ql9K81xK3HPxCpHMgwTZVyf+9JQ6VUbn9jjZVN7/Nkdz/Ugzs2CSjqnL/UPXroiVBVHUWUw== - dependencies: - tslib "^2.4.0" +lightningcss-darwin-arm64@1.27.0: + version "1.27.0" + resolved "https://registry.yarnpkg.com/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.27.0.tgz#565bd610533941cba648a70e105987578d82f996" + integrity sha512-Gl/lqIXY+d+ySmMbgDf0pgaWSqrWYxVHoc88q+Vhf2YNzZ8DwoRzGt5NZDVqqIW5ScpSnmmjcgXP87Dn2ylSSQ== + +lightningcss-darwin-x64@1.27.0: + version "1.27.0" + resolved "https://registry.yarnpkg.com/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.27.0.tgz#c906a267237b1c7fe08bff6c5ac032c099bc9482" + integrity sha512-0+mZa54IlcNAoQS9E0+niovhyjjQWEMrwW0p2sSdLRhLDc8LMQ/b67z7+B5q4VmjYCMSfnFi3djAAQFIDuj/Tg== + +lightningcss-freebsd-x64@1.27.0: + version "1.27.0" + resolved "https://registry.yarnpkg.com/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.27.0.tgz#a7c3c4d6ee18dffeb8fa69f14f8f9267f7dc0c34" + integrity sha512-n1sEf85fePoU2aDN2PzYjoI8gbBqnmLGEhKq7q0DKLj0UTVmOTwDC7PtLcy/zFxzASTSBlVQYJUhwIStQMIpRA== + +lightningcss-linux-arm-gnueabihf@1.27.0: + version "1.27.0" + resolved "https://registry.yarnpkg.com/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.27.0.tgz#c7c16432a571ec877bf734fe500e4a43d48c2814" + integrity sha512-MUMRmtdRkOkd5z3h986HOuNBD1c2lq2BSQA1Jg88d9I7bmPGx08bwGcnB75dvr17CwxjxD6XPi3Qh8ArmKFqCA== -lightningcss-darwin-arm64@1.23.0: - version "1.23.0" - resolved "https://registry.yarnpkg.com/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.23.0.tgz#11780f37158a458cead5e89202f74cd99b926e36" - integrity sha512-kl4Pk3Q2lnE6AJ7Qaij47KNEfY2/UXRZBT/zqGA24B8qwkgllr/j7rclKOf1axcslNXvvUdztjo4Xqh39Yq1aA== - -lightningcss-darwin-x64@1.23.0: - version "1.23.0" - resolved "https://registry.yarnpkg.com/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.23.0.tgz#8394edaa04f0984b971eab42b6f68edb1258b3ed" - integrity sha512-KeRFCNoYfDdcolcFXvokVw+PXCapd2yHS1Diko1z1BhRz/nQuD5XyZmxjWdhmhN/zj5sH8YvWsp0/lPLVzqKpg== - -lightningcss-freebsd-x64@1.23.0: - version "1.23.0" - resolved "https://registry.yarnpkg.com/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.23.0.tgz#d3f6faddc424f17ed046e8be9ca97868a5f804ed" - integrity sha512-xhnhf0bWPuZxcqknvMDRFFo2TInrmQRWZGB0f6YoAsZX8Y+epfjHeeOIGCfAmgF0DgZxHwYc8mIR5tQU9/+ROA== - -lightningcss-linux-arm-gnueabihf@1.23.0: - version "1.23.0" - resolved "https://registry.yarnpkg.com/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.23.0.tgz#040e9718c9a9dc088322da33983a894564ffcb10" - integrity sha512-fBamf/bULvmWft9uuX+bZske236pUZEoUlaHNBjnueaCTJ/xd8eXgb0cEc7S5o0Nn6kxlauMBnqJpF70Bgq3zg== - -lightningcss-linux-arm64-gnu@1.23.0: - version "1.23.0" - resolved "https://registry.yarnpkg.com/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.23.0.tgz#05cfcfa2cf47a042ca11cfce520ae9f91e4efcdb" - integrity sha512-RS7sY77yVLOmZD6xW2uEHByYHhQi5JYWmgVumYY85BfNoVI3DupXSlzbw+b45A9NnVKq45+oXkiN6ouMMtTwfg== - -lightningcss-linux-arm64-musl@1.23.0: - version "1.23.0" - resolved "https://registry.yarnpkg.com/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.23.0.tgz#3212a10dff37c70808113fbcf7cbd1b63c6cbc6f" - integrity sha512-cU00LGb6GUXCwof6ACgSMKo3q7XYbsyTj0WsKHLi1nw7pV0NCq8nFTn6ZRBYLoKiV8t+jWl0Hv8KkgymmK5L5g== - -lightningcss-linux-x64-gnu@1.23.0: - version "1.23.0" - resolved "https://registry.yarnpkg.com/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.23.0.tgz#3b27da32889285b1c5de3f26094ee234054634fc" - integrity sha512-q4jdx5+5NfB0/qMbXbOmuC6oo7caPnFghJbIAV90cXZqgV8Am3miZhC4p+sQVdacqxfd+3nrle4C8icR3p1AYw== - -lightningcss-linux-x64-musl@1.23.0: - version "1.23.0" - resolved "https://registry.yarnpkg.com/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.23.0.tgz#ad65b5a944f10d966cc10070bf20f81ddadd4240" - integrity sha512-G9Ri3qpmF4qef2CV/80dADHKXRAQeQXpQTLx7AiQrBYQHqBjB75oxqj06FCIe5g4hNCqLPnM9fsO4CyiT1sFSQ== - -lightningcss-win32-x64-msvc@1.23.0: - version "1.23.0" - resolved "https://registry.yarnpkg.com/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.23.0.tgz#62f3f619a7bb44f8713973103fbe1bcbd9d455f9" - integrity sha512-1rcBDJLU+obPPJM6qR5fgBUiCdZwZLafZM5f9kwjFLkb/UBNIzmae39uCSmh71nzPCTXZqHbvwu23OWnWEz+eg== - -lightningcss@^1.16.1: - version "1.23.0" - resolved "https://registry.yarnpkg.com/lightningcss/-/lightningcss-1.23.0.tgz#58c94a533d02d8416d4f2ec9ab87641f61943c78" - integrity sha512-SEArWKMHhqn/0QzOtclIwH5pXIYQOUEkF8DgICd/105O+GCgd7jxjNod/QPnBCSWvpRHQBGVz5fQ9uScby03zA== +lightningcss-linux-arm64-gnu@1.27.0: + version "1.27.0" + resolved "https://registry.yarnpkg.com/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.27.0.tgz#cfd9e18df1cd65131da286ddacfa3aee6862a752" + integrity sha512-cPsxo1QEWq2sfKkSq2Bq5feQDHdUEwgtA9KaB27J5AX22+l4l0ptgjMZZtYtUnteBofjee+0oW1wQ1guv04a7A== + +lightningcss-linux-arm64-musl@1.27.0: + version "1.27.0" + resolved "https://registry.yarnpkg.com/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.27.0.tgz#6682ff6b9165acef9a6796bd9127a8e1247bb0ed" + integrity sha512-rCGBm2ax7kQ9pBSeITfCW9XSVF69VX+fm5DIpvDZQl4NnQoMQyRwhZQm9pd59m8leZ1IesRqWk2v/DntMo26lg== + +lightningcss-linux-x64-gnu@1.27.0: + version "1.27.0" + resolved "https://registry.yarnpkg.com/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.27.0.tgz#714221212ad184ddfe974bbb7dbe9300dfde4bc0" + integrity sha512-Dk/jovSI7qqhJDiUibvaikNKI2x6kWPN79AQiD/E/KeQWMjdGe9kw51RAgoWFDi0coP4jinaH14Nrt/J8z3U4A== + +lightningcss-linux-x64-musl@1.27.0: + version "1.27.0" + resolved "https://registry.yarnpkg.com/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.27.0.tgz#247958daf622a030a6dc2285afa16b7184bdf21e" + integrity sha512-QKjTxXm8A9s6v9Tg3Fk0gscCQA1t/HMoF7Woy1u68wCk5kS4fR+q3vXa1p3++REW784cRAtkYKrPy6JKibrEZA== + +lightningcss-win32-arm64-msvc@1.27.0: + version "1.27.0" + resolved "https://registry.yarnpkg.com/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.27.0.tgz#64cfe473c264ef5dc275a4d57a516d77fcac6bc9" + integrity sha512-/wXegPS1hnhkeG4OXQKEMQeJd48RDC3qdh+OA8pCuOPCyvnm/yEayrJdJVqzBsqpy1aJklRCVxscpFur80o6iQ== + +lightningcss-win32-x64-msvc@1.27.0: + version "1.27.0" + resolved "https://registry.yarnpkg.com/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.27.0.tgz#237d0dc87d9cdc9cf82536bcbc07426fa9f3f422" + integrity sha512-/OJLj94Zm/waZShL8nB5jsNj3CfNATLCTyFxZyouilfTmSoLDX7VlVAmhPHoZWVFp4vdmoiEbPEYC8HID3m6yw== + +lightningcss@^1.22.1: + version "1.27.0" + resolved "https://registry.yarnpkg.com/lightningcss/-/lightningcss-1.27.0.tgz#d4608e63044343836dd9769f6c8b5d607867649a" + integrity sha512-8f7aNmS1+etYSLHht0fQApPc2kNO8qGRutifN5rVIc6Xo6ABsEbqOr758UwI7ALVbTt4x1fllKt0PYgzD9S3yQ== dependencies: detect-libc "^1.0.3" optionalDependencies: - lightningcss-darwin-arm64 "1.23.0" - lightningcss-darwin-x64 "1.23.0" - lightningcss-freebsd-x64 "1.23.0" - lightningcss-linux-arm-gnueabihf "1.23.0" - lightningcss-linux-arm64-gnu "1.23.0" - lightningcss-linux-arm64-musl "1.23.0" - lightningcss-linux-x64-gnu "1.23.0" - lightningcss-linux-x64-musl "1.23.0" - lightningcss-win32-x64-msvc "1.23.0" + lightningcss-darwin-arm64 "1.27.0" + lightningcss-darwin-x64 "1.27.0" + lightningcss-freebsd-x64 "1.27.0" + lightningcss-linux-arm-gnueabihf "1.27.0" + lightningcss-linux-arm64-gnu "1.27.0" + lightningcss-linux-arm64-musl "1.27.0" + lightningcss-linux-x64-gnu "1.27.0" + lightningcss-linux-x64-musl "1.27.0" + lightningcss-win32-arm64-msvc "1.27.0" + lightningcss-win32-x64-msvc "1.27.0" lines-and-columns@^1.1.6: version "1.2.4" resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.2.4.tgz#eca284f75d2965079309dc0ad9255abb2ebc1632" integrity sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg== -lmdb@2.5.2: - version "2.5.2" - resolved "https://registry.yarnpkg.com/lmdb/-/lmdb-2.5.2.tgz#37e28a9fb43405f4dc48c44cec0e13a14c4a6ff1" - integrity sha512-V5V5Xa2Hp9i2XsbDALkBTeHXnBXh/lEmk9p22zdr7jtuOIY9TGhjK6vAvTpOOx9IKU4hJkRWZxn/HsvR1ELLtA== +lmdb@2.8.5: + version "2.8.5" + resolved "https://registry.yarnpkg.com/lmdb/-/lmdb-2.8.5.tgz#ce191110c755c0951caa062722e300c703973837" + integrity sha512-9bMdFfc80S+vSldBmG3HOuLVHnxRdNTlpzR6QDnzqCQtCzGUEAGTzBKYMeIM+I/sU4oZfgbcbS7X7F65/z/oxQ== dependencies: - msgpackr "^1.5.4" - node-addon-api "^4.3.0" - node-gyp-build-optional-packages "5.0.3" - ordered-binary "^1.2.4" + msgpackr "^1.9.5" + node-addon-api "^6.1.0" + node-gyp-build-optional-packages "5.1.1" + ordered-binary "^1.4.1" weak-lru-cache "^1.2.2" optionalDependencies: - "@lmdb/lmdb-darwin-arm64" "2.5.2" - "@lmdb/lmdb-darwin-x64" "2.5.2" - "@lmdb/lmdb-linux-arm" "2.5.2" - "@lmdb/lmdb-linux-arm64" "2.5.2" - "@lmdb/lmdb-linux-x64" "2.5.2" - "@lmdb/lmdb-win32-x64" "2.5.2" + "@lmdb/lmdb-darwin-arm64" "2.8.5" + "@lmdb/lmdb-darwin-x64" "2.8.5" + "@lmdb/lmdb-linux-arm" "2.8.5" + "@lmdb/lmdb-linux-arm64" "2.8.5" + "@lmdb/lmdb-linux-x64" "2.8.5" + "@lmdb/lmdb-win32-x64" "2.8.5" lodash.get@^4.4.2: version "4.4.2" @@ -2287,12 +2391,12 @@ mdurl@^1.0.0: resolved "https://registry.yarnpkg.com/memoize-one/-/memoize-one-5.2.1.tgz#8337aa3c4335581839ec01c3d594090cebe8f00e" integrity sha512-zYiwtZUcYyXKo/np96AGZAckk+FWWsUdJ3cHGGmld7+AhvcWmQyGCYUh1hc4Q/pkOhb65dQR/pqCyK0cOaHz4Q== -micromatch@^4.0.5: - version "4.0.5" - resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.5.tgz#bc8999a7cbbf77cdc89f132f6e467051b49090c6" - integrity sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA== +micromatch@^4.0.5, micromatch@^4.0.8: + version "4.0.8" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.8.tgz#d66fa18f3a47076789320b9b1af32bd86d9fa202" + integrity sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA== dependencies: - braces "^3.0.2" + braces "^3.0.3" picomatch "^2.3.1" minimatch@^3.1.1: @@ -2302,11 +2406,6 @@ minimatch@^3.1.1: dependencies: brace-expansion "^1.1.7" -moment@^2.29.1: - version "2.29.4" - resolved "https://registry.yarnpkg.com/moment/-/moment-2.29.4.tgz#3dbe052889fe7c1b2ed966fcb3a77328964ef108" - integrity sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w== - ms@2.1.2: version "2.1.2" resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" @@ -2326,17 +2425,17 @@ msgpackr-extract@^3.0.2: "@msgpackr-extract/msgpackr-extract-linux-x64" "3.0.2" "@msgpackr-extract/msgpackr-extract-win32-x64" "3.0.2" -msgpackr@^1.5.4: - version "1.10.1" - resolved "https://registry.yarnpkg.com/msgpackr/-/msgpackr-1.10.1.tgz#51953bb4ce4f3494f0c4af3f484f01cfbb306555" - integrity sha512-r5VRLv9qouXuLiIBrLpl2d5ZvPt8svdQTl5/vMvE4nzDMyEX4sgW5yWhuBBj5UmgwOTWj8CIdSXn5sAfsHAWIQ== +msgpackr@^1.9.5, msgpackr@^1.9.9: + version "1.11.0" + resolved "https://registry.yarnpkg.com/msgpackr/-/msgpackr-1.11.0.tgz#8321d52333048cadc749f56385e3231e65337091" + integrity sha512-I8qXuuALqJe5laEBYoFykChhSXLikZmUhccjGsPuSJ/7uPip2TJ7lwdIQwWSAi0jGZDXv4WOP8Qg65QZRuXxXw== optionalDependencies: msgpackr-extract "^3.0.2" -node-addon-api@^4.3.0: - version "4.3.0" - resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-4.3.0.tgz#52a1a0b475193e0928e98e0426a0d1254782b77f" - integrity sha512-73sE9+3UaLYYFmDsFZnqCInzPyh3MqIwZO9cw58yIqAZhONrrabrYyYe3TuIqtIiOuTXVhsGau8hcrhhwSsDIQ== +node-addon-api@^6.1.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-6.1.0.tgz#ac8470034e58e67d0c6f1204a18ae6995d9c0d76" + integrity sha512-+eawOlIgy680F0kBzPUNFhMZGtJ1YmqM6l4+Crf4IkImjYrO/mqPwRMh352g23uIaQKFItcQ64I7KMaJxHgAVA== node-addon-api@^7.0.0: version "7.1.0" @@ -2350,16 +2449,18 @@ node-emoji@^1.10.0: dependencies: lodash "^4.17.21" -node-gyp-build-optional-packages@5.0.3: - version "5.0.3" - resolved "https://registry.yarnpkg.com/node-gyp-build-optional-packages/-/node-gyp-build-optional-packages-5.0.3.tgz#92a89d400352c44ad3975010368072b41ad66c17" - integrity sha512-k75jcVzk5wnnc/FMxsf4udAoTEUv2jY3ycfdSd3yWu6Cnd1oee6/CfZJApyscA4FJOmdoixWwiwOyf16RzD5JA== - node-gyp-build-optional-packages@5.0.7: version "5.0.7" resolved "https://registry.yarnpkg.com/node-gyp-build-optional-packages/-/node-gyp-build-optional-packages-5.0.7.tgz#5d2632bbde0ab2f6e22f1bbac2199b07244ae0b3" integrity sha512-YlCCc6Wffkx0kHkmam79GKvDQ6x+QZkMjFGrIMxgFNILFvGSbCp2fCBC55pGTT9gVaz8Na5CLmxt/urtzRv36w== +node-gyp-build-optional-packages@5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/node-gyp-build-optional-packages/-/node-gyp-build-optional-packages-5.1.1.tgz#52b143b9dd77b7669073cbfe39e3f4118bfc603c" + integrity sha512-+P72GAjVAbTxjjwUmwjVrqrdZROD4nf8KgpBoDxqXXTiYZZt/ud60dE5yvCSr9lRO8e8yv6kgJIC0K0PfZFVQw== + dependencies: + detect-libc "^2.0.1" + node-releases@^2.0.13: version "2.0.13" resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.13.tgz#d5ed1627c23e3461e819b02e57b75e4899b1c81d" @@ -2404,30 +2505,30 @@ once@^1.3.0: dependencies: wrappy "1" -ordered-binary@^1.2.4: - version "1.5.1" - resolved "https://registry.yarnpkg.com/ordered-binary/-/ordered-binary-1.5.1.tgz#94ccbf14181711081ee23931db0dc3f58aaa0df6" - integrity sha512-5VyHfHY3cd0iza71JepYG50My+YUbrFtGoUz2ooEydPyPM7Aai/JW098juLr+RG6+rDJuzNNTsEQu2DZa1A41A== - -parcel@2.8.3: - version "2.8.3" - resolved "https://registry.yarnpkg.com/parcel/-/parcel-2.8.3.tgz#1ff71d7317274fd367379bc7310a52c6b75d30c2" - integrity sha512-5rMBpbNE72g6jZvkdR5gS2nyhwIXaJy8i65osOqs/+5b7zgf3eMKgjSsDrv6bhz3gzifsba6MBJiZdBckl+vnA== - dependencies: - "@parcel/config-default" "2.8.3" - "@parcel/core" "2.8.3" - "@parcel/diagnostic" "2.8.3" - "@parcel/events" "2.8.3" - "@parcel/fs" "2.8.3" - "@parcel/logger" "2.8.3" - "@parcel/package-manager" "2.8.3" - "@parcel/reporter-cli" "2.8.3" - "@parcel/reporter-dev-server" "2.8.3" - "@parcel/utils" "2.8.3" +ordered-binary@^1.4.1: + version "1.5.2" + resolved "https://registry.yarnpkg.com/ordered-binary/-/ordered-binary-1.5.2.tgz#2007072bcc4cb3454e250ca8ecc994f092ca03dc" + integrity sha512-JTo+4+4Fw7FreyAvlSLjb1BBVaxEQAacmjD3jjuyPZclpbEghTvQZbXBb2qPd2LeIMxiHwXBZUcpmG2Gl/mDEA== + +parcel@^2.12.0: + version "2.12.0" + resolved "https://registry.yarnpkg.com/parcel/-/parcel-2.12.0.tgz#60529c268c2ce0754b225af835f1519da1364298" + integrity sha512-W+gxAq7aQ9dJIg/XLKGcRT0cvnStFAQHPaI0pvD0U2l6IVLueUAm3nwN7lkY62zZNmlvNx6jNtE4wlbS+CyqSg== + dependencies: + "@parcel/config-default" "2.12.0" + "@parcel/core" "2.12.0" + "@parcel/diagnostic" "2.12.0" + "@parcel/events" "2.12.0" + "@parcel/fs" "2.12.0" + "@parcel/logger" "2.12.0" + "@parcel/package-manager" "2.12.0" + "@parcel/reporter-cli" "2.12.0" + "@parcel/reporter-dev-server" "2.12.0" + "@parcel/reporter-tracer" "2.12.0" + "@parcel/utils" "2.12.0" chalk "^4.1.0" commander "^7.0.0" get-port "^4.2.0" - v8-compile-cache "^2.0.0" parent-module@^1.0.0: version "1.0.1" @@ -2527,6 +2628,11 @@ prismjs@~1.27.0: resolved "https://registry.yarnpkg.com/prismjs/-/prismjs-1.27.0.tgz#bb6ee3138a0b438a3653dd4d6ce0cc6510a45057" integrity sha512-t13BGPUlFDR7wRB5kQDG4jjl7XeuH6jbJGt11JHPL96qwsEHNX2+68tFXqc1/k+/jALsbSWJKUOT/hcYAZ5LkA== +process@^0.11.10: + version "0.11.10" + resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182" + integrity sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A== + prop-types@^15.5.8, prop-types@^15.6.0, prop-types@^15.6.2, prop-types@^15.7.2, prop-types@^15.8.1: version "15.8.1" resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.8.1.tgz#67d87bf1a694f48435cf332c24af10214a3140b5" @@ -2869,7 +2975,7 @@ scheduler@^0.20.2: loose-envify "^1.1.0" object-assign "^4.1.1" -semver@^5.7.0, semver@^5.7.1, semver@^6.3.1, semver@^7.5.2: +semver@^6.3.1, semver@^7.5.2: version "7.5.4" resolved "https://registry.yarnpkg.com/semver/-/semver-7.5.4.tgz#483986ec4ed38e1c6c48c34894a9182dbff68a6e" integrity sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA== @@ -3022,16 +3128,6 @@ terser@^5.16.6: commander "^2.20.0" source-map-support "~0.5.20" -terser@^5.2.0: - version "5.27.1" - resolved "https://registry.yarnpkg.com/terser/-/terser-5.27.1.tgz#b0092975ea1b379d166088a1a57e32f0839d84a2" - integrity sha512-29wAr6UU/oQpnTw5HoadwjUZnFQXGdOfj0LjZ4sVxzqwHh/QVkvr7m8y9WoR4iN3FRitVduTc6KdjcW38Npsug== - dependencies: - "@jridgewell/source-map" "^0.3.3" - acorn "^8.8.2" - commander "^2.20.0" - source-map-support "~0.5.20" - text-diff@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/text-diff/-/text-diff-1.0.1.tgz#6c105905435e337857375c9d2f6ca63e453ff565" @@ -3247,11 +3343,6 @@ uuid@^8.3.0: resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2" integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg== -v8-compile-cache@^2.0.0: - version "2.4.0" - resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.4.0.tgz#cdada8bec61e15865f05d097c5f4fd30e94dc128" - integrity sha512-ocyWc3bAHBB/guyqJQVI5o4BZkPhznPYUG2ea80Gond/BgNWpap8TOmLSeeQG7bnh2KMISxskdADG59j7zruhw== - vfile-location@^3.0.0, vfile-location@^3.2.0: version "3.2.0" resolved "https://registry.yarnpkg.com/vfile-location/-/vfile-location-3.2.0.tgz#d8e41fbcbd406063669ebf6c33d56ae8721d0f3c" @@ -3319,11 +3410,6 @@ xtend@^4.0.0, xtend@^4.0.1: resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54" integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ== -xxhash-wasm@^0.4.2: - version "0.4.2" - resolved "https://registry.yarnpkg.com/xxhash-wasm/-/xxhash-wasm-0.4.2.tgz#752398c131a4dd407b5132ba62ad372029be6f79" - integrity sha512-/eyHVRJQCirEkSZ1agRSCwriMhwlyUcFkXD5TPVSLP+IPzjsqMVzZwdoczLp1SoQU0R3dxz1RpIK+4YNQbCVOA== - y18n@^5.0.5: version "5.0.8" resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55" diff --git a/redisinsight/ui/src/packages/redisearch/package.json b/redisinsight/ui/src/packages/redisearch/package.json index 19e8e606e2..7989f290ee 100644 --- a/redisinsight/ui/src/packages/redisearch/package.json +++ b/redisinsight/ui/src/packages/redisearch/package.json @@ -77,6 +77,8 @@ "redisinsight-plugin-sdk": "^1.0.0" }, "resolutions": { + "@parcel/**/micromatch": "^4.0.8", + "@parcel/**/braces": "^3.0.3", "trim": "0.0.3", "**/semver": "^7.5.2" } diff --git a/redisinsight/ui/src/packages/redisearch/yarn.lock b/redisinsight/ui/src/packages/redisearch/yarn.lock index 6c35ff9cf8..fe965d1972 100644 --- a/redisinsight/ui/src/packages/redisearch/yarn.lock +++ b/redisinsight/ui/src/packages/redisearch/yarn.lock @@ -1213,12 +1213,12 @@ brace@^0.11.1: resolved "https://registry.yarnpkg.com/brace/-/brace-0.11.1.tgz#4896fcc9d544eef45f4bb7660db320d3b379fe58" integrity sha512-Fc8Ne62jJlKHiG/ajlonC4Sd66Pq68fFwK4ihJGNZpGqboc324SQk+lRvMzpPRuJOmfrJefdG8/7JdWX4bzJ2Q== -braces@^3.0.2, braces@~3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" - integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A== +braces@^3.0.3, braces@~3.0.2: + version "3.0.3" + resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.3.tgz#490332f40919452272d55a8480adc0c441358789" + integrity sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA== dependencies: - fill-range "^7.0.1" + fill-range "^7.1.1" browserslist@^4.6.6: version "4.23.0" @@ -1590,10 +1590,10 @@ file-selector@^0.4.0: dependencies: tslib "^2.0.3" -fill-range@^7.0.1: - version "7.0.1" - resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40" - integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ== +fill-range@^7.1.1: + version "7.1.1" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.1.1.tgz#44265d3cac07e3ea7dc247516380643754a05292" + integrity sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg== dependencies: to-regex-range "^5.0.1" @@ -2093,12 +2093,12 @@ mdurl@^1.0.0: resolved "https://registry.yarnpkg.com/memoize-one/-/memoize-one-5.2.1.tgz#8337aa3c4335581839ec01c3d594090cebe8f00e" integrity sha512-zYiwtZUcYyXKo/np96AGZAckk+FWWsUdJ3cHGGmld7+AhvcWmQyGCYUh1hc4Q/pkOhb65dQR/pqCyK0cOaHz4Q== -micromatch@^4.0.5: - version "4.0.5" - resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.5.tgz#bc8999a7cbbf77cdc89f132f6e467051b49090c6" - integrity sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA== +micromatch@^4.0.5, micromatch@^4.0.8: + version "4.0.8" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.8.tgz#d66fa18f3a47076789320b9b1af32bd86d9fa202" + integrity sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA== dependencies: - braces "^3.0.2" + braces "^3.0.3" picomatch "^2.3.1" minimatch@^3.1.1: diff --git a/redisinsight/ui/src/packages/redisgraph/package.json b/redisinsight/ui/src/packages/redisgraph/package.json index 9d2b9e099f..0bc431307e 100644 --- a/redisinsight/ui/src/packages/redisgraph/package.json +++ b/redisinsight/ui/src/packages/redisgraph/package.json @@ -64,6 +64,8 @@ "redisinsight-plugin-sdk": "^1.1.0" }, "resolutions": { + "@parcel/**/micromatch": "^4.0.8", + "@parcel/**/braces": "^3.0.3", "trim": "0.0.3", "**/semver": "^7.5.2" } diff --git a/redisinsight/ui/src/packages/redisgraph/yarn.lock b/redisinsight/ui/src/packages/redisgraph/yarn.lock index 9c008fa945..2f6df8f16c 100644 --- a/redisinsight/ui/src/packages/redisgraph/yarn.lock +++ b/redisinsight/ui/src/packages/redisgraph/yarn.lock @@ -1423,12 +1423,12 @@ brace@^0.11.1: resolved "https://registry.yarnpkg.com/brace/-/brace-0.11.1.tgz#4896fcc9d544eef45f4bb7660db320d3b379fe58" integrity sha512-Fc8Ne62jJlKHiG/ajlonC4Sd66Pq68fFwK4ihJGNZpGqboc324SQk+lRvMzpPRuJOmfrJefdG8/7JdWX4bzJ2Q== -braces@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" - integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A== +braces@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.3.tgz#490332f40919452272d55a8480adc0c441358789" + integrity sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA== dependencies: - fill-range "^7.0.1" + fill-range "^7.1.1" browserslist@^4.0.0, browserslist@^4.21.4, browserslist@^4.6.6: version "4.23.0" @@ -2153,10 +2153,10 @@ file-selector@^0.4.0: dependencies: tslib "^2.0.3" -fill-range@^7.0.1: - version "7.0.1" - resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40" - integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ== +fill-range@^7.1.1: + version "7.1.1" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.1.1.tgz#44265d3cac07e3ea7dc247516380643754a05292" + integrity sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg== dependencies: to-regex-range "^5.0.1" @@ -2676,12 +2676,12 @@ mdurl@^1.0.0: resolved "https://registry.yarnpkg.com/memoize-one/-/memoize-one-5.2.1.tgz#8337aa3c4335581839ec01c3d594090cebe8f00e" integrity sha512-zYiwtZUcYyXKo/np96AGZAckk+FWWsUdJ3cHGGmld7+AhvcWmQyGCYUh1hc4Q/pkOhb65dQR/pqCyK0cOaHz4Q== -micromatch@^4.0.5: - version "4.0.5" - resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.5.tgz#bc8999a7cbbf77cdc89f132f6e467051b49090c6" - integrity sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA== +micromatch@^4.0.5, micromatch@^4.0.8: + version "4.0.8" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.8.tgz#d66fa18f3a47076789320b9b1af32bd86d9fa202" + integrity sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA== dependencies: - braces "^3.0.2" + braces "^3.0.3" picomatch "^2.3.1" mime@^1.4.1: diff --git a/redisinsight/ui/src/packages/redistimeseries-app/package.json b/redisinsight/ui/src/packages/redistimeseries-app/package.json index f1f83470d2..17ec45aa8a 100644 --- a/redisinsight/ui/src/packages/redistimeseries-app/package.json +++ b/redisinsight/ui/src/packages/redistimeseries-app/package.json @@ -53,11 +53,11 @@ "concurrently": "^7.6.0", "cross-env": "^7.0.3", "esbuild": "^0.17.12", - "jest": "^27.5.1", + "jest": "^29.7.0", "less": "^4.1.2", "parcel": "^2.8.3", "rimraf": "^3.0.2", - "ts-jest": "^27.1.4" + "ts-jest": "^29.2.5" }, "dependencies": { "@elastic/eui": "34.6.0", @@ -71,6 +71,9 @@ "react-dom": "^17.0.2" }, "resolutions": { + "@parcel/**/micromatch": "^4.0.8", + "jest/**/micromatch": "^4.0.8", + "@parcel/**/braces": "^3.0.3", "trim": "0.0.3", "**/semver": "^7.5.2" } diff --git a/redisinsight/ui/src/packages/redistimeseries-app/yarn.lock b/redisinsight/ui/src/packages/redistimeseries-app/yarn.lock index 73aea0a3af..c0ce302055 100644 --- a/redisinsight/ui/src/packages/redistimeseries-app/yarn.lock +++ b/redisinsight/ui/src/packages/redistimeseries-app/yarn.lock @@ -25,12 +25,46 @@ "@babel/highlight" "^7.22.13" chalk "^2.4.2" +"@babel/code-frame@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.25.7.tgz#438f2c524071531d643c6f0188e1e28f130cebc7" + integrity sha512-0xZJFNE5XMpENsgfHYTw8FbX4kv53mFLn2i3XPoq69LyhYSCBJtitaHx9QnsVTrsogI4Z3+HtEfZ2/GFPOtf5g== + dependencies: + "@babel/highlight" "^7.25.7" + picocolors "^1.0.0" + "@babel/compat-data@^7.22.9": version "7.23.2" resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.23.2.tgz#6a12ced93455827037bfb5ed8492820d60fc32cc" integrity sha512-0S9TQMmDHlqAZ2ITT95irXKfxN9bncq8ZCoJhun3nHL/lLUxd2NKBJYoNGWH7S0hz6fRQwWlAWn/ILM0C70KZQ== -"@babel/core@^7.1.0", "@babel/core@^7.12.3", "@babel/core@^7.7.2", "@babel/core@^7.8.0": +"@babel/compat-data@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.25.7.tgz#b8479fe0018ef0ac87b6b7a5c6916fcd67ae2c9c" + integrity sha512-9ickoLz+hcXCeh7jrcin+/SLWm+GkxE2kTvoYyp38p4WkdFXfQJxDFGWp/YHjiKLPx06z2A7W8XKuqbReXDzsw== + +"@babel/core@^7.11.6", "@babel/core@^7.23.9": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.25.7.tgz#1b3d144157575daf132a3bc80b2b18e6e3ca6ece" + integrity sha512-yJ474Zv3cwiSOO9nXJuqzvwEeM+chDuQ8GJirw+pZ91sCGCyOZ3dJkVE09fTV0VEVzXyLWhh3G/AolYTPX7Mow== + dependencies: + "@ampproject/remapping" "^2.2.0" + "@babel/code-frame" "^7.25.7" + "@babel/generator" "^7.25.7" + "@babel/helper-compilation-targets" "^7.25.7" + "@babel/helper-module-transforms" "^7.25.7" + "@babel/helpers" "^7.25.7" + "@babel/parser" "^7.25.7" + "@babel/template" "^7.25.7" + "@babel/traverse" "^7.25.7" + "@babel/types" "^7.25.7" + convert-source-map "^2.0.0" + debug "^4.1.0" + gensync "^1.0.0-beta.2" + json5 "^2.2.3" + semver "^6.3.1" + +"@babel/core@^7.12.3": version "7.23.2" resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.23.2.tgz#ed10df0d580fff67c5f3ee70fd22e2e4c90a9f94" integrity sha512-n7s51eWdaWZ3vGT2tD4T7J6eJs3QoBXydv7vkUM06Bf1cbVD2Kc2UrkzhiQwobfV7NwOnQXYL7UBJ5VPU+RGoQ== @@ -61,6 +95,16 @@ "@jridgewell/trace-mapping" "^0.3.17" jsesc "^2.5.1" +"@babel/generator@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.25.7.tgz#de86acbeb975a3e11ee92dd52223e6b03b479c56" + integrity sha512-5Dqpl5fyV9pIAD62yK9P7fcA768uVPUyrQmqpqstHWgMma4feF1x/oFysBCVZLY5wJ2GkMUCdsNDnGZrPoR6rA== + dependencies: + "@babel/types" "^7.25.7" + "@jridgewell/gen-mapping" "^0.3.5" + "@jridgewell/trace-mapping" "^0.3.25" + jsesc "^3.0.2" + "@babel/helper-compilation-targets@^7.22.15": version "7.22.15" resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.22.15.tgz#0698fc44551a26cf29f18d4662d5bf545a6cfc52" @@ -72,6 +116,17 @@ lru-cache "^5.1.1" semver "^6.3.1" +"@babel/helper-compilation-targets@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.25.7.tgz#11260ac3322dda0ef53edfae6e97b961449f5fa4" + integrity sha512-DniTEax0sv6isaw6qSQSfV4gVRNtw2rte8HHM45t9ZR0xILaufBRNkpMifCRiAPyvL4ACD6v0gfCwCmtOQaV4A== + dependencies: + "@babel/compat-data" "^7.25.7" + "@babel/helper-validator-option" "^7.25.7" + browserslist "^4.24.0" + lru-cache "^5.1.1" + semver "^6.3.1" + "@babel/helper-environment-visitor@^7.22.20": version "7.22.20" resolved "https://registry.yarnpkg.com/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz#96159db61d34a29dba454c959f5ae4a649ba9167" @@ -106,6 +161,14 @@ dependencies: "@babel/types" "^7.22.15" +"@babel/helper-module-imports@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.25.7.tgz#dba00d9523539152906ba49263e36d7261040472" + integrity sha512-o0xCgpNmRohmnoWKQ0Ij8IdddjyBFE4T2kagL/x6M3+4zUgc+4qTOUBoNe4XxDskt1HPKO007ZPiMgLDq2s7Kw== + dependencies: + "@babel/traverse" "^7.25.7" + "@babel/types" "^7.25.7" + "@babel/helper-module-transforms@^7.23.0": version "7.23.0" resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.23.0.tgz#3ec246457f6c842c0aee62a01f60739906f7047e" @@ -117,11 +180,26 @@ "@babel/helper-split-export-declaration" "^7.22.6" "@babel/helper-validator-identifier" "^7.22.20" +"@babel/helper-module-transforms@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.25.7.tgz#2ac9372c5e001b19bc62f1fe7d96a18cb0901d1a" + integrity sha512-k/6f8dKG3yDz/qCwSM+RKovjMix563SLxQFo0UhRNo239SP6n9u5/eLtKD6EAjwta2JHJ49CsD8pms2HdNiMMQ== + dependencies: + "@babel/helper-module-imports" "^7.25.7" + "@babel/helper-simple-access" "^7.25.7" + "@babel/helper-validator-identifier" "^7.25.7" + "@babel/traverse" "^7.25.7" + "@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.12.13", "@babel/helper-plugin-utils@^7.14.5", "@babel/helper-plugin-utils@^7.22.5", "@babel/helper-plugin-utils@^7.8.0": version "7.22.5" resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz#dd7ee3735e8a313b9f7b05a773d892e88e6d7295" integrity sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg== +"@babel/helper-plugin-utils@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.25.7.tgz#8ec5b21812d992e1ef88a9b068260537b6f0e36c" + integrity sha512-eaPZai0PiqCi09pPs3pAFfl/zYgGaE6IdXtYvmf0qlcDTd3WCtO7JWCcRd64e0EQrcYgiHibEZnOGsSY4QSgaw== + "@babel/helper-simple-access@^7.22.5": version "7.22.5" resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.22.5.tgz#4938357dc7d782b80ed6dbb03a0fba3d22b1d5de" @@ -129,6 +207,14 @@ dependencies: "@babel/types" "^7.22.5" +"@babel/helper-simple-access@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.25.7.tgz#5eb9f6a60c5d6b2e0f76057004f8dacbddfae1c0" + integrity sha512-FPGAkJmyoChQeM+ruBGIDyrT2tKfZJO8NcxdC+CWNJi7N8/rZpSxK7yvBJ5O/nF1gfu5KzN7VKG3YVSLFfRSxQ== + dependencies: + "@babel/traverse" "^7.25.7" + "@babel/types" "^7.25.7" + "@babel/helper-split-export-declaration@^7.22.6": version "7.22.6" resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz#322c61b7310c0997fe4c323955667f18fcefb91c" @@ -146,6 +232,11 @@ resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.22.5.tgz#533f36457a25814cf1df6488523ad547d784a99f" integrity sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw== +"@babel/helper-string-parser@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.25.7.tgz#d50e8d37b1176207b4fe9acedec386c565a44a54" + integrity sha512-CbkjYdsJNHFk8uqpEkpCvRs3YRp9tY6FmFY7wLMSYuGYkrdUi7r2lc4/wqsvlHoMznX3WJ9IP8giGPq68T/Y6g== + "@babel/helper-validator-identifier@^7.18.6", "@babel/helper-validator-identifier@^7.19.1": version "7.19.1" resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz#7eea834cf32901ffdc1a7ee555e2f9c27e249ca2" @@ -156,11 +247,21 @@ resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz#c4ae002c61d2879e724581d96665583dbc1dc0e0" integrity sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A== +"@babel/helper-validator-identifier@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.7.tgz#77b7f60c40b15c97df735b38a66ba1d7c3e93da5" + integrity sha512-AM6TzwYqGChO45oiuPqwL2t20/HdMC1rTPAesnBCgPCSF1x3oN9MVUwQV2iyz4xqWrctwK5RNC8LV22kaQCNYg== + "@babel/helper-validator-option@^7.22.15": version "7.22.15" resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.22.15.tgz#694c30dfa1d09a6534cdfcafbe56789d36aba040" integrity sha512-bMn7RmyFjY/mdECUbgn9eoSY4vqvacUnS9i9vGAGttgFWesO6B4CYWA7XlpbWgBt71iv/hfbPlynohStqnu5hA== +"@babel/helper-validator-option@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.25.7.tgz#97d1d684448228b30b506d90cace495d6f492729" + integrity sha512-ytbPLsm+GjArDYXJ8Ydr1c/KJuutjF2besPNbIZnZ6MKUxi/uTA22t2ymmA4WFjZFpjiAMO0xuuJPqK2nvDVfQ== + "@babel/helpers@^7.23.2": version "7.23.2" resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.23.2.tgz#2832549a6e37d484286e15ba36a5330483cac767" @@ -170,6 +271,14 @@ "@babel/traverse" "^7.23.2" "@babel/types" "^7.23.0" +"@babel/helpers@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.25.7.tgz#091b52cb697a171fe0136ab62e54e407211f09c2" + integrity sha512-Sv6pASx7Esm38KQpF/U/OXLwPPrdGHNKoeblRxgZRLXnAtnkEe4ptJPDtAZM7fBLadbc1Q07kQpSiGQ0Jg6tRA== + dependencies: + "@babel/template" "^7.25.7" + "@babel/types" "^7.25.7" + "@babel/highlight@^7.18.6": version "7.18.6" resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.18.6.tgz#81158601e93e2563795adcbfbdf5d64be3f2ecdf" @@ -188,11 +297,28 @@ chalk "^2.4.2" js-tokens "^4.0.0" +"@babel/highlight@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.25.7.tgz#20383b5f442aa606e7b5e3043b0b1aafe9f37de5" + integrity sha512-iYyACpW3iW8Fw+ZybQK+drQre+ns/tKpXbNESfrhNnPLIklLbXr7MYJ6gPEd0iETGLOK+SxMjVvKb/ffmk+FEw== + dependencies: + "@babel/helper-validator-identifier" "^7.25.7" + chalk "^2.4.2" + js-tokens "^4.0.0" + picocolors "^1.0.0" + "@babel/parser@^7.1.0", "@babel/parser@^7.14.7", "@babel/parser@^7.20.7", "@babel/parser@^7.22.15", "@babel/parser@^7.23.0": version "7.23.0" resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.23.0.tgz#da950e622420bf96ca0d0f2909cdddac3acd8719" integrity sha512-vvPKKdMemU85V9WE/l5wZEmImpCtLqbnTvqDS2U1fJ96KrxoW7KrXhNsNCblQlg8Ck4b85yxdTyelsMUgFUXiw== +"@babel/parser@^7.23.9", "@babel/parser@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.25.7.tgz#99b927720f4ddbfeb8cd195a363ed4532f87c590" + integrity sha512-aZn7ETtQsjjGG5HruveUK06cU3Hljuhd9Iojm4M8WWv3wLE6OkE5PWbDUkItmMgegmccaITudyuW5RPYrYlgWw== + dependencies: + "@babel/types" "^7.25.7" + "@babel/plugin-syntax-async-generators@^7.8.4": version "7.8.4" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz#a983fb1aeb2ec3f6ed042a210f640e90e786fe0d" @@ -228,6 +354,13 @@ dependencies: "@babel/helper-plugin-utils" "^7.8.0" +"@babel/plugin-syntax-jsx@^7.7.2": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.25.7.tgz#5352d398d11ea5e7ef330c854dea1dae0bf18165" + integrity sha512-ruZOnKO+ajVL/MVx+PwNBPOkrnXTXoWMtte1MBpegfCArhqOe3Bj52avVj1huLLxNKYKXYaSxZ2F+woK1ekXfw== + dependencies: + "@babel/helper-plugin-utils" "^7.25.7" + "@babel/plugin-syntax-logical-assignment-operators@^7.8.3": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz#ca91ef46303530448b906652bac2e9fe9941f699" @@ -300,7 +433,16 @@ "@babel/parser" "^7.22.15" "@babel/types" "^7.22.15" -"@babel/traverse@^7.23.2", "@babel/traverse@^7.7.2": +"@babel/template@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.25.7.tgz#27f69ce382855d915b14ab0fe5fb4cbf88fa0769" + integrity sha512-wRwtAgI3bAS+JGU2upWNL9lSlDcRCqD05BZ1n3X2ONLH1WilFP6O1otQjeMK/1g0pvYcXC7b/qVUB1keofjtZA== + dependencies: + "@babel/code-frame" "^7.25.7" + "@babel/parser" "^7.25.7" + "@babel/types" "^7.25.7" + +"@babel/traverse@^7.23.2": version "7.23.2" resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.23.2.tgz#329c7a06735e144a506bdb2cad0268b7f46f4ad8" integrity sha512-azpe59SQ48qG6nu2CzcMLbxUudtN+dOM9kDbUqGq3HXUJRlo7i8fvPoxQUzYgLZ4cMVmuZgm8vvBpNeRhd6XSw== @@ -316,6 +458,19 @@ debug "^4.1.0" globals "^11.1.0" +"@babel/traverse@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.25.7.tgz#83e367619be1cab8e4f2892ef30ba04c26a40fa8" + integrity sha512-jatJPT1Zjqvh/1FyJs6qAHL+Dzb7sTb+xr7Q+gM1b+1oBsMsQQ4FkVKb6dFlJvLlVssqkRzV05Jzervt9yhnzg== + dependencies: + "@babel/code-frame" "^7.25.7" + "@babel/generator" "^7.25.7" + "@babel/parser" "^7.25.7" + "@babel/template" "^7.25.7" + "@babel/types" "^7.25.7" + debug "^4.3.1" + globals "^11.1.0" + "@babel/types@^7.0.0", "@babel/types@^7.20.7", "@babel/types@^7.22.15", "@babel/types@^7.22.5", "@babel/types@^7.23.0", "@babel/types@^7.3.3": version "7.23.0" resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.23.0.tgz#8c1f020c9df0e737e4e247c0619f58c68458aaeb" @@ -334,6 +489,15 @@ "@babel/helper-validator-identifier" "^7.19.1" to-fast-properties "^2.0.0" +"@babel/types@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.25.7.tgz#1b7725c1d3a59f328cb700ce704c46371e6eef9b" + integrity sha512-vwIVdXG+j+FOpkwqHRcBgHLYNL7XMkufrlaFvL9o6Ai9sJn9+PdyIL5qa0XzTZw084c+u9LOls53eoZWP/W5WQ== + dependencies: + "@babel/helper-string-parser" "^7.25.7" + "@babel/helper-validator-identifier" "^7.25.7" + to-fast-properties "^2.0.0" + "@bcoe/v8-coverage@^0.2.3": version "0.2.3" resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39" @@ -592,178 +756,201 @@ js-yaml "^3.13.1" resolve-from "^5.0.0" -"@istanbuljs/schema@^0.1.2": +"@istanbuljs/schema@^0.1.2", "@istanbuljs/schema@^0.1.3": version "0.1.3" resolved "https://registry.yarnpkg.com/@istanbuljs/schema/-/schema-0.1.3.tgz#e45e384e4b8ec16bce2fd903af78450f6bf7ec98" integrity sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA== -"@jest/console@^27.5.1": - version "27.5.1" - resolved "https://registry.yarnpkg.com/@jest/console/-/console-27.5.1.tgz#260fe7239602fe5130a94f1aa386eff54b014bba" - integrity sha512-kZ/tNpS3NXn0mlXXXPNuDZnb4c0oZ20r4K5eemM2k30ZC3G0T02nXUvyhf5YdbXWHPEJLc9qGLxEZ216MdL+Zg== +"@jest/console@^29.7.0": + version "29.7.0" + resolved "https://registry.yarnpkg.com/@jest/console/-/console-29.7.0.tgz#cd4822dbdb84529265c5a2bdb529a3c9cc950ffc" + integrity sha512-5Ni4CU7XHQi32IJ398EEP4RrB8eV09sXP2ROqD4bksHrnTree52PsxvX8tpL8LvTZ3pFzXyPbNQReSN41CAhOg== dependencies: - "@jest/types" "^27.5.1" + "@jest/types" "^29.6.3" "@types/node" "*" chalk "^4.0.0" - jest-message-util "^27.5.1" - jest-util "^27.5.1" + jest-message-util "^29.7.0" + jest-util "^29.7.0" slash "^3.0.0" -"@jest/core@^27.5.1": - version "27.5.1" - resolved "https://registry.yarnpkg.com/@jest/core/-/core-27.5.1.tgz#267ac5f704e09dc52de2922cbf3af9edcd64b626" - integrity sha512-AK6/UTrvQD0Cd24NSqmIA6rKsu0tKIxfiCducZvqxYdmMisOYAsdItspT+fQDQYARPf8XgjAFZi0ogW2agH5nQ== - dependencies: - "@jest/console" "^27.5.1" - "@jest/reporters" "^27.5.1" - "@jest/test-result" "^27.5.1" - "@jest/transform" "^27.5.1" - "@jest/types" "^27.5.1" +"@jest/core@^29.7.0": + version "29.7.0" + resolved "https://registry.yarnpkg.com/@jest/core/-/core-29.7.0.tgz#b6cccc239f30ff36609658c5a5e2291757ce448f" + integrity sha512-n7aeXWKMnGtDA48y8TLWJPJmLmmZ642Ceo78cYWEpiD7FzDgmNDV/GCVRorPABdXLJZ/9wzzgZAlHjXjxDHGsg== + dependencies: + "@jest/console" "^29.7.0" + "@jest/reporters" "^29.7.0" + "@jest/test-result" "^29.7.0" + "@jest/transform" "^29.7.0" + "@jest/types" "^29.6.3" "@types/node" "*" ansi-escapes "^4.2.1" chalk "^4.0.0" - emittery "^0.8.1" + ci-info "^3.2.0" exit "^0.1.2" graceful-fs "^4.2.9" - jest-changed-files "^27.5.1" - jest-config "^27.5.1" - jest-haste-map "^27.5.1" - jest-message-util "^27.5.1" - jest-regex-util "^27.5.1" - jest-resolve "^27.5.1" - jest-resolve-dependencies "^27.5.1" - jest-runner "^27.5.1" - jest-runtime "^27.5.1" - jest-snapshot "^27.5.1" - jest-util "^27.5.1" - jest-validate "^27.5.1" - jest-watcher "^27.5.1" + jest-changed-files "^29.7.0" + jest-config "^29.7.0" + jest-haste-map "^29.7.0" + jest-message-util "^29.7.0" + jest-regex-util "^29.6.3" + jest-resolve "^29.7.0" + jest-resolve-dependencies "^29.7.0" + jest-runner "^29.7.0" + jest-runtime "^29.7.0" + jest-snapshot "^29.7.0" + jest-util "^29.7.0" + jest-validate "^29.7.0" + jest-watcher "^29.7.0" micromatch "^4.0.4" - rimraf "^3.0.0" + pretty-format "^29.7.0" slash "^3.0.0" strip-ansi "^6.0.0" -"@jest/environment@^27.5.1": - version "27.5.1" - resolved "https://registry.yarnpkg.com/@jest/environment/-/environment-27.5.1.tgz#d7425820511fe7158abbecc010140c3fd3be9c74" - integrity sha512-/WQjhPJe3/ghaol/4Bq480JKXV/Rfw8nQdN7f41fM8VDHLcxKXou6QyXAh3EFr9/bVG3x74z1NWDkP87EiY8gA== +"@jest/environment@^29.7.0": + version "29.7.0" + resolved "https://registry.yarnpkg.com/@jest/environment/-/environment-29.7.0.tgz#24d61f54ff1f786f3cd4073b4b94416383baf2a7" + integrity sha512-aQIfHDq33ExsN4jP1NWGXhxgQ/wixs60gDiKO+XVMd8Mn0NWPWgc34ZQDTb2jKaUWQ7MuwoitXAsN2XVXNMpAw== dependencies: - "@jest/fake-timers" "^27.5.1" - "@jest/types" "^27.5.1" + "@jest/fake-timers" "^29.7.0" + "@jest/types" "^29.6.3" "@types/node" "*" - jest-mock "^27.5.1" + jest-mock "^29.7.0" -"@jest/fake-timers@^27.5.1": - version "27.5.1" - resolved "https://registry.yarnpkg.com/@jest/fake-timers/-/fake-timers-27.5.1.tgz#76979745ce0579c8a94a4678af7a748eda8ada74" - integrity sha512-/aPowoolwa07k7/oM3aASneNeBGCmGQsc3ugN4u6s4C/+s5M64MFo/+djTdiwcbQlRfFElGuDXWzaWj6QgKObQ== +"@jest/expect-utils@^29.7.0": + version "29.7.0" + resolved "https://registry.yarnpkg.com/@jest/expect-utils/-/expect-utils-29.7.0.tgz#023efe5d26a8a70f21677d0a1afc0f0a44e3a1c6" + integrity sha512-GlsNBWiFQFCVi9QVSx7f5AgMeLxe9YCCs5PuP2O2LdjDAA8Jh9eX7lA1Jq/xdXw3Wb3hyvlFNfZIfcRetSzYcA== + dependencies: + jest-get-type "^29.6.3" + +"@jest/expect@^29.7.0": + version "29.7.0" + resolved "https://registry.yarnpkg.com/@jest/expect/-/expect-29.7.0.tgz#76a3edb0cb753b70dfbfe23283510d3d45432bf2" + integrity sha512-8uMeAMycttpva3P1lBHB8VciS9V0XAr3GymPpipdyQXbBcuhkLQOSe8E/p92RyAdToS6ZD1tFkX+CkhoECE0dQ== + dependencies: + expect "^29.7.0" + jest-snapshot "^29.7.0" + +"@jest/fake-timers@^29.7.0": + version "29.7.0" + resolved "https://registry.yarnpkg.com/@jest/fake-timers/-/fake-timers-29.7.0.tgz#fd91bf1fffb16d7d0d24a426ab1a47a49881a565" + integrity sha512-q4DH1Ha4TTFPdxLsqDXK1d3+ioSL7yL5oCMJZgDYm6i+6CygW5E5xVr/D1HdsGxjt1ZWSfUAs9OxSB/BNelWrQ== dependencies: - "@jest/types" "^27.5.1" - "@sinonjs/fake-timers" "^8.0.1" + "@jest/types" "^29.6.3" + "@sinonjs/fake-timers" "^10.0.2" "@types/node" "*" - jest-message-util "^27.5.1" - jest-mock "^27.5.1" - jest-util "^27.5.1" + jest-message-util "^29.7.0" + jest-mock "^29.7.0" + jest-util "^29.7.0" -"@jest/globals@^27.5.1": - version "27.5.1" - resolved "https://registry.yarnpkg.com/@jest/globals/-/globals-27.5.1.tgz#7ac06ce57ab966566c7963431cef458434601b2b" - integrity sha512-ZEJNB41OBQQgGzgyInAv0UUfDDj3upmHydjieSxFvTRuZElrx7tXg/uVQ5hYVEwiXs3+aMsAeEc9X7xiSKCm4Q== +"@jest/globals@^29.7.0": + version "29.7.0" + resolved "https://registry.yarnpkg.com/@jest/globals/-/globals-29.7.0.tgz#8d9290f9ec47ff772607fa864ca1d5a2efae1d4d" + integrity sha512-mpiz3dutLbkW2MNFubUGUEVLkTGiqW6yLVTA+JbP6fI6J5iL9Y0Nlg8k95pcF8ctKwCS7WVxteBs29hhfAotzQ== dependencies: - "@jest/environment" "^27.5.1" - "@jest/types" "^27.5.1" - expect "^27.5.1" + "@jest/environment" "^29.7.0" + "@jest/expect" "^29.7.0" + "@jest/types" "^29.6.3" + jest-mock "^29.7.0" -"@jest/reporters@^27.5.1": - version "27.5.1" - resolved "https://registry.yarnpkg.com/@jest/reporters/-/reporters-27.5.1.tgz#ceda7be96170b03c923c37987b64015812ffec04" - integrity sha512-cPXh9hWIlVJMQkVk84aIvXuBB4uQQmFqZiacloFuGiP3ah1sbCxCosidXFDfqG8+6fO1oR2dTJTlsOy4VFmUfw== +"@jest/reporters@^29.7.0": + version "29.7.0" + resolved "https://registry.yarnpkg.com/@jest/reporters/-/reporters-29.7.0.tgz#04b262ecb3b8faa83b0b3d321623972393e8f4c7" + integrity sha512-DApq0KJbJOEzAFYjHADNNxAE3KbhxQB1y5Kplb5Waqw6zVbuWatSnMjE5gs8FUgEPmNsnZA3NCWl9NG0ia04Pg== dependencies: "@bcoe/v8-coverage" "^0.2.3" - "@jest/console" "^27.5.1" - "@jest/test-result" "^27.5.1" - "@jest/transform" "^27.5.1" - "@jest/types" "^27.5.1" + "@jest/console" "^29.7.0" + "@jest/test-result" "^29.7.0" + "@jest/transform" "^29.7.0" + "@jest/types" "^29.6.3" + "@jridgewell/trace-mapping" "^0.3.18" "@types/node" "*" chalk "^4.0.0" collect-v8-coverage "^1.0.0" exit "^0.1.2" - glob "^7.1.2" + glob "^7.1.3" graceful-fs "^4.2.9" istanbul-lib-coverage "^3.0.0" - istanbul-lib-instrument "^5.1.0" + istanbul-lib-instrument "^6.0.0" istanbul-lib-report "^3.0.0" istanbul-lib-source-maps "^4.0.0" istanbul-reports "^3.1.3" - jest-haste-map "^27.5.1" - jest-resolve "^27.5.1" - jest-util "^27.5.1" - jest-worker "^27.5.1" + jest-message-util "^29.7.0" + jest-util "^29.7.0" + jest-worker "^29.7.0" slash "^3.0.0" - source-map "^0.6.0" string-length "^4.0.1" - terminal-link "^2.0.0" - v8-to-istanbul "^8.1.0" + strip-ansi "^6.0.0" + v8-to-istanbul "^9.0.1" -"@jest/source-map@^27.5.1": - version "27.5.1" - resolved "https://registry.yarnpkg.com/@jest/source-map/-/source-map-27.5.1.tgz#6608391e465add4205eae073b55e7f279e04e8cf" - integrity sha512-y9NIHUYF3PJRlHk98NdC/N1gl88BL08aQQgu4k4ZopQkCw9t9cV8mtl3TV8b/YCB8XaVTFrmUTAJvjsntDireg== +"@jest/schemas@^29.6.3": + version "29.6.3" + resolved "https://registry.yarnpkg.com/@jest/schemas/-/schemas-29.6.3.tgz#430b5ce8a4e0044a7e3819663305a7b3091c8e03" + integrity sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA== dependencies: + "@sinclair/typebox" "^0.27.8" + +"@jest/source-map@^29.6.3": + version "29.6.3" + resolved "https://registry.yarnpkg.com/@jest/source-map/-/source-map-29.6.3.tgz#d90ba772095cf37a34a5eb9413f1b562a08554c4" + integrity sha512-MHjT95QuipcPrpLM+8JMSzFx6eHp5Bm+4XeFDJlwsvVBjmKNiIAvasGK2fxz2WbGRlnvqehFbh07MMa7n3YJnw== + dependencies: + "@jridgewell/trace-mapping" "^0.3.18" callsites "^3.0.0" graceful-fs "^4.2.9" - source-map "^0.6.0" -"@jest/test-result@^27.5.1": - version "27.5.1" - resolved "https://registry.yarnpkg.com/@jest/test-result/-/test-result-27.5.1.tgz#56a6585fa80f7cdab72b8c5fc2e871d03832f5bb" - integrity sha512-EW35l2RYFUcUQxFJz5Cv5MTOxlJIQs4I7gxzi2zVU7PJhOwfYq1MdC5nhSmYjX1gmMmLPvB3sIaC+BkcHRBfag== +"@jest/test-result@^29.7.0": + version "29.7.0" + resolved "https://registry.yarnpkg.com/@jest/test-result/-/test-result-29.7.0.tgz#8db9a80aa1a097bb2262572686734baed9b1657c" + integrity sha512-Fdx+tv6x1zlkJPcWXmMDAG2HBnaR9XPSd5aDWQVsfrZmLVT3lU1cwyxLgRmXR9yrq4NBoEm9BMsfgFzTQAbJYA== dependencies: - "@jest/console" "^27.5.1" - "@jest/types" "^27.5.1" + "@jest/console" "^29.7.0" + "@jest/types" "^29.6.3" "@types/istanbul-lib-coverage" "^2.0.0" collect-v8-coverage "^1.0.0" -"@jest/test-sequencer@^27.5.1": - version "27.5.1" - resolved "https://registry.yarnpkg.com/@jest/test-sequencer/-/test-sequencer-27.5.1.tgz#4057e0e9cea4439e544c6353c6affe58d095745b" - integrity sha512-LCheJF7WB2+9JuCS7VB/EmGIdQuhtqjRNI9A43idHv3E4KltCTsPsLxvdaubFHSYwY/fNjMWjl6vNRhDiN7vpQ== +"@jest/test-sequencer@^29.7.0": + version "29.7.0" + resolved "https://registry.yarnpkg.com/@jest/test-sequencer/-/test-sequencer-29.7.0.tgz#6cef977ce1d39834a3aea887a1726628a6f072ce" + integrity sha512-GQwJ5WZVrKnOJuiYiAF52UNUJXgTZx1NHjFSEB0qEMmSZKAkdMoIzw/Cj6x6NF4AvV23AUqDpFzQkN/eYCYTxw== dependencies: - "@jest/test-result" "^27.5.1" + "@jest/test-result" "^29.7.0" graceful-fs "^4.2.9" - jest-haste-map "^27.5.1" - jest-runtime "^27.5.1" + jest-haste-map "^29.7.0" + slash "^3.0.0" -"@jest/transform@^27.5.1": - version "27.5.1" - resolved "https://registry.yarnpkg.com/@jest/transform/-/transform-27.5.1.tgz#6c3501dcc00c4c08915f292a600ece5ecfe1f409" - integrity sha512-ipON6WtYgl/1329g5AIJVbUuEh0wZVbdpGwC99Jw4LwuoBNS95MVphU6zOeD9pDkon+LLbFL7lOQRapbB8SCHw== +"@jest/transform@^29.7.0": + version "29.7.0" + resolved "https://registry.yarnpkg.com/@jest/transform/-/transform-29.7.0.tgz#df2dd9c346c7d7768b8a06639994640c642e284c" + integrity sha512-ok/BTPFzFKVMwO5eOHRrvnBVHdRy9IrsrW1GpMaQ9MCnilNLXQKmAX8s1YXDFaai9xJpac2ySzV0YeRRECr2Vw== dependencies: - "@babel/core" "^7.1.0" - "@jest/types" "^27.5.1" + "@babel/core" "^7.11.6" + "@jest/types" "^29.6.3" + "@jridgewell/trace-mapping" "^0.3.18" babel-plugin-istanbul "^6.1.1" chalk "^4.0.0" - convert-source-map "^1.4.0" - fast-json-stable-stringify "^2.0.0" + convert-source-map "^2.0.0" + fast-json-stable-stringify "^2.1.0" graceful-fs "^4.2.9" - jest-haste-map "^27.5.1" - jest-regex-util "^27.5.1" - jest-util "^27.5.1" + jest-haste-map "^29.7.0" + jest-regex-util "^29.6.3" + jest-util "^29.7.0" micromatch "^4.0.4" pirates "^4.0.4" slash "^3.0.0" - source-map "^0.6.1" - write-file-atomic "^3.0.0" + write-file-atomic "^4.0.2" -"@jest/types@^27.5.1": - version "27.5.1" - resolved "https://registry.yarnpkg.com/@jest/types/-/types-27.5.1.tgz#3c79ec4a8ba61c170bf937bcf9e98a9df175ec80" - integrity sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw== +"@jest/types@^29.6.3": + version "29.6.3" + resolved "https://registry.yarnpkg.com/@jest/types/-/types-29.6.3.tgz#1131f8cf634e7e84c5e77bab12f052af585fba59" + integrity sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw== dependencies: + "@jest/schemas" "^29.6.3" "@types/istanbul-lib-coverage" "^2.0.0" "@types/istanbul-reports" "^3.0.0" "@types/node" "*" - "@types/yargs" "^16.0.0" + "@types/yargs" "^17.0.8" chalk "^4.0.0" "@jridgewell/gen-mapping@^0.3.0", "@jridgewell/gen-mapping@^0.3.2": @@ -775,6 +962,15 @@ "@jridgewell/sourcemap-codec" "^1.4.10" "@jridgewell/trace-mapping" "^0.3.9" +"@jridgewell/gen-mapping@^0.3.5": + version "0.3.5" + resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz#dcce6aff74bdf6dad1a95802b69b04a2fcb1fb36" + integrity sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg== + dependencies: + "@jridgewell/set-array" "^1.2.1" + "@jridgewell/sourcemap-codec" "^1.4.10" + "@jridgewell/trace-mapping" "^0.3.24" + "@jridgewell/resolve-uri@3.1.0": version "3.1.0" resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz#2203b118c157721addfe69d47b70465463066d78" @@ -790,6 +986,11 @@ resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.1.2.tgz#7c6cf998d6d20b914c0a55a91ae928ff25965e72" integrity sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw== +"@jridgewell/set-array@^1.2.1": + version "1.2.1" + resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.2.1.tgz#558fb6472ed16a4c850b889530e6b36438c49280" + integrity sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A== + "@jridgewell/sourcemap-codec@1.4.14": version "1.4.14" resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz#add4c98d341472a289190b424efbdb096991bb24" @@ -800,6 +1001,14 @@ resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz#d7c6e6755c78567a951e04ab52ef0fd26de59f32" integrity sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg== +"@jridgewell/trace-mapping@^0.3.12", "@jridgewell/trace-mapping@^0.3.18", "@jridgewell/trace-mapping@^0.3.24", "@jridgewell/trace-mapping@^0.3.25": + version "0.3.25" + resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz#15f190e98895f3fc23276ee14bc76b675c2e50f0" + integrity sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ== + dependencies: + "@jridgewell/resolve-uri" "^3.1.0" + "@jridgewell/sourcemap-codec" "^1.4.14" + "@jridgewell/trace-mapping@^0.3.17": version "0.3.20" resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.20.tgz#72e45707cf240fa6b081d0366f8265b0cd10197f" @@ -1757,19 +1966,24 @@ chrome-trace-event "^1.0.2" nullthrows "^1.1.1" -"@sinonjs/commons@^1.7.0": - version "1.8.6" - resolved "https://registry.yarnpkg.com/@sinonjs/commons/-/commons-1.8.6.tgz#80c516a4dc264c2a69115e7578d62581ff455ed9" - integrity sha512-Ky+XkAkqPZSm3NLBeUng77EBQl3cmeJhITaGHdYH8kjVB+aun3S4XBRti2zt17mtt0mIUDiNxYeoJm6drVvBJQ== +"@sinclair/typebox@^0.27.8": + version "0.27.8" + resolved "https://registry.yarnpkg.com/@sinclair/typebox/-/typebox-0.27.8.tgz#6667fac16c436b5434a387a34dedb013198f6e6e" + integrity sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA== + +"@sinonjs/commons@^3.0.0": + version "3.0.1" + resolved "https://registry.yarnpkg.com/@sinonjs/commons/-/commons-3.0.1.tgz#1029357e44ca901a615585f6d27738dbc89084cd" + integrity sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ== dependencies: type-detect "4.0.8" -"@sinonjs/fake-timers@^8.0.1": - version "8.1.0" - resolved "https://registry.yarnpkg.com/@sinonjs/fake-timers/-/fake-timers-8.1.0.tgz#3fdc2b6cb58935b21bfb8d1625eb1300484316e7" - integrity sha512-OAPJUAtgeINhh/TAlUID4QTs53Njm7xzddaVlEs/SXwgtiD1tW22zAB/W1wdqfrpmikgaWQ9Fw6Ws+hsiRm5Vg== +"@sinonjs/fake-timers@^10.0.2": + version "10.3.0" + resolved "https://registry.yarnpkg.com/@sinonjs/fake-timers/-/fake-timers-10.3.0.tgz#55fdff1ecab9f354019129daf4df0dd4d923ea66" + integrity sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA== dependencies: - "@sinonjs/commons" "^1.7.0" + "@sinonjs/commons" "^3.0.0" "@swc/core-darwin-arm64@1.4.1": version "1.4.1" @@ -1857,17 +2071,12 @@ resolved "https://registry.yarnpkg.com/@swc/types/-/types-0.1.5.tgz#043b731d4f56a79b4897a3de1af35e75d56bc63a" integrity sha512-myfUej5naTBWnqOCc/MdVOLVjXUXtIA+NpDrDBKJtLLg2shUjBu3cZmB/85RyitKc55+lUUyl7oRfLOvkr2hsw== -"@tootallnate/once@1": - version "1.1.2" - resolved "https://registry.yarnpkg.com/@tootallnate/once/-/once-1.1.2.tgz#ccb91445360179a04e7fe6aff78c00ffc1eeaf82" - integrity sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw== - "@trysound/sax@0.2.0": version "0.2.0" resolved "https://registry.yarnpkg.com/@trysound/sax/-/sax-0.2.0.tgz#cccaab758af56761eb7bf37af6f03f326dd798ad" integrity sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA== -"@types/babel__core@^7.0.0", "@types/babel__core@^7.1.14": +"@types/babel__core@^7.1.14": version "7.20.3" resolved "https://registry.yarnpkg.com/@types/babel__core/-/babel__core-7.20.3.tgz#d5625a50b6f18244425a1359a858c73d70340778" integrity sha512-54fjTSeSHwfan8AyHWrKbfBWiEUrNTZsUwPTDSNaaP1QDQIZbeNUg3a59E9D+375MzUw/x1vx2/0F5LBz+AeYA== @@ -1893,7 +2102,7 @@ "@babel/parser" "^7.1.0" "@babel/types" "^7.0.0" -"@types/babel__traverse@*", "@types/babel__traverse@^7.0.4", "@types/babel__traverse@^7.0.6": +"@types/babel__traverse@*", "@types/babel__traverse@^7.0.6": version "7.20.3" resolved "https://registry.yarnpkg.com/@types/babel__traverse/-/babel__traverse-7.20.3.tgz#a971aa47441b28ef17884ff945d0551265a2d058" integrity sha512-Lsh766rGEFbaxMIDH7Qa+Yha8cMVI3qAK6CHt3OR0YfxOIn5Z54iHiyDRycHrBqeIiqGa20Kpsv1cavfBKkRSw== @@ -1910,10 +2119,10 @@ resolved "https://registry.yarnpkg.com/@types/file-saver/-/file-saver-2.0.5.tgz#9ee342a5d1314bb0928375424a2f162f97c310c7" integrity sha512-zv9kNf3keYegP5oThGLaPk8E081DFDuwfqjtiTzm6PoxChdJ1raSuADf2YGCVIyrSynLrgc8JWv296s7Q7pQSQ== -"@types/graceful-fs@^4.1.2": - version "4.1.8" - resolved "https://registry.yarnpkg.com/@types/graceful-fs/-/graceful-fs-4.1.8.tgz#417e461e4dc79d957dc3107f45fe4973b09c2915" - integrity sha512-NhRH7YzWq8WiNKVavKPBmtLYZHxNY19Hh+az28O/phfp68CF45pMFud+ZzJ8ewnxnC5smIdF3dqFeiSUQ5I+pw== +"@types/graceful-fs@^4.1.3": + version "4.1.9" + resolved "https://registry.yarnpkg.com/@types/graceful-fs/-/graceful-fs-4.1.9.tgz#2a06bc0f68a20ab37b3e36aa238be6abdf49e8b4" + integrity sha512-olP3sd1qOEe5dXTSaFvQG+02VdRXcdytWLAZsAq1PecU8uqQAhkrnbli7DagjtXKW/Bl7YJbUsa8MPcuc8LHEQ== dependencies: "@types/node" "*" @@ -2008,11 +2217,6 @@ resolved "https://registry.yarnpkg.com/@types/plotly.js/-/plotly.js-2.12.18.tgz#7a231ce72a73fafe4842096b8c99d10a41b60962" integrity sha512-ff+CIEWnqZNjZqHtQZvkEAVuLs9fkm1f54QnPVmgoET7wMHdSqUka2hasVN4e5yfHD05YwGjsAtCseewJh/BMw== -"@types/prettier@^2.1.5": - version "2.7.3" - resolved "https://registry.yarnpkg.com/@types/prettier/-/prettier-2.7.3.tgz#3e51a17e291d01d17d3fc61422015a933af7a08f" - integrity sha512-+68kP9yzs4LMp7VNh8gdzMSPZFL44MLGqiHWvttYJe+6qnuVr4Ek9wSBQoveqY/r+LwjCcU29kNVkidwim+kYA== - "@types/prismjs@*": version "1.26.0" resolved "https://registry.yarnpkg.com/@types/prismjs/-/prismjs-1.26.0.tgz#a1c3809b0ad61c62cac6d4e0c56d610c910b7654" @@ -2109,53 +2313,18 @@ resolved "https://registry.yarnpkg.com/@types/yargs-parser/-/yargs-parser-21.0.0.tgz#0c60e537fa790f5f9472ed2776c2b71ec117351b" integrity sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA== -"@types/yargs@^16.0.0": - version "16.0.5" - resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-16.0.5.tgz#12cc86393985735a283e387936398c2f9e5f88e3" - integrity sha512-AxO/ADJOBFJScHbWhq2xAhlWP24rY4aCEG/NFaMvbT3X2MgRsLjhjQwsn0Zi5zn0LG9jUhCCZMeX9Dkuw6k+vQ== +"@types/yargs@^17.0.8": + version "17.0.33" + resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-17.0.33.tgz#8c32303da83eec050a84b3c7ae7b9f922d13e32d" + integrity sha512-WpxBCKWPLr4xSsHgz511rFJAM+wS28w2zEO1QDNY5zM/S8ok70NNfztH0xwhqKyaK0OHCbN98LDAZuy1ctxDkA== dependencies: "@types/yargs-parser" "*" -abab@^2.0.3, abab@^2.0.5: - version "2.0.6" - resolved "https://registry.yarnpkg.com/abab/-/abab-2.0.6.tgz#41b80f2c871d19686216b82309231cfd3cb3d291" - integrity sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA== - abortcontroller-polyfill@^1.1.9: version "1.7.5" resolved "https://registry.yarnpkg.com/abortcontroller-polyfill/-/abortcontroller-polyfill-1.7.5.tgz#6738495f4e901fbb57b6c0611d0c75f76c485bed" integrity sha512-JMJ5soJWP18htbbxJjG7bG6yuI6pRhgJ0scHHTfkUjf6wjP912xZWvM+A4sJK3gqd9E8fcPbDnOefbA9Th/FIQ== -acorn-globals@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/acorn-globals/-/acorn-globals-6.0.0.tgz#46cdd39f0f8ff08a876619b55f5ac8a6dc770b45" - integrity sha512-ZQl7LOWaF5ePqqcX4hLuv/bLXYQNfNWw2c0/yX/TsPRKamzHcTGQnlCjHT3TsmkOUVEPS3crCxiPfdzE/Trlhg== - dependencies: - acorn "^7.1.1" - acorn-walk "^7.1.1" - -acorn-walk@^7.1.1: - version "7.2.0" - resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-7.2.0.tgz#0de889a601203909b0fbe07b8938dc21d2e967bc" - integrity sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA== - -acorn@^7.1.1: - version "7.4.1" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.4.1.tgz#feaed255973d2e77555b83dbc08851a6c63520fa" - integrity sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A== - -acorn@^8.2.4: - version "8.10.0" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.10.0.tgz#8be5b3907a67221a81ab23c7889c4c5526b62ec5" - integrity sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw== - -agent-base@6: - version "6.0.2" - resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-6.0.2.tgz#49fff58577cfee3f37176feab4c22e00f86d7f77" - integrity sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ== - dependencies: - debug "4" - ansi-escapes@^4.2.1: version "4.3.2" resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-4.3.2.tgz#6b2291d1db7d98b6521d5f1efa42d0f3a9feb65e" @@ -2214,26 +2383,25 @@ aria-hidden@^1.2.2: dependencies: tslib "^2.0.0" -asynckit@^0.4.0: - version "0.4.0" - resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" - integrity sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q== +async@^3.2.3: + version "3.2.6" + resolved "https://registry.yarnpkg.com/async/-/async-3.2.6.tgz#1b0728e14929d51b85b449b7f06e27c1145e38ce" + integrity sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA== attr-accept@^2.2.2: version "2.2.2" resolved "https://registry.yarnpkg.com/attr-accept/-/attr-accept-2.2.2.tgz#646613809660110749e92f2c10833b70968d929b" integrity sha512-7prDjvt9HmqiZ0cl5CRjtS84sEyhsHP2coDkaZKRKVfCDo9s7iw7ChVmar78Gu9pC4SoR/28wFu/G5JJhTnqEg== -babel-jest@^27.5.1: - version "27.5.1" - resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-27.5.1.tgz#a1bf8d61928edfefd21da27eb86a695bfd691444" - integrity sha512-cdQ5dXjGRd0IBRATiQ4mZGlGlRE8kJpjPOixdNRdT+m3UcNqmYWN6rK6nvtXYfY3D76cb8s/O1Ss8ea24PIwcg== +babel-jest@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-29.7.0.tgz#f4369919225b684c56085998ac63dbd05be020d5" + integrity sha512-BrvGY3xZSwEcCzKvKsCi2GgHqDqsYkOP4/by5xCgIwGXQxIEh+8ew3gmrE1y7XRR6LHZIj6yLYnUi/mm2KXKBg== dependencies: - "@jest/transform" "^27.5.1" - "@jest/types" "^27.5.1" + "@jest/transform" "^29.7.0" "@types/babel__core" "^7.1.14" babel-plugin-istanbul "^6.1.1" - babel-preset-jest "^27.5.1" + babel-preset-jest "^29.6.3" chalk "^4.0.0" graceful-fs "^4.2.9" slash "^3.0.0" @@ -2249,14 +2417,14 @@ babel-plugin-istanbul@^6.1.1: istanbul-lib-instrument "^5.0.4" test-exclude "^6.0.0" -babel-plugin-jest-hoist@^27.5.1: - version "27.5.1" - resolved "https://registry.yarnpkg.com/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-27.5.1.tgz#9be98ecf28c331eb9f5df9c72d6f89deb8181c2e" - integrity sha512-50wCwD5EMNW4aRpOwtqzyZHIewTYNxLA4nhB+09d8BIssfNfzBRhkBIHiaPv1Si226TQSvp8gxAJm2iY2qs2hQ== +babel-plugin-jest-hoist@^29.6.3: + version "29.6.3" + resolved "https://registry.yarnpkg.com/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-29.6.3.tgz#aadbe943464182a8922c3c927c3067ff40d24626" + integrity sha512-ESAc/RJvGTFEzRwOTT4+lNDk/GNHMkKbNzsvT0qKRfDyyYTskxB5rnU2njIDYVxXCBHHEI1c0YwHob3WaYujOg== dependencies: "@babel/template" "^7.3.3" "@babel/types" "^7.3.3" - "@types/babel__core" "^7.0.0" + "@types/babel__core" "^7.1.14" "@types/babel__traverse" "^7.0.6" babel-plugin-macros@^3.1.0: @@ -2286,12 +2454,12 @@ babel-preset-current-node-syntax@^1.0.0: "@babel/plugin-syntax-optional-chaining" "^7.8.3" "@babel/plugin-syntax-top-level-await" "^7.8.3" -babel-preset-jest@^27.5.1: - version "27.5.1" - resolved "https://registry.yarnpkg.com/babel-preset-jest/-/babel-preset-jest-27.5.1.tgz#91f10f58034cb7989cb4f962b69fa6eef6a6bc81" - integrity sha512-Nptf2FzlPCWYuJg41HBqXVT8ym6bXOevuCTbhxlUpjwtysGaIWFvDEjp4y+G7fl13FgOdjs7P/DmErqH7da0Ag== +babel-preset-jest@^29.6.3: + version "29.6.3" + resolved "https://registry.yarnpkg.com/babel-preset-jest/-/babel-preset-jest-29.6.3.tgz#fa05fa510e7d493896d7b0dd2033601c840f171c" + integrity sha512-0B3bhxR6snWXJZtR/RliHTDPRgn1sNHOR0yVtq/IiQFyuOVjFS+wuio/R4gSNkyYmKmJB4wGZv2NZanmKmTnNA== dependencies: - babel-plugin-jest-hoist "^27.5.1" + babel-plugin-jest-hoist "^29.6.3" babel-preset-current-node-syntax "^1.0.0" bail@^1.0.0: @@ -2329,22 +2497,24 @@ brace-expansion@^1.1.7: balanced-match "^1.0.0" concat-map "0.0.1" +brace-expansion@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-2.0.1.tgz#1edc459e0f0c548486ecf9fc99f2221364b9a0ae" + integrity sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA== + dependencies: + balanced-match "^1.0.0" + brace@^0.11.1: version "0.11.1" resolved "https://registry.yarnpkg.com/brace/-/brace-0.11.1.tgz#4896fcc9d544eef45f4bb7660db320d3b379fe58" integrity sha512-Fc8Ne62jJlKHiG/ajlonC4Sd66Pq68fFwK4ihJGNZpGqboc324SQk+lRvMzpPRuJOmfrJefdG8/7JdWX4bzJ2Q== -braces@^3.0.2, braces@~3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" - integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A== +braces@^3.0.3, braces@~3.0.2: + version "3.0.3" + resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.3.tgz#490332f40919452272d55a8480adc0c441358789" + integrity sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA== dependencies: - fill-range "^7.0.1" - -browser-process-hrtime@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz#3c9b4b7d782c8121e56f10106d84c0d0ffc94626" - integrity sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow== + fill-range "^7.1.1" browserslist@^4.21.9: version "4.22.1" @@ -2356,6 +2526,16 @@ browserslist@^4.21.9: node-releases "^2.0.13" update-browserslist-db "^1.0.13" +browserslist@^4.24.0: + version "4.24.0" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.24.0.tgz#a1325fe4bc80b64fda169629fc01b3d6cecd38d4" + integrity sha512-Rmb62sR1Zpjql25eSanFGEhAxcFwfA1K0GuQcLoaJBAcENegrQut3hYdhXFF1obQfiDyqIW/cLM5HSJ/9k884A== + dependencies: + caniuse-lite "^1.0.30001663" + electron-to-chromium "^1.5.28" + node-releases "^2.0.18" + update-browserslist-db "^1.1.0" + browserslist@^4.6.6: version "4.23.0" resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.23.0.tgz#8f3acc2bbe73af7213399430890f86c63a5674ab" @@ -2366,7 +2546,7 @@ browserslist@^4.6.6: node-releases "^2.0.14" update-browserslist-db "^1.0.13" -bs-logger@0.x: +bs-logger@^0.2.6: version "0.2.6" resolved "https://registry.yarnpkg.com/bs-logger/-/bs-logger-0.2.6.tgz#eb7d365307a72cf974cc6cda76b68354ad336bd8" integrity sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog== @@ -2410,6 +2590,11 @@ caniuse-lite@^1.0.30001587: resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001588.tgz#07f16b65a7f95dba82377096923947fb25bce6e3" integrity sha512-+hVY9jE44uKLkH0SrUTqxjxqNTOWHsbnQDIKjwkZ3lNTzUUVdBLBGXtj/q5Mp5u98r3droaZAewQuEDzjQdZlQ== +caniuse-lite@^1.0.30001663: + version "1.0.30001667" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001667.tgz#99fc5ea0d9c6e96897a104a8352604378377f949" + integrity sha512-7LTwJjcRkzKFmtqGsibMeuXmvFDfZq/nzIjnmgCGzKKRVzjD72selLDK1oPF/Oxzmt4fNcPvTDvGqSDG4tCALw== + ccount@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/ccount/-/ccount-1.1.0.tgz#246687debb6014735131be8abab2d93898f8d043" @@ -2424,7 +2609,7 @@ chalk@^2.0.0, chalk@^2.4.2: escape-string-regexp "^1.0.5" supports-color "^5.3.0" -chalk@^4.0.0, chalk@^4.1.0: +chalk@^4.0.0, chalk@^4.0.2, chalk@^4.1.0: version "4.1.2" resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== @@ -2504,15 +2689,6 @@ cli-progress@^3.12.0: dependencies: string-width "^4.2.3" -cliui@^7.0.2: - version "7.0.4" - resolved "https://registry.yarnpkg.com/cliui/-/cliui-7.0.4.tgz#a0265ee655476fc807aea9df3df8df7783808b4f" - integrity sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ== - dependencies: - string-width "^4.2.0" - strip-ansi "^6.0.0" - wrap-ansi "^7.0.0" - cliui@^8.0.1: version "8.0.1" resolved "https://registry.yarnpkg.com/cliui/-/cliui-8.0.1.tgz#0c04b075db02cbfe60dc8e6cf2f5486b1a3608aa" @@ -2566,13 +2742,6 @@ color-name@~1.1.4: resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== -combined-stream@^1.0.8: - version "1.0.8" - resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f" - integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg== - dependencies: - delayed-stream "~1.0.0" - comma-separated-tokens@^1.0.0: version "1.0.8" resolved "https://registry.yarnpkg.com/comma-separated-tokens/-/comma-separated-tokens-1.0.8.tgz#632b80b6117867a158f1080ad498b2fbe7e3f5ea" @@ -2603,7 +2772,7 @@ concurrently@^7.6.0: tree-kill "^1.2.2" yargs "^17.3.1" -convert-source-map@^1.4.0, convert-source-map@^1.5.0, convert-source-map@^1.6.0: +convert-source-map@^1.5.0: version "1.9.0" resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.9.0.tgz#7faae62353fb4213366d0ca98358d22e8368b05f" integrity sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A== @@ -2641,6 +2810,19 @@ cosmiconfig@^8.0.0: parse-json "^5.2.0" path-type "^4.0.0" +create-jest@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/create-jest/-/create-jest-29.7.0.tgz#a355c5b3cb1e1af02ba177fe7afd7feee49a5320" + integrity sha512-Adz2bdH0Vq3F53KEMJOoftQFutWCukm6J24wbPWRO4k1kMY7gS7ds/uoJkNuV8wDCtWWnuwGcJwpWcih+zEW1Q== + dependencies: + "@jest/types" "^29.6.3" + chalk "^4.0.0" + exit "^0.1.2" + graceful-fs "^4.2.9" + jest-config "^29.7.0" + jest-util "^29.7.0" + prompts "^2.0.1" + cross-env@^7.0.3: version "7.0.3" resolved "https://registry.yarnpkg.com/cross-env/-/cross-env-7.0.3.tgz#865264b29677dc015ba8418918965dd232fc54cf" @@ -2695,49 +2877,16 @@ csso@^4.2.0: dependencies: css-tree "^1.1.2" -cssom@^0.4.4: - version "0.4.4" - resolved "https://registry.yarnpkg.com/cssom/-/cssom-0.4.4.tgz#5a66cf93d2d0b661d80bf6a44fb65f5c2e4e0a10" - integrity sha512-p3pvU7r1MyyqbTk+WbNJIgJjG2VmTIaB10rI93LzVPrmDJKkzKYMtxxyAvQXR/NS6otuzveI7+7BBq3SjBS2mw== - -cssom@~0.3.6: - version "0.3.8" - resolved "https://registry.yarnpkg.com/cssom/-/cssom-0.3.8.tgz#9f1276f5b2b463f2114d3f2c75250af8c1a36f4a" - integrity sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg== - -cssstyle@^2.3.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/cssstyle/-/cssstyle-2.3.0.tgz#ff665a0ddbdc31864b09647f34163443d90b0852" - integrity sha512-AZL67abkUzIuvcHqk7c09cezpGNcxUxU4Ioi/05xHk4DQeTkWmGYftIE6ctU6AEt+Gn4n1lDStOtj7FKycP71A== - dependencies: - cssom "~0.3.6" - csstype@^3.0.2: version "3.1.2" resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.1.2.tgz#1d4bf9d572f11c14031f0436e1c10bc1f571f50b" integrity sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ== -data-urls@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/data-urls/-/data-urls-2.0.0.tgz#156485a72963a970f5d5821aaf642bef2bf2db9b" - integrity sha512-X5eWTSXO/BJmpdIKCRuKUgSCgAN0OwliVK3yPKbwIWU1Tdw5BRajxlzMidvh+gwko9AfQ9zIj52pzF91Q3YAvQ== - dependencies: - abab "^2.0.3" - whatwg-mimetype "^2.3.0" - whatwg-url "^8.0.0" - date-fns@^2.28.0, date-fns@^2.29.1: version "2.29.3" resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-2.29.3.tgz#27402d2fc67eb442b511b70bbdf98e6411cd68a8" integrity sha512-dDCnyH2WnnKusqvZZ6+jA1O51Ibt8ZMRNkDZdyAyK4YfbDwa/cEmuztzG5pk6hqlp9aSBPYcjOlktquahGwGeA== -debug@4, debug@^4.1.0, debug@^4.1.1: - version "4.3.4" - resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" - integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== - dependencies: - ms "2.1.2" - debug@^3.2.6: version "3.2.7" resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.7.tgz#72580b7e9145fb39b6676f9c5e5fb100b934179a" @@ -2745,26 +2894,30 @@ debug@^3.2.6: dependencies: ms "^2.1.1" -decimal.js@^10.2.1: - version "10.4.3" - resolved "https://registry.yarnpkg.com/decimal.js/-/decimal.js-10.4.3.tgz#1044092884d245d1b7f65725fa4ad4c6f781cc23" - integrity sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA== +debug@^4.1.0, debug@^4.1.1: + version "4.3.4" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" + integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== + dependencies: + ms "2.1.2" + +debug@^4.3.1: + version "4.3.7" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.7.tgz#87945b4151a011d76d95a198d7111c865c360a52" + integrity sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ== + dependencies: + ms "^2.1.3" -dedent@^0.7.0: - version "0.7.0" - resolved "https://registry.yarnpkg.com/dedent/-/dedent-0.7.0.tgz#2495ddbaf6eb874abb0e1be9df22d2e5a544326c" - integrity sha512-Q6fKUPqnAHAyhiUgFU7BUzLiv0kd8saH9al7tnu5Q/okj6dnupxyTgFIBjVzJATdfIAm9NAsvXNzjaKa+bxVyA== +dedent@^1.0.0: + version "1.5.3" + resolved "https://registry.yarnpkg.com/dedent/-/dedent-1.5.3.tgz#99aee19eb9bae55a67327717b6e848d0bf777e5a" + integrity sha512-NHQtfOOW68WD8lgypbLA5oT+Bt0xXJhiYvoR6SmmNXZfpzOGXwdKWmcwG8N7PwVVWV3eF/68nmD9BaJSsTBhyQ== deepmerge@^4.2.2: version "4.3.1" resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-4.3.1.tgz#44b5f2147cd3b00d4b56137685966f26fd25dd4a" integrity sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A== -delayed-stream@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" - integrity sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ== - detect-libc@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b" @@ -2795,6 +2948,11 @@ diff-sequences@^27.5.1: resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-27.5.1.tgz#eaecc0d327fd68c8d9672a1e64ab8dccb2ef5327" integrity sha512-k1gCAXAsNgLwEL+Y8Wvl+M6oEFj5bgazfZULpS5CneoPPXRaCCW7dm+q21Ky2VEE5X+VeRDBVg1Pcvvsr4TtNQ== +diff-sequences@^29.6.3: + version "29.6.3" + resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-29.6.3.tgz#4deaf894d11407c51efc8418012f9e70b84ea921" + integrity sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q== + dom-serializer@^1.0.1: version "1.4.1" resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-1.4.1.tgz#de5d41b1aea290215dc45a6dae8adcf1d32e2d30" @@ -2809,13 +2967,6 @@ domelementtype@^2.0.1, domelementtype@^2.2.0: resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-2.3.0.tgz#5c45e8e869952626331d7aab326d01daf65d589d" integrity sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw== -domexception@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/domexception/-/domexception-2.0.1.tgz#fb44aefba793e1574b0af6aed2801d057529f304" - integrity sha512-yxJ2mFy/sibVQlu5qHjOkf9J3K6zgmCxgJ94u2EdvDOV09H+32LtRswEcUsmUWN72pVLOEnTSRaIVVzVQgS0dg== - dependencies: - webidl-conversions "^5.0.0" - domhandler@^4.2.0, domhandler@^4.2.2, domhandler@^4.3.1: version "4.3.1" resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-4.3.1.tgz#8d792033416f59d68bc03a5aa7b018c1ca89279c" @@ -2842,6 +2993,13 @@ dotenv@^7.0.0: resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-7.0.0.tgz#a2be3cd52736673206e8a85fb5210eea29628e7c" integrity sha512-M3NhsLbV1i6HuGzBUH8vXrtxOk+tWmzWKDMbAVSUp3Zsjm7ywFeuwrUXhmhQyRK1q5B5GGy7hcXPbj3bnfZg2g== +ejs@^3.1.10: + version "3.1.10" + resolved "https://registry.yarnpkg.com/ejs/-/ejs-3.1.10.tgz#69ab8358b14e896f80cc39e62087b88500c3ac3b" + integrity sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA== + dependencies: + jake "^10.8.5" + electron-to-chromium@^1.4.535: version "1.4.565" resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.565.tgz#205f3746a759ec3c43bce98b9eef5445f2721ea9" @@ -2852,10 +3010,15 @@ electron-to-chromium@^1.4.668: resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.673.tgz#1f077d9a095761804aec7ec6346c3f4b69b56534" integrity sha512-zjqzx4N7xGdl5468G+vcgzDhaHkaYgVcf9MqgexcTqsl2UHSCmOj/Bi3HAprg4BZCpC7HyD8a6nZl6QAZf72gw== -emittery@^0.8.1: - version "0.8.1" - resolved "https://registry.yarnpkg.com/emittery/-/emittery-0.8.1.tgz#bb23cc86d03b30aa75a7f734819dee2e1ba70860" - integrity sha512-uDfvUjVrfGJJhymx/kz6prltenw1u7WrCg1oa94zYY8xxVpLLUu045LAT0dhDZdXG58/EpPL/5kA180fQ/qudg== +electron-to-chromium@^1.5.28: + version "1.5.35" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.5.35.tgz#1d38d386186c72b1fa6e74c3a7de5f888b503100" + integrity sha512-hOSRInrIDm0Brzp4IHW2F/VM+638qOL2CzE0DgpnGzKW27C95IqqeqgKz/hxHGnvPxvQGpHUGD5qRVC9EZY2+A== + +emittery@^0.13.1: + version "0.13.1" + resolved "https://registry.yarnpkg.com/emittery/-/emittery-0.13.1.tgz#c04b8c3457490e0847ae51fced3af52d338e3dad" + integrity sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ== emoji-regex@^8.0.0: version "8.0.0" @@ -2924,6 +3087,11 @@ escalade@^3.1.1: resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40" integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw== +escalade@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.2.0.tgz#011a3f69856ba189dffa7dc8fcce99d2a87903e5" + integrity sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA== + escape-string-regexp@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" @@ -2939,32 +3107,11 @@ escape-string-regexp@^4.0.0: resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34" integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== -escodegen@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-2.1.0.tgz#ba93bbb7a43986d29d6041f99f5262da773e2e17" - integrity sha512-2NlIDTwUWJN0mRPQOdtQBzbUHvdGY2P1VXSyU83Q3xKxM7WHX2Ql8dKq782Q9TgQUNOLEzEYu9bzLNj1q88I5w== - dependencies: - esprima "^4.0.1" - estraverse "^5.2.0" - esutils "^2.0.2" - optionalDependencies: - source-map "~0.6.1" - -esprima@^4.0.0, esprima@^4.0.1: +esprima@^4.0.0: version "4.0.1" resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== -estraverse@^5.2.0: - version "5.3.0" - resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.3.0.tgz#2eea5290702f26ab8fe5370370ff86c965d21123" - integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA== - -esutils@^2.0.2: - version "2.0.3" - resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" - integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== - execa@^5.0.0: version "5.1.1" resolved "https://registry.yarnpkg.com/execa/-/execa-5.1.1.tgz#f80ad9cbf4298f7bd1d4c9555c21e93741c411dd" @@ -2985,22 +3132,23 @@ exit@^0.1.2: resolved "https://registry.yarnpkg.com/exit/-/exit-0.1.2.tgz#0632638f8d877cc82107d30a0fff1a17cba1cd0c" integrity sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ== -expect@^27.5.1: - version "27.5.1" - resolved "https://registry.yarnpkg.com/expect/-/expect-27.5.1.tgz#83ce59f1e5bdf5f9d2b94b61d2050db48f3fef74" - integrity sha512-E1q5hSUG2AmYQwQJ041nvgpkODHQvB+RKlB4IYdru6uJsyFTRyZAP463M+1lINorwbqAmUggi6+WwkD8lCS/Dw== +expect@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/expect/-/expect-29.7.0.tgz#578874590dcb3214514084c08115d8aee61e11bc" + integrity sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw== dependencies: - "@jest/types" "^27.5.1" - jest-get-type "^27.5.1" - jest-matcher-utils "^27.5.1" - jest-message-util "^27.5.1" + "@jest/expect-utils" "^29.7.0" + jest-get-type "^29.6.3" + jest-matcher-utils "^29.7.0" + jest-message-util "^29.7.0" + jest-util "^29.7.0" extend@^3.0.0: version "3.0.2" resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa" integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g== -fast-json-stable-stringify@2.x, fast-json-stable-stringify@^2.0.0: +fast-json-stable-stringify@2.x, fast-json-stable-stringify@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== @@ -3024,10 +3172,17 @@ file-selector@^0.4.0: dependencies: tslib "^2.0.3" -fill-range@^7.0.1: - version "7.0.1" - resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40" - integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ== +filelist@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/filelist/-/filelist-1.0.4.tgz#f78978a1e944775ff9e62e744424f215e58352b5" + integrity sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q== + dependencies: + minimatch "^5.0.1" + +fill-range@^7.1.1: + version "7.1.1" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.1.1.tgz#44265d3cac07e3ea7dc247516380643754a05292" + integrity sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg== dependencies: to-regex-range "^5.0.1" @@ -3051,15 +3206,6 @@ focus-lock@^0.11.6: dependencies: tslib "^2.0.3" -form-data@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/form-data/-/form-data-3.0.1.tgz#ebd53791b78356a99af9a300d4282c4d5eb9755f" - integrity sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg== - dependencies: - asynckit "^0.4.0" - combined-stream "^1.0.8" - mime-types "^2.1.12" - fs.realpath@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" @@ -3122,7 +3268,7 @@ glob-parent@~5.1.2: dependencies: is-glob "^4.0.1" -glob@^7.1.1, glob@^7.1.2, glob@^7.1.3, glob@^7.1.4: +glob@^7.1.3, glob@^7.1.4: version "7.2.3" resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b" integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q== @@ -3277,13 +3423,6 @@ hoist-non-react-statics@^3.3.0, hoist-non-react-statics@^3.3.1, hoist-non-react- dependencies: react-is "^16.7.0" -html-encoding-sniffer@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/html-encoding-sniffer/-/html-encoding-sniffer-2.0.1.tgz#42a6dc4fd33f00281176e8b23759ca4e4fa185f3" - integrity sha512-D5JbOMBIR/TVZkubHT+OyT2705QvogUW4IBn6nHd756OwieSF9aDYFj4dv6HHEVGYbHaLETa3WggZYWWMyy3ZQ== - dependencies: - whatwg-encoding "^1.0.5" - html-escaper@^2.0.0: version "2.0.2" resolved "https://registry.yarnpkg.com/html-escaper/-/html-escaper-2.0.2.tgz#dfd60027da36a36dfcbe236262c00a5822681453" @@ -3313,35 +3452,11 @@ htmlparser2@^7.1.1: domutils "^2.8.0" entities "^3.0.1" -http-proxy-agent@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz#8a8c8ef7f5932ccf953c296ca8291b95aa74aa3a" - integrity sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg== - dependencies: - "@tootallnate/once" "1" - agent-base "6" - debug "4" - -https-proxy-agent@^5.0.0: - version "5.0.1" - resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz#c59ef224a04fe8b754f3db0063a25ea30d0005d6" - integrity sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA== - dependencies: - agent-base "6" - debug "4" - human-signals@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-2.1.0.tgz#dc91fcba42e4d06e4abaed33b3e7a3c02f514ea0" integrity sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw== -iconv-lite@0.4.24: - version "0.4.24" - resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" - integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== - dependencies: - safer-buffer ">= 2.1.2 < 3" - iconv-lite@^0.6.3: version "0.6.3" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.6.3.tgz#a52f80bf38da1952eb5c681790719871a1a72501" @@ -3496,21 +3611,11 @@ is-plain-obj@^2.0.0: resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-2.1.0.tgz#45e42e37fccf1f40da8e5f76ee21515840c09287" integrity sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA== -is-potential-custom-element-name@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz#171ed6f19e3ac554394edf78caa05784a45bebb5" - integrity sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ== - is-stream@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-2.0.1.tgz#fac1e3d53b97ad5a9d0ae9cef2389f5810a5c077" integrity sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg== -is-typedarray@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" - integrity sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA== - is-what@^3.14.1: version "3.14.1" resolved "https://registry.yarnpkg.com/is-what/-/is-what-3.14.1.tgz#e1222f46ddda85dead0fd1c9df131760e77755c1" @@ -3536,7 +3641,7 @@ istanbul-lib-coverage@^3.0.0, istanbul-lib-coverage@^3.2.0: resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz#189e7909d0a39fa5a3dfad5b03f71947770191d3" integrity sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw== -istanbul-lib-instrument@^5.0.4, istanbul-lib-instrument@^5.1.0: +istanbul-lib-instrument@^5.0.4: version "5.2.1" resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz#d10c8885c2125574e1c231cacadf955675e1ce3d" integrity sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg== @@ -3547,6 +3652,17 @@ istanbul-lib-instrument@^5.0.4, istanbul-lib-instrument@^5.1.0: istanbul-lib-coverage "^3.2.0" semver "^6.3.0" +istanbul-lib-instrument@^6.0.0: + version "6.0.3" + resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-6.0.3.tgz#fa15401df6c15874bcb2105f773325d78c666765" + integrity sha512-Vtgk7L/R2JHyyGW07spoFlB8/lpjiOLTjMdms6AFMraYt3BaJauod/NGrfnVG/y4Ix1JEuMRPDPEj2ua+zz1/Q== + dependencies: + "@babel/core" "^7.23.9" + "@babel/parser" "^7.23.9" + "@istanbuljs/schema" "^0.1.3" + istanbul-lib-coverage "^3.2.0" + semver "^7.5.4" + istanbul-lib-report@^3.0.0: version "3.0.1" resolved "https://registry.yarnpkg.com/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz#908305bac9a5bd175ac6a74489eafd0fc2445a7d" @@ -3573,85 +3689,93 @@ istanbul-reports@^3.1.3: html-escaper "^2.0.0" istanbul-lib-report "^3.0.0" -jest-changed-files@^27.5.1: - version "27.5.1" - resolved "https://registry.yarnpkg.com/jest-changed-files/-/jest-changed-files-27.5.1.tgz#a348aed00ec9bf671cc58a66fcbe7c3dfd6a68f5" - integrity sha512-buBLMiByfWGCoMsLLzGUUSpAmIAGnbR2KJoMN10ziLhOLvP4e0SlypHnAel8iqQXTrcbmfEY9sSqae5sgUsTvw== +jake@^10.8.5: + version "10.9.2" + resolved "https://registry.yarnpkg.com/jake/-/jake-10.9.2.tgz#6ae487e6a69afec3a5e167628996b59f35ae2b7f" + integrity sha512-2P4SQ0HrLQ+fw6llpLnOaGAvN2Zu6778SJMrCUwns4fOoG9ayrTiZk3VV8sCPkVZF8ab0zksVpS8FDY5pRCNBA== dependencies: - "@jest/types" "^27.5.1" - execa "^5.0.0" - throat "^6.0.1" + async "^3.2.3" + chalk "^4.0.2" + filelist "^1.0.4" + minimatch "^3.1.2" -jest-circus@^27.5.1: - version "27.5.1" - resolved "https://registry.yarnpkg.com/jest-circus/-/jest-circus-27.5.1.tgz#37a5a4459b7bf4406e53d637b49d22c65d125ecc" - integrity sha512-D95R7x5UtlMA5iBYsOHFFbMD/GVA4R/Kdq15f7xYWUfWHBto9NYRsOvnSauTgdF+ogCpJ4tyKOXhUifxS65gdw== +jest-changed-files@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-changed-files/-/jest-changed-files-29.7.0.tgz#1c06d07e77c78e1585d020424dedc10d6e17ac3a" + integrity sha512-fEArFiwf1BpQ+4bXSprcDc3/x4HSzL4al2tozwVpDFpsxALjLYdyiIK4e5Vz66GQJIbXJ82+35PtysofptNX2w== dependencies: - "@jest/environment" "^27.5.1" - "@jest/test-result" "^27.5.1" - "@jest/types" "^27.5.1" + execa "^5.0.0" + jest-util "^29.7.0" + p-limit "^3.1.0" + +jest-circus@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-circus/-/jest-circus-29.7.0.tgz#b6817a45fcc835d8b16d5962d0c026473ee3668a" + integrity sha512-3E1nCMgipcTkCocFwM90XXQab9bS+GMsjdpmPrlelaxwD93Ad8iVEjX/vvHPdLPnFf+L40u+5+iutRdA1N9myw== + dependencies: + "@jest/environment" "^29.7.0" + "@jest/expect" "^29.7.0" + "@jest/test-result" "^29.7.0" + "@jest/types" "^29.6.3" "@types/node" "*" chalk "^4.0.0" co "^4.6.0" - dedent "^0.7.0" - expect "^27.5.1" + dedent "^1.0.0" is-generator-fn "^2.0.0" - jest-each "^27.5.1" - jest-matcher-utils "^27.5.1" - jest-message-util "^27.5.1" - jest-runtime "^27.5.1" - jest-snapshot "^27.5.1" - jest-util "^27.5.1" - pretty-format "^27.5.1" + jest-each "^29.7.0" + jest-matcher-utils "^29.7.0" + jest-message-util "^29.7.0" + jest-runtime "^29.7.0" + jest-snapshot "^29.7.0" + jest-util "^29.7.0" + p-limit "^3.1.0" + pretty-format "^29.7.0" + pure-rand "^6.0.0" slash "^3.0.0" stack-utils "^2.0.3" - throat "^6.0.1" -jest-cli@^27.5.1: - version "27.5.1" - resolved "https://registry.yarnpkg.com/jest-cli/-/jest-cli-27.5.1.tgz#278794a6e6458ea8029547e6c6cbf673bd30b145" - integrity sha512-Hc6HOOwYq4/74/c62dEE3r5elx8wjYqxY0r0G/nFrLDPMFRu6RA/u8qINOIkvhxG7mMQ5EJsOGfRpI8L6eFUVw== +jest-cli@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-cli/-/jest-cli-29.7.0.tgz#5592c940798e0cae677eec169264f2d839a37995" + integrity sha512-OVVobw2IubN/GSYsxETi+gOe7Ka59EFMR/twOU3Jb2GnKKeMGJB5SGUUrEz3SFVmJASUdZUzy83sLNNQ2gZslg== dependencies: - "@jest/core" "^27.5.1" - "@jest/test-result" "^27.5.1" - "@jest/types" "^27.5.1" + "@jest/core" "^29.7.0" + "@jest/test-result" "^29.7.0" + "@jest/types" "^29.6.3" chalk "^4.0.0" + create-jest "^29.7.0" exit "^0.1.2" - graceful-fs "^4.2.9" import-local "^3.0.2" - jest-config "^27.5.1" - jest-util "^27.5.1" - jest-validate "^27.5.1" - prompts "^2.0.1" - yargs "^16.2.0" + jest-config "^29.7.0" + jest-util "^29.7.0" + jest-validate "^29.7.0" + yargs "^17.3.1" -jest-config@^27.5.1: - version "27.5.1" - resolved "https://registry.yarnpkg.com/jest-config/-/jest-config-27.5.1.tgz#5c387de33dca3f99ad6357ddeccd91bf3a0e4a41" - integrity sha512-5sAsjm6tGdsVbW9ahcChPAFCk4IlkQUknH5AvKjuLTSlcO/wCZKyFdn7Rg0EkC+OGgWODEy2hDpWB1PgzH0JNA== +jest-config@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-config/-/jest-config-29.7.0.tgz#bcbda8806dbcc01b1e316a46bb74085a84b0245f" + integrity sha512-uXbpfeQ7R6TZBqI3/TxCU4q4ttk3u0PJeC+E0zbfSoSjq6bJ7buBPxzQPL0ifrkY4DNu4JUdk0ImlBUYi840eQ== dependencies: - "@babel/core" "^7.8.0" - "@jest/test-sequencer" "^27.5.1" - "@jest/types" "^27.5.1" - babel-jest "^27.5.1" + "@babel/core" "^7.11.6" + "@jest/test-sequencer" "^29.7.0" + "@jest/types" "^29.6.3" + babel-jest "^29.7.0" chalk "^4.0.0" ci-info "^3.2.0" deepmerge "^4.2.2" - glob "^7.1.1" + glob "^7.1.3" graceful-fs "^4.2.9" - jest-circus "^27.5.1" - jest-environment-jsdom "^27.5.1" - jest-environment-node "^27.5.1" - jest-get-type "^27.5.1" - jest-jasmine2 "^27.5.1" - jest-regex-util "^27.5.1" - jest-resolve "^27.5.1" - jest-runner "^27.5.1" - jest-util "^27.5.1" - jest-validate "^27.5.1" + jest-circus "^29.7.0" + jest-environment-node "^29.7.0" + jest-get-type "^29.6.3" + jest-regex-util "^29.6.3" + jest-resolve "^29.7.0" + jest-runner "^29.7.0" + jest-util "^29.7.0" + jest-validate "^29.7.0" micromatch "^4.0.4" parse-json "^5.2.0" - pretty-format "^27.5.1" + pretty-format "^29.7.0" slash "^3.0.0" strip-json-comments "^3.1.1" @@ -3665,106 +3789,84 @@ jest-diff@^27.5.1: jest-get-type "^27.5.1" pretty-format "^27.5.1" -jest-docblock@^27.5.1: - version "27.5.1" - resolved "https://registry.yarnpkg.com/jest-docblock/-/jest-docblock-27.5.1.tgz#14092f364a42c6108d42c33c8cf30e058e25f6c0" - integrity sha512-rl7hlABeTsRYxKiUfpHrQrG4e2obOiTQWfMEH3PxPjOtdsfLQO4ReWSZaQ7DETm4xu07rl4q/h4zcKXyU0/OzQ== +jest-diff@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-29.7.0.tgz#017934a66ebb7ecf6f205e84699be10afd70458a" + integrity sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw== dependencies: - detect-newline "^3.0.0" - -jest-each@^27.5.1: - version "27.5.1" - resolved "https://registry.yarnpkg.com/jest-each/-/jest-each-27.5.1.tgz#5bc87016f45ed9507fed6e4702a5b468a5b2c44e" - integrity sha512-1Ff6p+FbhT/bXQnEouYy00bkNSY7OUpfIcmdl8vZ31A1UUaurOLPA8a8BbJOF2RDUElwJhmeaV7LnagI+5UwNQ== - dependencies: - "@jest/types" "^27.5.1" chalk "^4.0.0" - jest-get-type "^27.5.1" - jest-util "^27.5.1" - pretty-format "^27.5.1" + diff-sequences "^29.6.3" + jest-get-type "^29.6.3" + pretty-format "^29.7.0" -jest-environment-jsdom@^27.5.1: - version "27.5.1" - resolved "https://registry.yarnpkg.com/jest-environment-jsdom/-/jest-environment-jsdom-27.5.1.tgz#ea9ccd1fc610209655a77898f86b2b559516a546" - integrity sha512-TFBvkTC1Hnnnrka/fUb56atfDtJ9VMZ94JkjTbggl1PEpwrYtUBKMezB3inLmWqQsXYLcMwNoDQwoBTAvFfsfw== +jest-docblock@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-docblock/-/jest-docblock-29.7.0.tgz#8fddb6adc3cdc955c93e2a87f61cfd350d5d119a" + integrity sha512-q617Auw3A612guyaFgsbFeYpNP5t2aoUNLwBUbc/0kD1R4t9ixDbyFTHd1nok4epoVFpr7PmeWHrhvuV3XaJ4g== dependencies: - "@jest/environment" "^27.5.1" - "@jest/fake-timers" "^27.5.1" - "@jest/types" "^27.5.1" - "@types/node" "*" - jest-mock "^27.5.1" - jest-util "^27.5.1" - jsdom "^16.6.0" + detect-newline "^3.0.0" -jest-environment-node@^27.5.1: - version "27.5.1" - resolved "https://registry.yarnpkg.com/jest-environment-node/-/jest-environment-node-27.5.1.tgz#dedc2cfe52fab6b8f5714b4808aefa85357a365e" - integrity sha512-Jt4ZUnxdOsTGwSRAfKEnE6BcwsSPNOijjwifq5sDFSA2kesnXTvNqKHYgM0hDq3549Uf/KzdXNYn4wMZJPlFLw== +jest-each@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-each/-/jest-each-29.7.0.tgz#162a9b3f2328bdd991beaabffbb74745e56577d1" + integrity sha512-gns+Er14+ZrEoC5fhOfYCY1LOHHr0TI+rQUHZS8Ttw2l7gl+80eHc/gFf2Ktkw0+SIACDTeWvpFcv3B04VembQ== dependencies: - "@jest/environment" "^27.5.1" - "@jest/fake-timers" "^27.5.1" - "@jest/types" "^27.5.1" + "@jest/types" "^29.6.3" + chalk "^4.0.0" + jest-get-type "^29.6.3" + jest-util "^29.7.0" + pretty-format "^29.7.0" + +jest-environment-node@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-environment-node/-/jest-environment-node-29.7.0.tgz#0b93e111dda8ec120bc8300e6d1fb9576e164376" + integrity sha512-DOSwCRqXirTOyheM+4d5YZOrWcdu0LNZ87ewUoywbcb2XR4wKgqiG8vNeYwhjFMbEkfju7wx2GYH0P2gevGvFw== + dependencies: + "@jest/environment" "^29.7.0" + "@jest/fake-timers" "^29.7.0" + "@jest/types" "^29.6.3" "@types/node" "*" - jest-mock "^27.5.1" - jest-util "^27.5.1" + jest-mock "^29.7.0" + jest-util "^29.7.0" jest-get-type@^27.5.1: version "27.5.1" resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-27.5.1.tgz#3cd613c507b0f7ace013df407a1c1cd578bcb4f1" integrity sha512-2KY95ksYSaK7DMBWQn6dQz3kqAf3BB64y2udeG+hv4KfSOb9qwcYQstTJc1KCbsix+wLZWZYN8t7nwX3GOBLRw== -jest-haste-map@^27.5.1: - version "27.5.1" - resolved "https://registry.yarnpkg.com/jest-haste-map/-/jest-haste-map-27.5.1.tgz#9fd8bd7e7b4fa502d9c6164c5640512b4e811e7f" - integrity sha512-7GgkZ4Fw4NFbMSDSpZwXeBiIbx+t/46nJ2QitkOjvwPYyZmqttu2TDSimMHP1EkPOi4xUZAN1doE5Vd25H4Jng== +jest-get-type@^29.6.3: + version "29.6.3" + resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-29.6.3.tgz#36f499fdcea197c1045a127319c0481723908fd1" + integrity sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw== + +jest-haste-map@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-haste-map/-/jest-haste-map-29.7.0.tgz#3c2396524482f5a0506376e6c858c3bbcc17b104" + integrity sha512-fP8u2pyfqx0K1rGn1R9pyE0/KTn+G7PxktWidOBTqFPLYX0b9ksaMFkhK5vrS3DVun09pckLdlx90QthlW7AmA== dependencies: - "@jest/types" "^27.5.1" - "@types/graceful-fs" "^4.1.2" + "@jest/types" "^29.6.3" + "@types/graceful-fs" "^4.1.3" "@types/node" "*" anymatch "^3.0.3" fb-watchman "^2.0.0" graceful-fs "^4.2.9" - jest-regex-util "^27.5.1" - jest-serializer "^27.5.1" - jest-util "^27.5.1" - jest-worker "^27.5.1" + jest-regex-util "^29.6.3" + jest-util "^29.7.0" + jest-worker "^29.7.0" micromatch "^4.0.4" - walker "^1.0.7" + walker "^1.0.8" optionalDependencies: fsevents "^2.3.2" -jest-jasmine2@^27.5.1: - version "27.5.1" - resolved "https://registry.yarnpkg.com/jest-jasmine2/-/jest-jasmine2-27.5.1.tgz#a037b0034ef49a9f3d71c4375a796f3b230d1ac4" - integrity sha512-jtq7VVyG8SqAorDpApwiJJImd0V2wv1xzdheGHRGyuT7gZm6gG47QEskOlzsN1PG/6WNaCo5pmwMHDf3AkG2pQ== +jest-leak-detector@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-leak-detector/-/jest-leak-detector-29.7.0.tgz#5b7ec0dadfdfec0ca383dc9aa016d36b5ea4c728" + integrity sha512-kYA8IJcSYtST2BY9I+SMC32nDpBT3J2NvWJx8+JCuCdl/CR1I4EKUJROiP8XtCcxqgTTBGJNdbB1A8XRKbTetw== dependencies: - "@jest/environment" "^27.5.1" - "@jest/source-map" "^27.5.1" - "@jest/test-result" "^27.5.1" - "@jest/types" "^27.5.1" - "@types/node" "*" - chalk "^4.0.0" - co "^4.6.0" - expect "^27.5.1" - is-generator-fn "^2.0.0" - jest-each "^27.5.1" - jest-matcher-utils "^27.5.1" - jest-message-util "^27.5.1" - jest-runtime "^27.5.1" - jest-snapshot "^27.5.1" - jest-util "^27.5.1" - pretty-format "^27.5.1" - throat "^6.0.1" + jest-get-type "^29.6.3" + pretty-format "^29.7.0" -jest-leak-detector@^27.5.1: - version "27.5.1" - resolved "https://registry.yarnpkg.com/jest-leak-detector/-/jest-leak-detector-27.5.1.tgz#6ec9d54c3579dd6e3e66d70e3498adf80fde3fb8" - integrity sha512-POXfWAMvfU6WMUXftV4HolnJfnPOGEu10fscNCA76KBpRRhcMN2c8d3iT2pxQS3HLbA+5X4sOUPzYO2NUyIlHQ== - dependencies: - jest-get-type "^27.5.1" - pretty-format "^27.5.1" - -jest-matcher-utils@^27.0.0, jest-matcher-utils@^27.5.1: +jest-matcher-utils@^27.0.0: version "27.5.1" resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-27.5.1.tgz#9c0cdbda8245bc22d2331729d1091308b40cf8ab" integrity sha512-z2uTx/T6LBaCoNWNFWwChLBKYxTMcGBRjAt+2SbP929/Fflb9aa5LGma654Rz8z9HLxsrUaYzxE9T/EFIL/PAw== @@ -3774,209 +3876,211 @@ jest-matcher-utils@^27.0.0, jest-matcher-utils@^27.5.1: jest-get-type "^27.5.1" pretty-format "^27.5.1" -jest-message-util@^27.5.1: - version "27.5.1" - resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-27.5.1.tgz#bdda72806da10d9ed6425e12afff38cd1458b6cf" - integrity sha512-rMyFe1+jnyAAf+NHwTclDz0eAaLkVDdKVHHBFWsBWHnnh5YeJMNWWsv7AbFYXfK3oTqvL7VTWkhNLu1jX24D+g== +jest-matcher-utils@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-29.7.0.tgz#ae8fec79ff249fd592ce80e3ee474e83a6c44f12" + integrity sha512-sBkD+Xi9DtcChsI3L3u0+N0opgPYnCRPtGcQYrgXmR+hmt/fYfWAL0xRXYU8eWOdfuLgBe0YCW3AFtnRLagq/g== + dependencies: + chalk "^4.0.0" + jest-diff "^29.7.0" + jest-get-type "^29.6.3" + pretty-format "^29.7.0" + +jest-message-util@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-29.7.0.tgz#8bc392e204e95dfe7564abbe72a404e28e51f7f3" + integrity sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w== dependencies: "@babel/code-frame" "^7.12.13" - "@jest/types" "^27.5.1" + "@jest/types" "^29.6.3" "@types/stack-utils" "^2.0.0" chalk "^4.0.0" graceful-fs "^4.2.9" micromatch "^4.0.4" - pretty-format "^27.5.1" + pretty-format "^29.7.0" slash "^3.0.0" stack-utils "^2.0.3" -jest-mock@^27.5.1: - version "27.5.1" - resolved "https://registry.yarnpkg.com/jest-mock/-/jest-mock-27.5.1.tgz#19948336d49ef4d9c52021d34ac7b5f36ff967d6" - integrity sha512-K4jKbY1d4ENhbrG2zuPWaQBvDly+iZ2yAW+T1fATN78hc0sInwn7wZB8XtlNnvHug5RMwV897Xm4LqmPM4e2Og== +jest-mock@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-mock/-/jest-mock-29.7.0.tgz#4e836cf60e99c6fcfabe9f99d017f3fdd50a6347" + integrity sha512-ITOMZn+UkYS4ZFh83xYAOzWStloNzJFO2s8DWrE4lhtGD+AorgnbkiKERe4wQVBydIGPx059g6riW5Btp6Llnw== dependencies: - "@jest/types" "^27.5.1" + "@jest/types" "^29.6.3" "@types/node" "*" + jest-util "^29.7.0" jest-pnp-resolver@^1.2.2: version "1.2.3" resolved "https://registry.yarnpkg.com/jest-pnp-resolver/-/jest-pnp-resolver-1.2.3.tgz#930b1546164d4ad5937d5540e711d4d38d4cad2e" integrity sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w== -jest-regex-util@^27.5.1: - version "27.5.1" - resolved "https://registry.yarnpkg.com/jest-regex-util/-/jest-regex-util-27.5.1.tgz#4da143f7e9fd1e542d4aa69617b38e4a78365b95" - integrity sha512-4bfKq2zie+x16okqDXjXn9ql2B0dScQu+vcwe4TvFVhkVyuWLqpZrZtXxLLWoXYgn0E87I6r6GRYHF7wFZBUvg== +jest-regex-util@^29.6.3: + version "29.6.3" + resolved "https://registry.yarnpkg.com/jest-regex-util/-/jest-regex-util-29.6.3.tgz#4a556d9c776af68e1c5f48194f4d0327d24e8a52" + integrity sha512-KJJBsRCyyLNWCNBOvZyRDnAIfUiRJ8v+hOBQYGn8gDyF3UegwiP4gwRR3/SDa42g1YbVycTidUF3rKjyLFDWbg== -jest-resolve-dependencies@^27.5.1: - version "27.5.1" - resolved "https://registry.yarnpkg.com/jest-resolve-dependencies/-/jest-resolve-dependencies-27.5.1.tgz#d811ecc8305e731cc86dd79741ee98fed06f1da8" - integrity sha512-QQOOdY4PE39iawDn5rzbIePNigfe5B9Z91GDD1ae/xNDlu9kaat8QQ5EKnNmVWPV54hUdxCVwwj6YMgR2O7IOg== +jest-resolve-dependencies@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-resolve-dependencies/-/jest-resolve-dependencies-29.7.0.tgz#1b04f2c095f37fc776ff40803dc92921b1e88428" + integrity sha512-un0zD/6qxJ+S0et7WxeI3H5XSe9lTBBR7bOHCHXkKR6luG5mwDDlIzVQ0V5cZCuoTgEdcdwzTghYkTWfubi+nA== dependencies: - "@jest/types" "^27.5.1" - jest-regex-util "^27.5.1" - jest-snapshot "^27.5.1" + jest-regex-util "^29.6.3" + jest-snapshot "^29.7.0" -jest-resolve@^27.5.1: - version "27.5.1" - resolved "https://registry.yarnpkg.com/jest-resolve/-/jest-resolve-27.5.1.tgz#a2f1c5a0796ec18fe9eb1536ac3814c23617b384" - integrity sha512-FFDy8/9E6CV83IMbDpcjOhumAQPDyETnU2KZ1O98DwTnz8AOBsW/Xv3GySr1mOZdItLR+zDZ7I/UdTFbgSOVCw== +jest-resolve@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-resolve/-/jest-resolve-29.7.0.tgz#64d6a8992dd26f635ab0c01e5eef4399c6bcbc30" + integrity sha512-IOVhZSrg+UvVAshDSDtHyFCCBUl/Q3AAJv8iZ6ZjnZ74xzvwuzLXid9IIIPgTnY62SJjfuupMKZsZQRsCvxEgA== dependencies: - "@jest/types" "^27.5.1" chalk "^4.0.0" graceful-fs "^4.2.9" - jest-haste-map "^27.5.1" + jest-haste-map "^29.7.0" jest-pnp-resolver "^1.2.2" - jest-util "^27.5.1" - jest-validate "^27.5.1" + jest-util "^29.7.0" + jest-validate "^29.7.0" resolve "^1.20.0" - resolve.exports "^1.1.0" + resolve.exports "^2.0.0" slash "^3.0.0" -jest-runner@^27.5.1: - version "27.5.1" - resolved "https://registry.yarnpkg.com/jest-runner/-/jest-runner-27.5.1.tgz#071b27c1fa30d90540805c5645a0ec167c7b62e5" - integrity sha512-g4NPsM4mFCOwFKXO4p/H/kWGdJp9V8kURY2lX8Me2drgXqG7rrZAx5kv+5H7wtt/cdFIjhqYx1HrlqWHaOvDaQ== - dependencies: - "@jest/console" "^27.5.1" - "@jest/environment" "^27.5.1" - "@jest/test-result" "^27.5.1" - "@jest/transform" "^27.5.1" - "@jest/types" "^27.5.1" +jest-runner@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-runner/-/jest-runner-29.7.0.tgz#809af072d408a53dcfd2e849a4c976d3132f718e" + integrity sha512-fsc4N6cPCAahybGBfTRcq5wFR6fpLznMg47sY5aDpsoejOcVYFb07AHuSnR0liMcPTgBsA3ZJL6kFOjPdoNipQ== + dependencies: + "@jest/console" "^29.7.0" + "@jest/environment" "^29.7.0" + "@jest/test-result" "^29.7.0" + "@jest/transform" "^29.7.0" + "@jest/types" "^29.6.3" "@types/node" "*" chalk "^4.0.0" - emittery "^0.8.1" + emittery "^0.13.1" graceful-fs "^4.2.9" - jest-docblock "^27.5.1" - jest-environment-jsdom "^27.5.1" - jest-environment-node "^27.5.1" - jest-haste-map "^27.5.1" - jest-leak-detector "^27.5.1" - jest-message-util "^27.5.1" - jest-resolve "^27.5.1" - jest-runtime "^27.5.1" - jest-util "^27.5.1" - jest-worker "^27.5.1" - source-map-support "^0.5.6" - throat "^6.0.1" - -jest-runtime@^27.5.1: - version "27.5.1" - resolved "https://registry.yarnpkg.com/jest-runtime/-/jest-runtime-27.5.1.tgz#4896003d7a334f7e8e4a53ba93fb9bcd3db0a1af" - integrity sha512-o7gxw3Gf+H2IGt8fv0RiyE1+r83FJBRruoA+FXrlHw6xEyBsU8ugA6IPfTdVyA0w8HClpbK+DGJxH59UrNMx8A== - dependencies: - "@jest/environment" "^27.5.1" - "@jest/fake-timers" "^27.5.1" - "@jest/globals" "^27.5.1" - "@jest/source-map" "^27.5.1" - "@jest/test-result" "^27.5.1" - "@jest/transform" "^27.5.1" - "@jest/types" "^27.5.1" + jest-docblock "^29.7.0" + jest-environment-node "^29.7.0" + jest-haste-map "^29.7.0" + jest-leak-detector "^29.7.0" + jest-message-util "^29.7.0" + jest-resolve "^29.7.0" + jest-runtime "^29.7.0" + jest-util "^29.7.0" + jest-watcher "^29.7.0" + jest-worker "^29.7.0" + p-limit "^3.1.0" + source-map-support "0.5.13" + +jest-runtime@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-runtime/-/jest-runtime-29.7.0.tgz#efecb3141cf7d3767a3a0cc8f7c9990587d3d817" + integrity sha512-gUnLjgwdGqW7B4LvOIkbKs9WGbn+QLqRQQ9juC6HndeDiezIwhDP+mhMwHWCEcfQ5RUXa6OPnFF8BJh5xegwwQ== + dependencies: + "@jest/environment" "^29.7.0" + "@jest/fake-timers" "^29.7.0" + "@jest/globals" "^29.7.0" + "@jest/source-map" "^29.6.3" + "@jest/test-result" "^29.7.0" + "@jest/transform" "^29.7.0" + "@jest/types" "^29.6.3" + "@types/node" "*" chalk "^4.0.0" cjs-module-lexer "^1.0.0" collect-v8-coverage "^1.0.0" - execa "^5.0.0" glob "^7.1.3" graceful-fs "^4.2.9" - jest-haste-map "^27.5.1" - jest-message-util "^27.5.1" - jest-mock "^27.5.1" - jest-regex-util "^27.5.1" - jest-resolve "^27.5.1" - jest-snapshot "^27.5.1" - jest-util "^27.5.1" + jest-haste-map "^29.7.0" + jest-message-util "^29.7.0" + jest-mock "^29.7.0" + jest-regex-util "^29.6.3" + jest-resolve "^29.7.0" + jest-snapshot "^29.7.0" + jest-util "^29.7.0" slash "^3.0.0" strip-bom "^4.0.0" -jest-serializer@^27.5.1: - version "27.5.1" - resolved "https://registry.yarnpkg.com/jest-serializer/-/jest-serializer-27.5.1.tgz#81438410a30ea66fd57ff730835123dea1fb1f64" - integrity sha512-jZCyo6iIxO1aqUxpuBlwTDMkzOAJS4a3eYz3YzgxxVQFwLeSA7Jfq5cbqCY+JLvTDrWirgusI/0KwxKMgrdf7w== - dependencies: - "@types/node" "*" - graceful-fs "^4.2.9" - -jest-snapshot@^27.5.1: - version "27.5.1" - resolved "https://registry.yarnpkg.com/jest-snapshot/-/jest-snapshot-27.5.1.tgz#b668d50d23d38054a51b42c4039cab59ae6eb6a1" - integrity sha512-yYykXI5a0I31xX67mgeLw1DZ0bJB+gpq5IpSuCAoyDi0+BhgU/RIrL+RTzDmkNTchvDFWKP8lp+w/42Z3us5sA== +jest-snapshot@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-snapshot/-/jest-snapshot-29.7.0.tgz#c2c574c3f51865da1bb329036778a69bf88a6be5" + integrity sha512-Rm0BMWtxBcioHr1/OX5YCP8Uov4riHvKPknOGs804Zg9JGZgmIBkbtlxJC/7Z4msKYVbIJtfU+tKb8xlYNfdkw== dependencies: - "@babel/core" "^7.7.2" + "@babel/core" "^7.11.6" "@babel/generator" "^7.7.2" + "@babel/plugin-syntax-jsx" "^7.7.2" "@babel/plugin-syntax-typescript" "^7.7.2" - "@babel/traverse" "^7.7.2" - "@babel/types" "^7.0.0" - "@jest/transform" "^27.5.1" - "@jest/types" "^27.5.1" - "@types/babel__traverse" "^7.0.4" - "@types/prettier" "^2.1.5" + "@babel/types" "^7.3.3" + "@jest/expect-utils" "^29.7.0" + "@jest/transform" "^29.7.0" + "@jest/types" "^29.6.3" babel-preset-current-node-syntax "^1.0.0" chalk "^4.0.0" - expect "^27.5.1" + expect "^29.7.0" graceful-fs "^4.2.9" - jest-diff "^27.5.1" - jest-get-type "^27.5.1" - jest-haste-map "^27.5.1" - jest-matcher-utils "^27.5.1" - jest-message-util "^27.5.1" - jest-util "^27.5.1" + jest-diff "^29.7.0" + jest-get-type "^29.6.3" + jest-matcher-utils "^29.7.0" + jest-message-util "^29.7.0" + jest-util "^29.7.0" natural-compare "^1.4.0" - pretty-format "^27.5.1" - semver "^7.3.2" + pretty-format "^29.7.0" + semver "^7.5.3" -jest-util@^27.0.0, jest-util@^27.5.1: - version "27.5.1" - resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-27.5.1.tgz#3ba9771e8e31a0b85da48fe0b0891fb86c01c2f9" - integrity sha512-Kv2o/8jNvX1MQ0KGtw480E/w4fBCDOnH6+6DmeKi6LZUIlKA5kwY0YNdlzaWTiVgxqAqik11QyxDOKk543aKXw== +jest-util@^29.0.0, jest-util@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-29.7.0.tgz#23c2b62bfb22be82b44de98055802ff3710fc0bc" + integrity sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA== dependencies: - "@jest/types" "^27.5.1" + "@jest/types" "^29.6.3" "@types/node" "*" chalk "^4.0.0" ci-info "^3.2.0" graceful-fs "^4.2.9" picomatch "^2.2.3" -jest-validate@^27.5.1: - version "27.5.1" - resolved "https://registry.yarnpkg.com/jest-validate/-/jest-validate-27.5.1.tgz#9197d54dc0bdb52260b8db40b46ae668e04df067" - integrity sha512-thkNli0LYTmOI1tDB3FI1S1RTp/Bqyd9pTarJwL87OIBFuqEb5Apv5EaApEudYg4g86e3CT6kM0RowkhtEnCBQ== +jest-validate@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-validate/-/jest-validate-29.7.0.tgz#7bf705511c64da591d46b15fce41400d52147d9c" + integrity sha512-ZB7wHqaRGVw/9hST/OuFUReG7M8vKeq0/J2egIGLdvjHCmYqGARhzXmtgi+gVeZ5uXFF219aOc3Ls2yLg27tkw== dependencies: - "@jest/types" "^27.5.1" + "@jest/types" "^29.6.3" camelcase "^6.2.0" chalk "^4.0.0" - jest-get-type "^27.5.1" + jest-get-type "^29.6.3" leven "^3.1.0" - pretty-format "^27.5.1" + pretty-format "^29.7.0" -jest-watcher@^27.5.1: - version "27.5.1" - resolved "https://registry.yarnpkg.com/jest-watcher/-/jest-watcher-27.5.1.tgz#71bd85fb9bde3a2c2ec4dc353437971c43c642a2" - integrity sha512-z676SuD6Z8o8qbmEGhoEUFOM1+jfEiL3DXHK/xgEiG2EyNYfFG60jluWcupY6dATjfEsKQuibReS1djInQnoVw== +jest-watcher@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-watcher/-/jest-watcher-29.7.0.tgz#7810d30d619c3a62093223ce6bb359ca1b28a2f2" + integrity sha512-49Fg7WXkU3Vl2h6LbLtMQ/HyB6rXSIX7SqvBLQmssRBGN9I0PNvPmAmCWSOY6SOvrjhI/F7/bGAv9RtnsPA03g== dependencies: - "@jest/test-result" "^27.5.1" - "@jest/types" "^27.5.1" + "@jest/test-result" "^29.7.0" + "@jest/types" "^29.6.3" "@types/node" "*" ansi-escapes "^4.2.1" chalk "^4.0.0" - jest-util "^27.5.1" + emittery "^0.13.1" + jest-util "^29.7.0" string-length "^4.0.1" -jest-worker@^27.5.1: - version "27.5.1" - resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-27.5.1.tgz#8d146f0900e8973b106b6f73cc1e9a8cb86f8db0" - integrity sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg== +jest-worker@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-29.7.0.tgz#acad073acbbaeb7262bd5389e1bcf43e10058d4a" + integrity sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw== dependencies: "@types/node" "*" + jest-util "^29.7.0" merge-stream "^2.0.0" supports-color "^8.0.0" -jest@^27.5.1: - version "27.5.1" - resolved "https://registry.yarnpkg.com/jest/-/jest-27.5.1.tgz#dadf33ba70a779be7a6fc33015843b51494f63fc" - integrity sha512-Yn0mADZB89zTtjkPJEXwrac3LHudkQMR+Paqa8uxJHCBr9agxztUifWCyiYrjhMPBoUVBjyny0I7XH6ozDr7QQ== +jest@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest/-/jest-29.7.0.tgz#994676fc24177f088f1c5e3737f5697204ff2613" + integrity sha512-NIy3oAFp9shda19hy4HK0HRTWKtPJmGdnvywu01nOqNC2vZg+Z+fvJDxpMQA88eb2I9EcafcdjYgsDthnYTvGw== dependencies: - "@jest/core" "^27.5.1" + "@jest/core" "^29.7.0" + "@jest/types" "^29.6.3" import-local "^3.0.2" - jest-cli "^27.5.1" + jest-cli "^29.7.0" "js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0: version "4.0.0" @@ -3998,50 +4102,22 @@ js-yaml@^4.1.0: dependencies: argparse "^2.0.1" -jsdom@^16.6.0: - version "16.7.0" - resolved "https://registry.yarnpkg.com/jsdom/-/jsdom-16.7.0.tgz#918ae71965424b197c819f8183a754e18977b710" - integrity sha512-u9Smc2G1USStM+s/x1ru5Sxrl6mPYCbByG1U/hUmqaVsm4tbNyS7CicOSRyuGQYZhTu0h84qkZZQ/I+dzizSVw== - dependencies: - abab "^2.0.5" - acorn "^8.2.4" - acorn-globals "^6.0.0" - cssom "^0.4.4" - cssstyle "^2.3.0" - data-urls "^2.0.0" - decimal.js "^10.2.1" - domexception "^2.0.1" - escodegen "^2.0.0" - form-data "^3.0.0" - html-encoding-sniffer "^2.0.1" - http-proxy-agent "^4.0.1" - https-proxy-agent "^5.0.0" - is-potential-custom-element-name "^1.0.1" - nwsapi "^2.2.0" - parse5 "6.0.1" - saxes "^5.0.1" - symbol-tree "^3.2.4" - tough-cookie "^4.0.0" - w3c-hr-time "^1.0.2" - w3c-xmlserializer "^2.0.0" - webidl-conversions "^6.1.0" - whatwg-encoding "^1.0.5" - whatwg-mimetype "^2.3.0" - whatwg-url "^8.5.0" - ws "^7.4.6" - xml-name-validator "^3.0.0" - jsesc@^2.5.1: version "2.5.2" resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4" integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA== +jsesc@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-3.0.2.tgz#bb8b09a6597ba426425f2e4a07245c3d00b9343e" + integrity sha512-xKqzzWXDttJuOcawBt4KnKHHIf5oQ/Cxax+0PWFG+DFDgHNAdi+TXECADI+RYiFUMmx8792xsMbbgXj4CwnP4g== + json-parse-even-better-errors@^2.3.0: version "2.3.1" resolved "https://registry.yarnpkg.com/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz#7c47805a94319928e05777405dc12e1f7a4ee02d" integrity sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w== -json5@2.x, json5@^2.2.0, json5@^2.2.1, json5@^2.2.3: +json5@^2.2.0, json5@^2.2.1, json5@^2.2.3: version "2.2.3" resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.3.tgz#78cd6f1a19bdc12b73db5ad0c61efd66c1e29283" integrity sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg== @@ -4210,12 +4286,12 @@ lodash.isequal@^4.5.0: resolved "https://registry.yarnpkg.com/lodash.isequal/-/lodash.isequal-4.5.0.tgz#415c4478f2bcc30120c22ce10ed3226f7d3e18e0" integrity sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ== -lodash.memoize@4.x: +lodash.memoize@^4.1.2: version "4.1.2" resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-4.1.2.tgz#bcc6c49a42a2840ed997f323eada5ecd182e0bfe" integrity sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag== -lodash@^4.17.21, lodash@^4.7.0: +lodash@^4.17.21: version "4.17.21" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== @@ -4256,7 +4332,7 @@ make-dir@^4.0.0: dependencies: semver "^7.5.3" -make-error@1.x: +make-error@^1.3.6: version "1.3.6" resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2" integrity sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw== @@ -4314,26 +4390,14 @@ merge-stream@^2.0.0: resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60" integrity sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w== -micromatch@^4.0.4, micromatch@^4.0.5: - version "4.0.5" - resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.5.tgz#bc8999a7cbbf77cdc89f132f6e467051b49090c6" - integrity sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA== +micromatch@^4.0.4, micromatch@^4.0.5, micromatch@^4.0.8: + version "4.0.8" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.8.tgz#d66fa18f3a47076789320b9b1af32bd86d9fa202" + integrity sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA== dependencies: - braces "^3.0.2" + braces "^3.0.3" picomatch "^2.3.1" -mime-db@1.52.0: - version "1.52.0" - resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70" - integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg== - -mime-types@^2.1.12: - version "2.1.35" - resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a" - integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw== - dependencies: - mime-db "1.52.0" - mime@^1.4.1: version "1.6.0" resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1" @@ -4344,19 +4408,26 @@ mimic-fn@^2.1.0: resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg== -minimatch@^3.0.4, minimatch@^3.1.1: +minimatch@^3.0.4, minimatch@^3.1.1, minimatch@^3.1.2: version "3.1.2" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== dependencies: brace-expansion "^1.1.7" +minimatch@^5.0.1: + version "5.1.6" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-5.1.6.tgz#1cfcb8cf5522ea69952cd2af95ae09477f122a96" + integrity sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g== + dependencies: + brace-expansion "^2.0.1" + ms@2.1.2: version "2.1.2" resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== -ms@^2.1.1: +ms@^2.1.1, ms@^2.1.3: version "2.1.3" resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== @@ -4450,6 +4521,11 @@ node-releases@^2.0.14: resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.14.tgz#2ffb053bceb8b2be8495ece1ab6ce600c4461b0b" integrity sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw== +node-releases@^2.0.18: + version "2.0.18" + resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.18.tgz#f010e8d35e2fe8d6b2944f03f70213ecedc4ca3f" + integrity sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g== + normalize-path@^3.0.0, normalize-path@~3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" @@ -4479,11 +4555,6 @@ numeral@^2.0.6: resolved "https://registry.yarnpkg.com/numeral/-/numeral-2.0.6.tgz#4ad080936d443c2561aed9f2197efffe25f4e506" integrity sha512-qaKRmtYPZ5qdw4jWJD6bxEf1FJEqllJrwxCLIm0sQU/A7v2/czigzOb+C2uSiFsa9lBUzeH7M1oK+Q+OLxL3kA== -nwsapi@^2.2.0: - version "2.2.7" - resolved "https://registry.yarnpkg.com/nwsapi/-/nwsapi-2.2.7.tgz#738e0707d3128cb750dddcfe90e4610482df0f30" - integrity sha512-ub5E4+FBPKwAZx0UwIQOjYWGHTEq5sPqHQNRN8Z9e4A7u3Tj1weLJsL59yH9vmvqEtBHaOmT6cYQKIZOxp35FQ== - object-assign@^4.1.1: version "4.1.1" resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" @@ -4515,6 +4586,13 @@ p-limit@^2.2.0: dependencies: p-try "^2.0.0" +p-limit@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-3.1.0.tgz#e1daccbe78d0d1388ca18c64fea38e3e57e3706b" + integrity sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ== + dependencies: + yocto-queue "^0.1.0" + p-locate@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-4.1.0.tgz#a3428bb7088b3a60292f66919278b7c297ad4f07" @@ -4581,7 +4659,7 @@ parse-node-version@^1.0.1: resolved "https://registry.yarnpkg.com/parse-node-version/-/parse-node-version-1.0.1.tgz#e2b5dbede00e7fa9bc363607f53327e8b073189b" integrity sha512-3YHlOa/JgH6Mnpr05jP9eDG254US9ek25LyIxZlDItp2iJtwyaXQb57lBYLdT3MowkUFYEV2XXNAYIPlESvJlA== -parse5@6.0.1, parse5@^6.0.0: +parse5@^6.0.0: version "6.0.1" resolved "https://registry.yarnpkg.com/parse5/-/parse5-6.0.1.tgz#e1a1c085c569b3dc08321184f19a39cc27f7c30b" integrity sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw== @@ -4616,6 +4694,11 @@ picocolors@^1.0.0: resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c" integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ== +picocolors@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.1.0.tgz#5358b76a78cde483ba5cef6a9dc9671440b27d59" + integrity sha512-TQ92mBOW0l3LeMeyLV6mzy/kWr8lkd/hp3mTg7wYK7zJhuBStmGMBG0BdeDZS/dZx1IukaX6Bk11zcln25o1Aw== + picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.2.3, picomatch@^2.3.1: version "2.3.1" resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" @@ -4686,6 +4769,15 @@ pretty-format@^27.0.0, pretty-format@^27.5.1: ansi-styles "^5.0.0" react-is "^17.0.1" +pretty-format@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-29.7.0.tgz#ca42c758310f365bfa71a0bda0a807160b776812" + integrity sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ== + dependencies: + "@jest/schemas" "^29.6.3" + ansi-styles "^5.0.0" + react-is "^18.0.0" + prismjs@~1.27.0: version "1.27.0" resolved "https://registry.yarnpkg.com/prismjs/-/prismjs-1.27.0.tgz#bb6ee3138a0b438a3653dd4d6ce0cc6510a45057" @@ -4720,15 +4812,10 @@ prr@~1.0.1: resolved "https://registry.yarnpkg.com/prr/-/prr-1.0.1.tgz#d3fc114ba06995a45ec6893f484ceb1d78f5f476" integrity sha512-yPw4Sng1gWghHQWj0B3ZggWUm4qVbPwPFcRG8KyxiU7J2OHFSoEHKS+EZ3fv5l1t9CyCiop6l/ZYeWbrgoQejw== -psl@^1.1.33: - version "1.9.0" - resolved "https://registry.yarnpkg.com/psl/-/psl-1.9.0.tgz#d0df2a137f00794565fcaf3b2c00cd09f8d5a5a7" - integrity sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag== - -punycode@^2.1.1: - version "2.3.0" - resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.3.0.tgz#f67fa67c94da8f4d0cfff981aee4118064199b8f" - integrity sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA== +pure-rand@^6.0.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/pure-rand/-/pure-rand-6.1.0.tgz#d173cf23258231976ccbdb05247c9787957604f2" + integrity sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA== querystringify@^2.1.1: version "2.2.0" @@ -4836,6 +4923,11 @@ react-is@^17.0.1, react-is@^17.0.2: resolved "https://registry.yarnpkg.com/react-is/-/react-is-17.0.2.tgz#e691d4a8e9c789365655539ab372762b0efb54f0" integrity sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w== +react-is@^18.0.0: + version "18.3.1" + resolved "https://registry.yarnpkg.com/react-is/-/react-is-18.3.1.tgz#e83557dc12eae63a99e003a46388b1dcbb44db7e" + integrity sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg== + react-is@~16.3.0: version "16.3.2" resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.3.2.tgz#f4d3d0e2f5fbb6ac46450641eb2e25bf05d36b22" @@ -5027,10 +5119,10 @@ resolve-from@^5.0.0: resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-5.0.0.tgz#c35225843df8f776df21c57557bc087e9dfdfc69" integrity sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw== -resolve.exports@^1.1.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/resolve.exports/-/resolve.exports-1.1.1.tgz#05cfd5b3edf641571fd46fa608b610dda9ead999" - integrity sha512-/NtpHNDN7jWhAaQ9BvBUYZ6YTXsRBgfqWFWP7BZBaoMJO/I3G5OFzvTuWNlZC3aPjins1F+TNrLKsGbH4rfsRQ== +resolve.exports@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/resolve.exports/-/resolve.exports-2.0.2.tgz#f8c934b8e6a13f539e38b7098e2e36134f01e800" + integrity sha512-X2UW6Nw3n/aMgDVy+0rSqgHlv39WZAlZrXCdnbyEiKm17DSqHX4MmQMaST3FbeWR5FTuRcUwYAziZajji0Y7mg== resolve@^1.19.0: version "1.22.2" @@ -5050,7 +5142,7 @@ resolve@^1.20.0: path-parse "^1.0.7" supports-preserve-symlinks-flag "^1.0.0" -rimraf@^3.0.0, rimraf@^3.0.2: +rimraf@^3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== @@ -5069,7 +5161,7 @@ safe-buffer@^5.0.1: resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== -"safer-buffer@>= 2.1.2 < 3", "safer-buffer@>= 2.1.2 < 3.0.0": +"safer-buffer@>= 2.1.2 < 3.0.0": version "2.1.2" resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== @@ -5088,13 +5180,6 @@ sax@^1.2.4: resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw== -saxes@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/saxes/-/saxes-5.0.1.tgz#eebab953fa3b7608dbe94e5dadb15c888fa6696d" - integrity sha512-5LBh1Tls8c9xgGjw3QrMwETmTMVk0oFgvrFSvWx62llR2hcEInrKNZ2GZCCuuy2lvWrdl5jhbpeqc5hRYKFOcw== - dependencies: - xmlchars "^2.2.0" - scheduler@^0.20.2: version "0.20.2" resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.20.2.tgz#4baee39436e34aa93b4874bddcbf0fe8b8b50e91" @@ -5103,7 +5188,7 @@ scheduler@^0.20.2: loose-envify "^1.1.0" object-assign "^4.1.1" -semver@7.x, semver@^5.6.0, semver@^5.7.1, semver@^6.3.0, semver@^6.3.1, semver@^7.3.2, semver@^7.5.2, semver@^7.5.3: +semver@^5.6.0, semver@^5.7.1, semver@^6.3.0, semver@^6.3.1, semver@^7.5.2, semver@^7.5.3, semver@^7.5.4, semver@^7.6.3: version "7.5.4" resolved "https://registry.yarnpkg.com/semver/-/semver-7.5.4.tgz#483986ec4ed38e1c6c48c34894a9182dbff68a6e" integrity sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA== @@ -5127,7 +5212,7 @@ shell-quote@^1.7.3: resolved "https://registry.yarnpkg.com/shell-quote/-/shell-quote-1.8.1.tgz#6dbf4db75515ad5bac63b4f1894c3a154c766680" integrity sha512-6j1W9l1iAs/4xYBI1SYOVZyFcCis9b4KCLQ8fgAGG07QvzaRLVVRQvAy85yNmmZSjYjg4MWh4gNvlPujU/5LpA== -signal-exit@^3.0.2, signal-exit@^3.0.3: +signal-exit@^3.0.3, signal-exit@^3.0.7: version "3.0.7" resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9" integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ== @@ -5147,10 +5232,10 @@ slash@^3.0.0: resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.0.2.tgz#adbc361d9c62df380125e7f161f71c826f1e490c" integrity sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw== -source-map-support@^0.5.6: - version "0.5.21" - resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.21.tgz#04fe7c7f9e1ed2d662233c28cb2b35b9f63f6e4f" - integrity sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w== +source-map-support@0.5.13: + version "0.5.13" + resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.13.tgz#31b24a9c2e73c2de85066c0feb7d44767ed52932" + integrity sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w== dependencies: buffer-from "^1.0.0" source-map "^0.6.0" @@ -5160,16 +5245,11 @@ source-map@^0.5.7: resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" integrity sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ== -source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.0, source-map@~0.6.1: +source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.0: version "0.6.1" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== -source-map@^0.7.3: - version "0.7.4" - resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.7.4.tgz#a9bbe705c9d8846f4e08ff6765acf0f1b0898656" - integrity sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA== - space-separated-tokens@^1.0.0: version "1.1.5" resolved "https://registry.yarnpkg.com/space-separated-tokens/-/space-separated-tokens-1.1.5.tgz#85f32c3d10d9682007e917414ddc5c26d1aa6899" @@ -5274,7 +5354,7 @@ supports-color@^5.3.0: dependencies: has-flag "^3.0.0" -supports-color@^7.0.0, supports-color@^7.1.0: +supports-color@^7.1.0: version "7.2.0" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== @@ -5288,14 +5368,6 @@ supports-color@^8.0.0, supports-color@^8.1.0: dependencies: has-flag "^4.0.0" -supports-hyperlinks@^2.0.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/supports-hyperlinks/-/supports-hyperlinks-2.3.0.tgz#3943544347c1ff90b15effb03fc14ae45ec10624" - integrity sha512-RpsAZlpWcDwOPQA22aCH4J0t7L8JmAvsCxfOSEwm7cQs3LshN36QaTkwd70DnBOXDWGssw2eUoc8CaRWT0XunA== - dependencies: - has-flag "^4.0.0" - supports-color "^7.0.0" - supports-preserve-symlinks-flag@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09" @@ -5314,11 +5386,6 @@ svgo@^2.4.0: picocolors "^1.0.0" stable "^0.1.8" -symbol-tree@^3.2.4: - version "3.2.4" - resolved "https://registry.yarnpkg.com/symbol-tree/-/symbol-tree-3.2.4.tgz#430637d248ba77e078883951fb9aa0eed7c63fa2" - integrity sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw== - tabbable@^3.0.0: version "3.1.2" resolved "https://registry.yarnpkg.com/tabbable/-/tabbable-3.1.2.tgz#f2d16cccd01f400e38635c7181adfe0ad965a4a2" @@ -5329,14 +5396,6 @@ term-size@^2.2.1: resolved "https://registry.yarnpkg.com/term-size/-/term-size-2.2.1.tgz#2a6a54840432c2fb6320fea0f415531e90189f54" integrity sha512-wK0Ri4fOGjv/XPy8SBHZChl8CM7uMc5VML7SqiQ0zG7+J5Vr+RMQDoHa2CNT6KHUnTGIXH34UDMkPzAUyapBZg== -terminal-link@^2.0.0: - version "2.1.1" - resolved "https://registry.yarnpkg.com/terminal-link/-/terminal-link-2.1.1.tgz#14a64a27ab3c0df933ea546fba55f2d078edc994" - integrity sha512-un0FmiRUQNr5PJqy9kP7c40F5BOfpGlYTrxonDChEZB7pzZxRNp/bt+ymiy9/npwXya9KH99nJ/GXFIiUkYGFQ== - dependencies: - ansi-escapes "^4.2.1" - supports-hyperlinks "^2.0.0" - test-exclude@^6.0.0: version "6.0.0" resolved "https://registry.yarnpkg.com/test-exclude/-/test-exclude-6.0.0.tgz#04a8698661d805ea6fa293b6cb9e63ac044ef15e" @@ -5351,11 +5410,6 @@ text-diff@^1.0.1: resolved "https://registry.yarnpkg.com/text-diff/-/text-diff-1.0.1.tgz#6c105905435e337857375c9d2f6ca63e453ff565" integrity sha512-jAnlP3ggZk7FeLX1awaMR8Y2sMyil9P9FXvNjaIJIQBAom1zvpKGGH31htOVrUFp0vlyygmJJpNrbJ4rfjsxrA== -throat@^6.0.1: - version "6.0.2" - resolved "https://registry.yarnpkg.com/throat/-/throat-6.0.2.tgz#51a3fbb5e11ae72e2cf74861ed5c8020f89f29fe" - integrity sha512-WKexMoJj3vEuK0yFEapj8y64V0A6xcuPuK9Gt1d0R+dzCSJc0lHqQytAbSB4cDAK0dWh4T0E2ETkoLE2WZ41OQ== - timsort@^0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/timsort/-/timsort-0.3.0.tgz#405411a8e7e6339fe64db9a234de11dc31e02bd4" @@ -5383,23 +5437,6 @@ to-regex-range@^5.0.1: dependencies: is-number "^7.0.0" -tough-cookie@^4.0.0: - version "4.1.3" - resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-4.1.3.tgz#97b9adb0728b42280aa3d814b6b999b2ff0318bf" - integrity sha512-aX/y5pVRkfRnfmuX+OdbSdXvPe6ieKX/G2s7e98f4poJHnqH3281gDPm/metm6E/WRamfx7WC4HUqkWHfQHprw== - dependencies: - psl "^1.1.33" - punycode "^2.1.1" - universalify "^0.2.0" - url-parse "^1.5.3" - -tr46@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/tr46/-/tr46-2.1.0.tgz#fa87aa81ca5d5941da8cbf1f9b749dc969a4e240" - integrity sha512-15Ih7phfcdP5YxqiB+iDtLoaTz4Nd35+IiAv0kQ5FNKHzXgdWqPoTIqEDDJmXceQt4JZk6lVPT8lnDlPpGDppw== - dependencies: - punycode "^2.1.1" - tree-kill@^1.2.2: version "1.2.2" resolved "https://registry.yarnpkg.com/tree-kill/-/tree-kill-1.2.2.tgz#4ca09a9092c88b73a7cdc5e8a01b507b0790a0cc" @@ -5420,19 +5457,20 @@ trough@^1.0.0: resolved "https://registry.yarnpkg.com/trough/-/trough-1.0.5.tgz#b8b639cefad7d0bb2abd37d433ff8293efa5f406" integrity sha512-rvuRbTarPXmMb79SmzEp8aqXNKcK+y0XaB298IXueQ8I2PsrATcPBCSPyK/dDNa2iWOhKlfNnOjdAOTBU/nkFA== -ts-jest@^27.1.4: - version "27.1.5" - resolved "https://registry.yarnpkg.com/ts-jest/-/ts-jest-27.1.5.tgz#0ddf1b163fbaae3d5b7504a1e65c914a95cff297" - integrity sha512-Xv6jBQPoBEvBq/5i2TeSG9tt/nqkbpcurrEG1b+2yfBrcJelOZF9Ml6dmyMh7bcW9JyFbRYpR5rxROSlBLTZHA== +ts-jest@^29.2.5: + version "29.2.5" + resolved "https://registry.yarnpkg.com/ts-jest/-/ts-jest-29.2.5.tgz#591a3c108e1f5ebd013d3152142cb5472b399d63" + integrity sha512-KD8zB2aAZrcKIdGk4OwpJggeLcH1FgrICqDSROWqlnJXGCXK4Mn6FcdK2B6670Xr73lHMG1kHw8R87A0ecZ+vA== dependencies: - bs-logger "0.x" - fast-json-stable-stringify "2.x" - jest-util "^27.0.0" - json5 "2.x" - lodash.memoize "4.x" - make-error "1.x" - semver "7.x" - yargs-parser "20.x" + bs-logger "^0.2.6" + ejs "^3.1.10" + fast-json-stable-stringify "^2.1.0" + jest-util "^29.0.0" + json5 "^2.2.3" + lodash.memoize "^4.1.2" + make-error "^1.3.6" + semver "^7.6.3" + yargs-parser "^21.1.1" tslib@^2.0.0, tslib@^2.0.3, tslib@^2.1.0, tslib@^2.3.0, tslib@^2.3.1: version "2.5.0" @@ -5459,13 +5497,6 @@ type-fest@^0.21.3: resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.21.3.tgz#d260a24b0198436e133fa26a524a6d65fa3b2e37" integrity sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w== -typedarray-to-buffer@^3.1.5: - version "3.1.5" - resolved "https://registry.yarnpkg.com/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz#a97ee7a9ff42691b9f783ff1bc5112fe3fca9080" - integrity sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q== - dependencies: - is-typedarray "^1.0.0" - unherit@^1.0.4: version "1.1.3" resolved "https://registry.yarnpkg.com/unherit/-/unherit-1.1.3.tgz#6c9b503f2b41b262330c80e91c8614abdaa69c22" @@ -5563,11 +5594,6 @@ unist-util-visit@^2.0.0, unist-util-visit@^2.0.3: unist-util-is "^4.0.0" unist-util-visit-parents "^3.0.0" -universalify@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.2.0.tgz#6451760566fa857534745ab1dde952d1b1761be0" - integrity sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg== - update-browserslist-db@^1.0.13: version "1.0.13" resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz#3c5e4f5c083661bd38ef64b6328c26ed6c8248c4" @@ -5576,7 +5602,15 @@ update-browserslist-db@^1.0.13: escalade "^3.1.1" picocolors "^1.0.0" -url-parse@^1.5.0, url-parse@^1.5.3: +update-browserslist-db@^1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.1.1.tgz#80846fba1d79e82547fb661f8d141e0945755fe5" + integrity sha512-R8UzCaa9Az+38REPiJ1tXlImTJXlVfgHZsglwBD/k6nj76ctsH1E3q4doGrukiLQd3sGQYu56r5+lo5r94l29A== + dependencies: + escalade "^3.2.0" + picocolors "^1.1.0" + +url-parse@^1.5.0: version "1.5.10" resolved "https://registry.yarnpkg.com/url-parse/-/url-parse-1.5.10.tgz#9d3c2f736c1d75dd3bd2be507dcc111f1e2ea9c1" integrity sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ== @@ -5614,14 +5648,14 @@ uuid@^8.3.0: resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2" integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg== -v8-to-istanbul@^8.1.0: - version "8.1.1" - resolved "https://registry.yarnpkg.com/v8-to-istanbul/-/v8-to-istanbul-8.1.1.tgz#77b752fd3975e31bbcef938f85e9bd1c7a8d60ed" - integrity sha512-FGtKtv3xIpR6BYhvgH8MI/y78oT7d8Au3ww4QIxymrCtZEh5b8gCw2siywE+puhEmuWKDtmfrvF5UlB298ut3w== +v8-to-istanbul@^9.0.1: + version "9.3.0" + resolved "https://registry.yarnpkg.com/v8-to-istanbul/-/v8-to-istanbul-9.3.0.tgz#b9572abfa62bd556c16d75fdebc1a411d5ff3175" + integrity sha512-kiGUalWN+rgBJ/1OHZsBtU4rXZOfj/7rKQxULKlIzwzQSvMJUUNgPwJEEh7gU6xEVxC0ahoOBvN2YI8GH6FNgA== dependencies: + "@jridgewell/trace-mapping" "^0.3.12" "@types/istanbul-lib-coverage" "^2.0.1" - convert-source-map "^1.6.0" - source-map "^0.7.3" + convert-source-map "^2.0.0" vfile-location@^3.0.0, vfile-location@^3.2.0: version "3.2.0" @@ -5654,21 +5688,7 @@ vfile@^4.0.0, vfile@^4.2.0: unist-util-stringify-position "^2.0.0" vfile-message "^2.0.0" -w3c-hr-time@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz#0a89cdf5cc15822df9c360543676963e0cc308cd" - integrity sha512-z8P5DvDNjKDoFIHK7q8r8lackT6l+jo/Ye3HOle7l9nICP9lf1Ci25fy9vHd0JOWewkIFzXIEig3TdKT7JQ5fQ== - dependencies: - browser-process-hrtime "^1.0.0" - -w3c-xmlserializer@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/w3c-xmlserializer/-/w3c-xmlserializer-2.0.0.tgz#3e7104a05b75146cc60f564380b7f683acf1020a" - integrity sha512-4tzD0mF8iSiMiNs30BiLO3EpfGLZUT2MSX/G+o7ZywDzliWQ3OPtTZ0PTC3B3ca1UAf4cJMHB+2Bf56EriJuRA== - dependencies: - xml-name-validator "^3.0.0" - -walker@^1.0.7: +walker@^1.0.8: version "1.0.8" resolved "https://registry.yarnpkg.com/walker/-/walker-1.0.8.tgz#bd498db477afe573dc04185f011d3ab8a8d7653f" integrity sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ== @@ -5685,37 +5705,6 @@ web-namespaces@^1.0.0: resolved "https://registry.yarnpkg.com/web-namespaces/-/web-namespaces-1.1.4.tgz#bc98a3de60dadd7faefc403d1076d529f5e030ec" integrity sha512-wYxSGajtmoP4WxfejAPIr4l0fVh+jeMXZb08wNc0tMg6xsfZXj3cECqIK0G7ZAqUq0PP8WlMDtaOGVBTAWztNw== -webidl-conversions@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-5.0.0.tgz#ae59c8a00b121543a2acc65c0434f57b0fc11aff" - integrity sha512-VlZwKPCkYKxQgeSbH5EyngOmRp7Ww7I9rQLERETtf5ofd9pGeswWiOtogpEO850jziPRarreGxn5QIiTqpb2wA== - -webidl-conversions@^6.1.0: - version "6.1.0" - resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-6.1.0.tgz#9111b4d7ea80acd40f5270d666621afa78b69514" - integrity sha512-qBIvFLGiBpLjfwmYAaHPXsn+ho5xZnGvyGvsarywGNc8VyQJUMHJ8OBKGGrPER0okBeMDaan4mNBlgBROxuI8w== - -whatwg-encoding@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/whatwg-encoding/-/whatwg-encoding-1.0.5.tgz#5abacf777c32166a51d085d6b4f3e7d27113ddb0" - integrity sha512-b5lim54JOPN9HtzvK9HFXvBma/rnfFeqsic0hSpjtDbVxR3dJKLc+KB4V6GgiGOvl7CY/KNh8rxSo9DKQrnUEw== - dependencies: - iconv-lite "0.4.24" - -whatwg-mimetype@^2.3.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz#3d4b1e0312d2079879f826aff18dbeeca5960fbf" - integrity sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g== - -whatwg-url@^8.0.0, whatwg-url@^8.5.0: - version "8.7.0" - resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-8.7.0.tgz#656a78e510ff8f3937bc0bcbe9f5c0ac35941b77" - integrity sha512-gAojqb/m9Q8a5IV96E3fHJM70AzCkgt4uXYX2O7EmuyOnLrViCQlsEBmF9UQIu3/aeAIp2U17rtbpZWNntQqdg== - dependencies: - lodash "^4.7.0" - tr46 "^2.1.0" - webidl-conversions "^6.1.0" - which@^2.0.1: version "2.0.2" resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" @@ -5737,30 +5726,13 @@ wrappy@1: resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== -write-file-atomic@^3.0.0: - version "3.0.3" - resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-3.0.3.tgz#56bd5c5a5c70481cd19c571bd39ab965a5de56e8" - integrity sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q== +write-file-atomic@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-4.0.2.tgz#a9df01ae5b77858a027fd2e80768ee433555fcfd" + integrity sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg== dependencies: imurmurhash "^0.1.4" - is-typedarray "^1.0.0" - signal-exit "^3.0.2" - typedarray-to-buffer "^3.1.5" - -ws@^7.4.6: - version "7.5.9" - resolved "https://registry.yarnpkg.com/ws/-/ws-7.5.9.tgz#54fa7db29f4c7cec68b1ddd3a89de099942bb591" - integrity sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q== - -xml-name-validator@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/xml-name-validator/-/xml-name-validator-3.0.0.tgz#6ae73e06de4d8c6e47f9fb181f78d648ad457c6a" - integrity sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw== - -xmlchars@^2.2.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/xmlchars/-/xmlchars-2.2.0.tgz#060fe1bcb7f9c76fe2a17db86a9bc3ab894210cb" - integrity sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw== + signal-exit "^3.0.7" xtend@^4.0.0, xtend@^4.0.1: version "4.0.2" @@ -5792,29 +5764,11 @@ yaml@^1.10.0: resolved "https://registry.yarnpkg.com/yaml/-/yaml-1.10.2.tgz#2301c5ffbf12b467de8da2333a459e29e7920e4b" integrity sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg== -yargs-parser@20.x, yargs-parser@^20.2.2: - version "20.2.9" - resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.9.tgz#2eb7dc3b0289718fc295f362753845c41a0c94ee" - integrity sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w== - yargs-parser@^21.1.1: version "21.1.1" resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-21.1.1.tgz#9096bceebf990d21bb31fa9516e0ede294a77d35" integrity sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw== -yargs@^16.2.0: - version "16.2.0" - resolved "https://registry.yarnpkg.com/yargs/-/yargs-16.2.0.tgz#1c82bf0f6b6a66eafce7ef30e376f49a12477f66" - integrity sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw== - dependencies: - cliui "^7.0.2" - escalade "^3.1.1" - get-caller-file "^2.0.5" - require-directory "^2.1.1" - string-width "^4.2.0" - y18n "^5.0.5" - yargs-parser "^20.2.2" - yargs@^17.3.1: version "17.7.1" resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.7.1.tgz#34a77645201d1a8fc5213ace787c220eabbd0967" @@ -5828,6 +5782,11 @@ yargs@^17.3.1: y18n "^5.0.5" yargs-parser "^21.1.1" +yocto-queue@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b" + integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q== + zwitch@^1.0.0: version "1.0.5" resolved "https://registry.yarnpkg.com/zwitch/-/zwitch-1.0.5.tgz#d11d7381ffed16b742f6af7b3f223d5cd9fe9920" diff --git a/redisinsight/ui/src/packages/ri-explain/package.json b/redisinsight/ui/src/packages/ri-explain/package.json index 35d6c2b3cf..6e63895320 100644 --- a/redisinsight/ui/src/packages/ri-explain/package.json +++ b/redisinsight/ui/src/packages/ri-explain/package.json @@ -70,6 +70,8 @@ "uuid": "^9.0.0" }, "resolutions": { + "@parcel/**/micromatch": "^4.0.8", + "@parcel/**/braces": "^3.0.3", "trim": "0.0.3", "**/semver": "^7.5.2" } diff --git a/redisinsight/ui/src/packages/ri-explain/yarn.lock b/redisinsight/ui/src/packages/ri-explain/yarn.lock index 8c1c2c2dcf..3194e15be6 100644 --- a/redisinsight/ui/src/packages/ri-explain/yarn.lock +++ b/redisinsight/ui/src/packages/ri-explain/yarn.lock @@ -1357,12 +1357,12 @@ brace@^0.11.1: resolved "https://registry.yarnpkg.com/brace/-/brace-0.11.1.tgz#4896fcc9d544eef45f4bb7660db320d3b379fe58" integrity sha512-Fc8Ne62jJlKHiG/ajlonC4Sd66Pq68fFwK4ihJGNZpGqboc324SQk+lRvMzpPRuJOmfrJefdG8/7JdWX4bzJ2Q== -braces@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" - integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A== +braces@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.3.tgz#490332f40919452272d55a8480adc0c441358789" + integrity sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA== dependencies: - fill-range "^7.0.1" + fill-range "^7.1.1" browserslist@^4.6.6: version "4.23.0" @@ -1754,10 +1754,10 @@ file-selector@^0.4.0: dependencies: tslib "^2.0.3" -fill-range@^7.0.1: - version "7.0.1" - resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40" - integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ== +fill-range@^7.1.1: + version "7.1.1" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.1.1.tgz#44265d3cac07e3ea7dc247516380643754a05292" + integrity sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg== dependencies: to-regex-range "^5.0.1" @@ -2309,12 +2309,12 @@ mdurl@^1.0.0: resolved "https://registry.yarnpkg.com/memoize-one/-/memoize-one-5.2.1.tgz#8337aa3c4335581839ec01c3d594090cebe8f00e" integrity sha512-zYiwtZUcYyXKo/np96AGZAckk+FWWsUdJ3cHGGmld7+AhvcWmQyGCYUh1hc4Q/pkOhb65dQR/pqCyK0cOaHz4Q== -micromatch@^4.0.5: - version "4.0.5" - resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.5.tgz#bc8999a7cbbf77cdc89f132f6e467051b49090c6" - integrity sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA== +micromatch@^4.0.5, micromatch@^4.0.8: + version "4.0.8" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.8.tgz#d66fa18f3a47076789320b9b1af32bd86d9fa202" + integrity sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA== dependencies: - braces "^3.0.2" + braces "^3.0.3" picomatch "^2.3.1" mime@^1.4.1: From a2edfaf44c1183552e539144e929c937e83fc78d Mon Sep 17 00:00:00 2001 From: Kristiyan Ivanov Date: Thu, 10 Oct 2024 15:09:32 +0300 Subject: [PATCH 137/256] RI-6188 There is no dropdown to specify how to add elements for adding a new list --- .../api/src/modules/browser/list/list.service.ts | 16 ++++++++++++---- .../components/add-key/AddKeyList/AddKeyList.tsx | 13 ++++++++++++- .../add-list-elements/AddListElements.tsx | 2 +- 3 files changed, 25 insertions(+), 6 deletions(-) diff --git a/redisinsight/api/src/modules/browser/list/list.service.ts b/redisinsight/api/src/modules/browser/list/list.service.ts index d2b14d2f56..6f9b5f33e0 100644 --- a/redisinsight/api/src/modules/browser/list/list.service.ts +++ b/redisinsight/api/src/modules/browser/list/list.service.ts @@ -234,17 +234,25 @@ export class ListService { client: RedisClient, dto: PushElementToListDto, ): Promise { - const { keyName, elements } = dto; - await client.sendCommand([BrowserToolListCommands.LPush, keyName, ...elements]); + const { keyName, elements, destination } = dto; + await client.sendCommand([ + BrowserToolListCommands[destination === ListElementDestination.Tail ? 'RPush' : 'LPush'], + keyName, + ...elements + ]); } public async createListWithExpiration( client: RedisClient, dto: CreateListWithExpireDto, ): Promise { - const { keyName, elements, expire } = dto; + const { keyName, elements, expire, destination } = dto; const transactionResults = await client.sendPipeline([ - [BrowserToolListCommands.LPush, keyName, ...elements], + [ + BrowserToolListCommands[destination === ListElementDestination.Tail ? 'RPush' : 'LPush'], + keyName, + ...elements + ], [BrowserToolKeysCommands.Expire, keyName, expire], ]); catchMultiTransactionError(transactionResults); diff --git a/redisinsight/ui/src/pages/browser/components/add-key/AddKeyList/AddKeyList.tsx b/redisinsight/ui/src/pages/browser/components/add-key/AddKeyList/AddKeyList.tsx index 086d492ef1..d13ff0a0ba 100644 --- a/redisinsight/ui/src/pages/browser/components/add-key/AddKeyList/AddKeyList.tsx +++ b/redisinsight/ui/src/pages/browser/components/add-key/AddKeyList/AddKeyList.tsx @@ -9,17 +9,20 @@ import { EuiFlexItem, EuiPanel, EuiFieldText, + EuiSuperSelect, } from '@elastic/eui' import { Maybe, stringToBuffer } from 'uiSrc/utils' import { addKeyStateSelector, addListKey } from 'uiSrc/slices/browser/keys' -import { CreateListWithExpireDto } from 'apiSrc/modules/browser/list/dto' +import { CreateListWithExpireDto, ListElementDestination } from 'apiSrc/modules/browser/list/dto' import { AddListFormConfig as config, } from '../constants/fields-config' import AddKeyFooter from '../AddKeyFooter/AddKeyFooter' import AddMultipleFields from '../../add-multiple-fields' +import { optionsDestinations, TAIL_DESTINATION } from 'uiSrc/pages/browser/modules/key-details/components/list-details/add-list-elements/AddListElements' + export interface Props { keyName: string @@ -30,6 +33,7 @@ export interface Props { const AddKeyList = (props: Props) => { const { keyName = '', keyTTL, onCancel } = props const [elements, setElements] = useState(['']) + const [destination, setDestination] = useState(TAIL_DESTINATION) const [isFormValid, setIsFormValid] = useState(false) @@ -70,6 +74,7 @@ const AddKeyList = (props: Props) => { const submitData = (): void => { const data: CreateListWithExpireDto = { + destination, keyName: stringToBuffer(keyName), elements: elements.map((el) => stringToBuffer(el)), } @@ -81,6 +86,12 @@ const AddKeyList = (props: Props) => { return ( + setDestination(value as ListElementDestination)} + data-testid="destination-select" + /> [] = [ +export const optionsDestinations: EuiSuperSelectOption[] = [ { value: TAIL_DESTINATION, inputDisplay: 'Push to tail', From f2be7b32185163da52ff1bbb264b4e0a3ce52207 Mon Sep 17 00:00:00 2001 From: Kristiyan Ivanov Date: Thu, 10 Oct 2024 16:02:17 +0300 Subject: [PATCH 138/256] RI-6188 There is no dropdown to specify how to add elements for adding a new list - tests updated --- .../modules/browser/list/list.service.spec.ts | 22 ++++++++++++++++--- .../add-key/AddKeyList/AddKeyList.spec.tsx | 12 +++++++++- .../AddListElements.spec.tsx | 1 - 3 files changed, 30 insertions(+), 5 deletions(-) diff --git a/redisinsight/api/src/modules/browser/list/list.service.spec.ts b/redisinsight/api/src/modules/browser/list/list.service.spec.ts index 28b9e11980..39f109d3be 100644 --- a/redisinsight/api/src/modules/browser/list/list.service.spec.ts +++ b/redisinsight/api/src/modules/browser/list/list.service.spec.ts @@ -93,6 +93,22 @@ describe('ListService', () => { ).resolves.not.toThrow(); expect(service.createListWithExpiration).not.toHaveBeenCalled(); }); + + it('create list with expiration and push at the head', async () => { + when(mockStandaloneRedisClient.sendCommand) + .calledWith([ + BrowserToolListCommands.LPush, + mockPushElementDto.keyName, + ...mockPushElementDto.elements, + ]) + .mockResolvedValue(1); + + await expect( + service.createList(mockBrowserClientMetadata, mockPushElementDto), + ).resolves.not.toThrow(); + expect(service.createListWithExpiration).not.toHaveBeenCalled(); + }); + it('key with this name exist', async () => { when(mockStandaloneRedisClient.sendCommand) .calledWith([BrowserToolKeysCommands.Exists, mockPushElementDto.keyName]) @@ -475,7 +491,7 @@ describe('ListService', () => { it("shouldn't throw error", async () => { when(mockStandaloneRedisClient.sendPipeline) .calledWith([ - [BrowserToolListCommands.LPush, dto.keyName, ...dto.elements], + [BrowserToolListCommands.RPush, dto.keyName, ...dto.elements], [BrowserToolKeysCommands.Expire, dto.keyName, dto.expire], ]) .mockResolvedValue([ @@ -490,11 +506,11 @@ describe('ListService', () => { it('should throw error', async () => { const replyError: ReplyError = { ...mockRedisNoPermError, - command: 'LPUSH', + command: 'RPUSH', }; when(mockStandaloneRedisClient.sendPipeline) .calledWith([ - [BrowserToolListCommands.LPush, dto.keyName, ...dto.elements], + [BrowserToolListCommands.RPush, dto.keyName, ...dto.elements], [BrowserToolKeysCommands.Expire, dto.keyName, dto.expire], ]) .mockResolvedValue([[replyError, []]]); diff --git a/redisinsight/ui/src/pages/browser/components/add-key/AddKeyList/AddKeyList.spec.tsx b/redisinsight/ui/src/pages/browser/components/add-key/AddKeyList/AddKeyList.spec.tsx index f93254b0ef..27f9ae9a6d 100644 --- a/redisinsight/ui/src/pages/browser/components/add-key/AddKeyList/AddKeyList.spec.tsx +++ b/redisinsight/ui/src/pages/browser/components/add-key/AddKeyList/AddKeyList.spec.tsx @@ -3,6 +3,7 @@ import { instance, mock } from 'ts-mockito' import { render, screen, fireEvent } from 'uiSrc/utils/test-utils' import AddKeyList, { Props } from './AddKeyList' import AddKeyFooter from '../AddKeyFooter/AddKeyFooter' +import { HEAD_DESTINATION } from 'uiSrc/pages/browser/modules/key-details/components/list-details/add-list-elements/AddListElements' const mockedProps = mock() @@ -33,6 +34,16 @@ describe('AddKeyList', () => { expect(valueInput).toHaveValue(value) }) + it('should set destination properly', () => { + render() + const destinationSelect = screen.getByTestId('destination-select') + fireEvent.change( + destinationSelect, + { target: { value: HEAD_DESTINATION } } + ) + expect(destinationSelect).toHaveValue(HEAD_DESTINATION) + }) + it('should render disabled add key button with empty keyName', () => { const { container } = render() expect(container.querySelector('.btn-add')).toBeDisabled() @@ -52,7 +63,6 @@ describe('AddKeyList', () => { it('should not allow deleting the last element', () => { render() - fireEvent.click(screen.getByTestId('add-item')) const deleteButtons = screen.getAllByTestId('remove-item') expect(deleteButtons[0]).toBeDisabled() }) diff --git a/redisinsight/ui/src/pages/browser/modules/key-details/components/list-details/add-list-elements/AddListElements.spec.tsx b/redisinsight/ui/src/pages/browser/modules/key-details/components/list-details/add-list-elements/AddListElements.spec.tsx index 25a2534cc7..106e192197 100644 --- a/redisinsight/ui/src/pages/browser/modules/key-details/components/list-details/add-list-elements/AddListElements.spec.tsx +++ b/redisinsight/ui/src/pages/browser/modules/key-details/components/list-details/add-list-elements/AddListElements.spec.tsx @@ -41,7 +41,6 @@ describe('AddListElements', () => { it('should not allow deleting the last element', () => { render() - fireEvent.click(screen.getByTestId('add-item')) const deleteButtons = screen.getAllByTestId('remove-item') expect(deleteButtons[0]).toBeDisabled() }) From b8437649a71706091beb6029edfb0052061e7c10 Mon Sep 17 00:00:00 2001 From: Roman Sergeenko Date: Thu, 10 Oct 2024 16:13:15 +0200 Subject: [PATCH 139/256] #RI-6151 - search suggestions in the workbench, refactoring --- .../monaco-laguages/MonacoLanguages.tsx | 13 +- redisinsight/ui/src/constants/commands.ts | 66 +- .../src/mocks/data/mocked_redis_commands.ts | 1521 +++++++++++++++++ .../results-history/ResultsHistory.tsx | 2 +- .../components/query/Query/Query.tsx | 443 ++--- .../components/query/QueryWrapper.tsx | 8 +- .../wb-results/WBResults/WBResults.tsx | 2 +- redisinsight/ui/src/pages/workbench/types.ts | 31 +- redisinsight/ui/src/pages/workbench/utils.ts | 41 - .../ui/src/pages/workbench/utils/monaco.ts | 10 +- .../ui/src/pages/workbench/utils/query.ts | 84 +- .../workbench/utils/searchSuggestions.ts | 186 ++ .../workbench/utils/tests/monaco.spec.ts | 60 + .../tests/profile.spec.ts} | 36 +- .../pages/workbench/utils/tests/query.spec.ts | 189 ++ .../utils/tests/test-cases/common.ts | 183 ++ .../utils/tests/test-cases/ft-aggregate.ts | 267 +++ .../utils/tests/test-cases/ft-search.ts | 283 +++ .../workbench/utils/tests/test-cases/index.ts | 3 + .../ui/src/utils/monaco/monacoInterfaces.ts | 8 +- .../src/utils/transformers/redisCommands.ts | 12 + 21 files changed, 3011 insertions(+), 437 deletions(-) create mode 100644 redisinsight/ui/src/mocks/data/mocked_redis_commands.ts delete mode 100644 redisinsight/ui/src/pages/workbench/utils.ts create mode 100644 redisinsight/ui/src/pages/workbench/utils/searchSuggestions.ts create mode 100644 redisinsight/ui/src/pages/workbench/utils/tests/monaco.spec.ts rename redisinsight/ui/src/pages/workbench/{utils.spec.ts => utils/tests/profile.spec.ts} (90%) create mode 100644 redisinsight/ui/src/pages/workbench/utils/tests/query.spec.ts create mode 100644 redisinsight/ui/src/pages/workbench/utils/tests/test-cases/common.ts create mode 100644 redisinsight/ui/src/pages/workbench/utils/tests/test-cases/ft-aggregate.ts create mode 100644 redisinsight/ui/src/pages/workbench/utils/tests/test-cases/ft-search.ts create mode 100644 redisinsight/ui/src/pages/workbench/utils/tests/test-cases/index.ts create mode 100644 redisinsight/ui/src/utils/transformers/redisCommands.ts diff --git a/redisinsight/ui/src/components/monaco-laguages/MonacoLanguages.tsx b/redisinsight/ui/src/components/monaco-laguages/MonacoLanguages.tsx index db84c5556f..4d3b9563a8 100644 --- a/redisinsight/ui/src/components/monaco-laguages/MonacoLanguages.tsx +++ b/redisinsight/ui/src/components/monaco-laguages/MonacoLanguages.tsx @@ -7,10 +7,11 @@ import { MonacoLanguage, redisLanguageConfig, Theme } from 'uiSrc/constants' import { getRedisMonarchTokensProvider } from 'uiSrc/utils' import { darkTheme, lightTheme, MonacoThemes } from 'uiSrc/constants/monaco' import { ThemeContext } from 'uiSrc/contexts/themeContext' -import { TokenType } from 'uiSrc/pages/workbench/types' import { getRediSearchSubRedisMonarchTokensProvider } from 'uiSrc/utils/monaco/monarchTokens/redisearchTokensSubRedis' import SEARCH_COMMANDS_SPEC from 'uiSrc/pages/workbench/data/supported_commands.json' +import { mergeRedisCommandsSpecs } from 'uiSrc/utils/transformers/redisCommands' +import { SearchCommandTree } from 'uiSrc/pages/search/types' const MonacoLanguages = () => { const { theme } = useContext(ThemeContext) @@ -42,16 +43,12 @@ const MonacoLanguages = () => { } monaco.languages.setLanguageConfiguration(MonacoLanguage.Redis, redisLanguageConfig) - const REDIS_COMMANDS = Object.keys(COMMANDS_SPEC).map((name) => ({ - ...(name in SEARCH_COMMANDS_SPEC ? SEARCH_COMMANDS_SPEC[name] : (COMMANDS_SPEC[name] || {})), - name, - token: name, - type: TokenType.Block - })) + const REDIS_COMMANDS = mergeRedisCommandsSpecs(COMMANDS_SPEC, SEARCH_COMMANDS_SPEC) as SearchCommandTree[] + const REDIS_SEARCH_COMMANDS = REDIS_COMMANDS.filter(({ name }) => name?.startsWith('FT.')) monaco.languages.setMonarchTokensProvider( MonacoLanguage.RediSearch, - getRediSearchSubRedisMonarchTokensProvider(REDIS_COMMANDS.filter(({ name }) => name.startsWith('FT.'))) + getRediSearchSubRedisMonarchTokensProvider(REDIS_SEARCH_COMMANDS) ) monaco.languages.setMonarchTokensProvider( MonacoLanguage.Redis, diff --git a/redisinsight/ui/src/constants/commands.ts b/redisinsight/ui/src/constants/commands.ts index 28d6ba575b..3130ada6f7 100644 --- a/redisinsight/ui/src/constants/commands.ts +++ b/redisinsight/ui/src/constants/commands.ts @@ -1,15 +1,15 @@ export interface ICommands { - [key: string]: ICommand; + [key: string]: ICommand } export interface ICommand { - name?: string; - summary: string; - complexity?: string; - arguments?: ICommandArg[]; - since: string; - group: CommandGroup | string; - provider?: string; + name?: string + summary: string + complexity?: string + arguments?: ICommandArg[] + since: string + group: CommandGroup | string + provider?: string } export enum CommandProvider { @@ -18,19 +18,49 @@ export enum CommandProvider { } export interface ICommandArg { - name?: string[] | string; - type?: CommandArgsType[] | CommandArgsType | string | string[]; - optional?: boolean; - enum?: string[]; - block?: ICommandArg[]; - command?: string; - multiple?: boolean; - variadic?: boolean; - dsl?: string; + name?: string[] | string + type?: CommandArgsType[] | CommandArgsType | string | string[] + optional?: boolean + enum?: string[] + block?: ICommandArg[] + command?: string + multiple?: boolean + variadic?: boolean + dsl?: string +} + +export enum ICommandTokenType { + PureToken = 'pure-token', + Block = 'block', + OneOf = 'oneof', + String = 'string', + Double = 'double', + Enum = 'enum', + Integer = 'integer', + Key = 'key', + POSIXTime = 'posix time', + Pattern = 'pattern', +} + +export interface IRedisCommand { + name?: string + summary?: string + expression?: boolean + type?: ICommandTokenType + token?: string + optional?: boolean + multiple?: boolean + arguments?: IRedisCommand[] + variadic?: boolean + dsl?: string +} + +export interface IRedisCommandTree extends IRedisCommand { + parent?: IRedisCommandTree } export interface ICommandArgGenerated extends ICommandArg { - generatedName?: string | string[]; + generatedName?: string | string[] } export enum CommandArgsType { diff --git a/redisinsight/ui/src/mocks/data/mocked_redis_commands.ts b/redisinsight/ui/src/mocks/data/mocked_redis_commands.ts new file mode 100644 index 0000000000..359c3b12ed --- /dev/null +++ b/redisinsight/ui/src/mocks/data/mocked_redis_commands.ts @@ -0,0 +1,1521 @@ +export const MOCKED_REDIS_COMMANDS = { + 'FT.SEARCH': { + summary: 'Searches the index with a textual query, returning either documents or just ids', + complexity: 'O(N)', + history: [ + [ + '2.0.0', + 'Deprecated `WITHPAYLOADS` and `PAYLOAD` arguments' + ] + ], + arguments: [ + { + name: 'index', + type: 'string' + }, + { + name: 'query', + type: 'string' + }, + { + name: 'nocontent', + type: 'pure-token', + token: 'NOCONTENT', + optional: true + }, + { + name: 'verbatim', + type: 'pure-token', + token: 'VERBATIM', + optional: true + }, + { + name: 'nostopwords', + type: 'pure-token', + token: 'NOSTOPWORDS', + optional: true + }, + { + name: 'withscores', + type: 'pure-token', + token: 'WITHSCORES', + optional: true + }, + { + name: 'withpayloads', + type: 'pure-token', + token: 'WITHPAYLOADS', + optional: true + }, + { + name: 'withsortkeys', + type: 'pure-token', + token: 'WITHSORTKEYS', + optional: true + }, + { + name: 'filter', + type: 'block', + optional: true, + multiple: true, + arguments: [ + { + name: 'numeric_field', + type: 'string', + token: 'FILTER' + }, + { + name: 'min', + type: 'double' + }, + { + name: 'max', + type: 'double' + } + ] + }, + { + name: 'geo_filter', + type: 'block', + optional: true, + multiple: true, + arguments: [ + { + name: 'geo_field', + type: 'string', + token: 'GEOFILTER' + }, + { + name: 'lon', + type: 'double' + }, + { + name: 'lat', + type: 'double' + }, + { + name: 'radius', + type: 'double' + }, + { + name: 'radius_type', + type: 'oneof', + arguments: [ + { + name: 'm', + type: 'pure-token', + token: 'm' + }, + { + name: 'km', + type: 'pure-token', + token: 'km' + }, + { + name: 'mi', + type: 'pure-token', + token: 'mi' + }, + { + name: 'ft', + type: 'pure-token', + token: 'ft' + } + ] + } + ] + }, + { + name: 'in_keys', + type: 'block', + optional: true, + arguments: [ + { + name: 'count', + type: 'string', + token: 'INKEYS' + }, + { + name: 'key', + type: 'string', + multiple: true + } + ] + }, + { + name: 'in_fields', + type: 'block', + optional: true, + arguments: [ + { + name: 'count', + type: 'string', + token: 'INFIELDS' + }, + { + name: 'field', + type: 'string', + multiple: true + } + ] + }, + { + name: 'return', + type: 'block', + optional: true, + arguments: [ + { + name: 'count', + type: 'string', + token: 'RETURN' + }, + { + name: 'identifiers', + type: 'block', + multiple: true, + arguments: [ + { + name: 'identifier', + type: 'string' + }, + { + name: 'property', + type: 'string', + token: 'AS', + optional: true + } + ] + } + ] + }, + { + name: 'summarize', + type: 'block', + optional: true, + arguments: [ + { + name: 'summarize', + type: 'pure-token', + token: 'SUMMARIZE' + }, + { + name: 'fields', + type: 'block', + optional: true, + arguments: [ + { + name: 'count', + type: 'string', + token: 'FIELDS' + }, + { + name: 'field', + type: 'string', + multiple: true + } + ] + }, + { + name: 'num', + type: 'integer', + token: 'FRAGS', + optional: true + }, + { + name: 'fragsize', + type: 'integer', + token: 'LEN', + optional: true + }, + { + name: 'separator', + type: 'string', + token: 'SEPARATOR', + optional: true + } + ] + }, + { + name: 'highlight', + type: 'block', + optional: true, + arguments: [ + { + name: 'highlight', + type: 'pure-token', + token: 'HIGHLIGHT' + }, + { + name: 'fields', + type: 'block', + optional: true, + arguments: [ + { + name: 'count', + type: 'string', + token: 'FIELDS' + }, + { + name: 'field', + type: 'string', + multiple: true + } + ] + }, + { + name: 'tags', + type: 'block', + optional: true, + arguments: [ + { + name: 'tags', + type: 'pure-token', + token: 'TAGS' + }, + { + name: 'open', + type: 'string' + }, + { + name: 'close', + type: 'string' + } + ] + } + ] + }, + { + name: 'slop', + type: 'integer', + optional: true, + token: 'SLOP' + }, + { + name: 'timeout', + type: 'integer', + optional: true, + token: 'TIMEOUT' + }, + { + name: 'inorder', + type: 'pure-token', + token: 'INORDER', + optional: true + }, + { + name: 'language', + type: 'string', + optional: true, + token: 'LANGUAGE' + }, + { + name: 'expander', + type: 'string', + optional: true, + token: 'EXPANDER' + }, + { + name: 'scorer', + type: 'string', + optional: true, + token: 'SCORER' + }, + { + name: 'explainscore', + type: 'pure-token', + token: 'EXPLAINSCORE', + optional: true + }, + { + name: 'payload', + type: 'string', + optional: true, + token: 'PAYLOAD' + }, + { + name: 'sortby', + type: 'block', + optional: true, + arguments: [ + { + name: 'sortby', + type: 'string', + token: 'SORTBY' + }, + { + name: 'order', + type: 'oneof', + optional: true, + arguments: [ + { + name: 'asc', + type: 'pure-token', + token: 'ASC' + }, + { + name: 'desc', + type: 'pure-token', + token: 'DESC' + } + ] + } + ] + }, + { + name: 'limit', + type: 'block', + optional: true, + arguments: [ + { + name: 'limit', + type: 'pure-token', + token: 'LIMIT' + }, + { + name: 'offset', + type: 'integer' + }, + { + name: 'num', + type: 'integer' + } + ] + }, + { + name: 'params', + type: 'block', + optional: true, + arguments: [ + { + name: 'params', + type: 'pure-token', + token: 'PARAMS' + }, + { + name: 'nargs', + type: 'integer' + }, + { + name: 'values', + type: 'block', + multiple: true, + arguments: [ + { + name: 'name', + type: 'string' + }, + { + name: 'value', + type: 'string' + } + ] + } + ] + }, + { + name: 'dialect', + type: 'integer', + optional: true, + token: 'DIALECT', + since: '2.4.3' + } + ], + since: '1.0.0', + group: 'search' + }, + 'FT.AGGREGATE': { + summary: 'Run a search query on an index and perform aggregate transformations on the results', + complexity: 'O(1)', + arguments: [ + { + name: 'index', + type: 'string' + }, + { + name: 'query', + type: 'string' + }, + { + name: 'verbatim', + type: 'pure-token', + token: 'VERBATIM', + optional: true + }, + { + name: 'load', + type: 'block', + optional: true, + arguments: [ + { + name: 'count', + type: 'string', + token: 'LOAD' + }, + { + name: 'field', + type: 'string', + multiple: true + } + ] + }, + { + name: 'timeout', + type: 'integer', + optional: true, + token: 'TIMEOUT' + }, + { + name: 'loadall', + type: 'pure-token', + token: 'LOAD *', + optional: true + }, + { + name: 'groupby', + type: 'block', + optional: true, + multiple: true, + arguments: [ + { + name: 'nargs', + type: 'integer', + token: 'GROUPBY' + }, + { + name: 'property', + type: 'string', + multiple: true + }, + { + name: 'reduce', + type: 'block', + optional: true, + multiple: true, + arguments: [ + { + name: 'function', + type: 'string', + token: 'REDUCE' + }, + { + name: 'nargs', + type: 'integer' + }, + { + name: 'arg', + type: 'string', + multiple: true + }, + { + name: 'name', + type: 'string', + token: 'AS', + optional: true + } + ] + } + ] + }, + { + name: 'sortby', + type: 'block', + optional: true, + arguments: [ + { + name: 'nargs', + type: 'integer', + token: 'SORTBY' + }, + { + name: 'fields', + type: 'block', + optional: true, + multiple: true, + arguments: [ + { + name: 'property', + type: 'string' + }, + { + name: 'order', + type: 'oneof', + arguments: [ + { + name: 'asc', + type: 'pure-token', + token: 'ASC' + }, + { + name: 'desc', + type: 'pure-token', + token: 'DESC' + } + ] + } + ] + }, + { + name: 'num', + type: 'integer', + token: 'MAX', + optional: true + } + ] + }, + { + name: 'apply', + type: 'block', + optional: true, + multiple: true, + arguments: [ + { + name: 'expression', + type: 'string', + token: 'APPLY' + }, + { + name: 'name', + type: 'string', + token: 'AS' + } + ] + }, + { + name: 'limit', + type: 'block', + optional: true, + arguments: [ + { + name: 'limit', + type: 'pure-token', + token: 'LIMIT' + }, + { + name: 'offset', + type: 'integer' + }, + { + name: 'num', + type: 'integer' + } + ] + }, + { + name: 'filter', + type: 'string', + optional: true, + token: 'FILTER' + }, + { + name: 'cursor', + type: 'block', + optional: true, + arguments: [ + { + name: 'withcursor', + type: 'pure-token', + token: 'WITHCURSOR' + }, + { + name: 'read_size', + type: 'integer', + optional: true, + token: 'COUNT' + }, + { + name: 'idle_time', + type: 'integer', + optional: true, + token: 'MAXIDLE' + } + ] + }, + { + name: 'params', + type: 'block', + optional: true, + arguments: [ + { + name: 'params', + type: 'pure-token', + token: 'PARAMS' + }, + { + name: 'nargs', + type: 'integer' + }, + { + name: 'values', + type: 'block', + multiple: true, + arguments: [ + { + name: 'name', + type: 'string' + }, + { + name: 'value', + type: 'string' + } + ] + } + ] + }, + { + name: 'dialect', + type: 'integer', + optional: true, + token: 'DIALECT', + since: '2.4.3' + } + ], + since: '1.1.0', + group: 'search' + }, + 'FT.PROFILE': { + summary: 'Performs a `FT.SEARCH` or `FT.AGGREGATE` command and collects performance information', + complexity: 'O(N)', + arguments: [ + { + name: 'index', + type: 'string' + }, + { + name: 'querytype', + type: 'oneof', + arguments: [ + { + name: 'search', + type: 'pure-token', + token: 'SEARCH' + }, + { + name: 'aggregate', + type: 'pure-token', + token: 'AGGREGATE' + } + ] + }, + { + name: 'limited', + type: 'pure-token', + token: 'LIMITED', + optional: true + }, + { + name: 'queryword', + type: 'pure-token', + token: 'QUERY' + }, + { + name: 'query', + type: 'string' + } + ], + since: '2.2.0', + group: 'search', + provider: 'redisearch' + }, + 'FT.ALIASADD': { + summary: 'Adds an alias to the index', + complexity: 'O(1)', + arguments: [ + { + name: 'alias', + type: 'string' + }, + { + name: 'index', + type: 'string' + } + ], + since: '1.0.0', + group: 'search', + provider: 'redisearch' + }, + 'FT.ALIASDEL': { + summary: 'Deletes an alias from the index', + complexity: 'O(1)', + arguments: [ + { + name: 'alias', + type: 'string' + } + ], + since: '1.0.0', + group: 'search', + provider: 'redisearch' + }, + 'FT.ALIASUPDATE': { + summary: 'Adds or updates an alias to the index', + complexity: 'O(1)', + arguments: [ + { + name: 'alias', + type: 'string' + }, + { + name: 'index', + type: 'string' + } + ], + since: '1.0.0', + group: 'search', + provider: 'redisearch' + }, + 'FT.ALTER': { + summary: 'Adds a new field to the index', + complexity: 'O(N) where N is the number of keys in the keyspace', + arguments: [ + { + name: 'index', + type: 'string' + }, + { + name: 'skipinitialscan', + type: 'pure-token', + token: 'SKIPINITIALSCAN', + optional: true + }, + { + name: 'schema', + type: 'pure-token', + token: 'SCHEMA' + }, + { + name: 'add', + type: 'pure-token', + token: 'ADD' + }, + { + name: 'field', + type: 'string' + }, + { + name: 'options', + type: 'string' + } + ], + since: '1.0.0', + group: 'search', + provider: 'redisearch' + }, + 'FT.CONFIG GET': { + summary: 'Retrieves runtime configuration options', + complexity: 'O(1)', + arguments: [ + { + name: 'option', + type: 'string' + } + ], + since: '1.0.0', + group: 'search', + provider: 'redisearch' + }, + 'FT.CONFIG HELP': { + summary: 'Help description of runtime configuration options', + complexity: 'O(1)', + arguments: [ + { + name: 'option', + type: 'string' + } + ], + since: '1.0.0', + group: 'search', + provider: 'redisearch' + }, + 'FT.CONFIG SET': { + summary: 'Sets runtime configuration options', + complexity: 'O(1)', + arguments: [ + { + name: 'option', + type: 'string' + }, + { + name: 'value', + type: 'string' + } + ], + since: '1.0.0', + group: 'search', + provider: 'redisearch' + }, + 'FT.CREATE': { + summary: 'Creates an index with the given spec', + complexity: 'O(K) at creation where K is the number of fields, O(N) if scanning the keyspace is triggered, where N is the number of keys in the keyspace', + history: [ + [ + '2.0.0', + 'Added `PAYLOAD_FIELD` argument for backward support of `FT.SEARCH` deprecated `WITHPAYLOADS` argument' + ], + [ + '2.0.0', + 'Deprecated `PAYLOAD_FIELD` argument' + ] + ], + arguments: [ + { + name: 'index', + type: 'string' + }, + { + name: 'data_type', + token: 'ON', + type: 'oneof', + arguments: [ + { + name: 'hash', + type: 'pure-token', + token: 'HASH' + }, + { + name: 'json', + type: 'pure-token', + token: 'JSON' + } + ], + optional: true + }, + { + name: 'prefix', + type: 'block', + optional: true, + arguments: [ + { + name: 'count', + type: 'integer', + token: 'PREFIX' + }, + { + name: 'prefix', + type: 'string', + multiple: true + } + ] + }, + { + name: 'filter', + type: 'string', + optional: true, + token: 'FILTER' + }, + { + name: 'default_lang', + type: 'string', + token: 'LANGUAGE', + optional: true + }, + { + name: 'lang_attribute', + type: 'string', + token: 'LANGUAGE_FIELD', + optional: true + }, + { + name: 'default_score', + type: 'double', + token: 'SCORE', + optional: true + }, + { + name: 'score_attribute', + type: 'string', + token: 'SCORE_FIELD', + optional: true + }, + { + name: 'payload_attribute', + type: 'string', + token: 'PAYLOAD_FIELD', + optional: true + }, + { + name: 'maxtextfields', + type: 'pure-token', + token: 'MAXTEXTFIELDS', + optional: true + }, + { + name: 'seconds', + type: 'double', + token: 'TEMPORARY', + optional: true + }, + { + name: 'nooffsets', + type: 'pure-token', + token: 'NOOFFSETS', + optional: true + }, + { + name: 'nohl', + type: 'pure-token', + token: 'NOHL', + optional: true + }, + { + name: 'nofields', + type: 'pure-token', + token: 'NOFIELDS', + optional: true + }, + { + name: 'nofreqs', + type: 'pure-token', + token: 'NOFREQS', + optional: true + }, + { + name: 'stopwords', + type: 'block', + optional: true, + token: 'STOPWORDS', + arguments: [ + { + name: 'count', + type: 'integer' + }, + { + name: 'stopword', + type: 'string', + multiple: true, + optional: true + } + ] + }, + { + name: 'skipinitialscan', + type: 'pure-token', + token: 'SKIPINITIALSCAN', + optional: true + }, + { + name: 'schema', + type: 'pure-token', + token: 'SCHEMA' + }, + { + name: 'field', + type: 'block', + multiple: true, + arguments: [ + { + name: 'field_name', + type: 'string' + }, + { + name: 'alias', + type: 'string', + token: 'AS', + optional: true + }, + { + name: 'field_type', + type: 'oneof', + arguments: [ + { + name: 'text', + type: 'pure-token', + token: 'TEXT' + }, + { + name: 'tag', + type: 'pure-token', + token: 'TAG' + }, + { + name: 'numeric', + type: 'pure-token', + token: 'NUMERIC' + }, + { + name: 'geo', + type: 'pure-token', + token: 'GEO' + }, + { + name: 'vector', + type: 'pure-token', + token: 'VECTOR' + } + ] + }, + { + name: 'withsuffixtrie', + type: 'pure-token', + token: 'WITHSUFFIXTRIE', + optional: true + }, + { + name: 'INDEXEMPTY', + type: 'pure-token', + token: 'INDEXEMPTY', + optional: true + }, + { + name: 'indexmissing', + type: 'pure-token', + token: 'INDEXMISSING', + optional: true + }, + { + name: 'sortable', + type: 'block', + optional: true, + arguments: [ + { + name: 'sortable', + type: 'pure-token', + token: 'SORTABLE' + }, + { + name: 'UNF', + type: 'pure-token', + token: 'UNF', + optional: true + } + ] + }, + { + name: 'noindex', + type: 'pure-token', + token: 'NOINDEX', + optional: true + } + ] + } + ], + since: '1.0.0', + group: 'search', + provider: 'redisearch' + }, + 'FT.CURSOR DEL': { + summary: 'Deletes a cursor', + complexity: 'O(1)', + arguments: [ + { + name: 'index', + type: 'string' + }, + { + name: 'cursor_id', + type: 'integer' + } + ], + since: '1.1.0', + group: 'search', + provider: 'redisearch' + }, + 'FT.CURSOR READ': { + summary: 'Reads from a cursor', + complexity: 'O(1)', + arguments: [ + { + name: 'index', + type: 'string' + }, + { + name: 'cursor_id', + type: 'integer' + }, + { + name: 'read size', + type: 'integer', + optional: true, + token: 'COUNT' + } + ], + since: '1.1.0', + group: 'search', + provider: 'redisearch' + }, + 'FT.DICTADD': { + summary: 'Adds terms to a dictionary', + complexity: 'O(1)', + arguments: [ + { + name: 'dict', + type: 'string' + }, + { + name: 'term', + type: 'string', + multiple: true + } + ], + since: '1.4.0', + group: 'search', + provider: 'redisearch' + }, + 'FT.DICTDEL': { + summary: 'Deletes terms from a dictionary', + complexity: 'O(1)', + arguments: [ + { + name: 'dict', + type: 'string' + }, + { + name: 'term', + type: 'string', + multiple: true + } + ], + since: '1.4.0', + group: 'search', + provider: 'redisearch' + }, + 'FT.DICTDUMP': { + summary: 'Dumps all terms in the given dictionary', + complexity: 'O(N), where N is the size of the dictionary', + arguments: [ + { + name: 'dict', + type: 'string' + } + ], + since: '1.4.0', + group: 'search', + provider: 'redisearch' + }, + 'FT.DROPINDEX': { + summary: 'Deletes the index', + complexity: 'O(1) or O(N) if documents are deleted, where N is the number of keys in the keyspace', + arguments: [ + { + name: 'index', + type: 'string' + }, + { + name: 'delete docs', + type: 'oneof', + arguments: [ + { + name: 'delete docs', + type: 'pure-token', + token: 'DD' + } + ], + optional: true + } + ], + since: '2.0.0', + group: 'search', + provider: 'redisearch' + }, + 'FT.EXPLAIN': { + summary: 'Returns the execution plan for a complex query', + complexity: 'O(1)', + arguments: [ + { + name: 'index', + type: 'string' + }, + { + name: 'query', + type: 'string' + }, + { + name: 'dialect', + type: 'integer', + optional: true, + token: 'DIALECT', + since: '2.4.3' + } + ], + since: '1.0.0', + group: 'search', + provider: 'redisearch' + }, + 'FT.EXPLAINCLI': { + summary: 'Returns the execution plan for a complex query', + complexity: 'O(1)', + arguments: [ + { + name: 'index', + type: 'string' + }, + { + name: 'query', + type: 'string' + }, + { + name: 'dialect', + type: 'integer', + optional: true, + token: 'DIALECT', + since: '2.4.3' + } + ], + since: '1.0.0', + group: 'search', + provider: 'redisearch' + }, + 'FT.INFO': { + summary: 'Returns information and statistics on the index', + complexity: 'O(1)', + arguments: [ + { + name: 'index', + type: 'string' + } + ], + since: '1.0.0', + group: 'search', + provider: 'redisearch' + }, + 'FT.SPELLCHECK': { + summary: 'Performs spelling correction on a query, returning suggestions for misspelled terms', + complexity: 'O(1)', + arguments: [ + { + name: 'index', + type: 'string' + }, + { + name: 'query', + type: 'string' + }, + { + name: 'distance', + token: 'DISTANCE', + type: 'integer', + optional: true + }, + { + name: 'terms', + token: 'TERMS', + type: 'block', + optional: true, + arguments: [ + { + name: 'inclusion', + type: 'oneof', + arguments: [ + { + name: 'include', + type: 'pure-token', + token: 'INCLUDE' + }, + { + name: 'exclude', + type: 'pure-token', + token: 'EXCLUDE' + } + ] + }, + { + name: 'dictionary', + type: 'string' + }, + { + name: 'terms', + type: 'string', + multiple: true, + optional: true + } + ] + }, + { + name: 'dialect', + type: 'integer', + optional: true, + token: 'DIALECT', + since: '2.4.3' + } + ], + since: '1.4.0', + group: 'search', + provider: 'redisearch' + }, + 'FT.SUGADD': { + summary: 'Adds a suggestion string to an auto-complete suggestion dictionary', + complexity: 'O(1)', + history: [ + [ + '2.0.0', + 'Deprecated `PAYLOAD` argument' + ] + ], + arguments: [ + { + name: 'key', + type: 'string' + }, + { + name: 'string', + type: 'string' + }, + { + name: 'score', + type: 'double' + }, + { + name: 'increment score', + type: 'oneof', + arguments: [ + { + name: 'incr', + type: 'pure-token', + token: 'INCR' + } + ], + optional: true + }, + { + name: 'payload', + token: 'PAYLOAD', + type: 'string', + optional: true + } + ], + since: '1.0.0', + group: 'suggestion', + provider: 'redisearch' + }, + 'FT.SUGDEL': { + summary: 'Deletes a string from a suggestion index', + complexity: 'O(1)', + arguments: [ + { + name: 'key', + type: 'string' + }, + { + name: 'string', + type: 'string' + } + ], + since: '1.0.0', + group: 'suggestion', + provider: 'redisearch' + }, + 'FT.SUGGET': { + summary: 'Gets completion suggestions for a prefix', + complexity: 'O(1)', + history: [ + [ + '2.0.0', + 'Deprecated `WITHPAYLOADS` argument' + ] + ], + arguments: [ + { + name: 'key', + type: 'string' + }, + { + name: 'prefix', + type: 'string' + }, + { + name: 'fuzzy', + type: 'pure-token', + token: 'FUZZY', + optional: true + }, + { + name: 'withscores', + type: 'pure-token', + token: 'WITHSCORES', + optional: true + }, + { + name: 'withpayloads', + type: 'pure-token', + token: 'WITHPAYLOADS', + optional: true + }, + { + name: 'max', + token: 'MAX', + type: 'integer', + optional: true + } + ], + since: '1.0.0', + group: 'suggestion', + provider: 'redisearch' + }, + 'FT.SUGLEN': { + summary: 'Gets the size of an auto-complete suggestion dictionary', + complexity: 'O(1)', + arguments: [ + { + name: 'key', + type: 'string' + } + ], + since: '1.0.0', + group: 'suggestion', + provider: 'redisearch' + }, + 'FT.SYNDUMP': { + summary: 'Dumps the contents of a synonym group', + complexity: 'O(1)', + arguments: [ + { + name: 'index', + type: 'string' + } + ], + since: '1.2.0', + group: 'search', + provider: 'redisearch' + }, + 'FT.SYNUPDATE': { + summary: 'Creates or updates a synonym group with additional terms', + complexity: 'O(1)', + arguments: [ + { + name: 'index', + type: 'string' + }, + { + name: 'synonym_group_id', + type: 'string' + }, + { + name: 'skipinitialscan', + type: 'pure-token', + token: 'SKIPINITIALSCAN', + optional: true + }, + { + name: 'term', + type: 'string', + multiple: true + } + ], + since: '1.2.0', + group: 'search', + provider: 'redisearch' + }, + 'FT.TAGVALS': { + summary: 'Returns the distinct tags indexed in a Tag field', + complexity: 'O(N)', + arguments: [ + { + name: 'index', + type: 'string' + }, + { + name: 'field_name', + type: 'string' + } + ], + since: '1.0.0', + group: 'search', + provider: 'redisearch' + }, + 'FT._LIST': { + summary: 'Returns a list of all existing indexes', + complexity: 'O(1)', + since: '2.0.0', + group: 'search', + provider: 'redisearch' + }, +} diff --git a/redisinsight/ui/src/pages/search/components/results-history/ResultsHistory.tsx b/redisinsight/ui/src/pages/search/components/results-history/ResultsHistory.tsx index 9d05a11205..ca85d28c35 100644 --- a/redisinsight/ui/src/pages/search/components/results-history/ResultsHistory.tsx +++ b/redisinsight/ui/src/pages/search/components/results-history/ResultsHistory.tsx @@ -20,7 +20,7 @@ import { searchAndQuerySelector } from 'uiSrc/slices/search/searchAndQuery' import { CommandExecutionType, RunQueryMode } from 'uiSrc/slices/interfaces' import { sendEventTelemetry, TelemetryEvent } from 'uiSrc/telemetry' import { ProfileQueryType } from 'uiSrc/pages/workbench/constants' -import { generateProfileQueryForCommand } from 'uiSrc/pages/workbench/utils' +import { generateProfileQueryForCommand } from 'uiSrc/pages/workbench/utils/profile' import { CodeButtonParams } from 'uiSrc/constants' import styles from './styles.module.scss' diff --git a/redisinsight/ui/src/pages/workbench/components/query/Query/Query.tsx b/redisinsight/ui/src/pages/workbench/components/query/Query/Query.tsx index 440dd63215..6541e6c389 100644 --- a/redisinsight/ui/src/pages/workbench/components/query/Query/Query.tsx +++ b/redisinsight/ui/src/pages/workbench/components/query/Query/Query.tsx @@ -1,6 +1,6 @@ import React, { useContext, useEffect, useRef, useState } from 'react' import { useDispatch, useSelector } from 'react-redux' -import { compact, first, isNumber } from 'lodash' +import { compact, first } from 'lodash' import cx from 'classnames' import MonacoEditor, { monaco as monacoEditor } from 'react-monaco-editor' import { useParams } from 'react-router-dom' @@ -9,6 +9,7 @@ import { Theme, MonacoLanguage, DSLNaming, + IRedisCommand, } from 'uiSrc/constants' import { actionTriggerParameterHints, @@ -35,30 +36,21 @@ import { QueryActions, QueryTutorials } from 'uiSrc/components/query' import { addOwnTokenToArgs, - findCurrentArgument, - splitQueryByArgs } from 'uiSrc/pages/workbench/utils/query' import { getRange, getRediSearchSignutureProvider, } from 'uiSrc/pages/workbench/utils/monaco' -import { CursorContext, FoundCommandArgument, SearchCommand, TokenType } from 'uiSrc/pages/workbench/types' -import SEARCH_COMMANDS_SPEC from 'uiSrc/pages/workbench/data/supported_commands.json' +import { CursorContext } from 'uiSrc/pages/workbench/types' import { asSuggestionsRef, getCommandsSuggestions, - getFieldsSuggestions, - getFunctionsSuggestions, - getGeneralSuggestions, - getIndexesSuggestions, - getNoIndexesSuggestion, isIndexComplete } from 'uiSrc/pages/workbench/utils/suggestions' import { COMMANDS_TO_GET_INDEX_INFO, - DefinedArgumentName, EmptySuggestionsIds, - FIELD_START_SYMBOL } from 'uiSrc/pages/workbench/constants' import { useDebouncedEffect } from 'uiSrc/services' import { fetchRedisearchInfoAction } from 'uiSrc/slices/browser/redisearch' +import { findSuggestionsByArg } from 'uiSrc/pages/workbench/utils/searchSuggestions' import { aroundQuotesRegExp, argInQuotesRegExp, @@ -71,6 +63,7 @@ import styles from './styles.module.scss' export interface Props { query: string + commands: IRedisCommand[] indexes: RedisResponseBuffer[] activeMode: RunQueryMode resultsMode?: ResultsMode @@ -89,6 +82,7 @@ let decorationCollection: Nullable { const { query = '', + commands = [], indexes = [], activeMode, resultsMode, @@ -125,16 +119,7 @@ const Query = (props: Props) => { const { theme } = useContext(ThemeContext) const monacoObjects = useRef>(null) - const getCommandByName = (name: string) => - (name in SEARCH_COMMANDS_SPEC ? SEARCH_COMMANDS_SPEC[name] : (REDIS_COMMANDS_SPEC[name] || {})) - - const REDIS_COMMANDS = REDIS_COMMANDS_ARRAY - .map((name) => ({ ...getCommandByName(name), name })) - .map((command) => ({ - ...addOwnTokenToArgs(command.name!, command), - token: command.name!, - type: TokenType.Block - })) + const REDIS_COMMANDS = commands.map((command) => ({ ...addOwnTokenToArgs(command.name!, command) })) const { instanceId = '' } = useParams<{ instanceId: string }>() @@ -204,28 +189,54 @@ const Query = (props: Props) => { })) }, 200, [selectedIndex]) - const triggerUpdateCursorPosition = (editor: monacoEditor.editor.IStandaloneCodeEditor) => { - const position = editor.getPosition() - isDedicatedEditorOpenRef.current = false - editor.trigger('mouse', '_moveTo', { position: { lineNumber: 1, column: 1 } }) - editor.trigger('mouse', '_moveTo', { position }) + const editorDidMount = ( + editor: monacoEditor.editor.IStandaloneCodeEditor, + monaco: typeof monacoEditor + ) => { + monacoObjects.current = { editor, monaco } + + // hack for exit from snippet mode after click Enter until no answer from monaco authors + // https://github.com/microsoft/monaco-editor/issues/2756 + contribution = editor.getContribution('snippetController2') + + syntaxWidgetContext = editor.createContextKey(SYNTAX_CONTEXT_ID, false) editor.focus() - } + setQueryEl(editor) - const onPressWidget = () => { - if (!monacoObjects.current) return - const { editor } = monacoObjects?.current + editor.onKeyDown(onKeyDownMonaco) + editor.onDidChangeCursorPosition(onKeyChangeCursorMonaco) - setIsDedicatedEditorOpen(true) - editor.updateOptions({ readOnly: true }) - hideSyntaxWidget(editor) - sendEventTelemetry({ - event: TelemetryEvent.WORKBENCH_NON_REDIS_EDITOR_OPENED, - eventData: { - databaseId: instanceId, - lang: syntaxCommand.current.lang, + setupMonacoRedisLang(monaco) + editor.addAction( + getMonacoAction(MonacoAction.Submit, (editor) => handleSubmit(editor.getValue()), monaco) + ) + + editor.addCommand(monaco.KeyMod.Shift | monaco.KeyCode.Space, () => { + onPressWidget() + }, SYNTAX_CONTEXT_ID) + + editor.onMouseDown((e: monacoEditor.editor.IEditorMouseEvent) => { + if ((e.target as monacoEditor.editor.IMouseTargetContentWidget)?.detail === SYNTAX_WIDGET_ID) { + onPressWidget() + } + }) + + editor.addCommand(monaco.KeyCode.Escape, () => { + hideSyntaxWidget(editor) + isWidgetEscaped.current = true + }, SYNTAX_CONTEXT_ID) + + decorationCollection = editor.createDecorationsCollection() + + const suggestionWidget = editor.getContribution('editor.contrib.suggestController') + suggestionWidget?.onWillInsertSuggestItem(({ item }: Record<'item', any>) => { + if (item.completion.id === EmptySuggestionsIds.NoIndexes) { + helpWidgetRef.current.isOpen = true + editor.trigger('', 'hideSuggestWidget', null) + editor.trigger('', 'editor.action.triggerParameterHints', '') } }) + suggestionsRef.current = getSuggestions(editor).data } const onChange = (value: string = '') => { @@ -237,15 +248,6 @@ const Query = (props: Props) => { } } - const handleKeyDown = (e: React.KeyboardEvent) => { - onKeyDown?.(e, query) - } - - const handleSubmit = (value?: string) => { - execHistoryPos = 0 - onSubmit(value) - } - const onTriggerParameterHints = () => { if (!monacoObjects.current) return @@ -314,6 +316,102 @@ const Query = (props: Props) => { } } + const onExitSnippetMode = () => { + if (!monacoObjects.current) return + const { editor } = monacoObjects?.current + + if (contribution?.isInSnippet?.()) { + const { lineNumber = 0, column = 0 } = editor?.getPosition() ?? {} + editor.setSelection(new monacoEditor.Selection(lineNumber, column, lineNumber, column)) + contribution?.cancel?.() + } + } + + const onKeyChangeCursorMonaco = (e: monacoEditor.editor.ICursorPositionChangedEvent) => { + if (!monacoObjects.current) return + const { editor } = monacoObjects?.current + const model = editor.getModel() + + isWidgetOpen.current && hideSyntaxWidget(editor) + + if (!model || isDedicatedEditorOpenRef.current) { + return + } + + const command = findCompleteQuery(model, e.position, REDIS_COMMANDS_SPEC, REDIS_COMMANDS_ARRAY) + handleSuggestions(editor, command) + handleDslSyntax(e, command) + } + + const onPressWidget = () => { + if (!monacoObjects.current) return + const { editor } = monacoObjects?.current + + setIsDedicatedEditorOpen(true) + editor.updateOptions({ readOnly: true }) + hideSyntaxWidget(editor) + sendEventTelemetry({ + event: TelemetryEvent.WORKBENCH_NON_REDIS_EDITOR_OPENED, + eventData: { + databaseId: instanceId, + lang: syntaxCommand.current.lang, + } + }) + } + + const onCancelDedicatedEditor = () => { + setIsDedicatedEditorOpen(false) + if (!monacoObjects.current) return + const { editor } = monacoObjects?.current + + editor.updateOptions({ readOnly: false }) + triggerUpdateCursorPosition(editor) + + sendEventTelemetry({ + event: TelemetryEvent.WORKBENCH_NON_REDIS_EDITOR_CANCELLED, + eventData: { + databaseId: instanceId, + lang: syntaxCommand.current.lang, + } + }) + } + + const handleKeyDown = (e: React.KeyboardEvent) => { + onKeyDown?.(e, query) + } + + const handleSubmit = (value?: string) => { + execHistoryPos = 0 + onSubmit(value) + } + + const handleSuggestions = ( + editor: monacoEditor.editor.IStandaloneCodeEditor, + command?: Nullable + ) => { + const { data, forceHide, forceShow } = getSuggestions(editor, command) + suggestionsRef.current = data + + if (!forceShow) { + editor.trigger('', 'editor.action.triggerParameterHints', '') + return + } + + if (data.length) { + helpWidgetRef.current.isOpen = false + triggerSuggestions() + return + } + + editor.trigger('', 'editor.action.triggerParameterHints', '') + + if (forceHide) { + setTimeout(() => editor?.trigger('', 'hideSuggestWidget', null), 0) + } else { + helpWidgetRef.current.isOpen = !isSuggestionsOpened() && helpWidgetRef.current.isOpen + } + } + const handleDslSyntax = ( e: monacoEditor.editor.ICursorPositionChangedEvent, command: Nullable @@ -354,6 +452,14 @@ const Query = (props: Props) => { } } + const triggerUpdateCursorPosition = (editor: monacoEditor.editor.IStandaloneCodeEditor) => { + const position = editor.getPosition() + isDedicatedEditorOpenRef.current = false + editor.trigger('mouse', '_moveTo', { position: { lineNumber: 1, column: 1 } }) + editor.trigger('mouse', '_moveTo', { position }) + editor.focus() + } + const isSuggestionsOpened = () => { const { editor } = monacoObjects.current || {} if (!editor) return false @@ -361,61 +467,11 @@ const Query = (props: Props) => { return suggestController?.model?.state === 1 } - const onKeyChangeCursorMonaco = (e: monacoEditor.editor.ICursorPositionChangedEvent) => { - if (!monacoObjects.current) return - const { editor } = monacoObjects?.current - const model = editor.getModel() - - isWidgetOpen.current && hideSyntaxWidget(editor) - - if (!model || isDedicatedEditorOpenRef.current) { - return - } - - const command = findCompleteQuery(model, e.position, REDIS_COMMANDS_SPEC, REDIS_COMMANDS_ARRAY) - - const { data, forceHide, forceShow } = getSuggestions(editor, command) - - suggestionsRef.current = data - - if (!forceShow) { - editor.trigger('', 'editor.action.triggerParameterHints', '') - return - } - - if (data.length) { - helpWidgetRef.current.isOpen = false - triggerSuggestions() - return - } - - editor.trigger('', 'editor.action.triggerParameterHints', '') - - if (forceHide) { - setTimeout(() => editor?.trigger('', 'hideSuggestWidget', null), 0) - } else { - helpWidgetRef.current.isOpen = !isSuggestionsOpened() && helpWidgetRef.current.isOpen - } - - handleDslSyntax(e, command) - } - const triggerSuggestions = () => { const { editor } = monacoObjects.current || {} setTimeout(() => editor?.trigger('', 'editor.action.triggerSuggest', { auto: false })) } - const onExitSnippetMode = () => { - if (!monacoObjects.current) return - const { editor } = monacoObjects?.current - - if (contribution?.isInSnippet?.()) { - const { lineNumber = 0, column = 0 } = editor?.getPosition() ?? {} - editor.setSelection(new monacoEditor.Selection(lineNumber, column, lineNumber, column)) - contribution?.cancel?.() - } - } - const hideSyntaxWidget = (editor: monacoEditor.editor.IStandaloneCodeEditor) => { editor.removeContentWidget(onTriggerContentWidget(null)) syntaxWidgetContext?.set(false) @@ -432,23 +488,6 @@ const Query = (props: Props) => { syntaxWidgetContext?.set(true) } - const onCancelDedicatedEditor = () => { - setIsDedicatedEditorOpen(false) - if (!monacoObjects.current) return - const { editor } = monacoObjects?.current - - editor.updateOptions({ readOnly: false }) - triggerUpdateCursorPosition(editor) - - sendEventTelemetry({ - event: TelemetryEvent.WORKBENCH_NON_REDIS_EDITOR_CANCELLED, - eventData: { - databaseId: instanceId, - lang: syntaxCommand.current.lang, - } - }) - } - const updateArgFromDedicatedEditor = (value: string = '') => { if (!syntaxCommand.current || !monacoObjects.current) return const { editor } = monacoObjects?.current @@ -484,56 +523,6 @@ const Query = (props: Props) => { }) } - const editorDidMount = ( - editor: monacoEditor.editor.IStandaloneCodeEditor, - monaco: typeof monacoEditor - ) => { - monacoObjects.current = { editor, monaco } - - // hack for exit from snippet mode after click Enter until no answer from monaco authors - // https://github.com/microsoft/monaco-editor/issues/2756 - contribution = editor.getContribution('snippetController2') - - syntaxWidgetContext = editor.createContextKey(SYNTAX_CONTEXT_ID, false) - editor.focus() - setQueryEl(editor) - - editor.onKeyDown(onKeyDownMonaco) - editor.onDidChangeCursorPosition(onKeyChangeCursorMonaco) - - setupMonacoRedisLang(monaco) - editor.addAction( - getMonacoAction(MonacoAction.Submit, (editor) => handleSubmit(editor.getValue()), monaco) - ) - - editor.addCommand(monaco.KeyMod.Shift | monaco.KeyCode.Space, () => { - onPressWidget() - }, SYNTAX_CONTEXT_ID) - - editor.onMouseDown((e: monacoEditor.editor.IEditorMouseEvent) => { - if ((e.target as monacoEditor.editor.IMouseTargetContentWidget)?.detail === SYNTAX_WIDGET_ID) { - onPressWidget() - } - }) - - editor.addCommand(monaco.KeyCode.Escape, () => { - hideSyntaxWidget(editor) - isWidgetEscaped.current = true - }, SYNTAX_CONTEXT_ID) - - decorationCollection = editor.createDecorationsCollection() - - const suggestionWidget = editor.getContribution('editor.contrib.suggestController') - suggestionWidget?.onWillInsertSuggestItem(({ item }: Record<'item', any>) => { - if (item.completion.id === EmptySuggestionsIds.NoIndexes) { - updateHelpWidget(true) - editor.trigger('', 'hideSuggestWidget', null) - editor.trigger('', 'editor.action.triggerParameterHints', '') - } - }) - suggestionsRef.current = getSuggestions(editor).data - } - const setupMonacoRedisLang = (monaco: typeof monacoEditor) => { disposeCompletionItemProvider = monaco.languages.registerCompletionItemProvider(MonacoLanguage.Redis, { provideCompletionItems: (): monacoEditor.languages.CompletionList => ({ suggestions: suggestionsRef.current }) @@ -544,13 +533,6 @@ const Query = (props: Props) => { }).dispose } - const updateHelpWidget = (isOpen: boolean, parent?: SearchCommand, currentArg?: SearchCommand) => { - helpWidgetRef.current = { - isOpen, - parent: parent || helpWidgetRef.current.parent, - currentArg: currentArg || helpWidgetRef.current.currentArg } - } - const getSuggestions = ( editor: monacoEditor.editor.IStandaloneCodeEditor, command?: Nullable @@ -567,6 +549,7 @@ const Query = (props: Props) => { const range = getRange(position, word) if (position.column === 1) { + helpWidgetRef.current.isOpen = false if (command) return asSuggestionsRef([]) return asSuggestionsRef(getCommandsSuggestions(REDIS_COMMANDS, range), false) @@ -577,115 +560,31 @@ const Query = (props: Props) => { } const { allArgs, args, cursor } = command - const { prevCursorChar } = cursor - const [beforeOffsetArgs, [currentOffsetArg]] = args + const [, [currentOffsetArg]] = args if (COMMANDS_TO_GET_INDEX_INFO.some((name) => name === command.name)) { setSelectedIndex(allArgs[1] || '') } - const cursorContext: CursorContext = { ...cursor, currentOffsetArg, offset: command.commandCursorPosition || 0 } - const foundArg = findCurrentArgument(REDIS_COMMANDS, beforeOffsetArgs) - - if (!command.name.startsWith('FT.')) { - updateHelpWidget(true, foundArg?.parent, foundArg?.stopArg) - return asSuggestionsRef([]) - } - - if (prevCursorChar === FIELD_START_SYMBOL) return handleFieldSuggestions(foundArg, range) - - switch (foundArg?.stopArg?.name) { - case DefinedArgumentName.index: { - return handleIndexSuggestions(command.info as SearchCommand, foundArg, currentOffsetArg, range) - } - case DefinedArgumentName.query: { - return handleQuerySuggestions(command.info as SearchCommand, foundArg) - } - default: { - return handleCommonSuggestions(command.fullQuery, foundArg, allArgs, cursorContext, range) - } - } - } - - const handleFieldSuggestions = (foundArg: Nullable, range: monacoEditor.IRange) => { - const isInQuery = foundArg?.stopArg?.name === DefinedArgumentName.query - const fieldSuggestions = getFieldsSuggestions(attributesRef.current, range, true, isInQuery) - return asSuggestionsRef(fieldSuggestions, true) - } + const cursorContext: CursorContext = { ...cursor, currentOffsetArg, offset: command.commandCursorPosition, range } + const { suggestions, helpWidget } = findSuggestionsByArg( + REDIS_COMMANDS, + command, + cursorContext, + { fields: attributesRef.current, indexes: indexesRef.current } + ) - const handleIndexSuggestions = ( - command: SearchCommand, - foundArg: FoundCommandArgument, - currentOffsetArg: Nullable, - range: monacoEditor.IRange - ) => { - const isIndex = indexesRef.current.length > 0 - updateHelpWidget(isIndex, command, foundArg?.stopArg) + console.log(helpWidgetRef) - if (!isIndex) { - updateHelpWidget(!!currentOffsetArg) - return asSuggestionsRef(!currentOffsetArg ? getNoIndexesSuggestion(range) : [], true) + if (helpWidget) { + const { isOpen, parent, currentArg } = helpWidget + helpWidgetRef.current = { + isOpen, + parent: parent || helpWidgetRef.current.parent, + currentArg: currentArg || helpWidgetRef.current.currentArg } } - if (!isIndex || currentOffsetArg) return asSuggestionsRef([], !currentOffsetArg) - - const argumentIndex = command?.arguments - ?.findIndex(({ name }) => foundArg?.stopArg?.name === name) - const isNextArgQuery = isNumber(argumentIndex) - && command?.arguments?.[argumentIndex + 1]?.name === DefinedArgumentName.query - - return asSuggestionsRef(getIndexesSuggestions(indexesRef.current, range, isNextArgQuery)) - } - - const handleQuerySuggestions = (command: SearchCommand, foundArg: FoundCommandArgument) => { - updateHelpWidget(true, command, foundArg?.stopArg) - return asSuggestionsRef([], false) - } - - const handleExpressionSuggestions = ( - value: string, - foundArg: FoundCommandArgument, - cursorContext: CursorContext, - range: monacoEditor.IRange - ) => { - updateHelpWidget(true, foundArg?.parent, foundArg?.stopArg) - - const { isCursorInQuotes, offset, argLeftOffset } = cursorContext - if (!isCursorInQuotes) return asSuggestionsRef([]) - - const stringBeforeCursor = value.substring(argLeftOffset, offset) || '' - const expression = stringBeforeCursor.replace(/^["']|["']$/g, '') - const { args } = splitQueryByArgs(expression, offset - argLeftOffset) - const [, [currentArg]] = args - - const functions = foundArg?.stopArg?.arguments ?? [] - const suggestions = getFunctionsSuggestions(functions, range) - const isStartsWithFunction = functions.some(({ token }) => token?.startsWith(currentArg)) - - return asSuggestionsRef(suggestions, true, isStartsWithFunction) - } - - const handleCommonSuggestions = ( - value: string, - foundArg: Nullable, - allArgs: string[], - cursorContext: CursorContext, - range: monacoEditor.IRange - ) => { - if (foundArg?.stopArg?.expression) return handleExpressionSuggestions(value, foundArg, cursorContext, range) - - const { prevCursorChar, nextCursorChar, isCursorInQuotes } = cursorContext - const shouldHideSuggestions = isCursorInQuotes || nextCursorChar || (prevCursorChar) - if (shouldHideSuggestions) return asSuggestionsRef([]) - - const { - suggestions, - forceHide, - helpWidgetData - } = getGeneralSuggestions(foundArg, allArgs, range, attributesRef.current) - - if (helpWidgetData) updateHelpWidget(helpWidgetData.isOpen, helpWidgetData.parent, helpWidgetData.currentArg) - return asSuggestionsRef(suggestions, forceHide) + return suggestions } const isLoading = loading || processing diff --git a/redisinsight/ui/src/pages/workbench/components/query/QueryWrapper.tsx b/redisinsight/ui/src/pages/workbench/components/query/QueryWrapper.tsx index d6e1d2f351..033eabf914 100644 --- a/redisinsight/ui/src/pages/workbench/components/query/QueryWrapper.tsx +++ b/redisinsight/ui/src/pages/workbench/components/query/QueryWrapper.tsx @@ -6,8 +6,10 @@ import { appRedisCommandsSelector } from 'uiSrc/slices/app/redis-commands' import { RunQueryMode, ResultsMode } from 'uiSrc/slices/interfaces/workbench' import { fetchRedisearchListAction, redisearchListSelector } from 'uiSrc/slices/browser/redisearch' import { connectedInstanceSelector } from 'uiSrc/slices/instances/instances' -import Query from './Query' +import { mergeRedisCommandsSpecs } from 'uiSrc/utils/transformers/redisCommands' +import SEARCH_COMMANDS_SPEC from 'uiSrc/pages/workbench/data/supported_commands.json' import styles from './Query/styles.module.scss' +import Query from './Query' export interface Props { query: string @@ -36,6 +38,9 @@ const QueryWrapper = (props: Props) => { const { loading: isCommandsLoading, } = useSelector(appRedisCommandsSelector) const { id: connectedIndstanceId } = useSelector(connectedInstanceSelector) const { data: indexes = [] } = useSelector(redisearchListSelector) + const { spec: COMMANDS_SPEC } = useSelector(appRedisCommandsSelector) + + const REDIS_COMMANDS = mergeRedisCommandsSpecs(COMMANDS_SPEC, SEARCH_COMMANDS_SPEC) const dispatch = useDispatch() @@ -58,6 +63,7 @@ const QueryWrapper = (props: Props) => { ) : ( + stopArg: Maybe isBlocked: boolean - append: Maybe> - parent: Maybe + append: Maybe> + parent: Maybe } export interface CursorContext { @@ -42,4 +22,5 @@ export interface CursorContext { offset: number argLeftOffset: number argRightOffset: number + range: monacoEditor.IRange } diff --git a/redisinsight/ui/src/pages/workbench/utils.ts b/redisinsight/ui/src/pages/workbench/utils.ts deleted file mode 100644 index 2bca2b87c2..0000000000 --- a/redisinsight/ui/src/pages/workbench/utils.ts +++ /dev/null @@ -1,41 +0,0 @@ -import { ProfileQueryType, SEARCH_COMMANDS, GRAPH_COMMANDS } from './constants' - -export const generateGraphProfileQuery = (query: string, type: ProfileQueryType) => { - const q = query?.split(' ')?.slice(1) - - if (q) { - return [`graph.${type.toLowerCase()}`, ...q].join(' ') - } - - return null -} - -export const generateSearchProfileQuery = (query: string, type: ProfileQueryType) => { - const commandSplit = query?.split(' ') - const cmd = commandSplit?.[0] - - if (!commandSplit || !cmd) { - return null - } - - if (type === ProfileQueryType.Explain) { - return [`ft.${type.toLowerCase()}`, ...commandSplit?.slice(1)].join(' ') - } else { - let index = commandSplit?.[1] - - const queryType = cmd.split('.')?.[1] // SEARCH / AGGREGATE - return [`ft.${type.toLowerCase()}`, index, queryType, 'QUERY', ...commandSplit?.slice(2)].join(' ') - } -} - -export const generateProfileQueryForCommand = (query: string, type: ProfileQueryType) => { - const cmd = query?.split(' ')?.[0]?.toLowerCase() - - if (GRAPH_COMMANDS.includes(cmd)) { - return generateGraphProfileQuery(query, type) - } else if (SEARCH_COMMANDS.includes(cmd)) { - return generateSearchProfileQuery(query, type) - } - - return null -} diff --git a/redisinsight/ui/src/pages/workbench/utils/monaco.ts b/redisinsight/ui/src/pages/workbench/utils/monaco.ts index 3bce209dd4..c6cd9bb58f 100644 --- a/redisinsight/ui/src/pages/workbench/utils/monaco.ts +++ b/redisinsight/ui/src/pages/workbench/utils/monaco.ts @@ -2,8 +2,8 @@ import { monaco } from 'react-monaco-editor' import * as monacoEditor from 'monaco-editor' import { isString } from 'lodash' import { generateDetail } from 'uiSrc/pages/workbench/utils/query' -import { SearchCommand, TokenType } from 'uiSrc/pages/workbench/types' import { Maybe } from 'uiSrc/utils' +import { IRedisCommand, ICommandTokenType } from 'uiSrc/constants' export const setCursorPositionAtTheEnd = (editor: monacoEditor.editor.IStandaloneCodeEditor) => { if (!editor) return @@ -25,7 +25,7 @@ export const getRange = (position: monaco.Position, word: monaco.editor.IWordAtP startColumn: word.startColumn, }) -export const buildSuggestion = (arg: SearchCommand, range: monaco.IRange, options: any = {}) => { +export const buildSuggestion = (arg: IRedisCommand, range: monaco.IRange, options: any = {}) => { const extraQuotes = arg.expression ? '\'$1\'' : '' return { label: isString(arg) ? arg : arg.token || arg.arguments?.[0].token || arg.name || '', @@ -39,14 +39,14 @@ export const buildSuggestion = (arg: SearchCommand, range: monaco.IRange, option export const getRediSearchSignutureProvider = (options: Maybe<{ isOpen: boolean - currentArg: SearchCommand - parent: Maybe + currentArg: IRedisCommand + parent: Maybe }>) => { const { isOpen, currentArg, parent } = options || {} if (!isOpen) return null const label = generateDetail(parent) - const arg = currentArg?.type === TokenType.Block + const arg = currentArg?.type === ICommandTokenType.Block ? currentArg?.arguments?.[0]?.name : (currentArg?.name || currentArg?.type || '') diff --git a/redisinsight/ui/src/pages/workbench/utils/query.ts b/redisinsight/ui/src/pages/workbench/utils/query.ts index c87887fbb8..ca9bcda8c8 100644 --- a/redisinsight/ui/src/pages/workbench/utils/query.ts +++ b/redisinsight/ui/src/pages/workbench/utils/query.ts @@ -2,9 +2,9 @@ import { isNumber, toNumber } from 'lodash' import { generateArgsNames, Maybe, Nullable } from 'uiSrc/utils' -import { CommandProvider } from 'uiSrc/constants' +import { CommandProvider, IRedisCommand, IRedisCommandTree, ICommandTokenType } from 'uiSrc/constants' import { COMPOSITE_ARGS } from 'uiSrc/pages/workbench/constants' -import { ArgName, FoundCommandArgument, SearchCommand, SearchCommandTree, TokenType } from '../types' +import { ArgName, FoundCommandArgument } from '../types' export const splitQueryByArgs = (query: string, position: number = 0) => { const args: [string[], string[]] = [[], []] @@ -102,16 +102,16 @@ export const splitQueryByArgs = (query: string, position: number = 0) => { } export const findCurrentArgument = ( - args: SearchCommand[], + args: IRedisCommand[], prev: string[], - parent?: SearchCommandTree + parent?: IRedisCommandTree ): Nullable => { for (let i = prev.length - 1; i >= 0; i--) { const arg = prev[i] const currentArg = findArgByToken(args, arg) - const currentWithParent: SearchCommandTree = { ...currentArg, parent } + const currentWithParent: IRedisCommandTree = { ...currentArg, parent } - if (currentArg?.arguments && currentArg?.type === TokenType.Block) { + if (currentArg?.arguments && currentArg?.type === ICommandTokenType.Block) { return findCurrentArgument(currentArg.arguments, prev.slice(i), currentWithParent) } @@ -137,13 +137,13 @@ export const findCurrentArgument = ( const findStopArgumentInQuery = ( queryArgs: string[], - restCommandArgs: Maybe = [], + restCommandArgs: Maybe = [], ): { - restArguments: SearchCommand[] + restArguments: IRedisCommand[] stopArgIndex: number argumentsIntered?: number isBlocked: boolean - parent?: SearchCommand + parent?: IRedisCommand } => { let currentCommandArgIndex = 0 let argumentsIntered = 0 @@ -168,14 +168,14 @@ const findStopArgumentInQuery = ( const arg = queryArgs[i] const currentCommandArg = restCommandArgs[currentCommandArgIndex] - if (currentCommandArg?.type === TokenType.PureToken) { + if (currentCommandArg?.type === ICommandTokenType.PureToken) { skipArg() continue } if (!isBlockedOnCommand && currentCommandArg?.optional) { const isNotToken = currentCommandArg?.token && currentCommandArg.token !== arg.toUpperCase() - const isNotOneOfToken = !currentCommandArg?.token && currentCommandArg?.type === TokenType.OneOf + const isNotOneOfToken = !currentCommandArg?.token && currentCommandArg?.type === ICommandTokenType.OneOf && currentCommandArg?.arguments?.every(({ token }) => token !== arg.toUpperCase()) if (isNotToken || isNotOneOfToken) { @@ -185,7 +185,7 @@ const findStopArgumentInQuery = ( } } - if (currentCommandArg?.type === TokenType.Block) { + if (currentCommandArg?.type === ICommandTokenType.Block) { let blockArguments = currentCommandArg.arguments ? [...currentCommandArg.arguments] : [] const nArgs = toNumber(queryArgs[i - 1]) || 0 @@ -199,7 +199,7 @@ const findStopArgumentInQuery = ( if (currentCommandArg.token && !isBlockHasToken && currentQueryArg) { blockArguments.unshift({ - type: TokenType.PureToken, + type: ICommandTokenType.PureToken, token: currentQueryArg }) } @@ -246,7 +246,7 @@ const findStopArgumentInQuery = ( continue } - if (currentCommandArg?.type === TokenType.OneOf && currentCommandArg?.optional) { + if (currentCommandArg?.type === ICommandTokenType.OneOf && currentCommandArg?.optional) { // if oneof is optional then we can switch to another argument if (!currentCommandArg?.arguments?.some(({ token }) => token === arg)) { moveToNextCommandArg() @@ -290,13 +290,13 @@ export const getArgumentSuggestions = ( tokenArgs: string[], levelArgs: string[] }, - pastCommandArgs: SearchCommand[], - current?: SearchCommandTree + pastCommandArgs: IRedisCommand[], + current?: IRedisCommandTree ): { isComplete: boolean - stopArg: Maybe, + stopArg: Maybe, isBlocked: boolean, - append: Array, + append: Array, } => { const { restArguments, @@ -309,8 +309,8 @@ export const getArgumentSuggestions = ( const stopArgument = restArguments[stopArgIndex] const restNotFilledArgs = restArguments.slice(stopArgIndex) - const isOneOfArgument = stopArgument?.type === TokenType.OneOf - || (stopArgument?.type === TokenType.PureToken && current?.parent?.type === TokenType.OneOf) + const isOneOfArgument = stopArgument?.type === ICommandTokenType.OneOf + || (stopArgument?.type === ICommandTokenType.PureToken && current?.parent?.type === ICommandTokenType.OneOf) if (isWasBlocked) { return { @@ -352,9 +352,9 @@ export const getArgumentSuggestions = ( } export const getRestArguments = ( - current: Maybe, - stopArgument: Nullable -): SearchCommandTree[] => { + current: Maybe, + stopArgument: Nullable +): IRedisCommandTree[] => { const argumentIndexInArg = current?.arguments ?.findIndex(({ name }) => name === stopArgument?.name) const nextMandatoryIndex = argumentIndexInArg && argumentIndexInArg > -1 ? current?.arguments @@ -377,7 +377,7 @@ export const getRestArguments = ( beforeMandatoryOptionalArgs.unshift(nextMandatoryArg) } - if (nextMandatoryArg?.type === TokenType.OneOf) { + if (nextMandatoryArg?.type === ICommandTokenType.OneOf) { beforeMandatoryOptionalArgs.unshift(...(nextMandatoryArg.arguments || [])) } @@ -385,12 +385,12 @@ export const getRestArguments = ( } export const getAllRestArguments = ( - current: Maybe, - stopArgument: Nullable, + current: Maybe, + stopArgument: Nullable, prevStringArgs: string[] = [], skipLevel = false ) => { - const appendArgs: Array = [] + const appendArgs: Array = [] const currentLvlNextArgs = removeNotSuggestedArgs( prevStringArgs, getRestArguments(current, stopArgument) @@ -410,39 +410,39 @@ export const getAllRestArguments = ( return appendArgs } -export const removeNotSuggestedArgs = (args: string[], commandArgs: SearchCommandTree[]) => +export const removeNotSuggestedArgs = (args: string[], commandArgs: IRedisCommandTree[]) => commandArgs.filter((arg) => { if (arg.token && arg.multiple) return true - if (arg.type === TokenType.OneOf) { + if (arg.type === ICommandTokenType.OneOf) { return !args .some((queryArg) => arg.arguments ?.some((oneOfArg) => oneOfArg.token?.toUpperCase() === queryArg.toUpperCase())) } - if (arg.type === TokenType.Block) { + if (arg.type === ICommandTokenType.Block) { return arg.arguments?.[0]?.token && !args.includes(arg.arguments?.[0]?.token?.toUpperCase()) } return arg.token && !args.includes(arg.token) }) -export const fillArgsByType = (args: SearchCommand[], expandBlock = true): SearchCommandTree[] => { - const result: SearchCommandTree[] = [] +export const fillArgsByType = (args: IRedisCommand[], expandBlock = true): IRedisCommandTree[] => { + const result: IRedisCommandTree[] = [] for (let i = 0; i < args.length; i++) { const currentArg = args[i] - if (expandBlock && currentArg.type === TokenType.OneOf && !currentArg.token) { + if (expandBlock && currentArg.type === ICommandTokenType.OneOf && !currentArg.token) { result.push(...(currentArg?.arguments?.map((arg) => ({ ...arg, parent: currentArg })) || [])) } - if (currentArg.type === TokenType.Block) { + if (currentArg.type === ICommandTokenType.Block) { result.push({ multiple: currentArg.multiple, optional: currentArg.optional, parent: currentArg, - ...(currentArg?.arguments?.[0] as SearchCommand || {}), + ...(currentArg?.arguments?.[0] as IRedisCommand || {}), }) } if (currentArg.token) result.push(currentArg) @@ -451,29 +451,29 @@ export const fillArgsByType = (args: SearchCommand[], expandBlock = true): Searc return result } -export const findArgByToken = (list: SearchCommand[], arg: string): Maybe => +export const findArgByToken = (list: IRedisCommand[], arg: string): Maybe => list.find((cArg) => - (cArg.type === TokenType.OneOf - ? cArg.arguments?.some((oneOfArg: SearchCommand) => oneOfArg?.token?.toLowerCase() === arg?.toLowerCase()) + (cArg.type === ICommandTokenType.OneOf + ? cArg.arguments?.some((oneOfArg: IRedisCommand) => oneOfArg?.token?.toLowerCase() === arg?.toLowerCase()) : cArg.arguments?.[0]?.token?.toLowerCase() === arg.toLowerCase())) export const isCompositeArgument = (arg: string, prevArg?: string) => COMPOSITE_ARGS.includes([prevArg?.toUpperCase(), arg?.toUpperCase()].join(' ')) -export const generateDetail = (command: Maybe) => { +export const generateDetail = (command: Maybe) => { if (!command) return '' if (command.arguments) return generateArgsNames(CommandProvider.Main, command.arguments).join(' ') if (command.token) { - if (command.type === TokenType.PureToken) return command.token + if (command.type === ICommandTokenType.PureToken) return command.token return `${command.token}` } return '' } -export const addOwnTokenToArgs = (token: string, command: SearchCommand) => { +export const addOwnTokenToArgs = (token: string, command: IRedisCommand) => { if (command.arguments) { - return ({ ...command, arguments: [{ token, type: TokenType.PureToken }, ...command.arguments] }) + return ({ ...command, arguments: [{ token, type: ICommandTokenType.PureToken }, ...command.arguments] }) } return command } diff --git a/redisinsight/ui/src/pages/workbench/utils/searchSuggestions.ts b/redisinsight/ui/src/pages/workbench/utils/searchSuggestions.ts new file mode 100644 index 0000000000..91eead84fa --- /dev/null +++ b/redisinsight/ui/src/pages/workbench/utils/searchSuggestions.ts @@ -0,0 +1,186 @@ +import { monaco as monacoEditor } from 'react-monaco-editor' +import { isNumber } from 'lodash' +import { IMonacoQuery, Nullable } from 'uiSrc/utils' +import { CursorContext, FoundCommandArgument } from 'uiSrc/pages/workbench/types' +import { findCurrentArgument, splitQueryByArgs } from 'uiSrc/pages/workbench/utils/query' +import { IRedisCommand } from 'uiSrc/constants' +import { + asSuggestionsRef, + getFieldsSuggestions, + getFunctionsSuggestions, + getGeneralSuggestions, + getIndexesSuggestions, + getNoIndexesSuggestion +} from 'uiSrc/pages/workbench/utils/suggestions' +import { DefinedArgumentName, FIELD_START_SYMBOL } from 'uiSrc/pages/workbench/constants' + +export const findSuggestionsByArg = ( + listOfCommands: IRedisCommand[], + command: IMonacoQuery, + cursorContext: CursorContext, + additionData: { + indexes?: any[] + fields?: any[], + } +): { + suggestions: any, + helpWidget?: any +} => { + const { allArgs, args, cursor } = command + const { prevCursorChar } = cursor + const [beforeOffsetArgs, [currentOffsetArg]] = args + + const foundArg = findCurrentArgument(listOfCommands, beforeOffsetArgs) + + console.log(foundArg) + + if (!command.name.startsWith('FT.')) { + return { + helpWidget: { isOpen: !!foundArg, parent: foundArg?.parent, currentArg: foundArg?.stopArg }, + suggestions: asSuggestionsRef([]) + } + } + + if (prevCursorChar === FIELD_START_SYMBOL) { + return handleFieldSuggestions(additionData.fields || [], foundArg, cursorContext.range) + } + + switch (foundArg?.stopArg?.name) { + case DefinedArgumentName.index: { + return handleIndexSuggestions( + additionData.indexes || [], + command.info as IRedisCommand, + foundArg, + currentOffsetArg, + cursorContext.range + ) + } + case DefinedArgumentName.query: { + console.log('handle query') + return handleQuerySuggestions(foundArg) + } + default: { + return handleCommonSuggestions( + command.fullQuery, + foundArg, + allArgs, + additionData.fields || [], + cursorContext + ) + } + } +} + +const handleFieldSuggestions = ( + fields: any[], + foundArg: Nullable, + range: monacoEditor.IRange +) => { + const isInQuery = foundArg?.stopArg?.name === DefinedArgumentName.query + const fieldSuggestions = getFieldsSuggestions(fields, range, true, isInQuery) + return { + suggestions: asSuggestionsRef(fieldSuggestions, true) + } +} + +const handleIndexSuggestions = ( + indexes: any[], + command: IRedisCommand, + foundArg: FoundCommandArgument, + currentOffsetArg: Nullable, + range: monacoEditor.IRange +) => { + const isIndex = indexes.length > 0 + const helpWidget = { isOpen: isIndex, parent: command, currentArg: foundArg?.stopArg } + + if (!isIndex) { + helpWidget.isOpen = !!currentOffsetArg + + return { + suggestions: asSuggestionsRef(!currentOffsetArg ? getNoIndexesSuggestion(range) : [], true), + helpWidget + } + } + + if (!isIndex || currentOffsetArg) { + return { + suggestions: asSuggestionsRef([], !currentOffsetArg), + helpWidget + } + } + + const argumentIndex = command?.arguments + ?.findIndex(({ name }) => foundArg?.stopArg?.name === name) + const isNextArgQuery = isNumber(argumentIndex) + && command?.arguments?.[argumentIndex + 1]?.name === DefinedArgumentName.query + + return { + suggestions: asSuggestionsRef(getIndexesSuggestions(indexes, range, isNextArgQuery)), + helpWidget + } +} + +const handleQuerySuggestions = (foundArg: FoundCommandArgument) => ({ + helpWidget: { isOpen: true, parent: foundArg?.parent, currentArg: foundArg?.stopArg }, + suggestions: asSuggestionsRef([], false) +}) + +const handleExpressionSuggestions = ( + value: string, + foundArg: FoundCommandArgument, + cursorContext: CursorContext, +) => { + const helpWidget = { isOpen: true, parent: foundArg?.parent, currentArg: foundArg?.stopArg } + + const { isCursorInQuotes, offset, argLeftOffset } = cursorContext + if (!isCursorInQuotes) { + return { + suggestions: asSuggestionsRef([]), + helpWidget + } + } + + const stringBeforeCursor = value.substring(argLeftOffset, offset) || '' + const expression = stringBeforeCursor.replace(/^["']|["']$/g, '') + const { args } = splitQueryByArgs(expression, offset - argLeftOffset) + const [, [currentArg]] = args + + const functions = foundArg?.stopArg?.arguments ?? [] + const suggestions = getFunctionsSuggestions(functions, cursorContext.range) + const isStartsWithFunction = functions.some(({ token }) => token?.startsWith(currentArg)) + + return { + suggestions: asSuggestionsRef(suggestions, true, isStartsWithFunction), + helpWidget + } +} + +const handleCommonSuggestions = ( + value: string, + foundArg: Nullable, + allArgs: string[], + fields: any[], + cursorContext: CursorContext, +) => { + if (foundArg?.stopArg?.expression) return handleExpressionSuggestions(value, foundArg, cursorContext) + + const { prevCursorChar, nextCursorChar, isCursorInQuotes } = cursorContext + const shouldHideSuggestions = isCursorInQuotes || nextCursorChar || (prevCursorChar) + if (shouldHideSuggestions) { + return { + helpWidget: { isOpen: true, parent: foundArg?.parent, currentArg: foundArg?.stopArg }, + suggestions: asSuggestionsRef([]) + } + } + + const { + suggestions, + forceHide, + helpWidgetData + } = getGeneralSuggestions(foundArg, allArgs, cursorContext.range, fields) + + return { + suggestions: asSuggestionsRef(suggestions, forceHide), + helpWidget: helpWidgetData + } +} diff --git a/redisinsight/ui/src/pages/workbench/utils/tests/monaco.spec.ts b/redisinsight/ui/src/pages/workbench/utils/tests/monaco.spec.ts new file mode 100644 index 0000000000..c72864bc06 --- /dev/null +++ b/redisinsight/ui/src/pages/workbench/utils/tests/monaco.spec.ts @@ -0,0 +1,60 @@ +import { getRediSearchSignutureProvider } from 'uiSrc/pages/search/utils' +import { MOCKED_REDIS_COMMANDS } from 'uiSrc/mocks/data/mocked_redis_commands' +import { SearchCommand } from 'uiSrc/pages/search/types' + +const ftAggregateCommand = MOCKED_REDIS_COMMANDS['FT.AGGREGATE'] + +const getRediSearchSignatureProviderTests = [ + { + input: { + isOpen: false, + currentArg: {}, + parent: {} + }, + result: null + }, + { + input: { + isOpen: true, + currentArg: ftAggregateCommand.arguments.find(({ name }) => name === 'groupby') as SearchCommand, + parent: null + }, + result: { + dispose: expect.any(Function), + value: { + activeParameter: 0, + activeSignature: 0, + signatures: [{ + label: '', + parameters: [{ label: 'nargs' }] + }] + } + } + }, + { + input: { + isOpen: true, + currentArg: { name: 'expression' }, + parent: ftAggregateCommand.arguments.find(({ name }) => name === 'apply') as SearchCommand + }, + result: { + dispose: expect.any(Function), + value: { + activeParameter: 0, + activeSignature: 0, + signatures: [{ + label: 'APPLY expression AS name', + parameters: [{ label: 'expression' }] + }] + } + } + } +] + +describe('getRediSearchSignatureProvider', () => { + it.each(getRediSearchSignatureProviderTests)('should properly return result', ({ input, result }) => { + const testResult = getRediSearchSignutureProvider(input) + + expect(result).toEqual(testResult) + }) +}) diff --git a/redisinsight/ui/src/pages/workbench/utils.spec.ts b/redisinsight/ui/src/pages/workbench/utils/tests/profile.spec.ts similarity index 90% rename from redisinsight/ui/src/pages/workbench/utils.spec.ts rename to redisinsight/ui/src/pages/workbench/utils/tests/profile.spec.ts index 3d91dad1d8..e7aef603fe 100644 --- a/redisinsight/ui/src/pages/workbench/utils.spec.ts +++ b/redisinsight/ui/src/pages/workbench/utils/tests/profile.spec.ts @@ -1,11 +1,10 @@ -import { ProfileQueryType, SEARCH_COMMANDS, GRAPH_COMMANDS } from './constants' +import { ProfileQueryType } from '../../constants' import { generateGraphProfileQuery, generateSearchProfileQuery, generateProfileQueryForCommand, -} from './utils' - +} from '../profile' const generateGraphProfileQueryTests: Record[] = [ { input: 'GRAPH.QUERY key "MATCH (n) RETURN n"', output: 'graph.profile key "MATCH (n) RETURN n"', type: ProfileQueryType.Profile }, @@ -17,14 +16,13 @@ const generateGraphProfileQueryTests: Record[] = [ ] describe('generateGraphProfileQuery', () => { - generateGraphProfileQueryTests.forEach(test => { + generateGraphProfileQueryTests.forEach((test) => { it(`should be output: ${test.output} for input: ${test.input} and type: ${test.type}`, () => { - const result = generateGraphProfileQuery(test.input, test.type); - expect(result).toEqual(test.output); - }); + const result = generateGraphProfileQuery(test.input, test.type) + expect(result).toEqual(test.output) + }) }) -}); - +}) const generateSearchProfileQueryTests: Record[] = [ { input: 'FT.SEARCH index tomatoes', output: 'ft.profile index SEARCH QUERY tomatoes', type: ProfileQueryType.Profile }, @@ -44,13 +42,13 @@ const generateSearchProfileQueryTests: Record[] = [ ] describe('generateSearchProfileQuery', () => { - generateSearchProfileQueryTests.forEach(test => { + generateSearchProfileQueryTests.forEach((test) => { it(`should be output: ${test.output} for input: ${test.input} and type: ${test.type}`, () => { - const result = generateSearchProfileQuery(test.input, test.type); - expect(result).toEqual(test.output); - }); + const result = generateSearchProfileQuery(test.input, test.type) + expect(result).toEqual(test.output) + }) }) -}); +}) const generateProfileQueryForCommandTests: Record[] = [ ...generateGraphProfileQueryTests, @@ -69,11 +67,11 @@ const generateProfileQueryForCommandTests: Record[] = [ { input: 'ft.explain index tomatoes', output: null, type: ProfileQueryType.Explain }, ] describe('generateProfileQueryForCommand', () => { - generateProfileQueryForCommandTests.forEach(test => { + generateProfileQueryForCommandTests.forEach((test) => { it(`should be output: ${test.output} for input: ${test.input} and type: ${test.type}`, () => { - const result = generateProfileQueryForCommand(test.input, test.type); + const result = generateProfileQueryForCommand(test.input, test.type) - expect(result).toEqual(test.output); - }); + expect(result).toEqual(test.output) + }) }) -}); +}) diff --git a/redisinsight/ui/src/pages/workbench/utils/tests/query.spec.ts b/redisinsight/ui/src/pages/workbench/utils/tests/query.spec.ts new file mode 100644 index 0000000000..5afe4fe26b --- /dev/null +++ b/redisinsight/ui/src/pages/workbench/utils/tests/query.spec.ts @@ -0,0 +1,189 @@ +import { SearchCommand, TokenType } from 'uiSrc/pages/search/types' +import { Maybe } from 'uiSrc/utils' +import { MOCKED_REDIS_COMMANDS } from 'uiSrc/mocks/data/mocked_redis_commands' +import { IRedisCommand } from 'uiSrc/constants' +import { + commonfindCurrentArgumentCases, + findArgumentftAggreageTests, + findArgumentftSearchTests +} from './test-cases' +import { addOwnTokenToArgs, findCurrentArgument, generateDetail, splitQueryByArgs } from '../query' + +const ftSearchCommand = MOCKED_REDIS_COMMANDS['FT.SEARCH'] +const ftAggregateCommand = MOCKED_REDIS_COMMANDS['FT.AGGREGATE'] +const COMMANDS = Object.keys(MOCKED_REDIS_COMMANDS).map((name) => ({ + name, + ...MOCKED_REDIS_COMMANDS[name] +})) + +describe('findCurrentArgument', () => { + describe('with list of commands', () => { + commonfindCurrentArgumentCases.forEach(({ input, result, appendIncludes, appendNotIncludes }) => { + it(`should return proper suggestions for ${input}`, () => { + const { args } = splitQueryByArgs(input) + const COMMANDS_LIST = COMMANDS.map((command) => ({ + ...addOwnTokenToArgs(command.name!, command), + token: command.name!, + type: TokenType.Block + })) + + const testResult = findCurrentArgument( + COMMANDS_LIST, + args.flat() + ) + expect(testResult).toEqual(result) + expect( + testResult?.append?.flat()?.map((arg) => arg.token) + ).toEqual( + expect.arrayContaining(appendIncludes) + ) + + if (appendNotIncludes) { + appendNotIncludes.forEach((token) => { + expect( + testResult?.append?.flat()?.map((arg) => arg.token) + ).not.toEqual( + expect.arrayContaining([token]) + ) + }) + } + }) + }) + }) + + describe('FT.AGGREGATE', () => { + findArgumentftAggreageTests.forEach(({ args, result: testResult }) => { + it(`should return proper suggestions for ${args.join(' ')}`, () => { + const result = findCurrentArgument( + ftAggregateCommand.arguments as IRedisCommand[], + args + ) + expect(testResult).toEqual(result) + }) + }) + }) + + describe('FT.SEARCH', () => { + findArgumentftSearchTests.forEach(({ args, result: testResult }) => { + it(`should return proper suggestions for ${args.join(' ')}`, () => { + const result = findCurrentArgument( + ftSearchCommand.arguments as IRedisCommand[], + args + ) + expect(testResult).toEqual(result) + }) + }) + }) +}) + +const splitQueryByArgsTests: Array<{ + input: [string, number?] + result: any +}> = [ + { + input: ['FT.SEARCH "idx:bicycle" "" WITHSORTKEYS'], + result: { + args: [[], ['FT.SEARCH', '"idx:bicycle"', '""', 'WITHSORTKEYS']], + cursor: { + argLeftOffset: 10, + argRightOffset: 23, + isCursorInQuotes: false, + nextCursorChar: 'F', + prevCursorChar: '' + } + } + }, + { + input: ['FT.SEARCH "idx:bicycle" "" WITHSORTKEYS', 17], + result: { + args: [['FT.SEARCH'], ['"idx:bicycle"', '""', 'WITHSORTKEYS']], + cursor: { + argLeftOffset: 10, + argRightOffset: 23, + isCursorInQuotes: true, + nextCursorChar: 'c', + prevCursorChar: 'i' + } + } + }, + { + input: ['FT.SEARCH "idx:bicycle" "" WITHSORTKEYS', 39], + result: { + args: [['FT.SEARCH', '"idx:bicycle"', '""'], ['WITHSORTKEYS']], + cursor: { + argLeftOffset: 27, + argRightOffset: 39, + isCursorInQuotes: false, + nextCursorChar: '', + prevCursorChar: 'S' + } + } + }, + { + input: ['FT.SEARCH "idx:bicycle" "" WITHSORTKEYS ', 40], + result: { + args: [['FT.SEARCH', '"idx:bicycle"', '""', 'WITHSORTKEYS'], []], + cursor: { + argLeftOffset: 0, + argRightOffset: 0, + isCursorInQuotes: false, + nextCursorChar: '', + prevCursorChar: '' + } + } + }, + { + input: ['FT.SEARCH "idx:bicycle \\" \\"" "" WITHSORTKEYS ', 46], + result: { + args: [['FT.SEARCH', '"idx:bicycle " ""', '""', 'WITHSORTKEYS'], []], + cursor: { + argLeftOffset: 0, + argRightOffset: 0, + isCursorInQuotes: false, + nextCursorChar: '', + prevCursorChar: '' + } + } + } +] + +describe('splitQueryByArgs', () => { + it.each(splitQueryByArgsTests)('should return for %input proper result', ({ input, result }) => { + const testResult = splitQueryByArgs(...input) + expect(testResult).toEqual(result) + }) +}) + +const generateDetailTests: Array<{ input: Maybe, result: any }> = [ + { + input: ftSearchCommand.arguments.find(({ name }) => name === 'nocontent') as SearchCommand, + result: 'NOCONTENT' + }, + { + input: ftSearchCommand.arguments.find(({ name }) => name === 'filter') as SearchCommand, + result: 'FILTER numeric_field min max' + }, + { + input: ftSearchCommand.arguments.find(({ name }) => name === 'geo_filter') as SearchCommand, + result: 'GEOFILTER geo_field lon lat radius m | km | mi | ft' + }, + { + input: ftAggregateCommand.arguments.find(({ name }) => name === 'groupby') as SearchCommand, + result: 'GROUPBY nargs property [property ...] [REDUCE function nargs arg [arg ...] [AS name] [REDUCE function nargs arg [arg ...] [AS name] ...]]' + }, +] + +describe('generateDetail', () => { + it.each(generateDetailTests)('should return for %input proper result', ({ input, result }) => { + const testResult = generateDetail(input) + expect(testResult).toEqual(result) + }) +}) + +describe('addOwnTokenToArgs', () => { + it('should add FT.SEARCH to args', () => { + const result = addOwnTokenToArgs('FT.SEARCH', { arguments: [] }) + + expect({ arguments: [{ token: 'FT.SEARCH', type: 'pure-token' }] }).toEqual(result) + }) +}) diff --git a/redisinsight/ui/src/pages/workbench/utils/tests/test-cases/common.ts b/redisinsight/ui/src/pages/workbench/utils/tests/test-cases/common.ts new file mode 100644 index 0000000000..7946e4baa6 --- /dev/null +++ b/redisinsight/ui/src/pages/workbench/utils/tests/test-cases/common.ts @@ -0,0 +1,183 @@ +// Common test cases +export const commonfindCurrentArgumentCases = [ + { + input: 'FT.SEARCH index "" DIALECT 1', + result: { + stopArg: undefined, + append: expect.any(Array), + isBlocked: false, + isComplete: true, + parent: expect.any(Object) + }, + appendIncludes: ['WITHSCORES', 'VERBATIM', 'FILTER', 'SORTBY', 'RETURN'], + appendNotIncludes: ['DIALECT'] + }, + { + input: 'FT.AGGREGATE "idx:schools" "" GROUPBY 1 p REDUCE AVG 1 a1 AS name ', + result: { + stopArg: undefined, + append: expect.any(Array), + isBlocked: false, + isComplete: true, + parent: expect.any(Object) + }, + appendIncludes: ['REDUCE', 'APPLY', 'SORTBY', 'GROUPBY'], + appendNotIncludes: ['AS'], + }, + { + input: 'FT.SEARCH "idx:bicycle" "*" ', + result: { + stopArg: expect.any(Object), + append: expect.any(Array), + isBlocked: false, + isComplete: true, + parent: expect.any(Object) + }, + appendIncludes: ['DIALECT', 'EXPANDER', 'INKEYS', 'LIMIT'], + appendNotIncludes: ['ASC'], + }, + { + input: 'FT.SEARCH "idx:bicycle" "*" DIALECT 2', + result: expect.any(Object), + appendIncludes: ['EXPANDER', 'INKEYS', 'LIMIT'], + appendNotIncludes: ['DIALECT'], + }, + { + input: 'FT.PROFILE \'idx:schools\' SEARCH ', + result: expect.any(Object), + appendIncludes: ['LIMITED', 'QUERY'], + appendNotIncludes: ['AGGREGATE', 'SEARCH'], + }, + { + input: 'FT.CREATE "idx:schools" ', + result: expect.any(Object), + appendIncludes: ['FILTER', 'ON', 'SCHEMA', 'SCORE', 'NOHL'], + appendNotIncludes: ['HASH', 'JSON'], + }, + { + input: 'FT.CREATE "idx:schools" ON', + result: expect.any(Object), + appendIncludes: ['HASH', 'JSON'], + appendNotIncludes: ['SCHEMA', 'SCORE', 'NOHL'], + }, + { + input: 'FT.CREATE "idx:schools" ON JSON NOFREQS', + result: expect.any(Object), + appendIncludes: ['TEMPORARY', 'NOFIELDS', 'PAYLOAD_FIELD', 'MAXTEXTFIELDS', 'PREFIX', 'SKIPINITIALSCAN'], + appendNotIncludes: ['ON', 'JSON', 'NOFREQS'], + }, + { + input: 'FT.CREATE "idx:schools" ON JSON NOFREQS SKIPINITIALSCAN', + result: expect.any(Object), + appendIncludes: ['TEMPORARY', 'NOFIELDS', 'PAYLOAD_FIELD', 'MAXTEXTFIELDS', 'PREFIX'], + appendNotIncludes: ['ON', 'JSON', 'NOFREQS', 'SKIPINITIALSCAN'], + }, + { + input: 'FT.CREATE "idx:schools" ON JSON SCHEMA address ', + result: { + stopArg: expect.any(Object), + append: expect.any(Array), + isBlocked: false, + isComplete: false, + parent: expect.any(Object) + }, + appendIncludes: ['AS', 'GEO', 'TEXT', 'VECTOR'], + appendNotIncludes: ['SCHEMA', 'SCORE', 'NOHL'], + }, + { + input: 'FT.CREATE "idx:schools" ON JSON SCHEMA address TEXT NOINDEX INDEXMISSING ', + result: { + stopArg: expect.any(Object), + append: expect.any(Array), + isBlocked: false, + isComplete: true, + parent: expect.any(Object) + }, + appendIncludes: ['INDEXEMPTY', 'SORTABLE', 'WITHSUFFIXTRIE'], + appendNotIncludes: ['SCHEMA', 'SCORE', 'NOHL'], + }, + { + input: 'FT.ALTER "idx:schools" ', + result: { + stopArg: expect.any(Object), + append: expect.any(Array), + isBlocked: false, + isComplete: false, + parent: expect.any(Object) + }, + appendIncludes: ['SCHEMA', 'SKIPINITIALSCAN'], + appendNotIncludes: ['ADD'], + }, + { + input: 'FT.ALTER "idx:schools" SCHEMA', + result: expect.any(Object), + appendIncludes: ['ADD'], + appendNotIncludes: ['SKIPINITIALSCAN'], + }, + { + input: 'FT.CONFIG SET ', + result: { + stopArg: { + name: 'option', + type: 'string' + }, + append: [], + isBlocked: true, + isComplete: false, + parent: expect.any(Object) + }, + appendIncludes: [], + appendNotIncludes: [expect.any(String)], + }, + { + input: 'FT.CURSOR READ "idx:schools" 1 ', + result: expect.any(Object), + appendIncludes: ['COUNT'], + }, + { + input: 'FT.DICTADD dict term1 ', + result: { + append: [], + isBlocked: true, + isComplete: false, + parent: expect.any(Object), + stopArg: { + multiple: true, + name: 'term', + type: 'string' + } + }, + appendIncludes: [], + }, + { + input: 'FT.SUGADD key string ', + result: { + append: [], + isBlocked: true, + isComplete: false, + parent: expect.any(Object), + stopArg: { + name: 'score', + type: 'double' + } + }, + appendIncludes: [], + }, + { + input: 'FT.SUGADD key string 1.0 ', + result: expect.any(Object), + appendIncludes: ['INCR', 'PAYLOAD'], + }, + { + input: 'FT.SUGADD key string 1.0 PAYLOAD 1 ', + result: expect.any(Object), + appendIncludes: ['INCR'], + appendNotIncludes: ['PAYLOAD'], + }, + { + input: 'FT.SUGGET k p FUZZY MAX 2 ', + result: expect.any(Object), + appendIncludes: ['WITHPAYLOADS', 'WITHSCORES'], + appendNotIncludes: ['FUZZY', 'MAX'], + }, +] diff --git a/redisinsight/ui/src/pages/workbench/utils/tests/test-cases/ft-aggregate.ts b/redisinsight/ui/src/pages/workbench/utils/tests/test-cases/ft-aggregate.ts new file mode 100644 index 0000000000..e1411809a9 --- /dev/null +++ b/redisinsight/ui/src/pages/workbench/utils/tests/test-cases/ft-aggregate.ts @@ -0,0 +1,267 @@ +export const findArgumentftAggreageTests = [ + { args: [''], result: null }, + { args: ['', ''], result: null }, + { + args: ['index', '"query"', 'APPLY'], + result: { + stopArg: { name: 'expression', token: 'APPLY', type: 'string' }, + append: [], + isBlocked: true, + isComplete: false, + parent: expect.any(Object) + } + }, + { + args: ['index', '"query"', 'APPLY', 'expression'], + result: { + stopArg: { name: 'name', token: 'AS', type: 'string' }, + append: expect.any(Array), + isBlocked: false, + isComplete: false, + parent: expect.any(Object) + } + }, + { + args: ['index', '"query"', 'APPLY', 'expression', 'AS'], + result: { + stopArg: { name: 'name', token: 'AS', type: 'string' }, + append: expect.any(Array), + isBlocked: true, + isComplete: false, + parent: expect.any(Object) + } + }, + { + args: ['index', '"query"', 'APPLY', 'expression', 'AS', 'name'], + result: { + stopArg: undefined, + append: expect.any(Array), + isBlocked: false, + isComplete: true, + parent: expect.any(Object) + } + }, + { + args: ['""', '""', 'GROUPBY', '2', 'p1', 'p2', 'REDUCE', 'f'], + result: { + stopArg: { name: 'nargs', type: 'integer' }, + append: [], + isBlocked: true, + isComplete: false, + parent: expect.any(Object) + } + }, + { + args: ['""', '""', 'GROUPBY', '2', 'p1', 'p2', 'REDUCE', 'f', '0'], + result: { + stopArg: { + name: 'name', + type: 'string', + token: 'AS', + optional: true + }, + append: [ + [ + { + name: 'name', + type: 'string', + token: 'AS', + optional: true, + parent: { + name: 'reduce', + type: 'block', + optional: true, + multiple: true, + arguments: [ + { + name: 'function', + token: 'REDUCE', + type: 'string' + }, + { + name: 'nargs', + type: 'integer' + }, + { + name: 'arg', + type: 'string', + multiple: true + }, + { + name: 'name', + type: 'string', + token: 'AS', + optional: true + } + ], + parent: expect.any(Object) + } + } + ], + [ + { + name: 'function', + token: 'REDUCE', + type: 'string', + multiple: true, + optional: true, + parent: expect.any(Object) + } + ] + ], + isBlocked: false, + isComplete: true, + parent: expect.any(Object) + } + }, + { + args: ['""', '""', 'GROUPBY', '2', 'p1', 'p2', 'REDUCE', 'f', '1', 'AS', 'name'], + result: { + stopArg: undefined, + append: [ + [], + [ + { + name: 'function', + token: 'REDUCE', + type: 'string', + multiple: true, + optional: true, + parent: expect.any(Object) + } + ] + ], + isBlocked: false, + isComplete: true, + parent: expect.any(Object) + } + }, + { + args: ['index', '"query"', 'SORTBY'], + result: { + stopArg: { name: 'nargs', token: 'SORTBY', type: 'integer' }, + append: expect.any(Array), + isBlocked: true, + isComplete: false, + parent: expect.any(Object) + } + }, + { + args: ['index', '"query"', 'SORTBY', '1', 'p1'], + result: { + stopArg: { + name: 'num', + type: 'integer', + token: 'MAX', + optional: true + }, + append: [ + [ + { + name: 'num', + type: 'integer', + token: 'MAX', + optional: true, + parent: expect.any(Object) + } + ] + ], + isBlocked: false, + isComplete: true, + parent: expect.any(Object) + } + }, + { + args: ['index', '"query"', 'SORTBY', '2', 'p1', 'ASC'], + result: { + stopArg: { + name: 'num', + type: 'integer', + token: 'MAX', + optional: true + }, + append: [ + [ + { + name: 'num', + type: 'integer', + token: 'MAX', + optional: true, + parent: expect.any(Object) + } + ] + ], + isBlocked: false, + isComplete: true, + parent: expect.any(Object) + } + }, + { + args: ['index', '"query"', 'SORTBY', '0'], + result: { + stopArg: { + name: 'num', + type: 'integer', + token: 'MAX', + optional: true + }, + append: [ + [{ + name: 'num', + type: 'integer', + token: 'MAX', + optional: true, + parent: expect.any(Object) + }] + ], + isBlocked: false, + isComplete: true, + parent: expect.any(Object) + } + }, + { + args: ['index', '"query"', 'SORTBY', '2', 'p1', 'ASC', 'MAX'], + result: { + stopArg: { + name: 'num', + type: 'integer', + token: 'MAX', + optional: true + }, + append: [], + isBlocked: true, + isComplete: false, + parent: expect.any(Object) + } + }, + { + args: ['index', '"query"', 'LOAD', '4'], + result: { + stopArg: { multiple: true, name: 'field', type: 'string' }, + append: [], + isBlocked: true, + isComplete: false, + parent: expect.any(Object) + } + }, + { + args: ['index', '"query"', 'LOAD', '4', '1', '2', '3'], + result: { + stopArg: { multiple: true, name: 'field', type: 'string' }, + append: [], + isBlocked: true, + isComplete: false, + parent: expect.any(Object) + } + }, + { + args: ['index', '"query"', 'LOAD', '4', '1', '2', '3', '4'], + result: { + stopArg: undefined, + append: [[]], + isBlocked: false, + isComplete: true, + parent: expect.any(Object) + } + }, +] diff --git a/redisinsight/ui/src/pages/workbench/utils/tests/test-cases/ft-search.ts b/redisinsight/ui/src/pages/workbench/utils/tests/test-cases/ft-search.ts new file mode 100644 index 0000000000..28137bf8e9 --- /dev/null +++ b/redisinsight/ui/src/pages/workbench/utils/tests/test-cases/ft-search.ts @@ -0,0 +1,283 @@ +export const findArgumentftSearchTests = [ + { args: [''], result: null }, + { args: ['', ''], result: null }, + { + args: ['', '', 'SUMMARIZE'], + result: { + stopArg: { + name: 'fields', + type: 'block', + optional: true, + arguments: [ + { + name: 'count', + type: 'string', + token: 'FIELDS' + }, + { + name: 'field', + type: 'string', + multiple: true + } + ] + }, + append: [[ + { + name: 'count', + type: 'string', + token: 'FIELDS', + optional: true, + parent: expect.any(Object), + }, + { + name: 'num', + type: 'integer', + token: 'FRAGS', + optional: true, + parent: expect.any(Object) + }, + { + name: 'fragsize', + type: 'integer', + token: 'LEN', + optional: true, + parent: expect.any(Object) + }, + { + name: 'separator', + type: 'string', + token: 'SEPARATOR', + optional: true, + parent: expect.any(Object) + } + ]], + isBlocked: false, + isComplete: true, + parent: expect.any(Object) + } + }, + { + args: ['', '', 'SUMMARIZE', 'FIELDS'], + result: { + stopArg: { + name: 'count', + type: 'string', + token: 'FIELDS' + }, + append: [], + isBlocked: true, + isComplete: false, + parent: expect.any(Object) + } + }, + { + args: ['', '', 'SUMMARIZE', 'FIELDS', '1'], + result: { + stopArg: { + name: 'field', + type: 'string', + multiple: true + }, + append: [], + isBlocked: true, + isComplete: false, + parent: expect.any(Object) + } + }, + { + args: ['', '', 'SUMMARIZE', 'FIELDS', '1', 'f', 'FRAGS'], + result: { + stopArg: { + name: 'num', + type: 'integer', + token: 'FRAGS', + optional: true + }, + append: [], + isBlocked: true, + isComplete: false, + parent: expect.any(Object) + } + }, + { + args: ['', '', 'SUMMARIZE', 'FIELDS', '1', 'f', 'FRAGS', '10'], + result: { + stopArg: { + name: 'fragsize', + type: 'integer', + token: 'LEN', + optional: true + }, + append: [[ + { + name: 'fragsize', + type: 'integer', + token: 'LEN', + optional: true, + parent: expect.any(Object) + }, + { + name: 'separator', + type: 'string', + token: 'SEPARATOR', + optional: true, + parent: expect.any(Object) + } + ]], + isBlocked: false, + isComplete: true, + parent: expect.any(Object) + } + }, + { + args: ['', '', 'RETURN', '1', 'iden'], + result: { + stopArg: undefined, + append: [ + [] + ], + isBlocked: false, + isComplete: true, + parent: expect.any(Object) + } + }, + { + args: ['', '', 'RETURN', '2', 'iden'], + result: { + stopArg: { + name: 'property', + type: 'string', + token: 'AS', + optional: true + }, + append: [ + [ + { + name: 'property', + type: 'string', + token: 'AS', + optional: true, + parent: expect.any(Object) + } + ], + [] + ], + isBlocked: false, + isComplete: false, + parent: expect.any(Object) + } + }, + { + args: ['', '', 'RETURN', '2', 'iden', 'iden'], + result: { + stopArg: undefined, + append: [ + [] + ], + isBlocked: false, + isComplete: true, + parent: expect.any(Object) + } + }, + { + args: ['', '', 'RETURN', '3', 'iden', 'iden'], + result: { + stopArg: { + name: 'property', + type: 'string', + token: 'AS', + optional: true + }, + append: [ + [ + { + name: 'property', + type: 'string', + token: 'AS', + optional: true, + parent: expect.any(Object) + } + ], + [] + ], + isBlocked: false, + isComplete: false, + parent: expect.any(Object) + } + }, + { + args: ['', '', 'RETURN', '3', 'iden', 'iden', 'AS', 'iden2'], + result: { + stopArg: undefined, + append: [ + [] + ], + isBlocked: false, + isComplete: true, + parent: expect.any(Object) + } + }, + { + args: ['', '', 'SORTBY', 'f'], + result: { + stopArg: { + name: 'order', + type: 'oneof', + optional: true, + arguments: [ + { + name: 'asc', + type: 'pure-token', + token: 'ASC' + }, + { + name: 'desc', + type: 'pure-token', + token: 'DESC' + } + ] + }, + append: [ + [ + { + name: 'asc', + type: 'pure-token', + token: 'ASC', + parent: expect.any(Object) + }, + { + name: 'desc', + type: 'pure-token', + token: 'DESC', + parent: expect.any(Object) + } + ] + ], + isBlocked: false, + isComplete: true, + parent: expect.any(Object) + } + }, + { + args: ['', '', 'SORTBY', 'f', 'DESC'], + result: { + stopArg: undefined, + append: [], + isBlocked: false, + isComplete: true, + parent: expect.any(Object) + } + }, + { + args: ['', '', 'DIALECT', '1'], + result: { + stopArg: undefined, + append: [ + [] + ], + isBlocked: false, + isComplete: true, + parent: expect.any(Object) + } + }, +] diff --git a/redisinsight/ui/src/pages/workbench/utils/tests/test-cases/index.ts b/redisinsight/ui/src/pages/workbench/utils/tests/test-cases/index.ts new file mode 100644 index 0000000000..42889e7be5 --- /dev/null +++ b/redisinsight/ui/src/pages/workbench/utils/tests/test-cases/index.ts @@ -0,0 +1,3 @@ +export * from './ft-aggregate' +export * from './ft-search' +export * from './common' diff --git a/redisinsight/ui/src/utils/monaco/monacoInterfaces.ts b/redisinsight/ui/src/utils/monaco/monacoInterfaces.ts index e092777374..1832854dc3 100644 --- a/redisinsight/ui/src/utils/monaco/monacoInterfaces.ts +++ b/redisinsight/ui/src/utils/monaco/monacoInterfaces.ts @@ -1,9 +1,9 @@ import { monaco as monacoEditor } from 'react-monaco-editor' -import { ICommand } from 'uiSrc/constants' +import { IRedisCommand } from 'uiSrc/constants' export interface IMonacoCommand { name: string - info?: ICommand + info?: IRedisCommand position?: monacoEditor.Position } @@ -19,8 +19,8 @@ export interface IMonacoQuery { argRightOffset: number } allArgs: string[] - info?: ICommand + info?: IRedisCommand commandPosition: any position?: monacoEditor.Position - commandCursorPosition?: number + commandCursorPosition: number } diff --git a/redisinsight/ui/src/utils/transformers/redisCommands.ts b/redisinsight/ui/src/utils/transformers/redisCommands.ts new file mode 100644 index 0000000000..3dd444ff5a --- /dev/null +++ b/redisinsight/ui/src/utils/transformers/redisCommands.ts @@ -0,0 +1,12 @@ +import { ICommand, ICommands, ICommandTokenType } from 'uiSrc/constants' + +export const mergeRedisCommandsSpecs = ( + initialSpec: ICommands, + updatedSpec: ICommands +): ICommand[] => + Object.keys(initialSpec).map((name) => ({ + name, + token: name, + type: ICommandTokenType.Block, + ...(name in updatedSpec ? updatedSpec[name] : (initialSpec[name] || {})), + })) From 2e29665bf92e9c77d70bf3ed30a681f1331aa5d2 Mon Sep 17 00:00:00 2001 From: Roman Sergeenko Date: Thu, 10 Oct 2024 16:34:17 +0200 Subject: [PATCH 140/256] #RI-6151 - fix pr comments --- .../monaco-laguages/MonacoLanguages.tsx | 3 ++- .../components/query-wrapper/QueryWrapper.tsx | 4 ++-- .../search/components/query/constants.ts | 19 ------------------- .../components/query/Query/Query.tsx | 2 -- .../ui/src/pages/workbench/constants.ts | 19 ------------------- .../workbench/utils/searchSuggestions.ts | 7 ++----- .../monacoRedisMonarchTokensProvider.ts | 7 ++++--- 7 files changed, 10 insertions(+), 51 deletions(-) diff --git a/redisinsight/ui/src/components/monaco-laguages/MonacoLanguages.tsx b/redisinsight/ui/src/components/monaco-laguages/MonacoLanguages.tsx index 4d3b9563a8..568775e2d4 100644 --- a/redisinsight/ui/src/components/monaco-laguages/MonacoLanguages.tsx +++ b/redisinsight/ui/src/components/monaco-laguages/MonacoLanguages.tsx @@ -12,6 +12,7 @@ import { getRediSearchSubRedisMonarchTokensProvider } from 'uiSrc/utils/monaco/m import SEARCH_COMMANDS_SPEC from 'uiSrc/pages/workbench/data/supported_commands.json' import { mergeRedisCommandsSpecs } from 'uiSrc/utils/transformers/redisCommands' import { SearchCommandTree } from 'uiSrc/pages/search/types' +import { ModuleCommandPrefix } from 'uiSrc/pages/workbench/constants' const MonacoLanguages = () => { const { theme } = useContext(ThemeContext) @@ -44,7 +45,7 @@ const MonacoLanguages = () => { monaco.languages.setLanguageConfiguration(MonacoLanguage.Redis, redisLanguageConfig) const REDIS_COMMANDS = mergeRedisCommandsSpecs(COMMANDS_SPEC, SEARCH_COMMANDS_SPEC) as SearchCommandTree[] - const REDIS_SEARCH_COMMANDS = REDIS_COMMANDS.filter(({ name }) => name?.startsWith('FT.')) + const REDIS_SEARCH_COMMANDS = REDIS_COMMANDS.filter(({ name }) => name?.startsWith(ModuleCommandPrefix.RediSearch)) monaco.languages.setMonarchTokensProvider( MonacoLanguage.RediSearch, diff --git a/redisinsight/ui/src/pages/search/components/query-wrapper/QueryWrapper.tsx b/redisinsight/ui/src/pages/search/components/query-wrapper/QueryWrapper.tsx index 88d2b7be62..accad99537 100644 --- a/redisinsight/ui/src/pages/search/components/query-wrapper/QueryWrapper.tsx +++ b/redisinsight/ui/src/pages/search/components/query-wrapper/QueryWrapper.tsx @@ -12,8 +12,8 @@ import { appContextSearchAndQuery, setSQScript } from 'uiSrc/slices/app/context' import { sendEventTelemetry, TelemetryEvent } from 'uiSrc/telemetry' import { fetchRedisearchListAction, redisearchListSelector } from 'uiSrc/slices/browser/redisearch' import { connectedInstanceSelector } from 'uiSrc/slices/instances/instances' -import { SUPPORTED_COMMANDS_LIST } from 'uiSrc/pages/search/components/query/constants' import { SearchCommand } from 'uiSrc/pages/search/types' +import { ModuleCommandPrefix } from 'uiSrc/pages/workbench/constants' import { TUTORIALS } from './constants' import REDIS_COMMANDS_SPEC from '../constants/supported_commands.json' @@ -49,7 +49,7 @@ const QueryWrapper = (props: Props) => { (name in REDIS_COMMANDS_SPEC ? REDIS_COMMANDS_SPEC[name] : (spec[name] || {})) const SUPPORTED_COMMANDS = commandsArray - .filter((item) => item.startsWith('FT.')) + .filter((item) => item.startsWith(ModuleCommandPrefix.RediSearch)) .map((name) => ({ ...getCommandByName(name), name })) as unknown as SearchCommand[] const { instanceId } = useParams<{ instanceId: string }>() diff --git a/redisinsight/ui/src/pages/search/components/query/constants.ts b/redisinsight/ui/src/pages/search/components/query/constants.ts index e3c7be2574..6617df7940 100644 --- a/redisinsight/ui/src/pages/search/components/query/constants.ts +++ b/redisinsight/ui/src/pages/search/components/query/constants.ts @@ -12,25 +12,6 @@ export const options = merge(defaultMonacoOptions, } }) -export const SUPPORTED_COMMANDS_LIST = [ - 'FT.SEARCH', - 'FT.AGGREGATE', - 'FT.PROFILE', - 'FT.EXPLAIN', - 'FT.INFO', - 'FT._LIST', - 'FT.ALIASADD', - 'FT.ALIASDEL', - 'FT.ALIASUPDATE', - 'FT.ALTER', - 'FT.CONFIG GET', - 'FT.CONFIG SET', - 'FT.CURSOR DEL', - 'FT.CURSOR READ', - 'FT.DICTADD', - 'FT.DICTDEL', -] - export const COMMANDS_TO_GET_INDEX_INFO = [ 'FT.SEARCH', 'FT.AGGREGATE', diff --git a/redisinsight/ui/src/pages/workbench/components/query/Query/Query.tsx b/redisinsight/ui/src/pages/workbench/components/query/Query/Query.tsx index 6541e6c389..c4eb8a232d 100644 --- a/redisinsight/ui/src/pages/workbench/components/query/Query/Query.tsx +++ b/redisinsight/ui/src/pages/workbench/components/query/Query/Query.tsx @@ -574,8 +574,6 @@ const Query = (props: Props) => { { fields: attributesRef.current, indexes: indexesRef.current } ) - console.log(helpWidgetRef) - if (helpWidget) { const { isOpen, parent, currentArg } = helpWidget helpWidgetRef.current = { diff --git a/redisinsight/ui/src/pages/workbench/constants.ts b/redisinsight/ui/src/pages/workbench/constants.ts index 9f84da285f..4453342d69 100644 --- a/redisinsight/ui/src/pages/workbench/constants.ts +++ b/redisinsight/ui/src/pages/workbench/constants.ts @@ -68,25 +68,6 @@ export enum ModuleCommandPrefix { TDIGEST = 'TDIGEST.', } -export const SUPPORTED_COMMANDS_LIST = [ - 'FT.SEARCH', - 'FT.AGGREGATE', - 'FT.PROFILE', - 'FT.EXPLAIN', - 'FT.INFO', - 'FT._LIST', - 'FT.ALIASADD', - 'FT.ALIASDEL', - 'FT.ALIASUPDATE', - 'FT.ALTER', - 'FT.CONFIG GET', - 'FT.CONFIG SET', - 'FT.CURSOR DEL', - 'FT.CURSOR READ', - 'FT.DICTADD', - 'FT.DICTDEL', -] - export const COMMANDS_TO_GET_INDEX_INFO = [ 'FT.SEARCH', 'FT.AGGREGATE', diff --git a/redisinsight/ui/src/pages/workbench/utils/searchSuggestions.ts b/redisinsight/ui/src/pages/workbench/utils/searchSuggestions.ts index 91eead84fa..cc236d3a66 100644 --- a/redisinsight/ui/src/pages/workbench/utils/searchSuggestions.ts +++ b/redisinsight/ui/src/pages/workbench/utils/searchSuggestions.ts @@ -12,7 +12,7 @@ import { getIndexesSuggestions, getNoIndexesSuggestion } from 'uiSrc/pages/workbench/utils/suggestions' -import { DefinedArgumentName, FIELD_START_SYMBOL } from 'uiSrc/pages/workbench/constants' +import { DefinedArgumentName, FIELD_START_SYMBOL, ModuleCommandPrefix } from 'uiSrc/pages/workbench/constants' export const findSuggestionsByArg = ( listOfCommands: IRedisCommand[], @@ -32,9 +32,7 @@ export const findSuggestionsByArg = ( const foundArg = findCurrentArgument(listOfCommands, beforeOffsetArgs) - console.log(foundArg) - - if (!command.name.startsWith('FT.')) { + if (!command.name.startsWith(ModuleCommandPrefix.RediSearch)) { return { helpWidget: { isOpen: !!foundArg, parent: foundArg?.parent, currentArg: foundArg?.stopArg }, suggestions: asSuggestionsRef([]) @@ -56,7 +54,6 @@ export const findSuggestionsByArg = ( ) } case DefinedArgumentName.query: { - console.log('handle query') return handleQuerySuggestions(foundArg) } default: { diff --git a/redisinsight/ui/src/utils/monaco/monacoRedisMonarchTokensProvider.ts b/redisinsight/ui/src/utils/monaco/monacoRedisMonarchTokensProvider.ts index a007c4cf3c..0c4b914333 100644 --- a/redisinsight/ui/src/utils/monaco/monacoRedisMonarchTokensProvider.ts +++ b/redisinsight/ui/src/utils/monaco/monacoRedisMonarchTokensProvider.ts @@ -1,12 +1,13 @@ import { monaco as monacoEditor } from 'react-monaco-editor' import { remove } from 'lodash' -import { SearchCommand } from 'uiSrc/pages/workbench/types' +import { ModuleCommandPrefix } from 'uiSrc/pages/workbench/constants' +import { IRedisCommand } from 'uiSrc/constants' const STRING_DOUBLE = 'string.double' -export const getRedisMonarchTokensProvider = (commands: SearchCommand[]): monacoEditor.languages.IMonarchLanguage => { +export const getRedisMonarchTokensProvider = (commands: IRedisCommand[]): monacoEditor.languages.IMonarchLanguage => { const commandRedisCommands = [...commands] - const searchCommands = remove(commandRedisCommands, ({ token }) => token?.startsWith('FT.')) + const searchCommands = remove(commandRedisCommands, ({ token }) => token?.startsWith(ModuleCommandPrefix.RediSearch)) const COMMON_COMMANDS_REGEX = `(${commandRedisCommands.map(({ token }) => token).join('|')})\\b` const SEARCH_COMMANDS_REGEX = `(${searchCommands.map(({ token }) => token).join('|')})\\b` From f0bd1bbc14d75ad5ad49637f0a2bba22730d3583 Mon Sep 17 00:00:00 2001 From: Kristiyan Ivanov Date: Fri, 11 Oct 2024 11:13:32 +0300 Subject: [PATCH 141/256] Fixed tests flagged by Maria --- redisinsight/api/test/api/list/POST-databases-id-list.test.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/redisinsight/api/test/api/list/POST-databases-id-list.test.ts b/redisinsight/api/test/api/list/POST-databases-id-list.test.ts index e4aa6db890..d7c763a859 100644 --- a/redisinsight/api/test/api/list/POST-databases-id-list.test.ts +++ b/redisinsight/api/test/api/list/POST-databases-id-list.test.ts @@ -10,6 +10,7 @@ import { validateInvalidDataTestCase, validateApiCall, getMainCheckFn, } from '../deps'; +import { ListElementDestination } from 'src/modules/browser/list/dto'; const { server, request, constants, rte } = deps; // endpoint to test @@ -193,6 +194,7 @@ describe('POST /databases/:databases/list', () => { data: { keyName: constants.getRandomString(), elements: [constants.TEST_LIST_ELEMENT_1], + destination: ListElementDestination.Head, }, statusCode: 201, }, @@ -202,6 +204,7 @@ describe('POST /databases/:databases/list', () => { data: { keyName: constants.getRandomString(), elements: [constants.getRandomString()], + destination: ListElementDestination.Head, }, statusCode: 403, responseBody: { @@ -216,6 +219,7 @@ describe('POST /databases/:databases/list', () => { data: { keyName: constants.getRandomString(), elements: [constants.getRandomString()], + destination: ListElementDestination.Head, }, statusCode: 403, responseBody: { From 050fd3c757a3120a9975de47e004a44af58edf69 Mon Sep 17 00:00:00 2001 From: mariasergeenko Date: Fri, 11 Oct 2024 10:40:47 +0200 Subject: [PATCH 142/256] remove separate tab --- tests/e2e/helpers/constants.ts | 6 - .../e2e/pageObjects/base-run-commands-page.ts | 105 -------- tests/e2e/pageObjects/browser-page.ts | 2 - .../components/keys-interaction-panel.ts | 59 ----- .../components/navigation-panel.ts | 2 - .../e2e/pageObjects/search-and-query-page.ts | 20 -- tests/e2e/pageObjects/workbench-page.ts | 128 +++++++-- .../enablement-area-autoupdate.e2e.ts | 7 +- .../critical-path/monitor/monitor.e2e.ts | 4 +- .../workbench/index-schema.e2e.ts | 5 +- .../workbench/json-workbench.e2e.ts | 5 +- .../workbench/redis-stack-commands.e2e.ts | 5 +- .../workbench/workbench-re-cluster.e2e.ts | 5 +- .../critical-path/browser/bulk-delete.e2e.ts | 6 +- .../browser/search-capabilities.e2e.ts | 6 +- .../database-overview/database-index.e2e.ts | 6 +- .../database-overview.e2e.ts | 5 +- .../web/critical-path/monitor/monitor.e2e.ts | 4 +- .../pub-sub/subscribe-unsubscribe.e2e.ts | 5 +- .../workbench/autocomplete.e2e.ts | 5 +- .../workbench/command-results.e2e.ts | 5 +- .../critical-path/workbench/context.e2e.ts | 9 +- .../web/critical-path/workbench/cypher.e2e.ts | 5 +- .../workbench/default-scripts-area.e2e.ts | 5 +- .../workbench/scripting-area.e2e.ts | 5 +- .../web/regression/browser/context.e2e.ts | 6 +- .../regression/browser/key-messages.e2e.ts | 4 +- .../browser/keys-all-databases.e2e.ts | 6 +- .../web/regression/browser/onboarding.e2e.ts | 9 +- .../regression/browser/resize-columns.e2e.ts | 6 +- .../web/regression/browser/survey-link.e2e.ts | 4 +- .../cli/cli-promote-workbench.e2e.ts | 5 +- .../database-overview/database-info.e2e.ts | 4 +- .../database-overview.e2e.ts | 4 +- .../web/regression/database/github.e2e.ts | 5 +- .../insights/import-tutorials.e2e.ts | 14 +- .../insights/live-recommendations.e2e.ts | 5 +- .../insights/open-insights-panel.e2e.ts | 4 +- .../web/regression/monitor/monitor.e2e.ts | 2 +- .../search-and-query/commands-history.e2e.ts | 163 ------------ .../no-indexes-suggestions.e2e.ts | 11 +- .../search-and-query/raw-mode.e2e.ts | 69 ----- .../search-and-query-tab.e2e.ts | 245 +++++++++--------- .../regression/workbench/autocomplete.e2e.ts | 4 +- .../workbench/autoexecute-button.e2e.ts | 4 +- .../workbench/command-results.e2e.ts | 6 +- .../web/regression/workbench/context.e2e.ts | 12 +- .../web/regression/workbench/cypher.e2e.ts | 4 +- .../workbench/default-scripts-area.e2e.ts | 6 +- .../workbench/editor-cleanup.e2e.ts | 7 +- .../workbench/empty-command-history.e2e.ts | 4 +- .../regression/workbench/group-mode.e2e.ts | 4 +- .../workbench/history-of-results.e2e.ts | 4 +- .../web/regression/workbench/raw-mode.e2e.ts | 10 +- .../workbench/redis-stack-commands.e2e.ts | 4 +- .../redisearch-module-not-available.e2e.ts | 4 +- .../workbench/scripting-area.e2e.ts | 10 +- .../workbench/workbench-all-db-types.e2e.ts | 4 +- .../workbench-non-auto-guides.e2e.ts | 6 +- .../workbench/workbench-pipeline.e2e.ts | 12 +- .../regression/workbench/workbench-tab.e2e.ts | 27 -- .../web/smoke/workbench/json-workbench.e2e.ts | 4 +- .../web/smoke/workbench/scripting-area.e2e.ts | 4 +- 63 files changed, 362 insertions(+), 763 deletions(-) delete mode 100644 tests/e2e/pageObjects/base-run-commands-page.ts delete mode 100644 tests/e2e/pageObjects/components/keys-interaction-panel.ts delete mode 100644 tests/e2e/pageObjects/search-and-query-page.ts delete mode 100644 tests/e2e/tests/web/regression/search-and-query/commands-history.e2e.ts delete mode 100644 tests/e2e/tests/web/regression/search-and-query/raw-mode.e2e.ts delete mode 100644 tests/e2e/tests/web/regression/workbench/workbench-tab.e2e.ts diff --git a/tests/e2e/helpers/constants.ts b/tests/e2e/helpers/constants.ts index b1b211106d..327c0eaa90 100644 --- a/tests/e2e/helpers/constants.ts +++ b/tests/e2e/helpers/constants.ts @@ -83,12 +83,6 @@ export enum ExploreTabs { Tips = 'Tips', } -export enum KeysInteractionTabs { - BrowserAndFilter = 'Browser and filter', - SearchAndQuery = 'Search and query', - Workbench = 'Workbench' -} - export enum Compatibility { SearchAndQuery = 'search', Json = 'json', diff --git a/tests/e2e/pageObjects/base-run-commands-page.ts b/tests/e2e/pageObjects/base-run-commands-page.ts deleted file mode 100644 index d40b647560..0000000000 --- a/tests/e2e/pageObjects/base-run-commands-page.ts +++ /dev/null @@ -1,105 +0,0 @@ -import { Selector, t } from 'testcafe'; -import { InstancePage } from './instance-page'; - -export class BaseRunCommandsPage extends InstancePage { - - submitCommandButton = Selector('[data-testid=btn-submit]'); - queryInput = Selector('[data-testid=query-input-container]'); - queryInputForText = Selector('[data-testid=query-input-container] .view-lines'); - - // History containers - queryCardCommand = Selector('[data-testid=query-card-command]'); - fullScreenButton = Selector('[data-testid=toggle-full-screen]'); - rawModeBtn = Selector('[data-testid="btn-change-mode"]'); - queryCardContainer = Selector('[data-testid^=query-card-container]'); - reRunCommandButton = Selector('[data-testid=re-run-command]'); - copyBtn = Selector('[data-testid^=copy-btn-]'); - copyCommand = Selector('[data-testid=copy-command]'); - - runButtonToolTip = Selector('[data-testid=run-query-tooltip]'); - loadedCommand = Selector('[class=euiLoadingContent__singleLine]'); - runButtonSpinner = Selector('[data-testid=loading-spinner]'); - commandExecutionDateAndTime = Selector('[data-testid=command-execution-date-time]'); - executionCommandTime = Selector('[data-testid=command-execution-time-value]'); - executionCommandIcon = Selector('[data-testid=command-execution-time-icon]'); - executedCommandTitle = Selector('[data-testid=query-card-tooltip-anchor]', { timeout: 500 }); - queryResult = Selector('[data-testid=query-common-result]'); - queryInputScriptArea = Selector('[data-testid=query-input-container] .view-line'); - parametersAnchor = Selector('[data-testid=parameters-anchor]'); - - iframe = Selector('[data-testid=pluginIframe]'); - - //OPTIONS - selectViewType = Selector('[data-testid=select-view-type]'); - queryTableResult = Selector('[data-testid^=query-table-result-]'); - textViewTypeOption = Selector('[data-test-subj^=view-type-option-Text]'); - tableViewTypeOption = Selector('[data-test-subj^=view-type-option-Plugin]'); - - clearResultsBtn = Selector('[data-testid=clear-history-btn]'); - rawModeIcon = Selector('[data-testid=raw-mode-tooltip]'); - - cssQueryCardCommand = '[data-testid=query-card-command]'; - cssQueryCardContainer = '[data-testid^="query-card-container-"]'; - cssQueryTextResult = '[data-testid=query-cli-result]'; - cssReRunCommandButton = '[data-testid=re-run-command]'; - cssDeleteCommandButton = '[data-testid=delete-command]'; - cssJsonViewTypeOption = '[data-testid=view-type-selected-Plugin-client-list__json-view]'; - cssQueryTableResult = '[data-testid^=query-table-result-]'; - cssTableViewTypeOption = '[data-testid=view-type-selected-Plugin-redisearch__redisearch]'; - cssCommandExecutionDateTime = '[data-testid=command-execution-date-time]'; - - queryTextResult = Selector(this.cssQueryTextResult); - - getTutorialLinkLocator = (tutorialName: string): Selector => - Selector(`[data-testid=query-tutorials-link_${tutorialName}]`); - - /** - * Get card container by command - * @param command The command - */ - async getCardContainerByCommand(command: string): Promise { - return this.queryCardCommand.withExactText(command).parent(this.cssQueryCardContainer); - } - - /** - * Send a command in Workbench - * @param command The command - * @param speed The speed in seconds. Default is 1 - * @param paste - */ - async sendCommandInWorkbench(command: string, speed = 1, paste = true): Promise { - await t - .click(this.queryInput) - .typeText(this.queryInput, command, { replace: true, speed, paste }) - .click(this.submitCommandButton); - } - - /** - * Check the last command and result in workbench - * @param command The command to check - * @param result The result to check - * @param childNum Indicator which command result need to check - */ - async checkWorkbenchCommandResult(command: string, result: string, childNum = 0): Promise { - // Compare the command with executed command - const actualCommand = await this.queryCardContainer.nth(childNum).find(this.cssQueryCardCommand).textContent; - await t.expect(actualCommand).contains(command, 'Actual command is not equal to executed'); - // Compare the command result with executed command - const actualCommandResult = await this.queryCardContainer.nth(childNum).find(this.cssQueryTextResult).textContent; - await t.expect(actualCommandResult).contains(result, 'Actual command result is not equal to executed'); - } - - // Select Text view option in Workbench results - async selectViewTypeText(): Promise { - await t - .click(this.selectViewType) - .click(this.textViewTypeOption); - } - - // Select Table view option in Workbench results - async selectViewTypeTable(): Promise { - await t - .click(this.selectViewType) - .doubleClick(this.tableViewTypeOption); - } -} diff --git a/tests/e2e/pageObjects/browser-page.ts b/tests/e2e/pageObjects/browser-page.ts index 7d71dc8475..297bdded5f 100644 --- a/tests/e2e/pageObjects/browser-page.ts +++ b/tests/e2e/pageObjects/browser-page.ts @@ -2,12 +2,10 @@ import { t, Selector } from 'testcafe'; import { Common } from '../helpers/common'; import { InstancePage } from './instance-page'; import { BulkActions, TreeView } from './components/browser'; -import { KeysInteractionPanel } from './components/keys-interaction-panel'; export class BrowserPage extends InstancePage { BulkActions = new BulkActions(); TreeView = new TreeView(); - KeysInteractionPanel = new KeysInteractionPanel(); //CSS Selectors cssSelectorGrid = '[aria-label="grid"]'; diff --git a/tests/e2e/pageObjects/components/keys-interaction-panel.ts b/tests/e2e/pageObjects/components/keys-interaction-panel.ts deleted file mode 100644 index 6f2ef1276c..0000000000 --- a/tests/e2e/pageObjects/components/keys-interaction-panel.ts +++ /dev/null @@ -1,59 +0,0 @@ -import { Selector, t } from 'testcafe'; -import { KeysInteractionTabs } from '../../helpers/constants'; -import { WorkbenchPage } from '../workbench-page'; -import { BrowserPage } from '../browser-page'; -import { SearchAndQueryPage } from '../search-and-query-page'; - -export class KeysInteractionPanel { - // CONTAINERS - horizontalPanel = Selector('[data-testid=browser-tabs]'); - activeTab = this.horizontalPanel.find('[class*="euiTab-isSelected"]'); - - searchTab = Selector('[data-testid=browser-tab-search]'); - browserTab = Selector('[data-testid=browser-tab-browser]'); - workbenchTab = Selector('[data-testid=browser-tab-workbench]'); - - /** - * get active tab - */ - async getActiveTabName(): Promise { - return this.activeTab.textContent; - } - - /** - * Click on Panel tab - * @param type of the tab - */ - async setActiveTab(type: KeysInteractionTabs.BrowserAndFilter): Promise - async setActiveTab(type: KeysInteractionTabs.SearchAndQuery): Promise - async setActiveTab(type: KeysInteractionTabs.Workbench): Promise - async setActiveTab(type: KeysInteractionTabs): Promise { - const activeTabName = await this.getActiveTabName(); - - let tabSelector; - let pageClass; - - switch (type) { - case KeysInteractionTabs.BrowserAndFilter: - tabSelector = this.browserTab; - pageClass = BrowserPage; - break; - case KeysInteractionTabs.Workbench: - tabSelector = this.workbenchTab; - pageClass = WorkbenchPage; - break; - case KeysInteractionTabs.SearchAndQuery: - tabSelector = this.searchTab; - pageClass = SearchAndQueryPage; - break; - default: - throw new Error(`Unknown tab type: ${type}`); - } - - if (type !== activeTabName) { - await t.click(tabSelector); - } - - return new pageClass(); - } -} diff --git a/tests/e2e/pageObjects/components/navigation-panel.ts b/tests/e2e/pageObjects/components/navigation-panel.ts index bf772e7442..b4edad4b30 100644 --- a/tests/e2e/pageObjects/components/navigation-panel.ts +++ b/tests/e2e/pageObjects/components/navigation-panel.ts @@ -7,6 +7,4 @@ export class NavigationPanel extends BaseNavigationPanel{ analysisPageButton = Selector('[data-testid=analytics-page-btn]'); browserButton = Selector('[data-testid=browser-page-btn]'); pubSubButton = Selector('[data-testid=pub-sub-page-btn]'); - - triggeredFunctionsButton = Selector('[data-testid=triggered-functions-page-btn]'); } diff --git a/tests/e2e/pageObjects/search-and-query-page.ts b/tests/e2e/pageObjects/search-and-query-page.ts deleted file mode 100644 index b4fa96b8e0..0000000000 --- a/tests/e2e/pageObjects/search-and-query-page.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { t } from 'testcafe'; -import { BaseRunCommandsPage } from './base-run-commands-page'; - -export class SearchAndQueryPage extends BaseRunCommandsPage { - - /** - * Select query using autosuggest - * @param query Value of query - */ - async selectFieldUsingAutosuggest(value: string): Promise { - await t.wait(200); - await t.typeText(this.queryInput, '@', { replace: false }); - await t.expect(this.MonacoEditor.monacoSuggestion.visible).ok('Suggestions not displayed'); - await t.typeText(this.queryInput, value, { replace: false }); - // Select query option into autosuggest and go out of quotes - await t.pressKey('tab'); - await t.pressKey('right'); - await t.pressKey('space'); - } -} diff --git a/tests/e2e/pageObjects/workbench-page.ts b/tests/e2e/pageObjects/workbench-page.ts index 3d4987677d..633af2da2b 100644 --- a/tests/e2e/pageObjects/workbench-page.ts +++ b/tests/e2e/pageObjects/workbench-page.ts @@ -1,7 +1,7 @@ import { Selector, t } from 'testcafe'; -import { BaseRunCommandsPage } from './base-run-commands-page'; +import { InstancePage } from './instance-page'; -export class WorkbenchPage extends BaseRunCommandsPage { +export class WorkbenchPage extends InstancePage { //CSS selectors cssSelectorPaginationButtonPrevious = '[data-test-subj=pagination-button-previous]'; cssSelectorPaginationButtonNext = '[data-test-subj=pagination-button-next]'; @@ -11,6 +11,14 @@ export class WorkbenchPage extends BaseRunCommandsPage { cssQueryCardCommand = '[data-testid=query-card-command]'; cssRowInVirtualizedTable = '[data-testid^=row-]'; cssClientListViewTypeOption = '[data-testid=view-type-selected-Plugin-client-list__clients-list]'; + cssQueryCardContainer = '[data-testid^="query-card-container-"]'; + cssQueryTextResult = '[data-testid=query-cli-result]'; + cssReRunCommandButton = '[data-testid=re-run-command]'; + cssDeleteCommandButton = '[data-testid=delete-command]'; + cssJsonViewTypeOption = '[data-testid=view-type-selected-Plugin-client-list__json-view]'; + cssQueryTableResult = '[data-testid^=query-table-result-]'; + cssTableViewTypeOption = '[data-testid=view-type-selected-Plugin-redisearch__redisearch]'; + cssCommandExecutionDateTime = '[data-testid=command-execution-date-time]'; //------------------------------------------------------------------------------------------- //DECLARATION OF SELECTORS //*Declare all elements/components of the relevant page. @@ -18,28 +26,35 @@ export class WorkbenchPage extends BaseRunCommandsPage { //*The following categories are ordered alphabetically (Alerts, Buttons, Checkboxes, etc.). //------------------------------------------------------------------------------------------- //BUTTON + submitCommandButton = Selector('[data-testid=btn-submit]'); + queryInput = Selector('[data-testid=query-input-container]'); + queryInputForText = Selector('[data-testid=query-input-container] .view-lines'); resizeButtonForScriptingAndResults = Selector('[data-test-subj=resize-btn-scripting-area-and-results]'); - collapsePreselectAreaButton = Selector('[data-testid=collapse-enablement-area]'); - expandPreselectAreaButton = Selector('[data-testid=expand-enablement-area]'); paginationButtonPrevious = Selector(this.cssSelectorPaginationButtonPrevious); paginationButtonNext = Selector(this.cssSelectorPaginationButtonNext); - preselectIndexInformation = Selector('[data-testid="preselect-Additional index information"]'); - preselectExactSearch = Selector('[data-testid="preselect-Exact text search"]'); - preselectCreateHashIndex = Selector('[data-testid="preselect-Create a hash index"]'); - preselectGroupBy = Selector('[data-testid*=preselect-Group]'); preselectButtons = Selector('[data-testid^=preselect-]'); preselectManual = Selector('[data-testid=preselect-Manual]'); queryCardNoModuleButton = Selector('[data-testid=query-card-no-module-button] a'); - closeEnablementPage = Selector('[data-testid=enablement-area__page-close]'); groupMode = Selector('[data-testid=btn-change-group-mode]'); + runButtonToolTip = Selector('[data-testid=run-query-tooltip]'); + loadedCommand = Selector('[class=euiLoadingContent__singleLine]'); + runButtonSpinner = Selector('[data-testid=loading-spinner]'); + commandExecutionDateAndTime = Selector('[data-testid=command-execution-date-time]'); + executionCommandTime = Selector('[data-testid=command-execution-time-value]'); + executionCommandIcon = Selector('[data-testid=command-execution-time-icon]'); + executedCommandTitle = Selector('[data-testid=query-card-tooltip-anchor]', { timeout: 500 }); + queryResult = Selector('[data-testid=query-common-result]'); + queryInputScriptArea = Selector('[data-testid=query-input-container] .view-line'); + parametersAnchor = Selector('[data-testid=parameters-anchor]'); + clearResultsBtn = Selector('[data-testid=clear-history-btn]'); //ICONS noCommandHistoryIcon = Selector('[data-testid=wb_no-results__icon]'); groupModeIcon = Selector('[data-testid=group-mode-tooltip]'); silentModeIcon = Selector('[data-testid=silent-mode-tooltip]'); + rawModeIcon = Selector('[data-testid=raw-mode-tooltip]'); //TEXT ELEMENTS - queryPluginResult = Selector('[data-testid=query-plugin-result]'); responseInfo = Selector('[class="responseInfo"]'); parsedRedisReply = Selector('[class="parsedRedisReply"]'); mainEditorArea = Selector('[data-testid=main-input-container-area]'); @@ -60,6 +75,29 @@ export class WorkbenchPage extends BaseRunCommandsPage { viewTypeOptionClientList = Selector('[data-test-subj=view-type-option-Plugin-client-list__clients-list]'); viewTypeOptionsText = Selector('[data-test-subj=view-type-option-Text-default__Text]'); + // History containers + queryCardCommand = Selector('[data-testid=query-card-command]'); + fullScreenButton = Selector('[data-testid=toggle-full-screen]'); + rawModeBtn = Selector('[data-testid="btn-change-mode"]'); + queryCardContainer = Selector('[data-testid^=query-card-container]'); + reRunCommandButton = Selector('[data-testid=re-run-command]'); + copyBtn = Selector('[data-testid^=copy-btn-]'); + copyCommand = Selector('[data-testid=copy-command]'); + + //OPTIONS + selectViewType = Selector('[data-testid=select-view-type]'); + queryTableResult = Selector('[data-testid^=query-table-result-]'); + textViewTypeOption = Selector('[data-test-subj^=view-type-option-Text]'); + tableViewTypeOption = Selector('[data-test-subj^=view-type-option-Plugin]'); + + iframe = Selector('[data-testid=pluginIframe]'); + + queryTextResult = Selector(this.cssQueryTextResult); + + getTutorialLinkLocator = (tutorialName: string): Selector => + Selector(`[data-testid=query-tutorials-link_${tutorialName}]`); + + // Select view option in Workbench results async selectViewTypeGraph(): Promise { await t @@ -90,26 +128,74 @@ export class WorkbenchPage extends BaseRunCommandsPage { } } + // Select Json view option in Workbench results + async selectViewTypeJson(): Promise { + await t + .click(this.selectViewType) + .click(this.jsonStringViewTypeOption); + } /** - * Get internal tutorial link with .md name - * @param internalLink name of the .md file + * Get card container by command + * @param command The command */ - getInternalLinkWithManifest(internalLink: string): Selector { - return Selector(`[data-testid="internal-link-${internalLink}.md"]`); + async getCardContainerByCommand(command: string): Promise { + return this.queryCardCommand.withExactText(command).parent(this.cssQueryCardContainer); } /** - * Get internal tutorial link without .md name - * @param internalLink name of the label + * Send a command in Workbench + * @param command The command + * @param speed The speed in seconds. Default is 1 + * @param paste */ - getInternalLinkWithoutManifest(internalLink: string): Selector { - return Selector(`[data-testid="internal-link-${internalLink}"]`); + async sendCommandInWorkbench(command: string, speed = 1, paste = true): Promise { + await t + .click(this.queryInput) + .typeText(this.queryInput, command, { replace: true, speed, paste }) + .click(this.submitCommandButton); } - // Select Json view option in Workbench results - async selectViewTypeJson(): Promise { + /** + * Check the last command and result in workbench + * @param command The command to check + * @param result The result to check + * @param childNum Indicator which command result need to check + */ + async checkWorkbenchCommandResult(command: string, result: string, childNum = 0): Promise { + // Compare the command with executed command + const actualCommand = await this.queryCardContainer.nth(childNum).find(this.cssQueryCardCommand).textContent; + await t.expect(actualCommand).contains(command, 'Actual command is not equal to executed'); + // Compare the command result with executed command + const actualCommandResult = await this.queryCardContainer.nth(childNum).find(this.cssQueryTextResult).textContent; + await t.expect(actualCommandResult).contains(result, 'Actual command result is not equal to executed'); + } + + // Select Text view option in Workbench results + async selectViewTypeText(): Promise { await t .click(this.selectViewType) - .click(this.jsonStringViewTypeOption); + .click(this.textViewTypeOption); + } + + // Select Table view option in Workbench results + async selectViewTypeTable(): Promise { + await t + .click(this.selectViewType) + .doubleClick(this.tableViewTypeOption); + } + + /** + * Select query using autosuggest + * @param query Value of query + */ + async selectFieldUsingAutosuggest(value: string): Promise { + await t.wait(200); + await t.typeText(this.queryInput, '@', { replace: false }); + await t.expect(this.MonacoEditor.monacoSuggestion.visible).ok('Suggestions not displayed'); + await t.typeText(this.queryInput, value, { replace: false }); + // Select query option into autosuggest and go out of quotes + await t.pressKey('tab'); + await t.pressKey('right'); + await t.pressKey('space'); } } diff --git a/tests/e2e/tests/electron/critical-path/files-auto-update/enablement-area-autoupdate.e2e.ts b/tests/e2e/tests/electron/critical-path/files-auto-update/enablement-area-autoupdate.e2e.ts index dc6a29752b..673236c4e1 100644 --- a/tests/e2e/tests/electron/critical-path/files-auto-update/enablement-area-autoupdate.e2e.ts +++ b/tests/e2e/tests/electron/critical-path/files-auto-update/enablement-area-autoupdate.e2e.ts @@ -1,11 +1,9 @@ -// import { join } from 'path'; -// import * as os from 'os'; import * as fs from 'fs'; import * as editJsonFile from 'edit-json-file'; import { DatabaseHelper } from '../../../../helpers/database'; import { BrowserPage, MyRedisDatabasePage, WorkbenchPage } from '../../../../pageObjects'; import { commonUrl, ossStandaloneConfig, workingDirectory } from '../../../../helpers/conf'; -import { ExploreTabs, KeysInteractionTabs, rte } from '../../../../helpers/constants'; +import { ExploreTabs, rte } from '../../../../helpers/constants'; import { DatabaseAPIRequests } from '../../../../helpers/api/api-database'; const myRedisDatabasePage = new MyRedisDatabasePage(); @@ -47,8 +45,7 @@ if (fs.existsSync(workingDirectory)) { const tutorialsTimestampFileNew = editJsonFile(tutorialsTimestampPath); // Open Workbench page - await t.click(myRedisDatabasePage.NavigationPanel.browserButton); - await browserPage.KeysInteractionPanel.setActiveTab(KeysInteractionTabs.Workbench); + await t.click(browserPage.NavigationPanel.workbenchButton); // Check Enablement area and validate that removed file is existed in Guides await workbenchPage.NavigationHeader.togglePanel(true); diff --git a/tests/e2e/tests/electron/critical-path/monitor/monitor.e2e.ts b/tests/e2e/tests/electron/critical-path/monitor/monitor.e2e.ts index 26613c2564..2cdf3c82f9 100644 --- a/tests/e2e/tests/electron/critical-path/monitor/monitor.e2e.ts +++ b/tests/e2e/tests/electron/critical-path/monitor/monitor.e2e.ts @@ -5,7 +5,7 @@ import { BrowserPage } from '../../../../pageObjects'; import { commonUrl, ossStandaloneConfig } from '../../../../helpers/conf'; -import { KeysInteractionTabs, rte } from '../../../../helpers/constants'; +import { rte } from '../../../../helpers/constants'; import { DatabaseAPIRequests } from '../../../../helpers/api/api-database'; import { Common } from '../../../../helpers/common'; import { APIKeyRequests } from '../../../../helpers/api/api-keys'; @@ -65,7 +65,7 @@ test('Verify that user can see the list of all commands from all clients ran for await browserPage.addHashKey(keyName); await browserPage.Profiler.checkCommandInMonitorResults(browser_command); //Open Workbench page to create new client - await browserPage.KeysInteractionPanel.setActiveTab(KeysInteractionTabs.Workbench); + await t.click(browserPage.NavigationPanel.workbenchButton); //Send command in Workbench await workbenchPage.sendCommandInWorkbench(workbench_command); //Check that command from Workbench is displayed in monitor diff --git a/tests/e2e/tests/electron/critical-path/workbench/index-schema.e2e.ts b/tests/e2e/tests/electron/critical-path/workbench/index-schema.e2e.ts index 9f55e7f9f3..8e6065c04b 100644 --- a/tests/e2e/tests/electron/critical-path/workbench/index-schema.e2e.ts +++ b/tests/e2e/tests/electron/critical-path/workbench/index-schema.e2e.ts @@ -1,4 +1,4 @@ -import { KeysInteractionTabs, rte } from '../../../../helpers/constants'; +import { rte } from '../../../../helpers/constants'; import { DatabaseHelper } from '../../../../helpers/database'; import { BrowserPage, MyRedisDatabasePage, WorkbenchPage } from '../../../../pageObjects'; import { commonUrl, ossStandaloneRedisearch } from '../../../../helpers/conf'; @@ -19,8 +19,7 @@ fixture `Index Schema at Workbench` .beforeEach(async t => { await databaseHelper.acceptLicenseTermsAndAddDatabaseApi(ossStandaloneRedisearch); // Go to Workbench page - await t.click(myRedisDatabasePage.NavigationPanel.browserButton); - await browserPage.KeysInteractionPanel.setActiveTab(KeysInteractionTabs.Workbench); + await t.click(browserPage.NavigationPanel.workbenchButton); }) .afterEach(async t => { // Drop index, documents and database diff --git a/tests/e2e/tests/electron/critical-path/workbench/json-workbench.e2e.ts b/tests/e2e/tests/electron/critical-path/workbench/json-workbench.e2e.ts index f7d44417fe..cd3c0bea8a 100644 --- a/tests/e2e/tests/electron/critical-path/workbench/json-workbench.e2e.ts +++ b/tests/e2e/tests/electron/critical-path/workbench/json-workbench.e2e.ts @@ -1,4 +1,4 @@ -import { KeysInteractionTabs, rte } from '../../../../helpers/constants'; +import { rte } from '../../../../helpers/constants'; import { DatabaseHelper } from '../../../../helpers/database'; import { BrowserPage, MyRedisDatabasePage, WorkbenchPage } from '../../../../pageObjects'; import { commonUrl, ossStandaloneRedisearch } from '../../../../helpers/conf'; @@ -19,8 +19,7 @@ fixture `JSON verifications at Workbench` .beforeEach(async t => { await databaseHelper.acceptLicenseTermsAndAddDatabaseApi(ossStandaloneRedisearch); // Go to Workbench page - await t.click(myRedisDatabasePage.NavigationPanel.browserButton); - await browserPage.KeysInteractionPanel.setActiveTab(KeysInteractionTabs.Workbench); + await t.click(browserPage.NavigationPanel.workbenchButton); }) .afterEach(async t => { // Drop index, documents and database diff --git a/tests/e2e/tests/electron/regression/workbench/redis-stack-commands.e2e.ts b/tests/e2e/tests/electron/regression/workbench/redis-stack-commands.e2e.ts index a1d9923aa6..4e7ee6c634 100644 --- a/tests/e2e/tests/electron/regression/workbench/redis-stack-commands.e2e.ts +++ b/tests/e2e/tests/electron/regression/workbench/redis-stack-commands.e2e.ts @@ -2,7 +2,7 @@ import { t } from 'testcafe'; import { DatabaseHelper } from '../../../../helpers/database'; import { WorkbenchPage, MyRedisDatabasePage, BrowserPage } from '../../../../pageObjects'; import { commonUrl, ossStandaloneConfig } from '../../../../helpers/conf'; -import { ExploreTabs, KeysInteractionTabs, rte } from '../../../../helpers/constants'; +import { ExploreTabs, rte } from '../../../../helpers/constants'; import { DatabaseAPIRequests } from '../../../../helpers/api/api-database'; const myRedisDatabasePage = new MyRedisDatabasePage(); @@ -18,8 +18,7 @@ fixture `Redis Stack command in Workbench` .page(commonUrl) .beforeEach(async t => { await databaseHelper.acceptLicenseTermsAndAddDatabaseApi(ossStandaloneConfig); - await t.click(myRedisDatabasePage.NavigationPanel.browserButton); - await browserPage.KeysInteractionPanel.setActiveTab(KeysInteractionTabs.Workbench); + await t.click(browserPage.NavigationPanel.workbenchButton); }) .afterEach(async() => { // Drop key and database diff --git a/tests/e2e/tests/electron/regression/workbench/workbench-re-cluster.e2e.ts b/tests/e2e/tests/electron/regression/workbench/workbench-re-cluster.e2e.ts index b6f207a0db..985e935ad0 100644 --- a/tests/e2e/tests/electron/regression/workbench/workbench-re-cluster.e2e.ts +++ b/tests/e2e/tests/electron/regression/workbench/workbench-re-cluster.e2e.ts @@ -1,5 +1,5 @@ import { t } from 'testcafe'; -import { KeysInteractionTabs, rte } from '../../../../helpers/constants'; +import { rte } from '../../../../helpers/constants'; import { DatabaseHelper } from '../../../../helpers/database'; import { BrowserPage, MyRedisDatabasePage, WorkbenchPage } from '../../../../pageObjects'; import { commonUrl, redisEnterpriseClusterConfig } from '../../../../helpers/conf'; @@ -18,8 +18,7 @@ const verifyCommandsInWorkbench = async(): Promise => { 'FT.SEARCH idx *' ]; - await t.click(myRedisDatabasePage.NavigationPanel.browserButton); - await browserPage.KeysInteractionPanel.setActiveTab(KeysInteractionTabs.Workbench); + await t.click(browserPage.NavigationPanel.workbenchButton); // Send commands await workbenchPage.sendCommandInWorkbench(commandForSend1); await workbenchPage.sendCommandInWorkbench(commandForSend2); diff --git a/tests/e2e/tests/web/critical-path/browser/bulk-delete.e2e.ts b/tests/e2e/tests/web/critical-path/browser/bulk-delete.e2e.ts index af77a10ed5..b077e82397 100644 --- a/tests/e2e/tests/web/critical-path/browser/bulk-delete.e2e.ts +++ b/tests/e2e/tests/web/critical-path/browser/bulk-delete.e2e.ts @@ -1,4 +1,4 @@ -import { KeysInteractionTabs, KeyTypesTexts, rte } from '../../../../helpers/constants'; +import { KeyTypesTexts, rte } from '../../../../helpers/constants'; import { DatabaseHelper } from '../../../../helpers/database'; import { BrowserPage, MyRedisDatabasePage } from '../../../../pageObjects'; import { commonUrl, ossStandaloneRedisearch } from '../../../../helpers/conf'; @@ -99,9 +99,9 @@ test await t.click(browserPage.bulkActionsButton); await browserPage.BulkActions.startBulkDelete(); // Go to Workbench page - await browserPage.KeysInteractionPanel.setActiveTab(KeysInteractionTabs.Workbench); + await t.click(browserPage.NavigationPanel.workbenchButton); // Go to Browser Page - await browserPage.KeysInteractionPanel.setActiveTab(KeysInteractionTabs.BrowserAndFilter); + await t.click(browserPage.NavigationPanel.browserButton); await t.expect(browserPage.BulkActions.bulkStatusInProgress.exists).ok('Progress value not displayed', { timeout: 5000 }); }); test diff --git a/tests/e2e/tests/web/critical-path/browser/search-capabilities.e2e.ts b/tests/e2e/tests/web/critical-path/browser/search-capabilities.e2e.ts index 3aa3195286..a649a07185 100644 --- a/tests/e2e/tests/web/critical-path/browser/search-capabilities.e2e.ts +++ b/tests/e2e/tests/web/critical-path/browser/search-capabilities.e2e.ts @@ -7,7 +7,7 @@ import { ossStandaloneConfig, ossStandaloneV5Config } from '../../../../helpers/conf'; -import { KeysInteractionTabs, rte } from '../../../../helpers/constants'; +import { rte } from '../../../../helpers/constants'; import { DatabaseAPIRequests } from '../../../../helpers/api/api-database'; import { Common } from '../../../../helpers/common'; import { verifyKeysDisplayingInTheList } from '../../../../helpers/keys'; @@ -242,8 +242,8 @@ test await t.click(browserPage.getKeySelectorByName(keyName)); // Verify that Redisearch context (inputs, key selected, scroll, key details) saved after switching between pages - await browserPage.KeysInteractionPanel.setActiveTab(KeysInteractionTabs.Workbench); - await browserPage.KeysInteractionPanel.setActiveTab(KeysInteractionTabs.BrowserAndFilter); + await t.click(browserPage.NavigationPanel.workbenchButton); + await t.click(browserPage.NavigationPanel.browserButton); await verifyContext(); // Verify that Redisearch context saved when switching between browser/tree view diff --git a/tests/e2e/tests/web/critical-path/database-overview/database-index.e2e.ts b/tests/e2e/tests/web/critical-path/database-overview/database-index.e2e.ts index 59a7c860e3..3a701cea09 100644 --- a/tests/e2e/tests/web/critical-path/database-overview/database-index.e2e.ts +++ b/tests/e2e/tests/web/critical-path/database-overview/database-index.e2e.ts @@ -1,5 +1,5 @@ import { DatabaseHelper } from '../../../../helpers/database'; -import { KeysInteractionTabs, KeyTypesTexts, rte } from '../../../../helpers/constants'; +import { KeyTypesTexts, rte } from '../../../../helpers/constants'; import { Common } from '../../../../helpers/common'; import { MyRedisDatabasePage, @@ -105,13 +105,13 @@ test('Switching between indexed databases', async t => { await verifySearchFilterValue('Hall School'); // Open Workbench page - await browserPage.KeysInteractionPanel.setActiveTab(KeysInteractionTabs.Workbench); + await t.click(browserPage.NavigationPanel.workbenchButton); await workbenchPage.sendCommandInWorkbench(command); // Verify that user can see the database index before the command name executed in Workbench await workbenchPage.checkWorkbenchCommandResult(`[db1] ${command}`, '8'); // Open Browser page - await browserPage.KeysInteractionPanel.setActiveTab(KeysInteractionTabs.SearchAndQuery); + await t.click(browserPage.NavigationPanel.browserButton); // Clear filter await t.click(browserPage.clearFilterButton); // Verify that data changed for indexed db on Workbench page (on Search capability page) diff --git a/tests/e2e/tests/web/critical-path/database-overview/database-overview.e2e.ts b/tests/e2e/tests/web/critical-path/database-overview/database-overview.e2e.ts index 53d84c7d95..19ac32068a 100644 --- a/tests/e2e/tests/web/critical-path/database-overview/database-overview.e2e.ts +++ b/tests/e2e/tests/web/critical-path/database-overview/database-overview.e2e.ts @@ -1,6 +1,6 @@ import { Chance } from 'chance'; import { DatabaseHelper } from '../../../../helpers/database'; -import { ExploreTabs, KeysInteractionTabs, rte } from '../../../../helpers/constants'; +import { ExploreTabs, rte } from '../../../../helpers/constants'; import { Common } from '../../../../helpers/common'; import { MyRedisDatabasePage, @@ -145,8 +145,7 @@ test }) .after(async t => { //Delete database and index - await t.click(myRedisDatabasePage.NavigationPanel.browserButton); - await browserPage.KeysInteractionPanel.setActiveTab(KeysInteractionTabs.Workbench); + await t.click(browserPage.NavigationPanel.workbenchButton); await workbenchPage.sendCommandInWorkbench('FT.DROPINDEX idx:schools DD'); await databaseAPIRequests.deleteStandaloneDatabaseApi(ossStandaloneBigConfig); })('Verify that user can see additional information in Overview: Connected Clients, Commands/Sec, CPU (%) using Standalone DB connection type', async t => { diff --git a/tests/e2e/tests/web/critical-path/monitor/monitor.e2e.ts b/tests/e2e/tests/web/critical-path/monitor/monitor.e2e.ts index 24895ef253..766baed5d1 100644 --- a/tests/e2e/tests/web/critical-path/monitor/monitor.e2e.ts +++ b/tests/e2e/tests/web/critical-path/monitor/monitor.e2e.ts @@ -5,7 +5,7 @@ import { BrowserPage } from '../../../../pageObjects'; import { commonUrl, ossStandaloneConfig } from '../../../../helpers/conf'; -import { KeysInteractionTabs, rte } from '../../../../helpers/constants'; +import { rte } from '../../../../helpers/constants'; import { DatabaseAPIRequests } from '../../../../helpers/api/api-database'; import { Common } from '../../../../helpers/common'; import { APIKeyRequests } from '../../../../helpers/api/api-keys'; @@ -64,7 +64,7 @@ test('Verify that user can see the list of all commands from all clients ran for await browserPage.addHashKey(keyName); await browserPage.Profiler.checkCommandInMonitorResults(browser_command); //Open Workbench page to create new client - await browserPage.KeysInteractionPanel.setActiveTab(KeysInteractionTabs.Workbench); + await t.click(browserPage.NavigationPanel.workbenchButton); //Send command in Workbench await workbenchPage.sendCommandInWorkbench(workbench_command); //Check that command from Workbench is displayed in monitor diff --git a/tests/e2e/tests/web/critical-path/pub-sub/subscribe-unsubscribe.e2e.ts b/tests/e2e/tests/web/critical-path/pub-sub/subscribe-unsubscribe.e2e.ts index 74b3bdc5a2..450e698f1b 100644 --- a/tests/e2e/tests/web/critical-path/pub-sub/subscribe-unsubscribe.e2e.ts +++ b/tests/e2e/tests/web/critical-path/pub-sub/subscribe-unsubscribe.e2e.ts @@ -1,7 +1,7 @@ import { DatabaseHelper } from '../../../../helpers/database'; import { BrowserPage, MyRedisDatabasePage, PubSubPage, WorkbenchPage } from '../../../../pageObjects'; import { commonUrl, ossStandaloneConfig, ossStandaloneV5Config } from '../../../../helpers/conf'; -import { KeysInteractionTabs, rte } from '../../../../helpers/constants'; +import { rte } from '../../../../helpers/constants'; import { verifyMessageDisplayingInPubSub } from '../../../../helpers/pub-sub'; import { DatabaseAPIRequests } from '../../../../helpers/api/api-database'; @@ -121,8 +121,7 @@ test('Verify that user can see a internal link to pubsub window under word “Pu await t.expect(pubSubPage.pubSubPageContainer.exists).ok('Pubsub page is opened'); // Verify that user can see a custom message when he tries to run SUBSCRIBE command in Workbench: “Use Pub/Sub tool to subscribe to channels.” - await t.click(pubSubPage.NavigationPanel.browserButton); - await browserPage.KeysInteractionPanel.setActiveTab(KeysInteractionTabs.Workbench); + await t.click(browserPage.NavigationPanel.workbenchButton); await workbenchPage.sendCommandInWorkbench(commandSecond); await t.expect(await workbenchPage.queryResult.textContent).eql('Use Pub/Sub tool to subscribe to channels.', 'Message is not displayed', { timeout: 10000 }); diff --git a/tests/e2e/tests/web/critical-path/workbench/autocomplete.e2e.ts b/tests/e2e/tests/web/critical-path/workbench/autocomplete.e2e.ts index 6bcb31367c..31968f0f40 100644 --- a/tests/e2e/tests/web/critical-path/workbench/autocomplete.e2e.ts +++ b/tests/e2e/tests/web/critical-path/workbench/autocomplete.e2e.ts @@ -1,4 +1,4 @@ -import { KeysInteractionTabs, rte } from '../../../../helpers/constants'; +import { rte } from '../../../../helpers/constants'; import { DatabaseHelper } from '../../../../helpers/database'; import { BrowserPage, MyRedisDatabasePage, WorkbenchPage } from '../../../../pageObjects'; import { commonUrl, ossStandaloneConfig } from '../../../../helpers/conf'; @@ -16,8 +16,7 @@ fixture `Autocomplete for entered commands` .beforeEach(async t => { await databaseHelper.acceptLicenseTermsAndAddDatabaseApi(ossStandaloneConfig); // Go to Workbench page - await t.click(myRedisDatabasePage.NavigationPanel.browserButton); - await browserPage.KeysInteractionPanel.setActiveTab(KeysInteractionTabs.Workbench); + await t.click(browserPage.NavigationPanel.workbenchButton); }) .afterEach(async() => { // Delete database diff --git a/tests/e2e/tests/web/critical-path/workbench/command-results.e2e.ts b/tests/e2e/tests/web/critical-path/workbench/command-results.e2e.ts index bb954b91b1..2bcd079210 100644 --- a/tests/e2e/tests/web/critical-path/workbench/command-results.e2e.ts +++ b/tests/e2e/tests/web/critical-path/workbench/command-results.e2e.ts @@ -1,4 +1,4 @@ -import { KeysInteractionTabs, rte } from '../../../../helpers/constants'; +import { rte } from '../../../../helpers/constants'; import { DatabaseHelper } from '../../../../helpers/database'; import { BrowserPage, MyRedisDatabasePage, WorkbenchPage } from '../../../../pageObjects'; import { commonUrl, ossStandaloneConfig } from '../../../../helpers/conf'; @@ -21,8 +21,7 @@ fixture `Command results at Workbench` .beforeEach(async t => { await databaseHelper.acceptLicenseTermsAndAddDatabaseApi(ossStandaloneConfig); // Go to Workbench page - await t.click(myRedisDatabasePage.NavigationPanel.browserButton); - await browserPage.KeysInteractionPanel.setActiveTab(KeysInteractionTabs.Workbench); + await t.click(browserPage.NavigationPanel.workbenchButton); }) .afterEach(async t => { await t.switchToMainWindow(); diff --git a/tests/e2e/tests/web/critical-path/workbench/context.e2e.ts b/tests/e2e/tests/web/critical-path/workbench/context.e2e.ts index 10038dd65c..5a638cb0e9 100644 --- a/tests/e2e/tests/web/critical-path/workbench/context.e2e.ts +++ b/tests/e2e/tests/web/critical-path/workbench/context.e2e.ts @@ -1,4 +1,4 @@ -import { KeysInteractionTabs, rte } from '../../../../helpers/constants'; +import { rte } from '../../../../helpers/constants'; import { DatabaseHelper } from '../../../../helpers/database'; import { BrowserPage, MyRedisDatabasePage, WorkbenchPage } from '../../../../pageObjects'; import { commonUrl, ossStandaloneConfig } from '../../../../helpers/conf'; @@ -20,8 +20,7 @@ fixture `Workbench Context` .beforeEach(async t => { await databaseHelper.acceptLicenseTermsAndAddDatabaseApi(ossStandaloneConfig); // Go to Workbench page - await t.click(myRedisDatabasePage.NavigationPanel.browserButton); - await browserPage.KeysInteractionPanel.setActiveTab(KeysInteractionTabs.Workbench); + await t.click(browserPage.NavigationPanel.workbenchButton); }) .afterEach(async() => { // Drop index, documents and database @@ -33,8 +32,8 @@ test('Verify that user can see saved input in Editor when navigates away to any const command = `FT.CREATE ${indexName} ON HASH PREFIX 1 product: SCHEMA name TEXT`; // Enter the command in the Workbench editor and navigate to Browser await t.typeText(workbenchPage.queryInput, command, { replace: true, speed: speed }); - await browserPage.KeysInteractionPanel.setActiveTab(KeysInteractionTabs.BrowserAndFilter); + await t.click(browserPage.NavigationPanel.browserButton); // Return back to Workbench and check input in editor - await browserPage.KeysInteractionPanel.setActiveTab(KeysInteractionTabs.Workbench); + await t.click(browserPage.NavigationPanel.workbenchButton); await t.expect((await workbenchPage.queryInputScriptArea.textContent).replace(/\s/g, ' ')).eql(command, 'Input in Editor is saved'); }); diff --git a/tests/e2e/tests/web/critical-path/workbench/cypher.e2e.ts b/tests/e2e/tests/web/critical-path/workbench/cypher.e2e.ts index 1dc48e7762..b572a05ed8 100644 --- a/tests/e2e/tests/web/critical-path/workbench/cypher.e2e.ts +++ b/tests/e2e/tests/web/critical-path/workbench/cypher.e2e.ts @@ -1,4 +1,4 @@ -import { KeysInteractionTabs, rte } from '../../../../helpers/constants'; +import { rte } from '../../../../helpers/constants'; import { DatabaseHelper } from '../../../../helpers/database'; import { BrowserPage, MyRedisDatabasePage, WorkbenchPage } from '../../../../pageObjects'; import { commonUrl, ossStandaloneConfig } from '../../../../helpers/conf'; @@ -16,8 +16,7 @@ fixture `Cypher syntax at Workbench` .beforeEach(async t => { await databaseHelper.acceptLicenseTermsAndAddDatabaseApi(ossStandaloneConfig); // Go to Workbench page - await t.click(myRedisDatabasePage.NavigationPanel.browserButton); - await browserPage.KeysInteractionPanel.setActiveTab(KeysInteractionTabs.Workbench); + await t.click(browserPage.NavigationPanel.workbenchButton); }) .afterEach(async() => { // Drop database diff --git a/tests/e2e/tests/web/critical-path/workbench/default-scripts-area.e2e.ts b/tests/e2e/tests/web/critical-path/workbench/default-scripts-area.e2e.ts index f994002218..89deed9dc1 100644 --- a/tests/e2e/tests/web/critical-path/workbench/default-scripts-area.e2e.ts +++ b/tests/e2e/tests/web/critical-path/workbench/default-scripts-area.e2e.ts @@ -1,7 +1,7 @@ import { Chance } from 'chance'; import { DatabaseHelper } from '../../../../helpers/database'; import { BrowserPage, MyRedisDatabasePage, WorkbenchPage } from '../../../../pageObjects'; -import { ExploreTabs, KeysInteractionTabs, rte } from '../../../../helpers/constants'; +import { ExploreTabs, rte } from '../../../../helpers/constants'; import { commonUrl, ossStandaloneRedisearch } from '../../../../helpers/conf'; import { DatabaseAPIRequests } from '../../../../helpers/api/api-database'; import { Telemetry } from '../../../../helpers/telemetry'; @@ -31,8 +31,7 @@ fixture `Default scripts area at Workbench` .beforeEach(async t => { await databaseHelper.acceptLicenseTermsAndAddDatabaseApi(ossStandaloneRedisearch); // Go to Workbench page - await t.click(myRedisDatabasePage.NavigationPanel.browserButton); - await browserPage.KeysInteractionPanel.setActiveTab(KeysInteractionTabs.Workbench); + await t.click(browserPage.NavigationPanel.workbenchButton); }) .afterEach(async t => { // Drop index, documents and database diff --git a/tests/e2e/tests/web/critical-path/workbench/scripting-area.e2e.ts b/tests/e2e/tests/web/critical-path/workbench/scripting-area.e2e.ts index 1374c4a9f3..ea74348a0a 100644 --- a/tests/e2e/tests/web/critical-path/workbench/scripting-area.e2e.ts +++ b/tests/e2e/tests/web/critical-path/workbench/scripting-area.e2e.ts @@ -1,4 +1,4 @@ -import { KeysInteractionTabs, rte } from '../../../../helpers/constants'; +import { rte } from '../../../../helpers/constants'; import { DatabaseHelper } from '../../../../helpers/database'; import { BrowserPage, MyRedisDatabasePage, WorkbenchPage } from '../../../../pageObjects'; import { commonUrl, ossStandaloneConfig } from '../../../../helpers/conf'; @@ -20,8 +20,7 @@ fixture `Scripting area at Workbench` .beforeEach(async t => { await databaseHelper.acceptLicenseTermsAndAddDatabaseApi(ossStandaloneConfig); //Go to Workbench page - await t.click(myRedisDatabasePage.NavigationPanel.browserButton); - await browserPage.KeysInteractionPanel.setActiveTab(KeysInteractionTabs.Workbench); + await t.click(browserPage.NavigationPanel.workbenchButton); }) .afterEach(async t => { await t.switchToMainWindow(); diff --git a/tests/e2e/tests/web/regression/browser/context.e2e.ts b/tests/e2e/tests/web/regression/browser/context.e2e.ts index 13e11ab855..84b983ae52 100644 --- a/tests/e2e/tests/web/regression/browser/context.e2e.ts +++ b/tests/e2e/tests/web/regression/browser/context.e2e.ts @@ -3,7 +3,7 @@ import { MyRedisDatabasePage, BrowserPage } from '../../../../pageObjects'; -import { KeysInteractionTabs, rte } from '../../../../helpers/constants'; +import { rte } from '../../../../helpers/constants'; import { commonUrl, ossStandaloneConfig } from '../../../../helpers/conf'; import { DatabaseAPIRequests } from '../../../../helpers/api/api-database'; import { Common } from '../../../../helpers/common'; @@ -53,9 +53,9 @@ test('Verify that when user reload the window with saved context(on any page), c // Create context modificaions and navigate to Workbench await browserPage.addStringKey(keyName); await browserPage.openKeyDetails(keyName); - await browserPage.KeysInteractionPanel.setActiveTab(KeysInteractionTabs.Workbench); + await t.click(browserPage.NavigationPanel.workbenchButton); // Open Browser page and verify context - await browserPage.KeysInteractionPanel.setActiveTab(KeysInteractionTabs.BrowserAndFilter); + await t.click(browserPage.NavigationPanel.browserButton); await verifySearchFilterValue(keyName); await t.expect(browserPage.keyNameFormDetails.withExactText(keyName).exists).ok('The key details is not selected'); // Navigate to Workbench and reload the window diff --git a/tests/e2e/tests/web/regression/browser/key-messages.e2e.ts b/tests/e2e/tests/web/regression/browser/key-messages.e2e.ts index 867b8c6b86..6ea552e431 100644 --- a/tests/e2e/tests/web/regression/browser/key-messages.e2e.ts +++ b/tests/e2e/tests/web/regression/browser/key-messages.e2e.ts @@ -1,4 +1,4 @@ -import { KeysInteractionTabs, rte } from '../../../../helpers/constants'; +import { rte } from '../../../../helpers/constants'; import { DatabaseHelper } from '../../../../helpers/database'; import { BrowserPage, MyRedisDatabasePage, WorkbenchPage } from '../../../../pageObjects'; import { commonUrl, ossStandaloneConfig } from '../../../../helpers/conf'; @@ -62,7 +62,7 @@ test('Verify that user can see link to Workbench under word “Workbench” in t // Add key and verify Workbench link await browserPage.Cli.sendCommandInCli(commands[i]); - await browserPage.KeysInteractionPanel.setActiveTab(KeysInteractionTabs.BrowserAndFilter); + await t.click(browserPage.NavigationPanel.browserButton); await browserPage.searchByKeyName(keyName); await t.click(browserPage.keyNameInTheList); await t.click(browserPage.internalLinkToWorkbench); diff --git a/tests/e2e/tests/web/regression/browser/keys-all-databases.e2e.ts b/tests/e2e/tests/web/regression/browser/keys-all-databases.e2e.ts index c0767b9456..182f558bb8 100644 --- a/tests/e2e/tests/web/regression/browser/keys-all-databases.e2e.ts +++ b/tests/e2e/tests/web/regression/browser/keys-all-databases.e2e.ts @@ -1,5 +1,5 @@ import { Selector, t } from 'testcafe'; -import { KeysInteractionTabs, rte } from '../../../../helpers/constants'; +import { rte } from '../../../../helpers/constants'; import { DatabaseHelper } from '../../../../helpers/database'; import { BrowserPage, MyRedisDatabasePage } from '../../../../pageObjects'; import { @@ -108,9 +108,9 @@ test await browserActions.verifyAllRenderedKeysHasText(); // Go to Workbench page - await browserPage.KeysInteractionPanel.setActiveTab(KeysInteractionTabs.Workbench); + await t.click(browserPage.NavigationPanel.workbenchButton); // Go to Browser Page - await browserPage.KeysInteractionPanel.setActiveTab(KeysInteractionTabs.BrowserAndFilter); + await t.click(browserPage.NavigationPanel.browserButton); // Verify that keys info in row not empty after switching between pages await browserActions.verifyAllRenderedKeysHasText(); }); diff --git a/tests/e2e/tests/web/regression/browser/onboarding.e2e.ts b/tests/e2e/tests/web/regression/browser/onboarding.e2e.ts index a38078a197..3d1a270a48 100644 --- a/tests/e2e/tests/web/regression/browser/onboarding.e2e.ts +++ b/tests/e2e/tests/web/regression/browser/onboarding.e2e.ts @@ -2,7 +2,7 @@ import { DatabaseHelper } from '../../../../helpers/database'; import { commonUrl, ossStandaloneConfigEmpty } from '../../../../helpers/conf'; -import { KeysInteractionTabs, rte } from '../../../../helpers/constants'; +import { rte } from '../../../../helpers/constants'; import { Common } from '../../../../helpers/common'; import { MemoryEfficiencyPage, @@ -132,12 +132,12 @@ test('Verify onboard new user skip tour', async(t) => { await onboardingCardsDialog.clickNextStep(); // verify tree view step is visible await onboardingCardsDialog.verifyStepVisible('Tree view'); - await browserPage.KeysInteractionPanel.setActiveTab(KeysInteractionTabs.Workbench); + await t.click(browserPage.NavigationPanel.workbenchButton); await t.click(myRedisDatabasePage.NavigationPanel.helpCenterButton); await t.expect(myRedisDatabasePage.NavigationPanel.HelpCenter.helpCenterPanel.visible).ok('help center panel is not opened'); await t.click(onboardingCardsDialog.resetOnboardingBtn); await t.click(myRedisDatabasePage.NavigationPanel.browserButton); - await browserPage.KeysInteractionPanel.setActiveTab(KeysInteractionTabs.BrowserAndFilter); + await t.click(browserPage.NavigationPanel.browserButton); // Verify that when user reset onboarding, user can see the onboarding triggered when user open the Browser page. await t.expect(onboardingCardsDialog.showMeAroundButton.visible).ok('onboarding starting is not visible'); // click skip tour @@ -160,7 +160,7 @@ test.requestHooks(logger)('Verify that the final onboarding step is closed when await onboardingCardsDialog.verifyStepVisible('Great job!'); // Go to Workbench page await t.click(myRedisDatabasePage.NavigationPanel.browserButton); - await browserPage.KeysInteractionPanel.setActiveTab(KeysInteractionTabs.Workbench); + await t.click(browserPage.NavigationPanel.workbenchButton); // Verify that “ONBOARDING_TOUR_FINISHED” event is sent when user opens another page (or close the app) await telemetry.verifyEventHasProperties(telemetryEvent, expectedProperties, logger); @@ -172,7 +172,6 @@ test.requestHooks(logger)('Verify that the final onboarding step is closed when await t.expect(onboardingCardsDialog.stepTitle.exists).notOk('Onboarding tooltip still visible'); // Go to Browser Page await t.click(myRedisDatabasePage.NavigationPanel.browserButton); - await browserPage.KeysInteractionPanel.setActiveTab(KeysInteractionTabs.BrowserAndFilter); // Verify onboarding completed successfully await onboardingCardsDialog.completeOnboarding(); await t.expect(browserPage.patternModeBtn.visible).ok('Browser page is not opened'); diff --git a/tests/e2e/tests/web/regression/browser/resize-columns.e2e.ts b/tests/e2e/tests/web/regression/browser/resize-columns.e2e.ts index 446c4b45a6..ffdec4b48e 100644 --- a/tests/e2e/tests/web/regression/browser/resize-columns.e2e.ts +++ b/tests/e2e/tests/web/regression/browser/resize-columns.e2e.ts @@ -3,7 +3,7 @@ import { MyRedisDatabasePage, BrowserPage } from '../../../../pageObjects'; -import { KeysInteractionTabs, rte } from '../../../../helpers/constants'; +import { rte } from '../../../../helpers/constants'; import { commonUrl, ossStandaloneConfig } from '../../../../helpers/conf'; import { DatabaseAPIRequests } from '../../../../helpers/api/api-database'; import { Common } from '../../../../helpers/common'; @@ -80,8 +80,8 @@ test('Resize of columns in Hash, List, Zset Key details', async t => { } // Verify that resize saved when switching between pages - await browserPage.KeysInteractionPanel.setActiveTab(KeysInteractionTabs.Workbench); - await browserPage.KeysInteractionPanel.setActiveTab(KeysInteractionTabs.BrowserAndFilter); + await t.click(browserPage.NavigationPanel.workbenchButton); + await t.click(browserPage.NavigationPanel.browserButton); await browserPage.openKeyDetails(keys[0].name); await t.expect(field.clientWidth).within(keys[0].fieldWidthEnd - 5, keys[0].fieldWidthEnd + 5, 'Resize context not saved for key when switching between pages'); diff --git a/tests/e2e/tests/web/regression/browser/survey-link.e2e.ts b/tests/e2e/tests/web/regression/browser/survey-link.e2e.ts index 84471aae6e..e89ee99259 100644 --- a/tests/e2e/tests/web/regression/browser/survey-link.e2e.ts +++ b/tests/e2e/tests/web/regression/browser/survey-link.e2e.ts @@ -1,5 +1,5 @@ import { DatabaseHelper } from '../../../../helpers/database'; -import { KeysInteractionTabs, rte } from '../../../../helpers/constants'; +import { rte } from '../../../../helpers/constants'; import { BrowserPage, MyRedisDatabasePage } from '../../../../pageObjects'; import { commonUrl, ossStandaloneConfig } from '../../../../helpers/conf'; import { DatabaseAPIRequests } from '../../../../helpers/api/api-database'; @@ -32,7 +32,7 @@ test('Verify that user can use survey link', async t => { // await Common.checkURL(externalPageLink); // await goBackHistory(); // Workbench page - await browserPage.KeysInteractionPanel.setActiveTab(KeysInteractionTabs.Workbench); + await t.click(browserPage.NavigationPanel.workbenchButton); await t.expect(browserPage.userSurveyLink.visible).ok('Survey Link is not displayed'); // Slow Log page await t.click(myRedisDatabasePage.NavigationPanel.analysisPageButton); diff --git a/tests/e2e/tests/web/regression/cli/cli-promote-workbench.e2e.ts b/tests/e2e/tests/web/regression/cli/cli-promote-workbench.e2e.ts index 30be6c7e77..cc0b7a428b 100644 --- a/tests/e2e/tests/web/regression/cli/cli-promote-workbench.e2e.ts +++ b/tests/e2e/tests/web/regression/cli/cli-promote-workbench.e2e.ts @@ -1,7 +1,7 @@ import { DatabaseHelper } from '../../../../helpers/database'; import { WorkbenchPage, MyRedisDatabasePage, BrowserPage } from '../../../../pageObjects'; import { commonUrl, ossStandaloneConfig } from '../../../../helpers/conf'; -import { KeysInteractionTabs, rte } from '../../../../helpers/constants'; +import { rte } from '../../../../helpers/constants'; import { DatabaseAPIRequests } from '../../../../helpers/api/api-database'; const browserPage = new BrowserPage(); @@ -22,8 +22,7 @@ fixture `Promote workbench in CLI` }); test('Verify that user can see saved workbench context after redirection from CLI to workbench', async t => { // Open Workbench - await t.click(myRedisDatabasePage.NavigationPanel.browserButton); - await browserPage.KeysInteractionPanel.setActiveTab(KeysInteractionTabs.Workbench); + await t.click(browserPage.NavigationPanel.workbenchButton); const command = 'INFO'; await t.typeText(workbenchPage.queryInput, command, { replace: true, speed: 1, paste: true }); await t.click(myRedisDatabasePage.NavigationPanel.browserButton); diff --git a/tests/e2e/tests/web/regression/database-overview/database-info.e2e.ts b/tests/e2e/tests/web/regression/database-overview/database-info.e2e.ts index 522babd78a..d691abc7b1 100644 --- a/tests/e2e/tests/web/regression/database-overview/database-info.e2e.ts +++ b/tests/e2e/tests/web/regression/database-overview/database-info.e2e.ts @@ -4,7 +4,7 @@ import { WorkbenchPage, BrowserPage } from '../../../../pageObjects'; -import { KeysInteractionTabs, rte } from '../../../../helpers/constants'; +import { rte } from '../../../../helpers/constants'; import { commonUrl, ossStandaloneConfig } from '../../../../helpers/conf'; import { DatabaseAPIRequests } from '../../../../helpers/api/api-database'; @@ -41,6 +41,6 @@ test('Verify that user can see DB name, endpoint, connection type, Redis version // Verify that user can see an (i) icon next to the database name on Browser and Workbench pages await t.expect(browserPage.OverviewPanel.databaseInfoIcon.visible).ok('User can not see (i) icon on Browser page', { timeout: 10000 }); // Move to the Workbench page and check icon - await browserPage.KeysInteractionPanel.setActiveTab(KeysInteractionTabs.Workbench); + await t.click(browserPage.NavigationPanel.workbenchButton); await t.expect(workbenchPage.OverviewPanel.overviewTotalMemory.visible).ok('User can not see (i) icon on Workbench page', { timeout: 10000 }); }); diff --git a/tests/e2e/tests/web/regression/database-overview/database-overview.e2e.ts b/tests/e2e/tests/web/regression/database-overview/database-overview.e2e.ts index a09cc88a66..919691ce06 100644 --- a/tests/e2e/tests/web/regression/database-overview/database-overview.e2e.ts +++ b/tests/e2e/tests/web/regression/database-overview/database-overview.e2e.ts @@ -4,7 +4,7 @@ import { WorkbenchPage, BrowserPage } from '../../../../pageObjects'; -import { KeysInteractionTabs, rte } from '../../../../helpers/constants'; +import { rte } from '../../../../helpers/constants'; import { commonUrl, ossStandaloneConfig } from '../../../../helpers/conf'; import { Common } from '../../../../helpers/common'; import { DatabaseAPIRequests } from '../../../../helpers/api/api-database'; @@ -35,7 +35,7 @@ test('Verify that user can connect to DB and see breadcrumbs at the top of the a // Verify that user can see breadcrumbs in Browser and Workbench views await t.expect(browserPage.breadcrumbsContainer.visible).ok('User can not see breadcrumbs in Browser page', { timeout: 10000 }); - await browserPage.KeysInteractionPanel.setActiveTab(KeysInteractionTabs.Workbench); + await t.click(browserPage.NavigationPanel.workbenchButton); await t.expect(browserPage.breadcrumbsContainer.visible).ok('User can not see breadcrumbs in Workbench page', { timeout: 10000 }); // Verify that user can see total memory and total number of keys updated in DB header in Workbench page diff --git a/tests/e2e/tests/web/regression/database/github.e2e.ts b/tests/e2e/tests/web/regression/database/github.e2e.ts index d1e5c008d2..c8ef0c3575 100644 --- a/tests/e2e/tests/web/regression/database/github.e2e.ts +++ b/tests/e2e/tests/web/regression/database/github.e2e.ts @@ -1,4 +1,4 @@ -import { KeysInteractionTabs, rte } from '../../../../helpers/constants'; +import { rte } from '../../../../helpers/constants'; import { DatabaseHelper } from '../../../../helpers/database'; import { BrowserPage, MyRedisDatabasePage } from '../../../../pageObjects'; import { commonUrl, ossStandaloneConfig } from '../../../../helpers/conf'; @@ -29,8 +29,7 @@ test('Verify that user can work with Github link in the application', async t => await myRedisDatabasePage.clickOnDBByName(ossStandaloneConfig.databaseName); await t.expect(myRedisDatabasePage.NavigationPanel.githubButton.visible).ok('Github button not found'); // Verify that user can see the icon for GitHub reference at the bottom of the left side bar on the Workbench page - await t.click(myRedisDatabasePage.NavigationPanel.browserButton); - await browserPage.KeysInteractionPanel.setActiveTab(KeysInteractionTabs.Workbench); + await t.click(browserPage.NavigationPanel.workbenchButton); await t.expect(myRedisDatabasePage.NavigationPanel.githubButton.visible).ok('Github button'); // Verify that when user clicks on Github icon he redirects to the URL: https://github.com/RedisInsight/RedisInsight await t.click(myRedisDatabasePage.NavigationPanel.githubButton); diff --git a/tests/e2e/tests/web/regression/insights/import-tutorials.e2e.ts b/tests/e2e/tests/web/regression/insights/import-tutorials.e2e.ts index c7fa7f9178..4a047986e9 100644 --- a/tests/e2e/tests/web/regression/insights/import-tutorials.e2e.ts +++ b/tests/e2e/tests/web/regression/insights/import-tutorials.e2e.ts @@ -2,7 +2,7 @@ import * as path from 'path'; import * as fs from 'fs'; import { join as joinPath } from 'path'; import { t } from 'testcafe'; -import { ExploreTabs, KeysInteractionTabs, rte } from '../../../../helpers/constants'; +import { ExploreTabs, rte } from '../../../../helpers/constants'; import { DatabaseHelper } from '../../../../helpers/database'; import { BrowserPage, MemoryEfficiencyPage, MyRedisDatabasePage, WorkbenchPage } from '../../../../pageObjects'; import { commonUrl, ossStandaloneConfig, ossStandaloneRedisearch, fileDownloadPath } from '../../../../helpers/conf'; @@ -41,8 +41,7 @@ fixture `Upload custom tutorials` .page(commonUrl) .beforeEach(async t => { await databaseHelper.acceptLicenseTermsAndAddDatabaseApi(ossStandaloneConfig); - await t.click(myRedisDatabasePage.NavigationPanel.browserButton); - await browserPage.KeysInteractionPanel.setActiveTab(KeysInteractionTabs.Workbench); + await t.click(browserPage.NavigationPanel.workbenchButton); }) .afterEach(async() => { await databaseAPIRequests.deleteStandaloneDatabaseApi(ossStandaloneConfig); @@ -53,8 +52,7 @@ https://redislabs.atlassian.net/browse/RI-4302, https://redislabs.atlassian.net/ test .before(async() => { await databaseHelper.acceptLicenseTermsAndAddDatabaseApi(ossStandaloneConfig); - await t.click(myRedisDatabasePage.NavigationPanel.browserButton); - await browserPage.KeysInteractionPanel.setActiveTab(KeysInteractionTabs.Workbench); + await t.click(browserPage.NavigationPanel.workbenchButton); tutorialName = `${zipFolderName}${Common.generateWord(5)}`; zipFilePath = path.join('..', 'test-data', 'upload-tutorials', `${tutorialName}.zip`); @@ -169,8 +167,7 @@ test test .before(async() => { await databaseHelper.acceptLicenseTermsAndAddDatabaseApi(ossStandaloneRedisearch); - await t.click(myRedisDatabasePage.NavigationPanel.browserButton); - await browserPage.KeysInteractionPanel.setActiveTab(KeysInteractionTabs.Workbench); + await t.click(browserPage.NavigationPanel.workbenchButton); tutorialName = `${zipFolderName}${Common.generateWord(5)}`; zipFilePath = path.join('..', 'test-data', 'upload-tutorials', `${tutorialName}.zip`); @@ -183,8 +180,7 @@ test await Common.deleteFileFromFolder(zipFilePath); await deleteAllKeysFromDB(ossStandaloneRedisearch.host, ossStandaloneRedisearch.port); // Clear and delete database - await t.click(browserPage.NavigationPanel.browserButton); - await browserPage.KeysInteractionPanel.setActiveTab(KeysInteractionTabs.Workbench); + await t.click(browserPage.NavigationPanel.workbenchButton); await workbenchPage.NavigationHeader.togglePanel(true); const tutorials = await workbenchPage.InsightsPanel.setActiveTab(ExploreTabs.Tutorials); diff --git a/tests/e2e/tests/web/regression/insights/live-recommendations.e2e.ts b/tests/e2e/tests/web/regression/insights/live-recommendations.e2e.ts index b6b5de168c..782b61a556 100644 --- a/tests/e2e/tests/web/regression/insights/live-recommendations.e2e.ts +++ b/tests/e2e/tests/web/regression/insights/live-recommendations.e2e.ts @@ -1,6 +1,6 @@ import * as path from 'path'; import { BrowserPage, MemoryEfficiencyPage, MyRedisDatabasePage, WorkbenchPage } from '../../../../pageObjects'; -import { ExploreTabs, KeysInteractionTabs, RecommendationIds, rte } from '../../../../helpers/constants'; +import { ExploreTabs, RecommendationIds, rte } from '../../../../helpers/constants'; import { DatabaseHelper } from '../../../../helpers/database'; import { commonUrl, ossStandaloneConfig, ossStandaloneV5Config, ossStandaloneV7Config } from '../../../../helpers/conf'; import { DatabaseAPIRequests } from '../../../../helpers/api/api-database'; @@ -246,8 +246,7 @@ test //Verify that user is navigated to DB Analysis page via Analyze button and new report is generated await t.click(memoryEfficiencyPage.selectedReport); await t.expect(memoryEfficiencyPage.reportItem.visible).ok('Database analysis page not opened'); - await t.click(memoryEfficiencyPage.NavigationPanel.browserButton); - await browserPage.KeysInteractionPanel.setActiveTab(KeysInteractionTabs.Workbench); + await t.click(memoryEfficiencyPage.NavigationPanel.workbenchButton); await workbenchPage.NavigationHeader.togglePanel(true); tab = await browserPage.InsightsPanel.setActiveTab(ExploreTabs.Tips); await t.click(tab.analyzeDatabaseLink); diff --git a/tests/e2e/tests/web/regression/insights/open-insights-panel.e2e.ts b/tests/e2e/tests/web/regression/insights/open-insights-panel.e2e.ts index c603f30c5c..d1346c1f85 100644 --- a/tests/e2e/tests/web/regression/insights/open-insights-panel.e2e.ts +++ b/tests/e2e/tests/web/regression/insights/open-insights-panel.e2e.ts @@ -1,5 +1,5 @@ import { BrowserPage, MyRedisDatabasePage, WorkbenchPage } from '../../../../pageObjects'; -import { Compatibility, ExploreTabs, KeysInteractionTabs, rte } from '../../../../helpers/constants'; +import { Compatibility, ExploreTabs, rte } from '../../../../helpers/constants'; import { DatabaseHelper } from '../../../../helpers/database'; import { commonUrl, @@ -47,7 +47,7 @@ test await t.click(browserPage.NavigationPanel.myRedisDBButton); await myRedisDatabasePage.clickOnDBByName(ossStandaloneV5Config.databaseName); - await browserPage.KeysInteractionPanel.setActiveTab(KeysInteractionTabs.Workbench); + await t.click(browserPage.NavigationPanel.workbenchButton); await workbenchPage.sendCommandInWorkbench('TS.'); await t.click(browserPage.NavigationPanel.myRedisDBButton); diff --git a/tests/e2e/tests/web/regression/monitor/monitor.e2e.ts b/tests/e2e/tests/web/regression/monitor/monitor.e2e.ts index de46faf847..761050361d 100644 --- a/tests/e2e/tests/web/regression/monitor/monitor.e2e.ts +++ b/tests/e2e/tests/web/regression/monitor/monitor.e2e.ts @@ -10,7 +10,7 @@ import { ossStandaloneBigConfig, ossStandaloneConfig, } from '../../../../helpers/conf'; -import { KeysInteractionTabs, rte } from '../../../../helpers/constants'; +import { rte } from '../../../../helpers/constants'; import { DatabaseAPIRequests } from '../../../../helpers/api/api-database'; const myRedisDatabasePage = new MyRedisDatabasePage(); diff --git a/tests/e2e/tests/web/regression/search-and-query/commands-history.e2e.ts b/tests/e2e/tests/web/regression/search-and-query/commands-history.e2e.ts deleted file mode 100644 index f41f2daea5..0000000000 --- a/tests/e2e/tests/web/regression/search-and-query/commands-history.e2e.ts +++ /dev/null @@ -1,163 +0,0 @@ -import { KeysInteractionTabs, rte } from '../../../../helpers/constants'; -import { DatabaseHelper } from '../../../../helpers/database'; -import { BrowserPage, MyRedisDatabasePage, WorkbenchPage } from '../../../../pageObjects'; -import { SearchAndQueryPage } from '../../../../pageObjects/search-and-query-page'; -import { commonUrl, ossClusterConfig } from '../../../../helpers/conf'; -import { DatabaseAPIRequests } from '../../../../helpers/api/api-database'; -import { Common } from '../../../../helpers/common'; - -const myRedisDatabasePage = new MyRedisDatabasePage(); -const searchAndQueryPage = new SearchAndQueryPage(); -const databaseHelper = new DatabaseHelper(); -const databaseAPIRequests = new DatabaseAPIRequests(); -const browserPage = new BrowserPage(); -const workbenchPage = new WorkbenchPage(); - -const commandForSend1 = 'FT.INFO'; -const commandForSend2 = 'FT._LIST'; -let indexName = Common.generateWord(5); - -const commandsForIndex = [ - `FT.CREATE ${indexName} ON HASH PREFIX 1 product: SCHEMA price NUMERIC SORTABLE`, - 'HMSET product:1 price 20', - 'HMSET product:2 price 100' -]; - -fixture `Command results at Search and Query` - .meta({ type: 'critical_path', rte: rte.standalone }) - .page(commonUrl) - .beforeEach(async t => { - await databaseHelper.acceptLicenseTermsAndAddOSSClusterDatabase(ossClusterConfig); - // Go to Workbench page - await t.click(myRedisDatabasePage.NavigationPanel.browserButton); - await browserPage.KeysInteractionPanel.setActiveTab(KeysInteractionTabs.SearchAndQuery); - }) - .afterEach(async t => { - await t.switchToMainWindow(); - await workbenchPage.sendCommandInWorkbench(`FT.DROPINDEX ${indexName} DD`); - await databaseAPIRequests.deleteOSSClusterDatabaseApi(ossClusterConfig); - }); -test('Verify that user can see re-run icon near the already executed command and re-execute the command by clicking on the icon in Workbench page', async t => { - // Send commands - await searchAndQueryPage.sendCommandInWorkbench(commandForSend1); - await searchAndQueryPage.sendCommandInWorkbench(commandForSend2); - const containerOfCommand = await searchAndQueryPage.getCardContainerByCommand(commandForSend1); - const containerOfCommand2 = await searchAndQueryPage.getCardContainerByCommand(commandForSend2); - // Verify that re-run icon is displayed - await t.expect(await searchAndQueryPage.reRunCommandButton.visible).ok('Re-run icon is not displayed'); - // Re-run the last command in results - await t.click(containerOfCommand.find(searchAndQueryPage.cssReRunCommandButton)); - // Verify that command is re-executed - await t.expect(searchAndQueryPage.queryCardCommand.textContent).eql(commandForSend1, 'The command is not re-executed'); - - // Verify that user can see expanded result after command re-run at the top of results table in Workbench - await t.expect(await searchAndQueryPage.queryCardContainer.nth(0).find(searchAndQueryPage.cssQueryTextResult).visible) - .ok('Re-executed command is not expanded'); - await t.expect(searchAndQueryPage.queryCardCommand.nth(0).textContent).eql(commandForSend1, 'The re-executed command is not at the top of results table'); - - // Delete the command from results - await t.click(containerOfCommand2.find(searchAndQueryPage.cssDeleteCommandButton)); - // Verify that user can delete command with result from table with results in Workbench - await t.expect(searchAndQueryPage.queryCardCommand.withExactText(commandForSend2).exists).notOk(`Command ${commandForSend2} is not deleted from table with results`); -}); -test('Verify that user can see the results found in the table view by default for FT.INFO, FT.SEARCH and FT.AGGREGATE', async t => { - const commands = [ - 'FT.INFO', - 'FT.SEARCH', - 'FT.AGGREGATE' - ]; - // Send commands and check table view is default - for(const command of commands) { - await searchAndQueryPage.sendCommandInWorkbench(command); - await t.expect(searchAndQueryPage.queryCardContainer.nth(0).find(searchAndQueryPage.cssTableViewTypeOption).exists).ok(`The table view is not selected by default for command ${command}`); - } -}); -test - .after(async() => { - await searchAndQueryPage.sendCommandInWorkbench(`FT.DROPINDEX ${indexName} DD`); - })('Verify that user can switches between views and see results according to the view rules in Workbench in results', async t => { - indexName = Common.generateWord(5); - const commands = [ - 'hset doc:10 title "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud" url "redis.io" author "Test" rate "undefined" review "0" comment "Test comment"', - `FT.CREATE ${indexName} ON HASH PREFIX 1 doc: SCHEMA title TEXT WEIGHT 5.0 body TEXT url TEXT author TEXT rate TEXT review TEXT comment TEXT`, - `FT.SEARCH ${indexName} * limit 0 10000` - ]; - // Send commands and check table view is default for Search command - for (const command of commands) { - await searchAndQueryPage.sendCommandInWorkbench(command); - } - await t.expect(await searchAndQueryPage.queryCardContainer.nth(0).find(searchAndQueryPage.cssTableViewTypeOption).exists) - .ok('The table view is not selected by default for command FT.SEARCH'); - await t.switchToIframe(searchAndQueryPage.iframe); - await t.expect(await searchAndQueryPage.queryTableResult.visible).ok('The table result is not displayed for command FT.SEARCH'); - // Select Text view and check result - await t.switchToMainWindow(); - await searchAndQueryPage.selectViewTypeText(); - await t.expect(await searchAndQueryPage.queryCardContainer.nth(0).find(searchAndQueryPage.cssQueryTextResult).visible).ok('The result is not displayed in Text view'); - }); - -test('Verify that user can clear all results at once.', async t => { - await t.click(searchAndQueryPage.clearResultsBtn); - await t.expect(searchAndQueryPage.queryTextResult.exists).notOk('Clear all button does not remove commands'); -}); - -test('Verify that user can switches between Table and Text for FT.AGGREGATE and see results corresponding to their views', async t => { - - await browserPage.KeysInteractionPanel.setActiveTab(KeysInteractionTabs.Workbench); - await workbenchPage.sendCommandsArrayInWorkbench(commandsForIndex); - await browserPage.KeysInteractionPanel.setActiveTab(KeysInteractionTabs.SearchAndQuery); - const aggregateCommand = `FT.Aggregate ${indexName} * GROUPBY 0 REDUCE MAX 1 @price AS max_price`; - - // Send FT.AGGREGATE and switch to Text view - await searchAndQueryPage.sendCommandInWorkbench(aggregateCommand); - await searchAndQueryPage.selectViewTypeText(); - await t.expect(searchAndQueryPage.queryCardContainer.nth(0).find(searchAndQueryPage.cssQueryTextResult).visible).ok('The text view is not switched for command FT.AGGREGATE'); - // Switch to Table view and check result - await searchAndQueryPage.selectViewTypeTable(); - await t.switchToIframe(searchAndQueryPage.iframe); - await t.expect(searchAndQueryPage.queryTableResult.exists).ok('The table view is not switched for command FT.AGGREGATE'); -}); - -test('Verify that user can switches between Table and Text for FT.SEARCH and see results corresponding to their views', async t => { - await browserPage.KeysInteractionPanel.setActiveTab(KeysInteractionTabs.Workbench); - await workbenchPage.sendCommandsArrayInWorkbench(commandsForIndex); - await browserPage.KeysInteractionPanel.setActiveTab(KeysInteractionTabs.SearchAndQuery); - const searchCommand = `FT.SEARCH ${indexName} *`; - - // Send FT.SEARCH and switch to Text view - await searchAndQueryPage.sendCommandInWorkbench(searchCommand); - await searchAndQueryPage.selectViewTypeText(); - await t.expect(searchAndQueryPage.queryCardContainer.nth(0).find(searchAndQueryPage.cssQueryTextResult).visible).ok('The text view is not switched for command FT.SEARCH'); - // Switch to Table view and check result - await searchAndQueryPage.selectViewTypeTable(); - await t.switchToIframe(searchAndQueryPage.iframe); - await t.expect(searchAndQueryPage.queryTableResult.exists).ok('The table view is not switched for command FT.SEARCH'); -}); -test('Verify that user can switches between Table and Text for FT.INFO and see results corresponding to their views', async t => { - await browserPage.KeysInteractionPanel.setActiveTab(KeysInteractionTabs.Workbench); - await workbenchPage.sendCommandsArrayInWorkbench(commandsForIndex); - await browserPage.KeysInteractionPanel.setActiveTab(KeysInteractionTabs.SearchAndQuery); - const infoCommand = `FT.INFO ${indexName}`; - - // Send FT.INFO and switch to Text view - await searchAndQueryPage.sendCommandInWorkbench(infoCommand); - await searchAndQueryPage.selectViewTypeText(); - await t.expect(searchAndQueryPage.queryCardContainer.nth(0).find(searchAndQueryPage.cssQueryTextResult).exists).ok('The text view is not switched for command FT.INFO'); - // Switch to Table view and check result - await searchAndQueryPage.selectViewTypeTable(); - await t.switchToIframe(searchAndQueryPage.iframe); - await t.expect(searchAndQueryPage.queryTableResult.exists).ok('The table view is not switched for command FT.INFO'); -}); -test('Verify that user can see original date and time of command execution in Workbench history after the page update', async t => { - const keyName = Common.generateWord(5); - const command = `set ${keyName} test`; - - // Send command and remember the time - await searchAndQueryPage.sendCommandInWorkbench(command); - const dateTime = await searchAndQueryPage.queryCardContainer.nth(0).find(searchAndQueryPage.cssCommandExecutionDateTime).textContent; - // Wait fo 1 minute, refresh page and check results - await t.wait(60000); - await searchAndQueryPage.reloadPage(); - await t.expect(searchAndQueryPage.queryCardContainer.nth(0).find(searchAndQueryPage.cssCommandExecutionDateTime).textContent).eql(dateTime, 'The original date and time of command execution is not saved after the page update'); -}); - diff --git a/tests/e2e/tests/web/regression/search-and-query/no-indexes-suggestions.e2e.ts b/tests/e2e/tests/web/regression/search-and-query/no-indexes-suggestions.e2e.ts index b076bd565c..3b6f4ec665 100644 --- a/tests/e2e/tests/web/regression/search-and-query/no-indexes-suggestions.e2e.ts +++ b/tests/e2e/tests/web/regression/search-and-query/no-indexes-suggestions.e2e.ts @@ -1,14 +1,13 @@ import { DatabaseHelper } from '../../../../helpers/database'; -import { BrowserPage } from '../../../../pageObjects'; +import { BrowserPage, WorkbenchPage } from '../../../../pageObjects'; import { rte } from '../../../../helpers/constants'; import { commonUrl, ossClusterConfig, ossStandaloneConfig, ossStandaloneRedisearch } from '../../../../helpers/conf'; import { DatabaseAPIRequests } from '../../../../helpers/api/api-database'; -import { SearchAndQueryPage } from '../../../../pageObjects/search-and-query-page'; const browserPage = new BrowserPage(); const databaseHelper = new DatabaseHelper(); const databaseAPIRequests = new DatabaseAPIRequests(); -const searchAndQueryPage = new SearchAndQueryPage(); +const workbenchPage = new WorkbenchPage(); fixture `Search and Query Raw mode` .meta({ type: 'critical_path', rte: rte.standalone }) @@ -26,11 +25,11 @@ test // TODO add navigation to search and query Monaco - await t.typeText(searchAndQueryPage.queryInput, 'FT.SE', { replace: true }); + await t.typeText(workbenchPage.queryInput, 'FT.SE', { replace: true }); await t.pressKey('enter'); - await t.expect(searchAndQueryPage.MonacoEditor.monacoSuggestion.withExactText('No indexes to display').exists).ok('info text is not displayed'); + await t.expect(workbenchPage.MonacoEditor.monacoSuggestion.withExactText('No indexes to display').exists).ok('info text is not displayed'); await t.pressKey('ctrl+space'); - await t.expect(await searchAndQueryPage.MonacoEditor.monacoCommandDetails.find('a').exists).ok('no link in the details') + await t.expect(await workbenchPage.MonacoEditor.monacoCommandDetails.find('a').exists).ok('no link in the details') }); diff --git a/tests/e2e/tests/web/regression/search-and-query/raw-mode.e2e.ts b/tests/e2e/tests/web/regression/search-and-query/raw-mode.e2e.ts deleted file mode 100644 index 32d7ed7a05..0000000000 --- a/tests/e2e/tests/web/regression/search-and-query/raw-mode.e2e.ts +++ /dev/null @@ -1,69 +0,0 @@ -import { DatabaseHelper } from '../../../../helpers/database'; -import { WorkbenchPage, MyRedisDatabasePage, BrowserPage } from '../../../../pageObjects'; -import { KeysInteractionTabs, rte } from '../../../../helpers/constants'; -import { commonUrl, ossStandaloneConfig, ossStandaloneRedisearch } from '../../../../helpers/conf'; -import { DatabaseAPIRequests } from '../../../../helpers/api/api-database'; -import { Common } from '../../../../helpers/common'; -import { SearchAndQueryPage } from '../../../../pageObjects/search-and-query-page'; - -const myRedisDatabasePage = new MyRedisDatabasePage(); -const workbenchPage = new WorkbenchPage(); -const browserPage = new BrowserPage(); -const databaseHelper = new DatabaseHelper(); -const databaseAPIRequests = new DatabaseAPIRequests(); -const searchAndQueryPage = new SearchAndQueryPage(); - -const indexName = Common.generateWord(5); -const unicodeValue = '山女馬 / 马目 abc 123'; - -const databasesForAdding = - { host: ossStandaloneConfig.host, port: ossStandaloneConfig.port, databaseName: 'testDB2' }; - -fixture `Search and Query Raw mode` - .meta({ type: 'critical_path', rte: rte.standalone }) - .page(commonUrl); - -test - .before(async t => { - await databaseHelper.acceptLicenseTerms(); - await databaseAPIRequests.addNewStandaloneDatabaseApi( - databasesForAdding); - await databaseHelper.acceptLicenseTermsAndAddDatabaseApi(ossStandaloneRedisearch); - // Go to Workbench page - await browserPage.KeysInteractionPanel.setActiveTab(KeysInteractionTabs.Workbench); - }) - .after(async t => { - // Drop index, documents and database - await t.switchToMainWindow(); - await workbenchPage.sendCommandInWorkbench(`FT.DROPINDEX ${indexName} DD`); - await databaseAPIRequests.deleteStandaloneDatabaseApi(ossStandaloneRedisearch); - - })('Display Raw mode for plugins and save state', async t => { - const commandsForSend = [ - `FT.CREATE ${indexName} ON HASH PREFIX 1 product: SCHEMA name TEXT`, - `HMSET product:1 name "${unicodeValue}"` - ]; - const commandSearch = `FT.SEARCH ${indexName} "${unicodeValue}"`; - - await workbenchPage.sendCommandsArrayInWorkbench(commandsForSend); - await browserPage.KeysInteractionPanel.setActiveTab(KeysInteractionTabs.SearchAndQuery); - // Send command in raw mode - await t.click(searchAndQueryPage.rawModeBtn); - await searchAndQueryPage.sendCommandInWorkbench(commandSearch); - // Check the FT.SEARCH result - await t.switchToIframe(workbenchPage.iframe); - let name = workbenchPage.queryTableResult.withText(unicodeValue); - await t.expect(name.exists).ok('The added key name field is not converted to Unicode'); - await t.switchToMainWindow(); - await t.click(myRedisDatabasePage.NavigationPanel.myRedisDBButton); - await myRedisDatabasePage.clickOnDBByName(databasesForAdding.databaseName); - await browserPage.KeysInteractionPanel.setActiveTab(KeysInteractionTabs.Workbench); - - await workbenchPage.sendCommandsArrayInWorkbench(commandsForSend); - await browserPage.KeysInteractionPanel.setActiveTab(KeysInteractionTabs.SearchAndQuery); - await searchAndQueryPage.sendCommandInWorkbench(commandSearch); - // Check the FT.SEARCH result - await t.switchToIframe(workbenchPage.iframe); - name = workbenchPage.queryTableResult.withText(unicodeValue); - await t.expect(name.exists).ok('The added key name field is not converted to Unicode'); - }); diff --git a/tests/e2e/tests/web/regression/search-and-query/search-and-query-tab.e2e.ts b/tests/e2e/tests/web/regression/search-and-query/search-and-query-tab.e2e.ts index 6050175477..0670de33ea 100644 --- a/tests/e2e/tests/web/regression/search-and-query/search-and-query-tab.e2e.ts +++ b/tests/e2e/tests/web/regression/search-and-query/search-and-query-tab.e2e.ts @@ -1,15 +1,14 @@ import { Common, DatabaseHelper } from '../../../../helpers'; import { DatabaseAPIRequests } from '../../../../helpers/api/api-database'; -import { BrowserPage } from '../../../../pageObjects'; -import { ExploreTabs, KeysInteractionTabs, rte } from '../../../../helpers/constants'; +import { BrowserPage, WorkbenchPage } from '../../../../pageObjects'; +import { ExploreTabs, rte } from '../../../../helpers/constants'; import { commonUrl, ossStandaloneConfig } from '../../../../helpers/conf'; -import { SearchAndQueryPage } from '../../../../pageObjects/search-and-query-page'; import { APIKeyRequests } from '../../../../helpers/api/api-keys'; const databaseHelper = new DatabaseHelper(); const databaseAPIRequests = new DatabaseAPIRequests(); const browserPage = new BrowserPage(); -const searchAndQueryPage = new SearchAndQueryPage(); +const workbenchPage = new WorkbenchPage(); const apiKeyRequests = new APIKeyRequests(); const keyName = Common.generateWord(10); @@ -21,7 +20,7 @@ let indexName3: string; fixture `Autocomplete for entered commands in search and query` .meta({ type: 'regression', rte: rte.standalone }) .page(commonUrl) - .beforeEach(async() => { + .beforeEach(async t => { await databaseHelper.acceptLicenseTermsAndAddDatabaseApi(ossStandaloneConfig); indexName1 = `idx1:${keyName}`; indexName2 = `idx2:${keyName}`; @@ -37,7 +36,7 @@ fixture `Autocomplete for entered commands in search and query` // Create 3 keys and index await browserPage.Cli.sendCommandsInCli(commands); - await browserPage.KeysInteractionPanel.setActiveTab(KeysInteractionTabs.SearchAndQuery); + await t.click(browserPage.NavigationPanel.workbenchButton); }) .afterEach(async() => { // Clear and delete database @@ -47,9 +46,9 @@ fixture `Autocomplete for entered commands in search and query` await databaseAPIRequests.deleteStandaloneDatabaseApi(ossStandaloneConfig); }); test('Verify that tutorials can be opened from Workbench', async t => { - await browserPage.KeysInteractionPanel.setActiveTab(KeysInteractionTabs.SearchAndQuery); - await t.click(searchAndQueryPage.getTutorialLinkLocator('sq-exact-match')); - await t.expect(searchAndQueryPage.InsightsPanel.sidePanel.exists).ok('Insight panel is not opened'); + await t.click(browserPage.NavigationPanel.workbenchButton); + await t.click(workbenchPage.getTutorialLinkLocator('sq-exact-match')); + await t.expect(workbenchPage.InsightsPanel.sidePanel.exists).ok('Insight panel is not opened'); const tab = await browserPage.InsightsPanel.setActiveTab(ExploreTabs.Tutorials); await t.expect(tab.preselectArea.textContent).contains('EXACT MATCH', 'the tutorial page is incorrect'); }); @@ -62,16 +61,16 @@ test('Verify that user can use show more to see command fully in 2nd tooltip', a 'required query', 'optional [verbatim]' ]; - await t.typeText(searchAndQueryPage.queryInput, 'FT', { replace: true }); + await t.typeText(workbenchPage.queryInput, 'FT', { replace: true }); // Verify that user can use show more to see command fully in 2nd tooltip await t.pressKey('ctrl+space'); - await t.expect(searchAndQueryPage.MonacoEditor.monacoCommandDetails.exists).ok('The "read more" about the command is not opened'); + await t.expect(workbenchPage.MonacoEditor.monacoCommandDetails.exists).ok('The "read more" about the command is not opened'); for(const detail of commandDetails) { - await t.expect(searchAndQueryPage.MonacoEditor.monacoCommandDetails.textContent).contains(detail, `The ${detail} command detail is not displayed`); + await t.expect(workbenchPage.MonacoEditor.monacoCommandDetails.textContent).contains(detail, `The ${detail} command detail is not displayed`); } // Verify that user can close show more tooltip by 'x' or 'Show less' await t.pressKey('ctrl+space'); - await t.expect(searchAndQueryPage.MonacoEditor.monacoCommandDetails.exists).notOk('The "read more" about the command is not closed'); + await t.expect(workbenchPage.MonacoEditor.monacoCommandDetails.exists).notOk('The "read more" about the command is not closed'); }); test('Verify full commands suggestions with index and query for FT.AGGREGATE', async t => { const groupByArgInfo = 'GROUPBY nargs property [property ...] [REDUCE '; @@ -86,257 +85,257 @@ test('Verify full commands suggestions with index and query for FT.AGGREGATE', a 'type' ]; // Verify basic commands suggestions FT.SEARCH and FT.AGGREGATE - await t.typeText(searchAndQueryPage.queryInput, 'FT', { replace: true }); + await t.typeText(workbenchPage.queryInput, 'FT', { replace: true }); // Verify that the list with FT.SEARCH and FT.AGGREGATE auto-suggestions is displayed - await t.expect(searchAndQueryPage.MonacoEditor.monacoSuggestion.withText('FT.SEARCH').exists).ok('FT.SEARCH auto-suggestions are not displayed'); - await t.expect(searchAndQueryPage.MonacoEditor.monacoSuggestion.withText('FT.AGGREGATE').exists).ok('FT.AGGREGATE auto-suggestions are not displayed'); + await t.expect(workbenchPage.MonacoEditor.monacoSuggestion.withText('FT.SEARCH').exists).ok('FT.SEARCH auto-suggestions are not displayed'); + await t.expect(workbenchPage.MonacoEditor.monacoSuggestion.withText('FT.AGGREGATE').exists).ok('FT.AGGREGATE auto-suggestions are not displayed'); // Select command and check result await t.pressKey('enter'); - let script = await searchAndQueryPage.queryInputScriptArea.textContent; + let script = await workbenchPage.queryInputScriptArea.textContent; await t.expect(script.replace(/\s/g, ' ')).contains('FT.AGGREGATE ', 'Result of sent command exists'); // Verify that user can see the list of all the indexes in database when put a space after only FT.SEARCH and FT.AGGREGATE commands await t.expect(script.replace(/\s/g, ' ')).contains(`"${indexName1}" "" `, 'Index not suggested into input'); - await t.expect(searchAndQueryPage.MonacoEditor.monacoSuggestion.withExactText(indexName1).exists).ok('Index not auto-suggested'); - await t.expect(searchAndQueryPage.MonacoEditor.monacoSuggestion.withExactText(indexName2).exists).ok('All indexes not auto-suggested'); + await t.expect(workbenchPage.MonacoEditor.monacoSuggestion.withExactText(indexName1).exists).ok('Index not auto-suggested'); + await t.expect(workbenchPage.MonacoEditor.monacoSuggestion.withExactText(indexName2).exists).ok('All indexes not auto-suggested'); await t.pressKey('tab'); await t.wait(200); - await t.typeText(searchAndQueryPage.queryInput, '@', { replace: false }); - script = await searchAndQueryPage.queryInputScriptArea.textContent; + await t.typeText(workbenchPage.queryInput, '@', { replace: false }); + script = await workbenchPage.queryInputScriptArea.textContent; // Verify that user can see the list of fields from the index selected when type in “@” await t.expect(script.replace(/\s/g, ' ')).contains('address', 'Index not suggested into input'); for(const field of indexFields) { - await t.expect(searchAndQueryPage.MonacoEditor.monacoSuggestion.withExactText(field).exists).ok(`${field} Index field not auto-suggested`); + await t.expect(workbenchPage.MonacoEditor.monacoSuggestion.withExactText(field).exists).ok(`${field} Index field not auto-suggested`); } // Verify that user can use autosuggestions by typing fields from index after "@" - await t.typeText(searchAndQueryPage.queryInput, 'ci', { replace: false }); - await t.expect(searchAndQueryPage.MonacoEditor.monacoSuggestion.withExactText('city').exists).ok('Index field not auto-suggested after starting typing'); - await t.expect(searchAndQueryPage.MonacoEditor.monacoSuggestion.count).eql(1, 'Wrong index fields suggested after typing first letter'); + await t.typeText(workbenchPage.queryInput, 'ci', { replace: false }); + await t.expect(workbenchPage.MonacoEditor.monacoSuggestion.withExactText('city').exists).ok('Index field not auto-suggested after starting typing'); + await t.expect(workbenchPage.MonacoEditor.monacoSuggestion.count).eql(1, 'Wrong index fields suggested after typing first letter'); // Verify contextual suggestions after typing letters for commands await t.pressKey('tab'); await t.pressKey('right'); await t.pressKey('space'); - await t.expect(searchAndQueryPage.MonacoEditor.monacoSuggestion.withExactText('APPLY').exists).ok('FT.AGGREGATE arguments not suggested'); - await t.typeText(searchAndQueryPage.queryInput, 'g', { replace: false }); - await t.expect(searchAndQueryPage.MonacoEditor.monacoSuggestion.nth(0).textContent).contains('GROUPBY', 'Argument not suggested after typing first letters'); + await t.expect(workbenchPage.MonacoEditor.monacoSuggestion.withExactText('APPLY').exists).ok('FT.AGGREGATE arguments not suggested'); + await t.typeText(workbenchPage.queryInput, 'g', { replace: false }); + await t.expect(workbenchPage.MonacoEditor.monacoSuggestion.nth(0).textContent).contains('GROUPBY', 'Argument not suggested after typing first letters'); await t.pressKey('tab'); // Verify that user can see widget about entered argument - await t.expect(searchAndQueryPage.MonacoEditor.monacoHintWithArguments.textContent).contains(groupByArgInfo, 'Widget with info about entered argument not displayed'); + await t.expect(workbenchPage.MonacoEditor.monacoHintWithArguments.textContent).contains(groupByArgInfo, 'Widget with info about entered argument not displayed'); - await t.typeText(searchAndQueryPage.queryInput, '1 "London"', { replace: false }); + await t.typeText(workbenchPage.queryInput, '1 "London"', { replace: false }); await t.pressKey('space'); // Verify correct order of suggested arguments like LOAD, GROUPBY, SORTBY - await t.expect(searchAndQueryPage.MonacoEditor.monacoSuggestion.nth(0).textContent).contains('REDUCE', 'Incorrect order of suggested arguments'); + await t.expect(workbenchPage.MonacoEditor.monacoSuggestion.nth(0).textContent).contains('REDUCE', 'Incorrect order of suggested arguments'); await t.pressKey('tab'); - await t.typeText(searchAndQueryPage.queryInput, 'SUM 1 @students', { replace: false }); + await t.typeText(workbenchPage.queryInput, 'SUM 1 @students', { replace: false }); await t.pressKey('space'); // Verify expression and function suggestions like AS for APPLY/GROUPBY - await t.expect(searchAndQueryPage.MonacoEditor.monacoSuggestion.nth(0).textContent).contains('AS', 'Incorrect order of suggested arguments'); + await t.expect(workbenchPage.MonacoEditor.monacoSuggestion.nth(0).textContent).contains('AS', 'Incorrect order of suggested arguments'); await t.pressKey('tab'); - await t.typeText(searchAndQueryPage.queryInput, 'stud', { replace: false }); + await t.typeText(workbenchPage.queryInput, 'stud', { replace: false }); await t.pressKey('space'); await t.debug(); // Verify multiple argument option suggestions - await t.expect(searchAndQueryPage.MonacoEditor.monacoSuggestion.nth(0).textContent).contains('REDUCE', 'Incorrect order of suggested arguments'); + await t.expect(workbenchPage.MonacoEditor.monacoSuggestion.nth(0).textContent).contains('REDUCE', 'Incorrect order of suggested arguments'); // Verify complex command sequences like nargs and properties are suggested accurately for GROUPBY const expectedText = `FT.AGGREGATE "${indexName1}" "@city" GROUPBY 1 "London" REDUCE SUM 1 @students AS stud REDUCE`.trim().replace(/\s+/g, ' '); - await t.expect((await searchAndQueryPage.queryInputForText.innerText).trim().replace(/\s+/g, ' ')).contains(expectedText, 'Incorrect order of entered arguments'); + await t.expect((await workbenchPage.queryInputForText.innerText).trim().replace(/\s+/g, ' ')).contains(expectedText, 'Incorrect order of entered arguments'); }); test('Verify full commands suggestions with index and query for FT.SEARCH', async t => { - await t.typeText(searchAndQueryPage.queryInput, 'FT.SE', { replace: true }); + await t.typeText(workbenchPage.queryInput, 'FT.SE', { replace: true }); // Select command and check result await t.pressKey('enter'); - const script = await searchAndQueryPage.queryInputScriptArea.textContent; + const script = await workbenchPage.queryInputScriptArea.textContent; await t.expect(script.replace(/\s/g, ' ')).contains('FT.SEARCH ', 'Result of sent command exists'); await t.pressKey('tab'); // Select '@city' field - await searchAndQueryPage.selectFieldUsingAutosuggest('city'); - await t.expect(searchAndQueryPage.MonacoEditor.monacoSuggestion.withExactText('DIALECT').exists).ok('FT.SEARCH arguments not suggested'); - await t.typeText(searchAndQueryPage.queryInput, 'n', { replace: false }); - await t.expect(searchAndQueryPage.MonacoEditor.monacoSuggestion.nth(0).textContent).contains('NOCONTENT', 'Argument not suggested after typing first letters'); + await workbenchPage.selectFieldUsingAutosuggest('city'); + await t.expect(workbenchPage.MonacoEditor.monacoSuggestion.withExactText('DIALECT').exists).ok('FT.SEARCH arguments not suggested'); + await t.typeText(workbenchPage.queryInput, 'n', { replace: false }); + await t.expect(workbenchPage.MonacoEditor.monacoSuggestion.nth(0).textContent).contains('NOCONTENT', 'Argument not suggested after typing first letters'); await t.pressKey('tab'); // Verify that FT.SEARCH and FT.AGGREGATE non-multiple arguments are suggested only once await t.pressKey('space'); - await t.expect(searchAndQueryPage.MonacoEditor.monacoSuggestion.withText('NOCONTENT').exists).notOk('Non-multiple arguments are suggested not only once'); + await t.expect(workbenchPage.MonacoEditor.monacoSuggestion.withText('NOCONTENT').exists).notOk('Non-multiple arguments are suggested not only once'); // Verify that suggestions correct to closest valid commands or options for invalid typing like WRONGCOMMAND - await t.typeText(searchAndQueryPage.queryInput, 'WRONGCOMMAND', { replace: false }); - await t.expect(searchAndQueryPage.MonacoEditor.monacoSuggestion.withExactText('WITHSORTKEYS').exists).ok('Closest suggestions not displayed'); + await t.typeText(workbenchPage.queryInput, 'WRONGCOMMAND', { replace: false }); + await t.expect(workbenchPage.MonacoEditor.monacoSuggestion.withExactText('WITHSORTKEYS').exists).ok('Closest suggestions not displayed'); await t.pressKey('space'); await t.pressKey('backspace'); await t.pressKey('backspace'); // Verify that 'No suggestions' tooltip is displayed when returning to invalid typing like WRONGCOMMAND - await t.expect(searchAndQueryPage.MonacoEditor.monacoSuggestWidget.textContent).contains('No suggestions.', 'Index not auto-suggested'); + await t.expect(workbenchPage.MonacoEditor.monacoSuggestWidget.textContent).contains('No suggestions.', 'Index not auto-suggested'); }); test('Verify full commands suggestions with index and query for FT.PROFILE(SEARCH)', async t => { - await t.typeText(searchAndQueryPage.queryInput, 'FT.PR', { replace: true }); + await t.typeText(workbenchPage.queryInput, 'FT.PR', { replace: true }); // Select command and check result await t.pressKey('enter'); - const script = await searchAndQueryPage.queryInputScriptArea.textContent; + const script = await workbenchPage.queryInputScriptArea.textContent; await t.expect(script.replace(/\s/g, ' ')).contains('FT.PROFILE ', 'Result of sent command exists'); await t.pressKey('tab'); - await t.expect(searchAndQueryPage.MonacoEditor.monacoSuggestion.withExactText('AGGREGATE').exists).ok('FT.PROFILE aggregate argument not suggested'); - await t.expect(searchAndQueryPage.MonacoEditor.monacoSuggestion.withExactText('SEARCH').exists).ok('FT.PROFILE search argument not suggested'); + await t.expect(workbenchPage.MonacoEditor.monacoSuggestion.withExactText('AGGREGATE').exists).ok('FT.PROFILE aggregate argument not suggested'); + await t.expect(workbenchPage.MonacoEditor.monacoSuggestion.withExactText('SEARCH').exists).ok('FT.PROFILE search argument not suggested'); // Select SEARCH command - await t.typeText(searchAndQueryPage.queryInput, 'SEA', { replace: false }); + await t.typeText(workbenchPage.queryInput, 'SEA', { replace: false }); await t.pressKey('enter'); - await t.expect(searchAndQueryPage.MonacoEditor.monacoSuggestion.withExactText('LIMITED').exists).ok('FT.PROFILE SEARCH arguments not suggested'); - await t.expect(searchAndQueryPage.MonacoEditor.monacoSuggestion.withExactText('QUERY').exists).ok('FT.PROFILE SEARCH arguments not suggested'); + await t.expect(workbenchPage.MonacoEditor.monacoSuggestion.withExactText('LIMITED').exists).ok('FT.PROFILE SEARCH arguments not suggested'); + await t.expect(workbenchPage.MonacoEditor.monacoSuggestion.withExactText('QUERY').exists).ok('FT.PROFILE SEARCH arguments not suggested'); // Select QUERY - await t.typeText(searchAndQueryPage.queryInput, 'QUE', { replace: false }); + await t.typeText(workbenchPage.queryInput, 'QUE', { replace: false }); await t.pressKey('enter'); - await searchAndQueryPage.selectFieldUsingAutosuggest('city'); + await workbenchPage.selectFieldUsingAutosuggest('city'); // Verify that there are no more suggestions - await t.expect(searchAndQueryPage.MonacoEditor.monacoSuggestion.exists).notOk('Additional invalid commands suggested'); + await t.expect(workbenchPage.MonacoEditor.monacoSuggestion.exists).notOk('Additional invalid commands suggested'); const expectedText = `FT.PROFILE "${indexName1}" SEARCH QUERY "@city"`.trim().replace(/\s+/g, ' '); // Verify command entered correctly - await t.expect((await searchAndQueryPage.queryInputForText.innerText).trim().replace(/\s+/g, ' ')).contains(expectedText, 'Incorrect order of entered arguments'); + await t.expect((await workbenchPage.queryInputForText.innerText).trim().replace(/\s+/g, ' ')).contains(expectedText, 'Incorrect order of entered arguments'); }); test('Verify full commands suggestions with index and query for FT.PROFILE(AGGREGATE)', async t => { - await t.typeText(searchAndQueryPage.queryInput, 'FT.PR', { replace: true }); + await t.typeText(workbenchPage.queryInput, 'FT.PR', { replace: true }); // Select command and check result await t.pressKey('enter'); await t.pressKey('tab'); // Select AGGREGATE command - await t.typeText(searchAndQueryPage.queryInput, 'AGG', { replace: false }); + await t.typeText(workbenchPage.queryInput, 'AGG', { replace: false }); await t.pressKey('enter'); - await t.expect(searchAndQueryPage.MonacoEditor.monacoSuggestion.withExactText('LIMITED').exists).ok('FT.PROFILE AGGREGATE arguments not suggested'); - await t.expect(searchAndQueryPage.MonacoEditor.monacoSuggestion.withExactText('QUERY').exists).ok('FT.PROFILE AGGREGATE arguments not suggested'); + await t.expect(workbenchPage.MonacoEditor.monacoSuggestion.withExactText('LIMITED').exists).ok('FT.PROFILE AGGREGATE arguments not suggested'); + await t.expect(workbenchPage.MonacoEditor.monacoSuggestion.withExactText('QUERY').exists).ok('FT.PROFILE AGGREGATE arguments not suggested'); // Select QUERY - await t.typeText(searchAndQueryPage.queryInput, 'QUE', { replace: false }); + await t.typeText(workbenchPage.queryInput, 'QUE', { replace: false }); await t.pressKey('enter'); - await searchAndQueryPage.selectFieldUsingAutosuggest('city'); + await workbenchPage.selectFieldUsingAutosuggest('city'); // Verify that there are no more suggestions - await t.expect(searchAndQueryPage.MonacoEditor.monacoSuggestion.exists).notOk('Additional invalid commands suggested'); + await t.expect(workbenchPage.MonacoEditor.monacoSuggestion.exists).notOk('Additional invalid commands suggested'); const expectedText = `FT.PROFILE "${indexName1}" AGGREGATE QUERY "@city"`.trim().replace(/\s+/g, ' '); // Verify command entered correctly - await t.expect((await searchAndQueryPage.queryInputForText.innerText).trim().replace(/\s+/g, ' ')).contains(expectedText, 'Incorrect order of entered arguments'); + await t.expect((await workbenchPage.queryInputForText.innerText).trim().replace(/\s+/g, ' ')).contains(expectedText, 'Incorrect order of entered arguments'); }); test('Verify full commands suggestions with index and query for FT.EXPLAIN', async t => { - await t.typeText(searchAndQueryPage.queryInput, 'FT.EX', { replace: true }); + await t.typeText(workbenchPage.queryInput, 'FT.EX', { replace: true }); // Select command and check result await t.pressKey('enter'); await t.pressKey('tab'); - await searchAndQueryPage.selectFieldUsingAutosuggest('city'); + await workbenchPage.selectFieldUsingAutosuggest('city'); - await t.expect(searchAndQueryPage.MonacoEditor.monacoSuggestion.withExactText('DIALECT').exists).ok('FT.EXPLAIN arguments not suggested'); + await t.expect(workbenchPage.MonacoEditor.monacoSuggestion.withExactText('DIALECT').exists).ok('FT.EXPLAIN arguments not suggested'); // Add DIALECT await t.pressKey('enter'); - await t.typeText(searchAndQueryPage.queryInput, 'dialectTest', { replace: false }); + await t.typeText(workbenchPage.queryInput, 'dialectTest', { replace: false }); // Verify that there are no more suggestions await t.pressKey('space'); - await t.expect(searchAndQueryPage.MonacoEditor.monacoSuggestion.exists).notOk('Additional invalid commands suggested'); + await t.expect(workbenchPage.MonacoEditor.monacoSuggestion.exists).notOk('Additional invalid commands suggested'); const expectedText = `FT.EXPLAIN "${indexName1}" "@city" DIALECT dialectTest`.trim().replace(/\s+/g, ' '); // Verify command entered correctly - await t.expect((await searchAndQueryPage.queryInputForText.innerText).trim().replace(/\s+/g, ' ')).contains(expectedText, 'Incorrect order of entered arguments'); + await t.expect((await workbenchPage.queryInputForText.innerText).trim().replace(/\s+/g, ' ')).contains(expectedText, 'Incorrect order of entered arguments'); }); test('Verify commands suggestions for APPLY and FILTER', async t => { - await t.typeText(searchAndQueryPage.queryInput, 'FT.AGGREGATE ', { replace: true }); + await t.typeText(workbenchPage.queryInput, 'FT.AGGREGATE ', { replace: true }); await t.pressKey('enter'); - await t.typeText(searchAndQueryPage.queryInput, '*'); + await t.typeText(workbenchPage.queryInput, '*'); await t.pressKey('right'); await t.pressKey('space'); // Verify APPLY command - await t.expect(searchAndQueryPage.MonacoEditor.monacoSuggestion.withExactText('APPLY').exists).ok('Apply is not suggested'); + await t.expect(workbenchPage.MonacoEditor.monacoSuggestion.withExactText('APPLY').exists).ok('Apply is not suggested'); await t.pressKey('enter'); - await t.typeText(searchAndQueryPage.queryInput, 'g'); - await t.expect(searchAndQueryPage.MonacoEditor.monacoSuggestion.exists).ok('commands is not suggested'); + await t.typeText(workbenchPage.queryInput, 'g'); + await t.expect(workbenchPage.MonacoEditor.monacoSuggestion.exists).ok('commands is not suggested'); await t.pressKey('enter'); - await t.typeText(searchAndQueryPage.queryInput, '@', { replace: false }); - await t.expect(searchAndQueryPage.MonacoEditor.monacoSuggestion.visible).ok('Suggestions not displayed'); - await t.typeText(searchAndQueryPage.queryInput, 'location', { replace: false }); - await t.typeText(searchAndQueryPage.queryInput, ', \'40.7128,-74.0060\''); + await t.typeText(workbenchPage.queryInput, '@', { replace: false }); + await t.expect(workbenchPage.MonacoEditor.monacoSuggestion.visible).ok('Suggestions not displayed'); + await t.typeText(workbenchPage.queryInput, 'location', { replace: false }); + await t.typeText(workbenchPage.queryInput, ', \'40.7128,-74.0060\''); for (let i = 0; i < 3; i++) { await t.pressKey('right'); } await t.pressKey('space'); await t.pressKey('tab'); - await t.typeText(searchAndQueryPage.queryInput, 'apply_key', { replace: false }); + await t.typeText(workbenchPage.queryInput, 'apply_key', { replace: false }); await t.pressKey('space'); // Verify Filter command - await t.typeText(searchAndQueryPage.queryInput, 'F'); - await t.expect(searchAndQueryPage.MonacoEditor.monacoSuggestion.withExactText('FILTER').exists).ok('FILTER is not suggested'); + await t.typeText(workbenchPage.queryInput, 'F'); + await t.expect(workbenchPage.MonacoEditor.monacoSuggestion.withExactText('FILTER').exists).ok('FILTER is not suggested'); await t.pressKey('enter'); - await t.typeText(searchAndQueryPage.queryInput, 'apply_key < 5000', { replace: false }); + await t.typeText(workbenchPage.queryInput, 'apply_key < 5000', { replace: false }); await t.pressKey('right'); await t.pressKey('space'); - await t.expect(searchAndQueryPage.MonacoEditor.monacoSuggestion.withExactText('GROUPBY').exists).ok('query can not be prolong'); + await t.expect(workbenchPage.MonacoEditor.monacoSuggestion.withExactText('GROUPBY').exists).ok('query can not be prolong'); }); test('Verify REDUCE commands', async t => { - await t.typeText(searchAndQueryPage.queryInput, `FT.AGGREGATE ${indexName1} "*" GROUPBY 1 @location`, { replace: true }); + await t.typeText(workbenchPage.queryInput, `FT.AGGREGATE ${indexName1} "*" GROUPBY 1 @location`, { replace: true }); await t.pressKey('space'); // select Reduce - await t.expect(searchAndQueryPage.MonacoEditor.monacoSuggestion.withExactText('REDUCE').exists).ok('REDUCE is not suggested'); - await t.typeText(searchAndQueryPage.queryInput, 'R'); + await t.expect(workbenchPage.MonacoEditor.monacoSuggestion.withExactText('REDUCE').exists).ok('REDUCE is not suggested'); + await t.typeText(workbenchPage.queryInput, 'R'); await t.pressKey('enter'); // set value of reduce - await t.expect(searchAndQueryPage.MonacoEditor.monacoSuggestion.visible).ok('Suggestions not displayed'); - await t.typeText(searchAndQueryPage.queryInput, 'CO'); + await t.expect(workbenchPage.MonacoEditor.monacoSuggestion.visible).ok('Suggestions not displayed'); + await t.typeText(workbenchPage.queryInput, 'CO'); await t.pressKey('enter'); - await t.typeText(searchAndQueryPage.queryInput, '0'); + await t.typeText(workbenchPage.queryInput, '0'); // verify that count of nargs is correct await t.pressKey('space'); - await t.expect(searchAndQueryPage.MonacoEditor.monacoSuggestion.withExactText('AS').exists).ok('AS is not suggested'); + await t.expect(workbenchPage.MonacoEditor.monacoSuggestion.withExactText('AS').exists).ok('AS is not suggested'); await t.pressKey('enter'); - await t.typeText(searchAndQueryPage.queryInput, 'item_count '); + await t.typeText(workbenchPage.queryInput, 'item_count '); // add additional reduce - await t.expect(searchAndQueryPage.MonacoEditor.monacoSuggestion.withExactText('REDUCE').exists).ok('Apply is not suggested'); - await t.typeText(searchAndQueryPage.queryInput, 'R'); + await t.expect(workbenchPage.MonacoEditor.monacoSuggestion.withExactText('REDUCE').exists).ok('Apply is not suggested'); + await t.typeText(workbenchPage.queryInput, 'R'); await t.pressKey('enter'); - await t.typeText(searchAndQueryPage.queryInput, 'SUM'); + await t.typeText(workbenchPage.queryInput, 'SUM'); await t.pressKey('enter'); - await t.typeText(searchAndQueryPage.queryInput, '1 '); + await t.typeText(workbenchPage.queryInput, '1 '); - await t.typeText(searchAndQueryPage.queryInput, '@', { replace: false }); - await t.expect(searchAndQueryPage.MonacoEditor.monacoSuggestion.visible).ok('Suggestions not displayed'); - await t.typeText(searchAndQueryPage.queryInput, 'students ', { replace: false }); - await t.expect(searchAndQueryPage.MonacoEditor.monacoSuggestion.withExactText('AS').exists).ok('AS is not suggested'); + await t.typeText(workbenchPage.queryInput, '@', { replace: false }); + await t.expect(workbenchPage.MonacoEditor.monacoSuggestion.visible).ok('Suggestions not displayed'); + await t.typeText(workbenchPage.queryInput, 'students ', { replace: false }); + await t.expect(workbenchPage.MonacoEditor.monacoSuggestion.withExactText('AS').exists).ok('AS is not suggested'); await t.pressKey('enter'); - await t.typeText(searchAndQueryPage.queryInput, 'total_students'); + await t.typeText(workbenchPage.queryInput, 'total_students'); }); test('Verify suggestions for fields', async t => { - await t.typeText(searchAndQueryPage.queryInput, 'FT.AGGREGATE ', { replace: true }); - await t.typeText(searchAndQueryPage.queryInput, 'idx1'); + await t.typeText(workbenchPage.queryInput, 'FT.AGGREGATE ', { replace: true }); + await t.typeText(workbenchPage.queryInput, 'idx1'); await t.pressKey('enter'); await t.wait(200); - await t.typeText(searchAndQueryPage.queryInput, '@'); - await t.expect(searchAndQueryPage.MonacoEditor.monacoSuggestion.visible).ok('Suggestions not displayed'); + await t.typeText(workbenchPage.queryInput, '@'); + await t.expect(workbenchPage.MonacoEditor.monacoSuggestion.visible).ok('Suggestions not displayed'); // verify suggestions for geo - await t.typeText(searchAndQueryPage.queryInput, 'l'); + await t.typeText(workbenchPage.queryInput, 'l'); await t.pressKey('tab'); - await t.expect((await searchAndQueryPage.MonacoEditor.getTextFromMonaco()).trim()).eql(`FT.AGGREGATE "${indexName1}" "@location:[lon lat radius unit]"`); + await t.expect((await workbenchPage.MonacoEditor.getTextFromMonaco()).trim()).eql(`FT.AGGREGATE "${indexName1}" "@location:[lon lat radius unit]"`); // verify for numeric - await t.typeText(searchAndQueryPage.queryInput, 'FT.AGGREGATE ', { replace: true }); - await t.typeText(searchAndQueryPage.queryInput, 'idx1'); + await t.typeText(workbenchPage.queryInput, 'FT.AGGREGATE ', { replace: true }); + await t.typeText(workbenchPage.queryInput, 'idx1'); await t.pressKey('enter'); await t.wait(200); - await t.typeText(searchAndQueryPage.queryInput, '@'); - await t.typeText(searchAndQueryPage.queryInput, 's'); + await t.typeText(workbenchPage.queryInput, '@'); + await t.typeText(workbenchPage.queryInput, 's'); await t.pressKey('tab'); - await t.expect((await searchAndQueryPage.MonacoEditor.getTextFromMonaco()).trim()).eql(`FT.AGGREGATE "${indexName1}" "@students:[range]"`); + await t.expect((await workbenchPage.MonacoEditor.getTextFromMonaco()).trim()).eql(`FT.AGGREGATE "${indexName1}" "@students:[range]"`); }); test @@ -348,33 +347,33 @@ test await browserPage.Cli.sendCommandsInCli([`DEL ${keyNames.join(' ')}`, `FT.DROPINDEX ${indexName3}`]); await databaseAPIRequests.deleteStandaloneDatabaseApi(ossStandaloneConfig); })('Verify commands suggestions for CREATE', async t => { - await t.typeText(searchAndQueryPage.queryInput, 'FT.CREATE ', { replace: true }); + await t.typeText(workbenchPage.queryInput, 'FT.CREATE ', { replace: true }); await t.pressKey('enter'); // Verify that indexes are not suggested for FT.CREATE - await t.expect(searchAndQueryPage.MonacoEditor.monacoSuggestion.exists).notOk('Existing index suggested'); + await t.expect(workbenchPage.MonacoEditor.monacoSuggestion.exists).notOk('Existing index suggested'); // Enter index name - await t.typeText(searchAndQueryPage.queryInput, indexName3); + await t.typeText(workbenchPage.queryInput, indexName3); await t.pressKey('space'); // Select FILTER keyword - await t.typeText(searchAndQueryPage.queryInput, 'FI'); + await t.typeText(workbenchPage.queryInput, 'FI'); await t.pressKey('tab'); - await t.typeText(searchAndQueryPage.queryInput, 'filterNew', { replace: false }); + await t.typeText(workbenchPage.queryInput, 'filterNew', { replace: false }); await t.pressKey('space'); // Select SCHEMA keyword - await t.typeText(searchAndQueryPage.queryInput, 'SCH'); + await t.typeText(workbenchPage.queryInput, 'SCH'); await t.pressKey('tab'); - await t.typeText(searchAndQueryPage.queryInput, 'field_name', { replace: false }); + await t.typeText(workbenchPage.queryInput, 'field_name', { replace: false }); await t.pressKey('space'); // Select TEXT keyword - await t.typeText(searchAndQueryPage.queryInput, 'te', { replace: false }); + await t.typeText(workbenchPage.queryInput, 'te', { replace: false }); await t.pressKey('tab'); // Select SORTABLE - await t.typeText(searchAndQueryPage.queryInput, 'so', { replace: false }); + await t.typeText(workbenchPage.queryInput, 'so', { replace: false }); await t.pressKey('tab'); - await t.expect((await searchAndQueryPage.MonacoEditor.getTextFromMonaco()).trim()).eql(`FT.CREATE ${indexName3} FILTER filterNew SCHEMA field_name TEXT SORTABLE`); + await t.expect((await workbenchPage.MonacoEditor.getTextFromMonaco()).trim()).eql(`FT.CREATE ${indexName3} FILTER filterNew SCHEMA field_name TEXT SORTABLE`); }); diff --git a/tests/e2e/tests/web/regression/workbench/autocomplete.e2e.ts b/tests/e2e/tests/web/regression/workbench/autocomplete.e2e.ts index db496c2bc3..6e52835a10 100644 --- a/tests/e2e/tests/web/regression/workbench/autocomplete.e2e.ts +++ b/tests/e2e/tests/web/regression/workbench/autocomplete.e2e.ts @@ -1,4 +1,4 @@ -import { KeysInteractionTabs, rte } from '../../../../helpers/constants'; +import { rte } from '../../../../helpers/constants'; import { DatabaseHelper } from '../../../../helpers/database'; import { BrowserPage, WorkbenchPage } from '../../../../pageObjects'; import { commonUrl, ossStandaloneConfig } from '../../../../helpers/conf'; @@ -15,7 +15,7 @@ fixture `Autocomplete for entered commands` .beforeEach(async t => { await databaseHelper.acceptLicenseTermsAndAddDatabaseApi(ossStandaloneConfig); // Go to Workbench page - await browserPage.KeysInteractionPanel.setActiveTab(KeysInteractionTabs.Workbench); + await t.click(browserPage.NavigationPanel.workbenchButton); }) .afterEach(async() => { // Delete database diff --git a/tests/e2e/tests/web/regression/workbench/autoexecute-button.e2e.ts b/tests/e2e/tests/web/regression/workbench/autoexecute-button.e2e.ts index bff30ffe92..938ffae5c5 100644 --- a/tests/e2e/tests/web/regression/workbench/autoexecute-button.e2e.ts +++ b/tests/e2e/tests/web/regression/workbench/autoexecute-button.e2e.ts @@ -1,6 +1,6 @@ import { DatabaseHelper } from '../../../../helpers/database'; import { WorkbenchPage, BrowserPage } from '../../../../pageObjects'; -import { ExploreTabs, KeysInteractionTabs, rte } from '../../../../helpers/constants'; +import { ExploreTabs, rte } from '../../../../helpers/constants'; import { commonUrl, ossStandaloneConfig } from '../../../../helpers/conf'; import { DatabaseAPIRequests } from '../../../../helpers/api/api-database'; @@ -14,7 +14,7 @@ fixture `Workbench Auto-Execute button` .page(commonUrl) .beforeEach(async t => { await databaseHelper.acceptLicenseTermsAndAddDatabaseApi(ossStandaloneConfig); - await browserPage.KeysInteractionPanel.setActiveTab(KeysInteractionTabs.Workbench); + await t.click(browserPage.NavigationPanel.workbenchButton); }) .afterEach(async() => { // Clear and delete database diff --git a/tests/e2e/tests/web/regression/workbench/command-results.e2e.ts b/tests/e2e/tests/web/regression/workbench/command-results.e2e.ts index 88b58e051e..4d75faf820 100644 --- a/tests/e2e/tests/web/regression/workbench/command-results.e2e.ts +++ b/tests/e2e/tests/web/regression/workbench/command-results.e2e.ts @@ -1,7 +1,7 @@ import { DatabaseHelper } from '../../../../helpers/database'; import { WorkbenchPage, BrowserPage } from '../../../../pageObjects'; import { commonUrl, ossStandaloneRedisearch } from '../../../../helpers/conf'; -import { KeysInteractionTabs, rte } from '../../../../helpers/constants'; +import { rte } from '../../../../helpers/constants'; import { DatabaseAPIRequests } from '../../../../helpers/api/api-database'; import { Common } from '../../../../helpers/common'; import { WorkbenchActions } from '../../../../common-actions/workbench-actions'; @@ -25,7 +25,7 @@ fixture `Command results at Workbench` .beforeEach(async t => { await databaseHelper.acceptLicenseTermsAndAddDatabaseApi(ossStandaloneRedisearch); // Add index and data - await browserPage.KeysInteractionPanel.setActiveTab(KeysInteractionTabs.Workbench); + await t.click(browserPage.NavigationPanel.workbenchButton); await workbenchPage.sendCommandsArrayInWorkbench(commandsForIndex); }) .afterEach(async t => { @@ -114,7 +114,7 @@ test('Big output in workbench is visible in virtualized table', async t => { test .before(async t => { await databaseHelper.acceptLicenseTermsAndAddDatabaseApi(ossStandaloneRedisearch); - await browserPage.KeysInteractionPanel.setActiveTab(KeysInteractionTabs.Workbench); + await t.click(browserPage.NavigationPanel.workbenchButton); }) .after(async t => { await t.switchToMainWindow(); diff --git a/tests/e2e/tests/web/regression/workbench/context.e2e.ts b/tests/e2e/tests/web/regression/workbench/context.e2e.ts index 16a0160f95..914efa16e4 100644 --- a/tests/e2e/tests/web/regression/workbench/context.e2e.ts +++ b/tests/e2e/tests/web/regression/workbench/context.e2e.ts @@ -1,4 +1,4 @@ -import { ExploreTabs, KeysInteractionTabs, rte } from '../../../../helpers/constants'; +import { ExploreTabs, rte } from '../../../../helpers/constants'; import { DatabaseHelper } from '../../../../helpers/database'; import { BrowserPage, MyRedisDatabasePage, WorkbenchPage } from '../../../../pageObjects'; import { commonUrl, ossStandaloneConfig } from '../../../../helpers/conf'; @@ -18,7 +18,7 @@ fixture `Workbench Context` .beforeEach(async t => { await databaseHelper.acceptLicenseTermsAndAddDatabaseApi(ossStandaloneConfig); // Go to Workbench page - await browserPage.KeysInteractionPanel.setActiveTab(KeysInteractionTabs.Workbench); + await t.click(browserPage.NavigationPanel.workbenchButton); }) .afterEach(async() => { // Delete database @@ -27,9 +27,7 @@ fixture `Workbench Context` test('Verify that user can see saved CLI state when navigates away to any other page', async t => { // Expand CLI and navigate to Browser await t.click(workbenchPage.Cli.cliExpandButton); - await t.click(myRedisDatabasePage.NavigationPanel.browserButton); - // Return back to Workbench and check CLI - await browserPage.KeysInteractionPanel.setActiveTab(KeysInteractionTabs.Workbench); + await t.click(browserPage.NavigationPanel.workbenchButton); await t.expect(workbenchPage.Cli.cliCollapseButton.exists).ok('CLI is not expanded'); }); // Update after resolving https://redislabs.atlassian.net/browse/RI-3299 @@ -53,9 +51,7 @@ test('Verify that user can see all the information removed when reloads the page // Create context modificaions and navigate to Browser await t.typeText(workbenchPage.queryInput, command, { replace: true, speed: speed }); await t.click(workbenchPage.Cli.cliExpandButton); - await t.click(myRedisDatabasePage.NavigationPanel.browserButton); - // Open Workbench page and verify context - await browserPage.KeysInteractionPanel.setActiveTab(KeysInteractionTabs.Workbench); + await t.click(browserPage.NavigationPanel.workbenchButton); await t.expect(workbenchPage.Cli.cliCollapseButton.exists).ok('CLI is not expanded'); await t.expect(workbenchPage.queryInputScriptArea.textContent).eql(command, 'Input in Editor is not saved'); // Reload the window and chek context diff --git a/tests/e2e/tests/web/regression/workbench/cypher.e2e.ts b/tests/e2e/tests/web/regression/workbench/cypher.e2e.ts index 13575f7249..2a383a2217 100644 --- a/tests/e2e/tests/web/regression/workbench/cypher.e2e.ts +++ b/tests/e2e/tests/web/regression/workbench/cypher.e2e.ts @@ -1,4 +1,4 @@ -import { KeysInteractionTabs, rte } from '../../../../helpers/constants'; +import { rte } from '../../../../helpers/constants'; import { DatabaseHelper } from '../../../../helpers/database'; import { BrowserPage, WorkbenchPage } from '../../../../pageObjects'; import { commonUrl, ossStandaloneConfig } from '../../../../helpers/conf'; @@ -17,7 +17,7 @@ fixture `Cypher syntax at Workbench` .beforeEach(async t => { await databaseHelper.acceptLicenseTermsAndAddDatabaseApi(ossStandaloneConfig); // Go to Workbench page - await browserPage.KeysInteractionPanel.setActiveTab(KeysInteractionTabs.Workbench); + await t.click(browserPage.NavigationPanel.workbenchButton); }) .afterEach(async() => { // Drop database diff --git a/tests/e2e/tests/web/regression/workbench/default-scripts-area.e2e.ts b/tests/e2e/tests/web/regression/workbench/default-scripts-area.e2e.ts index a0b3e7ff84..7055117953 100644 --- a/tests/e2e/tests/web/regression/workbench/default-scripts-area.e2e.ts +++ b/tests/e2e/tests/web/regression/workbench/default-scripts-area.e2e.ts @@ -1,4 +1,4 @@ -import { ExploreTabs, KeysInteractionTabs, rte } from '../../../../helpers/constants'; +import { ExploreTabs, rte } from '../../../../helpers/constants'; import { DatabaseHelper } from '../../../../helpers/database'; import { BrowserPage, MyRedisDatabasePage, WorkbenchPage } from '../../../../pageObjects'; import { commonUrl, ossStandaloneConfig } from '../../../../helpers/conf'; @@ -16,7 +16,7 @@ fixture `Default scripts area at Workbench` .beforeEach(async t => { await databaseHelper.acceptLicenseTermsAndAddDatabaseApi(ossStandaloneConfig); // Go to Workbench page - await browserPage.KeysInteractionPanel.setActiveTab(KeysInteractionTabs.Workbench); + await t.click(browserPage.NavigationPanel.workbenchButton); }) .afterEach(async() => { // Delete database @@ -70,7 +70,7 @@ test('Verify that user can see saved article in Enablement area when he leaves W // Go to Browser page await t.click(myRedisDatabasePage.NavigationPanel.browserButton); // Go back to Workbench page - await browserPage.KeysInteractionPanel.setActiveTab(KeysInteractionTabs.Workbench); + await t.click(browserPage.NavigationPanel.workbenchButton); // Verify that the same article is opened in Enablement area selector = tutorials.getRunSelector('Create a hash'); await t.expect(selector.visible).ok('The end of the page is not visible'); diff --git a/tests/e2e/tests/web/regression/workbench/editor-cleanup.e2e.ts b/tests/e2e/tests/web/regression/workbench/editor-cleanup.e2e.ts index 244a827ed5..00a0e7908c 100644 --- a/tests/e2e/tests/web/regression/workbench/editor-cleanup.e2e.ts +++ b/tests/e2e/tests/web/regression/workbench/editor-cleanup.e2e.ts @@ -1,6 +1,6 @@ import { DatabaseHelper } from '../../../../helpers/database'; import { WorkbenchPage, MyRedisDatabasePage, SettingsPage, BrowserPage } from '../../../../pageObjects'; -import { KeysInteractionTabs, rte } from '../../../../helpers/constants'; +import { rte } from '../../../../helpers/constants'; import { commonUrl, ossStandaloneConfig } from '../../../../helpers/conf'; import { DatabaseAPIRequests } from '../../../../helpers/api/api-database'; @@ -36,8 +36,7 @@ test('Disabled Editor Cleanup toggle behavior', async t => { // Verify that user can see text "Clear the Editor after running commands" for Editor Cleanup In Settings await t.expect(settingsPage.switchEditorCleanupOption.sibling(0).withExactText('Clear the Editor after running commands').visible).ok('Cleanup text is not correct'); // Go to Workbench page - await t.click(settingsPage.NavigationPanel.browserButton); - await browserPage.KeysInteractionPanel.setActiveTab(KeysInteractionTabs.Workbench); + await t.click(browserPage.NavigationPanel.workbenchButton); // Send commands await workbenchPage.sendCommandInWorkbench(commandToSend); await workbenchPage.sendCommandInWorkbench(commandToSend); @@ -46,7 +45,7 @@ test('Disabled Editor Cleanup toggle behavior', async t => { }); test('Enabled Editor Cleanup toggle behavior', async t => { // Go to Workbench page - await browserPage.KeysInteractionPanel.setActiveTab(KeysInteractionTabs.Workbench); + await t.click(browserPage.NavigationPanel.workbenchButton); // Send commands await workbenchPage.sendCommandInWorkbench(commandToSend); await workbenchPage.sendCommandInWorkbench(commandToSend); diff --git a/tests/e2e/tests/web/regression/workbench/empty-command-history.e2e.ts b/tests/e2e/tests/web/regression/workbench/empty-command-history.e2e.ts index 5071c5ae1d..1dd753d9f3 100644 --- a/tests/e2e/tests/web/regression/workbench/empty-command-history.e2e.ts +++ b/tests/e2e/tests/web/regression/workbench/empty-command-history.e2e.ts @@ -1,5 +1,5 @@ import { Selector } from 'testcafe'; -import { KeysInteractionTabs, rte } from '../../../../helpers/constants'; +import { rte } from '../../../../helpers/constants'; import { DatabaseHelper } from '../../../../helpers/database'; import { BrowserPage, WorkbenchPage } from '../../../../pageObjects'; import { commonUrl, ossStandaloneConfig } from '../../../../helpers/conf'; @@ -16,7 +16,7 @@ fixture `Empty command history in Workbench` .beforeEach(async t => { await databaseHelper.acceptLicenseTermsAndAddDatabaseApi(ossStandaloneConfig); // Go to Workbench page - await browserPage.KeysInteractionPanel.setActiveTab(KeysInteractionTabs.Workbench); + await t.click(browserPage.NavigationPanel.workbenchButton); }) .afterEach(async() => { // Delete database diff --git a/tests/e2e/tests/web/regression/workbench/group-mode.e2e.ts b/tests/e2e/tests/web/regression/workbench/group-mode.e2e.ts index 64c0cd0bb7..80f2e24fc5 100644 --- a/tests/e2e/tests/web/regression/workbench/group-mode.e2e.ts +++ b/tests/e2e/tests/web/regression/workbench/group-mode.e2e.ts @@ -1,5 +1,5 @@ import { Selector } from 'testcafe'; -import { KeysInteractionTabs, rte } from '../../../../helpers/constants'; +import { rte } from '../../../../helpers/constants'; import { DatabaseHelper } from '../../../../helpers/database'; import { BrowserPage, WorkbenchPage } from '../../../../pageObjects'; import { commonUrl, ossStandaloneBigConfig } from '../../../../helpers/conf'; @@ -23,7 +23,7 @@ fixture `Workbench Group Mode` .beforeEach(async t => { await databaseHelper.acceptLicenseTermsAndAddDatabaseApi(ossStandaloneBigConfig); // Go to Workbench page - await browserPage.KeysInteractionPanel.setActiveTab(KeysInteractionTabs.Workbench); + await t.click(browserPage.NavigationPanel.workbenchButton); }) .afterEach(async() => { // Delete database diff --git a/tests/e2e/tests/web/regression/workbench/history-of-results.e2e.ts b/tests/e2e/tests/web/regression/workbench/history-of-results.e2e.ts index fe0a0d024a..21303ac99e 100644 --- a/tests/e2e/tests/web/regression/workbench/history-of-results.e2e.ts +++ b/tests/e2e/tests/web/regression/workbench/history-of-results.e2e.ts @@ -1,7 +1,7 @@ import { getRandomParagraph } from '../../../../helpers/keys'; import { DatabaseHelper } from '../../../../helpers/database'; import { BrowserPage, WorkbenchPage } from '../../../../pageObjects'; -import { KeysInteractionTabs, rte } from '../../../../helpers/constants'; +import { rte } from '../../../../helpers/constants'; import { commonUrl, ossStandaloneConfig } from '../../../../helpers/conf'; import { DatabaseAPIRequests } from '../../../../helpers/api/api-database'; import { Common } from '../../../../helpers/common'; @@ -21,7 +21,7 @@ fixture `History of results at Workbench` .beforeEach(async t => { await databaseHelper.acceptLicenseTermsAndAddDatabaseApi(ossStandaloneConfig); // Go to Workbench page - await browserPage.KeysInteractionPanel.setActiveTab(KeysInteractionTabs.Workbench); + await t.click(browserPage.NavigationPanel.workbenchButton); }) .afterEach(async() => { // Clear and delete database diff --git a/tests/e2e/tests/web/regression/workbench/raw-mode.e2e.ts b/tests/e2e/tests/web/regression/workbench/raw-mode.e2e.ts index 94b08c001e..efdec7bc15 100644 --- a/tests/e2e/tests/web/regression/workbench/raw-mode.e2e.ts +++ b/tests/e2e/tests/web/regression/workbench/raw-mode.e2e.ts @@ -1,6 +1,6 @@ import { DatabaseHelper } from '../../../../helpers/database'; import { WorkbenchPage, MyRedisDatabasePage, BrowserPage } from '../../../../pageObjects'; -import { KeysInteractionTabs, rte } from '../../../../helpers/constants'; +import { rte } from '../../../../helpers/constants'; import { commonUrl, ossStandaloneConfig, ossStandaloneRedisearch } from '../../../../helpers/conf'; import { DatabaseAPIRequests } from '../../../../helpers/api/api-database'; import { Common } from '../../../../helpers/common'; @@ -32,7 +32,7 @@ fixture `Workbench Raw mode` .beforeEach(async t => { await databaseHelper.acceptLicenseTermsAndAddDatabaseApi(ossStandaloneConfig); // Go to Workbench page - await browserPage.KeysInteractionPanel.setActiveTab(KeysInteractionTabs.Workbench); + await t.click(browserPage.NavigationPanel.workbenchButton); }) .afterEach(async t => { // Clear and delete database @@ -65,7 +65,7 @@ test await myRedisDatabasePage.reloadPage(); await myRedisDatabasePage.clickOnDBByName(databasesForAdding[0].databaseName); // Go to Workbench page - await browserPage.KeysInteractionPanel.setActiveTab(KeysInteractionTabs.Workbench); + await t.click(browserPage.NavigationPanel.workbenchButton); }) .after(async() => { // Clear and delete database @@ -82,7 +82,7 @@ test await t.click(myRedisDatabasePage.NavigationPanel.myRedisDBButton); await myRedisDatabasePage.clickOnDBByName(databasesForAdding[1].databaseName); // Go to Workbench page - await browserPage.KeysInteractionPanel.setActiveTab(KeysInteractionTabs.Workbench); + await t.click(browserPage.NavigationPanel.workbenchButton); // Verify that user can see saved Raw mode state after re-connection to another DB await workbenchPage.sendCommandInWorkbench(commandsForSend[1]); await workbenchPage.checkWorkbenchCommandResult(commandsForSend[1], `"${unicodeValue}"`); @@ -94,7 +94,7 @@ test .before(async t => { await databaseHelper.acceptLicenseTermsAndAddDatabaseApi(ossStandaloneRedisearch); // Go to Workbench page - await browserPage.KeysInteractionPanel.setActiveTab(KeysInteractionTabs.Workbench); + await t.click(browserPage.NavigationPanel.workbenchButton); }) .after(async t => { // Drop index, documents and database diff --git a/tests/e2e/tests/web/regression/workbench/redis-stack-commands.e2e.ts b/tests/e2e/tests/web/regression/workbench/redis-stack-commands.e2e.ts index 7921974f72..2e40dc6d5c 100644 --- a/tests/e2e/tests/web/regression/workbench/redis-stack-commands.e2e.ts +++ b/tests/e2e/tests/web/regression/workbench/redis-stack-commands.e2e.ts @@ -2,7 +2,7 @@ import { t } from 'testcafe'; import { DatabaseHelper } from '../../../../helpers/database'; import { WorkbenchPage, BrowserPage } from '../../../../pageObjects'; import { commonUrl, ossStandaloneConfig } from '../../../../helpers/conf'; -import { ExploreTabs, KeysInteractionTabs, rte } from '../../../../helpers/constants'; +import { ExploreTabs, rte } from '../../../../helpers/constants'; import { DatabaseAPIRequests } from '../../../../helpers/api/api-database'; const browserPage = new BrowserPage(); @@ -17,7 +17,7 @@ fixture `Redis Stack command in Workbench` .page(commonUrl) .beforeEach(async t => { await databaseHelper.acceptLicenseTermsAndAddDatabaseApi(ossStandaloneConfig); - await browserPage.KeysInteractionPanel.setActiveTab(KeysInteractionTabs.Workbench); + await t.click(browserPage.NavigationPanel.workbenchButton); }) .afterEach(async() => { // Drop key and database diff --git a/tests/e2e/tests/web/regression/workbench/redisearch-module-not-available.e2e.ts b/tests/e2e/tests/web/regression/workbench/redisearch-module-not-available.e2e.ts index 19db310ce0..6aff416aa2 100644 --- a/tests/e2e/tests/web/regression/workbench/redisearch-module-not-available.e2e.ts +++ b/tests/e2e/tests/web/regression/workbench/redisearch-module-not-available.e2e.ts @@ -1,5 +1,5 @@ import { ClientFunction } from 'testcafe'; -import { KeysInteractionTabs, rte } from '../../../../helpers/constants'; +import { rte } from '../../../../helpers/constants'; import { DatabaseHelper } from '../../../../helpers/database'; import { BrowserPage, WorkbenchPage } from '../../../../pageObjects'; import { commonUrl, ossStandaloneV5Config } from '../../../../helpers/conf'; @@ -18,7 +18,7 @@ fixture `Redisearch module not available` .page(commonUrl) .beforeEach(async t => { await databaseHelper.acceptLicenseTermsAndAddDatabaseApi(ossStandaloneV5Config); - await browserPage.KeysInteractionPanel.setActiveTab(KeysInteractionTabs.Workbench); + await t.click(browserPage.NavigationPanel.workbenchButton); }) .afterEach(async() => { // Delete database diff --git a/tests/e2e/tests/web/regression/workbench/scripting-area.e2e.ts b/tests/e2e/tests/web/regression/workbench/scripting-area.e2e.ts index 20e5783eaa..c15dbec54d 100644 --- a/tests/e2e/tests/web/regression/workbench/scripting-area.e2e.ts +++ b/tests/e2e/tests/web/regression/workbench/scripting-area.e2e.ts @@ -1,4 +1,4 @@ -import { ExploreTabs, KeysInteractionTabs, rte } from '../../../../helpers/constants'; +import { ExploreTabs, rte } from '../../../../helpers/constants'; import { DatabaseHelper } from '../../../../helpers/database'; import { MyRedisDatabasePage, WorkbenchPage, SettingsPage, BrowserPage } from '../../../../pageObjects'; import { commonUrl, ossStandaloneConfig } from '../../../../helpers/conf'; @@ -21,7 +21,7 @@ fixture `Scripting area at Workbench` .beforeEach(async t => { await databaseHelper.acceptLicenseTermsAndAddDatabaseApi(ossStandaloneConfig); // Go to Workbench page - await browserPage.KeysInteractionPanel.setActiveTab(KeysInteractionTabs.Workbench); + await t.click(browserPage.NavigationPanel.workbenchButton); }) .afterEach(async() => { // Clear and delete database @@ -42,8 +42,7 @@ test('Verify that user can run multiple commands written in multiple lines in Wo await t.click(settingsPage.accordionWorkbenchSettings); await settingsPage.changeCommandsInPipeline('1'); // Go to Workbench page - await t.click(settingsPage.NavigationPanel.browserButton); - await browserPage.KeysInteractionPanel.setActiveTab(KeysInteractionTabs.Workbench); + await t.click(browserPage.NavigationPanel.workbenchButton); // Send commands in multiple lines await workbenchPage.sendCommandInWorkbench(commandsForSend.join('\n'), 0.5); // Check the result @@ -70,8 +69,7 @@ test await t.click(settingsPage.accordionWorkbenchSettings); await settingsPage.changeCommandsInPipeline('1'); // Go to Workbench page - await t.click(settingsPage.NavigationPanel.browserButton); - await browserPage.KeysInteractionPanel.setActiveTab(KeysInteractionTabs.Workbench); + await t.click(settingsPage.NavigationPanel.workbenchButton); // Send commands in multiple lines with double slashes (//) wrapped in double quotes await workbenchPage.sendCommandInWorkbench(commandsForSend.join('\n"//"'), 0.5); // Check that all commands are executed diff --git a/tests/e2e/tests/web/regression/workbench/workbench-all-db-types.e2e.ts b/tests/e2e/tests/web/regression/workbench/workbench-all-db-types.e2e.ts index 59de3d7644..b199d73987 100644 --- a/tests/e2e/tests/web/regression/workbench/workbench-all-db-types.e2e.ts +++ b/tests/e2e/tests/web/regression/workbench/workbench-all-db-types.e2e.ts @@ -1,5 +1,5 @@ import { t } from 'testcafe'; -import { KeysInteractionTabs, rte } from '../../../../helpers/constants'; +import { rte } from '../../../../helpers/constants'; import { DatabaseHelper } from '../../../../helpers/database'; import { BrowserPage, MyRedisDatabasePage, WorkbenchPage } from '../../../../pageObjects'; import { cloudDatabaseConfig, commonUrl, ossClusterConfig, ossSentinelConfig } from '../../../../helpers/conf'; @@ -21,7 +21,7 @@ const verifyCommandsInWorkbench = async(): Promise => { ]; await t.click(myRedisDatabasePage.NavigationPanel.browserButton); - await browserPage.KeysInteractionPanel.setActiveTab(KeysInteractionTabs.Workbench); + await t.click(browserPage.NavigationPanel.workbenchButton); // Send commands await workbenchPage.sendCommandInWorkbench(commandForSend1); await workbenchPage.sendCommandInWorkbench(commandForSend2); diff --git a/tests/e2e/tests/web/regression/workbench/workbench-non-auto-guides.e2e.ts b/tests/e2e/tests/web/regression/workbench/workbench-non-auto-guides.e2e.ts index b920f2b265..e5d8b550e6 100644 --- a/tests/e2e/tests/web/regression/workbench/workbench-non-auto-guides.e2e.ts +++ b/tests/e2e/tests/web/regression/workbench/workbench-non-auto-guides.e2e.ts @@ -1,6 +1,6 @@ import { DatabaseHelper } from '../../../../helpers/database'; import { WorkbenchPage, MyRedisDatabasePage, BrowserPage } from '../../../../pageObjects'; -import { KeysInteractionTabs, rte } from '../../../../helpers/constants'; +import { rte } from '../../../../helpers/constants'; import { commonUrl, ossStandaloneConfig } from '../../../../helpers/conf'; import { DatabaseAPIRequests } from '../../../../helpers/api/api-database'; import { Common } from '../../../../helpers/common'; @@ -38,7 +38,7 @@ fixture `Workbench modes to non-auto guides` .page(commonUrl) .beforeEach(async t => { await databaseHelper.acceptLicenseTermsAndAddDatabaseApi(ossStandaloneConfig); - await browserPage.KeysInteractionPanel.setActiveTab(KeysInteractionTabs.Workbench); + await t.click(browserPage.NavigationPanel.workbenchButton); }) .afterEach(async() => { // Delete database @@ -47,7 +47,7 @@ fixture `Workbench modes to non-auto guides` test .before(async t => { await databaseHelper.acceptLicenseTermsAndAddDatabaseApi(ossStandaloneConfig); - await browserPage.KeysInteractionPanel.setActiveTab(KeysInteractionTabs.Workbench); + await t.click(browserPage.NavigationPanel.workbenchButton); await workbenchPage.sendCommandInWorkbench(`set ${keyName} "${keyValue}"`); }) .after(async t => { diff --git a/tests/e2e/tests/web/regression/workbench/workbench-pipeline.e2e.ts b/tests/e2e/tests/web/regression/workbench/workbench-pipeline.e2e.ts index fc97f27f8a..de0906c84d 100644 --- a/tests/e2e/tests/web/regression/workbench/workbench-pipeline.e2e.ts +++ b/tests/e2e/tests/web/regression/workbench/workbench-pipeline.e2e.ts @@ -1,5 +1,4 @@ -// import { ClientFunction } from 'testcafe'; -import { KeysInteractionTabs, rte } from '../../../../helpers/constants'; +import { rte } from '../../../../helpers/constants'; import { DatabaseHelper } from '../../../../helpers/database'; import { BrowserPage, MyRedisDatabasePage, SettingsPage, WorkbenchPage } from '../../../../pageObjects'; import { commonUrl, ossStandaloneBigConfig } from '../../../../helpers/conf'; @@ -51,7 +50,7 @@ test.skip('Verify that only chosen in pipeline number of commands is loading at await settingsPage.changeCommandsInPipeline(pipelineValues[1]); // Go to Workbench page await t.click(settingsPage.NavigationPanel.browserButton); - await browserPage.KeysInteractionPanel.setActiveTab(KeysInteractionTabs.Workbench); + await t.click(browserPage.NavigationPanel.workbenchButton); await workbenchPage.sendCommandInWorkbench(commandForSend, 0.01); // Verify that only selected pipeline number of commands are loaded at the same time await t.expect(workbenchPage.loadedCommand.count).eql(Number(pipelineValues[1]), 'The number of sending commands is incorrect'); @@ -60,7 +59,7 @@ test.skip('Verify that user can see spinner over Run button and grey preloader f await settingsPage.changeCommandsInPipeline(pipelineValues[3]); // Go to Workbench page await t.click(settingsPage.NavigationPanel.browserButton); - await browserPage.KeysInteractionPanel.setActiveTab(KeysInteractionTabs.Workbench); + await t.click(browserPage.NavigationPanel.workbenchButton); await workbenchPage.sendCommandInWorkbench(commandForSend, 0.01); // Verify that user can`t start new commands from the Workbench while command(s) is executing await t.expect(workbenchPage.submitCommandButton.withAttribute('disabled').exists).ok('Run button is not disabled', { timeout: 5000 }); @@ -74,7 +73,7 @@ test('Verify that user can interact with the Editor while command(s) in progress await settingsPage.changeCommandsInPipeline(pipelineValues[2]); // Go to Workbench page await t.click(settingsPage.NavigationPanel.browserButton); - await browserPage.KeysInteractionPanel.setActiveTab(KeysInteractionTabs.Workbench); + await t.click(browserPage.NavigationPanel.workbenchButton); await workbenchPage.sendCommandInWorkbench(commandForSend); await t.typeText(workbenchPage.queryInput, commandForSend, { replace: true, paste: true }); await t.pressKey('enter'); @@ -93,8 +92,7 @@ test('Verify that command results are added to history in order most recent - on await settingsPage.changeCommandsInPipeline(pipelineValues[2]); // Go to Workbench page - await t.click(settingsPage.NavigationPanel.browserButton); - await browserPage.KeysInteractionPanel.setActiveTab(KeysInteractionTabs.Workbench); + await t.click(browserPage.NavigationPanel.workbenchButton); await workbenchPage.sendCommandInWorkbench(multipleCommands.join('\n')); // Check that the results for all commands are displayed in workbench history in reverse order (most recent - on top) for (let i = 0; i < multipleCommands.length; i++) { diff --git a/tests/e2e/tests/web/regression/workbench/workbench-tab.e2e.ts b/tests/e2e/tests/web/regression/workbench/workbench-tab.e2e.ts deleted file mode 100644 index 1091652ead..0000000000 --- a/tests/e2e/tests/web/regression/workbench/workbench-tab.e2e.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { ExploreTabs, KeysInteractionTabs, rte } from '../../../../helpers/constants'; -import { DatabaseHelper } from '../../../../helpers/database'; -import { BrowserPage } from '../../../../pageObjects'; -import { commonUrl, ossStandaloneConfig } from '../../../../helpers/conf'; -import { DatabaseAPIRequests } from '../../../../helpers/api/api-database'; - -const databaseHelper = new DatabaseHelper(); -const databaseAPIRequests = new DatabaseAPIRequests(); -const browserPage = new BrowserPage(); - -fixture `Autocomplete for entered commands` - .meta({ type: 'regression', rte: rte.standalone }) - .page(commonUrl) - .beforeEach(async t => { - await databaseHelper.acceptLicenseTermsAndAddDatabaseApi(ossStandaloneConfig); - }) - .afterEach(async() => { - // Delete database - await databaseAPIRequests.deleteStandaloneDatabaseApi(ossStandaloneConfig); - }); -test('Verify that tutorials can be opened from Workbench', async t => { - const workbench = await browserPage.KeysInteractionPanel.setActiveTab(KeysInteractionTabs.Workbench); - await t.click(workbench.getTutorialLinkLocator('redis_use_cases_basic')); - await t.expect(workbench.InsightsPanel.sidePanel.exists).ok('Insight panel is not opened'); - const tab = await browserPage.InsightsPanel.setActiveTab(ExploreTabs.Tutorials); - await t.expect(tab.preselectArea.textContent).contains('BASIC REDIS USE CASES', 'the tutorial page is incorrect'); -}); diff --git a/tests/e2e/tests/web/smoke/workbench/json-workbench.e2e.ts b/tests/e2e/tests/web/smoke/workbench/json-workbench.e2e.ts index 735d3226a2..f1f39d04cc 100644 --- a/tests/e2e/tests/web/smoke/workbench/json-workbench.e2e.ts +++ b/tests/e2e/tests/web/smoke/workbench/json-workbench.e2e.ts @@ -1,4 +1,4 @@ -import { KeysInteractionTabs, rte } from '../../../../helpers/constants'; +import { rte } from '../../../../helpers/constants'; import { DatabaseHelper } from '../../../../helpers/database'; import { BrowserPage, WorkbenchPage } from '../../../../pageObjects'; import { commonUrl, ossStandaloneRedisearch } from '../../../../helpers/conf'; @@ -18,7 +18,7 @@ fixture `JSON verifications at Workbench` .beforeEach(async t => { await databaseHelper.acceptLicenseTermsAndAddDatabaseApi(ossStandaloneRedisearch); // Go to Workbench page - await browserPage.KeysInteractionPanel.setActiveTab(KeysInteractionTabs.Workbench); + await t.click(browserPage.NavigationPanel.workbenchButton); }) .afterEach(async t => { // Clear and delete database diff --git a/tests/e2e/tests/web/smoke/workbench/scripting-area.e2e.ts b/tests/e2e/tests/web/smoke/workbench/scripting-area.e2e.ts index 0a8eae3019..8220170b74 100644 --- a/tests/e2e/tests/web/smoke/workbench/scripting-area.e2e.ts +++ b/tests/e2e/tests/web/smoke/workbench/scripting-area.e2e.ts @@ -1,7 +1,7 @@ import { DatabaseHelper } from '../../../../helpers/database'; import { BrowserPage, WorkbenchPage } from '../../../../pageObjects'; import { commonUrl, ossStandaloneConfig } from '../../../../helpers/conf'; -import { KeysInteractionTabs, rte } from '../../../../helpers/constants'; +import { rte } from '../../../../helpers/constants'; import { DatabaseAPIRequests } from '../../../../helpers/api/api-database'; const browserPage = new BrowserPage(); @@ -15,7 +15,7 @@ fixture `Scripting area at Workbench` .beforeEach(async t => { await databaseHelper.acceptLicenseTermsAndAddDatabaseApi(ossStandaloneConfig); // Go to Workbench page - await browserPage.KeysInteractionPanel.setActiveTab(KeysInteractionTabs.Workbench); + await t.click(browserPage.NavigationPanel.workbenchButton); }) .afterEach(async() => { // Delete database From bc1f40ef15792ad2e00dbe2aa87f63f7eee06510 Mon Sep 17 00:00:00 2001 From: kchepikava Date: Fri, 11 Oct 2024 11:30:21 +0200 Subject: [PATCH 143/256] RI-6141 await rdiClient before updating --- .../api/src/modules/rdi/providers/rdi.client.provider.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/redisinsight/api/src/modules/rdi/providers/rdi.client.provider.ts b/redisinsight/api/src/modules/rdi/providers/rdi.client.provider.ts index 9b5a9ca863..7b1df36310 100644 --- a/redisinsight/api/src/modules/rdi/providers/rdi.client.provider.ts +++ b/redisinsight/api/src/modules/rdi/providers/rdi.client.provider.ts @@ -36,7 +36,7 @@ export class RdiClientProvider { this.logger.error(`RDI with ${clientMetadata.id} was not Found`); throw new NotFoundException(ERROR_MESSAGES.INVALID_RDI_INSTANCE_ID); } - const rdiClient = this.rdiClientFactory.createClient(clientMetadata, rdi); + const rdiClient = await this.rdiClientFactory.createClient(clientMetadata, rdi); if (rdiClient) { this.updateLastConnection(clientMetadata); } From 5ad96cdbfa2887e2bd86e70bd96c631795fa4b0f Mon Sep 17 00:00:00 2001 From: ViktarStarastsenka <99594890+ViktarStarastsenka@users.noreply.github.com> Date: Fri, 11 Oct 2024 13:04:38 +0200 Subject: [PATCH 144/256] Update README.md --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index 8208c46c7d..9d739cce96 100644 --- a/README.md +++ b/README.md @@ -54,6 +54,9 @@ If you have any issues occurring in Redis Insight, you can follow the steps belo * [How to debug](https://github.com/RedisInsight/RedisInsight/wiki/How-to-debug) +## Redis Insight API (only for Docker) +http://localhost:5540/api/docs + ## Feedback * Request a new [feature](https://github.com/RedisInsight/RedisInsight/issues/new?assignees=&labels=&template=feature_request.md&title=%5BFeature+Request%5D%3A) From 7ae2b2e35f09885b85172161600a71dfb0628dfd Mon Sep 17 00:00:00 2001 From: mariasergeenko Date: Fri, 11 Oct 2024 13:58:03 +0200 Subject: [PATCH 145/256] fix part of tests --- tests/e2e/pageObjects/workbench-page.ts | 2 +- .../regression/search-and-query/no-indexes-suggestions.e2e.ts | 4 ++-- .../regression/search-and-query/search-and-query-tab.e2e.ts | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/e2e/pageObjects/workbench-page.ts b/tests/e2e/pageObjects/workbench-page.ts index 633af2da2b..60ba3cea29 100644 --- a/tests/e2e/pageObjects/workbench-page.ts +++ b/tests/e2e/pageObjects/workbench-page.ts @@ -95,7 +95,7 @@ export class WorkbenchPage extends InstancePage { queryTextResult = Selector(this.cssQueryTextResult); getTutorialLinkLocator = (tutorialName: string): Selector => - Selector(`[data-testid=query-tutorials-link_${tutorialName}]`); + Selector(`[data-testid=query-tutorials-link_${tutorialName}]`, { timeout: 1000 } ); // Select view option in Workbench results diff --git a/tests/e2e/tests/web/regression/search-and-query/no-indexes-suggestions.e2e.ts b/tests/e2e/tests/web/regression/search-and-query/no-indexes-suggestions.e2e.ts index 3b6f4ec665..ac2a27038c 100644 --- a/tests/e2e/tests/web/regression/search-and-query/no-indexes-suggestions.e2e.ts +++ b/tests/e2e/tests/web/regression/search-and-query/no-indexes-suggestions.e2e.ts @@ -23,10 +23,10 @@ test })('Verify suggestions when there are no indexes', async t => { - // TODO add navigation to search and query Monaco + await t.click(browserPage.NavigationPanel.workbenchButton); await t.typeText(workbenchPage.queryInput, 'FT.SE', { replace: true }); - await t.pressKey('enter'); + await t.pressKey('tab'); await t.expect(workbenchPage.MonacoEditor.monacoSuggestion.withExactText('No indexes to display').exists).ok('info text is not displayed'); diff --git a/tests/e2e/tests/web/regression/search-and-query/search-and-query-tab.e2e.ts b/tests/e2e/tests/web/regression/search-and-query/search-and-query-tab.e2e.ts index 0670de33ea..d7a8db68f3 100644 --- a/tests/e2e/tests/web/regression/search-and-query/search-and-query-tab.e2e.ts +++ b/tests/e2e/tests/web/regression/search-and-query/search-and-query-tab.e2e.ts @@ -61,7 +61,7 @@ test('Verify that user can use show more to see command fully in 2nd tooltip', a 'required query', 'optional [verbatim]' ]; - await t.typeText(workbenchPage.queryInput, 'FT', { replace: true }); + await t.typeText(workbenchPage.queryInput, 'FT.A', { replace: true }); // Verify that user can use show more to see command fully in 2nd tooltip await t.pressKey('ctrl+space'); await t.expect(workbenchPage.MonacoEditor.monacoCommandDetails.exists).ok('The "read more" about the command is not opened'); @@ -87,7 +87,7 @@ test('Verify full commands suggestions with index and query for FT.AGGREGATE', a // Verify basic commands suggestions FT.SEARCH and FT.AGGREGATE await t.typeText(workbenchPage.queryInput, 'FT', { replace: true }); // Verify that the list with FT.SEARCH and FT.AGGREGATE auto-suggestions is displayed - await t.expect(workbenchPage.MonacoEditor.monacoSuggestion.withText('FT.SEARCH').exists).ok('FT.SEARCH auto-suggestions are not displayed'); + await t.expect(workbenchPage.MonacoEditor.monacoSuggestion.withText('FT._LIST').exists).ok('FT._LIST auto-suggestions are not displayed'); await t.expect(workbenchPage.MonacoEditor.monacoSuggestion.withText('FT.AGGREGATE').exists).ok('FT.AGGREGATE auto-suggestions are not displayed'); // Select command and check result From ae8bb0e2668c4067e0926605f46699537a186f84 Mon Sep 17 00:00:00 2001 From: mariasergeenko Date: Fri, 11 Oct 2024 15:02:25 +0200 Subject: [PATCH 146/256] temp fix --- .../regression/search-and-query/no-indexes-suggestions.e2e.ts | 1 + .../web/regression/search-and-query/search-and-query-tab.e2e.ts | 1 + 2 files changed, 2 insertions(+) diff --git a/tests/e2e/tests/web/regression/search-and-query/no-indexes-suggestions.e2e.ts b/tests/e2e/tests/web/regression/search-and-query/no-indexes-suggestions.e2e.ts index ac2a27038c..f8d39232be 100644 --- a/tests/e2e/tests/web/regression/search-and-query/no-indexes-suggestions.e2e.ts +++ b/tests/e2e/tests/web/regression/search-and-query/no-indexes-suggestions.e2e.ts @@ -24,6 +24,7 @@ test })('Verify suggestions when there are no indexes', async t => { await t.click(browserPage.NavigationPanel.workbenchButton); + await t.pressKey('ctrl+space'); await t.typeText(workbenchPage.queryInput, 'FT.SE', { replace: true }); await t.pressKey('tab'); diff --git a/tests/e2e/tests/web/regression/search-and-query/search-and-query-tab.e2e.ts b/tests/e2e/tests/web/regression/search-and-query/search-and-query-tab.e2e.ts index d7a8db68f3..870252c6cf 100644 --- a/tests/e2e/tests/web/regression/search-and-query/search-and-query-tab.e2e.ts +++ b/tests/e2e/tests/web/regression/search-and-query/search-and-query-tab.e2e.ts @@ -37,6 +37,7 @@ fixture `Autocomplete for entered commands in search and query` // Create 3 keys and index await browserPage.Cli.sendCommandsInCli(commands); await t.click(browserPage.NavigationPanel.workbenchButton); + await t.pressKey('ctrl+space'); }) .afterEach(async() => { // Clear and delete database From 53652d5b6d89724c812f8f65603a639ef1a59641 Mon Sep 17 00:00:00 2001 From: mariasergeenko Date: Fri, 11 Oct 2024 15:07:17 +0200 Subject: [PATCH 147/256] recommendation fix --- .../tests/web/regression/insights/live-recommendations.e2e.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/e2e/tests/web/regression/insights/live-recommendations.e2e.ts b/tests/e2e/tests/web/regression/insights/live-recommendations.e2e.ts index 782b61a556..a2bf9b3db3 100644 --- a/tests/e2e/tests/web/regression/insights/live-recommendations.e2e.ts +++ b/tests/e2e/tests/web/regression/insights/live-recommendations.e2e.ts @@ -263,6 +263,7 @@ test await databaseAPIRequests.deleteStandaloneDatabasesApi(databasesForAdding); })('Verify that key name is displayed for Insights and DA recommendations', async t => { const cliCommand = `JSON.SET ${keyName} $ '{ "model": "Hyperion", "brand": "Velorim"}'`; + await browserPage.Cli.sendCommandInCli('flushdb'); await browserPage.Cli.sendCommandInCli(cliCommand); await t.click(browserPage.refreshKeysButton); await browserPage.NavigationHeader.togglePanel(true); From 7ee2d73abe7412c905b6a31c3abea751658a591a Mon Sep 17 00:00:00 2001 From: mariasergeenko Date: Fri, 11 Oct 2024 15:08:59 +0200 Subject: [PATCH 148/256] fix for tutorials --- .../web/regression/search-and-query/search-and-query-tab.e2e.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/e2e/tests/web/regression/search-and-query/search-and-query-tab.e2e.ts b/tests/e2e/tests/web/regression/search-and-query/search-and-query-tab.e2e.ts index 870252c6cf..2ea8711d2f 100644 --- a/tests/e2e/tests/web/regression/search-and-query/search-and-query-tab.e2e.ts +++ b/tests/e2e/tests/web/regression/search-and-query/search-and-query-tab.e2e.ts @@ -48,7 +48,7 @@ fixture `Autocomplete for entered commands in search and query` }); test('Verify that tutorials can be opened from Workbench', async t => { await t.click(browserPage.NavigationPanel.workbenchButton); - await t.click(workbenchPage.getTutorialLinkLocator('sq-exact-match')); + await t.click(workbenchPage.getTutorialLinkLocator('_sq-intro')); await t.expect(workbenchPage.InsightsPanel.sidePanel.exists).ok('Insight panel is not opened'); const tab = await browserPage.InsightsPanel.setActiveTab(ExploreTabs.Tutorials); await t.expect(tab.preselectArea.textContent).contains('EXACT MATCH', 'the tutorial page is incorrect'); From 1906e15358ebfc5453916d008b303c4983a220c9 Mon Sep 17 00:00:00 2001 From: mariasergeenko Date: Fri, 11 Oct 2024 15:10:10 +0200 Subject: [PATCH 149/256] fix for tutorials#2 --- .../web/regression/search-and-query/search-and-query-tab.e2e.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/e2e/tests/web/regression/search-and-query/search-and-query-tab.e2e.ts b/tests/e2e/tests/web/regression/search-and-query/search-and-query-tab.e2e.ts index 2ea8711d2f..494b74aa5c 100644 --- a/tests/e2e/tests/web/regression/search-and-query/search-and-query-tab.e2e.ts +++ b/tests/e2e/tests/web/regression/search-and-query/search-and-query-tab.e2e.ts @@ -48,7 +48,7 @@ fixture `Autocomplete for entered commands in search and query` }); test('Verify that tutorials can be opened from Workbench', async t => { await t.click(browserPage.NavigationPanel.workbenchButton); - await t.click(workbenchPage.getTutorialLinkLocator('_sq-intro')); + await t.click(workbenchPage.getTutorialLinkLocator('sq-intro')); await t.expect(workbenchPage.InsightsPanel.sidePanel.exists).ok('Insight panel is not opened'); const tab = await browserPage.InsightsPanel.setActiveTab(ExploreTabs.Tutorials); await t.expect(tab.preselectArea.textContent).contains('EXACT MATCH', 'the tutorial page is incorrect'); From ba3001b604e92d298f39eb5bd6e93362eae41b3f Mon Sep 17 00:00:00 2001 From: Roman Sergeenko Date: Fri, 11 Oct 2024 16:31:00 +0200 Subject: [PATCH 150/256] #RI-6173, #RI-6177, #RI-6178, #RI-6182, #RI-6183 - fix bugs --- .../components/query/Query/Query.tsx | 10 +++++- .../ui/src/pages/workbench/constants.ts | 5 ++- redisinsight/ui/src/pages/workbench/types.ts | 3 +- .../ui/src/pages/workbench/utils/query.ts | 35 ++++++++++++------- .../workbench/utils/searchSuggestions.ts | 34 +++++++++++++----- .../src/pages/workbench/utils/suggestions.ts | 11 +++--- .../utils/tests/test-cases/common.ts | 20 ++++++++++- 7 files changed, 87 insertions(+), 31 deletions(-) diff --git a/redisinsight/ui/src/pages/workbench/components/query/Query/Query.tsx b/redisinsight/ui/src/pages/workbench/components/query/Query/Query.tsx index c4eb8a232d..2708b01c04 100644 --- a/redisinsight/ui/src/pages/workbench/components/query/Query/Query.tsx +++ b/redisinsight/ui/src/pages/workbench/components/query/Query/Query.tsx @@ -112,6 +112,7 @@ const Query = (props: Props) => { const selectedArg = useRef('') const syntaxCommand = useRef(null) const isDedicatedEditorOpenRef = useRef(isDedicatedEditorOpen) + const isEscapedSuggestions = useRef(false) let syntaxWidgetContext: Nullable> = null const { commandsArray: REDIS_COMMANDS_ARRAY, spec: REDIS_COMMANDS_SPEC } = useSelector(appRedisCommandsSelector) @@ -314,6 +315,10 @@ const Query = (props: Props) => { if (e.keyCode === monacoEditor.KeyCode.Enter || e.keyCode === monacoEditor.KeyCode.Space) { onExitSnippetMode() } + + if (e.keyCode === monacoEditor.KeyCode.Escape && isSuggestionsOpened()) { + isEscapedSuggestions.current = true + } } const onExitSnippetMode = () => { @@ -564,6 +569,8 @@ const Query = (props: Props) => { if (COMMANDS_TO_GET_INDEX_INFO.some((name) => name === command.name)) { setSelectedIndex(allArgs[1] || '') + } else { + setSelectedIndex('') } const cursorContext: CursorContext = { ...cursor, currentOffsetArg, offset: command.commandCursorPosition, range } @@ -571,7 +578,8 @@ const Query = (props: Props) => { REDIS_COMMANDS, command, cursorContext, - { fields: attributesRef.current, indexes: indexesRef.current } + { fields: attributesRef.current, indexes: indexesRef.current }, + isEscapedSuggestions.current ) if (helpWidget) { diff --git a/redisinsight/ui/src/pages/workbench/constants.ts b/redisinsight/ui/src/pages/workbench/constants.ts index 4453342d69..86cdf3045c 100644 --- a/redisinsight/ui/src/pages/workbench/constants.ts +++ b/redisinsight/ui/src/pages/workbench/constants.ts @@ -76,7 +76,10 @@ export const COMMANDS_TO_GET_INDEX_INFO = [ 'FT.PROFILE', 'FT.SPELLCHECK', 'FT.TAGVALS', - 'FT.ALTER', + 'FT.ALTER' +] + +export const COMMANDS_WITHOUT_INDEX_PROPOSE = [ 'FT.CREATE' ] diff --git a/redisinsight/ui/src/pages/workbench/types.ts b/redisinsight/ui/src/pages/workbench/types.ts index 18f674fc67..7962623bbc 100644 --- a/redisinsight/ui/src/pages/workbench/types.ts +++ b/redisinsight/ui/src/pages/workbench/types.ts @@ -3,7 +3,8 @@ import { Maybe } from 'uiSrc/utils' import { IRedisCommand, IRedisCommandTree } from 'uiSrc/constants' export enum ArgName { - NArgs = 'nargs' + NArgs = 'nargs', + Count = 'count' } export interface FoundCommandArgument { diff --git a/redisinsight/ui/src/pages/workbench/utils/query.ts b/redisinsight/ui/src/pages/workbench/utils/query.ts index ca9bcda8c8..3bda2a3bc0 100644 --- a/redisinsight/ui/src/pages/workbench/utils/query.ts +++ b/redisinsight/ui/src/pages/workbench/utils/query.ts @@ -104,6 +104,7 @@ export const splitQueryByArgs = (query: string, position: number = 0) => { export const findCurrentArgument = ( args: IRedisCommand[], prev: string[], + untilTokenArgs: string[] = [], parent?: IRedisCommandTree ): Nullable => { for (let i = prev.length - 1; i >= 0; i--) { @@ -112,7 +113,7 @@ export const findCurrentArgument = ( const currentWithParent: IRedisCommandTree = { ...currentArg, parent } if (currentArg?.arguments && currentArg?.type === ICommandTokenType.Block) { - return findCurrentArgument(currentArg.arguments, prev.slice(i), currentWithParent) + return findCurrentArgument(currentArg.arguments, prev.slice(i), prev, currentWithParent) } const tokenIndex = args.findIndex((cArg) => @@ -126,7 +127,7 @@ export const findCurrentArgument = ( // getArgByRest - here we preparing the list of arguments which can be inserted, // this is the main function which creates the list of arguments return { - ...getArgumentSuggestions({ tokenArgs: pastArgs, levelArgs: prev }, commandArgs, parent), + ...getArgumentSuggestions({ tokenArgs: pastArgs, untilTokenArgs }, commandArgs, parent), parent: parent || token } } @@ -232,7 +233,7 @@ const findStopArgumentInQuery = ( continue } - if (currentCommandArg?.name === ArgName.NArgs) { + if (currentCommandArg?.name === ArgName.NArgs || currentCommandArg?.name === ArgName.Count) { const numberOfArgs = toNumber(arg) if (numberOfArgs === 0) { @@ -286,9 +287,9 @@ const findStopArgumentInQuery = ( } export const getArgumentSuggestions = ( - { tokenArgs, levelArgs }: { + { tokenArgs, untilTokenArgs }: { tokenArgs: string[], - levelArgs: string[] + untilTokenArgs: string[] }, pastCommandArgs: IRedisCommand[], current?: IRedisCommandTree @@ -340,7 +341,7 @@ export const getArgumentSuggestions = ( const foundParent = isBlockHasParent ? { ...parent, parent: current } : (parent || current) const isBlockComplete = !stopArgument && current?.name === lastArgument?.name - const beforeMandatoryOptionalArgs = getAllRestArguments(foundParent, lastArgument, levelArgs, isBlockComplete) + const beforeMandatoryOptionalArgs = getAllRestArguments(foundParent, lastArgument, untilTokenArgs, isBlockComplete) const requiredArgsLength = restNotFilledArgs.filter((arg) => !arg.optional).length return { @@ -357,8 +358,11 @@ export const getRestArguments = ( ): IRedisCommandTree[] => { const argumentIndexInArg = current?.arguments ?.findIndex(({ name }) => name === stopArgument?.name) - const nextMandatoryIndex = argumentIndexInArg && argumentIndexInArg > -1 ? current?.arguments - ?.findIndex(({ optional }, i) => !optional && i > argumentIndexInArg) : -1 + const nextMandatoryIndex = stopArgument && !stopArgument.optional + ? argumentIndexInArg + : argumentIndexInArg && argumentIndexInArg > -1 ? current?.arguments + ?.findIndex(({ optional }, i) => !optional && i > argumentIndexInArg) : -1 + const prevMandatory = current?.arguments?.slice(0, argumentIndexInArg).reverse() .find(({ optional }) => !optional) const prevMandatoryIndex = current?.arguments?.findIndex(({ name }) => name === prevMandatory?.name) @@ -387,12 +391,12 @@ export const getRestArguments = ( export const getAllRestArguments = ( current: Maybe, stopArgument: Nullable, - prevStringArgs: string[] = [], + untilTokenArgs: string[] = [], skipLevel = false ) => { const appendArgs: Array = [] const currentLvlNextArgs = removeNotSuggestedArgs( - prevStringArgs, + untilTokenArgs, getRestArguments(current, stopArgument) ) @@ -401,7 +405,7 @@ export const getAllRestArguments = ( } if (current?.parent) { - const parentArgs = getAllRestArguments(current.parent, current, skipLevel ? prevStringArgs : []) + const parentArgs = getAllRestArguments(current.parent, current, untilTokenArgs) if (parentArgs?.length) { appendArgs.push(...parentArgs) } @@ -421,7 +425,8 @@ export const removeNotSuggestedArgs = (args: string[], commandArgs: IRedisComman } if (arg.type === ICommandTokenType.Block) { - return arg.arguments?.[0]?.token && !args.includes(arg.arguments?.[0]?.token?.toUpperCase()) + if (arg.token) return !args.includes(arg.token) || arg.multiple + return arg.arguments?.[0]?.token && (!args.includes(arg.arguments?.[0]?.token?.toUpperCase()) || arg.multiple) } return arg.token && !args.includes(arg.token) @@ -437,6 +442,11 @@ export const fillArgsByType = (args: IRedisCommand[], expandBlock = true): IRedi result.push(...(currentArg?.arguments?.map((arg) => ({ ...arg, parent: currentArg })) || [])) } + if (currentArg.token) { + result.push(currentArg) + continue + } + if (currentArg.type === ICommandTokenType.Block) { result.push({ multiple: currentArg.multiple, @@ -445,7 +455,6 @@ export const fillArgsByType = (args: IRedisCommand[], expandBlock = true): IRedi ...(currentArg?.arguments?.[0] as IRedisCommand || {}), }) } - if (currentArg.token) result.push(currentArg) } return result diff --git a/redisinsight/ui/src/pages/workbench/utils/searchSuggestions.ts b/redisinsight/ui/src/pages/workbench/utils/searchSuggestions.ts index cc236d3a66..12c8e314db 100644 --- a/redisinsight/ui/src/pages/workbench/utils/searchSuggestions.ts +++ b/redisinsight/ui/src/pages/workbench/utils/searchSuggestions.ts @@ -12,7 +12,12 @@ import { getIndexesSuggestions, getNoIndexesSuggestion } from 'uiSrc/pages/workbench/utils/suggestions' -import { DefinedArgumentName, FIELD_START_SYMBOL, ModuleCommandPrefix } from 'uiSrc/pages/workbench/constants' +import { + COMMANDS_WITHOUT_INDEX_PROPOSE, + DefinedArgumentName, + FIELD_START_SYMBOL, + ModuleCommandPrefix +} from 'uiSrc/pages/workbench/constants' export const findSuggestionsByArg = ( listOfCommands: IRedisCommand[], @@ -21,7 +26,8 @@ export const findSuggestionsByArg = ( additionData: { indexes?: any[] fields?: any[], - } + }, + isEscaped: boolean = false ): { suggestions: any, helpWidget?: any @@ -47,7 +53,7 @@ export const findSuggestionsByArg = ( case DefinedArgumentName.index: { return handleIndexSuggestions( additionData.indexes || [], - command.info as IRedisCommand, + command, foundArg, currentOffsetArg, cursorContext.range @@ -62,7 +68,8 @@ export const findSuggestionsByArg = ( foundArg, allArgs, additionData.fields || [], - cursorContext + cursorContext, + isEscaped ) } } @@ -82,13 +89,21 @@ const handleFieldSuggestions = ( const handleIndexSuggestions = ( indexes: any[], - command: IRedisCommand, + command: IMonacoQuery, foundArg: FoundCommandArgument, currentOffsetArg: Nullable, range: monacoEditor.IRange ) => { const isIndex = indexes.length > 0 - const helpWidget = { isOpen: isIndex, parent: command, currentArg: foundArg?.stopArg } + const helpWidget = { isOpen: isIndex, parent: command.info, currentArg: foundArg?.stopArg } + const currentCommand = command.info + + if (COMMANDS_WITHOUT_INDEX_PROPOSE.includes(command.name || '')) { + return { + suggestions: asSuggestionsRef([]), + helpWidget + } + } if (!isIndex) { helpWidget.isOpen = !!currentOffsetArg @@ -106,10 +121,10 @@ const handleIndexSuggestions = ( } } - const argumentIndex = command?.arguments + const argumentIndex = currentCommand?.arguments ?.findIndex(({ name }) => foundArg?.stopArg?.name === name) const isNextArgQuery = isNumber(argumentIndex) - && command?.arguments?.[argumentIndex + 1]?.name === DefinedArgumentName.query + && currentCommand?.arguments?.[argumentIndex + 1]?.name === DefinedArgumentName.query return { suggestions: asSuggestionsRef(getIndexesSuggestions(indexes, range, isNextArgQuery)), @@ -158,11 +173,12 @@ const handleCommonSuggestions = ( allArgs: string[], fields: any[], cursorContext: CursorContext, + isEscaped: boolean ) => { if (foundArg?.stopArg?.expression) return handleExpressionSuggestions(value, foundArg, cursorContext) const { prevCursorChar, nextCursorChar, isCursorInQuotes } = cursorContext - const shouldHideSuggestions = isCursorInQuotes || nextCursorChar || (prevCursorChar) + const shouldHideSuggestions = isCursorInQuotes || nextCursorChar || (prevCursorChar && isEscaped) if (shouldHideSuggestions) { return { helpWidget: { isOpen: true, parent: foundArg?.parent, currentArg: foundArg?.stopArg }, diff --git a/redisinsight/ui/src/pages/workbench/utils/suggestions.ts b/redisinsight/ui/src/pages/workbench/utils/suggestions.ts index 288ae6dc69..b90823f0ff 100644 --- a/redisinsight/ui/src/pages/workbench/utils/suggestions.ts +++ b/redisinsight/ui/src/pages/workbench/utils/suggestions.ts @@ -2,10 +2,11 @@ import { monaco } from 'react-monaco-editor' import * as monacoEditor from 'monaco-editor' import { RedisResponseBuffer } from 'uiSrc/slices/interfaces' import { bufferToString, formatLongName, generateArgsForInsertText, getCommandMarkdown, Nullable } from 'uiSrc/utils' -import { FoundCommandArgument, SearchCommand } from 'uiSrc/pages/workbench/types' +import { FoundCommandArgument } from 'uiSrc/pages/workbench/types' import { DefinedArgumentName, EmptySuggestionsIds } from 'uiSrc/pages/workbench/constants' import { getUtmExternalLink } from 'uiSrc/utils/links' -import { removeNotSuggestedArgs, generateDetail } from './query' +import { IRedisCommand } from 'uiSrc/constants' +import { generateDetail, removeNotSuggestedArgs } from './query' import { buildSuggestion, } from './monaco' export const asSuggestionsRef = ( @@ -81,13 +82,13 @@ export const getFieldsSuggestions = ( } }) -const insertFunctionArguments = (args: SearchCommand[]) => +const insertFunctionArguments = (args: IRedisCommand[]) => generateArgsForInsertText( args.map(({ token, optional }) => (optional ? `[${token}]` : (token || ''))) as string[], ', ' ) -export const getFunctionsSuggestions = (functions: SearchCommand[], range: monaco.IRange) => functions +export const getFunctionsSuggestions = (functions: IRedisCommand[], range: monaco.IRange) => functions .map(({ token, summary, arguments: args }) => ({ label: token || '', insertText: `${token}(${insertFunctionArguments(args || [])})`, @@ -97,7 +98,7 @@ export const getFunctionsSuggestions = (functions: SearchCommand[], range: monac detail: summary })) -export const getCommandsSuggestions = (commands: SearchCommand[], range: monaco.IRange) => +export const getCommandsSuggestions = (commands: IRedisCommand[], range: monaco.IRange) => commands.map((command) => buildSuggestion(command, range, { detail: generateDetail(command), insertTextRules: monacoEditor.languages.CompletionItemInsertTextRule.InsertAsSnippet, diff --git a/redisinsight/ui/src/pages/workbench/utils/tests/test-cases/common.ts b/redisinsight/ui/src/pages/workbench/utils/tests/test-cases/common.ts index 7946e4baa6..2f8b3f3a1d 100644 --- a/redisinsight/ui/src/pages/workbench/utils/tests/test-cases/common.ts +++ b/redisinsight/ui/src/pages/workbench/utils/tests/test-cases/common.ts @@ -51,7 +51,7 @@ export const commonfindCurrentArgumentCases = [ { input: 'FT.CREATE "idx:schools" ', result: expect.any(Object), - appendIncludes: ['FILTER', 'ON', 'SCHEMA', 'SCORE', 'NOHL'], + appendIncludes: ['FILTER', 'ON', 'SCHEMA', 'SCORE', 'NOHL', 'STOPWORDS'], appendNotIncludes: ['HASH', 'JSON'], }, { @@ -180,4 +180,22 @@ export const commonfindCurrentArgumentCases = [ appendIncludes: ['WITHPAYLOADS', 'WITHSCORES'], appendNotIncludes: ['FUZZY', 'MAX'], }, + { + input: 'FT.ALTER index SKIPINITIALSCAN ', + result: expect.any(Object), + appendIncludes: ['SCHEMA'], + appendNotIncludes: ['ADD'], + }, + { + input: 'FT.SPELLCHECK idx "" ', + result: expect.any(Object), + appendIncludes: ['DIALECT', 'DISTANCE', 'TERMS'], + appendNotIncludes: ['EXCLUDE', 'INCLUDE'], + }, + { + input: 'FT.SEARCH index "" HIGHLIGHT FIELDS 1 f1 ', + result: expect.any(Object), + appendIncludes: ['TAGS', 'SUMMARIZE', 'DIALECT', 'FILTER', 'WITHSCORES', 'INKEYS'], + appendNotIncludes: ['FIELDS'], + }, ] From cae91528b5ec15a3e27f14ccd8bad8d7b84cf64b Mon Sep 17 00:00:00 2001 From: ViktarStarastsenka <99594890+ViktarStarastsenka@users.noreply.github.com> Date: Fri, 11 Oct 2024 16:50:44 +0200 Subject: [PATCH 151/256] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 9d739cce96..774a07714e 100644 --- a/README.md +++ b/README.md @@ -55,7 +55,7 @@ If you have any issues occurring in Redis Insight, you can follow the steps belo * [How to debug](https://github.com/RedisInsight/RedisInsight/wiki/How-to-debug) ## Redis Insight API (only for Docker) -http://localhost:5540/api/docs +If you are running Redis Insight from [Docker](https://hub.docker.com/r/redis/redisinsight), you can access the API from `http://localhost:5540/api/docs`. ## Feedback From cb9755fa63124cedbfb63d4df6b70cbff776594b Mon Sep 17 00:00:00 2001 From: zalenskiSofteq Date: Sun, 13 Oct 2024 23:16:55 +0200 Subject: [PATCH 152/256] #RI-6158 - Migrate build workflows from CircleCI to Github Actions --- .circleci/build/build.sh | 4 +- .github/README.md | 1 + .../actions/install-all-build-libs/action.yml | 95 +++++++++++ .../actions/install-apple-certs/action.yml | 49 ++++++ .github/actions/install-deps/action.yml | 39 +++++ .../actions/install-windows-certs/action.yml | 18 +++ .github/workflows/build.yml | 53 +++++++ .github/workflows/compress-images.yml | 27 ++++ .github/workflows/pipeline-build-docker.yml | 73 +++++++++ .github/workflows/pipeline-build-linux.yml | 89 +++++++++++ .github/workflows/pipeline-build-macos.yml | 120 ++++++++++++++ .github/workflows/pipeline-build-windows.yml | 49 ++++++ .github/workflows/pull-request-created.yml | 14 ++ .github/workflows/tests-backend.yml | 52 +++++++ .github/workflows/tests-frontend.yml | 50 ++++++ .github/workflows/tests.yml | 57 +++++++ .gitignore | 5 + configs/webpack.config.renderer.dev.dll.ts | 147 ------------------ configs/webpack.config.renderer.dev.ts | 0 configs/webpack.config.renderer.prod.ts | 0 configs/webpack.config.web.common.ts | 0 configs/webpack.config.web.prod.ts | 0 package.json | 7 +- yarn.lock | 12 +- 24 files changed, 803 insertions(+), 158 deletions(-) create mode 100644 .github/README.md create mode 100644 .github/actions/install-all-build-libs/action.yml create mode 100644 .github/actions/install-apple-certs/action.yml create mode 100644 .github/actions/install-deps/action.yml create mode 100644 .github/actions/install-windows-certs/action.yml create mode 100644 .github/workflows/build.yml create mode 100644 .github/workflows/compress-images.yml create mode 100644 .github/workflows/pipeline-build-docker.yml create mode 100644 .github/workflows/pipeline-build-linux.yml create mode 100644 .github/workflows/pipeline-build-macos.yml create mode 100644 .github/workflows/pipeline-build-windows.yml create mode 100644 .github/workflows/pull-request-created.yml create mode 100644 .github/workflows/tests-backend.yml create mode 100644 .github/workflows/tests-frontend.yml create mode 100644 .github/workflows/tests.yml delete mode 100644 configs/webpack.config.renderer.dev.dll.ts delete mode 100644 configs/webpack.config.renderer.dev.ts delete mode 100644 configs/webpack.config.renderer.prod.ts delete mode 100644 configs/webpack.config.web.common.ts delete mode 100644 configs/webpack.config.web.prod.ts diff --git a/.circleci/build/build.sh b/.circleci/build/build.sh index c93e24652b..780341b022 100755 --- a/.circleci/build/build.sh +++ b/.circleci/build/build.sh @@ -6,6 +6,8 @@ yarn yarn --cwd redisinsight/api # build -yarn build:statics + +# TODO remove +# yarn build:statics yarn build:ui yarn --cwd ./redisinsight/api build:prod diff --git a/.github/README.md b/.github/README.md new file mode 100644 index 0000000000..304360caba --- /dev/null +++ b/.github/README.md @@ -0,0 +1 @@ +Readme diff --git a/.github/actions/install-all-build-libs/action.yml b/.github/actions/install-all-build-libs/action.yml new file mode 100644 index 0000000000..c959e889d3 --- /dev/null +++ b/.github/actions/install-all-build-libs/action.yml @@ -0,0 +1,95 @@ +name: Install all libraries action +description: Install all libraries and dependencies +inputs: + skip-electron-deps: + description: Skip install electron dependencies + default: '0' + required: false + + skip-backend-deps: + description: Skip install backend dependencies + default: '0' + required: false + + skip-postinstall: + description: Skip postinstall + default: '0' + required: false + + keytar-host-mirror: + description: Keytar binary host mirror + required: false + + sqlite3-host-mirror: + description: SQLite3 binary host mirror + required: false + +#TODO: check !contains + +runs: + using: 'composite' + steps: + # OS libraries + - name: Setup Node + uses: actions/setup-node@v4.0.4 + with: + node-version: '20.15' + # disable cache for windows + # https://github.com/actions/setup-node/issues/975 + cache: ${{ runner.os != 'Windows' && 'yarn' || '' }} + cache-dependency-path: ${{ runner.os != 'Windows' && '**/yarn.lock' || '' }} + + # - run: echo "inputs.skip-electron-deps" + # - run: echo "${{inputs.skip-electron-deps}}" + # - run: echo "inputs.skip-backend-deps" + # - run: echo "${{inputs.skip-backend-deps}}" + + - name: Setup Python + # if: ${{ contains(inputs.skip-electron-deps, '1') }} + uses: actions/setup-python@v5 + with: + python-version: '3.11' + + - name: Install linux libraries + if: ${{ runner.os == 'Linux' }} + # if: ${{ runner.os == 'Linux' && !contains(inputs.skip-electron-deps, '1') }} + shell: bash + run: | + sudo apt-get update -qy + sudo apt-get install -qy libsecret-1-dev rpm + + - name: Install macos libraries + if: ${{ runner.os == 'macOS' }} + # if: ${{ runner.os == 'macOS' && !contains(inputs.skip-electron-deps, '1') }} + shell: bash + run: | + brew install libsecret + + # TODO: matrix? + # Javascript dependencies + - name: Install dependencies for redisinsight package.js + # if: ${{ contains(inputs.skip-electron-deps, '1') }} + uses: ./.github/actions/install-deps + with: + dir-path: './redisinsight' + keytar-host-mirror: ${{ inputs.keytar-host-mirror }} + sqlite3-host-mirror: ${{ inputs.sqlite3-host-mirror }} + + - name: Install dependencies for BE package.js + # if: ${{ !contains(inputs.skip-backend-deps, '1') }} + uses: ./.github/actions/install-deps + with: + dir-path: './redisinsight/api' + + - name: Install dependencies for root package.js + # if: ${{ contains(inputs.skip-electron-deps, '1') }} + uses: ./.github/actions/install-deps + with: + dir-path: './' + keytar-host-mirror: ${{ inputs.keytar-host-mirror }} + sqlite3-host-mirror: ${{ inputs.sqlite3-host-mirror }} + + + + + diff --git a/.github/actions/install-apple-certs/action.yml b/.github/actions/install-apple-certs/action.yml new file mode 100644 index 0000000000..580fbb04b8 --- /dev/null +++ b/.github/actions/install-apple-certs/action.yml @@ -0,0 +1,49 @@ +name: Add certs to the keychain (macos) + +inputs: + CSC_P12_BASE64: + required: true + CSC_MAC_INSTALLER_P12_BASE64: + required: true + CSC_MAS_P12_BASE64: + required: true + CSC_KEY_PASSWORD: + required: true + CSC_MAS_PASSWORD: + required: true + CSC_MAC_INSTALLER_PASSWORD: + required: true + +runs: + using: 'composite' + steps: + - name: Setup sign certificates + shell: bash + env: + CSC_P12_BASE64: ${{ inputs.CSC_P12_BASE64 }} + CSC_MAC_INSTALLER_P12_BASE64: ${{ inputs.CSC_MAC_INSTALLER_P12_BASE64 }} + CSC_MAS_P12_BASE64: ${{ inputs.CSC_MAS_P12_BASE64 }} + run: | + mkdir -p certs + echo "$CSC_P12_BASE64" | base64 -d > certs/mac-developer.p12 + echo "$CSC_MAC_INSTALLER_P12_BASE64" | base64 -d > certs/mac-installer.p12 + echo "$CSC_MAS_P12_BASE64" | base64 -d > certs/mas-distribution.p12 + + - name: Add certs to the keychain + shell: bash + env: + KEYCHAIN: redisinsight.keychain + CSC_KEY_PASSWORD: ${{ inputs.CSC_KEY_PASSWORD }} + CSC_MAS_PASSWORD: ${{ inputs.CSC_MAS_PASSWORD }} + CSC_MAC_INSTALLER_PASSWORD: ${{ inputs.CSC_MAC_INSTALLER_PASSWORD }} + run: | + security create-keychain -p mysecretpassword $KEYCHAIN + security default-keychain -s $KEYCHAIN + security unlock-keychain -p mysecretpassword $KEYCHAIN + security set-keychain-settings -u -t 10000000 $KEYCHAIN + security import certs/mac-developer.p12 -k $KEYCHAIN -P "$CSC_KEY_PASSWORD" -T /usr/bin/codesign -T /usr/bin/productbuild + security import certs/mas-distribution.p12 -k $KEYCHAIN -P "$CSC_MAS_PASSWORD" -T /usr/bin/codesign -T /usr/bin/productbuild + security import certs/mac-installer.p12 -k $KEYCHAIN -P "$CSC_MAC_INSTALLER_PASSWORD" -T /usr/bin/codesign -T /usr/bin/productbuild + security set-key-partition-list -S apple-tool:,apple: -s -k mysecretpassword $KEYCHAIN + security list-keychain -d user -s $KEYCHAIN + diff --git a/.github/actions/install-deps/action.yml b/.github/actions/install-deps/action.yml new file mode 100644 index 0000000000..41088e769b --- /dev/null +++ b/.github/actions/install-deps/action.yml @@ -0,0 +1,39 @@ +name: Install Dependencies action +description: Caches and installs dependencies for a given path +inputs: + dir-path: + description: Path to the directory + required: true + keytar-host-mirror: + description: Keytar binary host mirror + required: false + sqlite3-host-mirror: + description: SQLite3 binary host mirror + required: false + skip-postinstall: + description: Skip postinstall + required: false + default: '0' + +runs: + using: 'composite' + steps: + # - name: Cache dependencies + # uses: actions/cache@v4 + # with: + # path: ${{ inputs.dir-path }}/node_modules + # key: ${{ runner.os }}-yarn-${{ hashFiles('${{ inputs.dir-path }}/yarn.lock') }} + + - name: Install dependencies + working-directory: ${{ inputs.dir-path }} + shell: bash + + # env: + # SKIP_POSTINSTALL: ${{ inputs.skip-postinstall }} + # run: yarn install + run: | + export npm_config_keytar_binary_host_mirror=${{ inputs.keytar-host-mirror }} + export npm_config_node_sqlite3_binary_host_mirror=${{ inputs.sqlite3-host-mirror }} + + yarn install + echo $SKIP_POSTINSTALL diff --git a/.github/actions/install-windows-certs/action.yml b/.github/actions/install-windows-certs/action.yml new file mode 100644 index 0000000000..c69a0eeb59 --- /dev/null +++ b/.github/actions/install-windows-certs/action.yml @@ -0,0 +1,18 @@ +name: Install Windows certs + +inputs: + WIN_CSC_PFX_BASE64: + required: true + +runs: + using: 'composite' + steps: + - name: Setup sign certificates + shell: bash + env: + WIN_CSC_PFX_BASE64: ${{ inputs.WIN_CSC_PFX_BASE64 }} + run: | + mkdir -p certs + echo "$WIN_CSC_PFX_BASE64" | base64 -d > certs/redislabs_win.pfx + + diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 0000000000..1a7a1c9aa3 --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,53 @@ +name: Build + +on: + workflow_dispatch: + inputs: + target: + description: Build target + required: false + default: 'all' + type: choice + options: + - all + - docker + - windows:x64 + - macos + - macos:x64 + - macos:arm64 + - linux:appimage:x64 + - linux:deb:x64 + - linux:rpm:x64 + - linux:snap:x64 + + environment: + description: Environment to run build + type: environment + default: 'staging' + required: false + +jobs: + build_linux: + if: startsWith(inputs.target, 'linux') || inputs.target == 'all' + # concurrency: build + uses: ./.github/workflows/pipeline-build-linux.yml + secrets: inherit + with: + target: ${{ inputs.target }} + + build_macos: + if: startsWith(inputs.target, 'macos') || inputs.target == 'all' + uses: ./.github/workflows/pipeline-build-macos.yml + secrets: inherit + with: + target: ${{ inputs.target }} + + build_windows: + if: startsWith(inputs.target, 'windows') || inputs.target == 'all' + uses: ./.github/workflows/pipeline-build-windows.yml + secrets: inherit + + build_docker: + if: startsWith(inputs.target, 'docker') || inputs.target == 'all' + uses: ./.github/workflows/pipeline-build-docker.yml + secrets: inherit diff --git a/.github/workflows/compress-images.yml b/.github/workflows/compress-images.yml new file mode 100644 index 0000000000..f27ce65e3f --- /dev/null +++ b/.github/workflows/compress-images.yml @@ -0,0 +1,27 @@ +name: Compress Images +on: + pull_request: + # Run Image Actions when JPG, JPEG, PNG or WebP files are added or changed. + # See https://help.github.com/en/actions/automating-your-workflow-with-github-actions/workflow-syntax-for-github-actions#onpushpull_requestpaths for reference. + paths: + - '**.jpg' + - '**.jpeg' + - '**.png' + - '**.webp' +jobs: + build: + # Only run on Pull Requests within the same repository, and not from forks. + if: github.event.pull_request.head.repo.full_name == github.repository + name: calibreapp/image-actions + permissions: write-all + runs-on: ubuntu-latest + steps: + - name: Checkout Repo + uses: actions/checkout@v4 + + - name: Compress Images + uses: calibreapp/image-actions@main + with: + # The `GITHUB_TOKEN` is automatically generated by GitHub and scoped only to the repository that is currently running the action. By default, the action can’t update Pull Requests initiated from forked repositories. + # See https://docs.github.com/en/actions/reference/authentication-in-a-workflow and https://help.github.com/en/articles/virtual-environments-for-github-actions#token-permissions + githubToken: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/pipeline-build-docker.yml b/.github/workflows/pipeline-build-docker.yml new file mode 100644 index 0000000000..850d7cae53 --- /dev/null +++ b/.github/workflows/pipeline-build-docker.yml @@ -0,0 +1,73 @@ +name: Build docker pipeline +on: + workflow_call: + +jobs: + build: + runs-on: ubuntu-24.04 + name: Build doker job + + steps: + - uses: actions/checkout@v4.1.0 + + - name: Set up QEMU + uses: docker/setup-qemu-action@v3 + + - name: Install all libs and dependencies + uses: ./.github/actions/install-all-build-libs + with: + keytar-host-mirror: ${{ secrets.NPM_CONFIG_KEYTAR_BINARY_HOST_MIRROR }} + sqlite3-host-mirror: ${{ secrets.NPM_CONFIG_NODE_SQLITE3_BINARY_HOST_MIRROR }} + + - name: Build sources + run: ./.circleci/build/build.sh + + - name: Build web archives + run: | + unset npm_config_keytar_binary_host_mirror + unset npm_config_node_sqlite3_binary_host_mirror + # Docker sources + PLATFORM=linux ARCH=x64 LIBC=musl .circleci/build/build_modules.sh + PLATFORM=linux ARCH=arm64 LIBC=musl .circleci/build/build_modules.sh + # Redis Stack + VSC Linux + PLATFORM=linux ARCH=x64 .circleci/build/build_modules.sh + PLATFORM=linux ARCH=arm64 .circleci/build/build_modules.sh + # VSC Darwin + PLATFORM=darwin ARCH=x64 .circleci/build/build_modules.sh + PLATFORM=darwin ARCH=arm64 .circleci/build/build_modules.sh + # VSC Windows + PLATFORM=win32 ARCH=x64 .circleci/build/build_modules.sh + - name: Build Docker (x64, arm64) + env: + RI_SEGMENT_WRITE_KEY: ${{ secrets.RI_SEGMENT_WRITE_KEY }} + run: | + # Build alpine x64 image + docker buildx build \ + -f .circleci/build/build.Dockerfile \ + --platform linux/amd64 \ + --build-arg DIST=release/web/Redis-Insight-web-linux-musl.x64.tar.gz \ + --build-arg NODE_ENV="$env" \ + --build-arg RI_SEGMENT_WRITE_KEY="$RI_SEGMENT_WRITE_KEY" \ + -t redisinsight:amd64 \ + . + + # Build alpine arm64 image + docker buildx build \ + -f .circleci/build/build.Dockerfile \ + --platform linux/arm64 \ + --build-arg DIST=release/web/Redis-Insight-web-linux-musl.arm64.tar.gz \ + --build-arg NODE_ENV="$env" \ + --build-arg RI_SEGMENT_WRITE_KEY="$RI_SEGMENT_WRITE_KEY" \ + -t redisinsight:arm64 \ + . + + mkdir -p release/docker + docker image save -o release/docker/docker-linux-alpine.amd64.tar redisinsight:amd64 + docker image save -o release/docker/docker-linux-alpine.arm64.tar redisinsight:arm64 + + - uses: actions/upload-artifact@v4.1.0 + name: Upload docker images + with: + if-no-files-found: error + name: docker + path: ./release diff --git a/.github/workflows/pipeline-build-linux.yml b/.github/workflows/pipeline-build-linux.yml new file mode 100644 index 0000000000..f85d56e10b --- /dev/null +++ b/.github/workflows/pipeline-build-linux.yml @@ -0,0 +1,89 @@ +name: Build linux pipeline + +on: + workflow_call: + inputs: + target: + description: Build target + required: false + default: 'all' + type: string + +jobs: + build: + runs-on: ubuntu-24.04 + name: Build linux job + + steps: + #TODO: some debug information + # - uses: crazy-max/ghaction-dump-context@v2 + # - uses: hmarr/debug-action@v3 + # ssh + # - run: sudo apt-get update -qy && sudo apt-get install -qy tmux; + # - name: Setup upterm session + # - uses: mxschmitt/action-tmate #1 better + # uses: lhotari/action-upterm@v1 #2 + # with: + # limit-access-to-actor: true + # limit-access-to-users: zalenskiSofteq + + - uses: actions/checkout@v4.1.0 + + - name: Install all libs and dependencies + uses: ./.github/actions/install-all-build-libs + with: + keytar-host-mirror: ${{ secrets.NPM_CONFIG_KEYTAR_BINARY_HOST_MIRROR }} + sqlite3-host-mirror: ${{ secrets.NPM_CONFIG_NODE_SQLITE3_BINARY_HOST_MIRROR }} + + # TODO: Is it needed? + # - run: | + # mkdir electron + # CURRENT_VERSION=$(jq -r ".version" redisinsight/package.json) + # echo "Build version: $CURRENT_VERSION" + # cp ./redisinsight/package.json ./electron/package.json + # echo "$VERSION" > electron/version + # exit 0 + # - uses: actions/download-artifact@v4.1.0 + # with: + # path: "." + # - run: cp ./electron/package.json ./redisinsight/ + + # TODO: uncomment + # - name: Install plugins dependencies and build plugins + # run: yarn build:statics + + - name: Build linux packages (production) + if: vars.ENV == 'production' && inputs.target == 'all' + run: yarn package:prod + + - name: Build linux packages (staging) + if: (vars.ENV == 'staging' || vars.ENV == 'development') && inputs.target == 'all' + run: yarn package:stage + + - name: Build linux packages (development) + if: inputs.target != 'all' + run: | + target="" + if [ ${{ startsWith(inputs.target, 'linux:') }} == 'true' ]; then + inputsTarget=${{inputs.target}} + target=${inputsTarget#linux:} + fi + + yarn package:stage --linux $target + + - uses: actions/upload-artifact@v4.1.0 + name: Upload AppImage artifact + with: + name: 'linux-appimage-build' + path: | + ./release/Redis-Insight*.AppImage + ./release/*-linux.yml + + - uses: actions/upload-artifact@v4.1.0 + name: Upload artifacts + with: + name: 'linux-builds' + path: | + ./release/Redis-Insight*.deb + ./release/Redis-Insight*.rpm + ./release/Redis-Insight*.snap diff --git a/.github/workflows/pipeline-build-macos.yml b/.github/workflows/pipeline-build-macos.yml new file mode 100644 index 0000000000..5d63aaf4ed --- /dev/null +++ b/.github/workflows/pipeline-build-macos.yml @@ -0,0 +1,120 @@ +name: Build macos pipeline +on: + workflow_call: + inputs: + target: + description: Build target + required: false + default: 'all' + type: string + +jobs: + build: + runs-on: macos-14 + name: Build macos job + env: + APPLE_ID: ${{ secrets.APPLE_ID }} + APPLE_ID_PASSWORD: ${{ secrets.APPLE_ID_PASSWORD }} + APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }} + APPLE_APP_SPECIFIC_PASSWORD: ${{ secrets.APPLE_APP_SPECIFIC_PASSWORD }} + USE_HARD_LINKS: ${{ vars.USE_HARD_LINKS }} + CSC_KEYCHAIN: ${{ vars.CSC_KEYCHAIN }} + CSC_IDENTITY_AUTO_DISCOVERY: ${{ vars.CSC_IDENTITY_AUTO_DISCOVERY }} + CSC_KEY_PASSWORD: ${{ secrets.CSC_KEY_PASSWORD }} + + steps: + - uses: actions/checkout@v4.1.0 + + # Install libsecret + # - run: brew install libsecret + + - name: Add certificates to the keychain + uses: ./.github/actions/install-apple-certs + with: + CSC_P12_BASE64: ${{ secrets.CSC_P12_BASE64 }} + CSC_KEY_PASSWORD: ${{ secrets.CSC_KEY_PASSWORD }} + CSC_MAS_PASSWORD: ${{ secrets.CSC_MAS_PASSWORD }} + CSC_MAS_P12_BASE64: ${{ secrets.CSC_MAS_P12_BASE64 }} + CSC_MAC_INSTALLER_PASSWORD: ${{ secrets.CSC_MAC_INSTALLER_PASSWORD }} + CSC_MAC_INSTALLER_P12_BASE64: ${{ secrets.CSC_MAC_INSTALLER_P12_BASE64 }} + + - name: Install all libs and dependencies + uses: ./.github/actions/install-all-build-libs + with: + keytar-host-mirror: ${{ secrets.NPM_CONFIG_KEYTAR_BINARY_HOST_MIRROR }} + sqlite3-host-mirror: ${{ secrets.NPM_CONFIG_NODE_SQLITE3_BINARY_HOST_MIRROR }} + + + #TODO uncomment + # - name: Install plugins dependencies and build plugins + # run: yarn build:statics + + - name: Build macos dmg (prod) + if: vars.ENV == 'production' && inputs.target == 'all' + run: | + unset CSC_LINK + + yarn package:prod + yarn package:mas + rm -rf release/mac + mv release/mas-universal/Redis-Insight-mac-universal-mas.pkg release/Redis-Insight-mac-universal-mas.pkg + + - name: Build macos dmg (staging) + if: (vars.ENV == 'staging' || vars.ENV == 'development') && inputs.target == 'all' + run: | + unset CSC_LINK + + echo "$USE_HARD_LINKS" + echo $APP_BUNDLE_VERSION + echo $CSC_KEYCHAIN + + yarn package:stage && yarn package:mas + rm -rf release/mac + mv release/mas-universal/Redis-Insight-mac-universal-mas.pkg release/Redis-Insight-mac-universal-mas.pkg + + # handle manual builds + - name: Build macos dmg (dev) + if: inputs.target != 'all' + run: | + unset CSC_LINK + yarn package:stage --mac ${{ inputs.target }} + rm -rf release/mac + + - name: Repack dmg to tar + if: vars.ENV == 'staging' || vars.ENV == 'production' + run: | + ARCH=x64 ./.circleci/redisstack/dmg.repack.sh + ARCH=arm64 ./.circleci/redisstack/dmg.repack.sh + + - name: Upload x64 packages + uses: actions/upload-artifact@v4.1.0 + with: + name: 'macos-x64-builds' + path: | + ./release/Redis-Insight*x64.zip + ./release/Redis-Insight*x64.dmg + ./release/Redis-Insight*x64.dmg.blockmap + + - name: Upload ARM packages + uses: actions/upload-artifact@v4.1.0 + with: + name: 'macos-arm-builds' + path: | + ./release/Redis-Insight*arm64.zip + ./release/Redis-Insight*arm64.dmg + ./release/Redis-Insight*arm64.dmg.blockmap + + - name: Upload MAS packages + uses: actions/upload-artifact@v4.1.0 + with: + name: 'macos-mas-builds' + path: | + ./release/Redis-Insight*.pkg + ./release/*-mac.yml + + - name: Upload redis stack packages + uses: actions/upload-artifact@v4.1.0 + with: + name: 'redistack-builds' + path: | + ./release/redisstack diff --git a/.github/workflows/pipeline-build-windows.yml b/.github/workflows/pipeline-build-windows.yml new file mode 100644 index 0000000000..6398c3b620 --- /dev/null +++ b/.github/workflows/pipeline-build-windows.yml @@ -0,0 +1,49 @@ +name: Build windows pipeline +on: + workflow_call: + +jobs: + build: + runs-on: windows-2022 + name: Build windows job + env: + WIN_CSC_LINK: ${{ secrets.WIN_CSC_LINK }} + WIN_CSC_KEY_PASSWORD: ${{ secrets.WIN_CSC_KEY_PASSWORD }} + + steps: + - uses: actions/checkout@v4.1.0 + + - name: Install all libs and dependencies + uses: ./.github/actions/install-all-build-libs + + - name: Setup certs + uses: ./.github/actions/install-windows-certs + with: + WIN_CSC_PFX_BASE64: ${{ secrets.WIN_CSC_PFX_BASE64 }} + + #TODO uncomment + # - name: Install plugins dependencies and build plugins + # run: yarn build:statics:win + + - name: Build windows exe (production) + if: vars.ENV == 'production' + run: | + yarn package:prod + rm -rf release/win-unpacked + shell: bash + + - name: Build windows exe (staging) + if: (vars.ENV == 'staging' || vars.ENV == 'development') + run: | + yarn package:stage + rm -rf release/win-unpacked + shell: bash + + - uses: actions/upload-artifact@v4.1.0 + with: + name: 'windows-builds' + if-no-files-found: error + path: | + ./release/Redis-Insight*.exe + ./release/Redis-Insight*.exe.blockmap + ./release/*.yml diff --git a/.github/workflows/pull-request-created.yml b/.github/workflows/pull-request-created.yml new file mode 100644 index 0000000000..3d479b82d1 --- /dev/null +++ b/.github/workflows/pull-request-created.yml @@ -0,0 +1,14 @@ +name: Pull request created + +on: + pull_request_target: + +permissions: + pull-requests: write + +jobs: + assign-author: + runs-on: ubuntu-latest + name: Assign author pr + steps: + - uses: toshimaru/auto-author-assign@v2.1.1 diff --git a/.github/workflows/tests-backend.yml b/.github/workflows/tests-backend.yml new file mode 100644 index 0000000000..b9103d9ae1 --- /dev/null +++ b/.github/workflows/tests-backend.yml @@ -0,0 +1,52 @@ +name: Tests BE +on: + workflow_call: + inputs: + skip-electron-deps: + description: Skip install electron dependencies + type: boolean + default: false + required: false + +env: + SLACK_AUDIT_REPORT_KEY: ${{ secrets.SLACK_AUDIT_REPORT_KEY }} + +jobs: + unit-tests: + name: Unit tests Backend job + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4.1.0 + + - name: Install all libs and dependencies for BE + uses: ./.github/actions/install-all-build-libs + with: + skip-electron-deps: '1' + + - name: API PROD dependencies scan + run: | + FILENAME=api.prod.deps.audit.json + + yarn --cwd redisinsight/api audit --groups dependencies --json > $FILENAME || true && + FILENAME=$FILENAME DEPS="API prod" node .circleci/deps-audit-report.js && + curl -H "Content-type: application/json" --data @slack.$FILENAME -H "Authorization: Bearer $SLACK_AUDIT_REPORT_KEY" -X POST https://slack.com/api/chat.postMessage + + - name: API DEV dependencies scan + run: | + FILENAME=api.dev.deps.audit.json + + yarn --cwd redisinsight/api audit --groups devDependencies --json > $FILENAME || true && + FILENAME=$FILENAME DEPS="API dev" node .circleci/deps-audit-report.js && + curl -H "Content-type: application/json" --data @slack.$FILENAME -H "Authorization: Bearer $SLACK_AUDIT_REPORT_KEY" -X POST https://slack.com/api/chat.postMessage + + - name: Code analysis + run: | + FILENAME=api.lint.audit.json + WORKDIR="./redisinsight/api" + + yarn lint:api -f json -o $FILENAME || true && + FILENAME=$FILENAME WORKDIR=$WORKDIR TARGET="API" node .circleci/lint-report.js && + curl -H "Content-type: application/json" --data @$WORKDIR/slack.$FILENAME -H "Authorization: Bearer $SLACK_AUDIT_REPORT_KEY" -X POST https://slack.com/api/chat.postMessage + + - name: Unit tests API + run: yarn --cwd redisinsight/api/ test:cov --ci diff --git a/.github/workflows/tests-frontend.yml b/.github/workflows/tests-frontend.yml new file mode 100644 index 0000000000..77016a6dd7 --- /dev/null +++ b/.github/workflows/tests-frontend.yml @@ -0,0 +1,50 @@ +name: Tests UI +on: + workflow_call: + +env: + SLACK_AUDIT_REPORT_KEY: ${secrets.SLACK_AUDIT_REPORT_KEY }} + +jobs: + unit-tests: + runs-on: ubuntu-latest + name: Unit tests Frontend job + steps: + - uses: actions/checkout@v4.1.0 + + - name: Install all libs and dependencies + uses: ./.github/actions/install-all-build-libs + with: + skip-backend-deps: '1' + + - name: UI PROD dependencies audit + run: | + FILENAME=ui.prod.deps.audit.json + + yarn audit --groups dependencies --json > $FILENAME || true && + FILENAME=$FILENAME DEPS="UI prod" node .circleci/deps-audit-report.js && + curl -H "Content-type: application/json" --data @slack.$FILENAME -H "Authorization: Bearer $SLACK_AUDIT_REPORT_KEY" -X POST https://slack.com/api/chat.postMessage + + - name: UI DEV dependencies audit + run: | + FILENAME=ui.dev.deps.audit.json + + yarn audit --groups devDependencies --json > $FILENAME || true && + FILENAME=$FILENAME DEPS="UI dev" node .circleci/deps-audit-report.js && + curl -H "Content-type: application/json" --data @slack.$FILENAME -H "Authorization: Bearer $SLACK_AUDIT_REPORT_KEY" -X POST https://slack.com/api/chat.postMessage + + - name: Code analysis + run: | + FILENAME=ui.lint.audit.json + WORKDIR="." + + yarn lint:ui -f json -o $FILENAME || true && + FILENAME=$FILENAME WORKDIR=$WORKDIR TARGET="UI" node .circleci/lint-report.js && + curl -H "Content-type: application/json" --data @$WORKDIR/slack.$FILENAME -H "Authorization: Bearer $SLACK_AUDIT_REPORT_KEY" -X POST https://slack.com/api/chat.postMessage + + yarn lint -f json -o $FILENAME || true && + FILENAME=$FILENAME WORKDIR=$WORKDIR TARGET="REST" node .circleci/lint-report.js && + curl -H "Content-type: application/json" --data @$WORKDIR/slack.$FILENAME -H "Authorization: Bearer $SLACK_AUDIT_REPORT_KEY" -X POST https://slack.com/api/chat.postMessage + + - name: Unit tests UI + run: yarn test:cov --ci --silent diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml new file mode 100644 index 0000000000..c4d76e0ac6 --- /dev/null +++ b/.github/workflows/tests.yml @@ -0,0 +1,57 @@ +name: Tests Pipeline + +on: + push: + branches: + - 'gh/**' + # todo uncomment + # branches-ignore: + # - main + + workflow_dispatch: + inputs: + all-tests: + description: Run all tests (FE, BE, IT, E2E) + type: boolean + required: false + default: false + +jobs: + changes: + runs-on: ubuntu-latest + outputs: + frontend: ${{ steps.filter.outputs.frontend }} + backend: ${{ steps.filter.outputs.backend }} + desktop: ${{ steps.filter.outputs.desktop }} + e2e: ${{ steps.filter.outputs.e2e }} + steps: + - uses: actions/checkout@v4.1.0 + - uses: dorny/paths-filter@v3.0.2 + id: filter + with: + base: ${{ github.ref }} + filters: | + frontend: + - 'redisinsight/ui/**' + backend: + - 'redisinsight/api/**' + desktop: + - 'redisinsight/desktop/**' + e2e: + - 'tests/e2e/**' + + frontend-tests: + # TODO: concurrency + # concurrency: build + needs: changes + if: ${{ needs.changes.outputs.frontend == 'true' || inputs.all-tests }} + uses: ./.github/workflows/tests-frontend.yml + # secrets: inherit + + backend-tests: + # TODO: concurrency + # concurrency: build + needs: changes + if: ${{ needs.changes.outputs.backend == 'true' || inputs.all-tests }} + uses: ./.github/workflows/tests-backend.yml + # secrets: inherit diff --git a/.gitignore b/.gitignore index a8f55c5a81..232acd8c53 100644 --- a/.gitignore +++ b/.gitignore @@ -18,6 +18,11 @@ lerna-debug.log* /.nyc_output **/coverage +#CI +.actrc +my.secrets +my.inputs + # IDEs and editors /.idea .idea/ diff --git a/configs/webpack.config.renderer.dev.dll.ts b/configs/webpack.config.renderer.dev.dll.ts deleted file mode 100644 index 4953b7f4b7..0000000000 --- a/configs/webpack.config.renderer.dev.dll.ts +++ /dev/null @@ -1,147 +0,0 @@ -import webpack from 'webpack'; -import path from 'path'; -import { merge } from 'webpack-merge'; -import baseConfig from './webpack.config.base'; -import webpackPaths from './webpack.paths'; -import { dependencies } from '../package.json'; -import { dependencies as dependenciesApi } from '../redisinsight/package.json'; - -console.log('dependenciesApi', dependenciesApi); - -const dist = webpackPaths.dllPath; - -export default merge(baseConfig, { - context: webpackPaths.rootPath, - - devtool: 'eval', - - mode: 'development', - - target: 'electron-renderer', - - externals: ['fsevents', 'crypto-browserify', 'hiredis'], - - /** - * Use `module` from `webpack.config.renderer.dev.js` - */ - module: { - rules: [ - { - test: /\.css$/, - use: ['style-loader', 'css-loader'], - }, - - // TTF Font - { - test: /\.ttf(\?v=\d+\.\d+\.\d+)?$/, - exclude: /codicon\.ttf(\?v=\d+\.\d+\.\d+)?$/, - use: [ - { - loader: 'file-loader', - options: { - name: '[hash]-[name].[ext]', - outputPath: 'fonts', - publicPath: 'fonts', - }, - }, - ], - }, - // TTF codicon font - { - test: /codicon\.ttf(\?v=\d+\.\d+\.\d+)?$/, - use: 'url-loader', - }, - - // TODO remove after regression - // // WOFF Font - // { - // test: /\.woff(\?v=\d+\.\d+\.\d+)?$/, - // use: { - // loader: 'url-loader', - // options: { - // limit: 10000, - // mimetype: 'application/font-woff', - // }, - // }, - // }, - // // WOFF2 Font - // { - // test: /\.woff2(\?v=\d+\.\d+\.\d+)?$/, - // use: [ - // { - // loader: 'file-loader', - // options: { - // name: '[hash]-[name].[ext]', - // outputPath: 'fonts', - // publicPath: 'fonts', - // }, - // }, - // ], - // }, - // // OTF Font - // { - // test: /\.otf(\?v=\d+\.\d+\.\d+)?$/, - // use: [ - // { - // loader: 'file-loader', - // options: { - // name: '[hash]-[name].[ext]', - // outputPath: 'fonts', - // publicPath: 'fonts', - // }, - // }, - // ], - // }, - // // EOT Font - // { - // test: /\.eot(\?v=\d+\.\d+\.\d+)?$/, - // use: 'file-loader', - // }, - // { - // test: /\.svg$/, - // use: ['@svgr/webpack', 'url-loader'], - // }, - // // Common Image Formats - // { - // test: /\.(?:ico|gif|png|jpg|jpeg|webp)$/, - // use: 'url-loader', - // }, - ], - }, - - entry: { - renderer: [...Object.keys(dependencies || {}), ...Object.keys(dependenciesApi || {})], - }, - - output: { - path: dist, - filename: '[name].dev.dll.js', - library: { - name: 'renderer', - type: 'var', - }, - }, - - stats: 'errors-only', - - plugins: [ - new webpack.DllPlugin({ - path: path.join(dist, '[name].json'), - name: '[name]', - }), - - new webpack.EnvironmentPlugin({ - NODE_ENV: 'development', - }), - - new webpack.LoaderOptionsPlugin({ - debug: true, - options: { - context: webpackPaths.desktopPath, - output: { - path: webpackPaths.dllPath, - }, - }, - }), - ], -}); diff --git a/configs/webpack.config.renderer.dev.ts b/configs/webpack.config.renderer.dev.ts deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/configs/webpack.config.renderer.prod.ts b/configs/webpack.config.renderer.prod.ts deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/configs/webpack.config.web.common.ts b/configs/webpack.config.web.common.ts deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/configs/webpack.config.web.prod.ts b/configs/webpack.config.web.prod.ts deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/package.json b/package.json index de3b637fec..23d6d10bf9 100644 --- a/package.json +++ b/package.json @@ -26,15 +26,15 @@ "lint:e2e": "yarn --cwd tests/e2e lint", "package": "yarn package:dev", "package:prod": "ts-node ./scripts/prebuild.js dist && yarn build:prod && electron-builder build -p never", - "package:stage": "ts-node ./scripts/prebuild.js dist && yarn build:stage && electron-builder build -p never -c.mac.bundleVersion=$CIRCLE_BUILD_NUM", - "package:mas": "electron-builder build -p never -m mas:universal -c.mac.bundleVersion=$CIRCLE_BUILD_NUM -c ./electron-builder-mas.js", + "package:stage": "ts-node ./scripts/prebuild.js dist && yarn build:stage && electron-builder build -p never -c.mac.bundleVersion=$GITHUB_RUN_ID", + "package:mas": "electron-builder build -p never -m mas:universal -c.mac.bundleVersion=$GITHUB_RUN_ID -c ./electron-builder-mas.js", "package:mas:dev": "electron-builder build -p never -m mas-dev:universal -c ./electron-builder-mas.js", "package:dev": "yarn build && cross-env DEBUG=electron-builder electron-builder build -p never", "package:win": "yarn build:prod && electron-builder build --win --x64 -p never", "package:mac": "yarn build:prod && electron-builder build --mac -p never", "package:mac:arm": "yarn build:prod && electron-builder build --mac --arm64 -p never", "package:linux": "yarn build:prod && electron-builder build --linux -p never", - "postinstall": "patch-package && vite optimize && skip-postinstall || (electron-builder install-app-deps && cross-env NODE_ENV=development TS_NODE_TRANSPILE_ONLY=true webpack --config ./configs/webpack.config.renderer.dev.dll.ts && opencollective-postinstall && yarn-deduplicate yarn.lock)", + "postinstall": "patch-package && skip-postinstall || (electron-builder install-app-deps && yarn-deduplicate yarn.lock)", "start": "ts-node ./scripts/check-port-in-use.js && yarn start:renderer", "start:renderer": "cross-env NODE_ENV=development TS_NODE_TRANSPILE_ONLY=true webpack serve --config ./configs/webpack.config.renderer.dev.ts", "start:preload": "cross-env NODE_ENV=development TS_NODE_TRANSPILE_ONLY=true webpack --config ./configs/webpack.config.preload.dev.ts", @@ -173,7 +173,6 @@ "mini-css-extract-plugin": "2.7.2", "moment": "^2.29.3", "msw": "^1.3.2", - "opencollective-postinstall": "^2.0.3", "patch-package": "^8.0.0", "postinstall-postinstall": "^2.1.0", "react-refresh": "^0.9.0", diff --git a/yarn.lock b/yarn.lock index 72ec81393c..6c4e670ba1 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5524,16 +5524,16 @@ date-fns-tz@^3.1.3: resolved "https://registry.yarnpkg.com/date-fns-tz/-/date-fns-tz-3.1.3.tgz#643dfc7157008a3873cd717973e4074bb802f962" integrity sha512-ZfbMu+nbzW0mEzC8VZrLiSWvUIaI3aRHeq33mTe7Y38UctKukgqPR4nTDwcwS4d64Gf8GghnVsroBuMY3eiTeA== -date-fns@*, date-fns@^2.0.1: - version "2.29.3" - resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-2.29.3.tgz#27402d2fc67eb442b511b70bbdf98e6411cd68a8" - integrity sha512-dDCnyH2WnnKusqvZZ6+jA1O51Ibt8ZMRNkDZdyAyK4YfbDwa/cEmuztzG5pk6hqlp9aSBPYcjOlktquahGwGeA== - -date-fns@^3.6.0: +date-fns@*, date-fns@^3.6.0: version "3.6.0" resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-3.6.0.tgz#f20ca4fe94f8b754951b24240676e8618c0206bf" integrity sha512-fRHTG8g/Gif+kSh50gaGEdToemgfj74aRX3swtiouboip5JDLAyDE9F11nHMIcvOaXeOC6D7SpNhi7uFyB7Uww== +date-fns@^2.0.1: + version "2.29.3" + resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-2.29.3.tgz#27402d2fc67eb442b511b70bbdf98e6411cd68a8" + integrity sha512-dDCnyH2WnnKusqvZZ6+jA1O51Ibt8ZMRNkDZdyAyK4YfbDwa/cEmuztzG5pk6hqlp9aSBPYcjOlktquahGwGeA== + debounce-fn@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/debounce-fn/-/debounce-fn-4.0.0.tgz#ed76d206d8a50e60de0dd66d494d82835ffe61c7" From 5dede97a39fab8a4fc76a694e414f4c2d6a4db1b Mon Sep 17 00:00:00 2001 From: Roman Sergeenko Date: Mon, 14 Oct 2024 09:29:35 +0200 Subject: [PATCH 153/256] fix monitor typo --- redisinsight/ui/src/components/monitor-config/MonitorConfig.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/redisinsight/ui/src/components/monitor-config/MonitorConfig.tsx b/redisinsight/ui/src/components/monitor-config/MonitorConfig.tsx index 3720282095..ed62e75409 100644 --- a/redisinsight/ui/src/components/monitor-config/MonitorConfig.tsx +++ b/redisinsight/ui/src/components/monitor-config/MonitorConfig.tsx @@ -89,7 +89,7 @@ const MonitorConfig = ({ retryDelay = 15000 } : IProps) => { } payloadsRef.current.push({ isError: true, time: `${Date.now()}`, ...payload }) - setNewItems(payloadsRef.current, () => { payloads.length = 0 }) + setNewItems(payloadsRef.current, () => { payloadsRef.current.length = 0 }) dispatch(pauseMonitor()) }) From 0343fafa4e02075390c666cc1b4d39d93b3de4d1 Mon Sep 17 00:00:00 2001 From: zalenskiSofteq Date: Mon, 14 Oct 2024 09:31:33 +0200 Subject: [PATCH 154/256] #RI-6158 - Migrate build workflows from CircleCI to Github Actions --- .circleci/build/build.sh | 3 +- .../actions/install-all-build-libs/action.yml | 5 -- .github/actions/install-deps/action.yml | 6 -- .../actions/install-windows-certs/action.yml | 2 - .github/workflows/pipeline-build-linux.yml | 5 +- .github/workflows/pipeline-build-macos.yml | 9 +-- .github/workflows/pipeline-build-windows.yml | 5 +- .github/workflows/tests.yml | 7 +-- package.json | 4 -- yarn.lock | 55 ------------------- 10 files changed, 9 insertions(+), 92 deletions(-) diff --git a/.circleci/build/build.sh b/.circleci/build/build.sh index 780341b022..907587ced2 100755 --- a/.circleci/build/build.sh +++ b/.circleci/build/build.sh @@ -7,7 +7,6 @@ yarn --cwd redisinsight/api # build -# TODO remove -# yarn build:statics +yarn build:statics yarn build:ui yarn --cwd ./redisinsight/api build:prod diff --git a/.github/actions/install-all-build-libs/action.yml b/.github/actions/install-all-build-libs/action.yml index c959e889d3..8a7ef7d581 100644 --- a/.github/actions/install-all-build-libs/action.yml +++ b/.github/actions/install-all-build-libs/action.yml @@ -88,8 +88,3 @@ runs: dir-path: './' keytar-host-mirror: ${{ inputs.keytar-host-mirror }} sqlite3-host-mirror: ${{ inputs.sqlite3-host-mirror }} - - - - - diff --git a/.github/actions/install-deps/action.yml b/.github/actions/install-deps/action.yml index 41088e769b..8a5433605c 100644 --- a/.github/actions/install-deps/action.yml +++ b/.github/actions/install-deps/action.yml @@ -18,12 +18,6 @@ inputs: runs: using: 'composite' steps: - # - name: Cache dependencies - # uses: actions/cache@v4 - # with: - # path: ${{ inputs.dir-path }}/node_modules - # key: ${{ runner.os }}-yarn-${{ hashFiles('${{ inputs.dir-path }}/yarn.lock') }} - - name: Install dependencies working-directory: ${{ inputs.dir-path }} shell: bash diff --git a/.github/actions/install-windows-certs/action.yml b/.github/actions/install-windows-certs/action.yml index c69a0eeb59..9fbe9fb97b 100644 --- a/.github/actions/install-windows-certs/action.yml +++ b/.github/actions/install-windows-certs/action.yml @@ -14,5 +14,3 @@ runs: run: | mkdir -p certs echo "$WIN_CSC_PFX_BASE64" | base64 -d > certs/redislabs_win.pfx - - diff --git a/.github/workflows/pipeline-build-linux.yml b/.github/workflows/pipeline-build-linux.yml index f85d56e10b..b0ab2b2aec 100644 --- a/.github/workflows/pipeline-build-linux.yml +++ b/.github/workflows/pipeline-build-linux.yml @@ -48,9 +48,8 @@ jobs: # path: "." # - run: cp ./electron/package.json ./redisinsight/ - # TODO: uncomment - # - name: Install plugins dependencies and build plugins - # run: yarn build:statics + - name: Install plugins dependencies and build plugins + run: yarn build:statics - name: Build linux packages (production) if: vars.ENV == 'production' && inputs.target == 'all' diff --git a/.github/workflows/pipeline-build-macos.yml b/.github/workflows/pipeline-build-macos.yml index 5d63aaf4ed..3595ec221e 100644 --- a/.github/workflows/pipeline-build-macos.yml +++ b/.github/workflows/pipeline-build-macos.yml @@ -25,9 +25,6 @@ jobs: steps: - uses: actions/checkout@v4.1.0 - # Install libsecret - # - run: brew install libsecret - - name: Add certificates to the keychain uses: ./.github/actions/install-apple-certs with: @@ -44,10 +41,8 @@ jobs: keytar-host-mirror: ${{ secrets.NPM_CONFIG_KEYTAR_BINARY_HOST_MIRROR }} sqlite3-host-mirror: ${{ secrets.NPM_CONFIG_NODE_SQLITE3_BINARY_HOST_MIRROR }} - - #TODO uncomment - # - name: Install plugins dependencies and build plugins - # run: yarn build:statics + - name: Install plugins dependencies and build plugins + run: yarn build:statics - name: Build macos dmg (prod) if: vars.ENV == 'production' && inputs.target == 'all' diff --git a/.github/workflows/pipeline-build-windows.yml b/.github/workflows/pipeline-build-windows.yml index 6398c3b620..9b3dcbe060 100644 --- a/.github/workflows/pipeline-build-windows.yml +++ b/.github/workflows/pipeline-build-windows.yml @@ -21,9 +21,8 @@ jobs: with: WIN_CSC_PFX_BASE64: ${{ secrets.WIN_CSC_PFX_BASE64 }} - #TODO uncomment - # - name: Install plugins dependencies and build plugins - # run: yarn build:statics:win + - name: Install plugins dependencies and build plugins + run: yarn build:statics:win - name: Build windows exe (production) if: vars.ENV == 'production' diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index c4d76e0ac6..d41e5d61aa 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -2,11 +2,8 @@ name: Tests Pipeline on: push: - branches: - - 'gh/**' - # todo uncomment - # branches-ignore: - # - main + branches-ignore: + - main workflow_dispatch: inputs: diff --git a/package.json b/package.json index 23d6d10bf9..6794373a39 100644 --- a/package.json +++ b/package.json @@ -161,7 +161,6 @@ "google-auth-library": "^9.0.0", "googleapis": "^125.0.0", "html-webpack-plugin": "^5.6.0", - "husky": "^4.2.5", "identity-obj-proxy": "^3.0.0", "ioredis-mock": "^5.5.4", "jest": "^29.7.0", @@ -277,9 +276,6 @@ "npm": ">=6.x", "yarn": ">=1.21.3" }, - "husky": { - "hooks": {} - }, "browser": { "uuid": "./node_modules/uuid/dist/esm-browser/index.js" } diff --git a/yarn.lock b/yarn.lock index 6c4e670ba1..2220b6439a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4587,11 +4587,6 @@ chromium-pickle-js@^0.2.0: resolved "https://registry.yarnpkg.com/chromium-pickle-js/-/chromium-pickle-js-0.2.0.tgz#04a106672c18b085ab774d983dfa3ea138f22205" integrity sha512-1R5Fho+jBq0DDydt+/vHWj5KJNJCKdARKOCwZUen84I5BreWoLqRLANH1U87eJy1tiASPtMnGqJJq0ZsLoRPOw== -ci-info@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-2.0.0.tgz#67a9e964be31a51e15e5010d58e6f12834002f46" - integrity sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ== - ci-info@^3.2.0, ci-info@^3.7.0: version "3.9.0" resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-3.9.0.tgz#4279a62028a7b1f262f3473fc9605f5e218c59b4" @@ -4808,11 +4803,6 @@ compare-version@^0.1.2: resolved "https://registry.yarnpkg.com/compare-version/-/compare-version-0.1.2.tgz#0162ec2d9351f5ddd59a9202cba935366a725080" integrity sha512-pJDh5/4wrEnXX/VWRZvruAGHkzKdr46z11OlTPN+VrATlWWhSKewNCJ1futCO5C7eJB3nPMFZA1LeYtcFboZ2A== -compare-versions@^3.6.0: - version "3.6.0" - resolved "https://registry.yarnpkg.com/compare-versions/-/compare-versions-3.6.0.tgz#1a5689913685e5a87637b8d3ffca75514ec41d62" - integrity sha512-W6Af2Iw1z4CB7q4uU4hv646dW9GQuBM+YpC0UvUCWSD8w90SJjp+ujJuXaEMtAXBtSqGfMPuFOVn4/+FlaqfBA== - component-emitter@^1.2.0, component-emitter@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.3.0.tgz#16e4070fba8ae29b679f2215853ee181ab2eabc0" @@ -7128,13 +7118,6 @@ find-up@^5.0.0: locate-path "^6.0.0" path-exists "^4.0.0" -find-versions@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/find-versions/-/find-versions-4.0.0.tgz#3c57e573bf97769b8cb8df16934b627915da4965" - integrity sha512-wgpWy002tA+wgmO27buH/9KzyEOQnKsG/R0yrcjPT9BOFm0zRBVQbZ95nRGXWMywS8YR5knRbpohio0bcJABxQ== - dependencies: - semver-regex "^3.1.2" - find-yarn-workspace-root@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/find-yarn-workspace-root/-/find-yarn-workspace-root-2.0.0.tgz#f47fb8d239c900eb78179aa81b66673eac88f7bd" @@ -8091,22 +8074,6 @@ humanize-ms@^1.2.1: dependencies: ms "^2.0.0" -husky@^4.2.5: - version "4.3.8" - resolved "https://registry.yarnpkg.com/husky/-/husky-4.3.8.tgz#31144060be963fd6850e5cc8f019a1dfe194296d" - integrity sha512-LCqqsB0PzJQ/AlCgfrfzRe3e3+NvmefAdKQhRYpxS4u6clblBoDdzzvHi8fmxKRzvMxPY/1WZWzomPZww0Anow== - dependencies: - chalk "^4.0.0" - ci-info "^2.0.0" - compare-versions "^3.6.0" - cosmiconfig "^7.0.0" - find-versions "^4.0.0" - opencollective-postinstall "^2.0.2" - pkg-dir "^5.0.0" - please-upgrade-node "^3.2.0" - slash "^3.0.0" - which-pm-runs "^1.0.0" - iconv-corefoundation@^1.1.7: version "1.1.7" resolved "https://registry.yarnpkg.com/iconv-corefoundation/-/iconv-corefoundation-1.1.7.tgz#31065e6ab2c9272154c8b0821151e2c88f1b002a" @@ -10924,11 +10891,6 @@ open@^8.4.0: is-docker "^2.1.1" is-wsl "^2.2.0" -opencollective-postinstall@^2.0.2, opencollective-postinstall@^2.0.3: - version "2.0.3" - resolved "https://registry.yarnpkg.com/opencollective-postinstall/-/opencollective-postinstall-2.0.3.tgz#7a0fff978f6dbfa4d006238fbac98ed4198c3259" - integrity sha512-8AV/sCtuzUeTo8gQK5qDZzARrulB3egtLzFgteqB2tcT4Mw7B8Kt7JcDHmltjz6FOAHsvTevk70gZEbhM4ZS9Q== - opener@^1.5.2: version "1.5.2" resolved "https://registry.yarnpkg.com/opener/-/opener-1.5.2.tgz#5d37e1f35077b9dcac4301372271afdeb2a13598" @@ -11279,13 +11241,6 @@ pkg-dir@^4.2.0: dependencies: find-up "^4.0.0" -pkg-dir@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-5.0.0.tgz#a02d6aebe6ba133a928f74aec20bafdfe6b8e760" - integrity sha512-NPE8TDbzl/3YQYY7CSS228s3g2ollTFnc+Qi3tqmqJp9Vg2ovUpixcJEo2HJScN2Ez+kEaal6y70c0ehqJBJeA== - dependencies: - find-up "^5.0.0" - pkg-up@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/pkg-up/-/pkg-up-3.1.0.tgz#100ec235cc150e4fd42519412596a28512a0def5" @@ -12905,11 +12860,6 @@ semver-compare@^1.0.0: resolved "https://registry.yarnpkg.com/semver-compare/-/semver-compare-1.0.0.tgz#0dee216a1c941ab37e9efb1788f6afc5ff5537fc" integrity sha512-YM3/ITh2MJ5MtzaM429anh+x2jiLVjqILF4m4oyQB18W7Ggea7BfqdH/wGMK7dDiMghv/6WG7znWMwUDzJiXow== -semver-regex@^3.1.2: - version "3.1.4" - resolved "https://registry.yarnpkg.com/semver-regex/-/semver-regex-3.1.4.tgz#13053c0d4aa11d070a2f2872b6b1e3ae1e1971b4" - integrity sha512-6IiqeZNgq01qGf0TId0t3NvKzSvUsjcpdEO3AQNeIjR6A2+ckTnQlDpl4qu1bjRv0RzN3FP9hzFmws3lKqRWkA== - "semver@2 || 3 || 4 || 5", semver@7.3.5, semver@7.x, semver@^5.5.0, semver@^5.7.2, semver@^6.2.0, semver@^6.3.0, semver@^6.3.1, semver@^7.2.1, semver@^7.3.2, semver@^7.3.4, semver@^7.3.5, semver@^7.3.7, semver@^7.3.8, semver@^7.5.2, semver@^7.5.3, semver@^7.5.4: version "7.5.4" resolved "https://registry.yarnpkg.com/semver/-/semver-7.5.4.tgz#483986ec4ed38e1c6c48c34894a9182dbff68a6e" @@ -14969,11 +14919,6 @@ which-module@^2.0.0: resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.1.tgz#776b1fe35d90aebe99e8ac15eb24093389a4a409" integrity sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ== -which-pm-runs@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/which-pm-runs/-/which-pm-runs-1.1.0.tgz#35ccf7b1a0fce87bd8b92a478c9d045785d3bf35" - integrity sha512-n1brCuqClxfFfq/Rb0ICg9giSZqCS+pLtccdag6C2HyufBrh3fBOiy9nb6ggRMvWOVH5GrdJskj5iGTZNxd7SA== - which-typed-array@^1.1.14, which-typed-array@^1.1.15, which-typed-array@^1.1.2, which-typed-array@^1.1.9: version "1.1.15" resolved "https://registry.yarnpkg.com/which-typed-array/-/which-typed-array-1.1.15.tgz#264859e9b11a649b388bfaaf4f767df1f779b38d" From 1b183679641146089001ccf302aec1ef4090bd32 Mon Sep 17 00:00:00 2001 From: zalenskiSofteq Date: Mon, 14 Oct 2024 09:32:46 +0200 Subject: [PATCH 155/256] #RI-6158 - Migrate build workflows from CircleCI to Github Actions --- yarn.lock | 5 ----- 1 file changed, 5 deletions(-) diff --git a/yarn.lock b/yarn.lock index 80925110c2..76b721753b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -14804,11 +14804,6 @@ which-collection@^1.0.1: is-weakmap "^2.0.1" is-weakset "^2.0.1" -which-pm-runs@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/which-pm-runs/-/which-pm-runs-1.1.0.tgz#35ccf7b1a0fce87bd8b92a478c9d045785d3bf35" - integrity sha512-n1brCuqClxfFfq/Rb0ICg9giSZqCS+pLtccdag6C2HyufBrh3fBOiy9nb6ggRMvWOVH5GrdJskj5iGTZNxd7SA== - which-typed-array@^1.1.14, which-typed-array@^1.1.15, which-typed-array@^1.1.2, which-typed-array@^1.1.9: version "1.1.15" resolved "https://registry.yarnpkg.com/which-typed-array/-/which-typed-array-1.1.15.tgz#264859e9b11a649b388bfaaf4f767df1f779b38d" From 7a380988f21ad5d57e625192ccdcca16ecf5336f Mon Sep 17 00:00:00 2001 From: zalenskiSofteq Date: Mon, 14 Oct 2024 09:36:05 +0200 Subject: [PATCH 156/256] #RI-6158 - Migrate build workflows from CircleCI to Github Actions --- .github/workflows/build.yml | 18 ++++++++++++------ package.json | 2 +- 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 1a7a1c9aa3..65e9ea5df3 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -1,6 +1,10 @@ name: Build on: + push: + branches: + - 'feature/**' + workflow_dispatch: inputs: target: @@ -28,26 +32,28 @@ on: jobs: build_linux: - if: startsWith(inputs.target, 'linux') || inputs.target == 'all' + # if: startsWith(inputs.target, 'linux') || inputs.target == 'all' # concurrency: build uses: ./.github/workflows/pipeline-build-linux.yml secrets: inherit with: - target: ${{ inputs.target }} + target: 'all' + # target: ${{ inputs.target }} build_macos: - if: startsWith(inputs.target, 'macos') || inputs.target == 'all' + # if: startsWith(inputs.target, 'macos') || inputs.target == 'all' uses: ./.github/workflows/pipeline-build-macos.yml secrets: inherit with: - target: ${{ inputs.target }} + target: 'all' + # target: ${{ inputs.target }} build_windows: - if: startsWith(inputs.target, 'windows') || inputs.target == 'all' + # if: startsWith(inputs.target, 'windows') || inputs.target == 'all' uses: ./.github/workflows/pipeline-build-windows.yml secrets: inherit build_docker: - if: startsWith(inputs.target, 'docker') || inputs.target == 'all' + # if: startsWith(inputs.target, 'docker') || inputs.target == 'all' uses: ./.github/workflows/pipeline-build-docker.yml secrets: inherit diff --git a/package.json b/package.json index cca1e88ecc..9e8b477bf6 100644 --- a/package.json +++ b/package.json @@ -34,7 +34,7 @@ "package:mac": "yarn build:prod && electron-builder build --mac -p never", "package:mac:arm": "yarn build:prod && electron-builder build --mac --arm64 -p never", "package:linux": "yarn build:prod && electron-builder build --linux -p never", - "postinstall": "patch-package && skip-postinstall || (electron-builder install-app-deps && yarn-deduplicate yarn.lock)", + "postinstall": "patch-package && vite optimize && skip-postinstall || (electron-builder install-app-deps && yarn-deduplicate yarn.lock)", "start": "ts-node ./scripts/check-port-in-use.js && yarn start:renderer", "start:renderer": "cross-env NODE_ENV=development TS_NODE_TRANSPILE_ONLY=true webpack serve --config ./configs/webpack.config.renderer.dev.ts", "start:preload": "cross-env NODE_ENV=development TS_NODE_TRANSPILE_ONLY=true webpack --config ./configs/webpack.config.preload.dev.ts", From ffa934a3c747cae68f6997f41ef3d524a278c048 Mon Sep 17 00:00:00 2001 From: zalenskiSofteq Date: Mon, 14 Oct 2024 10:10:59 +0200 Subject: [PATCH 157/256] #RI-6158 - Migrate build workflows from CircleCI to Github Actions --- .github/workflows/build.yml | 18 ++++++------------ .github/workflows/tests.yml | 2 +- 2 files changed, 7 insertions(+), 13 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 65e9ea5df3..1a7a1c9aa3 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -1,10 +1,6 @@ name: Build on: - push: - branches: - - 'feature/**' - workflow_dispatch: inputs: target: @@ -32,28 +28,26 @@ on: jobs: build_linux: - # if: startsWith(inputs.target, 'linux') || inputs.target == 'all' + if: startsWith(inputs.target, 'linux') || inputs.target == 'all' # concurrency: build uses: ./.github/workflows/pipeline-build-linux.yml secrets: inherit with: - target: 'all' - # target: ${{ inputs.target }} + target: ${{ inputs.target }} build_macos: - # if: startsWith(inputs.target, 'macos') || inputs.target == 'all' + if: startsWith(inputs.target, 'macos') || inputs.target == 'all' uses: ./.github/workflows/pipeline-build-macos.yml secrets: inherit with: - target: 'all' - # target: ${{ inputs.target }} + target: ${{ inputs.target }} build_windows: - # if: startsWith(inputs.target, 'windows') || inputs.target == 'all' + if: startsWith(inputs.target, 'windows') || inputs.target == 'all' uses: ./.github/workflows/pipeline-build-windows.yml secrets: inherit build_docker: - # if: startsWith(inputs.target, 'docker') || inputs.target == 'all' + if: startsWith(inputs.target, 'docker') || inputs.target == 'all' uses: ./.github/workflows/pipeline-build-docker.yml secrets: inherit diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index d41e5d61aa..b103133c0d 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -1,4 +1,4 @@ -name: Tests Pipeline +name: Tests on: push: From de63de4c1293581c60d9cbb50b0225e6ef798a51 Mon Sep 17 00:00:00 2001 From: mariasergeenko Date: Mon, 14 Oct 2024 10:48:58 +0200 Subject: [PATCH 158/256] update response --- tests/e2e/helpers/common.ts | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/tests/e2e/helpers/common.ts b/tests/e2e/helpers/common.ts index bfae5c4f4c..c6cc4db1a9 100644 --- a/tests/e2e/helpers/common.ts +++ b/tests/e2e/helpers/common.ts @@ -16,11 +16,12 @@ declare global { const settingsApiUrl = `${apiUrl}/settings`; process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0'; // lgtm[js/disabling-certificate-validation] const mockedSettingsResponse = { - agreements: { - version: '0', - eula: false, - analytics: false - } + "theme": null, + "dateFormat": null, + "timezone": null, + "scanThreshold": 10000, + "batchSize": 5, + "agreements": null }; export class Common { From fef8ce3feb13a89ac2331d3202da83906109247a Mon Sep 17 00:00:00 2001 From: Roman Sergeenko Date: Mon, 14 Oct 2024 10:50:55 +0200 Subject: [PATCH 159/256] #RI-6203 - fix suggestions --- .../ui/src/pages/workbench/components/query/Query/Query.tsx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/redisinsight/ui/src/pages/workbench/components/query/Query/Query.tsx b/redisinsight/ui/src/pages/workbench/components/query/Query/Query.tsx index 2708b01c04..7670e4b8f2 100644 --- a/redisinsight/ui/src/pages/workbench/components/query/Query/Query.tsx +++ b/redisinsight/ui/src/pages/workbench/components/query/Query/Query.tsx @@ -556,12 +556,11 @@ const Query = (props: Props) => { if (position.column === 1) { helpWidgetRef.current.isOpen = false if (command) return asSuggestionsRef([]) - return asSuggestionsRef(getCommandsSuggestions(REDIS_COMMANDS, range), false) } if (!command) { - return asSuggestionsRef([], false) + return asSuggestionsRef(getCommandsSuggestions(REDIS_COMMANDS, range), false) } const { allArgs, args, cursor } = command From 7927f6c2493a53d153e0ab3a2e3f23b4629f97c5 Mon Sep 17 00:00:00 2001 From: mariasergeenko Date: Mon, 14 Oct 2024 11:01:48 +0200 Subject: [PATCH 160/256] unskip --- .../a-first-start-form/user-agreements-form.e2e.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/e2e/tests/electron/critical-path/a-first-start-form/user-agreements-form.e2e.ts b/tests/e2e/tests/electron/critical-path/a-first-start-form/user-agreements-form.e2e.ts index 5a6db46b2a..2124c81ff6 100644 --- a/tests/e2e/tests/electron/critical-path/a-first-start-form/user-agreements-form.e2e.ts +++ b/tests/e2e/tests/electron/critical-path/a-first-start-form/user-agreements-form.e2e.ts @@ -8,7 +8,7 @@ const userAgreementDialog = new UserAgreementDialog(); const myRedisDatabasePage = new MyRedisDatabasePage(); // Skipped due to unworking mocs to refresh eula https://redislabs.atlassian.net/browse/RI-5868 -fixture.skip `Agreements Verification` +fixture `Agreements Verification` .meta({ type: 'critical_path', rte: rte.none }) .page(commonUrl) .requestHooks(Common.mockSettingsResponse()) From 9aef9db033b36289fd930e476e3d95bd91ae1db6 Mon Sep 17 00:00:00 2001 From: zalenskiSofteq Date: Mon, 14 Oct 2024 12:50:40 +0200 Subject: [PATCH 161/256] #RI-6158 - Turn off auto run Unit tests --- .github/workflows/pipeline-build-macos.yml | 10 +++++----- .github/workflows/tests-frontend.yml | 2 +- .github/workflows/tests.yml | 10 +++++----- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/.github/workflows/pipeline-build-macos.yml b/.github/workflows/pipeline-build-macos.yml index 3595ec221e..776930a1bb 100644 --- a/.github/workflows/pipeline-build-macos.yml +++ b/.github/workflows/pipeline-build-macos.yml @@ -86,18 +86,18 @@ jobs: with: name: 'macos-x64-builds' path: | - ./release/Redis-Insight*x64.zip ./release/Redis-Insight*x64.dmg - ./release/Redis-Insight*x64.dmg.blockmap + # ./release/Redis-Insight*x64.zip + # ./release/Redis-Insight*x64.dmg.blockmap - name: Upload ARM packages uses: actions/upload-artifact@v4.1.0 with: name: 'macos-arm-builds' path: | - ./release/Redis-Insight*arm64.zip ./release/Redis-Insight*arm64.dmg - ./release/Redis-Insight*arm64.dmg.blockmap + # ./release/Redis-Insight*arm64.zip + # ./release/Redis-Insight*arm64.dmg.blockmap - name: Upload MAS packages uses: actions/upload-artifact@v4.1.0 @@ -105,7 +105,7 @@ jobs: name: 'macos-mas-builds' path: | ./release/Redis-Insight*.pkg - ./release/*-mac.yml + # ./release/*-mac.yml - name: Upload redis stack packages uses: actions/upload-artifact@v4.1.0 diff --git a/.github/workflows/tests-frontend.yml b/.github/workflows/tests-frontend.yml index 77016a6dd7..71468608fe 100644 --- a/.github/workflows/tests-frontend.yml +++ b/.github/workflows/tests-frontend.yml @@ -3,7 +3,7 @@ on: workflow_call: env: - SLACK_AUDIT_REPORT_KEY: ${secrets.SLACK_AUDIT_REPORT_KEY }} + SLACK_AUDIT_REPORT_KEY: ${{ secrets.SLACK_AUDIT_REPORT_KEY }} jobs: unit-tests: diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index b103133c0d..5d7165b690 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -1,9 +1,9 @@ name: Tests on: - push: - branches-ignore: - - main + # push: + # branches-ignore: + # - main workflow_dispatch: inputs: @@ -41,7 +41,7 @@ jobs: # TODO: concurrency # concurrency: build needs: changes - if: ${{ needs.changes.outputs.frontend == 'true' || inputs.all-tests }} + if: needs.changes.outputs.frontend == 'true' || inputs.all-tests uses: ./.github/workflows/tests-frontend.yml # secrets: inherit @@ -49,6 +49,6 @@ jobs: # TODO: concurrency # concurrency: build needs: changes - if: ${{ needs.changes.outputs.backend == 'true' || inputs.all-tests }} + if: needs.changes.outputs.backend == 'true' || inputs.all-tests uses: ./.github/workflows/tests-backend.yml # secrets: inherit From 19aa6631af494d5db1a55bc4e2e3258764bafd22 Mon Sep 17 00:00:00 2001 From: zalenskiSofteq Date: Mon, 14 Oct 2024 12:50:47 +0200 Subject: [PATCH 162/256] #RI-6158 - Turn off auto run Unit tests --- .github/workflows/pipeline-build-linux.yml | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/.github/workflows/pipeline-build-linux.yml b/.github/workflows/pipeline-build-linux.yml index b0ab2b2aec..b167f4454d 100644 --- a/.github/workflows/pipeline-build-linux.yml +++ b/.github/workflows/pipeline-build-linux.yml @@ -79,10 +79,22 @@ jobs: ./release/*-linux.yml - uses: actions/upload-artifact@v4.1.0 - name: Upload artifacts + name: Upload Deb artifact with: - name: 'linux-builds' + name: 'linux-deb-build' path: | ./release/Redis-Insight*.deb + + - uses: actions/upload-artifact@v4.1.0 + name: Upload rpm artifacts + with: + name: 'linux-rpm-build' + path: | ./release/Redis-Insight*.rpm + + - uses: actions/upload-artifact@v4.1.0 + name: Upload snap artifact + with: + name: 'linux-snap-builds' + path: | ./release/Redis-Insight*.snap From 886719ec27edda69b2a28673aa15916087323763 Mon Sep 17 00:00:00 2001 From: zalenskiSofteq Date: Mon, 14 Oct 2024 13:14:55 +0200 Subject: [PATCH 163/256] #RI-6158 - Add $ENV to docker build --- .github/workflows/pipeline-build-docker.yml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/workflows/pipeline-build-docker.yml b/.github/workflows/pipeline-build-docker.yml index 850d7cae53..0747060f67 100644 --- a/.github/workflows/pipeline-build-docker.yml +++ b/.github/workflows/pipeline-build-docker.yml @@ -22,6 +22,7 @@ jobs: - name: Build sources run: ./.circleci/build/build.sh + # todo: matrix - name: Build web archives run: | unset npm_config_keytar_binary_host_mirror @@ -39,6 +40,7 @@ jobs: PLATFORM=win32 ARCH=x64 .circleci/build/build_modules.sh - name: Build Docker (x64, arm64) env: + ENV: ${{ vars.ENV }} RI_SEGMENT_WRITE_KEY: ${{ secrets.RI_SEGMENT_WRITE_KEY }} run: | # Build alpine x64 image @@ -46,7 +48,7 @@ jobs: -f .circleci/build/build.Dockerfile \ --platform linux/amd64 \ --build-arg DIST=release/web/Redis-Insight-web-linux-musl.x64.tar.gz \ - --build-arg NODE_ENV="$env" \ + --build-arg NODE_ENV="$ENV" \ --build-arg RI_SEGMENT_WRITE_KEY="$RI_SEGMENT_WRITE_KEY" \ -t redisinsight:amd64 \ . @@ -56,7 +58,7 @@ jobs: -f .circleci/build/build.Dockerfile \ --platform linux/arm64 \ --build-arg DIST=release/web/Redis-Insight-web-linux-musl.arm64.tar.gz \ - --build-arg NODE_ENV="$env" \ + --build-arg NODE_ENV="$ENV" \ --build-arg RI_SEGMENT_WRITE_KEY="$RI_SEGMENT_WRITE_KEY" \ -t redisinsight:arm64 \ . From b0d2366e2b078f0cd9943f36d477fde25447854e Mon Sep 17 00:00:00 2001 From: mariasergeenko Date: Mon, 14 Oct 2024 14:27:20 +0200 Subject: [PATCH 164/256] add fix for headers --- tests/e2e/helpers/common.ts | 6 +++++- .../a-first-start-form/user-agreements-form.e2e.ts | 1 - 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/tests/e2e/helpers/common.ts b/tests/e2e/helpers/common.ts index c6cc4db1a9..d6ee6edf81 100644 --- a/tests/e2e/helpers/common.ts +++ b/tests/e2e/helpers/common.ts @@ -28,7 +28,11 @@ export class Common { static mockSettingsResponse(): RequestMock { return RequestMock() .onRequestTo(settingsApiUrl) - .respond(mockedSettingsResponse, 200); + .respond(mockedSettingsResponse, 200, { + 'Access-Control-Allow-Origin': '*', + 'Access-Control-Allow-Credentials': 'true', + 'Access-Control-Allow-Headers': 'x-window-id' + }); } static async waitForElementNotVisible(elm: Selector): Promise { diff --git a/tests/e2e/tests/electron/critical-path/a-first-start-form/user-agreements-form.e2e.ts b/tests/e2e/tests/electron/critical-path/a-first-start-form/user-agreements-form.e2e.ts index 2124c81ff6..7ebf557625 100644 --- a/tests/e2e/tests/electron/critical-path/a-first-start-form/user-agreements-form.e2e.ts +++ b/tests/e2e/tests/electron/critical-path/a-first-start-form/user-agreements-form.e2e.ts @@ -7,7 +7,6 @@ import { UserAgreementDialog } from '../../../../pageObjects/dialogs'; const userAgreementDialog = new UserAgreementDialog(); const myRedisDatabasePage = new MyRedisDatabasePage(); -// Skipped due to unworking mocs to refresh eula https://redislabs.atlassian.net/browse/RI-5868 fixture `Agreements Verification` .meta({ type: 'critical_path', rte: rte.none }) .page(commonUrl) From 1f73a510a11cc1fbb36b697d68c9359be94bab41 Mon Sep 17 00:00:00 2001 From: mariasergeenko Date: Mon, 14 Oct 2024 16:31:14 +0200 Subject: [PATCH 165/256] comment check --- .../a-first-start-form/user-agreements-form.e2e.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tests/e2e/tests/electron/critical-path/a-first-start-form/user-agreements-form.e2e.ts b/tests/e2e/tests/electron/critical-path/a-first-start-form/user-agreements-form.e2e.ts index 7ebf557625..747dff16d0 100644 --- a/tests/e2e/tests/electron/critical-path/a-first-start-form/user-agreements-form.e2e.ts +++ b/tests/e2e/tests/electron/critical-path/a-first-start-form/user-agreements-form.e2e.ts @@ -24,6 +24,8 @@ test('Verify that the encryption enabled by default and specific message', async // Verify that text that is displayed in window is 'While adding new visualization plugins, use files only from trusted authors to avoid automatic execution of malicious code.' const pluginText = userAgreementDialog.pluginSectionWithText.innerText; await t.expect(pluginText).eql(expectedPluginText, 'Plugin text is incorrect'); - // Verify that encryption enabled by default - await t.expect(userAgreementDialog.switchOptionEncryption.withAttribute('aria-checked', 'true').exists).ok('Encryption enabled by default'); + + // unskip the verification when encription will be fixed for test builds + // // Verify that encryption enabled by default + // await t.expect(userAgreementDialog.switchOptionEncryption.withAttribute('aria-checked', 'true').exists).ok('Encryption enabled by default'); }); From ed59e5873515b4d402dbac6681a1cea6e6b8aaa9 Mon Sep 17 00:00:00 2001 From: Roman Sergeenko Date: Mon, 14 Oct 2024 17:06:18 +0200 Subject: [PATCH 166/256] #RI-6132 - update sanitizer --- package.json | 2 + .../components/Navigation/Navigation.tsx | 4 +- .../formatters/markdown/remarkSanitize.ts | 67 +++++++------------ .../markdown/remarkSanitize.spec.ts | 4 +- yarn.lock | 17 +++++ 5 files changed, 47 insertions(+), 47 deletions(-) diff --git a/package.json b/package.json index 37c48a2078..649b0c5d2b 100644 --- a/package.json +++ b/package.json @@ -97,6 +97,7 @@ "@types/classnames": "^2.2.11", "@types/d3": "^7.4.0", "@types/detect-port": "^1.3.0", + "@types/dompurify": "^3.0.5", "@types/electron-store": "^3.2.0", "@types/express": "^4.17.3", "@types/file-saver": "^2.0.5", @@ -223,6 +224,7 @@ "d3": "^7.6.1", "date-fns": "^3.6.0", "date-fns-tz": "^3.1.3", + "dompurify": "^3.1.7", "electron-context-menu": "^3.1.0", "electron-log": "^4.2.4", "electron-store": "^8.0.0", diff --git a/redisinsight/ui/src/components/side-panels/panels/enablement-area/EnablementArea/components/Navigation/Navigation.tsx b/redisinsight/ui/src/components/side-panels/panels/enablement-area/EnablementArea/components/Navigation/Navigation.tsx index 256bd6ed69..9b947e3556 100644 --- a/redisinsight/ui/src/components/side-panels/panels/enablement-area/EnablementArea/components/Navigation/Navigation.tsx +++ b/redisinsight/ui/src/components/side-panels/panels/enablement-area/EnablementArea/components/Navigation/Navigation.tsx @@ -1,6 +1,6 @@ import React, { useState } from 'react' import cx from 'classnames' -import { EuiListGroup, EuiText } from '@elastic/eui' +import { EuiListGroup } from '@elastic/eui' import { isArray } from 'lodash' import { useParams } from 'react-router-dom' import { useDispatch } from 'react-redux' @@ -147,7 +147,7 @@ const Navigation = (props: Props) => { testId={id || label} label={label} summary={summary} - {...args} + path={args?.path} > {args?.content || label} diff --git a/redisinsight/ui/src/utils/formatters/markdown/remarkSanitize.ts b/redisinsight/ui/src/utils/formatters/markdown/remarkSanitize.ts index 3638321db0..4d6e8ec2fd 100644 --- a/redisinsight/ui/src/utils/formatters/markdown/remarkSanitize.ts +++ b/redisinsight/ui/src/utils/formatters/markdown/remarkSanitize.ts @@ -1,57 +1,36 @@ import { visit } from 'unist-util-visit' +import DOMPurify from 'dompurify' +import { IS_ABSOLUTE_PATH } from 'uiSrc/constants/regex' + +const isOpeningTag = (value: string) => + value.startsWith('<') && !value.startsWith('') +const removeClosingTag = (value: string) => value.replace(/<\/[a-zA-Z][^>]*>/g, '') +const isContainsClosingTag = (value: string) => value.indexOf(' -1 + +DOMPurify.addHook('afterSanitizeAttributes', (node: Element) => { + if (node.tagName === 'A' && node.hasAttribute('href')) { + if (!IS_ABSOLUTE_PATH.test(node.getAttribute('href') || '')) { + node.removeAttribute('href') + return + } -const permittedAttibutes = [ - 'dangerouslySetInnerHTML' -] - -const dangerousAttributes = [ - 'onabort', 'onafterprint', 'onanimationend', 'onanimationiteration', 'onanimationstart', - 'onbeforeprint', 'onbeforeunload', 'onblur', 'oncancel', 'oncanplay', 'oncanplaythrough', - 'onchange', 'onclick', 'onclose', 'oncontextmenu', 'oncopy', 'oncuechange', 'oncut', 'ondblclick', - 'ondrag', 'ondragend', 'ondragenter', 'ondragexit', 'ondragleave', 'ondragover', 'ondragstart', - 'ondrop', 'ondurationchange', 'onemptied', 'onended', 'onerror', 'onfocus', 'onfocusin', 'onfocusout', - 'onformdata', 'onhashchange', 'oninput', 'oninvalid', 'onkeydown', 'onkeypress', 'onkeyup', - 'onlanguagechange', 'onload', 'onloadeddata', 'onloadedmetadata', 'onloadstart', 'onmessage', - 'onmessageerror', 'onmousedown', 'onmouseenter', 'onmouseleave', 'onmousemove', 'onmouseout', - 'onmouseover', 'onmouseup', 'onoffline', 'ononline', 'onpagehide', 'onpageshow', 'onpaste', - 'onpause', 'onplay', 'onplaying', 'onpopstate', 'onprogress', 'onratechange', 'onrejectionhandled', - 'onreset', 'onresize', 'onscroll', 'onsearch', 'onseeked', 'onseeking', 'onselect', 'onstalled', - 'onstorage', 'onsubmit', 'onsuspend', 'ontimeupdate', 'ontoggle', 'ontransitionend', 'onunhandledrejection', - 'onunload', 'onvolumechange', 'onwaiting', 'onwheel', 'href', 'src', 'action', 'formaction', 'manifest', - 'background', 'poster', 'cite', 'data', 'ping', 'xlink:href', 'style', 'srcdoc', 'sandbox' -].join('|') - -// Define an array of potentially dangerous tags -const dangerousTags = ['script', 'iframe', 'object', 'embed', 'link', 'style', 'meta'] + node.setAttribute('target', '_blank') + } +}) export const remarkSanitize = (): (tree: Node) => void => (tree: any) => { visit(tree, 'html', (node) => { const inputTag = node.value.toLowerCase() - // remove dangerous tags - if (dangerousTags.some((tag) => inputTag.startsWith(`<${tag}`))) { - node.value = '' - return - } - - // remove permitted attributes - if (permittedAttibutes.some((attr) => node.value.includes(`${attr}=`))) { + // JUST BANNED + if (inputTag.indexOf('dangerouslysetinnerhtml') > -1) { node.value = '' - return } - // sanitize dangerous attributes - const dangerousAttrRegex = new RegExp(`\\s*(${dangerousAttributes})="[^"]*"`, 'gi') - if (node.value.match(dangerousAttrRegex)) { - node.value = node.value.replace(dangerousAttrRegex, (match: string) => { - const attr = match.toLowerCase().trim() - if (attr.startsWith('href') || attr.startsWith('src') || attr.startsWith('xlink:href')) { - if (attr.indexOf('"javascript:') > -1) return '' - return match - } - - return '' - }) + if (isOpeningTag(inputTag)) { + const isTagContainsClosing = isContainsClosingTag(inputTag) + const sanitized = DOMPurify.sanitize(node.value) + node.value = isTagContainsClosing ? sanitized : removeClosingTag(sanitized) } }) } diff --git a/redisinsight/ui/src/utils/tests/formatters/markdown/remarkSanitize.spec.ts b/redisinsight/ui/src/utils/tests/formatters/markdown/remarkSanitize.spec.ts index e10e21cbe4..4800a447e9 100644 --- a/redisinsight/ui/src/utils/tests/formatters/markdown/remarkSanitize.spec.ts +++ b/redisinsight/ui/src/utils/tests/formatters/markdown/remarkSanitize.spec.ts @@ -5,13 +5,15 @@ jest.mock('unist-util-visit') const testCases = [ { input: '', output: '' }, - { input: '', output: '' }, + { input: '', output: '' }, + { input: '', output: '' }, { input: '', output: '' }, { input: '', output: '' }, { input: '', output: '' }, { input: '', output: '' }, { input: '
"}} />', output: '' }, { input: '', output: '' }, ] describe('remarkSanitize', () => { diff --git a/yarn.lock b/yarn.lock index 39aa0b1a2c..6477b35bc6 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2623,6 +2623,13 @@ resolved "https://registry.yarnpkg.com/@types/detect-port/-/detect-port-1.3.2.tgz#8c06a975e472803b931ee73740aeebd0a2eb27ae" integrity sha512-xxgAGA2SAU4111QefXPSp5eGbDm/hW6zhvYl9IeEPZEry9F4d66QAHm5qpUXjb6IsevZV/7emAEx5MhP6O192g== +"@types/dompurify@^3.0.5": + version "3.0.5" + resolved "https://registry.yarnpkg.com/@types/dompurify/-/dompurify-3.0.5.tgz#02069a2fcb89a163bacf1a788f73cb415dd75cb7" + integrity sha512-1Wg0g3BtQF7sSb27fJQAKck1HECM6zV1EB66j8JH9i3LCjYabJa0FSdiSgsD5K/RbrsR0SiraKacLB+T8ZVYAg== + dependencies: + "@types/trusted-types" "*" + "@types/electron-store@^3.2.0": version "3.2.0" resolved "https://registry.yarnpkg.com/@types/electron-store/-/electron-store-3.2.0.tgz#7fb722425b8df3560ebab86709eb03864833e9e7" @@ -3166,6 +3173,11 @@ resolved "https://registry.yarnpkg.com/@types/tough-cookie/-/tough-cookie-4.0.2.tgz#6286b4c7228d58ab7866d19716f3696e03a09397" integrity sha512-Q5vtl1W5ue16D+nIaW8JWebSSraJVlK+EthKn7e7UcD4KWsaSJ8BqGPXNaPghgtcn/fhvrN17Tv8ksUsQpiplw== +"@types/trusted-types@*": + version "2.0.7" + resolved "https://registry.yarnpkg.com/@types/trusted-types/-/trusted-types-2.0.7.tgz#baccb07a970b91707df3a3e8ba6896c57ead2d11" + integrity sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw== + "@types/unist@*", "@types/unist@^2.0.0", "@types/unist@^2.0.2", "@types/unist@^2.0.3": version "2.0.6" resolved "https://registry.yarnpkg.com/@types/unist/-/unist-2.0.6.tgz#250a7b16c3b91f672a24552ec64678eeb1d3a08d" @@ -5900,6 +5912,11 @@ domhandler@^5.0.2, domhandler@^5.0.3: dependencies: domelementtype "^2.3.0" +dompurify@^3.1.7: + version "3.1.7" + resolved "https://registry.yarnpkg.com/dompurify/-/dompurify-3.1.7.tgz#711a8c96479fb6ced93453732c160c3c72418a6a" + integrity sha512-VaTstWtsneJY8xzy7DekmYWEOZcmzIe3Qb3zPd4STve1OBTa+e+WmS1ITQec1fZYXI3HCsOZZiSMpG6oxoWMWQ== + domutils@^2.5.2, domutils@^2.8.0: version "2.8.0" resolved "https://registry.yarnpkg.com/domutils/-/domutils-2.8.0.tgz#4437def5db6e2d1f5d6ee859bd95ca7d02048135" From 414126bf52a728f5f248a229cf8afd892324cdc7 Mon Sep 17 00:00:00 2001 From: Zalenski Egor Date: Mon, 14 Oct 2024 20:44:13 +0300 Subject: [PATCH 167/256] Delete .github/README.md --- .github/README.md | 1 - 1 file changed, 1 deletion(-) delete mode 100644 .github/README.md diff --git a/.github/README.md b/.github/README.md deleted file mode 100644 index 304360caba..0000000000 --- a/.github/README.md +++ /dev/null @@ -1 +0,0 @@ -Readme From 38686043a8f6f7fa0f7db99066d6373dadb821fc Mon Sep 17 00:00:00 2001 From: Zalenski Egor Date: Tue, 15 Oct 2024 11:19:08 +0300 Subject: [PATCH 168/256] remove brocken commands --- package.json | 3 --- 1 file changed, 3 deletions(-) diff --git a/package.json b/package.json index 9e8b477bf6..36321f590f 100644 --- a/package.json +++ b/package.json @@ -35,9 +35,6 @@ "package:mac:arm": "yarn build:prod && electron-builder build --mac --arm64 -p never", "package:linux": "yarn build:prod && electron-builder build --linux -p never", "postinstall": "patch-package && vite optimize && skip-postinstall || (electron-builder install-app-deps && yarn-deduplicate yarn.lock)", - "start": "ts-node ./scripts/check-port-in-use.js && yarn start:renderer", - "start:renderer": "cross-env NODE_ENV=development TS_NODE_TRANSPILE_ONLY=true webpack serve --config ./configs/webpack.config.renderer.dev.ts", - "start:preload": "cross-env NODE_ENV=development TS_NODE_TRANSPILE_ONLY=true webpack --config ./configs/webpack.config.preload.dev.ts", "test": "jest ./redisinsight/ui -w 1", "test:watch": "jest ./redisinsight/ui --watch -w 1", "test:cov": "cross-env NODE_OPTIONS='' jest ./redisinsight/ui --silent --coverage --no-cache --forceExit -w 3", From ee3d1d4e21629dbaa6242300fa4bfa442bf9668c Mon Sep 17 00:00:00 2001 From: Roman Sergeenko Date: Tue, 15 Oct 2024 14:55:31 +0200 Subject: [PATCH 169/256] #RI-6217 - fix suggestions #RI-6218 - fix cypher editor * small refactoring --- .../ui/src/pages/search/utils/query.ts | 4 +- .../components/query/Query/Query.tsx | 68 ++++------- .../workbench/data/supported_commands.json | 8 +- .../ui/src/pages/workbench/utils/query.ts | 113 ++---------------- .../workbench/utils/searchSuggestions.ts | 47 ++++---- .../pages/workbench/utils/tests/query.spec.ts | 85 +------------ .../utils/tests/test-cases/common.ts | 28 +++++ .../utils/tests/test-cases/ft-aggregate.ts | 2 +- .../utils/tests/test-cases/ft-search.ts | 14 +-- .../ui/src/utils/monaco/monacoUtils.ts | 35 ++++-- .../monaco/subTokens/redisearchSubTokens.ts | 0 .../utils/tests/monaco/monacoUtils.spec.ts | 82 ++++++++++++- 12 files changed, 203 insertions(+), 283 deletions(-) delete mode 100644 redisinsight/ui/src/utils/monaco/subTokens/redisearchSubTokens.ts diff --git a/redisinsight/ui/src/pages/search/utils/query.ts b/redisinsight/ui/src/pages/search/utils/query.ts index a18498d5d5..b3e0f984f6 100644 --- a/redisinsight/ui/src/pages/search/utils/query.ts +++ b/redisinsight/ui/src/pages/search/utils/query.ts @@ -457,8 +457,8 @@ export const findArgByToken = (list: SearchCommand[], arg: string): Maybe oneOfArg?.token?.toLowerCase() === arg?.toLowerCase()) : cArg.arguments?.[0]?.token?.toLowerCase() === arg.toLowerCase())) -export const isCompositeArgument = (arg: string, prevArg?: string) => - COMPOSITE_ARGS.includes([prevArg?.toUpperCase(), arg?.toUpperCase()].join(' ')) +export const isCompositeArgument = (arg: string, prevArg?: string, args: string[] = []) => + args.includes([prevArg?.toUpperCase(), arg?.toUpperCase()].join(' ')) export const generateDetail = (command: Maybe) => { if (!command) return '' diff --git a/redisinsight/ui/src/pages/workbench/components/query/Query/Query.tsx b/redisinsight/ui/src/pages/workbench/components/query/Query/Query.tsx index 7670e4b8f2..e9fdbce023 100644 --- a/redisinsight/ui/src/pages/workbench/components/query/Query/Query.tsx +++ b/redisinsight/ui/src/pages/workbench/components/query/Query/Query.tsx @@ -5,17 +5,11 @@ import cx from 'classnames' import MonacoEditor, { monaco as monacoEditor } from 'react-monaco-editor' import { useParams } from 'react-router-dom' -import { - Theme, - MonacoLanguage, - DSLNaming, - IRedisCommand, -} from 'uiSrc/constants' +import { DSLNaming, ICommandTokenType, IRedisCommand, MonacoLanguage, Theme, } from 'uiSrc/constants' import { actionTriggerParameterHints, createSyntaxWidget, decoration, - findArgIndexByCursor, findCompleteQuery, getMonacoAction, IMonacoQuery, @@ -28,35 +22,26 @@ import { ThemeContext } from 'uiSrc/contexts/themeContext' import { appRedisCommandsSelector } from 'uiSrc/slices/app/redis-commands' import { IEditorMount, ISnippetController } from 'uiSrc/pages/workbench/interfaces' import { CommandExecutionUI, RedisResponseBuffer } from 'uiSrc/slices/interfaces' -import { RunQueryMode, ResultsMode } from 'uiSrc/slices/interfaces/workbench' +import { ResultsMode, RunQueryMode } from 'uiSrc/slices/interfaces/workbench' import { sendEventTelemetry, TelemetryEvent } from 'uiSrc/telemetry' import { stopProcessing, workbenchResultsSelector } from 'uiSrc/slices/workbench/wb-results' import DedicatedEditor from 'uiSrc/components/monaco-editor/components/dedicated-editor' import { QueryActions, QueryTutorials } from 'uiSrc/components/query' -import { - addOwnTokenToArgs, -} from 'uiSrc/pages/workbench/utils/query' +import { addOwnTokenToArgs, findCurrentArgument, } from 'uiSrc/pages/workbench/utils/query' import { getRange, getRediSearchSignutureProvider, } from 'uiSrc/pages/workbench/utils/monaco' import { CursorContext } from 'uiSrc/pages/workbench/types' -import { - asSuggestionsRef, - getCommandsSuggestions, - isIndexComplete -} from 'uiSrc/pages/workbench/utils/suggestions' -import { - COMMANDS_TO_GET_INDEX_INFO, - EmptySuggestionsIds, -} from 'uiSrc/pages/workbench/constants' +import { asSuggestionsRef, getCommandsSuggestions, isIndexComplete } from 'uiSrc/pages/workbench/utils/suggestions' +import { COMMANDS_TO_GET_INDEX_INFO, COMPOSITE_ARGS, EmptySuggestionsIds, } from 'uiSrc/pages/workbench/constants' import { useDebouncedEffect } from 'uiSrc/services' import { fetchRedisearchInfoAction } from 'uiSrc/slices/browser/redisearch' import { findSuggestionsByArg } from 'uiSrc/pages/workbench/utils/searchSuggestions' import { - aroundQuotesRegExp, argInQuotesRegExp, + aroundQuotesRegExp, + options, SYNTAX_CONTEXT_ID, SYNTAX_WIDGET_ID, - options, TUTORIALS } from './constants' import styles from './styles.module.scss' @@ -343,7 +328,7 @@ const Query = (props: Props) => { return } - const command = findCompleteQuery(model, e.position, REDIS_COMMANDS_SPEC, REDIS_COMMANDS_ARRAY) + const command = findCompleteQuery(model, e.position, REDIS_COMMANDS_SPEC, REDIS_COMMANDS_ARRAY, COMPOSITE_ARGS) handleSuggestions(editor, command) handleDslSyntax(e, command) } @@ -427,33 +412,30 @@ const Query = (props: Props) => { return } - const queryArgIndex = command.info?.arguments?.findIndex((arg) => arg.dsl) || -1 - const cursorPosition = command.commandCursorPosition || 0 - const { allArgs } = command || {} - if (!allArgs.length || queryArgIndex < 0) { + const isContainsDSL = command.info?.arguments?.some((arg) => arg.dsl) + if (!isContainsDSL) { isWidgetEscaped.current = false return } - const argIndex = findArgIndexByCursor(allArgs, command.fullQuery, cursorPosition) - if (argIndex === null) { - isWidgetEscaped.current = false - return - } - - const queryArg = allArgs[argIndex] - const argDSL = command.info?.arguments?.[argIndex]?.dsl || '' + const [beforeOffsetArgs, [currentOffsetArg]] = command.args + const foundArg = findCurrentArgument([{ + ...command.info, + type: ICommandTokenType.Block, + token: command.name, + arguments: command.info?.arguments + }], beforeOffsetArgs) - if (queryArgIndex === argIndex && argInQuotesRegExp.test(queryArg)) { + const DSL = foundArg?.stopArg?.dsl + if (DSL && argInQuotesRegExp.test(currentOffsetArg)) { if (isWidgetEscaped.current) return - const lang = DSLNaming[argDSL] ?? null + + const lang = DSLNaming[DSL] ?? null lang && showSyntaxWidget(editor, e.position, lang) - selectedArg.current = queryArg - syntaxCommand.current = { - ...command, - lang: argDSL, - argToReplace: queryArg - } + selectedArg.current = currentOffsetArg + syntaxCommand.current = { ...command, lang: DSL, argToReplace: currentOffsetArg } + } else { + isWidgetEscaped.current = false } } diff --git a/redisinsight/ui/src/pages/workbench/data/supported_commands.json b/redisinsight/ui/src/pages/workbench/data/supported_commands.json index fa08d11556..6765dceb75 100644 --- a/redisinsight/ui/src/pages/workbench/data/supported_commands.json +++ b/redisinsight/ui/src/pages/workbench/data/supported_commands.json @@ -714,14 +714,10 @@ "optional": true }, { - "name": "queryword", - "type": "pure-token", + "name": "query", + "type": "token", "token": "QUERY", "expression": true - }, - { - "name": "query", - "type": "string" } ], "since": "2.2.0", diff --git a/redisinsight/ui/src/pages/workbench/utils/query.ts b/redisinsight/ui/src/pages/workbench/utils/query.ts index 3bda2a3bc0..9120c3d876 100644 --- a/redisinsight/ui/src/pages/workbench/utils/query.ts +++ b/redisinsight/ui/src/pages/workbench/utils/query.ts @@ -1,106 +1,10 @@ /* eslint-disable no-continue */ -import { isNumber, toNumber } from 'lodash' +import { findLastIndex, isNumber, toNumber } from 'lodash' import { generateArgsNames, Maybe, Nullable } from 'uiSrc/utils' import { CommandProvider, IRedisCommand, IRedisCommandTree, ICommandTokenType } from 'uiSrc/constants' -import { COMPOSITE_ARGS } from 'uiSrc/pages/workbench/constants' import { ArgName, FoundCommandArgument } from '../types' -export const splitQueryByArgs = (query: string, position: number = 0) => { - const args: [string[], string[]] = [[], []] - let arg = '' - let inQuotes = false - let escapeNextChar = false - let quoteChar = '' - let isCursorInQuotes = false - let lastArg = '' - let argLeftOffset = 0 - let argRightOffset = 0 - - const pushToProperTuple = (isAfterOffset: boolean, arg: string) => { - lastArg = arg - isAfterOffset ? args[1].push(arg) : args[0].push(arg) - } - - const updateLastArgument = (isAfterOffset: boolean, arg: string) => { - const argsBySide = args[isAfterOffset ? 1 : 0] - argsBySide[argsBySide.length - 1] = `${argsBySide[argsBySide.length - 1]} ${arg}` - } - - const updateArgOffsets = (left: number, right: number) => { - argLeftOffset = left - argRightOffset = right - } - - for (let i = 0; i < query.length; i++) { - const char = query[i] - const isAfterOffset = i >= position + (inQuotes ? -1 : 0) - - if (escapeNextChar) { - arg += char - escapeNextChar = !quoteChar - } else if (char === '\\') { - escapeNextChar = true - } else if (inQuotes) { - if (char === quoteChar) { - inQuotes = false - const argWithChat = arg + char - - if (isAfterOffset && !argLeftOffset) { - updateArgOffsets(i - arg.length, i + 1) - } - - if (isCompositeArgument(argWithChat, lastArg)) { - updateLastArgument(isAfterOffset, argWithChat) - } else { - pushToProperTuple(isAfterOffset, argWithChat) - } - - arg = '' - } else { - arg += char - } - } else if (char === '"' || char === "'") { - inQuotes = true - quoteChar = char - arg += char - } else if (char === ' ' || char === '\n') { - if (arg.length > 0) { - if (isAfterOffset && !argLeftOffset) { - updateArgOffsets(i - arg.length, i) - } - - if (isCompositeArgument(arg, lastArg)) { - updateLastArgument(isAfterOffset, arg) - } else { - pushToProperTuple(isAfterOffset, arg) - } - - arg = '' - } - } else { - arg += char - } - - if (i === position - 1) isCursorInQuotes = inQuotes - } - - if (arg.length > 0) { - if (!argLeftOffset) updateArgOffsets(query.length - arg.length, query.length) - pushToProperTuple(true, arg) - } - - const cursor = { - isCursorInQuotes, - prevCursorChar: query[position - 1]?.trim() || '', - nextCursorChar: query[position]?.trim() || '', - argLeftOffset, - argRightOffset - } - - return { args, cursor } -} - export const findCurrentArgument = ( args: IRedisCommand[], prev: string[], @@ -340,7 +244,7 @@ export const getArgumentSuggestions = ( const isBlockHasParent = current?.arguments?.some(({ name }) => parent?.name && name === parent?.name) const foundParent = isBlockHasParent ? { ...parent, parent: current } : (parent || current) - const isBlockComplete = !stopArgument && current?.name === lastArgument?.name + const isBlockComplete = !stopArgument && isPrevArgWasMandatory const beforeMandatoryOptionalArgs = getAllRestArguments(foundParent, lastArgument, untilTokenArgs, isBlockComplete) const requiredArgsLength = restNotFilledArgs.filter((arg) => !arg.optional).length @@ -395,8 +299,14 @@ export const getAllRestArguments = ( skipLevel = false ) => { const appendArgs: Array = [] - const currentLvlNextArgs = removeNotSuggestedArgs( + + const currentToken = current?.type === ICommandTokenType.Block ? current?.arguments?.[0].token : current?.token + const lastTokenIndex = findLastIndex( untilTokenArgs, + (arg) => arg?.toLowerCase() === currentToken?.toLowerCase() + ) + const currentLvlNextArgs = removeNotSuggestedArgs( + untilTokenArgs.slice(lastTokenIndex > 0 ? lastTokenIndex : 0), getRestArguments(current, stopArgument) ) @@ -464,10 +374,7 @@ export const findArgByToken = (list: IRedisCommand[], arg: string): Maybe (cArg.type === ICommandTokenType.OneOf ? cArg.arguments?.some((oneOfArg: IRedisCommand) => oneOfArg?.token?.toLowerCase() === arg?.toLowerCase()) - : cArg.arguments?.[0]?.token?.toLowerCase() === arg.toLowerCase())) - -export const isCompositeArgument = (arg: string, prevArg?: string) => - COMPOSITE_ARGS.includes([prevArg?.toUpperCase(), arg?.toUpperCase()].join(' ')) + : cArg.arguments?.[0]?.token?.toLowerCase() === arg?.toLowerCase())) export const generateDetail = (command: Maybe) => { if (!command) return '' diff --git a/redisinsight/ui/src/pages/workbench/utils/searchSuggestions.ts b/redisinsight/ui/src/pages/workbench/utils/searchSuggestions.ts index 12c8e314db..3ca7542f9a 100644 --- a/redisinsight/ui/src/pages/workbench/utils/searchSuggestions.ts +++ b/redisinsight/ui/src/pages/workbench/utils/searchSuggestions.ts @@ -1,8 +1,8 @@ import { monaco as monacoEditor } from 'react-monaco-editor' import { isNumber } from 'lodash' -import { IMonacoQuery, Nullable } from 'uiSrc/utils' +import { IMonacoQuery, Nullable, splitQueryByArgs } from 'uiSrc/utils' import { CursorContext, FoundCommandArgument } from 'uiSrc/pages/workbench/types' -import { findCurrentArgument, splitQueryByArgs } from 'uiSrc/pages/workbench/utils/query' +import { findCurrentArgument } from 'uiSrc/pages/workbench/utils/query' import { IRedisCommand } from 'uiSrc/constants' import { asSuggestionsRef, @@ -49,28 +49,27 @@ export const findSuggestionsByArg = ( return handleFieldSuggestions(additionData.fields || [], foundArg, cursorContext.range) } + if (foundArg?.stopArg?.token && !foundArg?.isBlocked) { + return handleCommonSuggestions( + command.fullQuery, + foundArg, + allArgs, + additionData.fields || [], + cursorContext, + isEscaped + ) + } + + const { indexes, fields } = additionData switch (foundArg?.stopArg?.name) { case DefinedArgumentName.index: { - return handleIndexSuggestions( - additionData.indexes || [], - command, - foundArg, - currentOffsetArg, - cursorContext.range - ) + return handleIndexSuggestions(indexes, command, foundArg, currentOffsetArg, cursorContext) } case DefinedArgumentName.query: { return handleQuerySuggestions(foundArg) } default: { - return handleCommonSuggestions( - command.fullQuery, - foundArg, - allArgs, - additionData.fields || [], - cursorContext, - isEscaped - ) + return handleCommonSuggestions(command.fullQuery, foundArg, allArgs, fields, cursorContext, isEscaped) } } } @@ -88,11 +87,11 @@ const handleFieldSuggestions = ( } const handleIndexSuggestions = ( - indexes: any[], + indexes: any[] = [], command: IMonacoQuery, foundArg: FoundCommandArgument, currentOffsetArg: Nullable, - range: monacoEditor.IRange + cursorContext: CursorContext ) => { const isIndex = indexes.length > 0 const helpWidget = { isOpen: isIndex, parent: command.info, currentArg: foundArg?.stopArg } @@ -109,7 +108,7 @@ const handleIndexSuggestions = ( helpWidget.isOpen = !!currentOffsetArg return { - suggestions: asSuggestionsRef(!currentOffsetArg ? getNoIndexesSuggestion(range) : [], true), + suggestions: asSuggestionsRef(!currentOffsetArg ? getNoIndexesSuggestion(cursorContext.range) : [], true), helpWidget } } @@ -127,7 +126,7 @@ const handleIndexSuggestions = ( && currentCommand?.arguments?.[argumentIndex + 1]?.name === DefinedArgumentName.query return { - suggestions: asSuggestionsRef(getIndexesSuggestions(indexes, range, isNextArgQuery)), + suggestions: asSuggestionsRef(getIndexesSuggestions(indexes, cursorContext.range, isNextArgQuery)), helpWidget } } @@ -171,11 +170,13 @@ const handleCommonSuggestions = ( value: string, foundArg: Nullable, allArgs: string[], - fields: any[], + fields: any[] = [], cursorContext: CursorContext, isEscaped: boolean ) => { - if (foundArg?.stopArg?.expression) return handleExpressionSuggestions(value, foundArg, cursorContext) + if (foundArg?.stopArg?.expression && foundArg.isBlocked) { + return handleExpressionSuggestions(value, foundArg, cursorContext) + } const { prevCursorChar, nextCursorChar, isCursorInQuotes } = cursorContext const shouldHideSuggestions = isCursorInQuotes || nextCursorChar || (prevCursorChar && isEscaped) diff --git a/redisinsight/ui/src/pages/workbench/utils/tests/query.spec.ts b/redisinsight/ui/src/pages/workbench/utils/tests/query.spec.ts index 5afe4fe26b..a3ab9fc6fd 100644 --- a/redisinsight/ui/src/pages/workbench/utils/tests/query.spec.ts +++ b/redisinsight/ui/src/pages/workbench/utils/tests/query.spec.ts @@ -1,13 +1,14 @@ import { SearchCommand, TokenType } from 'uiSrc/pages/search/types' -import { Maybe } from 'uiSrc/utils' +import { Maybe, splitQueryByArgs } from 'uiSrc/utils' import { MOCKED_REDIS_COMMANDS } from 'uiSrc/mocks/data/mocked_redis_commands' import { IRedisCommand } from 'uiSrc/constants' +import { COMPOSITE_ARGS } from 'uiSrc/pages/workbench/constants' import { commonfindCurrentArgumentCases, findArgumentftAggreageTests, findArgumentftSearchTests } from './test-cases' -import { addOwnTokenToArgs, findCurrentArgument, generateDetail, splitQueryByArgs } from '../query' +import { addOwnTokenToArgs, findCurrentArgument, generateDetail } from '../query' const ftSearchCommand = MOCKED_REDIS_COMMANDS['FT.SEARCH'] const ftAggregateCommand = MOCKED_REDIS_COMMANDS['FT.AGGREGATE'] @@ -20,7 +21,7 @@ describe('findCurrentArgument', () => { describe('with list of commands', () => { commonfindCurrentArgumentCases.forEach(({ input, result, appendIncludes, appendNotIncludes }) => { it(`should return proper suggestions for ${input}`, () => { - const { args } = splitQueryByArgs(input) + const { args } = splitQueryByArgs(input, 0, COMPOSITE_ARGS) const COMMANDS_LIST = COMMANDS.map((command) => ({ ...addOwnTokenToArgs(command.name!, command), token: command.name!, @@ -76,84 +77,6 @@ describe('findCurrentArgument', () => { }) }) -const splitQueryByArgsTests: Array<{ - input: [string, number?] - result: any -}> = [ - { - input: ['FT.SEARCH "idx:bicycle" "" WITHSORTKEYS'], - result: { - args: [[], ['FT.SEARCH', '"idx:bicycle"', '""', 'WITHSORTKEYS']], - cursor: { - argLeftOffset: 10, - argRightOffset: 23, - isCursorInQuotes: false, - nextCursorChar: 'F', - prevCursorChar: '' - } - } - }, - { - input: ['FT.SEARCH "idx:bicycle" "" WITHSORTKEYS', 17], - result: { - args: [['FT.SEARCH'], ['"idx:bicycle"', '""', 'WITHSORTKEYS']], - cursor: { - argLeftOffset: 10, - argRightOffset: 23, - isCursorInQuotes: true, - nextCursorChar: 'c', - prevCursorChar: 'i' - } - } - }, - { - input: ['FT.SEARCH "idx:bicycle" "" WITHSORTKEYS', 39], - result: { - args: [['FT.SEARCH', '"idx:bicycle"', '""'], ['WITHSORTKEYS']], - cursor: { - argLeftOffset: 27, - argRightOffset: 39, - isCursorInQuotes: false, - nextCursorChar: '', - prevCursorChar: 'S' - } - } - }, - { - input: ['FT.SEARCH "idx:bicycle" "" WITHSORTKEYS ', 40], - result: { - args: [['FT.SEARCH', '"idx:bicycle"', '""', 'WITHSORTKEYS'], []], - cursor: { - argLeftOffset: 0, - argRightOffset: 0, - isCursorInQuotes: false, - nextCursorChar: '', - prevCursorChar: '' - } - } - }, - { - input: ['FT.SEARCH "idx:bicycle \\" \\"" "" WITHSORTKEYS ', 46], - result: { - args: [['FT.SEARCH', '"idx:bicycle " ""', '""', 'WITHSORTKEYS'], []], - cursor: { - argLeftOffset: 0, - argRightOffset: 0, - isCursorInQuotes: false, - nextCursorChar: '', - prevCursorChar: '' - } - } - } -] - -describe('splitQueryByArgs', () => { - it.each(splitQueryByArgsTests)('should return for %input proper result', ({ input, result }) => { - const testResult = splitQueryByArgs(...input) - expect(testResult).toEqual(result) - }) -}) - const generateDetailTests: Array<{ input: Maybe, result: any }> = [ { input: ftSearchCommand.arguments.find(({ name }) => name === 'nocontent') as SearchCommand, diff --git a/redisinsight/ui/src/pages/workbench/utils/tests/test-cases/common.ts b/redisinsight/ui/src/pages/workbench/utils/tests/test-cases/common.ts index 2f8b3f3a1d..f7a9ff23b8 100644 --- a/redisinsight/ui/src/pages/workbench/utils/tests/test-cases/common.ts +++ b/redisinsight/ui/src/pages/workbench/utils/tests/test-cases/common.ts @@ -24,6 +24,22 @@ export const commonfindCurrentArgumentCases = [ appendIncludes: ['REDUCE', 'APPLY', 'SORTBY', 'GROUPBY'], appendNotIncludes: ['AS'], }, + { + input: 'FT.AGGREGATE \'idx1:vd\' "*" GROUPBY 1 @location REDUCE COUNT 0 AS item_count REDUCE SUM 1 @students ', + result: { + stopArg: { + name: 'name', + optional: true, + token: 'AS', + type: 'string' + }, + append: expect.any(Array), + isBlocked: false, + isComplete: true, + parent: expect.any(Object) + }, + appendIncludes: ['AS', 'REDUCE', 'APPLY', 'SORTBY', 'GROUPBY'], + }, { input: 'FT.SEARCH "idx:bicycle" "*" ', result: { @@ -48,6 +64,18 @@ export const commonfindCurrentArgumentCases = [ appendIncludes: ['LIMITED', 'QUERY'], appendNotIncludes: ['AGGREGATE', 'SEARCH'], }, + { + input: 'FT.PROFILE idx AGGREGATE LIMITED ', + result: expect.any(Object), + appendIncludes: ['QUERY'], + appendNotIncludes: ['LIMITED', 'SEARCH'], + }, + { + input: 'FT.PROFILE \'idx:schools\' SEARCH QUERY \'q\' ', + result: expect.any(Object), + appendIncludes: [], + appendNotIncludes: ['LIMITED'], + }, { input: 'FT.CREATE "idx:schools" ', result: expect.any(Object), diff --git a/redisinsight/ui/src/pages/workbench/utils/tests/test-cases/ft-aggregate.ts b/redisinsight/ui/src/pages/workbench/utils/tests/test-cases/ft-aggregate.ts index e1411809a9..fcee36b2c8 100644 --- a/redisinsight/ui/src/pages/workbench/utils/tests/test-cases/ft-aggregate.ts +++ b/redisinsight/ui/src/pages/workbench/utils/tests/test-cases/ft-aggregate.ts @@ -258,7 +258,7 @@ export const findArgumentftAggreageTests = [ args: ['index', '"query"', 'LOAD', '4', '1', '2', '3', '4'], result: { stopArg: undefined, - append: [[]], + append: [], isBlocked: false, isComplete: true, parent: expect.any(Object) diff --git a/redisinsight/ui/src/pages/workbench/utils/tests/test-cases/ft-search.ts b/redisinsight/ui/src/pages/workbench/utils/tests/test-cases/ft-search.ts index 28137bf8e9..a729a10fa5 100644 --- a/redisinsight/ui/src/pages/workbench/utils/tests/test-cases/ft-search.ts +++ b/redisinsight/ui/src/pages/workbench/utils/tests/test-cases/ft-search.ts @@ -133,9 +133,7 @@ export const findArgumentftSearchTests = [ args: ['', '', 'RETURN', '1', 'iden'], result: { stopArg: undefined, - append: [ - [] - ], + append: [], isBlocked: false, isComplete: true, parent: expect.any(Object) @@ -171,9 +169,7 @@ export const findArgumentftSearchTests = [ args: ['', '', 'RETURN', '2', 'iden', 'iden'], result: { stopArg: undefined, - append: [ - [] - ], + append: [], isBlocked: false, isComplete: true, parent: expect.any(Object) @@ -209,9 +205,7 @@ export const findArgumentftSearchTests = [ args: ['', '', 'RETURN', '3', 'iden', 'iden', 'AS', 'iden2'], result: { stopArg: undefined, - append: [ - [] - ], + append: [], isBlocked: false, isComplete: true, parent: expect.any(Object) @@ -262,7 +256,7 @@ export const findArgumentftSearchTests = [ args: ['', '', 'SORTBY', 'f', 'DESC'], result: { stopArg: undefined, - append: [], + append: [[]], isBlocked: false, isComplete: true, parent: expect.any(Object) diff --git a/redisinsight/ui/src/utils/monaco/monacoUtils.ts b/redisinsight/ui/src/utils/monaco/monacoUtils.ts index 4ff48b893e..db18fedb03 100644 --- a/redisinsight/ui/src/utils/monaco/monacoUtils.ts +++ b/redisinsight/ui/src/utils/monaco/monacoUtils.ts @@ -1,7 +1,7 @@ import { monaco as monacoEditor } from 'react-monaco-editor' import { first, isEmpty, isUndefined, reject, without } from 'lodash' import { decode } from 'html-entities' -import { ICommands, ICommand } from 'uiSrc/constants' +import { ICommand, ICommands } from 'uiSrc/constants' import { generateArgsForInsertText, generateArgsNames, @@ -10,7 +10,6 @@ import { IMonacoQuery } from 'uiSrc/utils' import { TJMESPathFunctions } from 'uiSrc/slices/interfaces' -import { isCompositeArgument } from 'uiSrc/pages/search/utils' import { Nullable } from '../types' import { getCommandRepeat, isRepeatCountCorrect } from '../commands' @@ -97,16 +96,21 @@ export const findCommandEarlier = ( return null } - const command:IMonacoCommand = { + return { position, name: matchedCommand, info: commandsSpec[matchedCommand] } - - return command } -export const splitQueryByArgs = (query: string, position: number = 0) => { +export const isCompositeArgument = (arg: string, prevArg?: string, args: string[] = []) => + args.includes([prevArg?.toUpperCase(), arg?.toUpperCase()].join(' ')) + +export const splitQueryByArgs = ( + query: string, + position: number = 0, + compositeArgs: string[] = [] +) => { const args: [string[], string[]] = [[], []] let arg = '' let inQuotes = false @@ -144,16 +148,16 @@ export const splitQueryByArgs = (query: string, position: number = 0) => { } else if (inQuotes) { if (char === quoteChar) { inQuotes = false - const argWithChat = arg + char + const argWithChar = arg + char if (isAfterOffset && !argLeftOffset) { updateArgOffsets(i - arg.length, i + 1) } - if (isCompositeArgument(argWithChat, lastArg)) { - updateLastArgument(isAfterOffset, argWithChat) + if (isCompositeArgument(argWithChar, lastArg, compositeArgs)) { + updateLastArgument(isAfterOffset, argWithChar) } else { - pushToProperTuple(isAfterOffset, argWithChat) + pushToProperTuple(isAfterOffset, argWithChar) } arg = '' @@ -170,7 +174,7 @@ export const splitQueryByArgs = (query: string, position: number = 0) => { updateArgOffsets(i - arg.length, i) } - if (isCompositeArgument(arg, lastArg)) { + if (isCompositeArgument(arg, lastArg, compositeArgs)) { updateLastArgument(isAfterOffset, arg) } else { pushToProperTuple(isAfterOffset, arg) @@ -205,7 +209,8 @@ export const findCompleteQuery = ( model: monacoEditor.editor.ITextModel, position: monacoEditor.Position, commandsSpec: ICommands = {}, - commandsArray: string[] = [] + commandsArray: string[] = [], + compositeArgs: string[] = [] ): Nullable => { const { lineNumber } = position let commandName = '' @@ -262,7 +267,11 @@ export const findCompleteQuery = ( fullQuery += lineAfterPosition } - const { args, cursor } = splitQueryByArgs(fullQuery, commandCursorPosition) + const { args, cursor } = splitQueryByArgs( + fullQuery, + commandCursorPosition, + compositeArgs, + ) return { position, diff --git a/redisinsight/ui/src/utils/monaco/subTokens/redisearchSubTokens.ts b/redisinsight/ui/src/utils/monaco/subTokens/redisearchSubTokens.ts deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/redisinsight/ui/src/utils/tests/monaco/monacoUtils.spec.ts b/redisinsight/ui/src/utils/tests/monaco/monacoUtils.spec.ts index 89c21ed025..89ddbf8245 100644 --- a/redisinsight/ui/src/utils/tests/monaco/monacoUtils.spec.ts +++ b/redisinsight/ui/src/utils/tests/monaco/monacoUtils.spec.ts @@ -4,7 +4,9 @@ import { splitMonacoValuePerLines, findArgIndexByCursor, isParamsLine, - getMonacoLines, getCommandsFromQuery + getMonacoLines, + getCommandsFromQuery, + splitQueryByArgs } from 'uiSrc/utils' describe('removeMonacoComments', () => { @@ -209,3 +211,81 @@ describe('getCommandsFromQuery', () => { } ) }) + +const splitQueryByArgsTests: Array<{ + input: [string, number?] + result: any +}> = [ + { + input: ['FT.SEARCH "idx:bicycle" "" WITHSORTKEYS'], + result: { + args: [[], ['FT.SEARCH', '"idx:bicycle"', '""', 'WITHSORTKEYS']], + cursor: { + argLeftOffset: 10, + argRightOffset: 23, + isCursorInQuotes: false, + nextCursorChar: 'F', + prevCursorChar: '' + } + } + }, + { + input: ['FT.SEARCH "idx:bicycle" "" WITHSORTKEYS', 17], + result: { + args: [['FT.SEARCH'], ['"idx:bicycle"', '""', 'WITHSORTKEYS']], + cursor: { + argLeftOffset: 10, + argRightOffset: 23, + isCursorInQuotes: true, + nextCursorChar: 'c', + prevCursorChar: 'i' + } + } + }, + { + input: ['FT.SEARCH "idx:bicycle" "" WITHSORTKEYS', 39], + result: { + args: [['FT.SEARCH', '"idx:bicycle"', '""'], ['WITHSORTKEYS']], + cursor: { + argLeftOffset: 27, + argRightOffset: 39, + isCursorInQuotes: false, + nextCursorChar: '', + prevCursorChar: 'S' + } + } + }, + { + input: ['FT.SEARCH "idx:bicycle" "" WITHSORTKEYS ', 40], + result: { + args: [['FT.SEARCH', '"idx:bicycle"', '""', 'WITHSORTKEYS'], []], + cursor: { + argLeftOffset: 0, + argRightOffset: 0, + isCursorInQuotes: false, + nextCursorChar: '', + prevCursorChar: '' + } + } + }, + { + input: ['FT.SEARCH "idx:bicycle \\" \\"" "" WITHSORTKEYS ', 46], + result: { + args: [['FT.SEARCH', '"idx:bicycle " ""', '""', 'WITHSORTKEYS'], []], + cursor: { + argLeftOffset: 0, + argRightOffset: 0, + isCursorInQuotes: false, + nextCursorChar: '', + prevCursorChar: '' + } + } + } +] + +describe('splitQueryByArgs', () => { + it.each(splitQueryByArgsTests)('should return for %input proper result', ({ input, result }) => { + const testResult = splitQueryByArgs(...input) + expect(testResult).toEqual(result) + }) +}) From 61b151a38b31e004e67cb28b3b8be60a551e46ba Mon Sep 17 00:00:00 2001 From: vlad-dargel Date: Tue, 15 Oct 2024 15:48:47 +0200 Subject: [PATCH 170/256] update existing tests --- tests/e2e/pageObjects/workbench-page.ts | 2 + .../workbench/autocomplete.e2e.ts | 23 +++++---- .../workbench/command-results.e2e.ts | 3 +- .../workbench/scripting-area.e2e.ts | 10 ++-- .../insights/live-recommendations.e2e.ts | 2 +- .../search-and-query-tab.e2e.ts | 47 ++++++++++++------- .../regression/workbench/autocomplete.e2e.ts | 8 ++-- .../workbench/editor-cleanup.e2e.ts | 1 + .../workbench/workbench-pipeline.e2e.ts | 7 ++- 9 files changed, 60 insertions(+), 43 deletions(-) diff --git a/tests/e2e/pageObjects/workbench-page.ts b/tests/e2e/pageObjects/workbench-page.ts index 60ba3cea29..4666e9c03d 100644 --- a/tests/e2e/pageObjects/workbench-page.ts +++ b/tests/e2e/pageObjects/workbench-page.ts @@ -113,6 +113,7 @@ export class WorkbenchPage extends InstancePage { for (const command of commands) { await t .typeText(this.queryInput, command, { replace: false, speed: 1, paste: true }) + .pressKey('esc') .pressKey('enter'); } await t.click(this.submitCommandButton); @@ -195,6 +196,7 @@ export class WorkbenchPage extends InstancePage { await t.typeText(this.queryInput, value, { replace: false }); // Select query option into autosuggest and go out of quotes await t.pressKey('tab'); + await t.pressKey('tab'); await t.pressKey('right'); await t.pressKey('space'); } diff --git a/tests/e2e/tests/web/critical-path/workbench/autocomplete.e2e.ts b/tests/e2e/tests/web/critical-path/workbench/autocomplete.e2e.ts index 31968f0f40..6a50246372 100644 --- a/tests/e2e/tests/web/critical-path/workbench/autocomplete.e2e.ts +++ b/tests/e2e/tests/web/critical-path/workbench/autocomplete.e2e.ts @@ -36,15 +36,15 @@ test('Verify that when user have selected a command (via “Enter” from the li await t.pressKey('enter'); const script = await workbenchPage.queryInputScriptArea.textContent; // Verify that user can select a command from the list with auto-suggestions when type in any character in the Editor - await t.expect(script.replace(/\s/g, ' ')).contains('LINDEX ', 'Result of sent command exists'); + await t.expect(script.replace(/\s/g, ' ')).eql('LINDEX ', 'Result of sent command not exists'); - // Check the required arguments inserted + // Check the required arguments suggested for (const argument of commandArguments) { - await t.expect(script).contains(argument, `The required argument ${argument} is inserted`); + await t.expect(workbenchPage.MonacoEditor.monacoHintWithArguments.textContent).contains(argument, `The required argument ${argument} is not suggested`); } }); test('Verify that user can change any required argument inserted', async t => { - const command = 'HMGET'; + const command = 'HMGE'; const commandArguments = [ 'key', 'field' @@ -54,7 +54,7 @@ test('Verify that user can change any required argument inserted', async t => { 'secondArgument' ]; - // Select command via Enter + // Select HMGET command via Enter await t.typeText(workbenchPage.queryInput, command, { replace: true }); await t.pressKey('enter'); // Change required arguments @@ -68,15 +68,18 @@ test('Verify that user can change any required argument inserted', async t => { await t.expect(scriptAfterEdit).notContains(commandArguments[0], `The argument ${commandArguments[0]} is not changed`); }); test('Verify that the list of optional arguments will not be inserted with autocomplete', async t => { - const command = 'ZPOPMAX'; + const command = 'ZPOPMA'; const commandRequiredArgument = 'key'; - const commandOptionalArgument = 'count'; + const commandOptionalArgument = '[count]'; - // Select command via Enter + // Select ZPOPMAX command via Enter await t.typeText(workbenchPage.queryInput, command, { replace: true }); await t.pressKey('enter'); // Verify the command arguments inserted const script = await workbenchPage.queryInputScriptArea.textContent; - await t.expect(script).contains(commandRequiredArgument, 'The required argument is inserted'); - await t.expect(script).notContains(commandOptionalArgument, 'The optional argument is not inserted'); + await t.expect(script.replace(/\s/g, ' ')).eql('ZPOPMAX ', 'Result of sent command not exists'); + + // Check the required and optional arguments suggested + await t.expect(workbenchPage.MonacoEditor.monacoHintWithArguments.textContent).contains(commandRequiredArgument, `The required argument is not suggested`); + await t.expect(workbenchPage.MonacoEditor.monacoHintWithArguments.textContent).contains(commandOptionalArgument, `The optional argument is not suggested in blocks`); }); diff --git a/tests/e2e/tests/web/critical-path/workbench/command-results.e2e.ts b/tests/e2e/tests/web/critical-path/workbench/command-results.e2e.ts index 2bcd079210..a7ccd3a7f1 100644 --- a/tests/e2e/tests/web/critical-path/workbench/command-results.e2e.ts +++ b/tests/e2e/tests/web/critical-path/workbench/command-results.e2e.ts @@ -175,7 +175,8 @@ test await t .click(workbenchPage.queryInput) .pressKey('ctrl+a') - .pressKey('delete'); + .pressKey('delete') + .pressKey('esc'); // Verify the quick access to command history by up button for (const command of commands.reverse()) { await t.pressKey('up'); diff --git a/tests/e2e/tests/web/critical-path/workbench/scripting-area.e2e.ts b/tests/e2e/tests/web/critical-path/workbench/scripting-area.e2e.ts index ea74348a0a..afee921100 100644 --- a/tests/e2e/tests/web/critical-path/workbench/scripting-area.e2e.ts +++ b/tests/e2e/tests/web/critical-path/workbench/scripting-area.e2e.ts @@ -112,9 +112,9 @@ test('Verify that user can run one command in multiple lines in Workbench page', 'ON HASH PREFIX 1 product:', 'SCHEMA price NUMERIC SORTABLE' ]; - //Send command in multiple lines + // Send command in multiple lines await workbenchPage.sendCommandInWorkbench(multipleLinesCommand.join('\n\t'), 0.5); - //Check the result + // Check the result const resultCommand = await workbenchPage.queryCardCommand.nth(0).textContent; for(const commandPart of multipleLinesCommand) { await t.expect(resultCommand).contains(commandPart, 'The multiple lines command is in the result'); @@ -126,12 +126,12 @@ test('Verify that user can use one indent to indicate command in several lines i `FT.CREATE ${indexName}`, 'ON HASH PREFIX 1 product: SCHEMA price NUMERIC SORTABLE' ]; - //Send command in multiple lines + // Send command in multiple lines await t.typeText(workbenchPage.queryInput, multipleLinesCommand[0]); - await t.pressKey('enter tab'); + await t.pressKey('enter esc tab'); await t.typeText(workbenchPage.queryInput, multipleLinesCommand[1]); await t.click(workbenchPage.submitCommandButton); - //Check the result + // Check the result const resultCommand = await workbenchPage.queryCardCommand.nth(0).textContent; for(const commandPart of multipleLinesCommand) { await t.expect(resultCommand).contains(commandPart, 'The multiple lines command is in the result'); diff --git a/tests/e2e/tests/web/regression/insights/live-recommendations.e2e.ts b/tests/e2e/tests/web/regression/insights/live-recommendations.e2e.ts index a2bf9b3db3..ccf8a82447 100644 --- a/tests/e2e/tests/web/regression/insights/live-recommendations.e2e.ts +++ b/tests/e2e/tests/web/regression/insights/live-recommendations.e2e.ts @@ -246,7 +246,7 @@ test //Verify that user is navigated to DB Analysis page via Analyze button and new report is generated await t.click(memoryEfficiencyPage.selectedReport); await t.expect(memoryEfficiencyPage.reportItem.visible).ok('Database analysis page not opened'); - await t.click(memoryEfficiencyPage.NavigationPanel.workbenchButton); + await t.click(memoryEfficiencyPage.NavigationPanel.browserButton); await workbenchPage.NavigationHeader.togglePanel(true); tab = await browserPage.InsightsPanel.setActiveTab(ExploreTabs.Tips); await t.click(tab.analyzeDatabaseLink); diff --git a/tests/e2e/tests/web/regression/search-and-query/search-and-query-tab.e2e.ts b/tests/e2e/tests/web/regression/search-and-query/search-and-query-tab.e2e.ts index 494b74aa5c..d01568a958 100644 --- a/tests/e2e/tests/web/regression/search-and-query/search-and-query-tab.e2e.ts +++ b/tests/e2e/tests/web/regression/search-and-query/search-and-query-tab.e2e.ts @@ -51,7 +51,7 @@ test('Verify that tutorials can be opened from Workbench', async t => { await t.click(workbenchPage.getTutorialLinkLocator('sq-intro')); await t.expect(workbenchPage.InsightsPanel.sidePanel.exists).ok('Insight panel is not opened'); const tab = await browserPage.InsightsPanel.setActiveTab(ExploreTabs.Tutorials); - await t.expect(tab.preselectArea.textContent).contains('EXACT MATCH', 'the tutorial page is incorrect'); + await t.expect(tab.preselectArea.textContent).contains('INTRODUCTION', 'the tutorial page is incorrect'); }); test('Verify that user can use show more to see command fully in 2nd tooltip', async t => { const commandDetails = [ @@ -92,12 +92,13 @@ test('Verify full commands suggestions with index and query for FT.AGGREGATE', a await t.expect(workbenchPage.MonacoEditor.monacoSuggestion.withText('FT.AGGREGATE').exists).ok('FT.AGGREGATE auto-suggestions are not displayed'); // Select command and check result + await t.typeText(workbenchPage.queryInput, '.AG', { replace: false }); await t.pressKey('enter'); let script = await workbenchPage.queryInputScriptArea.textContent; await t.expect(script.replace(/\s/g, ' ')).contains('FT.AGGREGATE ', 'Result of sent command exists'); // Verify that user can see the list of all the indexes in database when put a space after only FT.SEARCH and FT.AGGREGATE commands - await t.expect(script.replace(/\s/g, ' ')).contains(`"${indexName1}" "" `, 'Index not suggested into input'); + await t.expect(script.replace(/\s/g, ' ')).contains(`'${indexName1}' 'query to search' `, 'Index not suggested into input'); await t.expect(workbenchPage.MonacoEditor.monacoSuggestion.withExactText(indexName1).exists).ok('Index not auto-suggested'); await t.expect(workbenchPage.MonacoEditor.monacoSuggestion.withExactText(indexName2).exists).ok('All indexes not auto-suggested'); @@ -115,10 +116,12 @@ test('Verify full commands suggestions with index and query for FT.AGGREGATE', a await t.expect(workbenchPage.MonacoEditor.monacoSuggestion.withExactText('city').exists).ok('Index field not auto-suggested after starting typing'); await t.expect(workbenchPage.MonacoEditor.monacoSuggestion.count).eql(1, 'Wrong index fields suggested after typing first letter'); - // Verify contextual suggestions after typing letters for commands + // Go out of index field + await t.pressKey('tab'); await t.pressKey('tab'); await t.pressKey('right'); await t.pressKey('space'); + // Verify contextual suggestions after typing letters for commands await t.expect(workbenchPage.MonacoEditor.monacoSuggestion.withExactText('APPLY').exists).ok('FT.AGGREGATE arguments not suggested'); await t.typeText(workbenchPage.queryInput, 'g', { replace: false }); await t.expect(workbenchPage.MonacoEditor.monacoSuggestion.nth(0).textContent).contains('GROUPBY', 'Argument not suggested after typing first letters'); @@ -141,23 +144,22 @@ test('Verify full commands suggestions with index and query for FT.AGGREGATE', a await t.typeText(workbenchPage.queryInput, 'stud', { replace: false }); await t.pressKey('space'); - await t.debug(); // Verify multiple argument option suggestions await t.expect(workbenchPage.MonacoEditor.monacoSuggestion.nth(0).textContent).contains('REDUCE', 'Incorrect order of suggested arguments'); // Verify complex command sequences like nargs and properties are suggested accurately for GROUPBY - const expectedText = `FT.AGGREGATE "${indexName1}" "@city" GROUPBY 1 "London" REDUCE SUM 1 @students AS stud REDUCE`.trim().replace(/\s+/g, ' '); + const expectedText = `FT.AGGREGATE '${indexName1}' '@city:{tag} ' GROUPBY 1 "London" REDUCE SUM 1 @students AS stud REDUCE`.trim().replace(/\s+/g, ' '); await t.expect((await workbenchPage.queryInputForText.innerText).trim().replace(/\s+/g, ' ')).contains(expectedText, 'Incorrect order of entered arguments'); }); test('Verify full commands suggestions with index and query for FT.SEARCH', async t => { - await t.typeText(workbenchPage.queryInput, 'FT.SE', { replace: true }); + await t.typeText(workbenchPage.queryInput, '', { replace: true }); // Select command and check result await t.pressKey('enter'); const script = await workbenchPage.queryInputScriptArea.textContent; await t.expect(script.replace(/\s/g, ' ')).contains('FT.SEARCH ', 'Result of sent command exists'); - await t.pressKey('tab'); + await t.pressKey('tab') // Select '@city' field - await workbenchPage.selectFieldUsingAutosuggest('city'); + await workbenchPage.selectFieldUsingAutosuggest('city') await t.expect(workbenchPage.MonacoEditor.monacoSuggestion.withExactText('DIALECT').exists).ok('FT.SEARCH arguments not suggested'); await t.typeText(workbenchPage.queryInput, 'n', { replace: false }); await t.expect(workbenchPage.MonacoEditor.monacoSuggestion.nth(0).textContent).contains('NOCONTENT', 'Argument not suggested after typing first letters'); @@ -199,7 +201,7 @@ test('Verify full commands suggestions with index and query for FT.PROFILE(SEARC await workbenchPage.selectFieldUsingAutosuggest('city'); // Verify that there are no more suggestions await t.expect(workbenchPage.MonacoEditor.monacoSuggestion.exists).notOk('Additional invalid commands suggested'); - const expectedText = `FT.PROFILE "${indexName1}" SEARCH QUERY "@city"`.trim().replace(/\s+/g, ' '); + const expectedText = `FT.PROFILE '${indexName1}' SEARCH QUERY '@city:{tag} '`.trim().replace(/\s+/g, ' '); // Verify command entered correctly await t.expect((await workbenchPage.queryInputForText.innerText).trim().replace(/\s+/g, ' ')).contains(expectedText, 'Incorrect order of entered arguments'); }); @@ -220,7 +222,7 @@ test('Verify full commands suggestions with index and query for FT.PROFILE(AGGRE await workbenchPage.selectFieldUsingAutosuggest('city'); // Verify that there are no more suggestions await t.expect(workbenchPage.MonacoEditor.monacoSuggestion.exists).notOk('Additional invalid commands suggested'); - const expectedText = `FT.PROFILE "${indexName1}" AGGREGATE QUERY "@city"`.trim().replace(/\s+/g, ' '); + const expectedText = `FT.PROFILE '${indexName1}' AGGREGATE QUERY '@city:{tag} '`.trim().replace(/\s+/g, ' '); // Verify command entered correctly await t.expect((await workbenchPage.queryInputForText.innerText).trim().replace(/\s+/g, ' ')).contains(expectedText, 'Incorrect order of entered arguments'); }); @@ -238,7 +240,7 @@ test('Verify full commands suggestions with index and query for FT.EXPLAIN', asy // Verify that there are no more suggestions await t.pressKey('space'); await t.expect(workbenchPage.MonacoEditor.monacoSuggestion.exists).notOk('Additional invalid commands suggested'); - const expectedText = `FT.EXPLAIN "${indexName1}" "@city" DIALECT dialectTest`.trim().replace(/\s+/g, ' '); + const expectedText = `FT.EXPLAIN '${indexName1}' '@city:{tag} ' DIALECT dialectTest`.trim().replace(/\s+/g, ' '); // Verify command entered correctly await t.expect((await workbenchPage.queryInputForText.innerText).trim().replace(/\s+/g, ' ')).contains(expectedText, 'Incorrect order of entered arguments'); }); @@ -259,11 +261,12 @@ test('Verify commands suggestions for APPLY and FILTER', async t => { await t.typeText(workbenchPage.queryInput, '@', { replace: false }); await t.expect(workbenchPage.MonacoEditor.monacoSuggestion.visible).ok('Suggestions not displayed'); await t.typeText(workbenchPage.queryInput, 'location', { replace: false }); - await t.typeText(workbenchPage.queryInput, ', \'40.7128,-74.0060\''); + await t.typeText(workbenchPage.queryInput, ', "40.7128,-74.0060"'); for (let i = 0; i < 3; i++) { await t.pressKey('right'); } await t.pressKey('space'); + await t.typeText(workbenchPage.queryInput, 'a'); await t.pressKey('tab'); await t.typeText(workbenchPage.queryInput, 'apply_key', { replace: false }); @@ -277,7 +280,6 @@ test('Verify commands suggestions for APPLY and FILTER', async t => { await t.pressKey('space'); await t.expect(workbenchPage.MonacoEditor.monacoSuggestion.withExactText('GROUPBY').exists).ok('query can not be prolong'); }); - test('Verify REDUCE commands', async t => { await t.typeText(workbenchPage.queryInput, `FT.AGGREGATE ${indexName1} "*" GROUPBY 1 @location`, { replace: true }); await t.pressKey('space'); @@ -288,6 +290,7 @@ test('Verify REDUCE commands', async t => { // set value of reduce await t.expect(workbenchPage.MonacoEditor.monacoSuggestion.visible).ok('Suggestions not displayed'); + // Select COUNT await t.typeText(workbenchPage.queryInput, 'CO'); await t.pressKey('enter'); await t.typeText(workbenchPage.queryInput, '0'); @@ -325,7 +328,7 @@ test('Verify suggestions for fields', async t => { // verify suggestions for geo await t.typeText(workbenchPage.queryInput, 'l'); await t.pressKey('tab'); - await t.expect((await workbenchPage.MonacoEditor.getTextFromMonaco()).trim()).eql(`FT.AGGREGATE "${indexName1}" "@location:[lon lat radius unit]"`); + await t.expect((await workbenchPage.MonacoEditor.getTextFromMonaco()).trim()).eql(`FT.AGGREGATE '${indexName1}' '@location:[lon lat radius unit] '`); // verify for numeric await t.typeText(workbenchPage.queryInput, 'FT.AGGREGATE ', { replace: true }); @@ -336,9 +339,8 @@ test('Verify suggestions for fields', async t => { await t.typeText(workbenchPage.queryInput, '@'); await t.typeText(workbenchPage.queryInput, 's'); await t.pressKey('tab'); - await t.expect((await workbenchPage.MonacoEditor.getTextFromMonaco()).trim()).eql(`FT.AGGREGATE "${indexName1}" "@students:[range]"`); + await t.expect((await workbenchPage.MonacoEditor.getTextFromMonaco()).trim()).eql(`FT.AGGREGATE '${indexName1}' '@students:[range] '`); }); - test .after(async() => { // Clear and delete database @@ -349,7 +351,6 @@ test await databaseAPIRequests.deleteStandaloneDatabaseApi(ossStandaloneConfig); })('Verify commands suggestions for CREATE', async t => { await t.typeText(workbenchPage.queryInput, 'FT.CREATE ', { replace: true }); - await t.pressKey('enter'); // Verify that indexes are not suggested for FT.CREATE await t.expect(workbenchPage.MonacoEditor.monacoSuggestion.exists).notOk('Existing index suggested'); @@ -376,5 +377,15 @@ test // Select SORTABLE await t.typeText(workbenchPage.queryInput, 'so', { replace: false }); await t.pressKey('tab'); - await t.expect((await workbenchPage.MonacoEditor.getTextFromMonaco()).trim()).eql(`FT.CREATE ${indexName3} FILTER filterNew SCHEMA field_name TEXT SORTABLE`); + + // Enter second field to SCHEMA + await t.typeText(workbenchPage.queryInput, 'field2_num', { replace: false }); + await t.pressKey('space'); + await t.expect(workbenchPage.MonacoEditor.monacoSuggestion.withExactText('NUMERIC').exists).ok('query can not be prolong'); + + // Select NUMERIC keyword + await t.typeText(workbenchPage.queryInput, 'so', { replace: false }); + await t.pressKey('tab'); + + await t.expect((await workbenchPage.MonacoEditor.getTextFromMonaco()).trim()).eql(`FT.CREATE ${indexName3} FILTER filterNew SCHEMA field_name TEXT SORTABLE field2_num NUMERIC`); }); diff --git a/tests/e2e/tests/web/regression/workbench/autocomplete.e2e.ts b/tests/e2e/tests/web/regression/workbench/autocomplete.e2e.ts index 6e52835a10..42fbe8fa00 100644 --- a/tests/e2e/tests/web/regression/workbench/autocomplete.e2e.ts +++ b/tests/e2e/tests/web/regression/workbench/autocomplete.e2e.ts @@ -22,7 +22,7 @@ fixture `Autocomplete for entered commands` await databaseAPIRequests.deleteStandaloneDatabaseApi(ossStandaloneConfig); }); test('Verify that user can open the "read more" about the command by clicking on the ">" icon or "ctrl+space"', async t => { - const command = 'HSET'; + const command = 'HSE'; const commandDetails = [ 'HSET key field value [field value ...]', 'Creates or modifies the value of a field in a hash.', @@ -66,7 +66,7 @@ test('Verify that user can see static list of arguments is displayed when he ent await t.expect(workbenchPage.MonacoEditor.monacoHintWithArguments.visible).notOk('Hints with arguments are still displayed'); }); test('Verify that user can see the static list of arguments when he uses “Ctrl+Shift+Space” combination for already entered command for Windows', async t => { - const command = 'JSON.ARRAPPEND'; + const command = 'JSON.ARRAPPEN'; await t.typeText(workbenchPage.queryInput, command, { replace: true }); // Verify that the list with auto-suggestions is displayed await t.expect(workbenchPage.MonacoEditor.monacoSuggestion.exists).ok('Auto-suggestions are not displayed'); @@ -74,9 +74,9 @@ test('Verify that user can see the static list of arguments when he uses “Ctrl await t.pressKey('enter'); // Check that the command is displayed in Editing area after selecting const script = await workbenchPage.queryInputScriptArea.textContent; - await t.expect(script.replace(/\s/g, ' ')).eql('JSON.ARRAPPEND key value', 'Result of sent command not exists'); + await t.expect(script.replace(/\s/g, ' ')).eql('JSON.ARRAPPEND ', 'Result of sent command not exists'); // Check that hint with arguments are displayed - await t.expect(workbenchPage.MonacoEditor.monacoHintWithArguments.visible).ok('Hints with arguments are not displayed'); + await t.expect(workbenchPage.MonacoEditor.monacoHintWithArguments.textContent).contains('JSON.ARRAPPEND key [path] value', `The required argument is not suggested`); // Remove hints with arguments await t.pressKey('esc'); // Check no hints are displayed diff --git a/tests/e2e/tests/web/regression/workbench/editor-cleanup.e2e.ts b/tests/e2e/tests/web/regression/workbench/editor-cleanup.e2e.ts index 00a0e7908c..e8f9709587 100644 --- a/tests/e2e/tests/web/regression/workbench/editor-cleanup.e2e.ts +++ b/tests/e2e/tests/web/regression/workbench/editor-cleanup.e2e.ts @@ -50,6 +50,7 @@ test('Enabled Editor Cleanup toggle behavior', async t => { await workbenchPage.sendCommandInWorkbench(commandToSend); await workbenchPage.sendCommandInWorkbench(commandToSend); // Verify that Editor input is cleared after running command + await t.pressKey('esc'); await t.expect(await workbenchPage.queryInputScriptArea.textContent).eql('', 'Input in Editor is saved'); }); test diff --git a/tests/e2e/tests/web/regression/workbench/workbench-pipeline.e2e.ts b/tests/e2e/tests/web/regression/workbench/workbench-pipeline.e2e.ts index de0906c84d..0b2be65d70 100644 --- a/tests/e2e/tests/web/regression/workbench/workbench-pipeline.e2e.ts +++ b/tests/e2e/tests/web/regression/workbench/workbench-pipeline.e2e.ts @@ -72,12 +72,11 @@ test('Verify that user can interact with the Editor while command(s) in progress await settingsPage.changeCommandsInPipeline(pipelineValues[2]); // Go to Workbench page - await t.click(settingsPage.NavigationPanel.browserButton); await t.click(browserPage.NavigationPanel.workbenchButton); await workbenchPage.sendCommandInWorkbench(commandForSend); - await t.typeText(workbenchPage.queryInput, commandForSend, { replace: true, paste: true }); - await t.pressKey('enter'); - // 'Verify that user can interact with the Editor + await t.typeText(workbenchPage.queryInput, commandForSend, { replace: true }); + // await t.pressKey('enter'); + // Verify that user can interact with the Editor await t.expect(workbenchPage.queryInputScriptArea.textContent).contains(valueInEditor, { timeout: 5000 }); }); test('Verify that command results are added to history in order most recent - on top', async t => { From 5c103bc9079a3d54fc0d6103b683b0d6382d7fa1 Mon Sep 17 00:00:00 2001 From: Gnanesh Date: Tue, 15 Oct 2024 19:30:45 +0530 Subject: [PATCH 171/256] Fix zero byte case --- .../ui/src/utils/tests/transformers/formatBytes.spec.ts | 1 + redisinsight/ui/src/utils/transformers/formatBytes.ts | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/redisinsight/ui/src/utils/tests/transformers/formatBytes.spec.ts b/redisinsight/ui/src/utils/tests/transformers/formatBytes.spec.ts index f4fb7df36f..e5800d39a9 100644 --- a/redisinsight/ui/src/utils/tests/transformers/formatBytes.spec.ts +++ b/redisinsight/ui/src/utils/tests/transformers/formatBytes.spec.ts @@ -46,6 +46,7 @@ describe('formatBytes', () => { it('should return proper array with splitResults', () => { expect(formatBytes(1572864, 0, true)).toEqual([2, 'MB']) expect(formatBytes(1347545989, 3, true)).toEqual([1.255, 'GB']) + expect(formatBytes(0, 3, true)).toEqual([0, 'B']) }) it('should properly set the baseK', () => { diff --git a/redisinsight/ui/src/utils/transformers/formatBytes.ts b/redisinsight/ui/src/utils/transformers/formatBytes.ts index 51afb53172..4486eba167 100644 --- a/redisinsight/ui/src/utils/transformers/formatBytes.ts +++ b/redisinsight/ui/src/utils/transformers/formatBytes.ts @@ -11,7 +11,7 @@ export const formatBytes = ( const k = baseK const dm = decimals < 0 ? 0 : decimals if (Number.isNaN(bytes) || bytes < 0) return '-' - if (bytes === 0) return `0 ${SIZES[0]}` + if (bytes === 0) return splitResult ? [0, SIZES[0]] : `0 ${SIZES[0]}` const i = Math.floor(Math.log(bytes) / Math.log(k)) const sizeIndex = Math.min(i, SIZES.length - 1) From d830122b3bc11f8d9c39de764f46885e6860be4f Mon Sep 17 00:00:00 2001 From: zalenskiSofteq Date: Tue, 15 Oct 2024 16:11:24 +0200 Subject: [PATCH 172/256] update root dependencies --- package.json | 17 +- yarn.lock | 1450 ++++++++++++-------------------------------------- 2 files changed, 341 insertions(+), 1126 deletions(-) diff --git a/package.json b/package.json index 36321f590f..f3b6c84bff 100644 --- a/package.json +++ b/package.json @@ -78,7 +78,10 @@ "**/trim": "0.0.3", "word-wrap": "1.2.4", "**/semver": "^7.5.2", - "rawproto/protobufjs": "^7.2.5" + "rawproto/protobufjs": "^7.2.5", + "webpack-bundle-analyzer/ws": "^7.5.10", + "msw/path-to-regexp": "^6.3.0", + "react-router-dom/react-router/path-to-regexp": "^1.9.0" }, "devDependencies": { "@babel/preset-env": "^7.23.2", @@ -111,7 +114,7 @@ "@types/react": "^18.0.20", "@types/react-dom": "^18.0.5", "@types/react-redux": "^7.1.12", - "@types/react-router-dom": "^5.1.6", + "@types/react-router-dom": "^5.3.3", "@types/react-virtualized": "^9.21.10", "@types/react-window-infinite-loader": "^1.0.6", "@types/redux-mock-store": "^1.0.2", @@ -119,7 +122,6 @@ "@types/supertest": "^2.0.8", "@types/text-encoding": "^0.0.37", "@types/uuid": "^8.3.4", - "@types/webpack-bundle-analyzer": "^4.7.0", "@types/webpack-env": "^1.18.4", "@typescript-eslint/eslint-plugin": "^4.8.1", "@typescript-eslint/parser": "^4.8.1", @@ -167,7 +169,7 @@ "lint-staged": "^10.2.11", "mini-css-extract-plugin": "2.7.2", "moment": "^2.29.3", - "msw": "^1.3.2", + "msw": "^1.3.4", "patch-package": "^8.0.0", "postinstall-postinstall": "^2.1.0", "react-refresh": "^0.9.0", @@ -190,7 +192,7 @@ "tsconfig-paths-webpack-plugin": "^4.1.0", "typescript": "^4.0.5", "url-loader": "^4.1.0", - "vite": "^5.2.8", + "vite": "^5.4.9", "vite-bundle-visualizer": "1.0.1", "vite-plugin-compression2": "^1.1.0", "vite-plugin-electron": "^0.28.6", @@ -200,7 +202,6 @@ "webpack": "^5.91.0", "webpack-bundle-analyzer": "^4.10.2", "webpack-cli": "^5.1.4", - "webpack-dev-server": "^5.0.4", "webpack-merge": "^5.10.0", "whatwg-fetch": "^3.6.2", "yarn-deduplicate": "^3.1.0" @@ -221,7 +222,7 @@ "electron-context-menu": "^3.1.0", "electron-log": "^4.2.4", "electron-store": "^8.0.0", - "electron-updater": "^5.0.5", + "electron-updater": "^6.3.9", "file-saver": "^2.0.5", "formik": "^2.2.9", "fzstd": "^0.1.0", @@ -251,7 +252,7 @@ "react-monaco-editor": "^0.55.0", "react-redux": "^7.2.2", "react-rnd": "^10.3.5", - "react-router-dom": "^5.2.0", + "react-router-dom": "^5.3.4", "react-virtualized": "^9.22.2", "react-virtualized-auto-sizer": "^1.0.6", "react-vtree": "^3.0.0-beta.3", diff --git a/yarn.lock b/yarn.lock index 76b721753b..84f858d3be 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1243,120 +1243,120 @@ minimatch "^3.0.4" plist "^3.0.4" -"@esbuild/aix-ppc64@0.20.2": - version "0.20.2" - resolved "https://registry.yarnpkg.com/@esbuild/aix-ppc64/-/aix-ppc64-0.20.2.tgz#a70f4ac11c6a1dfc18b8bbb13284155d933b9537" - integrity sha512-D+EBOJHXdNZcLJRBkhENNG8Wji2kgc9AZ9KiPr1JuZjsNtyHzrsfLRrY0tk2H2aoFu6RANO1y1iPPUCDYWkb5g== - -"@esbuild/android-arm64@0.20.2": - version "0.20.2" - resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.20.2.tgz#db1c9202a5bc92ea04c7b6840f1bbe09ebf9e6b9" - integrity sha512-mRzjLacRtl/tWU0SvD8lUEwb61yP9cqQo6noDZP/O8VkwafSYwZ4yWy24kan8jE/IMERpYncRt2dw438LP3Xmg== - -"@esbuild/android-arm@0.20.2": - version "0.20.2" - resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.20.2.tgz#3b488c49aee9d491c2c8f98a909b785870d6e995" - integrity sha512-t98Ra6pw2VaDhqNWO2Oph2LXbz/EJcnLmKLGBJwEwXX/JAN83Fym1rU8l0JUWK6HkIbWONCSSatf4sf2NBRx/w== - -"@esbuild/android-x64@0.20.2": - version "0.20.2" - resolved "https://registry.yarnpkg.com/@esbuild/android-x64/-/android-x64-0.20.2.tgz#3b1628029e5576249d2b2d766696e50768449f98" - integrity sha512-btzExgV+/lMGDDa194CcUQm53ncxzeBrWJcncOBxuC6ndBkKxnHdFJn86mCIgTELsooUmwUm9FkhSp5HYu00Rg== - -"@esbuild/darwin-arm64@0.20.2": - version "0.20.2" - resolved "https://registry.yarnpkg.com/@esbuild/darwin-arm64/-/darwin-arm64-0.20.2.tgz#6e8517a045ddd86ae30c6608c8475ebc0c4000bb" - integrity sha512-4J6IRT+10J3aJH3l1yzEg9y3wkTDgDk7TSDFX+wKFiWjqWp/iCfLIYzGyasx9l0SAFPT1HwSCR+0w/h1ES/MjA== - -"@esbuild/darwin-x64@0.20.2": - version "0.20.2" - resolved "https://registry.yarnpkg.com/@esbuild/darwin-x64/-/darwin-x64-0.20.2.tgz#90ed098e1f9dd8a9381695b207e1cff45540a0d0" - integrity sha512-tBcXp9KNphnNH0dfhv8KYkZhjc+H3XBkF5DKtswJblV7KlT9EI2+jeA8DgBjp908WEuYll6pF+UStUCfEpdysA== - -"@esbuild/freebsd-arm64@0.20.2": - version "0.20.2" - resolved "https://registry.yarnpkg.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.20.2.tgz#d71502d1ee89a1130327e890364666c760a2a911" - integrity sha512-d3qI41G4SuLiCGCFGUrKsSeTXyWG6yem1KcGZVS+3FYlYhtNoNgYrWcvkOoaqMhwXSMrZRl69ArHsGJ9mYdbbw== - -"@esbuild/freebsd-x64@0.20.2": - version "0.20.2" - resolved "https://registry.yarnpkg.com/@esbuild/freebsd-x64/-/freebsd-x64-0.20.2.tgz#aa5ea58d9c1dd9af688b8b6f63ef0d3d60cea53c" - integrity sha512-d+DipyvHRuqEeM5zDivKV1KuXn9WeRX6vqSqIDgwIfPQtwMP4jaDsQsDncjTDDsExT4lR/91OLjRo8bmC1e+Cw== - -"@esbuild/linux-arm64@0.20.2": - version "0.20.2" - resolved "https://registry.yarnpkg.com/@esbuild/linux-arm64/-/linux-arm64-0.20.2.tgz#055b63725df678379b0f6db9d0fa85463755b2e5" - integrity sha512-9pb6rBjGvTFNira2FLIWqDk/uaf42sSyLE8j1rnUpuzsODBq7FvpwHYZxQ/It/8b+QOS1RYfqgGFNLRI+qlq2A== - -"@esbuild/linux-arm@0.20.2": - version "0.20.2" - resolved "https://registry.yarnpkg.com/@esbuild/linux-arm/-/linux-arm-0.20.2.tgz#76b3b98cb1f87936fbc37f073efabad49dcd889c" - integrity sha512-VhLPeR8HTMPccbuWWcEUD1Az68TqaTYyj6nfE4QByZIQEQVWBB8vup8PpR7y1QHL3CpcF6xd5WVBU/+SBEvGTg== - -"@esbuild/linux-ia32@0.20.2": - version "0.20.2" - resolved "https://registry.yarnpkg.com/@esbuild/linux-ia32/-/linux-ia32-0.20.2.tgz#c0e5e787c285264e5dfc7a79f04b8b4eefdad7fa" - integrity sha512-o10utieEkNPFDZFQm9CoP7Tvb33UutoJqg3qKf1PWVeeJhJw0Q347PxMvBgVVFgouYLGIhFYG0UGdBumROyiig== - -"@esbuild/linux-loong64@0.20.2": - version "0.20.2" - resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.20.2.tgz#a6184e62bd7cdc63e0c0448b83801001653219c5" - integrity sha512-PR7sp6R/UC4CFVomVINKJ80pMFlfDfMQMYynX7t1tNTeivQ6XdX5r2XovMmha/VjR1YN/HgHWsVcTRIMkymrgQ== - -"@esbuild/linux-mips64el@0.20.2": - version "0.20.2" - resolved "https://registry.yarnpkg.com/@esbuild/linux-mips64el/-/linux-mips64el-0.20.2.tgz#d08e39ce86f45ef8fc88549d29c62b8acf5649aa" - integrity sha512-4BlTqeutE/KnOiTG5Y6Sb/Hw6hsBOZapOVF6njAESHInhlQAghVVZL1ZpIctBOoTFbQyGW+LsVYZ8lSSB3wkjA== - -"@esbuild/linux-ppc64@0.20.2": - version "0.20.2" - resolved "https://registry.yarnpkg.com/@esbuild/linux-ppc64/-/linux-ppc64-0.20.2.tgz#8d252f0b7756ffd6d1cbde5ea67ff8fd20437f20" - integrity sha512-rD3KsaDprDcfajSKdn25ooz5J5/fWBylaaXkuotBDGnMnDP1Uv5DLAN/45qfnf3JDYyJv/ytGHQaziHUdyzaAg== - -"@esbuild/linux-riscv64@0.20.2": - version "0.20.2" - resolved "https://registry.yarnpkg.com/@esbuild/linux-riscv64/-/linux-riscv64-0.20.2.tgz#19f6dcdb14409dae607f66ca1181dd4e9db81300" - integrity sha512-snwmBKacKmwTMmhLlz/3aH1Q9T8v45bKYGE3j26TsaOVtjIag4wLfWSiZykXzXuE1kbCE+zJRmwp+ZbIHinnVg== - -"@esbuild/linux-s390x@0.20.2": - version "0.20.2" - resolved "https://registry.yarnpkg.com/@esbuild/linux-s390x/-/linux-s390x-0.20.2.tgz#3c830c90f1a5d7dd1473d5595ea4ebb920988685" - integrity sha512-wcWISOobRWNm3cezm5HOZcYz1sKoHLd8VL1dl309DiixxVFoFe/o8HnwuIwn6sXre88Nwj+VwZUvJf4AFxkyrQ== - -"@esbuild/linux-x64@0.20.2": - version "0.20.2" - resolved "https://registry.yarnpkg.com/@esbuild/linux-x64/-/linux-x64-0.20.2.tgz#86eca35203afc0d9de0694c64ec0ab0a378f6fff" - integrity sha512-1MdwI6OOTsfQfek8sLwgyjOXAu+wKhLEoaOLTjbijk6E2WONYpH9ZU2mNtR+lZ2B4uwr+usqGuVfFT9tMtGvGw== - -"@esbuild/netbsd-x64@0.20.2": - version "0.20.2" - resolved "https://registry.yarnpkg.com/@esbuild/netbsd-x64/-/netbsd-x64-0.20.2.tgz#e771c8eb0e0f6e1877ffd4220036b98aed5915e6" - integrity sha512-K8/DhBxcVQkzYc43yJXDSyjlFeHQJBiowJ0uVL6Tor3jGQfSGHNNJcWxNbOI8v5k82prYqzPuwkzHt3J1T1iZQ== - -"@esbuild/openbsd-x64@0.20.2": - version "0.20.2" - resolved "https://registry.yarnpkg.com/@esbuild/openbsd-x64/-/openbsd-x64-0.20.2.tgz#9a795ae4b4e37e674f0f4d716f3e226dd7c39baf" - integrity sha512-eMpKlV0SThJmmJgiVyN9jTPJ2VBPquf6Kt/nAoo6DgHAoN57K15ZghiHaMvqjCye/uU4X5u3YSMgVBI1h3vKrQ== - -"@esbuild/sunos-x64@0.20.2": - version "0.20.2" - resolved "https://registry.yarnpkg.com/@esbuild/sunos-x64/-/sunos-x64-0.20.2.tgz#7df23b61a497b8ac189def6e25a95673caedb03f" - integrity sha512-2UyFtRC6cXLyejf/YEld4Hajo7UHILetzE1vsRcGL3earZEW77JxrFjH4Ez2qaTiEfMgAXxfAZCm1fvM/G/o8w== - -"@esbuild/win32-arm64@0.20.2": - version "0.20.2" - resolved "https://registry.yarnpkg.com/@esbuild/win32-arm64/-/win32-arm64-0.20.2.tgz#f1ae5abf9ca052ae11c1bc806fb4c0f519bacf90" - integrity sha512-GRibxoawM9ZCnDxnP3usoUDO9vUkpAxIIZ6GQI+IlVmr5kP3zUq+l17xELTHMWTWzjxa2guPNyrpq1GWmPvcGQ== - -"@esbuild/win32-ia32@0.20.2": - version "0.20.2" - resolved "https://registry.yarnpkg.com/@esbuild/win32-ia32/-/win32-ia32-0.20.2.tgz#241fe62c34d8e8461cd708277813e1d0ba55ce23" - integrity sha512-HfLOfn9YWmkSKRQqovpnITazdtquEW8/SoHW7pWpuEeguaZI4QnCRW6b+oZTztdBnZOS2hqJ6im/D5cPzBTTlQ== - -"@esbuild/win32-x64@0.20.2": - version "0.20.2" - resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.20.2.tgz#9c907b21e30a52db959ba4f80bb01a0cc403d5cc" - integrity sha512-N49X4lJX27+l9jbLKSqZ6bKNjzQvHaT8IIFUy+YIqmXQdjYCToGWwOItDrfby14c78aDd5NHQl29xingXfCdLQ== +"@esbuild/aix-ppc64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz#c7184a326533fcdf1b8ee0733e21c713b975575f" + integrity sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ== + +"@esbuild/android-arm64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz#09d9b4357780da9ea3a7dfb833a1f1ff439b4052" + integrity sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A== + +"@esbuild/android-arm@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.21.5.tgz#9b04384fb771926dfa6d7ad04324ecb2ab9b2e28" + integrity sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg== + +"@esbuild/android-x64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/android-x64/-/android-x64-0.21.5.tgz#29918ec2db754cedcb6c1b04de8cd6547af6461e" + integrity sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA== + +"@esbuild/darwin-arm64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz#e495b539660e51690f3928af50a76fb0a6ccff2a" + integrity sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ== + +"@esbuild/darwin-x64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz#c13838fa57372839abdddc91d71542ceea2e1e22" + integrity sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw== + +"@esbuild/freebsd-arm64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz#646b989aa20bf89fd071dd5dbfad69a3542e550e" + integrity sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g== + +"@esbuild/freebsd-x64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz#aa615cfc80af954d3458906e38ca22c18cf5c261" + integrity sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ== + +"@esbuild/linux-arm64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz#70ac6fa14f5cb7e1f7f887bcffb680ad09922b5b" + integrity sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q== + +"@esbuild/linux-arm@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz#fc6fd11a8aca56c1f6f3894f2bea0479f8f626b9" + integrity sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA== + +"@esbuild/linux-ia32@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz#3271f53b3f93e3d093d518d1649d6d68d346ede2" + integrity sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg== + +"@esbuild/linux-loong64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz#ed62e04238c57026aea831c5a130b73c0f9f26df" + integrity sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg== + +"@esbuild/linux-mips64el@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz#e79b8eb48bf3b106fadec1ac8240fb97b4e64cbe" + integrity sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg== + +"@esbuild/linux-ppc64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz#5f2203860a143b9919d383ef7573521fb154c3e4" + integrity sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w== + +"@esbuild/linux-riscv64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz#07bcafd99322d5af62f618cb9e6a9b7f4bb825dc" + integrity sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA== + +"@esbuild/linux-s390x@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz#b7ccf686751d6a3e44b8627ababc8be3ef62d8de" + integrity sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A== + +"@esbuild/linux-x64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz#6d8f0c768e070e64309af8004bb94e68ab2bb3b0" + integrity sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ== + +"@esbuild/netbsd-x64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz#bbe430f60d378ecb88decb219c602667387a6047" + integrity sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg== + +"@esbuild/openbsd-x64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz#99d1cf2937279560d2104821f5ccce220cb2af70" + integrity sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow== + +"@esbuild/sunos-x64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz#08741512c10d529566baba837b4fe052c8f3487b" + integrity sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg== + +"@esbuild/win32-arm64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz#675b7385398411240735016144ab2e99a60fc75d" + integrity sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A== + +"@esbuild/win32-ia32@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz#1bfc3ce98aa6ca9a0969e4d2af72144c59c1193b" + integrity sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA== + +"@esbuild/win32-x64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz#acad351d582d157bb145535db2a6ff53dd514b5c" + integrity sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw== "@eslint-community/eslint-utils@^4.2.0": version "4.4.0" @@ -1678,11 +1678,6 @@ "@jridgewell/resolve-uri" "^3.1.0" "@jridgewell/sourcemap-codec" "^1.4.14" -"@leichtgewicht/ip-codec@^2.0.1": - version "2.0.4" - resolved "https://registry.yarnpkg.com/@leichtgewicht/ip-codec/-/ip-codec-2.0.4.tgz#b2ac626d6cb9c8718ab459166d4bb405b8ffa78b" - integrity sha512-Hcv+nVC0kZnQ3tD9GVu5xSMR4VVYOteQIr/hwFPVEvPdlXqgGEuRjiheChHgdM+JyqdgNcmzZOX/tnl0JOiI7A== - "@malept/cross-spawn-promise@^1.1.0": version "1.1.1" resolved "https://registry.yarnpkg.com/@malept/cross-spawn-promise/-/cross-spawn-promise-1.1.1.tgz#504af200af6b98e198bce768bc1730c6936ae01d" @@ -1910,85 +1905,85 @@ estree-walker "^2.0.2" picomatch "^2.3.1" -"@rollup/rollup-android-arm-eabi@4.16.1": - version "4.16.1" - resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.16.1.tgz#ad76cc870b1e2bc4476dfc02b82e20cea272a09d" - integrity sha512-92/y0TqNLRYOTXpm6Z7mnpvKAG9P7qmK7yJeRJSdzElNCUnsgbpAsGqerUboYRIQKzgfq4pWu9xVkgpWLfmNsw== - -"@rollup/rollup-android-arm64@4.16.1": - version "4.16.1" - resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.16.1.tgz#e7bd4f2b8ec5e049f98edbc68d72cb05356f81d8" - integrity sha512-ttWB6ZCfRLuDIUiE0yiu5gcqOsYjA5F7kEV1ggHMj20FwLZ8A1FMeahZJFl/pnOmcnD2QL0z4AcDuo27utGU8A== - -"@rollup/rollup-darwin-arm64@4.16.1": - version "4.16.1" - resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.16.1.tgz#8fd277b4be6cc956167710e36b4ee365f8a44050" - integrity sha512-QLDvPLetbqjHojTGFw9+nuSP3YY/iz2k1cep6crYlr97sS+ZJ0W43b8Z0zC00+lnFZj6JSNxiA4DjboNQMuh1A== - -"@rollup/rollup-darwin-x64@4.16.1": - version "4.16.1" - resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.16.1.tgz#5ab829322926fefce42db3529649a1098b420fe3" - integrity sha512-TAUK/D8khRrRIa1KwRzo8JNKk3tcqaeXWdtsiLgA8zmACWwlWLjPCJ4DULGHQrMkeBjp1Cd3Yuwx04lZgFx5Vg== - -"@rollup/rollup-linux-arm-gnueabihf@4.16.1": - version "4.16.1" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.16.1.tgz#0154bc34e6a88fb0147adc827512add8d3a2338c" - integrity sha512-KO+WGZjrh6zyFTD1alIFkfdtxf8B4BC+hqd3kBZHscPLvE5FR/6QKsyuCT0JlERxxYBSUKNUQ/UHyX5uwO1x2A== - -"@rollup/rollup-linux-arm-musleabihf@4.16.1": - version "4.16.1" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.16.1.tgz#0f3fa433a81b389042555133d38b4b886b369e58" - integrity sha512-NqxbllzIB1WoAo4ThUXVtd21iiM5IHMTTXmXySKBLVcZvkU0HIZmatlP7hLzb5yQubcmdIeWmncd2NdsjocEiw== - -"@rollup/rollup-linux-arm64-gnu@4.16.1": - version "4.16.1" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.16.1.tgz#c8f2d523ac4bcff382601306989b27137d536dd6" - integrity sha512-snma5NvV8y7IECQ5rq0sr0f3UUu+92NVmG/913JXJMcXo84h9ak9TA5UI9Cl2XRM9j3m37QwDBtEYnJzRkSmxA== - -"@rollup/rollup-linux-arm64-musl@4.16.1": - version "4.16.1" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.16.1.tgz#86b5104635131182b6b2b6997c4aa5594ce557b7" - integrity sha512-KOvqGprlD84ueivhCi2flvcUwDRD20mAsE3vxQNVEI2Di9tnPGAfEu6UcrSPZbM+jG2w1oSr43hrPo0RNg6GGg== - -"@rollup/rollup-linux-powerpc64le-gnu@4.16.1": - version "4.16.1" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.16.1.tgz#5de8b20105aaaeb36eb86fab0a1020d81c7bd4d5" - integrity sha512-/gsNwtiGLqYwN4vP+EIdUC6Q6LTlpupWqokqIndvZcjn9ig/5P01WyaYCU2wvfL/2Z82jp5kX8c1mDBOvCP3zg== - -"@rollup/rollup-linux-riscv64-gnu@4.16.1": - version "4.16.1" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.16.1.tgz#5319629dcdcb85ba201c6f0f894c9472e7d1013d" - integrity sha512-uU8zuGkQfGqfD9w6VRJZI4IuG4JIfNxxJgEmLMAmPVHREKGsxFVfgHy5c6CexQF2vOfgjB33OsET3Vdn2lln9A== - -"@rollup/rollup-linux-s390x-gnu@4.16.1": - version "4.16.1" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.16.1.tgz#246ac211ed0d78f7a9bc5c1d0653bde4c6cd9f63" - integrity sha512-lsjLtDgtcGFEuBP6yrXwkRN5/wKlvUZtfbKZZu0yaoNpiBL4epgnO21osAALIspVRnl4qZgyLFd8xjCYYWgwfw== - -"@rollup/rollup-linux-x64-gnu@4.16.1": - version "4.16.1" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.16.1.tgz#d0c03203ddeb9454fc6fdde93a39b01c176ac6d9" - integrity sha512-N2ZizKhUryqqrMfdCnjhJhZRgv61C6gK+hwVtCIKC8ts8J+go+vqENnGexwg21nHIOvLN5mBM8a7DI2vlyIOPg== - -"@rollup/rollup-linux-x64-musl@4.16.1": - version "4.16.1" - resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.16.1.tgz#20235632e2be4689d663aadaceaaf90df03b1a33" - integrity sha512-5ICeMxqg66FrOA2AbnBQ2TJVxfvZsKLxmof0ibvPLaYtbsJqnTUtJOofgWb46Gjd4uZcA4rdsp4JCxegzQPqCg== - -"@rollup/rollup-win32-arm64-msvc@4.16.1": - version "4.16.1" - resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.16.1.tgz#af113ad682fc13d1f870242c5539031f8cc27cf1" - integrity sha512-1vIP6Ce02L+qWD7uZYRiFiuAJo3m9kARatWmFSnss0gZnVj2Id7OPUU9gm49JPGasgcR3xMqiH3fqBJ8t00yVg== - -"@rollup/rollup-win32-ia32-msvc@4.16.1": - version "4.16.1" - resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.16.1.tgz#4e7b57e757c95da8e79092056d1b428617515668" - integrity sha512-Y3M92DcVsT6LoP+wrKpoUWPaazaP1fzbNkp0a0ZSj5Y//+pQVfVe/tQdsYQQy7dwXR30ZfALUIc9PCh9Izir6w== - -"@rollup/rollup-win32-x64-msvc@4.16.1": - version "4.16.1" - resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.16.1.tgz#5068a893ba292279adbe76fc487316724b15d811" - integrity sha512-x0fvpHMuF7fK5r8oZxSi8VYXkrVmRgubXpO/wcf15Lk3xZ4Jvvh5oG+u7Su1776A7XzVKZhD2eRc4t7H50gL3w== +"@rollup/rollup-android-arm-eabi@4.24.0": + version "4.24.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.24.0.tgz#1661ff5ea9beb362795304cb916049aba7ac9c54" + integrity sha512-Q6HJd7Y6xdB48x8ZNVDOqsbh2uByBhgK8PiQgPhwkIw/HC/YX5Ghq2mQY5sRMZWHb3VsFkWooUVOZHKr7DmDIA== + +"@rollup/rollup-android-arm64@4.24.0": + version "4.24.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.24.0.tgz#2ffaa91f1b55a0082b8a722525741aadcbd3971e" + integrity sha512-ijLnS1qFId8xhKjT81uBHuuJp2lU4x2yxa4ctFPtG+MqEE6+C5f/+X/bStmxapgmwLwiL3ih122xv8kVARNAZA== + +"@rollup/rollup-darwin-arm64@4.24.0": + version "4.24.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.24.0.tgz#627007221b24b8cc3063703eee0b9177edf49c1f" + integrity sha512-bIv+X9xeSs1XCk6DVvkO+S/z8/2AMt/2lMqdQbMrmVpgFvXlmde9mLcbQpztXm1tajC3raFDqegsH18HQPMYtA== + +"@rollup/rollup-darwin-x64@4.24.0": + version "4.24.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.24.0.tgz#0605506142b9e796c370d59c5984ae95b9758724" + integrity sha512-X6/nOwoFN7RT2svEQWUsW/5C/fYMBe4fnLK9DQk4SX4mgVBiTA9h64kjUYPvGQ0F/9xwJ5U5UfTbl6BEjaQdBQ== + +"@rollup/rollup-linux-arm-gnueabihf@4.24.0": + version "4.24.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.24.0.tgz#62dfd196d4b10c0c2db833897164d2d319ee0cbb" + integrity sha512-0KXvIJQMOImLCVCz9uvvdPgfyWo93aHHp8ui3FrtOP57svqrF/roSSR5pjqL2hcMp0ljeGlU4q9o/rQaAQ3AYA== + +"@rollup/rollup-linux-arm-musleabihf@4.24.0": + version "4.24.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.24.0.tgz#53ce72aeb982f1f34b58b380baafaf6a240fddb3" + integrity sha512-it2BW6kKFVh8xk/BnHfakEeoLPv8STIISekpoF+nBgWM4d55CZKc7T4Dx1pEbTnYm/xEKMgy1MNtYuoA8RFIWw== + +"@rollup/rollup-linux-arm64-gnu@4.24.0": + version "4.24.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.24.0.tgz#1632990f62a75c74f43e4b14ab3597d7ed416496" + integrity sha512-i0xTLXjqap2eRfulFVlSnM5dEbTVque/3Pi4g2y7cxrs7+a9De42z4XxKLYJ7+OhE3IgxvfQM7vQc43bwTgPwA== + +"@rollup/rollup-linux-arm64-musl@4.24.0": + version "4.24.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.24.0.tgz#8c03a996efb41e257b414b2e0560b7a21f2d9065" + integrity sha512-9E6MKUJhDuDh604Qco5yP/3qn3y7SLXYuiC0Rpr89aMScS2UAmK1wHP2b7KAa1nSjWJc/f/Lc0Wl1L47qjiyQw== + +"@rollup/rollup-linux-powerpc64le-gnu@4.24.0": + version "4.24.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.24.0.tgz#5b98729628d5bcc8f7f37b58b04d6845f85c7b5d" + integrity sha512-2XFFPJ2XMEiF5Zi2EBf4h73oR1V/lycirxZxHZNc93SqDN/IWhYYSYj8I9381ikUFXZrz2v7r2tOVk2NBwxrWw== + +"@rollup/rollup-linux-riscv64-gnu@4.24.0": + version "4.24.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.24.0.tgz#48e42e41f4cabf3573cfefcb448599c512e22983" + integrity sha512-M3Dg4hlwuntUCdzU7KjYqbbd+BLq3JMAOhCKdBE3TcMGMZbKkDdJ5ivNdehOssMCIokNHFOsv7DO4rlEOfyKpg== + +"@rollup/rollup-linux-s390x-gnu@4.24.0": + version "4.24.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.24.0.tgz#e0b4f9a966872cb7d3e21b9e412a4b7efd7f0b58" + integrity sha512-mjBaoo4ocxJppTorZVKWFpy1bfFj9FeCMJqzlMQGjpNPY9JwQi7OuS1axzNIk0nMX6jSgy6ZURDZ2w0QW6D56g== + +"@rollup/rollup-linux-x64-gnu@4.24.0": + version "4.24.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.24.0.tgz#78144741993100f47bd3da72fce215e077ae036b" + integrity sha512-ZXFk7M72R0YYFN5q13niV0B7G8/5dcQ9JDp8keJSfr3GoZeXEoMHP/HlvqROA3OMbMdfr19IjCeNAnPUG93b6A== + +"@rollup/rollup-linux-x64-musl@4.24.0": + version "4.24.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.24.0.tgz#d9fe32971883cd1bd858336bd33a1c3ca6146127" + integrity sha512-w1i+L7kAXZNdYl+vFvzSZy8Y1arS7vMgIy8wusXJzRrPyof5LAb02KGr1PD2EkRcl73kHulIID0M501lN+vobQ== + +"@rollup/rollup-win32-arm64-msvc@4.24.0": + version "4.24.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.24.0.tgz#71fa3ea369316db703a909c790743972e98afae5" + integrity sha512-VXBrnPWgBpVDCVY6XF3LEW0pOU51KbaHhccHw6AS6vBWIC60eqsH19DAeeObl+g8nKAz04QFdl/Cefta0xQtUQ== + +"@rollup/rollup-win32-ia32-msvc@4.24.0": + version "4.24.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.24.0.tgz#653f5989a60658e17d7576a3996deb3902e342e2" + integrity sha512-xrNcGDU0OxVcPTH/8n/ShH4UevZxKIO6HJFK0e15XItZP2UcaiLFd5kiX7hJnqCbSztUF8Qot+JWBC/QXRPYWQ== + +"@rollup/rollup-win32-x64-msvc@4.24.0": + version "4.24.0" + resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.24.0.tgz#0574d7e87b44ee8511d08cc7f914bcb802b70818" + integrity sha512-fbMkAF7fufku0N2dE5TBXcNlg0pt0cJue4xBRE2Qc5Vqikxr4VCgKj/ht6SMdFcOacVA9rqF70APJ8RN/4vMJw== "@sinclair/typebox@^0.27.8": version "0.27.8" @@ -2347,13 +2342,6 @@ "@types/connect" "*" "@types/node" "*" -"@types/bonjour@^3.5.13": - version "3.5.13" - resolved "https://registry.yarnpkg.com/@types/bonjour/-/bonjour-3.5.13.tgz#adf90ce1a105e81dd1f9c61fdc5afda1bfb92956" - integrity sha512-z9fJ5Im06zvUL548KvYNecEVlA7cVDkGUi6kZusb04mpyEFKCIZJvloCcmpmLaIahDpOQGHaHmG6imtPMmPXGQ== - dependencies: - "@types/node" "*" - "@types/cacheable-request@^6.0.1": version "6.0.3" resolved "https://registry.yarnpkg.com/@types/cacheable-request/-/cacheable-request-6.0.3.tgz#a430b3260466ca7b5ca5bfd735693b36e7a9d183" @@ -2376,14 +2364,6 @@ dependencies: classnames "*" -"@types/connect-history-api-fallback@^1.5.4": - version "1.5.4" - resolved "https://registry.yarnpkg.com/@types/connect-history-api-fallback/-/connect-history-api-fallback-1.5.4.tgz#7de71645a103056b48ac3ce07b3520b819c1d5b3" - integrity sha512-n6Cr2xS1h4uAulPRdlw6Jl6s1oG8KrVilPN2yUITEs+K48EzMJJ3W1xy8K5eWuFvjp3R74AOIGSmp2UfBJ8HFw== - dependencies: - "@types/express-serve-static-core" "*" - "@types/node" "*" - "@types/connect@*": version "3.4.35" resolved "https://registry.yarnpkg.com/@types/connect/-/connect-3.4.35.tgz#5fcf6ae445e4021d1fc2219a4873cc73a3bb2ad1" @@ -2646,12 +2626,12 @@ "@types/estree" "*" "@types/json-schema" "*" -"@types/estree@*", "@types/estree@1.0.5", "@types/estree@^1.0.0", "@types/estree@^1.0.5": - version "1.0.5" - resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.5.tgz#a6ce3e556e00fd9895dd872dd172ad0d4bd687f4" - integrity sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw== +"@types/estree@*", "@types/estree@1.0.6", "@types/estree@^1.0.0", "@types/estree@^1.0.5": + version "1.0.6" + resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.6.tgz#628effeeae2064a1b4e79f78e81d87b7e5fc7b50" + integrity sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw== -"@types/express-serve-static-core@*", "@types/express-serve-static-core@^4.17.33": +"@types/express-serve-static-core@^4.17.33": version "4.17.34" resolved "https://registry.yarnpkg.com/@types/express-serve-static-core/-/express-serve-static-core-4.17.34.tgz#c119e85b75215178bc127de588e93100698ab4cc" integrity sha512-fvr49XlCGoUj2Pp730AItckfjat4WNb0lb3kfrLWffd+RLeoGAMsq7UOy04PAPtoL01uKwcp6u8nhzpgpDYr3w== @@ -2661,7 +2641,7 @@ "@types/range-parser" "*" "@types/send" "*" -"@types/express@*", "@types/express@^4.17.21", "@types/express@^4.17.3": +"@types/express@^4.17.3": version "4.17.21" resolved "https://registry.yarnpkg.com/@types/express/-/express-4.17.21.tgz#c26d4a151e60efe0084b23dc3369ebc631ed192d" integrity sha512-ejlPM315qwLpaQlQDTjPdsUFSc6ZsP4AN6AlWnogPjQ7CVi7PYF3YVz+CY3jE2pwYf7E/7HlDAN0rV2GxTG0HQ== @@ -2744,13 +2724,6 @@ resolved "https://registry.yarnpkg.com/@types/http-errors/-/http-errors-2.0.4.tgz#7eb47726c391b7345a6ec35ad7f4de469cf5ba4f" integrity sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA== -"@types/http-proxy@^1.17.8": - version "1.17.11" - resolved "https://registry.yarnpkg.com/@types/http-proxy/-/http-proxy-1.17.11.tgz#0ca21949a5588d55ac2b659b69035c84bd5da293" - integrity sha512-HC8G7c1WmaF2ekqpnFq626xd3Zz0uvaqFmBJNRZCGEZCXkvSdJoNFn/8Ygbd9fKNQj8UzLdCETaI0UWPAjK7IA== - dependencies: - "@types/node" "*" - "@types/ioredis@^4.26.0": version "4.28.10" resolved "https://registry.yarnpkg.com/@types/ioredis/-/ioredis-4.28.10.tgz#40ceb157a4141088d1394bb87c98ed09a75a06ff" @@ -2867,13 +2840,6 @@ resolved "https://registry.yarnpkg.com/@types/ms/-/ms-0.7.31.tgz#31b7ca6407128a3d2bbc27fe2d21b345397f6197" integrity sha512-iiUgKzV9AuaEkZqkOLDIvlQiL6ltuZd9tGcW3gwpnX8JbuiuhFlEGmmFXEXkN50Cvq7Os88IY2v0dkDqXYWVgA== -"@types/node-forge@^1.3.0": - version "1.3.11" - resolved "https://registry.yarnpkg.com/@types/node-forge/-/node-forge-1.3.11.tgz#0972ea538ddb0f4d9c2fa0ec5db5724773a604da" - integrity sha512-FQx220y22OKNTqaByeBGqHWYz4cl94tpcxeFdvBo3wjG6XPBuZ0BNgNZRV5J5TFmmcsJ4IzsLkmGRiQbnYsBEQ== - dependencies: - "@types/node" "*" - "@types/node@*", "@types/node@>=13.7.0", "@types/node@^20.9.0": version "20.14.8" resolved "https://registry.yarnpkg.com/@types/node/-/node-20.14.8.tgz#45c26a2a5de26c3534a9504530ddb3b27ce031ac" @@ -2987,7 +2953,7 @@ hoist-non-react-statics "^3.3.0" redux "^4.0.0" -"@types/react-router-dom@^5.1.6": +"@types/react-router-dom@^5.3.3": version "5.3.3" resolved "https://registry.yarnpkg.com/@types/react-router-dom/-/react-router-dom-5.3.3.tgz#e9d6b4a66fcdbd651a5f106c2656a30088cc1e83" integrity sha512-kpqnYK4wcdm5UaWI3fLcELopqLrHgLqNsdpHauzlQktfkHL3npOSwtj1Uz9oKBAzs7lFtVkV8j83voAz2D8fhw== @@ -3078,11 +3044,6 @@ dependencies: "@types/node" "*" -"@types/retry@0.12.2": - version "0.12.2" - resolved "https://registry.yarnpkg.com/@types/retry/-/retry-0.12.2.tgz#ed279a64fa438bb69f2480eda44937912bb7480a" - integrity sha512-XISRgDJ2Tc5q4TRqvgJtzsRkFYNJzZrhTdtMoGVBttwzzQJkPnS3WWTFc7kuDRoPtPakl+T+OfdEUjYJj7Jbow== - "@types/scheduler@*": version "0.16.3" resolved "https://registry.yarnpkg.com/@types/scheduler/-/scheduler-0.16.3.tgz#cef09e3ec9af1d63d2a6cc5b383a737e24e6dcf5" @@ -3093,7 +3054,7 @@ resolved "https://registry.yarnpkg.com/@types/segment-analytics/-/segment-analytics-0.0.34.tgz#e88fd5286e27eefafbc1b98c8c7e143b9aab5fb5" integrity sha512-fiOyEgyqJY2Mv9k72WG4XoY4fVE31byiSUrEFcNh+MgHcH3HuJmoz2J7ktO3YizBrN6/RuaH1tY5J/5I5BJHJQ== -"@types/semver@^7.3.12", "@types/semver@^7.3.6": +"@types/semver@^7.3.12": version "7.3.13" resolved "https://registry.yarnpkg.com/@types/semver/-/semver-7.3.13.tgz#da4bfd73f49bd541d28920ab0e2bf0ee80f71c91" integrity sha512-21cFJr9z3g5dW8B0CVI9g2O9beqaThGQ6ZFBqHfwhzLDKUxaqTIy3vnfah/UPkfOiF2pLq+tGz+W8RyCskuslw== @@ -3106,14 +3067,7 @@ "@types/mime" "^1" "@types/node" "*" -"@types/serve-index@^1.9.4": - version "1.9.4" - resolved "https://registry.yarnpkg.com/@types/serve-index/-/serve-index-1.9.4.tgz#e6ae13d5053cb06ed36392110b4f9a49ac4ec898" - integrity sha512-qLpGZ/c2fhSs5gnYsQxtDEq3Oy8SXPClIXkW5ghvAvsNuVSA8k+gCONcUCS/UjLEYvYps+e8uBtfgXgvhwfNug== - dependencies: - "@types/express" "*" - -"@types/serve-static@*", "@types/serve-static@^1.15.5": +"@types/serve-static@*": version "1.15.7" resolved "https://registry.yarnpkg.com/@types/serve-static/-/serve-static-1.15.7.tgz#22174bbd74fb97fe303109738e9b5c2f3064f714" integrity sha512-W8Ym+h8nhuRwaKPaDw34QUkwsGi6Rc4yYqvKFo5rm2FUEhCFbzVWrxXUxuKK8TASjWsysJY0nsmNCGhCOIsrOw== @@ -3129,13 +3083,6 @@ dependencies: "@types/node" "*" -"@types/sockjs@^0.3.36": - version "0.3.36" - resolved "https://registry.yarnpkg.com/@types/sockjs/-/sockjs-0.3.36.tgz#ce322cf07bcc119d4cbf7f88954f3a3bd0f67535" - integrity sha512-MK9V6NzAS1+Ud7JV9lJLFqW85VbC9dq3LmwZCuBe4wBDgKC0Kj/jd8Xl+nSviU+Qc3+m7umHHyHg//2KSa0a0Q== - dependencies: - "@types/node" "*" - "@types/stack-utils@^2.0.0": version "2.0.1" resolved "https://registry.yarnpkg.com/@types/stack-utils/-/stack-utils-2.0.1.tgz#20f18294f797f2209b5f65c8e3b5c8e8261d127c" @@ -3188,27 +3135,11 @@ dependencies: vfile-message "*" -"@types/webpack-bundle-analyzer@^4.7.0": - version "4.7.0" - resolved "https://registry.yarnpkg.com/@types/webpack-bundle-analyzer/-/webpack-bundle-analyzer-4.7.0.tgz#fe199e724ce3d38705f6f1ba4d62429b7c360541" - integrity sha512-c5i2ThslSNSG8W891BRvOd/RoCjI2zwph8maD22b1adtSns20j+0azDDMCK06DiVrzTgnwiDl5Ntmu1YRJw8Sg== - dependencies: - "@types/node" "*" - tapable "^2.2.0" - webpack "^5" - "@types/webpack-env@^1.18.4": version "1.18.4" resolved "https://registry.yarnpkg.com/@types/webpack-env/-/webpack-env-1.18.4.tgz#62879b0a9c653f9b1172d403b882f2045ecce032" integrity sha512-I6e+9+HtWADAWeeJWDFQtdk4EVSAbj6Rtz4q8fJ7mSr1M0jzlFcs8/HZ+Xb5SHzVm1dxH7aUiI+A8kA8Gcrm0A== -"@types/ws@^8.5.10": - version "8.5.10" - resolved "https://registry.yarnpkg.com/@types/ws/-/ws-8.5.10.tgz#4acfb517970853fa6574a3a6886791d04a396787" - integrity sha512-vmQSUcfalpIq0R9q7uTo2lXs6eGIpt9wtnLdMv9LVpIjCA/+ufZRozlVoVelIYixx1ugCBKDhn89vnsEGOCx9A== - dependencies: - "@types/node" "*" - "@types/yargs-parser@*": version "21.0.0" resolved "https://registry.yarnpkg.com/@types/yargs-parser/-/yargs-parser-21.0.0.tgz#0c60e537fa790f5f9472ed2776c2b71ec117351b" @@ -3549,14 +3480,6 @@ abbrev@1, abbrev@^1.0.0: resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" integrity sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q== -accepts@~1.3.4, accepts@~1.3.5, accepts@~1.3.8: - version "1.3.8" - resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.8.tgz#0bf0be125b67014adcb0b0921e62db7bffe16b2e" - integrity sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw== - dependencies: - mime-types "~2.1.34" - negotiator "0.6.3" - acorn-globals@^7.0.0: version "7.0.1" resolved "https://registry.yarnpkg.com/acorn-globals/-/acorn-globals-7.0.1.tgz#0dbf05c44fa7c94332914c02066d5beff62c40c3" @@ -3820,11 +3743,6 @@ array-find-index@^1.0.2: resolved "https://registry.yarnpkg.com/array-find-index/-/array-find-index-1.0.2.tgz#df010aa1287e164bbda6f9723b0a96a1ec4187a1" integrity sha512-M1HQyIXcBGtVywBt8WVdim+lrNaK7VHp99Qt5pSNziXznKHViIBbXWtfRTpEFpF/c4FdfxNAsCCwPp5phBYJtw== -array-flatten@1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2" - integrity sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg== - array-includes@^3.1.1, array-includes@^3.1.5, array-includes@^3.1.6: version "3.1.6" resolved "https://registry.yarnpkg.com/array-includes/-/array-includes-3.1.6.tgz#9e9e720e194f198266ba9e18c29e6a9b0e4b225f" @@ -4112,11 +4030,6 @@ base64-js@^1.3.0, base64-js@^1.3.1, base64-js@^1.5.1: resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a" integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA== -batch@0.6.1: - version "0.6.1" - resolved "https://registry.yarnpkg.com/batch/-/batch-0.6.1.tgz#dc34314f4e679318093fc760272525f94bf25c16" - integrity sha512-x+VAiMRL6UPkx+kudNvxTl6hB2XNNCG2r+7wixVfIYwu/2HKRXimwQyaumLjMveWvT2Hkd/cAJw+QBMfJ/EKVw== - big.js@^5.2.2: version "5.2.2" resolved "https://registry.yarnpkg.com/big.js/-/big.js-5.2.2.tgz#65f0af382f578bcdc742bd9c281e9cb2d7768328" @@ -4153,32 +4066,6 @@ bluebird@^3.5.5: resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.7.2.tgz#9f229c15be272454ffa973ace0dbee79a1b0c36f" integrity sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg== -body-parser@1.20.1: - version "1.20.1" - resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.20.1.tgz#b1812a8912c195cd371a3ee5e66faa2338a5c668" - integrity sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw== - dependencies: - bytes "3.1.2" - content-type "~1.0.4" - debug "2.6.9" - depd "2.0.0" - destroy "1.2.0" - http-errors "2.0.0" - iconv-lite "0.4.24" - on-finished "2.4.1" - qs "6.11.0" - raw-body "2.5.1" - type-is "~1.6.18" - unpipe "1.0.0" - -bonjour-service@^1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/bonjour-service/-/bonjour-service-1.2.1.tgz#eb41b3085183df3321da1264719fbada12478d02" - integrity sha512-oSzCS2zV14bh2kji6vNe7vrpJYCHGvcZnlffFQ1MEoX/WOeQ/teD8SYWKR942OI3INjq8OMNJlbPK5LLLUxFDw== - dependencies: - fast-deep-equal "^3.1.3" - multicast-dns "^7.2.5" - boolbase@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/boolbase/-/boolbase-1.0.0.tgz#68dff5fbe60c51eb37725ea9e3ed310dcc1e776e" @@ -4309,10 +4196,10 @@ buffer@^6.0.3: base64-js "^1.3.1" ieee754 "^1.2.1" -builder-util-runtime@9.1.1: - version "9.1.1" - resolved "https://registry.yarnpkg.com/builder-util-runtime/-/builder-util-runtime-9.1.1.tgz#2da7b34e78a64ad14ccd070d6eed4662d893bd60" - integrity sha512-azRhYLEoDvRDR8Dhis4JatELC/jUvYjm4cVSj7n9dauGTOM2eeNn9KS0z6YA6oDsjI1xphjNbY6PZZeHPzzqaw== +builder-util-runtime@9.2.10: + version "9.2.10" + resolved "https://registry.yarnpkg.com/builder-util-runtime/-/builder-util-runtime-9.2.10.tgz#a0f7d9e214158402e78b74a745c8d9f870c604bc" + integrity sha512-6p/gfG1RJSQeIbz8TK5aPNkoztgY1q5TgmGFMAXcY8itsGW6Y2ld1ALsZ5UJn8rog7hKF3zHx5iQbNQ8uLcRlw== dependencies: debug "^4.3.4" sax "^1.2.4" @@ -4347,23 +4234,6 @@ builder-util@24.13.1: stat-mode "^1.0.0" temp-file "^3.4.0" -bundle-name@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/bundle-name/-/bundle-name-4.1.0.tgz#f3b96b34160d6431a19d7688135af7cfb8797889" - integrity sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q== - dependencies: - run-applescript "^7.0.0" - -bytes@3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.0.0.tgz#d32815404d689699f85a4ea4fa8755dd13a96048" - integrity sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw== - -bytes@3.1.2: - version "3.1.2" - resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.2.tgz#8b0beeb98605adf1b128fa4386403c009e0221a5" - integrity sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg== - cac@^6.7.14: version "6.7.14" resolved "https://registry.yarnpkg.com/cac/-/cac-6.7.14.tgz#804e1e6f506ee363cb0e3ccbb09cad5dd9870959" @@ -4540,7 +4410,7 @@ chardet@^0.7.0: resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.7.0.tgz#90094849f0937f2eedc2425d0d28a9e5f0cbad9e" integrity sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA== -chokidar@^3.4.2, chokidar@^3.6.0: +chokidar@^3.4.2: version "3.6.0" resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.6.0.tgz#197c6cc669ef2a8dc5e7b4d97ee4e092c3eb0d5b" integrity sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw== @@ -4720,7 +4590,7 @@ colord@^2.9.3: resolved "https://registry.yarnpkg.com/colord/-/colord-2.9.3.tgz#4f8ce919de456f1d5c1c368c307fe20f3e59fb43" integrity sha512-jeC1axXpnb0/2nn/Y1LPuLdgXBLH7aDcHu4KEKfqw3CUhX7ZpfBSlPKyqXE6btIgEzfWtrX3/tyBCaCvXvMkOw== -colorette@^2.0.10, colorette@^2.0.14, colorette@^2.0.16: +colorette@^2.0.14, colorette@^2.0.16: version "2.0.20" resolved "https://registry.yarnpkg.com/colorette/-/colorette-2.0.20.tgz#9eb793e6833067f7235902fcd3b09917a000a95a" integrity sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w== @@ -4787,26 +4657,6 @@ component-emitter@^1.2.0, component-emitter@^1.3.0: resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.3.0.tgz#16e4070fba8ae29b679f2215853ee181ab2eabc0" integrity sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg== -compressible@~2.0.16: - version "2.0.18" - resolved "https://registry.yarnpkg.com/compressible/-/compressible-2.0.18.tgz#af53cca6b070d4c3c0750fbd77286a6d7cc46fba" - integrity sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg== - dependencies: - mime-db ">= 1.43.0 < 2" - -compression@^1.7.4: - version "1.7.4" - resolved "https://registry.yarnpkg.com/compression/-/compression-1.7.4.tgz#95523eff170ca57c29a0ca41e6fe131f41e5bb8f" - integrity sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ== - dependencies: - accepts "~1.3.5" - bytes "3.0.0" - compressible "~2.0.16" - debug "2.6.9" - on-headers "~1.0.2" - safe-buffer "5.1.2" - vary "~1.1.2" - concat-map@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" @@ -4854,11 +4704,6 @@ confusing-browser-globals@^1.0.10: resolved "https://registry.yarnpkg.com/confusing-browser-globals/-/confusing-browser-globals-1.0.11.tgz#ae40e9b57cdd3915408a2805ebd3a5585608dc81" integrity sha512-JsPKdmh8ZkmnHxDk55FZ1TqVLvEQTvoByJZRN9jzI0UjxK/QgAmsphz7PGtqgPieQZ/CQcHWXCR7ATDNhGe+YA== -connect-history-api-fallback@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/connect-history-api-fallback/-/connect-history-api-fallback-2.0.0.tgz#647264845251a0daf25b97ce87834cace0f5f1c8" - integrity sha512-U73+6lQFmfiNPrYbXqr6kZ1i1wiRqXnp2nhMsINseWXO8lDau0LGEffJ8kQi4EjLZympVgRdvqjAgiZ1tgzDDA== - connection-string@^4.3.2: version "4.3.6" resolved "https://registry.yarnpkg.com/connection-string/-/connection-string-4.3.6.tgz#4aa23f0b6d31f6a310afffd4e9a481d000c64836" @@ -4874,33 +4719,11 @@ construct-style-sheets-polyfill@^3.1.0: resolved "https://registry.yarnpkg.com/construct-style-sheets-polyfill/-/construct-style-sheets-polyfill-3.1.0.tgz#c490abd79efdb359fafa62ec14ea55232be0eecf" integrity sha512-HBLKP0chz8BAY6rBdzda11c3wAZeCZ+kIG4weVC2NM3AXzxx09nhe8t0SQNdloAvg5GLuHwq/0SPOOSPvtCcKw== -content-disposition@0.5.4: - version "0.5.4" - resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.4.tgz#8b82b4efac82512a02bb0b1dcec9d2c5e8eb5bfe" - integrity sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ== - dependencies: - safe-buffer "5.2.1" - -content-type@~1.0.4: - version "1.0.5" - resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.5.tgz#8b773162656d1d1086784c8f23a54ce6d73d7918" - integrity sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA== - convert-source-map@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-2.0.0.tgz#4b560f649fc4e918dd0ab75cf4961e8bc882d82a" integrity sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg== -cookie-signature@1.0.6: - version "1.0.6" - resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c" - integrity sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ== - -cookie@0.5.0: - version "0.5.0" - resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.5.0.tgz#d1f5d71adec6558c58f389987c366aa47e994f8b" - integrity sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw== - cookie@^0.4.2: version "0.4.2" resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.4.2.tgz#0e41f24de5ecf317947c82fc789e06a884824432" @@ -5508,13 +5331,6 @@ debounce@^1.2.1: resolved "https://registry.yarnpkg.com/debounce/-/debounce-1.2.1.tgz#38881d8f4166a5c5848020c11827b834bcb3e0a5" integrity sha512-XRRe6Glud4rd/ZGQfiV1ruXSfbvfJedlV9Y6zOlP+2K04vBYiJEte6stfFkCP03aMnY5tsipamumUjL14fofug== -debug@2.6.9: - version "2.6.9" - resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" - integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== - dependencies: - ms "2.0.0" - debug@4, debug@^4.0.0, debug@^4.0.1, debug@^4.1.0, debug@^4.1.1, debug@^4.2.0, debug@^4.3.1, debug@^4.3.3, debug@^4.3.4, debug@~4.3.1, debug@~4.3.2: version "4.3.4" resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" @@ -5602,26 +5418,6 @@ deepmerge@^4.2.2, deepmerge@^4.3.1: resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-4.3.1.tgz#44b5f2147cd3b00d4b56137685966f26fd25dd4a" integrity sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A== -default-browser-id@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/default-browser-id/-/default-browser-id-5.0.0.tgz#a1d98bf960c15082d8a3fa69e83150ccccc3af26" - integrity sha512-A6p/pu/6fyBcA1TRz/GqWYPViplrftcW2gZC9q79ngNCKAeR/X3gcEdXQHl4KNXV+3wgIJ1CPkJQ3IHM6lcsyA== - -default-browser@^5.2.1: - version "5.2.1" - resolved "https://registry.yarnpkg.com/default-browser/-/default-browser-5.2.1.tgz#7b7ba61204ff3e425b556869ae6d3e9d9f1712cf" - integrity sha512-WY/3TUME0x3KPYdRRxEJJvXRHV4PyPoUsxtZa78lwItwRQRHhd2U9xOscaT/YTf8uCXIAjeJOFBVEh/7FtD8Xg== - dependencies: - bundle-name "^4.1.0" - default-browser-id "^5.0.0" - -default-gateway@^6.0.3: - version "6.0.3" - resolved "https://registry.yarnpkg.com/default-gateway/-/default-gateway-6.0.3.tgz#819494c888053bdb743edbf343d6cdf7f2943a71" - integrity sha512-fwSOJsbbNzZ/CUFpqFBqYfYNLj1NbMPm8MMCIzHjC83iSJRBEGmDUxU+WP661BaBQImeC2yHwXtz+P/O9o+XEg== - dependencies: - execa "^5.0.0" - defaults@^1.0.3: version "1.0.4" resolved "https://registry.yarnpkg.com/defaults/-/defaults-1.0.4.tgz#b0b02062c1e2aa62ff5d9528f0f98baa90978d7a" @@ -5648,11 +5444,6 @@ define-lazy-prop@^2.0.0: resolved "https://registry.yarnpkg.com/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz#3f7ae421129bcaaac9bc74905c98a0009ec9ee7f" integrity sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og== -define-lazy-prop@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/define-lazy-prop/-/define-lazy-prop-3.0.0.tgz#dbb19adfb746d7fc6d734a06b72f4a00d021255f" - integrity sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg== - define-properties@^1.1.3, define-properties@^1.1.4, define-properties@^1.2.0, define-properties@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.2.1.tgz#10781cc616eb951a80a034bafcaa7377f6af2b6c" @@ -5684,26 +5475,11 @@ delegates@^1.0.0: resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a" integrity sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ== -depd@2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/depd/-/depd-2.0.0.tgz#b696163cc757560d09cf22cc8fad1571b79e76df" - integrity sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw== - -depd@~1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9" - integrity sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ== - dequal@^2.0.0: version "2.0.3" resolved "https://registry.yarnpkg.com/dequal/-/dequal-2.0.3.tgz#2644214f1997d39ed0ee0ece72335490a7ac67be" integrity sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA== -destroy@1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.2.0.tgz#4803735509ad8be552934c67df614f94e66fa015" - integrity sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg== - detect-libc@^2.0.1: version "2.0.2" resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-2.0.2.tgz#8ccf2ba9315350e1241b88d0ac3b0e1fbd99605d" @@ -5800,13 +5576,6 @@ dmg-license@^1.0.11: smart-buffer "^4.0.2" verror "^1.10.0" -dns-packet@^5.2.2: - version "5.6.0" - resolved "https://registry.yarnpkg.com/dns-packet/-/dns-packet-5.6.0.tgz#2202c947845c7a63c23ece58f2f70ff6ab4c2f7d" - integrity sha512-rza3UH1LwdHh9qyPXp8lkwpjSNk/AMD3dPytUoRoqnypDUhY0xvbdmVhWOfxO68frEfV9BU8V12Ez7ZsHGZpCQ== - dependencies: - "@leichtgewicht/ip-codec" "^2.0.1" - doctrine@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-2.1.0.tgz#5cd01fc101621b42c4cd7f5d1a66243716d3f39d" @@ -5965,11 +5734,6 @@ ecdsa-sig-formatter@1.0.11, ecdsa-sig-formatter@^1.0.11: dependencies: safe-buffer "^5.0.1" -ee-first@1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" - integrity sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow== - ejs@^3.1.8: version "3.1.10" resolved "https://registry.yarnpkg.com/ejs/-/ejs-3.1.10.tgz#69ab8358b14e896f80cc39e62087b88500c3ac3b" @@ -6104,20 +5868,19 @@ electron-to-chromium@^1.4.668: resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.745.tgz#9c202ce9cbf18a5b5e0ca47145fd127cc4dd2290" integrity sha512-tRbzkaRI5gbUn5DEvF0dV4TQbMZ5CLkWeTAXmpC9IrYT+GE+x76i9p+o3RJ5l9XmdQlI1pPhVtE9uNcJJ0G0EA== -electron-updater@^5.0.5: - version "5.3.0" - resolved "https://registry.yarnpkg.com/electron-updater/-/electron-updater-5.3.0.tgz#3ba0d20407911a2edc5a68bee45c5aa2023e9ff8" - integrity sha512-iKEr7yQBcvnQUPnSDYGSWC9t0eF2YbZWeYYYZzYxdl+HiRejXFENjYMnYjoOm2zxyD6Cr2JTHZhp9pqxiXuCOw== +electron-updater@^6.3.9: + version "6.3.9" + resolved "https://registry.yarnpkg.com/electron-updater/-/electron-updater-6.3.9.tgz#e1e7f155624c58e6f3760f376c3a584028165ec4" + integrity sha512-2PJNONi+iBidkoC5D1nzT9XqsE8Q1X28Fn6xRQhO3YX8qRRyJ3mkV4F1aQsuRnYPqq6Hw+E51y27W75WgDoofw== dependencies: - "@types/semver" "^7.3.6" - builder-util-runtime "9.1.1" - fs-extra "^10.0.0" + builder-util-runtime "9.2.10" + fs-extra "^10.1.0" js-yaml "^4.1.0" lazy-val "^1.0.5" lodash.escaperegexp "^4.1.2" lodash.isequal "^4.5.0" - semver "^7.3.5" - typed-emitter "^2.1.0" + semver "^7.6.3" + tiny-typed-emitter "^2.1.0" electron@31.0.2: version "31.0.2" @@ -6153,11 +5916,6 @@ emoticon@^3.2.0: resolved "https://registry.yarnpkg.com/emoticon/-/emoticon-3.2.0.tgz#c008ca7d7620fac742fe1bf4af8ff8fed154ae7f" integrity sha512-SNujglcLTTg+lDAcApPNgEdudaqQFiAbJCqzjNxJkvN9vAwCGi0uu8IUVvx+f16h+V44KCY6Y2yboroc9pilHg== -encodeurl@~1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" - integrity sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w== - encoding@^0.1.13: version "0.1.13" resolved "https://registry.yarnpkg.com/encoding/-/encoding-0.1.13.tgz#56574afdd791f54a8e9b2785c0582a2d26210fa9" @@ -6382,34 +6140,34 @@ esbuild-plugin-react-virtualized@^1.0.4: resolved "https://registry.yarnpkg.com/esbuild-plugin-react-virtualized/-/esbuild-plugin-react-virtualized-1.0.4.tgz#b8911ce8fae4636daa87cfa898752170f5d45609" integrity sha512-/Y+82TBduHox0/uhJlTgUqi3ZWN+qZPF0xy9crkHQE2AOOdm76l6VY2F0Mdfvue9hqXz2FOlKHlHUVXNalHLzA== -esbuild@^0.20.1: - version "0.20.2" - resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.20.2.tgz#9d6b2386561766ee6b5a55196c6d766d28c87ea1" - integrity sha512-WdOOppmUNU+IbZ0PaDiTst80zjnrOkyJNHoKupIcVyU8Lvla3Ugx94VzkQ32Ijqd7UhHJy75gNWDMUekcrSJ6g== +esbuild@^0.21.3: + version "0.21.5" + resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.21.5.tgz#9ca301b120922959b766360d8ac830da0d02997d" + integrity sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw== optionalDependencies: - "@esbuild/aix-ppc64" "0.20.2" - "@esbuild/android-arm" "0.20.2" - "@esbuild/android-arm64" "0.20.2" - "@esbuild/android-x64" "0.20.2" - "@esbuild/darwin-arm64" "0.20.2" - "@esbuild/darwin-x64" "0.20.2" - "@esbuild/freebsd-arm64" "0.20.2" - "@esbuild/freebsd-x64" "0.20.2" - "@esbuild/linux-arm" "0.20.2" - "@esbuild/linux-arm64" "0.20.2" - "@esbuild/linux-ia32" "0.20.2" - "@esbuild/linux-loong64" "0.20.2" - "@esbuild/linux-mips64el" "0.20.2" - "@esbuild/linux-ppc64" "0.20.2" - "@esbuild/linux-riscv64" "0.20.2" - "@esbuild/linux-s390x" "0.20.2" - "@esbuild/linux-x64" "0.20.2" - "@esbuild/netbsd-x64" "0.20.2" - "@esbuild/openbsd-x64" "0.20.2" - "@esbuild/sunos-x64" "0.20.2" - "@esbuild/win32-arm64" "0.20.2" - "@esbuild/win32-ia32" "0.20.2" - "@esbuild/win32-x64" "0.20.2" + "@esbuild/aix-ppc64" "0.21.5" + "@esbuild/android-arm" "0.21.5" + "@esbuild/android-arm64" "0.21.5" + "@esbuild/android-x64" "0.21.5" + "@esbuild/darwin-arm64" "0.21.5" + "@esbuild/darwin-x64" "0.21.5" + "@esbuild/freebsd-arm64" "0.21.5" + "@esbuild/freebsd-x64" "0.21.5" + "@esbuild/linux-arm" "0.21.5" + "@esbuild/linux-arm64" "0.21.5" + "@esbuild/linux-ia32" "0.21.5" + "@esbuild/linux-loong64" "0.21.5" + "@esbuild/linux-mips64el" "0.21.5" + "@esbuild/linux-ppc64" "0.21.5" + "@esbuild/linux-riscv64" "0.21.5" + "@esbuild/linux-s390x" "0.21.5" + "@esbuild/linux-x64" "0.21.5" + "@esbuild/netbsd-x64" "0.21.5" + "@esbuild/openbsd-x64" "0.21.5" + "@esbuild/sunos-x64" "0.21.5" + "@esbuild/win32-arm64" "0.21.5" + "@esbuild/win32-ia32" "0.21.5" + "@esbuild/win32-x64" "0.21.5" escalade@^3.1.1: version "3.1.1" @@ -6421,11 +6179,6 @@ escape-goat@^2.0.0: resolved "https://registry.yarnpkg.com/escape-goat/-/escape-goat-2.1.1.tgz#1b2dc77003676c457ec760b2dc68edb648188675" integrity sha512-8/uIhbG12Csjy2JEW7D9pHbreaVaS/OpN3ycnyvElTdwM5n6GY6W6e2IPemfvGZeUMqZ9A/3GqIZMgKnBhAw/Q== -escape-html@~1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" - integrity sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow== - escape-string-regexp@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" @@ -6760,16 +6513,6 @@ esutils@^2.0.2: resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== -etag@~1.8.1: - version "1.8.1" - resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887" - integrity sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg== - -eventemitter3@^4.0.0: - version "4.0.7" - resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.7.tgz#2de9b68f6528d5644ef5c59526a1b4a07306169f" - integrity sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw== - events@^3.2.0, events@^3.3.0: version "3.3.0" resolved "https://registry.yarnpkg.com/events/-/events-3.3.0.tgz#31a95ad0a924e2d2c419a813aeb2c4e878ea7400" @@ -6826,43 +6569,6 @@ exponential-backoff@^3.1.1: resolved "https://registry.yarnpkg.com/exponential-backoff/-/exponential-backoff-3.1.1.tgz#64ac7526fe341ab18a39016cd22c787d01e00bf6" integrity sha512-dX7e/LHVJ6W3DE1MHWi9S1EYzDESENfLrYohG2G++ovZrYOkm4Knwa0mc1cn84xJOR4KEU0WSchhLbd0UklbHw== -express@^4.17.3: - version "4.18.2" - resolved "https://registry.yarnpkg.com/express/-/express-4.18.2.tgz#3fabe08296e930c796c19e3c516979386ba9fd59" - integrity sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ== - dependencies: - accepts "~1.3.8" - array-flatten "1.1.1" - body-parser "1.20.1" - content-disposition "0.5.4" - content-type "~1.0.4" - cookie "0.5.0" - cookie-signature "1.0.6" - debug "2.6.9" - depd "2.0.0" - encodeurl "~1.0.2" - escape-html "~1.0.3" - etag "~1.8.1" - finalhandler "1.2.0" - fresh "0.5.2" - http-errors "2.0.0" - merge-descriptors "1.0.1" - methods "~1.1.2" - on-finished "2.4.1" - parseurl "~1.3.3" - path-to-regexp "0.1.7" - proxy-addr "~2.0.7" - qs "6.11.0" - range-parser "~1.2.1" - safe-buffer "5.2.1" - send "0.18.0" - serve-static "1.15.0" - setprototypeof "1.2.0" - statuses "2.0.1" - type-is "~1.6.18" - utils-merge "1.0.1" - vary "~1.1.2" - ext-list@^2.0.0: version "2.2.2" resolved "https://registry.yarnpkg.com/ext-list/-/ext-list-2.2.2.tgz#0b98e64ed82f5acf0f2931babf69212ef52ddd37" @@ -6956,13 +6662,6 @@ fastq@^1.6.0: dependencies: reusify "^1.0.4" -faye-websocket@^0.11.3: - version "0.11.4" - resolved "https://registry.yarnpkg.com/faye-websocket/-/faye-websocket-0.11.4.tgz#7f0d9275cfdd86a1c963dc8b65fcc451edcbb1da" - integrity sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g== - dependencies: - websocket-driver ">=0.5.1" - fb-watchman@^2.0.0: version "2.0.2" resolved "https://registry.yarnpkg.com/fb-watchman/-/fb-watchman-2.0.2.tgz#e9524ee6b5c77e9e5001af0f85f3adbb8623255c" @@ -7039,19 +6738,6 @@ fill-range@^7.1.1: dependencies: to-regex-range "^5.0.1" -finalhandler@1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.2.0.tgz#7d23fe5731b207b4640e4fcd00aec1f9207a7b32" - integrity sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg== - dependencies: - debug "2.6.9" - encodeurl "~1.0.2" - escape-html "~1.0.3" - on-finished "2.4.1" - parseurl "~1.3.3" - statuses "2.0.1" - unpipe "~1.0.0" - find-root@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/find-root/-/find-root-1.1.0.tgz#abcfc8ba76f708c42a97b3d685b7e9450bfb9ce4" @@ -7112,7 +6798,7 @@ focus-lock@^0.9.2: dependencies: tslib "^2.0.3" -follow-redirects@^1.0.0, follow-redirects@^1.15.6: +follow-redirects@^1.15.6: version "1.15.6" resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.6.tgz#7f815c0cda4249c74ff09e95ef97c23b5fd0399b" integrity sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA== @@ -7168,16 +6854,6 @@ formik@^2.2.9: tiny-warning "^1.0.2" tslib "^1.10.0" -forwarded@0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.2.0.tgz#2269936428aad4c15c7ebe9779a84bf0b2a81811" - integrity sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow== - -fresh@0.5.2: - version "0.5.2" - resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7" - integrity sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q== - fs-extra@^10.0.0, fs-extra@^10.1.0: version "10.1.0" resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-10.1.0.tgz#02873cfbc4084dde127eaa5f9905eef2325d1abf" @@ -7359,7 +7035,7 @@ glob-to-regexp@^0.4.1: resolved "https://registry.yarnpkg.com/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz#c75297087c851b9a578bd217dd59a92f59fe546e" integrity sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw== -glob@^10.3.10, glob@^10.3.7: +glob@^10.3.10: version "10.4.2" resolved "https://registry.yarnpkg.com/glob/-/glob-10.4.2.tgz#bed6b95dade5c1f80b4434daced233aee76160e5" integrity sha512-GwMlUF6PkPo3Gk21UxkCohOv0PLcIXVtKyLlpEI28R/cO/4eNOdmLk3CMW1wROV/WR/EsZOWAfBbBOqYvs88/w== @@ -7540,11 +7216,6 @@ gzip-size@^6.0.0: dependencies: duplexer "^0.1.2" -handle-thing@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/handle-thing/-/handle-thing-2.0.1.tgz#857f79ce359580c340d43081cc648970d0bb234e" - integrity sha512-9Qn4yBxelxoh2Ow62nP+Ka/kMnOXRi8BXnRaUwezLNhqelnN49xKz4F/dPP8OYLxLxq6JDtZb2i9XznUQbNPTg== - harmony-reflect@^1.4.6: version "1.6.2" resolved "https://registry.yarnpkg.com/harmony-reflect/-/harmony-reflect-1.6.2.tgz#31ecbd32e648a34d030d86adb67d4d47547fe710" @@ -7831,16 +7502,6 @@ hotkeys-js@3.9.4: resolved "https://registry.yarnpkg.com/hotkeys-js/-/hotkeys-js-3.9.4.tgz#ce1aa4c3a132b6a63a9dd5644fc92b8a9b9cbfb9" integrity sha512-2zuLt85Ta+gIyvs4N88pCYskNrxf1TFv3LR9t5mdAZIX8BcgQQ48F2opUptvHa6m8zsy5v/a0i9mWzTrlNWU0Q== -hpack.js@^2.1.6: - version "2.1.6" - resolved "https://registry.yarnpkg.com/hpack.js/-/hpack.js-2.1.6.tgz#87774c0949e513f42e84575b3c45681fade2a0b2" - integrity sha512-zJxVehUdMGIKsRaNt7apO2Gqp0BdqW5yaiGHXXmbpvxgBYVZnAql+BJb4RO5ad2MgpbZKn5G6nMnegrH1FcNYQ== - dependencies: - inherits "^2.0.1" - obuf "^1.0.0" - readable-stream "^2.0.1" - wbuf "^1.1.0" - html-dom-parser@1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/html-dom-parser/-/html-dom-parser-1.2.0.tgz#8f689b835982ffbf245eda99730e92b8462c111e" @@ -7856,7 +7517,7 @@ html-encoding-sniffer@^3.0.0: dependencies: whatwg-encoding "^2.0.0" -html-entities@*, html-entities@^2.1.0, html-entities@^2.3.2, html-entities@^2.4.0: +html-entities@*, html-entities@^2.1.0, html-entities@^2.3.2: version "2.5.2" resolved "https://registry.yarnpkg.com/html-entities/-/html-entities-2.5.2.tgz#201a3cf95d3a15be7099521620d19dfb4f65359f" integrity sha512-K//PSRMQk4FZ78Kyau+mZurHn3FH0Vwr+H36eE0rPbeYkRRi9YxceYPhuN60UwWorxyKHhqoAJl2OFKa4BVtaA== @@ -7935,37 +7596,6 @@ http-cache-semantics@^4.0.0, http-cache-semantics@^4.1.0: resolved "https://registry.yarnpkg.com/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz#abe02fcb2985460bf0323be664436ec3476a6d5a" integrity sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ== -http-deceiver@^1.2.7: - version "1.2.7" - resolved "https://registry.yarnpkg.com/http-deceiver/-/http-deceiver-1.2.7.tgz#fa7168944ab9a519d337cb0bec7284dc3e723d87" - integrity sha512-LmpOGxTfbpgtGVxJrj5k7asXHCgNZp5nLfp+hWc8QQRqtb7fUy6kRY3BO1h9ddF6yIPYUARgxGOwB42DnxIaNw== - -http-errors@2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-2.0.0.tgz#b7774a1486ef73cf7667ac9ae0858c012c57b9d3" - integrity sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ== - dependencies: - depd "2.0.0" - inherits "2.0.4" - setprototypeof "1.2.0" - statuses "2.0.1" - toidentifier "1.0.1" - -http-errors@~1.6.2: - version "1.6.3" - resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.6.3.tgz#8b55680bb4be283a0b5bf4ea2e38580be1d9320d" - integrity sha512-lks+lVC8dgGyh97jxvxeYTWQFvh4uw4yC12gVl63Cg30sjPX4wuGcdkICVXDAESr6OJGjqGA8Iz5mkeN6zlD7A== - dependencies: - depd "~1.1.2" - inherits "2.0.3" - setprototypeof "1.1.0" - statuses ">= 1.4.0 < 2" - -http-parser-js@>=0.5.1: - version "0.5.8" - resolved "https://registry.yarnpkg.com/http-parser-js/-/http-parser-js-0.5.8.tgz#af23090d9ac4e24573de6f6aecc9d84a48bf20e3" - integrity sha512-SGeBX54F94Wgu5RH3X5jsDtf4eHyRogWX1XGT3b4HuW3tQPM4AaBzoUji/4AAJNXCEOWZ5O0DgZmJw1947gD5Q== - http-proxy-agent@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz#5129800203520d434f142bc78ff3c170800f2b43" @@ -7975,26 +7605,6 @@ http-proxy-agent@^5.0.0: agent-base "6" debug "4" -http-proxy-middleware@^2.0.3: - version "2.0.6" - resolved "https://registry.yarnpkg.com/http-proxy-middleware/-/http-proxy-middleware-2.0.6.tgz#e1a4dd6979572c7ab5a4e4b55095d1f32a74963f" - integrity sha512-ya/UeJ6HVBYxrgYotAZo1KvPWlgB48kUJLDePFeneHsVujFaW5WNj2NgWCAE//B1Dl02BIfYlpNgBy8Kf8Rjmw== - dependencies: - "@types/http-proxy" "^1.17.8" - http-proxy "^1.18.1" - is-glob "^4.0.1" - is-plain-obj "^3.0.0" - micromatch "^4.0.2" - -http-proxy@^1.18.1: - version "1.18.1" - resolved "https://registry.yarnpkg.com/http-proxy/-/http-proxy-1.18.1.tgz#401541f0534884bbf95260334e72f88ee3976549" - integrity sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ== - dependencies: - eventemitter3 "^4.0.0" - follow-redirects "^1.0.0" - requires-port "^1.0.0" - http2-wrapper@^1.0.0-beta.5.2: version "1.0.3" resolved "https://registry.yarnpkg.com/http2-wrapper/-/http2-wrapper-1.0.3.tgz#b8f55e0c1f25d4ebd08b3b0c2c079f9590800b3d" @@ -8044,13 +7654,6 @@ iconv-corefoundation@^1.1.7: cli-truncate "^2.1.0" node-addon-api "^1.6.3" -iconv-lite@0.4.24, iconv-lite@^0.4.24: - version "0.4.24" - resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" - integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== - dependencies: - safer-buffer ">= 2.1.2 < 3" - iconv-lite@0.6, iconv-lite@0.6.3, iconv-lite@^0.6.2: version "0.6.3" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.6.3.tgz#a52f80bf38da1952eb5c681790719871a1a72501" @@ -8058,6 +7661,13 @@ iconv-lite@0.6, iconv-lite@0.6.3, iconv-lite@^0.6.2: dependencies: safer-buffer ">= 2.1.2 < 3.0.0" +iconv-lite@^0.4.24: + version "0.4.24" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" + integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== + dependencies: + safer-buffer ">= 2.1.2 < 3" + icss-utils@^5.0.0, icss-utils@^5.1.0: version "5.1.0" resolved "https://registry.yarnpkg.com/icss-utils/-/icss-utils-5.1.0.tgz#c6be6858abd013d768e98366ae47e25d5887b1ae" @@ -8152,16 +7762,11 @@ inflight@^1.0.4: once "^1.3.0" wrappy "1" -inherits@2, inherits@2.0.4, inherits@^2.0.0, inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.1, inherits@~2.0.3: +inherits@2, inherits@^2.0.0, inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.1, inherits@~2.0.3: version "2.0.4" resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== -inherits@2.0.3: - version "2.0.3" - resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" - integrity sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw== - inline-style-parser@0.1.1: version "0.1.1" resolved "https://registry.yarnpkg.com/inline-style-parser/-/inline-style-parser-0.1.1.tgz#ec8a3b429274e9c0a1f1c4ffa9453a7fef72cea1" @@ -8237,16 +7842,6 @@ ip-address@^9.0.5: jsbn "1.1.0" sprintf-js "^1.1.3" -ipaddr.js@1.9.1: - version "1.9.1" - resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.1.tgz#bff38543eeb8984825079ff3a2a8e6cbd46781b3" - integrity sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g== - -ipaddr.js@^2.1.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-2.2.0.tgz#d33fa7bac284f4de7af949638c9d68157c6b92e8" - integrity sha512-Ag3wB2o37wslZS19hZqorUnrnzSkpOVy+IiiDEiTqNubEYpYuHWIf6K4psgN2ZWKExS4xhVCrRVfb/wfW8fWJA== - is-alphabetical@^1.0.0: version "1.0.4" resolved "https://registry.yarnpkg.com/is-alphabetical/-/is-alphabetical-1.0.4.tgz#9e7d6b94916be22153745d184c298cbf986a686d" @@ -8356,11 +7951,6 @@ is-docker@^2.0.0, is-docker@^2.1.1: resolved "https://registry.yarnpkg.com/is-docker/-/is-docker-2.2.1.tgz#33eeabe23cfe86f14bde4408a02c0cfb853acdaa" integrity sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ== -is-docker@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/is-docker/-/is-docker-3.0.0.tgz#90093aa3106277d8a77a5910dbae71747e15a200" - integrity sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ== - is-extglob@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" @@ -8400,13 +7990,6 @@ is-hexadecimal@^1.0.0: resolved "https://registry.yarnpkg.com/is-hexadecimal/-/is-hexadecimal-1.0.4.tgz#cc35c97588da4bd49a8eedd6bc4082d44dcb23a7" integrity sha512-gyPJuv83bHMpocVYoqof5VDiZveEoGoFL8m3BXNb2VW8Xs+rz9kqO8LOQ5DH6EsuvilT1ApazU0pyl+ytbPtlw== -is-inside-container@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-inside-container/-/is-inside-container-1.0.0.tgz#e81fba699662eb31dbdaf26766a61d4814717ea4" - integrity sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA== - dependencies: - is-docker "^3.0.0" - is-interactive@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/is-interactive/-/is-interactive-1.0.0.tgz#cea6e6ae5c870a7b0a0004070b7b587e0252912e" @@ -8435,11 +8018,6 @@ is-negative-zero@^2.0.3: resolved "https://registry.yarnpkg.com/is-negative-zero/-/is-negative-zero-2.0.3.tgz#ced903a027aca6381b777a5743069d7376a49747" integrity sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw== -is-network-error@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/is-network-error/-/is-network-error-1.1.0.tgz#d26a760e3770226d11c169052f266a4803d9c997" - integrity sha512-tUdRRAnhT+OtCZR/LxZelH/C7QtjtFrTu5tXCA8pl55eTUElUHT+GPYV8MBMBvea/j+NxQqVt3LbWMRir7Gx9g== - is-node-process@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/is-node-process/-/is-node-process-1.2.0.tgz#ea02a1b90ddb3934a19aea414e88edef7e11d134" @@ -8477,11 +8055,6 @@ is-plain-obj@^2.0.0: resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-2.1.0.tgz#45e42e37fccf1f40da8e5f76ee21515840c09287" integrity sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA== -is-plain-obj@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-3.0.0.tgz#af6f2ea14ac5a646183a5bbdb5baabbc156ad9d7" - integrity sha512-gwsOE28k+23GP1B6vFl1oVh/WOzmawBrKwo5Ev6wMKzPkaXaCDIQKzLnvsA42DRlbVTWorkgTKIviAKCWkfUwA== - is-plain-obj@^4.0.0: version "4.1.0" resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-4.1.0.tgz#d65025edec3657ce032fd7db63c97883eaed71f0" @@ -8592,13 +8165,6 @@ is-wsl@^2.1.1, is-wsl@^2.2.0: dependencies: is-docker "^2.0.0" -is-wsl@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-3.1.0.tgz#e1c657e39c10090afcbedec61720f6b924c3cbd2" - integrity sha512-UcVfVfaK4Sc4m7X3dUSoHoozQGBEFeDC+zVo06t98xe8CzHSZZBekNXH+tu0NalHolcJ/QAGqS46Hef7QXBIMw== - dependencies: - is-inside-container "^1.0.0" - isarray@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf" @@ -9395,14 +8961,6 @@ language-tags@^1.0.5: dependencies: language-subtag-registry "^0.3.20" -launch-editor@^2.6.1: - version "2.6.1" - resolved "https://registry.yarnpkg.com/launch-editor/-/launch-editor-2.6.1.tgz#f259c9ef95cbc9425620bbbd14b468fcdb4ffe3c" - integrity sha512-eB/uXmFVpY4zezmGp5XtU21kwo7GBbKB+EQ+UZeWtGb9yAM5xt/Evk+lYH3eRNAtId+ej4u7TYPFZ07w4s7rRw== - dependencies: - picocolors "^1.0.0" - shell-quote "^1.8.1" - lazy-val@^1.0.4, lazy-val@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/lazy-val/-/lazy-val-1.0.5.tgz#6cf3b9f5bc31cee7ee3e369c0832b7583dcd923d" @@ -9910,18 +9468,6 @@ mdurl@^1.0.0: resolved "https://registry.yarnpkg.com/mdurl/-/mdurl-1.0.1.tgz#fe85b2ec75a59037f2adfec100fd6c601761152e" integrity sha512-/sKlQJCBYVY9Ers9hqzKou4H6V5UWc/M59TH2dvkt+84itfnq7uFOMLpOiOS4ujvHP4etln18fmIxA5R5fll0g== -media-typer@0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" - integrity sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ== - -memfs@^4.6.0: - version "4.8.2" - resolved "https://registry.yarnpkg.com/memfs/-/memfs-4.8.2.tgz#9bb7c3e43647348451082557f05fb170b7442949" - integrity sha512-j4WKth315edViMBGkHW6NTF0QBjsTrcRDmYNcGsPq+ozMEyCCCIlX2d2mJ5wuh6iHvJ3FevUrr48v58YRqVdYg== - dependencies: - tslib "^2.0.0" - "memoize-one@>=3.1.1 <6", memoize-one@^5.1.1: version "5.2.1" resolved "https://registry.yarnpkg.com/memoize-one/-/memoize-one-5.2.1.tgz#8337aa3c4335581839ec01c3d594090cebe8f00e" @@ -9932,11 +9478,6 @@ memory-fs@^0.2.0: resolved "https://registry.yarnpkg.com/memory-fs/-/memory-fs-0.2.0.tgz#f2bb25368bc121e391c2520de92969caee0a0290" integrity sha512-+y4mDxU4rvXXu5UDSGCGNiesFmwCHuefGMoPCO1WYucNYj7DsLqrFaa2fXVI0H+NNiPTwwzKwspn9yTZqUGqng== -merge-descriptors@1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61" - integrity sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w== - merge-stream@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60" @@ -9947,7 +9488,7 @@ merge2@^1.3.0, merge2@^1.4.1: resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae" integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg== -methods@^1.1.1, methods@^1.1.2, methods@~1.1.2: +methods@^1.1.1, methods@^1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" integrity sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w== @@ -10235,19 +9776,19 @@ micromatch@^4.0.0, micromatch@^4.0.2, micromatch@^4.0.4: braces "^3.0.3" picomatch "^2.3.1" -mime-db@1.52.0, "mime-db@>= 1.43.0 < 2", mime-db@^1.28.0: +mime-db@1.52.0, mime-db@^1.28.0: version "1.52.0" resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70" integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg== -mime-types@^2.1.12, mime-types@^2.1.27, mime-types@^2.1.31, mime-types@~2.1.17, mime-types@~2.1.24, mime-types@~2.1.34: +mime-types@^2.1.12, mime-types@^2.1.27: version "2.1.35" resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a" integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw== dependencies: mime-db "1.52.0" -mime@1.6.0, mime@^1.4.1: +mime@^1.4.1: version "1.6.0" resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1" integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg== @@ -10289,11 +9830,6 @@ mini-css-extract-plugin@2.7.2: dependencies: schema-utils "^4.0.0" -minimalistic-assert@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz#2e194de044626d4a10e7f7fbc00ce73e83e4d5c7" - integrity sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A== - minimatch@^3.0.3, minimatch@^3.0.4, minimatch@^3.1.1, minimatch@^3.1.2: version "3.1.2" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" @@ -10463,17 +9999,12 @@ mrmime@^2.0.0: resolved "https://registry.yarnpkg.com/mrmime/-/mrmime-2.0.0.tgz#151082a6e06e59a9a39b46b3e14d5cfe92b3abb4" integrity sha512-eu38+hdgojoyq63s+yTpN4XMBdt5l8HhMhc4VKLO9KM5caLIBvUm4thi7fFaxyTmCKeNnXZ5pAlBwCUnhA09uw== -ms@2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" - integrity sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A== - ms@2.1.2: version "2.1.2" resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== -ms@2.1.3, ms@^2.0.0, ms@^2.1.1: +ms@^2.0.0, ms@^2.1.1: version "2.1.3" resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== @@ -10499,10 +10030,10 @@ msgpackr@^1.10.1: optionalDependencies: msgpackr-extract "^3.0.2" -msw@^1.3.2: - version "1.3.2" - resolved "https://registry.yarnpkg.com/msw/-/msw-1.3.2.tgz#35e0271293e893fc3c55116e90aad5d955c66899" - integrity sha512-wKLhFPR+NitYTkQl5047pia0reNGgf0P6a1eTnA5aNlripmiz0sabMvvHcicE8kQ3/gZcI0YiPFWmYfowfm3lA== +msw@^1.3.4: + version "1.3.4" + resolved "https://registry.yarnpkg.com/msw/-/msw-1.3.4.tgz#76ad0396a9c7fff07c6893ce4d3997787dc8fd55" + integrity sha512-XxA/VomMIYLlgpFS00eQanBWIAT9gto4wxrRt9y58WBXJs1I0lQYRIWk7nKcY/7X6DhkKukcDgPcyAvkEc1i7w== dependencies: "@mswjs/cookies" "^0.2.2" "@mswjs/interceptors" "^0.17.10" @@ -10524,14 +10055,6 @@ msw@^1.3.2: type-fest "^2.19.0" yargs "^17.3.1" -multicast-dns@^7.2.5: - version "7.2.5" - resolved "https://registry.yarnpkg.com/multicast-dns/-/multicast-dns-7.2.5.tgz#77eb46057f4d7adbd16d9290fa7299f6fa64cced" - integrity sha512-2eznPJP8z2BFLX50tf0LuODrpINqP1RVIm/CObbTcBRITQgmC/TjcREF1NeTBzIcR5XO/ukWo+YHOjBbFwIupg== - dependencies: - dns-packet "^5.2.2" - thunky "^1.0.2" - mute-stream@0.0.8: version "0.0.8" resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.8.tgz#1630c42b2251ff81e2a283de96a5497ea92e5e0d" @@ -10547,7 +10070,7 @@ natural-compare@^1.4.0: resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" integrity sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw== -negotiator@0.6.3, negotiator@^0.6.3: +negotiator@^0.6.3: version "0.6.3" resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.3.tgz#58e323a72fedc0d6f9cd4d31fe49f51479590ccd" integrity sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg== @@ -10598,11 +10121,6 @@ node-fetch@^2.6.7, node-fetch@^2.6.9: dependencies: whatwg-url "^5.0.0" -node-forge@^1: - version "1.3.1" - resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-1.3.1.tgz#be8da2af243b2417d5f646a770663a92b7e9ded3" - integrity sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA== - node-gyp-build-optional-packages@5.0.7: version "5.0.7" resolved "https://registry.yarnpkg.com/node-gyp-build-optional-packages/-/node-gyp-build-optional-packages-5.0.7.tgz#5d2632bbde0ab2f6e22f1bbac2199b07244ae0b3" @@ -10785,23 +10303,6 @@ object.values@^1.1.6: define-properties "^1.1.4" es-abstract "^1.20.4" -obuf@^1.0.0, obuf@^1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/obuf/-/obuf-1.1.2.tgz#09bea3343d41859ebd446292d11c9d4db619084e" - integrity sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg== - -on-finished@2.4.1, on-finished@^2.4.1: - version "2.4.1" - resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.4.1.tgz#58c8c44116e54845ad57f14ab10b03533184ac3f" - integrity sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg== - dependencies: - ee-first "1.1.1" - -on-headers@~1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/on-headers/-/on-headers-1.0.2.tgz#772b0ae6aaa525c399e489adfad90c403eb3c28f" - integrity sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA== - once@^1.3.0, once@^1.3.1, once@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" @@ -10816,16 +10317,6 @@ onetime@^5.1.0, onetime@^5.1.2: dependencies: mimic-fn "^2.1.0" -open@^10.0.3: - version "10.1.0" - resolved "https://registry.yarnpkg.com/open/-/open-10.1.0.tgz#a7795e6e5d519abe4286d9937bb24b51122598e1" - integrity sha512-mnkeQ1qP5Ue2wd+aivTD3NHd/lZ96Lu0jgf0pwktLPtx6cTZiH7tyeGRRHs0zX0rbrahXPnXlUnbeXyaBBuIaw== - dependencies: - default-browser "^5.2.1" - define-lazy-prop "^3.0.0" - is-inside-container "^1.0.0" - is-wsl "^3.1.0" - open@^7.4.2: version "7.4.2" resolved "https://registry.yarnpkg.com/open/-/open-7.4.2.tgz#b8147e26dcf3e426316c730089fd71edd29c2321" @@ -10957,15 +10448,6 @@ p-map@^4.0.0: dependencies: aggregate-error "^3.0.0" -p-retry@^6.2.0: - version "6.2.0" - resolved "https://registry.yarnpkg.com/p-retry/-/p-retry-6.2.0.tgz#8d6df01af298750009691ce2f9b3ad2d5968f3bd" - integrity sha512-JA6nkq6hKyWLLasXQXUrO4z8BUZGUt/LjlJxx8Gb2+2ntodU/SS63YZ8b0LUTbQ8ZB9iwOfhEPhg4ykKnn2KsA== - dependencies: - "@types/retry" "0.12.2" - is-network-error "^1.0.0" - retry "^0.13.1" - p-try@^2.0.0: version "2.2.0" resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" @@ -11040,11 +10522,6 @@ parse5@^7.0.0, parse5@^7.1.1: dependencies: entities "^4.4.0" -parseurl@~1.3.2, parseurl@~1.3.3: - version "1.3.3" - resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4" - integrity sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ== - pascal-case@^3.1.2: version "3.1.2" resolved "https://registry.yarnpkg.com/pascal-case/-/pascal-case-3.1.2.tgz#b48e0ef2b98e205e7c1dae747d0b1508237660eb" @@ -11112,11 +10589,6 @@ path-scurry@^1.11.1: lru-cache "^10.2.0" minipass "^5.0.0 || ^6.0.2 || ^7.0.0" -path-to-regexp@0.1.7: - version "0.1.7" - resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c" - integrity sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ== - path-to-regexp@^1.7.0: version "1.8.0" resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-1.8.0.tgz#887b3ba9d84393e87a0a0b9f4cb756198b53548a" @@ -11124,10 +10596,10 @@ path-to-regexp@^1.7.0: dependencies: isarray "0.0.1" -path-to-regexp@^6.2.0: - version "6.2.1" - resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-6.2.1.tgz#d54934d6798eb9e5ef14e7af7962c945906918e5" - integrity sha512-JLyh7xT1kizaEvcaXOQwOc2/Yhw6KZOvPf1S8401UyLk86CU79LN3vl7ztXGm/pZ+YjoyAJ4rxmHwbkBXJX+yw== +path-to-regexp@^6.2.0, path-to-regexp@^6.3.0: + version "6.3.0" + resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-6.3.0.tgz#2b6a26a337737a8e1416f9272ed0766b1c0389f4" + integrity sha512-Yhpw4T9C6hPpgPeA28us07OJeqZ5EzQTkbfwuhsUg0c237RomFoETJgmp2sa3F/41gfLE6G5cqcYwznmeEeOlQ== path-type@^4.0.0: version "4.0.0" @@ -11158,10 +10630,10 @@ pickleparser@^0.2.1: resolved "https://registry.yarnpkg.com/pickleparser/-/pickleparser-0.2.1.tgz#7a03f1e9204e91ec9b8efbd3ba2f1eb5955b994d" integrity sha512-kMzY3uFYcR6OjOqr7nV2nkaXaBsUEOafu3zgPxeD6s/2ueMfVQH8lrymcDWBPGx0OkVxGMikxQit6jgByXjwBg== -picocolors@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c" - integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ== +picocolors@^1.0.0, picocolors@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.1.0.tgz#5358b76a78cde483ba5cef6a9dc9671440b27d59" + integrity sha512-TQ92mBOW0l3LeMeyLV6mzy/kWr8lkd/hp3mTg7wYK7zJhuBStmGMBG0BdeDZS/dZx1IukaX6Bk11zcln25o1Aw== picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.2.3, picomatch@^2.3.1: version "2.3.1" @@ -11445,14 +10917,14 @@ postcss-value-parser@^4.1.0, postcss-value-parser@^4.2.0: resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz#723c09920836ba6d3e5af019f92bc0971c02e514" integrity sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ== -postcss@^8.2.15, postcss@^8.4.33, postcss@^8.4.38: - version "8.4.38" - resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.38.tgz#b387d533baf2054288e337066d81c6bee9db9e0e" - integrity sha512-Wglpdk03BSfXkHoQa3b/oulrotAkwrlLDRSOb9D0bN86FdRyE9lppSp33aHNPgBa0JKCoB+drFLZkQoRRYae5A== +postcss@^8.2.15, postcss@^8.4.33, postcss@^8.4.43: + version "8.4.47" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.47.tgz#5bf6c9a010f3e724c503bf03ef7947dcb0fea365" + integrity sha512-56rxCq7G/XfB4EkXq9Egn5GCqugWvDFjafDOThIdMBsI15iqPqR5r15TfSr1YPYeEI19YeaXMCbY6u88Y76GLQ== dependencies: nanoid "^3.3.7" - picocolors "^1.0.0" - source-map-js "^1.2.0" + picocolors "^1.1.0" + source-map-js "^1.2.1" postinstall-postinstall@^2.1.0: version "2.1.0" @@ -11575,14 +11047,6 @@ protobufjs@^6.10.2, protobufjs@^7.2.5: "@types/node" ">=13.7.0" long "^5.0.0" -proxy-addr@~2.0.7: - version "2.0.7" - resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.7.tgz#f19fe69ceab311eeb94b42e70e8c2070f9ba1025" - integrity sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg== - dependencies: - forwarded "0.2.0" - ipaddr.js "1.9.1" - proxy-from-env@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/proxy-from-env/-/proxy-from-env-1.1.0.tgz#e102f16ca355424865755d2c9e8ea4f24d58c3e2" @@ -11635,13 +11099,6 @@ pure-rand@^6.0.0: resolved "https://registry.yarnpkg.com/pure-rand/-/pure-rand-6.0.4.tgz#50b737f6a925468679bff00ad20eade53f37d5c7" integrity sha512-LA0Y9kxMYv47GIPJy6MI84fqTd2HmYZI83W/kM/SkKfDlajnZYfmXFTxkbY+xSBPkLJxltMa9hIkmdc29eguMA== -qs@6.11.0: - version "6.11.0" - resolved "https://registry.yarnpkg.com/qs/-/qs-6.11.0.tgz#fd0d963446f7a65e1367e01abd85429453f0c37a" - integrity sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q== - dependencies: - side-channel "^1.0.4" - qs@^6.5.1, qs@^6.7.0: version "6.11.2" resolved "https://registry.yarnpkg.com/qs/-/qs-6.11.2.tgz#64bea51f12c1f5da1bc01496f48ffcff7c69d7d9" @@ -11681,21 +11138,6 @@ randombytes@^2.1.0: dependencies: safe-buffer "^5.1.0" -range-parser@^1.2.1, range-parser@~1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031" - integrity sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg== - -raw-body@2.5.1: - version "2.5.1" - resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.5.1.tgz#fe1b1628b181b700215e5fd42389f98b71392857" - integrity sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig== - dependencies: - bytes "3.1.2" - http-errors "2.0.0" - iconv-lite "0.4.24" - unpipe "1.0.0" - rawproto@^0.7.6: version "0.7.6" resolved "https://registry.yarnpkg.com/rawproto/-/rawproto-0.7.6.tgz#82c272f6d8de7a20be433487fe84753527604c12" @@ -11925,7 +11367,7 @@ react-rnd@^10.3.5: react-draggable "4.4.5" tslib "2.3.1" -react-router-dom@^5.2.0: +react-router-dom@^5.3.4: version "5.3.4" resolved "https://registry.yarnpkg.com/react-router-dom/-/react-router-dom-5.3.4.tgz#2ed62ffd88cae6db134445f4a0c0ae8b91d2e5e6" integrity sha512-m4EqFMHv/Ih4kpcBCONHbkT68KoAeHN4p3lAGoNryfHi0dMy0kCzEZakiKRsvg5wHZ/JLrLW8o8KomWiz/qbYQ== @@ -12069,7 +11511,7 @@ read-pkg@^5.2.0: parse-json "^5.0.0" type-fest "^0.6.0" -readable-stream@^2.0.0, readable-stream@^2.0.1, readable-stream@^2.3.5, readable-stream@~2.3.6: +readable-stream@^2.0.0, readable-stream@^2.3.5, readable-stream@~2.3.6: version "2.3.8" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.8.tgz#91125e8042bba1b9887f49345f6277027ce8be9b" integrity sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA== @@ -12082,7 +11524,7 @@ readable-stream@^2.0.0, readable-stream@^2.0.1, readable-stream@^2.3.5, readable string_decoder "~1.1.1" util-deprecate "~1.0.1" -readable-stream@^3.0.6, readable-stream@^3.4.0, readable-stream@^3.6.0: +readable-stream@^3.4.0, readable-stream@^3.6.0: version "3.6.2" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.2.tgz#56a9b36ea965c00c5a93ef31eb111a0f11056967" integrity sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA== @@ -12433,11 +11875,6 @@ retry@^0.12.0: resolved "https://registry.yarnpkg.com/retry/-/retry-0.12.0.tgz#1b42a6266a21f07421d1b0b54b7dc167b01c013b" integrity sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow== -retry@^0.13.1: - version "0.13.1" - resolved "https://registry.yarnpkg.com/retry/-/retry-0.13.1.tgz#185b1587acf67919d63b357349e03537b2484658" - integrity sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg== - reusify@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76" @@ -12462,13 +11899,6 @@ rimraf@^3.0.2: dependencies: glob "^7.1.3" -rimraf@^5.0.5: - version "5.0.5" - resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-5.0.5.tgz#9be65d2d6e683447d2e9013da2bf451139a61ccf" - integrity sha512-CqDakW+hMe/Bz202FPEymy68P+G50RfMQK+Qo5YUqc9SPipvbGjCGKd0RSKEelbsfQuw3g5NZDSrlZZAJurH1A== - dependencies: - glob "^10.3.7" - roarr@^2.15.3: version "2.15.4" resolved "https://registry.yarnpkg.com/roarr/-/roarr-2.15.4.tgz#f5fe795b7b838ccfe35dc608e0282b9eba2e7afd" @@ -12496,36 +11926,31 @@ rollup-plugin-visualizer@^5.11.0: source-map "^0.7.4" yargs "^17.5.1" -rollup@^4.13.0: - version "4.16.1" - resolved "https://registry.yarnpkg.com/rollup/-/rollup-4.16.1.tgz#5a60230987fe95ebe68bab517297c116dbb1a88d" - integrity sha512-5CaD3MPDlPKfhqzRvWXK96G6ELJfPZNb3LHiZxTHgDdC6jvwfGz2E8nY+9g1ONk4ttHsK1WaFP19Js4PSr1E3g== +rollup@^4.20.0: + version "4.24.0" + resolved "https://registry.yarnpkg.com/rollup/-/rollup-4.24.0.tgz#c14a3576f20622ea6a5c9cad7caca5e6e9555d05" + integrity sha512-DOmrlGSXNk1DM0ljiQA+i+o0rSLhtii1je5wgk60j49d1jHT5YYttBv1iWOnYSTG+fZZESUOSNiAl89SIet+Cg== dependencies: - "@types/estree" "1.0.5" + "@types/estree" "1.0.6" optionalDependencies: - "@rollup/rollup-android-arm-eabi" "4.16.1" - "@rollup/rollup-android-arm64" "4.16.1" - "@rollup/rollup-darwin-arm64" "4.16.1" - "@rollup/rollup-darwin-x64" "4.16.1" - "@rollup/rollup-linux-arm-gnueabihf" "4.16.1" - "@rollup/rollup-linux-arm-musleabihf" "4.16.1" - "@rollup/rollup-linux-arm64-gnu" "4.16.1" - "@rollup/rollup-linux-arm64-musl" "4.16.1" - "@rollup/rollup-linux-powerpc64le-gnu" "4.16.1" - "@rollup/rollup-linux-riscv64-gnu" "4.16.1" - "@rollup/rollup-linux-s390x-gnu" "4.16.1" - "@rollup/rollup-linux-x64-gnu" "4.16.1" - "@rollup/rollup-linux-x64-musl" "4.16.1" - "@rollup/rollup-win32-arm64-msvc" "4.16.1" - "@rollup/rollup-win32-ia32-msvc" "4.16.1" - "@rollup/rollup-win32-x64-msvc" "4.16.1" + "@rollup/rollup-android-arm-eabi" "4.24.0" + "@rollup/rollup-android-arm64" "4.24.0" + "@rollup/rollup-darwin-arm64" "4.24.0" + "@rollup/rollup-darwin-x64" "4.24.0" + "@rollup/rollup-linux-arm-gnueabihf" "4.24.0" + "@rollup/rollup-linux-arm-musleabihf" "4.24.0" + "@rollup/rollup-linux-arm64-gnu" "4.24.0" + "@rollup/rollup-linux-arm64-musl" "4.24.0" + "@rollup/rollup-linux-powerpc64le-gnu" "4.24.0" + "@rollup/rollup-linux-riscv64-gnu" "4.24.0" + "@rollup/rollup-linux-s390x-gnu" "4.24.0" + "@rollup/rollup-linux-x64-gnu" "4.24.0" + "@rollup/rollup-linux-x64-musl" "4.24.0" + "@rollup/rollup-win32-arm64-msvc" "4.24.0" + "@rollup/rollup-win32-ia32-msvc" "4.24.0" + "@rollup/rollup-win32-x64-msvc" "4.24.0" fsevents "~2.3.2" -run-applescript@^7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/run-applescript/-/run-applescript-7.0.0.tgz#e5a553c2bffd620e169d276c1cd8f1b64778fbeb" - integrity sha512-9by4Ij99JUr/MCFBUkDKLWK3G9HVXmabKz9U5MlIAIuvuzkiOicRYs8XJLxX+xahD+mLiiCYDqF9dKAgtzKP1A== - run-async@^2.4.0: version "2.4.1" resolved "https://registry.yarnpkg.com/run-async/-/run-async-2.4.1.tgz#8440eccf99ea3e70bd409d49aab88e10c189a455" @@ -12543,7 +11968,7 @@ rw@1: resolved "https://registry.yarnpkg.com/rw/-/rw-1.3.3.tgz#3f862dfa91ab766b14885ef4d01124bfda074fb4" integrity sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ== -rxjs@^7.4.0, rxjs@^7.5.1, rxjs@^7.5.2, rxjs@^7.5.5, rxjs@^7.8.1: +rxjs@^7.4.0, rxjs@^7.5.1, rxjs@^7.5.5, rxjs@^7.8.1: version "7.8.1" resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-7.8.1.tgz#6f6f3d99ea8044291efd92e7c7fcf562c4057543" integrity sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg== @@ -12567,16 +11992,16 @@ safe-array-concat@^1.1.2: has-symbols "^1.0.3" isarray "^2.0.5" -safe-buffer@5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1: - version "5.1.2" - resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" - integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== - -safe-buffer@5.2.1, safe-buffer@>=5.1.0, safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@~5.2.0: +safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@~5.2.0: version "5.2.1" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== +safe-buffer@~5.1.0, safe-buffer@~5.1.1: + version "5.1.2" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" + integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== + safe-regex-test@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/safe-regex-test/-/safe-regex-test-1.0.3.tgz#a5b4c0f06e0ab50ea2c395c14d8371232924c377" @@ -12760,50 +12185,18 @@ schema-utils@^4.0.0, schema-utils@^4.2.0: ajv-formats "^2.1.1" ajv-keywords "^5.1.0" -select-hose@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/select-hose/-/select-hose-2.0.0.tgz#625d8658f865af43ec962bfc376a37359a4994ca" - integrity sha512-mEugaLK+YfkijB4fx0e6kImuJdCIt2LxCRcbEYPqRGCs4F2ogyfZU5IAZRdjCP8JPq2AtdNoC/Dux63d9Kiryg== - -selfsigned@^2.4.1: - version "2.4.1" - resolved "https://registry.yarnpkg.com/selfsigned/-/selfsigned-2.4.1.tgz#560d90565442a3ed35b674034cec4e95dceb4ae0" - integrity sha512-th5B4L2U+eGLq1TVh7zNRGBapioSORUeymIydxgFpwww9d2qyKvtuPU2jJuHvYAwwqi2Y596QBL3eEqcPEYL8Q== - dependencies: - "@types/node-forge" "^1.3.0" - node-forge "^1" - semver-compare@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/semver-compare/-/semver-compare-1.0.0.tgz#0dee216a1c941ab37e9efb1788f6afc5ff5537fc" integrity sha512-YM3/ITh2MJ5MtzaM429anh+x2jiLVjqILF4m4oyQB18W7Ggea7BfqdH/wGMK7dDiMghv/6WG7znWMwUDzJiXow== -"semver@2 || 3 || 4 || 5", semver@7.3.5, semver@7.x, semver@^5.5.0, semver@^5.7.2, semver@^6.2.0, semver@^6.3.0, semver@^6.3.1, semver@^7.2.1, semver@^7.3.2, semver@^7.3.4, semver@^7.3.5, semver@^7.3.7, semver@^7.3.8, semver@^7.5.2, semver@^7.5.3, semver@^7.5.4: +"semver@2 || 3 || 4 || 5", semver@7.3.5, semver@7.x, semver@^5.5.0, semver@^5.7.2, semver@^6.2.0, semver@^6.3.0, semver@^6.3.1, semver@^7.2.1, semver@^7.3.2, semver@^7.3.4, semver@^7.3.5, semver@^7.3.7, semver@^7.3.8, semver@^7.5.2, semver@^7.5.3, semver@^7.5.4, semver@^7.6.3: version "7.5.4" resolved "https://registry.yarnpkg.com/semver/-/semver-7.5.4.tgz#483986ec4ed38e1c6c48c34894a9182dbff68a6e" integrity sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA== dependencies: lru-cache "^6.0.0" -send@0.18.0: - version "0.18.0" - resolved "https://registry.yarnpkg.com/send/-/send-0.18.0.tgz#670167cc654b05f5aa4a767f9113bb371bc706be" - integrity sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg== - dependencies: - debug "2.6.9" - depd "2.0.0" - destroy "1.2.0" - encodeurl "~1.0.2" - escape-html "~1.0.3" - etag "~1.8.1" - fresh "0.5.2" - http-errors "2.0.0" - mime "1.6.0" - ms "2.1.3" - on-finished "2.4.1" - range-parser "~1.2.1" - statuses "2.0.1" - serialize-error@^7.0.1: version "7.0.1" resolved "https://registry.yarnpkg.com/serialize-error/-/serialize-error-7.0.1.tgz#f1360b0447f61ffb483ec4157c737fab7d778e18" @@ -12818,29 +12211,6 @@ serialize-javascript@^6.0.1, serialize-javascript@^6.0.2: dependencies: randombytes "^2.1.0" -serve-index@^1.9.1: - version "1.9.1" - resolved "https://registry.yarnpkg.com/serve-index/-/serve-index-1.9.1.tgz#d3768d69b1e7d82e5ce050fff5b453bea12a9239" - integrity sha512-pXHfKNP4qujrtteMrSBb0rc8HJ9Ms/GrXwcUtUtD5s4ewDJI8bT3Cz2zTVRMKtri49pLx2e0Ya8ziP5Ya2pZZw== - dependencies: - accepts "~1.3.4" - batch "0.6.1" - debug "2.6.9" - escape-html "~1.0.3" - http-errors "~1.6.2" - mime-types "~2.1.17" - parseurl "~1.3.2" - -serve-static@1.15.0: - version "1.15.0" - resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.15.0.tgz#faaef08cffe0a1a62f60cad0c4e513cff0ac9540" - integrity sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g== - dependencies: - encodeurl "~1.0.2" - escape-html "~1.0.3" - parseurl "~1.3.3" - send "0.18.0" - set-blocking@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" @@ -12878,16 +12248,6 @@ setimmediate@^1.0.5: resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285" integrity sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA== -setprototypeof@1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.1.0.tgz#d0bd85536887b6fe7c0d818cb962d9d91c54e656" - integrity sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ== - -setprototypeof@1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.2.0.tgz#66c9a24a73f9fc28cbe66b09fed3d33dcaf1b424" - integrity sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw== - shallow-clone@^3.0.0: version "3.0.1" resolved "https://registry.yarnpkg.com/shallow-clone/-/shallow-clone-3.0.1.tgz#8f2981ad92531f55035b01fb230769a40e02efa3" @@ -13028,15 +12388,6 @@ socket.io-parser@~4.2.4: "@socket.io/component-emitter" "~3.1.0" debug "~4.3.1" -sockjs@^0.3.24: - version "0.3.24" - resolved "https://registry.yarnpkg.com/sockjs/-/sockjs-0.3.24.tgz#c9bc8995f33a111bea0395ec30aa3206bdb5ccce" - integrity sha512-GJgLTZ7vYb/JtPSSZ10hsOYIvEYsjbNU+zPdIHcUaWVNUEPivzxku31865sSSud0Da0W4lEeOPlmw93zLQchuQ== - dependencies: - faye-websocket "^0.11.3" - uuid "^8.3.2" - websocket-driver "^0.7.4" - socks-proxy-agent@^7.0.0: version "7.0.0" resolved "https://registry.yarnpkg.com/socks-proxy-agent/-/socks-proxy-agent-7.0.0.tgz#dc069ecf34436621acb41e3efa66ca1b5fed15b6" @@ -13068,10 +12419,10 @@ sort-keys@^1.0.0: dependencies: is-plain-obj "^1.0.0" -source-map-js@^1.0.1, source-map-js@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.2.0.tgz#16b809c162517b5b8c3e7dcd315a2a5c2612b2af" - integrity sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg== +source-map-js@^1.0.1, source-map-js@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.2.1.tgz#1ce5650fddd87abc099eda37dcff024c2667ae46" + integrity sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA== source-map-support@0.5.13: version "0.5.13" @@ -13158,29 +12509,6 @@ spdx-satisfies@^4.0.0: spdx-expression-parse "^3.0.0" spdx-ranges "^2.0.0" -spdy-transport@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/spdy-transport/-/spdy-transport-3.0.0.tgz#00d4863a6400ad75df93361a1608605e5dcdcf31" - integrity sha512-hsLVFE5SjA6TCisWeJXFKniGGOpBgMLmerfO2aCyCU5s7nJ/rpAepqmFifv/GCbSbueEeAJJnmSQ2rKC/g8Fcw== - dependencies: - debug "^4.1.0" - detect-node "^2.0.4" - hpack.js "^2.1.6" - obuf "^1.1.2" - readable-stream "^3.0.6" - wbuf "^1.7.3" - -spdy@^4.0.2: - version "4.0.2" - resolved "https://registry.yarnpkg.com/spdy/-/spdy-4.0.2.tgz#b74f466203a3eda452c02492b91fb9e84a27677b" - integrity sha512-r46gZQZQV+Kl9oItvl1JZZqJKGr+oEkB08A6BzkiR7593/7IbtuncXHd2YoYeTsG4157ZssMu9KYvUHLcjcDoA== - dependencies: - debug "^4.1.0" - handle-thing "^2.0.0" - http-deceiver "^1.2.7" - select-hose "^2.0.0" - spdy-transport "^3.0.0" - sprintf-js@^1.1.1, sprintf-js@^1.1.2, sprintf-js@^1.1.3: version "1.1.3" resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.1.3.tgz#4914b903a2f8b685d17fdf78a70e917e872e444a" @@ -13232,16 +12560,6 @@ static-eval@2.0.2: dependencies: escodegen "^1.8.1" -statuses@2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/statuses/-/statuses-2.0.1.tgz#55cb000ccf1d48728bd23c685a063998cf1a1b63" - integrity sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ== - -"statuses@>= 1.4.0 < 2": - version "1.5.0" - resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c" - integrity sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA== - stop-iteration-iterator@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/stop-iteration-iterator/-/stop-iteration-iterator-1.0.0.tgz#6a60be0b4ee757d1ed5254858ec66b10c49285e4" @@ -13658,16 +12976,16 @@ through@^2.3.6, through@^2.3.8: resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" integrity sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg== -thunky@^1.0.2: - version "1.1.0" - resolved "https://registry.yarnpkg.com/thunky/-/thunky-1.1.0.tgz#5abaf714a9405db0504732bbccd2cedd9ef9537d" - integrity sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA== - tiny-invariant@^1.0.2, tiny-invariant@^1.0.6: version "1.3.1" resolved "https://registry.yarnpkg.com/tiny-invariant/-/tiny-invariant-1.3.1.tgz#8560808c916ef02ecfd55e66090df23a4b7aa642" integrity sha512-AD5ih2NlSssTCwsMznbvwMZpJ1cbhkGd2uueNxzv2jDlEeZdU04JQfRnggJQ8DrcVBGjAsCKwFBbDlVNtEMlzw== +tiny-typed-emitter@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/tiny-typed-emitter/-/tiny-typed-emitter-2.1.0.tgz#b3b027fdd389ff81a152c8e847ee2f5be9fad7b5" + integrity sha512-qVtvMxeXbVej0cQWKqVSSAHmKZEHAvxdF8HEUBFWts8h+xEo5m/lEiPakuyZ3BnCBjOD8i24kzNOiOLLgsSxhA== + tiny-warning@^1.0.0, tiny-warning@^1.0.2: version "1.0.3" resolved "https://registry.yarnpkg.com/tiny-warning/-/tiny-warning-1.0.3.tgz#94a30db453df4c643d0fd566060d60a875d84754" @@ -13709,11 +13027,6 @@ to-regex-range@^5.0.1: dependencies: is-number "^7.0.0" -toidentifier@1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.1.tgz#3be34321a88a820ed1bd80dfaa33e479fbb8dd35" - integrity sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA== - totalist@^3.0.0: version "3.0.1" resolved "https://registry.yarnpkg.com/totalist/-/totalist-3.0.1.tgz#ba3a3d600c915b1a97872348f79c127475f6acf8" @@ -13933,14 +13246,6 @@ type-fest@^2.17.0, type-fest@^2.19.0: resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-2.19.0.tgz#88068015bb33036a598b952e55e9311a60fd3a9b" integrity sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA== -type-is@~1.6.18: - version "1.6.18" - resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.18.tgz#4e552cd05df09467dcbc4ef739de89f2cf37c131" - integrity sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g== - dependencies: - media-typer "0.3.0" - mime-types "~2.1.24" - typed-array-buffer@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/typed-array-buffer/-/typed-array-buffer-1.0.2.tgz#1867c5d83b20fcb5ccf32649e5e2fc7424474ff3" @@ -13985,13 +13290,6 @@ typed-array-length@^1.0.6: is-typed-array "^1.1.13" possible-typed-array-names "^1.0.0" -typed-emitter@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/typed-emitter/-/typed-emitter-2.1.0.tgz#ca78e3d8ef1476f228f548d62e04e3d4d3fd77fb" - integrity sha512-g/KzbYKbH5C2vPkaXGu8DJlHrGKHLsM25Zg9WuC9pMGfuvT+X25tZQWo5fK1BjBm8+UrVE9LDCvaY0CQk+fXDA== - optionalDependencies: - rxjs "^7.5.2" - typescript@^4.0.5: version "4.9.5" resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.9.5.tgz#095979f9bcc0d09da324d58d03ce8f8374cbe65a" @@ -14220,11 +13518,6 @@ universalify@^2.0.0: resolved "https://registry.yarnpkg.com/universalify/-/universalify-2.0.0.tgz#75a4984efedc4b08975c5aeb73f530d02df25717" integrity sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ== -unpipe@1.0.0, unpipe@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" - integrity sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ== - untildify@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/untildify/-/untildify-4.0.0.tgz#2bc947b953652487e4600949fb091e3ae8cd919b" @@ -14335,11 +13628,6 @@ utila@~0.4: resolved "https://registry.yarnpkg.com/utila/-/utila-0.4.0.tgz#8a16a05d445657a3aea5eecc5b12a4fa5379772c" integrity sha512-Z0DbgELS9/L/75wZbro8xAnT50pBVFQZ+hUEueGDU5FN51YSCYM+jdxsfCiHjwNP/4LCDD0i/graKpeBnOXKRA== -utils-merge@1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" - integrity sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA== - uuid@^8.3.0, uuid@^8.3.2: version "8.3.2" resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2" @@ -14397,11 +13685,6 @@ varint@^6.0.0: resolved "https://registry.yarnpkg.com/varint/-/varint-6.0.0.tgz#9881eb0ce8feaea6512439d19ddf84bf551661d0" integrity sha512-cXEIW6cfr15lFv563k4GuVuW/fiwjknytD37jIOLSdSWuOI6WnO/oKwmP2FQTU2l01LP8/M5TSAJpzUaGe3uWg== -vary@~1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" - integrity sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg== - verror@^1.10.0: version "1.10.1" resolved "https://registry.yarnpkg.com/verror/-/verror-1.10.1.tgz#4bf09eeccf4563b109ed4b3d458380c972b0cdeb" @@ -14503,14 +13786,14 @@ vite-plugin-svgr@^4.2.0: "@svgr/core" "^8.1.0" "@svgr/plugin-jsx" "^8.1.0" -vite@^5.2.8: - version "5.2.10" - resolved "https://registry.yarnpkg.com/vite/-/vite-5.2.10.tgz#2ac927c91e99d51b376a5c73c0e4b059705f5bd7" - integrity sha512-PAzgUZbP7msvQvqdSD+ErD5qGnSFiGOoWmV5yAKUEI0kdhjbH6nMWVyZQC/hSc4aXwc0oJ9aEdIiF9Oje0JFCw== +vite@^5.4.9: + version "5.4.9" + resolved "https://registry.yarnpkg.com/vite/-/vite-5.4.9.tgz#215c80cbebfd09ccbb9ceb8c0621391c9abdc19c" + integrity sha512-20OVpJHh0PAM0oSOELa5GaZNWeDjcAvQjGXy2Uyr+Tp+/D2/Hdz6NLgpJLsarPTA2QJ6v8mX2P1ZfbsSKvdMkg== dependencies: - esbuild "^0.20.1" - postcss "^8.4.38" - rollup "^4.13.0" + esbuild "^0.21.3" + postcss "^8.4.43" + rollup "^4.20.0" optionalDependencies: fsevents "~2.3.3" @@ -14564,13 +13847,6 @@ watchpack@^2.4.1: glob-to-regexp "^0.4.1" graceful-fs "^4.1.2" -wbuf@^1.1.0, wbuf@^1.7.3: - version "1.7.3" - resolved "https://registry.yarnpkg.com/wbuf/-/wbuf-1.7.3.tgz#c1d8d149316d3ea852848895cb6a0bfe887b87df" - integrity sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA== - dependencies: - minimalistic-assert "^1.0.0" - wcwidth@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/wcwidth/-/wcwidth-1.0.1.tgz#f0b0dcf915bc5ff1528afadb2c0e17b532da2fe8" @@ -14644,54 +13920,6 @@ webpack-cli@^5.1.4: rechoir "^0.8.0" webpack-merge "^5.7.3" -webpack-dev-middleware@^7.1.0: - version "7.2.1" - resolved "https://registry.yarnpkg.com/webpack-dev-middleware/-/webpack-dev-middleware-7.2.1.tgz#2af00538b6e4eda05f5afdd5d711dbebc05958f7" - integrity sha512-hRLz+jPQXo999Nx9fXVdKlg/aehsw1ajA9skAneGmT03xwmyuhvF93p6HUKKbWhXdcERtGTzUCtIQr+2IQegrA== - dependencies: - colorette "^2.0.10" - memfs "^4.6.0" - mime-types "^2.1.31" - on-finished "^2.4.1" - range-parser "^1.2.1" - schema-utils "^4.0.0" - -webpack-dev-server@^5.0.4: - version "5.0.4" - resolved "https://registry.yarnpkg.com/webpack-dev-server/-/webpack-dev-server-5.0.4.tgz#cb6ea47ff796b9251ec49a94f24a425e12e3c9b8" - integrity sha512-dljXhUgx3HqKP2d8J/fUMvhxGhzjeNVarDLcbO/EWMSgRizDkxHQDZQaLFL5VJY9tRBj2Gz+rvCEYYvhbqPHNA== - dependencies: - "@types/bonjour" "^3.5.13" - "@types/connect-history-api-fallback" "^1.5.4" - "@types/express" "^4.17.21" - "@types/serve-index" "^1.9.4" - "@types/serve-static" "^1.15.5" - "@types/sockjs" "^0.3.36" - "@types/ws" "^8.5.10" - ansi-html-community "^0.0.8" - bonjour-service "^1.2.1" - chokidar "^3.6.0" - colorette "^2.0.10" - compression "^1.7.4" - connect-history-api-fallback "^2.0.0" - default-gateway "^6.0.3" - express "^4.17.3" - graceful-fs "^4.2.6" - html-entities "^2.4.0" - http-proxy-middleware "^2.0.3" - ipaddr.js "^2.1.0" - launch-editor "^2.6.1" - open "^10.0.3" - p-retry "^6.2.0" - rimraf "^5.0.5" - schema-utils "^4.2.0" - selfsigned "^2.4.1" - serve-index "^1.9.1" - sockjs "^0.3.24" - spdy "^4.0.2" - webpack-dev-middleware "^7.1.0" - ws "^8.16.0" - webpack-merge@^5.10.0, webpack-merge@^5.7.3: version "5.10.0" resolved "https://registry.yarnpkg.com/webpack-merge/-/webpack-merge-5.10.0.tgz#a3ad5d773241e9c682803abf628d4cd62b8a4177" @@ -14706,7 +13934,7 @@ webpack-sources@^3.2.3: resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-3.2.3.tgz#2d4daab8451fd4b240cc27055ff6a0c2ccea0cde" integrity sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w== -webpack@^5, webpack@^5.91.0: +webpack@^5.91.0: version "5.91.0" resolved "https://registry.yarnpkg.com/webpack/-/webpack-5.91.0.tgz#ffa92c1c618d18c878f06892bbdc3373c71a01d9" integrity sha512-rzVwlLeBWHJbmgTC/8TvAcu5vpJNII+MelQpylD4jNERPwpBJOE2lEcko1zJX3QJeLjTTAnQxn/OJ8bjDzVQaw== @@ -14736,20 +13964,6 @@ webpack@^5, webpack@^5.91.0: watchpack "^2.4.1" webpack-sources "^3.2.3" -websocket-driver@>=0.5.1, websocket-driver@^0.7.4: - version "0.7.4" - resolved "https://registry.yarnpkg.com/websocket-driver/-/websocket-driver-0.7.4.tgz#89ad5295bbf64b480abcba31e4953aca706f5760" - integrity sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg== - dependencies: - http-parser-js ">=0.5.1" - safe-buffer ">=5.1.0" - websocket-extensions ">=0.1.1" - -websocket-extensions@>=0.1.1: - version "0.1.4" - resolved "https://registry.yarnpkg.com/websocket-extensions/-/websocket-extensions-0.1.4.tgz#7f8473bc839dfd87608adb95d7eb075211578a42" - integrity sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg== - whatwg-encoding@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/whatwg-encoding/-/whatwg-encoding-2.0.0.tgz#e7635f597fd87020858626805a2729fa7698ac53" @@ -14879,12 +14093,12 @@ write-file-atomic@^4.0.2: imurmurhash "^0.1.4" signal-exit "^3.0.7" -ws@^7.3.1: - version "7.5.9" - resolved "https://registry.yarnpkg.com/ws/-/ws-7.5.9.tgz#54fa7db29f4c7cec68b1ddd3a89de099942bb591" - integrity sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q== +ws@^7.3.1, ws@^7.5.10: + version "7.5.10" + resolved "https://registry.yarnpkg.com/ws/-/ws-7.5.10.tgz#58b5c20dc281633f6c19113f39b349bd8bd558d9" + integrity sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ== -ws@^8.11.0, ws@^8.16.0, ws@~8.17.1: +ws@^8.11.0, ws@~8.17.1: version "8.17.1" resolved "https://registry.yarnpkg.com/ws/-/ws-8.17.1.tgz#9293da530bb548febc95371d90f9c878727d919b" integrity sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ== From 098f474e9c658dc22a7ca1f43218c799e322f14d Mon Sep 17 00:00:00 2001 From: vlad-dargel Date: Tue, 15 Oct 2024 17:04:58 +0200 Subject: [PATCH 173/256] update --- .../regression/search-and-query/search-and-query-tab.e2e.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tests/e2e/tests/web/regression/search-and-query/search-and-query-tab.e2e.ts b/tests/e2e/tests/web/regression/search-and-query/search-and-query-tab.e2e.ts index d01568a958..498a3c7c61 100644 --- a/tests/e2e/tests/web/regression/search-and-query/search-and-query-tab.e2e.ts +++ b/tests/e2e/tests/web/regression/search-and-query/search-and-query-tab.e2e.ts @@ -151,7 +151,7 @@ test('Verify full commands suggestions with index and query for FT.AGGREGATE', a await t.expect((await workbenchPage.queryInputForText.innerText).trim().replace(/\s+/g, ' ')).contains(expectedText, 'Incorrect order of entered arguments'); }); test('Verify full commands suggestions with index and query for FT.SEARCH', async t => { - await t.typeText(workbenchPage.queryInput, '', { replace: true }); + await t.typeText(workbenchPage.queryInput, 'FT.SEA', { replace: true }); // Select command and check result await t.pressKey('enter'); const script = await workbenchPage.queryInputScriptArea.textContent; @@ -341,7 +341,8 @@ test('Verify suggestions for fields', async t => { await t.pressKey('tab'); await t.expect((await workbenchPage.MonacoEditor.getTextFromMonaco()).trim()).eql(`FT.AGGREGATE '${indexName1}' '@students:[range] '`); }); -test +// Unskip after fixing https://redislabs.atlassian.net/browse/RI-6212 +test.skip .after(async() => { // Clear and delete database await apiKeyRequests.deleteKeyByNameApi(keyName, ossStandaloneConfig.databaseName); From 6c028595248c3f06aa0b862dfeb2334ce71a28f1 Mon Sep 17 00:00:00 2001 From: vlad-dargel Date: Tue, 15 Oct 2024 19:02:30 +0200 Subject: [PATCH 174/256] remove opening by keyboard --- .../regression/search-and-query/no-indexes-suggestions.e2e.ts | 1 - .../web/regression/search-and-query/search-and-query-tab.e2e.ts | 1 - 2 files changed, 2 deletions(-) diff --git a/tests/e2e/tests/web/regression/search-and-query/no-indexes-suggestions.e2e.ts b/tests/e2e/tests/web/regression/search-and-query/no-indexes-suggestions.e2e.ts index f8d39232be..ac2a27038c 100644 --- a/tests/e2e/tests/web/regression/search-and-query/no-indexes-suggestions.e2e.ts +++ b/tests/e2e/tests/web/regression/search-and-query/no-indexes-suggestions.e2e.ts @@ -24,7 +24,6 @@ test })('Verify suggestions when there are no indexes', async t => { await t.click(browserPage.NavigationPanel.workbenchButton); - await t.pressKey('ctrl+space'); await t.typeText(workbenchPage.queryInput, 'FT.SE', { replace: true }); await t.pressKey('tab'); diff --git a/tests/e2e/tests/web/regression/search-and-query/search-and-query-tab.e2e.ts b/tests/e2e/tests/web/regression/search-and-query/search-and-query-tab.e2e.ts index 498a3c7c61..2bbb08ab01 100644 --- a/tests/e2e/tests/web/regression/search-and-query/search-and-query-tab.e2e.ts +++ b/tests/e2e/tests/web/regression/search-and-query/search-and-query-tab.e2e.ts @@ -37,7 +37,6 @@ fixture `Autocomplete for entered commands in search and query` // Create 3 keys and index await browserPage.Cli.sendCommandsInCli(commands); await t.click(browserPage.NavigationPanel.workbenchButton); - await t.pressKey('ctrl+space'); }) .afterEach(async() => { // Clear and delete database From 66e26aa992a3dba4470a58d9cd4f51ada9a449b9 Mon Sep 17 00:00:00 2001 From: ArtemHoruzhenko Date: Wed, 16 Oct 2024 11:24:10 +0300 Subject: [PATCH 175/256] move to newest class-transformer and class-validator --- redisinsight/api/package.json | 4 +- .../api/src/__mocks__/browser-history.ts | 4 +- redisinsight/api/src/__mocks__/cloud-user.ts | 4 +- .../client-metadata.decorator.ts | 4 +- .../data-as-json-string.decorator.ts | 19 +-- .../api/src/common/decorators/default.ts | 2 +- .../decorators/hidden-field.decorator.ts | 2 +- .../decorators/object-as-map.decorator.ts | 56 +++++---- .../session/session-metadata.decorator.ts | 4 +- .../single-user-auth.middleware.ts | 6 +- .../any-to-redis-string.transformer.ts | 6 +- .../redis-string-to-ascii.transformer.ts | 6 +- .../redis-string-to-buffer.transformer.ts | 6 +- .../redis-string-to-utf8.transformer.ts | 6 +- .../api/src/dto/dto-transformer.spec.ts | 4 +- redisinsight/api/src/dto/dto-transformer.ts | 10 +- .../src/modules/ai/chat/ai-chat.service.ts | 6 +- .../src/modules/ai/query/ai-query.service.ts | 6 +- .../autodiscovery/autodiscovery.service.ts | 4 +- .../browser-history.service.ts | 4 +- .../local.browser-history.repository.ts | 4 +- .../src/modules/browser/hash/hash.service.ts | 8 +- .../modules/browser/keys/dto/get.keys.dto.ts | 2 +- .../src/modules/browser/keys/keys.service.ts | 12 +- .../src/modules/browser/list/list.service.ts | 12 +- .../browser/redisearch/redisearch.service.ts | 8 +- .../src/modules/browser/set/set.service.ts | 4 +- .../stream/services/consumer-group.service.ts | 6 +- .../stream/services/consumer.service.ts | 6 +- .../browser/stream/services/stream.service.ts | 8 +- .../modules/browser/string/string.service.ts | 4 +- .../modules/browser/z-set/z-set.service.ts | 10 +- .../auth/auth-strategy/cloud-auth.strategy.ts | 4 +- .../sso-idp.cloud.auth-strategy.ts | 4 +- .../cloud/capi-key/cloud-capi-key.service.ts | 4 +- .../common/decorators/cloud-auth.decorator.ts | 4 +- .../database/utils/cloud-data-converter.ts | 4 +- .../modules/cloud/job/cloud-job.gateway.ts | 4 +- .../src/modules/cloud/job/jobs/cloud-job.ts | 6 +- .../cloud/session/cloud-session.service.ts | 8 +- .../utils/cloud-data-converter.ts | 8 +- .../cloud/task/utils/cloud-data-converter.ts | 4 +- .../in-session.cloud-user.repository.ts | 10 +- .../cloud/user/utils/cloud-data-converter.ts | 4 +- .../strategies/abstract.info.strategy.ts | 4 +- .../custom-tutorial.service.ts | 6 +- .../custom-tutorial.manifest.provider.ts | 4 +- .../database-analysis.service.ts | 4 +- .../entities/database-analysis.entity.ts | 111 ++++++++++-------- .../database-analysis.provider.spec.ts | 4 +- .../providers/database-analysis.provider.ts | 6 +- .../database-import.service.ts | 6 +- .../dto/database-import.response.ts | 37 +++--- .../database-recommendation.service.ts | 4 +- .../database-recommendation.emitter.ts | 4 +- ...ocal.database.recommendation.repository.ts | 8 +- .../database/entities/database.entity.ts | 22 ++-- .../middleware/connection.middleware.ts | 4 +- .../feature/features-config.service.spec.ts | 6 +- .../feature/features-config.service.ts | 4 +- .../feature/model/features-config.spec.ts | 6 +- .../local.features-config.repository.spec.ts | 4 +- .../local.features-config.repository.ts | 6 +- .../feature-config-filter.transformer.ts | 6 +- .../notification/notification.service.ts | 6 +- .../providers/global-notification.provider.ts | 8 +- .../providers/notification.emitter.ts | 4 +- .../api/src/modules/plugin/plugin.service.ts | 6 +- .../src/modules/rdi/client/api.rdi.client.ts | 4 +- .../request.rdi.client.metadata.decorator.ts | 4 +- .../src/modules/rdi/utils/pipeline.util.ts | 4 +- .../providers/single-user.session.provider.ts | 4 +- .../modules/settings/settings.controller.ts | 6 - .../entities/command-execution.entity.ts | 30 +---- .../workbench/entities/plugin-state.entity.ts | 12 +- .../src/modules/workbench/plugins.service.ts | 4 +- .../local-command-execution.repository.ts | 4 +- .../local-plugin-state.repository.ts | 4 +- .../api/src/utils/class-transformer.ts | 13 +- redisinsight/api/yarn.lock | 46 ++++---- 80 files changed, 357 insertions(+), 369 deletions(-) diff --git a/redisinsight/api/package.json b/redisinsight/api/package.json index b89633e836..cf1871fbd0 100644 --- a/redisinsight/api/package.json +++ b/redisinsight/api/package.json @@ -63,8 +63,8 @@ "axios": "^1.7.4", "body-parser": "^1.20.3", "busboy": "^1.6.0", - "class-transformer": "^0.2.3", - "class-validator": "^0.14.0", + "class-transformer": "^0.5.1", + "class-validator": "^0.14.1", "combined-stream": "^1.0.8", "connect-timeout": "^1.9.0", "date-fns": "^2.29.3", diff --git a/redisinsight/api/src/__mocks__/browser-history.ts b/redisinsight/api/src/__mocks__/browser-history.ts index 6ea46029ce..f3017d69a2 100644 --- a/redisinsight/api/src/__mocks__/browser-history.ts +++ b/redisinsight/api/src/__mocks__/browser-history.ts @@ -1,4 +1,4 @@ -import { plainToClass } from 'class-transformer'; +import { plainToInstance } from 'class-transformer'; import { v4 as uuidv4 } from 'uuid'; import { mockDatabase, @@ -26,7 +26,7 @@ export const mockBrowserHistoryRepository = jest.fn(() => ({ export const mockCreateBrowserHistoryDto: CreateBrowserHistoryDto = { mode: BrowserHistoryMode.Pattern, - filter: plainToClass(ScanFilter, { + filter: plainToInstance(ScanFilter, { type: RedisDataType.String, match: 'key*', }), diff --git a/redisinsight/api/src/__mocks__/cloud-user.ts b/redisinsight/api/src/__mocks__/cloud-user.ts index 0effd6aadd..187abf9a19 100644 --- a/redisinsight/api/src/__mocks__/cloud-user.ts +++ b/redisinsight/api/src/__mocks__/cloud-user.ts @@ -7,7 +7,7 @@ import { ICloudCapiAccount, } from 'src/modules/cloud/user/models'; import config, { Config } from 'src/utils/config'; -import { classToPlain } from 'class-transformer'; +import { instanceToPlain } from 'class-transformer'; import { mockCloudApiCapiAccessKey, mockCloudCapiAuthDto, mockCloudCapiKey } from 'src/__mocks__/cloud-capi-key'; import { mockCloudApiAuthDto, mockCloudSession } from 'src/__mocks__/cloud-session'; @@ -102,7 +102,7 @@ export const mockCloudUser = Object.assign(new CloudUser(), { capiKey: mockCloudCapiKey, }); -export const mockCloudUserSafe = classToPlain(mockCloudUser); // omits all data in the "security" group +export const mockCloudUserSafe = instanceToPlain(mockCloudUser); // omits all data in the "security" group export const mockCloudApiAccount: ICloudApiAccount = { id: mockCloudCapiAccount.id, diff --git a/redisinsight/api/src/common/decorators/client-metadata/client-metadata.decorator.ts b/redisinsight/api/src/common/decorators/client-metadata/client-metadata.decorator.ts index 02c0beb8ee..ba32ea34a6 100644 --- a/redisinsight/api/src/common/decorators/client-metadata/client-metadata.decorator.ts +++ b/redisinsight/api/src/common/decorators/client-metadata/client-metadata.decorator.ts @@ -1,5 +1,5 @@ import { BadRequestException, createParamDecorator, ExecutionContext } from '@nestjs/common'; -import { plainToClass } from 'class-transformer'; +import { plainToInstance } from 'class-transformer'; import { ClientContext, ClientMetadata } from 'src/common/models'; import { Validator } from 'class-validator'; import { API_HEADER_DATABASE_INDEX, API_PARAM_DATABASE_ID } from 'src/common/constants'; @@ -31,7 +31,7 @@ export const clientMetadataParamFactory = ( uniqueId = req.params?.[options.uniqueIdParam]; } - const clientMetadata = plainToClass(ClientMetadata, { + const clientMetadata = plainToInstance(ClientMetadata, { sessionMetadata: sessionMetadataFromRequestExecutionContext(undefined, ctx), databaseId, uniqueId, diff --git a/redisinsight/api/src/common/decorators/data-as-json-string.decorator.ts b/redisinsight/api/src/common/decorators/data-as-json-string.decorator.ts index d55499c79d..029f10e611 100644 --- a/redisinsight/api/src/common/decorators/data-as-json-string.decorator.ts +++ b/redisinsight/api/src/common/decorators/data-as-json-string.decorator.ts @@ -3,13 +3,16 @@ import { Transform } from 'class-transformer'; export function DataAsJsonString() { return applyDecorators( - Transform((object) => JSON.stringify(object), { toClassOnly: true }), - Transform((string) => { - try { - return JSON.parse(string); - } catch (e) { - return undefined; - } - }, { toPlainOnly: true }), + Transform(({ value }) => JSON.stringify(value), { toClassOnly: true }), + Transform( + ({ value }) => { + try { + return JSON.parse(value); + } catch (e) { + return undefined; + } + }, + { toPlainOnly: true }, + ), ); } diff --git a/redisinsight/api/src/common/decorators/default.ts b/redisinsight/api/src/common/decorators/default.ts index 4e3b4cd6d9..418ff32ed2 100644 --- a/redisinsight/api/src/common/decorators/default.ts +++ b/redisinsight/api/src/common/decorators/default.ts @@ -2,5 +2,5 @@ import { Transform } from 'class-transformer'; import { cloneDeep } from 'lodash'; export function Default(defaultValue: unknown): PropertyDecorator { - return Transform((value: unknown) => value ?? cloneDeep(defaultValue)); + return Transform(({ value }) => value ?? cloneDeep(defaultValue)); } diff --git a/redisinsight/api/src/common/decorators/hidden-field.decorator.ts b/redisinsight/api/src/common/decorators/hidden-field.decorator.ts index 495124415c..542befbe51 100644 --- a/redisinsight/api/src/common/decorators/hidden-field.decorator.ts +++ b/redisinsight/api/src/common/decorators/hidden-field.decorator.ts @@ -1,7 +1,7 @@ import { Transform } from 'class-transformer'; export function HiddenField(field: any): PropertyDecorator { - return Transform((value: string) => (value ? field : undefined), { + return Transform(({ value }) => (value ? field : undefined), { toPlainOnly: true, }); } diff --git a/redisinsight/api/src/common/decorators/object-as-map.decorator.ts b/redisinsight/api/src/common/decorators/object-as-map.decorator.ts index 86ae6ecce4..212ef764e3 100644 --- a/redisinsight/api/src/common/decorators/object-as-map.decorator.ts +++ b/redisinsight/api/src/common/decorators/object-as-map.decorator.ts @@ -1,35 +1,41 @@ import { forEach } from 'lodash'; import { applyDecorators } from '@nestjs/common'; -import { classToPlain, plainToClass, Transform } from 'class-transformer'; -import { ClassType } from 'class-transformer/ClassTransformer'; +import { instanceToPlain, plainToInstance, Transform } from 'class-transformer'; +import { ClassConstructor } from 'class-transformer/types/interfaces'; -export function ObjectAsMap(targetClass: ClassType) { +export function ObjectAsMap(targetClass: ClassConstructor) { return applyDecorators( - Transform((object = {}): Map => { - const result = new Map(); + Transform( + ({ value: object }): Map => { + const result = new Map(); - try { - forEach(object, (value, key) => { - result.set(key, plainToClass(targetClass, value)); - }); + try { + forEach(object, (value, key) => { + result.set(key, plainToInstance(targetClass, value)); + }); - return result; - } catch (e) { - return result; - } - }, { toClassOnly: true }), - Transform((map): object => { - try { - const result = {}; + return result; + } catch (e) { + return result; + } + }, + { toClassOnly: true }, + ), + Transform( + ({ value: map }): object => { + try { + const result = {}; - forEach(Array.from(map), ([key, value]) => { - result[key] = classToPlain(value); - }); + forEach(Array.from(map), ([key, value]) => { + result[key] = instanceToPlain(value); + }); - return result; - } catch (e) { - return undefined; - } - }, { toPlainOnly: true }), + return result; + } catch (e) { + return undefined; + } + }, + { toPlainOnly: true }, + ), ); } diff --git a/redisinsight/api/src/common/decorators/session/session-metadata.decorator.ts b/redisinsight/api/src/common/decorators/session/session-metadata.decorator.ts index fd1b3476b0..5ed113e7bf 100644 --- a/redisinsight/api/src/common/decorators/session/session-metadata.decorator.ts +++ b/redisinsight/api/src/common/decorators/session/session-metadata.decorator.ts @@ -1,5 +1,5 @@ import { BadRequestException, createParamDecorator, ExecutionContext } from '@nestjs/common'; -import { plainToClass } from 'class-transformer'; +import { plainToInstance } from 'class-transformer'; import { Validator } from 'class-validator'; import { Request } from 'express'; import { SessionMetadata } from 'src/common/models'; @@ -16,7 +16,7 @@ export const sessionMetadataFromRequest = (request: Request): SessionMetadata => }; // todo: do not forget to deal with session vs sessionMetadata property - const session = plainToClass(SessionMetadata, requestSession); + const session = plainToInstance(SessionMetadata, requestSession); const errors = validator.validateSync(session, { whitelist: false, // we need this to allow additional fields if needed for flexibility diff --git a/redisinsight/api/src/common/middlewares/single-user-auth.middleware.ts b/redisinsight/api/src/common/middlewares/single-user-auth.middleware.ts index 28d3784223..a2dcc307f1 100644 --- a/redisinsight/api/src/common/middlewares/single-user-auth.middleware.ts +++ b/redisinsight/api/src/common/middlewares/single-user-auth.middleware.ts @@ -6,7 +6,7 @@ import { NextFunction, Request, Response } from 'express'; import { ISessionMetadata, Session, SessionMetadata } from 'src/common/models/session'; import { DEFAULT_SESSION_ID, DEFAULT_USER_ID } from 'src/common/constants'; import { SessionService } from 'src/modules/session/session.service'; -import { plainToClass } from 'class-transformer'; +import { plainToInstance } from 'class-transformer'; @Injectable() export class SingleUserAuthMiddleware implements NestMiddleware { @@ -16,7 +16,7 @@ export class SingleUserAuthMiddleware implements NestMiddleware { async use(req: Request, res: Response, next: NextFunction): Promise { if (!await this.sessionService.getSession(DEFAULT_SESSION_ID)) { - await this.sessionService.createSession(plainToClass(Session, { + await this.sessionService.createSession(plainToInstance(Session, { id: DEFAULT_SESSION_ID, userId: DEFAULT_USER_ID, data: { @@ -30,7 +30,7 @@ export class SingleUserAuthMiddleware implements NestMiddleware { } res.locals.session = { - data: Object.freeze(plainToClass(SessionMetadata, { + data: Object.freeze(plainToInstance(SessionMetadata, { userId: DEFAULT_USER_ID, sessionId: DEFAULT_SESSION_ID, })), diff --git a/redisinsight/api/src/common/transformers/redis-string/any-to-redis-string.transformer.ts b/redisinsight/api/src/common/transformers/redis-string/any-to-redis-string.transformer.ts index 3a2ef96af9..25f31ba348 100644 --- a/redisinsight/api/src/common/transformers/redis-string/any-to-redis-string.transformer.ts +++ b/redisinsight/api/src/common/transformers/redis-string/any-to-redis-string.transformer.ts @@ -3,7 +3,7 @@ import { isArray, isObject, isString } from 'lodash'; import { getBufferFromSafeASCIIString } from 'src/utils/cli-helper'; import { Transform } from 'class-transformer'; -const SingleToRedisStringTransformer = (value): RedisString => { +const SingleToRedisStringTransformer = ({ value }): RedisString => { if (value?.type === 'Buffer') { if (isArray(value.data)) { return Buffer.from(value); @@ -21,9 +21,9 @@ const SingleToRedisStringTransformer = (value): RedisString => { return value; }; -const ArrayToRedisStringTransformer = (value) => { +const ArrayToRedisStringTransformer = ({ value }) => { if (isArray(value)) { - return value.map(SingleToRedisStringTransformer); + return value.map((val) => SingleToRedisStringTransformer({ value: val })); } return value; diff --git a/redisinsight/api/src/common/transformers/redis-string/redis-string-to-ascii.transformer.ts b/redisinsight/api/src/common/transformers/redis-string/redis-string-to-ascii.transformer.ts index de8dba9280..88a2935a25 100644 --- a/redisinsight/api/src/common/transformers/redis-string/redis-string-to-ascii.transformer.ts +++ b/redisinsight/api/src/common/transformers/redis-string/redis-string-to-ascii.transformer.ts @@ -3,7 +3,7 @@ import { getASCIISafeStringFromBuffer } from 'src/utils/cli-helper'; import { RedisStringTransformOptions } from 'src/common/constants'; import { Transform } from 'class-transformer'; -const SingleRedisStringToASCII = (value: any) => { +const SingleRedisStringToASCII = ({ value }) => { if (value instanceof Buffer) { return getASCIISafeStringFromBuffer(value); } @@ -12,9 +12,9 @@ const SingleRedisStringToASCII = (value: any) => { return value; }; -const ArrayRedisStringToASCII = (value: any) => { +const ArrayRedisStringToASCII = ({ value }) => { if (isArray(value)) { - return value.map(SingleRedisStringToASCII); + return value.map((val) => SingleRedisStringToASCII({ value: val })); } return value; diff --git a/redisinsight/api/src/common/transformers/redis-string/redis-string-to-buffer.transformer.ts b/redisinsight/api/src/common/transformers/redis-string/redis-string-to-buffer.transformer.ts index a51b72824d..09961a9e47 100644 --- a/redisinsight/api/src/common/transformers/redis-string/redis-string-to-buffer.transformer.ts +++ b/redisinsight/api/src/common/transformers/redis-string/redis-string-to-buffer.transformer.ts @@ -2,7 +2,7 @@ import { isArray } from 'lodash'; import { RedisStringTransformOptions } from 'src/common/constants'; import { Transform } from 'class-transformer'; -const SingleRedisStringToBuffer = (value: any) => { +const SingleRedisStringToBuffer = ({ value }) => { if (value instanceof Buffer) { return value; } @@ -10,9 +10,9 @@ const SingleRedisStringToBuffer = (value: any) => { return Buffer.from(value); }; -const ArrayRedisStringToBuffer = (value: any) => { +const ArrayRedisStringToBuffer = ({ value }) => { if (isArray(value)) { - return value.map(SingleRedisStringToBuffer); + return value.map((val) => SingleRedisStringToBuffer({ value: val })); } return Buffer.from(value); diff --git a/redisinsight/api/src/common/transformers/redis-string/redis-string-to-utf8.transformer.ts b/redisinsight/api/src/common/transformers/redis-string/redis-string-to-utf8.transformer.ts index 3411fb767a..053dc03f97 100644 --- a/redisinsight/api/src/common/transformers/redis-string/redis-string-to-utf8.transformer.ts +++ b/redisinsight/api/src/common/transformers/redis-string/redis-string-to-utf8.transformer.ts @@ -2,7 +2,7 @@ import { isArray } from 'lodash'; import { RedisStringTransformOptions } from 'src/common/constants'; import { Transform } from 'class-transformer'; -const SingleRedisStringToUTF8 = (value: any) => { +const SingleRedisStringToUTF8 = ({ value }) => { if (value instanceof Buffer) { return value.toString('utf8'); } @@ -10,9 +10,9 @@ const SingleRedisStringToUTF8 = (value: any) => { return value; }; -const ArrayRedisStringToUTF8 = (value: any) => { +const ArrayRedisStringToUTF8 = ({ value }) => { if (isArray(value)) { - return value.map(SingleRedisStringToUTF8); + return value.map((val) => SingleRedisStringToUTF8({ value: val })); } return value; diff --git a/redisinsight/api/src/dto/dto-transformer.spec.ts b/redisinsight/api/src/dto/dto-transformer.spec.ts index f453c5c647..31d5cbd974 100644 --- a/redisinsight/api/src/dto/dto-transformer.spec.ts +++ b/redisinsight/api/src/dto/dto-transformer.spec.ts @@ -2,12 +2,12 @@ import { pickDefinedAgreements } from 'src/dto/dto-transformer'; describe('pickDefinedAgreements', () => { it('should pick only agreements that defined in specification', () => { - const input = new Map([ + const value = new Map([ ['eula', true], ['undefined', true], ]); - const output = pickDefinedAgreements(input); + const output = pickDefinedAgreements({ value }); expect(output).toEqual(new Map([['eula', true]])); }); diff --git a/redisinsight/api/src/dto/dto-transformer.ts b/redisinsight/api/src/dto/dto-transformer.ts index d92e18dcb1..86568256af 100644 --- a/redisinsight/api/src/dto/dto-transformer.ts +++ b/redisinsight/api/src/dto/dto-transformer.ts @@ -2,13 +2,13 @@ import { isMap } from 'lodash'; import * as AGREEMENTS_SPEC from 'src/constants/agreements-spec.json'; // Delete all keys from the validated Map that are not included in the settings specification. -export const pickDefinedAgreements = (data: Map) => { - if (isMap(data)) { - for (const k of data?.keys()) { +export const pickDefinedAgreements = ({ value }) => { + if (isMap(value)) { + for (const k of value?.keys()) { if (!AGREEMENTS_SPEC.agreements[k]) { - data.delete(k); + value.delete(k); } } } - return data; + return value; }; diff --git a/redisinsight/api/src/modules/ai/chat/ai-chat.service.ts b/redisinsight/api/src/modules/ai/chat/ai-chat.service.ts index 3d1802c54c..01142e64ca 100644 --- a/redisinsight/api/src/modules/ai/chat/ai-chat.service.ts +++ b/redisinsight/api/src/modules/ai/chat/ai-chat.service.ts @@ -1,7 +1,7 @@ import { Injectable } from '@nestjs/common'; import { SessionMetadata } from 'src/common/models'; import { ConvAiProvider } from 'src/modules/ai/chat/providers/conv-ai.provider'; -import { plainToClass } from 'class-transformer'; +import { plainToInstance } from 'class-transformer'; import { AiChat } from 'src/modules/ai/chat/models'; import { SendAiChatMessageDto } from 'src/modules/ai/chat/dto/send.ai-chat.message.dto'; @@ -14,7 +14,7 @@ export class AiChatService { async create(sessionMetadata: SessionMetadata): Promise> { const id = await this.convAiProvider.auth(sessionMetadata); - return plainToClass(AiChat, { id }); + return plainToInstance(AiChat, { id }); } async postMessage(sessionMetadata: SessionMetadata, chatId: string, dto: SendAiChatMessageDto) { @@ -22,7 +22,7 @@ export class AiChatService { } async getHistory(sessionMetadata: SessionMetadata, chatId: string): Promise { - return plainToClass(AiChat, { + return plainToInstance(AiChat, { id: chatId, messages: await this.convAiProvider.getHistory(sessionMetadata, chatId), }); diff --git a/redisinsight/api/src/modules/ai/query/ai-query.service.ts b/redisinsight/api/src/modules/ai/query/ai-query.service.ts index 9f43609677..bcd633d7b6 100644 --- a/redisinsight/api/src/modules/ai/query/ai-query.service.ts +++ b/redisinsight/api/src/modules/ai/query/ai-query.service.ts @@ -20,7 +20,7 @@ import { import { AiQueryMessageRepository } from 'src/modules/ai/query/repositories/ai-query.message.repository'; import { AiQueryAuthProvider } from 'src/modules/ai/query/providers/auth/ai-query-auth.provider'; import { classToClass, Config } from 'src/utils'; -import { plainToClass } from 'class-transformer'; +import { plainToInstance } from 'class-transformer'; import { AiQueryContextRepository } from 'src/modules/ai/query/repositories/ai-query.context.repository'; import config from 'src/utils/config'; @@ -197,14 +197,14 @@ export class AiQueryService { }); socket.on(AiQueryWsEvents.TOOL_CALL, async (data) => { - answer.steps.push(plainToClass(AiQueryIntermediateStep, { + answer.steps.push(plainToInstance(AiQueryIntermediateStep, { type: AiQueryIntermediateStepType.TOOL_CALL, data, })); }); socket.on(AiQueryWsEvents.TOOL_REPLY, async (data) => { - answer.steps.push(plainToClass(AiQueryIntermediateStep, { + answer.steps.push(plainToInstance(AiQueryIntermediateStep, { type: AiQueryIntermediateStepType.TOOL, data, })); diff --git a/redisinsight/api/src/modules/autodiscovery/autodiscovery.service.ts b/redisinsight/api/src/modules/autodiscovery/autodiscovery.service.ts index ebb17ad424..a9b21da163 100644 --- a/redisinsight/api/src/modules/autodiscovery/autodiscovery.service.ts +++ b/redisinsight/api/src/modules/autodiscovery/autodiscovery.service.ts @@ -8,7 +8,7 @@ import { Database } from 'src/modules/database/models/database'; import { DatabaseService } from 'src/modules/database/database.service'; import { ClientContext, ClientMetadata, SessionMetadata } from 'src/common/models'; import { RedisClientFactory } from 'src/modules/redis/redis.client.factory'; -import { plainToClass } from 'class-transformer'; +import { plainToInstance } from 'class-transformer'; import { ConstantsProvider } from 'src/modules/constants/providers/constants.provider'; const SERVER_CONFIG = config.get('server') as Config['server']; @@ -87,7 +87,7 @@ export class AutodiscoveryService implements OnModuleInit { context: ClientContext.Common, sessionMetadata, } as ClientMetadata, - plainToClass(Database, endpoint), + plainToInstance(Database, endpoint), { useRetry: false, connectionName: 'redisinsight-auto-discovery' }, ); diff --git a/redisinsight/api/src/modules/browser/browser-history/browser-history.service.ts b/redisinsight/api/src/modules/browser/browser-history/browser-history.service.ts index 6d400e6b89..893df82db2 100644 --- a/redisinsight/api/src/modules/browser/browser-history/browser-history.service.ts +++ b/redisinsight/api/src/modules/browser/browser-history/browser-history.service.ts @@ -1,7 +1,7 @@ import { HttpException, Injectable, Logger } from '@nestjs/common'; import { catchAclError } from 'src/utils'; import { sum } from 'lodash'; -import { plainToClass } from 'class-transformer'; +import { plainToInstance } from 'class-transformer'; import { ClientMetadata, SessionMetadata } from 'src/common/models'; import { BrowserHistoryMode } from 'src/common/constants'; import { @@ -29,7 +29,7 @@ export class BrowserHistoryService { dto: CreateBrowserHistoryDto, ): Promise { try { - const history = plainToClass(BrowserHistory, { ...dto, databaseId: clientMetadata.databaseId }); + const history = plainToInstance(BrowserHistory, { ...dto, databaseId: clientMetadata.databaseId }); return this.browserHistoryRepository.create(clientMetadata.sessionMetadata, history); } catch (e) { this.logger.error('Unable to create browser history item', e); diff --git a/redisinsight/api/src/modules/browser/browser-history/repositories/local.browser-history.repository.ts b/redisinsight/api/src/modules/browser/browser-history/repositories/local.browser-history.repository.ts index 950343674c..25c15243ee 100644 --- a/redisinsight/api/src/modules/browser/browser-history/repositories/local.browser-history.repository.ts +++ b/redisinsight/api/src/modules/browser/browser-history/repositories/local.browser-history.repository.ts @@ -4,7 +4,7 @@ import { import { InjectRepository } from '@nestjs/typeorm'; import { Repository } from 'typeorm'; import { EncryptionService } from 'src/modules/encryption/encryption.service'; -import { plainToClass } from 'class-transformer'; +import { plainToInstance } from 'class-transformer'; import { classToClass } from 'src/utils'; import config from 'src/utils/config'; import ERROR_MESSAGES from 'src/constants/error-messages'; @@ -38,7 +38,7 @@ export class LocalBrowserHistoryRepository extends BrowserHistoryRepository { * @param history */ async create(sessionMetadata: SessionMetadata, history: Partial): Promise { - const encryptedDto = await this.modelEncryptor.encryptEntity(plainToClass(BrowserHistoryEntity, history)); + const encryptedDto = await this.modelEncryptor.encryptEntity(plainToInstance(BrowserHistoryEntity, history)); const entity = await this.repository.save(encryptedDto); // cleanup history and ignore error if any diff --git a/redisinsight/api/src/modules/browser/hash/hash.service.ts b/redisinsight/api/src/modules/browser/hash/hash.service.ts index 0cf230089a..4941d4e4ae 100644 --- a/redisinsight/api/src/modules/browser/hash/hash.service.ts +++ b/redisinsight/api/src/modules/browser/hash/hash.service.ts @@ -10,7 +10,7 @@ import { RECOMMENDATION_NAMES, RedisErrorCodes } from 'src/constants'; import config, { Config } from 'src/utils/config'; import { ClientMetadata } from 'src/common/models'; import { BrowserToolHashCommands, BrowserToolKeysCommands } from 'src/modules/browser/constants/browser-tool-commands'; -import { plainToClass } from 'class-transformer'; +import { plainToInstance } from 'class-transformer'; import { DatabaseRecommendationService } from 'src/modules/database-recommendation/database-recommendation.service'; import { AddFieldsToHashDto, @@ -111,7 +111,7 @@ export class HashService { result.nextCursor = 0; const value = await client.sendCommand([BrowserToolHashCommands.HGet, keyName, field]); if (!isNull(value)) { - result.fields.push(plainToClass(HashFieldDto, { field, value })); + result.fields.push(plainToInstance(HashFieldDto, { field, value })); } } else { const scanResult = await this.scanHash(client, dto); @@ -144,7 +144,7 @@ export class HashService { ); this.logger.log('Succeed to get fields of the Hash data type.'); - return plainToClass(GetHashFieldsResponse, result); + return plainToInstance(GetHashFieldsResponse, result); } catch (error) { this.logger.error('Failed to get fields of the Hash data type.', error); if (error.message.includes(RedisErrorCodes.WrongType)) { @@ -278,7 +278,7 @@ export class HashService { const fields: HashFieldDto[] = chunk( fieldsArray, 2, - ).map(([field, value]: string[]) => plainToClass(HashFieldDto, { field, value })); + ).map(([field, value]: string[]) => plainToInstance(HashFieldDto, { field, value })); result = { ...result, nextCursor: parseInt(nextCursor, 10), diff --git a/redisinsight/api/src/modules/browser/keys/dto/get.keys.dto.ts b/redisinsight/api/src/modules/browser/keys/dto/get.keys.dto.ts index 316d2ff055..d51214981d 100644 --- a/redisinsight/api/src/modules/browser/keys/dto/get.keys.dto.ts +++ b/redisinsight/api/src/modules/browser/keys/dto/get.keys.dto.ts @@ -63,7 +63,7 @@ export class GetKeysDto { }) @IsBoolean() @IsOptional() - @Transform((val) => val === true || val === 'true') + @Transform(({ value }) => value === true || value === 'true') keysInfo?: boolean = true; @ApiPropertyOptional({ diff --git a/redisinsight/api/src/modules/browser/keys/keys.service.ts b/redisinsight/api/src/modules/browser/keys/keys.service.ts index a079c9459f..cb49d3653f 100644 --- a/redisinsight/api/src/modules/browser/keys/keys.service.ts +++ b/redisinsight/api/src/modules/browser/keys/keys.service.ts @@ -22,7 +22,7 @@ import { BrowserToolKeysCommands } from 'src/modules/browser/constants/browser-t import { ClientMetadata } from 'src/common/models'; import { Scanner } from 'src/modules/browser/keys/scanner/scanner'; import { BrowserHistoryMode, RedisString } from 'src/common/constants'; -import { plainToClass } from 'class-transformer'; +import { plainToInstance } from 'class-transformer'; import { DatabaseRecommendationService } from 'src/modules/database-recommendation/database-recommendation.service'; import { pick } from 'lodash'; import { BrowserHistoryService } from 'src/modules/browser/browser-history/browser-history.service'; @@ -58,7 +58,7 @@ export class KeysService { if (dto.match !== DEFAULT_MATCH) { await this.browserHistory.create( clientMetadata, - plainToClass( + plainToInstance( CreateBrowserHistoryDto, { filter: pick(dto, 'type', 'match'), mode: BrowserHistoryMode.Pattern }, ), @@ -71,7 +71,7 @@ export class KeysService { result[0]?.total, ); - return result.map((nodeResult) => plainToClass(GetKeysWithDetailsResponse, nodeResult)); + return result.map((nodeResult) => plainToInstance(GetKeysWithDetailsResponse, nodeResult)); } catch (error) { this.logger.error( `Failed to get keys with details info. ${error.message}.`, @@ -110,7 +110,7 @@ export class KeysService { { keys: result, client, databaseId: clientMetadata.databaseId }, ); - return plainToClass(GetKeyInfoResponse, result); + return plainToInstance(GetKeyInfoResponse, result); } catch (error) { this.logger.error(`Failed to get keys info: ${error.message}.`); throw catchAclError(error); @@ -159,7 +159,7 @@ export class KeysService { RECOMMENDATION_NAMES.COMPRESSION_FOR_LIST, result, ); - return plainToClass(GetKeyInfoResponse, result); + return plainToInstance(GetKeyInfoResponse, result); } catch (error) { this.logger.error('Failed to get key info.', error); throw catchAclError(error); @@ -222,7 +222,7 @@ export class KeysService { return Promise.reject(new BadRequestException(ERROR_MESSAGES.NEW_KEY_NAME_EXIST)); } this.logger.log('Succeed to rename key'); - return plainToClass(RenameKeyResponse, { keyName: newKeyName }); + return plainToInstance(RenameKeyResponse, { keyName: newKeyName }); } catch (error) { this.logger.error('Failed to rename key.', error); throw catchAclError(error); diff --git a/redisinsight/api/src/modules/browser/list/list.service.ts b/redisinsight/api/src/modules/browser/list/list.service.ts index 6f9b5f33e0..aec54e2672 100644 --- a/redisinsight/api/src/modules/browser/list/list.service.ts +++ b/redisinsight/api/src/modules/browser/list/list.service.ts @@ -27,7 +27,7 @@ import { BrowserToolKeysCommands, BrowserToolListCommands, } from 'src/modules/browser/constants/browser-tool-commands'; -import { plainToClass } from 'class-transformer'; +import { plainToInstance } from 'class-transformer'; import { DatabaseClientFactory } from 'src/modules/database/providers/database.client.factory'; import { RedisClient, RedisClientCommandReply } from 'src/modules/redis/client'; import { checkIfKeyExists, checkIfKeyNotExists } from 'src/modules/browser/utils'; @@ -85,7 +85,7 @@ export class ListService { } this.logger.log(`Succeed to insert element at the ${destination} of the list data type.`); - return plainToClass(PushListElementsResponse, { keyName, total }); + return plainToInstance(PushListElementsResponse, { keyName, total }); } catch (error) { this.logger.error('Failed to inserts element to the list data type.', error); if (error.message.includes(RedisErrorCodes.WrongType)) { @@ -118,7 +118,7 @@ export class ListService { ]); this.logger.log('Succeed to get elements of the list.'); - return plainToClass(GetListElementsResponse, { keyName, total, elements }); + return plainToInstance(GetListElementsResponse, { keyName, total, elements }); } catch (error) { this.logger.error('Failed to to get elements of the list.', error); if (error?.message.includes(RedisErrorCodes.WrongType)) { @@ -153,7 +153,7 @@ export class ListService { } this.logger.log('Succeed to get List element by index.'); - return plainToClass(GetListElementResponse, { keyName, value }); + return plainToInstance(GetListElementResponse, { keyName, value }); } catch (error) { this.logger.error('Failed to to get List element by index.', error); if (error?.message.includes(RedisErrorCodes.WrongType)) { @@ -176,7 +176,7 @@ export class ListService { await client.sendCommand([BrowserToolListCommands.LSet, keyName, index, element]); this.logger.log('Succeed to set the list element at index.'); - return plainToClass(SetListElementResponse, { index, element }); + return plainToInstance(SetListElementResponse, { index, element }); } catch (error) { if (error?.message.includes(RedisErrorCodes.WrongType)) { throw new BadRequestException(error.message); @@ -215,7 +215,7 @@ export class ListService { return Promise.reject(new NotFoundException(ERROR_MESSAGES.KEY_NOT_EXIST)); } - return plainToClass(DeleteListElementsResponse, { + return plainToInstance(DeleteListElementsResponse, { elements: isArray(result) ? [...result] : [result], }); } catch (error) { diff --git a/redisinsight/api/src/modules/browser/redisearch/redisearch.service.ts b/redisinsight/api/src/modules/browser/redisearch/redisearch.service.ts index 325b41b555..98ffd04e9a 100644 --- a/redisinsight/api/src/modules/browser/redisearch/redisearch.service.ts +++ b/redisinsight/api/src/modules/browser/redisearch/redisearch.service.ts @@ -16,7 +16,7 @@ import { } from 'src/modules/browser/redisearch/dto'; import { GetKeysWithDetailsResponse } from 'src/modules/browser/keys/dto'; import { DEFAULT_MATCH, RedisErrorCodes } from 'src/constants'; -import { plainToClass } from 'class-transformer'; +import { plainToInstance } from 'class-transformer'; import { numberWithSpaces } from 'src/utils/base.helper'; import { BrowserHistoryMode, RedisString } from 'src/common/constants'; import { CreateBrowserHistoryDto } from 'src/modules/browser/browser-history/dto'; @@ -55,7 +55,7 @@ export class RedisearchService { ['FT._LIST'], ))); - return plainToClass(ListRedisearchIndexesResponse, { + return plainToInstance(ListRedisearchIndexesResponse, { indexes: ( uniq( ([].concat(...res)).map((idx) => idx.toString('hex')), @@ -200,14 +200,14 @@ export class RedisearchService { if (query !== DEFAULT_MATCH) { await this.browserHistory.create( clientMetadata, - plainToClass( + plainToInstance( CreateBrowserHistoryDto, { filter: { match: query, type: null }, mode: BrowserHistoryMode.Redisearch }, ), ); } - return plainToClass(GetKeysWithDetailsResponse, { + return plainToInstance(GetKeysWithDetailsResponse, { cursor: limit + offset >= total ? 0 : limit + offset, total, scanned: keyNames.length + offset, diff --git a/redisinsight/api/src/modules/browser/set/set.service.ts b/redisinsight/api/src/modules/browser/set/set.service.ts index 10dddc66fd..9e59b5e7c3 100644 --- a/redisinsight/api/src/modules/browser/set/set.service.ts +++ b/redisinsight/api/src/modules/browser/set/set.service.ts @@ -16,7 +16,7 @@ import { BrowserToolKeysCommands, BrowserToolSetCommands, } from 'src/modules/browser/constants/browser-tool-commands'; -import { plainToClass } from 'class-transformer'; +import { plainToInstance } from 'class-transformer'; import { AddMembersToSetDto, CreateSetWithExpireDto, @@ -103,7 +103,7 @@ export class SetService { } this.logger.log('Succeed to get members of the Set data type.'); - return plainToClass(GetSetMembersResponse, result); + return plainToInstance(GetSetMembersResponse, result); } catch (error) { this.logger.error('Failed to get members of the Set data type.', error); if (error?.message.includes(RedisErrorCodes.WrongType)) { diff --git a/redisinsight/api/src/modules/browser/stream/services/consumer-group.service.ts b/redisinsight/api/src/modules/browser/stream/services/consumer-group.service.ts index f707cba066..05175a4e3b 100644 --- a/redisinsight/api/src/modules/browser/stream/services/consumer-group.service.ts +++ b/redisinsight/api/src/modules/browser/stream/services/consumer-group.service.ts @@ -20,7 +20,7 @@ import { DeleteConsumerGroupsResponse, UpdateConsumerGroupDto, } from 'src/modules/browser/stream/dto'; -import { plainToClass } from 'class-transformer'; +import { plainToInstance } from 'class-transformer'; import { RedisString } from 'src/common/constants'; import { ClientMetadata } from 'src/common/models'; import { DatabaseClientFactory } from 'src/modules/database/providers/database.client.factory'; @@ -91,7 +91,7 @@ export class ConsumerGroupService { group.name, ]); - return plainToClass(ConsumerGroupDto, { + return plainToInstance(ConsumerGroupDto, { ...group, smallestPendingId: info?.[1] || null, greatestPendingId: info?.[2] || null, @@ -277,7 +277,7 @@ export class ConsumerGroupService { const [,name,,consumers,,pending,,lastDeliveredId] = entry; - return plainToClass(ConsumerGroupDto, { + return plainToInstance(ConsumerGroupDto, { name, consumers, pending, diff --git a/redisinsight/api/src/modules/browser/stream/services/consumer.service.ts b/redisinsight/api/src/modules/browser/stream/services/consumer.service.ts index 9b75a0fe33..332d3d7ed5 100644 --- a/redisinsight/api/src/modules/browser/stream/services/consumer.service.ts +++ b/redisinsight/api/src/modules/browser/stream/services/consumer.service.ts @@ -22,7 +22,7 @@ import { GetPendingEntriesDto, PendingEntryDto, } from 'src/modules/browser/stream/dto'; -import { plainToClass } from 'class-transformer'; +import { plainToInstance } from 'class-transformer'; import { ClientMetadata } from 'src/common/models'; import { RedisClient } from 'src/modules/redis/client'; import { checkIfKeyNotExists } from 'src/modules/browser/utils'; @@ -304,7 +304,7 @@ export class ConsumerService { const [,name,,pending,,idle] = entry; - return plainToClass(ConsumerDto, { + return plainToInstance(ConsumerDto, { name, pending, idle, @@ -344,7 +344,7 @@ export class ConsumerService { return null; } - return plainToClass(PendingEntryDto, { + return plainToInstance(PendingEntryDto, { id: `${entry[0]}`, consumerName: entry[1], idle: +entry[2], diff --git a/redisinsight/api/src/modules/browser/stream/services/stream.service.ts b/redisinsight/api/src/modules/browser/stream/services/stream.service.ts index ed97dd04d5..a051d0a0ce 100644 --- a/redisinsight/api/src/modules/browser/stream/services/stream.service.ts +++ b/redisinsight/api/src/modules/browser/stream/services/stream.service.ts @@ -24,7 +24,7 @@ import { StreamEntryFieldDto, } from 'src/modules/browser/stream/dto'; import { RedisErrorCodes } from 'src/constants'; -import { plainToClass } from 'class-transformer'; +import { plainToInstance } from 'class-transformer'; import { ClientMetadata } from 'src/common/models'; import { DatabaseClientFactory } from 'src/modules/database/providers/database.client.factory'; import { RedisClient } from 'src/modules/redis/client'; @@ -70,7 +70,7 @@ export class StreamService { this.logger.log('Succeed to get entries from the stream.'); - return plainToClass(GetStreamEntriesResponse, { + return plainToInstance(GetStreamEntriesResponse, { keyName, total: info['length'], lastGeneratedId: info['last-generated-id'].toString(), @@ -240,7 +240,7 @@ export class StreamService { catchMultiTransactionError(transactionResults); this.logger.log('Succeed to add entries to the stream.'); - return plainToClass(AddStreamEntriesResponse, { + return plainToInstance(AddStreamEntriesResponse, { keyName, entries: transactionResults.map((entryResult) => entryResult[1].toString()), }); @@ -327,7 +327,7 @@ export class StreamService { return { id: entry[0].toString(), - fields: chunk(entry[1] || [], 2).map((field) => plainToClass( + fields: chunk(entry[1] || [], 2).map((field) => plainToInstance( StreamEntryFieldDto, { name: field[0], diff --git a/redisinsight/api/src/modules/browser/string/string.service.ts b/redisinsight/api/src/modules/browser/string/string.service.ts index 876f992316..e56807815a 100644 --- a/redisinsight/api/src/modules/browser/string/string.service.ts +++ b/redisinsight/api/src/modules/browser/string/string.service.ts @@ -15,7 +15,7 @@ import { BrowserToolKeysCommands, BrowserToolStringCommands, } from 'src/modules/browser/constants/browser-tool-commands'; -import { plainToClass } from 'class-transformer'; +import { plainToInstance } from 'class-transformer'; import { GetKeyInfoDto } from 'src/modules/browser/keys/dto'; import { ClientMetadata } from 'src/common/models'; import { DatabaseRecommendationService } from 'src/modules/database-recommendation/database-recommendation.service'; @@ -100,7 +100,7 @@ export class StringService { ); this.logger.log('Succeed to get string value.'); - return plainToClass(GetStringValueResponse, { value, keyName }); + return plainToInstance(GetStringValueResponse, { value, keyName }); } catch (error) { this.logger.error('Failed to get string value.', error); if (error.message.includes(RedisErrorCodes.WrongType)) { diff --git a/redisinsight/api/src/modules/browser/z-set/z-set.service.ts b/redisinsight/api/src/modules/browser/z-set/z-set.service.ts index 4387998a2a..b240f1951e 100644 --- a/redisinsight/api/src/modules/browser/z-set/z-set.service.ts +++ b/redisinsight/api/src/modules/browser/z-set/z-set.service.ts @@ -18,7 +18,7 @@ import { BrowserToolKeysCommands, BrowserToolZSetCommands, } from 'src/modules/browser/constants/browser-tool-commands'; -import { plainToClass } from 'class-transformer'; +import { plainToInstance } from 'class-transformer'; import { ClientMetadata } from 'src/common/models'; import { AddMembersToZSetDto, @@ -107,7 +107,7 @@ export class ZSetService { ); this.logger.log('Succeed to get members of the ZSet data type.'); - return plainToClass(GetZSetResponse, { + return plainToInstance(GetZSetResponse, { keyName, total, members, @@ -234,7 +234,7 @@ export class ZSetService { const formattedScore = isNaN(parseFloat(score)) ? String(score) : parseFloat(score); if (!isNull(score)) { - result.members.push(plainToClass(ZSetMemberDto, { name: member, score: formattedScore })); + result.members.push(plainToInstance(ZSetMemberDto, { name: member, score: formattedScore })); } } else { const scanResult = await this.scanZSet(client, dto); @@ -242,7 +242,7 @@ export class ZSetService { } this.logger.log('Succeed to search members of the ZSet data type.'); - return plainToClass(SearchZSetMembersResponse, result); + return plainToInstance(SearchZSetMembersResponse, result); } catch (error) { this.logger.error('Failed to search members of the ZSet data type.', error); if (error?.message.includes(RedisErrorCodes.WrongType)) { @@ -357,7 +357,7 @@ export class ZSetService { while (reply.length) { const member = reply.splice(0, 2); const score = isNaN(parseFloat(member[1])) ? String(member[1]) : parseFloat(member[1]); - result.push(plainToClass(ZSetMemberDto, { + result.push(plainToInstance(ZSetMemberDto, { name: member[0], score, })); diff --git a/redisinsight/api/src/modules/cloud/auth/auth-strategy/cloud-auth.strategy.ts b/redisinsight/api/src/modules/cloud/auth/auth-strategy/cloud-auth.strategy.ts index 4cf64f1182..fcf4c2db9c 100644 --- a/redisinsight/api/src/modules/cloud/auth/auth-strategy/cloud-auth.strategy.ts +++ b/redisinsight/api/src/modules/cloud/auth/auth-strategy/cloud-auth.strategy.ts @@ -2,7 +2,7 @@ import { Injectable } from '@nestjs/common'; import { CloudAuthRequest, CloudAuthRequestOptions } from 'src/modules/cloud/auth/models/cloud-auth-request'; import { SessionMetadata } from 'src/common/models'; import { OktaAuth } from '@okta/okta-auth-js'; -import { plainToClass } from 'class-transformer'; +import { plainToInstance } from 'class-transformer'; @Injectable() export abstract class CloudAuthStrategy { @@ -18,7 +18,7 @@ export abstract class CloudAuthStrategy { const authClient = new OktaAuth(this.config); const tokenParams = await authClient.token.prepareTokenParams(this.config); - return plainToClass(CloudAuthRequest, { + return plainToInstance(CloudAuthRequest, { ...this.config, ...tokenParams, sessionMetadata, diff --git a/redisinsight/api/src/modules/cloud/auth/auth-strategy/sso-idp.cloud.auth-strategy.ts b/redisinsight/api/src/modules/cloud/auth/auth-strategy/sso-idp.cloud.auth-strategy.ts index a2f0963394..50cf0b160a 100644 --- a/redisinsight/api/src/modules/cloud/auth/auth-strategy/sso-idp.cloud.auth-strategy.ts +++ b/redisinsight/api/src/modules/cloud/auth/auth-strategy/sso-idp.cloud.auth-strategy.ts @@ -7,7 +7,7 @@ import { CloudAuthRequestOptions, } from 'src/modules/cloud/auth/models/cloud-auth-request'; import { SessionMetadata } from 'src/common/models'; -import { plainToClass } from 'class-transformer'; +import { plainToInstance } from 'class-transformer'; import axios from 'axios'; import * as path from 'path'; import { @@ -67,7 +67,7 @@ export class SsoIdpCloudAuthStrategy extends CloudAuthStrategy { const authClient = new OktaAuth(this.config); const tokenParams = await authClient.token.prepareTokenParams(this.config); - return plainToClass(CloudAuthRequest, { + return plainToInstance(CloudAuthRequest, { ...this.config, ...tokenParams, idp, diff --git a/redisinsight/api/src/modules/cloud/capi-key/cloud-capi-key.service.ts b/redisinsight/api/src/modules/cloud/capi-key/cloud-capi-key.service.ts index bcd6c3d3d8..fe871962bb 100644 --- a/redisinsight/api/src/modules/cloud/capi-key/cloud-capi-key.service.ts +++ b/redisinsight/api/src/modules/cloud/capi-key/cloud-capi-key.service.ts @@ -9,7 +9,7 @@ import { CloudApiBadRequestException, CloudCapiUnauthorizedException } from 'src import { CloudSessionService } from 'src/modules/cloud/session/cloud-session.service'; import { CloudCapiKeyApiProvider } from 'src/modules/cloud/capi-key/cloud-capi-key.api.provider'; import { ServerService } from 'src/modules/server/server.service'; -import { plainToClass } from 'class-transformer'; +import { plainToInstance } from 'class-transformer'; import { CloudCapiKeyNotFoundException, CloudCapiKeyUnauthorizedException, @@ -83,7 +83,7 @@ export class CloudCapiKeyService { } as CloudCapiKey; capiKey.name = await this.generateName(capiKey); - capiKey = await this.repository.create(plainToClass(CloudCapiKey, capiKey)); + capiKey = await this.repository.create(plainToInstance(CloudCapiKey, capiKey)); this.analytics.sendCloudAccountKeyGenerated(); } catch (e) { diff --git a/redisinsight/api/src/modules/cloud/common/decorators/cloud-auth.decorator.ts b/redisinsight/api/src/modules/cloud/common/decorators/cloud-auth.decorator.ts index 916036ce74..a72bcd2000 100644 --- a/redisinsight/api/src/modules/cloud/common/decorators/cloud-auth.decorator.ts +++ b/redisinsight/api/src/modules/cloud/common/decorators/cloud-auth.decorator.ts @@ -1,6 +1,6 @@ import { createParamDecorator, ExecutionContext, UnauthorizedException } from '@nestjs/common'; import { Validator } from 'class-validator'; -import { plainToClass } from 'class-transformer'; +import { plainToInstance } from 'class-transformer'; import { CloudCapiAuthDto } from 'src/modules/cloud/common/dto'; const validator = new Validator(); @@ -8,7 +8,7 @@ const validator = new Validator(); export const cloudAuthDtoFromRequestHeadersFactory = (data: unknown, ctx: ExecutionContext): CloudCapiAuthDto => { const request = ctx.switchToHttp().getRequest(); - const dto = plainToClass(CloudCapiAuthDto, { + const dto = plainToInstance(CloudCapiAuthDto, { capiKey: request.headers['x-cloud-api-key'], capiSecret: request.headers['x-cloud-api-secret'], }); diff --git a/redisinsight/api/src/modules/cloud/database/utils/cloud-data-converter.ts b/redisinsight/api/src/modules/cloud/database/utils/cloud-data-converter.ts index e493abf851..5c24d7ee69 100644 --- a/redisinsight/api/src/modules/cloud/database/utils/cloud-data-converter.ts +++ b/redisinsight/api/src/modules/cloud/database/utils/cloud-data-converter.ts @@ -1,5 +1,5 @@ import { find, get, isArray } from 'lodash'; -import { plainToClass } from 'class-transformer'; +import { plainToInstance } from 'class-transformer'; import { CloudDatabase, CloudDatabaseMemoryStorage, CloudDatabasePersistencePolicy, CloudDatabaseProtocol, ICloudCapiDatabase, ICloudCapiSubscriptionDatabases, @@ -21,7 +21,7 @@ export const parseCloudDatabaseCapiResponse = ( databaseId, name, publicEndpoint, status, security, planMemoryLimit, memoryLimitMeasurementUnit, } = database; - return plainToClass(CloudDatabase, { + return plainToInstance(CloudDatabase, { subscriptionId, subscriptionType, databaseId, diff --git a/redisinsight/api/src/modules/cloud/job/cloud-job.gateway.ts b/redisinsight/api/src/modules/cloud/job/cloud-job.gateway.ts index 1d74ee8fba..90a44ffe59 100644 --- a/redisinsight/api/src/modules/cloud/job/cloud-job.gateway.ts +++ b/redisinsight/api/src/modules/cloud/job/cloud-job.gateway.ts @@ -14,7 +14,7 @@ import { CloudJobEvents } from 'src/modules/cloud/common/constants'; import { CloudJobService } from 'src/modules/cloud/job/cloud-job.service'; import { MonitorCloudJobDto } from 'src/modules/cloud/job/dto/monitor.cloud-job.dto'; import { Validator } from 'class-validator'; -import { plainToClass } from 'class-transformer'; +import { plainToInstance } from 'class-transformer'; import { CloudJobInfo } from 'src/modules/cloud/job/models'; import { SessionMetadata } from 'src/common/models'; import { WSSessionMetadata } from 'src/modules/auth/session-metadata/decorators/ws-session-metadata.decorator'; @@ -42,7 +42,7 @@ export class CloudJobGateway { @Body() data: MonitorCloudJobDto, ): Promise { try { - const dto = plainToClass(MonitorCloudJobDto, data); + const dto = plainToInstance(MonitorCloudJobDto, data); const errors = await this.validator.validate( dto, diff --git a/redisinsight/api/src/modules/cloud/job/jobs/cloud-job.ts b/redisinsight/api/src/modules/cloud/job/jobs/cloud-job.ts index 834c11575d..5eec99971e 100644 --- a/redisinsight/api/src/modules/cloud/job/jobs/cloud-job.ts +++ b/redisinsight/api/src/modules/cloud/job/jobs/cloud-job.ts @@ -2,13 +2,13 @@ import { v4 as uuidv4 } from 'uuid'; import config from 'src/utils/config'; import { CloudJobInfo, CloudJobStatus, CloudJobStep } from 'src/modules/cloud/job/models/cloud-job-info'; import { HttpException, Logger } from '@nestjs/common'; -import { ClassType } from 'class-transformer/ClassTransformer'; import { CloudJobAbortedException, wrapCloudJobError } from 'src/modules/cloud/job/exceptions'; import { SessionMetadata } from 'src/common/models'; import { CloudJobName } from 'src/modules/cloud/job/constants'; import { CloudRequestUtm } from 'src/modules/cloud/common/models'; import { debounce } from 'lodash'; import { CloudCapiAuthDto } from 'src/modules/cloud/common/dto'; +import { ClassConstructor } from 'class-transformer/types/interfaces'; const cloudConfig = config.get('cloud'); @@ -129,7 +129,7 @@ export abstract class CloudJob { }; } - public createChildJob(TargetJob: ClassType, data: {}, options = {}): T { + public createChildJob(TargetJob: ClassConstructor, data: {}, options = {}): T { return new TargetJob( { ...this.options, @@ -142,7 +142,7 @@ export abstract class CloudJob { ); } - public async runChildJob(TargetJob: ClassType, data: {}, options: CloudJobOptions): Promise { + public async runChildJob(TargetJob: ClassConstructor, data: {}, options: CloudJobOptions): Promise { const child = this.createChildJob(TargetJob, data, options); this.changeState({ child }); diff --git a/redisinsight/api/src/modules/cloud/session/cloud-session.service.ts b/redisinsight/api/src/modules/cloud/session/cloud-session.service.ts index 877eb8fb72..168d1ed5fc 100644 --- a/redisinsight/api/src/modules/cloud/session/cloud-session.service.ts +++ b/redisinsight/api/src/modules/cloud/session/cloud-session.service.ts @@ -1,7 +1,7 @@ import { Injectable } from '@nestjs/common'; import { SessionService } from 'src/modules/session/session.service'; import { CloudSession } from 'src/modules/cloud/session/models/cloud-session'; -import { classToPlain, plainToClass } from 'class-transformer'; +import { instanceToPlain, plainToInstance } from 'class-transformer'; import { TransformGroup } from 'src/common/constants'; @Injectable() @@ -19,9 +19,9 @@ export class CloudSessionService { const session = await this.getSession(id); return (await this.sessionService.updateSessionData(id, { - cloud: plainToClass(CloudSession, { - ...classToPlain(session, { groups: [TransformGroup.Secure] }), - ...classToPlain(cloud, { groups: [TransformGroup.Secure] }), + cloud: plainToInstance(CloudSession, { + ...instanceToPlain(session, { groups: [TransformGroup.Secure] }), + ...instanceToPlain(cloud, { groups: [TransformGroup.Secure] }), }, { groups: [TransformGroup.Secure] }), }))?.data?.cloud || null; } diff --git a/redisinsight/api/src/modules/cloud/subscription/utils/cloud-data-converter.ts b/redisinsight/api/src/modules/cloud/subscription/utils/cloud-data-converter.ts index a1938d8d32..0ad6f212a8 100644 --- a/redisinsight/api/src/modules/cloud/subscription/utils/cloud-data-converter.ts +++ b/redisinsight/api/src/modules/cloud/subscription/utils/cloud-data-converter.ts @@ -2,12 +2,12 @@ import { get, toNumber } from 'lodash'; import { CloudSubscription, CloudSubscriptionPlan, CloudSubscriptionRegion, CloudSubscriptionType, ICloudCapiSubscription, ICloudApiSubscriptionCloudRegion, ICloudCapiSubscriptionPlan, } from 'src/modules/cloud/subscription/models'; -import { plainToClass } from 'class-transformer'; +import { plainToInstance } from 'class-transformer'; export const parseCloudSubscriptionCapiResponse = ( subscription: ICloudCapiSubscription, type: CloudSubscriptionType, -): CloudSubscription => plainToClass(CloudSubscription, { +): CloudSubscription => plainToInstance(CloudSubscription, { id: subscription.id, type, name: subscription.name, @@ -45,7 +45,7 @@ export const parseCloudSubscriptionsPlansCapiResponse = ( const result: CloudSubscriptionPlan[] = []; if (plans?.length) { plans?.forEach?.((plan): void => { - result.push(plainToClass(CloudSubscriptionPlan, { + result.push(plainToInstance(CloudSubscriptionPlan, { id: plan.id, type, name: plan.name, @@ -65,7 +65,7 @@ export const parseCloudSubscriptionsCloudRegionsApiResponse = ( const result: CloudSubscriptionRegion[] = []; if (regions?.length) { regions?.forEach?.((plan): void => { - result.push(plainToClass(CloudSubscriptionRegion, { + result.push(plainToInstance(CloudSubscriptionRegion, { id: toNumber(plan.id), name: plan.name, cloud: plan.cloud, diff --git a/redisinsight/api/src/modules/cloud/task/utils/cloud-data-converter.ts b/redisinsight/api/src/modules/cloud/task/utils/cloud-data-converter.ts index b3f85d0d7f..b819659318 100644 --- a/redisinsight/api/src/modules/cloud/task/utils/cloud-data-converter.ts +++ b/redisinsight/api/src/modules/cloud/task/utils/cloud-data-converter.ts @@ -1,6 +1,6 @@ -import { plainToClass } from 'class-transformer'; +import { plainToInstance } from 'class-transformer'; import { CloudTask, ICloudCapiTask } from 'src/modules/cloud/task/models'; export const parseCloudTaskCapiResponse = ( task: ICloudCapiTask, -): CloudTask => plainToClass(CloudTask, task); +): CloudTask => plainToInstance(CloudTask, task); diff --git a/redisinsight/api/src/modules/cloud/user/repositories/in-session.cloud-user.repository.ts b/redisinsight/api/src/modules/cloud/user/repositories/in-session.cloud-user.repository.ts index 7a55be0ff4..4452873183 100644 --- a/redisinsight/api/src/modules/cloud/user/repositories/in-session.cloud-user.repository.ts +++ b/redisinsight/api/src/modules/cloud/user/repositories/in-session.cloud-user.repository.ts @@ -1,5 +1,5 @@ import { Injectable } from '@nestjs/common'; -import { classToPlain, plainToClass } from 'class-transformer'; +import { instanceToPlain, plainToInstance } from 'class-transformer'; import { CloudUserRepository } from 'src/modules/cloud/user/repositories/cloud-user.repository'; import { CloudUser } from 'src/modules/cloud/user/models'; import { CloudSessionService } from 'src/modules/cloud/session/cloud-session.service'; @@ -20,7 +20,7 @@ export class InSessionCloudUserRepository extends CloudUserRepository { async get(sessionId: string): Promise { const session = await this.sessionService.getSession(sessionId); - return plainToClass(CloudUser, session?.user, { groups: [TransformGroup.Secure] }) || null; + return plainToInstance(CloudUser, session?.user, { groups: [TransformGroup.Secure] }) || null; } /** @@ -31,9 +31,9 @@ export class InSessionCloudUserRepository extends CloudUserRepository { async update(sessionId: string, data: Partial): Promise { const user = await this.get(sessionId); await this.sessionService.updateSessionData(sessionId, { - user: plainToClass(CloudUser, { - ...classToPlain(user, { groups: [TransformGroup.Secure] }), - ...classToPlain(data, { groups: [TransformGroup.Secure] }), + user: plainToInstance(CloudUser, { + ...instanceToPlain(user, { groups: [TransformGroup.Secure] }), + ...instanceToPlain(data, { groups: [TransformGroup.Secure] }), }, { groups: [TransformGroup.Secure] }), }); diff --git a/redisinsight/api/src/modules/cloud/user/utils/cloud-data-converter.ts b/redisinsight/api/src/modules/cloud/user/utils/cloud-data-converter.ts index df507108f8..35d95a56c4 100644 --- a/redisinsight/api/src/modules/cloud/user/utils/cloud-data-converter.ts +++ b/redisinsight/api/src/modules/cloud/user/utils/cloud-data-converter.ts @@ -2,9 +2,9 @@ import { get } from 'lodash'; import { CloudAccountInfo, ICloudCapiAccount, } from 'src/modules/cloud/user/models'; -import { plainToClass } from 'class-transformer'; +import { plainToInstance } from 'class-transformer'; -export const parseCloudAccountCapiResponse = (account: ICloudCapiAccount): CloudAccountInfo => plainToClass( +export const parseCloudAccountCapiResponse = (account: ICloudCapiAccount): CloudAccountInfo => plainToInstance( CloudAccountInfo, { accountId: account.id, diff --git a/redisinsight/api/src/modules/cluster-monitor/strategies/abstract.info.strategy.ts b/redisinsight/api/src/modules/cluster-monitor/strategies/abstract.info.strategy.ts index ea395c341e..e0b667207d 100644 --- a/redisinsight/api/src/modules/cluster-monitor/strategies/abstract.info.strategy.ts +++ b/redisinsight/api/src/modules/cluster-monitor/strategies/abstract.info.strategy.ts @@ -2,7 +2,7 @@ import { IClusterInfo } from 'src/modules/cluster-monitor/strategies/cluster.inf import { convertRedisInfoReplyToObject, convertStringToNumber } from 'src/utils'; import { get, map, sum } from 'lodash'; import { ClusterDetails, ClusterNodeDetails } from 'src/modules/cluster-monitor/models'; -import { plainToClass } from 'class-transformer'; +import { plainToInstance } from 'class-transformer'; import { convertMultilineReplyToObject } from 'src/modules/redis/utils'; import { RedisClient } from 'src/modules/redis/client'; @@ -27,7 +27,7 @@ export abstract class AbstractInfoStrategy implements IClusterInfo { mode: get(nodes, '0.mode'), }; - return plainToClass(ClusterDetails, clusterDetails); + return plainToInstance(ClusterDetails, clusterDetails); } /** diff --git a/redisinsight/api/src/modules/custom-tutorial/custom-tutorial.service.ts b/redisinsight/api/src/modules/custom-tutorial/custom-tutorial.service.ts index e5367dfc96..e7d4373f01 100644 --- a/redisinsight/api/src/modules/custom-tutorial/custom-tutorial.service.ts +++ b/redisinsight/api/src/modules/custom-tutorial/custom-tutorial.service.ts @@ -6,7 +6,7 @@ import { v4 as uuidv4 } from 'uuid'; import { CustomTutorialRepository } from 'src/modules/custom-tutorial/repositories/custom-tutorial.repository'; import { CustomTutorial, CustomTutorialActions } from 'src/modules/custom-tutorial/models/custom-tutorial'; import { UploadCustomTutorialDto } from 'src/modules/custom-tutorial/dto/upload.custom-tutorial.dto'; -import { plainToClass } from 'class-transformer'; +import { plainToInstance } from 'class-transformer'; import ERROR_MESSAGES from 'src/constants/error-messages'; import { CustomTutorialFsProvider } from 'src/modules/custom-tutorial/providers/custom-tutorial.fs.provider'; import { @@ -51,7 +51,7 @@ export class CustomTutorialService { } const errors = await this.validator.validate( - plainToClass(RootCustomTutorialManifest, manifest), + plainToInstance(RootCustomTutorialManifest, manifest), { whitelist: true }, ); @@ -91,7 +91,7 @@ export class CustomTutorialService { await this.validateManifestJson(tmpPath); // create tutorial model - const model = plainToClass(CustomTutorial, { + const model = plainToInstance(CustomTutorial, { ...dto, id: uuidv4(), }); diff --git a/redisinsight/api/src/modules/custom-tutorial/providers/custom-tutorial.manifest.provider.ts b/redisinsight/api/src/modules/custom-tutorial/providers/custom-tutorial.manifest.provider.ts index 4ecc7fdd56..a90911caa9 100644 --- a/redisinsight/api/src/modules/custom-tutorial/providers/custom-tutorial.manifest.provider.ts +++ b/redisinsight/api/src/modules/custom-tutorial/providers/custom-tutorial.manifest.provider.ts @@ -8,7 +8,7 @@ import { CustomTutorialManifestType, RootCustomTutorialManifest, } from 'src/modules/custom-tutorial/models/custom-tutorial.manifest'; -import { plainToClass } from 'class-transformer'; +import { plainToInstance } from 'class-transformer'; import { winPathToNormalPath } from 'src/utils'; const MANIFEST_FILE = 'manifest.json'; @@ -134,7 +134,7 @@ export class CustomTutorialManifestProvider { return null; } - return plainToClass(RootCustomTutorialManifest, manifestJson, { excludeExtraneousValues: true }); + return plainToInstance(RootCustomTutorialManifest, manifestJson, { excludeExtraneousValues: true }); } catch (e) { this.logger.warn('Unable to get manifest for tutorial'); return null; diff --git a/redisinsight/api/src/modules/database-analysis/database-analysis.service.ts b/redisinsight/api/src/modules/database-analysis/database-analysis.service.ts index f81cc81645..ed38b8ec52 100644 --- a/redisinsight/api/src/modules/database-analysis/database-analysis.service.ts +++ b/redisinsight/api/src/modules/database-analysis/database-analysis.service.ts @@ -4,7 +4,7 @@ import { RecommendationService } from 'src/modules/recommendation/recommendation import { catchAclError } from 'src/utils'; import { ONE_NODE_RECOMMENDATIONS } from 'src/constants'; import { DatabaseAnalyzer } from 'src/modules/database-analysis/providers/database-analyzer'; -import { plainToClass } from 'class-transformer'; +import { plainToInstance } from 'class-transformer'; import { DatabaseAnalysis, ShortDatabaseAnalysis } from 'src/modules/database-analysis/models'; import { DatabaseAnalysisProvider } from 'src/modules/database-analysis/providers/database-analysis.provider'; import { CreateDatabaseAnalysisDto, RecommendationVoteDto } from 'src/modules/database-analysis/dto'; @@ -80,7 +80,7 @@ export class DatabaseAnalysisService { jobsArray.push(foundedRecommendations); return flatten(jobsArray); }, Promise.resolve([])); - const analysis = plainToClass(DatabaseAnalysis, await this.analyzer.analyze({ + const analysis = plainToInstance(DatabaseAnalysis, await this.analyzer.analyze({ databaseId: clientMetadata.databaseId, db: await client?.getCurrentDbIndex(), ...dto, diff --git a/redisinsight/api/src/modules/database-analysis/entities/database-analysis.entity.ts b/redisinsight/api/src/modules/database-analysis/entities/database-analysis.entity.ts index ad1cacc744..4605f5a7c8 100644 --- a/redisinsight/api/src/modules/database-analysis/entities/database-analysis.entity.ts +++ b/redisinsight/api/src/modules/database-analysis/entities/database-analysis.entity.ts @@ -17,13 +17,10 @@ export class DatabaseAnalysisEntity { @Expose() databaseId: string; - @ManyToOne( - () => DatabaseEntity, - { - nullable: false, - onDelete: 'CASCADE', - }, - ) + @ManyToOne(() => DatabaseEntity, { + nullable: false, + onDelete: 'CASCADE', + }) @JoinColumn({ name: 'databaseId' }) database: DatabaseEntity; @@ -52,62 +49,74 @@ export class DatabaseAnalysisEntity { totalMemory: string; @Column({ nullable: true, type: 'blob' }) - @Transform((object) => JSON.stringify(object), { toClassOnly: true }) - @Transform((str) => { - try { - return JSON.parse(str).map((value) => ({ - ...value, - nsp: Buffer.from(value.nsp), - })); - } catch (e) { - return undefined; - } - }, { toPlainOnly: true }) + @Transform(({ value }) => JSON.stringify(value), { toClassOnly: true }) + @Transform( + ({ value: str }) => { + try { + return JSON.parse(str).map((value) => ({ + ...value, + nsp: Buffer.from(value.nsp), + })); + } catch (e) { + return undefined; + } + }, + { toPlainOnly: true }, + ) @Expose() topKeysNsp: string; @Column({ nullable: true, type: 'blob' }) - @Transform((object) => JSON.stringify(object), { toClassOnly: true }) - @Transform((str) => { - try { - return JSON.parse(str).map((value) => ({ - ...value, - nsp: Buffer.from(value.nsp), - })); - } catch (e) { - return undefined; - } - }, { toPlainOnly: true }) + @Transform(({ value }) => JSON.stringify(value), { toClassOnly: true }) + @Transform( + ({ value: str }) => { + try { + return JSON.parse(str).map((value) => ({ + ...value, + nsp: Buffer.from(value.nsp), + })); + } catch (e) { + return undefined; + } + }, + { toPlainOnly: true }, + ) @Expose() topMemoryNsp: string; @Column({ nullable: true, type: 'blob' }) - @Transform((object) => JSON.stringify(object), { toClassOnly: true }) - @Transform((str) => { - try { - return JSON.parse(str).map((value) => ({ - ...value, - name: Buffer.from(value.name), - })); - } catch (e) { - return undefined; - } - }, { toPlainOnly: true }) + @Transform(({ value }) => JSON.stringify(value), { toClassOnly: true }) + @Transform( + ({ value: str }) => { + try { + return JSON.parse(str).map((value) => ({ + ...value, + name: Buffer.from(value.name), + })); + } catch (e) { + return undefined; + } + }, + { toPlainOnly: true }, + ) @Expose() topKeysLength: string; @Column({ nullable: true, type: 'blob' }) - @Transform((object) => JSON.stringify(object), { toClassOnly: true }) - @Transform((str) => { - try { - return JSON.parse(str).map((value) => ({ - ...value, - name: Buffer.from(value.name), - })); - } catch (e) { - return undefined; - } - }, { toPlainOnly: true }) + @Transform(({ value }) => JSON.stringify(value), { toClassOnly: true }) + @Transform( + ({ value: str }) => { + try { + return JSON.parse(str).map((value) => ({ + ...value, + name: Buffer.from(value.name), + })); + } catch (e) { + return undefined; + } + }, + { toPlainOnly: true }, + ) @Expose() topKeysMemory: string; diff --git a/redisinsight/api/src/modules/database-analysis/providers/database-analysis.provider.spec.ts b/redisinsight/api/src/modules/database-analysis/providers/database-analysis.provider.spec.ts index ef791fb78f..83717a89c5 100644 --- a/redisinsight/api/src/modules/database-analysis/providers/database-analysis.provider.spec.ts +++ b/redisinsight/api/src/modules/database-analysis/providers/database-analysis.provider.spec.ts @@ -15,7 +15,7 @@ import { DatabaseAnalysisProvider } from 'src/modules/database-analysis/provider import { DatabaseAnalysis } from 'src/modules/database-analysis/models'; import { CreateDatabaseAnalysisDto, RecommendationVoteDto } from 'src/modules/database-analysis/dto'; import { RedisDataType } from 'src/modules/browser/keys/dto'; -import { plainToClass } from 'class-transformer'; +import { plainToInstance } from 'class-transformer'; import { ScanFilter } from 'src/modules/database-analysis/models/scan-filter'; import { DatabaseAnalysisEntity } from 'src/modules/database-analysis/entities/database-analysis.entity'; import { NotFoundException } from '@nestjs/common'; @@ -24,7 +24,7 @@ import { KeytarDecryptionErrorException } from 'src/modules/encryption/exception export const mockCreateDatabaseAnalysisDto: CreateDatabaseAnalysisDto = { delimiter: ':', - filter: plainToClass(ScanFilter, { + filter: plainToInstance(ScanFilter, { type: RedisDataType.String, match: 'key*', count: 15, diff --git a/redisinsight/api/src/modules/database-analysis/providers/database-analysis.provider.ts b/redisinsight/api/src/modules/database-analysis/providers/database-analysis.provider.ts index de816747f6..a576a35bf4 100644 --- a/redisinsight/api/src/modules/database-analysis/providers/database-analysis.provider.ts +++ b/redisinsight/api/src/modules/database-analysis/providers/database-analysis.provider.ts @@ -4,7 +4,7 @@ import { isUndefined } from 'lodash'; import { InjectRepository } from '@nestjs/typeorm'; import { Repository } from 'typeorm'; import { EncryptionService } from 'src/modules/encryption/encryption.service'; -import { plainToClass } from 'class-transformer'; +import { plainToInstance } from 'class-transformer'; import { DatabaseAnalysis, ShortDatabaseAnalysis } from 'src/modules/database-analysis/models'; import { RecommendationVoteDto } from 'src/modules/database-analysis/dto'; import { classToClass } from 'src/utils'; @@ -43,7 +43,7 @@ export class DatabaseAnalysisProvider { */ async create(analysis: Partial): Promise { const entity = await this.repository.save( - await this.encryptEntity(plainToClass(DatabaseAnalysisEntity, analysis)), + await this.encryptEntity(plainToInstance(DatabaseAnalysisEntity, analysis)), ); // cleanup history and ignore error if any @@ -91,7 +91,7 @@ export class DatabaseAnalysisProvider { entity.recommendations = entity.recommendations.map((recommendation) => ( recommendation.name === name ? { ...recommendation, vote } : recommendation)); - await this.repository.update(id, await this.encryptEntity(plainToClass(DatabaseAnalysisEntity, entity))); + await this.repository.update(id, await this.encryptEntity(plainToInstance(DatabaseAnalysisEntity, entity))); return entity; } diff --git a/redisinsight/api/src/modules/database-import/database-import.service.ts b/redisinsight/api/src/modules/database-import/database-import.service.ts index ae75415f20..467a6f95bc 100644 --- a/redisinsight/api/src/modules/database-import/database-import.service.ts +++ b/redisinsight/api/src/modules/database-import/database-import.service.ts @@ -3,7 +3,7 @@ import { } from '@nestjs/common'; import { get, isArray, set } from 'lodash'; import { Database } from 'src/modules/database/models/database'; -import { plainToClass } from 'class-transformer'; +import { plainToInstance } from 'class-transformer'; import { ConnectionType, Compressor } from 'src/modules/database/entities/database.entity'; import { DatabaseRepository } from 'src/modules/database/repositories/database.repository'; import { @@ -123,7 +123,7 @@ export class DatabaseImportService { } })), Promise.resolve()); - response = plainToClass(DatabaseImportResponse, response); + response = plainToInstance(DatabaseImportResponse, response); this.analytics.sendImportResults(response); @@ -231,7 +231,7 @@ export class DatabaseImportService { errors.push(new InvalidCompressorException()); } - const dto = plainToClass( + const dto = plainToInstance( ImportDatabaseDto, // additionally replace empty strings ("") with null Object.keys(data) diff --git a/redisinsight/api/src/modules/database-import/dto/database-import.response.ts b/redisinsight/api/src/modules/database-import/dto/database-import.response.ts index 79f29f659b..e69facdbca 100644 --- a/redisinsight/api/src/modules/database-import/dto/database-import.response.ts +++ b/redisinsight/api/src/modules/database-import/dto/database-import.response.ts @@ -28,7 +28,7 @@ export class DatabaseImportResult { type: String, }) @Expose() - @Transform((v) => (isString(v) ? v : undefined), { toPlainOnly: true }) + @Transform(({ value }) => (isString(value) ? value : undefined), { toPlainOnly: true }) host?: string; @ApiPropertyOptional({ @@ -36,7 +36,7 @@ export class DatabaseImportResult { type: Number, }) @Expose() - @Transform((v) => (isNumber(v) ? v : undefined), { toPlainOnly: true }) + @Transform(({ value }) => (isNumber(value) ? value : undefined), { toPlainOnly: true }) port?: number; @ApiPropertyOptional({ @@ -44,23 +44,26 @@ export class DatabaseImportResult { type: String, }) @Expose() - @Transform((e) => { - if (!e) { - return undefined; - } - - return e.map((error) => { - if (error?.response) { - return error.response; + @Transform( + ({ value: e }) => { + if (!e) { + return undefined; } - return { - statusCode: 500, - message: error?.message || 'Unhandled Error', - error: 'Unhandled Error', - }; - }); - }, { toPlainOnly: true }) + return e.map((error) => { + if (error?.response) { + return error.response; + } + + return { + statusCode: 500, + message: error?.message || 'Unhandled Error', + error: 'Unhandled Error', + }; + }); + }, + { toPlainOnly: true }, + ) errors?: Error[]; } diff --git a/redisinsight/api/src/modules/database-recommendation/database-recommendation.service.ts b/redisinsight/api/src/modules/database-recommendation/database-recommendation.service.ts index 6ee9397395..5a494f96ee 100644 --- a/redisinsight/api/src/modules/database-recommendation/database-recommendation.service.ts +++ b/redisinsight/api/src/modules/database-recommendation/database-recommendation.service.ts @@ -1,6 +1,6 @@ import { Injectable, Logger } from '@nestjs/common'; import { sum } from 'lodash'; -import { plainToClass } from 'class-transformer'; +import { plainToInstance } from 'class-transformer'; import { DatabaseRecommendationRepository } from 'src/modules/database-recommendation/repositories/database-recommendation.repository'; import { DatabaseRecommendation } from 'src/modules/database-recommendation/models'; @@ -78,7 +78,7 @@ export class DatabaseRecommendationService { const recommendation = await this.scanner.determineRecommendation(recommendationName, data); if (recommendation) { - const entity = plainToClass( + const entity = plainToInstance( DatabaseRecommendation, { databaseId: newClientMetadata?.databaseId, ...recommendation }, ); diff --git a/redisinsight/api/src/modules/database-recommendation/providers/database-recommendation.emitter.ts b/redisinsight/api/src/modules/database-recommendation/providers/database-recommendation.emitter.ts index 87f677e712..18a1a288a1 100644 --- a/redisinsight/api/src/modules/database-recommendation/providers/database-recommendation.emitter.ts +++ b/redisinsight/api/src/modules/database-recommendation/providers/database-recommendation.emitter.ts @@ -1,6 +1,6 @@ import { Injectable, Logger } from '@nestjs/common'; import { EventEmitter2, OnEvent } from '@nestjs/event-emitter'; -import { plainToClass } from 'class-transformer'; +import { plainToInstance } from 'class-transformer'; import { ClientMetadata } from 'src/common/models'; import { RecommendationEvents, RecommendationServerEvents } from 'src/modules/database-recommendation/constants'; import { @@ -35,7 +35,7 @@ export class DatabaseRecommendationEmitter { this.eventEmitter.emit( RecommendationServerEvents.Recommendation, recommendations[0].databaseId, - plainToClass( + plainToInstance( DatabaseRecommendationsResponse, { totalUnread, diff --git a/redisinsight/api/src/modules/database-recommendation/repositories/local.database.recommendation.repository.ts b/redisinsight/api/src/modules/database-recommendation/repositories/local.database.recommendation.repository.ts index 811800be3f..3d2030db03 100644 --- a/redisinsight/api/src/modules/database-recommendation/repositories/local.database.recommendation.repository.ts +++ b/redisinsight/api/src/modules/database-recommendation/repositories/local.database.recommendation.repository.ts @@ -7,7 +7,7 @@ import { DatabaseRecommendationRepository } from 'src/modules/database-recommendation/repositories/database-recommendation.repository'; import { InjectRepository } from '@nestjs/typeorm'; import { Repository } from 'typeorm'; -import { plainToClass } from 'class-transformer'; +import { plainToInstance } from 'class-transformer'; import { DatabaseRecommendation } from 'src/modules/database-recommendation/models'; import { ModifyDatabaseRecommendationDto } from 'src/modules/database-recommendation/dto'; import { EncryptionService } from 'src/modules/encryption/encryption.service'; @@ -49,7 +49,7 @@ export class LocalDatabaseRecommendationRepository extends DatabaseRecommendatio try { const model = await this.repository.save( - await this.modelEncryptor.encryptEntity(plainToClass(DatabaseRecommendationEntity, entity)), + await this.modelEncryptor.encryptEntity(plainToInstance(DatabaseRecommendationEntity, entity)), ); const recommendation = classToClass( @@ -127,7 +127,7 @@ export class LocalDatabaseRecommendationRepository extends DatabaseRecommendatio ): Promise { this.logger.log(`Updating database recommendation with id:${id}`); const oldEntity = await this.modelEncryptor.decryptEntity(await this.repository.findOneBy({ id })); - const newEntity = plainToClass(DatabaseRecommendationEntity, recommendation); + const newEntity = plainToInstance(DatabaseRecommendationEntity, recommendation); if (!oldEntity) { this.logger.error(`Database recommendation with id:${id} was not Found`); @@ -197,7 +197,7 @@ export class LocalDatabaseRecommendationRepository extends DatabaseRecommendatio const sortedRecommendations = sortRecommendations(dbAnalysisRecommendations); for (let i = 0; i < sortedRecommendations.length; i += 1) { if (!await this.isExist(clientMetadata, sortedRecommendations[i].name)) { - const entity = plainToClass( + const entity = plainToInstance( DatabaseRecommendation, { databaseId: clientMetadata?.databaseId, diff --git a/redisinsight/api/src/modules/database/entities/database.entity.ts b/redisinsight/api/src/modules/database/entities/database.entity.ts index 3c9baf9918..992843638f 100644 --- a/redisinsight/api/src/modules/database/entities/database.entity.ts +++ b/redisinsight/api/src/modules/database/entities/database.entity.ts @@ -84,32 +84,32 @@ export class DatabaseEntity { @Expose() @Column({ nullable: true }) - @Transform((_, model) => ( - model?.sentinelMaster?.name + @Transform(({ obj }) => ( + obj?.sentinelMaster?.name ), { toClassOnly: true }) sentinelMasterName: string; @Expose() @Column({ nullable: true }) - @Transform((_, model) => ( - model?.sentinelMaster?.username + @Transform(({ obj }) => ( + obj?.sentinelMaster?.username ), { toClassOnly: true }) sentinelMasterUsername: string; @Expose() @Column({ nullable: true }) - @Transform((_, model) => ( - model?.sentinelMaster?.password + @Transform(({ obj }) => ( + obj?.sentinelMaster?.password ), { toClassOnly: true }) sentinelMasterPassword: string; @Expose() - @Transform((_, entity) => { - if (entity?.sentinelMasterName) { + @Transform(({ obj }) => { + if (obj?.sentinelMasterName) { return { - name: entity?.sentinelMasterName, - username: entity?.sentinelMasterUsername, - password: entity?.sentinelMasterPassword, + name: obj?.sentinelMasterName, + username: obj?.sentinelMasterUsername, + password: obj?.sentinelMasterPassword, }; } diff --git a/redisinsight/api/src/modules/database/middleware/connection.middleware.ts b/redisinsight/api/src/modules/database/middleware/connection.middleware.ts index 67ee6ed75d..2384514100 100644 --- a/redisinsight/api/src/modules/database/middleware/connection.middleware.ts +++ b/redisinsight/api/src/modules/database/middleware/connection.middleware.ts @@ -10,7 +10,7 @@ import { NextFunction, Request, Response } from 'express'; import ERROR_MESSAGES from 'src/constants/error-messages'; import { RedisErrorCodes } from 'src/constants'; import { DatabaseService } from 'src/modules/database/database.service'; -import { plainToClass } from 'class-transformer'; +import { plainToInstance } from 'class-transformer'; import { sessionMetadataFromRequest } from 'src/common/decorators'; import { Database } from '../models/database'; @@ -28,7 +28,7 @@ export class ConnectionMiddleware implements NestMiddleware { const sessionMetadata = sessionMetadataFromRequest(req); if (instanceIdFromReq) { - timeout = plainToClass( + timeout = plainToInstance( Database, await this.databaseService.get(sessionMetadata, instanceIdFromReq), )?.timeout; diff --git a/redisinsight/api/src/modules/feature/features-config.service.spec.ts b/redisinsight/api/src/modules/feature/features-config.service.spec.ts index 77d7818b99..a022e742dd 100644 --- a/redisinsight/api/src/modules/feature/features-config.service.spec.ts +++ b/redisinsight/api/src/modules/feature/features-config.service.spec.ts @@ -11,7 +11,7 @@ import { import { FeaturesConfigService } from 'src/modules/feature/features-config.service'; import { FeaturesConfigRepository } from 'src/modules/feature/repositories/features-config.repository'; import { EventEmitter2 } from '@nestjs/event-emitter'; -import { plainToClass } from 'class-transformer'; +import { plainToInstance } from 'class-transformer'; import { FeaturesConfigData } from 'src/modules/feature/model/features-config'; import { FeatureConfigConfigDestination, FeatureServerEvents, KnownFeatures } from 'src/modules/feature/constants'; import { FeatureAnalytics } from 'src/modules/feature/feature.analytics'; @@ -127,7 +127,7 @@ describe('FeaturesConfigService', () => { it('should update to the latest remote config', async () => { repository.getOrCreate.mockResolvedValue({ ...mockFeaturesConfig, - data: plainToClass(FeaturesConfigData, defaultConfig), + data: plainToInstance(FeaturesConfigData, defaultConfig), }); await service['sync'](); @@ -143,7 +143,7 @@ describe('FeaturesConfigService', () => { it('should not fail and not emit recalculate event in case of an error', async () => { repository.getOrCreate.mockResolvedValue({ ...mockFeaturesConfig, - data: plainToClass(FeaturesConfigData, defaultConfig), + data: plainToInstance(FeaturesConfigData, defaultConfig), }); repository.update.mockRejectedValueOnce(new Error('update error')); diff --git a/redisinsight/api/src/modules/feature/features-config.service.ts b/redisinsight/api/src/modules/feature/features-config.service.ts index f44176b3d4..b98a3d6325 100644 --- a/redisinsight/api/src/modules/feature/features-config.service.ts +++ b/redisinsight/api/src/modules/feature/features-config.service.ts @@ -7,7 +7,7 @@ import config from 'src/utils/config'; import { FeaturesConfigRepository } from 'src/modules/feature/repositories/features-config.repository'; import { FeatureConfigConfigDestination, FeatureServerEvents } from 'src/modules/feature/constants'; import { Validator } from 'class-validator'; -import { plainToClass } from 'class-transformer'; +import { plainToInstance } from 'class-transformer'; import { FeaturesConfigData } from 'src/modules/feature/model/features-config'; import { FeatureAnalytics } from 'src/modules/feature/feature.analytics'; import { UnableToFetchRemoteConfigException } from 'src/modules/feature/exceptions'; @@ -64,7 +64,7 @@ export class FeaturesConfigService implements OnApplicationBootstrap { remoteConfig = await this.fetchRemoteConfig(); // we should use default config in case when remote is invalid - await this.validator.validateOrReject(plainToClass(FeaturesConfigData, remoteConfig)); + await this.validator.validateOrReject(plainToInstance(FeaturesConfigData, remoteConfig)); if (remoteConfig?.version > defaultConfig?.version) { newConfig = { diff --git a/redisinsight/api/src/modules/feature/model/features-config.spec.ts b/redisinsight/api/src/modules/feature/model/features-config.spec.ts index 33358a08fa..6ae01e03b3 100644 --- a/redisinsight/api/src/modules/feature/model/features-config.spec.ts +++ b/redisinsight/api/src/modules/feature/model/features-config.spec.ts @@ -2,7 +2,7 @@ import { mockFeaturesConfig, mockFeaturesConfigComplex, mockFeaturesConfigEntity, mockFeaturesConfigEntityComplex, mockFeaturesConfigJson, mockFeaturesConfigJsonComplex, } from 'src/__mocks__'; -import { classToPlain, plainToClass } from 'class-transformer'; +import { instanceToPlain, plainToInstance } from 'class-transformer'; import { FeaturesConfig } from 'src/modules/feature/model/features-config'; import { classToClass } from 'src/utils'; import { FeaturesConfigEntity } from 'src/modules/feature/entities/features-config.entity'; @@ -50,8 +50,8 @@ describe('FeaturesConfig', () => { describe('transform', () => { testCases.forEach((tc) => { it(`input ${JSON.stringify(tc.plain)}`, async () => { - const modelFromPlain = plainToClass(FeaturesConfig, tc.plain); - const plainFromModel = classToPlain(modelFromPlain); + const modelFromPlain = plainToInstance(FeaturesConfig, tc.plain); + const plainFromModel = instanceToPlain(modelFromPlain); const entityFromModel = classToClass(FeaturesConfigEntity, modelFromPlain); const modelFromEntity = classToClass(FeaturesConfig, entityFromModel); diff --git a/redisinsight/api/src/modules/feature/repositories/local.features-config.repository.spec.ts b/redisinsight/api/src/modules/feature/repositories/local.features-config.repository.spec.ts index 75cf9d0cb7..43c2f4a3eb 100644 --- a/redisinsight/api/src/modules/feature/repositories/local.features-config.repository.spec.ts +++ b/redisinsight/api/src/modules/feature/repositories/local.features-config.repository.spec.ts @@ -9,7 +9,7 @@ import { } from 'src/__mocks__' import { LocalFeaturesConfigRepository } from 'src/modules/feature/repositories/local.features-config.repository'; import { FeaturesConfigEntity } from 'src/modules/feature/entities/features-config.entity'; -import { plainToClass } from 'class-transformer'; +import { plainToInstance } from 'class-transformer'; import * as defaultConfig from '../../../../config/features-config.json'; describe('LocalFeaturesConfigRepository', () => { @@ -109,7 +109,7 @@ describe('LocalFeaturesConfigRepository', () => { expect(result).toEqual(mockFeaturesConfig); expect(repository.update).toHaveBeenCalledWith( { id: service['id'] }, - plainToClass(FeaturesConfigEntity, { id: service['id'], data: defaultConfig }), + plainToInstance(FeaturesConfigEntity, { id: service['id'], data: defaultConfig }), ); }); }); diff --git a/redisinsight/api/src/modules/feature/repositories/local.features-config.repository.ts b/redisinsight/api/src/modules/feature/repositories/local.features-config.repository.ts index 93922d053c..1177d9232b 100644 --- a/redisinsight/api/src/modules/feature/repositories/local.features-config.repository.ts +++ b/redisinsight/api/src/modules/feature/repositories/local.features-config.repository.ts @@ -3,7 +3,7 @@ import { } from '@nestjs/common'; import { InjectRepository } from '@nestjs/typeorm'; import { Repository } from 'typeorm'; -import { plainToClass } from 'class-transformer'; +import { plainToInstance } from 'class-transformer'; import { classToClass } from 'src/utils'; import { FeaturesConfigRepository } from 'src/modules/feature/repositories/features-config.repository'; import { FeaturesConfigEntity } from 'src/modules/feature/entities/features-config.entity'; @@ -46,7 +46,7 @@ export class LocalFeaturesConfigRepository extends FeaturesConfigRepository { try { this.logger.log('Creating features config entity'); - entity = await this.repository.save(plainToClass(FeaturesConfigEntity, { + entity = await this.repository.save(plainToInstance(FeaturesConfigEntity, { id: this.id, data: defaultConfig, controlNumber: this.generateControlNumber(), @@ -69,7 +69,7 @@ export class LocalFeaturesConfigRepository extends FeaturesConfigRepository { async update(data: any): Promise { await this.repository.update( { id: this.id }, - plainToClass(FeaturesConfigEntity, { data, id: this.id }), + plainToInstance(FeaturesConfigEntity, { data, id: this.id }), ); return this.getOrCreate(); diff --git a/redisinsight/api/src/modules/feature/transformers/feature-config-filter.transformer.ts b/redisinsight/api/src/modules/feature/transformers/feature-config-filter.transformer.ts index 9bd8eba9ab..db38fc9601 100644 --- a/redisinsight/api/src/modules/feature/transformers/feature-config-filter.transformer.ts +++ b/redisinsight/api/src/modules/feature/transformers/feature-config-filter.transformer.ts @@ -1,12 +1,12 @@ import { get, map } from 'lodash'; -import { plainToClass } from 'class-transformer'; +import { plainToInstance } from 'class-transformer'; import { FeatureConfigFilter, FeatureConfigFilterAnd, FeatureConfigFilterOr, } from 'src/modules/feature/model/features-config'; -export const featureConfigFilterTransformer = (value) => map(value || [], (filter) => { +export const featureConfigFilterTransformer = ({ value }) => map(value || [], (filter) => { let cls: any = FeatureConfigFilter; if (get(filter, 'and')) { @@ -17,5 +17,5 @@ export const featureConfigFilterTransformer = (value) => map(value || [], (filte cls = FeatureConfigFilterOr; } - return plainToClass(cls, filter); + return plainToInstance(cls, filter); }); diff --git a/redisinsight/api/src/modules/notification/notification.service.ts b/redisinsight/api/src/modules/notification/notification.service.ts index 45f2f61c7a..f0dd8b8d04 100644 --- a/redisinsight/api/src/modules/notification/notification.service.ts +++ b/redisinsight/api/src/modules/notification/notification.service.ts @@ -1,5 +1,5 @@ import { Injectable, InternalServerErrorException, Logger } from '@nestjs/common'; -import { plainToClass } from 'class-transformer'; +import { plainToInstance } from 'class-transformer'; import { SessionMetadata } from 'src/common/models'; import { NotificationsDto, ReadNotificationsDto } from 'src/modules/notification/dto'; import { NotificationRepository } from './repositories/notification.repository'; @@ -21,7 +21,7 @@ export class NotificationService { this.notificationRepository.getTotalUnread(sessionMetadata), ]); - return plainToClass(NotificationsDto, { + return plainToInstance(NotificationsDto, { notifications, totalUnread, }); @@ -46,7 +46,7 @@ export class NotificationService { const notifications = await this.notificationRepository.readNotifications(sessionMetadata, type, timestamp); - return plainToClass(NotificationsDto, { + return plainToInstance(NotificationsDto, { notifications, totalUnread: await this.notificationRepository.getTotalUnread(sessionMetadata), }); diff --git a/redisinsight/api/src/modules/notification/providers/global-notification.provider.ts b/redisinsight/api/src/modules/notification/providers/global-notification.provider.ts index 2e7baa14ad..6228b1b996 100644 --- a/redisinsight/api/src/modules/notification/providers/global-notification.provider.ts +++ b/redisinsight/api/src/modules/notification/providers/global-notification.provider.ts @@ -5,7 +5,7 @@ import { Logger, } from '@nestjs/common'; import { EventEmitter2 } from '@nestjs/event-emitter'; -import { plainToClass } from 'class-transformer'; +import { plainToInstance } from 'class-transformer'; import { Validator } from 'class-validator'; import { forEach, keyBy, orderBy, values, @@ -55,7 +55,7 @@ export class GlobalNotificationProvider { await this.validatedNotifications(remoteNotificationsDto); const toInsert = keyBy( - remoteNotificationsDto.notifications.map((notification) => plainToClass(Notification, { + remoteNotificationsDto.notifications.map((notification) => plainToInstance(Notification, { ...notification, type: NotificationType.Global, read: false, @@ -108,7 +108,7 @@ export class GlobalNotificationProvider { this.logger.debug('Validating notifications from remote'); try { - const notificationsDto: CreateNotificationsDto = plainToClass( + const notificationsDto: CreateNotificationsDto = plainToInstance( CreateNotificationsDto, dto, ); @@ -128,7 +128,7 @@ export class GlobalNotificationProvider { const buffer = await getFile(NOTIFICATIONS_CONFIG.updateUrl); const serializedString = buffer.toString(); const json = JSON.parse(serializedString); - return plainToClass(CreateNotificationsDto, json); + return plainToInstance(CreateNotificationsDto, json); } catch (e) { this.logger.error( `Unable to download or parse notifications json. ${e.message}`, diff --git a/redisinsight/api/src/modules/notification/providers/notification.emitter.ts b/redisinsight/api/src/modules/notification/providers/notification.emitter.ts index b35c6269f4..89ee6fe30e 100644 --- a/redisinsight/api/src/modules/notification/providers/notification.emitter.ts +++ b/redisinsight/api/src/modules/notification/providers/notification.emitter.ts @@ -4,7 +4,7 @@ import { SessionMetadata } from 'src/common/models'; import { NotificationEvents, NotificationServerEvents } from 'src/modules/notification/constants'; import { NotificationsDto } from 'src/modules/notification/dto'; import { Notification } from 'src/modules/notification/models/notification'; -import { plainToClass } from 'class-transformer'; +import { plainToInstance } from 'class-transformer'; import { NotificationRepository } from '../repositories/notification.repository'; @Injectable() @@ -27,7 +27,7 @@ export class NotificationEmitter { const totalUnread = await this.notificationRepository.getTotalUnread(sessionMetadata); - this.eventEmitter.emit(NotificationServerEvents.Notification, plainToClass(NotificationsDto, { + this.eventEmitter.emit(NotificationServerEvents.Notification, plainToInstance(NotificationsDto, { notifications, totalUnread, })); diff --git a/redisinsight/api/src/modules/plugin/plugin.service.ts b/redisinsight/api/src/modules/plugin/plugin.service.ts index cca1353cd8..11c466bb3b 100644 --- a/redisinsight/api/src/modules/plugin/plugin.service.ts +++ b/redisinsight/api/src/modules/plugin/plugin.service.ts @@ -1,5 +1,5 @@ import { Injectable, Logger } from '@nestjs/common'; -import { plainToClass } from 'class-transformer'; +import { plainToInstance } from 'class-transformer'; import { Validator } from 'class-validator'; import { readdirSync, existsSync, readFileSync } from 'fs'; import config, { Config } from 'src/utils/config'; @@ -41,8 +41,8 @@ export class PluginService { readFileSync(path.join(pluginsFolder, pluginFolder, 'package.json'), 'utf8'), ); - // const plugin = plainToClass(Plugin, manifest, { excludeExtraneousValues: true, strategy: 'exposeAll' }); - const plugin = plainToClass(Plugin, manifest); + // const plugin = plainToInstance(Plugin, manifest, { excludeExtraneousValues: true, strategy: 'exposeAll' }); + const plugin = plainToInstance(Plugin, manifest); await this.validator.validateOrReject(plugin, { whitelist: true, }); diff --git a/redisinsight/api/src/modules/rdi/client/api.rdi.client.ts b/redisinsight/api/src/modules/rdi/client/api.rdi.client.ts index 62fb5a0b03..99283097ac 100644 --- a/redisinsight/api/src/modules/rdi/client/api.rdi.client.ts +++ b/redisinsight/api/src/modules/rdi/client/api.rdi.client.ts @@ -1,5 +1,5 @@ import axios, { AxiosInstance } from 'axios'; -import { plainToClass } from 'class-transformer'; +import { plainToInstance } from 'class-transformer'; import { RdiClient } from 'src/modules/rdi/client/rdi.client'; import { @@ -200,7 +200,7 @@ export class ApiRdiClient extends RdiClient { return { status: RdiStatisticsStatus.Success, - data: plainToClass(RdiStatisticsData, convertKeysToCamelCase(data)), + data: plainToInstance(RdiStatisticsData, convertKeysToCamelCase(data)), }; } catch (e) { const message: string = parseErrorMessage(e); diff --git a/redisinsight/api/src/modules/rdi/decorators/request.rdi.client.metadata.decorator.ts b/redisinsight/api/src/modules/rdi/decorators/request.rdi.client.metadata.decorator.ts index e4d92f0c47..0591e5b200 100644 --- a/redisinsight/api/src/modules/rdi/decorators/request.rdi.client.metadata.decorator.ts +++ b/redisinsight/api/src/modules/rdi/decorators/request.rdi.client.metadata.decorator.ts @@ -1,6 +1,6 @@ import { BadRequestException, createParamDecorator, ExecutionContext } from '@nestjs/common'; import { sessionMetadataFromRequest } from 'src/common/decorators'; -import { plainToClass } from 'class-transformer'; +import { plainToInstance } from 'class-transformer'; import { RdiClientMetadata } from 'src/modules/rdi/models'; import { Validator } from 'class-validator'; import { ApiParam } from '@nestjs/swagger'; @@ -10,7 +10,7 @@ const validator = new Validator(); export const RequestRdiClientMetadata = createParamDecorator((_: unknown, ctx: ExecutionContext) => { const req = ctx.switchToHttp().getRequest(); - const rdiClientMetadata = plainToClass(RdiClientMetadata, { + const rdiClientMetadata = plainToInstance(RdiClientMetadata, { id: req.params?.['id'], sessionMetadata: sessionMetadataFromRequest(req), }); diff --git a/redisinsight/api/src/modules/rdi/utils/pipeline.util.ts b/redisinsight/api/src/modules/rdi/utils/pipeline.util.ts index 5bd339b3bf..f637e7576c 100644 --- a/redisinsight/api/src/modules/rdi/utils/pipeline.util.ts +++ b/redisinsight/api/src/modules/rdi/utils/pipeline.util.ts @@ -1,7 +1,7 @@ import { isArray, unset, set, forEach, isObjectLike, isEmpty, } from 'lodash'; -import { plainToClass } from 'class-transformer'; +import { plainToInstance } from 'class-transformer'; import { RdiPipeline } from 'src/modules/rdi/models'; export const convertApiDataToRdiJobs = (jobs?: [Record]): Record => { @@ -41,7 +41,7 @@ export const convertApiDataToRdiPipeline = (data: Record = {}): Rdi // do not show jobs in the config area unset(pipeline, 'config.jobs'); - return plainToClass(RdiPipeline, pipeline, { excludeExtraneousValues: true }); + return plainToInstance(RdiPipeline, pipeline, { excludeExtraneousValues: true }); }; export const convertRdiJobsToApiPayload = (jobs: Record): Record[] => { diff --git a/redisinsight/api/src/modules/session/providers/single-user.session.provider.ts b/redisinsight/api/src/modules/session/providers/single-user.session.provider.ts index 9390651a0c..10a46e32fc 100644 --- a/redisinsight/api/src/modules/session/providers/single-user.session.provider.ts +++ b/redisinsight/api/src/modules/session/providers/single-user.session.provider.ts @@ -2,7 +2,7 @@ import { SessionProvider } from 'src/modules/session/providers/session.provider' import { Session } from 'src/common/models'; import { DEFAULT_SESSION_ID } from 'src/common/constants'; import { Injectable } from '@nestjs/common'; -import { plainToClass } from 'class-transformer'; +import { plainToInstance } from 'class-transformer'; @Injectable() export class SingleUserSessionProvider extends SessionProvider { @@ -11,7 +11,7 @@ export class SingleUserSessionProvider extends SessionProvider { } async createSession(session: Session): Promise { - return this.sessionStorage.createSession(plainToClass(Session, { + return this.sessionStorage.createSession(plainToInstance(Session, { ...session, id: DEFAULT_SESSION_ID, })); diff --git a/redisinsight/api/src/modules/settings/settings.controller.ts b/redisinsight/api/src/modules/settings/settings.controller.ts index 74bbc10ccf..f63cd6f4cf 100644 --- a/redisinsight/api/src/modules/settings/settings.controller.ts +++ b/redisinsight/api/src/modules/settings/settings.controller.ts @@ -71,12 +71,6 @@ export class SettingsController { }, ], }) - @UsePipes( - new ValidationPipe({ - transform: true, - whitelist: true, - }), - ) async update( @RequestSessionMetadata() sessionMetadata: SessionMetadata, @Body() dto: UpdateSettingsDto, diff --git a/redisinsight/api/src/modules/workbench/entities/command-execution.entity.ts b/redisinsight/api/src/modules/workbench/entities/command-execution.entity.ts index ec060896a1..3d725b6151 100644 --- a/redisinsight/api/src/modules/workbench/entities/command-execution.entity.ts +++ b/redisinsight/api/src/modules/workbench/entities/command-execution.entity.ts @@ -3,8 +3,9 @@ import { } from 'typeorm'; import { DatabaseEntity } from 'src/modules/database/entities/database.entity'; import { RunQueryMode, ResultsMode } from 'src/modules/workbench/dto/create-command-execution.dto'; -import { Expose, Transform } from 'class-transformer'; +import { Expose } from 'class-transformer'; import { IsInt, Min } from 'class-validator'; +import { DataAsJsonString } from 'src/common/decorators'; @Entity('command_execution') export class CommandExecutionEntity { @@ -35,14 +36,7 @@ export class CommandExecutionEntity { mode?: string = RunQueryMode.ASCII; @Column({ nullable: false, type: 'text' }) - @Transform((object) => JSON.stringify(object), { toClassOnly: true }) - @Transform((string) => { - try { - return JSON.parse(string); - } catch (e) { - return undefined; - } - }, { toPlainOnly: true }) + @DataAsJsonString() @Expose() result: string; @@ -55,26 +49,12 @@ export class CommandExecutionEntity { resultsMode?: string = ResultsMode.Default; @Column({ nullable: true }) - @Transform((object) => JSON.stringify(object), { toClassOnly: true }) - @Transform((string) => { - try { - return JSON.parse(string); - } catch (e) { - return undefined; - } - }, { toPlainOnly: true }) + @DataAsJsonString() @Expose() summary?: string; @Column({ nullable: true }) - @Transform((object) => JSON.stringify(object), { toClassOnly: true }) - @Transform((string) => { - try { - return JSON.parse(string); - } catch (e) { - return undefined; - } - }, { toPlainOnly: true }) + @DataAsJsonString() @Expose() nodeOptions?: string = null; diff --git a/redisinsight/api/src/modules/workbench/entities/plugin-state.entity.ts b/redisinsight/api/src/modules/workbench/entities/plugin-state.entity.ts index 81478785e1..4f767898be 100644 --- a/redisinsight/api/src/modules/workbench/entities/plugin-state.entity.ts +++ b/redisinsight/api/src/modules/workbench/entities/plugin-state.entity.ts @@ -7,8 +7,9 @@ import { UpdateDateColumn, PrimaryColumn, } from 'typeorm'; -import { Expose, Transform } from 'class-transformer'; +import { Expose } from 'class-transformer'; import { CommandExecutionEntity } from 'src/modules/workbench/entities/command-execution.entity'; +import { DataAsJsonString } from 'src/common/decorators'; @Entity('plugin_state') export class PluginStateEntity { @@ -31,14 +32,7 @@ export class PluginStateEntity { visualizationId: string; @Column({ nullable: false, type: 'text' }) - @Transform((object) => JSON.stringify(object), { toClassOnly: true }) - @Transform((string) => { - try { - return JSON.parse(string); - } catch (e) { - return undefined; - } - }, { toPlainOnly: true }) + @DataAsJsonString() @Expose() state: string; diff --git a/redisinsight/api/src/modules/workbench/plugins.service.ts b/redisinsight/api/src/modules/workbench/plugins.service.ts index dda9d1b02b..8be958f5cb 100644 --- a/redisinsight/api/src/modules/workbench/plugins.service.ts +++ b/redisinsight/api/src/modules/workbench/plugins.service.ts @@ -4,7 +4,7 @@ import { CreateCommandExecutionDto } from 'src/modules/workbench/dto/create-comm import { CommandNotSupportedError } from 'src/modules/cli/constants/errors'; import ERROR_MESSAGES from 'src/constants/error-messages'; import { PluginCommandExecution } from 'src/modules/workbench/models/plugin-command-execution'; -import { plainToClass } from 'class-transformer'; +import { plainToInstance } from 'class-transformer'; import { PluginCommandsWhitelistProvider } from 'src/modules/workbench/providers/plugin-commands-whitelist.provider'; import { CommandExecutionStatus } from 'src/modules/cli/dto/cli.dto'; import { CommandExecutionResult } from 'src/modules/workbench/models/command-execution-result'; @@ -42,7 +42,7 @@ export class PluginsService { const result = await this.commandsExecutor.sendCommand(client, dto); - return plainToClass(PluginCommandExecution, { + return plainToInstance(PluginCommandExecution, { ...dto, databaseId: clientMetadata.databaseId, result, diff --git a/redisinsight/api/src/modules/workbench/repositories/local-command-execution.repository.ts b/redisinsight/api/src/modules/workbench/repositories/local-command-execution.repository.ts index be0f4c6e05..810bf782cc 100644 --- a/redisinsight/api/src/modules/workbench/repositories/local-command-execution.repository.ts +++ b/redisinsight/api/src/modules/workbench/repositories/local-command-execution.repository.ts @@ -2,7 +2,7 @@ import { Injectable, Logger, NotFoundException } from '@nestjs/common'; import { InjectRepository } from '@nestjs/typeorm'; import { Repository } from 'typeorm'; import { filter, isNull } from 'lodash'; -import { plainToClass } from 'class-transformer'; +import { plainToInstance } from 'class-transformer'; import { EncryptionService } from 'src/modules/encryption/encryption.service'; import { CommandExecutionEntity } from 'src/modules/workbench/entities/command-execution.entity'; import { CommandExecution } from 'src/modules/workbench/models/command-execution'; @@ -41,7 +41,7 @@ export class LocalCommandExecutionRepository extends CommandExecutionRepository async createMany(_: SessionMetadata, commandExecutions: Partial[]): Promise { // todo: limit by 30 max to insert let entities = await Promise.all(commandExecutions.map(async (commandExecution) => { - const entity = plainToClass(CommandExecutionEntity, commandExecution); + const entity = plainToInstance(CommandExecutionEntity, commandExecution); // Do not store command execution result that exceeded limitation if (JSON.stringify(entity.result).length > WORKBENCH_CONFIG.maxResultSize) { diff --git a/redisinsight/api/src/modules/workbench/repositories/local-plugin-state.repository.ts b/redisinsight/api/src/modules/workbench/repositories/local-plugin-state.repository.ts index 1236806b40..7169b6476a 100644 --- a/redisinsight/api/src/modules/workbench/repositories/local-plugin-state.repository.ts +++ b/redisinsight/api/src/modules/workbench/repositories/local-plugin-state.repository.ts @@ -1,7 +1,7 @@ import { Injectable, Logger, NotFoundException } from '@nestjs/common'; import { InjectRepository } from '@nestjs/typeorm'; import { Repository } from 'typeorm'; -import { plainToClass } from 'class-transformer'; +import { plainToInstance } from 'class-transformer'; import { EncryptionService } from 'src/modules/encryption/encryption.service'; import ERROR_MESSAGES from 'src/constants/error-messages'; import { classToClass } from 'src/utils'; @@ -33,7 +33,7 @@ export class LocalPluginStateRepository extends PluginStateRepository { * @param pluginState */ async upsert(_: SessionMetadata, pluginState: Partial): Promise { - const entity = plainToClass(PluginStateEntity, pluginState); + const entity = plainToInstance(PluginStateEntity, pluginState); try { await this.repository.save(await this.modelEncryptor.encryptEntity(entity)); } catch (e) { diff --git a/redisinsight/api/src/utils/class-transformer.ts b/redisinsight/api/src/utils/class-transformer.ts index bc701c0563..45edcda29a 100644 --- a/redisinsight/api/src/utils/class-transformer.ts +++ b/redisinsight/api/src/utils/class-transformer.ts @@ -1,13 +1,12 @@ -import { ClassType } from 'class-transformer/ClassTransformer'; -import { ClassTransformOptions } from 'class-transformer/ClassTransformOptions'; -import { classToPlain, plainToClass } from 'class-transformer'; +import { ClassTransformOptions, instanceToPlain, plainToInstance } from 'class-transformer'; +import { ClassConstructor } from 'class-transformer/types/interfaces'; export function classToClass( - targetClass: ClassType, + targetClass: ClassConstructor, classInstance: V, options?: ClassTransformOptions, ): T { - const defaultOptions = { + const defaultOptions: ClassTransformOptions = { excludeExtraneousValues: true, groups: ['security'], }; @@ -17,7 +16,7 @@ export function classToClass( ...options, }; - return plainToClass(targetClass, classToPlain(classInstance, transformOptions), transformOptions); + return plainToInstance(targetClass, instanceToPlain(classInstance, transformOptions), transformOptions); } -export const cloneClassInstance = (entity: V): V => classToClass(entity.constructor as ClassType, entity); +export const cloneClassInstance = (entity: V): V => classToClass(entity.constructor as ClassConstructor, entity); diff --git a/redisinsight/api/yarn.lock b/redisinsight/api/yarn.lock index 011481f835..8e0e5eeaef 100644 --- a/redisinsight/api/yarn.lock +++ b/redisinsight/api/yarn.lock @@ -1445,10 +1445,10 @@ resolved "https://registry.yarnpkg.com/@types/urijs/-/urijs-1.19.25.tgz#ac92b53e674c3b108decdbe88dc5f444a2f42f6a" integrity sha512-XOfUup9r3Y06nFAZh3WvO0rBU4OtlfPB/vgxpjg+NRdGU6CN6djdc6OEiH+PcqHCY6eFLo9Ista73uarf4gnBg== -"@types/validator@^13.7.10": - version "13.7.17" - resolved "https://registry.yarnpkg.com/@types/validator/-/validator-13.7.17.tgz#0a6d1510395065171e3378a4afc587a3aefa7cc1" - integrity sha512-aqayTNmeWrZcvnG2MG9eGYI6b7S5fl+yKgPs6bAjOTwPS316R5SxBGKvtSExfyoJU7pIeHJfsHI0Ji41RVMkvQ== +"@types/validator@^13.11.8": + version "13.12.2" + resolved "https://registry.yarnpkg.com/@types/validator/-/validator-13.12.2.tgz#760329e756e18a4aab82fc502b51ebdfebbe49f5" + integrity sha512-6SlHBzUW8Jhf3liqrGGXyTJSIFe4nqlJ5A5KaMZ2l/vbM3Wh3KSybots/wfWVzNLK4D1NZluDlSQIbIEPx6oyA== "@types/yargs-parser@*": version "21.0.0" @@ -2546,10 +2546,10 @@ cjs-module-lexer@^0.6.0: resolved "https://registry.yarnpkg.com/cjs-module-lexer/-/cjs-module-lexer-0.6.0.tgz#4186fcca0eae175970aee870b9fe2d6cf8d5655f" integrity sha512-uc2Vix1frTfnuzxxu1Hp4ktSvM3QaI4oXl4ZUqL1wjTu/BGki9TrCWoqLTg/drR1KwAEarXuRFCG2Svr1GxPFw== -class-transformer@^0.2.3: - version "0.2.3" - resolved "https://registry.yarnpkg.com/class-transformer/-/class-transformer-0.2.3.tgz#598c92ca71dcca73f91ccb875d74a3847ccfa32d" - integrity sha512-qsP+0xoavpOlJHuYsQJsN58HXSl8Jvveo+T37rEvCEeRfMWoytAyR0Ua/YsFgpM6AZYZ/og2PJwArwzJl1aXtQ== +class-transformer@^0.5.1: + version "0.5.1" + resolved "https://registry.yarnpkg.com/class-transformer/-/class-transformer-0.5.1.tgz#24147d5dffd2a6cea930a3250a677addf96ab336" + integrity sha512-SQa1Ws6hUbfC98vKGxZH3KFY0Y1lm5Zm0SY8XX9zbK7FJCyVEac3ATW0RIpwzW+oOfmHE5PMPufDG9hCfoEOMw== class-utils@^0.3.5: version "0.3.6" @@ -2561,14 +2561,14 @@ class-utils@^0.3.5: isobject "^3.0.0" static-extend "^0.1.1" -class-validator@^0.14.0: - version "0.14.0" - resolved "https://registry.yarnpkg.com/class-validator/-/class-validator-0.14.0.tgz#40ed0ecf3c83b2a8a6a320f4edb607be0f0df159" - integrity sha512-ct3ltplN8I9fOwUd8GrP8UQixwff129BkEtuWDKL5W45cQuLd19xqmTLu5ge78YDm/fdje6FMt0hGOhl0lii3A== +class-validator@^0.14.1: + version "0.14.1" + resolved "https://registry.yarnpkg.com/class-validator/-/class-validator-0.14.1.tgz#ff2411ed8134e9d76acfeb14872884448be98110" + integrity sha512-2VEG9JICxIqTpoK1eMzZqaV+u/EiwEJkMGzTrZf6sU/fwsnOITVgYJ8yojSy6CaXtO9V0Cc6ZQZ8h8m4UBuLwQ== dependencies: - "@types/validator" "^13.7.10" - libphonenumber-js "^1.10.14" - validator "^13.7.0" + "@types/validator" "^13.11.8" + libphonenumber-js "^1.10.53" + validator "^13.9.0" clean-stack@^2.0.0: version "2.2.0" @@ -5879,10 +5879,10 @@ levn@^0.4.1: prelude-ls "^1.2.1" type-check "~0.4.0" -libphonenumber-js@^1.10.14: - version "1.10.37" - resolved "https://registry.yarnpkg.com/libphonenumber-js/-/libphonenumber-js-1.10.37.tgz#185264130c9375f17d0c487a288223294579929c" - integrity sha512-Z10PCaOCiAxbUxLyR31DNeeNugSVP6iv/m7UrSKS5JHziEMApJtgku4e9Q69pzzSC9LnQiM09sqsGf2ticZnMw== +libphonenumber-js@^1.10.53: + version "1.11.11" + resolved "https://registry.yarnpkg.com/libphonenumber-js/-/libphonenumber-js-1.11.11.tgz#f4d521d7e2d1958916820e3725e609a2ea7575a8" + integrity sha512-mF3KaORjJQR6JBNcOkluDcJKhtoQT4VTLRMrX1v/wlBayL4M8ybwEDeryyPcrSEJmD0rVwHUbBarpZwN5NfPFQ== lines-and-columns@^1.1.6: version "1.2.4" @@ -9112,10 +9112,10 @@ validate-npm-package-license@^3.0.1: spdx-correct "^3.0.0" spdx-expression-parse "^3.0.0" -validator@^13.7.0: - version "13.9.0" - resolved "https://registry.yarnpkg.com/validator/-/validator-13.9.0.tgz#33e7b85b604f3bbce9bb1a05d5c3e22e1c2ff855" - integrity sha512-B+dGG8U3fdtM0/aNK4/X8CXq/EcxU2WPrPEkJGslb47qyHsxmbggTWK0yEA4qnYVNF+nxNlN88o14hIcPmSIEA== +validator@^13.9.0: + version "13.12.0" + resolved "https://registry.yarnpkg.com/validator/-/validator-13.12.0.tgz#7d78e76ba85504da3fee4fd1922b385914d4b35f" + integrity sha512-c1Q0mCiPlgdTVVVIJIrBuxNicYE+t/7oKeI9MWLj3fh/uq2Pxh/3eeWbVZ4OcGW1TUf53At0njHw5SMdA3tmMg== vary@^1, vary@~1.1.2: version "1.1.2" From 43ba936861b33620dd6e02094f7e4b7ddbaa1381 Mon Sep 17 00:00:00 2001 From: Roman Sergeenko Date: Wed, 16 Oct 2024 10:41:30 +0200 Subject: [PATCH 176/256] #RI-6221 - fix arguments in details --- .../ui/src/pages/workbench/components/query/Query/Query.tsx | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/redisinsight/ui/src/pages/workbench/components/query/Query/Query.tsx b/redisinsight/ui/src/pages/workbench/components/query/Query/Query.tsx index e9fdbce023..82200d2e5d 100644 --- a/redisinsight/ui/src/pages/workbench/components/query/Query/Query.tsx +++ b/redisinsight/ui/src/pages/workbench/components/query/Query/Query.tsx @@ -105,6 +105,7 @@ const Query = (props: Props) => { const { theme } = useContext(ThemeContext) const monacoObjects = useRef>(null) + // TODO: need refactor to avoid this const REDIS_COMMANDS = commands.map((command) => ({ ...addOwnTokenToArgs(command.name!, command) })) const { instanceId = '' } = useParams<{ instanceId: string }>() @@ -538,11 +539,11 @@ const Query = (props: Props) => { if (position.column === 1) { helpWidgetRef.current.isOpen = false if (command) return asSuggestionsRef([]) - return asSuggestionsRef(getCommandsSuggestions(REDIS_COMMANDS, range), false) + return asSuggestionsRef(getCommandsSuggestions(commands, range), false) } if (!command) { - return asSuggestionsRef(getCommandsSuggestions(REDIS_COMMANDS, range), false) + return asSuggestionsRef(getCommandsSuggestions(commands, range), false) } const { allArgs, args, cursor } = command From 24a88664ad33bb0e84dcabbf85f52fe024215f66 Mon Sep 17 00:00:00 2001 From: ArtemHoruzhenko Date: Wed, 16 Oct 2024 11:52:32 +0300 Subject: [PATCH 177/256] update jest --- redisinsight/api/package.json | 9 +- .../api/src/__mocks__/bulk-actions.ts | 2 +- .../local.ai-query.message.repository.spec.ts | 12 +- .../cluster.scanner.strategy.spec.ts | 10 +- .../bulk-actions/bulk-import.service.spec.ts | 10 +- .../local.ca-certificate.repository.spec.ts | 2 +- ...ocal.client-certificate.repository.spec.ts | 4 +- .../local.cloud-capi-key.repository.spec.ts | 6 +- .../local.custom-tutorial.repository.spec.ts | 2 +- .../strategies/abstract.info.strategy.spec.ts | 4 +- .../strategies/graph-info.strategy.spec.ts | 2 +- .../strategies/hash-info.strategy.spec.ts | 2 +- .../strategies/json-info.strategy.spec.ts | 14 +- .../strategies/list-info.strategy.spec.ts | 2 +- .../strategies/set-info.strategy.spec.ts | 2 +- .../strategies/stream-info.strategy.spec.ts | 2 +- .../strategies/string-info.strategy.spec.ts | 2 +- .../strategies/ts-info.strategy.spec.ts | 2 +- .../strategies/z-set-info.strategy.spec.ts | 2 +- .../scanner/keys-scanner.spec.ts | 14 +- .../certificate-import.service.spec.ts | 6 +- ...database.recommendation.repository.spec.ts | 2 +- .../strategies/search-JSON.strategy.spec.ts | 6 +- .../local.database.repository.spec.ts | 12 +- .../stack.database.repository.spec.ts | 4 +- .../repository/local.rdi.repository.spec.ts | 2 +- .../providers/recommendation.provider.spec.ts | 62 +- .../ioredis.redis.connection.strategy.spec.ts | 4 + redisinsight/api/test/api/deps.ts | 2 +- redisinsight/api/yarn.lock | 2577 +++++++---------- 30 files changed, 1096 insertions(+), 1686 deletions(-) diff --git a/redisinsight/api/package.json b/redisinsight/api/package.json index cf1871fbd0..42229295c9 100644 --- a/redisinsight/api/package.json +++ b/redisinsight/api/package.json @@ -42,6 +42,8 @@ "resolutions": { "nanoid": "^3.1.31", "word-wrap": "1.2.4", + "jest/**/micromatch": "^4.0.8", + "ts-loader/micromatch": "^4.0.8", "mocha/minimatch": "^3.0.5", "@nestjs/platform-socket.io/socket.io": "^4.8.0", "**/semver": "^7.5.2", @@ -120,7 +122,7 @@ "eslint-plugin-import": "^2.20.1", "eslint-plugin-sonarjs": "^0.9.1", "ioredis-mock": "^8.2.2", - "jest": "^26.6.3", + "jest": "^29.7.0", "jest-when": "^3.2.1", "joi": "^17.4.0", "mocha": "^8.4.0", @@ -132,7 +134,7 @@ "rimraf": "^3.0.2", "socket.io-mock": "^1.3.2", "supertest": "^4.0.2", - "ts-jest": "^26.1.0", + "ts-jest": "^29.2.5", "ts-loader": "^6.2.1", "ts-mocha": "^8.0.0", "ts-node": "^9.1.1", @@ -164,8 +166,7 @@ "moduleNameMapper": { "src/(.*)": "/$1", "apiSrc/(.*)": "/$1", - "tests/(.*)": "/__tests__/$1", - "axios": "axios/dist/node/axios.cjs" + "tests/(.*)": "/__tests__/$1" } } } diff --git a/redisinsight/api/src/__mocks__/bulk-actions.ts b/redisinsight/api/src/__mocks__/bulk-actions.ts index d7ff92c0cc..1ca750ec5b 100644 --- a/redisinsight/api/src/__mocks__/bulk-actions.ts +++ b/redisinsight/api/src/__mocks__/bulk-actions.ts @@ -48,7 +48,7 @@ export const mockCombinedStream = { export const mockBulkActionOverviewMatcher = { ...mockBulkActionOverview, - duration: jasmine.any(Number), + duration: expect.any(Number), }; export const mockBulkActionFilter = new BulkActionFilter(); diff --git a/redisinsight/api/src/modules/ai/query/repositories/local.ai-query.message.repository.spec.ts b/redisinsight/api/src/modules/ai/query/repositories/local.ai-query.message.repository.spec.ts index 4c376fe79f..f1b6953dec 100644 --- a/redisinsight/api/src/modules/ai/query/repositories/local.ai-query.message.repository.spec.ts +++ b/redisinsight/api/src/modules/ai/query/repositories/local.ai-query.message.repository.spec.ts @@ -51,20 +51,20 @@ describe('LocalAiQueryAuthProvider', () => { encryptionService.decrypt.mockImplementation((value) => value); when(encryptionService.decrypt) - .calledWith(mockAiQueryHumanMessageEntity.content, jasmine.anything()) + .calledWith(mockAiQueryHumanMessageEntity.content, expect.anything()) .mockResolvedValue(mockAiQueryHumanMessage.content) - .calledWith(mockAiQueryAiResponseEntity.content, jasmine.anything()) + .calledWith(mockAiQueryAiResponseEntity.content, expect.anything()) .mockResolvedValue(mockAiQueryAiResponse.content) - .calledWith(mockAiQueryAiResponseEntity.steps, jasmine.anything()) + .calledWith(mockAiQueryAiResponseEntity.steps, expect.anything()) .mockResolvedValue(JSON.stringify(mockAiQueryAiResponse.steps)); encryptionService.encrypt.mockImplementation((value) => value); when(encryptionService.encrypt) - .calledWith(mockAiQueryHumanMessage.content, jasmine.anything()) + .calledWith(mockAiQueryHumanMessage.content, expect.anything()) .mockResolvedValue(mockAiQueryHumanMessageEntity.content) - .calledWith(mockAiQueryAiResponse.content, jasmine.anything()) + .calledWith(mockAiQueryAiResponse.content, expect.anything()) .mockResolvedValue(mockAiQueryAiResponseEntity.content) - .calledWith(JSON.stringify(mockAiQueryAiResponse.steps), jasmine.anything()) + .calledWith(JSON.stringify(mockAiQueryAiResponse.steps), expect.anything()) .mockResolvedValue(mockAiQueryAiResponseEntity.steps); }); diff --git a/redisinsight/api/src/modules/browser/keys/scanner/strategies/cluster.scanner.strategy.spec.ts b/redisinsight/api/src/modules/browser/keys/scanner/strategies/cluster.scanner.strategy.spec.ts index e16203b021..73489ec548 100644 --- a/redisinsight/api/src/modules/browser/keys/scanner/strategies/cluster.scanner.strategy.spec.ts +++ b/redisinsight/api/src/modules/browser/keys/scanner/strategies/cluster.scanner.strategy.spec.ts @@ -776,16 +776,16 @@ describe('Cluster Scanner Strategy', () => { beforeEach(() => { when(mockClusterRedisClient.sendPipeline) .calledWith([ - jasmine.arrayContaining([BrowserToolKeysCommands.Ttl]), - jasmine.arrayContaining(['memory', 'usage']), - jasmine.arrayContaining([BrowserToolKeysCommands.Type]), + expect.arrayContaining([BrowserToolKeysCommands.Ttl]), + expect.arrayContaining(['memory', 'usage']), + expect.arrayContaining([BrowserToolKeysCommands.Type]), ], { replyEncoding: 'utf8' }) .mockResolvedValue([[null, -1], [null, 50], [null, 'string']]); when(mockClusterRedisClient.sendPipeline) .calledWith([ - jasmine.arrayContaining([BrowserToolKeysCommands.Ttl]), - jasmine.arrayContaining(['memory', 'usage']), + expect.arrayContaining([BrowserToolKeysCommands.Ttl]), + expect.arrayContaining(['memory', 'usage']), ], { replyEncoding: 'utf8' }) .mockResolvedValue([[null, 999], [null, 555]]); diff --git a/redisinsight/api/src/modules/bulk-actions/bulk-import.service.spec.ts b/redisinsight/api/src/modules/bulk-actions/bulk-import.service.spec.ts index 206f59a2f9..741eaa506e 100644 --- a/redisinsight/api/src/modules/bulk-actions/bulk-import.service.spec.ts +++ b/redisinsight/api/src/modules/bulk-actions/bulk-import.service.spec.ts @@ -162,11 +162,11 @@ describe('BulkImportService', () => { spy.mockResolvedValue(mockSummary); expect(await service.import(mockClientMetadata, mockReadableStream)).toEqual({ ...mockImportResult, - duration: jasmine.anything(), + duration: expect.anything(), }); expect(analytics.sendActionSucceed).toHaveBeenCalledWith({ ...mockImportResult, - duration: jasmine.anything(), + duration: expect.anything(), }); }); @@ -185,7 +185,7 @@ describe('BulkImportService', () => { failed: 0, errors: [], }, - duration: jasmine.anything(), + duration: expect.anything(), }); }); @@ -204,7 +204,7 @@ describe('BulkImportService', () => { failed: 0, errors: [], }, - duration: jasmine.anything(), + duration: expect.anything(), }); }); @@ -225,7 +225,7 @@ describe('BulkImportService', () => { failed: 2, errors: [], }, - duration: jasmine.anything(), + duration: expect.anything(), }); expect(mockStandaloneRedisClient.disconnect).toHaveBeenCalled(); }); diff --git a/redisinsight/api/src/modules/certificate/repositories/local.ca-certificate.repository.spec.ts b/redisinsight/api/src/modules/certificate/repositories/local.ca-certificate.repository.spec.ts index baf4791bf4..6a90559423 100644 --- a/redisinsight/api/src/modules/certificate/repositories/local.ca-certificate.repository.spec.ts +++ b/redisinsight/api/src/modules/certificate/repositories/local.ca-certificate.repository.spec.ts @@ -57,7 +57,7 @@ describe('LocalCaCertificateRepository', () => { repository.save.mockResolvedValue(mockCaCertificateEntity); repository.create.mockReturnValue(mockCaCertificate); // not entity since it happens before encryption - when(encryptionService.decrypt).calledWith(mockCaCertificateCertificateEncrypted, jasmine.anything()) + when(encryptionService.decrypt).calledWith(mockCaCertificateCertificateEncrypted, expect.anything()) .mockResolvedValue(mockCaCertificateCertificatePlain); when(encryptionService.encrypt).calledWith(mockCaCertificateCertificatePlain) .mockResolvedValue({ diff --git a/redisinsight/api/src/modules/certificate/repositories/local.client-certificate.repository.spec.ts b/redisinsight/api/src/modules/certificate/repositories/local.client-certificate.repository.spec.ts index 79aa19387b..80bf8e088d 100644 --- a/redisinsight/api/src/modules/certificate/repositories/local.client-certificate.repository.spec.ts +++ b/redisinsight/api/src/modules/certificate/repositories/local.client-certificate.repository.spec.ts @@ -65,9 +65,9 @@ describe('LocalClientCertificateRepository', () => { repository.create.mockReturnValue(mockClientCertificate); // not an entity since create happens before encryption when(encryptionService.decrypt) - .calledWith(mockClientCertificateCertificateEncrypted, jasmine.anything()) + .calledWith(mockClientCertificateCertificateEncrypted, expect.anything()) .mockResolvedValue(mockClientCertificateCertificatePlain) - .calledWith(mockClientCertificateKeyEncrypted, jasmine.anything()) + .calledWith(mockClientCertificateKeyEncrypted, expect.anything()) .mockResolvedValue(mockClientCertificateKeyPlain); when(encryptionService.encrypt) .calledWith(mockClientCertificateCertificatePlain) diff --git a/redisinsight/api/src/modules/cloud/capi-key/repository/local.cloud-capi-key.repository.spec.ts b/redisinsight/api/src/modules/cloud/capi-key/repository/local.cloud-capi-key.repository.spec.ts index 7db382eb0d..51579f4db3 100644 --- a/redisinsight/api/src/modules/cloud/capi-key/repository/local.cloud-capi-key.repository.spec.ts +++ b/redisinsight/api/src/modules/cloud/capi-key/repository/local.cloud-capi-key.repository.spec.ts @@ -60,9 +60,9 @@ describe('LocalCloudCapiKeyRepository', () => { repository.merge.mockReturnValue(mockFeatureEntity); when(encryptionService.decrypt) - .calledWith(mockCapiKeyEncrypted, jasmine.anything()) + .calledWith(mockCapiKeyEncrypted, expect.anything()) .mockResolvedValue(mockCloudCapiAuthDto.capiKey) - .calledWith(mockCapiSecretEncrypted, jasmine.anything()) + .calledWith(mockCapiSecretEncrypted, expect.anything()) .mockResolvedValue(mockCloudCapiAuthDto.capiSecret); when(encryptionService.encrypt) @@ -80,7 +80,7 @@ describe('LocalCloudCapiKeyRepository', () => { }); it('should return null fields in case of decryption errors', async () => { when(encryptionService.decrypt) - .calledWith(mockCapiKeyEncrypted, jasmine.anything()) + .calledWith(mockCapiKeyEncrypted, expect.anything()) .mockRejectedValueOnce(new KeytarDecryptionErrorException()); expect(await service.get(mockDatabase.id)).toEqual({ diff --git a/redisinsight/api/src/modules/custom-tutorial/repositories/local.custom-tutorial.repository.spec.ts b/redisinsight/api/src/modules/custom-tutorial/repositories/local.custom-tutorial.repository.spec.ts index 926f6c5857..c5cb1d5df8 100644 --- a/redisinsight/api/src/modules/custom-tutorial/repositories/local.custom-tutorial.repository.spec.ts +++ b/redisinsight/api/src/modules/custom-tutorial/repositories/local.custom-tutorial.repository.spec.ts @@ -71,7 +71,7 @@ describe('LocalCustomTutorialRepository', () => { expect(result).toEqual(mockCustomTutorial); expect(repository.save).toHaveBeenCalledWith({ ...mockCustomTutorialEntity, - createdAt: jasmine.anything(), + createdAt: expect.anything(), }); }); }); diff --git a/redisinsight/api/src/modules/database-analysis/scanner/key-info/strategies/abstract.info.strategy.spec.ts b/redisinsight/api/src/modules/database-analysis/scanner/key-info/strategies/abstract.info.strategy.spec.ts index 9e045274ae..aeaff9ca65 100644 --- a/redisinsight/api/src/modules/database-analysis/scanner/key-info/strategies/abstract.info.strategy.spec.ts +++ b/redisinsight/api/src/modules/database-analysis/scanner/key-info/strategies/abstract.info.strategy.spec.ts @@ -11,7 +11,7 @@ describe('AbstractInfoStrategy', () => { beforeEach(async () => { when(client.sendCommand) - .calledWith(jasmine.arrayContaining(['hlen'])) + .calledWith(expect.arrayContaining(['hlen'])) .mockResolvedValue(mockRedisResponse); }); @@ -21,7 +21,7 @@ describe('AbstractInfoStrategy', () => { }); it('should return null in case of error', async () => { when(client.sendCommand) - .calledWith(jasmine.arrayContaining(['hlen'])) + .calledWith(expect.arrayContaining(['hlen'])) .mockRejectedValueOnce(new Error('some error')); expect(await strategy.getLengthSafe(client, mockKey)).toEqual(null); diff --git a/redisinsight/api/src/modules/database-analysis/scanner/key-info/strategies/graph-info.strategy.spec.ts b/redisinsight/api/src/modules/database-analysis/scanner/key-info/strategies/graph-info.strategy.spec.ts index c0b51e0428..59abfa6861 100644 --- a/redisinsight/api/src/modules/database-analysis/scanner/key-info/strategies/graph-info.strategy.spec.ts +++ b/redisinsight/api/src/modules/database-analysis/scanner/key-info/strategies/graph-info.strategy.spec.ts @@ -18,7 +18,7 @@ describe('GraphInfoStrategy', () => { beforeEach(async () => { when(client.sendCommand) - .calledWith(jasmine.arrayContaining(['graph.query']), expect.anything()) + .calledWith(expect.arrayContaining(['graph.query']), expect.anything()) .mockResolvedValue(mockRedisResponse); }); diff --git a/redisinsight/api/src/modules/database-analysis/scanner/key-info/strategies/hash-info.strategy.spec.ts b/redisinsight/api/src/modules/database-analysis/scanner/key-info/strategies/hash-info.strategy.spec.ts index f904214744..a016225a9c 100644 --- a/redisinsight/api/src/modules/database-analysis/scanner/key-info/strategies/hash-info.strategy.spec.ts +++ b/redisinsight/api/src/modules/database-analysis/scanner/key-info/strategies/hash-info.strategy.spec.ts @@ -11,7 +11,7 @@ describe('HashInfoStrategy', () => { beforeEach(async () => { when(client.sendCommand) - .calledWith(jasmine.arrayContaining(['hlen'])) + .calledWith(expect.arrayContaining(['hlen'])) .mockResolvedValue(mockRedisResponse); }); diff --git a/redisinsight/api/src/modules/database-analysis/scanner/key-info/strategies/json-info.strategy.spec.ts b/redisinsight/api/src/modules/database-analysis/scanner/key-info/strategies/json-info.strategy.spec.ts index aa903c5fb2..bff85ff318 100644 --- a/redisinsight/api/src/modules/database-analysis/scanner/key-info/strategies/json-info.strategy.spec.ts +++ b/redisinsight/api/src/modules/database-analysis/scanner/key-info/strategies/json-info.strategy.spec.ts @@ -10,39 +10,39 @@ describe('JsonInfoStrategy', () => { beforeEach(async () => { when(client.sendCommand) - .calledWith(jasmine.arrayContaining(['json.objlen']), expect.anything()) + .calledWith(expect.arrayContaining(['json.objlen']), expect.anything()) .mockResolvedValue(1) - .calledWith(jasmine.arrayContaining(['json.arrlen']), expect.anything()) + .calledWith(expect.arrayContaining(['json.arrlen']), expect.anything()) .mockResolvedValue(2) - .calledWith(jasmine.arrayContaining(['json.strlen']), expect.anything()) + .calledWith(expect.arrayContaining(['json.strlen']), expect.anything()) .mockResolvedValue(3); }); describe('getLength', () => { it('should get length (object)', async () => { when(client.sendCommand) - .calledWith(jasmine.arrayContaining(['json.type']), expect.anything()) + .calledWith(expect.arrayContaining(['json.type']), expect.anything()) .mockResolvedValue('object'); expect(await strategy.getLength(client, mockKey)).toEqual(1); }); it('should get length (array)', async () => { when(client.sendCommand) - .calledWith(jasmine.arrayContaining(['json.type']), expect.anything()) + .calledWith(expect.arrayContaining(['json.type']), expect.anything()) .mockResolvedValue('array'); expect(await strategy.getLength(client, mockKey)).toEqual(2); }); it('should get length (string)', async () => { when(client.sendCommand) - .calledWith(jasmine.arrayContaining(['json.type']), expect.anything()) + .calledWith(expect.arrayContaining(['json.type']), expect.anything()) .mockResolvedValue('string'); expect(await strategy.getLength(client, mockKey)).toEqual(3); }); it('should get length (undefined)', async () => { when(client.sendCommand) - .calledWith(jasmine.arrayContaining(['json.type']), expect.anything()) + .calledWith(expect.arrayContaining(['json.type']), expect.anything()) .mockResolvedValue('undefined'); expect(await strategy.getLength(client, mockKey)).toEqual(null); diff --git a/redisinsight/api/src/modules/database-analysis/scanner/key-info/strategies/list-info.strategy.spec.ts b/redisinsight/api/src/modules/database-analysis/scanner/key-info/strategies/list-info.strategy.spec.ts index 21766ab06d..09462dbeba 100644 --- a/redisinsight/api/src/modules/database-analysis/scanner/key-info/strategies/list-info.strategy.spec.ts +++ b/redisinsight/api/src/modules/database-analysis/scanner/key-info/strategies/list-info.strategy.spec.ts @@ -11,7 +11,7 @@ describe('ListInfoStrategy', () => { beforeEach(async () => { when(client.sendCommand) - .calledWith(jasmine.arrayContaining(['llen'])) + .calledWith(expect.arrayContaining(['llen'])) .mockResolvedValue(mockRedisResponse); }); diff --git a/redisinsight/api/src/modules/database-analysis/scanner/key-info/strategies/set-info.strategy.spec.ts b/redisinsight/api/src/modules/database-analysis/scanner/key-info/strategies/set-info.strategy.spec.ts index 52c2a33fd5..3938d2d950 100644 --- a/redisinsight/api/src/modules/database-analysis/scanner/key-info/strategies/set-info.strategy.spec.ts +++ b/redisinsight/api/src/modules/database-analysis/scanner/key-info/strategies/set-info.strategy.spec.ts @@ -11,7 +11,7 @@ describe('SetInfoStrategy', () => { beforeEach(async () => { when(client.sendCommand) - .calledWith(jasmine.arrayContaining(['scard'])) + .calledWith(expect.arrayContaining(['scard'])) .mockResolvedValue(mockRedisResponse); }); diff --git a/redisinsight/api/src/modules/database-analysis/scanner/key-info/strategies/stream-info.strategy.spec.ts b/redisinsight/api/src/modules/database-analysis/scanner/key-info/strategies/stream-info.strategy.spec.ts index 781608df83..de9587647f 100644 --- a/redisinsight/api/src/modules/database-analysis/scanner/key-info/strategies/stream-info.strategy.spec.ts +++ b/redisinsight/api/src/modules/database-analysis/scanner/key-info/strategies/stream-info.strategy.spec.ts @@ -11,7 +11,7 @@ describe('StreamInfoStrategy', () => { beforeEach(async () => { when(client.sendCommand) - .calledWith(jasmine.arrayContaining(['xlen'])) + .calledWith(expect.arrayContaining(['xlen'])) .mockResolvedValue(mockRedisResponse); }); diff --git a/redisinsight/api/src/modules/database-analysis/scanner/key-info/strategies/string-info.strategy.spec.ts b/redisinsight/api/src/modules/database-analysis/scanner/key-info/strategies/string-info.strategy.spec.ts index 39763c9064..338f59aff2 100644 --- a/redisinsight/api/src/modules/database-analysis/scanner/key-info/strategies/string-info.strategy.spec.ts +++ b/redisinsight/api/src/modules/database-analysis/scanner/key-info/strategies/string-info.strategy.spec.ts @@ -11,7 +11,7 @@ describe('StringInfoStrategy', () => { beforeEach(async () => { when(client.sendCommand) - .calledWith(jasmine.arrayContaining(['strlen'])) + .calledWith(expect.arrayContaining(['strlen'])) .mockResolvedValue(mockRedisResponse); }); diff --git a/redisinsight/api/src/modules/database-analysis/scanner/key-info/strategies/ts-info.strategy.spec.ts b/redisinsight/api/src/modules/database-analysis/scanner/key-info/strategies/ts-info.strategy.spec.ts index 45fd4d5223..43744a9633 100644 --- a/redisinsight/api/src/modules/database-analysis/scanner/key-info/strategies/ts-info.strategy.spec.ts +++ b/redisinsight/api/src/modules/database-analysis/scanner/key-info/strategies/ts-info.strategy.spec.ts @@ -26,7 +26,7 @@ describe('TsInfoStrategy', () => { beforeEach(async () => { when(client.sendCommand) - .calledWith(jasmine.arrayContaining(['ts.info']), expect.anything()) + .calledWith(expect.arrayContaining(['ts.info']), expect.anything()) .mockResolvedValue(mockRedisResponse); }); diff --git a/redisinsight/api/src/modules/database-analysis/scanner/key-info/strategies/z-set-info.strategy.spec.ts b/redisinsight/api/src/modules/database-analysis/scanner/key-info/strategies/z-set-info.strategy.spec.ts index ec7b3959aa..c3bb9eccd0 100644 --- a/redisinsight/api/src/modules/database-analysis/scanner/key-info/strategies/z-set-info.strategy.spec.ts +++ b/redisinsight/api/src/modules/database-analysis/scanner/key-info/strategies/z-set-info.strategy.spec.ts @@ -11,7 +11,7 @@ describe('ZSetInfoStrategy', () => { beforeEach(async () => { when(client.sendCommand) - .calledWith(jasmine.arrayContaining(['zcard'])) + .calledWith(expect.arrayContaining(['zcard'])) .mockResolvedValue(mockRedisResponse); }); diff --git a/redisinsight/api/src/modules/database-analysis/scanner/keys-scanner.spec.ts b/redisinsight/api/src/modules/database-analysis/scanner/keys-scanner.spec.ts index 5d86c8133a..d4d4d87d43 100644 --- a/redisinsight/api/src/modules/database-analysis/scanner/keys-scanner.spec.ts +++ b/redisinsight/api/src/modules/database-analysis/scanner/keys-scanner.spec.ts @@ -64,22 +64,22 @@ describe('KeysScanner', () => { infoStrategy.getLengthSafe.mockResolvedValue(2); clusterClient.nodes.mockReturnValue([standaloneClient, standaloneClient, standaloneClient]); when(standaloneClient.sendCommand) - .calledWith(jasmine.arrayContaining(['scan'])) + .calledWith(expect.arrayContaining(['scan'])) .mockResolvedValue(['0', [mockKey.name]]); when(standaloneClient.sendPipeline) - .calledWith(jasmine.arrayContaining([ - jasmine.arrayContaining(['memory']), + .calledWith(expect.arrayContaining([ + expect.arrayContaining(['memory']), ])) .mockReturnValue([[null, 10]]); when(standaloneClient.sendPipeline) - .calledWith(jasmine.arrayContaining([ - jasmine.arrayContaining(['ttl']), + .calledWith(expect.arrayContaining([ + expect.arrayContaining(['ttl']), ])) .mockReturnValue([[null, -1]]); when(standaloneClient.sendPipeline) .calledWith( - jasmine.arrayContaining([ - jasmine.arrayContaining(['type']), + expect.arrayContaining([ + expect.arrayContaining(['type']), ]), expect.anything(), ) diff --git a/redisinsight/api/src/modules/database-import/certificate-import.service.spec.ts b/redisinsight/api/src/modules/database-import/certificate-import.service.spec.ts index 2939250c52..2617451fa7 100644 --- a/redisinsight/api/src/modules/database-import/certificate-import.service.spec.ts +++ b/redisinsight/api/src/modules/database-import/certificate-import.service.spec.ts @@ -66,7 +66,7 @@ describe('CertificateImportService', () => { clientRepository = await module.get(getRepositoryToken(ClientCertificateEntity)); encryptionService = await module.get(EncryptionService); - when(encryptionService.decrypt).calledWith(mockCaCertificateCertificateEncrypted, jasmine.anything()) + when(encryptionService.decrypt).calledWith(mockCaCertificateCertificateEncrypted, expect.anything()) .mockResolvedValue(mockCaCertificateCertificatePlain); when(encryptionService.encrypt).calledWith(mockCaCertificateCertificatePlain) .mockResolvedValue({ @@ -75,9 +75,9 @@ describe('CertificateImportService', () => { }); when(encryptionService.decrypt) - .calledWith(mockClientCertificateCertificateEncrypted, jasmine.anything()) + .calledWith(mockClientCertificateCertificateEncrypted, expect.anything()) .mockResolvedValue(mockClientCertificateCertificatePlain) - .calledWith(mockClientCertificateKeyEncrypted, jasmine.anything()) + .calledWith(mockClientCertificateKeyEncrypted, expect.anything()) .mockResolvedValue(mockClientCertificateKeyPlain); when(encryptionService.encrypt) .calledWith(mockClientCertificateCertificatePlain) diff --git a/redisinsight/api/src/modules/database-recommendation/repositories/local.database.recommendation.repository.spec.ts b/redisinsight/api/src/modules/database-recommendation/repositories/local.database.recommendation.repository.spec.ts index abe736fdb9..39ce13b00b 100644 --- a/redisinsight/api/src/modules/database-recommendation/repositories/local.database.recommendation.repository.spec.ts +++ b/redisinsight/api/src/modules/database-recommendation/repositories/local.database.recommendation.repository.spec.ts @@ -58,7 +58,7 @@ describe('LocalDatabaseRecommendationRepository', () => { data: mockDatabaseRecommendationEntity.params, }); when(encryptionService.decrypt) - .calledWith(mockDatabaseRecommendationEntity.params, jasmine.anything()) + .calledWith(mockDatabaseRecommendationEntity.params, expect.anything()) .mockReturnValue(JSON.stringify(mockDatabaseRecommendation.params)); }); diff --git a/redisinsight/api/src/modules/database-recommendation/scanner/strategies/search-JSON.strategy.spec.ts b/redisinsight/api/src/modules/database-recommendation/scanner/strategies/search-JSON.strategy.spec.ts index 060f02065c..72e78f3b00 100644 --- a/redisinsight/api/src/modules/database-recommendation/scanner/strategies/search-JSON.strategy.spec.ts +++ b/redisinsight/api/src/modules/database-recommendation/scanner/strategies/search-JSON.strategy.spec.ts @@ -34,7 +34,7 @@ describe('SearchJSONStrategy', () => { describe('with search module', () => { it('should return true when there is JSON key', async () => { when(client.sendCommand) - .calledWith(jasmine.arrayContaining(['FT._LIST']), expect.anything()) + .calledWith(expect.arrayContaining(['FT._LIST']), expect.anything()) .mockResolvedValue(mockEmptyIndexes); expect(await strategy.isRecommendationReached({ @@ -54,7 +54,7 @@ describe('SearchJSONStrategy', () => { it('should return false when FT._LIST return indexes', async () => { when(client.sendCommand) - .calledWith(jasmine.arrayContaining(['FT._LIST']), expect.anything()) + .calledWith(expect.arrayContaining(['FT._LIST']), expect.anything()) .mockResolvedValue(mockIndexes); expect(await strategy.isRecommendationReached({ @@ -68,7 +68,7 @@ describe('SearchJSONStrategy', () => { describe('without search module', () => { beforeEach(() => { when(client.sendCommand) - .calledWith(jasmine.arrayContaining(['FT._LIST']), expect.anything()) + .calledWith(expect.arrayContaining(['FT._LIST']), expect.anything()) .mockReturnValue(new Error('Unsupported command')); }); diff --git a/redisinsight/api/src/modules/database/repositories/local.database.repository.spec.ts b/redisinsight/api/src/modules/database/repositories/local.database.repository.spec.ts index 1cadbf8892..c9818e90c9 100644 --- a/redisinsight/api/src/modules/database/repositories/local.database.repository.spec.ts +++ b/redisinsight/api/src/modules/database/repositories/local.database.repository.spec.ts @@ -108,17 +108,17 @@ describe('LocalDatabaseRepository', () => { repository.update.mockResolvedValue(mockDatabaseEntity); when(encryptionService.decrypt) - .calledWith(mockDatabasePasswordEncrypted, jasmine.anything()) + .calledWith(mockDatabasePasswordEncrypted, expect.anything()) .mockResolvedValue(mockDatabasePasswordPlain) - .calledWith(mockDatabaseSentinelMasterPasswordEncrypted, jasmine.anything()) + .calledWith(mockDatabaseSentinelMasterPasswordEncrypted, expect.anything()) .mockResolvedValue(mockDatabaseSentinelMasterPasswordPlain) - .calledWith(mockSshOptionsUsernameEncrypted, jasmine.anything()) + .calledWith(mockSshOptionsUsernameEncrypted, expect.anything()) .mockResolvedValue(mockSshOptionsUsernamePlain) - .calledWith(mockSshOptionsPasswordEncrypted, jasmine.anything()) + .calledWith(mockSshOptionsPasswordEncrypted, expect.anything()) .mockResolvedValue(mockSshOptionsPasswordPlain) - .calledWith(mockSshOptionsPrivateKeyEncrypted, jasmine.anything()) + .calledWith(mockSshOptionsPrivateKeyEncrypted, expect.anything()) .mockResolvedValue(mockSshOptionsPrivateKeyPlain) - .calledWith(mockSshOptionsPassphraseEncrypted, jasmine.anything()) + .calledWith(mockSshOptionsPassphraseEncrypted, expect.anything()) .mockResolvedValue(mockSshOptionsPassphrasePlain); when(encryptionService.encrypt) .calledWith(mockDatabasePasswordPlain) diff --git a/redisinsight/api/src/modules/database/repositories/stack.database.repository.spec.ts b/redisinsight/api/src/modules/database/repositories/stack.database.repository.spec.ts index 3c25d16958..6f91458d50 100644 --- a/redisinsight/api/src/modules/database/repositories/stack.database.repository.spec.ts +++ b/redisinsight/api/src/modules/database/repositories/stack.database.repository.spec.ts @@ -93,9 +93,9 @@ describe('StackDatabasesRepository', () => { repository.update.mockResolvedValue(mockDatabaseEntity); when(encryptionService.decrypt) - .calledWith(mockDatabasePasswordEncrypted, jasmine.anything()) + .calledWith(mockDatabasePasswordEncrypted, expect.anything()) .mockResolvedValue(mockDatabasePasswordPlain) - .calledWith(mockDatabaseSentinelMasterPasswordEncrypted, jasmine.anything()) + .calledWith(mockDatabaseSentinelMasterPasswordEncrypted, expect.anything()) .mockResolvedValue(mockDatabaseSentinelMasterPasswordPlain); when(encryptionService.encrypt) .calledWith(mockDatabasePasswordPlain) diff --git a/redisinsight/api/src/modules/rdi/repository/local.rdi.repository.spec.ts b/redisinsight/api/src/modules/rdi/repository/local.rdi.repository.spec.ts index 1fde16ea6a..438e4fd466 100644 --- a/redisinsight/api/src/modules/rdi/repository/local.rdi.repository.spec.ts +++ b/redisinsight/api/src/modules/rdi/repository/local.rdi.repository.spec.ts @@ -39,7 +39,7 @@ describe('LocalRdiRepository', () => { encryptionService = module.get(EncryptionService); when(encryptionService.decrypt) - .calledWith(mockRdiPasswordEncrypted, jasmine.anything()) + .calledWith(mockRdiPasswordEncrypted, expect.anything()) .mockResolvedValue(mockRdiPasswordPlain); when(encryptionService.encrypt) diff --git a/redisinsight/api/src/modules/recommendation/providers/recommendation.provider.spec.ts b/redisinsight/api/src/modules/recommendation/providers/recommendation.provider.spec.ts index 629d5e3d1a..e5d01c7161 100644 --- a/redisinsight/api/src/modules/recommendation/providers/recommendation.provider.spec.ts +++ b/redisinsight/api/src/modules/recommendation/providers/recommendation.provider.spec.ts @@ -151,7 +151,7 @@ describe('RecommendationProvider', () => { describe('determineLuaScriptRecommendation', () => { it('should not return luaScript recommendation', async () => { when(client.sendCommand) - .calledWith(jasmine.arrayContaining(['info']), expect.anything()) + .calledWith(expect.arrayContaining(['info']), expect.anything()) .mockResolvedValue(mockRedisMemoryInfoResponse1); const luaScriptRecommendation = await service.determineLuaScriptRecommendation(client); @@ -160,7 +160,7 @@ describe('RecommendationProvider', () => { it('should return luaScript recommendation', async () => { when(client.sendCommand) - .calledWith(jasmine.arrayContaining(['info']), expect.anything()) + .calledWith(expect.arrayContaining(['info']), expect.anything()) .mockResolvedValue(mockRedisMemoryInfoResponse2); const luaScriptRecommendation = await service.determineLuaScriptRecommendation(client); @@ -169,7 +169,7 @@ describe('RecommendationProvider', () => { it('should not return luaScript recommendation when info command executed with error', async () => { when(client.sendCommand) - .calledWith(jasmine.arrayContaining(['info']), expect.anything()) + .calledWith(expect.arrayContaining(['info']), expect.anything()) .mockRejectedValue('some error'); const luaScriptRecommendation = await service.determineLuaScriptRecommendation(client); @@ -205,7 +205,7 @@ describe('RecommendationProvider', () => { describe('determineLogicalDatabasesRecommendation', () => { it('should not return avoidLogicalDatabases recommendation when only one logical db', async () => { when(client.sendCommand) - .calledWith(jasmine.arrayContaining(['info']), expect.anything()) + .calledWith(expect.arrayContaining(['info']), expect.anything()) .mockResolvedValue(mockRedisKeyspaceInfoResponse1); const avoidLogicalDatabasesRecommendation = await service.determineLogicalDatabasesRecommendation(client); @@ -214,7 +214,7 @@ describe('RecommendationProvider', () => { it('should not return avoidLogicalDatabases recommendation when only on logical db with keys', async () => { when(client.sendCommand) - .calledWith(jasmine.arrayContaining(['info']), expect.anything()) + .calledWith(expect.arrayContaining(['info']), expect.anything()) .mockResolvedValue(mockRedisKeyspaceInfoResponse2); const avoidLogicalDatabasesRecommendation = await service.determineLogicalDatabasesRecommendation(client); @@ -223,7 +223,7 @@ describe('RecommendationProvider', () => { it('should return avoidLogicalDatabases recommendation', async () => { when(client.sendCommand) - .calledWith(jasmine.arrayContaining(['info']), expect.anything()) + .calledWith(expect.arrayContaining(['info']), expect.anything()) .mockResolvedValue(mockRedisKeyspaceInfoResponse3); const avoidLogicalDatabasesRecommendation = await service.determineLogicalDatabasesRecommendation(client); @@ -232,7 +232,7 @@ describe('RecommendationProvider', () => { it('should not return avoidLogicalDatabases recommendation when info command executed with error', async () => { when(client.sendCommand) - .calledWith(jasmine.arrayContaining(['info']), expect.anything()) + .calledWith(expect.arrayContaining(['info']), expect.anything()) .mockRejectedValue('some error'); const avoidLogicalDatabasesRecommendation = await service.determineLogicalDatabasesRecommendation(client); @@ -242,7 +242,7 @@ describe('RecommendationProvider', () => { it('should not return avoidLogicalDatabases recommendation when isCluster', async () => { client.getConnectionType = jest.fn().mockReturnValueOnce(RedisClientConnectionType.CLUSTER); when(client.sendCommand) - .calledWith(jasmine.arrayContaining(['info']), expect.anything()) + .calledWith(expect.arrayContaining(['info']), expect.anything()) .mockResolvedValue(mockRedisKeyspaceInfoResponse3); const avoidLogicalDatabasesRecommendation = await service.determineLogicalDatabasesRecommendation(client); @@ -278,7 +278,7 @@ describe('RecommendationProvider', () => { describe('determineIncreaseSetMaxIntsetEntriesRecommendation', () => { it('should not return increaseSetMaxIntsetEntries', async () => { when(client.sendCommand) - .calledWith(jasmine.arrayContaining(['config']), expect.anything()) + .calledWith(expect.arrayContaining(['config']), expect.anything()) .mockResolvedValue(mockRedisConfigResponse); const increaseSetMaxIntsetEntriesRecommendation = await service @@ -288,7 +288,7 @@ describe('RecommendationProvider', () => { it('should return increaseSetMaxIntsetEntries recommendation', async () => { when(client.sendCommand) - .calledWith(jasmine.arrayContaining(['config']), expect.anything()) + .calledWith(expect.arrayContaining(['config']), expect.anything()) .mockResolvedValue(mockRedisConfigResponse); const increaseSetMaxIntsetEntriesRecommendation = await service @@ -303,7 +303,7 @@ describe('RecommendationProvider', () => { it('should not return increaseSetMaxIntsetEntries recommendation when config command executed with error', async () => { when(client.sendCommand) - .calledWith(jasmine.arrayContaining(['config']), expect.anything()) + .calledWith(expect.arrayContaining(['config']), expect.anything()) .mockRejectedValue('some error'); const increaseSetMaxIntsetEntriesRecommendation = await service @@ -315,7 +315,7 @@ describe('RecommendationProvider', () => { describe('determineHashHashtableToZiplistRecommendation', () => { it('should not return hashHashtableToZiplist recommendation', async () => { when(client.sendCommand) - .calledWith(jasmine.arrayContaining(['config']), expect.anything()) + .calledWith(expect.arrayContaining(['config']), expect.anything()) .mockResolvedValue(mockRedisConfigResponse); const convertHashtableToZiplistRecommendation = await service @@ -325,7 +325,7 @@ describe('RecommendationProvider', () => { it('should return hashHashtableToZiplist recommendation', async () => { when(client.sendCommand) - .calledWith(jasmine.arrayContaining(['config']), expect.anything()) + .calledWith(expect.arrayContaining(['config']), expect.anything()) .mockResolvedValue(mockRedisConfigResponse); const convertHashtableToZiplistRecommendation = await service @@ -342,7 +342,7 @@ describe('RecommendationProvider', () => { it('should not return hashHashtableToZiplist recommendation when config command executed with error', async () => { when(client.sendCommand) - .calledWith(jasmine.arrayContaining(['config']), expect.anything()) + .calledWith(expect.arrayContaining(['config']), expect.anything()) .mockRejectedValue('some error'); const convertHashtableToZiplistRecommendation = await service @@ -388,7 +388,7 @@ describe('RecommendationProvider', () => { describe('determineZSetHashtableToZiplistRecommendation', () => { it('should not return zSetHashtableToZiplist recommendation', async () => { when(client.sendCommand) - .calledWith(jasmine.arrayContaining(['config']), expect.anything()) + .calledWith(expect.arrayContaining(['config']), expect.anything()) .mockResolvedValue(mockRedisConfigResponse); const zSetHashtableToZiplistRecommendation = await service @@ -398,7 +398,7 @@ describe('RecommendationProvider', () => { it('should return zSetHashtableToZiplist recommendation', async () => { when(client.sendCommand) - .calledWith(jasmine.arrayContaining(['config']), expect.anything()) + .calledWith(expect.arrayContaining(['config']), expect.anything()) .mockResolvedValue(mockRedisConfigResponse); const zSetHashtableToZiplistRecommendation = await service @@ -413,7 +413,7 @@ describe('RecommendationProvider', () => { it('should not return zSetHashtableToZiplist recommendation when config command executed with error', async () => { when(client.sendCommand) - .calledWith(jasmine.arrayContaining(['config']), expect.anything()) + .calledWith(expect.arrayContaining(['config']), expect.anything()) .mockRejectedValue('some error'); const zSetHashtableToZiplistRecommendation = await service @@ -442,7 +442,7 @@ describe('RecommendationProvider', () => { describe('determineConnectionClientsRecommendation', () => { it('should not return connectionClients recommendation', async () => { when(client.sendCommand) - .calledWith(jasmine.arrayContaining(['info']), expect.anything()) + .calledWith(expect.arrayContaining(['info']), expect.anything()) .mockResolvedValue(mockRedisClientsResponse1); const connectionClientsRecommendation = await service @@ -452,7 +452,7 @@ describe('RecommendationProvider', () => { it('should return connectionClients recommendation', async () => { when(client.sendCommand) - .calledWith(jasmine.arrayContaining(['info']), expect.anything()) + .calledWith(expect.arrayContaining(['info']), expect.anything()) .mockResolvedValue(mockRedisClientsResponse2); const connectionClientsRecommendation = await service @@ -464,7 +464,7 @@ describe('RecommendationProvider', () => { it('should not return connectionClients recommendation when info command executed with error', async () => { when(client.sendCommand) - .calledWith(jasmine.arrayContaining(['info']), expect.anything()) + .calledWith(expect.arrayContaining(['info']), expect.anything()) .mockRejectedValue('some error'); const connectionClientsRecommendation = await service @@ -476,7 +476,7 @@ describe('RecommendationProvider', () => { describe('determineSetPasswordRecommendation', () => { it('should not return setPassword recommendation', async () => { when(client.sendCommand) - .calledWith(jasmine.arrayContaining(['acl']), expect.anything()) + .calledWith(expect.arrayContaining(['acl']), expect.anything()) .mockResolvedValue(mockRedisAclListResponse1); const setPasswordRecommendation = await service @@ -486,7 +486,7 @@ describe('RecommendationProvider', () => { it('should return setPassword recommendation', async () => { when(client.sendCommand) - .calledWith(jasmine.arrayContaining(['acl']), expect.anything()) + .calledWith(expect.arrayContaining(['acl']), expect.anything()) .mockResolvedValue(mockRedisAclListResponse2); const setPasswordRecommendation = await service @@ -497,7 +497,7 @@ describe('RecommendationProvider', () => { it('should not return setPassword recommendation when acl command executed with error', async () => { when(client.sendCommand) - .calledWith(jasmine.arrayContaining(['acl']), expect.anything()) + .calledWith(expect.arrayContaining(['acl']), expect.anything()) .mockRejectedValue('some error'); const setPasswordRecommendation = await service @@ -508,7 +508,7 @@ describe('RecommendationProvider', () => { it('should not return setPassword recommendation when acl command executed with error', async () => { when(client.sendCommand) - .calledWith(jasmine.arrayContaining(['auth'])) + .calledWith(expect.arrayContaining(['auth'])) .mockRejectedValue(mockRedisNoAuthError); const setPasswordRecommendation = await service @@ -520,7 +520,7 @@ describe('RecommendationProvider', () => { describe('determineRedisVersionRecommendation', () => { it('should not return redis version recommendation', async () => { when(client.sendCommand) - .calledWith(jasmine.arrayContaining(['info']), expect.anything()) + .calledWith(expect.arrayContaining(['info']), expect.anything()) .mockResolvedValue(mockRedisServerResponse1); const redisVersionRecommendation = await service @@ -530,7 +530,7 @@ describe('RecommendationProvider', () => { it('should return redis version recommendation', async () => { when(client.sendCommand) - .calledWith(jasmine.arrayContaining(['info']), expect.anything()) + .calledWith(expect.arrayContaining(['info']), expect.anything()) .mockResolvedValueOnce(mockRedisServerResponse2); const redisVersionRecommendation = await service @@ -542,7 +542,7 @@ describe('RecommendationProvider', () => { async () => { resetAllWhenMocks(); when(client.sendCommand) - .calledWith(jasmine.arrayContaining(['info']), expect.anything()) + .calledWith(expect.arrayContaining(['info']), expect.anything()) .mockRejectedValue('some error'); const redisVersionRecommendation = await service @@ -609,7 +609,7 @@ describe('RecommendationProvider', () => { describe('determineRTSRecommendation', () => { test.each(generateRTSRecommendationTests)('%j', async ({ input, expected }) => { when(client.sendCommand) - .calledWith(jasmine.arrayContaining(['zscan']), expect.anything()) + .calledWith(expect.arrayContaining(['zscan']), expect.anything()) .mockResolvedValue(input); const RTSRecommendation = await service @@ -621,13 +621,13 @@ describe('RecommendationProvider', () => { let counter = 0; while (counter <= 100) { when(client.sendCommand) - .calledWith(jasmine.arrayContaining(['zscan']), expect.anything()) + .calledWith(expect.arrayContaining(['zscan']), expect.anything()) .mockResolvedValueOnce(mockZScanResponse1); counter += 1; } when(client.sendCommand) - .calledWith(jasmine.arrayContaining(['zscan']), expect.anything()) + .calledWith(expect.arrayContaining(['zscan']), expect.anything()) .mockResolvedValueOnce(mockZScanResponse2); const RTSRecommendation = await service @@ -639,7 +639,7 @@ describe('RecommendationProvider', () => { async () => { resetAllWhenMocks(); when(client.sendCommand) - .calledWith(jasmine.arrayContaining(['zscan']), expect.anything()) + .calledWith(expect.arrayContaining(['zscan']), expect.anything()) .mockRejectedValue('some error'); const RTSRecommendation = await service diff --git a/redisinsight/api/src/modules/redis/connection/ioredis.redis.connection.strategy.spec.ts b/redisinsight/api/src/modules/redis/connection/ioredis.redis.connection.strategy.spec.ts index cfe70bd903..61c9f9df78 100644 --- a/redisinsight/api/src/modules/redis/connection/ioredis.redis.connection.strategy.spec.ts +++ b/redisinsight/api/src/modules/redis/connection/ioredis.redis.connection.strategy.spec.ts @@ -29,6 +29,10 @@ const checkError = (cb) => (e) => { cb(); }; +function fail(data?: any) { + expect(`Expected to fail but got ${data}`).toBeFalsy(); +} + describe('IoredisRedisConnectionStrategy', () => { let service: IoredisRedisConnectionStrategy; let mockIoredisNativeClient; diff --git a/redisinsight/api/test/api/deps.ts b/redisinsight/api/test/api/deps.ts index 9e647a3642..9f766759d5 100644 --- a/redisinsight/api/test/api/deps.ts +++ b/redisinsight/api/test/api/deps.ts @@ -37,7 +37,7 @@ global['jest'] = { fn: dummyJest, }; -global['jasmine'] = { +global['expect'] = { any: () => {}, } diff --git a/redisinsight/api/yarn.lock b/redisinsight/api/yarn.lock index 8e0e5eeaef..f87e5994dc 100644 --- a/redisinsight/api/yarn.lock +++ b/redisinsight/api/yarn.lock @@ -80,6 +80,14 @@ dependencies: "@babel/highlight" "^7.18.6" +"@babel/code-frame@^7.12.13", "@babel/code-frame@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.25.7.tgz#438f2c524071531d643c6f0188e1e28f130cebc7" + integrity sha512-0xZJFNE5XMpENsgfHYTw8FbX4kv53mFLn2i3XPoq69LyhYSCBJtitaHx9QnsVTrsogI4Z3+HtEfZ2/GFPOtf5g== + dependencies: + "@babel/highlight" "^7.25.7" + picocolors "^1.0.0" + "@babel/code-frame@^7.22.13": version "7.22.13" resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.22.13.tgz#e3c1c099402598483b7a8c46a721d1038803755e" @@ -93,7 +101,33 @@ resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.23.3.tgz#3febd552541e62b5e883a25eb3effd7c7379db11" integrity sha512-BmR4bWbDIoFJmJ9z2cZ8Gmm2MXgEDgjdWgpKmKWUt54UGFJdlj31ECtbaDvCG/qVdG3AQ1SfpZEs01lUFbzLOQ== -"@babel/core@^7.1.0", "@babel/core@^7.12.3", "@babel/core@^7.7.5": +"@babel/compat-data@^7.25.7": + version "7.25.8" + resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.25.8.tgz#0376e83df5ab0eb0da18885c0140041f0747a402" + integrity sha512-ZsysZyXY4Tlx+Q53XdnOFmqwfB9QDTHYxaZYajWRoBLuLEAwI2UIbtxOjWh/cFaa9IKUlcB+DDuoskLuKu56JA== + +"@babel/core@^7.11.6", "@babel/core@^7.23.9": + version "7.25.8" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.25.8.tgz#a57137d2a51bbcffcfaeba43cb4dd33ae3e0e1c6" + integrity sha512-Oixnb+DzmRT30qu9d3tJSQkxuygWm32DFykT4bRoORPa9hZ/L4KhVB/XiRm6KG+roIEM7DBQlmg27kw2HZkdZg== + dependencies: + "@ampproject/remapping" "^2.2.0" + "@babel/code-frame" "^7.25.7" + "@babel/generator" "^7.25.7" + "@babel/helper-compilation-targets" "^7.25.7" + "@babel/helper-module-transforms" "^7.25.7" + "@babel/helpers" "^7.25.7" + "@babel/parser" "^7.25.8" + "@babel/template" "^7.25.7" + "@babel/traverse" "^7.25.7" + "@babel/types" "^7.25.8" + convert-source-map "^2.0.0" + debug "^4.1.0" + gensync "^1.0.0-beta.2" + json5 "^2.2.3" + semver "^6.3.1" + +"@babel/core@^7.12.3", "@babel/core@^7.7.5": version "7.23.3" resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.23.3.tgz#5ec09c8803b91f51cc887dedc2654a35852849c9" integrity sha512-Jg+msLuNuCJDyBvFv5+OKOUjWMZgd85bKjbICd3zWrKAo+bJ49HJufi7CQE0q0uR8NGyO6xkCACScNqyjHSZew== @@ -124,6 +158,16 @@ "@jridgewell/trace-mapping" "^0.3.17" jsesc "^2.5.1" +"@babel/generator@^7.25.7", "@babel/generator@^7.7.2": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.25.7.tgz#de86acbeb975a3e11ee92dd52223e6b03b479c56" + integrity sha512-5Dqpl5fyV9pIAD62yK9P7fcA768uVPUyrQmqpqstHWgMma4feF1x/oFysBCVZLY5wJ2GkMUCdsNDnGZrPoR6rA== + dependencies: + "@babel/types" "^7.25.7" + "@jridgewell/gen-mapping" "^0.3.5" + "@jridgewell/trace-mapping" "^0.3.25" + jsesc "^3.0.2" + "@babel/helper-compilation-targets@^7.22.15": version "7.22.15" resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.22.15.tgz#0698fc44551a26cf29f18d4662d5bf545a6cfc52" @@ -135,6 +179,17 @@ lru-cache "^5.1.1" semver "^6.3.1" +"@babel/helper-compilation-targets@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.25.7.tgz#11260ac3322dda0ef53edfae6e97b961449f5fa4" + integrity sha512-DniTEax0sv6isaw6qSQSfV4gVRNtw2rte8HHM45t9ZR0xILaufBRNkpMifCRiAPyvL4ACD6v0gfCwCmtOQaV4A== + dependencies: + "@babel/compat-data" "^7.25.7" + "@babel/helper-validator-option" "^7.25.7" + browserslist "^4.24.0" + lru-cache "^5.1.1" + semver "^6.3.1" + "@babel/helper-environment-visitor@^7.22.20": version "7.22.20" resolved "https://registry.yarnpkg.com/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz#96159db61d34a29dba454c959f5ae4a649ba9167" @@ -162,6 +217,14 @@ dependencies: "@babel/types" "^7.22.15" +"@babel/helper-module-imports@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.25.7.tgz#dba00d9523539152906ba49263e36d7261040472" + integrity sha512-o0xCgpNmRohmnoWKQ0Ij8IdddjyBFE4T2kagL/x6M3+4zUgc+4qTOUBoNe4XxDskt1HPKO007ZPiMgLDq2s7Kw== + dependencies: + "@babel/traverse" "^7.25.7" + "@babel/types" "^7.25.7" + "@babel/helper-module-transforms@^7.23.3": version "7.23.3" resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.23.3.tgz#d7d12c3c5d30af5b3c0fcab2a6d5217773e2d0f1" @@ -173,11 +236,26 @@ "@babel/helper-split-export-declaration" "^7.22.6" "@babel/helper-validator-identifier" "^7.22.20" +"@babel/helper-module-transforms@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.25.7.tgz#2ac9372c5e001b19bc62f1fe7d96a18cb0901d1a" + integrity sha512-k/6f8dKG3yDz/qCwSM+RKovjMix563SLxQFo0UhRNo239SP6n9u5/eLtKD6EAjwta2JHJ49CsD8pms2HdNiMMQ== + dependencies: + "@babel/helper-module-imports" "^7.25.7" + "@babel/helper-simple-access" "^7.25.7" + "@babel/helper-validator-identifier" "^7.25.7" + "@babel/traverse" "^7.25.7" + "@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.12.13", "@babel/helper-plugin-utils@^7.14.5", "@babel/helper-plugin-utils@^7.8.0": version "7.22.5" resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz#dd7ee3735e8a313b9f7b05a773d892e88e6d7295" integrity sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg== +"@babel/helper-plugin-utils@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.25.7.tgz#8ec5b21812d992e1ef88a9b068260537b6f0e36c" + integrity sha512-eaPZai0PiqCi09pPs3pAFfl/zYgGaE6IdXtYvmf0qlcDTd3WCtO7JWCcRd64e0EQrcYgiHibEZnOGsSY4QSgaw== + "@babel/helper-simple-access@^7.22.5": version "7.22.5" resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.22.5.tgz#4938357dc7d782b80ed6dbb03a0fba3d22b1d5de" @@ -185,6 +263,14 @@ dependencies: "@babel/types" "^7.22.5" +"@babel/helper-simple-access@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.25.7.tgz#5eb9f6a60c5d6b2e0f76057004f8dacbddfae1c0" + integrity sha512-FPGAkJmyoChQeM+ruBGIDyrT2tKfZJO8NcxdC+CWNJi7N8/rZpSxK7yvBJ5O/nF1gfu5KzN7VKG3YVSLFfRSxQ== + dependencies: + "@babel/traverse" "^7.25.7" + "@babel/types" "^7.25.7" + "@babel/helper-split-export-declaration@^7.22.6": version "7.22.6" resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz#322c61b7310c0997fe4c323955667f18fcefb91c" @@ -197,6 +283,11 @@ resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.22.5.tgz#533f36457a25814cf1df6488523ad547d784a99f" integrity sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw== +"@babel/helper-string-parser@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.25.7.tgz#d50e8d37b1176207b4fe9acedec386c565a44a54" + integrity sha512-CbkjYdsJNHFk8uqpEkpCvRs3YRp9tY6FmFY7wLMSYuGYkrdUi7r2lc4/wqsvlHoMznX3WJ9IP8giGPq68T/Y6g== + "@babel/helper-validator-identifier@^7.18.6": version "7.19.1" resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz#7eea834cf32901ffdc1a7ee555e2f9c27e249ca2" @@ -207,11 +298,21 @@ resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz#c4ae002c61d2879e724581d96665583dbc1dc0e0" integrity sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A== +"@babel/helper-validator-identifier@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.7.tgz#77b7f60c40b15c97df735b38a66ba1d7c3e93da5" + integrity sha512-AM6TzwYqGChO45oiuPqwL2t20/HdMC1rTPAesnBCgPCSF1x3oN9MVUwQV2iyz4xqWrctwK5RNC8LV22kaQCNYg== + "@babel/helper-validator-option@^7.22.15": version "7.22.15" resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.22.15.tgz#694c30dfa1d09a6534cdfcafbe56789d36aba040" integrity sha512-bMn7RmyFjY/mdECUbgn9eoSY4vqvacUnS9i9vGAGttgFWesO6B4CYWA7XlpbWgBt71iv/hfbPlynohStqnu5hA== +"@babel/helper-validator-option@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.25.7.tgz#97d1d684448228b30b506d90cace495d6f492729" + integrity sha512-ytbPLsm+GjArDYXJ8Ydr1c/KJuutjF2besPNbIZnZ6MKUxi/uTA22t2ymmA4WFjZFpjiAMO0xuuJPqK2nvDVfQ== + "@babel/helpers@^7.23.2": version "7.23.2" resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.23.2.tgz#2832549a6e37d484286e15ba36a5330483cac767" @@ -221,6 +322,14 @@ "@babel/traverse" "^7.23.2" "@babel/types" "^7.23.0" +"@babel/helpers@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.25.7.tgz#091b52cb697a171fe0136ab62e54e407211f09c2" + integrity sha512-Sv6pASx7Esm38KQpF/U/OXLwPPrdGHNKoeblRxgZRLXnAtnkEe4ptJPDtAZM7fBLadbc1Q07kQpSiGQ0Jg6tRA== + dependencies: + "@babel/template" "^7.25.7" + "@babel/types" "^7.25.7" + "@babel/highlight@^7.10.4", "@babel/highlight@^7.18.6": version "7.18.6" resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.18.6.tgz#81158601e93e2563795adcbfbdf5d64be3f2ecdf" @@ -239,11 +348,28 @@ chalk "^2.4.2" js-tokens "^4.0.0" +"@babel/highlight@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.25.7.tgz#20383b5f442aa606e7b5e3043b0b1aafe9f37de5" + integrity sha512-iYyACpW3iW8Fw+ZybQK+drQre+ns/tKpXbNESfrhNnPLIklLbXr7MYJ6gPEd0iETGLOK+SxMjVvKb/ffmk+FEw== + dependencies: + "@babel/helper-validator-identifier" "^7.25.7" + chalk "^2.4.2" + js-tokens "^4.0.0" + picocolors "^1.0.0" + "@babel/parser@^7.1.0", "@babel/parser@^7.14.7", "@babel/parser@^7.20.7", "@babel/parser@^7.22.15", "@babel/parser@^7.23.3": version "7.23.3" resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.23.3.tgz#0ce0be31a4ca4f1884b5786057cadcb6c3be58f9" integrity sha512-uVsWNvlVsIninV2prNz/3lHCb+5CJ+e+IUBfbjToAHODtfGYLfCFuY4AU7TskI+dAKk+njsPiBjq1gKTvZOBaw== +"@babel/parser@^7.23.9", "@babel/parser@^7.25.7", "@babel/parser@^7.25.8": + version "7.25.8" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.25.8.tgz#f6aaf38e80c36129460c1657c0762db584c9d5e2" + integrity sha512-HcttkxzdPucv3nNFmfOOMfFf64KgdJVqm1KaCm25dPGMLElo9nsLvXeJECQg8UzPuBGLyTSA0ZzqCtDSzKTEoQ== + dependencies: + "@babel/types" "^7.25.8" + "@babel/plugin-syntax-async-generators@^7.8.4": version "7.8.4" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz#a983fb1aeb2ec3f6ed042a210f640e90e786fe0d" @@ -279,6 +405,13 @@ dependencies: "@babel/helper-plugin-utils" "^7.8.0" +"@babel/plugin-syntax-jsx@^7.7.2": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.25.7.tgz#5352d398d11ea5e7ef330c854dea1dae0bf18165" + integrity sha512-ruZOnKO+ajVL/MVx+PwNBPOkrnXTXoWMtte1MBpegfCArhqOe3Bj52avVj1huLLxNKYKXYaSxZ2F+woK1ekXfw== + dependencies: + "@babel/helper-plugin-utils" "^7.25.7" + "@babel/plugin-syntax-logical-assignment-operators@^7.8.3": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz#ca91ef46303530448b906652bac2e9fe9941f699" @@ -328,6 +461,13 @@ dependencies: "@babel/helper-plugin-utils" "^7.14.5" +"@babel/plugin-syntax-typescript@^7.7.2": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.25.7.tgz#bfc05b0cc31ebd8af09964650cee723bb228108b" + integrity sha512-rR+5FDjpCHqqZN2bzZm18bVYGaejGq5ZkpVCJLXor/+zlSrSoc4KWcHI0URVWjl/68Dyr1uwZUz/1njycEAv9g== + dependencies: + "@babel/helper-plugin-utils" "^7.25.7" + "@babel/runtime@^7.12.5", "@babel/runtime@^7.16.0", "@babel/runtime@^7.6.2": version "7.22.5" resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.22.5.tgz#8564dd588182ce0047d55d7a75e93921107b57ec" @@ -344,7 +484,16 @@ "@babel/parser" "^7.22.15" "@babel/types" "^7.22.15" -"@babel/traverse@^7.1.0", "@babel/traverse@^7.23.2", "@babel/traverse@^7.23.3": +"@babel/template@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.25.7.tgz#27f69ce382855d915b14ab0fe5fb4cbf88fa0769" + integrity sha512-wRwtAgI3bAS+JGU2upWNL9lSlDcRCqD05BZ1n3X2ONLH1WilFP6O1otQjeMK/1g0pvYcXC7b/qVUB1keofjtZA== + dependencies: + "@babel/code-frame" "^7.25.7" + "@babel/parser" "^7.25.7" + "@babel/types" "^7.25.7" + +"@babel/traverse@^7.23.2", "@babel/traverse@^7.23.3": version "7.23.3" resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.23.3.tgz#26ee5f252e725aa7aca3474aa5b324eaf7908b5b" integrity sha512-+K0yF1/9yR0oHdE0StHuEj3uTPzwwbrLGfNOndVJVV2TqA5+j3oljJUb4nmB954FLGjNem976+B+eDuLIjesiQ== @@ -360,6 +509,19 @@ debug "^4.1.0" globals "^11.1.0" +"@babel/traverse@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.25.7.tgz#83e367619be1cab8e4f2892ef30ba04c26a40fa8" + integrity sha512-jatJPT1Zjqvh/1FyJs6qAHL+Dzb7sTb+xr7Q+gM1b+1oBsMsQQ4FkVKb6dFlJvLlVssqkRzV05Jzervt9yhnzg== + dependencies: + "@babel/code-frame" "^7.25.7" + "@babel/generator" "^7.25.7" + "@babel/parser" "^7.25.7" + "@babel/template" "^7.25.7" + "@babel/types" "^7.25.7" + debug "^4.3.1" + globals "^11.1.0" + "@babel/types@^7.0.0", "@babel/types@^7.20.7", "@babel/types@^7.22.15", "@babel/types@^7.22.5", "@babel/types@^7.23.0", "@babel/types@^7.23.3", "@babel/types@^7.3.3": version "7.23.3" resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.23.3.tgz#d5ea892c07f2ec371ac704420f4dcdb07b5f9598" @@ -369,19 +531,20 @@ "@babel/helper-validator-identifier" "^7.22.20" to-fast-properties "^2.0.0" +"@babel/types@^7.25.7", "@babel/types@^7.25.8": + version "7.25.8" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.25.8.tgz#5cf6037258e8a9bcad533f4979025140cb9993e1" + integrity sha512-JWtuCu8VQsMladxVz/P4HzHUGCAwpuqacmowgXFs5XjxIgKuNjnLokQzuVjlTvIzODaDmpjT3oxcC48vyk9EWg== + dependencies: + "@babel/helper-string-parser" "^7.25.7" + "@babel/helper-validator-identifier" "^7.25.7" + to-fast-properties "^2.0.0" + "@bcoe/v8-coverage@^0.2.3": version "0.2.3" resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39" integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw== -"@cnakazawa/watch@^1.0.3": - version "1.0.4" - resolved "https://registry.yarnpkg.com/@cnakazawa/watch/-/watch-1.0.4.tgz#f864ae85004d0fcab6f50be9141c4da368d1656a" - integrity sha512-v9kIhKwjeZThiWrLmj0y17CWoyddASLj9O2yvbZkbvw/N3rWOYy9zkV66ursAoVr0mV15bL8g0c4QZUE6cdDoQ== - dependencies: - exec-sh "^0.3.2" - minimist "^1.2.0" - "@colors/colors@1.5.0": version "1.5.0" resolved "https://registry.yarnpkg.com/@colors/colors/-/colors-1.5.0.tgz#bb504579c1cae923e6576a4f5da43d25f97bdbd9" @@ -588,170 +751,190 @@ js-yaml "^3.13.1" resolve-from "^5.0.0" -"@istanbuljs/schema@^0.1.2": +"@istanbuljs/schema@^0.1.2", "@istanbuljs/schema@^0.1.3": version "0.1.3" resolved "https://registry.yarnpkg.com/@istanbuljs/schema/-/schema-0.1.3.tgz#e45e384e4b8ec16bce2fd903af78450f6bf7ec98" integrity sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA== -"@jest/console@^26.6.2": - version "26.6.2" - resolved "https://registry.yarnpkg.com/@jest/console/-/console-26.6.2.tgz#4e04bc464014358b03ab4937805ee36a0aeb98f2" - integrity sha512-IY1R2i2aLsLr7Id3S6p2BA82GNWryt4oSvEXLAKc+L2zdi89dSkE8xC1C+0kpATG4JhBJREnQOH7/zmccM2B0g== +"@jest/console@^29.7.0": + version "29.7.0" + resolved "https://registry.yarnpkg.com/@jest/console/-/console-29.7.0.tgz#cd4822dbdb84529265c5a2bdb529a3c9cc950ffc" + integrity sha512-5Ni4CU7XHQi32IJ398EEP4RrB8eV09sXP2ROqD4bksHrnTree52PsxvX8tpL8LvTZ3pFzXyPbNQReSN41CAhOg== dependencies: - "@jest/types" "^26.6.2" + "@jest/types" "^29.6.3" "@types/node" "*" chalk "^4.0.0" - jest-message-util "^26.6.2" - jest-util "^26.6.2" + jest-message-util "^29.7.0" + jest-util "^29.7.0" slash "^3.0.0" -"@jest/core@^26.6.3": - version "26.6.3" - resolved "https://registry.yarnpkg.com/@jest/core/-/core-26.6.3.tgz#7639fcb3833d748a4656ada54bde193051e45fad" - integrity sha512-xvV1kKbhfUqFVuZ8Cyo+JPpipAHHAV3kcDBftiduK8EICXmTFddryy3P7NfZt8Pv37rA9nEJBKCCkglCPt/Xjw== +"@jest/core@^29.7.0": + version "29.7.0" + resolved "https://registry.yarnpkg.com/@jest/core/-/core-29.7.0.tgz#b6cccc239f30ff36609658c5a5e2291757ce448f" + integrity sha512-n7aeXWKMnGtDA48y8TLWJPJmLmmZ642Ceo78cYWEpiD7FzDgmNDV/GCVRorPABdXLJZ/9wzzgZAlHjXjxDHGsg== dependencies: - "@jest/console" "^26.6.2" - "@jest/reporters" "^26.6.2" - "@jest/test-result" "^26.6.2" - "@jest/transform" "^26.6.2" - "@jest/types" "^26.6.2" + "@jest/console" "^29.7.0" + "@jest/reporters" "^29.7.0" + "@jest/test-result" "^29.7.0" + "@jest/transform" "^29.7.0" + "@jest/types" "^29.6.3" "@types/node" "*" ansi-escapes "^4.2.1" chalk "^4.0.0" + ci-info "^3.2.0" exit "^0.1.2" - graceful-fs "^4.2.4" - jest-changed-files "^26.6.2" - jest-config "^26.6.3" - jest-haste-map "^26.6.2" - jest-message-util "^26.6.2" - jest-regex-util "^26.0.0" - jest-resolve "^26.6.2" - jest-resolve-dependencies "^26.6.3" - jest-runner "^26.6.3" - jest-runtime "^26.6.3" - jest-snapshot "^26.6.2" - jest-util "^26.6.2" - jest-validate "^26.6.2" - jest-watcher "^26.6.2" - micromatch "^4.0.2" - p-each-series "^2.1.0" - rimraf "^3.0.0" + graceful-fs "^4.2.9" + jest-changed-files "^29.7.0" + jest-config "^29.7.0" + jest-haste-map "^29.7.0" + jest-message-util "^29.7.0" + jest-regex-util "^29.6.3" + jest-resolve "^29.7.0" + jest-resolve-dependencies "^29.7.0" + jest-runner "^29.7.0" + jest-runtime "^29.7.0" + jest-snapshot "^29.7.0" + jest-util "^29.7.0" + jest-validate "^29.7.0" + jest-watcher "^29.7.0" + micromatch "^4.0.4" + pretty-format "^29.7.0" slash "^3.0.0" strip-ansi "^6.0.0" -"@jest/environment@^26.6.2": - version "26.6.2" - resolved "https://registry.yarnpkg.com/@jest/environment/-/environment-26.6.2.tgz#ba364cc72e221e79cc8f0a99555bf5d7577cf92c" - integrity sha512-nFy+fHl28zUrRsCeMB61VDThV1pVTtlEokBRgqPrcT1JNq4yRNIyTHfyht6PqtUvY9IsuLGTrbG8kPXjSZIZwA== +"@jest/environment@^29.7.0": + version "29.7.0" + resolved "https://registry.yarnpkg.com/@jest/environment/-/environment-29.7.0.tgz#24d61f54ff1f786f3cd4073b4b94416383baf2a7" + integrity sha512-aQIfHDq33ExsN4jP1NWGXhxgQ/wixs60gDiKO+XVMd8Mn0NWPWgc34ZQDTb2jKaUWQ7MuwoitXAsN2XVXNMpAw== dependencies: - "@jest/fake-timers" "^26.6.2" - "@jest/types" "^26.6.2" + "@jest/fake-timers" "^29.7.0" + "@jest/types" "^29.6.3" "@types/node" "*" - jest-mock "^26.6.2" + jest-mock "^29.7.0" -"@jest/fake-timers@^26.6.2": - version "26.6.2" - resolved "https://registry.yarnpkg.com/@jest/fake-timers/-/fake-timers-26.6.2.tgz#459c329bcf70cee4af4d7e3f3e67848123535aad" - integrity sha512-14Uleatt7jdzefLPYM3KLcnUl1ZNikaKq34enpb5XG9i81JpppDb5muZvonvKyrl7ftEHkKS5L5/eB/kxJ+bvA== +"@jest/expect-utils@^29.7.0": + version "29.7.0" + resolved "https://registry.yarnpkg.com/@jest/expect-utils/-/expect-utils-29.7.0.tgz#023efe5d26a8a70f21677d0a1afc0f0a44e3a1c6" + integrity sha512-GlsNBWiFQFCVi9QVSx7f5AgMeLxe9YCCs5PuP2O2LdjDAA8Jh9eX7lA1Jq/xdXw3Wb3hyvlFNfZIfcRetSzYcA== dependencies: - "@jest/types" "^26.6.2" - "@sinonjs/fake-timers" "^6.0.1" + jest-get-type "^29.6.3" + +"@jest/expect@^29.7.0": + version "29.7.0" + resolved "https://registry.yarnpkg.com/@jest/expect/-/expect-29.7.0.tgz#76a3edb0cb753b70dfbfe23283510d3d45432bf2" + integrity sha512-8uMeAMycttpva3P1lBHB8VciS9V0XAr3GymPpipdyQXbBcuhkLQOSe8E/p92RyAdToS6ZD1tFkX+CkhoECE0dQ== + dependencies: + expect "^29.7.0" + jest-snapshot "^29.7.0" + +"@jest/fake-timers@^29.7.0": + version "29.7.0" + resolved "https://registry.yarnpkg.com/@jest/fake-timers/-/fake-timers-29.7.0.tgz#fd91bf1fffb16d7d0d24a426ab1a47a49881a565" + integrity sha512-q4DH1Ha4TTFPdxLsqDXK1d3+ioSL7yL5oCMJZgDYm6i+6CygW5E5xVr/D1HdsGxjt1ZWSfUAs9OxSB/BNelWrQ== + dependencies: + "@jest/types" "^29.6.3" + "@sinonjs/fake-timers" "^10.0.2" "@types/node" "*" - jest-message-util "^26.6.2" - jest-mock "^26.6.2" - jest-util "^26.6.2" + jest-message-util "^29.7.0" + jest-mock "^29.7.0" + jest-util "^29.7.0" -"@jest/globals@^26.6.2": - version "26.6.2" - resolved "https://registry.yarnpkg.com/@jest/globals/-/globals-26.6.2.tgz#5b613b78a1aa2655ae908eba638cc96a20df720a" - integrity sha512-85Ltnm7HlB/KesBUuALwQ68YTU72w9H2xW9FjZ1eL1U3lhtefjjl5c2MiUbpXt/i6LaPRvoOFJ22yCBSfQ0JIA== +"@jest/globals@^29.7.0": + version "29.7.0" + resolved "https://registry.yarnpkg.com/@jest/globals/-/globals-29.7.0.tgz#8d9290f9ec47ff772607fa864ca1d5a2efae1d4d" + integrity sha512-mpiz3dutLbkW2MNFubUGUEVLkTGiqW6yLVTA+JbP6fI6J5iL9Y0Nlg8k95pcF8ctKwCS7WVxteBs29hhfAotzQ== dependencies: - "@jest/environment" "^26.6.2" - "@jest/types" "^26.6.2" - expect "^26.6.2" + "@jest/environment" "^29.7.0" + "@jest/expect" "^29.7.0" + "@jest/types" "^29.6.3" + jest-mock "^29.7.0" -"@jest/reporters@^26.6.2": - version "26.6.2" - resolved "https://registry.yarnpkg.com/@jest/reporters/-/reporters-26.6.2.tgz#1f518b99637a5f18307bd3ecf9275f6882a667f6" - integrity sha512-h2bW53APG4HvkOnVMo8q3QXa6pcaNt1HkwVsOPMBV6LD/q9oSpxNSYZQYkAnjdMjrJ86UuYeLo+aEZClV6opnw== +"@jest/reporters@^29.7.0": + version "29.7.0" + resolved "https://registry.yarnpkg.com/@jest/reporters/-/reporters-29.7.0.tgz#04b262ecb3b8faa83b0b3d321623972393e8f4c7" + integrity sha512-DApq0KJbJOEzAFYjHADNNxAE3KbhxQB1y5Kplb5Waqw6zVbuWatSnMjE5gs8FUgEPmNsnZA3NCWl9NG0ia04Pg== dependencies: "@bcoe/v8-coverage" "^0.2.3" - "@jest/console" "^26.6.2" - "@jest/test-result" "^26.6.2" - "@jest/transform" "^26.6.2" - "@jest/types" "^26.6.2" + "@jest/console" "^29.7.0" + "@jest/test-result" "^29.7.0" + "@jest/transform" "^29.7.0" + "@jest/types" "^29.6.3" + "@jridgewell/trace-mapping" "^0.3.18" + "@types/node" "*" chalk "^4.0.0" collect-v8-coverage "^1.0.0" exit "^0.1.2" - glob "^7.1.2" - graceful-fs "^4.2.4" + glob "^7.1.3" + graceful-fs "^4.2.9" istanbul-lib-coverage "^3.0.0" - istanbul-lib-instrument "^4.0.3" + istanbul-lib-instrument "^6.0.0" istanbul-lib-report "^3.0.0" istanbul-lib-source-maps "^4.0.0" - istanbul-reports "^3.0.2" - jest-haste-map "^26.6.2" - jest-resolve "^26.6.2" - jest-util "^26.6.2" - jest-worker "^26.6.2" + istanbul-reports "^3.1.3" + jest-message-util "^29.7.0" + jest-util "^29.7.0" + jest-worker "^29.7.0" slash "^3.0.0" - source-map "^0.6.0" string-length "^4.0.1" - terminal-link "^2.0.0" - v8-to-istanbul "^7.0.0" - optionalDependencies: - node-notifier "^8.0.0" + strip-ansi "^6.0.0" + v8-to-istanbul "^9.0.1" -"@jest/source-map@^26.6.2": - version "26.6.2" - resolved "https://registry.yarnpkg.com/@jest/source-map/-/source-map-26.6.2.tgz#29af5e1e2e324cafccc936f218309f54ab69d535" - integrity sha512-YwYcCwAnNmOVsZ8mr3GfnzdXDAl4LaenZP5z+G0c8bzC9/dugL8zRmxZzdoTl4IaS3CryS1uWnROLPFmb6lVvA== +"@jest/schemas@^29.6.3": + version "29.6.3" + resolved "https://registry.yarnpkg.com/@jest/schemas/-/schemas-29.6.3.tgz#430b5ce8a4e0044a7e3819663305a7b3091c8e03" + integrity sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA== + dependencies: + "@sinclair/typebox" "^0.27.8" + +"@jest/source-map@^29.6.3": + version "29.6.3" + resolved "https://registry.yarnpkg.com/@jest/source-map/-/source-map-29.6.3.tgz#d90ba772095cf37a34a5eb9413f1b562a08554c4" + integrity sha512-MHjT95QuipcPrpLM+8JMSzFx6eHp5Bm+4XeFDJlwsvVBjmKNiIAvasGK2fxz2WbGRlnvqehFbh07MMa7n3YJnw== dependencies: + "@jridgewell/trace-mapping" "^0.3.18" callsites "^3.0.0" - graceful-fs "^4.2.4" - source-map "^0.6.0" + graceful-fs "^4.2.9" -"@jest/test-result@^26.6.2": - version "26.6.2" - resolved "https://registry.yarnpkg.com/@jest/test-result/-/test-result-26.6.2.tgz#55da58b62df134576cc95476efa5f7949e3f5f18" - integrity sha512-5O7H5c/7YlojphYNrK02LlDIV2GNPYisKwHm2QTKjNZeEzezCbwYs9swJySv2UfPMyZ0VdsmMv7jIlD/IKYQpQ== +"@jest/test-result@^29.7.0": + version "29.7.0" + resolved "https://registry.yarnpkg.com/@jest/test-result/-/test-result-29.7.0.tgz#8db9a80aa1a097bb2262572686734baed9b1657c" + integrity sha512-Fdx+tv6x1zlkJPcWXmMDAG2HBnaR9XPSd5aDWQVsfrZmLVT3lU1cwyxLgRmXR9yrq4NBoEm9BMsfgFzTQAbJYA== dependencies: - "@jest/console" "^26.6.2" - "@jest/types" "^26.6.2" + "@jest/console" "^29.7.0" + "@jest/types" "^29.6.3" "@types/istanbul-lib-coverage" "^2.0.0" collect-v8-coverage "^1.0.0" -"@jest/test-sequencer@^26.6.3": - version "26.6.3" - resolved "https://registry.yarnpkg.com/@jest/test-sequencer/-/test-sequencer-26.6.3.tgz#98e8a45100863886d074205e8ffdc5a7eb582b17" - integrity sha512-YHlVIjP5nfEyjlrSr8t/YdNfU/1XEt7c5b4OxcXCjyRhjzLYu/rO69/WHPuYcbCWkz8kAeZVZp2N2+IOLLEPGw== +"@jest/test-sequencer@^29.7.0": + version "29.7.0" + resolved "https://registry.yarnpkg.com/@jest/test-sequencer/-/test-sequencer-29.7.0.tgz#6cef977ce1d39834a3aea887a1726628a6f072ce" + integrity sha512-GQwJ5WZVrKnOJuiYiAF52UNUJXgTZx1NHjFSEB0qEMmSZKAkdMoIzw/Cj6x6NF4AvV23AUqDpFzQkN/eYCYTxw== dependencies: - "@jest/test-result" "^26.6.2" - graceful-fs "^4.2.4" - jest-haste-map "^26.6.2" - jest-runner "^26.6.3" - jest-runtime "^26.6.3" + "@jest/test-result" "^29.7.0" + graceful-fs "^4.2.9" + jest-haste-map "^29.7.0" + slash "^3.0.0" -"@jest/transform@^26.6.2": - version "26.6.2" - resolved "https://registry.yarnpkg.com/@jest/transform/-/transform-26.6.2.tgz#5ac57c5fa1ad17b2aae83e73e45813894dcf2e4b" - integrity sha512-E9JjhUgNzvuQ+vVAL21vlyfy12gP0GhazGgJC4h6qUt1jSdUXGWJ1wfu/X7Sd8etSgxV4ovT1pb9v5D6QW4XgA== +"@jest/transform@^29.7.0": + version "29.7.0" + resolved "https://registry.yarnpkg.com/@jest/transform/-/transform-29.7.0.tgz#df2dd9c346c7d7768b8a06639994640c642e284c" + integrity sha512-ok/BTPFzFKVMwO5eOHRrvnBVHdRy9IrsrW1GpMaQ9MCnilNLXQKmAX8s1YXDFaai9xJpac2ySzV0YeRRECr2Vw== dependencies: - "@babel/core" "^7.1.0" - "@jest/types" "^26.6.2" - babel-plugin-istanbul "^6.0.0" + "@babel/core" "^7.11.6" + "@jest/types" "^29.6.3" + "@jridgewell/trace-mapping" "^0.3.18" + babel-plugin-istanbul "^6.1.1" chalk "^4.0.0" - convert-source-map "^1.4.0" - fast-json-stable-stringify "^2.0.0" - graceful-fs "^4.2.4" - jest-haste-map "^26.6.2" - jest-regex-util "^26.0.0" - jest-util "^26.6.2" - micromatch "^4.0.2" - pirates "^4.0.1" + convert-source-map "^2.0.0" + fast-json-stable-stringify "^2.1.0" + graceful-fs "^4.2.9" + jest-haste-map "^29.7.0" + jest-regex-util "^29.6.3" + jest-util "^29.7.0" + micromatch "^4.0.4" + pirates "^4.0.4" slash "^3.0.0" - source-map "^0.6.1" - write-file-atomic "^3.0.0" + write-file-atomic "^4.0.2" "@jest/types@^26.6.2": version "26.6.2" @@ -764,6 +947,18 @@ "@types/yargs" "^15.0.0" chalk "^4.0.0" +"@jest/types@^29.6.3": + version "29.6.3" + resolved "https://registry.yarnpkg.com/@jest/types/-/types-29.6.3.tgz#1131f8cf634e7e84c5e77bab12f052af585fba59" + integrity sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw== + dependencies: + "@jest/schemas" "^29.6.3" + "@types/istanbul-lib-coverage" "^2.0.0" + "@types/istanbul-reports" "^3.0.0" + "@types/node" "*" + "@types/yargs" "^17.0.8" + chalk "^4.0.0" + "@jridgewell/gen-mapping@^0.3.0", "@jridgewell/gen-mapping@^0.3.2": version "0.3.3" resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz#7e02e6eb5df901aaedb08514203b096614024098" @@ -773,16 +968,35 @@ "@jridgewell/sourcemap-codec" "^1.4.10" "@jridgewell/trace-mapping" "^0.3.9" +"@jridgewell/gen-mapping@^0.3.5": + version "0.3.5" + resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz#dcce6aff74bdf6dad1a95802b69b04a2fcb1fb36" + integrity sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg== + dependencies: + "@jridgewell/set-array" "^1.2.1" + "@jridgewell/sourcemap-codec" "^1.4.10" + "@jridgewell/trace-mapping" "^0.3.24" + "@jridgewell/resolve-uri@3.1.0": version "3.1.0" resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz#2203b118c157721addfe69d47b70465463066d78" integrity sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w== +"@jridgewell/resolve-uri@^3.1.0": + version "3.1.2" + resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz#7a0ee601f60f99a20c7c7c5ff0c80388c1189bd6" + integrity sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw== + "@jridgewell/set-array@^1.0.1": version "1.1.2" resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.1.2.tgz#7c6cf998d6d20b914c0a55a91ae928ff25965e72" integrity sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw== +"@jridgewell/set-array@^1.2.1": + version "1.2.1" + resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.2.1.tgz#558fb6472ed16a4c850b889530e6b36438c49280" + integrity sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A== + "@jridgewell/source-map@^0.3.2": version "0.3.3" resolved "https://registry.yarnpkg.com/@jridgewell/source-map/-/source-map-0.3.3.tgz#8108265659d4c33e72ffe14e33d6cc5eb59f2fda" @@ -801,6 +1015,19 @@ resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz#d7c6e6755c78567a951e04ab52ef0fd26de59f32" integrity sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg== +"@jridgewell/sourcemap-codec@^1.4.14": + version "1.5.0" + resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz#3188bcb273a414b0d215fd22a58540b989b9409a" + integrity sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ== + +"@jridgewell/trace-mapping@^0.3.12", "@jridgewell/trace-mapping@^0.3.18", "@jridgewell/trace-mapping@^0.3.24", "@jridgewell/trace-mapping@^0.3.25": + version "0.3.25" + resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz#15f190e98895f3fc23276ee14bc76b675c2e50f0" + integrity sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ== + dependencies: + "@jridgewell/resolve-uri" "^3.1.0" + "@jridgewell/sourcemap-codec" "^1.4.14" + "@jridgewell/trace-mapping@^0.3.17", "@jridgewell/trace-mapping@^0.3.9": version "0.3.18" resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.18.tgz#25783b2086daf6ff1dcb53c9249ae480e4dd4cd6" @@ -1139,19 +1366,24 @@ resolved "https://registry.yarnpkg.com/@sideway/pinpoint/-/pinpoint-2.0.0.tgz#cff8ffadc372ad29fd3f78277aeb29e632cc70df" integrity sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ== -"@sinonjs/commons@^1.7.0": - version "1.8.6" - resolved "https://registry.yarnpkg.com/@sinonjs/commons/-/commons-1.8.6.tgz#80c516a4dc264c2a69115e7578d62581ff455ed9" - integrity sha512-Ky+XkAkqPZSm3NLBeUng77EBQl3cmeJhITaGHdYH8kjVB+aun3S4XBRti2zt17mtt0mIUDiNxYeoJm6drVvBJQ== +"@sinclair/typebox@^0.27.8": + version "0.27.8" + resolved "https://registry.yarnpkg.com/@sinclair/typebox/-/typebox-0.27.8.tgz#6667fac16c436b5434a387a34dedb013198f6e6e" + integrity sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA== + +"@sinonjs/commons@^3.0.0": + version "3.0.1" + resolved "https://registry.yarnpkg.com/@sinonjs/commons/-/commons-3.0.1.tgz#1029357e44ca901a615585f6d27738dbc89084cd" + integrity sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ== dependencies: type-detect "4.0.8" -"@sinonjs/fake-timers@^6.0.1": - version "6.0.1" - resolved "https://registry.yarnpkg.com/@sinonjs/fake-timers/-/fake-timers-6.0.1.tgz#293674fccb3262ac782c7aadfdeca86b10c75c40" - integrity sha512-MZPUxrmFubI36XS1DI3qmI0YdN1gks62JtFZvxR67ljjSNCeK6U08Zx4msEWOXuofgqUt6zPHSi1H9fbjR/NRA== +"@sinonjs/fake-timers@^10.0.2": + version "10.3.0" + resolved "https://registry.yarnpkg.com/@sinonjs/fake-timers/-/fake-timers-10.3.0.tgz#55fdff1ecab9f354019129daf4df0dd4d923ea66" + integrity sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA== dependencies: - "@sinonjs/commons" "^1.7.0" + "@sinonjs/commons" "^3.0.0" "@socket.io/component-emitter@~3.1.0": version "3.1.0" @@ -1180,10 +1412,10 @@ dependencies: "@types/node" "*" -"@types/babel__core@^7.0.0", "@types/babel__core@^7.1.7": - version "7.20.4" - resolved "https://registry.yarnpkg.com/@types/babel__core/-/babel__core-7.20.4.tgz#26a87347e6c6f753b3668398e34496d6d9ac6ac0" - integrity sha512-mLnSC22IC4vcWiuObSRjrLd9XcBTGf59vUSoq2jkQDJ/QQ8PMI9rSuzE+aEV8karUMbskw07bKYoUJCKTUaygg== +"@types/babel__core@^7.1.14": + version "7.20.5" + resolved "https://registry.yarnpkg.com/@types/babel__core/-/babel__core-7.20.5.tgz#3df15f27ba85319caa07ba08d0721889bb39c017" + integrity sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA== dependencies: "@babel/parser" "^7.20.7" "@babel/types" "^7.20.7" @@ -1206,7 +1438,7 @@ "@babel/parser" "^7.1.0" "@babel/types" "^7.0.0" -"@types/babel__traverse@*", "@types/babel__traverse@^7.0.4", "@types/babel__traverse@^7.0.6": +"@types/babel__traverse@*", "@types/babel__traverse@^7.0.6": version "7.20.4" resolved "https://registry.yarnpkg.com/@types/babel__traverse/-/babel__traverse-7.20.4.tgz#ec2c06fed6549df8bc0eb4615b683749a4a92e1b" integrity sha512-mSM/iKUk5fDDrEV/e83qY+Cr3I1+Q3qqTuEn++HAWYjEa1+NxZr6CNrcJGf2ZTnq4HoFGC3zaTPZTobCzCFukA== @@ -1286,7 +1518,7 @@ "@types/qs" "*" "@types/serve-static" "*" -"@types/graceful-fs@^4.1.2": +"@types/graceful-fs@^4.1.3": version "4.1.9" resolved "https://registry.yarnpkg.com/@types/graceful-fs/-/graceful-fs-4.1.9.tgz#2a06bc0f68a20ab37b3e36aa238be6abdf49e8b4" integrity sha512-olP3sd1qOEe5dXTSaFvQG+02VdRXcdytWLAZsAq1PecU8uqQAhkrnbli7DagjtXKW/Bl7YJbUsa8MPcuc8LHEQ== @@ -1360,21 +1592,11 @@ resolved "https://registry.yarnpkg.com/@types/node/-/node-14.14.10.tgz#5958a82e41863cfc71f2307b3748e3491ba03785" integrity sha512-J32dgx2hw8vXrSbu4ZlVhn1Nm3GbeCFNw2FWL8S5QKucHGY0cyNwjdQdO+KMBZ4wpmC7KhLCiNsdk1RFRIYUQQ== -"@types/normalize-package-data@^2.4.0": - version "2.4.4" - resolved "https://registry.yarnpkg.com/@types/normalize-package-data/-/normalize-package-data-2.4.4.tgz#56e2cc26c397c038fab0e3a917a12d5c5909e901" - integrity sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA== - "@types/parse-json@^4.0.0": version "4.0.0" resolved "https://registry.yarnpkg.com/@types/parse-json/-/parse-json-4.0.0.tgz#2f8bb441434d163b35fb8ffdccd7138927ffb8c0" integrity sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA== -"@types/prettier@^2.0.0": - version "2.7.3" - resolved "https://registry.yarnpkg.com/@types/prettier/-/prettier-2.7.3.tgz#3e51a17e291d01d17d3fc61422015a933af7a08f" - integrity sha512-+68kP9yzs4LMp7VNh8gdzMSPZFL44MLGqiHWvttYJe+6qnuVr4Ek9wSBQoveqY/r+LwjCcU29kNVkidwim+kYA== - "@types/qs@*": version "6.9.7" resolved "https://registry.yarnpkg.com/@types/qs/-/qs-6.9.7.tgz#63bb7d067db107cc1e457c303bc25d511febf6cb" @@ -1462,6 +1684,13 @@ dependencies: "@types/yargs-parser" "*" +"@types/yargs@^17.0.8": + version "17.0.33" + resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-17.0.33.tgz#8c32303da83eec050a84b3c7ae7b9f922d13e32d" + integrity sha512-WpxBCKWPLr4xSsHgz511rFJAM+wS28w2zEO1QDNY5zM/S8ok70NNfztH0xwhqKyaK0OHCbN98LDAZuy1ctxDkA== + dependencies: + "@types/yargs-parser" "*" + "@typescript-eslint/eslint-plugin@^4.8.1": version "4.33.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.33.0.tgz#c24dc7c8069c7706bc40d99f6fa87edcb2005276" @@ -1673,11 +1902,6 @@ Base64@1.1.0: resolved "https://registry.yarnpkg.com/Base64/-/Base64-1.1.0.tgz#810ef21afa8357df92ad7b5389188c446b9cb956" integrity sha512-qeacf8dvGpf+XAT27ESHMh7z84uRzj/ua2pQdJg483m3bEXv/kVFtDnMgvf70BQGqzbZhR9t6BmASzKvqfJf3Q== -abab@^2.0.3, abab@^2.0.5: - version "2.0.6" - resolved "https://registry.yarnpkg.com/abab/-/abab-2.0.6.tgz#41b80f2c871d19686216b82309231cfd3cb3d291" - integrity sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA== - abbrev@1: version "1.1.1" resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" @@ -1698,14 +1922,6 @@ accepts@~1.3.4, accepts@~1.3.8: mime-types "~2.1.34" negotiator "0.6.3" -acorn-globals@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/acorn-globals/-/acorn-globals-6.0.0.tgz#46cdd39f0f8ff08a876619b55f5ac8a6dc770b45" - integrity sha512-ZQl7LOWaF5ePqqcX4hLuv/bLXYQNfNWw2c0/yX/TsPRKamzHcTGQnlCjHT3TsmkOUVEPS3crCxiPfdzE/Trlhg== - dependencies: - acorn "^7.1.1" - acorn-walk "^7.1.1" - acorn-import-assertions@^1.7.6: version "1.8.0" resolved "https://registry.yarnpkg.com/acorn-import-assertions/-/acorn-import-assertions-1.8.0.tgz#ba2b5939ce62c238db6d93d81c9b111b29b855e9" @@ -1716,21 +1932,11 @@ acorn-jsx@^5.3.1: resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937" integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ== -acorn-walk@^7.1.1: - version "7.2.0" - resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-7.2.0.tgz#0de889a601203909b0fbe07b8938dc21d2e967bc" - integrity sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA== - -acorn@^7.1.1, acorn@^7.4.0: +acorn@^7.4.0: version "7.4.1" resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.4.1.tgz#feaed255973d2e77555b83dbc08851a6c63520fa" integrity sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A== -acorn@^8.2.4: - version "8.11.2" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.11.2.tgz#ca0d78b51895be5390a5903c5b3bdcdaf78ae40b" - integrity sha512-nc0Axzp/0FILLEVsm4fNwLCwMttvhEI263QtVPQcbpfZZ3ts0hLsZGOpE6czNlid7CJ9MlyH8reXkpsf3YUY4w== - acorn@^8.5.0, acorn@^8.7.1: version "8.8.2" resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.8.2.tgz#1b2f25db02af965399b9776b0c2c391276d37c4a" @@ -1846,19 +2052,16 @@ ansi-styles@^4.0.0, ansi-styles@^4.1.0: dependencies: color-convert "^2.0.1" +ansi-styles@^5.0.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-5.2.0.tgz#07449690ad45777d1924ac2abb2fc8895dba836b" + integrity sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA== + any-promise@^1.0.0: version "1.3.0" resolved "https://registry.yarnpkg.com/any-promise/-/any-promise-1.3.0.tgz#abc6afeedcea52e809cdc0376aed3ce39635d17f" integrity sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A== -anymatch@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-2.0.0.tgz#bcb24b4f37934d9aa7ac17b4adaf89e7c76ef2eb" - integrity sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw== - dependencies: - micromatch "^3.1.4" - normalize-path "^2.1.1" - anymatch@^3.0.3, anymatch@~3.1.1, anymatch@~3.1.2: version "3.1.3" resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.3.tgz#790c58b19ba1720a84205b57c618d5ad8524973e" @@ -1919,21 +2122,6 @@ argparse@^2.0.1: resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38" integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q== -arr-diff@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-4.0.0.tgz#d6461074febfec71e7e15235761a329a5dc7c520" - integrity sha512-YVIQ82gZPGBebQV/a8dar4AitzCQs0jjXwMPZllpXMaGjXPYVUawSxQrRsjhjupyVxEvbHgUmIhKVlND+j02kA== - -arr-flatten@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/arr-flatten/-/arr-flatten-1.1.0.tgz#36048bbff4e7b47e136644316c99669ea5ae91f1" - integrity sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg== - -arr-union@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/arr-union/-/arr-union-3.1.0.tgz#e39b09aea9def866a8f206e288af63919bae39c4" - integrity sha512-sKpyeERZ02v1FeCZT8lrfJq5u6goHCtpTAzPwJYe7c8SPFOboNjNg1vz2L4VTn9T4PQxEx13TbXLmYUcS6Ug7Q== - array-buffer-byte-length@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/array-buffer-byte-length/-/array-buffer-byte-length-1.0.0.tgz#fabe8bc193fea865f317fe7807085ee0dee5aead" @@ -1963,11 +2151,6 @@ array-union@^2.1.0: resolved "https://registry.yarnpkg.com/array-union/-/array-union-2.1.0.tgz#b798420adbeb1de828d84acd8a2e23d3efe85e8d" integrity sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw== -array-unique@^0.3.2: - version "0.3.2" - resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.3.2.tgz#a894b75d4bc4f6cd679ef3244a9fd8f46ae2d428" - integrity sha512-SleRWjh9JUud2wH1hPs9rZBZ33H6T9HOiL0uwGnGx9FpE6wKGyfWugmbkEOIs6qWrZhg0LWeLziLrEwQJhs5mQ== - array.prototype.flat@^1.3.1: version "1.3.1" resolved "https://registry.yarnpkg.com/array.prototype.flat/-/array.prototype.flat-1.3.1.tgz#ffc6576a7ca3efc2f46a143b9d1dda9b4b3cf5e2" @@ -2014,11 +2197,6 @@ assertion-error@^1.1.0: resolved "https://registry.yarnpkg.com/assertion-error/-/assertion-error-1.1.0.tgz#e60b6b0e8f301bd97e5375215bda406c85118c0b" integrity sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw== -assign-symbols@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/assign-symbols/-/assign-symbols-1.0.0.tgz#59667f41fadd4f20ccbc2bb96b8d4f7f78ec0367" - integrity sha512-Q+JC7Whu8HhmTdBph/Tq59IoRtoy6KAm5zzPv00WdujX82lbAL8K7WVjne7vdCsAmbF4AYaDOPyO3k0kl8qIrw== - astral-regex@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-2.0.0.tgz#483143c567aeed4785759c0865786dc77d7d2e31" @@ -2053,21 +2231,20 @@ axios@^1.7.4: form-data "^4.0.0" proxy-from-env "^1.1.0" -babel-jest@^26.6.3: - version "26.6.3" - resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-26.6.3.tgz#d87d25cb0037577a0c89f82e5755c5d293c01056" - integrity sha512-pl4Q+GAVOHwvjrck6jKjvmGhnO3jHX/xuB9d27f+EJZ/6k+6nMuPjorrYp7s++bKKdANwzElBWnLWaObvTnaZA== +babel-jest@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-29.7.0.tgz#f4369919225b684c56085998ac63dbd05be020d5" + integrity sha512-BrvGY3xZSwEcCzKvKsCi2GgHqDqsYkOP4/by5xCgIwGXQxIEh+8ew3gmrE1y7XRR6LHZIj6yLYnUi/mm2KXKBg== dependencies: - "@jest/transform" "^26.6.2" - "@jest/types" "^26.6.2" - "@types/babel__core" "^7.1.7" - babel-plugin-istanbul "^6.0.0" - babel-preset-jest "^26.6.2" + "@jest/transform" "^29.7.0" + "@types/babel__core" "^7.1.14" + babel-plugin-istanbul "^6.1.1" + babel-preset-jest "^29.6.3" chalk "^4.0.0" - graceful-fs "^4.2.4" + graceful-fs "^4.2.9" slash "^3.0.0" -babel-plugin-istanbul@^6.0.0: +babel-plugin-istanbul@^6.1.1: version "6.1.1" resolved "https://registry.yarnpkg.com/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz#fa88ec59232fd9b4e36dbbc540a8ec9a9b47da73" integrity sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA== @@ -2078,14 +2255,14 @@ babel-plugin-istanbul@^6.0.0: istanbul-lib-instrument "^5.0.4" test-exclude "^6.0.0" -babel-plugin-jest-hoist@^26.6.2: - version "26.6.2" - resolved "https://registry.yarnpkg.com/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-26.6.2.tgz#8185bd030348d254c6d7dd974355e6a28b21e62d" - integrity sha512-PO9t0697lNTmcEHH69mdtYiOIkkOlj9fySqfO3K1eCcdISevLAE0xY59VLLUj0SoiPiTX/JU2CYFpILydUa5Lw== +babel-plugin-jest-hoist@^29.6.3: + version "29.6.3" + resolved "https://registry.yarnpkg.com/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-29.6.3.tgz#aadbe943464182a8922c3c927c3067ff40d24626" + integrity sha512-ESAc/RJvGTFEzRwOTT4+lNDk/GNHMkKbNzsvT0qKRfDyyYTskxB5rnU2njIDYVxXCBHHEI1c0YwHob3WaYujOg== dependencies: "@babel/template" "^7.3.3" "@babel/types" "^7.3.3" - "@types/babel__core" "^7.0.0" + "@types/babel__core" "^7.1.14" "@types/babel__traverse" "^7.0.6" babel-preset-current-node-syntax@^1.0.0: @@ -2106,12 +2283,12 @@ babel-preset-current-node-syntax@^1.0.0: "@babel/plugin-syntax-optional-chaining" "^7.8.3" "@babel/plugin-syntax-top-level-await" "^7.8.3" -babel-preset-jest@^26.6.2: - version "26.6.2" - resolved "https://registry.yarnpkg.com/babel-preset-jest/-/babel-preset-jest-26.6.2.tgz#747872b1171df032252426586881d62d31798fee" - integrity sha512-YvdtlVm9t3k777c5NPQIv6cxFFFapys25HiUmuSgHwIZhfifweR5c5Sf5nwE3MAbfu327CYSvps8Yx6ANLyleQ== +babel-preset-jest@^29.6.3: + version "29.6.3" + resolved "https://registry.yarnpkg.com/babel-preset-jest/-/babel-preset-jest-29.6.3.tgz#fa05fa510e7d493896d7b0dd2033601c840f171c" + integrity sha512-0B3bhxR6snWXJZtR/RliHTDPRgn1sNHOR0yVtq/IiQFyuOVjFS+wuio/R4gSNkyYmKmJB4wGZv2NZanmKmTnNA== dependencies: - babel-plugin-jest-hoist "^26.6.2" + babel-plugin-jest-hoist "^29.6.3" babel-preset-current-node-syntax "^1.0.0" balanced-match@^1.0.0: @@ -2129,19 +2306,6 @@ base64id@2.0.0, base64id@~2.0.0: resolved "https://registry.yarnpkg.com/base64id/-/base64id-2.0.0.tgz#2770ac6bc47d312af97a8bf9a634342e0cd25cb6" integrity sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog== -base@^0.11.1: - version "0.11.2" - resolved "https://registry.yarnpkg.com/base/-/base-0.11.2.tgz#7bde5ced145b6d551a90db87f83c558b4eb48a8f" - integrity sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg== - dependencies: - cache-base "^1.0.1" - class-utils "^0.3.5" - component-emitter "^1.2.1" - define-property "^1.0.0" - isobject "^3.0.1" - mixin-deep "^1.2.0" - pascalcase "^0.1.1" - bcrypt-pbkdf@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz#a4301d389b6a43f9b67ff3ca11a3f6637e360e9e" @@ -2208,22 +2372,6 @@ brace-expansion@^2.0.1: dependencies: balanced-match "^1.0.0" -braces@^2.3.1: - version "2.3.2" - resolved "https://registry.yarnpkg.com/braces/-/braces-2.3.2.tgz#5979fd3f14cd531565e5fa2df1abfff1dfaee729" - integrity sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w== - dependencies: - arr-flatten "^1.1.0" - array-unique "^0.3.2" - extend-shallow "^2.0.1" - fill-range "^4.0.0" - isobject "^3.0.1" - repeat-element "^1.1.2" - snapdragon "^0.8.1" - snapdragon-node "^2.0.1" - split-string "^3.0.2" - to-regex "^3.0.1" - braces@^3.0.2, braces@~3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" @@ -2231,6 +2379,13 @@ braces@^3.0.2, braces@~3.0.2: dependencies: fill-range "^7.0.1" +braces@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.3.tgz#490332f40919452272d55a8480adc0c441358789" + integrity sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA== + dependencies: + fill-range "^7.1.1" + broadcast-channel@~4.17.0: version "4.17.0" resolved "https://registry.yarnpkg.com/broadcast-channel/-/broadcast-channel-4.17.0.tgz#599d44674b09a4e2e07af6da5d03b45ca8bffd11" @@ -2247,11 +2402,6 @@ browser-or-node@^2.1.1: resolved "https://registry.yarnpkg.com/browser-or-node/-/browser-or-node-2.1.1.tgz#738790b3a86a8fc020193fa581273fbe65eaea0f" integrity sha512-8CVjaLJGuSKMVTxJ2DpBl5XnlNDiT4cQFeuCJJrvJmts9YrTZDizTX7PjC2s6W4x+MBGZeEY6dGMrF04/6Hgqg== -browser-process-hrtime@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz#3c9b4b7d782c8121e56f10106d84c0d0ffc94626" - integrity sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow== - browser-stdout@1.3.1: version "1.3.1" resolved "https://registry.yarnpkg.com/browser-stdout/-/browser-stdout-1.3.1.tgz#baa559ee14ced73452229bad7326467c61fabd60" @@ -2277,7 +2427,17 @@ browserslist@^4.21.9: node-releases "^2.0.13" update-browserslist-db "^1.0.13" -bs-logger@0.x: +browserslist@^4.24.0: + version "4.24.0" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.24.0.tgz#a1325fe4bc80b64fda169629fc01b3d6cecd38d4" + integrity sha512-Rmb62sR1Zpjql25eSanFGEhAxcFwfA1K0GuQcLoaJBAcENegrQut3hYdhXFF1obQfiDyqIW/cLM5HSJ/9k884A== + dependencies: + caniuse-lite "^1.0.30001663" + electron-to-chromium "^1.5.28" + node-releases "^2.0.18" + update-browserslist-db "^1.1.0" + +bs-logger@^0.2.6: version "0.2.6" resolved "https://registry.yarnpkg.com/bs-logger/-/bs-logger-0.2.6.tgz#eb7d365307a72cf974cc6cda76b68354ad336bd8" integrity sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog== @@ -2301,7 +2461,7 @@ buffer-equal-constant-time@1.0.1: resolved "https://registry.yarnpkg.com/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz#f8e71132f7ffe6e01a5c9697a4c6f3e48d5cc819" integrity sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA== -buffer-from@1.x, buffer-from@^1.0.0, buffer-from@^1.1.0: +buffer-from@^1.0.0, buffer-from@^1.1.0: version "1.1.2" resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.2.tgz#2b146a6fd72e80b4f55d255f35ed59a3a9a41bd5" integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ== @@ -2363,21 +2523,6 @@ cacache@^15.2.0: tar "^6.0.2" unique-filename "^1.1.1" -cache-base@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/cache-base/-/cache-base-1.0.1.tgz#0a7f46416831c8b662ee36fe4e7c59d76f666ab2" - integrity sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ== - dependencies: - collection-visit "^1.0.0" - component-emitter "^1.2.1" - get-value "^2.0.6" - has-value "^1.0.0" - isobject "^3.0.1" - set-value "^2.0.0" - to-object-path "^0.3.0" - union-value "^1.0.0" - unset-value "^1.0.0" - caching-transform@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/caching-transform/-/caching-transform-4.0.0.tgz#00d297a4206d71e2163c39eaffa8157ac0651f0f" @@ -2417,7 +2562,7 @@ camelcase@^5.0.0, camelcase@^5.3.1: resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320" integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg== -camelcase@^6.0.0: +camelcase@^6.0.0, camelcase@^6.2.0: version "6.3.0" resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.3.0.tgz#5685b95eb209ac9c0c177467778c9c84df58ba9a" integrity sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA== @@ -2432,12 +2577,10 @@ caniuse-lite@^1.0.30001541: resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001561.tgz#752f21f56f96f1b1a52e97aae98c57c562d5d9da" integrity sha512-NTt0DNoKe958Q0BE0j0c1V9jbUzhBxHIEJy7asmGrpE0yG63KTV7PLHPnK2E1O9RsQrQ081I3NLuXGS6zht3cw== -capture-exit@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/capture-exit/-/capture-exit-2.0.0.tgz#fb953bfaebeb781f62898239dabb426d08a509a4" - integrity sha512-PiT/hQmTonHhl/HFGN+Lx3JJUznrVYJ3+AQsnthneZbvW7x+f08Tk7yLJTLEOUvBTbduLeeBkxEaYXUOUrRq6g== - dependencies: - rsvp "^4.8.4" +caniuse-lite@^1.0.30001663: + version "1.0.30001669" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001669.tgz#fda8f1d29a8bfdc42de0c170d7f34a9cf19ed7a3" + integrity sha512-DlWzFDJqstqtIVx1zeSpIMLjunf5SmwOw0N2Ck/QSQdS8PLS4+9HrLaYei4w8BIAL7IB/UEDu889d8vhCTPA0w== chai@^4.3.4: version "4.3.10" @@ -2452,7 +2595,7 @@ chai@^4.3.4: pathval "^1.1.1" type-detect "^4.0.8" -chalk@4.1.2, chalk@^4.0.0, chalk@^4.1.0, chalk@^4.1.1, chalk@^4.1.2: +chalk@4.1.2, chalk@^4.0.0, chalk@^4.0.2, chalk@^4.1.0, chalk@^4.1.1, chalk@^4.1.2: version "4.1.2" resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== @@ -2536,31 +2679,21 @@ chrome-trace-event@^1.0.2: resolved "https://registry.yarnpkg.com/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz#1015eced4741e15d06664a957dbbf50d041e26ac" integrity sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg== -ci-info@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-2.0.0.tgz#67a9e964be31a51e15e5010d58e6f12834002f46" - integrity sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ== +ci-info@^3.2.0: + version "3.9.0" + resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-3.9.0.tgz#4279a62028a7b1f262f3473fc9605f5e218c59b4" + integrity sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ== -cjs-module-lexer@^0.6.0: - version "0.6.0" - resolved "https://registry.yarnpkg.com/cjs-module-lexer/-/cjs-module-lexer-0.6.0.tgz#4186fcca0eae175970aee870b9fe2d6cf8d5655f" - integrity sha512-uc2Vix1frTfnuzxxu1Hp4ktSvM3QaI4oXl4ZUqL1wjTu/BGki9TrCWoqLTg/drR1KwAEarXuRFCG2Svr1GxPFw== +cjs-module-lexer@^1.0.0: + version "1.4.1" + resolved "https://registry.yarnpkg.com/cjs-module-lexer/-/cjs-module-lexer-1.4.1.tgz#707413784dbb3a72aa11c2f2b042a0bef4004170" + integrity sha512-cuSVIHi9/9E/+821Qjdvngor+xpnlwnuwIyZOaLmHBVdXL+gP+I6QQB9VkO7RI77YIcTV+S1W9AreJ5eN63JBA== class-transformer@^0.5.1: version "0.5.1" resolved "https://registry.yarnpkg.com/class-transformer/-/class-transformer-0.5.1.tgz#24147d5dffd2a6cea930a3250a677addf96ab336" integrity sha512-SQa1Ws6hUbfC98vKGxZH3KFY0Y1lm5Zm0SY8XX9zbK7FJCyVEac3ATW0RIpwzW+oOfmHE5PMPufDG9hCfoEOMw== -class-utils@^0.3.5: - version "0.3.6" - resolved "https://registry.yarnpkg.com/class-utils/-/class-utils-0.3.6.tgz#f93369ae8b9a7ce02fd41faad0ca83033190c463" - integrity sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg== - dependencies: - arr-union "^3.1.0" - define-property "^0.2.5" - isobject "^3.0.0" - static-extend "^0.1.1" - class-validator@^0.14.1: version "0.14.1" resolved "https://registry.yarnpkg.com/class-validator/-/class-validator-0.14.1.tgz#ff2411ed8134e9d76acfeb14872884448be98110" @@ -2679,14 +2812,6 @@ collection-utils@^1.0.1: resolved "https://registry.yarnpkg.com/collection-utils/-/collection-utils-1.0.1.tgz#31d14336488674f27aefc0a7c5eccacf6df78044" integrity sha512-LA2YTIlR7biSpXkKYwwuzGjwL5rjWEZVOSnvdUc7gObvWe4WkjxOpfrdhoP7Hs09YWDVfg0Mal9BpAqLfVEzQg== -collection-visit@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/collection-visit/-/collection-visit-1.0.0.tgz#4bc0373c164bc3291b4d368c829cf1a80a59dca0" - integrity sha512-lNkKvzEeMBBjUGHZ+q6z9pSJla0KWAQPvtzhEV9+iGyQYG+pBpl7xKDhxoNSOZH2hhv0v5k0y2yAM4o4SjoSkw== - dependencies: - map-visit "^1.0.0" - object-visit "^1.0.0" - color-convert@^1.9.0, color-convert@^1.9.3: version "1.9.3" resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" @@ -2762,7 +2887,7 @@ commondir@^1.0.1: resolved "https://registry.yarnpkg.com/commondir/-/commondir-1.0.1.tgz#ddd800da0c66127393cca5950ea968a3aaf1253b" integrity sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg== -component-emitter@^1.2.0, component-emitter@^1.2.1, component-emitter@^1.3.0: +component-emitter@^1.2.0, component-emitter@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.3.0.tgz#16e4070fba8ae29b679f2215853ee181ab2eabc0" integrity sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg== @@ -2844,7 +2969,7 @@ content-type@~1.0.4, content-type@~1.0.5: resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.5.tgz#8b773162656d1d1086784c8f23a54ce6d73d7918" integrity sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA== -convert-source-map@^1.4.0, convert-source-map@^1.6.0, convert-source-map@^1.7.0: +convert-source-map@^1.7.0: version "1.9.0" resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.9.0.tgz#7faae62353fb4213366d0ca98358d22e8368b05f" integrity sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A== @@ -2874,11 +2999,6 @@ cookiejar@^2.1.0: resolved "https://registry.yarnpkg.com/cookiejar/-/cookiejar-2.1.4.tgz#ee669c1fea2cf42dc31585469d193fef0d65771b" integrity sha512-LDx6oHrK+PhzLKJU9j5S7/Y3jM/mUHvD/DeI1WQmJn652iPC5Y4TBzC9l+5OMOXlyTTA+SmVUPm0HQUwpD5Jqw== -copy-descriptor@^0.1.0: - version "0.1.1" - resolved "https://registry.yarnpkg.com/copy-descriptor/-/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d" - integrity sha512-XgZ0pFcakEUlbwQEVNg3+QAis1FyTL3Qel9FYy8pSkQqoG3PNoT0bOCQtOXcOkur21r2Eq2kI+IE+gsmAEVlYw== - core-js@^3.6.5: version "3.31.0" resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.31.0.tgz#4471dd33e366c79d8c0977ed2d940821719db344" @@ -2916,6 +3036,19 @@ cpu-features@~0.0.9: buildcheck "~0.0.6" nan "^2.17.0" +create-jest@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/create-jest/-/create-jest-29.7.0.tgz#a355c5b3cb1e1af02ba177fe7afd7feee49a5320" + integrity sha512-Adz2bdH0Vq3F53KEMJOoftQFutWCukm6J24wbPWRO4k1kMY7gS7ds/uoJkNuV8wDCtWWnuwGcJwpWcih+zEW1Q== + dependencies: + "@jest/types" "^29.6.3" + chalk "^4.0.0" + exit "^0.1.2" + graceful-fs "^4.2.9" + jest-config "^29.7.0" + jest-util "^29.7.0" + prompts "^2.0.1" + create-require@^1.1.0: version "1.1.1" resolved "https://registry.yarnpkg.com/create-require/-/create-require-1.1.1.tgz#c1d7e8f1e5f6cfc9ff65f9cd352d37348756c333" @@ -2942,17 +3075,6 @@ cross-fetch@^4.0.0: dependencies: node-fetch "^2.6.12" -cross-spawn@^6.0.0: - version "6.0.5" - resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4" - integrity sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ== - dependencies: - nice-try "^1.0.4" - path-key "^2.0.1" - semver "^5.5.0" - shebang-command "^1.2.0" - which "^1.2.9" - cross-spawn@^7.0.0, cross-spawn@^7.0.1, cross-spawn@^7.0.2, cross-spawn@^7.0.3: version "7.0.3" resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" @@ -2967,38 +3089,12 @@ crypt@0.0.2: resolved "https://registry.yarnpkg.com/crypt/-/crypt-0.0.2.tgz#88d7ff7ec0dfb86f713dc87bbb42d044d3e6c41b" integrity sha512-mCxBlsHFYh9C+HVpiEacem8FEBnMXgU9gy4zmNC+SXAZNB/1idgp/aulFJ4FgCi7GPEVbfyng092GqL2k2rmow== -cssom@^0.4.4: - version "0.4.4" - resolved "https://registry.yarnpkg.com/cssom/-/cssom-0.4.4.tgz#5a66cf93d2d0b661d80bf6a44fb65f5c2e4e0a10" - integrity sha512-p3pvU7r1MyyqbTk+WbNJIgJjG2VmTIaB10rI93LzVPrmDJKkzKYMtxxyAvQXR/NS6otuzveI7+7BBq3SjBS2mw== - -cssom@~0.3.6: - version "0.3.8" - resolved "https://registry.yarnpkg.com/cssom/-/cssom-0.3.8.tgz#9f1276f5b2b463f2114d3f2c75250af8c1a36f4a" - integrity sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg== - -cssstyle@^2.3.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/cssstyle/-/cssstyle-2.3.0.tgz#ff665a0ddbdc31864b09647f34163443d90b0852" - integrity sha512-AZL67abkUzIuvcHqk7c09cezpGNcxUxU4Ioi/05xHk4DQeTkWmGYftIE6ctU6AEt+Gn4n1lDStOtj7FKycP71A== - dependencies: - cssom "~0.3.6" - -data-urls@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/data-urls/-/data-urls-2.0.0.tgz#156485a72963a970f5d5821aaf642bef2bf2db9b" - integrity sha512-X5eWTSXO/BJmpdIKCRuKUgSCgAN0OwliVK3yPKbwIWU1Tdw5BRajxlzMidvh+gwko9AfQ9zIj52pzF91Q3YAvQ== - dependencies: - abab "^2.0.3" - whatwg-mimetype "^2.3.0" - whatwg-url "^8.0.0" - date-fns@^2.0.1, date-fns@^2.29.3: version "2.29.3" resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-2.29.3.tgz#27402d2fc67eb442b511b70bbdf98e6411cd68a8" integrity sha512-dDCnyH2WnnKusqvZZ6+jA1O51Ibt8ZMRNkDZdyAyK4YfbDwa/cEmuztzG5pk6hqlp9aSBPYcjOlktquahGwGeA== -debug@2.6.9, debug@^2.2.0, debug@^2.3.3: +debug@2.6.9: version "2.6.9" resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== @@ -3043,16 +3139,6 @@ decamelize@^4.0.0: resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-4.0.0.tgz#aa472d7bf660eb15f3494efd531cab7f2a709837" integrity sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ== -decimal.js@^10.2.1: - version "10.4.3" - resolved "https://registry.yarnpkg.com/decimal.js/-/decimal.js-10.4.3.tgz#1044092884d245d1b7f65725fa4ad4c6f781cc23" - integrity sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA== - -decode-uri-component@^0.2.0: - version "0.2.2" - resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.2.tgz#e69dbe25d37941171dd540e024c444cd5188e1e9" - integrity sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ== - decompress-response@^6.0.0: version "6.0.0" resolved "https://registry.yarnpkg.com/decompress-response/-/decompress-response-6.0.0.tgz#ca387612ddb7e104bd16d85aab00d5ecf09c66fc" @@ -3060,6 +3146,11 @@ decompress-response@^6.0.0: dependencies: mimic-response "^3.1.0" +dedent@^1.0.0: + version "1.5.3" + resolved "https://registry.yarnpkg.com/dedent/-/dedent-1.5.3.tgz#99aee19eb9bae55a67327717b6e848d0bf777e5a" + integrity sha512-NHQtfOOW68WD8lgypbLA5oT+Bt0xXJhiYvoR6SmmNXZfpzOGXwdKWmcwG8N7PwVVWV3eF/68nmD9BaJSsTBhyQ== + deep-eql@^4.1.3: version "4.1.3" resolved "https://registry.yarnpkg.com/deep-eql/-/deep-eql-4.1.3.tgz#7c7775513092f7df98d8df9996dd085eb668cc6d" @@ -3113,28 +3204,6 @@ define-properties@^1.1.3, define-properties@^1.1.4, define-properties@^1.2.0: has-property-descriptors "^1.0.0" object-keys "^1.1.1" -define-property@^0.2.5: - version "0.2.5" - resolved "https://registry.yarnpkg.com/define-property/-/define-property-0.2.5.tgz#c35b1ef918ec3c990f9a5bc57be04aacec5c8116" - integrity sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA== - dependencies: - is-descriptor "^0.1.0" - -define-property@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/define-property/-/define-property-1.0.0.tgz#769ebaaf3f4a63aad3af9e8d304c9bbe79bfb0e6" - integrity sha512-cZTYKFWspt9jZsMscWo8sc/5lbPC9Q0N5nBLgb+Yd915iL3udB1uFgS3B8YCx66UVHq018DAVFoee7x+gxggeA== - dependencies: - is-descriptor "^1.0.0" - -define-property@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/define-property/-/define-property-2.0.2.tgz#d459689e8d654ba77e02a817f8710d702cb16e9d" - integrity sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ== - dependencies: - is-descriptor "^1.0.2" - isobject "^3.0.1" - delayed-stream@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" @@ -3193,6 +3262,11 @@ diff-sequences@^26.6.2: resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-26.6.2.tgz#48ba99157de1923412eed41db6b6d4aa9ca7c0b1" integrity sha512-Mv/TDa3nZ9sbc5soK+OoA74BsS3mL37yixCvUAQkiuA4Wz6YtwP/K47n2rv2ovzHZvoiQeA5FTQOschKkEwB0Q== +diff-sequences@^29.6.3: + version "29.6.3" + resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-29.6.3.tgz#4deaf894d11407c51efc8418012f9e70b84ea921" + integrity sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q== + diff@5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/diff/-/diff-5.0.0.tgz#7ed6ad76d859d030787ec35855f5b1daf31d852b" @@ -3229,13 +3303,6 @@ doctrine@^3.0.0: dependencies: esutils "^2.0.2" -domexception@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/domexception/-/domexception-2.0.1.tgz#fb44aefba793e1574b0af6aed2801d057529f304" - integrity sha512-yxJ2mFy/sibVQlu5qHjOkf9J3K6zgmCxgJ94u2EdvDOV09H+32LtRswEcUsmUWN72pVLOEnTSRaIVVzVQgS0dg== - dependencies: - webidl-conversions "^5.0.0" - dotenv@^16.0.0, dotenv@^16.0.3: version "16.0.3" resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-16.0.3.tgz#115aec42bac5053db3c456db30cc243a5a836a07" @@ -3258,6 +3325,13 @@ ee-first@1.1.1: resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" integrity sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow== +ejs@^3.1.10: + version "3.1.10" + resolved "https://registry.yarnpkg.com/ejs/-/ejs-3.1.10.tgz#69ab8358b14e896f80cc39e62087b88500c3ac3b" + integrity sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA== + dependencies: + jake "^10.8.5" + electron-to-chromium@^1.4.284: version "1.4.374" resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.374.tgz#091b2de9d80b970f9b5e689675ea62622cd1d74b" @@ -3268,10 +3342,15 @@ electron-to-chromium@^1.4.535: resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.581.tgz#23b684c67bf56d4284e95598c05a5d266653b6d8" integrity sha512-6uhqWBIapTJUxgPTCHH9sqdbxIMPt7oXl0VcAL1kOtlU6aECdcMncCrX5Z7sHQ/invtrC9jUQUef7+HhO8vVFw== -emittery@^0.7.1: - version "0.7.2" - resolved "https://registry.yarnpkg.com/emittery/-/emittery-0.7.2.tgz#25595908e13af0f5674ab419396e2fb394cdfa82" - integrity sha512-A8OG5SR/ij3SsJdWDJdkkSYUjQdCUx6APQXem0SaEePBSRg4eymGYwBkKo1Y6DU+af/Jn2dBQqDBvjnr9Vi8nQ== +electron-to-chromium@^1.5.28: + version "1.5.39" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.5.39.tgz#5cbe5200b43dff7b7c2bcb6bdacf65d514c76bb2" + integrity sha512-4xkpSR6CjuiaNyvwiWDI85N9AxsvbPawB8xc7yzLPonYTuP19BVgYweKyUMFtHEZgIcHWMt1ks5Cqx2m+6/Grg== + +emittery@^0.13.1: + version "0.13.1" + resolved "https://registry.yarnpkg.com/emittery/-/emittery-0.13.1.tgz#c04b8c3457490e0847ae51fced3af52d338e3dad" + integrity sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ== emoji-regex@^7.0.1: version "7.0.3" @@ -3540,6 +3619,11 @@ escalade@^3.1.1: resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40" integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw== +escalade@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.2.0.tgz#011a3f69856ba189dffa7dc8fcce99d2a87903e5" + integrity sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA== + escape-html@~1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" @@ -3560,17 +3644,6 @@ escape-string-regexp@^2.0.0: resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz#a30304e99daa32e23b2fd20f51babd07cffca344" integrity sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w== -escodegen@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-2.1.0.tgz#ba93bbb7a43986d29d6041f99f5262da773e2e17" - integrity sha512-2NlIDTwUWJN0mRPQOdtQBzbUHvdGY2P1VXSyU83Q3xKxM7WHX2Ql8dKq782Q9TgQUNOLEzEYu9bzLNj1q88I5w== - dependencies: - esprima "^4.0.1" - estraverse "^5.2.0" - esutils "^2.0.2" - optionalDependencies: - source-map "~0.6.1" - eslint-config-airbnb-base@^14.2.0, eslint-config-airbnb-base@^14.2.1: version "14.2.1" resolved "https://registry.yarnpkg.com/eslint-config-airbnb-base/-/eslint-config-airbnb-base-14.2.1.tgz#8a2eb38455dc5a312550193b319cdaeef042cd1e" @@ -3734,7 +3807,7 @@ espree@^7.3.0, espree@^7.3.1: acorn-jsx "^5.3.1" eslint-visitor-keys "^1.3.0" -esprima@^4.0.0, esprima@^4.0.1: +esprima@^4.0.0: version "4.0.1" resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== @@ -3793,25 +3866,7 @@ events@^3.2.0, events@^3.3.0: resolved "https://registry.yarnpkg.com/events/-/events-3.3.0.tgz#31a95ad0a924e2d2c419a813aeb2c4e878ea7400" integrity sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q== -exec-sh@^0.3.2: - version "0.3.6" - resolved "https://registry.yarnpkg.com/exec-sh/-/exec-sh-0.3.6.tgz#ff264f9e325519a60cb5e273692943483cca63bc" - integrity sha512-nQn+hI3yp+oD0huYhKwvYI32+JFeq+XkNcD1GAo3Y/MjxsfVGmrrzrnzjWiNY6f+pUCP440fThsFh5gZrRAU/w== - -execa@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/execa/-/execa-1.0.0.tgz#c6236a5bb4df6d6f15e88e7f017798216749ddd8" - integrity sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA== - dependencies: - cross-spawn "^6.0.0" - get-stream "^4.0.0" - is-stream "^1.1.0" - npm-run-path "^2.0.0" - p-finally "^1.0.0" - signal-exit "^3.0.0" - strip-eof "^1.0.0" - -execa@^4.0.0, execa@^4.0.2: +execa@^4.0.2: version "4.1.0" resolved "https://registry.yarnpkg.com/execa/-/execa-4.1.0.tgz#4e5491ad1572f2f17a77d388c6c857135b22847a" integrity sha512-j5W0//W7f8UxAn8hXVnwG8tLwdiUy4FJLcSupCg6maBYZDpyBvTApK7KyuI4bKj8KOh1r2YH+6ucuYtJv1bTZA== @@ -3826,40 +3881,41 @@ execa@^4.0.0, execa@^4.0.2: signal-exit "^3.0.2" strip-final-newline "^2.0.0" +execa@^5.0.0: + version "5.1.1" + resolved "https://registry.yarnpkg.com/execa/-/execa-5.1.1.tgz#f80ad9cbf4298f7bd1d4c9555c21e93741c411dd" + integrity sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg== + dependencies: + cross-spawn "^7.0.3" + get-stream "^6.0.0" + human-signals "^2.1.0" + is-stream "^2.0.0" + merge-stream "^2.0.0" + npm-run-path "^4.0.1" + onetime "^5.1.2" + signal-exit "^3.0.3" + strip-final-newline "^2.0.0" + exit@^0.1.2: version "0.1.2" resolved "https://registry.yarnpkg.com/exit/-/exit-0.1.2.tgz#0632638f8d877cc82107d30a0fff1a17cba1cd0c" integrity sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ== -expand-brackets@^2.1.4: - version "2.1.4" - resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-2.1.4.tgz#b77735e315ce30f6b6eff0f83b04151a22449622" - integrity sha512-w/ozOKR9Obk3qoWeY/WDi6MFta9AoMR+zud60mdnbniMcBxRuFJyDt2LdX/14A1UABeqk+Uk+LDfUpvoGKppZA== - dependencies: - debug "^2.3.3" - define-property "^0.2.5" - extend-shallow "^2.0.1" - posix-character-classes "^0.1.0" - regex-not "^1.0.0" - snapdragon "^0.8.1" - to-regex "^3.0.1" - expand-template@^2.0.3: version "2.0.3" resolved "https://registry.yarnpkg.com/expand-template/-/expand-template-2.0.3.tgz#6e14b3fcee0f3a6340ecb57d2e8918692052a47c" integrity sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg== -expect@^26.6.2: - version "26.6.2" - resolved "https://registry.yarnpkg.com/expect/-/expect-26.6.2.tgz#c6b996bf26bf3fe18b67b2d0f51fc981ba934417" - integrity sha512-9/hlOBkQl2l/PLHJx6JjoDF6xPKcJEsUlWKb23rKE7KzeDqUZKXKNMW27KIue5JMdBV9HgmoJPcc8HtO85t9IA== +expect@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/expect/-/expect-29.7.0.tgz#578874590dcb3214514084c08115d8aee61e11bc" + integrity sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw== dependencies: - "@jest/types" "^26.6.2" - ansi-styles "^4.0.0" - jest-get-type "^26.3.0" - jest-matcher-utils "^26.6.2" - jest-message-util "^26.6.2" - jest-regex-util "^26.0.0" + "@jest/expect-utils" "^29.7.0" + jest-get-type "^29.6.3" + jest-matcher-utils "^29.7.0" + jest-message-util "^29.7.0" + jest-util "^29.7.0" express@4.21.0, express@^4.21.0: version "4.21.0" @@ -3898,21 +3954,6 @@ express@4.21.0, express@^4.21.0: utils-merge "1.0.1" vary "~1.1.2" -extend-shallow@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-2.0.1.tgz#51af7d614ad9a9f610ea1bafbb989d6b1c56890f" - integrity sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug== - dependencies: - is-extendable "^0.1.0" - -extend-shallow@^3.0.0, extend-shallow@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-3.0.2.tgz#26a71aaf073b39fb2127172746131c2704028db8" - integrity sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q== - dependencies: - assign-symbols "^1.0.0" - is-extendable "^1.0.1" - extend@^3.0.0: version "3.0.2" resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa" @@ -3927,20 +3968,6 @@ external-editor@^3.0.3: iconv-lite "^0.4.24" tmp "^0.0.33" -extglob@^2.0.4: - version "2.0.4" - resolved "https://registry.yarnpkg.com/extglob/-/extglob-2.0.4.tgz#ad00fe4dc612a9232e8718711dc5cb5ab0285543" - integrity sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw== - dependencies: - array-unique "^0.3.2" - define-property "^1.0.0" - expand-brackets "^2.1.4" - extend-shallow "^2.0.1" - fragment-cache "^0.2.1" - regex-not "^1.0.0" - snapdragon "^0.8.1" - to-regex "^3.0.1" - fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3: version "3.1.3" resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" @@ -3957,7 +3984,7 @@ fast-glob@^3.2.9: merge2 "^1.3.0" micromatch "^4.0.4" -fast-json-stable-stringify@2.x, fast-json-stable-stringify@^2.0.0: +fast-json-stable-stringify@2.x, fast-json-stable-stringify@^2.0.0, fast-json-stable-stringify@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== @@ -4043,15 +4070,12 @@ file-uri-to-path@1.0.0: resolved "https://registry.yarnpkg.com/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz#553a7b8446ff6f684359c445f1e37a05dacc33dd" integrity sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw== -fill-range@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-4.0.0.tgz#d544811d428f98eb06a63dc402d2403c328c38f7" - integrity sha512-VcpLTWqWDiTerugjj8e3+esbg+skS3M9e54UuR3iCeIDMXCLTsAH8hTSzDQU/X6/6t3eYkOKoZSef2PlU6U1XQ== +filelist@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/filelist/-/filelist-1.0.4.tgz#f78978a1e944775ff9e62e744424f215e58352b5" + integrity sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q== dependencies: - extend-shallow "^2.0.1" - is-number "^3.0.0" - repeat-string "^1.6.1" - to-regex-range "^2.1.0" + minimatch "^5.0.1" fill-range@^7.0.1: version "7.0.1" @@ -4060,7 +4084,14 @@ fill-range@^7.0.1: dependencies: to-regex-range "^5.0.1" -finalhandler@1.3.1: +fill-range@^7.1.1: + version "7.1.1" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.1.1.tgz#44265d3cac07e3ea7dc247516380643754a05292" + integrity sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg== + dependencies: + to-regex-range "^5.0.1" + +finalhandler@1.3.1: version "1.3.1" resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.3.1.tgz#0c575f1d1d324ddd1da35ad7ece3df7d19088019" integrity sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ== @@ -4140,11 +4171,6 @@ for-each@^0.3.3: dependencies: is-callable "^1.1.3" -for-in@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80" - integrity sha512-7EwmXrOjyL+ChxMhmG5lnW9MPt1aIeZEwKhQzoBUdTV0N3zuwWDZYVJatDvZ2OyzPUvdIAZDsCetk3coyMfcnQ== - foreground-child@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/foreground-child/-/foreground-child-2.0.0.tgz#71b32800c9f15aa8f2f83f4a6bd9bff35d861a53" @@ -4180,15 +4206,6 @@ form-data@^2.3.1: combined-stream "^1.0.6" mime-types "^2.1.12" -form-data@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/form-data/-/form-data-3.0.1.tgz#ebd53791b78356a99af9a300d4282c4d5eb9755f" - integrity sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg== - dependencies: - asynckit "^0.4.0" - combined-stream "^1.0.8" - mime-types "^2.1.12" - form-data@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/form-data/-/form-data-4.0.0.tgz#93919daeaf361ee529584b9b31664dc12c9fa452" @@ -4208,13 +4225,6 @@ forwarded@0.2.0: resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.2.0.tgz#2269936428aad4c15c7ebe9779a84bf0b2a81811" integrity sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow== -fragment-cache@^0.2.1: - version "0.2.1" - resolved "https://registry.yarnpkg.com/fragment-cache/-/fragment-cache-0.2.1.tgz#4290fad27f13e89be7f33799c6bc5a0abfff0d19" - integrity sha512-GMBAbW9antB8iZRHLoGw0b3HANt57diZYFO/HL1JGIC1MjKrdmhxvrJbupnVvpys0zsz7yBApXdQyfepKly2kA== - dependencies: - map-cache "^0.2.2" - fresh@0.5.2: version "0.5.2" resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7" @@ -4256,7 +4266,7 @@ fs.realpath@^1.0.0: resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== -fsevents@^2.1.2: +fsevents@^2.3.2: version "2.3.3" resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.3.tgz#cac6407785d03675a2a5e1a5305c697b347d90d6" integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw== @@ -4360,13 +4370,6 @@ get-stdin@^6.0.0: resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-6.0.0.tgz#9e09bf712b360ab9225e812048f71fde9c89657b" integrity sha512-jp4tHawyV7+fkkSKyvjuLZswblUtz+SQKzSWnBbii16BuZksJlU1wuBYXY75r+duh/llF1ur6oNwi+2ZzjKZ7g== -get-stream@^4.0.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-4.1.0.tgz#c1b255575f3dc21d59bfc79cd3d2b46b1c3a54b5" - integrity sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w== - dependencies: - pump "^3.0.0" - get-stream@^5.0.0: version "5.2.0" resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-5.2.0.tgz#4966a1795ee5ace65e706c4b7beb71257d6e22d3" @@ -4374,6 +4377,11 @@ get-stream@^5.0.0: dependencies: pump "^3.0.0" +get-stream@^6.0.0: + version "6.0.1" + resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-6.0.1.tgz#a262d8eef67aced57c2852ad6167526a43cbf7b7" + integrity sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg== + get-symbol-description@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/get-symbol-description/-/get-symbol-description-1.0.0.tgz#7fdb81c900101fbd564dd5f1a30af5aadc1e58d6" @@ -4382,11 +4390,6 @@ get-symbol-description@^1.0.0: call-bind "^1.0.2" get-intrinsic "^1.1.1" -get-value@^2.0.3, get-value@^2.0.6: - version "2.0.6" - resolved "https://registry.yarnpkg.com/get-value/-/get-value-2.0.6.tgz#dc15ca1c672387ca76bd37ac0a395ba2042a2c28" - integrity sha512-Ln0UQDlxH1BapMu3GPtf7CuYNwRZf2gwCuPqbyG6pB8WfmFpzqcy4xtAaAMUhnNqjMKTiCPZG2oMT3YSx8U2NA== - github-from-package@0.0.0: version "0.0.0" resolved "https://registry.yarnpkg.com/github-from-package/-/github-from-package-0.0.0.tgz#97fb5d96bfde8973313f20e8288ef9a167fa64ce" @@ -4416,7 +4419,7 @@ glob@7.1.6: once "^1.3.0" path-is-absolute "^1.0.0" -glob@^7.0.0, glob@^7.1.1, glob@^7.1.2, glob@^7.1.3, glob@^7.1.4, glob@^7.1.6: +glob@^7.0.0, glob@^7.1.3, glob@^7.1.4, glob@^7.1.6: version "7.2.3" resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b" integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q== @@ -4497,11 +4500,6 @@ growl@1.10.5: resolved "https://registry.yarnpkg.com/growl/-/growl-1.10.5.tgz#f2735dc2283674fa67478b10181059355c369e5e" integrity sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA== -growly@^1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/growly/-/growly-1.3.0.tgz#f10748cbe76af964b7c96c93c6bcc28af120c081" - integrity sha512-+xGQY0YyAWCnqy7Cd++hc2JqMYzlm0dG30Jd0beaA64sROr8C4nt8Yc9V5Ro3avlSUDTN0ulqP/VBKi1/lLygw== - has-bigints@^1.0.1, has-bigints@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/has-bigints/-/has-bigints-1.0.2.tgz#0871bd3e3d51626f6ca0966668ba35d5602d6eaa" @@ -4553,37 +4551,6 @@ has-unicode@^2.0.1: resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9" integrity sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ== -has-value@^0.3.1: - version "0.3.1" - resolved "https://registry.yarnpkg.com/has-value/-/has-value-0.3.1.tgz#7b1f58bada62ca827ec0a2078025654845995e1f" - integrity sha512-gpG936j8/MzaeID5Yif+577c17TxaDmhuyVgSwtnL/q8UUTySg8Mecb+8Cf1otgLoD7DDH75axp86ER7LFsf3Q== - dependencies: - get-value "^2.0.3" - has-values "^0.1.4" - isobject "^2.0.0" - -has-value@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/has-value/-/has-value-1.0.0.tgz#18b281da585b1c5c51def24c930ed29a0be6b177" - integrity sha512-IBXk4GTsLYdQ7Rvt+GRBrFSVEkmuOUy4re0Xjd9kJSUQpnTrWR4/y9RpfexN9vkAPMFuQoeWKwqzPozRTlasGw== - dependencies: - get-value "^2.0.6" - has-values "^1.0.0" - isobject "^3.0.0" - -has-values@^0.1.4: - version "0.1.4" - resolved "https://registry.yarnpkg.com/has-values/-/has-values-0.1.4.tgz#6d61de95d91dfca9b9a02089ad384bff8f62b771" - integrity sha512-J8S0cEdWuQbqD9//tlZxiMuMNmxB8PlEwvYwuxsTmR1G5RXUePEX/SJn7aD0GMLieuZYSwNH0cQuJGwnYunXRQ== - -has-values@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/has-values/-/has-values-1.0.0.tgz#95b0b63fec2146619a6fe57fe75628d5a39efe4f" - integrity sha512-ODYZC64uqzmtfGMEAX/FvZiRyWLpAC3vYnNunURUnkGVTS+mI0smVsWaPydRBsE3g+ok7h960jChO8mFcWlHaQ== - dependencies: - is-number "^3.0.0" - kind-of "^4.0.0" - has@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796" @@ -4621,13 +4588,6 @@ hosted-git-info@^2.1.4: resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.8.9.tgz#dffc0bf9a21c02209090f2aa69429e1414daf3f9" integrity sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw== -html-encoding-sniffer@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/html-encoding-sniffer/-/html-encoding-sniffer-2.0.1.tgz#42a6dc4fd33f00281176e8b23759ca4e4fa185f3" - integrity sha512-D5JbOMBIR/TVZkubHT+OyT2705QvogUW4IBn6nHd756OwieSF9aDYFj4dv6HHEVGYbHaLETa3WggZYWWMyy3ZQ== - dependencies: - whatwg-encoding "^1.0.5" - html-escaper@^2.0.0: version "2.0.2" resolved "https://registry.yarnpkg.com/html-escaper/-/html-escaper-2.0.2.tgz#dfd60027da36a36dfcbe236262c00a5822681453" @@ -4681,6 +4641,11 @@ human-signals@^1.1.1: resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-1.1.1.tgz#c5b1cd14f50aeae09ab6c59fe63ba3395fe4dfa3" integrity sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw== +human-signals@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-2.1.0.tgz#dc91fcba42e4d06e4abaed33b3e7a3c02f514ea0" + integrity sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw== + humanize-ms@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/humanize-ms/-/humanize-ms-1.2.1.tgz#c46e3159a293f6b896da29316d8b6fe8bb79bbed" @@ -4866,13 +4831,6 @@ ipaddr.js@1.9.1: resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.1.tgz#bff38543eeb8984825079ff3a2a8e6cbd46781b3" integrity sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g== -is-accessor-descriptor@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-1.0.1.tgz#3223b10628354644b86260db29b3e693f5ceedd4" - integrity sha512-YBUanLI8Yoihw923YeFUS5fs0fF2f5TSFTNiYAAzhhDscDa3lEqYuz1pDOEP5KvX94I9ey3vsqjJcLVFVU+3QA== - dependencies: - hasown "^2.0.0" - is-array-buffer@^3.0.1, is-array-buffer@^3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/is-array-buffer/-/is-array-buffer-3.0.2.tgz#f2653ced8412081638ecb0ebbd0c41c6e0aecbbe" @@ -4914,7 +4872,7 @@ is-boolean-object@^1.1.0: call-bind "^1.0.2" has-tostringtag "^1.0.0" -is-buffer@^1.1.5, is-buffer@~1.1.6: +is-buffer@~1.1.6: version "1.1.6" resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w== @@ -4924,13 +4882,6 @@ is-callable@^1.1.3, is-callable@^1.1.4, is-callable@^1.2.7: resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.7.tgz#3bc2a85ea742d9e36205dcacdd72ca1fdc51b055" integrity sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA== -is-ci@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/is-ci/-/is-ci-2.0.0.tgz#6bc6334181810e04b5c22b3d589fdca55026404c" - integrity sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w== - dependencies: - ci-info "^2.0.0" - is-core-module@^2.11.0: version "2.12.0" resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.12.0.tgz#36ad62f6f73c8253fd6472517a12483cf03e7ec4" @@ -4945,13 +4896,6 @@ is-core-module@^2.13.0: dependencies: hasown "^2.0.0" -is-data-descriptor@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-1.0.1.tgz#2109164426166d32ea38c405c1e0945d9e6a4eeb" - integrity sha512-bc4NlCDiCr28U4aEsQ3Qs2491gVq4V8G7MQyws968ImqjKuYtTJXrl7Vq7jsN7Ly/C3xj5KWFrY7sHNeDkAzXw== - dependencies: - hasown "^2.0.0" - is-date-object@^1.0.1: version "1.0.5" resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.5.tgz#0841d5536e724c25597bf6ea62e1bd38298df31f" @@ -4959,39 +4903,6 @@ is-date-object@^1.0.1: dependencies: has-tostringtag "^1.0.0" -is-descriptor@^0.1.0: - version "0.1.7" - resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-0.1.7.tgz#2727eb61fd789dcd5bdf0ed4569f551d2fe3be33" - integrity sha512-C3grZTvObeN1xud4cRWl366OMXZTj0+HGyk4hvfpx4ZHt1Pb60ANSXqCK7pdOTeUQpRzECBSTphqvD7U+l22Eg== - dependencies: - is-accessor-descriptor "^1.0.1" - is-data-descriptor "^1.0.1" - -is-descriptor@^1.0.0, is-descriptor@^1.0.2: - version "1.0.3" - resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-1.0.3.tgz#92d27cb3cd311c4977a4db47df457234a13cb306" - integrity sha512-JCNNGbwWZEVaSPtS45mdtrneRWJFp07LLmykxeFV5F6oBvNF8vHSfJuJgoT472pSfk+Mf8VnlrspaFBHWM8JAw== - dependencies: - is-accessor-descriptor "^1.0.1" - is-data-descriptor "^1.0.1" - -is-docker@^2.0.0: - version "2.2.1" - resolved "https://registry.yarnpkg.com/is-docker/-/is-docker-2.2.1.tgz#33eeabe23cfe86f14bde4408a02c0cfb853acdaa" - integrity sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ== - -is-extendable@^0.1.0, is-extendable@^0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89" - integrity sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw== - -is-extendable@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-1.0.1.tgz#a7470f9e426733d81bd81e1155264e3a3507cab4" - integrity sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA== - dependencies: - is-plain-object "^2.0.4" - is-extglob@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" @@ -5041,13 +4952,6 @@ is-number-object@^1.0.4: dependencies: has-tostringtag "^1.0.0" -is-number@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/is-number/-/is-number-3.0.0.tgz#24fd6201a4782cf50561c810276afc7d12d71195" - integrity sha512-4cboCqIpliH+mAvFNegjZQ4kgKc3ZUhQVr3HvWbSh5q3WH2v82ct+T2Y1hdU5Gdtorx/cLifQjqCbL7bpznLTg== - dependencies: - kind-of "^3.0.2" - is-number@^7.0.0: version "7.0.0" resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" @@ -5058,18 +4962,6 @@ is-plain-obj@^2.1.0: resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-2.1.0.tgz#45e42e37fccf1f40da8e5f76ee21515840c09287" integrity sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA== -is-plain-object@^2.0.3, is-plain-object@^2.0.4: - version "2.0.4" - resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-2.0.4.tgz#2c163b3fafb1b606d9d17928f05c2a1c38e07677" - integrity sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og== - dependencies: - isobject "^3.0.1" - -is-potential-custom-element-name@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz#171ed6f19e3ac554394edf78caa05784a45bebb5" - integrity sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ== - is-regex@^1.1.4: version "1.1.4" resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.1.4.tgz#eef5663cd59fa4c0ae339505323df6854bb15958" @@ -5085,11 +4977,6 @@ is-shared-array-buffer@^1.0.2: dependencies: call-bind "^1.0.2" -is-stream@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" - integrity sha512-uQPm8kcs47jx38atAcWTVxyltQYoPT68y9aWYdV6yWXSyW8mzSat0TL6CiWdZeCdF3KrAvpVtnHbTv4RN+rqdQ== - is-stream@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-2.0.1.tgz#fac1e3d53b97ad5a9d0ae9cef2389f5810a5c077" @@ -5147,14 +5034,7 @@ is-windows@^1.0.2: resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d" integrity sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA== -is-wsl@^2.2.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-2.2.0.tgz#74a4c76e77ca9fd3f932f290c17ea326cd157271" - integrity sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww== - dependencies: - is-docker "^2.0.0" - -isarray@1.0.0, isarray@~1.0.0: +isarray@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" integrity sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ== @@ -5164,18 +5044,6 @@ isexe@^2.0.0: resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw== -isobject@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/isobject/-/isobject-2.1.0.tgz#f065561096a3f1da2ef46272f815c840d87e0c89" - integrity sha512-+OUdGJlgjOBZDfxnDjYYG6zp487z0JGNQq3cYQYg5f5hKR+syHMsaztzGeml/4kGG55CSpKSpWTY+jYGgsHLgA== - dependencies: - isarray "1.0.0" - -isobject@^3.0.0, isobject@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df" - integrity sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg== - istanbul-lib-coverage@^3.0.0, istanbul-lib-coverage@^3.2.0: version "3.2.2" resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz#2d166c4b0644d43a39f04bf6c2edd1e585f31756" @@ -5188,7 +5056,7 @@ istanbul-lib-hook@^3.0.0: dependencies: append-transform "^2.0.0" -istanbul-lib-instrument@^4.0.0, istanbul-lib-instrument@^4.0.3: +istanbul-lib-instrument@^4.0.0: version "4.0.3" resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-4.0.3.tgz#873c6fff897450118222774696a3f28902d77c1d" integrity sha512-BXgQl9kf4WTCPCCpmFGoJkz/+uhvm7h7PFKUYxh7qarQd3ER33vHG//qaE8eN25l07YqZPpHXU9I09l/RD5aGQ== @@ -5209,6 +5077,17 @@ istanbul-lib-instrument@^5.0.4: istanbul-lib-coverage "^3.2.0" semver "^6.3.0" +istanbul-lib-instrument@^6.0.0: + version "6.0.3" + resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-6.0.3.tgz#fa15401df6c15874bcb2105f773325d78c666765" + integrity sha512-Vtgk7L/R2JHyyGW07spoFlB8/lpjiOLTjMdms6AFMraYt3BaJauod/NGrfnVG/y4Ix1JEuMRPDPEj2ua+zz1/Q== + dependencies: + "@babel/core" "^7.23.9" + "@babel/parser" "^7.23.9" + "@istanbuljs/schema" "^0.1.3" + istanbul-lib-coverage "^3.2.0" + semver "^7.5.4" + istanbul-lib-processinfo@^2.0.2: version "2.0.3" resolved "https://registry.yarnpkg.com/istanbul-lib-processinfo/-/istanbul-lib-processinfo-2.0.3.tgz#366d454cd0dcb7eb6e0e419378e60072c8626169" @@ -5247,64 +5126,110 @@ istanbul-reports@^3.0.2: html-escaper "^2.0.0" istanbul-lib-report "^3.0.0" +istanbul-reports@^3.1.3: + version "3.1.7" + resolved "https://registry.yarnpkg.com/istanbul-reports/-/istanbul-reports-3.1.7.tgz#daed12b9e1dca518e15c056e1e537e741280fa0b" + integrity sha512-BewmUXImeuRk2YY0PVbxgKAysvhRPUQE0h5QRM++nVWyubKGV0l8qQ5op8+B2DOmwSe63Jivj0BjkPQVf8fP5g== + dependencies: + html-escaper "^2.0.0" + istanbul-lib-report "^3.0.0" + iterare@1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/iterare/-/iterare-1.2.1.tgz#139c400ff7363690e33abffa33cbba8920f00042" integrity sha512-RKYVTCjAnRthyJes037NX/IiqeidgN1xc3j1RjFfECFp28A1GVwK9nA+i0rJPaHqSZwygLzRnFlzUuHFoWWy+Q== -jest-changed-files@^26.6.2: - version "26.6.2" - resolved "https://registry.yarnpkg.com/jest-changed-files/-/jest-changed-files-26.6.2.tgz#f6198479e1cc66f22f9ae1e22acaa0b429c042d0" - integrity sha512-fDS7szLcY9sCtIip8Fjry9oGf3I2ht/QT21bAHm5Dmf0mD4X3ReNUf17y+bO6fR8WgbIZTlbyG1ak/53cbRzKQ== +jake@^10.8.5: + version "10.9.2" + resolved "https://registry.yarnpkg.com/jake/-/jake-10.9.2.tgz#6ae487e6a69afec3a5e167628996b59f35ae2b7f" + integrity sha512-2P4SQ0HrLQ+fw6llpLnOaGAvN2Zu6778SJMrCUwns4fOoG9ayrTiZk3VV8sCPkVZF8ab0zksVpS8FDY5pRCNBA== dependencies: - "@jest/types" "^26.6.2" - execa "^4.0.0" - throat "^5.0.0" + async "^3.2.3" + chalk "^4.0.2" + filelist "^1.0.4" + minimatch "^3.1.2" -jest-cli@^26.6.3: - version "26.6.3" - resolved "https://registry.yarnpkg.com/jest-cli/-/jest-cli-26.6.3.tgz#43117cfef24bc4cd691a174a8796a532e135e92a" - integrity sha512-GF9noBSa9t08pSyl3CY4frMrqp+aQXFGFkf5hEPbh/pIUFYWMK6ZLTfbmadxJVcJrdRoChlWQsA2VkJcDFK8hg== +jest-changed-files@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-changed-files/-/jest-changed-files-29.7.0.tgz#1c06d07e77c78e1585d020424dedc10d6e17ac3a" + integrity sha512-fEArFiwf1BpQ+4bXSprcDc3/x4HSzL4al2tozwVpDFpsxALjLYdyiIK4e5Vz66GQJIbXJ82+35PtysofptNX2w== dependencies: - "@jest/core" "^26.6.3" - "@jest/test-result" "^26.6.2" - "@jest/types" "^26.6.2" + execa "^5.0.0" + jest-util "^29.7.0" + p-limit "^3.1.0" + +jest-circus@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-circus/-/jest-circus-29.7.0.tgz#b6817a45fcc835d8b16d5962d0c026473ee3668a" + integrity sha512-3E1nCMgipcTkCocFwM90XXQab9bS+GMsjdpmPrlelaxwD93Ad8iVEjX/vvHPdLPnFf+L40u+5+iutRdA1N9myw== + dependencies: + "@jest/environment" "^29.7.0" + "@jest/expect" "^29.7.0" + "@jest/test-result" "^29.7.0" + "@jest/types" "^29.6.3" + "@types/node" "*" chalk "^4.0.0" - exit "^0.1.2" - graceful-fs "^4.2.4" - import-local "^3.0.2" - is-ci "^2.0.0" - jest-config "^26.6.3" - jest-util "^26.6.2" - jest-validate "^26.6.2" - prompts "^2.0.1" - yargs "^15.4.1" + co "^4.6.0" + dedent "^1.0.0" + is-generator-fn "^2.0.0" + jest-each "^29.7.0" + jest-matcher-utils "^29.7.0" + jest-message-util "^29.7.0" + jest-runtime "^29.7.0" + jest-snapshot "^29.7.0" + jest-util "^29.7.0" + p-limit "^3.1.0" + pretty-format "^29.7.0" + pure-rand "^6.0.0" + slash "^3.0.0" + stack-utils "^2.0.3" -jest-config@^26.6.3: - version "26.6.3" - resolved "https://registry.yarnpkg.com/jest-config/-/jest-config-26.6.3.tgz#64f41444eef9eb03dc51d5c53b75c8c71f645349" - integrity sha512-t5qdIj/bCj2j7NFVHb2nFB4aUdfucDn3JRKgrZnplb8nieAirAzRSHP8uDEd+qV6ygzg9Pz4YG7UTJf94LPSyg== +jest-cli@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-cli/-/jest-cli-29.7.0.tgz#5592c940798e0cae677eec169264f2d839a37995" + integrity sha512-OVVobw2IubN/GSYsxETi+gOe7Ka59EFMR/twOU3Jb2GnKKeMGJB5SGUUrEz3SFVmJASUdZUzy83sLNNQ2gZslg== dependencies: - "@babel/core" "^7.1.0" - "@jest/test-sequencer" "^26.6.3" - "@jest/types" "^26.6.2" - babel-jest "^26.6.3" + "@jest/core" "^29.7.0" + "@jest/test-result" "^29.7.0" + "@jest/types" "^29.6.3" + chalk "^4.0.0" + create-jest "^29.7.0" + exit "^0.1.2" + import-local "^3.0.2" + jest-config "^29.7.0" + jest-util "^29.7.0" + jest-validate "^29.7.0" + yargs "^17.3.1" + +jest-config@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-config/-/jest-config-29.7.0.tgz#bcbda8806dbcc01b1e316a46bb74085a84b0245f" + integrity sha512-uXbpfeQ7R6TZBqI3/TxCU4q4ttk3u0PJeC+E0zbfSoSjq6bJ7buBPxzQPL0ifrkY4DNu4JUdk0ImlBUYi840eQ== + dependencies: + "@babel/core" "^7.11.6" + "@jest/test-sequencer" "^29.7.0" + "@jest/types" "^29.6.3" + babel-jest "^29.7.0" chalk "^4.0.0" + ci-info "^3.2.0" deepmerge "^4.2.2" - glob "^7.1.1" - graceful-fs "^4.2.4" - jest-environment-jsdom "^26.6.2" - jest-environment-node "^26.6.2" - jest-get-type "^26.3.0" - jest-jasmine2 "^26.6.3" - jest-regex-util "^26.0.0" - jest-resolve "^26.6.2" - jest-util "^26.6.2" - jest-validate "^26.6.2" - micromatch "^4.0.2" - pretty-format "^26.6.2" + glob "^7.1.3" + graceful-fs "^4.2.9" + jest-circus "^29.7.0" + jest-environment-node "^29.7.0" + jest-get-type "^29.6.3" + jest-regex-util "^29.6.3" + jest-resolve "^29.7.0" + jest-runner "^29.7.0" + jest-util "^29.7.0" + jest-validate "^29.7.0" + micromatch "^4.0.4" + parse-json "^5.2.0" + pretty-format "^29.7.0" + slash "^3.0.0" + strip-json-comments "^3.1.1" -jest-diff@^26.0.0, jest-diff@^26.6.2: +jest-diff@^26.0.0: version "26.6.2" resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-26.6.2.tgz#1aa7468b52c3a68d7d5c5fdcdfcd5e49bd164394" integrity sha512-6m+9Z3Gv9wN0WFVasqjCL/06+EFCMTqDEUl/b87HYK2rAPTyfz4ZIuSlPhY51PIQRWx5TaxeF1qmXKe9gfN3sA== @@ -5314,297 +5239,267 @@ jest-diff@^26.0.0, jest-diff@^26.6.2: jest-get-type "^26.3.0" pretty-format "^26.6.2" -jest-docblock@^26.0.0: - version "26.0.0" - resolved "https://registry.yarnpkg.com/jest-docblock/-/jest-docblock-26.0.0.tgz#3e2fa20899fc928cb13bd0ff68bd3711a36889b5" - integrity sha512-RDZ4Iz3QbtRWycd8bUEPxQsTlYazfYn/h5R65Fc6gOfwozFhoImx+affzky/FFBuqISPTqjXomoIGJVKBWoo0w== - dependencies: - detect-newline "^3.0.0" - -jest-each@^26.6.2: - version "26.6.2" - resolved "https://registry.yarnpkg.com/jest-each/-/jest-each-26.6.2.tgz#02526438a77a67401c8a6382dfe5999952c167cb" - integrity sha512-Mer/f0KaATbjl8MCJ+0GEpNdqmnVmDYqCTJYTvoo7rqmRiDllmp2AYN+06F93nXcY3ur9ShIjS+CO/uD+BbH4A== +jest-diff@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-29.7.0.tgz#017934a66ebb7ecf6f205e84699be10afd70458a" + integrity sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw== dependencies: - "@jest/types" "^26.6.2" chalk "^4.0.0" - jest-get-type "^26.3.0" - jest-util "^26.6.2" - pretty-format "^26.6.2" + diff-sequences "^29.6.3" + jest-get-type "^29.6.3" + pretty-format "^29.7.0" -jest-environment-jsdom@^26.6.2: - version "26.6.2" - resolved "https://registry.yarnpkg.com/jest-environment-jsdom/-/jest-environment-jsdom-26.6.2.tgz#78d09fe9cf019a357009b9b7e1f101d23bd1da3e" - integrity sha512-jgPqCruTlt3Kwqg5/WVFyHIOJHsiAvhcp2qiR2QQstuG9yWox5+iHpU3ZrcBxW14T4fe5Z68jAfLRh7joCSP2Q== +jest-docblock@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-docblock/-/jest-docblock-29.7.0.tgz#8fddb6adc3cdc955c93e2a87f61cfd350d5d119a" + integrity sha512-q617Auw3A612guyaFgsbFeYpNP5t2aoUNLwBUbc/0kD1R4t9ixDbyFTHd1nok4epoVFpr7PmeWHrhvuV3XaJ4g== dependencies: - "@jest/environment" "^26.6.2" - "@jest/fake-timers" "^26.6.2" - "@jest/types" "^26.6.2" - "@types/node" "*" - jest-mock "^26.6.2" - jest-util "^26.6.2" - jsdom "^16.4.0" + detect-newline "^3.0.0" -jest-environment-node@^26.6.2: - version "26.6.2" - resolved "https://registry.yarnpkg.com/jest-environment-node/-/jest-environment-node-26.6.2.tgz#824e4c7fb4944646356f11ac75b229b0035f2b0c" - integrity sha512-zhtMio3Exty18dy8ee8eJ9kjnRyZC1N4C1Nt/VShN1apyXc8rWGtJ9lI7vqiWcyyXS4BVSEn9lxAM2D+07/Tag== +jest-each@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-each/-/jest-each-29.7.0.tgz#162a9b3f2328bdd991beaabffbb74745e56577d1" + integrity sha512-gns+Er14+ZrEoC5fhOfYCY1LOHHr0TI+rQUHZS8Ttw2l7gl+80eHc/gFf2Ktkw0+SIACDTeWvpFcv3B04VembQ== dependencies: - "@jest/environment" "^26.6.2" - "@jest/fake-timers" "^26.6.2" - "@jest/types" "^26.6.2" + "@jest/types" "^29.6.3" + chalk "^4.0.0" + jest-get-type "^29.6.3" + jest-util "^29.7.0" + pretty-format "^29.7.0" + +jest-environment-node@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-environment-node/-/jest-environment-node-29.7.0.tgz#0b93e111dda8ec120bc8300e6d1fb9576e164376" + integrity sha512-DOSwCRqXirTOyheM+4d5YZOrWcdu0LNZ87ewUoywbcb2XR4wKgqiG8vNeYwhjFMbEkfju7wx2GYH0P2gevGvFw== + dependencies: + "@jest/environment" "^29.7.0" + "@jest/fake-timers" "^29.7.0" + "@jest/types" "^29.6.3" "@types/node" "*" - jest-mock "^26.6.2" - jest-util "^26.6.2" + jest-mock "^29.7.0" + jest-util "^29.7.0" jest-get-type@^26.3.0: version "26.3.0" resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-26.3.0.tgz#e97dc3c3f53c2b406ca7afaed4493b1d099199e0" integrity sha512-TpfaviN1R2pQWkIihlfEanwOXK0zcxrKEE4MlU6Tn7keoXdN6/3gK/xl0yEh8DOunn5pOVGKf8hB4R9gVh04ig== -jest-haste-map@^26.6.2: - version "26.6.2" - resolved "https://registry.yarnpkg.com/jest-haste-map/-/jest-haste-map-26.6.2.tgz#dd7e60fe7dc0e9f911a23d79c5ff7fb5c2cafeaa" - integrity sha512-easWIJXIw71B2RdR8kgqpjQrbMRWQBgiBwXYEhtGUTaX+doCjBheluShdDMeR8IMfJiTqH4+zfhtg29apJf/8w== +jest-get-type@^29.6.3: + version "29.6.3" + resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-29.6.3.tgz#36f499fdcea197c1045a127319c0481723908fd1" + integrity sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw== + +jest-haste-map@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-haste-map/-/jest-haste-map-29.7.0.tgz#3c2396524482f5a0506376e6c858c3bbcc17b104" + integrity sha512-fP8u2pyfqx0K1rGn1R9pyE0/KTn+G7PxktWidOBTqFPLYX0b9ksaMFkhK5vrS3DVun09pckLdlx90QthlW7AmA== dependencies: - "@jest/types" "^26.6.2" - "@types/graceful-fs" "^4.1.2" + "@jest/types" "^29.6.3" + "@types/graceful-fs" "^4.1.3" "@types/node" "*" anymatch "^3.0.3" fb-watchman "^2.0.0" - graceful-fs "^4.2.4" - jest-regex-util "^26.0.0" - jest-serializer "^26.6.2" - jest-util "^26.6.2" - jest-worker "^26.6.2" - micromatch "^4.0.2" - sane "^4.0.3" - walker "^1.0.7" + graceful-fs "^4.2.9" + jest-regex-util "^29.6.3" + jest-util "^29.7.0" + jest-worker "^29.7.0" + micromatch "^4.0.4" + walker "^1.0.8" optionalDependencies: - fsevents "^2.1.2" + fsevents "^2.3.2" -jest-jasmine2@^26.6.3: - version "26.6.3" - resolved "https://registry.yarnpkg.com/jest-jasmine2/-/jest-jasmine2-26.6.3.tgz#adc3cf915deacb5212c93b9f3547cd12958f2edd" - integrity sha512-kPKUrQtc8aYwBV7CqBg5pu+tmYXlvFlSFYn18ev4gPFtrRzB15N2gW/Roew3187q2w2eHuu0MU9TJz6w0/nPEg== +jest-leak-detector@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-leak-detector/-/jest-leak-detector-29.7.0.tgz#5b7ec0dadfdfec0ca383dc9aa016d36b5ea4c728" + integrity sha512-kYA8IJcSYtST2BY9I+SMC32nDpBT3J2NvWJx8+JCuCdl/CR1I4EKUJROiP8XtCcxqgTTBGJNdbB1A8XRKbTetw== dependencies: - "@babel/traverse" "^7.1.0" - "@jest/environment" "^26.6.2" - "@jest/source-map" "^26.6.2" - "@jest/test-result" "^26.6.2" - "@jest/types" "^26.6.2" - "@types/node" "*" - chalk "^4.0.0" - co "^4.6.0" - expect "^26.6.2" - is-generator-fn "^2.0.0" - jest-each "^26.6.2" - jest-matcher-utils "^26.6.2" - jest-message-util "^26.6.2" - jest-runtime "^26.6.3" - jest-snapshot "^26.6.2" - jest-util "^26.6.2" - pretty-format "^26.6.2" - throat "^5.0.0" + jest-get-type "^29.6.3" + pretty-format "^29.7.0" -jest-leak-detector@^26.6.2: - version "26.6.2" - resolved "https://registry.yarnpkg.com/jest-leak-detector/-/jest-leak-detector-26.6.2.tgz#7717cf118b92238f2eba65054c8a0c9c653a91af" - integrity sha512-i4xlXpsVSMeKvg2cEKdfhh0H39qlJlP5Ex1yQxwF9ubahboQYMgTtz5oML35AVA3B4Eu+YsmwaiKVev9KCvLxg== - dependencies: - jest-get-type "^26.3.0" - pretty-format "^26.6.2" - -jest-matcher-utils@^26.6.2: - version "26.6.2" - resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-26.6.2.tgz#8e6fd6e863c8b2d31ac6472eeb237bc595e53e7a" - integrity sha512-llnc8vQgYcNqDrqRDXWwMr9i7rS5XFiCwvh6DTP7Jqa2mqpcCBBlpCbn+trkG0KNhPu/h8rzyBkriOtBstvWhw== +jest-matcher-utils@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-29.7.0.tgz#ae8fec79ff249fd592ce80e3ee474e83a6c44f12" + integrity sha512-sBkD+Xi9DtcChsI3L3u0+N0opgPYnCRPtGcQYrgXmR+hmt/fYfWAL0xRXYU8eWOdfuLgBe0YCW3AFtnRLagq/g== dependencies: chalk "^4.0.0" - jest-diff "^26.6.2" - jest-get-type "^26.3.0" - pretty-format "^26.6.2" + jest-diff "^29.7.0" + jest-get-type "^29.6.3" + pretty-format "^29.7.0" -jest-message-util@^26.6.2: - version "26.6.2" - resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-26.6.2.tgz#58173744ad6fc0506b5d21150b9be56ef001ca07" - integrity sha512-rGiLePzQ3AzwUshu2+Rn+UMFk0pHN58sOG+IaJbk5Jxuqo3NYO1U2/MIR4S1sKgsoYSXSzdtSa0TgrmtUwEbmA== +jest-message-util@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-29.7.0.tgz#8bc392e204e95dfe7564abbe72a404e28e51f7f3" + integrity sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w== dependencies: - "@babel/code-frame" "^7.0.0" - "@jest/types" "^26.6.2" + "@babel/code-frame" "^7.12.13" + "@jest/types" "^29.6.3" "@types/stack-utils" "^2.0.0" chalk "^4.0.0" - graceful-fs "^4.2.4" - micromatch "^4.0.2" - pretty-format "^26.6.2" + graceful-fs "^4.2.9" + micromatch "^4.0.4" + pretty-format "^29.7.0" slash "^3.0.0" - stack-utils "^2.0.2" + stack-utils "^2.0.3" -jest-mock@^26.6.2: - version "26.6.2" - resolved "https://registry.yarnpkg.com/jest-mock/-/jest-mock-26.6.2.tgz#d6cb712b041ed47fe0d9b6fc3474bc6543feb302" - integrity sha512-YyFjePHHp1LzpzYcmgqkJ0nm0gg/lJx2aZFzFy1S6eUqNjXsOqTK10zNRff2dNfssgokjkG65OlWNcIlgd3zew== +jest-mock@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-mock/-/jest-mock-29.7.0.tgz#4e836cf60e99c6fcfabe9f99d017f3fdd50a6347" + integrity sha512-ITOMZn+UkYS4ZFh83xYAOzWStloNzJFO2s8DWrE4lhtGD+AorgnbkiKERe4wQVBydIGPx059g6riW5Btp6Llnw== dependencies: - "@jest/types" "^26.6.2" + "@jest/types" "^29.6.3" "@types/node" "*" + jest-util "^29.7.0" jest-pnp-resolver@^1.2.2: version "1.2.3" resolved "https://registry.yarnpkg.com/jest-pnp-resolver/-/jest-pnp-resolver-1.2.3.tgz#930b1546164d4ad5937d5540e711d4d38d4cad2e" integrity sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w== -jest-regex-util@^26.0.0: - version "26.0.0" - resolved "https://registry.yarnpkg.com/jest-regex-util/-/jest-regex-util-26.0.0.tgz#d25e7184b36e39fd466c3bc41be0971e821fee28" - integrity sha512-Gv3ZIs/nA48/Zvjrl34bf+oD76JHiGDUxNOVgUjh3j890sblXryjY4rss71fPtD/njchl6PSE2hIhvyWa1eT0A== +jest-regex-util@^29.6.3: + version "29.6.3" + resolved "https://registry.yarnpkg.com/jest-regex-util/-/jest-regex-util-29.6.3.tgz#4a556d9c776af68e1c5f48194f4d0327d24e8a52" + integrity sha512-KJJBsRCyyLNWCNBOvZyRDnAIfUiRJ8v+hOBQYGn8gDyF3UegwiP4gwRR3/SDa42g1YbVycTidUF3rKjyLFDWbg== -jest-resolve-dependencies@^26.6.3: - version "26.6.3" - resolved "https://registry.yarnpkg.com/jest-resolve-dependencies/-/jest-resolve-dependencies-26.6.3.tgz#6680859ee5d22ee5dcd961fe4871f59f4c784fb6" - integrity sha512-pVwUjJkxbhe4RY8QEWzN3vns2kqyuldKpxlxJlzEYfKSvY6/bMvxoFrYYzUO1Gx28yKWN37qyV7rIoIp2h8fTg== +jest-resolve-dependencies@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-resolve-dependencies/-/jest-resolve-dependencies-29.7.0.tgz#1b04f2c095f37fc776ff40803dc92921b1e88428" + integrity sha512-un0zD/6qxJ+S0et7WxeI3H5XSe9lTBBR7bOHCHXkKR6luG5mwDDlIzVQ0V5cZCuoTgEdcdwzTghYkTWfubi+nA== dependencies: - "@jest/types" "^26.6.2" - jest-regex-util "^26.0.0" - jest-snapshot "^26.6.2" + jest-regex-util "^29.6.3" + jest-snapshot "^29.7.0" -jest-resolve@^26.6.2: - version "26.6.2" - resolved "https://registry.yarnpkg.com/jest-resolve/-/jest-resolve-26.6.2.tgz#a3ab1517217f469b504f1b56603c5bb541fbb507" - integrity sha512-sOxsZOq25mT1wRsfHcbtkInS+Ek7Q8jCHUB0ZUTP0tc/c41QHriU/NunqMfCUWsL4H3MHpvQD4QR9kSYhS7UvQ== +jest-resolve@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-resolve/-/jest-resolve-29.7.0.tgz#64d6a8992dd26f635ab0c01e5eef4399c6bcbc30" + integrity sha512-IOVhZSrg+UvVAshDSDtHyFCCBUl/Q3AAJv8iZ6ZjnZ74xzvwuzLXid9IIIPgTnY62SJjfuupMKZsZQRsCvxEgA== dependencies: - "@jest/types" "^26.6.2" chalk "^4.0.0" - graceful-fs "^4.2.4" + graceful-fs "^4.2.9" + jest-haste-map "^29.7.0" jest-pnp-resolver "^1.2.2" - jest-util "^26.6.2" - read-pkg-up "^7.0.1" - resolve "^1.18.1" + jest-util "^29.7.0" + jest-validate "^29.7.0" + resolve "^1.20.0" + resolve.exports "^2.0.0" slash "^3.0.0" -jest-runner@^26.6.3: - version "26.6.3" - resolved "https://registry.yarnpkg.com/jest-runner/-/jest-runner-26.6.3.tgz#2d1fed3d46e10f233fd1dbd3bfaa3fe8924be159" - integrity sha512-atgKpRHnaA2OvByG/HpGA4g6CSPS/1LK0jK3gATJAoptC1ojltpmVlYC3TYgdmGp+GLuhzpH30Gvs36szSL2JQ== +jest-runner@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-runner/-/jest-runner-29.7.0.tgz#809af072d408a53dcfd2e849a4c976d3132f718e" + integrity sha512-fsc4N6cPCAahybGBfTRcq5wFR6fpLznMg47sY5aDpsoejOcVYFb07AHuSnR0liMcPTgBsA3ZJL6kFOjPdoNipQ== dependencies: - "@jest/console" "^26.6.2" - "@jest/environment" "^26.6.2" - "@jest/test-result" "^26.6.2" - "@jest/types" "^26.6.2" + "@jest/console" "^29.7.0" + "@jest/environment" "^29.7.0" + "@jest/test-result" "^29.7.0" + "@jest/transform" "^29.7.0" + "@jest/types" "^29.6.3" "@types/node" "*" chalk "^4.0.0" - emittery "^0.7.1" - exit "^0.1.2" - graceful-fs "^4.2.4" - jest-config "^26.6.3" - jest-docblock "^26.0.0" - jest-haste-map "^26.6.2" - jest-leak-detector "^26.6.2" - jest-message-util "^26.6.2" - jest-resolve "^26.6.2" - jest-runtime "^26.6.3" - jest-util "^26.6.2" - jest-worker "^26.6.2" - source-map-support "^0.5.6" - throat "^5.0.0" - -jest-runtime@^26.6.3: - version "26.6.3" - resolved "https://registry.yarnpkg.com/jest-runtime/-/jest-runtime-26.6.3.tgz#4f64efbcfac398331b74b4b3c82d27d401b8fa2b" - integrity sha512-lrzyR3N8sacTAMeonbqpnSka1dHNux2uk0qqDXVkMv2c/A3wYnvQ4EXuI013Y6+gSKSCxdaczvf4HF0mVXHRdw== - dependencies: - "@jest/console" "^26.6.2" - "@jest/environment" "^26.6.2" - "@jest/fake-timers" "^26.6.2" - "@jest/globals" "^26.6.2" - "@jest/source-map" "^26.6.2" - "@jest/test-result" "^26.6.2" - "@jest/transform" "^26.6.2" - "@jest/types" "^26.6.2" - "@types/yargs" "^15.0.0" + emittery "^0.13.1" + graceful-fs "^4.2.9" + jest-docblock "^29.7.0" + jest-environment-node "^29.7.0" + jest-haste-map "^29.7.0" + jest-leak-detector "^29.7.0" + jest-message-util "^29.7.0" + jest-resolve "^29.7.0" + jest-runtime "^29.7.0" + jest-util "^29.7.0" + jest-watcher "^29.7.0" + jest-worker "^29.7.0" + p-limit "^3.1.0" + source-map-support "0.5.13" + +jest-runtime@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-runtime/-/jest-runtime-29.7.0.tgz#efecb3141cf7d3767a3a0cc8f7c9990587d3d817" + integrity sha512-gUnLjgwdGqW7B4LvOIkbKs9WGbn+QLqRQQ9juC6HndeDiezIwhDP+mhMwHWCEcfQ5RUXa6OPnFF8BJh5xegwwQ== + dependencies: + "@jest/environment" "^29.7.0" + "@jest/fake-timers" "^29.7.0" + "@jest/globals" "^29.7.0" + "@jest/source-map" "^29.6.3" + "@jest/test-result" "^29.7.0" + "@jest/transform" "^29.7.0" + "@jest/types" "^29.6.3" + "@types/node" "*" chalk "^4.0.0" - cjs-module-lexer "^0.6.0" + cjs-module-lexer "^1.0.0" collect-v8-coverage "^1.0.0" - exit "^0.1.2" glob "^7.1.3" - graceful-fs "^4.2.4" - jest-config "^26.6.3" - jest-haste-map "^26.6.2" - jest-message-util "^26.6.2" - jest-mock "^26.6.2" - jest-regex-util "^26.0.0" - jest-resolve "^26.6.2" - jest-snapshot "^26.6.2" - jest-util "^26.6.2" - jest-validate "^26.6.2" + graceful-fs "^4.2.9" + jest-haste-map "^29.7.0" + jest-message-util "^29.7.0" + jest-mock "^29.7.0" + jest-regex-util "^29.6.3" + jest-resolve "^29.7.0" + jest-snapshot "^29.7.0" + jest-util "^29.7.0" slash "^3.0.0" strip-bom "^4.0.0" - yargs "^15.4.1" - -jest-serializer@^26.6.2: - version "26.6.2" - resolved "https://registry.yarnpkg.com/jest-serializer/-/jest-serializer-26.6.2.tgz#d139aafd46957d3a448f3a6cdabe2919ba0742d1" - integrity sha512-S5wqyz0DXnNJPd/xfIzZ5Xnp1HrJWBczg8mMfMpN78OJ5eDxXyf+Ygld9wX1DnUWbIbhM1YDY95NjR4CBXkb2g== - dependencies: - "@types/node" "*" - graceful-fs "^4.2.4" -jest-snapshot@^26.6.2: - version "26.6.2" - resolved "https://registry.yarnpkg.com/jest-snapshot/-/jest-snapshot-26.6.2.tgz#f3b0af1acb223316850bd14e1beea9837fb39c84" - integrity sha512-OLhxz05EzUtsAmOMzuupt1lHYXCNib0ECyuZ/PZOx9TrZcC8vL0x+DUG3TL+GLX3yHG45e6YGjIm0XwDc3q3og== +jest-snapshot@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-snapshot/-/jest-snapshot-29.7.0.tgz#c2c574c3f51865da1bb329036778a69bf88a6be5" + integrity sha512-Rm0BMWtxBcioHr1/OX5YCP8Uov4riHvKPknOGs804Zg9JGZgmIBkbtlxJC/7Z4msKYVbIJtfU+tKb8xlYNfdkw== dependencies: - "@babel/types" "^7.0.0" - "@jest/types" "^26.6.2" - "@types/babel__traverse" "^7.0.4" - "@types/prettier" "^2.0.0" + "@babel/core" "^7.11.6" + "@babel/generator" "^7.7.2" + "@babel/plugin-syntax-jsx" "^7.7.2" + "@babel/plugin-syntax-typescript" "^7.7.2" + "@babel/types" "^7.3.3" + "@jest/expect-utils" "^29.7.0" + "@jest/transform" "^29.7.0" + "@jest/types" "^29.6.3" + babel-preset-current-node-syntax "^1.0.0" chalk "^4.0.0" - expect "^26.6.2" - graceful-fs "^4.2.4" - jest-diff "^26.6.2" - jest-get-type "^26.3.0" - jest-haste-map "^26.6.2" - jest-matcher-utils "^26.6.2" - jest-message-util "^26.6.2" - jest-resolve "^26.6.2" + expect "^29.7.0" + graceful-fs "^4.2.9" + jest-diff "^29.7.0" + jest-get-type "^29.6.3" + jest-matcher-utils "^29.7.0" + jest-message-util "^29.7.0" + jest-util "^29.7.0" natural-compare "^1.4.0" - pretty-format "^26.6.2" - semver "^7.3.2" + pretty-format "^29.7.0" + semver "^7.5.3" -jest-util@^26.1.0, jest-util@^26.6.2: - version "26.6.2" - resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-26.6.2.tgz#907535dbe4d5a6cb4c47ac9b926f6af29576cbc1" - integrity sha512-MDW0fKfsn0OI7MS7Euz6h8HNDXVQ0gaM9uW6RjfDmd1DAFcaxX9OqIakHIqhbnmF08Cf2DLDG+ulq8YQQ0Lp0Q== +jest-util@^29.0.0, jest-util@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-29.7.0.tgz#23c2b62bfb22be82b44de98055802ff3710fc0bc" + integrity sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA== dependencies: - "@jest/types" "^26.6.2" + "@jest/types" "^29.6.3" "@types/node" "*" chalk "^4.0.0" - graceful-fs "^4.2.4" - is-ci "^2.0.0" - micromatch "^4.0.2" + ci-info "^3.2.0" + graceful-fs "^4.2.9" + picomatch "^2.2.3" -jest-validate@^26.6.2: - version "26.6.2" - resolved "https://registry.yarnpkg.com/jest-validate/-/jest-validate-26.6.2.tgz#23d380971587150467342911c3d7b4ac57ab20ec" - integrity sha512-NEYZ9Aeyj0i5rQqbq+tpIOom0YS1u2MVu6+euBsvpgIme+FOfRmoC4R5p0JiAUpaFvFy24xgrpMknarR/93XjQ== +jest-validate@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-validate/-/jest-validate-29.7.0.tgz#7bf705511c64da591d46b15fce41400d52147d9c" + integrity sha512-ZB7wHqaRGVw/9hST/OuFUReG7M8vKeq0/J2egIGLdvjHCmYqGARhzXmtgi+gVeZ5uXFF219aOc3Ls2yLg27tkw== dependencies: - "@jest/types" "^26.6.2" - camelcase "^6.0.0" + "@jest/types" "^29.6.3" + camelcase "^6.2.0" chalk "^4.0.0" - jest-get-type "^26.3.0" + jest-get-type "^29.6.3" leven "^3.1.0" - pretty-format "^26.6.2" + pretty-format "^29.7.0" -jest-watcher@^26.6.2: - version "26.6.2" - resolved "https://registry.yarnpkg.com/jest-watcher/-/jest-watcher-26.6.2.tgz#a5b683b8f9d68dbcb1d7dae32172d2cca0592975" - integrity sha512-WKJob0P/Em2csiVthsI68p6aGKTIcsfjH9Gsx1f0A3Italz43e3ho0geSAVsmj09RWOELP1AZ/DXyJgOgDKxXQ== +jest-watcher@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-watcher/-/jest-watcher-29.7.0.tgz#7810d30d619c3a62093223ce6bb359ca1b28a2f2" + integrity sha512-49Fg7WXkU3Vl2h6LbLtMQ/HyB6rXSIX7SqvBLQmssRBGN9I0PNvPmAmCWSOY6SOvrjhI/F7/bGAv9RtnsPA03g== dependencies: - "@jest/test-result" "^26.6.2" - "@jest/types" "^26.6.2" + "@jest/test-result" "^29.7.0" + "@jest/types" "^29.6.3" "@types/node" "*" ansi-escapes "^4.2.1" chalk "^4.0.0" - jest-util "^26.6.2" + emittery "^0.13.1" + jest-util "^29.7.0" string-length "^4.0.1" jest-when@^3.2.1: @@ -5612,15 +5507,6 @@ jest-when@^3.2.1: resolved "https://registry.yarnpkg.com/jest-when/-/jest-when-3.5.2.tgz#651d8a73751ab55c29698d388dffd3460cd52bdc" integrity sha512-4rDvnhaWh08RcPsoEVXgxRnUIE9wVIbZtGqZ5x2Wm9Ziz9aQs89PipQFmOK0ycbEhVAgiV3MUeTXp3Ar4s2FcQ== -jest-worker@^26.6.2: - version "26.6.2" - resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-26.6.2.tgz#7f72cbc4d643c365e27b9fd775f9d0eaa9c7a8ed" - integrity sha512-KWYVV1c4i+jbMpaBC+U++4Va0cp8OisU185o73T1vo99hqi7w8tSJfUXYswwqqrjzwxa6KpRK54WhPvwf5w6PQ== - dependencies: - "@types/node" "*" - merge-stream "^2.0.0" - supports-color "^7.0.0" - jest-worker@^27.4.5: version "27.5.1" resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-27.5.1.tgz#8d146f0900e8973b106b6f73cc1e9a8cb86f8db0" @@ -5630,14 +5516,25 @@ jest-worker@^27.4.5: merge-stream "^2.0.0" supports-color "^8.0.0" -jest@^26.6.3: - version "26.6.3" - resolved "https://registry.yarnpkg.com/jest/-/jest-26.6.3.tgz#40e8fdbe48f00dfa1f0ce8121ca74b88ac9148ef" - integrity sha512-lGS5PXGAzR4RF7V5+XObhqz2KZIDUA1yD0DG6pBVmy10eh0ZIXQImRuzocsI/N2XZ1GrLFwTS27In2i2jlpq1Q== +jest-worker@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-29.7.0.tgz#acad073acbbaeb7262bd5389e1bcf43e10058d4a" + integrity sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw== dependencies: - "@jest/core" "^26.6.3" + "@types/node" "*" + jest-util "^29.7.0" + merge-stream "^2.0.0" + supports-color "^8.0.0" + +jest@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest/-/jest-29.7.0.tgz#994676fc24177f088f1c5e3737f5697204ff2613" + integrity sha512-NIy3oAFp9shda19hy4HK0HRTWKtPJmGdnvywu01nOqNC2vZg+Z+fvJDxpMQA88eb2I9EcafcdjYgsDthnYTvGw== + dependencies: + "@jest/core" "^29.7.0" + "@jest/types" "^29.6.3" import-local "^3.0.2" - jest-cli "^26.6.3" + jest-cli "^29.7.0" joi@^17.4.0: version "17.9.2" @@ -5697,44 +5594,16 @@ jsbn@1.1.0: resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-1.1.0.tgz#b01307cb29b618a1ed26ec79e911f803c4da0040" integrity sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A== -jsdom@^16.4.0: - version "16.7.0" - resolved "https://registry.yarnpkg.com/jsdom/-/jsdom-16.7.0.tgz#918ae71965424b197c819f8183a754e18977b710" - integrity sha512-u9Smc2G1USStM+s/x1ru5Sxrl6mPYCbByG1U/hUmqaVsm4tbNyS7CicOSRyuGQYZhTu0h84qkZZQ/I+dzizSVw== - dependencies: - abab "^2.0.5" - acorn "^8.2.4" - acorn-globals "^6.0.0" - cssom "^0.4.4" - cssstyle "^2.3.0" - data-urls "^2.0.0" - decimal.js "^10.2.1" - domexception "^2.0.1" - escodegen "^2.0.0" - form-data "^3.0.0" - html-encoding-sniffer "^2.0.1" - http-proxy-agent "^4.0.1" - https-proxy-agent "^5.0.0" - is-potential-custom-element-name "^1.0.1" - nwsapi "^2.2.0" - parse5 "6.0.1" - saxes "^5.0.1" - symbol-tree "^3.2.4" - tough-cookie "^4.0.0" - w3c-hr-time "^1.0.2" - w3c-xmlserializer "^2.0.0" - webidl-conversions "^6.1.0" - whatwg-encoding "^1.0.5" - whatwg-mimetype "^2.3.0" - whatwg-url "^8.5.0" - ws "^7.4.6" - xml-name-validator "^3.0.0" - jsesc@^2.5.1: version "2.5.2" resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4" integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA== +jsesc@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-3.0.2.tgz#bb8b09a6597ba426425f2e4a07245c3d00b9343e" + integrity sha512-xKqzzWXDttJuOcawBt4KnKHHIf5oQ/Cxax+0PWFG+DFDgHNAdi+TXECADI+RYiFUMmx8792xsMbbgXj4CwnP4g== + json-parse-better-errors@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz#bb867cfb3450e69107c131d1c514bab3dc8bcaa9" @@ -5765,11 +5634,6 @@ json-stringify-safe@^5.0.1: resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" integrity sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA== -json5@2.x, json5@^2.2.2, json5@^2.2.3: - version "2.2.3" - resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.3.tgz#78cd6f1a19bdc12b73db5ad0c61efd66c1e29283" - integrity sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg== - json5@^1.0.1, json5@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/json5/-/json5-1.0.2.tgz#63d98d60f21b313b77c4d6da18bfa69d80e1d593" @@ -5777,6 +5641,11 @@ json5@^1.0.1, json5@^1.0.2: dependencies: minimist "^1.2.0" +json5@^2.2.2, json5@^2.2.3: + version "2.2.3" + resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.3.tgz#78cd6f1a19bdc12b73db5ad0c61efd66c1e29283" + integrity sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg== + jsonc-parser@3.2.0: version "3.2.0" resolved "https://registry.yarnpkg.com/jsonc-parser/-/jsonc-parser-3.2.0.tgz#31ff3f4c2b9793f89c67212627c51c6394f88e76" @@ -5837,25 +5706,6 @@ keytar@^7.9.0: node-addon-api "^4.3.0" prebuild-install "^7.0.1" -kind-of@^3.0.2, kind-of@^3.0.3, kind-of@^3.2.0: - version "3.2.2" - resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.2.2.tgz#31ea21a734bab9bbb0f32466d893aea51e4a3c64" - integrity sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ== - dependencies: - is-buffer "^1.1.5" - -kind-of@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-4.0.0.tgz#20813df3d712928b207378691a45066fae72dd57" - integrity sha512-24XsCxmEbRwEDbz/qz3stgin8TTzZ1ESR56OMCN0ujYg+vRutNSiOj9bHH9u85DKgXguraugV5sFuvbD4FW/hw== - dependencies: - is-buffer "^1.1.5" - -kind-of@^6.0.2: - version "6.0.3" - resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.3.tgz#07c05034a6c349fa06e24fa35aa76db4580ce4dd" - integrity sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw== - kleur@^3.0.3: version "3.0.3" resolved "https://registry.yarnpkg.com/kleur/-/kleur-3.0.3.tgz#a79c9ecc86ee1ce3fa6206d1216c501f147fc07e" @@ -5970,6 +5820,11 @@ lodash.isstring@^4.0.1: resolved "https://registry.yarnpkg.com/lodash.isstring/-/lodash.isstring-4.0.1.tgz#d527dfb5456eca7cc9bb95d5daeaf88ba54a5451" integrity sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw== +lodash.memoize@^4.1.2: + version "4.1.2" + resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-4.1.2.tgz#bcc6c49a42a2840ed997f323eada5ecd182e0bfe" + integrity sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag== + lodash.merge@^4.6.2: version "4.6.2" resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a" @@ -5985,7 +5840,7 @@ lodash.truncate@^4.4.2: resolved "https://registry.yarnpkg.com/lodash.truncate/-/lodash.truncate-4.4.2.tgz#5a350da0b1113b837ecfffd5812cbe58d6eae193" integrity sha512-jttmRe7bRse52OsWIMDLaXxWqRAmtIUccAQ3garviCqJjafXOfNMO0yMfNpdD6zbGaTU0P5Nz7e7gAT6cKmJRw== -lodash@4.17.21, lodash@4.x, lodash@^4.17.15, lodash@^4.17.20, lodash@^4.17.21, lodash@^4.7.0: +lodash@4.17.21, lodash@^4.17.15, lodash@^4.17.20, lodash@^4.17.21: version "4.17.21" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== @@ -6069,7 +5924,7 @@ make-dir@^4.0.0: dependencies: semver "^7.5.3" -make-error@1.x, make-error@^1.1.1: +make-error@^1.1.1, make-error@^1.3.6: version "1.3.6" resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2" integrity sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw== @@ -6103,18 +5958,6 @@ makeerror@1.0.12: dependencies: tmpl "1.0.5" -map-cache@^0.2.2: - version "0.2.2" - resolved "https://registry.yarnpkg.com/map-cache/-/map-cache-0.2.2.tgz#c32abd0bd6525d9b051645bb4f26ac5dc98a0dbf" - integrity sha512-8y/eV9QQZCiyn1SprXSrCmqJN0yNRATe+PO8ztwqrvrbdRLA3eYJF0yaR0YayLWkMbsQSKWS9N2gPcGEc4UsZg== - -map-visit@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/map-visit/-/map-visit-1.0.0.tgz#ecdca8f13144e660f1b5bd41f12f3479d98dfb8f" - integrity sha512-4y7uGv8bd2WdM9vpQsiQNo41Ln1NvhvDRuVt0k2JZQ+ezN2uaQes7lZeZ+QQUHOLQAtDaBJ+7wCbi+ab/KFs+w== - dependencies: - object-visit "^1.0.0" - md5@^2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/md5/-/md5-2.3.0.tgz#c3da9a6aae3a30b46b7b0c349b87b110dc3bda4f" @@ -6164,31 +6007,12 @@ methods@^1.1.1, methods@^1.1.2, methods@~1.1.2: resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" integrity sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w== -micromatch@^3.1.4: - version "3.1.10" - resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-3.1.10.tgz#70859bc95c9840952f359a068a3fc49f9ecfac23" - integrity sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg== - dependencies: - arr-diff "^4.0.0" - array-unique "^0.3.2" - braces "^2.3.1" - define-property "^2.0.2" - extend-shallow "^3.0.2" - extglob "^2.0.4" - fragment-cache "^0.2.1" - kind-of "^6.0.2" - nanomatch "^1.2.9" - object.pick "^1.3.0" - regex-not "^1.0.0" - snapdragon "^0.8.1" - to-regex "^3.0.2" - -micromatch@^4.0.0, micromatch@^4.0.2, micromatch@^4.0.4: - version "4.0.5" - resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.5.tgz#bc8999a7cbbf77cdc89f132f6e467051b49090c6" - integrity sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA== - dependencies: - braces "^3.0.2" +micromatch@^4.0.0, micromatch@^4.0.4, micromatch@^4.0.8: + version "4.0.8" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.8.tgz#d66fa18f3a47076789320b9b1af32bd86d9fa202" + integrity sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA== + dependencies: + braces "^3.0.3" picomatch "^2.3.1" mime-db@1.52.0: @@ -6239,7 +6063,7 @@ minimatch@^8.0.2: dependencies: brace-expansion "^2.0.1" -minimist@^1.1.1, minimist@^1.2.0, minimist@^1.2.3, minimist@^1.2.6: +minimist@^1.2.0, minimist@^1.2.3, minimist@^1.2.6: version "1.2.8" resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.8.tgz#c1a464e7693302e082a075cee0c057741ac4772c" integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA== @@ -6308,24 +6132,11 @@ minizlib@^2.0.0, minizlib@^2.1.1: minipass "^3.0.0" yallist "^4.0.0" -mixin-deep@^1.2.0: - version "1.3.2" - resolved "https://registry.yarnpkg.com/mixin-deep/-/mixin-deep-1.3.2.tgz#1120b43dc359a785dce65b55b82e257ccf479566" - integrity sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA== - dependencies: - for-in "^1.0.2" - is-extendable "^1.0.1" - mkdirp-classic@^0.5.2, mkdirp-classic@^0.5.3: version "0.5.3" resolved "https://registry.yarnpkg.com/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz#fa10c9115cc6d8865be221ba47ee9bed78601113" integrity sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A== -mkdirp@1.x, mkdirp@^1.0.3, mkdirp@^1.0.4, mkdirp@~1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e" - integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw== - mkdirp@^0.5.1, mkdirp@^0.5.4: version "0.5.6" resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.6.tgz#7def03d2432dcae4ba1d611445c48396062255f6" @@ -6333,6 +6144,11 @@ mkdirp@^0.5.1, mkdirp@^0.5.4: dependencies: minimist "^1.2.6" +mkdirp@^1.0.3, mkdirp@^1.0.4, mkdirp@~1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e" + integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw== + mkdirp@^2.1.3: version "2.1.6" resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-2.1.6.tgz#964fbcb12b2d8c5d6fbc62a963ac95a273e2cc19" @@ -6445,23 +6261,6 @@ nanoid@3.1.20, nanoid@^3.1.31: resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.6.tgz#443380c856d6e9f9824267d960b4236ad583ea4c" integrity sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA== -nanomatch@^1.2.9: - version "1.2.13" - resolved "https://registry.yarnpkg.com/nanomatch/-/nanomatch-1.2.13.tgz#b87a8aa4fc0de8fe6be88895b38983ff265bd119" - integrity sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA== - dependencies: - arr-diff "^4.0.0" - array-unique "^0.3.2" - define-property "^2.0.2" - extend-shallow "^3.0.2" - fragment-cache "^0.2.1" - is-windows "^1.0.2" - kind-of "^6.0.2" - object.pick "^1.3.0" - regex-not "^1.0.0" - snapdragon "^0.8.1" - to-regex "^3.0.1" - napi-build-utils@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/napi-build-utils/-/napi-build-utils-1.0.2.tgz#b1fddc0b2c46e380a0b7a76f984dd47c41a13806" @@ -6502,11 +6301,6 @@ nestjs-form-data@^1.8.7: mkdirp "^1.0.4" type-is "^1.6.18" -nice-try@^1.0.4: - version "1.0.5" - resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366" - integrity sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ== - nock@^13.3.0: version "13.3.0" resolved "https://registry.yarnpkg.com/nock/-/nock-13.3.0.tgz#b13069c1a03f1ad63120f994b04bfd2556925768" @@ -6595,18 +6389,6 @@ node-int64@^0.4.0: resolved "https://registry.yarnpkg.com/node-int64/-/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b" integrity sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw== -node-notifier@^8.0.0: - version "8.0.2" - resolved "https://registry.yarnpkg.com/node-notifier/-/node-notifier-8.0.2.tgz#f3167a38ef0d2c8a866a83e318c1ba0efeb702c5" - integrity sha512-oJP/9NAdd9+x2Q+rfphB2RJCHjod70RcRLjosiPMMu5gjIfwVnOUGq2nbTjTUbmy0DJ/tFIVT30+Qe3nzl4TJg== - dependencies: - growly "^1.3.0" - is-wsl "^2.2.0" - semver "^7.3.2" - shellwords "^0.1.1" - uuid "^8.3.0" - which "^2.0.2" - node-preload@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/node-preload/-/node-preload-0.2.1.tgz#c03043bb327f417a18fee7ab7ee57b408a144301" @@ -6619,6 +6401,11 @@ node-releases@^2.0.13: resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.13.tgz#d5ed1627c23e3461e819b02e57b75e4899b1c81d" integrity sha512-uYr7J37ae/ORWdZeQ1xxMJe3NtdmqMC/JZK+geofDrkLUApKRHPd18/TxtBOJ4A0/+uUIliorNrfYV6s1b02eQ== +node-releases@^2.0.18: + version "2.0.18" + resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.18.tgz#f010e8d35e2fe8d6b2944f03f70213ecedc4ca3f" + integrity sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g== + node-releases@^2.0.8: version "2.0.10" resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.10.tgz#c311ebae3b6a148c89b1813fd7c4d3c024ef537f" @@ -6636,7 +6423,7 @@ nopt@^5.0.0: dependencies: abbrev "1" -normalize-package-data@^2.3.2, normalize-package-data@^2.5.0: +normalize-package-data@^2.3.2: version "2.5.0" resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.5.0.tgz#e66db1838b200c1dfc233225d12cb36520e234a8" integrity sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA== @@ -6646,26 +6433,12 @@ normalize-package-data@^2.3.2, normalize-package-data@^2.5.0: semver "2 || 3 || 4 || 5" validate-npm-package-license "^3.0.1" -normalize-path@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-2.1.1.tgz#1ab28b556e198363a8c1a6f7e6fa20137fe6aed9" - integrity sha512-3pKJwH184Xo/lnH6oyP1q2pMd7HcypqqmRs91/6/i2CGtWwIKGCkOOMTm/zXbgTEWHw1uNpNi/igc3ePOYHb6w== - dependencies: - remove-trailing-separator "^1.0.1" - normalize-path@^3.0.0, normalize-path@~3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== -npm-run-path@^2.0.0: - version "2.0.2" - resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-2.0.2.tgz#35a9232dfa35d7067b4cb2ddf2357b1871536c5f" - integrity sha512-lJxZYlT4DW/bRUtFh1MQIWqmLwQfAxnqWG4HhEdjMlkrJYnJn0Jrr2u3mgxqaWsdiBc76TYkTG/mhrnYTuzfHw== - dependencies: - path-key "^2.0.0" - -npm-run-path@^4.0.0: +npm-run-path@^4.0.0, npm-run-path@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-4.0.1.tgz#b7ecd1e5ed53da8e37a55e1c2269e0b97ed748ea" integrity sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw== @@ -6682,11 +6455,6 @@ npmlog@^6.0.0: gauge "^4.0.3" set-blocking "^2.0.0" -nwsapi@^2.2.0: - version "2.2.7" - resolved "https://registry.yarnpkg.com/nwsapi/-/nwsapi-2.2.7.tgz#738e0707d3128cb750dddcfe90e4610482df0f30" - integrity sha512-ub5E4+FBPKwAZx0UwIQOjYWGHTEq5sPqHQNRN8Z9e4A7u3Tj1weLJsL59yH9vmvqEtBHaOmT6cYQKIZOxp35FQ== - nyc@^15.1.0: version "15.1.0" resolved "https://registry.yarnpkg.com/nyc/-/nyc-15.1.0.tgz#1335dae12ddc87b6e249d5a1994ca4bdaea75f02" @@ -6725,15 +6493,6 @@ object-assign@^4, object-assign@^4.0.1, object-assign@^4.1.1: resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" integrity sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg== -object-copy@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/object-copy/-/object-copy-0.1.0.tgz#7e7d858b781bd7c991a41ba975ed3812754e998c" - integrity sha512-79LYn6VAb63zgtmAteVOWo9Vdj71ZVBy3Pbse+VqxDpEP83XuujMrGqHIwAXJ5I/aM0zU7dIyIAhifVTPrNItQ== - dependencies: - copy-descriptor "^0.1.0" - define-property "^0.2.5" - kind-of "^3.0.3" - object-diff@^0.0.4: version "0.0.4" resolved "https://registry.yarnpkg.com/object-diff/-/object-diff-0.0.4.tgz#d883b0444fe8fd6e04e595d7bb665682c916047f" @@ -6764,13 +6523,6 @@ object-keys@^1.1.1: resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e" integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA== -object-visit@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/object-visit/-/object-visit-1.0.1.tgz#f79c4493af0c5377b59fe39d395e41042dd045bb" - integrity sha512-GBaMwwAVK9qbQN3Scdo0OyvgPW7l3lnaVMj84uTOZlswkX0KpF6fyDBJhtTthf7pymztoN36/KEr1DyhF96zEA== - dependencies: - isobject "^3.0.0" - object.assign@^4.1.2, object.assign@^4.1.4: version "4.1.4" resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.4.tgz#9673c7c7c351ab8c4d0b516f4343ebf4dfb7799f" @@ -6790,13 +6542,6 @@ object.entries@^1.1.2: define-properties "^1.1.4" es-abstract "^1.20.4" -object.pick@^1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/object.pick/-/object.pick-1.3.0.tgz#87a10ac4c1694bd2e1cbf53591a66141fb5dd747" - integrity sha512-tqa/UMy/CCoYmj+H5qc07qvSL9dqcs/WZENZ1JbtWBlATP+iVOe778gE6MSijnyCnORzDuX6hU+LA4SZ09YjFQ== - dependencies: - isobject "^3.0.1" - object.values@^1.1.6: version "1.1.6" resolved "https://registry.yarnpkg.com/object.values/-/object.values-1.1.6.tgz#4abbaa71eba47d63589d402856f908243eea9b1d" @@ -6844,7 +6589,7 @@ one-time@^1.0.0: dependencies: fn.name "1.x.x" -onetime@^5.1.0: +onetime@^5.1.0, onetime@^5.1.2: version "5.1.2" resolved "https://registry.yarnpkg.com/onetime/-/onetime-5.1.2.tgz#d0e96ebb56b07476df1dd9c4806e5237985ca45e" integrity sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg== @@ -6896,11 +6641,6 @@ p-cancelable@^2.0.0: resolved "https://registry.yarnpkg.com/p-cancelable/-/p-cancelable-2.1.1.tgz#aab7fbd416582fa32a3db49859c122487c5ed2cf" integrity sha512-BZOr3nRQHOntUjTrH8+Lh54smKHoHyur8We1V8DSMVrl5A2malOOwuJRnKRDjSnkoeBh4at6BwEnb5I7Jl31wg== -p-each-series@^2.1.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/p-each-series/-/p-each-series-2.2.0.tgz#105ab0357ce72b202a8a8b94933672657b5e2a9a" - integrity sha512-ycIL2+1V32th+8scbpTvyHNaHe02z0sjgh91XXjAk+ZeXoPN4Z46DVUnzdso0aX4KckKw0FNNFHdjZ2UsZvxiA== - p-finally@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae" @@ -6913,7 +6653,7 @@ p-limit@^2.0.0, p-limit@^2.2.0: dependencies: p-try "^2.0.0" -p-limit@^3.0.2: +p-limit@^3.0.2, p-limit@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-3.1.0.tgz#e1daccbe78d0d1388ca18c64fea38e3e57e3706b" integrity sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ== @@ -7010,7 +6750,7 @@ parse-json@^4.0.0: error-ex "^1.3.1" json-parse-better-errors "^1.0.1" -parse-json@^5.0.0: +parse-json@^5.0.0, parse-json@^5.2.0: version "5.2.0" resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-5.2.0.tgz#c76fc66dee54231c962b22bcc8a72cf2f99753cd" integrity sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg== @@ -7027,26 +6767,21 @@ parse5-htmlparser2-tree-adapter@^6.0.0: dependencies: parse5 "^6.0.1" -parse5@6.0.1, parse5@^6.0.1: - version "6.0.1" - resolved "https://registry.yarnpkg.com/parse5/-/parse5-6.0.1.tgz#e1a1c085c569b3dc08321184f19a39cc27f7c30b" - integrity sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw== - parse5@^5.1.1: version "5.1.1" resolved "https://registry.yarnpkg.com/parse5/-/parse5-5.1.1.tgz#f68e4e5ba1852ac2cadc00f4555fff6c2abb6178" integrity sha512-ugq4DFI0Ptb+WWjAdOK16+u/nHfiIrcE+sh8kZMaM0WllQKLI9rOUq6c2b7cwPkXdzfQESqvoqK6ug7U/Yyzug== +parse5@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/parse5/-/parse5-6.0.1.tgz#e1a1c085c569b3dc08321184f19a39cc27f7c30b" + integrity sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw== + parseurl@~1.3.3: version "1.3.3" resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4" integrity sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ== -pascalcase@^0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/pascalcase/-/pascalcase-0.1.1.tgz#b363e55e8006ca6fe21784d2db22bd15d7917f14" - integrity sha512-XHXfu/yOQRy9vYOtUDVMN60OEJjW013GoObG1o+xwQTpB9eYJX/BjXMsdW13ZDPruFhYYn0AG22w0xgQMwl3Nw== - path-exists@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515" @@ -7062,11 +6797,6 @@ path-is-absolute@^1.0.0: resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" integrity sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg== -path-key@^2.0.0, path-key@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40" - integrity sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw== - path-key@^3.0.0, path-key@^3.1.0: version "3.1.1" resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" @@ -7120,7 +6850,12 @@ picocolors@^1.0.0: resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c" integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ== -picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.3.1: +picocolors@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.1.0.tgz#5358b76a78cde483ba5cef6a9dc9671440b27d59" + integrity sha512-TQ92mBOW0l3LeMeyLV6mzy/kWr8lkd/hp3mTg7wYK7zJhuBStmGMBG0BdeDZS/dZx1IukaX6Bk11zcln25o1Aw== + +picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.2.3, picomatch@^2.3.1: version "2.3.1" resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== @@ -7130,7 +6865,7 @@ pify@^3.0.0: resolved "https://registry.yarnpkg.com/pify/-/pify-3.0.0.tgz#e5a4acd2c101fdf3d9a4d07f0dbc4db49dd28176" integrity sha512-C3FsVNH1udSEX48gGX1xfvwTWfsYWj5U+8/uK15BGzIGrKoUpghX8hWZwa/OFnakBiiVNmBvemTJR5mcy7iPcg== -pirates@^4.0.1: +pirates@^4.0.4: version "4.0.6" resolved "https://registry.yarnpkg.com/pirates/-/pirates-4.0.6.tgz#3018ae32ecfcff6c29ba2267cbf21166ac1f36b9" integrity sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg== @@ -7147,11 +6882,6 @@ pluralize@8.0.0, pluralize@^8.0.0: resolved "https://registry.yarnpkg.com/pluralize/-/pluralize-8.0.0.tgz#1a6fa16a38d12a1901e0320fa017051c539ce3b1" integrity sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA== -posix-character-classes@^0.1.0: - version "0.1.1" - resolved "https://registry.yarnpkg.com/posix-character-classes/-/posix-character-classes-0.1.1.tgz#01eac0fe3b5af71a2a6c02feabb8c1fef7e00eab" - integrity sha512-xTgYBc3fuo7Yt7JbiuFxSYGToMoz8fLoE6TC9Wx1P/u+LfeThMOAqmuyECnlBaaJb+u1m9hHiXUEtwW4OzfUJg== - prebuild-install@^7.0.1: version "7.1.1" resolved "https://registry.yarnpkg.com/prebuild-install/-/prebuild-install-7.1.1.tgz#de97d5b34a70a0c81334fd24641f2a1702352e45" @@ -7203,6 +6933,15 @@ pretty-format@^26.0.0, pretty-format@^26.6.2: ansi-styles "^4.0.0" react-is "^17.0.1" +pretty-format@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-29.7.0.tgz#ca42c758310f365bfa71a0bda0a807160b776812" + integrity sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ== + dependencies: + "@jest/schemas" "^29.6.3" + ansi-styles "^5.0.0" + react-is "^18.0.0" + process-nextick-args@~2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2" @@ -7269,11 +7008,6 @@ prr@~1.0.1: resolved "https://registry.yarnpkg.com/prr/-/prr-1.0.1.tgz#d3fc114ba06995a45ec6893f484ceb1d78f5f476" integrity sha512-yPw4Sng1gWghHQWj0B3ZggWUm4qVbPwPFcRG8KyxiU7J2OHFSoEHKS+EZ3fv5l1t9CyCiop6l/ZYeWbrgoQejw== -psl@^1.1.33: - version "1.9.0" - resolved "https://registry.yarnpkg.com/psl/-/psl-1.9.0.tgz#d0df2a137f00794565fcaf3b2c00cd09f8d5a5a7" - integrity sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag== - pump@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/pump/-/pump-3.0.0.tgz#b4a2116815bde2f4e1ea602354e8c75565107a64" @@ -7287,10 +7021,10 @@ punycode@^2.1.0: resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.3.0.tgz#f67fa67c94da8f4d0cfff981aee4118064199b8f" integrity sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA== -punycode@^2.1.1: - version "2.3.1" - resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.3.1.tgz#027422e2faec0b25e1549c3e1bd8309b9133b6e5" - integrity sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg== +pure-rand@^6.0.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/pure-rand/-/pure-rand-6.1.0.tgz#d173cf23258231976ccbdb05247c9787957604f2" + integrity sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA== pvtsutils@^1.3.2: version "1.3.2" @@ -7318,11 +7052,6 @@ qs@^6.5.1: dependencies: side-channel "^1.0.4" -querystringify@^2.1.1: - version "2.2.0" - resolved "https://registry.yarnpkg.com/querystringify/-/querystringify-2.2.0.tgz#3345941b4153cb9d082d8eee4cda2016a9aef7f6" - integrity sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ== - queue-microtask@^1.2.2: version "1.2.3" resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243" @@ -7386,14 +7115,10 @@ react-is@^17.0.1: resolved "https://registry.yarnpkg.com/react-is/-/react-is-17.0.2.tgz#e691d4a8e9c789365655539ab372762b0efb54f0" integrity sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w== -read-pkg-up@^7.0.1: - version "7.0.1" - resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-7.0.1.tgz#f3a6135758459733ae2b95638056e1854e7ef507" - integrity sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg== - dependencies: - find-up "^4.1.0" - read-pkg "^5.2.0" - type-fest "^0.8.1" +react-is@^18.0.0: + version "18.3.1" + resolved "https://registry.yarnpkg.com/react-is/-/react-is-18.3.1.tgz#e83557dc12eae63a99e003a46388b1dcbb44db7e" + integrity sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg== read-pkg@^4.0.1: version "4.0.1" @@ -7404,16 +7129,6 @@ read-pkg@^4.0.1: parse-json "^4.0.0" pify "^3.0.0" -read-pkg@^5.2.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-5.2.0.tgz#7bf295438ca5a33e56cd30e053b34ee7250c93cc" - integrity sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg== - dependencies: - "@types/normalize-package-data" "^2.4.0" - normalize-package-data "^2.5.0" - parse-json "^5.0.0" - type-fest "^0.6.0" - readable-stream@4.5.2: version "4.5.2" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-4.5.2.tgz#9e7fc4c45099baeed934bff6eb97ba6cf2729e09" @@ -7514,14 +7229,6 @@ regenerator-runtime@^0.13.11: resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz#f6dca3e7ceec20590d07ada785636a90cdca17f9" integrity sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg== -regex-not@^1.0.0, regex-not@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/regex-not/-/regex-not-1.0.2.tgz#1f4ece27e00b0b65e0247a6810e6a85d83a5752c" - integrity sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A== - dependencies: - extend-shallow "^3.0.2" - safe-regex "^1.1.0" - regexp.prototype.flags@^1.4.3: version "1.5.0" resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.5.0.tgz#fe7ce25e7e4cca8db37b6634c8a2c7009199b9cb" @@ -7543,21 +7250,6 @@ release-zalgo@^1.0.0: dependencies: es6-error "^4.0.1" -remove-trailing-separator@^1.0.1: - version "1.1.0" - resolved "https://registry.yarnpkg.com/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz#c24bce2a283adad5bc3f58e0d48249b92379d8ef" - integrity sha512-/hS+Y0u3aOfIETiaiirUFwDBDzmXPvO+jAfKTitUngIPzdKc6Z0LoFjM/CK5PL4C+eKwHohlHAb6H0VFfmmUsw== - -repeat-element@^1.1.2: - version "1.1.4" - resolved "https://registry.yarnpkg.com/repeat-element/-/repeat-element-1.1.4.tgz#be681520847ab58c7568ac75fbfad28ed42d39e9" - integrity sha512-LFiNfRcSu7KK3evMyYOuCzv3L10TW7yC1G2/+StMjK8Y6Vqd2MG7r/Qjw4ghtuCOjFvlnms/iMmLqpvW/ES/WQ== - -repeat-string@^1.6.1: - version "1.6.1" - resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637" - integrity sha512-PV0dzCYDNfRi1jCDbJzpW7jNNDRuCOG/jI5ctQcGKt/clZD+YcPS3yIlWuTJMmESC8aevCFmWJy5wjAFgNqN6w== - require-directory@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" @@ -7573,11 +7265,6 @@ require-main-filename@^2.0.0: resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-2.0.0.tgz#d0b329ecc7cc0f61649f62215be69af54aa8989b" integrity sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg== -requires-port@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff" - integrity sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ== - resolve-cwd@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/resolve-cwd/-/resolve-cwd-3.0.0.tgz#0f0075f1bb2544766cf73ba6a6e2adfebcb13f2d" @@ -7595,10 +7282,10 @@ resolve-from@^5.0.0: resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-5.0.0.tgz#c35225843df8f776df21c57557bc087e9dfdfc69" integrity sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw== -resolve-url@^0.2.1: - version "0.2.1" - resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a" - integrity sha512-ZuF55hVUQaaczgOIwqWzkEcEidmlD/xl44x1UZnhOXcYuFN2S6+rcxpG+C1N3So0wvNI3DmJICUFfu2SxhBmvg== +resolve.exports@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/resolve.exports/-/resolve.exports-2.0.2.tgz#f8c934b8e6a13f539e38b7098e2e36134f01e800" + integrity sha512-X2UW6Nw3n/aMgDVy+0rSqgHlv39WZAlZrXCdnbyEiKm17DSqHX4MmQMaST3FbeWR5FTuRcUwYAziZajji0Y7mg== resolve@^1.1.6, resolve@^1.10.0, resolve@^1.22.1: version "1.22.2" @@ -7609,7 +7296,7 @@ resolve@^1.1.6, resolve@^1.10.0, resolve@^1.22.1: path-parse "^1.0.7" supports-preserve-symlinks-flag "^1.0.0" -resolve@^1.18.1: +resolve@^1.20.0: version "1.22.8" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.8.tgz#b6c87a9f2aa06dfab52e3d70ac8cde321fa5a48d" integrity sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw== @@ -7626,11 +7313,6 @@ restore-cursor@^3.1.0: onetime "^5.1.0" signal-exit "^3.0.2" -ret@~0.1.10: - version "0.1.15" - resolved "https://registry.yarnpkg.com/ret/-/ret-0.1.15.tgz#b8a4825d5bdb1fc3f6f53c2bc33f81388681c7bc" - integrity sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg== - retry@^0.12.0: version "0.12.0" resolved "https://registry.yarnpkg.com/retry/-/retry-0.12.0.tgz#1b42a6266a21f07421d1b0b54b7dc167b01c013b" @@ -7655,11 +7337,6 @@ rimraf@4.4.1: dependencies: glob "^9.2.0" -rsvp@^4.8.4: - version "4.8.5" - resolved "https://registry.yarnpkg.com/rsvp/-/rsvp-4.8.5.tgz#c8f155311d167f68f21e168df71ec5b083113734" - integrity sha512-nfMOlASu9OnRJo1mbEk2cz0D56a1MBNrJ7orjRZQG10XDyuvwksKbuXNp6qa+kbn839HwjwhBzhFmdsaEAfauA== - run-async@^2.4.0: version "2.4.1" resolved "https://registry.yarnpkg.com/run-async/-/run-async-2.4.1.tgz#8440eccf99ea3e70bd409d49aab88e10c189a455" @@ -7705,13 +7382,6 @@ safe-regex-test@^1.0.0: get-intrinsic "^1.1.3" is-regex "^1.1.4" -safe-regex@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/safe-regex/-/safe-regex-1.1.0.tgz#40a3669f3b077d1e943d44629e157dd48023bf2e" - integrity sha512-aJXcif4xnaNUzvUuC5gcb46oTS7zvg4jpMTnuqtrEPlR3vFr4pxtdTwaF1Qs3Enjn9HK+ZlwQui+a7z0SywIzg== - dependencies: - ret "~0.1.10" - safe-stable-stringify@^2.3.1: version "2.4.3" resolved "https://registry.yarnpkg.com/safe-stable-stringify/-/safe-stable-stringify-2.4.3.tgz#138c84b6f6edb3db5f8ef3ef7115b8f55ccbf886" @@ -7722,28 +7392,6 @@ safe-stable-stringify@^2.3.1: resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== -sane@^4.0.3: - version "4.1.0" - resolved "https://registry.yarnpkg.com/sane/-/sane-4.1.0.tgz#ed881fd922733a6c461bc189dc2b6c006f3ffded" - integrity sha512-hhbzAgTIX8O7SHfp2c8/kREfEn4qO/9q8C9beyY6+tvZ87EpoZ3i1RIEvp27YBswnNbY9mWd6paKVmKbAgLfZA== - dependencies: - "@cnakazawa/watch" "^1.0.3" - anymatch "^2.0.0" - capture-exit "^2.0.0" - exec-sh "^0.3.2" - execa "^1.0.0" - fb-watchman "^2.0.0" - micromatch "^3.1.4" - minimist "^1.1.1" - walker "~1.0.5" - -saxes@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/saxes/-/saxes-5.0.1.tgz#eebab953fa3b7608dbe94e5dadb15c888fa6696d" - integrity sha512-5LBh1Tls8c9xgGjw3QrMwETmTMVk0oFgvrFSvWx62llR2hcEInrKNZ2GZCCuuy2lvWrdl5jhbpeqc5hRYKFOcw== - dependencies: - xmlchars "^2.2.0" - schema-utils@^3.1.1, schema-utils@^3.1.2: version "3.1.2" resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-3.1.2.tgz#36c10abca6f7577aeae136c804b0c741edeadc99" @@ -7753,7 +7401,7 @@ schema-utils@^3.1.1, schema-utils@^3.1.2: ajv "^6.12.5" ajv-keywords "^3.5.2" -"semver@2 || 3 || 4 || 5", semver@7.x, semver@^5.5.0, semver@^6.0.0, semver@^6.3.0, semver@^6.3.1, semver@^7.2.1, semver@^7.3.2, semver@^7.3.5, semver@^7.3.8, semver@^7.5.2, semver@^7.5.3, semver@^7.5.4: +"semver@2 || 3 || 4 || 5", semver@^6.0.0, semver@^6.3.0, semver@^6.3.1, semver@^7.2.1, semver@^7.3.5, semver@^7.3.8, semver@^7.5.2, semver@^7.5.3, semver@^7.5.4, semver@^7.6.3: version "7.5.4" resolved "https://registry.yarnpkg.com/semver/-/semver-7.5.4.tgz#483986ec4ed38e1c6c48c34894a9182dbff68a6e" integrity sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA== @@ -7820,16 +7468,6 @@ set-function-length@^1.2.1: gopd "^1.0.1" has-property-descriptors "^1.0.2" -set-value@^2.0.0, set-value@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/set-value/-/set-value-2.0.1.tgz#a18d40530e6f07de4228c7defe4227af8cad005b" - integrity sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw== - dependencies: - extend-shallow "^2.0.1" - is-extendable "^0.1.1" - is-plain-object "^2.0.3" - split-string "^3.0.1" - setprototypeof@1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.1.0.tgz#d0bd85536887b6fe7c0d818cb962d9d91c54e656" @@ -7848,13 +7486,6 @@ sha.js@^2.4.11: inherits "^2.0.1" safe-buffer "^5.0.1" -shebang-command@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea" - integrity sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg== - dependencies: - shebang-regex "^1.0.0" - shebang-command@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea" @@ -7862,11 +7493,6 @@ shebang-command@^2.0.0: dependencies: shebang-regex "^3.0.0" -shebang-regex@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3" - integrity sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ== - shebang-regex@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" @@ -7881,11 +7507,6 @@ shelljs@0.8.5: interpret "^1.0.0" rechoir "^0.6.2" -shellwords@^0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/shellwords/-/shellwords-0.1.1.tgz#d6b9181c1a48d397324c84871efbcfc73fc0654b" - integrity sha512-vFwSUfQvqybiICwZY5+DAWIPLKsWO31Q91JSKl3UYv+K5c2QRPzn0qzec6QPu1Qc9eHYItiP3NdJqNVqetYAww== - side-channel@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.4.tgz#efce5c8fdc104ee751b25c58d4290011fa5ea2cf" @@ -7905,7 +7526,7 @@ side-channel@^1.0.6: get-intrinsic "^1.2.4" object-inspect "^1.13.1" -signal-exit@^3.0.0, signal-exit@^3.0.2, signal-exit@^3.0.7: +signal-exit@^3.0.2, signal-exit@^3.0.3, signal-exit@^3.0.7: version "3.0.7" resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9" integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ== @@ -7955,36 +7576,6 @@ smart-buffer@^4.2.0: resolved "https://registry.yarnpkg.com/smart-buffer/-/smart-buffer-4.2.0.tgz#6e1d71fa4f18c05f7d0ff216dd16a481d0e8d9ae" integrity sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg== -snapdragon-node@^2.0.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/snapdragon-node/-/snapdragon-node-2.1.1.tgz#6c175f86ff14bdb0724563e8f3c1b021a286853b" - integrity sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw== - dependencies: - define-property "^1.0.0" - isobject "^3.0.0" - snapdragon-util "^3.0.1" - -snapdragon-util@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/snapdragon-util/-/snapdragon-util-3.0.1.tgz#f956479486f2acd79700693f6f7b805e45ab56e2" - integrity sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ== - dependencies: - kind-of "^3.2.0" - -snapdragon@^0.8.1: - version "0.8.2" - resolved "https://registry.yarnpkg.com/snapdragon/-/snapdragon-0.8.2.tgz#64922e7c565b0e14204ba1aa7d6964278d25182d" - integrity sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg== - dependencies: - base "^0.11.1" - debug "^2.2.0" - define-property "^0.2.5" - extend-shallow "^2.0.1" - map-cache "^0.2.2" - source-map "^0.5.6" - source-map-resolve "^0.5.0" - use "^3.1.0" - socket.io-adapter@~2.5.2: version "2.5.2" resolved "https://registry.yarnpkg.com/socket.io-adapter/-/socket.io-adapter-2.5.2.tgz#5de9477c9182fdc171cd8c8364b9a8894ec75d12" @@ -8060,16 +7651,13 @@ socks@^2.6.2: ip-address "^9.0.5" smart-buffer "^4.2.0" -source-map-resolve@^0.5.0: - version "0.5.3" - resolved "https://registry.yarnpkg.com/source-map-resolve/-/source-map-resolve-0.5.3.tgz#190866bece7553e1f8f267a2ee82c606b5509a1a" - integrity sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw== +source-map-support@0.5.13: + version "0.5.13" + resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.13.tgz#31b24a9c2e73c2de85066c0feb7d44767ed52932" + integrity sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w== dependencies: - atob "^2.1.2" - decode-uri-component "^0.2.0" - resolve-url "^0.2.1" - source-map-url "^0.4.0" - urix "^0.1.0" + buffer-from "^1.0.0" + source-map "^0.6.0" source-map-support@0.5.21, source-map-support@^0.5.17, source-map-support@^0.5.19, source-map-support@^0.5.6, source-map-support@~0.5.20: version "0.5.21" @@ -8079,22 +7667,12 @@ source-map-support@0.5.21, source-map-support@^0.5.17, source-map-support@^0.5.1 buffer-from "^1.0.0" source-map "^0.6.0" -source-map-url@^0.4.0: - version "0.4.1" - resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.4.1.tgz#0af66605a745a5a2f91cf1bbf8a7afbc283dec56" - integrity sha512-cPiFOTLUKvJFIg4SKVScy4ilPPW6rFgMgfuZJPNoDuMs3nC1HbMUycBoJw77xFIp6z1UJQJOfx6C9GMH80DiTw== - -source-map@0.7.4, source-map@^0.7.3: +source-map@0.7.4: version "0.7.4" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.7.4.tgz#a9bbe705c9d8846f4e08ff6765acf0f1b0898656" integrity sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA== -source-map@^0.5.6: - version "0.5.7" - resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" - integrity sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ== - -source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.1: +source-map@^0.6.0, source-map@^0.6.1: version "0.6.1" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== @@ -8142,13 +7720,6 @@ spdx-license-ids@^3.0.0: resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.13.tgz#7189a474c46f8d47c7b0da4b987bb45e908bd2d5" integrity sha512-XkD+zwiqXHikFZm4AX/7JSCXA98U5Db4AFd5XUg/+9UNtnH75+Z9KxtpYiJZx36mUDVOwH83pl7yvCer6ewM3w== -split-string@^3.0.1, split-string@^3.0.2: - version "3.1.0" - resolved "https://registry.yarnpkg.com/split-string/-/split-string-3.1.0.tgz#7cb09dda3a86585705c64b39a6466038682e8fe2" - integrity sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw== - dependencies: - extend-shallow "^3.0.0" - sprintf-js@^1.1.1: version "1.1.2" resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.1.2.tgz#da1765262bf8c0f571749f2ad6c26300207ae673" @@ -8199,7 +7770,7 @@ stack-trace@0.0.x: resolved "https://registry.yarnpkg.com/stack-trace/-/stack-trace-0.0.10.tgz#547c70b347e8d32b4e108ea1a2a159e5fdde19c0" integrity sha512-KGzahc7puUKkzyMt+IqAep+TVNbKP+k2Lmwhub39m1AsTSkaDutx56aDCo+HLDzf/D26BIHTJWNiTG1KAJiQCg== -stack-utils@^2.0.2: +stack-utils@^2.0.3: version "2.0.6" resolved "https://registry.yarnpkg.com/stack-utils/-/stack-utils-2.0.6.tgz#aaf0748169c02fc33c8232abccf933f54a1cc34f" integrity sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ== @@ -8211,14 +7782,6 @@ standard-as-callback@^2.1.0: resolved "https://registry.yarnpkg.com/standard-as-callback/-/standard-as-callback-2.1.0.tgz#8953fc05359868a77b5b9739a665c5977bb7df45" integrity sha512-qoRRSyROncaz1z0mvYqIE4lCd9p2R90i6GxW3uZv5ucSu8tU7B5HXUP1gG8pVZsYNVaXjk8ClXHPttLyxAL48A== -static-extend@^0.1.1: - version "0.1.2" - resolved "https://registry.yarnpkg.com/static-extend/-/static-extend-0.1.2.tgz#60809c39cbff55337226fd5e0b520f341f1fb5c6" - integrity sha512-72E9+uLc27Mt718pMHt9VMNiAL4LMsmDbBva8mxWUCkT07fSzEGMYUCk0XWY6lp0j6RBAG4cJ3mWuZv2OE3s0g== - dependencies: - define-property "^0.2.5" - object-copy "^0.1.0" - statuses@2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/statuses/-/statuses-2.0.1.tgz#55cb000ccf1d48728bd23c685a063998cf1a1b63" @@ -8340,11 +7903,6 @@ strip-bom@^4.0.0: resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-4.0.0.tgz#9c3505c1db45bcedca3d9cf7a16f5c5aa3901878" integrity sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w== -strip-eof@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf" - integrity sha512-7FCwGGmx8mD5xQd3RPUvnSpUXHM3BWuzjtpD4TXsfcZ9EL4azvVVUscFYwD9nx8Kh+uCBC00XBtAykoMHwTh8Q== - strip-final-newline@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/strip-final-newline/-/strip-final-newline-2.0.0.tgz#89b852fb2fcbe936f6f4b3187afb0a12c1ab58ad" @@ -8413,21 +7971,13 @@ supports-color@^6.1.0: dependencies: has-flag "^3.0.0" -supports-color@^7.0.0, supports-color@^7.1.0: +supports-color@^7.1.0: version "7.2.0" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== dependencies: has-flag "^4.0.0" -supports-hyperlinks@^2.0.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/supports-hyperlinks/-/supports-hyperlinks-2.3.0.tgz#3943544347c1ff90b15effb03fc14ae45ec10624" - integrity sha512-RpsAZlpWcDwOPQA22aCH4J0t7L8JmAvsCxfOSEwm7cQs3LshN36QaTkwd70DnBOXDWGssw2eUoc8CaRWT0XunA== - dependencies: - has-flag "^4.0.0" - supports-color "^7.0.0" - supports-preserve-symlinks-flag@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09" @@ -8455,11 +8005,6 @@ symbol-observable@4.0.0: resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-4.0.0.tgz#5b425f192279e87f2f9b937ac8540d1984b39205" integrity sha512-b19dMThMV4HVFynSAM1++gBHAbk2Tc/osgLIBZMKsyqh34jb2e8Os7T6ZW/Bt3pJFdBTd2JwAnAAEQV7rSNvcQ== -symbol-tree@^3.2.4: - version "3.2.4" - resolved "https://registry.yarnpkg.com/symbol-tree/-/symbol-tree-3.2.4.tgz#430637d248ba77e078883951fb9aa0eed7c63fa2" - integrity sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw== - table@^6.0.9: version "6.8.1" resolved "https://registry.yarnpkg.com/table/-/table-6.8.1.tgz#ea2b71359fe03b017a5fbc296204471158080bdf" @@ -8514,14 +8059,6 @@ tar@^6.0.2, tar@^6.1.11, tar@^6.1.2: mkdirp "^1.0.3" yallist "^4.0.0" -terminal-link@^2.0.0: - version "2.1.1" - resolved "https://registry.yarnpkg.com/terminal-link/-/terminal-link-2.1.1.tgz#14a64a27ab3c0df933ea546fba55f2d078edc994" - integrity sha512-un0FmiRUQNr5PJqy9kP7c40F5BOfpGlYTrxonDChEZB7pzZxRNp/bt+ymiy9/npwXya9KH99nJ/GXFIiUkYGFQ== - dependencies: - ansi-escapes "^4.2.1" - supports-hyperlinks "^2.0.0" - terser-webpack-plugin@^5.3.7: version "5.3.7" resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-5.3.7.tgz#ef760632d24991760f339fe9290deb936ad1ffc7" @@ -8576,11 +8113,6 @@ thenify-all@^1.0.0: dependencies: any-promise "^1.0.0" -throat@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/throat/-/throat-5.0.0.tgz#c5199235803aad18754a667d659b5e72ce16764b" - integrity sha512-fcwX4mndzpLQKBS1DVYhGAcYaYt7vsHNIvQV+WXMvnow5cgjPphq5CaayLaGsjRdSCKZFNGt7/GYAuXaNOiYCA== - through@^2.3.6: version "2.3.8" resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" @@ -8613,21 +8145,6 @@ to-fast-properties@^2.0.0: resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e" integrity sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog== -to-object-path@^0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/to-object-path/-/to-object-path-0.3.0.tgz#297588b7b0e7e0ac08e04e672f85c1f4999e17af" - integrity sha512-9mWHdnGRuh3onocaHzukyvCZhzvr6tiflAy/JRFXcJX0TjgfWA9pk9t8CMbzmBE4Jfw58pXbkngtBtqYxzNEyg== - dependencies: - kind-of "^3.0.2" - -to-regex-range@^2.1.0: - version "2.1.1" - resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-2.1.1.tgz#7c80c17b9dfebe599e27367e0d4dd5590141db38" - integrity sha512-ZZWNfCjUokXXDGXFpZehJIkZqq91BcULFq/Pi7M5i4JnxXdhMKAK682z8bCW3o8Hj1wuuzoKcW3DfVzaP6VuNg== - dependencies: - is-number "^3.0.0" - repeat-string "^1.6.1" - to-regex-range@^5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" @@ -8635,16 +8152,6 @@ to-regex-range@^5.0.1: dependencies: is-number "^7.0.0" -to-regex@^3.0.1, to-regex@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/to-regex/-/to-regex-3.0.2.tgz#13cfdd9b336552f30b51f33a8ae1b42a7a7599ce" - integrity sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw== - dependencies: - define-property "^2.0.2" - extend-shallow "^3.0.2" - regex-not "^1.0.2" - safe-regex "^1.1.0" - toidentifier@1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.1.tgz#3be34321a88a820ed1bd80dfaa33e479fbb8dd35" @@ -8658,23 +8165,6 @@ token-types@^4.1.1: "@tokenizer/token" "^0.3.0" ieee754 "^1.2.1" -tough-cookie@^4.0.0: - version "4.1.3" - resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-4.1.3.tgz#97b9adb0728b42280aa3d814b6b999b2ff0318bf" - integrity sha512-aX/y5pVRkfRnfmuX+OdbSdXvPe6ieKX/G2s7e98f4poJHnqH3281gDPm/metm6E/WRamfx7WC4HUqkWHfQHprw== - dependencies: - psl "^1.1.33" - punycode "^2.1.1" - universalify "^0.2.0" - url-parse "^1.5.3" - -tr46@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/tr46/-/tr46-2.1.0.tgz#fa87aa81ca5d5941da8cbf1f9b749dc969a4e240" - integrity sha512-15Ih7phfcdP5YxqiB+iDtLoaTz4Nd35+IiAv0kQ5FNKHzXgdWqPoTIqEDDJmXceQt4JZk6lVPT8lnDlPpGDppw== - dependencies: - punycode "^2.1.1" - tr46@~0.0.3: version "0.0.3" resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a" @@ -8690,21 +8180,20 @@ triple-beam@^1.3.0: resolved "https://registry.yarnpkg.com/triple-beam/-/triple-beam-1.3.0.tgz#a595214c7298db8339eeeee083e4d10bd8cb8dd9" integrity sha512-XrHUvV5HpdLmIj4uVMxHggLbFSZYIn7HEWsqePZcI50pco+MPqJ50wMGY794X7AOOhxOBAjbkqfAbEe/QMp2Lw== -ts-jest@^26.1.0: - version "26.5.6" - resolved "https://registry.yarnpkg.com/ts-jest/-/ts-jest-26.5.6.tgz#c32e0746425274e1dfe333f43cd3c800e014ec35" - integrity sha512-rua+rCP8DxpA8b4DQD/6X2HQS8Zy/xzViVYfEs2OQu68tkCuKLV0Md8pmX55+W24uRIyAsf/BajRfxOs+R2MKA== +ts-jest@^29.2.5: + version "29.2.5" + resolved "https://registry.yarnpkg.com/ts-jest/-/ts-jest-29.2.5.tgz#591a3c108e1f5ebd013d3152142cb5472b399d63" + integrity sha512-KD8zB2aAZrcKIdGk4OwpJggeLcH1FgrICqDSROWqlnJXGCXK4Mn6FcdK2B6670Xr73lHMG1kHw8R87A0ecZ+vA== dependencies: - bs-logger "0.x" - buffer-from "1.x" - fast-json-stable-stringify "2.x" - jest-util "^26.1.0" - json5 "2.x" - lodash "4.x" - make-error "1.x" - mkdirp "1.x" - semver "7.x" - yargs-parser "20.x" + bs-logger "^0.2.6" + ejs "^3.1.10" + fast-json-stable-stringify "^2.1.0" + jest-util "^29.0.0" + json5 "^2.2.3" + lodash.memoize "^4.1.2" + make-error "^1.3.6" + semver "^7.6.3" + yargs-parser "^21.1.1" ts-loader@^6.2.1: version "6.2.2" @@ -8867,12 +8356,7 @@ type-fest@^0.21.3: resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.21.3.tgz#d260a24b0198436e133fa26a524a6d65fa3b2e37" integrity sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w== -type-fest@^0.6.0: - version "0.6.0" - resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.6.0.tgz#8d2a2370d3df886eb5c90ada1c5bf6188acf838b" - integrity sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg== - -type-fest@^0.8.0, type-fest@^0.8.1: +type-fest@^0.8.0: version "0.8.1" resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.8.1.tgz#09e249ebde851d3b1e48d27c105444667f17b83d" integrity sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA== @@ -8969,16 +8453,6 @@ unicode-trie@^2.0.0: pako "^0.2.5" tiny-inflate "^1.0.0" -union-value@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/union-value/-/union-value-1.0.1.tgz#0b6fe7b835aecda61c6ea4d4f02c14221e109847" - integrity sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg== - dependencies: - arr-union "^3.1.0" - get-value "^2.0.6" - is-extendable "^0.1.1" - set-value "^2.0.1" - unique-filename@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/unique-filename/-/unique-filename-1.1.1.tgz#1d69769369ada0583103a1e6ae87681b56573230" @@ -8993,11 +8467,6 @@ unique-slug@^2.0.0: dependencies: imurmurhash "^0.1.4" -universalify@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.2.0.tgz#6451760566fa857534745ab1dde952d1b1761be0" - integrity sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg== - universalify@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/universalify/-/universalify-2.0.0.tgz#75a4984efedc4b08975c5aeb73f530d02df25717" @@ -9016,14 +8485,6 @@ unpipe@1.0.0, unpipe@~1.0.0: resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" integrity sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ== -unset-value@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/unset-value/-/unset-value-1.0.0.tgz#8376873f7d2335179ffb1e6fc3a8ed0dfc8ab559" - integrity sha512-PcA2tsuGSF9cnySLHTLSh2qrQiJ70mn+r+Glzxv2TWZblxsxCC52BDlZoPCsz7STd9pN7EZetkWZBAvk4cgZdQ== - dependencies: - has-value "^0.3.1" - isobject "^3.0.0" - update-browserslist-db@^1.0.10: version "1.0.11" resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.0.11.tgz#9a2a641ad2907ae7b3616506f4b977851db5b940" @@ -9040,6 +8501,14 @@ update-browserslist-db@^1.0.13: escalade "^3.1.1" picocolors "^1.0.0" +update-browserslist-db@^1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.1.1.tgz#80846fba1d79e82547fb661f8d141e0945755fe5" + integrity sha512-R8UzCaa9Az+38REPiJ1tXlImTJXlVfgHZsglwBD/k6nj76ctsH1E3q4doGrukiLQd3sGQYu56r5+lo5r94l29A== + dependencies: + escalade "^3.2.0" + picocolors "^1.1.0" + uri-js@^4.2.2: version "4.4.1" resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e" @@ -9052,24 +8521,6 @@ urijs@^1.19.1: resolved "https://registry.yarnpkg.com/urijs/-/urijs-1.19.11.tgz#204b0d6b605ae80bea54bea39280cdb7c9f923cc" integrity sha512-HXgFDgDommxn5/bIv0cnQZsPhHDA90NPHD6+c/v21U5+Sx5hoP8+dP9IZXBU1gIfvdRfhG8cel9QNPeionfcCQ== -urix@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/urix/-/urix-0.1.0.tgz#da937f7a62e21fec1fd18d49b35c2935067a6c72" - integrity sha512-Am1ousAhSLBeB9cG/7k7r2R0zj50uDRlZHPGbazid5s9rlF1F/QKYObEKSIunSjIOkJZqwRRLpvewjEkM7pSqg== - -url-parse@^1.5.3: - version "1.5.10" - resolved "https://registry.yarnpkg.com/url-parse/-/url-parse-1.5.10.tgz#9d3c2f736c1d75dd3bd2be507dcc111f1e2ea9c1" - integrity sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ== - dependencies: - querystringify "^2.1.1" - requires-port "^1.0.0" - -use@^3.1.0: - version "3.1.1" - resolved "https://registry.yarnpkg.com/use/-/use-3.1.1.tgz#d50c8cac79a19fbc20f2911f56eb973f4e10070f" - integrity sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ== - util-deprecate@^1.0.1, util-deprecate@~1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" @@ -9080,7 +8531,7 @@ utils-merge@1.0.1: resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" integrity sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA== -uuid@8.3.2, uuid@^8.3.0, uuid@^8.3.2: +uuid@8.3.2, uuid@^8.3.2: version "8.3.2" resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2" integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg== @@ -9095,14 +8546,14 @@ v8-compile-cache@^2.0.3: resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz#2de19618c66dc247dcfb6f99338035d8245a2cee" integrity sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA== -v8-to-istanbul@^7.0.0: - version "7.1.2" - resolved "https://registry.yarnpkg.com/v8-to-istanbul/-/v8-to-istanbul-7.1.2.tgz#30898d1a7fa0c84d225a2c1434fb958f290883c1" - integrity sha512-TxNb7YEUwkLXCQYeudi6lgQ/SZrzNO4kMdlqVxaZPUIUjCv6iSSypUQX70kNBSERpQ8fk48+d61FXk+tgqcWow== +v8-to-istanbul@^9.0.1: + version "9.3.0" + resolved "https://registry.yarnpkg.com/v8-to-istanbul/-/v8-to-istanbul-9.3.0.tgz#b9572abfa62bd556c16d75fdebc1a411d5ff3175" + integrity sha512-kiGUalWN+rgBJ/1OHZsBtU4rXZOfj/7rKQxULKlIzwzQSvMJUUNgPwJEEh7gU6xEVxC0ahoOBvN2YI8GH6FNgA== dependencies: + "@jridgewell/trace-mapping" "^0.3.12" "@types/istanbul-lib-coverage" "^2.0.1" - convert-source-map "^1.6.0" - source-map "^0.7.3" + convert-source-map "^2.0.0" validate-npm-package-license@^3.0.1: version "3.0.4" @@ -9122,21 +8573,7 @@ vary@^1, vary@~1.1.2: resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" integrity sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg== -w3c-hr-time@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz#0a89cdf5cc15822df9c360543676963e0cc308cd" - integrity sha512-z8P5DvDNjKDoFIHK7q8r8lackT6l+jo/Ye3HOle7l9nICP9lf1Ci25fy9vHd0JOWewkIFzXIEig3TdKT7JQ5fQ== - dependencies: - browser-process-hrtime "^1.0.0" - -w3c-xmlserializer@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/w3c-xmlserializer/-/w3c-xmlserializer-2.0.0.tgz#3e7104a05b75146cc60f564380b7f683acf1020a" - integrity sha512-4tzD0mF8iSiMiNs30BiLO3EpfGLZUT2MSX/G+o7ZywDzliWQ3OPtTZ0PTC3B3ca1UAf4cJMHB+2Bf56EriJuRA== - dependencies: - xml-name-validator "^3.0.0" - -walker@^1.0.7, walker@~1.0.5: +walker@^1.0.8: version "1.0.8" resolved "https://registry.yarnpkg.com/walker/-/walker-1.0.8.tgz#bd498db477afe573dc04185f011d3ab8a8d7653f" integrity sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ== @@ -9179,16 +8616,6 @@ webidl-conversions@^3.0.0: resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871" integrity sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ== -webidl-conversions@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-5.0.0.tgz#ae59c8a00b121543a2acc65c0434f57b0fc11aff" - integrity sha512-VlZwKPCkYKxQgeSbH5EyngOmRp7Ww7I9rQLERETtf5ofd9pGeswWiOtogpEO850jziPRarreGxn5QIiTqpb2wA== - -webidl-conversions@^6.1.0: - version "6.1.0" - resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-6.1.0.tgz#9111b4d7ea80acd40f5270d666621afa78b69514" - integrity sha512-qBIvFLGiBpLjfwmYAaHPXsn+ho5xZnGvyGvsarywGNc8VyQJUMHJ8OBKGGrPER0okBeMDaan4mNBlgBROxuI8w== - webpack-node-externals@3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/webpack-node-externals/-/webpack-node-externals-3.0.0.tgz#1a3407c158d547a9feb4229a9e3385b7b60c9917" @@ -9229,18 +8656,6 @@ webpack@5.80.0: watchpack "^2.4.0" webpack-sources "^3.2.3" -whatwg-encoding@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/whatwg-encoding/-/whatwg-encoding-1.0.5.tgz#5abacf777c32166a51d085d6b4f3e7d27113ddb0" - integrity sha512-b5lim54JOPN9HtzvK9HFXvBma/rnfFeqsic0hSpjtDbVxR3dJKLc+KB4V6GgiGOvl7CY/KNh8rxSo9DKQrnUEw== - dependencies: - iconv-lite "0.4.24" - -whatwg-mimetype@^2.3.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz#3d4b1e0312d2079879f826aff18dbeeca5960fbf" - integrity sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g== - whatwg-url@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-5.0.0.tgz#966454e8765462e37644d3626f6742ce8b70965d" @@ -9249,15 +8664,6 @@ whatwg-url@^5.0.0: tr46 "~0.0.3" webidl-conversions "^3.0.0" -whatwg-url@^8.0.0, whatwg-url@^8.5.0: - version "8.7.0" - resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-8.7.0.tgz#656a78e510ff8f3937bc0bcbe9f5c0ac35941b77" - integrity sha512-gAojqb/m9Q8a5IV96E3fHJM70AzCkgt4uXYX2O7EmuyOnLrViCQlsEBmF9UQIu3/aeAIp2U17rtbpZWNntQqdg== - dependencies: - lodash "^4.7.0" - tr46 "^2.1.0" - webidl-conversions "^6.1.0" - which-boxed-primitive@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz#13757bc89b209b049fe5d86430e21cf40a89a8e6" @@ -9293,13 +8699,6 @@ which@2.0.2, which@^2.0.1, which@^2.0.2: dependencies: isexe "^2.0.0" -which@^1.2.9: - version "1.3.1" - resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" - integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ== - dependencies: - isexe "^2.0.0" - wide-align@1.1.3: version "1.1.3" resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.3.tgz#ae074e6bdc0c14a431e804e624549c633b000457" @@ -9414,10 +8813,13 @@ write-file-atomic@^3.0.0: signal-exit "^3.0.2" typedarray-to-buffer "^3.1.5" -ws@^7.4.6: - version "7.5.9" - resolved "https://registry.yarnpkg.com/ws/-/ws-7.5.9.tgz#54fa7db29f4c7cec68b1ddd3a89de099942bb591" - integrity sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q== +write-file-atomic@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-4.0.2.tgz#a9df01ae5b77858a027fd2e80768ee433555fcfd" + integrity sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg== + dependencies: + imurmurhash "^0.1.4" + signal-exit "^3.0.7" ws@~8.11.0: version "8.11.0" @@ -9434,21 +8836,11 @@ xhr2@0.1.3: resolved "https://registry.yarnpkg.com/xhr2/-/xhr2-0.1.3.tgz#cbfc4759a69b4a888e78cf4f20b051038757bd11" integrity sha512-6RmGK22QwC7yXB1CRwyLWuS2opPcKOlAu0ViAnyZjDlzrEmCKL4kLHkfvB8oMRWeztMsNoDGAjsMZY15w/4tTw== -xml-name-validator@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/xml-name-validator/-/xml-name-validator-3.0.0.tgz#6ae73e06de4d8c6e47f9fb181f78d648ad457c6a" - integrity sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw== - xml@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/xml/-/xml-1.0.1.tgz#78ba72020029c5bc87b8a81a3cfcd74b4a2fc1e5" integrity sha512-huCv9IH9Tcf95zuYCsQraZtWnJvBtLVE0QHMOs8bWyZAFZNDcYjsPq1nEx8jKA9y+Beo9v+7OBPRisQTjinQMw== -xmlchars@^2.2.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/xmlchars/-/xmlchars-2.2.0.tgz#060fe1bcb7f9c76fe2a17db86a9bc3ab894210cb" - integrity sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw== - xmlhttprequest-ssl@~2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/xmlhttprequest-ssl/-/xmlhttprequest-ssl-2.1.1.tgz#0d045c3b2babad8e7db1af5af093f5d0d60df99a" @@ -9494,11 +8886,6 @@ yargs-parser@20.2.4: resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.4.tgz#b42890f14566796f85ae8e3a25290d205f154a54" integrity sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA== -yargs-parser@20.x, yargs-parser@^20.2.2: - version "20.2.9" - resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.9.tgz#2eb7dc3b0289718fc295f362753845c41a0c94ee" - integrity sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w== - yargs-parser@21.1.1, yargs-parser@^21.1.1: version "21.1.1" resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-21.1.1.tgz#9096bceebf990d21bb31fa9516e0ede294a77d35" @@ -9520,6 +8907,11 @@ yargs-parser@^18.1.2: camelcase "^5.0.0" decamelize "^1.2.0" +yargs-parser@^20.2.2: + version "20.2.9" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.9.tgz#2eb7dc3b0289718fc295f362753845c41a0c94ee" + integrity sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w== + yargs-unparser@2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/yargs-unparser/-/yargs-unparser-2.0.0.tgz#f131f9226911ae5d9ad38c432fe809366c2325eb" @@ -9559,7 +8951,7 @@ yargs@^13.3.0: y18n "^4.0.0" yargs-parser "^13.1.2" -yargs@^15.0.2, yargs@^15.4.1: +yargs@^15.0.2: version "15.4.1" resolved "https://registry.yarnpkg.com/yargs/-/yargs-15.4.1.tgz#0d87a16de01aee9d8bec2bfbf74f67851730f4f8" integrity sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A== @@ -9576,6 +8968,19 @@ yargs@^15.0.2, yargs@^15.4.1: y18n "^4.0.0" yargs-parser "^18.1.2" +yargs@^17.3.1: + version "17.7.2" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.7.2.tgz#991df39aca675a192b816e1e0363f9d75d2aa269" + integrity sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w== + dependencies: + cliui "^8.0.1" + escalade "^3.1.1" + get-caller-file "^2.0.5" + require-directory "^2.1.1" + string-width "^4.2.3" + y18n "^5.0.5" + yargs-parser "^21.1.1" + yargs@^17.6.2: version "17.7.1" resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.7.1.tgz#34a77645201d1a8fc5213ace787c220eabbd0967" From 7044eab5c7ead2ea3ea1afeef9414a4a7aeade69 Mon Sep 17 00:00:00 2001 From: zalenskiSofteq Date: Wed, 16 Oct 2024 11:12:25 +0200 Subject: [PATCH 178/256] update root dependencies --- yarn.lock | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/yarn.lock b/yarn.lock index 84f858d3be..33c835f027 100644 --- a/yarn.lock +++ b/yarn.lock @@ -10589,10 +10589,10 @@ path-scurry@^1.11.1: lru-cache "^10.2.0" minipass "^5.0.0 || ^6.0.2 || ^7.0.0" -path-to-regexp@^1.7.0: - version "1.8.0" - resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-1.8.0.tgz#887b3ba9d84393e87a0a0b9f4cb756198b53548a" - integrity sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA== +path-to-regexp@^1.7.0, path-to-regexp@^1.9.0: + version "1.9.0" + resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-1.9.0.tgz#5dc0753acbf8521ca2e0f137b4578b917b10cf24" + integrity sha512-xIp7/apCFJuUHdDLWe8O1HIkb0kQrOMb/0u6FXQjemHn/ii5LrIzU6bdECnsiTF/GjZkMEKg1xdiZwNqDYlZ6g== dependencies: isarray "0.0.1" From dc8ef5a31ec748ad1f69f7ce86381e7d3aa1e97b Mon Sep 17 00:00:00 2001 From: ArtemHoruzhenko Date: Wed, 16 Oct 2024 12:13:44 +0300 Subject: [PATCH 179/256] fix tests --- .../modules/ai/query/ai-query.service.spec.ts | 2 +- .../utils/autodiscovery.util.spec.ts | 17 ++++++++--------- redisinsight/api/yarn.lock | 14 +++++++------- 3 files changed, 16 insertions(+), 17 deletions(-) diff --git a/redisinsight/api/src/modules/ai/query/ai-query.service.spec.ts b/redisinsight/api/src/modules/ai/query/ai-query.service.spec.ts index 4f76eae1b3..830d5544a5 100644 --- a/redisinsight/api/src/modules/ai/query/ai-query.service.spec.ts +++ b/redisinsight/api/src/modules/ai/query/ai-query.service.spec.ts @@ -57,7 +57,7 @@ describe('AiQueryService', () => { clientSocket.disconnect(); serverSocket.disconnect(); wsServer.close(); - httpServer.stop(); + httpServer?.stop(); }); beforeEach(async () => { diff --git a/redisinsight/api/src/modules/autodiscovery/utils/autodiscovery.util.spec.ts b/redisinsight/api/src/modules/autodiscovery/utils/autodiscovery.util.spec.ts index ded19a8696..9fb77462f2 100644 --- a/redisinsight/api/src/modules/autodiscovery/utils/autodiscovery.util.spec.ts +++ b/redisinsight/api/src/modules/autodiscovery/utils/autodiscovery.util.spec.ts @@ -4,7 +4,6 @@ import { import * as os from 'os'; import * as ch from 'child_process'; import * as net from 'net'; -import { mocked } from 'ts-jest/utils'; import * as events from 'events'; import * as stream from 'stream'; import { ChildProcess } from 'child_process'; @@ -39,17 +38,17 @@ describe('getSpawnArgs', () => { const getSpawnArgsTests = [ { name: 'Linux', - before: () => mocked(os.type).mockReturnValue('Linux'), + before: () => (os.type as jest.Mock).mockReturnValue('Linux'), output: ['netstat', ['-anpt']], }, { name: 'Darwin', - before: () => mocked(os.type).mockReturnValue('Darwin'), + before: () => (os.type as jest.Mock).mockReturnValue('Darwin'), output: ['netstat', ['-anvp', 'tcp']], }, { name: 'Windows_NT', - before: () => mocked(os.type).mockReturnValue('Windows_NT'), + before: () => (os.type as jest.Mock).mockReturnValue('Windows_NT'), output: ['netstat.exe', ['-a', '-n', '-o']], }, ]; @@ -67,8 +66,8 @@ describe('getSpawnArgs', () => { describe('getRunningProcesses', () => { beforeEach(() => { - mocked(os.type).mockReturnValue('Linux'); - mocked(ch.spawn).mockReturnValue(mockChildProcess); + (os.type as jest.Mock).mockReturnValue('Linux'); + (ch.spawn as jest.Mock).mockReturnValue(mockChildProcess); }); const getRunningProcessesTests = [ { @@ -94,7 +93,7 @@ describe('getRunningProcesses', () => { }); it('Should throw an error for unsupported platform', async () => { - mocked(os.type).mockReturnValueOnce('custom_os'); + (os.type as jest.Mock).mockReturnValueOnce('custom_os'); try { await autodiscoveryUtility.getRunningProcesses(); @@ -172,7 +171,7 @@ describe('getTCPEndpoints', () => { describe('testEndpoint', () => { beforeEach(() => { - mocked(net.createConnection).mockReturnValue(mockSocket); + (net.createConnection as jest.Mock).mockReturnValue(mockSocket); }); const testEndpointTests = [ { @@ -224,7 +223,7 @@ describe('getAvailableEndpoints', () => { beforeEach(() => { const getRunningProcessesSpy = jest.spyOn(autodiscoveryUtility, 'getRunningProcesses'); getRunningProcessesSpy.mockResolvedValue(['']); - mocked(net.createConnection).mockReturnValue(mockSocket); + (net.createConnection as jest.Mock).mockReturnValue(mockSocket); }); const getAvailableEndpointsTests = [ { diff --git a/redisinsight/api/yarn.lock b/redisinsight/api/yarn.lock index f87e5994dc..dbbfea3e88 100644 --- a/redisinsight/api/yarn.lock +++ b/redisinsight/api/yarn.lock @@ -2372,13 +2372,6 @@ brace-expansion@^2.0.1: dependencies: balanced-match "^1.0.0" -braces@^3.0.2, braces@~3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" - integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A== - dependencies: - fill-range "^7.0.1" - braces@^3.0.3: version "3.0.3" resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.3.tgz#490332f40919452272d55a8480adc0c441358789" @@ -2386,6 +2379,13 @@ braces@^3.0.3: dependencies: fill-range "^7.1.1" +braces@~3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" + integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A== + dependencies: + fill-range "^7.0.1" + broadcast-channel@~4.17.0: version "4.17.0" resolved "https://registry.yarnpkg.com/broadcast-channel/-/broadcast-channel-4.17.0.tgz#599d44674b09a4e2e07af6da5d03b45ca8bffd11" From bf36292ffc695adfe8c626d4a329d412bc13c890 Mon Sep 17 00:00:00 2001 From: ArtemHoruzhenko Date: Wed, 16 Oct 2024 12:26:50 +0300 Subject: [PATCH 180/256] fix unit tests --- .../api/src/modules/ai/query/ai-query.service.spec.ts | 2 +- .../autodiscovery/autodiscovery.service.spec.ts | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/redisinsight/api/src/modules/ai/query/ai-query.service.spec.ts b/redisinsight/api/src/modules/ai/query/ai-query.service.spec.ts index 830d5544a5..1d9e4aa7ae 100644 --- a/redisinsight/api/src/modules/ai/query/ai-query.service.spec.ts +++ b/redisinsight/api/src/modules/ai/query/ai-query.service.spec.ts @@ -57,7 +57,7 @@ describe('AiQueryService', () => { clientSocket.disconnect(); serverSocket.disconnect(); wsServer.close(); - httpServer?.stop(); + httpServer?.stop?.(); }); beforeEach(async () => { diff --git a/redisinsight/api/src/modules/autodiscovery/autodiscovery.service.spec.ts b/redisinsight/api/src/modules/autodiscovery/autodiscovery.service.spec.ts index 1edbcbeec2..72de8aad2d 100644 --- a/redisinsight/api/src/modules/autodiscovery/autodiscovery.service.spec.ts +++ b/redisinsight/api/src/modules/autodiscovery/autodiscovery.service.spec.ts @@ -13,7 +13,6 @@ import { import { SettingsService } from 'src/modules/settings/settings.service'; import { AutodiscoveryService } from 'src/modules/autodiscovery/autodiscovery.service'; import { DatabaseService } from 'src/modules/database/database.service'; -import { mocked } from 'ts-jest/utils'; import config, { Config } from 'src/utils/config'; import { RedisClientFactory } from 'src/modules/redis/redis.client.factory'; import { ConstantsProvider } from 'src/modules/constants/providers/constants.provider'; @@ -84,7 +83,7 @@ describe('AutodiscoveryService', () => { databaseService = module.get(DatabaseService); redisClientFactory = module.get(RedisClientFactory); - mocked(utils.convertRedisInfoReplyToObject).mockReturnValue({ + (utils.convertRedisInfoReplyToObject as jest.Mock).mockReturnValue({ server: { redis_mode: 'standalone', }, @@ -155,7 +154,7 @@ describe('AutodiscoveryService', () => { let addRedisDatabaseSpy; beforeEach(async () => { - mocked(getAvailableEndpoints).mockResolvedValue([]); + (getAvailableEndpoints as jest.Mock).mockResolvedValue([]); addRedisDatabaseSpy = jest.spyOn(service as any, 'addRedisDatabase'); addRedisDatabaseSpy.mockResolvedValue(null); }); @@ -167,7 +166,8 @@ describe('AutodiscoveryService', () => { }); it('should should call addRedisDatabase 2 times', async () => { - mocked(getAvailableEndpoints).mockResolvedValueOnce([mockAutodiscoveryEndpoint, mockAutodiscoveryEndpoint]); + (getAvailableEndpoints as jest.Mock) + .mockResolvedValueOnce([mockAutodiscoveryEndpoint, mockAutodiscoveryEndpoint]); await service['discoverDatabases'](mockSessionMetadata); expect(addRedisDatabaseSpy).toHaveBeenCalledTimes(2); @@ -193,7 +193,7 @@ describe('AutodiscoveryService', () => { }); it('should not create database if redis_mode is not standalone', async () => { - mocked(utils.convertRedisInfoReplyToObject).mockReturnValueOnce({ + (utils.convertRedisInfoReplyToObject as jest.Mock).mockReturnValueOnce({ server: { redis_mode: 'cluster', }, From 72c82385dd2ddf41d02eb59fa7faedaff86d08b0 Mon Sep 17 00:00:00 2001 From: ArtemHoruzhenko Date: Wed, 16 Oct 2024 13:45:46 +0300 Subject: [PATCH 181/256] upgrade nest packages --- redisinsight/api/package.json | 26 +- redisinsight/api/yarn.lock | 1327 +++++++++++++++++---------------- 2 files changed, 686 insertions(+), 667 deletions(-) diff --git a/redisinsight/api/package.json b/redisinsight/api/package.json index 42229295c9..7a88688fe2 100644 --- a/redisinsight/api/package.json +++ b/redisinsight/api/package.json @@ -45,20 +45,23 @@ "jest/**/micromatch": "^4.0.8", "ts-loader/micromatch": "^4.0.8", "mocha/minimatch": "^3.0.5", + "@nestjs/serve-static/path-to-regexp": "^1.9.0", + "@nestjs/platform-express/express": "^4.21.1", "@nestjs/platform-socket.io/socket.io": "^4.8.0", + "@nestjs/cli/**/braces": "^3.0.3", "**/semver": "^7.5.2", "winston-daily-rotate-file/**/file-stream-rotator": "^1.0.0" }, "dependencies": { - "@nestjs/common": "^10.3.7", - "@nestjs/core": "^10.3.7", + "@nestjs/common": "^10.4.4", + "@nestjs/core": "^10.4.4", "@nestjs/event-emitter": "^2.0.4", "@nestjs/platform-express": "^10.4.4", "@nestjs/platform-socket.io": "^10.4.4", - "@nestjs/serve-static": "^3.0.0", - "@nestjs/swagger": "^7.3.1", - "@nestjs/typeorm": "^9.0.1", - "@nestjs/websockets": "^10.3.7", + "@nestjs/serve-static": "^4.0.2", + "@nestjs/swagger": "^7.4.2", + "@nestjs/typeorm": "^10.0.2", + "@nestjs/websockets": "^10.4.4", "@okta/okta-auth-js": "^7.3.0", "@segment/analytics-node": "^2.1.3", "adm-zip": "^0.5.9", @@ -72,7 +75,7 @@ "date-fns": "^2.29.3", "detect-port": "^1.5.1", "dotenv": "^16.0.0", - "express": "^4.21.0", + "express": "^4.21.1", "fs-extra": "^10.0.0", "ioredis": "^5.2.2", "is-glob": "^4.0.1", @@ -99,15 +102,14 @@ }, "devDependencies": { "@mochajs/json-file-reporter": "^1.3.0", - "@nestjs/cli": "^9.1.2", - "@nestjs/schematics": "^9.0.3", - "@nestjs/testing": "^9.0.11", + "@nestjs/cli": "^10.4.5", + "@nestjs/schematics": "^10.1.4", + "@nestjs/testing": "^10.4.4", "@types/adm-zip": "^0.5.0", "@types/express": "^4.17.3", "@types/jest": "^26.0.15", "@types/lodash": "^4.14.167", "@types/node": "14.14.10", - "@types/socket.io": "^3.0.2", "@types/ssh2": "^1.11.6", "@types/supertest": "^2.0.8", "@typescript-eslint/eslint-plugin": "^4.8.1", @@ -140,7 +142,7 @@ "ts-node": "^9.1.1", "tsconfig-paths": "^3.9.0", "tsconfig-paths-webpack-plugin": "^3.3.0", - "typescript": "^4.0.5" + "typescript": "^4.8.2" }, "jest": { "moduleFileExtensions": [ diff --git a/redisinsight/api/yarn.lock b/redisinsight/api/yarn.lock index dbbfea3e88..5d474aa531 100644 --- a/redisinsight/api/yarn.lock +++ b/redisinsight/api/yarn.lock @@ -10,61 +10,40 @@ "@jridgewell/gen-mapping" "^0.3.0" "@jridgewell/trace-mapping" "^0.3.9" -"@angular-devkit/core@15.2.4": - version "15.2.4" - resolved "https://registry.yarnpkg.com/@angular-devkit/core/-/core-15.2.4.tgz#f7696f09c66d01568a07f0e71672e887fdf57280" - integrity sha512-yl+0j1bMwJLKShsyCXw77tbJG8Sd21+itisPLL2MgEpLNAO252kr9zG4TLlFRJyKVftm2l1h78KjqvM5nbOXNg== +"@angular-devkit/core@17.3.8": + version "17.3.8" + resolved "https://registry.yarnpkg.com/@angular-devkit/core/-/core-17.3.8.tgz#8679cacf84cf79764f027811020e235ab32016d2" + integrity sha512-Q8q0voCGudbdCgJ7lXdnyaxKHbNQBARH68zPQV72WT8NWy+Gw/tys870i6L58NWbBaCJEUcIj/kb6KoakSRu+Q== dependencies: ajv "8.12.0" ajv-formats "2.1.1" - jsonc-parser "3.2.0" - rxjs "6.6.7" + jsonc-parser "3.2.1" + picomatch "4.0.1" + rxjs "7.8.1" source-map "0.7.4" -"@angular-devkit/core@15.2.6": - version "15.2.6" - resolved "https://registry.yarnpkg.com/@angular-devkit/core/-/core-15.2.6.tgz#9118faadbc5e3613283da1774826d2b41883330f" - integrity sha512-YVTWZ+M+xNKdFX4EnY9QX49PZraawiaA0iTd2CUW8ZoTUvU7yOGMKZLSdz6aokTMRVfm0449wt6YL994ibOo1g== +"@angular-devkit/schematics-cli@17.3.8": + version "17.3.8" + resolved "https://registry.yarnpkg.com/@angular-devkit/schematics-cli/-/schematics-cli-17.3.8.tgz#26eeb9b581309be474868d01d9f87555760557c3" + integrity sha512-TjmiwWJarX7oqvNiRAroQ5/LeKUatxBOCNEuKXO/PV8e7pn/Hr/BqfFm+UcYrQoFdZplmtNAfqmbqgVziKvCpA== dependencies: - ajv "8.12.0" - ajv-formats "2.1.1" - jsonc-parser "3.2.0" - rxjs "6.6.7" - source-map "0.7.4" - -"@angular-devkit/schematics-cli@15.2.6": - version "15.2.6" - resolved "https://registry.yarnpkg.com/@angular-devkit/schematics-cli/-/schematics-cli-15.2.6.tgz#d93cf220e61a0597828715bf9a36d2341e0561d0" - integrity sha512-dkmJAvLmiXIX3uAY0a7GcnEvKNN/RKR5Q/ez4OQb+jaz+2/XbAiQVmTgZ5uwU2gYkFNLvG9ZCAaQdC4JJp9xaw== - dependencies: - "@angular-devkit/core" "15.2.6" - "@angular-devkit/schematics" "15.2.6" + "@angular-devkit/core" "17.3.8" + "@angular-devkit/schematics" "17.3.8" ansi-colors "4.1.3" - inquirer "8.2.4" + inquirer "9.2.15" symbol-observable "4.0.0" yargs-parser "21.1.1" -"@angular-devkit/schematics@15.2.4": - version "15.2.4" - resolved "https://registry.yarnpkg.com/@angular-devkit/schematics/-/schematics-15.2.4.tgz#85129ebabcdb362f4b65a6e290bb2ae846f3d64c" - integrity sha512-/W7/vvn59PAVLzhcvD4/N/E8RDhub8ny1A7I96LTRjC5o+yvVV16YJ4YJzolrRrIEN01KmLVQJ9A58VCaweMgw== +"@angular-devkit/schematics@17.3.8": + version "17.3.8" + resolved "https://registry.yarnpkg.com/@angular-devkit/schematics/-/schematics-17.3.8.tgz#f853eb21682aadfb6667e090b5b509fc95ce8442" + integrity sha512-QRVEYpIfgkprNHc916JlPuNbLzOgrm9DZalHasnLUz4P6g7pR21olb8YCyM2OTJjombNhya9ZpckcADU5Qyvlg== dependencies: - "@angular-devkit/core" "15.2.4" - jsonc-parser "3.2.0" - magic-string "0.29.0" + "@angular-devkit/core" "17.3.8" + jsonc-parser "3.2.1" + magic-string "0.30.8" ora "5.4.1" - rxjs "6.6.7" - -"@angular-devkit/schematics@15.2.6": - version "15.2.6" - resolved "https://registry.yarnpkg.com/@angular-devkit/schematics/-/schematics-15.2.6.tgz#fb5b7530f21586dbdec45cac56f8a418bcfd053d" - integrity sha512-f7VgnAcok7AwR/DhX0ZWskB0rFBo/KsvtIUA2qZSrpKMf8eFiwu03dv/b2mI0vnf+1FBfIQzJvO0ww45zRp6dA== - dependencies: - "@angular-devkit/core" "15.2.6" - jsonc-parser "3.2.0" - magic-string "0.29.0" - ora "5.4.1" - rxjs "6.6.7" + rxjs "7.8.1" "@babel/code-frame@7.12.11": version "7.12.11" @@ -740,6 +719,18 @@ resolved "https://registry.yarnpkg.com/@ioredis/commands/-/commands-1.2.0.tgz#6d61b3097470af1fdbbe622795b8921d42018e11" integrity sha512-Sx1pU8EM64o2BrqNpEO1CNLtKQwyhuXuqyfH7oGKCk+1a33d2r5saW8zNwm3j6BTExtjrv2BxTgzzkMwts6vGg== +"@isaacs/cliui@^8.0.2": + version "8.0.2" + resolved "https://registry.yarnpkg.com/@isaacs/cliui/-/cliui-8.0.2.tgz#b37667b7bc181c168782259bab42474fbf52b550" + integrity sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA== + dependencies: + string-width "^5.1.2" + string-width-cjs "npm:string-width@^4.2.0" + strip-ansi "^7.0.1" + strip-ansi-cjs "npm:strip-ansi@^6.0.1" + wrap-ansi "^8.1.0" + wrap-ansi-cjs "npm:wrap-ansi@^7.0.0" + "@istanbuljs/load-nyc-config@^1.0.0": version "1.1.0" resolved "https://registry.yarnpkg.com/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz#fd3db1d59ecf7cf121e80650bb86712f9b55eced" @@ -997,30 +988,30 @@ resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.2.1.tgz#558fb6472ed16a4c850b889530e6b36438c49280" integrity sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A== -"@jridgewell/source-map@^0.3.2": - version "0.3.3" - resolved "https://registry.yarnpkg.com/@jridgewell/source-map/-/source-map-0.3.3.tgz#8108265659d4c33e72ffe14e33d6cc5eb59f2fda" - integrity sha512-b+fsZXeLYi9fEULmfBrhxn4IrPlINf8fiNarzTof004v3lFdntdwa9PF7vFJqm3mg7s+ScJMxXaE3Acp1irZcg== +"@jridgewell/source-map@^0.3.3": + version "0.3.6" + resolved "https://registry.yarnpkg.com/@jridgewell/source-map/-/source-map-0.3.6.tgz#9d71ca886e32502eb9362c9a74a46787c36df81a" + integrity sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ== dependencies: - "@jridgewell/gen-mapping" "^0.3.0" - "@jridgewell/trace-mapping" "^0.3.9" + "@jridgewell/gen-mapping" "^0.3.5" + "@jridgewell/trace-mapping" "^0.3.25" "@jridgewell/sourcemap-codec@1.4.14": version "1.4.14" resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz#add4c98d341472a289190b424efbdb096991bb24" integrity sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw== -"@jridgewell/sourcemap-codec@^1.4.10", "@jridgewell/sourcemap-codec@^1.4.13": +"@jridgewell/sourcemap-codec@^1.4.10": version "1.4.15" resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz#d7c6e6755c78567a951e04ab52ef0fd26de59f32" integrity sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg== -"@jridgewell/sourcemap-codec@^1.4.14": +"@jridgewell/sourcemap-codec@^1.4.14", "@jridgewell/sourcemap-codec@^1.4.15": version "1.5.0" resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz#3188bcb273a414b0d215fd22a58540b989b9409a" integrity sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ== -"@jridgewell/trace-mapping@^0.3.12", "@jridgewell/trace-mapping@^0.3.18", "@jridgewell/trace-mapping@^0.3.24", "@jridgewell/trace-mapping@^0.3.25": +"@jridgewell/trace-mapping@^0.3.12", "@jridgewell/trace-mapping@^0.3.18", "@jridgewell/trace-mapping@^0.3.20", "@jridgewell/trace-mapping@^0.3.24", "@jridgewell/trace-mapping@^0.3.25": version "0.3.25" resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz#15f190e98895f3fc23276ee14bc76b675c2e50f0" integrity sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ== @@ -1036,6 +1027,13 @@ "@jridgewell/resolve-uri" "3.1.0" "@jridgewell/sourcemap-codec" "1.4.14" +"@ljharb/through@^2.3.12": + version "2.3.13" + resolved "https://registry.yarnpkg.com/@ljharb/through/-/through-2.3.13.tgz#b7e4766e0b65aa82e529be945ab078de79874edc" + integrity sha512-/gKJun8NNiWGZJkGzI/Ragc53cOdcLNdzjLaIa+GEjguQs0ulsurx8WN0jijdK9yPqDvziX995sMRLyLt1uZMQ== + dependencies: + call-bind "^1.0.7" + "@lukeed/csprng@^1.0.0", "@lukeed/csprng@^1.1.0": version "1.1.0" resolved "https://registry.yarnpkg.com/@lukeed/csprng/-/csprng-1.1.0.tgz#1e3e4bd05c1cc7a0b2ddbd8a03f39f6e4b5e6cfe" @@ -1048,64 +1046,61 @@ dependencies: "@lukeed/csprng" "^1.1.0" -"@microsoft/tsdoc@^0.14.2": - version "0.14.2" - resolved "https://registry.yarnpkg.com/@microsoft/tsdoc/-/tsdoc-0.14.2.tgz#c3ec604a0b54b9a9b87e9735dfc59e1a5da6a5fb" - integrity sha512-9b8mPpKrfeGRuhFH5iO1iwCLeIIsV6+H1sRfxbkoGXIyQE2BTsPd9zqSqQJ+pv5sJ/hT5M1zvOFL02MnEezFug== +"@microsoft/tsdoc@^0.15.0": + version "0.15.0" + resolved "https://registry.yarnpkg.com/@microsoft/tsdoc/-/tsdoc-0.15.0.tgz#f29a55df17cb6e87cfbabce33ff6a14a9f85076d" + integrity sha512-HZpPoABogPvjeJOdzCOSJsXeL/SMCBgBZMVC3X3d7YYp2gf31MfxhUoYUNwf1ERPJOnQc0wkFn9trqI6ZEdZuA== "@mochajs/json-file-reporter@^1.3.0": version "1.3.0" resolved "https://registry.yarnpkg.com/@mochajs/json-file-reporter/-/json-file-reporter-1.3.0.tgz#63a53bcda93d75f5c5c74af60e45da063931370b" integrity sha512-evIxpeP8EOixo/T2xh5xYEIzwbEHk8YNJfRUm1KeTs8F3bMjgNn2580Ogze9yisXNlTxu88JiJJYzXjjg5NdLA== -"@nestjs/cli@^9.1.2": - version "9.4.2" - resolved "https://registry.yarnpkg.com/@nestjs/cli/-/cli-9.4.2.tgz#d74668fde59129a9992b70ea72f9f66845efe11d" - integrity sha512-QWpk3UkpcAIvlqh2sSc6atHyaNFl7POi45Ujd5sAtVNogzpGphOlSyh39XuJcpe0FP3Z9IxX/0AUHF7KL/VyJQ== +"@nestjs/cli@^10.4.5": + version "10.4.5" + resolved "https://registry.yarnpkg.com/@nestjs/cli/-/cli-10.4.5.tgz#d6563b87e8ca1d0f256c19a7847dbcc96c76a88e" + integrity sha512-FP7Rh13u8aJbHe+zZ7hM0CC4785g9Pw4lz4r2TTgRtf0zTxSWMkJaPEwyjX8SK9oWK2GsYxl+fKpwVZNbmnj9A== dependencies: - "@angular-devkit/core" "15.2.6" - "@angular-devkit/schematics" "15.2.6" - "@angular-devkit/schematics-cli" "15.2.6" - "@nestjs/schematics" "^9.0.4" + "@angular-devkit/core" "17.3.8" + "@angular-devkit/schematics" "17.3.8" + "@angular-devkit/schematics-cli" "17.3.8" + "@nestjs/schematics" "^10.0.1" chalk "4.1.2" - chokidar "3.5.3" - cli-table3 "0.6.3" + chokidar "3.6.0" + cli-table3 "0.6.5" commander "4.1.1" - fork-ts-checker-webpack-plugin "8.0.0" - inquirer "8.2.5" + fork-ts-checker-webpack-plugin "9.0.2" + glob "10.4.2" + inquirer "8.2.6" node-emoji "1.11.0" ora "5.4.1" - os-name "4.0.1" - rimraf "4.4.1" - shelljs "0.8.5" - source-map-support "0.5.21" tree-kill "1.2.2" tsconfig-paths "4.2.0" - tsconfig-paths-webpack-plugin "4.0.1" - typescript "4.9.5" - webpack "5.80.0" + tsconfig-paths-webpack-plugin "4.1.0" + typescript "5.3.3" + webpack "5.94.0" webpack-node-externals "3.0.0" -"@nestjs/common@^10.3.7": - version "10.3.7" - resolved "https://registry.yarnpkg.com/@nestjs/common/-/common-10.3.7.tgz#38ab5ff92277cf1f26f4749c264524e76962cfff" - integrity sha512-gKFtFzcJznrwsRYjtNZoPAvSOPYdNgxbTYoAyLTpoy393cIKgLmJTHu6ReH8/qIB9AaZLdGaFLkx98W/tFWFUw== +"@nestjs/common@^10.4.4": + version "10.4.4" + resolved "https://registry.yarnpkg.com/@nestjs/common/-/common-10.4.4.tgz#673d0eca273e1ab3a4d3ec9e212114b9f4fbf6e8" + integrity sha512-0j2/zqRw9nvHV1GKTktER8B/hIC/Z8CYFjN/ZqUuvwayCH+jZZBhCR2oRyuvLTXdnlSmtCAg2xvQ0ULqQvzqhA== dependencies: uid "2.0.2" iterare "1.2.1" - tslib "2.6.2" + tslib "2.7.0" -"@nestjs/core@^10.3.7": - version "10.3.7" - resolved "https://registry.yarnpkg.com/@nestjs/core/-/core-10.3.7.tgz#736906ec27bc39b91519506babc231c8ab56ea21" - integrity sha512-hsdlnfiQ3kgqHL5k7js3CU0PV7hBJVi+LfFMgCkoagRxNMf67z0GFGeOV2jk5d65ssB19qdYsDa1MGVuEaoUpg== +"@nestjs/core@^10.4.4": + version "10.4.4" + resolved "https://registry.yarnpkg.com/@nestjs/core/-/core-10.4.4.tgz#12cb1110da6d76e12ceccf0e92f6f5220fe27525" + integrity sha512-y9tjmAzU6LTh1cC/lWrRsCcOd80khSR0qAHAqwY2svbW+AhsR/XCzgpZrAAKJrm/dDfjLCZKyxJSayeirGcW5Q== dependencies: uid "2.0.2" "@nuxtjs/opencollective" "0.3.2" fast-safe-stringify "2.1.1" iterare "1.2.1" - path-to-regexp "3.2.0" - tslib "2.6.2" + path-to-regexp "3.3.0" + tslib "2.7.0" "@nestjs/event-emitter@^2.0.4": version "2.0.4" @@ -1138,57 +1133,58 @@ socket.io "4.7.5" tslib "2.7.0" -"@nestjs/schematics@^9.0.3", "@nestjs/schematics@^9.0.4": - version "9.1.0" - resolved "https://registry.yarnpkg.com/@nestjs/schematics/-/schematics-9.1.0.tgz#8afc4b1e7c7988c18d3ab44cffe56773b7507272" - integrity sha512-/7CyMTnPJSK9/xD9CkCqwuHPOlHVlLC2RDnbdCJ7mIO07SdbBbY14msTqtYW9VRQtsjZPLh1GTChf7ryJUImwA== +"@nestjs/schematics@^10.0.1", "@nestjs/schematics@^10.1.4": + version "10.1.4" + resolved "https://registry.yarnpkg.com/@nestjs/schematics/-/schematics-10.1.4.tgz#e445b856eefce9bd338c5fc1cf2c95f0985849cf" + integrity sha512-QpY8ez9cTvXXPr3/KBrtSgXQHMSV6BkOUYy2c2TTe6cBqriEdGnCYqGl8cnfrQl3632q3lveQPaZ/c127dHsEw== dependencies: - "@angular-devkit/core" "15.2.4" - "@angular-devkit/schematics" "15.2.4" - jsonc-parser "3.2.0" + "@angular-devkit/core" "17.3.8" + "@angular-devkit/schematics" "17.3.8" + comment-json "4.2.3" + jsonc-parser "3.3.1" pluralize "8.0.0" -"@nestjs/serve-static@^3.0.0": - version "3.0.1" - resolved "https://registry.yarnpkg.com/@nestjs/serve-static/-/serve-static-3.0.1.tgz#d7d736b47171923d9e87262e19cc58ade8f4ba56" - integrity sha512-i766UJPYOqvQ2BbRKh0/+Mmq5NkJnmKcShjWV1i5qpXyeM0KDZTn0n7g7ykWq/3LbQgjpMzrhYtGv35GX7GVQw== +"@nestjs/serve-static@^4.0.2": + version "4.0.2" + resolved "https://registry.yarnpkg.com/@nestjs/serve-static/-/serve-static-4.0.2.tgz#f003bbd90922bdc73d0261edacf001dfef174c96" + integrity sha512-cT0vdWN5ar7jDI2NKbhf4LcwJzU4vS5sVpMkVrHuyLcltbrz6JdGi1TfIMMatP2pNiq5Ie/uUdPSFDVaZX/URQ== dependencies: path-to-regexp "0.2.5" -"@nestjs/swagger@^7.3.1": - version "7.3.1" - resolved "https://registry.yarnpkg.com/@nestjs/swagger/-/swagger-7.3.1.tgz#353fdd5bd6f23564505117b1c82d7decc145e8fe" - integrity sha512-LUC4mr+5oAleEC/a2j8pNRh1S5xhKXJ1Gal5ZdRjt9XebQgbngXCdW7JTA9WOEcwGtFZN9EnKYdquzH971LZfw== +"@nestjs/swagger@^7.4.2": + version "7.4.2" + resolved "https://registry.yarnpkg.com/@nestjs/swagger/-/swagger-7.4.2.tgz#3b72eb8a6d1366e8e211f9a90681283bb18817e9" + integrity sha512-Mu6TEn1M/owIvAx2B4DUQObQXqo2028R2s9rSZ/hJEgBK95+doTwS0DjmVA2wTeZTyVtXOoN7CsoM5pONBzvKQ== dependencies: - "@microsoft/tsdoc" "^0.14.2" + "@microsoft/tsdoc" "^0.15.0" "@nestjs/mapped-types" "2.0.5" js-yaml "4.1.0" lodash "4.17.21" - path-to-regexp "3.2.0" - swagger-ui-dist "5.11.2" + path-to-regexp "3.3.0" + swagger-ui-dist "5.17.14" -"@nestjs/testing@^9.0.11": - version "9.4.0" - resolved "https://registry.yarnpkg.com/@nestjs/testing/-/testing-9.4.0.tgz#1e5d1e799413e996c9c2da02a89dfefa62c3b70e" - integrity sha512-xZWp363P4otcebg++gSjUcdCfTK0RorORzyFq3aLaSAQOlq8kxfFDRIKzEATR4aOUfqTMMsAA8lhnMJWf35N6A== +"@nestjs/testing@^10.4.4": + version "10.4.4" + resolved "https://registry.yarnpkg.com/@nestjs/testing/-/testing-10.4.4.tgz#1f73f4b6c8d7a996a267ec498679e53763936963" + integrity sha512-qRGFj51A5RM7JqA8pcyEwSLA3Y0dle/PAZ8oxP0suimoCusRY3Tk7wYqutZdCNj1ATb678SDaUZDHk2pwSv9/g== dependencies: - tslib "2.5.0" + tslib "2.7.0" -"@nestjs/typeorm@^9.0.1": - version "9.0.1" - resolved "https://registry.yarnpkg.com/@nestjs/typeorm/-/typeorm-9.0.1.tgz#f78bfc00e71731ea860288e4a03830107daf3d9c" - integrity sha512-A2BgLIPsMtmMI0bPKEf4bmzgFPsnvHqNBx3KkvaJ7hJrBQy0OqYOb+Rr06ifblKWDWS2tUPNrAFQbZjtk3PI+g== +"@nestjs/typeorm@^10.0.2": + version "10.0.2" + resolved "https://registry.yarnpkg.com/@nestjs/typeorm/-/typeorm-10.0.2.tgz#25e3ec3c9a127b085c06fd7ea25f8690dba145c2" + integrity sha512-H738bJyydK4SQkRCTeh1aFBxoO1E9xdL/HaLGThwrqN95os5mEyAtK7BLADOS+vldP4jDZ2VQPLj4epWwRqCeQ== dependencies: - uuid "8.3.2" + uuid "9.0.1" -"@nestjs/websockets@^10.3.7": - version "10.3.7" - resolved "https://registry.yarnpkg.com/@nestjs/websockets/-/websockets-10.3.7.tgz#10837e9f370be348dea6fd4f9c6428843891dbf8" - integrity sha512-iYdsWiRNPUy0XzPoW44bx2MW1griuraTr5fNhoe2rUSNO0mEW1aeXp4v56KeZDLAss31WbeckC5P3N223Fys5g== +"@nestjs/websockets@^10.4.4": + version "10.4.4" + resolved "https://registry.yarnpkg.com/@nestjs/websockets/-/websockets-10.4.4.tgz#34a758bbe7ef7e61168682dc964cb14f95dc7898" + integrity sha512-ZHnak04i/iKBS0csjJa7K6D6xdsB0Yz6duJuCR7xGLItchFK+Ne21m9rEF8ffvW74U7UAYkQHBgD5242LBBYiQ== dependencies: iterare "1.2.1" object-hash "3.0.0" - tslib "2.6.2" + tslib "2.7.0" "@nodelib/fs.scandir@2.1.5": version "2.1.5" @@ -1285,6 +1281,11 @@ tslib "^2.5.0" webcrypto-core "^1.7.7" +"@pkgjs/parseargs@^0.11.0": + version "0.11.0" + resolved "https://registry.yarnpkg.com/@pkgjs/parseargs/-/parseargs-0.11.0.tgz#a77ea742fab25775145434eb1d2328cf5013ac33" + integrity sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg== + "@redis/bloom@1.2.0": version "1.2.0" resolved "https://registry.yarnpkg.com/@redis/bloom/-/bloom-1.2.0.tgz#d3fd6d3c0af3ef92f26767b56414a370c7b63b71" @@ -1386,9 +1387,9 @@ "@sinonjs/commons" "^3.0.0" "@socket.io/component-emitter@~3.1.0": - version "3.1.0" - resolved "https://registry.yarnpkg.com/@socket.io/component-emitter/-/component-emitter-3.1.0.tgz#96116f2a912e0c02817345b3c10751069920d553" - integrity sha512-+9jVqKhRSpsc591z5vX+X5Yyw+he/HCB4iQ/RYxw35CEPaY1gnsNE43nf9n9AaYjAQrTiI/mOwKUKdUs9vf7Xg== + version "3.1.2" + resolved "https://registry.yarnpkg.com/@socket.io/component-emitter/-/component-emitter-3.1.2.tgz#821f8442f4175d8f0467b9daf26e3a18e2d02af2" + integrity sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA== "@sqltools/formatter@^1.2.5": version "1.2.5" @@ -1471,32 +1472,16 @@ integrity sha512-t73xJJrvdTjXrn4jLS9VSGRbz0nUY3cl2DMGDU48lKl+HR9dbbjW2A9r3g40VA++mQpy6uuHg33gy7du2BKpog== "@types/cors@^2.8.12": - version "2.8.13" - resolved "https://registry.yarnpkg.com/@types/cors/-/cors-2.8.13.tgz#b8ade22ba455a1b8cb3b5d3f35910fd204f84f94" - integrity sha512-RG8AStHlUiV5ysZQKq97copd2UmVYw3/pRMLefISZ3S1hK104Cwm7iLQ3fTKx+lsUH2CE8FlLaYeEA2LSeqYUA== + version "2.8.17" + resolved "https://registry.yarnpkg.com/@types/cors/-/cors-2.8.17.tgz#5d718a5e494a8166f569d986794e49c48b216b2b" + integrity sha512-8CGDvrBj1zgo2qE+oS3pOCyYNqCPryMWY2bGfwA0dcfopWGgxs+78df0Rs3rc9THP4JkOhLsAa+15VdpAqkcUA== dependencies: "@types/node" "*" -"@types/eslint-scope@^3.7.3": - version "3.7.4" - resolved "https://registry.yarnpkg.com/@types/eslint-scope/-/eslint-scope-3.7.4.tgz#37fc1223f0786c39627068a12e94d6e6fc61de16" - integrity sha512-9K4zoImiZc3HlIp6AVUDE4CWYx22a+lhSZMYNpbjW04+YF0KWj4pJXnEMjdnFTiQibFFmElcsasJXDbdI/EPhA== - dependencies: - "@types/eslint" "*" - "@types/estree" "*" - -"@types/eslint@*": - version "8.37.0" - resolved "https://registry.yarnpkg.com/@types/eslint/-/eslint-8.37.0.tgz#29cebc6c2a3ac7fea7113207bf5a828fdf4d7ef1" - integrity sha512-Piet7dG2JBuDIfohBngQ3rCt7MgO9xCO4xIMKxBThCq5PNRB91IjlJ10eJVwfoNtvTErmxLzwBZ7rHZtbOMmFQ== - dependencies: - "@types/estree" "*" - "@types/json-schema" "*" - -"@types/estree@*", "@types/estree@^1.0.0": - version "1.0.1" - resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.1.tgz#aa22750962f3bf0e79d753d3cc067f010c95f194" - integrity sha512-LG4opVs2ANWZ1TJoKc937iMmNstM/d0ae1vNbnBvBhqCSezgVUOzcLCqbI5elV8Vy6WKwKjaqR+zO9VKirBBCA== +"@types/estree@^1.0.5": + version "1.0.6" + resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.6.tgz#628effeeae2064a1b4e79f78e81d87b7e5fc7b50" + integrity sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw== "@types/express-serve-static-core@^4.17.33": version "4.17.34" @@ -1557,7 +1542,7 @@ jest-diff "^26.0.0" pretty-format "^26.0.0" -"@types/json-schema@*", "@types/json-schema@^7.0.7", "@types/json-schema@^7.0.8": +"@types/json-schema@^7.0.7", "@types/json-schema@^7.0.8": version "7.0.11" resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.11.tgz#d421b6c527a3037f7c84433fd2c4229e016863d3" integrity sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ== @@ -1582,20 +1567,22 @@ resolved "https://registry.yarnpkg.com/@types/mime/-/mime-1.3.2.tgz#93e25bf9ee75fe0fd80b594bc4feb0e862111b5a" integrity sha512-YATxVxgRqNH6nHEIsvg6k2Boc1JHI9ZbH5iWFFv/MTkchz3b1ieGDa5T0a9RznNdI0KhVbdbWSN+KWWrQZRxTw== -"@types/node@*", "@types/node@>=10.0.0", "@types/node@^18.11.18": - version "18.16.1" - resolved "https://registry.yarnpkg.com/@types/node/-/node-18.16.1.tgz#5db121e9c5352925bb1f1b892c4ae620e3526799" - integrity sha512-DZxSZWXxFfOlx7k7Rv4LAyiMroaxa3Ly/7OOzZO8cBNho0YzAi4qlbrx8W27JGqG57IgR/6J7r+nOJWw6kcvZA== +"@types/node@*", "@types/node@>=10.0.0": + version "22.7.5" + resolved "https://registry.yarnpkg.com/@types/node/-/node-22.7.5.tgz#cfde981727a7ab3611a481510b473ae54442b92b" + integrity sha512-jML7s2NAzMWc//QSJ1a3prpk78cOPchGvXJsC3C6R6PSMoooztvRVQEz89gmBTBY1SPMaqo5teB4uNHPdetShQ== + dependencies: + undici-types "~6.19.2" "@types/node@14.14.10": version "14.14.10" resolved "https://registry.yarnpkg.com/@types/node/-/node-14.14.10.tgz#5958a82e41863cfc71f2307b3748e3491ba03785" integrity sha512-J32dgx2hw8vXrSbu4ZlVhn1Nm3GbeCFNw2FWL8S5QKucHGY0cyNwjdQdO+KMBZ4wpmC7KhLCiNsdk1RFRIYUQQ== -"@types/parse-json@^4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@types/parse-json/-/parse-json-4.0.0.tgz#2f8bb441434d163b35fb8ffdccd7138927ffb8c0" - integrity sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA== +"@types/node@^18.11.18": + version "18.16.1" + resolved "https://registry.yarnpkg.com/@types/node/-/node-18.16.1.tgz#5db121e9c5352925bb1f1b892c4ae620e3526799" + integrity sha512-DZxSZWXxFfOlx7k7Rv4LAyiMroaxa3Ly/7OOzZO8cBNho0YzAi4qlbrx8W27JGqG57IgR/6J7r+nOJWw6kcvZA== "@types/qs@*": version "6.9.7" @@ -1623,13 +1610,6 @@ "@types/mime" "*" "@types/node" "*" -"@types/socket.io@^3.0.2": - version "3.0.2" - resolved "https://registry.yarnpkg.com/@types/socket.io/-/socket.io-3.0.2.tgz#606c9639e3f93bb8454cba8f5f0a283d47917759" - integrity sha512-pu0sN9m5VjCxBZVK8hW37ZcMe8rjn4HHggBN5CbaRTvFwv5jOmuIRZEuddsBPa9Th0ts0SIo3Niukq+95cMBbQ== - dependencies: - socket.io "*" - "@types/ssh2@^1.11.6": version "1.11.11" resolved "https://registry.yarnpkg.com/@types/ssh2/-/ssh2-1.11.11.tgz#02fb707d821890a655fd27c2d842b0c7114078fb" @@ -1766,125 +1746,125 @@ resolved "https://registry.yarnpkg.com/@ungap/promise-all-settled/-/promise-all-settled-1.1.2.tgz#aa58042711d6e3275dd37dc597e5d31e8c290a44" integrity sha512-sL/cEvJWAnClXw0wHk85/2L0G6Sj8UB0Ctc1TEMbKSsmpRosqhwj9gWgFRZSrBr2f9tiXISwNhCPmlfqUqyb9Q== -"@webassemblyjs/ast@1.11.5", "@webassemblyjs/ast@^1.11.5": - version "1.11.5" - resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.11.5.tgz#6e818036b94548c1fb53b754b5cae3c9b208281c" - integrity sha512-LHY/GSAZZRpsNQH+/oHqhRQ5FT7eoULcBqgfyTB5nQHogFnK3/7QoN7dLnwSE/JkUAF0SrRuclT7ODqMFtWxxQ== +"@webassemblyjs/ast@1.12.1", "@webassemblyjs/ast@^1.12.1": + version "1.12.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.12.1.tgz#bb16a0e8b1914f979f45864c23819cc3e3f0d4bb" + integrity sha512-EKfMUOPRRUTy5UII4qJDGPpqfwjOmZ5jeGFwid9mnoqIFK+e0vqoi1qH56JpmZSzEL53jKnNzScdmftJyG5xWg== dependencies: - "@webassemblyjs/helper-numbers" "1.11.5" - "@webassemblyjs/helper-wasm-bytecode" "1.11.5" + "@webassemblyjs/helper-numbers" "1.11.6" + "@webassemblyjs/helper-wasm-bytecode" "1.11.6" -"@webassemblyjs/floating-point-hex-parser@1.11.5": - version "1.11.5" - resolved "https://registry.yarnpkg.com/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.5.tgz#e85dfdb01cad16b812ff166b96806c050555f1b4" - integrity sha512-1j1zTIC5EZOtCplMBG/IEwLtUojtwFVwdyVMbL/hwWqbzlQoJsWCOavrdnLkemwNoC/EOwtUFch3fuo+cbcXYQ== +"@webassemblyjs/floating-point-hex-parser@1.11.6": + version "1.11.6" + resolved "https://registry.yarnpkg.com/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.6.tgz#dacbcb95aff135c8260f77fa3b4c5fea600a6431" + integrity sha512-ejAj9hfRJ2XMsNHk/v6Fu2dGS+i4UaXBXGemOfQ/JfQ6mdQg/WXtwleQRLLS4OvfDhv8rYnVwH27YJLMyYsxhw== -"@webassemblyjs/helper-api-error@1.11.5": - version "1.11.5" - resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.5.tgz#1e82fa7958c681ddcf4eabef756ce09d49d442d1" - integrity sha512-L65bDPmfpY0+yFrsgz8b6LhXmbbs38OnwDCf6NpnMUYqa+ENfE5Dq9E42ny0qz/PdR0LJyq/T5YijPnU8AXEpA== +"@webassemblyjs/helper-api-error@1.11.6": + version "1.11.6" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.6.tgz#6132f68c4acd59dcd141c44b18cbebbd9f2fa768" + integrity sha512-o0YkoP4pVu4rN8aTJgAyj9hC2Sv5UlkzCHhxqWj8butaLvnpdc2jOwh4ewE6CX0txSfLn/UYaV/pheS2Txg//Q== -"@webassemblyjs/helper-buffer@1.11.5": - version "1.11.5" - resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.5.tgz#91381652ea95bb38bbfd270702351c0c89d69fba" - integrity sha512-fDKo1gstwFFSfacIeH5KfwzjykIE6ldh1iH9Y/8YkAZrhmu4TctqYjSh7t0K2VyDSXOZJ1MLhht/k9IvYGcIxg== +"@webassemblyjs/helper-buffer@1.12.1": + version "1.12.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-buffer/-/helper-buffer-1.12.1.tgz#6df20d272ea5439bf20ab3492b7fb70e9bfcb3f6" + integrity sha512-nzJwQw99DNDKr9BVCOZcLuJJUlqkJh+kVzVl6Fmq/tI5ZtEyWT1KZMyOXltXLZJmDtvLCDgwsyrkohEtopTXCw== -"@webassemblyjs/helper-numbers@1.11.5": - version "1.11.5" - resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.5.tgz#23380c910d56764957292839006fecbe05e135a9" - integrity sha512-DhykHXM0ZABqfIGYNv93A5KKDw/+ywBFnuWybZZWcuzWHfbp21wUfRkbtz7dMGwGgT4iXjWuhRMA2Mzod6W4WA== +"@webassemblyjs/helper-numbers@1.11.6": + version "1.11.6" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.6.tgz#cbce5e7e0c1bd32cf4905ae444ef64cea919f1b5" + integrity sha512-vUIhZ8LZoIWHBohiEObxVm6hwP034jwmc9kuq5GdHZH0wiLVLIPcMCdpJzG4C11cHoQ25TFIQj9kaVADVX7N3g== dependencies: - "@webassemblyjs/floating-point-hex-parser" "1.11.5" - "@webassemblyjs/helper-api-error" "1.11.5" + "@webassemblyjs/floating-point-hex-parser" "1.11.6" + "@webassemblyjs/helper-api-error" "1.11.6" "@xtuc/long" "4.2.2" -"@webassemblyjs/helper-wasm-bytecode@1.11.5": - version "1.11.5" - resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.5.tgz#e258a25251bc69a52ef817da3001863cc1c24b9f" - integrity sha512-oC4Qa0bNcqnjAowFn7MPCETQgDYytpsfvz4ujZz63Zu/a/v71HeCAAmZsgZ3YVKec3zSPYytG3/PrRCqbtcAvA== +"@webassemblyjs/helper-wasm-bytecode@1.11.6": + version "1.11.6" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.6.tgz#bb2ebdb3b83aa26d9baad4c46d4315283acd51e9" + integrity sha512-sFFHKwcmBprO9e7Icf0+gddyWYDViL8bpPjJJl0WHxCdETktXdmtWLGVzoHbqUcY4Be1LkNfwTmXOJUFZYSJdA== -"@webassemblyjs/helper-wasm-section@1.11.5": - version "1.11.5" - resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.5.tgz#966e855a6fae04d5570ad4ec87fbcf29b42ba78e" - integrity sha512-uEoThA1LN2NA+K3B9wDo3yKlBfVtC6rh0i4/6hvbz071E8gTNZD/pT0MsBf7MeD6KbApMSkaAK0XeKyOZC7CIA== +"@webassemblyjs/helper-wasm-section@1.12.1": + version "1.12.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.12.1.tgz#3da623233ae1a60409b509a52ade9bc22a37f7bf" + integrity sha512-Jif4vfB6FJlUlSbgEMHUyk1j234GTNG9dBJ4XJdOySoj518Xj0oGsNi59cUQF4RRMS9ouBUxDDdyBVfPTypa5g== dependencies: - "@webassemblyjs/ast" "1.11.5" - "@webassemblyjs/helper-buffer" "1.11.5" - "@webassemblyjs/helper-wasm-bytecode" "1.11.5" - "@webassemblyjs/wasm-gen" "1.11.5" + "@webassemblyjs/ast" "1.12.1" + "@webassemblyjs/helper-buffer" "1.12.1" + "@webassemblyjs/helper-wasm-bytecode" "1.11.6" + "@webassemblyjs/wasm-gen" "1.12.1" -"@webassemblyjs/ieee754@1.11.5": - version "1.11.5" - resolved "https://registry.yarnpkg.com/@webassemblyjs/ieee754/-/ieee754-1.11.5.tgz#b2db1b33ce9c91e34236194c2b5cba9b25ca9d60" - integrity sha512-37aGq6qVL8A8oPbPrSGMBcp38YZFXcHfiROflJn9jxSdSMMM5dS5P/9e2/TpaJuhE+wFrbukN2WI6Hw9MH5acg== +"@webassemblyjs/ieee754@1.11.6": + version "1.11.6" + resolved "https://registry.yarnpkg.com/@webassemblyjs/ieee754/-/ieee754-1.11.6.tgz#bb665c91d0b14fffceb0e38298c329af043c6e3a" + integrity sha512-LM4p2csPNvbij6U1f19v6WR56QZ8JcHg3QIJTlSwzFcmx6WSORicYj6I63f9yU1kEUtrpG+kjkiIAkevHpDXrg== dependencies: "@xtuc/ieee754" "^1.2.0" -"@webassemblyjs/leb128@1.11.5": - version "1.11.5" - resolved "https://registry.yarnpkg.com/@webassemblyjs/leb128/-/leb128-1.11.5.tgz#482e44d26b6b949edf042a8525a66c649e38935a" - integrity sha512-ajqrRSXaTJoPW+xmkfYN6l8VIeNnR4vBOTQO9HzR7IygoCcKWkICbKFbVTNMjMgMREqXEr0+2M6zukzM47ZUfQ== +"@webassemblyjs/leb128@1.11.6": + version "1.11.6" + resolved "https://registry.yarnpkg.com/@webassemblyjs/leb128/-/leb128-1.11.6.tgz#70e60e5e82f9ac81118bc25381a0b283893240d7" + integrity sha512-m7a0FhE67DQXgouf1tbN5XQcdWoNgaAuoULHIfGFIEVKA6tu/edls6XnIlkmS6FrXAquJRPni3ZZKjw6FSPjPQ== dependencies: "@xtuc/long" "4.2.2" -"@webassemblyjs/utf8@1.11.5": - version "1.11.5" - resolved "https://registry.yarnpkg.com/@webassemblyjs/utf8/-/utf8-1.11.5.tgz#83bef94856e399f3740e8df9f63bc47a987eae1a" - integrity sha512-WiOhulHKTZU5UPlRl53gHR8OxdGsSOxqfpqWeA2FmcwBMaoEdz6b2x2si3IwC9/fSPLfe8pBMRTHVMk5nlwnFQ== - -"@webassemblyjs/wasm-edit@^1.11.5": - version "1.11.5" - resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.5.tgz#93ee10a08037657e21c70de31c47fdad6b522b2d" - integrity sha512-C0p9D2fAu3Twwqvygvf42iGCQ4av8MFBLiTb+08SZ4cEdwzWx9QeAHDo1E2k+9s/0w1DM40oflJOpkZ8jW4HCQ== - dependencies: - "@webassemblyjs/ast" "1.11.5" - "@webassemblyjs/helper-buffer" "1.11.5" - "@webassemblyjs/helper-wasm-bytecode" "1.11.5" - "@webassemblyjs/helper-wasm-section" "1.11.5" - "@webassemblyjs/wasm-gen" "1.11.5" - "@webassemblyjs/wasm-opt" "1.11.5" - "@webassemblyjs/wasm-parser" "1.11.5" - "@webassemblyjs/wast-printer" "1.11.5" - -"@webassemblyjs/wasm-gen@1.11.5": - version "1.11.5" - resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.5.tgz#ceb1c82b40bf0cf67a492c53381916756ef7f0b1" - integrity sha512-14vteRlRjxLK9eSyYFvw1K8Vv+iPdZU0Aebk3j6oB8TQiQYuO6hj9s4d7qf6f2HJr2khzvNldAFG13CgdkAIfA== - dependencies: - "@webassemblyjs/ast" "1.11.5" - "@webassemblyjs/helper-wasm-bytecode" "1.11.5" - "@webassemblyjs/ieee754" "1.11.5" - "@webassemblyjs/leb128" "1.11.5" - "@webassemblyjs/utf8" "1.11.5" - -"@webassemblyjs/wasm-opt@1.11.5": - version "1.11.5" - resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.5.tgz#b52bac29681fa62487e16d3bb7f0633d5e62ca0a" - integrity sha512-tcKwlIXstBQgbKy1MlbDMlXaxpucn42eb17H29rawYLxm5+MsEmgPzeCP8B1Cl69hCice8LeKgZpRUAPtqYPgw== - dependencies: - "@webassemblyjs/ast" "1.11.5" - "@webassemblyjs/helper-buffer" "1.11.5" - "@webassemblyjs/wasm-gen" "1.11.5" - "@webassemblyjs/wasm-parser" "1.11.5" - -"@webassemblyjs/wasm-parser@1.11.5", "@webassemblyjs/wasm-parser@^1.11.5": - version "1.11.5" - resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.5.tgz#7ba0697ca74c860ea13e3ba226b29617046982e2" - integrity sha512-SVXUIwsLQlc8srSD7jejsfTU83g7pIGr2YYNb9oHdtldSxaOhvA5xwvIiWIfcX8PlSakgqMXsLpLfbbJ4cBYew== - dependencies: - "@webassemblyjs/ast" "1.11.5" - "@webassemblyjs/helper-api-error" "1.11.5" - "@webassemblyjs/helper-wasm-bytecode" "1.11.5" - "@webassemblyjs/ieee754" "1.11.5" - "@webassemblyjs/leb128" "1.11.5" - "@webassemblyjs/utf8" "1.11.5" - -"@webassemblyjs/wast-printer@1.11.5": - version "1.11.5" - resolved "https://registry.yarnpkg.com/@webassemblyjs/wast-printer/-/wast-printer-1.11.5.tgz#7a5e9689043f3eca82d544d7be7a8e6373a6fa98" - integrity sha512-f7Pq3wvg3GSPUPzR0F6bmI89Hdb+u9WXrSKc4v+N0aV0q6r42WoF92Jp2jEorBEBRoRNXgjp53nBniDXcqZYPA== - dependencies: - "@webassemblyjs/ast" "1.11.5" +"@webassemblyjs/utf8@1.11.6": + version "1.11.6" + resolved "https://registry.yarnpkg.com/@webassemblyjs/utf8/-/utf8-1.11.6.tgz#90f8bc34c561595fe156603be7253cdbcd0fab5a" + integrity sha512-vtXf2wTQ3+up9Zsg8sa2yWiQpzSsMyXj0qViVP6xKGCUT8p8YJ6HqI7l5eCnWx1T/FYdsv07HQs2wTFbbof/RA== + +"@webassemblyjs/wasm-edit@^1.12.1": + version "1.12.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-edit/-/wasm-edit-1.12.1.tgz#9f9f3ff52a14c980939be0ef9d5df9ebc678ae3b" + integrity sha512-1DuwbVvADvS5mGnXbE+c9NfA8QRcZ6iKquqjjmR10k6o+zzsRVesil54DKexiowcFCPdr/Q0qaMgB01+SQ1u6g== + dependencies: + "@webassemblyjs/ast" "1.12.1" + "@webassemblyjs/helper-buffer" "1.12.1" + "@webassemblyjs/helper-wasm-bytecode" "1.11.6" + "@webassemblyjs/helper-wasm-section" "1.12.1" + "@webassemblyjs/wasm-gen" "1.12.1" + "@webassemblyjs/wasm-opt" "1.12.1" + "@webassemblyjs/wasm-parser" "1.12.1" + "@webassemblyjs/wast-printer" "1.12.1" + +"@webassemblyjs/wasm-gen@1.12.1": + version "1.12.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-gen/-/wasm-gen-1.12.1.tgz#a6520601da1b5700448273666a71ad0a45d78547" + integrity sha512-TDq4Ojh9fcohAw6OIMXqiIcTq5KUXTGRkVxbSo1hQnSy6lAM5GSdfwWeSxpAo0YzgsgF182E/U0mDNhuA0tW7w== + dependencies: + "@webassemblyjs/ast" "1.12.1" + "@webassemblyjs/helper-wasm-bytecode" "1.11.6" + "@webassemblyjs/ieee754" "1.11.6" + "@webassemblyjs/leb128" "1.11.6" + "@webassemblyjs/utf8" "1.11.6" + +"@webassemblyjs/wasm-opt@1.12.1": + version "1.12.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-opt/-/wasm-opt-1.12.1.tgz#9e6e81475dfcfb62dab574ac2dda38226c232bc5" + integrity sha512-Jg99j/2gG2iaz3hijw857AVYekZe2SAskcqlWIZXjji5WStnOpVoat3gQfT/Q5tb2djnCjBtMocY/Su1GfxPBg== + dependencies: + "@webassemblyjs/ast" "1.12.1" + "@webassemblyjs/helper-buffer" "1.12.1" + "@webassemblyjs/wasm-gen" "1.12.1" + "@webassemblyjs/wasm-parser" "1.12.1" + +"@webassemblyjs/wasm-parser@1.12.1", "@webassemblyjs/wasm-parser@^1.12.1": + version "1.12.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-parser/-/wasm-parser-1.12.1.tgz#c47acb90e6f083391e3fa61d113650eea1e95937" + integrity sha512-xikIi7c2FHXysxXe3COrVUPSheuBtpcfhbpFj4gmu7KRLYOzANztwUU0IbsqvMqzuNK2+glRGWCEqZo1WCLyAQ== + dependencies: + "@webassemblyjs/ast" "1.12.1" + "@webassemblyjs/helper-api-error" "1.11.6" + "@webassemblyjs/helper-wasm-bytecode" "1.11.6" + "@webassemblyjs/ieee754" "1.11.6" + "@webassemblyjs/leb128" "1.11.6" + "@webassemblyjs/utf8" "1.11.6" + +"@webassemblyjs/wast-printer@1.12.1": + version "1.12.1" + resolved "https://registry.yarnpkg.com/@webassemblyjs/wast-printer/-/wast-printer-1.12.1.tgz#bcecf661d7d1abdaf989d8341a4833e33e2b31ac" + integrity sha512-+X4WAlOisVWQMikjbcvY2e0rwPsKQ9F688lksZhBcPycBBuii3O7m8FACbDMWDojpAqvjIncrG8J0XHKyQfVeA== + dependencies: + "@webassemblyjs/ast" "1.12.1" "@xtuc/long" "4.2.2" "@xtuc/ieee754@^1.2.0": @@ -1922,10 +1902,10 @@ accepts@~1.3.4, accepts@~1.3.8: mime-types "~2.1.34" negotiator "0.6.3" -acorn-import-assertions@^1.7.6: - version "1.8.0" - resolved "https://registry.yarnpkg.com/acorn-import-assertions/-/acorn-import-assertions-1.8.0.tgz#ba2b5939ce62c238db6d93d81c9b111b29b855e9" - integrity sha512-m7VZ3jwz4eK6A4Vtt8Ew1/mNbP24u0FhdyfA7fSvnJR6LMdfOYnmuIrrJAgrYfYJ10F/otaHTtrtrtmHdMNzEw== +acorn-import-attributes@^1.9.5: + version "1.9.5" + resolved "https://registry.yarnpkg.com/acorn-import-attributes/-/acorn-import-attributes-1.9.5.tgz#7eb1557b1ba05ef18b5ed0ec67591bfab04688ef" + integrity sha512-n02Vykv5uA3eHGM/Z2dQrcD56kL8TyDb2p1+0P83PClMnC/nc+anbQRhIOWnSq4Ke/KvDPrY3C9hDtC/A3eHnQ== acorn-jsx@^5.3.1: version "5.3.2" @@ -1937,11 +1917,16 @@ acorn@^7.4.0: resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.4.1.tgz#feaed255973d2e77555b83dbc08851a6c63520fa" integrity sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A== -acorn@^8.5.0, acorn@^8.7.1: +acorn@^8.7.1: version "8.8.2" resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.8.2.tgz#1b2f25db02af965399b9776b0c2c391276d37c4a" integrity sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw== +acorn@^8.8.2: + version "8.13.0" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.13.0.tgz#2a30d670818ad16ddd6a35d3842dacec9e5d7ca3" + integrity sha512-8zSiw54Oxrdym50NlZ9sUusyO1Z1ZchgRLWRaK6c86XJFClyCgFKetdowBg5bKxyp/u+CDBJG4Mpp0m3HLZl9w== + address@^1.0.1: version "1.2.2" resolved "https://registry.yarnpkg.com/address/-/address-1.2.2.tgz#2b5248dac5485a6390532c6a517fda2e3faac89e" @@ -2016,7 +2001,7 @@ ansi-colors@4.1.3, ansi-colors@^4.1.1: resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-4.1.3.tgz#37611340eb2243e70cc604cad35d63270d48781b" integrity sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw== -ansi-escapes@^4.2.1: +ansi-escapes@^4.2.1, ansi-escapes@^4.3.2: version "4.3.2" resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-4.3.2.tgz#6b2291d1db7d98b6521d5f1efa42d0f3a9feb65e" integrity sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ== @@ -2038,6 +2023,11 @@ ansi-regex@^5.0.0, ansi-regex@^5.0.1: resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== +ansi-regex@^6.0.1: + version "6.1.0" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-6.1.0.tgz#95ec409c69619d6cb1b8b34f14b660ef28ebd654" + integrity sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA== + ansi-styles@^3.2.0, ansi-styles@^3.2.1: version "3.2.1" resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" @@ -2057,6 +2047,11 @@ ansi-styles@^5.0.0: resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-5.2.0.tgz#07449690ad45777d1924ac2abb2fc8895dba836b" integrity sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA== +ansi-styles@^6.1.0: + version "6.2.1" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-6.2.1.tgz#0e62320cf99c21afff3b3012192546aacbfb05c5" + integrity sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug== + any-promise@^1.0.0: version "1.3.0" resolved "https://registry.yarnpkg.com/any-promise/-/any-promise-1.3.0.tgz#abc6afeedcea52e809cdc0376aed3ce39635d17f" @@ -2146,6 +2141,11 @@ array-includes@^3.1.6: get-intrinsic "^1.1.3" is-string "^1.0.7" +array-timsort@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/array-timsort/-/array-timsort-1.0.3.tgz#3c9e4199e54fb2b9c3fe5976396a21614ef0d926" + integrity sha512-/+3GRL7dDAGEfM6TseQk/U+mi18TU2Ms9I3UlLdUMhz2hbvGNTKdj9xniwXfUqgYhHxRx0+8UnKkvlNwVU+cWQ== + array-union@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/array-union/-/array-union-2.1.0.tgz#b798420adbeb1de828d84acd8a2e23d3efe85e8d" @@ -2372,20 +2372,13 @@ brace-expansion@^2.0.1: dependencies: balanced-match "^1.0.0" -braces@^3.0.3: +braces@^3.0.3, braces@~3.0.2: version "3.0.3" resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.3.tgz#490332f40919452272d55a8480adc0c441358789" integrity sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA== dependencies: fill-range "^7.1.1" -braces@~3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" - integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A== - dependencies: - fill-range "^7.0.1" - broadcast-channel@~4.17.0: version "4.17.0" resolved "https://registry.yarnpkg.com/broadcast-channel/-/broadcast-channel-4.17.0.tgz#599d44674b09a4e2e07af6da5d03b45ca8bffd11" @@ -2407,15 +2400,15 @@ browser-stdout@1.3.1: resolved "https://registry.yarnpkg.com/browser-stdout/-/browser-stdout-1.3.1.tgz#baa559ee14ced73452229bad7326467c61fabd60" integrity sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw== -browserslist@^4.14.5: - version "4.21.5" - resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.21.5.tgz#75c5dae60063ee641f977e00edd3cfb2fb7af6a7" - integrity sha512-tUkiguQGW7S3IhB7N+c2MV/HZPSCPAAiYBZXLsBhFB/PCy6ZKKsZrmBayHV9fdGV/ARIfJ14NkxKzRDjvp7L6w== +browserslist@^4.21.10, browserslist@^4.24.0: + version "4.24.0" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.24.0.tgz#a1325fe4bc80b64fda169629fc01b3d6cecd38d4" + integrity sha512-Rmb62sR1Zpjql25eSanFGEhAxcFwfA1K0GuQcLoaJBAcENegrQut3hYdhXFF1obQfiDyqIW/cLM5HSJ/9k884A== dependencies: - caniuse-lite "^1.0.30001449" - electron-to-chromium "^1.4.284" - node-releases "^2.0.8" - update-browserslist-db "^1.0.10" + caniuse-lite "^1.0.30001663" + electron-to-chromium "^1.5.28" + node-releases "^2.0.18" + update-browserslist-db "^1.1.0" browserslist@^4.21.9: version "4.22.1" @@ -2427,16 +2420,6 @@ browserslist@^4.21.9: node-releases "^2.0.13" update-browserslist-db "^1.0.13" -browserslist@^4.24.0: - version "4.24.0" - resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.24.0.tgz#a1325fe4bc80b64fda169629fc01b3d6cecd38d4" - integrity sha512-Rmb62sR1Zpjql25eSanFGEhAxcFwfA1K0GuQcLoaJBAcENegrQut3hYdhXFF1obQfiDyqIW/cLM5HSJ/9k884A== - dependencies: - caniuse-lite "^1.0.30001663" - electron-to-chromium "^1.5.28" - node-releases "^2.0.18" - update-browserslist-db "^1.1.0" - bs-logger@^0.2.6: version "0.2.6" resolved "https://registry.yarnpkg.com/bs-logger/-/bs-logger-0.2.6.tgz#eb7d365307a72cf974cc6cda76b68354ad336bd8" @@ -2567,11 +2550,6 @@ camelcase@^6.0.0, camelcase@^6.2.0: resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.3.0.tgz#5685b95eb209ac9c0c177467778c9c84df58ba9a" integrity sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA== -caniuse-lite@^1.0.30001449: - version "1.0.30001481" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001481.tgz#f58a717afe92f9e69d0e35ff64df596bfad93912" - integrity sha512-KCqHwRnaa1InZBtqXzP98LPg0ajCVujMKjqKDhZEthIpAsJl/YEIa3YvXjGXPVqzZVguccuu7ga9KOE1J9rKPQ== - caniuse-lite@^1.0.30001541: version "1.0.30001561" resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001561.tgz#752f21f56f96f1b1a52e97aae98c57c562d5d9da" @@ -2612,6 +2590,11 @@ chalk@^2.0.0, chalk@^2.3.0, chalk@^2.4.2: escape-string-regexp "^1.0.5" supports-color "^5.3.0" +chalk@^5.3.0: + version "5.3.0" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-5.3.0.tgz#67c20a7ebef70e7f3970a01f90fa210cb6860385" + integrity sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w== + char-regex@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/char-regex/-/char-regex-1.0.2.tgz#d744358226217f981ed58f479b1d6bcc29545dcf" @@ -2649,7 +2632,22 @@ chokidar@3.5.1: optionalDependencies: fsevents "~2.3.1" -chokidar@3.5.3, chokidar@^3.5.3: +chokidar@3.6.0: + version "3.6.0" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.6.0.tgz#197c6cc669ef2a8dc5e7b4d97ee4e092c3eb0d5b" + integrity sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw== + dependencies: + anymatch "~3.1.2" + braces "~3.0.2" + glob-parent "~5.1.2" + is-binary-path "~2.1.0" + is-glob "~4.0.1" + normalize-path "~3.0.0" + readdirp "~3.6.0" + optionalDependencies: + fsevents "~2.3.2" + +chokidar@^3.5.3: version "3.5.3" resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.3.tgz#1cf37c8707b932bd1af1ae22c0432e2acd1903bd" integrity sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw== @@ -2732,10 +2730,10 @@ cli-spinners@^2.5.0: resolved "https://registry.yarnpkg.com/cli-spinners/-/cli-spinners-2.8.0.tgz#e97a3e2bd00e6d85aa0c13d7f9e3ce236f7787fc" integrity sha512-/eG5sJcvEIwxcdYM86k5tPwn0MUzkX5YY3eImTGpJOZgVe4SdTMY14vQpcxgBzJ0wXwAYrS8E+c3uHeK4JNyzQ== -cli-table3@0.6.3: - version "0.6.3" - resolved "https://registry.yarnpkg.com/cli-table3/-/cli-table3-0.6.3.tgz#61ab765aac156b52f222954ffc607a6f01dbeeb2" - integrity sha512-w5Jac5SykAeZJKntOxJCrm63Eg5/4dhMWIcuTbo9rpE+brgaSZo0RuNJZeOyMgsUdhDeojvgyQLmjI+K50ZGyg== +cli-table3@0.6.5: + version "0.6.5" + resolved "https://registry.yarnpkg.com/cli-table3/-/cli-table3-0.6.5.tgz#013b91351762739c16a9567c21a04632e449bf2f" + integrity sha512-+W/5efTR7y5HRD7gACw9yQjqMVvEMLBHmboM/kPWam+H+Hmyrgjh6YncVKK122YZkXrLudzTuAukUw9FnMf7IQ== dependencies: string-width "^4.2.0" optionalDependencies: @@ -2746,6 +2744,11 @@ cli-width@^3.0.0: resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-3.0.0.tgz#a2f48437a2caa9a22436e794bf071ec9e61cedf6" integrity sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw== +cli-width@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-4.1.0.tgz#42daac41d3c254ef38ad8ac037672130173691c5" + integrity sha512-ouuZd4/dm2Sw5Gmqy6bGyNNNe1qt9RpmxveLSO7KcgsTnU7RXfsw+/bukWGo1abgBiMAic068rclZsO4IWmmxQ== + cliui@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/cliui/-/cliui-5.0.0.tgz#deefcfdb2e800784aa34f46fa08e06851c7bbbc5" @@ -2882,6 +2885,17 @@ commander@^2.20.0: resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ== +comment-json@4.2.3: + version "4.2.3" + resolved "https://registry.yarnpkg.com/comment-json/-/comment-json-4.2.3.tgz#50b487ebbf43abe44431f575ebda07d30d015365" + integrity sha512-SsxdiOf064DWoZLH799Ata6u7iV658A11PlWtZATDlXPpKGJnbJZ5Z24ybixAi+LUUqJ/GKowAejtC5GFUG7Tw== + dependencies: + array-timsort "^1.0.3" + core-util-is "^1.0.3" + esprima "^4.0.1" + has-own-prop "^2.0.0" + repeat-string "^1.6.1" + commondir@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/commondir/-/commondir-1.0.1.tgz#ddd800da0c66127393cca5950ea968a3aaf1253b" @@ -2984,15 +2998,15 @@ cookie-signature@1.0.6: resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c" integrity sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ== -cookie@0.6.0: - version "0.6.0" - resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.6.0.tgz#2798b04b071b0ecbff0dbb62a505a8efa4e19051" - integrity sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw== +cookie@0.7.1: + version "0.7.1" + resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.7.1.tgz#2f73c42142d5d5cf71310a74fc4ae61670e5dbc9" + integrity sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w== -cookie@~0.4.1: - version "0.4.2" - resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.4.2.tgz#0e41f24de5ecf317947c82fc789e06a884824432" - integrity sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA== +cookie@~0.7.2: + version "0.7.2" + resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.7.2.tgz#556369c472a2ba910f2979891b526b3436237ed7" + integrity sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w== cookiejar@^2.1.0: version "2.1.4" @@ -3004,7 +3018,7 @@ core-js@^3.6.5: resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.31.0.tgz#4471dd33e366c79d8c0977ed2d940821719db344" integrity sha512-NIp2TQSGfR6ba5aalZD+ZQ1fSxGhDo/s1w0nx3RYzf2pnJxt7YynxFlFScP6eV7+GZsKO95NSjGxyJsU3DZgeQ== -core-util-is@~1.0.0: +core-util-is@^1.0.3, core-util-is@~1.0.0: version "1.0.3" resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.3.tgz#a6042d3634c2b27e9328f837b965fac83808db85" integrity sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ== @@ -3017,16 +3031,15 @@ cors@2.8.5, cors@~2.8.5: object-assign "^4" vary "^1" -cosmiconfig@^7.0.1: - version "7.1.0" - resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-7.1.0.tgz#1443b9afa596b670082ea46cbd8f6a62b84635f6" - integrity sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA== +cosmiconfig@^8.2.0: + version "8.3.6" + resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-8.3.6.tgz#060a2b871d66dba6c8538ea1118ba1ac16f5fae3" + integrity sha512-kcZ6+W5QzcJ3P1Mt+83OUv/oHFqZHIx8DuxG6eZ5RGMERoLqp4BuGjhHLYGK+Kf5XVkQvqBSmAy/nGWN3qDgEA== dependencies: - "@types/parse-json" "^4.0.0" - import-fresh "^3.2.1" - parse-json "^5.0.0" + import-fresh "^3.3.0" + js-yaml "^4.1.0" + parse-json "^5.2.0" path-type "^4.0.0" - yaml "^1.10.0" cpu-features@~0.0.9: version "0.0.9" @@ -3101,7 +3114,7 @@ debug@2.6.9: dependencies: ms "2.0.0" -debug@4, debug@^4.0.1, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.4, debug@~4.3.1, debug@~4.3.2: +debug@4, debug@^4.0.1, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.4: version "4.3.4" resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== @@ -3129,6 +3142,13 @@ debug@^4.3.3: dependencies: ms "2.1.2" +debug@~4.3.1, debug@~4.3.2, debug@~4.3.4: + version "4.3.7" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.7.tgz#87945b4151a011d76d95a198d7111c865c360a52" + integrity sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ== + dependencies: + ms "^2.1.3" + decamelize@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" @@ -3313,6 +3333,11 @@ dset@^3.1.4: resolved "https://registry.yarnpkg.com/dset/-/dset-3.1.4.tgz#f8eaf5f023f068a036d08cd07dc9ffb7d0065248" integrity sha512-2QF/g9/zTaPDc3BjNcVTGoBbXBgYfMTTceLaYcFJ/W9kggFUkhxD/hMEeuLKbugyef9SqAx8cpgwlIP/jinUTA== +eastasianwidth@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/eastasianwidth/-/eastasianwidth-0.2.0.tgz#696ce2ec0aa0e6ea93a397ffcf24aa7840c827cb" + integrity sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA== + ecdsa-sig-formatter@1.0.11: version "1.0.11" resolved "https://registry.yarnpkg.com/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz#ae0f0fa2d85045ef14a817daa3ce9acd0489e5bf" @@ -3332,11 +3357,6 @@ ejs@^3.1.10: dependencies: jake "^10.8.5" -electron-to-chromium@^1.4.284: - version "1.4.374" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.374.tgz#091b2de9d80b970f9b5e689675ea62622cd1d74b" - integrity sha512-dNP9tQNTrjgVlSXMqGaj0BdrCS+9pcUvy5/emB6x8kh0YwCoDZ0Z4ce1+7aod+KhybHUd5o5LgKrc5al4kVmzQ== - electron-to-chromium@^1.4.535: version "1.4.581" resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.581.tgz#23b684c67bf56d4284e95598c05a5d266653b6d8" @@ -3362,6 +3382,11 @@ emoji-regex@^8.0.0: resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== +emoji-regex@^9.2.2: + version "9.2.2" + resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-9.2.2.tgz#840c8803b0d8047f4ff0cf963176b32d4ef3ed72" + integrity sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg== + emojis-list@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-3.0.0.tgz#5570662046ad29e2e916e71aae260abdff4f6a78" @@ -3407,43 +3432,22 @@ engine.io-client@~6.6.1: ws "~8.17.1" xmlhttprequest-ssl "~2.1.1" -engine.io-parser@~5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/engine.io-parser/-/engine.io-parser-5.1.0.tgz#d593d6372d7f79212df48f807b8cace1ea1cb1b8" - integrity sha512-enySgNiK5tyZFynt3z7iqBR+Bto9EVVVvDFuTT0ioHCGbzirZVGDGiQjZzEp8hWl6hd5FSVytJGuScX1C1C35w== - engine.io-parser@~5.2.1: - version "5.2.2" - resolved "https://registry.yarnpkg.com/engine.io-parser/-/engine.io-parser-5.2.2.tgz#37b48e2d23116919a3453738c5720455e64e1c49" - integrity sha512-RcyUFKA93/CXH20l4SoVvzZfrSDMOTUS3bWVpTt2FuFP+XYrL8i8oonHP7WInRyVHXh0n/ORtoeiE1os+8qkSw== - -engine.io@~6.5.0: - version "6.5.1" - resolved "https://registry.yarnpkg.com/engine.io/-/engine.io-6.5.1.tgz#59725f8593ccc891abb47f1efcdc52a089525a56" - integrity sha512-mGqhI+D7YxS9KJMppR6Iuo37Ed3abhU8NdfgSvJSDUafQutrN+sPTncJYTyM9+tkhSmWodKtVYGPPHyXJEwEQA== - dependencies: - "@types/cookie" "^0.4.1" - "@types/cors" "^2.8.12" - "@types/node" ">=10.0.0" - accepts "~1.3.4" - base64id "2.0.0" - cookie "~0.4.1" - cors "~2.8.5" - debug "~4.3.1" - engine.io-parser "~5.1.0" - ws "~8.11.0" + version "5.2.3" + resolved "https://registry.yarnpkg.com/engine.io-parser/-/engine.io-parser-5.2.3.tgz#00dc5b97b1f233a23c9398d0209504cf5f94d92f" + integrity sha512-HqD3yTBfnBxIrbnM1DoD6Pcq8NECnh8d4As1Qgh0z5Gg3jRRIqijury0CL3ghu/edArpUYiYqQiDUQBIs4np3Q== engine.io@~6.6.0: - version "6.6.1" - resolved "https://registry.yarnpkg.com/engine.io/-/engine.io-6.6.1.tgz#a82b1e5511239a0e95fac14516870ee9138febc8" - integrity sha512-NEpDCw9hrvBW+hVEOK4T7v0jFJ++KgtPl4jKFwsZVfG1XhS0dCrSb3VMb9gPAd7VAdW52VT1EnaNiU2vM8C0og== + version "6.6.2" + resolved "https://registry.yarnpkg.com/engine.io/-/engine.io-6.6.2.tgz#32bd845b4db708f8c774a4edef4e5c8a98b3da72" + integrity sha512-gmNvsYi9C8iErnZdVcJnvCpSKbWTt1E8+JZo8b+daLninywUWi5NQ5STSHZ9rFjFO7imNcvb8Pc5pe/wMR5xEw== dependencies: "@types/cookie" "^0.4.1" "@types/cors" "^2.8.12" "@types/node" ">=10.0.0" accepts "~1.3.4" base64id "2.0.0" - cookie "~0.4.1" + cookie "~0.7.2" cors "~2.8.5" debug "~4.3.1" engine.io-parser "~5.2.1" @@ -3458,7 +3462,15 @@ enhanced-resolve@^4.0.0: memory-fs "^0.5.0" tapable "^1.0.0" -enhanced-resolve@^5.13.0, enhanced-resolve@^5.7.0: +enhanced-resolve@^5.17.1: + version "5.17.1" + resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-5.17.1.tgz#67bfbbcc2f81d511be77d686a90267ef7f898a15" + integrity sha512-LMHl3dXhTcfv8gM4kEzIUeTQ+7fpdA0l2tUf34BddXPkz2A5xJ5L/Pchd5BL6rdccM9QGvu0sWZzK1Z1t4wwyg== + dependencies: + graceful-fs "^4.2.4" + tapable "^2.2.0" + +enhanced-resolve@^5.7.0: version "5.13.0" resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-5.13.0.tgz#26d1ecc448c02de997133217b5c1053f34a0a275" integrity sha512-eyV8f0y1+bzyfh8xAwW/WTSZpLbjhqc4ne9eGSH4Zo2ejdyiNG9pU6mf9DG8a7+Auk6MFTlNOT4Y2y/9k8GKVg== @@ -3807,7 +3819,7 @@ espree@^7.3.0, espree@^7.3.1: acorn-jsx "^5.3.1" eslint-visitor-keys "^1.3.0" -esprima@^4.0.0: +esprima@^4.0.0, esprima@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== @@ -3866,21 +3878,6 @@ events@^3.2.0, events@^3.3.0: resolved "https://registry.yarnpkg.com/events/-/events-3.3.0.tgz#31a95ad0a924e2d2c419a813aeb2c4e878ea7400" integrity sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q== -execa@^4.0.2: - version "4.1.0" - resolved "https://registry.yarnpkg.com/execa/-/execa-4.1.0.tgz#4e5491ad1572f2f17a77d388c6c857135b22847a" - integrity sha512-j5W0//W7f8UxAn8hXVnwG8tLwdiUy4FJLcSupCg6maBYZDpyBvTApK7KyuI4bKj8KOh1r2YH+6ucuYtJv1bTZA== - dependencies: - cross-spawn "^7.0.0" - get-stream "^5.0.0" - human-signals "^1.1.1" - is-stream "^2.0.0" - merge-stream "^2.0.0" - npm-run-path "^4.0.0" - onetime "^5.1.0" - signal-exit "^3.0.2" - strip-final-newline "^2.0.0" - execa@^5.0.0: version "5.1.1" resolved "https://registry.yarnpkg.com/execa/-/execa-5.1.1.tgz#f80ad9cbf4298f7bd1d4c9555c21e93741c411dd" @@ -3917,17 +3914,17 @@ expect@^29.7.0: jest-message-util "^29.7.0" jest-util "^29.7.0" -express@4.21.0, express@^4.21.0: - version "4.21.0" - resolved "https://registry.yarnpkg.com/express/-/express-4.21.0.tgz#d57cb706d49623d4ac27833f1cbc466b668eb915" - integrity sha512-VqcNGcj/Id5ZT1LZ/cfihi3ttTn+NJmkli2eZADigjq29qTlWi/hAQ43t/VLPq8+UX06FCEx3ByOYet6ZFblng== +express@4.21.0, express@^4.21.1: + version "4.21.1" + resolved "https://registry.yarnpkg.com/express/-/express-4.21.1.tgz#9dae5dda832f16b4eec941a4e44aa89ec481b281" + integrity sha512-YSFlK1Ee0/GC8QaO91tHcDxJiE/X4FbpAyQWkxAvG6AXCuR65YzK8ua6D9hvi/TzUfZMpc+BwuM1IPw8fmQBiQ== dependencies: accepts "~1.3.8" array-flatten "1.1.1" body-parser "1.20.3" content-disposition "0.5.4" content-type "~1.0.4" - cookie "0.6.0" + cookie "0.7.1" cookie-signature "1.0.6" debug "2.6.9" depd "2.0.0" @@ -3959,7 +3956,7 @@ extend@^3.0.0: resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa" integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g== -external-editor@^3.0.3: +external-editor@^3.0.3, external-editor@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-3.1.0.tgz#cb03f740befae03ea4d283caed2741a83f335495" integrity sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew== @@ -4037,7 +4034,7 @@ fengari@^0.1.4: sprintf-js "^1.1.1" tmp "^0.0.33" -figures@^3.0.0: +figures@^3.0.0, figures@^3.2.0: version "3.2.0" resolved "https://registry.yarnpkg.com/figures/-/figures-3.2.0.tgz#625c18bd293c604dc4a8ddb2febf0c88341746af" integrity sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg== @@ -4077,13 +4074,6 @@ filelist@^1.0.4: dependencies: minimatch "^5.0.1" -fill-range@^7.0.1: - version "7.0.1" - resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40" - integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ== - dependencies: - to-regex-range "^5.0.1" - fill-range@^7.1.1: version "7.1.1" resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.1.1.tgz#44265d3cac07e3ea7dc247516380643754a05292" @@ -4179,15 +4169,23 @@ foreground-child@^2.0.0: cross-spawn "^7.0.0" signal-exit "^3.0.2" -fork-ts-checker-webpack-plugin@8.0.0: - version "8.0.0" - resolved "https://registry.yarnpkg.com/fork-ts-checker-webpack-plugin/-/fork-ts-checker-webpack-plugin-8.0.0.tgz#dae45dfe7298aa5d553e2580096ced79b6179504" - integrity sha512-mX3qW3idpueT2klaQXBzrIM/pHw+T0B/V9KHEvNrqijTq9NFnMZU6oreVxDYcf33P8a5cW+67PjodNHthGnNVg== +foreground-child@^3.1.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/foreground-child/-/foreground-child-3.3.0.tgz#0ac8644c06e431439f8561db8ecf29a7b5519c77" + integrity sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg== + dependencies: + cross-spawn "^7.0.0" + signal-exit "^4.0.1" + +fork-ts-checker-webpack-plugin@9.0.2: + version "9.0.2" + resolved "https://registry.yarnpkg.com/fork-ts-checker-webpack-plugin/-/fork-ts-checker-webpack-plugin-9.0.2.tgz#c12c590957837eb02b02916902dcf3e675fd2b1e" + integrity sha512-Uochze2R8peoN1XqlSi/rGUkDQpRogtLFocP9+PGu68zk1BDAKXfdeCdyVZpgTk8V8WFVQXdEz426VKjXLO1Gg== dependencies: "@babel/code-frame" "^7.16.7" chalk "^4.1.2" chokidar "^3.5.3" - cosmiconfig "^7.0.1" + cosmiconfig "^8.2.0" deepmerge "^4.2.2" fs-extra "^10.0.0" memfs "^3.4.1" @@ -4276,12 +4274,7 @@ fsevents@~2.3.1, fsevents@~2.3.2: resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a" integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA== -function-bind@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" - integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== - -function-bind@^1.1.2: +function-bind@^1.1.1, function-bind@^1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.2.tgz#2c02d864d97f3ea6c8830c464cbd11ab6eab7a1c" integrity sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA== @@ -4340,7 +4333,7 @@ get-func-name@^2.0.1, get-func-name@^2.0.2: resolved "https://registry.yarnpkg.com/get-func-name/-/get-func-name-2.0.2.tgz#0d7cf20cd13fda808669ffa88f4ffc7a3943fc41" integrity sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ== -get-intrinsic@^1.0.2, get-intrinsic@^1.1.1, get-intrinsic@^1.1.3, get-intrinsic@^1.2.0: +get-intrinsic@^1.0.2, get-intrinsic@^1.1.1, get-intrinsic@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.2.0.tgz#7ad1dc0535f3a2904bba075772763e5051f6d05f" integrity sha512-L049y6nFOuom5wGyRc3/gdTLO94dySVKRACj1RmJZBQXlbTMhtNIgkWkUHq+jYmZvKf14EW1EoJnnjbmoHij0Q== @@ -4349,7 +4342,7 @@ get-intrinsic@^1.0.2, get-intrinsic@^1.1.1, get-intrinsic@^1.1.3, get-intrinsic@ has "^1.0.3" has-symbols "^1.0.3" -get-intrinsic@^1.2.4: +get-intrinsic@^1.1.3, get-intrinsic@^1.2.4: version "1.2.4" resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.2.4.tgz#e385f5a4b5227d449c3eabbad05494ef0abbeadd" integrity sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ== @@ -4370,13 +4363,6 @@ get-stdin@^6.0.0: resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-6.0.0.tgz#9e09bf712b360ab9225e812048f71fde9c89657b" integrity sha512-jp4tHawyV7+fkkSKyvjuLZswblUtz+SQKzSWnBbii16BuZksJlU1wuBYXY75r+duh/llF1ur6oNwi+2ZzjKZ7g== -get-stream@^5.0.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-5.2.0.tgz#4966a1795ee5ace65e706c4b7beb71257d6e22d3" - integrity sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA== - dependencies: - pump "^3.0.0" - get-stream@^6.0.0: version "6.0.1" resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-6.0.1.tgz#a262d8eef67aced57c2852ad6167526a43cbf7b7" @@ -4407,6 +4393,18 @@ glob-to-regexp@^0.4.1: resolved "https://registry.yarnpkg.com/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz#c75297087c851b9a578bd217dd59a92f59fe546e" integrity sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw== +glob@10.4.2: + version "10.4.2" + resolved "https://registry.yarnpkg.com/glob/-/glob-10.4.2.tgz#bed6b95dade5c1f80b4434daced233aee76160e5" + integrity sha512-GwMlUF6PkPo3Gk21UxkCohOv0PLcIXVtKyLlpEI28R/cO/4eNOdmLk3CMW1wROV/WR/EsZOWAfBbBOqYvs88/w== + dependencies: + foreground-child "^3.1.0" + jackspeak "^3.1.2" + minimatch "^9.0.4" + minipass "^7.1.2" + package-json-from-dist "^1.0.0" + path-scurry "^1.11.1" + glob@7.1.6: version "7.1.6" resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.6.tgz#141f33b81a7c2492e125594307480c46679278a6" @@ -4419,7 +4417,7 @@ glob@7.1.6: once "^1.3.0" path-is-absolute "^1.0.0" -glob@^7.0.0, glob@^7.1.3, glob@^7.1.4, glob@^7.1.6: +glob@^7.1.3, glob@^7.1.4, glob@^7.1.6: version "7.2.3" resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b" integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q== @@ -4442,16 +4440,6 @@ glob@^8.1.0: minimatch "^5.0.1" once "^1.3.0" -glob@^9.2.0: - version "9.3.5" - resolved "https://registry.yarnpkg.com/glob/-/glob-9.3.5.tgz#ca2ed8ca452781a3009685607fdf025a899dfe21" - integrity sha512-e1LleDykUz2Iu+MTYdkSsuWX8lvAjAcs0Xef0lNIu0S2wOAzuTxCJtcd9S3cijlwYF18EsU3rzb8jPVobxDh9Q== - dependencies: - fs.realpath "^1.0.0" - minimatch "^8.0.2" - minipass "^4.2.4" - path-scurry "^1.6.1" - globals@^11.1.0: version "11.12.0" resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e" @@ -4490,7 +4478,7 @@ gopd@^1.0.1: dependencies: get-intrinsic "^1.1.3" -graceful-fs@^4.1.15, graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.4, graceful-fs@^4.2.6, graceful-fs@^4.2.9: +graceful-fs@^4.1.15, graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.11, graceful-fs@^4.2.4, graceful-fs@^4.2.6, graceful-fs@^4.2.9: version "4.2.11" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3" integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ== @@ -4515,6 +4503,11 @@ has-flag@^4.0.0: resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== +has-own-prop@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/has-own-prop/-/has-own-prop-2.0.0.tgz#f0f95d58f65804f5d218db32563bb85b8e0417af" + integrity sha512-Pq0h+hvsVm6dDEa8x82GnLSYHOzNDt7f0ddFa3FqcQlgzEiptPqL+XrOJNavjOzSYiYWIrgeVYYgGlLmnxwilQ== + has-property-descriptors@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz#610708600606d36961ed04c196193b6a607fa861" @@ -4530,9 +4523,9 @@ has-property-descriptors@^1.0.2: es-define-property "^1.0.0" has-proto@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/has-proto/-/has-proto-1.0.1.tgz#1885c1305538958aff469fef37937c22795408e0" - integrity sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg== + version "1.0.3" + resolved "https://registry.yarnpkg.com/has-proto/-/has-proto-1.0.3.tgz#b31ddfe9b0e6e9914536a6ab286426d0214f77fd" + integrity sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q== has-symbols@^1.0.2, has-symbols@^1.0.3: version "1.0.3" @@ -4552,11 +4545,9 @@ has-unicode@^2.0.1: integrity sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ== has@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796" - integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw== - dependencies: - function-bind "^1.1.1" + version "1.0.4" + resolved "https://registry.yarnpkg.com/has/-/has-1.0.4.tgz#2eb2860e000011dae4f1406a86fe80e530fb2ec6" + integrity sha512-qdSAmqLF6209RFj4VVItywPMbm3vWylknmB3nvNiUIs72xAimcM8nVYxYr7ncvZq5qzk9MKIZR8ijqD/1QuYjQ== hasha@^5.0.0: version "5.2.2" @@ -4567,9 +4558,9 @@ hasha@^5.0.0: type-fest "^0.8.0" hasown@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/hasown/-/hasown-2.0.0.tgz#f4c513d454a57b7c7e1650778de226b11700546c" - integrity sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA== + version "2.0.2" + resolved "https://registry.yarnpkg.com/hasown/-/hasown-2.0.2.tgz#003eaf91be7adc372e84ec59dc37252cedb80003" + integrity sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ== dependencies: function-bind "^1.1.2" @@ -4636,11 +4627,6 @@ https-proxy-agent@^5.0.0: agent-base "6" debug "4" -human-signals@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-1.1.1.tgz#c5b1cd14f50aeae09ab6c59fe63ba3395fe4dfa3" - integrity sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw== - human-signals@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-2.1.0.tgz#dc91fcba42e4d06e4abaed33b3e7a3c02f514ea0" @@ -4682,7 +4668,7 @@ ignore@^5.1.8, ignore@^5.2.0: resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.2.4.tgz#a291c0c6178ff1b960befe47fcdec301674a6324" integrity sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ== -import-fresh@^3.0.0, import-fresh@^3.2.1: +import-fresh@^3.0.0, import-fresh@^3.2.1, import-fresh@^3.3.0: version "3.3.0" resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b" integrity sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw== @@ -4736,10 +4722,10 @@ ini@~1.3.0: resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.8.tgz#a29da425b48806f34767a4efce397269af28432c" integrity sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew== -inquirer@8.2.4: - version "8.2.4" - resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-8.2.4.tgz#ddbfe86ca2f67649a67daa6f1051c128f684f0b4" - integrity sha512-nn4F01dxU8VeKfq192IjLsxu0/OmMZ4Lg3xKAns148rCaXP6ntAoEkVYZThWjwON8AlzdZZi6oqnhNbxUG9hVg== +inquirer@8.2.6: + version "8.2.6" + resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-8.2.6.tgz#733b74888195d8d400a67ac332011b5fae5ea562" + integrity sha512-M1WuAmb7pn9zdFRtQYk26ZBoY043Sse0wVDdk4Bppr+JOXyQYybdtvK+l9wUibhtjdjvtoiNy8tk+EgsYIUqKg== dependencies: ansi-escapes "^4.2.1" chalk "^4.1.1" @@ -4755,28 +4741,28 @@ inquirer@8.2.4: string-width "^4.1.0" strip-ansi "^6.0.0" through "^2.3.6" - wrap-ansi "^7.0.0" + wrap-ansi "^6.0.1" -inquirer@8.2.5: - version "8.2.5" - resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-8.2.5.tgz#d8654a7542c35a9b9e069d27e2df4858784d54f8" - integrity sha512-QAgPDQMEgrDssk1XiwwHoOGYF9BAbUcc1+j+FhEvaOt8/cKRqyLn0U5qA6F74fGhTMGxf92pOvPBeh29jQJDTQ== +inquirer@9.2.15: + version "9.2.15" + resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-9.2.15.tgz#2135a36190a6e5c92f5d205e0af1fea36b9d3492" + integrity sha512-vI2w4zl/mDluHt9YEQ/543VTCwPKWiHzKtm9dM2V0NdFcqEexDAjUHzO1oA60HRNaVifGXXM1tRRNluLVHa0Kg== dependencies: - ansi-escapes "^4.2.1" - chalk "^4.1.1" + "@ljharb/through" "^2.3.12" + ansi-escapes "^4.3.2" + chalk "^5.3.0" cli-cursor "^3.1.0" - cli-width "^3.0.0" - external-editor "^3.0.3" - figures "^3.0.0" + cli-width "^4.1.0" + external-editor "^3.1.0" + figures "^3.2.0" lodash "^4.17.21" - mute-stream "0.0.8" + mute-stream "1.0.0" ora "^5.4.1" - run-async "^2.4.0" - rxjs "^7.5.5" - string-width "^4.1.0" - strip-ansi "^6.0.0" - through "^2.3.6" - wrap-ansi "^7.0.0" + run-async "^3.0.0" + rxjs "^7.8.1" + string-width "^4.2.3" + strip-ansi "^6.0.1" + wrap-ansi "^6.2.0" internal-slot@^1.0.5: version "1.0.5" @@ -4787,11 +4773,6 @@ internal-slot@^1.0.5: has "^1.0.3" side-channel "^1.0.4" -interpret@^1.0.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.4.0.tgz#665ab8bc4da27a774a40584e812e3e0fa45b1a1e" - integrity sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA== - ioredis-mock@^8.2.2: version "8.7.0" resolved "https://registry.yarnpkg.com/ioredis-mock/-/ioredis-mock-8.7.0.tgz#9877a85e0d233e1b49123d1c6e320df01e9a1d36" @@ -5034,6 +5015,11 @@ is-windows@^1.0.2: resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d" integrity sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA== +isarray@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf" + integrity sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ== + isarray@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" @@ -5139,6 +5125,15 @@ iterare@1.2.1: resolved "https://registry.yarnpkg.com/iterare/-/iterare-1.2.1.tgz#139c400ff7363690e33abffa33cbba8920f00042" integrity sha512-RKYVTCjAnRthyJes037NX/IiqeidgN1xc3j1RjFfECFp28A1GVwK9nA+i0rJPaHqSZwygLzRnFlzUuHFoWWy+Q== +jackspeak@^3.1.2: + version "3.4.3" + resolved "https://registry.yarnpkg.com/jackspeak/-/jackspeak-3.4.3.tgz#8833a9d89ab4acde6188942bd1c53b6390ed5a8a" + integrity sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw== + dependencies: + "@isaacs/cliui" "^8.0.2" + optionalDependencies: + "@pkgjs/parseargs" "^0.11.0" + jake@^10.8.5: version "10.9.2" resolved "https://registry.yarnpkg.com/jake/-/jake-10.9.2.tgz#6ae487e6a69afec3a5e167628996b59f35ae2b7f" @@ -5574,7 +5569,7 @@ js-yaml@4.0.0: dependencies: argparse "^2.0.1" -js-yaml@4.1.0: +js-yaml@4.1.0, js-yaml@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602" integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA== @@ -5646,10 +5641,15 @@ json5@^2.2.2, json5@^2.2.3: resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.3.tgz#78cd6f1a19bdc12b73db5ad0c61efd66c1e29283" integrity sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg== -jsonc-parser@3.2.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/jsonc-parser/-/jsonc-parser-3.2.0.tgz#31ff3f4c2b9793f89c67212627c51c6394f88e76" - integrity sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w== +jsonc-parser@3.2.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/jsonc-parser/-/jsonc-parser-3.2.1.tgz#031904571ccf929d7670ee8c547545081cb37f1a" + integrity sha512-AilxAyFOAcK5wA1+LeaySVBrHsGQvUFCDWXKpZjzaL0PqW+xfBOttn8GNtWKFWqneyMZj41MWF9Kl6iPWLwgOA== + +jsonc-parser@3.3.1: + version "3.3.1" + resolved "https://registry.yarnpkg.com/jsonc-parser/-/jsonc-parser-3.3.1.tgz#f2a524b4f7fd11e3d791e559977ad60b98b798b4" + integrity sha512-HUgH65KyejrUFPvHFPbqOY0rsFip3Bo5wb4ngvdi1EpCYWUQDC5V+Y7mZws+DLkr4M//zQJoanu1SP+87Dv1oQ== jsonfile@^6.0.1: version "6.1.0" @@ -5879,6 +5879,11 @@ loupe@^2.3.6: dependencies: get-func-name "^2.0.1" +lru-cache@^10.2.0: + version "10.4.3" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-10.4.3.tgz#410fc8a17b70e598013df257c2446b7f3383f119" + integrity sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ== + lru-cache@^5.1.1: version "5.1.1" resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-5.1.1.tgz#1da27e6710271947695daf6848e847f01d84b920" @@ -5893,22 +5898,12 @@ lru-cache@^6.0.0: dependencies: yallist "^4.0.0" -lru-cache@^9.0.0: - version "9.1.1" - resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-9.1.1.tgz#c58a93de58630b688de39ad04ef02ef26f1902f1" - integrity sha512-65/Jky17UwSb0BuB9V+MyDpsOtXKmYwzhyl+cOa9XUiI4uV2Ouy/2voFP3+al0BjZbJgMBD8FojMpAf+Z+qn4A== - -macos-release@^2.5.0: - version "2.5.1" - resolved "https://registry.yarnpkg.com/macos-release/-/macos-release-2.5.1.tgz#bccac4a8f7b93163a8d163b8ebf385b3c5f55bf9" - integrity sha512-DXqXhEM7gW59OjZO8NIjBCz9AQ1BEMrfiOAl4AYByHCtVHRF4KoGNO8mqQeM8lRCtQe/UnJ4imO/d2HdkKsd+A== - -magic-string@0.29.0: - version "0.29.0" - resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.29.0.tgz#f034f79f8c43dba4ae1730ffb5e8c4e084b16cf3" - integrity sha512-WcfidHrDjMY+eLjlU+8OvwREqHwpgCeKVBUpQ3OhYYuvfaYCUgcbuBzappNzZvg/v8onU3oQj+BYpkOJe9Iw4Q== +magic-string@0.30.8: + version "0.30.8" + resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.30.8.tgz#14e8624246d2bedba70d5462aa99ac9681844613" + integrity sha512-ISQTe55T2ao7XtlAStud6qwYPZjE4GK1S/BeVPus4jrq6JuOnQ00YKQC581RWhR122W7msZV263KzVeLoqidyQ== dependencies: - "@jridgewell/sourcemap-codec" "^1.4.13" + "@jridgewell/sourcemap-codec" "^1.4.15" make-dir@^3.0.0, make-dir@^3.0.2: version "3.1.0" @@ -6056,10 +6051,10 @@ minimatch@^5.0.1: dependencies: brace-expansion "^2.0.1" -minimatch@^8.0.2: - version "8.0.4" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-8.0.4.tgz#847c1b25c014d4e9a7f68aaf63dedd668a626229" - integrity sha512-W0Wvr9HyFXZRGIDgCicunpQ299OKXs9RgZfaukz4qAW/pJhcpUfupc9c+OObPOFueNy8VSrZgEmDtk6Kh4WzDA== +minimatch@^9.0.4: + version "9.0.5" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.5.tgz#d74f9dd6b57d83d8e98cfb82133b03978bc929e5" + integrity sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow== dependencies: brace-expansion "^2.0.1" @@ -6114,16 +6109,16 @@ minipass@^3.0.0, minipass@^3.1.0, minipass@^3.1.1, minipass@^3.1.3: dependencies: yallist "^4.0.0" -minipass@^4.2.4: - version "4.2.8" - resolved "https://registry.yarnpkg.com/minipass/-/minipass-4.2.8.tgz#f0010f64393ecfc1d1ccb5f582bcaf45f48e1a3a" - integrity sha512-fNzuVyifolSLFL4NzpF+wEF4qrgqaaKX0haXPQEdQ7NKAN+WecoKMHV09YcuL/DHxrUsYQOK3MiuDf7Ip2OXfQ== - minipass@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/minipass/-/minipass-5.0.0.tgz#3e9788ffb90b694a5d0ec94479a45b5d8738133d" integrity sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ== +"minipass@^5.0.0 || ^6.0.2 || ^7.0.0", minipass@^7.1.2: + version "7.1.2" + resolved "https://registry.yarnpkg.com/minipass/-/minipass-7.1.2.tgz#93a9626ce5e5e66bd4db86849e7515e92340a707" + integrity sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw== + minizlib@^2.0.0, minizlib@^2.1.1: version "2.1.2" resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-2.1.2.tgz#e90d3466ba209b932451508a11ce3d3632145931" @@ -6214,7 +6209,7 @@ ms@2.1.2: resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== -ms@2.1.3, ms@^2.0.0, ms@^2.1.1: +ms@2.1.3, ms@^2.0.0, ms@^2.1.1, ms@^2.1.3: version "2.1.3" resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== @@ -6237,6 +6232,11 @@ mute-stream@0.0.8: resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.8.tgz#1630c42b2251ff81e2a283de96a5497ea92e5e0d" integrity sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA== +mute-stream@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-1.0.0.tgz#e31bd9fe62f0aed23520aa4324ea6671531e013e" + integrity sha512-avsJQhyd+680gKXyG/sQc0nXaC6rBkPOfyHYcFb9+hdkqQkR9bdnkJ0AMZhke0oesPqIO+mFFJ+IdBc7mst4IA== + mz@^2.4.0: version "2.7.0" resolved "https://registry.yarnpkg.com/mz/-/mz-2.7.0.tgz#95008057a56cafadc2bc63dde7f9ff6955948e32" @@ -6406,11 +6406,6 @@ node-releases@^2.0.18: resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.18.tgz#f010e8d35e2fe8d6b2944f03f70213ecedc4ca3f" integrity sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g== -node-releases@^2.0.8: - version "2.0.10" - resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.10.tgz#c311ebae3b6a148c89b1813fd7c4d3c024ef537f" - integrity sha512-5GFldHPXVG/YZmFzJvKK2zDSzPKhEp0+ZR5SVaoSag9fsL5YgHbUHDfnG5494ISANDcK4KwPXAx2xqVEydmd7w== - node-version-compare@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/node-version-compare/-/node-version-compare-1.0.3.tgz#ca6d2005e67822fb4dfa259e08f1f6cfaabe2e81" @@ -6438,7 +6433,7 @@ normalize-path@^3.0.0, normalize-path@~3.0.0: resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== -npm-run-path@^4.0.0, npm-run-path@^4.0.1: +npm-run-path@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-4.0.1.tgz#b7ecd1e5ed53da8e37a55e1c2269e0b97ed748ea" integrity sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw== @@ -6623,14 +6618,6 @@ ora@5.4.1, ora@^5.4.1: strip-ansi "^6.0.0" wcwidth "^1.0.1" -os-name@4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/os-name/-/os-name-4.0.1.tgz#32cee7823de85a8897647ba4d76db46bf845e555" - integrity sha512-xl9MAoU97MH1Xt5K9ERft2YfCAoaO6msy1OBA0ozxEC0x0TmIoE6K3QvgJMMZA9yKGLmHXNY/YZoDbiGDj4zYw== - dependencies: - macos-release "^2.5.0" - windows-release "^4.0.0" - os-tmpdir@~1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" @@ -6725,6 +6712,11 @@ package-hash@^4.0.0: lodash.flattendeep "^4.4.0" release-zalgo "^1.0.0" +package-json-from-dist@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz#4f1471a010827a86f94cfd9b0727e36d267de505" + integrity sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw== + pako@^0.2.5: version "0.2.9" resolved "https://registry.yarnpkg.com/pako/-/pako-0.2.9.tgz#f3f7522f4ef782348da8161bad9ecfd51bf83a75" @@ -6750,7 +6742,7 @@ parse-json@^4.0.0: error-ex "^1.3.1" json-parse-better-errors "^1.0.1" -parse-json@^5.0.0, parse-json@^5.2.0: +parse-json@^5.2.0: version "5.2.0" resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-5.2.0.tgz#c76fc66dee54231c962b22bcc8a72cf2f99753cd" integrity sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg== @@ -6807,28 +6799,30 @@ path-parse@^1.0.7: resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== -path-scurry@^1.6.1: - version "1.7.0" - resolved "https://registry.yarnpkg.com/path-scurry/-/path-scurry-1.7.0.tgz#99c741a2cfbce782294a39994d63748b5a24f6db" - integrity sha512-UkZUeDjczjYRE495+9thsgcVgsaCPkaw80slmfVFgllxY+IO8ubTsOpFVjDPROBqJdHfVPUFRHPBV/WciOVfWg== +path-scurry@^1.11.1: + version "1.11.1" + resolved "https://registry.yarnpkg.com/path-scurry/-/path-scurry-1.11.1.tgz#7960a668888594a0720b12a911d1a742ab9f11d2" + integrity sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA== dependencies: - lru-cache "^9.0.0" - minipass "^5.0.0" + lru-cache "^10.2.0" + minipass "^5.0.0 || ^6.0.2 || ^7.0.0" path-to-regexp@0.1.10: version "0.1.10" resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.10.tgz#67e9108c5c0551b9e5326064387de4763c4d5f8b" integrity sha512-7lf7qcQidTku0Gu3YDPc8DJ1q7OOucfa/BSsIwjuh56VU7katFvuM8hULfkwB3Fns/rsVF7PwPKVw1sl5KQS9w== -path-to-regexp@0.2.5: - version "0.2.5" - resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.2.5.tgz#0b426991e387fc4c675de23557f358715eb66fb0" - integrity sha512-l6qtdDPIkmAmzEO6egquYDfqQGPMRNGjYtrU13HAXb3YSRrt7HSb1sJY0pKp6o2bAa86tSB6iwaW2JbthPKr7Q== +path-to-regexp@0.2.5, path-to-regexp@^1.9.0: + version "1.9.0" + resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-1.9.0.tgz#5dc0753acbf8521ca2e0f137b4578b917b10cf24" + integrity sha512-xIp7/apCFJuUHdDLWe8O1HIkb0kQrOMb/0u6FXQjemHn/ii5LrIzU6bdECnsiTF/GjZkMEKg1xdiZwNqDYlZ6g== + dependencies: + isarray "0.0.1" -path-to-regexp@3.2.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-3.2.0.tgz#fa7877ecbc495c601907562222453c43cc204a5f" - integrity sha512-jczvQbCUS7XmS7o+y1aEO9OBVFeZBQ1MDSEqmO7xSoPgOPoowY/SxLpZ6Vh97/8qHZOteiCKb7gkG9gA2ZUxJA== +path-to-regexp@3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-3.3.0.tgz#f7f31d32e8518c2660862b644414b6d5c63a611b" + integrity sha512-qyCH421YQPS2WFDxDjftfc1ZR5WKQzVzqsp4n9M2kQhVOo/ByahFoUNJfl58kOcEGfQ//7weFTDhm+ss8Ecxgw== path-type@^4.0.0: version "4.0.0" @@ -6855,6 +6849,11 @@ picocolors@^1.1.0: resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.1.0.tgz#5358b76a78cde483ba5cef6a9dc9671440b27d59" integrity sha512-TQ92mBOW0l3LeMeyLV6mzy/kWr8lkd/hp3mTg7wYK7zJhuBStmGMBG0BdeDZS/dZx1IukaX6Bk11zcln25o1Aw== +picomatch@4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-4.0.1.tgz#68c26c8837399e5819edce48590412ea07f17a07" + integrity sha512-xUXwsxNjwTQ8K3GnT4pCJm+xq3RUPQbmkYJTP5aFIfNIvbcc/4MUxgBaaRSZJ6yGJZiGSyYlM6MzwTsRk8SYCg== + picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.2.3, picomatch@^2.3.1: version "2.3.1" resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" @@ -7188,13 +7187,6 @@ readline-sync@^1.4.9: resolved "https://registry.yarnpkg.com/readline-sync/-/readline-sync-1.4.10.tgz#41df7fbb4b6312d673011594145705bf56d8873b" integrity sha512-gNva8/6UAe8QYepIQH/jQ2qn91Qj0B9sYjMBBs3QOB8F2CXcKgLxQaJRP76sWVRQt+QU+8fAkCbCvjjMFu7Ycw== -rechoir@^0.6.2: - version "0.6.2" - resolved "https://registry.yarnpkg.com/rechoir/-/rechoir-0.6.2.tgz#85204b54dba82d5742e28c96756ef43af50e3384" - integrity sha512-HFM8rkZ+i3zrV+4LQjwQ0W+ez98pApMGM3HUrN04j3CqzPOzl9nmP15Y8YXNm8QHGv/eacOVEjqhmWpkRV0NAw== - dependencies: - resolve "^1.1.6" - redis-errors@^1.0.0, redis-errors@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/redis-errors/-/redis-errors-1.2.0.tgz#eb62d2adb15e4eaf4610c04afe1529384250abad" @@ -7250,6 +7242,11 @@ release-zalgo@^1.0.0: dependencies: es6-error "^4.0.1" +repeat-string@^1.6.1: + version "1.6.1" + resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637" + integrity sha512-PV0dzCYDNfRi1jCDbJzpW7jNNDRuCOG/jI5ctQcGKt/clZD+YcPS3yIlWuTJMmESC8aevCFmWJy5wjAFgNqN6w== + require-directory@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" @@ -7287,7 +7284,7 @@ resolve.exports@^2.0.0: resolved "https://registry.yarnpkg.com/resolve.exports/-/resolve.exports-2.0.2.tgz#f8c934b8e6a13f539e38b7098e2e36134f01e800" integrity sha512-X2UW6Nw3n/aMgDVy+0rSqgHlv39WZAlZrXCdnbyEiKm17DSqHX4MmQMaST3FbeWR5FTuRcUwYAziZajji0Y7mg== -resolve@^1.1.6, resolve@^1.10.0, resolve@^1.22.1: +resolve@^1.10.0, resolve@^1.22.1: version "1.22.2" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.2.tgz#0ed0943d4e301867955766c9f3e1ae6d01c6845f" integrity sha512-Sb+mjNHOULsBv818T40qSPeRiuWLyaGMa5ewydRLFimneixmVy2zdivRl+AF6jaYPC8ERxGDmFSiqui6SfPd+g== @@ -7330,18 +7327,16 @@ rimraf@3.0.2, rimraf@^3.0.0, rimraf@^3.0.2: dependencies: glob "^7.1.3" -rimraf@4.4.1: - version "4.4.1" - resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-4.4.1.tgz#bd33364f67021c5b79e93d7f4fa0568c7c21b755" - integrity sha512-Gk8NlF062+T9CqNGn6h4tls3k6T1+/nXdOcSZVikNVtlRdYpA7wRJJMoXmuvOnLW844rPjdQ7JgXCYM6PPC/og== - dependencies: - glob "^9.2.0" - run-async@^2.4.0: version "2.4.1" resolved "https://registry.yarnpkg.com/run-async/-/run-async-2.4.1.tgz#8440eccf99ea3e70bd409d49aab88e10c189a455" integrity sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ== +run-async@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/run-async/-/run-async-3.0.0.tgz#42a432f6d76c689522058984384df28be379daad" + integrity sha512-540WwVDOMxA6dN6We19EcT9sc3hkXPw5mzRNGM3FkdN/vtE9NFvj5lFAPNwUDmJjXidm3v7TC1cTE7t17Ulm1Q== + run-parallel@^1.1.9: version "1.2.0" resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.2.0.tgz#66d1368da7bdf921eb9d95bd1a9229e7f21a43ee" @@ -7349,20 +7344,20 @@ run-parallel@^1.1.9: dependencies: queue-microtask "^1.2.2" -rxjs@6.6.7, rxjs@^6.5.2: - version "6.6.7" - resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.6.7.tgz#90ac018acabf491bf65044235d5863c4dab804c9" - integrity sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ== - dependencies: - tslib "^1.9.0" - -rxjs@^7.5.5, rxjs@^7.5.6: +rxjs@7.8.1, rxjs@^7.5.5, rxjs@^7.5.6, rxjs@^7.8.1: version "7.8.1" resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-7.8.1.tgz#6f6f3d99ea8044291efd92e7c7fcf562c4057543" integrity sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg== dependencies: tslib "^2.1.0" +rxjs@^6.5.2: + version "6.6.7" + resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.6.7.tgz#90ac018acabf491bf65044235d5863c4dab804c9" + integrity sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ== + dependencies: + tslib "^1.9.0" + safe-buffer@5.2.1, safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@~5.2.0: version "5.2.1" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" @@ -7392,7 +7387,7 @@ safe-stable-stringify@^2.3.1: resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== -schema-utils@^3.1.1, schema-utils@^3.1.2: +schema-utils@^3.1.1: version "3.1.2" resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-3.1.2.tgz#36c10abca6f7577aeae136c804b0c741edeadc99" integrity sha512-pvjEHOgWc9OWA/f/DE3ohBWTD6EleVLf7iFUkoSwAxttdBhB9QUebQgxER2kWueOvRJXPHNnyrvvh9eZINB8Eg== @@ -7401,6 +7396,15 @@ schema-utils@^3.1.1, schema-utils@^3.1.2: ajv "^6.12.5" ajv-keywords "^3.5.2" +schema-utils@^3.2.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-3.3.0.tgz#f50a88877c3c01652a15b622ae9e9795df7a60fe" + integrity sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg== + dependencies: + "@types/json-schema" "^7.0.8" + ajv "^6.12.5" + ajv-keywords "^3.5.2" + "semver@2 || 3 || 4 || 5", semver@^6.0.0, semver@^6.3.0, semver@^6.3.1, semver@^7.2.1, semver@^7.3.5, semver@^7.3.8, semver@^7.5.2, semver@^7.5.3, semver@^7.5.4, semver@^7.6.3: version "7.5.4" resolved "https://registry.yarnpkg.com/semver/-/semver-7.5.4.tgz#483986ec4ed38e1c6c48c34894a9182dbff68a6e" @@ -7498,15 +7502,6 @@ shebang-regex@^3.0.0: resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== -shelljs@0.8.5: - version "0.8.5" - resolved "https://registry.yarnpkg.com/shelljs/-/shelljs-0.8.5.tgz#de055408d8361bed66c669d2f000538ced8ee20c" - integrity sha512-TiwcRcrkhHvbrZbnRcFYMLl30Dfov3HKqzp5tO5b4pt6G/SezKcYhmDg15zXVBswHmctSAQKznqNW2LO5tTDow== - dependencies: - glob "^7.0.0" - interpret "^1.0.0" - rechoir "^0.6.2" - side-channel@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.4.tgz#efce5c8fdc104ee751b25c58d4290011fa5ea2cf" @@ -7531,6 +7526,11 @@ signal-exit@^3.0.2, signal-exit@^3.0.3, signal-exit@^3.0.7: resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9" integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ== +signal-exit@^4.0.1: + version "4.1.0" + resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-4.1.0.tgz#952188c1cbd546070e2dd20d0f41c0ae0530cb04" + integrity sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw== + simple-concat@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/simple-concat/-/simple-concat-1.0.1.tgz#f46976082ba35c2263f1c8ab5edfe26c41c9552f" @@ -7577,11 +7577,12 @@ smart-buffer@^4.2.0: integrity sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg== socket.io-adapter@~2.5.2: - version "2.5.2" - resolved "https://registry.yarnpkg.com/socket.io-adapter/-/socket.io-adapter-2.5.2.tgz#5de9477c9182fdc171cd8c8364b9a8894ec75d12" - integrity sha512-87C3LO/NOMc+eMcpcxUBebGjkpMDkNBS9tf7KJqcDsmL936EChtVva71Dw2q4tQcuVC+hAUy4an2NO/sYXmwRA== + version "2.5.5" + resolved "https://registry.yarnpkg.com/socket.io-adapter/-/socket.io-adapter-2.5.5.tgz#c7a1f9c703d7756844751b6ff9abfc1780664082" + integrity sha512-eLDQas5dzPgOWCk9GuuJC2lBqItuhKI4uxGgo9aIV7MYbk2h9Q6uULEh8WBzThoI7l+qU9Ast9fVUmkqPP9wYg== dependencies: - ws "~8.11.0" + debug "~4.3.4" + ws "~8.17.1" socket.io-client@^4.8.0: version "4.8.0" @@ -7608,19 +7609,6 @@ socket.io-parser@~4.2.4: "@socket.io/component-emitter" "~3.1.0" debug "~4.3.1" -socket.io@*: - version "4.7.1" - resolved "https://registry.yarnpkg.com/socket.io/-/socket.io-4.7.1.tgz#9009f31bf7be25478895145e92fbc972ad1db900" - integrity sha512-W+utHys2w//dhFjy7iQQu9sGd3eokCjGbl2r59tyLqNiJJBdIebn3GAKEXBr3osqHTObJi2die/25bCx2zsaaw== - dependencies: - accepts "~1.3.4" - base64id "~2.0.0" - cors "~2.8.5" - debug "~4.3.2" - engine.io "~6.5.0" - socket.io-adapter "~2.5.2" - socket.io-parser "~4.2.4" - socket.io@4.7.5, socket.io@^4.8.0: version "4.8.0" resolved "https://registry.yarnpkg.com/socket.io/-/socket.io-4.8.0.tgz#33d05ae0915fad1670bd0c4efcc07ccfabebe3b1" @@ -7659,7 +7647,7 @@ source-map-support@0.5.13: buffer-from "^1.0.0" source-map "^0.6.0" -source-map-support@0.5.21, source-map-support@^0.5.17, source-map-support@^0.5.19, source-map-support@^0.5.6, source-map-support@~0.5.20: +source-map-support@^0.5.17, source-map-support@^0.5.19, source-map-support@^0.5.6, source-map-support@~0.5.20: version "0.5.21" resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.21.tgz#04fe7c7f9e1ed2d662233c28cb2b35b9f63f6e4f" integrity sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w== @@ -7805,6 +7793,15 @@ string-length@^4.0.1: char-regex "^1.0.2" strip-ansi "^6.0.0" +"string-width-cjs@npm:string-width@^4.2.0": + version "4.2.3" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" + integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== + dependencies: + emoji-regex "^8.0.0" + is-fullwidth-code-point "^3.0.0" + strip-ansi "^6.0.1" + "string-width@^1.0.2 || 2": version "2.1.1" resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e" @@ -7831,6 +7828,15 @@ string-width@^3.0.0, string-width@^3.1.0: is-fullwidth-code-point "^2.0.0" strip-ansi "^5.1.0" +string-width@^5.0.1, string-width@^5.1.2: + version "5.1.2" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-5.1.2.tgz#14f8daec6d81e7221d2a357e668cab73bdbca794" + integrity sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA== + dependencies: + eastasianwidth "^0.2.0" + emoji-regex "^9.2.2" + strip-ansi "^7.0.1" + string.prototype.trim@^1.2.7: version "1.2.7" resolved "https://registry.yarnpkg.com/string.prototype.trim/-/string.prototype.trim-1.2.7.tgz#a68352740859f6893f14ce3ef1bb3037f7a90533" @@ -7872,6 +7878,13 @@ string_decoder@~1.1.1: dependencies: safe-buffer "~5.1.0" +"strip-ansi-cjs@npm:strip-ansi@^6.0.1": + version "6.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" + integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== + dependencies: + ansi-regex "^5.0.1" + strip-ansi@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-4.0.0.tgz#a8479022eb1ac368a871389b635262c505ee368f" @@ -7893,6 +7906,13 @@ strip-ansi@^6.0.0, strip-ansi@^6.0.1: dependencies: ansi-regex "^5.0.1" +strip-ansi@^7.0.1: + version "7.1.0" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-7.1.0.tgz#d5b6568ca689d8561370b0707685d22434faff45" + integrity sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ== + dependencies: + ansi-regex "^6.0.1" + strip-bom@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3" @@ -7983,10 +8003,10 @@ supports-preserve-symlinks-flag@^1.0.0: resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09" integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w== -swagger-ui-dist@5.11.2: - version "5.11.2" - resolved "https://registry.yarnpkg.com/swagger-ui-dist/-/swagger-ui-dist-5.11.2.tgz#b423e820928df703586ff58f80b09ffcf2434e08" - integrity sha512-jQG0cRgJNMZ7aCoiFofnoojeSaa/+KgWaDlfgs8QN+BXoGMpxeMVY5OEnjq4OlNvF3yjftO8c9GRAgcHlO+u7A== +swagger-ui-dist@5.17.14: + version "5.17.14" + resolved "https://registry.yarnpkg.com/swagger-ui-dist/-/swagger-ui-dist-5.17.14.tgz#e2c222e5bf9e15ccf80ec4bc08b4aaac09792fd6" + integrity sha512-CVbSfaLpstV65OnSjbXfVd6Sta3q3F7Cj/yYuvHMp1P90LztOLs6PfUnKEVAeiIVQt9u2SaPwv0LiH/OyMjHRw== swagger-ui-dist@>=4.11.0: version "4.18.3" @@ -8059,24 +8079,24 @@ tar@^6.0.2, tar@^6.1.11, tar@^6.1.2: mkdirp "^1.0.3" yallist "^4.0.0" -terser-webpack-plugin@^5.3.7: - version "5.3.7" - resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-5.3.7.tgz#ef760632d24991760f339fe9290deb936ad1ffc7" - integrity sha512-AfKwIktyP7Cu50xNjXF/6Qb5lBNzYaWpU6YfoX3uZicTx0zTy0stDDCsvjDapKsSDvOeWo5MEq4TmdBy2cNoHw== +terser-webpack-plugin@^5.3.10: + version "5.3.10" + resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-5.3.10.tgz#904f4c9193c6fd2a03f693a2150c62a92f40d199" + integrity sha512-BKFPWlPDndPs+NGGCr1U59t0XScL5317Y0UReNrHaw9/FwhPENlq6bfgs+4yPfyP51vqC1bQ4rp1EfXW5ZSH9w== dependencies: - "@jridgewell/trace-mapping" "^0.3.17" + "@jridgewell/trace-mapping" "^0.3.20" jest-worker "^27.4.5" schema-utils "^3.1.1" serialize-javascript "^6.0.1" - terser "^5.16.5" + terser "^5.26.0" -terser@^5.16.5: - version "5.17.1" - resolved "https://registry.yarnpkg.com/terser/-/terser-5.17.1.tgz#948f10830454761e2eeedc6debe45c532c83fd69" - integrity sha512-hVl35zClmpisy6oaoKALOpS0rDYLxRFLHhRuDlEGTKey9qHjS1w9GMORjuwIMt70Wan4lwsLYyWDVnWgF+KUEw== +terser@^5.26.0: + version "5.34.1" + resolved "https://registry.yarnpkg.com/terser/-/terser-5.34.1.tgz#af40386bdbe54af0d063e0670afd55c3105abeb6" + integrity sha512-FsJZ7iZLd/BXkz+4xrRTGJ26o/6VTjQytUk8b8OxkwcD2I+79VPJlz7qss1+zE7h8GNIScFqXcDyJ/KqBYZFVA== dependencies: - "@jridgewell/source-map" "^0.3.2" - acorn "^8.5.0" + "@jridgewell/source-map" "^0.3.3" + acorn "^8.8.2" commander "^2.20.0" source-map-support "~0.5.20" @@ -8241,10 +8261,10 @@ ts-node@^9.1.1: source-map-support "^0.5.17" yn "3.1.1" -tsconfig-paths-webpack-plugin@4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/tsconfig-paths-webpack-plugin/-/tsconfig-paths-webpack-plugin-4.0.1.tgz#a24651d0f69668a1abad38d3c2489855c257460d" - integrity sha512-m5//KzLoKmqu2MVix+dgLKq70MnFi8YL8sdzQZ6DblmCdfuq/y3OqvJd5vMndg2KEVCOeNz8Es4WVZhYInteLw== +tsconfig-paths-webpack-plugin@4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/tsconfig-paths-webpack-plugin/-/tsconfig-paths-webpack-plugin-4.1.0.tgz#3c6892c5e7319c146eee1e7302ed9e6f2be4f763" + integrity sha512-xWFISjviPydmtmgeUAuXp4N1fky+VCtfhOkDUFIv5ea7p4wuTomI4QTrXvFBX2S4jZsmyTSrStQl+E+4w+RzxA== dependencies: chalk "^4.1.0" enhanced-resolve "^5.7.0" @@ -8278,16 +8298,6 @@ tsconfig-paths@^3.14.1, tsconfig-paths@^3.5.0, tsconfig-paths@^3.9.0: minimist "^1.2.6" strip-bom "^3.0.0" -tslib@2.5.0, tslib@^2.1.0, tslib@^2.5.0: - version "2.5.0" - resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.5.0.tgz#42bfed86f5787aeb41d031866c8f402429e0fddf" - integrity sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg== - -tslib@2.6.2: - version "2.6.2" - resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.6.2.tgz#703ac29425e7b37cd6fd456e92404d46d1f3e4ae" - integrity sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q== - tslib@2.7.0: version "2.7.0" resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.7.0.tgz#d9b40c5c40ab59e8738f297df3087bf1a2690c01" @@ -8303,6 +8313,11 @@ tslib@^2.0.0, tslib@^2.4.0: resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.6.0.tgz#b295854684dbda164e181d259a22cd779dcd7bc3" integrity sha512-7At1WUettjcSRHXCyYtTselblcHl9PJFFVKiCAy/bY97+BPZXSQ2wbq0P9s8tK2G7dFQfNnlJnPAiArVBVBsfA== +tslib@^2.1.0, tslib@^2.5.0: + version "2.5.0" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.5.0.tgz#42bfed86f5787aeb41d031866c8f402429e0fddf" + integrity sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg== + tslib@^2.4.1: version "2.6.3" resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.6.3.tgz#0438f810ad7a9edcde7a241c3d80db693c8cbfe0" @@ -8410,16 +8425,16 @@ typeorm@^0.3.9: uuid "^9.0.0" yargs "^17.6.2" -typescript@4.9.5: +typescript@5.3.3: + version "5.3.3" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.3.3.tgz#b3ce6ba258e72e6305ba66f5c9b452aaee3ffe37" + integrity sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw== + +typescript@^4.8.2: version "4.9.5" resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.9.5.tgz#095979f9bcc0d09da324d58d03ce8f8374cbe65a" integrity sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g== -typescript@^4.0.5: - version "4.5.4" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.5.4.tgz#a17d3a0263bf5c8723b9c52f43c5084edf13c2e8" - integrity sha512-VgYs2A2QIRuGphtzFV7aQJduJ2gyfTljngLzjpfW9FoYZF6xuw1W0vW9ghCKLfcWrCFxK81CSGRAvS1pn4fIUg== - uid@2.0.2, uid@^2.0.0: version "2.0.2" resolved "https://registry.yarnpkg.com/uid/-/uid-2.0.2.tgz#4b5782abf0f2feeefc00fa88006b2b3b7af3e3b9" @@ -8437,6 +8452,11 @@ unbox-primitive@^1.0.2: has-symbols "^1.0.3" which-boxed-primitive "^1.0.2" +undici-types@~6.19.2: + version "6.19.8" + resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-6.19.8.tgz#35111c9d1437ab83a7cdc0abae2f26d88eda0a02" + integrity sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw== + unicode-properties@^1.4.1: version "1.4.1" resolved "https://registry.yarnpkg.com/unicode-properties/-/unicode-properties-1.4.1.tgz#96a9cffb7e619a0dc7368c28da27e05fc8f9be5f" @@ -8485,14 +8505,6 @@ unpipe@1.0.0, unpipe@~1.0.0: resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" integrity sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ== -update-browserslist-db@^1.0.10: - version "1.0.11" - resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.0.11.tgz#9a2a641ad2907ae7b3616506f4b977851db5b940" - integrity sha512-dCwEFf0/oT85M1fHBg4F0jtLwJrutGoHSQXCh7u4o2t1drG+c0a9Flnqww6XUKSfQMPpJBRjU8d4RXB09qtvaA== - dependencies: - escalade "^3.1.1" - picocolors "^1.0.0" - update-browserslist-db@^1.0.13: version "1.0.13" resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz#3c5e4f5c083661bd38ef64b6328c26ed6c8248c4" @@ -8531,7 +8543,12 @@ utils-merge@1.0.1: resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" integrity sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA== -uuid@8.3.2, uuid@^8.3.2: +uuid@9.0.1: + version "9.0.1" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-9.0.1.tgz#e188d4c8853cc722220392c424cd637f32293f30" + integrity sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA== + +uuid@^8.3.2: version "8.3.2" resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2" integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg== @@ -8580,10 +8597,10 @@ walker@^1.0.8: dependencies: makeerror "1.0.12" -watchpack@^2.4.0: - version "2.4.0" - resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-2.4.0.tgz#fa33032374962c78113f93c7f2fb4c54c9862a5d" - integrity sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg== +watchpack@^2.4.1: + version "2.4.2" + resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-2.4.2.tgz#2feeaed67412e7c33184e5a79ca738fbd38564da" + integrity sha512-TnbFSbcOCcDgjZ4piURLCbJ3nJhznVh9kw6F6iokjiFPl8ONxe9A6nMDVXDiNbrSfLILs6vB07F7wLBrwPYzJw== dependencies: glob-to-regexp "^0.4.1" graceful-fs "^4.1.2" @@ -8626,34 +8643,33 @@ webpack-sources@^3.2.3: resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-3.2.3.tgz#2d4daab8451fd4b240cc27055ff6a0c2ccea0cde" integrity sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w== -webpack@5.80.0: - version "5.80.0" - resolved "https://registry.yarnpkg.com/webpack/-/webpack-5.80.0.tgz#3e660b4ab572be38c5e954bdaae7e2bf76010fdc" - integrity sha512-OIMiq37XK1rWO8mH9ssfFKZsXg4n6klTEDL7S8/HqbAOBBaiy8ABvXvz0dDCXeEF9gqwxSvVk611zFPjS8hJxA== +webpack@5.94.0: + version "5.94.0" + resolved "https://registry.yarnpkg.com/webpack/-/webpack-5.94.0.tgz#77a6089c716e7ab90c1c67574a28da518a20970f" + integrity sha512-KcsGn50VT+06JH/iunZJedYGUJS5FGjow8wb9c0v5n1Om8O1g4L6LjtfxwlXIATopoQu+vOXXa7gYisWxCoPyg== dependencies: - "@types/eslint-scope" "^3.7.3" - "@types/estree" "^1.0.0" - "@webassemblyjs/ast" "^1.11.5" - "@webassemblyjs/wasm-edit" "^1.11.5" - "@webassemblyjs/wasm-parser" "^1.11.5" + "@types/estree" "^1.0.5" + "@webassemblyjs/ast" "^1.12.1" + "@webassemblyjs/wasm-edit" "^1.12.1" + "@webassemblyjs/wasm-parser" "^1.12.1" acorn "^8.7.1" - acorn-import-assertions "^1.7.6" - browserslist "^4.14.5" + acorn-import-attributes "^1.9.5" + browserslist "^4.21.10" chrome-trace-event "^1.0.2" - enhanced-resolve "^5.13.0" + enhanced-resolve "^5.17.1" es-module-lexer "^1.2.1" eslint-scope "5.1.1" events "^3.2.0" glob-to-regexp "^0.4.1" - graceful-fs "^4.2.9" + graceful-fs "^4.2.11" json-parse-even-better-errors "^2.3.1" loader-runner "^4.2.0" mime-types "^2.1.27" neo-async "^2.6.2" - schema-utils "^3.1.2" + schema-utils "^3.2.0" tapable "^2.1.1" - terser-webpack-plugin "^5.3.7" - watchpack "^2.4.0" + terser-webpack-plugin "^5.3.10" + watchpack "^2.4.1" webpack-sources "^3.2.3" whatwg-url@^5.0.0: @@ -8713,13 +8729,6 @@ wide-align@^1.1.5: dependencies: string-width "^1.0.2 || 2 || 3 || 4" -windows-release@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/windows-release/-/windows-release-4.0.0.tgz#4725ec70217d1bf6e02c7772413b29cdde9ec377" - integrity sha512-OxmV4wzDKB1x7AZaZgXMVsdJ1qER1ed83ZrTYd5Bwq2HfJVg3DJS8nqlAG4sMoJ7mu8cuRmLEYyU13BKwctRAg== - dependencies: - execa "^4.0.2" - winston-daily-rotate-file@^4.5.0: version "4.7.1" resolved "https://registry.yarnpkg.com/winston-daily-rotate-file/-/winston-daily-rotate-file-4.7.1.tgz#f60a643af87f8867f23170d8cd87dbe3603a625f" @@ -8771,6 +8780,15 @@ workerpool@6.1.0: resolved "https://registry.yarnpkg.com/workerpool/-/workerpool-6.1.0.tgz#a8e038b4c94569596852de7a8ea4228eefdeb37b" integrity sha512-toV7q9rWNYha963Pl/qyeZ6wG+3nnsyvolaNUS8+R5Wtw6qJPTxIlOP1ZSvcGhEJw+l3HMMmtiNo9Gl61G4GVg== +"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0": + version "7.0.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" + integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== + dependencies: + ansi-styles "^4.0.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" + wrap-ansi@^5.1.0: version "5.1.0" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-5.1.0.tgz#1fd1f67235d5b6d0fee781056001bfb694c03b09" @@ -8780,7 +8798,7 @@ wrap-ansi@^5.1.0: string-width "^3.0.0" strip-ansi "^5.0.0" -wrap-ansi@^6.2.0: +wrap-ansi@^6.0.1, wrap-ansi@^6.2.0: version "6.2.0" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-6.2.0.tgz#e9393ba07102e6c91a3b221478f0257cd2856e53" integrity sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA== @@ -8798,6 +8816,15 @@ wrap-ansi@^7.0.0: string-width "^4.1.0" strip-ansi "^6.0.0" +wrap-ansi@^8.1.0: + version "8.1.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-8.1.0.tgz#56dc22368ee570face1b49819975d9b9a5ead214" + integrity sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ== + dependencies: + ansi-styles "^6.1.0" + string-width "^5.0.1" + strip-ansi "^7.0.1" + wrappy@1: version "1.0.2" resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" @@ -8821,11 +8848,6 @@ write-file-atomic@^4.0.2: imurmurhash "^0.1.4" signal-exit "^3.0.7" -ws@~8.11.0: - version "8.11.0" - resolved "https://registry.yarnpkg.com/ws/-/ws-8.11.0.tgz#6a0d36b8edfd9f96d8b25683db2f8d7de6e8e143" - integrity sha512-HPG3wQd9sNQoT9xHyNCXoDUa+Xw/VevmY9FoHyQ+g+rrMn4j6FB4np7Z0OhdTgjx6MgQLK7jwSy1YecU1+4Asg== - ws@~8.17.1: version "8.17.1" resolved "https://registry.yarnpkg.com/ws/-/ws-8.17.1.tgz#9293da530bb548febc95371d90f9c878727d919b" @@ -8871,11 +8893,6 @@ yallist@^3.0.2: resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.1.1.tgz#dbb7daf9bfd8bac9ab45ebf602b8cbad0d5d08fd" integrity sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g== -yaml@^1.10.0: - version "1.10.2" - resolved "https://registry.yarnpkg.com/yaml/-/yaml-1.10.2.tgz#2301c5ffbf12b467de8da2333a459e29e7920e4b" - integrity sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg== - yaml@^2.3.1: version "2.4.1" resolved "https://registry.yarnpkg.com/yaml/-/yaml-2.4.1.tgz#2e57e0b5e995292c25c75d2658f0664765210eed" From 613b06b900fce41fa6b7bcccbf58ca01d3b3c1d0 Mon Sep 17 00:00:00 2001 From: ArtemHoruzhenko Date: Wed, 16 Oct 2024 14:13:57 +0300 Subject: [PATCH 182/256] the rest of nestjs libraries --- redisinsight/api/package.json | 4 ++-- redisinsight/api/yarn.lock | 17 ++++++++--------- 2 files changed, 10 insertions(+), 11 deletions(-) diff --git a/redisinsight/api/package.json b/redisinsight/api/package.json index 7a88688fe2..e9a54d0c0e 100644 --- a/redisinsight/api/package.json +++ b/redisinsight/api/package.json @@ -82,8 +82,8 @@ "jsonwebtoken": "^9.0.2", "keytar": "^7.9.0", "lodash": "^4.17.20", - "nest-winston": "^1.4.0", - "nestjs-form-data": "^1.8.7", + "nest-winston": "^1.9.7", + "nestjs-form-data": "^1.9.91", "node-version-compare": "^1.0.3", "quicktype-core": "^23.0.116", "redis": "^4.6.10", diff --git a/redisinsight/api/yarn.lock b/redisinsight/api/yarn.lock index 5d474aa531..19047c14e9 100644 --- a/redisinsight/api/yarn.lock +++ b/redisinsight/api/yarn.lock @@ -6281,20 +6281,19 @@ neo-async@^2.6.2: resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.2.tgz#b4aafb93e3aeb2d8174ca53cf163ab7d7308305f" integrity sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw== -nest-winston@^1.4.0: - version "1.9.1" - resolved "https://registry.yarnpkg.com/nest-winston/-/nest-winston-1.9.1.tgz#2968a9553ca60728be93e47ccb659a8946e97481" - integrity sha512-L3fjIfas+7ZziKsCQiTYvTVw0Hpv3oN4TDnbLLYLIQgKLNpzQyf/2yZv1/buDPMrGJKrNPwiHLoifjGHon34+A== +nest-winston@^1.9.7: + version "1.9.7" + resolved "https://registry.yarnpkg.com/nest-winston/-/nest-winston-1.9.7.tgz#1ef6eb2459ce595655de37d5beb900d2e75b61d3" + integrity sha512-pTTgImRgv7urojsDvaTlenAjyJNLj7ywamfjzrhWKhLhp80AKLYNwf103dVHeqZWe+nzp/vd9DGRs/UN/YadOQ== dependencies: fast-safe-stringify "^2.1.1" -nestjs-form-data@^1.8.7: - version "1.8.7" - resolved "https://registry.yarnpkg.com/nestjs-form-data/-/nestjs-form-data-1.8.7.tgz#ccdbc2060849e34018841bfba557de37ae64abdb" - integrity sha512-mk17APNXELILClea2nwffRrD/NK5Q6zulTJCzNPxwMWfWucHO2HD7Ftjwg2BVnwO27QgqILDLuaO6LEpP6Ng4w== +nestjs-form-data@^1.9.91: + version "1.9.91" + resolved "https://registry.yarnpkg.com/nestjs-form-data/-/nestjs-form-data-1.9.91.tgz#379812fb9b920cb505b50960433be38bc9bda72f" + integrity sha512-g9PDq97UjOoDFjYnhtc/N5HIwTWiyp1DDA9iYs8suSXZK7Z17UE+Hw8HsKH9l2TXlUGUY/BrvaiACFZ472CXuw== dependencies: uid "^2.0.0" - append-field "^1.0.0" busboy "^1.6.0" concat-stream "^2.0.0" file-type "^16.5.4" From 2837da7027c83b6b1b4fb7799c2c258ed17b6a9d Mon Sep 17 00:00:00 2001 From: ArtemHoruzhenko Date: Wed, 16 Oct 2024 14:53:37 +0300 Subject: [PATCH 183/256] fix the rest of the modules + electron --- configs/webpack.config.base.ts | 2 +- redisinsight/api/package.json | 3 +- redisinsight/api/yarn.lock | 82 +++++++++++++++++++++------------- redisinsight/package.json | 3 +- redisinsight/yarn.lock | 8 ++-- 5 files changed, 61 insertions(+), 37 deletions(-) diff --git a/configs/webpack.config.base.ts b/configs/webpack.config.base.ts index 097389890d..8a09570263 100644 --- a/configs/webpack.config.base.ts +++ b/configs/webpack.config.base.ts @@ -61,7 +61,7 @@ const configuration: webpack.Configuration = { // 'reflect-metadata', // 'swagger-ui-express', // 'class-transformer', - // 'class-transformer/storage', + 'class-transformer/storage', // '@nestjs/websockets', // '@nestjs/core/adapters/http-adapter', // '@nestjs/core/helpers/router-method-factory', diff --git a/redisinsight/api/package.json b/redisinsight/api/package.json index e9a54d0c0e..a5ff984946 100644 --- a/redisinsight/api/package.json +++ b/redisinsight/api/package.json @@ -49,6 +49,7 @@ "@nestjs/platform-express/express": "^4.21.1", "@nestjs/platform-socket.io/socket.io": "^4.8.0", "@nestjs/cli/**/braces": "^3.0.3", + "@okta/okta-auth-js/**/jsonpath-plus": "^10.0.0", "**/semver": "^7.5.2", "winston-daily-rotate-file/**/file-stream-rotator": "^1.0.0" }, @@ -62,7 +63,7 @@ "@nestjs/swagger": "^7.4.2", "@nestjs/typeorm": "^10.0.2", "@nestjs/websockets": "^10.4.4", - "@okta/okta-auth-js": "^7.3.0", + "@okta/okta-auth-js": "^7.8.0", "@segment/analytics-node": "^2.1.3", "adm-zip": "^0.5.9", "axios": "^1.7.4", diff --git a/redisinsight/api/yarn.lock b/redisinsight/api/yarn.lock index 19047c14e9..3fb39d5320 100644 --- a/redisinsight/api/yarn.lock +++ b/redisinsight/api/yarn.lock @@ -447,7 +447,14 @@ dependencies: "@babel/helper-plugin-utils" "^7.25.7" -"@babel/runtime@^7.12.5", "@babel/runtime@^7.16.0", "@babel/runtime@^7.6.2": +"@babel/runtime@7.22.10": + version "7.22.10" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.22.10.tgz#ae3e9631fd947cb7e3610d3e9d8fef5f76696682" + integrity sha512-21t/fkKLMZI4pqP2wlmsQAWnYW1PDyKyyUV4vCi+B25ydmdaYTKXPwCj0BzSUnZf4seIiYvSA3jcZ3gdsMFkLQ== + dependencies: + regenerator-runtime "^0.14.0" + +"@babel/runtime@^7.12.5": version "7.22.5" resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.22.5.tgz#8564dd588182ce0047d55d7a75e93921107b57ec" integrity sha512-ecjvYlnAaZ/KVneE/OdKYBYfgXV3Ptu6zQWmgEF7vwKhQnvVS6bjMD2XYgj+SNvQ1GfK/pjgokfPkC/2CO8CuA== @@ -1027,6 +1034,16 @@ "@jridgewell/resolve-uri" "3.1.0" "@jridgewell/sourcemap-codec" "1.4.14" +"@jsep-plugin/assignment@^1.2.1": + version "1.2.1" + resolved "https://registry.yarnpkg.com/@jsep-plugin/assignment/-/assignment-1.2.1.tgz#07277bdd7862451a865d391e2142efba33f46c9b" + integrity sha512-gaHqbubTi29aZpVbBlECRpmdia+L5/lh2BwtIJTmtxdbecEyyX/ejAOg7eQDGNvGOUmPY7Z2Yxdy9ioyH/VJeA== + +"@jsep-plugin/regex@^1.0.3": + version "1.0.3" + resolved "https://registry.yarnpkg.com/@jsep-plugin/regex/-/regex-1.0.3.tgz#3aeaa2e5fa45d89de116aeafbfa41c95935b7f6d" + integrity sha512-XfZgry4DwEZvSFtS/6Y+R48D7qJYJK6R9/yJFyUFHCIUMEEHuJ4X95TDgJp5QkmzfLYvapMPzskV5HpIDrREug== + "@ljharb/through@^2.3.12": version "2.3.13" resolved "https://registry.yarnpkg.com/@ljharb/through/-/through-2.3.13.tgz#b7e4766e0b65aa82e529be945ab078de79874edc" @@ -1232,16 +1249,16 @@ consola "^2.15.0" node-fetch "^2.6.1" -"@okta/okta-auth-js@^7.3.0": - version "7.3.0" - resolved "https://registry.yarnpkg.com/@okta/okta-auth-js/-/okta-auth-js-7.3.0.tgz#79a4392ab157960cf6d72811447279edd9f74589" - integrity sha512-9/e+sMs5PBFPiujoZRzhEaO9s7XPGzUk/Ongrlwo8EAnC6/oSO/qodlSlJy2ehNZmexdESOgkebmxF8WuKItSA== +"@okta/okta-auth-js@^7.8.0": + version "7.8.0" + resolved "https://registry.yarnpkg.com/@okta/okta-auth-js/-/okta-auth-js-7.8.0.tgz#1ab69c47cbf6fd7f3ce9f6caed2e05685f5bb22d" + integrity sha512-yFjv0wD9T5GYcFg6zzQ0M/WGdq2IMoaI/SK/0s9AqazZ6ILv6eyZq47L2nJJ7xld5DBFUhVewnD6BS3Ee7Im1A== dependencies: "@babel/runtime" "^7.12.5" "@peculiar/webcrypto" "^1.4.0" Base64 "1.1.0" atob "^2.1.2" - broadcast-channel "~4.17.0" + broadcast-channel "~5.3.0" btoa "^1.2.1" core-js "^3.6.5" cross-fetch "^3.1.5" @@ -2379,16 +2396,15 @@ braces@^3.0.3, braces@~3.0.2: dependencies: fill-range "^7.1.1" -broadcast-channel@~4.17.0: - version "4.17.0" - resolved "https://registry.yarnpkg.com/broadcast-channel/-/broadcast-channel-4.17.0.tgz#599d44674b09a4e2e07af6da5d03b45ca8bffd11" - integrity sha512-r2GSQMNgZv7eAsbdsu9xofSjc3J2diCQTPkSuyVhLBfx8fylLCVhi5KheuhuAQBJNd4pxqUyz9U6rvdnt7GZng== +broadcast-channel@~5.3.0: + version "5.3.0" + resolved "https://registry.yarnpkg.com/broadcast-channel/-/broadcast-channel-5.3.0.tgz#9d9e55fb8db2a1dbbe436ae6d51382a354e76fc3" + integrity sha512-0PmDYc/iUGZ4QbnCnV7u+WleygiS1bZ4oV6t4rANXYtSgEFtGhB5jimJPLOVpPtce61FVxrH8CYylfO5g7OLKw== dependencies: - "@babel/runtime" "^7.16.0" + "@babel/runtime" "7.22.10" oblivious-set "1.1.1" p-queue "6.6.2" - rimraf "3.0.2" - unload "2.3.1" + unload "2.4.1" browser-or-node@^2.1.1: version "2.1.1" @@ -3264,11 +3280,6 @@ detect-newline@^3.0.0: resolved "https://registry.yarnpkg.com/detect-newline/-/detect-newline-3.1.0.tgz#576f5dfc63ae1a192ff192d8ad3af6308991b651" integrity sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA== -detect-node@2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/detect-node/-/detect-node-2.1.0.tgz#c9c70775a49c3d03bc2c06d9a73be550f978f8b1" - integrity sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g== - detect-port@^1.5.1: version "1.5.1" resolved "https://registry.yarnpkg.com/detect-port/-/detect-port-1.5.1.tgz#451ca9b6eaf20451acb0799b8ab40dff7718727b" @@ -5589,6 +5600,11 @@ jsbn@1.1.0: resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-1.1.0.tgz#b01307cb29b618a1ed26ec79e911f803c4da0040" integrity sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A== +jsep@^1.3.9: + version "1.3.9" + resolved "https://registry.yarnpkg.com/jsep/-/jsep-1.3.9.tgz#8ce42df80ee9c1b39e52d0dd062a465342f35440" + integrity sha512-i1rBX5N7VPl0eYb6+mHNp52sEuaS2Wi8CDYx1X5sn9naevL78+265XJqy1qENEk7mRKwS06NHpUqiBwR7qeodw== + jsesc@^2.5.1: version "2.5.2" resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4" @@ -5660,10 +5676,14 @@ jsonfile@^6.0.1: optionalDependencies: graceful-fs "^4.1.6" -jsonpath-plus@^6.0.1: - version "6.0.1" - resolved "https://registry.yarnpkg.com/jsonpath-plus/-/jsonpath-plus-6.0.1.tgz#9a3e16cedadfab07a3d8dc4e8cd5df4ed8f49c4d" - integrity sha512-EvGovdvau6FyLexFH2OeXfIITlgIbgZoAZe3usiySeaIDm5QS+A10DKNpaPBBqqRSZr2HN6HVNXxtwUAr2apEw== +jsonpath-plus@^10.0.0, jsonpath-plus@^6.0.1: + version "10.0.0" + resolved "https://registry.yarnpkg.com/jsonpath-plus/-/jsonpath-plus-10.0.0.tgz#7a747d47e20a27867dbbc80b57fd554788b91474" + integrity sha512-v7j76HGp/ibKlXYeZ7UrfCLSNDaBWuJMA0GaMjA4sZJtCtY89qgPyToDDcl2zdeHh4B5q/B3g2pQdW76fOg/dA== + dependencies: + "@jsep-plugin/assignment" "^1.2.1" + "@jsep-plugin/regex" "^1.0.3" + jsep "^1.3.9" jsonwebtoken@^9.0.2: version "9.0.2" @@ -7220,6 +7240,11 @@ regenerator-runtime@^0.13.11: resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz#f6dca3e7ceec20590d07ada785636a90cdca17f9" integrity sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg== +regenerator-runtime@^0.14.0: + version "0.14.1" + resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz#356ade10263f685dda125100cd862c1db895327f" + integrity sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw== + regexp.prototype.flags@^1.4.3: version "1.5.0" resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.5.0.tgz#fe7ce25e7e4cca8db37b6634c8a2c7009199b9cb" @@ -7319,7 +7344,7 @@ reusify@^1.0.4: resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76" integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw== -rimraf@3.0.2, rimraf@^3.0.0, rimraf@^3.0.2: +rimraf@^3.0.0, rimraf@^3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== @@ -8491,13 +8516,10 @@ universalify@^2.0.0: resolved "https://registry.yarnpkg.com/universalify/-/universalify-2.0.0.tgz#75a4984efedc4b08975c5aeb73f530d02df25717" integrity sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ== -unload@2.3.1: - version "2.3.1" - resolved "https://registry.yarnpkg.com/unload/-/unload-2.3.1.tgz#9d16862d372a5ce5cb630ad1309c2fd6e35dacfe" - integrity sha512-MUZEiDqvAN9AIDRbbBnVYVvfcR6DrjCqeU2YQMmliFZl9uaBUjTkhuDQkBiyAy8ad5bx1TXVbqZ3gg7namsWjA== - dependencies: - "@babel/runtime" "^7.6.2" - detect-node "2.1.0" +unload@2.4.1: + version "2.4.1" + resolved "https://registry.yarnpkg.com/unload/-/unload-2.4.1.tgz#b0c5b7fb44e17fcbf50dcb8fb53929c59dd226a5" + integrity sha512-IViSAm8Z3sRBYA+9wc0fLQmU9Nrxb16rcDmIiR6Y9LJSZzI7QY5QsDhqPpKOjAn0O9/kfK1TfNEMMAGPTIraPw== unpipe@1.0.0, unpipe@~1.0.0: version "1.0.0" diff --git a/redisinsight/package.json b/redisinsight/package.json index 2431a579ca..bf7c8e284a 100644 --- a/redisinsight/package.json +++ b/redisinsight/package.json @@ -15,7 +15,8 @@ "postinstall": "npx patch-package" }, "resolutions": { - "**/semver": "^7.5.2" + "**/semver": "^7.5.2", + "sqlite3/**/tar": "^6.2.1" }, "dependencies": { "keytar": "^7.9.0", diff --git a/redisinsight/yarn.lock b/redisinsight/yarn.lock index 19b2d0d299..c12a5b9c62 100644 --- a/redisinsight/yarn.lock +++ b/redisinsight/yarn.lock @@ -876,10 +876,10 @@ tar-stream@^2.1.4: inherits "^2.0.3" readable-stream "^3.1.1" -tar@^6.0.2, tar@^6.1.11, tar@^6.1.2: - version "6.2.0" - resolved "https://registry.yarnpkg.com/tar/-/tar-6.2.0.tgz#b14ce49a79cb1cd23bc9b016302dea5474493f73" - integrity sha512-/Wo7DcT0u5HUV486xg675HtjNd3BXZ6xDbzsCUZPt5iw8bTQ63bP0Raut3mvro9u+CUyq7YQd8Cx55fsZXxqLQ== +tar@^6.0.2, tar@^6.1.11, tar@^6.1.2, tar@^6.2.1: + version "6.2.1" + resolved "https://registry.yarnpkg.com/tar/-/tar-6.2.1.tgz#717549c541bc3c2af15751bea94b1dd068d4b03a" + integrity sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A== dependencies: chownr "^2.0.0" fs-minipass "^2.0.0" From bafff48dc56fee83e03843433bb35fb813bf66d2 Mon Sep 17 00:00:00 2001 From: ArtemHoruzhenko Date: Wed, 16 Oct 2024 15:32:26 +0300 Subject: [PATCH 184/256] setup codeql to ignore test files/folders --- .github/codeql/config.yml | 6 ++++++ .github/workflows/codeql-analysis.yml | 1 + 2 files changed, 7 insertions(+) create mode 100644 .github/codeql/config.yml diff --git a/.github/codeql/config.yml b/.github/codeql/config.yml new file mode 100644 index 0000000000..9117ded815 --- /dev/null +++ b/.github/codeql/config.yml @@ -0,0 +1,6 @@ +paths-ignore: + - 'tests/**' + - '**/*.test.ts' + - '**/*.spec.ts' + - '**/*.spec.tsx' + - '**/__mocks__/**' diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 0c9660b8dd..4abd72195d 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -45,6 +45,7 @@ jobs: uses: github/codeql-action/init@v1 with: languages: ${{ matrix.language }} + config-file: ./.github/codeql/config.yml # If you wish to specify custom queries, you can do so here or in a config file. # By default, queries listed here will override any specified in a config file. # Prefix the list here with "+" to use these queries and those in the config file. From d8982edd5b4e217558e14ca4ca2a6a3db9dc8b86 Mon Sep 17 00:00:00 2001 From: ArtemHoruzhenko Date: Wed, 16 Oct 2024 16:07:11 +0300 Subject: [PATCH 185/256] exclude api/test folder from codeql analysis --- .github/codeql/config.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/codeql/config.yml b/.github/codeql/config.yml index 9117ded815..e73bc20095 100644 --- a/.github/codeql/config.yml +++ b/.github/codeql/config.yml @@ -4,3 +4,4 @@ paths-ignore: - '**/*.spec.ts' - '**/*.spec.tsx' - '**/__mocks__/**' + - './redisinsight/api/test' From a4dc861a1fb99eab037e2146e82ec1d4e358128c Mon Sep 17 00:00:00 2001 From: ArtemHoruzhenko Date: Wed, 16 Oct 2024 16:28:55 +0300 Subject: [PATCH 186/256] upgrade all the packages --- tests/e2e/package.json | 54 +- tests/e2e/yarn.lock | 2450 +++++++++++++++++++++++----------------- 2 files changed, 1455 insertions(+), 1049 deletions(-) diff --git a/tests/e2e/package.json b/tests/e2e/package.json index 6844badc51..7b1e324780 100644 --- a/tests/e2e/package.json +++ b/tests/e2e/package.json @@ -24,9 +24,9 @@ "keywords": [], "author": "", "dependencies": { - "axios": "^1.6.0", + "axios": "^1.7.7", "brotli-unicode": "^1.0.2", - "cli-argument-parser": "0.4.5", + "cli-argument-parser": "0.7.4", "fflate": "^0.8.2", "js-yaml": "^4.1.0", "lz4js": "^0.2.0", @@ -40,36 +40,36 @@ "**/semver": "^7.5.2" }, "devDependencies": { - "@types/archiver": "^5.3.2", - "@types/chance": "1.1.3", - "@types/edit-json-file": "1.7.0", - "@types/fs-extra": "9.0.11", - "@types/selenium-webdriver": "^4.1.22", - "@types/sqlite3": "^3.1.8", - "@types/supertest": "^2.0.8", - "@typescript-eslint/eslint-plugin": "4.28.2", - "@typescript-eslint/parser": "4.28.2", - "archiver": "^5.3.1", - "chance": "1.1.8", - "chromedriver": "^124.0.1", - "cli-argument-parser": "0.4.5", + "@types/archiver": "^6.0.2", + "@types/chance": "1.1.6", + "@types/edit-json-file": "1.7.3", + "@types/fs-extra": "11.0.4", + "@types/selenium-webdriver": "^4.1.26", + "@types/sqlite3": "^3.1.11", + "@types/supertest": "^6.0.2", + "@typescript-eslint/eslint-plugin": "8.9.0", + "@typescript-eslint/parser": "8.9.0", + "archiver": "^7.0.1", + "chance": "1.1.12", + "chromedriver": "^130.0.0", + "cli-argument-parser": "0.7.4", "cross-env": "^7.0.3", - "dotenv-cli": "^5.0.0", - "edit-json-file": "1.7.0", - "eslint": "7.32.0", - "eslint-plugin-import": "2.24.2", - "fs-extra": "^10.0.0", - "open": "^8.4.2", - "redis": "3.1.1", - "selenium-webdriver": "^4.20.0", - "sqlite3": "^5.1.6", - "supertest": "^4.0.2", + "dotenv-cli": "^7.4.2", + "edit-json-file": "1.8.0", + "eslint": "9.12.0", + "eslint-plugin-import": "2.31.0", + "fs-extra": "^11.2.0", + "open": "^10.1.0", + "redis": "4.7.0", + "selenium-webdriver": "^4.25.0", + "sqlite3": "^5.1.7", + "supertest": "^7.0.0", "testcafe": "3.6.2", "testcafe-browser-provider-electron": "0.0.21", "testcafe-reporter-html": "1.4.6", "testcafe-reporter-json": "2.2.0", "testcafe-reporter-spec": "2.2.0", - "ts-node": "10.9.1", - "typescript": "5.1.3" + "ts-node": "10.9.2", + "typescript": "5.6.3" } } diff --git a/tests/e2e/yarn.lock b/tests/e2e/yarn.lock index 620ef8ec53..ecbdad2497 100644 --- a/tests/e2e/yarn.lock +++ b/tests/e2e/yarn.lock @@ -15,13 +15,6 @@ "@jridgewell/gen-mapping" "^0.3.0" "@jridgewell/trace-mapping" "^0.3.9" -"@babel/code-frame@7.12.11": - version "7.12.11" - resolved "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.11.tgz" - integrity sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw== - dependencies: - "@babel/highlight" "^7.10.4" - "@babel/code-frame@^7.23.5": version "7.23.5" resolved "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.23.5.tgz" @@ -298,11 +291,6 @@ resolved "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.23.4.tgz" integrity sha512-803gmbQdqwdf4olxrX4AJyFBV/RTr3rSmOj0rKwesmzlfhYNDEs+/iOcznzpNWlJlIlTJC2QfPFcHB6DlzdVLQ== -"@babel/helper-validator-identifier@^7.18.6": - version "7.19.1" - resolved "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz" - integrity sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w== - "@babel/helper-validator-identifier@^7.22.20": version "7.22.20" resolved "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz" @@ -331,15 +319,6 @@ "@babel/traverse" "^7.24.1" "@babel/types" "^7.24.0" -"@babel/highlight@^7.10.4": - version "7.18.6" - resolved "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz" - integrity sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g== - dependencies: - "@babel/helper-validator-identifier" "^7.18.6" - chalk "^2.0.0" - js-tokens "^4.0.0" - "@babel/highlight@^7.23.4": version "7.23.4" resolved "https://registry.npmjs.org/@babel/highlight/-/highlight-7.23.4.tgz" @@ -1242,6 +1221,11 @@ "@babel/helper-validator-identifier" "^7.22.20" to-fast-properties "^2.0.0" +"@bazel/runfiles@^5.8.1": + version "5.8.1" + resolved "https://registry.yarnpkg.com/@bazel/runfiles/-/runfiles-5.8.1.tgz#737d5b3dc9739767054820265cfe432a80564c82" + integrity sha512-NDdfpdQ6rZlylgv++iMn5FkObC/QlBQvipinGLSOguTYpRywmieOyJ29XHvUilspwTFSILWpoE9CqMGkHXug1g== + "@cspotcode/source-map-support@^0.8.0": version "0.8.1" resolved "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz" @@ -1276,39 +1260,103 @@ glob "^7.1.6" minimatch "^3.0.4" -"@eslint/eslintrc@^0.4.3": - version "0.4.3" - resolved "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.4.3.tgz" - integrity sha512-J6KFFz5QCYUJq3pf0mjEcCJVERbzv71PUIDczuh9JkwGEzced6CO5ADLHB1rbf/+oPBtoPfMYNOpGDzCANlbXw== +"@eslint-community/eslint-utils@^4.2.0", "@eslint-community/eslint-utils@^4.4.0": + version "4.4.0" + resolved "https://registry.yarnpkg.com/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz#a23514e8fb9af1269d5f7788aa556798d61c6b59" + integrity sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA== + dependencies: + eslint-visitor-keys "^3.3.0" + +"@eslint-community/regexpp@^4.10.0", "@eslint-community/regexpp@^4.11.0": + version "4.11.1" + resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.11.1.tgz#a547badfc719eb3e5f4b556325e542fbe9d7a18f" + integrity sha512-m4DVN9ZqskZoLU5GlWZadwDnYo3vAEydiUayB9widCl9ffWx2IvPnp6n3on5rJmziJSw9Bv+Z3ChDVdMwXCY8Q== + +"@eslint/config-array@^0.18.0": + version "0.18.0" + resolved "https://registry.yarnpkg.com/@eslint/config-array/-/config-array-0.18.0.tgz#37d8fe656e0d5e3dbaea7758ea56540867fd074d" + integrity sha512-fTxvnS1sRMu3+JjXwJG0j/i4RT9u4qJ+lqS/yCGap4lH4zZGzQ7tu+xZqQmcMZq5OBZDL4QRxQzRjkWcGt8IVw== + dependencies: + "@eslint/object-schema" "^2.1.4" + debug "^4.3.1" + minimatch "^3.1.2" + +"@eslint/core@^0.6.0": + version "0.6.0" + resolved "https://registry.yarnpkg.com/@eslint/core/-/core-0.6.0.tgz#9930b5ba24c406d67a1760e94cdbac616a6eb674" + integrity sha512-8I2Q8ykA4J0x0o7cg67FPVnehcqWTBehu/lmY+bolPFHGjh49YzGBMXTvpqVgEbBdvNCSxj6iFgiIyHzf03lzg== + +"@eslint/eslintrc@^3.1.0": + version "3.1.0" + resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-3.1.0.tgz#dbd3482bfd91efa663cbe7aa1f506839868207b6" + integrity sha512-4Bfj15dVJdoy3RfZmmo86RK1Fwzn6SstsvK9JS+BaVKqC6QQQQyXekNaC+g+LKNgkQ+2VhGAzm6hO40AhMR3zQ== dependencies: ajv "^6.12.4" - debug "^4.1.1" - espree "^7.3.0" - globals "^13.9.0" - ignore "^4.0.6" + debug "^4.3.2" + espree "^10.0.1" + globals "^14.0.0" + ignore "^5.2.0" import-fresh "^3.2.1" - js-yaml "^3.13.1" - minimatch "^3.0.4" + js-yaml "^4.1.0" + minimatch "^3.1.2" strip-json-comments "^3.1.1" +"@eslint/js@9.12.0": + version "9.12.0" + resolved "https://registry.yarnpkg.com/@eslint/js/-/js-9.12.0.tgz#69ca3ca9fab9a808ec6d67b8f6edb156cbac91e1" + integrity sha512-eohesHH8WFRUprDNyEREgqP6beG6htMeUYeCpkEgBCieCMme5r9zFWjzAJp//9S+Kub4rqE+jXe9Cp1a7IYIIA== + +"@eslint/object-schema@^2.1.4": + version "2.1.4" + resolved "https://registry.yarnpkg.com/@eslint/object-schema/-/object-schema-2.1.4.tgz#9e69f8bb4031e11df79e03db09f9dbbae1740843" + integrity sha512-BsWiH1yFGjXXS2yvrf5LyuoSIIbPrGUWob917o+BTKuZ7qJdxX8aJLRxs1fS9n6r7vESrq1OUqb68dANcFXuQQ== + +"@eslint/plugin-kit@^0.2.0": + version "0.2.0" + resolved "https://registry.yarnpkg.com/@eslint/plugin-kit/-/plugin-kit-0.2.0.tgz#8712dccae365d24e9eeecb7b346f85e750ba343d" + integrity sha512-vH9PiIMMwvhCx31Af3HiGzsVNULDbyVkHXwlemn/B0TFj/00ho3y55efXrUZTfQipxoHC5u4xq6zblww1zm1Ig== + dependencies: + levn "^0.4.1" + "@gar/promisify@^1.0.1": version "1.1.3" resolved "https://registry.npmjs.org/@gar/promisify/-/promisify-1.1.3.tgz" integrity sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw== -"@humanwhocodes/config-array@^0.5.0": - version "0.5.0" - resolved "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.5.0.tgz" - integrity sha512-FagtKFz74XrTl7y6HCzQpwDfXP0yhxe9lHLD1UZxjvZIcbyRz8zTFF/yYNfSfzU414eDwZ1SrO0Qvtyf+wFMQg== +"@humanfs/core@^0.19.0": + version "0.19.0" + resolved "https://registry.yarnpkg.com/@humanfs/core/-/core-0.19.0.tgz#08db7a8c73bb07673d9ebd925f2dad746411fcec" + integrity sha512-2cbWIHbZVEweE853g8jymffCA+NCMiuqeECeBBLm8dg2oFdjuGJhgN4UAbI+6v0CKbbhvtXA4qV8YR5Ji86nmw== + +"@humanfs/node@^0.16.5": + version "0.16.5" + resolved "https://registry.yarnpkg.com/@humanfs/node/-/node-0.16.5.tgz#a9febb7e7ad2aff65890fdc630938f8d20aa84ba" + integrity sha512-KSPA4umqSG4LHYRodq31VDwKAvaTF4xmVlzM8Aeh4PlU1JQ3IG0wiA8C25d3RQ9nJyM3mBHyI53K06VVL/oFFg== dependencies: - "@humanwhocodes/object-schema" "^1.2.0" - debug "^4.1.1" - minimatch "^3.0.4" + "@humanfs/core" "^0.19.0" + "@humanwhocodes/retry" "^0.3.0" -"@humanwhocodes/object-schema@^1.2.0": - version "1.2.1" - resolved "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz" - integrity sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA== +"@humanwhocodes/module-importer@^1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz#af5b2691a22b44be847b0ca81641c5fb6ad0172c" + integrity sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA== + +"@humanwhocodes/retry@^0.3.0", "@humanwhocodes/retry@^0.3.1": + version "0.3.1" + resolved "https://registry.yarnpkg.com/@humanwhocodes/retry/-/retry-0.3.1.tgz#c72a5c76a9fbaf3488e231b13dc52c0da7bab42a" + integrity sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA== + +"@isaacs/cliui@^8.0.2": + version "8.0.2" + resolved "https://registry.yarnpkg.com/@isaacs/cliui/-/cliui-8.0.2.tgz#b37667b7bc181c168782259bab42474fbf52b550" + integrity sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA== + dependencies: + string-width "^5.1.2" + string-width-cjs "npm:string-width@^4.2.0" + strip-ansi "^7.0.1" + strip-ansi-cjs "npm:strip-ansi@^6.0.1" + wrap-ansi "^8.1.0" + wrap-ansi-cjs "npm:wrap-ansi@^7.0.0" "@jridgewell/gen-mapping@^0.3.0": version "0.3.3" @@ -1444,6 +1492,11 @@ mkdirp "^1.0.4" rimraf "^3.0.2" +"@pkgjs/parseargs@^0.11.0": + version "0.11.0" + resolved "https://registry.yarnpkg.com/@pkgjs/parseargs/-/parseargs-0.11.0.tgz#a77ea742fab25775145434eb1d2328cf5013ac33" + integrity sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg== + "@protobufjs/aspromise@^1.1.1", "@protobufjs/aspromise@^1.1.2": version "1.1.2" resolved "https://registry.yarnpkg.com/@protobufjs/aspromise/-/aspromise-1.1.2.tgz#9b8b0cc663d669a7d8f6f5d0893a14d348f30fbf" @@ -1497,6 +1550,45 @@ resolved "https://registry.yarnpkg.com/@protobufjs/utf8/-/utf8-1.1.0.tgz#a777360b5b39a1a2e5106f8e858f2fd2d060c570" integrity sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw== +"@redis/bloom@1.2.0": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@redis/bloom/-/bloom-1.2.0.tgz#d3fd6d3c0af3ef92f26767b56414a370c7b63b71" + integrity sha512-HG2DFjYKbpNmVXsa0keLHp/3leGJz1mjh09f2RLGGLQZzSHpkmZWuwJbAvo3QcRY8p80m5+ZdXZdYOSBLlp7Cg== + +"@redis/client@1.6.0": + version "1.6.0" + resolved "https://registry.yarnpkg.com/@redis/client/-/client-1.6.0.tgz#dcf4ae1319763db6fdddd6de7f0af68a352c30ea" + integrity sha512-aR0uffYI700OEEH4gYnitAnv3vzVGXCFvYfdpu/CJKvk4pHfLPEy/JSZyrpQ+15WhXe1yJRXLtfQ84s4mEXnPg== + dependencies: + cluster-key-slot "1.1.2" + generic-pool "3.9.0" + yallist "4.0.0" + +"@redis/graph@1.1.1": + version "1.1.1" + resolved "https://registry.yarnpkg.com/@redis/graph/-/graph-1.1.1.tgz#8c10df2df7f7d02741866751764031a957a170ea" + integrity sha512-FEMTcTHZozZciLRl6GiiIB4zGm5z5F3F6a6FZCyrfxdKOhFlGkiAqlexWMBzCi4DcRoyiOsuLfW+cjlGWyExOw== + +"@redis/json@1.0.7": + version "1.0.7" + resolved "https://registry.yarnpkg.com/@redis/json/-/json-1.0.7.tgz#016257fcd933c4cbcb9c49cde8a0961375c6893b" + integrity sha512-6UyXfjVaTBTJtKNG4/9Z8PSpKE6XgSyEb8iwaqDcy+uKrd/DGYHTWkUdnQDyzm727V7p21WUMhsqz5oy65kPcQ== + +"@redis/search@1.2.0": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@redis/search/-/search-1.2.0.tgz#50976fd3f31168f585666f7922dde111c74567b8" + integrity sha512-tYoDBbtqOVigEDMAcTGsRlMycIIjwMCgD8eR2t0NANeQmgK/lvxNAvYyb6bZDD4frHRhIHkJu2TBRvB0ERkOmw== + +"@redis/time-series@1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@redis/time-series/-/time-series-1.1.0.tgz#cba454c05ec201bd5547aaf55286d44682ac8eb5" + integrity sha512-c1Q99M5ljsIuc4YdaCwfUEXsofakb9c8+Zse2qxTadu8TalLXuAESzLvFAvNVbkmSlvlzIQOLpBCmWI9wTOt+g== + +"@rtsao/scc@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@rtsao/scc/-/scc-1.1.0.tgz#927dd2fae9bc3361403ac2c7a00c32ddce9ad7e8" + integrity sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g== + "@testim/chrome-version@^1.1.4": version "1.1.4" resolved "https://registry.npmjs.org/@testim/chrome-version/-/chrome-version-1.1.4.tgz" @@ -1532,27 +1624,27 @@ resolved "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz" integrity sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA== -"@types/archiver@^5.3.2": - version "5.3.2" - resolved "https://registry.npmjs.org/@types/archiver/-/archiver-5.3.2.tgz" - integrity sha512-IctHreBuWE5dvBDz/0WeKtyVKVRs4h75IblxOACL92wU66v+HGAfEYAOyXkOFphvRJMhuXdI9huDXpX0FC6lCw== +"@types/archiver@^6.0.2": + version "6.0.2" + resolved "https://registry.yarnpkg.com/@types/archiver/-/archiver-6.0.2.tgz#0daf8c83359cbde69de1e4b33dcade6a48a929e2" + integrity sha512-KmROQqbQzKGuaAbmK+ZcytkJ51+YqDa7NmbXjmtC5YBLSyQYo21YaUnQ3HbaPFKL1ooo6RQ6OPYPIDyxfpDDXw== dependencies: "@types/readdir-glob" "*" -"@types/chance@1.1.3": - version "1.1.3" - resolved "https://registry.npmjs.org/@types/chance/-/chance-1.1.3.tgz" - integrity sha512-X6c6ghhe4/sQh4XzcZWSFaTAUOda38GQHmq9BUanYkOE/EO7ZrkazwKmtsj3xzTjkLWmwULE++23g3d3CCWaWw== +"@types/chance@1.1.6": + version "1.1.6" + resolved "https://registry.yarnpkg.com/@types/chance/-/chance-1.1.6.tgz#2fe3de58742629602c3fbab468093b27207f04ad" + integrity sha512-V+pm3stv1Mvz8fSKJJod6CglNGVqEQ6OyuqitoDkWywEODM/eJd1eSuIp9xt6DrX8BWZ2eDSIzbw1tPCUTvGbQ== -"@types/cookiejar@*": - version "2.1.2" - resolved "https://registry.npmjs.org/@types/cookiejar/-/cookiejar-2.1.2.tgz" - integrity sha512-t73xJJrvdTjXrn4jLS9VSGRbz0nUY3cl2DMGDU48lKl+HR9dbbjW2A9r3g40VA++mQpy6uuHg33gy7du2BKpog== +"@types/cookiejar@^2.1.5": + version "2.1.5" + resolved "https://registry.yarnpkg.com/@types/cookiejar/-/cookiejar-2.1.5.tgz#14a3e83fa641beb169a2dd8422d91c3c345a9a78" + integrity sha512-he+DHOWReW0nghN24E1WUqM0efK4kI9oTqDm6XmK8ZPe2djZ90BSNdGnIyCLzCPw7/pogPlGbzI2wHGGmi4O/Q== -"@types/edit-json-file@1.7.0": - version "1.7.0" - resolved "https://registry.npmjs.org/@types/edit-json-file/-/edit-json-file-1.7.0.tgz" - integrity sha512-yZrbGD4Qp92s6xU80MWBdz9vJE8k8EbO+gLWYb4W1UL9WYVUMOtUr5zvKlKgbcc2veYmFLO9dPnYA9Mxul0lOw== +"@types/edit-json-file@1.7.3": + version "1.7.3" + resolved "https://registry.yarnpkg.com/@types/edit-json-file/-/edit-json-file-1.7.3.tgz#2b0c9fe362f52fee4c909b0fe0c45950a1f3da9f" + integrity sha512-88OYHTiVq7PNN50T+CIm+65Sl0aRweoXvTuTz4JhoQfy1FeK+wTCC9Peu1dljOqslRaqqSFlDee3wgkWMpxKHg== dependencies: "@types/node" "*" "@types/set-value" "*" @@ -1562,11 +1654,17 @@ resolved "https://registry.npmjs.org/@types/estree/-/estree-0.0.46.tgz" integrity sha512-laIjwTQaD+5DukBZaygQ79K1Z0jb1bPEMRrkXSLjtCcZm+abyp5YbrqpSLzD42FwWW6gK/aS4NYpJ804nG2brg== -"@types/fs-extra@9.0.11": - version "9.0.11" - resolved "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-9.0.11.tgz" - integrity sha512-mZsifGG4QeQ7hlkhO56u7zt/ycBgGxSVsFI/6lGTU34VtwkiqrrSDgw0+ygs8kFGWcXnFQWMrzF2h7TtDFNixA== +"@types/estree@^1.0.6": + version "1.0.6" + resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.6.tgz#628effeeae2064a1b4e79f78e81d87b7e5fc7b50" + integrity sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw== + +"@types/fs-extra@11.0.4": + version "11.0.4" + resolved "https://registry.yarnpkg.com/@types/fs-extra/-/fs-extra-11.0.4.tgz#e16a863bb8843fba8c5004362b5a73e17becca45" + integrity sha512-yTbItCNreRooED33qjunPthRcSjERP1r4MqCZc7wv0u2sUkzTFp45tgUfS5+r7FrZPdmCCNflLhVSP/o+SemsQ== dependencies: + "@types/jsonfile" "*" "@types/node" "*" "@types/glob@^7.1.1": @@ -1577,21 +1675,33 @@ "@types/minimatch" "*" "@types/node" "*" -"@types/json-schema@^7.0.7": - version "7.0.12" - resolved "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.12.tgz" - integrity sha512-Hr5Jfhc9eYOQNPYO5WLDq/n4jqijdHNlDXjuAQkkt+mWdQR+XJToOHrsD4cPaMXpn6KO7y2+wM8AZEs8VpBLVA== +"@types/json-schema@^7.0.15": + version "7.0.15" + resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.15.tgz#596a1747233694d50f6ad8a7869fcb6f56cf5841" + integrity sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA== "@types/json5@^0.0.29": version "0.0.29" resolved "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz" integrity sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ== +"@types/jsonfile@*": + version "6.1.4" + resolved "https://registry.yarnpkg.com/@types/jsonfile/-/jsonfile-6.1.4.tgz#614afec1a1164e7d670b4a7ad64df3e7beb7b702" + integrity sha512-D5qGUYwjvnNNextdU59/+fI+spnwtTFmyQP0h+PfIOSkNfpU6AOICUOkm4i0OnSk+NyjdPJrxCDro0sJsWlRpQ== + dependencies: + "@types/node" "*" + "@types/lodash@4.14.192", "@types/lodash@^4.14.72": version "4.14.192" resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.192.tgz#5790406361a2852d332d41635d927f1600811285" integrity sha512-km+Vyn3BYm5ytMO13k9KTp27O75rbQ0NFw+U//g+PX7VZyjCioXaRFisqSIJRECljcTv73G3i6BpglNGHgUQ5A== +"@types/methods@^1.1.4": + version "1.1.4" + resolved "https://registry.yarnpkg.com/@types/methods/-/methods-1.1.4.tgz#d3b7ac30ac47c91054ea951ce9eed07b1051e547" + integrity sha512-ymXWVrDiCxTBE3+RIrrP533E70eA+9qu7zdWoHuOmGujkYtzf4HQF96b8nwHLqhuf4ykX61IGRIB38CC6/sImQ== + "@types/minimatch@*": version "5.1.2" resolved "https://registry.npmjs.org/@types/minimatch/-/minimatch-5.1.2.tgz" @@ -1609,11 +1719,12 @@ dependencies: "@types/node" "*" -"@types/selenium-webdriver@^4.1.22": - version "4.1.22" - resolved "https://registry.npmjs.org/@types/selenium-webdriver/-/selenium-webdriver-4.1.22.tgz" - integrity sha512-MCL4l7q8dwxejr2Q2NXLyNwHWMPdlWE0Kpn6fFwJtvkJF7PTkG5jkvbH/X1IAAQxgt/L1dA8u2GtDeekvSKvOA== +"@types/selenium-webdriver@^4.1.26": + version "4.1.26" + resolved "https://registry.yarnpkg.com/@types/selenium-webdriver/-/selenium-webdriver-4.1.26.tgz#09c696a341cf8cfc1641cded11d14813350b6ca9" + integrity sha512-PUgqsyNffal0eAU0bzGlh37MJo558aporAPZoKqBeB/pF7zhKl1S3zqza0GpwFqgoigNxWhEIJzru75eeYco/w== dependencies: + "@types/node" "*" "@types/ws" "*" "@types/set-value@*": @@ -1621,27 +1732,30 @@ resolved "https://registry.npmjs.org/@types/set-value/-/set-value-4.0.1.tgz" integrity sha512-mP/CLy6pdrhsDVrz1+Yp5Ly6Tcel2IAEejhyI5NxY6WnBUdWN+AAfGa0HHsdgCdsPWWcd/4D5J2X2TrRYcYRag== -"@types/sqlite3@^3.1.8": - version "3.1.8" - resolved "https://registry.npmjs.org/@types/sqlite3/-/sqlite3-3.1.8.tgz" - integrity sha512-sQMt/qnyUWnqiTcJXm5ZfNPIBeJ/DVvJDwxw+0tAxPJvadzfiP1QhryO1JOR6t1yfb8NpzQb/Rud06mob5laIA== +"@types/sqlite3@^3.1.11": + version "3.1.11" + resolved "https://registry.yarnpkg.com/@types/sqlite3/-/sqlite3-3.1.11.tgz#845044b81585f1fcc143ee8d963ca5da63d0e768" + integrity sha512-KYF+QgxAnnAh7DWPdNDroxkDI3/MspH1NMx6m/N/6fT1G6+jvsw4/ZePt8R8cr7ta58aboeTfYFBDxTJ5yv15w== dependencies: "@types/node" "*" -"@types/superagent@*": - version "4.1.18" - resolved "https://registry.npmjs.org/@types/superagent/-/superagent-4.1.18.tgz" - integrity sha512-LOWgpacIV8GHhrsQU+QMZuomfqXiqzz3ILLkCtKx3Us6AmomFViuzKT9D693QTKgyut2oCytMG8/efOop+DB+w== +"@types/superagent@^8.1.0": + version "8.1.9" + resolved "https://registry.yarnpkg.com/@types/superagent/-/superagent-8.1.9.tgz#28bfe4658e469838ed0bf66d898354bcab21f49f" + integrity sha512-pTVjI73witn+9ILmoJdajHGW2jkSaOzhiFYF1Rd3EQ94kymLqB9PjD9ISg7WaALC7+dCHT0FGe9T2LktLq/3GQ== dependencies: - "@types/cookiejar" "*" + "@types/cookiejar" "^2.1.5" + "@types/methods" "^1.1.4" "@types/node" "*" + form-data "^4.0.0" -"@types/supertest@^2.0.8": - version "2.0.12" - resolved "https://registry.npmjs.org/@types/supertest/-/supertest-2.0.12.tgz" - integrity sha512-X3HPWTwXRerBZS7Mo1k6vMVR1Z6zmJcDVn5O/31whe0tnjE4te6ZJSJGq1RiqHPjzPdMTfjCFogDJmwng9xHaQ== +"@types/supertest@^6.0.2": + version "6.0.2" + resolved "https://registry.yarnpkg.com/@types/supertest/-/supertest-6.0.2.tgz#2af1c466456aaf82c7c6106c6b5cbd73a5e86588" + integrity sha512-137ypx2lk/wTQbW6An6safu9hXmajAifU/s7szAHLN/FeIm5w7yR0Wkl9fdJMRSHwOn4HLAI0DaB2TOORuhPDg== dependencies: - "@types/superagent" "*" + "@types/methods" "^1.1.4" + "@types/superagent" "^8.1.0" "@types/ws@*": version "8.5.10" @@ -1657,80 +1771,99 @@ dependencies: "@types/node" "*" -"@typescript-eslint/eslint-plugin@4.28.2": - version "4.28.2" - resolved "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.28.2.tgz" - integrity sha512-PGqpLLzHSxq956rzNGasO3GsAPf2lY9lDUBXhS++SKonglUmJypaUtcKzRtUte8CV7nruwnDxtLUKpVxs0wQBw== - dependencies: - "@typescript-eslint/experimental-utils" "4.28.2" - "@typescript-eslint/scope-manager" "4.28.2" - debug "^4.3.1" - functional-red-black-tree "^1.0.1" - regexpp "^3.1.0" - semver "^7.3.5" - tsutils "^3.21.0" - -"@typescript-eslint/experimental-utils@4.28.2": - version "4.28.2" - resolved "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-4.28.2.tgz" - integrity sha512-MwHPsL6qo98RC55IoWWP8/opTykjTp4JzfPu1VfO2Z0MshNP0UZ1GEV5rYSSnZSUI8VD7iHvtIPVGW5Nfh7klQ== - dependencies: - "@types/json-schema" "^7.0.7" - "@typescript-eslint/scope-manager" "4.28.2" - "@typescript-eslint/types" "4.28.2" - "@typescript-eslint/typescript-estree" "4.28.2" - eslint-scope "^5.1.1" - eslint-utils "^3.0.0" - -"@typescript-eslint/parser@4.28.2": - version "4.28.2" - resolved "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-4.28.2.tgz" - integrity sha512-Q0gSCN51eikAgFGY+gnd5p9bhhCUAl0ERMiDKrTzpSoMYRubdB8MJrTTR/BBii8z+iFwz8oihxd0RAdP4l8w8w== - dependencies: - "@typescript-eslint/scope-manager" "4.28.2" - "@typescript-eslint/types" "4.28.2" - "@typescript-eslint/typescript-estree" "4.28.2" - debug "^4.3.1" +"@typescript-eslint/eslint-plugin@8.9.0": + version "8.9.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.9.0.tgz#bf0b25305b0bf014b4b194a6919103d7ac2a7907" + integrity sha512-Y1n621OCy4m7/vTXNlCbMVp87zSd7NH0L9cXD8aIpOaNlzeWxIK4+Q19A68gSmTNRZn92UjocVUWDthGxtqHFg== + dependencies: + "@eslint-community/regexpp" "^4.10.0" + "@typescript-eslint/scope-manager" "8.9.0" + "@typescript-eslint/type-utils" "8.9.0" + "@typescript-eslint/utils" "8.9.0" + "@typescript-eslint/visitor-keys" "8.9.0" + graphemer "^1.4.0" + ignore "^5.3.1" + natural-compare "^1.4.0" + ts-api-utils "^1.3.0" -"@typescript-eslint/scope-manager@4.28.2": - version "4.28.2" - resolved "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-4.28.2.tgz" - integrity sha512-MqbypNjIkJFEFuOwPWNDjq0nqXAKZvDNNs9yNseoGBB1wYfz1G0WHC2AVOy4XD7di3KCcW3+nhZyN6zruqmp2A== +"@typescript-eslint/parser@8.9.0": + version "8.9.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-8.9.0.tgz#0cecda6def8aef95d7c7098359c0fda5a362d6ad" + integrity sha512-U+BLn2rqTTHnc4FL3FJjxaXptTxmf9sNftJK62XLz4+GxG3hLHm/SUNaaXP5Y4uTiuYoL5YLy4JBCJe3+t8awQ== dependencies: - "@typescript-eslint/types" "4.28.2" - "@typescript-eslint/visitor-keys" "4.28.2" + "@typescript-eslint/scope-manager" "8.9.0" + "@typescript-eslint/types" "8.9.0" + "@typescript-eslint/typescript-estree" "8.9.0" + "@typescript-eslint/visitor-keys" "8.9.0" + debug "^4.3.4" -"@typescript-eslint/types@4.28.2": - version "4.28.2" - resolved "https://registry.npmjs.org/@typescript-eslint/types/-/types-4.28.2.tgz" - integrity sha512-Gr15fuQVd93uD9zzxbApz3wf7ua3yk4ZujABZlZhaxxKY8ojo448u7XTm/+ETpy0V0dlMtj6t4VdDvdc0JmUhA== +"@typescript-eslint/scope-manager@8.9.0": + version "8.9.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-8.9.0.tgz#c98fef0c4a82a484e6a1eb610a55b154d14d46f3" + integrity sha512-bZu9bUud9ym1cabmOYH9S6TnbWRzpklVmwqICeOulTCZ9ue2/pczWzQvt/cGj2r2o1RdKoZbuEMalJJSYw3pHQ== + dependencies: + "@typescript-eslint/types" "8.9.0" + "@typescript-eslint/visitor-keys" "8.9.0" -"@typescript-eslint/typescript-estree@4.28.2": - version "4.28.2" - resolved "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-4.28.2.tgz" - integrity sha512-86lLstLvK6QjNZjMoYUBMMsULFw0hPHJlk1fzhAVoNjDBuPVxiwvGuPQq3fsBMCxuDJwmX87tM/AXoadhHRljg== +"@typescript-eslint/type-utils@8.9.0": + version "8.9.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-8.9.0.tgz#aa86da3e4555fe7c8b42ab75e13561c4b5a8dfeb" + integrity sha512-JD+/pCqlKqAk5961vxCluK+clkppHY07IbV3vett97KOV+8C6l+CPEPwpUuiMwgbOz/qrN3Ke4zzjqbT+ls+1Q== dependencies: - "@typescript-eslint/types" "4.28.2" - "@typescript-eslint/visitor-keys" "4.28.2" - debug "^4.3.1" - globby "^11.0.3" - is-glob "^4.0.1" - semver "^7.3.5" - tsutils "^3.21.0" + "@typescript-eslint/typescript-estree" "8.9.0" + "@typescript-eslint/utils" "8.9.0" + debug "^4.3.4" + ts-api-utils "^1.3.0" -"@typescript-eslint/visitor-keys@4.28.2": - version "4.28.2" - resolved "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-4.28.2.tgz" - integrity sha512-aT2B4PLyyRDUVUafXzpZFoc0C9t0za4BJAKP5sgWIhG+jHECQZUEjuQSCIwZdiJJ4w4cgu5r3Kh20SOdtEBl0w== +"@typescript-eslint/types@8.9.0": + version "8.9.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-8.9.0.tgz#b733af07fb340b32e962c6c63b1062aec2dc0fe6" + integrity sha512-SjgkvdYyt1FAPhU9c6FiYCXrldwYYlIQLkuc+LfAhCna6ggp96ACncdtlbn8FmnG72tUkXclrDExOpEYf1nfJQ== + +"@typescript-eslint/typescript-estree@8.9.0": + version "8.9.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-8.9.0.tgz#1714f167e9063062dc0df49c1d25afcbc7a96199" + integrity sha512-9iJYTgKLDG6+iqegehc5+EqE6sqaee7kb8vWpmHZ86EqwDjmlqNNHeqDVqb9duh+BY6WCNHfIGvuVU3Tf9Db0g== dependencies: - "@typescript-eslint/types" "4.28.2" - eslint-visitor-keys "^2.0.0" + "@typescript-eslint/types" "8.9.0" + "@typescript-eslint/visitor-keys" "8.9.0" + debug "^4.3.4" + fast-glob "^3.3.2" + is-glob "^4.0.3" + minimatch "^9.0.4" + semver "^7.6.0" + ts-api-utils "^1.3.0" + +"@typescript-eslint/utils@8.9.0": + version "8.9.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-8.9.0.tgz#748bbe3ea5bee526d9786d9405cf1b0df081c299" + integrity sha512-PKgMmaSo/Yg/F7kIZvrgrWa1+Vwn036CdNUvYFEkYbPwOH4i8xvkaRlu148W3vtheWK9ckKRIz7PBP5oUlkrvQ== + dependencies: + "@eslint-community/eslint-utils" "^4.4.0" + "@typescript-eslint/scope-manager" "8.9.0" + "@typescript-eslint/types" "8.9.0" + "@typescript-eslint/typescript-estree" "8.9.0" + +"@typescript-eslint/visitor-keys@8.9.0": + version "8.9.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-8.9.0.tgz#5f11f4d9db913f37da42776893ffe0dd1ae78f78" + integrity sha512-Ht4y38ubk4L5/U8xKUBfKNYGmvKvA1CANoxiTRMM+tOLk3lbF3DvzZCxJCRSE+2GdCMSh6zq9VZJc3asc1XuAA== + dependencies: + "@typescript-eslint/types" "8.9.0" + eslint-visitor-keys "^3.4.3" abbrev@1: version "1.1.1" resolved "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz" integrity sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q== +abort-controller@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/abort-controller/-/abort-controller-3.0.0.tgz#eaf54d53b62bae4138e809ca225c8439a6efb392" + integrity sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg== + dependencies: + event-target-shim "^5.0.0" + acorn-hammerhead@0.6.2: version "0.6.2" resolved "https://registry.npmjs.org/acorn-hammerhead/-/acorn-hammerhead-0.6.2.tgz" @@ -1738,9 +1871,9 @@ acorn-hammerhead@0.6.2: dependencies: "@types/estree" "0.0.46" -acorn-jsx@^5.3.1: +acorn-jsx@^5.3.2: version "5.3.2" - resolved "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz" + resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937" integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ== acorn-walk@^8.1.1: @@ -1748,10 +1881,10 @@ acorn-walk@^8.1.1: resolved "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz" integrity sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA== -acorn@^7.4.0: - version "7.4.1" - resolved "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz" - integrity sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A== +acorn@^8.12.0: + version "8.13.0" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.13.0.tgz#2a30d670818ad16ddd6a35d3842dacec9e5d7ca3" + integrity sha512-8zSiw54Oxrdym50NlZ9sUusyO1Z1ZchgRLWRaK6c86XJFClyCgFKetdowBg5bKxyp/u+CDBJG4Mpp0m3HLZl9w== acorn@^8.4.1: version "8.8.2" @@ -1792,7 +1925,7 @@ aggregate-error@^3.0.0: clean-stack "^2.0.0" indent-string "^4.0.0" -ajv@^6.10.0, ajv@^6.12.4: +ajv@^6.12.4: version "6.12.6" resolved "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz" integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== @@ -1802,21 +1935,6 @@ ajv@^6.10.0, ajv@^6.12.4: json-schema-traverse "^0.4.1" uri-js "^4.2.2" -ajv@^8.0.1: - version "8.12.0" - resolved "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz" - integrity sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA== - dependencies: - fast-deep-equal "^3.1.1" - json-schema-traverse "^1.0.0" - require-from-string "^2.0.2" - uri-js "^4.2.2" - -ansi-colors@^4.1.1: - version "4.1.3" - resolved "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz" - integrity sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw== - ansi-escapes@^4.3.2: version "4.3.2" resolved "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz" @@ -1829,6 +1947,11 @@ ansi-regex@^5.0.1: resolved "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz" integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== +ansi-regex@^6.0.1: + version "6.1.0" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-6.1.0.tgz#95ec409c69619d6cb1b8b34f14b660ef28ebd654" + integrity sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA== + ansi-styles@^3.2.1: version "3.2.1" resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz" @@ -1843,39 +1966,41 @@ ansi-styles@^4.0.0, ansi-styles@^4.1.0: dependencies: color-convert "^2.0.1" +ansi-styles@^6.1.0: + version "6.2.1" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-6.2.1.tgz#0e62320cf99c21afff3b3012192546aacbfb05c5" + integrity sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug== + "aproba@^1.0.3 || ^2.0.0": version "2.0.0" resolved "https://registry.npmjs.org/aproba/-/aproba-2.0.0.tgz" integrity sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ== -archiver-utils@^2.1.0: - version "2.1.0" - resolved "https://registry.npmjs.org/archiver-utils/-/archiver-utils-2.1.0.tgz" - integrity sha512-bEL/yUb/fNNiNTuUz979Z0Yg5L+LzLxGJz8x79lYmR54fmTIb6ob/hNQgkQnIUDWIFjZVQwl9Xs356I6BAMHfw== +archiver-utils@^5.0.0, archiver-utils@^5.0.2: + version "5.0.2" + resolved "https://registry.yarnpkg.com/archiver-utils/-/archiver-utils-5.0.2.tgz#63bc719d951803efc72cf961a56ef810760dd14d" + integrity sha512-wuLJMmIBQYCsGZgYLTy5FIB2pF6Lfb6cXMSF8Qywwk3t20zWnAi7zLcQFdKQmIB8wyZpY5ER38x08GbwtR2cLA== dependencies: - glob "^7.1.4" + glob "^10.0.0" graceful-fs "^4.2.0" + is-stream "^2.0.1" lazystream "^1.0.0" - lodash.defaults "^4.2.0" - lodash.difference "^4.5.0" - lodash.flatten "^4.4.0" - lodash.isplainobject "^4.0.6" - lodash.union "^4.6.0" + lodash "^4.17.15" normalize-path "^3.0.0" - readable-stream "^2.0.0" + readable-stream "^4.0.0" -archiver@^5.3.1: - version "5.3.1" - resolved "https://registry.npmjs.org/archiver/-/archiver-5.3.1.tgz" - integrity sha512-8KyabkmbYrH+9ibcTScQ1xCJC/CGcugdVIwB+53f5sZziXgwUh3iXlAlANMxcZyDEfTHMe6+Z5FofV8nopXP7w== +archiver@^7.0.1: + version "7.0.1" + resolved "https://registry.yarnpkg.com/archiver/-/archiver-7.0.1.tgz#c9d91c350362040b8927379c7aa69c0655122f61" + integrity sha512-ZcbTaIqJOfCc03QwD468Unz/5Ir8ATtvAHsK+FdXbDIbGfihqh9mrvdcYunQzqn4HrvWWaFyaxJhGZagaJJpPQ== dependencies: - archiver-utils "^2.1.0" - async "^3.2.3" - buffer-crc32 "^0.2.1" - readable-stream "^3.6.0" - readdir-glob "^1.0.0" - tar-stream "^2.2.0" - zip-stream "^4.1.0" + archiver-utils "^5.0.2" + async "^3.2.4" + buffer-crc32 "^1.0.0" + readable-stream "^4.0.0" + readdir-glob "^1.1.2" + tar-stream "^3.0.0" + zip-stream "^6.0.1" are-we-there-yet@^3.0.0: version "3.0.1" @@ -1890,40 +2015,34 @@ arg@^4.1.0: resolved "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz" integrity sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA== -argparse@^1.0.7: - version "1.0.10" - resolved "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz" - integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg== - dependencies: - sprintf-js "~1.0.2" - argparse@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38" integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q== -array-buffer-byte-length@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.0.tgz" - integrity sha512-LPuwb2P+NrQw3XhxGc36+XSvuBPopovXYTR9Ew++Du9Yb/bx5AzBfrIsBoj0EZUifjQU+sHL21sseZ3jerWO/A== +array-buffer-byte-length@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/array-buffer-byte-length/-/array-buffer-byte-length-1.0.1.tgz#1e5583ec16763540a27ae52eed99ff899223568f" + integrity sha512-ahC5W1xgou+KTXix4sAO8Ki12Q+jf4i0+tmk3sC+zgcynshkHxzpXdImBehiUYKKKDwvfFiJl1tZt6ewscS1Mg== dependencies: - call-bind "^1.0.2" - is-array-buffer "^3.0.1" + call-bind "^1.0.5" + is-array-buffer "^3.0.4" array-find@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/array-find/-/array-find-1.0.0.tgz" integrity sha512-kO/vVCacW9mnpn3WPWbTVlEnOabK2L7LWi2HViURtCM46y1zb6I8UMjx4LgbiqadTgHnLInUronwn3ampNTJtQ== -array-includes@^3.1.3: - version "3.1.6" - resolved "https://registry.npmjs.org/array-includes/-/array-includes-3.1.6.tgz" - integrity sha512-sgTbLvL6cNnw24FnbaDyjmvddQ2ML8arZsgaJhoABMoplz/4QRhtrYS+alr1BUM1Bwp6dhx8vVCBSLG+StwOFw== - dependencies: - call-bind "^1.0.2" - define-properties "^1.1.4" - es-abstract "^1.20.4" - get-intrinsic "^1.1.3" +array-includes@^3.1.8: + version "3.1.8" + resolved "https://registry.yarnpkg.com/array-includes/-/array-includes-3.1.8.tgz#5e370cbe172fdd5dd6530c1d4aadda25281ba97d" + integrity sha512-itaWrbYbqpGXkGhZPGUulwnhVf5Hpy1xiCFsGqyIGglbBxmG5vSjxQen3/WGOjPpNEv1RtBLKxbmVXm8HpJStQ== + dependencies: + call-bind "^1.0.7" + define-properties "^1.2.1" + es-abstract "^1.23.2" + es-object-atoms "^1.0.0" + get-intrinsic "^1.2.4" is-string "^1.0.7" array-union@^1.0.1: @@ -1943,16 +2062,57 @@ array-uniq@^1.0.1: resolved "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz" integrity sha512-MNha4BWQ6JbwhFhj03YK552f7cb3AzoE8SzeljgChvL1dl3IcvggXVz1DilzySZkCja+CXuZbdW7yATchWn8/Q== -array.prototype.flat@^1.2.4: - version "1.3.1" - resolved "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.1.tgz" - integrity sha512-roTU0KWIOmJ4DRLmwKd19Otg0/mT3qPNt0Qb3GWW8iObuZXxrjB/pzn0R3hqpRSWg4HCwqx+0vwOnWnvlOyeIA== +array.prototype.findlastindex@^1.2.5: + version "1.2.5" + resolved "https://registry.yarnpkg.com/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.5.tgz#8c35a755c72908719453f87145ca011e39334d0d" + integrity sha512-zfETvRFA8o7EiNn++N5f/kaCw221hrpGsDmcpndVupkPzEc1Wuf3VgC0qby1BbHs7f5DVYjgtEU2LLh5bqeGfQ== + dependencies: + call-bind "^1.0.7" + define-properties "^1.2.1" + es-abstract "^1.23.2" + es-errors "^1.3.0" + es-object-atoms "^1.0.0" + es-shim-unscopables "^1.0.2" + +array.prototype.flat@^1.3.2: + version "1.3.2" + resolved "https://registry.yarnpkg.com/array.prototype.flat/-/array.prototype.flat-1.3.2.tgz#1476217df8cff17d72ee8f3ba06738db5b387d18" + integrity sha512-djYB+Zx2vLewY8RWlNCUdHjDXs2XOgm602S9E7P/UpHgfeHL00cRiIF+IN/G/aUJ7kGPb6yO/ErDI5V2s8iycA== dependencies: call-bind "^1.0.2" - define-properties "^1.1.4" - es-abstract "^1.20.4" + define-properties "^1.2.0" + es-abstract "^1.22.1" + es-shim-unscopables "^1.0.0" + +array.prototype.flatmap@^1.3.2: + version "1.3.2" + resolved "https://registry.yarnpkg.com/array.prototype.flatmap/-/array.prototype.flatmap-1.3.2.tgz#c9a7c6831db8e719d6ce639190146c24bbd3e527" + integrity sha512-Ewyx0c9PmpcsByhSW4r+9zDU7sGjFc86qf/kKtuSCRdhfbk0SNLLkaT5qvcHnRGgc5NP/ly/y+qkXkqONX54CQ== + dependencies: + call-bind "^1.0.2" + define-properties "^1.2.0" + es-abstract "^1.22.1" es-shim-unscopables "^1.0.0" +arraybuffer.prototype.slice@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.3.tgz#097972f4255e41bc3425e37dc3f6421cf9aefde6" + integrity sha512-bMxMKAjg13EBSVscxTaYA4mRc5t1UAXa2kXiGTNfZ079HIWXEkKmkgFrh/nJqamaLSrXO5H4WFFkPEaLJWbs3A== + dependencies: + array-buffer-byte-length "^1.0.1" + call-bind "^1.0.5" + define-properties "^1.2.1" + es-abstract "^1.22.3" + es-errors "^1.2.1" + get-intrinsic "^1.2.3" + is-array-buffer "^3.0.4" + is-shared-array-buffer "^1.0.2" + +asap@^2.0.0: + version "2.0.6" + resolved "https://registry.yarnpkg.com/asap/-/asap-2.0.6.tgz#e50347611d7e690943208bbdafebcbc2fb866d46" + integrity sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA== + assertion-error@^1.1.0: version "1.1.0" resolved "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz" @@ -1965,11 +2125,6 @@ ast-types@^0.13.4: dependencies: tslib "^2.0.1" -astral-regex@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz" - integrity sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ== - async-exit-hook@^1.1.2: version "1.1.2" resolved "https://registry.npmjs.org/async-exit-hook/-/async-exit-hook-1.1.2.tgz" @@ -1985,39 +2140,37 @@ async@^3.2.0: resolved "https://registry.npmjs.org/async/-/async-3.2.5.tgz" integrity sha512-baNZyqaaLhyLVKm/DlvdW051MSgO6b8eVfIezl9E5PqWxFgzLm/wQntEW4zOytVburDEr0JlALEpdOFwvErLsg== -async@^3.2.3: - version "3.2.4" - resolved "https://registry.npmjs.org/async/-/async-3.2.4.tgz" - integrity sha512-iAB+JbDEGXhyIUavoDl9WP/Jj106Kz9DEn1DPgYw5ruDn0e3Wgi3sKFm55sASdGBNOQB8F59d9qQ7deqrHA8wQ== +async@^3.2.4: + version "3.2.6" + resolved "https://registry.yarnpkg.com/async/-/async-3.2.6.tgz#1b0728e14929d51b85b449b7f06e27c1145e38ce" + integrity sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA== asynckit@^0.4.0: version "0.4.0" resolved "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz" integrity sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q== -available-typed-arrays@^1.0.5: - version "1.0.5" - resolved "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz" - integrity sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw== - -axios@^1.6.0: - version "1.6.7" - resolved "https://registry.npmjs.org/axios/-/axios-1.6.7.tgz" - integrity sha512-/hDJGff6/c7u0hDkvkGxR/oy6CbCs8ziCsC7SqmhjfozqiJGc8Z11wrv9z9lYfY4K8l+H9TpjcMDX0xOZmx+RA== +available-typed-arrays@^1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz#a5cc375d6a03c2efc87a553f3e0b1522def14846" + integrity sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ== dependencies: - follow-redirects "^1.15.4" - form-data "^4.0.0" - proxy-from-env "^1.1.0" + possible-typed-array-names "^1.0.0" -axios@^1.6.7: - version "1.6.8" - resolved "https://registry.npmjs.org/axios/-/axios-1.6.8.tgz" - integrity sha512-v/ZHtJDU39mDpyBoFVkETcd/uNdxrWRrg3bKpOKzXFA6Bvqopts6ALSMU3y6ijYxbw2B+wPrIv46egTzJXCLGQ== +axios@^1.7.4, axios@^1.7.7: + version "1.7.7" + resolved "https://registry.yarnpkg.com/axios/-/axios-1.7.7.tgz#2f554296f9892a72ac8d8e4c5b79c14a91d0a47f" + integrity sha512-S4kL7XrjgBmvdGut0sN3yJxqYzrDOnivkBiN0OFs6hLiUam3UPvswUo0kqGyhqUZGEOytHyumEdXsAkgCOUf3Q== dependencies: follow-redirects "^1.15.6" form-data "^4.0.0" proxy-from-env "^1.1.0" +b4a@^1.6.4: + version "1.6.7" + resolved "https://registry.yarnpkg.com/b4a/-/b4a-1.6.7.tgz#a99587d4ebbfbd5a6e3b21bdb5d5fa385767abe4" + integrity sha512-OnAYlL5b7LEkALw87fUVafQw5rVR9RjwGd4KUwNQ6DrrNmaVaUCgLipfVlzrPQ4tWOR9P0IXGNOx50jYCCdSJg== + babel-plugin-module-resolver@5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/babel-plugin-module-resolver/-/babel-plugin-module-resolver-5.0.0.tgz#2b7fc176bd55da25f516abf96015617b4f70fc73" @@ -2078,6 +2231,11 @@ balanced-match@^1.0.0: resolved "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz" integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== +bare-events@^2.2.0: + version "2.5.0" + resolved "https://registry.yarnpkg.com/bare-events/-/bare-events-2.5.0.tgz#305b511e262ffd8b9d5616b056464f8e1b3329cc" + integrity sha512-/E8dDe9dsbLyh2qrZ64PEPadOQ0F4gbl1sUJOrmph7xOiIxfY8vwab/4bFLh4Y88/Hk/ujKcrQKc+ps0mv873A== + base-unicode@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/base-unicode/-/base-unicode-1.0.0.tgz#44b61fd4460b18f6d47ae6f5ea95a45b16a4885a" @@ -2174,7 +2332,12 @@ browserslist@^4.22.2, browserslist@^4.22.3, browserslist@^4.23.0: node-releases "^2.0.14" update-browserslist-db "^1.0.13" -buffer-crc32@^0.2.1, buffer-crc32@^0.2.13, buffer-crc32@~0.2.3: +buffer-crc32@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/buffer-crc32/-/buffer-crc32-1.0.0.tgz#a10993b9055081d55304bd9feb4a072de179f405" + integrity sha512-Db1SbgBS/fg/392AblrMJk97KggmvYhr4pB5ZIMTWtaivCPMWLkmb7m21cJvpvgK+J3nsU2CmmixNBZx4vFj/w== + +buffer-crc32@~0.2.3: version "0.2.13" resolved "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz" integrity sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ== @@ -2200,6 +2363,13 @@ buffer@^6.0.3: base64-js "^1.3.1" ieee754 "^1.2.1" +bundle-name@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/bundle-name/-/bundle-name-4.1.0.tgz#f3b96b34160d6431a19d7688135af7cfb8797889" + integrity sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q== + dependencies: + run-applescript "^7.0.0" + cacache@^15.2.0: version "15.3.0" resolved "https://registry.npmjs.org/cacache/-/cacache-15.3.0.tgz" @@ -2232,6 +2402,17 @@ call-bind@^1.0.0, call-bind@^1.0.2: function-bind "^1.1.1" get-intrinsic "^1.0.2" +call-bind@^1.0.5, call-bind@^1.0.6, call-bind@^1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.7.tgz#06016599c40c56498c18769d2730be242b6fa3b9" + integrity sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w== + dependencies: + es-define-property "^1.0.0" + es-errors "^1.3.0" + function-bind "^1.1.2" + get-intrinsic "^1.2.4" + set-function-length "^1.2.1" + callsite@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/callsite/-/callsite-1.0.0.tgz" @@ -2259,7 +2440,7 @@ chai@4.3.4: pathval "^1.1.1" type-detect "^4.0.5" -chalk@^2.0.0, chalk@^2.3.0, chalk@^2.4.0, chalk@^2.4.2: +chalk@^2.3.0, chalk@^2.4.0, chalk@^2.4.2: version "2.4.2" resolved "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz" integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== @@ -2276,10 +2457,10 @@ chalk@^4.0.0: ansi-styles "^4.1.0" supports-color "^7.1.0" -chance@1.1.8: - version "1.1.8" - resolved "https://registry.npmjs.org/chance/-/chance-1.1.8.tgz" - integrity sha512-v7fi5Hj2VbR6dJEGRWLmJBA83LJMS47pkAbmROFxHWd9qmE1esHRZW8Clf1Fhzr3rjxnNZVCjOEv/ivFxeIMtg== +chance@1.1.12: + version "1.1.12" + resolved "https://registry.yarnpkg.com/chance/-/chance-1.1.12.tgz#6a263cf241674af50a1b903357f9d328a6f252fb" + integrity sha512-vVBIGQVnwtUG+SYe0ge+3MvF78cvSpuCOEUJr7sVEk2vSBuMW6OXNJjSzdtzrlxNUEaoqH2GBd5Y/+18BEB01Q== check-error@^1.0.2: version "1.0.3" @@ -2314,13 +2495,13 @@ chrome-remote-interface@^0.32.2: commander "2.11.x" ws "^7.2.0" -chromedriver@^124.0.1: - version "124.0.1" - resolved "https://registry.npmjs.org/chromedriver/-/chromedriver-124.0.1.tgz" - integrity sha512-hxd1tpAUhgMFBZd1h3W7KyMckxofOYCuKAMtcvBDAU0YKKorZcWuq6zP06+Ph0Z1ynPjtgAj0hP9VphCwesjZw== +chromedriver@^130.0.0: + version "130.0.0" + resolved "https://registry.yarnpkg.com/chromedriver/-/chromedriver-130.0.0.tgz#a6251ebfc4aeaca9bc2f22cddc4fcf7a105c04b8" + integrity sha512-1g1eMoKF22Uh6l8DTFOPvWLovINPrkAMw7yDHlF6Rx+4W4JI9aGdCZ2Cx7c181hUgALU1oSKGH3uKNryYM5DaQ== dependencies: "@testim/chrome-version" "^1.1.4" - axios "^1.6.7" + axios "^1.7.4" compare-versions "^6.1.0" extract-zip "^2.0.1" proxy-agent "^6.4.0" @@ -2337,13 +2518,19 @@ clean-stack@^2.0.0: resolved "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz" integrity sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A== -cli-argument-parser@0.4.5: - version "0.4.5" - resolved "https://registry.npmjs.org/cli-argument-parser/-/cli-argument-parser-0.4.5.tgz" - integrity sha512-Uh7ONWH3qSPgmtzV+oQ1i697RwIA4jpo4NdcHwNzFg8HinBtmo1drPsRJVN068WJbr8j2loEhAyTUWm+bqi2jg== +cli-argument-parser@0.7.4: + version "0.7.4" + resolved "https://registry.yarnpkg.com/cli-argument-parser/-/cli-argument-parser-0.7.4.tgz#8538daa4b870c2817f0b36305371a722b716327b" + integrity sha512-23Qg4HABAHmIypZxUBVWnNFKdKZ3//zYSDwS3MUh4fWZ1dMRIZfDezcGPREVJhiWhSGEihPaEETCiuFa3/QAkw== dependencies: + dotenv "16.4.5" file-exists "5.0.1" +cluster-key-slot@1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/cluster-key-slot/-/cluster-key-slot-1.1.2.tgz#88ddaa46906e303b5de30d3153b7d9fe0a0c19ac" + integrity sha512-RMr0FhtfXemyinomL4hrWcYJxmX6deFdCxpJzhDttxgO1+bcCnkk+9drydLVDmAMG7NE6aN/fl4F7ucU/90gAA== + coffeescript@^2.3.1: version "2.7.0" resolved "https://registry.npmjs.org/coffeescript/-/coffeescript-2.7.0.tgz" @@ -2378,7 +2565,7 @@ color-support@^1.1.3: resolved "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz" integrity sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg== -combined-stream@^1.0.6, combined-stream@^1.0.8: +combined-stream@^1.0.8: version "1.0.8" resolved "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz" integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg== @@ -2405,20 +2592,21 @@ compare-versions@^6.1.0: resolved "https://registry.npmjs.org/compare-versions/-/compare-versions-6.1.0.tgz" integrity sha512-LNZQXhqUvqUTotpZ00qLSaify3b4VFD588aRr8MKFw4CMUr98ytzCW5wDH5qx/DEY5kCDXcbcRuCqL0szEf2tg== -component-emitter@^1.2.0: - version "1.3.0" - resolved "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz" - integrity sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg== +component-emitter@^1.3.0: + version "1.3.1" + resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.3.1.tgz#ef1d5796f7d93f135ee6fb684340b26403c97d17" + integrity sha512-T0+barUSQRTUQASh8bx02dl+DhF54GtIDY13Y3m9oWTklKbb3Wv974meRpeZ3lp1JpLVECWWNHC4vaG2XHXouQ== -compress-commons@^4.1.0: - version "4.1.1" - resolved "https://registry.npmjs.org/compress-commons/-/compress-commons-4.1.1.tgz" - integrity sha512-QLdDLCKNV2dtoTorqgxngQCMA+gWXkM/Nwu7FpeBhk/RdkzimqC3jueb/FDmaZeXh+uby1jkBqE3xArsLBE5wQ== +compress-commons@^6.0.2: + version "6.0.2" + resolved "https://registry.yarnpkg.com/compress-commons/-/compress-commons-6.0.2.tgz#26d31251a66b9d6ba23a84064ecd3a6a71d2609e" + integrity sha512-6FqVXeETqWPoGcfzrXb37E50NP0LXT8kAMu5ooZayhWWdgEY4lBEEcbQNXtkuKQsGduxiIcI4gOTsxTmuq/bSg== dependencies: - buffer-crc32 "^0.2.13" - crc32-stream "^4.0.2" + crc-32 "^1.2.0" + crc32-stream "^6.0.0" + is-stream "^2.0.1" normalize-path "^3.0.0" - readable-stream "^3.6.0" + readable-stream "^4.0.0" concat-map@0.0.1: version "0.0.1" @@ -2435,9 +2623,9 @@ convert-source-map@^2.0.0: resolved "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz" integrity sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg== -cookiejar@^2.1.0: +cookiejar@^2.1.4: version "2.1.4" - resolved "https://registry.npmjs.org/cookiejar/-/cookiejar-2.1.4.tgz" + resolved "https://registry.yarnpkg.com/cookiejar/-/cookiejar-2.1.4.tgz#ee669c1fea2cf42dc31585469d193fef0d65771b" integrity sha512-LDx6oHrK+PhzLKJU9j5S7/Y3jM/mUHvD/DeI1WQmJn652iPC5Y4TBzC9l+5OMOXlyTTA+SmVUPm0HQUwpD5Jqw== core-js-compat@^3.31.0: @@ -2464,13 +2652,13 @@ crc-32@^1.2.0: resolved "https://registry.npmjs.org/crc-32/-/crc-32-1.2.2.tgz" integrity sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ== -crc32-stream@^4.0.2: - version "4.0.2" - resolved "https://registry.npmjs.org/crc32-stream/-/crc32-stream-4.0.2.tgz" - integrity sha512-DxFZ/Hk473b/muq1VJ///PMNLj0ZMnzye9thBpmjpJKCc5eMgB95aK8zCGrGfQ90cWo561Te6HK9D+j4KPdM6w== +crc32-stream@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/crc32-stream/-/crc32-stream-6.0.0.tgz#8529a3868f8b27abb915f6c3617c0fadedbf9430" + integrity sha512-piICUB6ei4IlTv1+653yq5+KoqfBYmj9bw6LqXoOneTMDXk5nM1qt12mFW1caG3LlJXEKW1Bp0WggEmIfQB34g== dependencies: crc-32 "^1.2.0" - readable-stream "^3.4.0" + readable-stream "^4.0.0" create-require@^1.1.0: version "1.1.1" @@ -2503,7 +2691,34 @@ data-uri-to-buffer@^6.0.2: resolved "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-6.0.2.tgz" integrity sha512-7hvf7/GW8e86rW0ptuwS3OcBGDjIi6SZva7hCyWC0yYry2cOPmLIjXAUHI6DK2HsnwJd9ifmt57i8eV2n4YNpw== -debug@4, debug@^4.0.1, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.3, debug@^4.3.4: +data-view-buffer@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/data-view-buffer/-/data-view-buffer-1.0.1.tgz#8ea6326efec17a2e42620696e671d7d5a8bc66b2" + integrity sha512-0lht7OugA5x3iJLOWFhWK/5ehONdprk0ISXqVFn/NFrDu+cuc8iADFrGQz5BnRK7LLU3JmkbXSxaqX+/mXYtUA== + dependencies: + call-bind "^1.0.6" + es-errors "^1.3.0" + is-data-view "^1.0.1" + +data-view-byte-length@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/data-view-byte-length/-/data-view-byte-length-1.0.1.tgz#90721ca95ff280677eb793749fce1011347669e2" + integrity sha512-4J7wRJD3ABAzr8wP+OcIcqq2dlUKp4DVflx++hs5h5ZKydWMI6/D/fAot+yh6g2tHh8fLFTvNOaVN357NvSrOQ== + dependencies: + call-bind "^1.0.7" + es-errors "^1.3.0" + is-data-view "^1.0.1" + +data-view-byte-offset@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/data-view-byte-offset/-/data-view-byte-offset-1.0.0.tgz#5e0bbfb4828ed2d1b9b400cd8a7d119bca0ff18a" + integrity sha512-t/Ygsytq+R995EJ5PZlD4Cu56sWa8InXySaViRzw9apusqsOO2bQP+SbYzAhR0pFKoB+43lYy8rWban9JSuXnA== + dependencies: + call-bind "^1.0.6" + es-errors "^1.3.0" + is-data-view "^1.0.1" + +debug@4, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.3, debug@^4.3.4: version "4.3.4" resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== @@ -2517,20 +2732,20 @@ debug@4.3.1: dependencies: ms "2.1.2" -debug@^2.6.9: - version "2.6.9" - resolved "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz" - integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== - dependencies: - ms "2.0.0" - -debug@^3.1.0, debug@^3.2.7: +debug@^3.2.7: version "3.2.7" resolved "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz" integrity sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ== dependencies: ms "^2.1.1" +debug@^4.3.2: + version "4.3.7" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.7.tgz#87945b4151a011d76d95a198d7111c865c360a52" + integrity sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ== + dependencies: + ms "^2.1.3" + decompress-response@^6.0.0: version "6.0.0" resolved "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz" @@ -2570,12 +2785,34 @@ deep-is@^0.1.3: resolved "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz" integrity sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ== -define-lazy-prop@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz#3f7ae421129bcaaac9bc74905c98a0009ec9ee7f" - integrity sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og== +default-browser-id@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/default-browser-id/-/default-browser-id-5.0.0.tgz#a1d98bf960c15082d8a3fa69e83150ccccc3af26" + integrity sha512-A6p/pu/6fyBcA1TRz/GqWYPViplrftcW2gZC9q79ngNCKAeR/X3gcEdXQHl4KNXV+3wgIJ1CPkJQ3IHM6lcsyA== + +default-browser@^5.2.1: + version "5.2.1" + resolved "https://registry.yarnpkg.com/default-browser/-/default-browser-5.2.1.tgz#7b7ba61204ff3e425b556869ae6d3e9d9f1712cf" + integrity sha512-WY/3TUME0x3KPYdRRxEJJvXRHV4PyPoUsxtZa78lwItwRQRHhd2U9xOscaT/YTf8uCXIAjeJOFBVEh/7FtD8Xg== + dependencies: + bundle-name "^4.1.0" + default-browser-id "^5.0.0" + +define-data-property@^1.0.1, define-data-property@^1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/define-data-property/-/define-data-property-1.1.4.tgz#894dc141bb7d3060ae4366f6a0107e68fbe48c5e" + integrity sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A== + dependencies: + es-define-property "^1.0.0" + es-errors "^1.3.0" + gopd "^1.0.1" + +define-lazy-prop@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/define-lazy-prop/-/define-lazy-prop-3.0.0.tgz#dbb19adfb746d7fc6d734a06b72f4a00d021255f" + integrity sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg== -define-properties@^1.1.3, define-properties@^1.1.4, define-properties@^1.2.0: +define-properties@^1.1.3, define-properties@^1.2.0: version "1.2.0" resolved "https://registry.npmjs.org/define-properties/-/define-properties-1.2.0.tgz" integrity sha512-xvqAVKGfT1+UAvPwKTVw/njhdQ8ZhXK4lI0bCIuCMrp2up9nPnaDftrLtmpTazqd1o+UY4zgzU+avtMbDP+ldA== @@ -2583,6 +2820,15 @@ define-properties@^1.1.3, define-properties@^1.1.4, define-properties@^1.2.0: has-property-descriptors "^1.0.0" object-keys "^1.1.1" +define-properties@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.2.1.tgz#10781cc616eb951a80a034bafcaa7377f6af2b6c" + integrity sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg== + dependencies: + define-data-property "^1.0.1" + has-property-descriptors "^1.0.0" + object-keys "^1.1.1" + degenerator@^5.0.0: version "5.0.1" resolved "https://registry.npmjs.org/degenerator/-/degenerator-5.0.1.tgz" @@ -2628,11 +2874,6 @@ delegates@^1.0.0: resolved "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz" integrity sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ== -denque@^1.5.0: - version "1.5.1" - resolved "https://registry.npmjs.org/denque/-/denque-1.5.1.tgz" - integrity sha512-XwE+iZ4D6ZUB7mfYRMb5wByE8L74HCn30FBN7sWnXksWc1LO1bPDl67pBR9o/kC4z/xSNAwkMYcGgqDV3BE3Hw== - des.js@^1.0.1: version "1.1.0" resolved "https://registry.npmjs.org/des.js/-/des.js-1.1.0.tgz" @@ -2656,6 +2897,14 @@ device-specs@^1.0.0: resolved "https://registry.npmjs.org/device-specs/-/device-specs-1.0.1.tgz" integrity sha512-rxns/NDZfbdYumnn801z9uo8kWIz3Eld7Bk/F0V9zw4sZemSoD93+gxHEonLdxYulkws4iCMt7ZP8zuM8EzUSg== +dezalgo@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/dezalgo/-/dezalgo-1.0.4.tgz#751235260469084c132157dfa857f386d4c33d81" + integrity sha512-rXSP0bf+5n0Qonsb+SVVfNfIsimO4HEtmnIpPHY8Q1UCzKlQrDMfdobr8nJOOsRgWCyMRqeSBQzmWUMq7zvVig== + dependencies: + asap "^2.0.0" + wrappy "1" + diff@^4.0.1, diff@^4.0.2: version "4.0.2" resolved "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz" @@ -2675,42 +2924,40 @@ doctrine@^2.1.0: dependencies: esutils "^2.0.2" -doctrine@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz" - integrity sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w== - dependencies: - esutils "^2.0.2" - -dotenv-cli@^5.0.0: - version "5.1.0" - resolved "https://registry.npmjs.org/dotenv-cli/-/dotenv-cli-5.1.0.tgz" - integrity sha512-NoEZAlKo9WVrG0b3i9mBxdD6INdDuGqdgR74t68t8084QcI077/1MnPerRW1odl+9uULhcdnQp2U0pYVppKHOA== +dotenv-cli@^7.4.2: + version "7.4.2" + resolved "https://registry.yarnpkg.com/dotenv-cli/-/dotenv-cli-7.4.2.tgz#c158a818de08e1fbc51d310f628cbace9075b734" + integrity sha512-SbUj8l61zIbzyhIbg0FwPJq6+wjbzdn9oEtozQpZ6kW2ihCcapKVZj49oCT3oPM+mgQm+itgvUQcG5szxVrZTA== dependencies: cross-spawn "^7.0.3" - dotenv "^16.0.0" - dotenv-expand "^8.0.1" - minimist "^1.2.5" + dotenv "^16.3.0" + dotenv-expand "^10.0.0" + minimist "^1.2.6" -dotenv-expand@^8.0.1: - version "8.0.3" - resolved "https://registry.npmjs.org/dotenv-expand/-/dotenv-expand-8.0.3.tgz" - integrity sha512-SErOMvge0ZUyWd5B0NXMQlDkN+8r+HhVUsxgOO7IoPDOdDRD2JjExpN6y3KnFR66jsJMwSn1pqIivhU5rcJiNg== +dotenv-expand@^10.0.0: + version "10.0.0" + resolved "https://registry.yarnpkg.com/dotenv-expand/-/dotenv-expand-10.0.0.tgz#12605d00fb0af6d0a592e6558585784032e4ef37" + integrity sha512-GopVGCpVS1UKH75VKHGuQFqS1Gusej0z4FyQkPdwjil2gNIv+LNsqBlboOzpJFZKVT95GkCyWJbBSdFEFUWI2A== + +dotenv@16.4.5, dotenv@^16.3.0: + version "16.4.5" + resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-16.4.5.tgz#cdd3b3b604cb327e286b4762e13502f717cb099f" + integrity sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg== -dotenv@^16.0.0: - version "16.1.3" - resolved "https://registry.npmjs.org/dotenv/-/dotenv-16.1.3.tgz" - integrity sha512-FYssxsmCTtKL72fGBSvb1K9dRz0/VZeWqFme/vSb7r7323x4CRaHu4LvQ5JG3+s6yt2YPbBrkpiEODktfyjI9A== +eastasianwidth@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/eastasianwidth/-/eastasianwidth-0.2.0.tgz#696ce2ec0aa0e6ea93a397ffcf24aa7840c827cb" + integrity sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA== easy-stack@^1.0.1: version "1.0.1" resolved "https://registry.npmjs.org/easy-stack/-/easy-stack-1.0.1.tgz" integrity sha512-wK2sCs4feiiJeFXn3zvY0p41mdU5VUgbgs1rNsc/y5ngFUijdWd+iIN8eoyuZHKB8xN6BL4PdWmzqFmxNg6V2w== -edit-json-file@1.7.0: - version "1.7.0" - resolved "https://registry.npmjs.org/edit-json-file/-/edit-json-file-1.7.0.tgz" - integrity sha512-eIkLJ9i4ija7b2TbaLHy3scyjWFLzwM2Wa6kHbV4ppVLcCqn7FzqnO1vmCG3dLrkd+teWE3mvACfv166mO0VZg== +edit-json-file@1.8.0: + version "1.8.0" + resolved "https://registry.yarnpkg.com/edit-json-file/-/edit-json-file-1.8.0.tgz#2e4c6efa6410dbe1915a728c9328f99f340e7a93" + integrity sha512-IBOpbe2aQufNl5oZ4jsr2AmNVUy5bO7jS5hk0cCyWhOLdH59Xv41B3XQObE/JB89Ae5qDY9hVsq13/hgGhFBZg== dependencies: find-value "^1.0.12" iterate-object "^1.3.4" @@ -2743,6 +2990,11 @@ emoji-regex@^8.0.0: resolved "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz" integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== +emoji-regex@^9.2.2: + version "9.2.2" + resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-9.2.2.tgz#840c8803b0d8047f4ff0cf963176b32d4ef3ed72" + integrity sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg== + encoding@^0.1.12: version "0.1.13" resolved "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz" @@ -2765,13 +3017,6 @@ endpoint-utils@^1.0.2: ip "^1.1.3" pinkie-promise "^1.0.0" -enquirer@^2.3.5: - version "2.3.6" - resolved "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz" - integrity sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg== - dependencies: - ansi-colors "^4.1.1" - entities@^4.4.0: version "4.5.0" resolved "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz" @@ -2787,13 +3032,6 @@ err-code@^2.0.2: resolved "https://registry.npmjs.org/err-code/-/err-code-2.0.3.tgz" integrity sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA== -error-ex@^1.3.1: - version "1.3.2" - resolved "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz" - integrity sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g== - dependencies: - is-arrayish "^0.2.1" - error-stack-parser@^2.1.4: version "2.1.4" resolved "https://registry.npmjs.org/error-stack-parser/-/error-stack-parser-2.1.4.tgz" @@ -2801,54 +3039,85 @@ error-stack-parser@^2.1.4: dependencies: stackframe "^1.3.4" -es-abstract@^1.19.0, es-abstract@^1.20.4: - version "1.21.2" - resolved "https://registry.npmjs.org/es-abstract/-/es-abstract-1.21.2.tgz" - integrity sha512-y/B5POM2iBnIxCiernH1G7rC9qQoM77lLIMQLuob0zhp8C56Po81+2Nj0WFKnd0pNReDTnkYryc+zhOzpEIROg== - dependencies: - array-buffer-byte-length "^1.0.0" - available-typed-arrays "^1.0.5" - call-bind "^1.0.2" - es-set-tostringtag "^2.0.1" +es-abstract@^1.22.1, es-abstract@^1.22.3, es-abstract@^1.23.0, es-abstract@^1.23.2: + version "1.23.3" + resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.23.3.tgz#8f0c5a35cd215312573c5a27c87dfd6c881a0aa0" + integrity sha512-e+HfNH61Bj1X9/jLc5v1owaLYuHdeHHSQlkhCBiTK8rBvKaULl/beGMxwrMXjpYrv4pz22BlY570vVePA2ho4A== + dependencies: + array-buffer-byte-length "^1.0.1" + arraybuffer.prototype.slice "^1.0.3" + available-typed-arrays "^1.0.7" + call-bind "^1.0.7" + data-view-buffer "^1.0.1" + data-view-byte-length "^1.0.1" + data-view-byte-offset "^1.0.0" + es-define-property "^1.0.0" + es-errors "^1.3.0" + es-object-atoms "^1.0.0" + es-set-tostringtag "^2.0.3" es-to-primitive "^1.2.1" - function.prototype.name "^1.1.5" - get-intrinsic "^1.2.0" - get-symbol-description "^1.0.0" + function.prototype.name "^1.1.6" + get-intrinsic "^1.2.4" + get-symbol-description "^1.0.2" globalthis "^1.0.3" gopd "^1.0.1" - has "^1.0.3" - has-property-descriptors "^1.0.0" - has-proto "^1.0.1" + has-property-descriptors "^1.0.2" + has-proto "^1.0.3" has-symbols "^1.0.3" - internal-slot "^1.0.5" - is-array-buffer "^3.0.2" + hasown "^2.0.2" + internal-slot "^1.0.7" + is-array-buffer "^3.0.4" is-callable "^1.2.7" - is-negative-zero "^2.0.2" + is-data-view "^1.0.1" + is-negative-zero "^2.0.3" is-regex "^1.1.4" - is-shared-array-buffer "^1.0.2" + is-shared-array-buffer "^1.0.3" is-string "^1.0.7" - is-typed-array "^1.1.10" + is-typed-array "^1.1.13" is-weakref "^1.0.2" - object-inspect "^1.12.3" + object-inspect "^1.13.1" object-keys "^1.1.1" - object.assign "^4.1.4" - regexp.prototype.flags "^1.4.3" - safe-regex-test "^1.0.0" - string.prototype.trim "^1.2.7" - string.prototype.trimend "^1.0.6" - string.prototype.trimstart "^1.0.6" - typed-array-length "^1.0.4" + object.assign "^4.1.5" + regexp.prototype.flags "^1.5.2" + safe-array-concat "^1.1.2" + safe-regex-test "^1.0.3" + string.prototype.trim "^1.2.9" + string.prototype.trimend "^1.0.8" + string.prototype.trimstart "^1.0.8" + typed-array-buffer "^1.0.2" + typed-array-byte-length "^1.0.1" + typed-array-byte-offset "^1.0.2" + typed-array-length "^1.0.6" unbox-primitive "^1.0.2" - which-typed-array "^1.1.9" + which-typed-array "^1.1.15" -es-set-tostringtag@^2.0.1: - version "2.0.1" - resolved "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.1.tgz" - integrity sha512-g3OMbtlwY3QewlqAiMLI47KywjWZoEytKr8pf6iTC8uJq5bIAH52Z9pnQ8pVL6whrCto53JZDuUIsifGeLorTg== +es-define-property@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/es-define-property/-/es-define-property-1.0.0.tgz#c7faefbdff8b2696cf5f46921edfb77cc4ba3845" + integrity sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ== dependencies: - get-intrinsic "^1.1.3" - has "^1.0.3" - has-tostringtag "^1.0.0" + get-intrinsic "^1.2.4" + +es-errors@^1.2.1, es-errors@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/es-errors/-/es-errors-1.3.0.tgz#05f75a25dab98e4fb1dcd5e1472c0546d5057c8f" + integrity sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw== + +es-object-atoms@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/es-object-atoms/-/es-object-atoms-1.0.0.tgz#ddb55cd47ac2e240701260bc2a8e31ecb643d941" + integrity sha512-MZ4iQ6JwHOBQjahnjwaC1ZtIBH+2ohjamzAO3oaHcXYup7qxjF2fixyH+Q71voWHeOkI2q/TnJao/KfXYIZWbw== + dependencies: + es-errors "^1.3.0" + +es-set-tostringtag@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/es-set-tostringtag/-/es-set-tostringtag-2.0.3.tgz#8bb60f0a440c2e4281962428438d58545af39777" + integrity sha512-3T8uNMC3OQTHkFUsFq8r/BwAXLHvU/9O9mE0fBc/MY5iq/8H7ncvO947LmYA6ldWw9Uh8Yhf25zu6n7nML5QWQ== + dependencies: + get-intrinsic "^1.2.4" + has-tostringtag "^1.0.2" + hasown "^2.0.1" es-shim-unscopables@^1.0.0: version "1.0.0" @@ -2857,6 +3126,13 @@ es-shim-unscopables@^1.0.0: dependencies: has "^1.0.3" +es-shim-unscopables@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/es-shim-unscopables/-/es-shim-unscopables-1.0.2.tgz#1f6942e71ecc7835ed1c8a83006d8771a63a3763" + integrity sha512-J3yBRXCzDu4ULnQwxyToo/OjdMx6akgVC7K6few0a7F/0wLtmKKN7I73AH5T2836UuXRqN7Qg+IIUw/+YJksRw== + dependencies: + hasown "^2.0.0" + es-to-primitive@^1.2.1: version "1.2.1" resolved "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz" @@ -2892,120 +3168,105 @@ escodegen@^2.1.0: optionalDependencies: source-map "~0.6.1" -eslint-import-resolver-node@^0.3.6: - version "0.3.7" - resolved "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.7.tgz" - integrity sha512-gozW2blMLJCeFpBwugLTGyvVjNoeo1knonXAcatC6bjPBZitotxdWf7Gimr25N4c0AAOo4eOUfaG82IJPDpqCA== +eslint-import-resolver-node@^0.3.9: + version "0.3.9" + resolved "https://registry.yarnpkg.com/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.9.tgz#d4eaac52b8a2e7c3cd1903eb00f7e053356118ac" + integrity sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g== dependencies: debug "^3.2.7" - is-core-module "^2.11.0" - resolve "^1.22.1" + is-core-module "^2.13.0" + resolve "^1.22.4" -eslint-module-utils@^2.6.2: - version "2.8.0" - resolved "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.8.0.tgz" - integrity sha512-aWajIYfsqCKRDgUfjEXNN/JlrzauMuSEy5sbd7WXbtW3EH6A6MpwEh42c7qD+MqQo9QMJ6fWLAeIJynx0g6OAw== +eslint-module-utils@^2.12.0: + version "2.12.0" + resolved "https://registry.yarnpkg.com/eslint-module-utils/-/eslint-module-utils-2.12.0.tgz#fe4cfb948d61f49203d7b08871982b65b9af0b0b" + integrity sha512-wALZ0HFoytlyh/1+4wuZ9FJCD/leWHQzzrxJ8+rebyReSLk7LApMyd3WJaLVoN+D5+WIdJyDK1c6JnE65V4Zyg== dependencies: debug "^3.2.7" -eslint-plugin-import@2.24.2: - version "2.24.2" - resolved "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.24.2.tgz" - integrity sha512-hNVtyhiEtZmpsabL4neEj+6M5DCLgpYyG9nzJY8lZQeQXEn5UPW1DpUdsMHMXsq98dbNm7nt1w9ZMSVpfJdi8Q== +eslint-plugin-import@2.31.0: + version "2.31.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.31.0.tgz#310ce7e720ca1d9c0bb3f69adfd1c6bdd7d9e0e7" + integrity sha512-ixmkI62Rbc2/w8Vfxyh1jQRTdRTF52VxwRVHl/ykPAmqG+Nb7/kNn+byLP0LxPgI7zWA16Jt82SybJInmMia3A== dependencies: - array-includes "^3.1.3" - array.prototype.flat "^1.2.4" - debug "^2.6.9" + "@rtsao/scc" "^1.1.0" + array-includes "^3.1.8" + array.prototype.findlastindex "^1.2.5" + array.prototype.flat "^1.3.2" + array.prototype.flatmap "^1.3.2" + debug "^3.2.7" doctrine "^2.1.0" - eslint-import-resolver-node "^0.3.6" - eslint-module-utils "^2.6.2" - find-up "^2.0.0" - has "^1.0.3" - is-core-module "^2.6.0" - minimatch "^3.0.4" - object.values "^1.1.4" - pkg-up "^2.0.0" - read-pkg-up "^3.0.0" - resolve "^1.20.0" - tsconfig-paths "^3.11.0" + eslint-import-resolver-node "^0.3.9" + eslint-module-utils "^2.12.0" + hasown "^2.0.2" + is-core-module "^2.15.1" + is-glob "^4.0.3" + minimatch "^3.1.2" + object.fromentries "^2.0.8" + object.groupby "^1.0.3" + object.values "^1.2.0" + semver "^6.3.1" + string.prototype.trimend "^1.0.8" + tsconfig-paths "^3.15.0" -eslint-scope@^5.1.1: - version "5.1.1" - resolved "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz" - integrity sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw== +eslint-scope@^8.1.0: + version "8.1.0" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-8.1.0.tgz#70214a174d4cbffbc3e8a26911d8bf51b9ae9d30" + integrity sha512-14dSvlhaVhKKsa9Fx1l8A17s7ah7Ef7wCakJ10LYk6+GYmP9yDti2oq2SEwcyndt6knfcZyhyxwY3i9yL78EQw== dependencies: esrecurse "^4.3.0" - estraverse "^4.1.1" - -eslint-utils@^2.1.0: - version "2.1.0" - resolved "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz" - integrity sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg== - dependencies: - eslint-visitor-keys "^1.1.0" - -eslint-utils@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz" - integrity sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA== - dependencies: - eslint-visitor-keys "^2.0.0" + estraverse "^5.2.0" -eslint-visitor-keys@^1.1.0, eslint-visitor-keys@^1.3.0: - version "1.3.0" - resolved "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz" - integrity sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ== +eslint-visitor-keys@^3.3.0, eslint-visitor-keys@^3.4.3: + version "3.4.3" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz#0cd72fe8550e3c2eae156a96a4dddcd1c8ac5800" + integrity sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag== -eslint-visitor-keys@^2.0.0: - version "2.1.0" - resolved "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz" - integrity sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw== - -eslint@7.32.0: - version "7.32.0" - resolved "https://registry.npmjs.org/eslint/-/eslint-7.32.0.tgz" - integrity sha512-VHZ8gX+EDfz+97jGcgyGCyRia/dPOd6Xh9yPv8Bl1+SoaIwD+a/vlrOmGRUyOYu7MwUhc7CxqeaDZU13S4+EpA== - dependencies: - "@babel/code-frame" "7.12.11" - "@eslint/eslintrc" "^0.4.3" - "@humanwhocodes/config-array" "^0.5.0" - ajv "^6.10.0" +eslint-visitor-keys@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-4.1.0.tgz#1f785cc5e81eb7534523d85922248232077d2f8c" + integrity sha512-Q7lok0mqMUSf5a/AdAZkA5a/gHcO6snwQClVNNvFKCAVlxXucdU8pKydU5ZVZjBx5xr37vGbFFWtLQYreLzrZg== + +eslint@9.12.0: + version "9.12.0" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-9.12.0.tgz#54fcba2876c90528396da0fa44b6446329031e86" + integrity sha512-UVIOlTEWxwIopRL1wgSQYdnVDcEvs2wyaO6DGo5mXqe3r16IoCNWkR29iHhyaP4cICWjbgbmFUGAhh0GJRuGZw== + dependencies: + "@eslint-community/eslint-utils" "^4.2.0" + "@eslint-community/regexpp" "^4.11.0" + "@eslint/config-array" "^0.18.0" + "@eslint/core" "^0.6.0" + "@eslint/eslintrc" "^3.1.0" + "@eslint/js" "9.12.0" + "@eslint/plugin-kit" "^0.2.0" + "@humanfs/node" "^0.16.5" + "@humanwhocodes/module-importer" "^1.0.1" + "@humanwhocodes/retry" "^0.3.1" + "@types/estree" "^1.0.6" + "@types/json-schema" "^7.0.15" + ajv "^6.12.4" chalk "^4.0.0" cross-spawn "^7.0.2" - debug "^4.0.1" - doctrine "^3.0.0" - enquirer "^2.3.5" + debug "^4.3.2" escape-string-regexp "^4.0.0" - eslint-scope "^5.1.1" - eslint-utils "^2.1.0" - eslint-visitor-keys "^2.0.0" - espree "^7.3.1" - esquery "^1.4.0" + eslint-scope "^8.1.0" + eslint-visitor-keys "^4.1.0" + espree "^10.2.0" + esquery "^1.5.0" esutils "^2.0.2" fast-deep-equal "^3.1.3" - file-entry-cache "^6.0.1" - functional-red-black-tree "^1.0.1" - glob-parent "^5.1.2" - globals "^13.6.0" - ignore "^4.0.6" - import-fresh "^3.0.0" + file-entry-cache "^8.0.0" + find-up "^5.0.0" + glob-parent "^6.0.2" + ignore "^5.2.0" imurmurhash "^0.1.4" is-glob "^4.0.0" - js-yaml "^3.13.1" json-stable-stringify-without-jsonify "^1.0.1" - levn "^0.4.1" lodash.merge "^4.6.2" - minimatch "^3.0.4" + minimatch "^3.1.2" natural-compare "^1.4.0" - optionator "^0.9.1" - progress "^2.0.0" - regexpp "^3.1.0" - semver "^7.2.1" - strip-ansi "^6.0.0" - strip-json-comments "^3.1.0" - table "^6.0.9" + optionator "^0.9.3" text-table "^0.2.0" - v8-compile-cache "^2.0.3" esotope-hammerhead@0.6.8: version "0.6.8" @@ -3014,24 +3275,24 @@ esotope-hammerhead@0.6.8: dependencies: "@types/estree" "0.0.46" -espree@^7.3.0, espree@^7.3.1: - version "7.3.1" - resolved "https://registry.npmjs.org/espree/-/espree-7.3.1.tgz" - integrity sha512-v3JCNCE64umkFpmkFGqzVKsOT0tN1Zr+ueqLZfpV1Ob8e+CEgPWa+OxCoGH3tnhimMKIaBm4m/vaRpJ/krRz2g== +espree@^10.0.1, espree@^10.2.0: + version "10.2.0" + resolved "https://registry.yarnpkg.com/espree/-/espree-10.2.0.tgz#f4bcead9e05b0615c968e85f83816bc386a45df6" + integrity sha512-upbkBJbckcCNBDBDXEbuhjbP68n+scUd3k/U2EkyM9nw+I/jPiL4cLF/Al06CF96wRltFda16sxDFrxsI1v0/g== dependencies: - acorn "^7.4.0" - acorn-jsx "^5.3.1" - eslint-visitor-keys "^1.3.0" + acorn "^8.12.0" + acorn-jsx "^5.3.2" + eslint-visitor-keys "^4.1.0" -esprima@^4.0.0, esprima@^4.0.1: +esprima@^4.0.1: version "4.0.1" resolved "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz" integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== -esquery@^1.4.0: - version "1.5.0" - resolved "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz" - integrity sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg== +esquery@^1.5.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.6.0.tgz#91419234f804d852a82dceec3e16cdc22cf9dae7" + integrity sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg== dependencies: estraverse "^5.1.0" @@ -3042,11 +3303,6 @@ esrecurse@^4.3.0: dependencies: estraverse "^5.2.0" -estraverse@^4.1.1: - version "4.3.0" - resolved "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz" - integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw== - estraverse@^5.1.0, estraverse@^5.2.0: version "5.3.0" resolved "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz" @@ -3062,6 +3318,16 @@ event-pubsub@4.3.0: resolved "https://registry.npmjs.org/event-pubsub/-/event-pubsub-4.3.0.tgz" integrity sha512-z7IyloorXvKbFx9Bpie2+vMJKKx1fH1EN5yiTfp8CiLOTptSYy1g8H4yDpGlEdshL1PBiFtBHepF2cNsqeEeFQ== +event-target-shim@^5.0.0: + version "5.0.1" + resolved "https://registry.yarnpkg.com/event-target-shim/-/event-target-shim-5.0.1.tgz#5d4d3ebdf9583d63a5333ce2deb7480ab2b05789" + integrity sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ== + +events@^3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/events/-/events-3.3.0.tgz#31a95ad0a924e2d2c419a813aeb2c4e878ea7400" + integrity sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q== + execa@^3.3.0: version "3.4.0" resolved "https://registry.npmjs.org/execa/-/execa-3.4.0.tgz" @@ -3113,11 +3379,6 @@ expand-template@^2.0.3: resolved "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz" integrity sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg== -extend@^3.0.0: - version "3.0.2" - resolved "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz" - integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g== - extract-zip@^2.0.1: version "2.0.1" resolved "https://registry.npmjs.org/extract-zip/-/extract-zip-2.0.1.tgz" @@ -3134,9 +3395,14 @@ fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3: resolved "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz" integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== -fast-glob@^3.0.3: +fast-fifo@^1.2.0, fast-fifo@^1.3.2: + version "1.3.2" + resolved "https://registry.yarnpkg.com/fast-fifo/-/fast-fifo-1.3.2.tgz#286e31de96eb96d38a97899815740ba2a4f3640c" + integrity sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ== + +fast-glob@^3.0.3, fast-glob@^3.3.2: version "3.3.2" - resolved "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz" + resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.3.2.tgz#a904501e57cfdd2ffcded45e99a54fef55e46129" integrity sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow== dependencies: "@nodelib/fs.stat" "^2.0.2" @@ -3166,6 +3432,11 @@ fast-levenshtein@^2.0.6: resolved "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz" integrity sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw== +fast-safe-stringify@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz#c406a83b6e70d9e35ce3b30a81141df30aeba884" + integrity sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA== + fastq@^1.6.0: version "1.15.0" resolved "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz" @@ -3185,12 +3456,12 @@ fflate@^0.8.2: resolved "https://registry.yarnpkg.com/fflate/-/fflate-0.8.2.tgz#fc8631f5347812ad6028bbe4a2308b2792aa1dea" integrity sha512-cPJU47OaAoCbg0pBvzsgpTPhmhqI5eJjh/JIu8tPj5q+T7iLvW/JAYUqmE7KOB4R1ZyEhzBaIQpQpardBF5z8A== -file-entry-cache@^6.0.1: - version "6.0.1" - resolved "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz" - integrity sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg== +file-entry-cache@^8.0.0: + version "8.0.0" + resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-8.0.0.tgz#7787bddcf1131bffb92636c69457bbc0edd6d81f" + integrity sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ== dependencies: - flat-cache "^3.0.4" + flat-cache "^4.0.0" file-exists@5.0.1: version "5.0.1" @@ -3225,13 +3496,6 @@ find-babel-config@^2.0.0: json5 "^2.2.3" path-exists "^4.0.0" -find-up@^2.0.0, find-up@^2.1.0: - version "2.1.0" - resolved "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz" - integrity sha512-NWzkk0jSJtTt08+FBFMvXoeZnOJD+jTtsRmBYbAIzJdX6l7dLgR7CTubCM5/eDdPUBvLCeVasP1brfVR/9/EZQ== - dependencies: - locate-path "^2.0.0" - find-up@^3.0.0: version "3.0.0" resolved "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz" @@ -3239,28 +3503,31 @@ find-up@^3.0.0: dependencies: locate-path "^3.0.0" +find-up@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-5.0.0.tgz#4c92819ecb7083561e4f4a240a86be5198f536fc" + integrity sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng== + dependencies: + locate-path "^6.0.0" + path-exists "^4.0.0" + find-value@^1.0.12: version "1.0.12" resolved "https://registry.npmjs.org/find-value/-/find-value-1.0.12.tgz" integrity sha512-OCpo8LTk8eZ2sdDCwbU2Lc3ivYsdM6yod6jP2jHcNEFcjPhkgH0+POzTIol7xx1LZgtbI5rkO5jqxsG5MWtPjQ== -flat-cache@^3.0.4: - version "3.0.4" - resolved "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz" - integrity sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg== +flat-cache@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-4.0.1.tgz#0ece39fcb14ee012f4b0410bd33dd9c1f011127c" + integrity sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw== dependencies: - flatted "^3.1.0" - rimraf "^3.0.2" + flatted "^3.2.9" + keyv "^4.5.4" -flatted@^3.1.0: - version "3.2.7" - resolved "https://registry.npmjs.org/flatted/-/flatted-3.2.7.tgz" - integrity sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ== - -follow-redirects@^1.15.4: - version "1.15.5" - resolved "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.5.tgz" - integrity sha512-vSFWUON1B+yAw1VN4xMfxgn5fTUiaOzAJCKBwIIgT/+7CuGy9+r+5gITvP62j3RmaD5Ph65UaERdOSRGUzZtgw== +flatted@^3.2.9: + version "3.3.1" + resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.3.1.tgz#21db470729a6734d4997002f439cb308987f567a" + integrity sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw== follow-redirects@^1.15.6: version "1.15.6" @@ -3274,14 +3541,13 @@ for-each@^0.3.3: dependencies: is-callable "^1.1.3" -form-data@^2.3.1: - version "2.5.1" - resolved "https://registry.npmjs.org/form-data/-/form-data-2.5.1.tgz" - integrity sha512-m21N3WOmEEURgk6B9GLOE4RuWOFf28Lhh9qGYeNlGq4VDXUlJy2th2slBNU8Gp8EzloYZOibZJ7t5ecIrFSjVA== +foreground-child@^3.1.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/foreground-child/-/foreground-child-3.3.0.tgz#0ac8644c06e431439f8561db8ecf29a7b5519c77" + integrity sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg== dependencies: - asynckit "^0.4.0" - combined-stream "^1.0.6" - mime-types "^2.1.12" + cross-spawn "^7.0.0" + signal-exit "^4.0.1" form-data@^4.0.0: version "4.0.0" @@ -3292,10 +3558,14 @@ form-data@^4.0.0: combined-stream "^1.0.8" mime-types "^2.1.12" -formidable@^1.2.0: - version "1.2.6" - resolved "https://registry.npmjs.org/formidable/-/formidable-1.2.6.tgz" - integrity sha512-KcpbcpuLNOwrEjnbpMC0gS+X8ciDoZE1kkqzat4a8vrprf+s9pKNQ/QIwWfbfs4ltgmFl3MD177SNTkve3BwGQ== +formidable@^3.5.1: + version "3.5.1" + resolved "https://registry.yarnpkg.com/formidable/-/formidable-3.5.1.tgz#9360a23a656f261207868b1484624c4c8d06ee1a" + integrity sha512-WJWKelbRHN41m5dumb0/k8TeAx7Id/y3a+Z7QfhxP/htI9Js5zYaEDtG8uMgG0vM0lOlqnmjE99/kfpOYi/0Og== + dependencies: + dezalgo "^1.0.4" + hexoid "^1.0.0" + once "^1.4.0" fs-constants@^1.0.0: version "1.0.0" @@ -3342,22 +3612,17 @@ function-bind@^1.1.2: resolved "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz" integrity sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA== -function.prototype.name@^1.1.5: - version "1.1.5" - resolved "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.5.tgz" - integrity sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA== +function.prototype.name@^1.1.6: + version "1.1.6" + resolved "https://registry.yarnpkg.com/function.prototype.name/-/function.prototype.name-1.1.6.tgz#cdf315b7d90ee77a4c6ee216c3c3362da07533fd" + integrity sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg== dependencies: call-bind "^1.0.2" - define-properties "^1.1.3" - es-abstract "^1.19.0" - functions-have-names "^1.2.2" - -functional-red-black-tree@^1.0.1: - version "1.0.1" - resolved "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz" - integrity sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g== + define-properties "^1.2.0" + es-abstract "^1.22.1" + functions-have-names "^1.2.3" -functions-have-names@^1.2.2, functions-have-names@^1.2.3: +functions-have-names@^1.2.3: version "1.2.3" resolved "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz" integrity sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ== @@ -3376,6 +3641,11 @@ gauge@^4.0.3: strip-ansi "^6.0.1" wide-align "^1.1.5" +generic-pool@3.9.0: + version "3.9.0" + resolved "https://registry.yarnpkg.com/generic-pool/-/generic-pool-3.9.0.tgz#36f4a678e963f4fdb8707eab050823abc4e8f5e4" + integrity sha512-hymDOu5B53XvN4QT9dBmZxPX4CWhBPPLguTZ9MMFeFa/Kg0xWVfylOVNlJji/E7yTZWFd/q9GO5TxDLq156D7g== + gensync@^1.0.0-beta.2: version "1.0.0-beta.2" resolved "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz" @@ -3386,7 +3656,7 @@ get-func-name@^2.0.0, get-func-name@^2.0.2: resolved "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.2.tgz" integrity sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ== -get-intrinsic@^1.0.2, get-intrinsic@^1.1.1, get-intrinsic@^1.1.3, get-intrinsic@^1.2.0: +get-intrinsic@^1.0.2, get-intrinsic@^1.1.1, get-intrinsic@^1.1.3: version "1.2.1" resolved "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.1.tgz" integrity sha512-2DcsyfABl+gVHEfCOaTrWgyt+tb6MSEGmKq+kI5HwLbIYgjgmMcV8KQ41uaKz1xxUcn9tJtgFbQUEVcEbd0FYw== @@ -3396,6 +3666,17 @@ get-intrinsic@^1.0.2, get-intrinsic@^1.1.1, get-intrinsic@^1.1.3, get-intrinsic@ has-proto "^1.0.1" has-symbols "^1.0.3" +get-intrinsic@^1.2.1, get-intrinsic@^1.2.3, get-intrinsic@^1.2.4: + version "1.2.4" + resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.2.4.tgz#e385f5a4b5227d449c3eabbad05494ef0abbeadd" + integrity sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ== + dependencies: + es-errors "^1.3.0" + function-bind "^1.1.2" + has-proto "^1.0.1" + has-symbols "^1.0.3" + hasown "^2.0.0" + get-os-info@^1.0.2: version "1.0.2" resolved "https://registry.npmjs.org/get-os-info/-/get-os-info-1.0.2.tgz" @@ -3423,13 +3704,14 @@ get-stream@^6.0.0: resolved "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz" integrity sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg== -get-symbol-description@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz" - integrity sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw== +get-symbol-description@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/get-symbol-description/-/get-symbol-description-1.0.2.tgz#533744d5aa20aca4e079c8e5daf7fd44202821f5" + integrity sha512-g0QYk1dZBxGwk+Ngc+ltRH2IBp2f7zBkBMBJZCDerh6EhlhSR6+9irMCuT/09zD6qkarHUSn529sK/yL4S27mg== dependencies: - call-bind "^1.0.2" - get-intrinsic "^1.1.1" + call-bind "^1.0.5" + es-errors "^1.3.0" + get-intrinsic "^1.2.4" get-uri@^6.0.1: version "6.0.3" @@ -3460,6 +3742,25 @@ glob-parent@^5.1.2: dependencies: is-glob "^4.0.1" +glob-parent@^6.0.2: + version "6.0.2" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-6.0.2.tgz#6d237d99083950c79290f24c7642a3de9a28f9e3" + integrity sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A== + dependencies: + is-glob "^4.0.3" + +glob@^10.0.0: + version "10.4.5" + resolved "https://registry.yarnpkg.com/glob/-/glob-10.4.5.tgz#f4d9f0b90ffdbab09c9d77f5f29b4262517b0956" + integrity sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg== + dependencies: + foreground-child "^3.1.0" + jackspeak "^3.1.2" + minimatch "^9.0.4" + minipass "^7.1.2" + package-json-from-dist "^1.0.0" + path-scurry "^1.11.1" + glob@^7.0.3, glob@^7.1.3, glob@^7.1.4, glob@^7.1.6: version "7.2.3" resolved "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz" @@ -3488,12 +3789,10 @@ globals@^11.1.0: resolved "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz" integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== -globals@^13.6.0, globals@^13.9.0: - version "13.20.0" - resolved "https://registry.npmjs.org/globals/-/globals-13.20.0.tgz" - integrity sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ== - dependencies: - type-fest "^0.20.2" +globals@^14.0.0: + version "14.0.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-14.0.0.tgz#898d7413c29babcf6bafe56fcadded858ada724e" + integrity sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ== globalthis@^1.0.3: version "1.0.3" @@ -3516,7 +3815,7 @@ globby@^10.0.1: merge2 "^1.2.3" slash "^3.0.0" -globby@^11.0.3, globby@^11.0.4: +globby@^11.0.4: version "11.1.0" resolved "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz" integrity sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g== @@ -3546,11 +3845,16 @@ gopd@^1.0.1: dependencies: get-intrinsic "^1.1.3" -graceful-fs@^4.1.11, graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.2, graceful-fs@^4.2.6: +graceful-fs@^4.1.11, graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.2, graceful-fs@^4.2.6: version "4.2.11" resolved "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz" integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ== +graphemer@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/graphemer/-/graphemer-1.4.0.tgz#fb2f1d55e0e3a1849aeffc90c4fa0dd53a0e66c6" + integrity sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag== + graphlib@^2.1.5: version "2.1.8" resolved "https://registry.npmjs.org/graphlib/-/graphlib-2.1.8.tgz" @@ -3580,11 +3884,23 @@ has-property-descriptors@^1.0.0: dependencies: get-intrinsic "^1.1.1" +has-property-descriptors@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz#963ed7d071dc7bf5f084c5bfbe0d1b6222586854" + integrity sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg== + dependencies: + es-define-property "^1.0.0" + has-proto@^1.0.1: version "1.0.1" resolved "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz" integrity sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg== +has-proto@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/has-proto/-/has-proto-1.0.3.tgz#b31ddfe9b0e6e9914536a6ab286426d0214f77fd" + integrity sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q== + has-symbols@^1.0.2, has-symbols@^1.0.3: version "1.0.3" resolved "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz" @@ -3597,6 +3913,13 @@ has-tostringtag@^1.0.0: dependencies: has-symbols "^1.0.2" +has-tostringtag@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/has-tostringtag/-/has-tostringtag-1.0.2.tgz#2cdc42d40bef2e5b4eeab7c01a73c54ce7ab5abc" + integrity sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw== + dependencies: + has-symbols "^1.0.3" + has-unicode@^2.0.1: version "2.0.1" resolved "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz" @@ -3616,6 +3939,18 @@ hasown@^2.0.0: dependencies: function-bind "^1.1.2" +hasown@^2.0.1, hasown@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/hasown/-/hasown-2.0.2.tgz#003eaf91be7adc372e84ec59dc37252cedb80003" + integrity sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ== + dependencies: + function-bind "^1.1.2" + +hexoid@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/hexoid/-/hexoid-1.0.0.tgz#ad10c6573fb907de23d9ec63a711267d9dc9bc18" + integrity sha512-QFLV0taWQOZtvIRIAdBChesmogZrtuXvVWsFHZTk2SU+anspqZ2vMnoLg7IE1+Uk16N19APic1BuF8bC8c2m5g== + highlight-es@^1.0.0: version "1.0.3" resolved "https://registry.npmjs.org/highlight-es/-/highlight-es-1.0.3.tgz" @@ -3625,11 +3960,6 @@ highlight-es@^1.0.0: is-es2016-keyword "^1.0.0" js-tokens "^3.0.0" -hosted-git-info@^2.1.4: - version "2.8.9" - resolved "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz" - integrity sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw== - http-cache-semantics@^4.1.0: version "4.1.1" resolved "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz" @@ -3729,11 +4059,6 @@ ieee754@^1.1.13, ieee754@^1.2.1: resolved "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz" integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA== -ignore@^4.0.6: - version "4.0.6" - resolved "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz" - integrity sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg== - ignore@^5.1.1: version "5.3.1" resolved "https://registry.npmjs.org/ignore/-/ignore-5.3.1.tgz" @@ -3744,12 +4069,17 @@ ignore@^5.2.0: resolved "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz" integrity sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ== +ignore@^5.3.1: + version "5.3.2" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.3.2.tgz#3cd40e729f3643fd87cb04e50bf0eb722bc596f5" + integrity sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g== + immediate@~3.0.5: version "3.0.6" resolved "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz" integrity sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ== -import-fresh@^3.0.0, import-fresh@^3.2.1: +import-fresh@^3.2.1: version "3.3.0" resolved "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz" integrity sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw== @@ -3804,13 +4134,13 @@ ini@~1.3.0: resolved "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz" integrity sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew== -internal-slot@^1.0.5: - version "1.0.5" - resolved "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.5.tgz" - integrity sha512-Y+R5hJrzs52QCG2laLn4udYVnxsfny9CpOhNhUvk/SSSVyF6T27FzRbF0sroPidSu3X8oEAkOn2K804mjpt6UQ== +internal-slot@^1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/internal-slot/-/internal-slot-1.0.7.tgz#c06dcca3ed874249881007b0a5523b172a190802" + integrity sha512-NGnrKwXzSms2qUUih/ILZ5JBqNTSa1+ZmP6flaIp6KmSElgE9qdndzS3cqjrDovwFdmwsGsLdeFgB6suw+1e9g== dependencies: - get-intrinsic "^1.2.0" - has "^1.0.3" + es-errors "^1.3.0" + hasown "^2.0.0" side-channel "^1.0.4" ip-address@^9.0.5: @@ -3831,19 +4161,13 @@ ip@^1.1.3: resolved "https://registry.npmjs.org/ip/-/ip-1.1.8.tgz" integrity sha512-PuExPYUiu6qMBQb4l06ecm6T6ujzhmh+MeJcW9wa89PoAz5pvd4zPgN5WJV104mb6S2T1AwNIAaB70JNrLQWhg== -is-array-buffer@^3.0.1, is-array-buffer@^3.0.2: - version "3.0.2" - resolved "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.2.tgz" - integrity sha512-y+FyyR/w8vfIRq4eQcM1EYgSTnmHXPqaF+IgzgraytCFq5Xh8lllDVmAZolPJiZttZLeFSINPYMaEJ7/vWUa1w== +is-array-buffer@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/is-array-buffer/-/is-array-buffer-3.0.4.tgz#7a1f92b3d61edd2bc65d24f130530ea93d7fae98" + integrity sha512-wcjaerHw0ydZwfhiKbXJWLDY8A7yV7KhjQOpb83hGgGfId/aQa4TOvwyzn2PuswW2gPCYEL/nEAiSVpdOj1lXw== dependencies: call-bind "^1.0.2" - get-intrinsic "^1.2.0" - is-typed-array "^1.1.10" - -is-arrayish@^0.2.1: - version "0.2.1" - resolved "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz" - integrity sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg== + get-intrinsic "^1.2.1" is-bigint@^1.0.1: version "1.0.4" @@ -3872,7 +4196,7 @@ is-ci@^1.0.10: dependencies: ci-info "^1.5.0" -is-core-module@^2.11.0, is-core-module@^2.6.0: +is-core-module@^2.11.0: version "2.12.1" resolved "https://registry.npmjs.org/is-core-module/-/is-core-module-2.12.1.tgz" integrity sha512-Q4ZuBAe2FUsKtyQJoQHlvP8OvBERxO3jEmy1I7hcRXcJBGGHFh/aJBswbXuS9sgrDH2QUO8ilkwNPHvHMd8clg== @@ -3886,6 +4210,20 @@ is-core-module@^2.13.0: dependencies: hasown "^2.0.0" +is-core-module@^2.15.1: + version "2.15.1" + resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.15.1.tgz#a7363a25bee942fefab0de13bf6aa372c82dcc37" + integrity sha512-z0vtXSwucUJtANQWldhbtbt7BnL0vxiFjIdDLAatwhDYty2bad6s+rijD6Ri4YuYJubLzIJLUidCh09e1djEVQ== + dependencies: + hasown "^2.0.2" + +is-data-view@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-data-view/-/is-data-view-1.0.1.tgz#4b4d3a511b70f3dc26d42c03ca9ca515d847759f" + integrity sha512-AHkaJrsUVW6wq6JS8y3JnM/GJF/9cf+k20+iDzlSaJrinEo5+7vRiteOSwBhHRiAyQATN1AmY4hwzxJKPmYf+w== + dependencies: + is-typed-array "^1.1.13" + is-date-object@^1.0.1: version "1.0.5" resolved "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz" @@ -3893,11 +4231,16 @@ is-date-object@^1.0.1: dependencies: has-tostringtag "^1.0.0" -is-docker@^2.0.0, is-docker@^2.1.1: +is-docker@^2.0.0: version "2.2.1" resolved "https://registry.yarnpkg.com/is-docker/-/is-docker-2.2.1.tgz#33eeabe23cfe86f14bde4408a02c0cfb853acdaa" integrity sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ== +is-docker@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/is-docker/-/is-docker-3.0.0.tgz#90093aa3106277d8a77a5910dbae71747e15a200" + integrity sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ== + is-es2016-keyword@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/is-es2016-keyword/-/is-es2016-keyword-1.0.0.tgz" @@ -3930,22 +4273,29 @@ is-glob@^2.0.1: dependencies: is-extglob "^1.0.0" -is-glob@^4.0.0, is-glob@^4.0.1: +is-glob@^4.0.0, is-glob@^4.0.1, is-glob@^4.0.3: version "4.0.3" - resolved "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084" integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== dependencies: is-extglob "^2.1.1" +is-inside-container@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-inside-container/-/is-inside-container-1.0.0.tgz#e81fba699662eb31dbdaf26766a61d4814717ea4" + integrity sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA== + dependencies: + is-docker "^3.0.0" + is-lambda@^1.0.1: version "1.0.1" resolved "https://registry.npmjs.org/is-lambda/-/is-lambda-1.0.1.tgz" integrity sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ== -is-negative-zero@^2.0.2: - version "2.0.2" - resolved "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz" - integrity sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA== +is-negative-zero@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/is-negative-zero/-/is-negative-zero-2.0.3.tgz#ced903a027aca6381b777a5743069d7376a49747" + integrity sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw== is-number-object@^1.0.4: version "1.0.7" @@ -4025,9 +4375,16 @@ is-shared-array-buffer@^1.0.2: dependencies: call-bind "^1.0.2" -is-stream@^2.0.0: +is-shared-array-buffer@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/is-shared-array-buffer/-/is-shared-array-buffer-1.0.3.tgz#1237f1cba059cdb62431d378dcc37d9680181688" + integrity sha512-nA2hv5XIhLR3uVzDDfCIknerhx8XUKnstuOERPNNIinXG7v9u+ohXF67vxm4TPTEPU6lm61ZkwP3c9PCB97rhg== + dependencies: + call-bind "^1.0.7" + +is-stream@^2.0.0, is-stream@^2.0.1: version "2.0.1" - resolved "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz" + resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-2.0.1.tgz#fac1e3d53b97ad5a9d0ae9cef2389f5810a5c077" integrity sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg== is-string@^1.0.5, is-string@^1.0.7: @@ -4044,16 +4401,12 @@ is-symbol@^1.0.2, is-symbol@^1.0.3: dependencies: has-symbols "^1.0.2" -is-typed-array@^1.1.10, is-typed-array@^1.1.9: - version "1.1.10" - resolved "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.10.tgz" - integrity sha512-PJqgEHiWZvMpaFZ3uTc8kHPM4+4ADTlDniuQL7cU/UDA0Ql7F70yGfHph3cLNe+c9toaigv+DFzTJKhc2CtO6A== +is-typed-array@^1.1.13: + version "1.1.13" + resolved "https://registry.yarnpkg.com/is-typed-array/-/is-typed-array-1.1.13.tgz#d6c5ca56df62334959322d7d7dd1cca50debe229" + integrity sha512-uZ25/bUAlUY5fR4OKT4rZQEBrzQWYV9ZJYGGsUmEJ6thodVJ1HX64ePQ6Z0qPWP+m+Uq6e9UugrE38jeYsDSMw== dependencies: - available-typed-arrays "^1.0.5" - call-bind "^1.0.2" - for-each "^0.3.3" - gopd "^1.0.1" - has-tostringtag "^1.0.0" + which-typed-array "^1.1.14" is-url@^1.2.4: version "1.2.4" @@ -4072,12 +4425,12 @@ is-weakref@^1.0.2: dependencies: call-bind "^1.0.2" -is-wsl@^2.2.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-2.2.0.tgz#74a4c76e77ca9fd3f932f290c17ea326cd157271" - integrity sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww== +is-wsl@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-3.1.0.tgz#e1c657e39c10090afcbedec61720f6b924c3cbd2" + integrity sha512-UcVfVfaK4Sc4m7X3dUSoHoozQGBEFeDC+zVo06t98xe8CzHSZZBekNXH+tu0NalHolcJ/QAGqS46Hef7QXBIMw== dependencies: - is-docker "^2.0.0" + is-inside-container "^1.0.0" is2@^2.0.6: version "2.0.9" @@ -4088,6 +4441,11 @@ is2@^2.0.6: ip-regex "^4.1.0" is-url "^1.2.4" +isarray@^2.0.5: + version "2.0.5" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-2.0.5.tgz#8af1e4c1221244cc62459faf38940d4e644a5723" + integrity sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw== + isarray@~1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz" @@ -4108,6 +4466,15 @@ iterate-object@^1.3.4: resolved "https://registry.npmjs.org/iterate-object/-/iterate-object-1.3.4.tgz" integrity sha512-4dG1D1x/7g8PwHS9aK6QV5V94+ZvyP4+d19qDv43EzImmrndysIl4prmJ1hWWIGCqrZHyaHBm6BSEWHOLnpoNw== +jackspeak@^3.1.2: + version "3.4.3" + resolved "https://registry.yarnpkg.com/jackspeak/-/jackspeak-3.4.3.tgz#8833a9d89ab4acde6188942bd1c53b6390ed5a8a" + integrity sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw== + dependencies: + "@isaacs/cliui" "^8.0.2" + optionalDependencies: + "@pkgjs/parseargs" "^0.11.0" + js-md4@^0.3.2: version "0.3.2" resolved "https://registry.npmjs.org/js-md4/-/js-md4-0.3.2.tgz" @@ -4135,14 +4502,6 @@ js-tokens@^4.0.0: resolved "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz" integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== -js-yaml@^3.13.1: - version "3.14.1" - resolved "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz" - integrity sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g== - dependencies: - argparse "^1.0.7" - esprima "^4.0.0" - js-yaml@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602" @@ -4165,21 +4524,16 @@ jsesc@~0.5.0: resolved "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz" integrity sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA== -json-parse-better-errors@^1.0.1: - version "1.0.2" - resolved "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz" - integrity sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw== +json-buffer@3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.1.tgz#9338802a30d3b6605fbe0613e094008ca8c05a13" + integrity sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ== json-schema-traverse@^0.4.1: version "0.4.1" resolved "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz" integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== -json-schema-traverse@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz" - integrity sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug== - json-stable-stringify-without-jsonify@^1.0.1: version "1.0.1" resolved "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz" @@ -4216,6 +4570,13 @@ jszip@^3.10.1: readable-stream "~2.3.6" setimmediate "^1.0.5" +keyv@^4.5.4: + version "4.5.4" + resolved "https://registry.yarnpkg.com/keyv/-/keyv-4.5.4.tgz#a879a99e29452f942439f2a405e3af8b31d4de93" + integrity sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw== + dependencies: + json-buffer "3.0.1" + kleur@^3.0.3: version "3.0.3" resolved "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz" @@ -4250,24 +4611,6 @@ linux-platform-info@^0.0.3: dependencies: os-family "^1.0.0" -load-json-file@^4.0.0: - version "4.0.0" - resolved "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz" - integrity sha512-Kx8hMakjX03tiGTLAIdJ+lL0htKnXjEZN6hk/tozf/WOuYGdZBJrZ+rCJRbVCugsjB3jMLn9746NsQIf5VjBMw== - dependencies: - graceful-fs "^4.1.2" - parse-json "^4.0.0" - pify "^3.0.0" - strip-bom "^3.0.0" - -locate-path@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz" - integrity sha512-NCI2kiDkyR7VeEKm27Kda/iQHyKJe1Bu0FlTbYp3CqJu+9IFe9bLyAjMxf5ZDDbEg+iMPzB5zYyUTSm8wVTKmA== - dependencies: - p-locate "^2.0.0" - path-exists "^3.0.0" - locate-path@^3.0.0: version "3.0.0" resolved "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz" @@ -4276,46 +4619,23 @@ locate-path@^3.0.0: p-locate "^3.0.0" path-exists "^3.0.0" +locate-path@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-6.0.0.tgz#55321eb309febbc59c4801d931a72452a681d286" + integrity sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw== + dependencies: + p-locate "^5.0.0" + lodash.debounce@^4.0.8: version "4.0.8" resolved "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz" integrity sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow== -lodash.defaults@^4.2.0: - version "4.2.0" - resolved "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-4.2.0.tgz" - integrity sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ== - -lodash.difference@^4.5.0: - version "4.5.0" - resolved "https://registry.npmjs.org/lodash.difference/-/lodash.difference-4.5.0.tgz" - integrity sha512-dS2j+W26TQ7taQBGN8Lbbq04ssV3emRw4NY58WErlTO29pIqS0HmoT5aJ9+TUQ1N3G+JOZSji4eugsWwGp9yPA== - -lodash.flatten@^4.4.0: - version "4.4.0" - resolved "https://registry.npmjs.org/lodash.flatten/-/lodash.flatten-4.4.0.tgz" - integrity sha512-C5N2Z3DgnnKr0LOpv/hKCgKdb7ZZwafIrsesve6lmzvZIRZRGaZ/l6Q8+2W7NaT+ZwO3fFlSCzCzrDCFdJfZ4g== - -lodash.isplainobject@^4.0.6: - version "4.0.6" - resolved "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz" - integrity sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA== - lodash.merge@^4.6.2: version "4.6.2" resolved "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz" integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ== -lodash.truncate@^4.4.2: - version "4.4.2" - resolved "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz" - integrity sha512-jttmRe7bRse52OsWIMDLaXxWqRAmtIUccAQ3garviCqJjafXOfNMO0yMfNpdD6zbGaTU0P5Nz7e7gAT6cKmJRw== - -lodash.union@^4.6.0: - version "4.6.0" - resolved "https://registry.npmjs.org/lodash.union/-/lodash.union-4.6.0.tgz" - integrity sha512-c4pB2CdGrGdjMKYLA+XiRDO7Y0PRQbm/Gzg8qMj+QH+pFVAoTp5sBpO0odL3FjoPCGjK96p6qsP+yQoiLoOBcw== - "lodash@4.6.1 || ^4.16.1", lodash@^4.14.0, lodash@^4.17.15, lodash@^4.17.21, lodash@^4.17.4: version "4.17.21" resolved "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz" @@ -4341,6 +4661,11 @@ lru-cache@2.6.3: resolved "https://registry.npmjs.org/lru-cache/-/lru-cache-2.6.3.tgz" integrity sha512-qkisDmHMe8gxKujmC1BdaqgkoFlioLDCUwaFBA3lX8Ilhr3YzsasbGYaiADMjxQnj+aiZUKgGKe/BN3skMwXWw== +lru-cache@^10.2.0: + version "10.4.3" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-10.4.3.tgz#410fc8a17b70e598013df257c2446b7f3383f119" + integrity sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ== + lru-cache@^5.1.1: version "5.1.1" resolved "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz" @@ -4433,7 +4758,7 @@ merge2@^1.2.3, merge2@^1.3.0, merge2@^1.4.1: resolved "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz" integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg== -methods@^1.1.1, methods@^1.1.2: +methods@^1.1.2: version "1.1.2" resolved "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz" integrity sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w== @@ -4458,10 +4783,10 @@ mime-types@^2.1.12: dependencies: mime-db "1.52.0" -mime@^1.4.1: - version "1.6.0" - resolved "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz" - integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg== +mime@2.6.0: + version "2.6.0" + resolved "https://registry.yarnpkg.com/mime/-/mime-2.6.0.tgz#a2a682a95cd4d0cb1d6257e28f83da7e35800367" + integrity sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg== mime@~1.4.1: version "1.4.1" @@ -4488,9 +4813,9 @@ minimalistic-assert@^1.0.0: resolved "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz" integrity sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A== -minimatch@^3.0.4, minimatch@^3.1.1: +minimatch@^3.0.4, minimatch@^3.1.1, minimatch@^3.1.2: version "3.1.2" - resolved "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== dependencies: brace-expansion "^1.1.7" @@ -4502,7 +4827,14 @@ minimatch@^5.0.1, minimatch@^5.1.0: dependencies: brace-expansion "^2.0.1" -minimist@^1.1.0, minimist@^1.2.0, minimist@^1.2.3, minimist@^1.2.5, minimist@^1.2.6: +minimatch@^9.0.4: + version "9.0.5" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.5.tgz#d74f9dd6b57d83d8e98cfb82133b03978bc929e5" + integrity sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow== + dependencies: + brace-expansion "^2.0.1" + +minimist@^1.1.0, minimist@^1.2.0, minimist@^1.2.3, minimist@^1.2.6: version "1.2.8" resolved "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz" integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA== @@ -4558,6 +4890,11 @@ minipass@^5.0.0: resolved "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz" integrity sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ== +"minipass@^5.0.0 || ^6.0.2 || ^7.0.0", minipass@^7.1.2: + version "7.1.2" + resolved "https://registry.yarnpkg.com/minipass/-/minipass-7.1.2.tgz#93a9626ce5e5e66bd4db86849e7515e92340a707" + integrity sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw== + minizlib@^2.0.0, minizlib@^2.1.1: version "2.1.2" resolved "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz" @@ -4598,19 +4935,14 @@ moment@^2.14.1, moment@^2.29.4: resolved "https://registry.npmjs.org/moment/-/moment-2.30.1.tgz" integrity sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how== -ms@2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz" - integrity sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A== - ms@2.1.2: version "2.1.2" resolved "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz" integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== -ms@^2.0.0, ms@^2.1.1: +ms@^2.0.0, ms@^2.1.1, ms@^2.1.3: version "2.1.3" - resolved "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== msgpackr-extract@^3.0.2: @@ -4720,16 +5052,6 @@ nopt@^5.0.0: dependencies: abbrev "1" -normalize-package-data@^2.3.2: - version "2.5.0" - resolved "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz" - integrity sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA== - dependencies: - hosted-git-info "^2.1.4" - resolve "^1.10.0" - semver "2 || 3 || 4 || 5" - validate-npm-package-license "^3.0.1" - normalize-path@^3.0.0: version "3.0.0" resolved "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz" @@ -4757,7 +5079,12 @@ object-assign@^4.0.1: resolved "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz" integrity sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg== -object-inspect@^1.12.3, object-inspect@^1.9.0: +object-inspect@^1.13.1: + version "1.13.2" + resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.13.2.tgz#dea0088467fb991e67af4058147a24824a3043ff" + integrity sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g== + +object-inspect@^1.9.0: version "1.12.3" resolved "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz" integrity sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g== @@ -4767,24 +5094,43 @@ object-keys@^1.1.1: resolved "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz" integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA== -object.assign@^4.1.4: - version "4.1.4" - resolved "https://registry.npmjs.org/object.assign/-/object.assign-4.1.4.tgz" - integrity sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ== +object.assign@^4.1.5: + version "4.1.5" + resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.5.tgz#3a833f9ab7fdb80fc9e8d2300c803d216d8fdbb0" + integrity sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ== dependencies: - call-bind "^1.0.2" - define-properties "^1.1.4" + call-bind "^1.0.5" + define-properties "^1.2.1" has-symbols "^1.0.3" object-keys "^1.1.1" -object.values@^1.1.4: - version "1.1.6" - resolved "https://registry.npmjs.org/object.values/-/object.values-1.1.6.tgz" - integrity sha512-FVVTkD1vENCsAcwNs9k6jea2uHC/X0+JcjG8YA60FN5CMaJmG95wT9jek/xX9nornqGRrBkKtzuAu2wuHpKqvw== +object.fromentries@^2.0.8: + version "2.0.8" + resolved "https://registry.yarnpkg.com/object.fromentries/-/object.fromentries-2.0.8.tgz#f7195d8a9b97bd95cbc1999ea939ecd1a2b00c65" + integrity sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ== dependencies: - call-bind "^1.0.2" - define-properties "^1.1.4" - es-abstract "^1.20.4" + call-bind "^1.0.7" + define-properties "^1.2.1" + es-abstract "^1.23.2" + es-object-atoms "^1.0.0" + +object.groupby@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/object.groupby/-/object.groupby-1.0.3.tgz#9b125c36238129f6f7b61954a1e7176148d5002e" + integrity sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ== + dependencies: + call-bind "^1.0.7" + define-properties "^1.2.1" + es-abstract "^1.23.2" + +object.values@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/object.values/-/object.values-1.2.0.tgz#65405a9d92cee68ac2d303002e0b8470a4d9ab1b" + integrity sha512-yBYjY9QX2hnRmZHAjG/f13MzmBzxzYgQhFrke06TTyKY5zSTEqkOeukBzIdVA3j3ulu8Qa3MbVFShV7T2RmGtQ== + dependencies: + call-bind "^1.0.7" + define-properties "^1.2.1" + es-object-atoms "^1.0.0" once@^1.3.0, once@^1.3.1, once@^1.4.0: version "1.4.0" @@ -4807,26 +5153,27 @@ onetime@^5.1.0, onetime@^5.1.2: dependencies: mimic-fn "^2.1.0" -open@^8.4.2: - version "8.4.2" - resolved "https://registry.yarnpkg.com/open/-/open-8.4.2.tgz#5b5ffe2a8f793dcd2aad73e550cb87b59cb084f9" - integrity sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ== +open@^10.1.0: + version "10.1.0" + resolved "https://registry.yarnpkg.com/open/-/open-10.1.0.tgz#a7795e6e5d519abe4286d9937bb24b51122598e1" + integrity sha512-mnkeQ1qP5Ue2wd+aivTD3NHd/lZ96Lu0jgf0pwktLPtx6cTZiH7tyeGRRHs0zX0rbrahXPnXlUnbeXyaBBuIaw== dependencies: - define-lazy-prop "^2.0.0" - is-docker "^2.1.1" - is-wsl "^2.2.0" + default-browser "^5.2.1" + define-lazy-prop "^3.0.0" + is-inside-container "^1.0.0" + is-wsl "^3.1.0" -optionator@^0.9.1: - version "0.9.1" - resolved "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz" - integrity sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw== +optionator@^0.9.3: + version "0.9.4" + resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.9.4.tgz#7ea1c1a5d91d764fb282139c88fe11e182a3a734" + integrity sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g== dependencies: deep-is "^0.1.3" fast-levenshtein "^2.0.6" levn "^0.4.1" prelude-ls "^1.2.1" type-check "^0.4.0" - word-wrap "^1.2.3" + word-wrap "^1.2.5" os-family@^1.0.0, os-family@^1.1.0: version "1.1.0" @@ -4843,13 +5190,6 @@ p-finally@^2.0.0: resolved "https://registry.npmjs.org/p-finally/-/p-finally-2.0.1.tgz" integrity sha512-vpm09aKwq6H9phqRQzecoDpD8TmVyGw70qmWlyq5onxY7tqyTTFVvxMykxQSQKILBSFlbXpypIw2T1Ml7+DDtw== -p-limit@^1.1.0: - version "1.3.0" - resolved "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz" - integrity sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q== - dependencies: - p-try "^1.0.0" - p-limit@^2.0.0: version "2.3.0" resolved "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz" @@ -4857,12 +5197,12 @@ p-limit@^2.0.0: dependencies: p-try "^2.0.0" -p-locate@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz" - integrity sha512-nQja7m7gSKuewoVRen45CtVfODR3crN3goVQ0DDZ9N3yHxgpkuBhZqsaiotSQRrADUrne346peY7kT3TSACykg== +p-limit@^3.0.2: + version "3.1.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-3.1.0.tgz#e1daccbe78d0d1388ca18c64fea38e3e57e3706b" + integrity sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ== dependencies: - p-limit "^1.1.0" + yocto-queue "^0.1.0" p-locate@^3.0.0: version "3.0.0" @@ -4871,6 +5211,13 @@ p-locate@^3.0.0: dependencies: p-limit "^2.0.0" +p-locate@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-5.0.0.tgz#83c8315c6785005e3bd021839411c9e110e6d834" + integrity sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw== + dependencies: + p-limit "^3.0.2" + p-map@^1.1.1: version "1.2.0" resolved "https://registry.npmjs.org/p-map/-/p-map-1.2.0.tgz" @@ -4890,11 +5237,6 @@ p-map@^4.0.0: dependencies: aggregate-error "^3.0.0" -p-try@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz" - integrity sha512-U1etNYuMJoIz3ZXSrrySFjsXQTWOx2/jdi86L+2pRvph/qMKL6sbcCYdH23fqsbm8TH2Gn0OybpT4eSFlCVHww== - p-try@^2.0.0: version "2.2.0" resolved "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz" @@ -4922,6 +5264,11 @@ pac-resolver@^7.0.0: degenerator "^5.0.0" netmask "^2.0.2" +package-json-from-dist@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz#4f1471a010827a86f94cfd9b0727e36d267de505" + integrity sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw== + pako@~1.0.2: version "1.0.11" resolved "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz" @@ -4934,14 +5281,6 @@ parent-module@^1.0.0: dependencies: callsites "^3.0.0" -parse-json@^4.0.0: - version "4.0.0" - resolved "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz" - integrity sha512-aOIos8bujGN93/8Ox/jPLh7RwVnPEysynVFE+fQZyg6jKELEHwzgKdLRFHUgXJL6kylijVSBC4BvN9OmsB48Rw== - dependencies: - error-ex "^1.3.1" - json-parse-better-errors "^1.0.1" - parse5@^1.5.0: version "1.5.1" resolved "https://registry.npmjs.org/parse5/-/parse5-1.5.1.tgz" @@ -4989,12 +5328,13 @@ path-parse@^1.0.7: resolved "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz" integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== -path-type@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz" - integrity sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg== +path-scurry@^1.11.1: + version "1.11.1" + resolved "https://registry.yarnpkg.com/path-scurry/-/path-scurry-1.11.1.tgz#7960a668888594a0720b12a911d1a742ab9f11d2" + integrity sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA== dependencies: - pify "^3.0.0" + lru-cache "^10.2.0" + minipass "^5.0.0 || ^6.0.2 || ^7.0.0" path-type@^4.0.0: version "4.0.0" @@ -5055,13 +5395,6 @@ pinkie@^1.0.0: resolved "https://registry.npmjs.org/pinkie/-/pinkie-1.0.0.tgz" integrity sha512-VFVaU1ysKakao68ktZm76PIdOhvEfoNNRaGkyLln9Os7r0/MCxqHjHyBM7dT3pgTiBybqiPtpqKfpENwdBp50Q== -pkg-up@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/pkg-up/-/pkg-up-2.0.0.tgz" - integrity sha512-fjAPuiws93rm7mPUu21RdBnkeZNrbfCFCwfAhPWY+rR3zG0ubpe5cEReHOw5fIbfmsxEV/g2kSxGTATY3Bpnwg== - dependencies: - find-up "^2.1.0" - pkg-up@^3.1.0: version "3.1.0" resolved "https://registry.npmjs.org/pkg-up/-/pkg-up-3.1.0.tgz" @@ -5074,6 +5407,11 @@ pngjs@^3.3.1: resolved "https://registry.npmjs.org/pngjs/-/pngjs-3.4.0.tgz" integrity sha512-NCrCHhWmnQklfH4MtJMRjZ2a8c80qXeMlQMv2uVp9ISJMTt562SbGd6n2oq0PaPgKm7Z6pL9E2UlLIhC+SHL3w== +possible-typed-array-names@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/possible-typed-array-names/-/possible-typed-array-names-1.0.0.tgz#89bb63c6fada2c3e90adc4a647beeeb39cc7bf8f" + integrity sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q== + prebuild-install@^7.1.1: version "7.1.1" resolved "https://registry.npmjs.org/prebuild-install/-/prebuild-install-7.1.1.tgz" @@ -5107,10 +5445,10 @@ process-nextick-args@~2.0.0: resolved "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz" integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag== -progress@^2.0.0: - version "2.0.3" - resolved "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz" - integrity sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA== +process@^0.11.10: + version "0.11.10" + resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182" + integrity sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A== promise-inflight@^1.0.1: version "1.0.1" @@ -5214,12 +5552,12 @@ qrcode-terminal@^0.10.0: resolved "https://registry.npmjs.org/qrcode-terminal/-/qrcode-terminal-0.10.0.tgz" integrity sha512-ZvWjbAj4MWAj6bnCc9CnculsXnJr7eoKsvH/8rVpZbqYxP2z05HNQa43ZVwe/dVRcFxgfFHE2CkUqn0sCyLfHw== -qs@^6.5.1: - version "6.11.2" - resolved "https://registry.npmjs.org/qs/-/qs-6.11.2.tgz" - integrity sha512-tDNIz22aBzCDxLtVH++VnTfzxlfeK5CbqohpSqpJgj1Wg/cQbStNAz3NuqCs5vV+pjBsK4x4pN9HlVh7rcYRiA== +qs@^6.11.0: + version "6.13.0" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.13.0.tgz#6ca3bd58439f7e245655798997787b0d88a51906" + integrity sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg== dependencies: - side-channel "^1.0.4" + side-channel "^1.0.6" querystringify@^2.1.1: version "2.2.0" @@ -5231,6 +5569,11 @@ queue-microtask@^1.2.2: resolved "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz" integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A== +queue-tick@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/queue-tick/-/queue-tick-1.0.1.tgz#f6f07ac82c1fd60f82e098b417a80e52f1f4c142" + integrity sha512-kJt5qhMxoszgU/62PLP1CJytzd2NKetjSRnyuj31fDd3Rlcz3fzlFdFLD1SItunPwyqEOkca6GbV612BWfaBag== + r-json@^1.2.10: version "1.2.10" resolved "https://registry.npmjs.org/r-json/-/r-json-1.2.10.tgz" @@ -5253,24 +5596,7 @@ read-file-relative@^1.2.0: dependencies: callsite "^1.0.0" -read-pkg-up@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-3.0.0.tgz" - integrity sha512-YFzFrVvpC6frF1sz8psoHDBGF7fLPc+llq/8NB43oagqWkx8ar5zYtsTORtOjw9W2RHLpWP+zTWwBvf1bCmcSw== - dependencies: - find-up "^2.0.0" - read-pkg "^3.0.0" - -read-pkg@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz" - integrity sha512-BLq/cCO9two+lBgiTYNqD6GdtK8s4NpaWrl6/rCO9w0TUS8oJl7cmToOZfRYllKTISY6nt1U7jQ53brmKqY6BA== - dependencies: - load-json-file "^4.0.0" - normalize-package-data "^2.3.2" - path-type "^3.0.0" - -readable-stream@^2.0.0, readable-stream@^2.0.1, readable-stream@^2.0.5, readable-stream@^2.3.5, readable-stream@~2.3.6: +readable-stream@^2.0.1, readable-stream@^2.0.5, readable-stream@~2.3.6: version "2.3.8" resolved "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz" integrity sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA== @@ -5292,39 +5618,35 @@ readable-stream@^3.1.1, readable-stream@^3.4.0, readable-stream@^3.6.0: string_decoder "^1.1.1" util-deprecate "^1.0.1" -readdir-glob@^1.0.0: +readable-stream@^4.0.0: + version "4.5.2" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-4.5.2.tgz#9e7fc4c45099baeed934bff6eb97ba6cf2729e09" + integrity sha512-yjavECdqeZ3GLXNgRXgeQEdz9fvDDkNKyHnbHRFtOr7/LcfgBcmct7t/ET+HaCTqfh06OzoAxrkN/IfjJBVe+g== + dependencies: + abort-controller "^3.0.0" + buffer "^6.0.3" + events "^3.3.0" + process "^0.11.10" + string_decoder "^1.3.0" + +readdir-glob@^1.1.2: version "1.1.3" - resolved "https://registry.npmjs.org/readdir-glob/-/readdir-glob-1.1.3.tgz" + resolved "https://registry.yarnpkg.com/readdir-glob/-/readdir-glob-1.1.3.tgz#c3d831f51f5e7bfa62fa2ffbe4b508c640f09584" integrity sha512-v05I2k7xN8zXvPD9N+z/uhXPaj0sUFCe2rcWZIpBsqxfP7xXFQ0tipAd/wjj1YxWyWtUS5IDJpOG82JKt2EAVA== dependencies: minimatch "^5.1.0" -redis-commands@^1.7.0: - version "1.7.0" - resolved "https://registry.npmjs.org/redis-commands/-/redis-commands-1.7.0.tgz" - integrity sha512-nJWqw3bTFy21hX/CPKHth6sfhZbdiHP6bTawSgQBlKOVRG7EZkfHbbHwQJnrE4vsQf0CMNE+3gJ4Fmm16vdVlQ== - -redis-errors@^1.0.0, redis-errors@^1.2.0: - version "1.2.0" - resolved "https://registry.npmjs.org/redis-errors/-/redis-errors-1.2.0.tgz" - integrity sha512-1qny3OExCf0UvUV/5wpYKf2YwPcOqXzkwKKSmKHiE6ZMQs5heeE/c8eXK+PNllPvmjgAbfnsbpkGZWy8cBpn9w== - -redis-parser@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/redis-parser/-/redis-parser-3.0.0.tgz" - integrity sha512-DJnGAeenTdpMEH6uAJRK/uiyEIH9WVsUmoLwzudwGJUwZPp80PDBWPHXSAGNPwNvIXAbe7MSUB1zQFugFml66A== +redis@4.7.0: + version "4.7.0" + resolved "https://registry.yarnpkg.com/redis/-/redis-4.7.0.tgz#b401787514d25dd0cfc22406d767937ba3be55d6" + integrity sha512-zvmkHEAdGMn+hMRXuMBtu4Vo5P6rHQjLoHftu+lBqq8ZTA3RCVC/WzD790bkKKiNFp7d5/9PcSD19fJyyRvOdQ== dependencies: - redis-errors "^1.0.0" - -redis@3.1.1: - version "3.1.1" - resolved "https://registry.npmjs.org/redis/-/redis-3.1.1.tgz" - integrity sha512-QhkKhOuzhogR1NDJfBD34TQJz2ZJwDhhIC6ZmvpftlmfYShHHQXjjNspAJ+Z2HH5NwSBVYBVganbiZ8bgFMHjg== - dependencies: - denque "^1.5.0" - redis-commands "^1.7.0" - redis-errors "^1.2.0" - redis-parser "^3.0.0" + "@redis/bloom" "1.2.0" + "@redis/client" "1.6.0" + "@redis/graph" "1.1.1" + "@redis/json" "1.0.7" + "@redis/search" "1.2.0" + "@redis/time-series" "1.1.0" regenerate-unicode-properties@^10.1.0: version "10.1.1" @@ -5350,19 +5672,15 @@ regenerator-transform@^0.15.2: dependencies: "@babel/runtime" "^7.8.4" -regexp.prototype.flags@^1.4.3: - version "1.5.0" - resolved "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.0.tgz" - integrity sha512-0SutC3pNudRKgquxGoRGIz946MZVHqbNfPjBdxeOhBrdgDKlRoXmYLQN9xRbrR09ZXWeGAdPuif7egofn6v5LA== +regexp.prototype.flags@^1.5.2: + version "1.5.3" + resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.5.3.tgz#b3ae40b1d2499b8350ab2c3fe6ef3845d3a96f42" + integrity sha512-vqlC04+RQoFalODCbCumG2xIOvapzVMHwsyIGM/SIE8fRhFFsXeH8/QQ+s0T0kDAhKc4k30s73/0ydkHQz6HlQ== dependencies: - call-bind "^1.0.2" - define-properties "^1.2.0" - functions-have-names "^1.2.3" - -regexpp@^3.1.0: - version "3.2.0" - resolved "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz" - integrity sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg== + call-bind "^1.0.7" + define-properties "^1.2.1" + es-errors "^1.3.0" + set-function-name "^2.0.2" regexpu-core@^5.3.1: version "5.3.2" @@ -5395,11 +5713,6 @@ replicator@^1.0.5: resolved "https://registry.npmjs.org/replicator/-/replicator-1.0.5.tgz" integrity sha512-saxS4y7NFkLMa92BR4bPHR41GD+f/qoDAwD2xZmN+MpDXgibkxwLO2qk7dCHYtskSkd/bWS8Jy6kC5MZUkg1tw== -require-from-string@^2.0.2: - version "2.0.2" - resolved "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz" - integrity sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw== - requires-port@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz" @@ -5427,21 +5740,21 @@ resolve-from@^4.0.0: resolved "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz" integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g== -resolve@^1.10.0, resolve@^1.20.0, resolve@^1.22.1: - version "1.22.2" - resolved "https://registry.npmjs.org/resolve/-/resolve-1.22.2.tgz" - integrity sha512-Sb+mjNHOULsBv818T40qSPeRiuWLyaGMa5ewydRLFimneixmVy2zdivRl+AF6jaYPC8ERxGDmFSiqui6SfPd+g== +resolve@^1.14.2, resolve@^1.22.4: + version "1.22.8" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.8.tgz#b6c87a9f2aa06dfab52e3d70ac8cde321fa5a48d" + integrity sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw== dependencies: - is-core-module "^2.11.0" + is-core-module "^2.13.0" path-parse "^1.0.7" supports-preserve-symlinks-flag "^1.0.0" -resolve@^1.14.2: - version "1.22.8" - resolved "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz" - integrity sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw== +resolve@^1.22.1: + version "1.22.2" + resolved "https://registry.npmjs.org/resolve/-/resolve-1.22.2.tgz" + integrity sha512-Sb+mjNHOULsBv818T40qSPeRiuWLyaGMa5ewydRLFimneixmVy2zdivRl+AF6jaYPC8ERxGDmFSiqui6SfPd+g== dependencies: - is-core-module "^2.13.0" + is-core-module "^2.11.0" path-parse "^1.0.7" supports-preserve-symlinks-flag "^1.0.0" @@ -5474,6 +5787,11 @@ rimraf@^3.0.0, rimraf@^3.0.2: dependencies: glob "^7.1.3" +run-applescript@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/run-applescript/-/run-applescript-7.0.0.tgz#e5a553c2bffd620e169d276c1cd8f1b64778fbeb" + integrity sha512-9by4Ij99JUr/MCFBUkDKLWK3G9HVXmabKz9U5MlIAIuvuzkiOicRYs8XJLxX+xahD+mLiiCYDqF9dKAgtzKP1A== + run-parallel@^1.1.9: version "1.2.0" resolved "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz" @@ -5481,6 +5799,16 @@ run-parallel@^1.1.9: dependencies: queue-microtask "^1.2.2" +safe-array-concat@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/safe-array-concat/-/safe-array-concat-1.1.2.tgz#81d77ee0c4e8b863635227c721278dd524c20edb" + integrity sha512-vj6RsCsWBCf19jIeHEfkRMw8DPiBb+DMXklQ/1SGDHOMlHdPUkZXFQ2YdplS23zESTijAcurb1aSgJA3AgMu1Q== + dependencies: + call-bind "^1.0.7" + get-intrinsic "^1.2.4" + has-symbols "^1.0.3" + isarray "^2.0.5" + safe-buffer@^5.0.1, safe-buffer@~5.2.0: version "5.2.1" resolved "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz" @@ -5491,13 +5819,13 @@ safe-buffer@~5.1.0, safe-buffer@~5.1.1: resolved "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz" integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== -safe-regex-test@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.0.tgz" - integrity sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA== +safe-regex-test@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/safe-regex-test/-/safe-regex-test-1.0.3.tgz#a5b4c0f06e0ab50ea2c395c14d8371232924c377" + integrity sha512-CdASjNJPvRa7roO6Ra/gLYBTzYzzPyyBXxIMdGW3USQLyjWEls2RgW5UBTXaQVp+OrpeCK3bLem8smtmheoRuw== dependencies: - call-bind "^1.0.2" - get-intrinsic "^1.1.3" + call-bind "^1.0.6" + es-errors "^1.3.0" is-regex "^1.1.4" "safer-buffer@>= 2.1.2 < 3", "safer-buffer@>= 2.1.2 < 3.0.0": @@ -5512,16 +5840,17 @@ sanitize-filename@^1.6.0: dependencies: truncate-utf8-bytes "^1.0.0" -selenium-webdriver@^4.20.0: - version "4.20.0" - resolved "https://registry.npmjs.org/selenium-webdriver/-/selenium-webdriver-4.20.0.tgz" - integrity sha512-s/G44lGQ1xB3tmtX6NNPomlkpL6CxLdmAvp/AGWWwi4qv5Te1+qji7tPSyr6gyuoPpdYiof1rKnWe3luy0MrYA== +selenium-webdriver@^4.25.0: + version "4.25.0" + resolved "https://registry.yarnpkg.com/selenium-webdriver/-/selenium-webdriver-4.25.0.tgz#3562b49668817974bb1d13d25a50e8bc0264fcf3" + integrity sha512-zl9IX93caOT8wbcCpZzAkEtYa+hNgJ4C5GUN8uhpzggqRLvsg1asfKi0p1uNZC8buYVvsBZbx8S+9MjVAjs4oA== dependencies: + "@bazel/runfiles" "^5.8.1" jszip "^3.10.1" tmp "^0.2.3" - ws ">=8.16.0" + ws "^8.18.0" -"semver@2 || 3 || 4 || 5", semver@7.5.3, semver@^6.0.0, semver@^6.3.1, semver@^7.2.1, semver@^7.3.5, semver@^7.5.2, semver@^7.5.3: +semver@7.5.3, semver@^6.0.0, semver@^6.3.1, semver@^7.3.5, semver@^7.5.2, semver@^7.5.3, semver@^7.6.0: version "7.6.0" resolved "https://registry.yarnpkg.com/semver/-/semver-7.6.0.tgz#1a46a4db4bffcccd97b743b5005c8325f23d4e2d" integrity sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg== @@ -5538,6 +5867,28 @@ set-cookie-parser@^2.5.1: resolved "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.6.0.tgz" integrity sha512-RVnVQxTXuerk653XfuliOxBP81Sf0+qfQE73LIYKcyMYHG94AuH0kgrQpRDuTZnSmjpysHmzxJXKNfa6PjFhyQ== +set-function-length@^1.2.1: + version "1.2.2" + resolved "https://registry.yarnpkg.com/set-function-length/-/set-function-length-1.2.2.tgz#aac72314198eaed975cf77b2c3b6b880695e5449" + integrity sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg== + dependencies: + define-data-property "^1.1.4" + es-errors "^1.3.0" + function-bind "^1.1.2" + get-intrinsic "^1.2.4" + gopd "^1.0.1" + has-property-descriptors "^1.0.2" + +set-function-name@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/set-function-name/-/set-function-name-2.0.2.tgz#16a705c5a0dc2f5e638ca96d8a8cd4e1c2b90985" + integrity sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ== + dependencies: + define-data-property "^1.1.4" + es-errors "^1.3.0" + functions-have-names "^1.2.3" + has-property-descriptors "^1.0.2" + set-value@^4.1.0: version "4.1.0" resolved "https://registry.npmjs.org/set-value/-/set-value-4.1.0.tgz" @@ -5572,11 +5923,26 @@ side-channel@^1.0.4: get-intrinsic "^1.0.2" object-inspect "^1.9.0" +side-channel@^1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.6.tgz#abd25fb7cd24baf45466406b1096b7831c9215f2" + integrity sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA== + dependencies: + call-bind "^1.0.7" + es-errors "^1.3.0" + get-intrinsic "^1.2.4" + object-inspect "^1.13.1" + signal-exit@^3.0.2, signal-exit@^3.0.3, signal-exit@^3.0.7: version "3.0.7" resolved "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz" integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ== +signal-exit@^4.0.1: + version "4.1.0" + resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-4.1.0.tgz#952188c1cbd546070e2dd20d0f41c0ae0530cb04" + integrity sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw== + simple-concat@^1.0.0: version "1.0.1" resolved "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz" @@ -5601,15 +5967,6 @@ slash@^3.0.0: resolved "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz" integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q== -slice-ansi@^4.0.0: - version "4.0.0" - resolved "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz" - integrity sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ== - dependencies: - ansi-styles "^4.0.0" - astral-regex "^2.0.0" - is-fullwidth-code-point "^3.0.0" - smart-buffer@^4.2.0: version "4.2.0" resolved "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz" @@ -5662,45 +6019,14 @@ source-map@^0.6.0, source-map@~0.6.1: resolved "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz" integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== -spdx-correct@^3.0.0: - version "3.2.0" - resolved "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.2.0.tgz" - integrity sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA== - dependencies: - spdx-expression-parse "^3.0.0" - spdx-license-ids "^3.0.0" - -spdx-exceptions@^2.1.0: - version "2.3.0" - resolved "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz" - integrity sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A== - -spdx-expression-parse@^3.0.0: - version "3.0.1" - resolved "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz" - integrity sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q== - dependencies: - spdx-exceptions "^2.1.0" - spdx-license-ids "^3.0.0" - -spdx-license-ids@^3.0.0: - version "3.0.13" - resolved "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.13.tgz" - integrity sha512-XkD+zwiqXHikFZm4AX/7JSCXA98U5Db4AFd5XUg/+9UNtnH75+Z9KxtpYiJZx36mUDVOwH83pl7yvCer6ewM3w== - sprintf-js@^1.1.3: version "1.1.3" resolved "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.3.tgz" integrity sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA== -sprintf-js@~1.0.2: - version "1.0.3" - resolved "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz" - integrity sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g== - -sqlite3@^5.1.6: +sqlite3@^5.1.7: version "5.1.7" - resolved "https://registry.npmjs.org/sqlite3/-/sqlite3-5.1.7.tgz" + resolved "https://registry.yarnpkg.com/sqlite3/-/sqlite3-5.1.7.tgz#59ca1053c1ab38647396586edad019b1551041b7" integrity sha512-GGIyOiFaG+TUra3JIfkI/zGP8yZYLPQ0pl1bH+ODjiX57sPhrLU5sQJn1y9bDKZUFYkX1crlrPfSYt0BKKdkog== dependencies: bindings "^1.5.0" @@ -5722,6 +6048,26 @@ stackframe@^1.3.4: resolved "https://registry.npmjs.org/stackframe/-/stackframe-1.3.4.tgz" integrity sha512-oeVtt7eWQS+Na6F//S4kJ2K2VbRlS9D43mAlMyVpVWovy9o+jfgH8O9agzANzaiLjclA0oYzUXEM4PurhSUChw== +streamx@^2.15.0: + version "2.20.1" + resolved "https://registry.yarnpkg.com/streamx/-/streamx-2.20.1.tgz#471c4f8b860f7b696feb83d5b125caab2fdbb93c" + integrity sha512-uTa0mU6WUC65iUvzKH4X9hEdvSW7rbPxPtwfWiLMSj3qTdQbAiUboZTxauKfpFuGIGa1C2BYijZ7wgdUXICJhA== + dependencies: + fast-fifo "^1.3.2" + queue-tick "^1.0.1" + text-decoder "^1.1.0" + optionalDependencies: + bare-events "^2.2.0" + +"string-width-cjs@npm:string-width@^4.2.0": + version "4.2.3" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" + integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== + dependencies: + emoji-regex "^8.0.0" + is-fullwidth-code-point "^3.0.0" + strip-ansi "^6.0.1" + "string-width@^1.0.2 || 2 || 3 || 4", string-width@^4.1.0, string-width@^4.2.3: version "4.2.3" resolved "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz" @@ -5731,36 +6077,46 @@ stackframe@^1.3.4: is-fullwidth-code-point "^3.0.0" strip-ansi "^6.0.1" -string.prototype.trim@^1.2.7: - version "1.2.7" - resolved "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.7.tgz" - integrity sha512-p6TmeT1T3411M8Cgg9wBTMRtY2q9+PNy9EV1i2lIXUN/btt763oIfxwN3RR8VU6wHX8j/1CFy0L+YuThm6bgOg== +string-width@^5.0.1, string-width@^5.1.2: + version "5.1.2" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-5.1.2.tgz#14f8daec6d81e7221d2a357e668cab73bdbca794" + integrity sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA== dependencies: - call-bind "^1.0.2" - define-properties "^1.1.4" - es-abstract "^1.20.4" + eastasianwidth "^0.2.0" + emoji-regex "^9.2.2" + strip-ansi "^7.0.1" -string.prototype.trimend@^1.0.6: - version "1.0.6" - resolved "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.6.tgz" - integrity sha512-JySq+4mrPf9EsDBEDYMOb/lM7XQLulwg5R/m1r0PXEFqrV0qHvl58sdTilSXtKOflCsK2E8jxf+GKC0T07RWwQ== +string.prototype.trim@^1.2.9: + version "1.2.9" + resolved "https://registry.yarnpkg.com/string.prototype.trim/-/string.prototype.trim-1.2.9.tgz#b6fa326d72d2c78b6df02f7759c73f8f6274faa4" + integrity sha512-klHuCNxiMZ8MlsOihJhJEBJAiMVqU3Z2nEXWfWnIqjN0gEFS9J9+IxKozWWtQGcgoa1WUZzLjKPTr4ZHNFTFxw== dependencies: - call-bind "^1.0.2" - define-properties "^1.1.4" - es-abstract "^1.20.4" + call-bind "^1.0.7" + define-properties "^1.2.1" + es-abstract "^1.23.0" + es-object-atoms "^1.0.0" -string.prototype.trimstart@^1.0.6: - version "1.0.6" - resolved "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.6.tgz" - integrity sha512-omqjMDaY92pbn5HOX7f9IccLA+U1tA9GvtU4JrodiXFfYB7jPzzHpRzpglLAjtUV6bB557zwClJezTqnAiYnQA== +string.prototype.trimend@^1.0.8: + version "1.0.8" + resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.8.tgz#3651b8513719e8a9f48de7f2f77640b26652b229" + integrity sha512-p73uL5VCHCO2BZZ6krwwQE3kCzM7NKmis8S//xEC6fQonchbum4eP6kR4DLEjQFO3Wnj3Fuo8NM0kOSjVdHjZQ== dependencies: - call-bind "^1.0.2" - define-properties "^1.1.4" - es-abstract "^1.20.4" + call-bind "^1.0.7" + define-properties "^1.2.1" + es-object-atoms "^1.0.0" + +string.prototype.trimstart@^1.0.8: + version "1.0.8" + resolved "https://registry.yarnpkg.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.8.tgz#7ee834dda8c7c17eff3118472bb35bfedaa34dde" + integrity sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg== + dependencies: + call-bind "^1.0.7" + define-properties "^1.2.1" + es-object-atoms "^1.0.0" -string_decoder@^1.1.1: +string_decoder@^1.1.1, string_decoder@^1.3.0: version "1.3.0" - resolved "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e" integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA== dependencies: safe-buffer "~5.2.0" @@ -5772,6 +6128,13 @@ string_decoder@~1.1.1: dependencies: safe-buffer "~5.1.0" +"strip-ansi-cjs@npm:strip-ansi@^6.0.1": + version "6.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" + integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== + dependencies: + ansi-regex "^5.0.1" + strip-ansi@^6.0.0, strip-ansi@^6.0.1: version "6.0.1" resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz" @@ -5779,6 +6142,13 @@ strip-ansi@^6.0.0, strip-ansi@^6.0.1: dependencies: ansi-regex "^5.0.1" +strip-ansi@^7.0.1: + version "7.1.0" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-7.1.0.tgz#d5b6568ca689d8561370b0707685d22434faff45" + integrity sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ== + dependencies: + ansi-regex "^6.0.1" + strip-bom@^2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz" @@ -5796,7 +6166,7 @@ strip-final-newline@^2.0.0: resolved "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz" integrity sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA== -strip-json-comments@^3.1.0, strip-json-comments@^3.1.1: +strip-json-comments@^3.1.1: version "3.1.1" resolved "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz" integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== @@ -5806,29 +6176,28 @@ strip-json-comments@~2.0.1: resolved "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz" integrity sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ== -superagent@^3.8.3: - version "3.8.3" - resolved "https://registry.npmjs.org/superagent/-/superagent-3.8.3.tgz" - integrity sha512-GLQtLMCoEIK4eDv6OGtkOoSMt3D+oq0y3dsxMuYuDvaNUvuT8eFBuLmfR0iYYzHC1e8hpzC6ZsxbuP6DIalMFA== - dependencies: - component-emitter "^1.2.0" - cookiejar "^2.1.0" - debug "^3.1.0" - extend "^3.0.0" - form-data "^2.3.1" - formidable "^1.2.0" - methods "^1.1.1" - mime "^1.4.1" - qs "^6.5.1" - readable-stream "^2.3.5" - -supertest@^4.0.2: - version "4.0.2" - resolved "https://registry.npmjs.org/supertest/-/supertest-4.0.2.tgz" - integrity sha512-1BAbvrOZsGA3YTCWqbmh14L0YEq0EGICX/nBnfkfVJn7SrxQV1I3pMYjSzG9y/7ZU2V9dWqyqk2POwxlb09duQ== +superagent@^9.0.1: + version "9.0.2" + resolved "https://registry.yarnpkg.com/superagent/-/superagent-9.0.2.tgz#a18799473fc57557289d6b63960610e358bdebc1" + integrity sha512-xuW7dzkUpcJq7QnhOsnNUgtYp3xRwpt2F7abdRYIpCsAt0hhUqia0EdxyXZQQpNmGtsCzYHryaKSV3q3GJnq7w== + dependencies: + component-emitter "^1.3.0" + cookiejar "^2.1.4" + debug "^4.3.4" + fast-safe-stringify "^2.1.1" + form-data "^4.0.0" + formidable "^3.5.1" + methods "^1.1.2" + mime "2.6.0" + qs "^6.11.0" + +supertest@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/supertest/-/supertest-7.0.0.tgz#cac53b3d6872a0b317980b2b0cfa820f09cd7634" + integrity sha512-qlsr7fIC0lSddmA3tzojvzubYxvlGtzumcdHgPwbFWMISQwL22MhM2Y3LNt+6w9Yyx7559VW5ab70dgphm8qQA== dependencies: methods "^1.1.2" - superagent "^3.8.3" + superagent "^9.0.1" supports-color@^5.3.0: version "5.5.0" @@ -5849,17 +6218,6 @@ supports-preserve-symlinks-flag@^1.0.0: resolved "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz" integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w== -table@^6.0.9: - version "6.8.1" - resolved "https://registry.npmjs.org/table/-/table-6.8.1.tgz" - integrity sha512-Y4X9zqrCftUhMeH2EptSSERdVKt/nEdijTOacGD/97EKjhQ/Qs8RTlEGABSJNNN8lac9kheH+af7yAkEWlgneA== - dependencies: - ajv "^8.0.1" - lodash.truncate "^4.4.2" - slice-ansi "^4.0.0" - string-width "^4.2.3" - strip-ansi "^6.0.1" - tar-fs@^2.0.0: version "2.1.1" resolved "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.1.tgz" @@ -5870,7 +6228,7 @@ tar-fs@^2.0.0: pump "^3.0.0" tar-stream "^2.1.4" -tar-stream@^2.1.4, tar-stream@^2.2.0: +tar-stream@^2.1.4: version "2.2.0" resolved "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz" integrity sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ== @@ -5881,6 +6239,15 @@ tar-stream@^2.1.4, tar-stream@^2.2.0: inherits "^2.0.3" readable-stream "^3.1.1" +tar-stream@^3.0.0: + version "3.1.7" + resolved "https://registry.yarnpkg.com/tar-stream/-/tar-stream-3.1.7.tgz#24b3fb5eabada19fe7338ed6d26e5f7c482e792b" + integrity sha512-qJj60CXt7IU1Ffyc3NJMjh6EkuCFej46zUqJ4J7pqYlThyd9bO0XBTmcOIhSzZJVWfsLks0+nle/j538YAW9RQ== + dependencies: + b4a "^1.6.4" + fast-fifo "^1.2.0" + streamx "^2.15.0" + tar@^6.0.2, tar@^6.1.11, tar@^6.1.2: version "6.2.1" resolved "https://registry.yarnpkg.com/tar/-/tar-6.2.1.tgz#717549c541bc3c2af15751bea94b1dd068d4b03a" @@ -6166,6 +6533,13 @@ testcafe@3.6.2: unquote "^1.1.1" url-to-options "^2.0.0" +text-decoder@^1.1.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/text-decoder/-/text-decoder-1.2.0.tgz#85f19d4d5088e0b45cd841bdfaeac458dbffeefc" + integrity sha512-n1yg1mOj9DNpk3NeZOx7T6jchTbyJS3i3cucbNN6FcdPriMZx7NsgrGpWWdWZZGxD7ES1XB+3uoqHMgOKaN+fg== + dependencies: + b4a "^1.6.4" + text-table@^0.2.0: version "0.2.0" resolved "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz" @@ -6222,10 +6596,15 @@ truncate-utf8-bytes@^1.0.0: dependencies: utf8-byte-length "^1.0.1" -ts-node@10.9.1: - version "10.9.1" - resolved "https://registry.npmjs.org/ts-node/-/ts-node-10.9.1.tgz" - integrity sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw== +ts-api-utils@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/ts-api-utils/-/ts-api-utils-1.3.0.tgz#4b490e27129f1e8e686b45cc4ab63714dc60eea1" + integrity sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ== + +ts-node@10.9.2: + version "10.9.2" + resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-10.9.2.tgz#70f021c9e185bccdca820e26dc413805c101c71f" + integrity sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ== dependencies: "@cspotcode/source-map-support" "^0.8.0" "@tsconfig/node10" "^1.0.7" @@ -6241,33 +6620,21 @@ ts-node@10.9.1: v8-compile-cache-lib "^3.0.1" yn "3.1.1" -tsconfig-paths@^3.11.0: - version "3.14.2" - resolved "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.14.2.tgz" - integrity sha512-o/9iXgCYc5L/JxCHPe3Hvh8Q/2xm5Z+p18PESBU6Ff33695QnCHBEjcytY2q19ua7Mbl/DavtBOLq+oG0RCL+g== +tsconfig-paths@^3.15.0: + version "3.15.0" + resolved "https://registry.yarnpkg.com/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz#5299ec605e55b1abb23ec939ef15edaf483070d4" + integrity sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg== dependencies: "@types/json5" "^0.0.29" json5 "^1.0.2" minimist "^1.2.6" strip-bom "^3.0.0" -tslib@^1.8.1: - version "1.14.1" - resolved "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz" - integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== - tslib@^2.0.1: version "2.6.2" resolved "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz" integrity sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q== -tsutils@^3.21.0: - version "3.21.0" - resolved "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz" - integrity sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA== - dependencies: - tslib "^1.8.1" - tunnel-agent@0.6.0, tunnel-agent@^0.6.0: version "0.6.0" resolved "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz" @@ -6287,34 +6654,64 @@ type-detect@^4.0.0, type-detect@^4.0.5: resolved "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz" integrity sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g== -type-fest@^0.20.2: - version "0.20.2" - resolved "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz" - integrity sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ== - type-fest@^0.21.3: version "0.21.3" resolved "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz" integrity sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w== -typed-array-length@^1.0.4: - version "1.0.4" - resolved "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.4.tgz" - integrity sha512-KjZypGq+I/H7HI5HlOoGHkWUUGq+Q0TPhQurLbyrVrvnKTBgzLhIJ7j6J/XTQOi0d1RjyZ0wdas8bKs2p0x3Ng== +typed-array-buffer@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/typed-array-buffer/-/typed-array-buffer-1.0.2.tgz#1867c5d83b20fcb5ccf32649e5e2fc7424474ff3" + integrity sha512-gEymJYKZtKXzzBzM4jqa9w6Q1Jjm7x2d+sh19AdsD4wqnMPDYyvwpsIc2Q/835kHuo3BEQ7CjelGhfTsoBb2MQ== dependencies: - call-bind "^1.0.2" + call-bind "^1.0.7" + es-errors "^1.3.0" + is-typed-array "^1.1.13" + +typed-array-byte-length@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/typed-array-byte-length/-/typed-array-byte-length-1.0.1.tgz#d92972d3cff99a3fa2e765a28fcdc0f1d89dec67" + integrity sha512-3iMJ9q0ao7WE9tWcaYKIptkNBuOIcZCCT0d4MRvuuH88fEoEH62IuQe0OtraD3ebQEoTRk8XCBoknUNc1Y67pw== + dependencies: + call-bind "^1.0.7" + for-each "^0.3.3" + gopd "^1.0.1" + has-proto "^1.0.3" + is-typed-array "^1.1.13" + +typed-array-byte-offset@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/typed-array-byte-offset/-/typed-array-byte-offset-1.0.2.tgz#f9ec1acb9259f395093e4567eb3c28a580d02063" + integrity sha512-Ous0vodHa56FviZucS2E63zkgtgrACj7omjwd/8lTEMEPFFyjfixMZ1ZXenpgCFBBt4EC1J2XsyVS2gkG0eTFA== + dependencies: + available-typed-arrays "^1.0.7" + call-bind "^1.0.7" for-each "^0.3.3" - is-typed-array "^1.1.9" + gopd "^1.0.1" + has-proto "^1.0.3" + is-typed-array "^1.1.13" + +typed-array-length@^1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/typed-array-length/-/typed-array-length-1.0.6.tgz#57155207c76e64a3457482dfdc1c9d1d3c4c73a3" + integrity sha512-/OxDN6OtAk5KBpGb28T+HZc2M+ADtvRxXrKKbUwtsLgdoxgX13hyy7ek6bFRl5+aBs2yZzB0c4CnQfAtVypW/g== + dependencies: + call-bind "^1.0.7" + for-each "^0.3.3" + gopd "^1.0.1" + has-proto "^1.0.3" + is-typed-array "^1.1.13" + possible-typed-array-names "^1.0.0" typescript@4.7.4: version "4.7.4" resolved "https://registry.npmjs.org/typescript/-/typescript-4.7.4.tgz" integrity sha512-C0WQT0gezHuw6AdY1M2jxUO83Rjf0HP7Sk1DtXj6j1EwkQNZrHAg2XPWlq62oqEhYvONq5pkC2Y9oPljWToLmQ== -typescript@5.1.3: - version "5.1.3" - resolved "https://registry.npmjs.org/typescript/-/typescript-5.1.3.tgz" - integrity sha512-XH627E9vkeqhlZFQuL+UsyAXEnibT0kWR2FWONlr4sTjvxyJYnyefgrkyECLzM5NenmKzRAy2rR/OlYLA1HkZw== +typescript@5.6.3: + version "5.6.3" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.6.3.tgz#5f3449e31c9d94febb17de03cc081dd56d81db5b" + integrity sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw== unbox-primitive@^1.0.2: version "1.0.2" @@ -6426,19 +6823,6 @@ v8-compile-cache-lib@^3.0.1: resolved "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz" integrity sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg== -v8-compile-cache@^2.0.3: - version "2.3.0" - resolved "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz" - integrity sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA== - -validate-npm-package-license@^3.0.1: - version "3.0.4" - resolved "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz" - integrity sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew== - dependencies: - spdx-correct "^3.0.0" - spdx-expression-parse "^3.0.0" - w-json@^1.3.10: version "1.3.10" resolved "https://registry.npmjs.org/w-json/-/w-json-1.3.10.tgz" @@ -6464,17 +6848,16 @@ which-promise@^1.0.0: pinkie-promise "^1.0.0" which "^1.1.2" -which-typed-array@^1.1.9: - version "1.1.9" - resolved "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.9.tgz" - integrity sha512-w9c4xkx6mPidwp7180ckYWfMmvxpjlZuIudNtDf4N/tTAUB8VJbX25qZoAsrtGuYNnGw3pa0AXgbGKRB8/EceA== +which-typed-array@^1.1.14, which-typed-array@^1.1.15: + version "1.1.15" + resolved "https://registry.yarnpkg.com/which-typed-array/-/which-typed-array-1.1.15.tgz#264859e9b11a649b388bfaaf4f767df1f779b38d" + integrity sha512-oV0jmFtUky6CXfkqehVvBP/LSWJ2sy4vWMioiENyJLePrBO/yKyV9OyJySfAKosh+RYkIl5zJCNZ8/4JncrpdA== dependencies: - available-typed-arrays "^1.0.5" - call-bind "^1.0.2" + available-typed-arrays "^1.0.7" + call-bind "^1.0.7" for-each "^0.3.3" gopd "^1.0.1" - has-tostringtag "^1.0.0" - is-typed-array "^1.1.10" + has-tostringtag "^1.0.2" which@^1.1.2: version "1.3.1" @@ -6504,11 +6887,20 @@ windows-release@^5.0.1: dependencies: execa "^5.1.1" -word-wrap@1.2.4, word-wrap@^1.2.3: +word-wrap@1.2.4, word-wrap@^1.2.5: version "1.2.4" resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.4.tgz#cb4b50ec9aca570abd1f52f33cd45b6c61739a9f" integrity sha512-2V81OA4ugVo5pRo46hAoD2ivUJx8jXmWXfUkY4KFNw0hEptvN0QfH3K4nHiwzGeKl5rFKedV48QVoqYavy4YpA== +"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0": + version "7.0.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" + integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== + dependencies: + ansi-styles "^4.0.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" + wrap-ansi@^7.0.0: version "7.0.0" resolved "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz" @@ -6518,31 +6910,40 @@ wrap-ansi@^7.0.0: string-width "^4.1.0" strip-ansi "^6.0.0" +wrap-ansi@^8.1.0: + version "8.1.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-8.1.0.tgz#56dc22368ee570face1b49819975d9b9a5ead214" + integrity sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ== + dependencies: + ansi-styles "^6.1.0" + string-width "^5.0.1" + strip-ansi "^7.0.1" + wrappy@1: version "1.0.2" resolved "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz" integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== -ws@>=8.16.0: - version "8.17.0" - resolved "https://registry.npmjs.org/ws/-/ws-8.17.0.tgz" - integrity sha512-uJq6108EgZMAl20KagGkzCKfMEjxmKvZHG7Tlq0Z6nOky7YF7aq4mOx6xK8TJ/i1LeK4Qus7INktacctDgY8Ow== - ws@^7.2.0, ws@^7.4.6: version "7.5.9" resolved "https://registry.npmjs.org/ws/-/ws-7.5.9.tgz" integrity sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q== -yallist@^3.0.2: - version "3.1.1" - resolved "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz" - integrity sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g== +ws@^8.18.0: + version "8.18.0" + resolved "https://registry.yarnpkg.com/ws/-/ws-8.18.0.tgz#0d7505a6eafe2b0e712d232b42279f53bc289bbc" + integrity sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw== -yallist@^4.0.0: +yallist@4.0.0, yallist@^4.0.0: version "4.0.0" resolved "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz" integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== +yallist@^3.0.2: + version "3.1.1" + resolved "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz" + integrity sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g== + yauzl@^2.10.0: version "2.10.0" resolved "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz" @@ -6556,11 +6957,16 @@ yn@3.1.1: resolved "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz" integrity sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q== -zip-stream@^4.1.0: - version "4.1.0" - resolved "https://registry.npmjs.org/zip-stream/-/zip-stream-4.1.0.tgz" - integrity sha512-zshzwQW7gG7hjpBlgeQP9RuyPGNxvJdzR8SUM3QhxCnLjWN2E7j3dOvpeDcQoETfHx0urRS7EtmVToql7YpU4A== +yocto-queue@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b" + integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q== + +zip-stream@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/zip-stream/-/zip-stream-6.0.1.tgz#e141b930ed60ccaf5d7fa9c8260e0d1748a2bbfb" + integrity sha512-zK7YHHz4ZXpW89AHXUPbQVGKI7uvkd3hzusTdotCg1UxyaVtg0zFJSTfW/Dq5f7OBBVnq6cZIaC8Ti4hb6dtCA== dependencies: - archiver-utils "^2.1.0" - compress-commons "^4.1.0" - readable-stream "^3.6.0" + archiver-utils "^5.0.0" + compress-commons "^6.0.2" + readable-stream "^4.0.0" From 23c5bee8ba0aa9c93f449899a330b6de78f4bfe3 Mon Sep 17 00:00:00 2001 From: ArtemHoruzhenko Date: Wed, 16 Oct 2024 16:34:52 +0300 Subject: [PATCH 187/256] upgrade all the packages --- tests/e2e/yarn.lock | 2559 +++++++++++++++++++------------------------ 1 file changed, 1128 insertions(+), 1431 deletions(-) diff --git a/tests/e2e/yarn.lock b/tests/e2e/yarn.lock index ecbdad2497..06ecbacb52 100644 --- a/tests/e2e/yarn.lock +++ b/tests/e2e/yarn.lock @@ -3,142 +3,113 @@ "@adobe/css-tools@^4.3.0-rc.1": - version "4.3.3" - resolved "https://registry.npmjs.org/@adobe/css-tools/-/css-tools-4.3.3.tgz" - integrity sha512-rE0Pygv0sEZ4vBWHlAgJLGDU7Pm8xoO6p3wsEceb7GYAjScrOHpEo8KK/eVkAcnSM+slAEtXjA2JpdjLp4fJQQ== + version "4.4.0" + resolved "https://registry.yarnpkg.com/@adobe/css-tools/-/css-tools-4.4.0.tgz#728c484f4e10df03d5a3acd0d8adcbbebff8ad63" + integrity sha512-Ff9+ksdQQB3rMncgqDK78uLznstjyfIf2Arnh22pW8kBpLs6rpKDwgnZT46hin5Hl1WzazzK64DOrhSwYpS7bQ== "@ampproject/remapping@^2.2.0": - version "2.2.1" - resolved "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.1.tgz" - integrity sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg== - dependencies: - "@jridgewell/gen-mapping" "^0.3.0" - "@jridgewell/trace-mapping" "^0.3.9" - -"@babel/code-frame@^7.23.5": - version "7.23.5" - resolved "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.23.5.tgz" - integrity sha512-CgH3s1a96LipHCmSUmYFPwY7MNx8C3avkq7i4Wl3cfa662ldtUe4VM1TPXX70pfmrlWTb6jLqTYrZyT2ZTJBgA== + version "2.3.0" + resolved "https://registry.yarnpkg.com/@ampproject/remapping/-/remapping-2.3.0.tgz#ed441b6fa600072520ce18b43d2c8cc8caecc7f4" + integrity sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw== dependencies: - "@babel/highlight" "^7.23.4" - chalk "^2.4.2" + "@jridgewell/gen-mapping" "^0.3.5" + "@jridgewell/trace-mapping" "^0.3.24" -"@babel/code-frame@^7.24.1", "@babel/code-frame@^7.24.2": - version "7.24.2" - resolved "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.2.tgz" - integrity sha512-y5+tLQyV8pg3fsiln67BVLD1P13Eg4lh5RW9mF0zUuvLrv9uIQ4MCL+CRT+FTsBlBjcIan6PGsLcBN0m3ClUyQ== +"@babel/code-frame@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.25.7.tgz#438f2c524071531d643c6f0188e1e28f130cebc7" + integrity sha512-0xZJFNE5XMpENsgfHYTw8FbX4kv53mFLn2i3XPoq69LyhYSCBJtitaHx9QnsVTrsogI4Z3+HtEfZ2/GFPOtf5g== dependencies: - "@babel/highlight" "^7.24.2" + "@babel/highlight" "^7.25.7" picocolors "^1.0.0" -"@babel/compat-data@^7.20.5", "@babel/compat-data@^7.22.6", "@babel/compat-data@^7.23.5": - version "7.23.5" - resolved "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.23.5.tgz" - integrity sha512-uU27kfDRlhfKl+w1U6vp16IuvSLtjAxdArVXPa9BvLkrr7CYIsxH5adpHObeAGY/41+syctUWOZ140a2Rvkgjw== - -"@babel/compat-data@^7.24.4": - version "7.24.4" - resolved "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.24.4.tgz" - integrity sha512-vg8Gih2MLK+kOkHJp4gBEIkyaIi00jgWot2D9QOmmfLC8jINSOzmCLta6Bvz/JSBCqnegV0L80jhxkol5GWNfQ== +"@babel/compat-data@^7.20.5", "@babel/compat-data@^7.22.6", "@babel/compat-data@^7.25.7", "@babel/compat-data@^7.25.8": + version "7.25.8" + resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.25.8.tgz#0376e83df5ab0eb0da18885c0140041f0747a402" + integrity sha512-ZsysZyXY4Tlx+Q53XdnOFmqwfB9QDTHYxaZYajWRoBLuLEAwI2UIbtxOjWh/cFaa9IKUlcB+DDuoskLuKu56JA== "@babel/core@^7.23.2": - version "7.24.4" - resolved "https://registry.npmjs.org/@babel/core/-/core-7.24.4.tgz" - integrity sha512-MBVlMXP+kkl5394RBLSxxk/iLTeVGuXTV3cIDXavPpMMqnSnt6apKgan/U8O3USWZCWZT/TbgfEpKa4uMgN4Dg== + version "7.25.8" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.25.8.tgz#a57137d2a51bbcffcfaeba43cb4dd33ae3e0e1c6" + integrity sha512-Oixnb+DzmRT30qu9d3tJSQkxuygWm32DFykT4bRoORPa9hZ/L4KhVB/XiRm6KG+roIEM7DBQlmg27kw2HZkdZg== dependencies: "@ampproject/remapping" "^2.2.0" - "@babel/code-frame" "^7.24.2" - "@babel/generator" "^7.24.4" - "@babel/helper-compilation-targets" "^7.23.6" - "@babel/helper-module-transforms" "^7.23.3" - "@babel/helpers" "^7.24.4" - "@babel/parser" "^7.24.4" - "@babel/template" "^7.24.0" - "@babel/traverse" "^7.24.1" - "@babel/types" "^7.24.0" + "@babel/code-frame" "^7.25.7" + "@babel/generator" "^7.25.7" + "@babel/helper-compilation-targets" "^7.25.7" + "@babel/helper-module-transforms" "^7.25.7" + "@babel/helpers" "^7.25.7" + "@babel/parser" "^7.25.8" + "@babel/template" "^7.25.7" + "@babel/traverse" "^7.25.7" + "@babel/types" "^7.25.8" convert-source-map "^2.0.0" debug "^4.1.0" gensync "^1.0.0-beta.2" json5 "^2.2.3" semver "^6.3.1" -"@babel/generator@^7.24.1", "@babel/generator@^7.24.4": - version "7.24.4" - resolved "https://registry.npmjs.org/@babel/generator/-/generator-7.24.4.tgz" - integrity sha512-Xd6+v6SnjWVx/nus+y0l1sxMOTOMBkyL4+BIdbALyatQnAe/SRVjANeDPSCYaX+i1iJmuGSKf3Z+E+V/va1Hvw== +"@babel/generator@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.25.7.tgz#de86acbeb975a3e11ee92dd52223e6b03b479c56" + integrity sha512-5Dqpl5fyV9pIAD62yK9P7fcA768uVPUyrQmqpqstHWgMma4feF1x/oFysBCVZLY5wJ2GkMUCdsNDnGZrPoR6rA== dependencies: - "@babel/types" "^7.24.0" + "@babel/types" "^7.25.7" "@jridgewell/gen-mapping" "^0.3.5" "@jridgewell/trace-mapping" "^0.3.25" - jsesc "^2.5.1" + jsesc "^3.0.2" -"@babel/helper-annotate-as-pure@^7.22.5": - version "7.22.5" - resolved "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.22.5.tgz" - integrity sha512-LvBTxu8bQSQkcyKOU+a1btnNFQ1dMAd0R6PyW3arXes06F6QLWLIrd681bxRPIXlrMGR3XYnW9JyML7dP3qgxg== +"@babel/helper-annotate-as-pure@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.25.7.tgz#63f02dbfa1f7cb75a9bdb832f300582f30bb8972" + integrity sha512-4xwU8StnqnlIhhioZf1tqnVWeQ9pvH/ujS8hRfw/WOza+/a+1qv69BWNy+oY231maTCWgKWhfBU7kDpsds6zAA== dependencies: - "@babel/types" "^7.22.5" + "@babel/types" "^7.25.7" -"@babel/helper-builder-binary-assignment-operator-visitor@^7.22.15": - version "7.22.15" - resolved "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.22.15.tgz" - integrity sha512-QkBXwGgaoC2GtGZRoma6kv7Szfv06khvhFav67ZExau2RaXzy8MpHSMO2PNoP2XtmQphJQRHFfg77Bq731Yizw== +"@babel/helper-builder-binary-assignment-operator-visitor@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.25.7.tgz#d721650c1f595371e0a23ee816f1c3c488c0d622" + integrity sha512-12xfNeKNH7jubQNm7PAkzlLwEmCs1tfuX3UjIw6vP6QXi+leKh6+LyC/+Ed4EIQermwd58wsyh070yjDHFlNGg== dependencies: - "@babel/types" "^7.22.15" + "@babel/traverse" "^7.25.7" + "@babel/types" "^7.25.7" -"@babel/helper-compilation-targets@^7.20.7", "@babel/helper-compilation-targets@^7.22.6", "@babel/helper-compilation-targets@^7.23.6": - version "7.23.6" - resolved "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.23.6.tgz" - integrity sha512-9JB548GZoQVmzrFgp8o7KxdgkTGm6xs9DW0o/Pim72UDjzr5ObUQ6ZzYPqA+g9OTS2bBQoctLJrky0RDCAWRgQ== +"@babel/helper-compilation-targets@^7.20.7", "@babel/helper-compilation-targets@^7.22.6", "@babel/helper-compilation-targets@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.25.7.tgz#11260ac3322dda0ef53edfae6e97b961449f5fa4" + integrity sha512-DniTEax0sv6isaw6qSQSfV4gVRNtw2rte8HHM45t9ZR0xILaufBRNkpMifCRiAPyvL4ACD6v0gfCwCmtOQaV4A== dependencies: - "@babel/compat-data" "^7.23.5" - "@babel/helper-validator-option" "^7.23.5" - browserslist "^4.22.2" + "@babel/compat-data" "^7.25.7" + "@babel/helper-validator-option" "^7.25.7" + browserslist "^4.24.0" lru-cache "^5.1.1" semver "^6.3.1" -"@babel/helper-create-class-features-plugin@^7.18.6": - version "7.23.10" - resolved "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.23.10.tgz" - integrity sha512-2XpP2XhkXzgxecPNEEK8Vz8Asj9aRxt08oKOqtiZoqV2UGZ5T+EkyP9sXQ9nwMxBIG34a7jmasVqoMop7VdPUw== - dependencies: - "@babel/helper-annotate-as-pure" "^7.22.5" - "@babel/helper-environment-visitor" "^7.22.20" - "@babel/helper-function-name" "^7.23.0" - "@babel/helper-member-expression-to-functions" "^7.23.0" - "@babel/helper-optimise-call-expression" "^7.22.5" - "@babel/helper-replace-supers" "^7.22.20" - "@babel/helper-skip-transparent-expression-wrappers" "^7.22.5" - "@babel/helper-split-export-declaration" "^7.22.6" +"@babel/helper-create-class-features-plugin@^7.18.6", "@babel/helper-create-class-features-plugin@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.25.7.tgz#5d65074c76cae75607421c00d6bd517fe1892d6b" + integrity sha512-bD4WQhbkx80mAyj/WCm4ZHcF4rDxkoLFO6ph8/5/mQ3z4vAzltQXAmbc7GvVJx5H+lk5Mi5EmbTeox5nMGCsbw== + dependencies: + "@babel/helper-annotate-as-pure" "^7.25.7" + "@babel/helper-member-expression-to-functions" "^7.25.7" + "@babel/helper-optimise-call-expression" "^7.25.7" + "@babel/helper-replace-supers" "^7.25.7" + "@babel/helper-skip-transparent-expression-wrappers" "^7.25.7" + "@babel/traverse" "^7.25.7" semver "^6.3.1" -"@babel/helper-create-class-features-plugin@^7.24.1", "@babel/helper-create-class-features-plugin@^7.24.4": - version "7.24.4" - resolved "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.24.4.tgz" - integrity sha512-lG75yeuUSVu0pIcbhiYMXBXANHrpUPaOfu7ryAzskCgKUHuAxRQI5ssrtmF0X9UXldPlvT0XM/A4F44OXRt6iQ== - dependencies: - "@babel/helper-annotate-as-pure" "^7.22.5" - "@babel/helper-environment-visitor" "^7.22.20" - "@babel/helper-function-name" "^7.23.0" - "@babel/helper-member-expression-to-functions" "^7.23.0" - "@babel/helper-optimise-call-expression" "^7.22.5" - "@babel/helper-replace-supers" "^7.24.1" - "@babel/helper-skip-transparent-expression-wrappers" "^7.22.5" - "@babel/helper-split-export-declaration" "^7.22.6" - semver "^6.3.1" - -"@babel/helper-create-regexp-features-plugin@^7.18.6", "@babel/helper-create-regexp-features-plugin@^7.22.15", "@babel/helper-create-regexp-features-plugin@^7.22.5": - version "7.22.15" - resolved "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.22.15.tgz" - integrity sha512-29FkPLFjn4TPEa3RE7GpW+qbE8tlsu3jntNYNfcGsc49LphF1PQIiD+vMZ1z1xVOKt+93khA9tc2JBs3kBjA7w== +"@babel/helper-create-regexp-features-plugin@^7.18.6", "@babel/helper-create-regexp-features-plugin@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.25.7.tgz#dcb464f0e2cdfe0c25cc2a0a59c37ab940ce894e" + integrity sha512-byHhumTj/X47wJ6C6eLpK7wW/WBEcnUeb7D0FNc/jFQnQVw7DOso3Zz5u9x/zLrFVkHa89ZGDbkAa1D54NdrCQ== dependencies: - "@babel/helper-annotate-as-pure" "^7.22.5" - regexpu-core "^5.3.1" + "@babel/helper-annotate-as-pure" "^7.25.7" + regexpu-core "^6.1.1" semver "^6.3.1" "@babel/helper-define-polyfill-provider@^0.4.4": version "0.4.4" - resolved "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.4.4.tgz" + resolved "https://registry.yarnpkg.com/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.4.4.tgz#64df615451cb30e94b59a9696022cffac9a10088" integrity sha512-QcJMILQCu2jm5TFPGA3lCpJJTeEP+mqeXooG/NZbg/h5FTFi6V0+99ahlRsW8/kRLyb24LZVCCiclDedhLKcBA== dependencies: "@babel/helper-compilation-targets" "^7.22.6" @@ -149,7 +120,7 @@ "@babel/helper-define-polyfill-provider@^0.5.0": version "0.5.0" - resolved "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.5.0.tgz" + resolved "https://registry.yarnpkg.com/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.5.0.tgz#465805b7361f461e86c680f1de21eaf88c25901b" integrity sha512-NovQquuQLAQ5HuyjCz7WQP9MjRj7dx++yspwiyUiGl9ZyadHRSql1HZh5ogRd8W8w6YM6EQ/NTB8rgjLt5W65Q== dependencies: "@babel/helper-compilation-targets" "^7.22.6" @@ -158,9 +129,9 @@ lodash.debounce "^4.0.8" resolve "^1.14.2" -"@babel/helper-define-polyfill-provider@^0.6.1", "@babel/helper-define-polyfill-provider@^0.6.2": +"@babel/helper-define-polyfill-provider@^0.6.2": version "0.6.2" - resolved "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.6.2.tgz" + resolved "https://registry.yarnpkg.com/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.6.2.tgz#18594f789c3594acb24cfdb4a7f7b7d2e8bd912d" integrity sha512-LV76g+C502biUK6AyZ3LK10vDpDyCzZnhZFXkH1L75zHPj68+qc8Zfpx2th+gzwA2MzyK+1g/3EPl62yFnVttQ== dependencies: "@babel/helper-compilation-targets" "^7.22.6" @@ -169,220 +140,176 @@ lodash.debounce "^4.0.8" resolve "^1.14.2" -"@babel/helper-environment-visitor@^7.18.9", "@babel/helper-environment-visitor@^7.22.20": - version "7.22.20" - resolved "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz" - integrity sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA== - -"@babel/helper-function-name@^7.22.5", "@babel/helper-function-name@^7.23.0": - version "7.23.0" - resolved "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz" - integrity sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw== - dependencies: - "@babel/template" "^7.22.15" - "@babel/types" "^7.23.0" - -"@babel/helper-hoist-variables@^7.22.5": - version "7.22.5" - resolved "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz" - integrity sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw== - dependencies: - "@babel/types" "^7.22.5" - -"@babel/helper-member-expression-to-functions@^7.22.15", "@babel/helper-member-expression-to-functions@^7.23.0": - version "7.23.0" - resolved "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.23.0.tgz" - integrity sha512-6gfrPwh7OuT6gZyJZvd6WbTfrqAo7vm4xCzAXOusKqq/vWdKXphTpj5klHKNmRUU6/QRGlBsyU9mAIPaWHlqJA== - dependencies: - "@babel/types" "^7.23.0" - -"@babel/helper-module-imports@^7.22.15": - version "7.22.15" - resolved "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.22.15.tgz" - integrity sha512-0pYVBnDKZO2fnSPCrgM/6WMc7eS20Fbok+0r88fp+YtWVLZrp4CkafFGIp+W0VKw4a22sgebPT99y+FDNMdP4w== - dependencies: - "@babel/types" "^7.22.15" - -"@babel/helper-module-imports@^7.24.1": - version "7.24.3" - resolved "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.24.3.tgz" - integrity sha512-viKb0F9f2s0BCS22QSF308z/+1YWKV/76mwt61NBzS5izMzDPwdq1pTrzf+Li3npBWX9KdQbkeCt1jSAM7lZqg== - dependencies: - "@babel/types" "^7.24.0" - -"@babel/helper-module-transforms@^7.23.3": - version "7.23.3" - resolved "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.23.3.tgz" - integrity sha512-7bBs4ED9OmswdfDzpz4MpWgSrV7FXlc3zIagvLFjS5H+Mk7Snr21vQ6QwrsoCGMfNC4e4LQPdoULEt4ykz0SRQ== - dependencies: - "@babel/helper-environment-visitor" "^7.22.20" - "@babel/helper-module-imports" "^7.22.15" - "@babel/helper-simple-access" "^7.22.5" - "@babel/helper-split-export-declaration" "^7.22.6" - "@babel/helper-validator-identifier" "^7.22.20" - -"@babel/helper-optimise-call-expression@^7.22.5": - version "7.22.5" - resolved "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.22.5.tgz" - integrity sha512-HBwaojN0xFRx4yIvpwGqxiV2tUfl7401jlok564NgB9EHS1y6QT17FmKWm4ztqjeVdXLuC4fSvHc5ePpQjoTbw== - dependencies: - "@babel/types" "^7.22.5" - -"@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.12.13", "@babel/helper-plugin-utils@^7.14.5", "@babel/helper-plugin-utils@^7.18.6", "@babel/helper-plugin-utils@^7.20.2", "@babel/helper-plugin-utils@^7.22.5", "@babel/helper-plugin-utils@^7.8.0", "@babel/helper-plugin-utils@^7.8.3": - version "7.22.5" - resolved "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz" - integrity sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg== - -"@babel/helper-plugin-utils@^7.24.0": - version "7.24.0" - resolved "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.24.0.tgz" - integrity sha512-9cUznXMG0+FxRuJfvL82QlTqIzhVW9sL0KjMPHhAOOvpQGL8QtdxnBKILjBqxlHyliz0yCa1G903ZXI/FuHy2w== - -"@babel/helper-remap-async-to-generator@^7.18.9", "@babel/helper-remap-async-to-generator@^7.22.20": - version "7.22.20" - resolved "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.22.20.tgz" - integrity sha512-pBGyV4uBqOns+0UvhsTO8qgl8hO89PmiDYv+/COyp1aeMcmfrfruz+/nCMFiYyFF/Knn0yfrC85ZzNFjembFTw== - dependencies: - "@babel/helper-annotate-as-pure" "^7.22.5" - "@babel/helper-environment-visitor" "^7.22.20" - "@babel/helper-wrap-function" "^7.22.20" - -"@babel/helper-replace-supers@^7.22.20": - version "7.22.20" - resolved "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.22.20.tgz" - integrity sha512-qsW0In3dbwQUbK8kejJ4R7IHVGwHJlV6lpG6UA7a9hSa2YEiAib+N1T2kr6PEeUT+Fl7najmSOS6SmAwCHK6Tw== - dependencies: - "@babel/helper-environment-visitor" "^7.22.20" - "@babel/helper-member-expression-to-functions" "^7.22.15" - "@babel/helper-optimise-call-expression" "^7.22.5" - -"@babel/helper-replace-supers@^7.24.1": - version "7.24.1" - resolved "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.24.1.tgz" - integrity sha512-QCR1UqC9BzG5vZl8BMicmZ28RuUBnHhAMddD8yHFHDRH9lLTZ9uUPehX8ctVPT8l0TKblJidqcgUUKGVrePleQ== - dependencies: - "@babel/helper-environment-visitor" "^7.22.20" - "@babel/helper-member-expression-to-functions" "^7.23.0" - "@babel/helper-optimise-call-expression" "^7.22.5" - -"@babel/helper-simple-access@^7.22.5": - version "7.22.5" - resolved "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.22.5.tgz" - integrity sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w== - dependencies: - "@babel/types" "^7.22.5" - -"@babel/helper-skip-transparent-expression-wrappers@^7.22.5": - version "7.22.5" - resolved "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.22.5.tgz" - integrity sha512-tK14r66JZKiC43p8Ki33yLBVJKlQDFoA8GYN67lWCDCqoL6EMMSuM9b+Iff2jHaM/RRFYl7K+iiru7hbRqNx8Q== - dependencies: - "@babel/types" "^7.22.5" - -"@babel/helper-split-export-declaration@^7.22.6": - version "7.22.6" - resolved "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz" - integrity sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g== - dependencies: - "@babel/types" "^7.22.5" - -"@babel/helper-string-parser@^7.23.4": - version "7.23.4" - resolved "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.23.4.tgz" - integrity sha512-803gmbQdqwdf4olxrX4AJyFBV/RTr3rSmOj0rKwesmzlfhYNDEs+/iOcznzpNWlJlIlTJC2QfPFcHB6DlzdVLQ== - -"@babel/helper-validator-identifier@^7.22.20": - version "7.22.20" - resolved "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz" - integrity sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A== - -"@babel/helper-validator-option@^7.23.5": - version "7.23.5" - resolved "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.23.5.tgz" - integrity sha512-85ttAOMLsr53VgXkTbkx8oA6YTfT4q7/HzXSLEYmjcSTJPMPQtvq1BD79Byep5xMUYbGRzEpDsjUf3dyp54IKw== - -"@babel/helper-wrap-function@^7.22.20": - version "7.22.20" - resolved "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.22.20.tgz" - integrity sha512-pms/UwkOpnQe/PDAEdV/d7dVCoBbB+R4FvYoHGZz+4VPcg7RtYy2KP7S2lbuWM6FCSgob5wshfGESbC/hzNXZw== - dependencies: - "@babel/helper-function-name" "^7.22.5" - "@babel/template" "^7.22.15" - "@babel/types" "^7.22.19" - -"@babel/helpers@^7.24.4": - version "7.24.4" - resolved "https://registry.npmjs.org/@babel/helpers/-/helpers-7.24.4.tgz" - integrity sha512-FewdlZbSiwaVGlgT1DPANDuCHaDMiOo+D/IDYRFYjHOuv66xMSJ7fQwwODwRNAPkADIO/z1EoF/l2BCWlWABDw== - dependencies: - "@babel/template" "^7.24.0" - "@babel/traverse" "^7.24.1" - "@babel/types" "^7.24.0" - -"@babel/highlight@^7.23.4": - version "7.23.4" - resolved "https://registry.npmjs.org/@babel/highlight/-/highlight-7.23.4.tgz" - integrity sha512-acGdbYSfp2WheJoJm/EBBBLh/ID8KDc64ISZ9DYtBmC8/Q204PZJLHyzeB5qMzJ5trcOkybd78M4x2KWsUq++A== - dependencies: - "@babel/helper-validator-identifier" "^7.22.20" - chalk "^2.4.2" - js-tokens "^4.0.0" - -"@babel/highlight@^7.24.2": - version "7.24.2" - resolved "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.2.tgz" - integrity sha512-Yac1ao4flkTxTteCDZLEvdxg2fZfz1v8M4QpaGypq/WPDqg3ijHYbDfs+LG5hvzSoqaSZ9/Z9lKSP3CjZjv+pA== - dependencies: - "@babel/helper-validator-identifier" "^7.22.20" +"@babel/helper-environment-visitor@^7.18.9": + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/helper-environment-visitor/-/helper-environment-visitor-7.24.7.tgz#4b31ba9551d1f90781ba83491dd59cf9b269f7d9" + integrity sha512-DoiN84+4Gnd0ncbBOM9AZENV4a5ZiL39HYMyZJGZ/AZEykHYdJw0wW3kdcsh9/Kn+BRXHLkkklZ51ecPKmI1CQ== + dependencies: + "@babel/types" "^7.24.7" + +"@babel/helper-member-expression-to-functions@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.25.7.tgz#541a33b071f0355a63a0fa4bdf9ac360116b8574" + integrity sha512-O31Ssjd5K6lPbTX9AAYpSKrZmLeagt9uwschJd+Ixo6QiRyfpvgtVQp8qrDR9UNFjZ8+DO34ZkdrN+BnPXemeA== + dependencies: + "@babel/traverse" "^7.25.7" + "@babel/types" "^7.25.7" + +"@babel/helper-module-imports@^7.22.15", "@babel/helper-module-imports@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.25.7.tgz#dba00d9523539152906ba49263e36d7261040472" + integrity sha512-o0xCgpNmRohmnoWKQ0Ij8IdddjyBFE4T2kagL/x6M3+4zUgc+4qTOUBoNe4XxDskt1HPKO007ZPiMgLDq2s7Kw== + dependencies: + "@babel/traverse" "^7.25.7" + "@babel/types" "^7.25.7" + +"@babel/helper-module-transforms@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.25.7.tgz#2ac9372c5e001b19bc62f1fe7d96a18cb0901d1a" + integrity sha512-k/6f8dKG3yDz/qCwSM+RKovjMix563SLxQFo0UhRNo239SP6n9u5/eLtKD6EAjwta2JHJ49CsD8pms2HdNiMMQ== + dependencies: + "@babel/helper-module-imports" "^7.25.7" + "@babel/helper-simple-access" "^7.25.7" + "@babel/helper-validator-identifier" "^7.25.7" + "@babel/traverse" "^7.25.7" + +"@babel/helper-optimise-call-expression@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.25.7.tgz#1de1b99688e987af723eed44fa7fc0ee7b97d77a" + integrity sha512-VAwcwuYhv/AT+Vfr28c9y6SHzTan1ryqrydSTFGjU0uDJHw3uZ+PduI8plCLkRsDnqK2DMEDmwrOQRsK/Ykjng== + dependencies: + "@babel/types" "^7.25.7" + +"@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.18.6", "@babel/helper-plugin-utils@^7.20.2", "@babel/helper-plugin-utils@^7.22.5", "@babel/helper-plugin-utils@^7.25.7", "@babel/helper-plugin-utils@^7.8.0": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.25.7.tgz#8ec5b21812d992e1ef88a9b068260537b6f0e36c" + integrity sha512-eaPZai0PiqCi09pPs3pAFfl/zYgGaE6IdXtYvmf0qlcDTd3WCtO7JWCcRd64e0EQrcYgiHibEZnOGsSY4QSgaw== + +"@babel/helper-remap-async-to-generator@^7.18.9", "@babel/helper-remap-async-to-generator@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.25.7.tgz#9efdc39df5f489bcd15533c912b6c723a0a65021" + integrity sha512-kRGE89hLnPfcz6fTrlNU+uhgcwv0mBE4Gv3P9Ke9kLVJYpi4AMVVEElXvB5CabrPZW4nCM8P8UyyjrzCM0O2sw== + dependencies: + "@babel/helper-annotate-as-pure" "^7.25.7" + "@babel/helper-wrap-function" "^7.25.7" + "@babel/traverse" "^7.25.7" + +"@babel/helper-replace-supers@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.25.7.tgz#38cfda3b6e990879c71d08d0fef9236b62bd75f5" + integrity sha512-iy8JhqlUW9PtZkd4pHM96v6BdJ66Ba9yWSE4z0W4TvSZwLBPkyDsiIU3ENe4SmrzRBs76F7rQXTy1lYC49n6Lw== + dependencies: + "@babel/helper-member-expression-to-functions" "^7.25.7" + "@babel/helper-optimise-call-expression" "^7.25.7" + "@babel/traverse" "^7.25.7" + +"@babel/helper-simple-access@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.25.7.tgz#5eb9f6a60c5d6b2e0f76057004f8dacbddfae1c0" + integrity sha512-FPGAkJmyoChQeM+ruBGIDyrT2tKfZJO8NcxdC+CWNJi7N8/rZpSxK7yvBJ5O/nF1gfu5KzN7VKG3YVSLFfRSxQ== + dependencies: + "@babel/traverse" "^7.25.7" + "@babel/types" "^7.25.7" + +"@babel/helper-skip-transparent-expression-wrappers@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.25.7.tgz#382831c91038b1a6d32643f5f49505b8442cb87c" + integrity sha512-pPbNbchZBkPMD50K0p3JGcFMNLVUCuU/ABybm/PGNj4JiHrpmNyqqCphBk4i19xXtNV0JhldQJJtbSW5aUvbyA== + dependencies: + "@babel/traverse" "^7.25.7" + "@babel/types" "^7.25.7" + +"@babel/helper-string-parser@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.25.7.tgz#d50e8d37b1176207b4fe9acedec386c565a44a54" + integrity sha512-CbkjYdsJNHFk8uqpEkpCvRs3YRp9tY6FmFY7wLMSYuGYkrdUi7r2lc4/wqsvlHoMznX3WJ9IP8giGPq68T/Y6g== + +"@babel/helper-validator-identifier@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.7.tgz#77b7f60c40b15c97df735b38a66ba1d7c3e93da5" + integrity sha512-AM6TzwYqGChO45oiuPqwL2t20/HdMC1rTPAesnBCgPCSF1x3oN9MVUwQV2iyz4xqWrctwK5RNC8LV22kaQCNYg== + +"@babel/helper-validator-option@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.25.7.tgz#97d1d684448228b30b506d90cace495d6f492729" + integrity sha512-ytbPLsm+GjArDYXJ8Ydr1c/KJuutjF2besPNbIZnZ6MKUxi/uTA22t2ymmA4WFjZFpjiAMO0xuuJPqK2nvDVfQ== + +"@babel/helper-wrap-function@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/helper-wrap-function/-/helper-wrap-function-7.25.7.tgz#9f6021dd1c4fdf4ad515c809967fc4bac9a70fe7" + integrity sha512-MA0roW3JF2bD1ptAaJnvcabsVlNQShUaThyJbCDD4bCp8NEgiFvpoqRI2YS22hHlc2thjO/fTg2ShLMC3jygAg== + dependencies: + "@babel/template" "^7.25.7" + "@babel/traverse" "^7.25.7" + "@babel/types" "^7.25.7" + +"@babel/helpers@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.25.7.tgz#091b52cb697a171fe0136ab62e54e407211f09c2" + integrity sha512-Sv6pASx7Esm38KQpF/U/OXLwPPrdGHNKoeblRxgZRLXnAtnkEe4ptJPDtAZM7fBLadbc1Q07kQpSiGQ0Jg6tRA== + dependencies: + "@babel/template" "^7.25.7" + "@babel/types" "^7.25.7" + +"@babel/highlight@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.25.7.tgz#20383b5f442aa606e7b5e3043b0b1aafe9f37de5" + integrity sha512-iYyACpW3iW8Fw+ZybQK+drQre+ns/tKpXbNESfrhNnPLIklLbXr7MYJ6gPEd0iETGLOK+SxMjVvKb/ffmk+FEw== + dependencies: + "@babel/helper-validator-identifier" "^7.25.7" chalk "^2.4.2" js-tokens "^4.0.0" picocolors "^1.0.0" -"@babel/parser@^7.23.9": - version "7.23.9" - resolved "https://registry.npmjs.org/@babel/parser/-/parser-7.23.9.tgz" - integrity sha512-9tcKgqKbs3xGJ+NtKF2ndOBBLVwPjl1SHxPQkd36r3Dlirw3xWUeGaTbqr7uGZcTaxkVNwc+03SVP7aCdWrTlA== +"@babel/parser@^7.25.7", "@babel/parser@^7.25.8": + version "7.25.8" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.25.8.tgz#f6aaf38e80c36129460c1657c0762db584c9d5e2" + integrity sha512-HcttkxzdPucv3nNFmfOOMfFf64KgdJVqm1KaCm25dPGMLElo9nsLvXeJECQg8UzPuBGLyTSA0ZzqCtDSzKTEoQ== + dependencies: + "@babel/types" "^7.25.8" -"@babel/parser@^7.24.0", "@babel/parser@^7.24.1", "@babel/parser@^7.24.4": - version "7.24.4" - resolved "https://registry.npmjs.org/@babel/parser/-/parser-7.24.4.tgz" - integrity sha512-zTvEBcghmeBma9QIGunWevvBAp4/Qu9Bdq+2k0Ot4fVMD6v3dsC9WOcRSKk7tRRyBM/53yKMJko9xOatGQAwSg== +"@babel/plugin-bugfix-firefox-class-in-computed-class-key@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-firefox-class-in-computed-class-key/-/plugin-bugfix-firefox-class-in-computed-class-key-7.25.7.tgz#93969ac50ef4d68b2504b01b758af714e4cbdd64" + integrity sha512-UV9Lg53zyebzD1DwQoT9mzkEKa922LNUp5YkTJ6Uta0RbyXaQNUgcvSt7qIu1PpPzVb6rd10OVNTzkyBGeVmxQ== + dependencies: + "@babel/helper-plugin-utils" "^7.25.7" + "@babel/traverse" "^7.25.7" -"@babel/plugin-bugfix-firefox-class-in-computed-class-key@^7.24.4": - version "7.24.4" - resolved "https://registry.npmjs.org/@babel/plugin-bugfix-firefox-class-in-computed-class-key/-/plugin-bugfix-firefox-class-in-computed-class-key-7.24.4.tgz" - integrity sha512-qpl6vOOEEzTLLcsuqYYo8yDtrTocmu2xkGvgNebvPjT9DTtfFYGmgDqY+rBYXNlqL4s9qLDn6xkrJv4RxAPiTA== +"@babel/plugin-bugfix-safari-class-field-initializer-scope@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-safari-class-field-initializer-scope/-/plugin-bugfix-safari-class-field-initializer-scope-7.25.7.tgz#a338d611adb9dcd599b8b1efa200c88ebeffe046" + integrity sha512-GDDWeVLNxRIkQTnJn2pDOM1pkCgYdSqPeT1a9vh9yIqu2uzzgw1zcqEb+IJOhy+dTBMlNdThrDIksr2o09qrrQ== dependencies: - "@babel/helper-environment-visitor" "^7.22.20" - "@babel/helper-plugin-utils" "^7.24.0" + "@babel/helper-plugin-utils" "^7.25.7" -"@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@^7.24.1": - version "7.24.1" - resolved "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.24.1.tgz" - integrity sha512-y4HqEnkelJIOQGd+3g1bTeKsA5c6qM7eOn7VggGVbBc0y8MLSKHacwcIE2PplNlQSj0PqS9rrXL/nkPVK+kUNg== +"@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.25.7.tgz#c5f755e911dfac7ef6957300c0f9c4a8c18c06f4" + integrity sha512-wxyWg2RYaSUYgmd9MR0FyRGyeOMQE/Uzr1wzd/g5cf5bwi9A4v6HFdDm7y1MgDtod/fLOSTZY6jDgV0xU9d5bA== dependencies: - "@babel/helper-plugin-utils" "^7.24.0" + "@babel/helper-plugin-utils" "^7.25.7" -"@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@^7.24.1": - version "7.24.1" - resolved "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.24.1.tgz" - integrity sha512-Hj791Ii4ci8HqnaKHAlLNs+zaLXb0EzSDhiAWp5VNlyvCNymYfacs64pxTxbH1znW/NcArSmwpmG9IKE/TUVVQ== +"@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.25.7.tgz#3b7ea04492ded990978b6deaa1dfca120ad4455a" + integrity sha512-Xwg6tZpLxc4iQjorYsyGMyfJE7nP5MV8t/Ka58BgiA7Jw0fRqQNcANlLfdJ/yvBt9z9LD2We+BEkT7vLqZRWng== dependencies: - "@babel/helper-plugin-utils" "^7.24.0" - "@babel/helper-skip-transparent-expression-wrappers" "^7.22.5" - "@babel/plugin-transform-optional-chaining" "^7.24.1" + "@babel/helper-plugin-utils" "^7.25.7" + "@babel/helper-skip-transparent-expression-wrappers" "^7.25.7" + "@babel/plugin-transform-optional-chaining" "^7.25.7" -"@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@^7.24.1": - version "7.24.1" - resolved "https://registry.npmjs.org/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly/-/plugin-bugfix-v8-static-class-fields-redefine-readonly-7.24.1.tgz" - integrity sha512-m9m/fXsXLiHfwdgydIFnpk+7jlVbnvlK5B2EKiPdLUb6WX654ZaaEWJUjk8TftRbZpK0XibovlLWX4KIZhV6jw== +"@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly/-/plugin-bugfix-v8-static-class-fields-redefine-readonly-7.25.7.tgz#9622b1d597a703aa3a921e6f58c9c2d9a028d2c5" + integrity sha512-UVATLMidXrnH+GMUIuxq55nejlj02HP7F5ETyBONzP6G87fPBogG4CH6kxrSrdIuAjdwNO9VzyaYsrZPscWUrw== dependencies: - "@babel/helper-environment-visitor" "^7.22.20" - "@babel/helper-plugin-utils" "^7.24.0" + "@babel/helper-plugin-utils" "^7.25.7" + "@babel/traverse" "^7.25.7" "@babel/plugin-proposal-async-generator-functions@^7.20.7": version "7.20.7" - resolved "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.20.7.tgz" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.20.7.tgz#bfb7276d2d573cb67ba379984a2334e262ba5326" integrity sha512-xMbiLsn/8RK7Wq7VeVytytS2L6qE69bXPB10YCmMdDZbKF4okCqY74pI/jJQ/8U0b/F6NrT2+14b8/P9/3AMGA== dependencies: "@babel/helper-environment-visitor" "^7.18.9" @@ -392,24 +319,24 @@ "@babel/plugin-proposal-class-properties@^7.18.6": version "7.18.6" - resolved "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.18.6.tgz" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.18.6.tgz#b110f59741895f7ec21a6fff696ec46265c446a3" integrity sha512-cumfXOF0+nzZrrN8Rf0t7M+tF6sZc7vhQwYQck9q1/5w2OExlD+b4v4RpMJFaV1Z7WcDRgO6FqvxqxGlwo+RHQ== dependencies: "@babel/helper-create-class-features-plugin" "^7.18.6" "@babel/helper-plugin-utils" "^7.18.6" "@babel/plugin-proposal-decorators@^7.23.2": - version "7.24.1" - resolved "https://registry.npmjs.org/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.24.1.tgz" - integrity sha512-zPEvzFijn+hRvJuX2Vu3KbEBN39LN3f7tW3MQO2LsIs57B26KU+kUc82BdAktS1VCM6libzh45eKGI65lg0cpA== + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.25.7.tgz#dabfd82df5dff3a8fc61a434233bf8227c88402c" + integrity sha512-q1mqqqH0e1lhmsEQHV5U8OmdueBC2y0RFr2oUzZoFRtN3MvPmt2fsFRcNQAoGLTSNdHBFUYGnlgcRFhkBbKjPw== dependencies: - "@babel/helper-create-class-features-plugin" "^7.24.1" - "@babel/helper-plugin-utils" "^7.24.0" - "@babel/plugin-syntax-decorators" "^7.24.1" + "@babel/helper-create-class-features-plugin" "^7.25.7" + "@babel/helper-plugin-utils" "^7.25.7" + "@babel/plugin-syntax-decorators" "^7.25.7" "@babel/plugin-proposal-object-rest-spread@^7.20.7": version "7.20.7" - resolved "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.20.7.tgz" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.20.7.tgz#aa662940ef425779c75534a5c41e9d936edc390a" integrity sha512-d2S98yCiLxDVmBmE8UjGcfPvNEUbA1U5q5WxaWFUGRzJSVAZqm5W6MbPct0jxnegUZ0niLeNX+IOzEs7wYg9Dg== dependencies: "@babel/compat-data" "^7.20.5" @@ -420,7 +347,7 @@ "@babel/plugin-proposal-private-methods@^7.18.6": version "7.18.6" - resolved "https://registry.npmjs.org/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.18.6.tgz" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.18.6.tgz#5209de7d213457548a98436fa2882f52f4be6bea" integrity sha512-nutsvktDItsNn4rpGItSNV2sz1XwS+nfU0Rg8aCx3W3NOKVzdMjJRu0O5OkgDp3ZGICSTbgRpxZoWsxoKRvbeA== dependencies: "@babel/helper-create-class-features-plugin" "^7.18.6" @@ -428,528 +355,438 @@ "@babel/plugin-proposal-private-property-in-object@7.21.0-placeholder-for-preset-env.2": version "7.21.0-placeholder-for-preset-env.2" - resolved "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.0-placeholder-for-preset-env.2.tgz" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.0-placeholder-for-preset-env.2.tgz#7844f9289546efa9febac2de4cfe358a050bd703" integrity sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w== "@babel/plugin-syntax-async-generators@^7.8.4": version "7.8.4" - resolved "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz#a983fb1aeb2ec3f6ed042a210f640e90e786fe0d" integrity sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw== dependencies: "@babel/helper-plugin-utils" "^7.8.0" -"@babel/plugin-syntax-class-properties@^7.12.13": - version "7.12.13" - resolved "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz" - integrity sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA== - dependencies: - "@babel/helper-plugin-utils" "^7.12.13" - -"@babel/plugin-syntax-class-static-block@^7.14.5": - version "7.14.5" - resolved "https://registry.npmjs.org/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz" - integrity sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw== - dependencies: - "@babel/helper-plugin-utils" "^7.14.5" - -"@babel/plugin-syntax-decorators@^7.24.1": - version "7.24.1" - resolved "https://registry.npmjs.org/@babel/plugin-syntax-decorators/-/plugin-syntax-decorators-7.24.1.tgz" - integrity sha512-05RJdO/cCrtVWuAaSn1tS3bH8jbsJa/Y1uD186u6J4C/1mnHFxseeuWpsqr9anvo7TUulev7tm7GDwRV+VuhDw== +"@babel/plugin-syntax-decorators@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-decorators/-/plugin-syntax-decorators-7.25.7.tgz#cf26fdde4e750688e133c0e33ead2506377e88f7" + integrity sha512-oXduHo642ZhstLVYTe2z2GSJIruU0c/W3/Ghr6A5yGMsVrvdnxO1z+3pbTcT7f3/Clnt+1z8D/w1r1f1SHaCHw== dependencies: - "@babel/helper-plugin-utils" "^7.24.0" + "@babel/helper-plugin-utils" "^7.25.7" "@babel/plugin-syntax-dynamic-import@^7.8.3": version "7.8.3" - resolved "https://registry.npmjs.org/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz#62bf98b2da3cd21d626154fc96ee5b3cb68eacb3" integrity sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ== dependencies: "@babel/helper-plugin-utils" "^7.8.0" -"@babel/plugin-syntax-export-namespace-from@^7.8.3": - version "7.8.3" - resolved "https://registry.npmjs.org/@babel/plugin-syntax-export-namespace-from/-/plugin-syntax-export-namespace-from-7.8.3.tgz" - integrity sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q== - dependencies: - "@babel/helper-plugin-utils" "^7.8.3" - -"@babel/plugin-syntax-flow@^7.24.1": - version "7.24.1" - resolved "https://registry.npmjs.org/@babel/plugin-syntax-flow/-/plugin-syntax-flow-7.24.1.tgz" - integrity sha512-sxi2kLTI5DeW5vDtMUsk4mTPwvlUDbjOnoWayhynCwrw4QXRld4QEYwqzY8JmQXaJUtgUuCIurtSRH5sn4c7mA== +"@babel/plugin-syntax-flow@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-flow/-/plugin-syntax-flow-7.25.7.tgz#7d1255201b55d7644c57e0eb354aaf9f8b8d2d02" + integrity sha512-fyoj6/YdVtlv2ROig/J0fP7hh/wNO1MJGm1NR70Pg7jbkF+jOUL9joorqaCOQh06Y+LfgTagHzC8KqZ3MF782w== dependencies: - "@babel/helper-plugin-utils" "^7.24.0" + "@babel/helper-plugin-utils" "^7.25.7" -"@babel/plugin-syntax-import-assertions@^7.24.1": - version "7.24.1" - resolved "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.24.1.tgz" - integrity sha512-IuwnI5XnuF189t91XbxmXeCDz3qs6iDRO7GJ++wcfgeXNs/8FmIlKcpDSXNVyuLQxlwvskmI3Ct73wUODkJBlQ== +"@babel/plugin-syntax-import-assertions@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.25.7.tgz#8ce248f9f4ed4b7ed4cb2e0eb4ed9efd9f52921f" + integrity sha512-ZvZQRmME0zfJnDQnVBKYzHxXT7lYBB3Revz1GuS7oLXWMgqUPX4G+DDbT30ICClht9WKV34QVrZhSw6WdklwZQ== dependencies: - "@babel/helper-plugin-utils" "^7.24.0" + "@babel/helper-plugin-utils" "^7.25.7" -"@babel/plugin-syntax-import-attributes@^7.24.1": - version "7.24.1" - resolved "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.24.1.tgz" - integrity sha512-zhQTMH0X2nVLnb04tz+s7AMuasX8U0FnpE+nHTOhSOINjWMnopoZTxtIKsd45n4GQ/HIZLyfIpoul8e2m0DnRA== +"@babel/plugin-syntax-import-attributes@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.25.7.tgz#d78dd0499d30df19a598e63ab895e21b909bc43f" + integrity sha512-AqVo+dguCgmpi/3mYBdu9lkngOBlQ2w2vnNpa6gfiCxQZLzV4ZbhsXitJ2Yblkoe1VQwtHSaNmIaGll/26YWRw== dependencies: - "@babel/helper-plugin-utils" "^7.24.0" + "@babel/helper-plugin-utils" "^7.25.7" "@babel/plugin-syntax-import-meta@^7.10.4": version "7.10.4" - resolved "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz#ee601348c370fa334d2207be158777496521fd51" integrity sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g== dependencies: "@babel/helper-plugin-utils" "^7.10.4" -"@babel/plugin-syntax-json-strings@^7.8.3": - version "7.8.3" - resolved "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz" - integrity sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA== +"@babel/plugin-syntax-jsx@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.25.7.tgz#5352d398d11ea5e7ef330c854dea1dae0bf18165" + integrity sha512-ruZOnKO+ajVL/MVx+PwNBPOkrnXTXoWMtte1MBpegfCArhqOe3Bj52avVj1huLLxNKYKXYaSxZ2F+woK1ekXfw== dependencies: - "@babel/helper-plugin-utils" "^7.8.0" + "@babel/helper-plugin-utils" "^7.25.7" -"@babel/plugin-syntax-jsx@^7.23.3": - version "7.23.3" - resolved "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.23.3.tgz" - integrity sha512-EB2MELswq55OHUoRZLGg/zC7QWUKfNLpE57m/S2yr1uEneIgsTgrSzXP3NXEsMkVn76OlaVVnzN+ugObuYGwhg== - dependencies: - "@babel/helper-plugin-utils" "^7.22.5" - -"@babel/plugin-syntax-logical-assignment-operators@^7.10.4": - version "7.10.4" - resolved "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz" - integrity sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig== - dependencies: - "@babel/helper-plugin-utils" "^7.10.4" - -"@babel/plugin-syntax-nullish-coalescing-operator@^7.8.3": +"@babel/plugin-syntax-object-rest-spread@^7.8.3": version "7.8.3" - resolved "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz" - integrity sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ== + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz#60e225edcbd98a640332a2e72dd3e66f1af55871" + integrity sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA== dependencies: "@babel/helper-plugin-utils" "^7.8.0" -"@babel/plugin-syntax-numeric-separator@^7.10.4": - version "7.10.4" - resolved "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz" - integrity sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug== +"@babel/plugin-syntax-unicode-sets-regex@^7.18.6": + version "7.18.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-unicode-sets-regex/-/plugin-syntax-unicode-sets-regex-7.18.6.tgz#d49a3b3e6b52e5be6740022317580234a6a47357" + integrity sha512-727YkEAPwSIQTv5im8QHz3upqp92JTWhidIC81Tdx4VJYIte/VndKf1qKrfnnhPLiPghStWfvC/iFaMCQu7Nqg== dependencies: - "@babel/helper-plugin-utils" "^7.10.4" + "@babel/helper-create-regexp-features-plugin" "^7.18.6" + "@babel/helper-plugin-utils" "^7.18.6" -"@babel/plugin-syntax-object-rest-spread@^7.8.3": - version "7.8.3" - resolved "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz" - integrity sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA== +"@babel/plugin-transform-arrow-functions@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.25.7.tgz#1b9ed22e6890a0e9ff470371c73b8c749bcec386" + integrity sha512-EJN2mKxDwfOUCPxMO6MUI58RN3ganiRAG/MS/S3HfB6QFNjroAMelQo/gybyYq97WerCBAZoyrAoW8Tzdq2jWg== dependencies: - "@babel/helper-plugin-utils" "^7.8.0" + "@babel/helper-plugin-utils" "^7.25.7" -"@babel/plugin-syntax-optional-catch-binding@^7.8.3": - version "7.8.3" - resolved "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz" - integrity sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q== +"@babel/plugin-transform-async-generator-functions@^7.25.8": + version "7.25.8" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.25.8.tgz#3331de02f52cc1f2c75b396bec52188c85b0b1ec" + integrity sha512-9ypqkozyzpG+HxlH4o4gdctalFGIjjdufzo7I2XPda0iBnZ6a+FO0rIEQcdSPXp02CkvGsII1exJhmROPQd5oA== dependencies: - "@babel/helper-plugin-utils" "^7.8.0" + "@babel/helper-plugin-utils" "^7.25.7" + "@babel/helper-remap-async-to-generator" "^7.25.7" + "@babel/traverse" "^7.25.7" -"@babel/plugin-syntax-optional-chaining@^7.8.3": - version "7.8.3" - resolved "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz" - integrity sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg== +"@babel/plugin-transform-async-to-generator@^7.22.5", "@babel/plugin-transform-async-to-generator@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.25.7.tgz#a44c7323f8d4285a6c568dd43c5c361d6367ec52" + integrity sha512-ZUCjAavsh5CESCmi/xCpX1qcCaAglzs/7tmuvoFnJgA1dM7gQplsguljoTg+Ru8WENpX89cQyAtWoaE0I3X3Pg== dependencies: - "@babel/helper-plugin-utils" "^7.8.0" + "@babel/helper-module-imports" "^7.25.7" + "@babel/helper-plugin-utils" "^7.25.7" + "@babel/helper-remap-async-to-generator" "^7.25.7" -"@babel/plugin-syntax-private-property-in-object@^7.14.5": - version "7.14.5" - resolved "https://registry.npmjs.org/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz" - integrity sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg== +"@babel/plugin-transform-block-scoped-functions@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.25.7.tgz#e0b8843d5571719a2f1bf7e284117a3379fcc17c" + integrity sha512-xHttvIM9fvqW+0a3tZlYcZYSBpSWzGBFIt/sYG3tcdSzBB8ZeVgz2gBP7Df+sM0N1850jrviYSSeUuc+135dmQ== dependencies: - "@babel/helper-plugin-utils" "^7.14.5" + "@babel/helper-plugin-utils" "^7.25.7" -"@babel/plugin-syntax-top-level-await@^7.14.5": - version "7.14.5" - resolved "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz" - integrity sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw== +"@babel/plugin-transform-block-scoping@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.25.7.tgz#6dab95e98adf780ceef1b1c3ab0e55cd20dd410a" + integrity sha512-ZEPJSkVZaeTFG/m2PARwLZQ+OG0vFIhPlKHK/JdIMy8DbRJ/htz6LRrTFtdzxi9EHmcwbNPAKDnadpNSIW+Aow== dependencies: - "@babel/helper-plugin-utils" "^7.14.5" + "@babel/helper-plugin-utils" "^7.25.7" -"@babel/plugin-syntax-unicode-sets-regex@^7.18.6": - version "7.18.6" - resolved "https://registry.npmjs.org/@babel/plugin-syntax-unicode-sets-regex/-/plugin-syntax-unicode-sets-regex-7.18.6.tgz" - integrity sha512-727YkEAPwSIQTv5im8QHz3upqp92JTWhidIC81Tdx4VJYIte/VndKf1qKrfnnhPLiPghStWfvC/iFaMCQu7Nqg== +"@babel/plugin-transform-class-properties@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.25.7.tgz#a389cfca7a10ac80e3ff4c75fca08bd097ad1523" + integrity sha512-mhyfEW4gufjIqYFo9krXHJ3ElbFLIze5IDp+wQTxoPd+mwFb1NxatNAwmv8Q8Iuxv7Zc+q8EkiMQwc9IhyGf4g== dependencies: - "@babel/helper-create-regexp-features-plugin" "^7.18.6" - "@babel/helper-plugin-utils" "^7.18.6" + "@babel/helper-create-class-features-plugin" "^7.25.7" + "@babel/helper-plugin-utils" "^7.25.7" -"@babel/plugin-transform-arrow-functions@^7.24.1": - version "7.24.1" - resolved "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.24.1.tgz" - integrity sha512-ngT/3NkRhsaep9ck9uj2Xhv9+xB1zShY3tM3g6om4xxCELwCDN4g4Aq5dRn48+0hasAql7s2hdBOysCfNpr4fw== +"@babel/plugin-transform-class-static-block@^7.25.8": + version "7.25.8" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.25.8.tgz#a8af22028920fe404668031eceb4c3aadccb5262" + integrity sha512-e82gl3TCorath6YLf9xUwFehVvjvfqFhdOo4+0iVIVju+6XOi5XHkqB3P2AXnSwoeTX0HBoXq5gJFtvotJzFnQ== dependencies: - "@babel/helper-plugin-utils" "^7.24.0" + "@babel/helper-create-class-features-plugin" "^7.25.7" + "@babel/helper-plugin-utils" "^7.25.7" -"@babel/plugin-transform-async-generator-functions@^7.24.3": - version "7.24.3" - resolved "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.24.3.tgz" - integrity sha512-Qe26CMYVjpQxJ8zxM1340JFNjZaF+ISWpr1Kt/jGo+ZTUzKkfw/pphEWbRCb+lmSM6k/TOgfYLvmbHkUQ0asIg== +"@babel/plugin-transform-classes@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-classes/-/plugin-transform-classes-7.25.7.tgz#5103206cf80d02283bbbd044509ea3b65d0906bb" + integrity sha512-9j9rnl+YCQY0IGoeipXvnk3niWicIB6kCsWRGLwX241qSXpbA4MKxtp/EdvFxsc4zI5vqfLxzOd0twIJ7I99zg== dependencies: - "@babel/helper-environment-visitor" "^7.22.20" - "@babel/helper-plugin-utils" "^7.24.0" - "@babel/helper-remap-async-to-generator" "^7.22.20" - "@babel/plugin-syntax-async-generators" "^7.8.4" - -"@babel/plugin-transform-async-to-generator@^7.22.5", "@babel/plugin-transform-async-to-generator@^7.24.1": - version "7.24.1" - resolved "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.24.1.tgz" - integrity sha512-AawPptitRXp1y0n4ilKcGbRYWfbbzFWz2NqNu7dacYDtFtz0CMjG64b3LQsb3KIgnf4/obcUL78hfaOS7iCUfw== - dependencies: - "@babel/helper-module-imports" "^7.24.1" - "@babel/helper-plugin-utils" "^7.24.0" - "@babel/helper-remap-async-to-generator" "^7.22.20" - -"@babel/plugin-transform-block-scoped-functions@^7.24.1": - version "7.24.1" - resolved "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.24.1.tgz" - integrity sha512-TWWC18OShZutrv9C6mye1xwtam+uNi2bnTOCBUd5sZxyHOiWbU6ztSROofIMrK84uweEZC219POICK/sTYwfgg== - dependencies: - "@babel/helper-plugin-utils" "^7.24.0" - -"@babel/plugin-transform-block-scoping@^7.24.4": - version "7.24.4" - resolved "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.24.4.tgz" - integrity sha512-nIFUZIpGKDf9O9ttyRXpHFpKC+X3Y5mtshZONuEUYBomAKoM4y029Jr+uB1bHGPhNmK8YXHevDtKDOLmtRrp6g== - dependencies: - "@babel/helper-plugin-utils" "^7.24.0" - -"@babel/plugin-transform-class-properties@^7.24.1": - version "7.24.1" - resolved "https://registry.npmjs.org/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.24.1.tgz" - integrity sha512-OMLCXi0NqvJfORTaPQBwqLXHhb93wkBKZ4aNwMl6WtehO7ar+cmp+89iPEQPqxAnxsOKTaMcs3POz3rKayJ72g== - dependencies: - "@babel/helper-create-class-features-plugin" "^7.24.1" - "@babel/helper-plugin-utils" "^7.24.0" - -"@babel/plugin-transform-class-static-block@^7.24.4": - version "7.24.4" - resolved "https://registry.npmjs.org/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.24.4.tgz" - integrity sha512-B8q7Pz870Hz/q9UgP8InNpY01CSLDSCyqX7zcRuv3FcPl87A2G17lASroHWaCtbdIcbYzOZ7kWmXFKbijMSmFg== - dependencies: - "@babel/helper-create-class-features-plugin" "^7.24.4" - "@babel/helper-plugin-utils" "^7.24.0" - "@babel/plugin-syntax-class-static-block" "^7.14.5" - -"@babel/plugin-transform-classes@^7.24.1": - version "7.24.1" - resolved "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.24.1.tgz" - integrity sha512-ZTIe3W7UejJd3/3R4p7ScyyOoafetUShSf4kCqV0O7F/RiHxVj/wRaRnQlrGwflvcehNA8M42HkAiEDYZu2F1Q== - dependencies: - "@babel/helper-annotate-as-pure" "^7.22.5" - "@babel/helper-compilation-targets" "^7.23.6" - "@babel/helper-environment-visitor" "^7.22.20" - "@babel/helper-function-name" "^7.23.0" - "@babel/helper-plugin-utils" "^7.24.0" - "@babel/helper-replace-supers" "^7.24.1" - "@babel/helper-split-export-declaration" "^7.22.6" + "@babel/helper-annotate-as-pure" "^7.25.7" + "@babel/helper-compilation-targets" "^7.25.7" + "@babel/helper-plugin-utils" "^7.25.7" + "@babel/helper-replace-supers" "^7.25.7" + "@babel/traverse" "^7.25.7" globals "^11.1.0" -"@babel/plugin-transform-computed-properties@^7.24.1": - version "7.24.1" - resolved "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.24.1.tgz" - integrity sha512-5pJGVIUfJpOS+pAqBQd+QMaTD2vCL/HcePooON6pDpHgRp4gNRmzyHTPIkXntwKsq3ayUFVfJaIKPw2pOkOcTw== +"@babel/plugin-transform-computed-properties@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.25.7.tgz#7f621f0aa1354b5348a935ab12e3903842466f65" + integrity sha512-QIv+imtM+EtNxg/XBKL3hiWjgdLjMOmZ+XzQwSgmBfKbfxUjBzGgVPklUuE55eq5/uVoh8gg3dqlrwR/jw3ZeA== dependencies: - "@babel/helper-plugin-utils" "^7.24.0" - "@babel/template" "^7.24.0" + "@babel/helper-plugin-utils" "^7.25.7" + "@babel/template" "^7.25.7" -"@babel/plugin-transform-destructuring@^7.24.1": - version "7.24.1" - resolved "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.24.1.tgz" - integrity sha512-ow8jciWqNxR3RYbSNVuF4U2Jx130nwnBnhRw6N6h1bOejNkABmcI5X5oz29K4alWX7vf1C+o6gtKXikzRKkVdw== +"@babel/plugin-transform-destructuring@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.25.7.tgz#f6f26a9feefb5aa41fd45b6f5838901b5333d560" + integrity sha512-xKcfLTlJYUczdaM1+epcdh1UGewJqr9zATgrNHcLBcV2QmfvPPEixo/sK/syql9cEmbr7ulu5HMFG5vbbt/sEA== dependencies: - "@babel/helper-plugin-utils" "^7.24.0" + "@babel/helper-plugin-utils" "^7.25.7" -"@babel/plugin-transform-dotall-regex@^7.24.1": - version "7.24.1" - resolved "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.24.1.tgz" - integrity sha512-p7uUxgSoZwZ2lPNMzUkqCts3xlp8n+o05ikjy7gbtFJSt9gdU88jAmtfmOxHM14noQXBxfgzf2yRWECiNVhTCw== +"@babel/plugin-transform-dotall-regex@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.25.7.tgz#9d775c4a3ff1aea64045300fcd4309b4a610ef02" + integrity sha512-kXzXMMRzAtJdDEgQBLF4oaiT6ZCU3oWHgpARnTKDAqPkDJ+bs3NrZb310YYevR5QlRo3Kn7dzzIdHbZm1VzJdQ== dependencies: - "@babel/helper-create-regexp-features-plugin" "^7.22.15" - "@babel/helper-plugin-utils" "^7.24.0" + "@babel/helper-create-regexp-features-plugin" "^7.25.7" + "@babel/helper-plugin-utils" "^7.25.7" -"@babel/plugin-transform-duplicate-keys@^7.24.1": - version "7.24.1" - resolved "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.24.1.tgz" - integrity sha512-msyzuUnvsjsaSaocV6L7ErfNsa5nDWL1XKNnDePLgmz+WdU4w/J8+AxBMrWfi9m4IxfL5sZQKUPQKDQeeAT6lA== +"@babel/plugin-transform-duplicate-keys@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.25.7.tgz#fbba7d1155eab76bd4f2a038cbd5d65883bd7a93" + integrity sha512-by+v2CjoL3aMnWDOyCIg+yxU9KXSRa9tN6MbqggH5xvymmr9p4AMjYkNlQy4brMceBnUyHZ9G8RnpvT8wP7Cfg== dependencies: - "@babel/helper-plugin-utils" "^7.24.0" + "@babel/helper-plugin-utils" "^7.25.7" -"@babel/plugin-transform-dynamic-import@^7.24.1": - version "7.24.1" - resolved "https://registry.npmjs.org/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.24.1.tgz" - integrity sha512-av2gdSTyXcJVdI+8aFZsCAtR29xJt0S5tas+Ef8NvBNmD1a+N/3ecMLeMBgfcK+xzsjdLDT6oHt+DFPyeqUbDA== +"@babel/plugin-transform-duplicate-named-capturing-groups-regex@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-duplicate-named-capturing-groups-regex/-/plugin-transform-duplicate-named-capturing-groups-regex-7.25.7.tgz#102b31608dcc22c08fbca1894e104686029dc141" + integrity sha512-HvS6JF66xSS5rNKXLqkk7L9c/jZ/cdIVIcoPVrnl8IsVpLggTjXs8OWekbLHs/VtYDDh5WXnQyeE3PPUGm22MA== dependencies: - "@babel/helper-plugin-utils" "^7.24.0" - "@babel/plugin-syntax-dynamic-import" "^7.8.3" + "@babel/helper-create-regexp-features-plugin" "^7.25.7" + "@babel/helper-plugin-utils" "^7.25.7" -"@babel/plugin-transform-exponentiation-operator@^7.22.5", "@babel/plugin-transform-exponentiation-operator@^7.24.1": - version "7.24.1" - resolved "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.24.1.tgz" - integrity sha512-U1yX13dVBSwS23DEAqU+Z/PkwE9/m7QQy8Y9/+Tdb8UWYaGNDYwTLi19wqIAiROr8sXVum9A/rtiH5H0boUcTw== +"@babel/plugin-transform-dynamic-import@^7.25.8": + version "7.25.8" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.25.8.tgz#f1edbe75b248cf44c70c8ca8ed3818a668753aaa" + integrity sha512-gznWY+mr4ZQL/EWPcbBQUP3BXS5FwZp8RUOw06BaRn8tQLzN4XLIxXejpHN9Qo8x8jjBmAAKp6FoS51AgkSA/A== dependencies: - "@babel/helper-builder-binary-assignment-operator-visitor" "^7.22.15" - "@babel/helper-plugin-utils" "^7.24.0" + "@babel/helper-plugin-utils" "^7.25.7" -"@babel/plugin-transform-export-namespace-from@^7.24.1": - version "7.24.1" - resolved "https://registry.npmjs.org/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.24.1.tgz" - integrity sha512-Ft38m/KFOyzKw2UaJFkWG9QnHPG/Q/2SkOrRk4pNBPg5IPZ+dOxcmkK5IyuBcxiNPyyYowPGUReyBvrvZs7IlQ== +"@babel/plugin-transform-exponentiation-operator@^7.22.5", "@babel/plugin-transform-exponentiation-operator@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.25.7.tgz#5961a3a23a398faccd6cddb34a2182807d75fb5f" + integrity sha512-yjqtpstPfZ0h/y40fAXRv2snciYr0OAoMXY/0ClC7tm4C/nG5NJKmIItlaYlLbIVAWNfrYuy9dq1bE0SbX0PEg== dependencies: - "@babel/helper-plugin-utils" "^7.24.0" - "@babel/plugin-syntax-export-namespace-from" "^7.8.3" + "@babel/helper-builder-binary-assignment-operator-visitor" "^7.25.7" + "@babel/helper-plugin-utils" "^7.25.7" -"@babel/plugin-transform-flow-strip-types@^7.24.1": - version "7.24.1" - resolved "https://registry.npmjs.org/@babel/plugin-transform-flow-strip-types/-/plugin-transform-flow-strip-types-7.24.1.tgz" - integrity sha512-iIYPIWt3dUmUKKE10s3W+jsQ3icFkw0JyRVyY1B7G4yK/nngAOHLVx8xlhA6b/Jzl/Y0nis8gjqhqKtRDQqHWQ== +"@babel/plugin-transform-export-namespace-from@^7.25.8": + version "7.25.8" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.25.8.tgz#d1988c3019a380b417e0516418b02804d3858145" + integrity sha512-sPtYrduWINTQTW7FtOy99VCTWp4H23UX7vYcut7S4CIMEXU+54zKX9uCoGkLsWXteyaMXzVHgzWbLfQ1w4GZgw== dependencies: - "@babel/helper-plugin-utils" "^7.24.0" - "@babel/plugin-syntax-flow" "^7.24.1" + "@babel/helper-plugin-utils" "^7.25.7" -"@babel/plugin-transform-for-of@^7.22.15", "@babel/plugin-transform-for-of@^7.24.1": - version "7.24.1" - resolved "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.24.1.tgz" - integrity sha512-OxBdcnF04bpdQdR3i4giHZNZQn7cm8RQKcSwA17wAAqEELo1ZOwp5FFgeptWUQXFyT9kwHo10aqqauYkRZPCAg== +"@babel/plugin-transform-flow-strip-types@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-flow-strip-types/-/plugin-transform-flow-strip-types-7.25.7.tgz#32be871a80e10bbe6d8b1c8a7eeedbbc896d5e80" + integrity sha512-q8Td2PPc6/6I73g96SreSUCKEcwMXCwcXSIAVTyTTN6CpJe0dMj8coxu1fg1T9vfBLi6Rsi6a4ECcFBbKabS5w== dependencies: - "@babel/helper-plugin-utils" "^7.24.0" - "@babel/helper-skip-transparent-expression-wrappers" "^7.22.5" + "@babel/helper-plugin-utils" "^7.25.7" + "@babel/plugin-syntax-flow" "^7.25.7" -"@babel/plugin-transform-function-name@^7.24.1": - version "7.24.1" - resolved "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.24.1.tgz" - integrity sha512-BXmDZpPlh7jwicKArQASrj8n22/w6iymRnvHYYd2zO30DbE277JO20/7yXJT3QxDPtiQiOxQBbZH4TpivNXIxA== +"@babel/plugin-transform-for-of@^7.22.15", "@babel/plugin-transform-for-of@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.25.7.tgz#0acfea0f27aa290818b5b48a5a44b3f03fc13669" + integrity sha512-n/TaiBGJxYFWvpJDfsxSj9lEEE44BFM1EPGz4KEiTipTgkoFVVcCmzAL3qA7fdQU96dpo4gGf5HBx/KnDvqiHw== dependencies: - "@babel/helper-compilation-targets" "^7.23.6" - "@babel/helper-function-name" "^7.23.0" - "@babel/helper-plugin-utils" "^7.24.0" + "@babel/helper-plugin-utils" "^7.25.7" + "@babel/helper-skip-transparent-expression-wrappers" "^7.25.7" -"@babel/plugin-transform-json-strings@^7.24.1": - version "7.24.1" - resolved "https://registry.npmjs.org/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.24.1.tgz" - integrity sha512-U7RMFmRvoasscrIFy5xA4gIp8iWnWubnKkKuUGJjsuOH7GfbMkB+XZzeslx2kLdEGdOJDamEmCqOks6e8nv8DQ== +"@babel/plugin-transform-function-name@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.25.7.tgz#7e394ccea3693902a8b50ded8b6ae1fa7b8519fd" + integrity sha512-5MCTNcjCMxQ63Tdu9rxyN6cAWurqfrDZ76qvVPrGYdBxIj+EawuuxTu/+dgJlhK5eRz3v1gLwp6XwS8XaX2NiQ== dependencies: - "@babel/helper-plugin-utils" "^7.24.0" - "@babel/plugin-syntax-json-strings" "^7.8.3" + "@babel/helper-compilation-targets" "^7.25.7" + "@babel/helper-plugin-utils" "^7.25.7" + "@babel/traverse" "^7.25.7" -"@babel/plugin-transform-literals@^7.24.1": - version "7.24.1" - resolved "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.24.1.tgz" - integrity sha512-zn9pwz8U7nCqOYIiBaOxoQOtYmMODXTJnkxG4AtX8fPmnCRYWBOHD0qcpwS9e2VDSp1zNJYpdnFMIKb8jmwu6g== +"@babel/plugin-transform-json-strings@^7.25.8": + version "7.25.8" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.25.8.tgz#6fb3ec383a2ea92652289fdba653e3f9de722694" + integrity sha512-4OMNv7eHTmJ2YXs3tvxAfa/I43di+VcF+M4Wt66c88EAED1RoGaf1D64cL5FkRpNL+Vx9Hds84lksWvd/wMIdA== dependencies: - "@babel/helper-plugin-utils" "^7.24.0" + "@babel/helper-plugin-utils" "^7.25.7" -"@babel/plugin-transform-logical-assignment-operators@^7.24.1": - version "7.24.1" - resolved "https://registry.npmjs.org/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.24.1.tgz" - integrity sha512-OhN6J4Bpz+hIBqItTeWJujDOfNP+unqv/NJgyhlpSqgBTPm37KkMmZV6SYcOj+pnDbdcl1qRGV/ZiIjX9Iy34w== +"@babel/plugin-transform-literals@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-literals/-/plugin-transform-literals-7.25.7.tgz#70cbdc742f2cfdb1a63ea2cbd018d12a60b213c3" + integrity sha512-fwzkLrSu2fESR/cm4t6vqd7ebNIopz2QHGtjoU+dswQo/P6lwAG04Q98lliE3jkz/XqnbGFLnUcE0q0CVUf92w== dependencies: - "@babel/helper-plugin-utils" "^7.24.0" - "@babel/plugin-syntax-logical-assignment-operators" "^7.10.4" + "@babel/helper-plugin-utils" "^7.25.7" -"@babel/plugin-transform-member-expression-literals@^7.24.1": - version "7.24.1" - resolved "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.24.1.tgz" - integrity sha512-4ojai0KysTWXzHseJKa1XPNXKRbuUrhkOPY4rEGeR+7ChlJVKxFa3H3Bz+7tWaGKgJAXUWKOGmltN+u9B3+CVg== +"@babel/plugin-transform-logical-assignment-operators@^7.25.8": + version "7.25.8" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.25.8.tgz#01868ff92daa9e525b4c7902aa51979082a05710" + integrity sha512-f5W0AhSbbI+yY6VakT04jmxdxz+WsID0neG7+kQZbCOjuyJNdL5Nn4WIBm4hRpKnUcO9lP0eipUhFN12JpoH8g== dependencies: - "@babel/helper-plugin-utils" "^7.24.0" + "@babel/helper-plugin-utils" "^7.25.7" -"@babel/plugin-transform-modules-amd@^7.24.1": - version "7.24.1" - resolved "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.24.1.tgz" - integrity sha512-lAxNHi4HVtjnHd5Rxg3D5t99Xm6H7b04hUS7EHIXcUl2EV4yl1gWdqZrNzXnSrHveL9qMdbODlLF55mvgjAfaQ== +"@babel/plugin-transform-member-expression-literals@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.25.7.tgz#0a36c3fbd450cc9e6485c507f005fa3d1bc8fca5" + integrity sha512-Std3kXwpXfRV0QtQy5JJcRpkqP8/wG4XL7hSKZmGlxPlDqmpXtEPRmhF7ztnlTCtUN3eXRUJp+sBEZjaIBVYaw== dependencies: - "@babel/helper-module-transforms" "^7.23.3" - "@babel/helper-plugin-utils" "^7.24.0" + "@babel/helper-plugin-utils" "^7.25.7" -"@babel/plugin-transform-modules-commonjs@^7.24.1": - version "7.24.1" - resolved "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.24.1.tgz" - integrity sha512-szog8fFTUxBfw0b98gEWPaEqF42ZUD/T3bkynW/wtgx2p/XCP55WEsb+VosKceRSd6njipdZvNogqdtI4Q0chw== +"@babel/plugin-transform-modules-amd@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.25.7.tgz#bb4e543b5611f6c8c685a2fd485408713a3adf3d" + integrity sha512-CgselSGCGzjQvKzghCvDTxKHP3iooenLpJDO842ehn5D2G5fJB222ptnDwQho0WjEvg7zyoxb9P+wiYxiJX5yA== dependencies: - "@babel/helper-module-transforms" "^7.23.3" - "@babel/helper-plugin-utils" "^7.24.0" - "@babel/helper-simple-access" "^7.22.5" + "@babel/helper-module-transforms" "^7.25.7" + "@babel/helper-plugin-utils" "^7.25.7" -"@babel/plugin-transform-modules-systemjs@^7.24.1": - version "7.24.1" - resolved "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.24.1.tgz" - integrity sha512-mqQ3Zh9vFO1Tpmlt8QPnbwGHzNz3lpNEMxQb1kAemn/erstyqw1r9KeOlOfo3y6xAnFEcOv2tSyrXfmMk+/YZA== +"@babel/plugin-transform-modules-commonjs@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.25.7.tgz#173f0c791bb7407c092ce6d77ee90eb3f2d1d2fd" + integrity sha512-L9Gcahi0kKFYXvweO6n0wc3ZG1ChpSFdgG+eV1WYZ3/dGbJK7vvk91FgGgak8YwRgrCuihF8tE/Xg07EkL5COg== dependencies: - "@babel/helper-hoist-variables" "^7.22.5" - "@babel/helper-module-transforms" "^7.23.3" - "@babel/helper-plugin-utils" "^7.24.0" - "@babel/helper-validator-identifier" "^7.22.20" + "@babel/helper-module-transforms" "^7.25.7" + "@babel/helper-plugin-utils" "^7.25.7" + "@babel/helper-simple-access" "^7.25.7" -"@babel/plugin-transform-modules-umd@^7.24.1": - version "7.24.1" - resolved "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.24.1.tgz" - integrity sha512-tuA3lpPj+5ITfcCluy6nWonSL7RvaG0AOTeAuvXqEKS34lnLzXpDb0dcP6K8jD0zWZFNDVly90AGFJPnm4fOYg== +"@babel/plugin-transform-modules-systemjs@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.25.7.tgz#8b14d319a177cc9c85ef8b0512afd429d9e2e60b" + integrity sha512-t9jZIvBmOXJsiuyOwhrIGs8dVcD6jDyg2icw1VL4A/g+FnWyJKwUfSSU2nwJuMV2Zqui856El9u+ElB+j9fV1g== dependencies: - "@babel/helper-module-transforms" "^7.23.3" - "@babel/helper-plugin-utils" "^7.24.0" + "@babel/helper-module-transforms" "^7.25.7" + "@babel/helper-plugin-utils" "^7.25.7" + "@babel/helper-validator-identifier" "^7.25.7" + "@babel/traverse" "^7.25.7" -"@babel/plugin-transform-named-capturing-groups-regex@^7.22.5": - version "7.22.5" - resolved "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.22.5.tgz" - integrity sha512-YgLLKmS3aUBhHaxp5hi1WJTgOUb/NCuDHzGT9z9WTt3YG+CPRhJs6nprbStx6DnWM4dh6gt7SU3sZodbZ08adQ== +"@babel/plugin-transform-modules-umd@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.25.7.tgz#00ee7a7e124289549381bfb0e24d87fd7f848367" + integrity sha512-p88Jg6QqsaPh+EB7I9GJrIqi1Zt4ZBHUQtjw3z1bzEXcLh6GfPqzZJ6G+G1HBGKUNukT58MnKG7EN7zXQBCODw== dependencies: - "@babel/helper-create-regexp-features-plugin" "^7.22.5" - "@babel/helper-plugin-utils" "^7.22.5" + "@babel/helper-module-transforms" "^7.25.7" + "@babel/helper-plugin-utils" "^7.25.7" -"@babel/plugin-transform-new-target@^7.24.1": - version "7.24.1" - resolved "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.24.1.tgz" - integrity sha512-/rurytBM34hYy0HKZQyA0nHbQgQNFm4Q/BOc9Hflxi2X3twRof7NaE5W46j4kQitm7SvACVRXsa6N/tSZxvPug== +"@babel/plugin-transform-named-capturing-groups-regex@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.25.7.tgz#a2f3f6d7f38693b462542951748f0a72a34d196d" + integrity sha512-BtAT9LzCISKG3Dsdw5uso4oV1+v2NlVXIIomKJgQybotJY3OwCwJmkongjHgwGKoZXd0qG5UZ12JUlDQ07W6Ow== dependencies: - "@babel/helper-plugin-utils" "^7.24.0" + "@babel/helper-create-regexp-features-plugin" "^7.25.7" + "@babel/helper-plugin-utils" "^7.25.7" -"@babel/plugin-transform-nullish-coalescing-operator@^7.24.1": - version "7.24.1" - resolved "https://registry.npmjs.org/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.24.1.tgz" - integrity sha512-iQ+caew8wRrhCikO5DrUYx0mrmdhkaELgFa+7baMcVuhxIkN7oxt06CZ51D65ugIb1UWRQ8oQe+HXAVM6qHFjw== +"@babel/plugin-transform-new-target@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.25.7.tgz#52b2bde523b76c548749f38dc3054f1f45e82bc9" + integrity sha512-CfCS2jDsbcZaVYxRFo2qtavW8SpdzmBXC2LOI4oO0rP+JSRDxxF3inF4GcPsLgfb5FjkhXG5/yR/lxuRs2pySA== dependencies: - "@babel/helper-plugin-utils" "^7.24.0" - "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.3" + "@babel/helper-plugin-utils" "^7.25.7" -"@babel/plugin-transform-numeric-separator@^7.24.1": - version "7.24.1" - resolved "https://registry.npmjs.org/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.24.1.tgz" - integrity sha512-7GAsGlK4cNL2OExJH1DzmDeKnRv/LXq0eLUSvudrehVA5Rgg4bIrqEUW29FbKMBRT0ztSqisv7kjP+XIC4ZMNw== +"@babel/plugin-transform-nullish-coalescing-operator@^7.25.8": + version "7.25.8" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.25.8.tgz#befb4900c130bd52fccf2b926314557987f1b552" + integrity sha512-Z7WJJWdQc8yCWgAmjI3hyC+5PXIubH9yRKzkl9ZEG647O9szl9zvmKLzpbItlijBnVhTUf1cpyWBsZ3+2wjWPQ== dependencies: - "@babel/helper-plugin-utils" "^7.24.0" - "@babel/plugin-syntax-numeric-separator" "^7.10.4" + "@babel/helper-plugin-utils" "^7.25.7" -"@babel/plugin-transform-object-rest-spread@^7.24.1": - version "7.24.1" - resolved "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.24.1.tgz" - integrity sha512-XjD5f0YqOtebto4HGISLNfiNMTTs6tbkFf2TOqJlYKYmbo+mN9Dnpl4SRoofiziuOWMIyq3sZEUqLo3hLITFEA== +"@babel/plugin-transform-numeric-separator@^7.25.8": + version "7.25.8" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.25.8.tgz#91e370486371637bd42161052f2602c701386891" + integrity sha512-rm9a5iEFPS4iMIy+/A/PiS0QN0UyjPIeVvbU5EMZFKJZHt8vQnasbpo3T3EFcxzCeYO0BHfc4RqooCZc51J86Q== dependencies: - "@babel/helper-compilation-targets" "^7.23.6" - "@babel/helper-plugin-utils" "^7.24.0" - "@babel/plugin-syntax-object-rest-spread" "^7.8.3" - "@babel/plugin-transform-parameters" "^7.24.1" + "@babel/helper-plugin-utils" "^7.25.7" -"@babel/plugin-transform-object-super@^7.24.1": - version "7.24.1" - resolved "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.24.1.tgz" - integrity sha512-oKJqR3TeI5hSLRxudMjFQ9re9fBVUU0GICqM3J1mi8MqlhVr6hC/ZN4ttAyMuQR6EZZIY6h/exe5swqGNNIkWQ== +"@babel/plugin-transform-object-rest-spread@^7.25.8": + version "7.25.8" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.25.8.tgz#0904ac16bcce41df4db12d915d6780f85c7fb04b" + integrity sha512-LkUu0O2hnUKHKE7/zYOIjByMa4VRaV2CD/cdGz0AxU9we+VA3kDDggKEzI0Oz1IroG+6gUP6UmWEHBMWZU316g== dependencies: - "@babel/helper-plugin-utils" "^7.24.0" - "@babel/helper-replace-supers" "^7.24.1" + "@babel/helper-compilation-targets" "^7.25.7" + "@babel/helper-plugin-utils" "^7.25.7" + "@babel/plugin-transform-parameters" "^7.25.7" -"@babel/plugin-transform-optional-catch-binding@^7.24.1": - version "7.24.1" - resolved "https://registry.npmjs.org/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.24.1.tgz" - integrity sha512-oBTH7oURV4Y+3EUrf6cWn1OHio3qG/PVwO5J03iSJmBg6m2EhKjkAu/xuaXaYwWW9miYtvbWv4LNf0AmR43LUA== +"@babel/plugin-transform-object-super@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.25.7.tgz#582a9cea8cf0a1e02732be5b5a703a38dedf5661" + integrity sha512-pWT6UXCEW3u1t2tcAGtE15ornCBvopHj9Bps9D2DsH15APgNVOTwwczGckX+WkAvBmuoYKRCFa4DK+jM8vh5AA== dependencies: - "@babel/helper-plugin-utils" "^7.24.0" - "@babel/plugin-syntax-optional-catch-binding" "^7.8.3" + "@babel/helper-plugin-utils" "^7.25.7" + "@babel/helper-replace-supers" "^7.25.7" -"@babel/plugin-transform-optional-chaining@^7.24.1": - version "7.24.1" - resolved "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.24.1.tgz" - integrity sha512-n03wmDt+987qXwAgcBlnUUivrZBPZ8z1plL0YvgQalLm+ZE5BMhGm94jhxXtA1wzv1Cu2aaOv1BM9vbVttrzSg== +"@babel/plugin-transform-optional-catch-binding@^7.25.8": + version "7.25.8" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.25.8.tgz#2649b86a3bb202c6894ec81a6ddf41b94d8f3103" + integrity sha512-EbQYweoMAHOn7iJ9GgZo14ghhb9tTjgOc88xFgYngifx7Z9u580cENCV159M4xDh3q/irbhSjZVpuhpC2gKBbg== dependencies: - "@babel/helper-plugin-utils" "^7.24.0" - "@babel/helper-skip-transparent-expression-wrappers" "^7.22.5" - "@babel/plugin-syntax-optional-chaining" "^7.8.3" + "@babel/helper-plugin-utils" "^7.25.7" -"@babel/plugin-transform-parameters@^7.20.7": - version "7.23.3" - resolved "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.23.3.tgz" - integrity sha512-09lMt6UsUb3/34BbECKVbVwrT9bO6lILWln237z7sLaWnMsTi7Yc9fhX5DLpkJzAGfaReXI22wP41SZmnAA3Vw== +"@babel/plugin-transform-optional-chaining@^7.25.7", "@babel/plugin-transform-optional-chaining@^7.25.8": + version "7.25.8" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.25.8.tgz#f46283b78adcc5b6ab988a952f989e7dce70653f" + integrity sha512-q05Bk7gXOxpTHoQ8RSzGSh/LHVB9JEIkKnk3myAWwZHnYiTGYtbdrYkIsS8Xyh4ltKf7GNUSgzs/6P2bJtBAQg== dependencies: - "@babel/helper-plugin-utils" "^7.22.5" + "@babel/helper-plugin-utils" "^7.25.7" + "@babel/helper-skip-transparent-expression-wrappers" "^7.25.7" -"@babel/plugin-transform-parameters@^7.24.1": - version "7.24.1" - resolved "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.24.1.tgz" - integrity sha512-8Jl6V24g+Uw5OGPeWNKrKqXPDw2YDjLc53ojwfMcKwlEoETKU9rU0mHUtcg9JntWI/QYzGAXNWEcVHZ+fR+XXg== +"@babel/plugin-transform-parameters@^7.20.7", "@babel/plugin-transform-parameters@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.25.7.tgz#80c38b03ef580f6d6bffe1c5254bb35986859ac7" + integrity sha512-FYiTvku63me9+1Nz7TOx4YMtW3tWXzfANZtrzHhUZrz4d47EEtMQhzFoZWESfXuAMMT5mwzD4+y1N8ONAX6lMQ== dependencies: - "@babel/helper-plugin-utils" "^7.24.0" + "@babel/helper-plugin-utils" "^7.25.7" -"@babel/plugin-transform-private-methods@^7.24.1": - version "7.24.1" - resolved "https://registry.npmjs.org/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.24.1.tgz" - integrity sha512-tGvisebwBO5em4PaYNqt4fkw56K2VALsAbAakY0FjTYqJp7gfdrgr7YX76Or8/cpik0W6+tj3rZ0uHU9Oil4tw== +"@babel/plugin-transform-private-methods@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.25.7.tgz#c790a04f837b4bd61d6b0317b43aa11ff67dce80" + integrity sha512-KY0hh2FluNxMLwOCHbxVOKfdB5sjWG4M183885FmaqWWiGMhRZq4DQRKH6mHdEucbJnyDyYiZNwNG424RymJjA== dependencies: - "@babel/helper-create-class-features-plugin" "^7.24.1" - "@babel/helper-plugin-utils" "^7.24.0" + "@babel/helper-create-class-features-plugin" "^7.25.7" + "@babel/helper-plugin-utils" "^7.25.7" -"@babel/plugin-transform-private-property-in-object@^7.24.1": - version "7.24.1" - resolved "https://registry.npmjs.org/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.24.1.tgz" - integrity sha512-pTHxDVa0BpUbvAgX3Gat+7cSciXqUcY9j2VZKTbSB6+VQGpNgNO9ailxTGHSXlqOnX1Hcx1Enme2+yv7VqP9bg== +"@babel/plugin-transform-private-property-in-object@^7.25.8": + version "7.25.8" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.25.8.tgz#1234f856ce85e061f9688764194e51ea7577c434" + integrity sha512-8Uh966svuB4V8RHHg0QJOB32QK287NBksJOByoKmHMp1TAobNniNalIkI2i5IPj5+S9NYCG4VIjbEuiSN8r+ow== dependencies: - "@babel/helper-annotate-as-pure" "^7.22.5" - "@babel/helper-create-class-features-plugin" "^7.24.1" - "@babel/helper-plugin-utils" "^7.24.0" - "@babel/plugin-syntax-private-property-in-object" "^7.14.5" + "@babel/helper-annotate-as-pure" "^7.25.7" + "@babel/helper-create-class-features-plugin" "^7.25.7" + "@babel/helper-plugin-utils" "^7.25.7" -"@babel/plugin-transform-property-literals@^7.24.1": - version "7.24.1" - resolved "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.24.1.tgz" - integrity sha512-LetvD7CrHmEx0G442gOomRr66d7q8HzzGGr4PMHGr+5YIm6++Yke+jxj246rpvsbyhJwCLxcTn6zW1P1BSenqA== +"@babel/plugin-transform-property-literals@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.25.7.tgz#a8612b4ea4e10430f00012ecf0155662c7d6550d" + integrity sha512-lQEeetGKfFi0wHbt8ClQrUSUMfEeI3MMm74Z73T9/kuz990yYVtfofjf3NuA42Jy3auFOpbjDyCSiIkTs1VIYw== dependencies: - "@babel/helper-plugin-utils" "^7.24.0" + "@babel/helper-plugin-utils" "^7.25.7" -"@babel/plugin-transform-react-display-name@^7.24.1": - version "7.24.1" - resolved "https://registry.npmjs.org/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.24.1.tgz" - integrity sha512-mvoQg2f9p2qlpDQRBC7M3c3XTr0k7cp/0+kFKKO/7Gtu0LSw16eKB+Fabe2bDT/UpsyasTBBkAnbdsLrkD5XMw== +"@babel/plugin-transform-react-display-name@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.25.7.tgz#2753e875a1b702fb1d806c4f5d4c194d64cadd88" + integrity sha512-r0QY7NVU8OnrwE+w2IWiRom0wwsTbjx4+xH2RTd7AVdof3uurXOF+/mXHQDRk+2jIvWgSaCHKMgggfvM4dyUGA== dependencies: - "@babel/helper-plugin-utils" "^7.24.0" + "@babel/helper-plugin-utils" "^7.25.7" -"@babel/plugin-transform-react-jsx-development@^7.22.5": - version "7.22.5" - resolved "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-development/-/plugin-transform-react-jsx-development-7.22.5.tgz" - integrity sha512-bDhuzwWMuInwCYeDeMzyi7TaBgRQei6DqxhbyniL7/VG4RSS7HtSL2QbY4eESy1KJqlWt8g3xeEBGPuo+XqC8A== +"@babel/plugin-transform-react-jsx-development@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx-development/-/plugin-transform-react-jsx-development-7.25.7.tgz#2fbd77887b8fa2942d7cb61edf1029ea1b048554" + integrity sha512-5yd3lH1PWxzW6IZj+p+Y4OLQzz0/LzlOG8vGqonHfVR3euf1vyzyMUJk9Ac+m97BH46mFc/98t9PmYLyvgL3qg== dependencies: - "@babel/plugin-transform-react-jsx" "^7.22.5" + "@babel/plugin-transform-react-jsx" "^7.25.7" -"@babel/plugin-transform-react-jsx@^7.22.5", "@babel/plugin-transform-react-jsx@^7.23.4": - version "7.23.4" - resolved "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.23.4.tgz" - integrity sha512-5xOpoPguCZCRbo/JeHlloSkTA8Bld1J/E1/kLfD1nsuiW1m8tduTA1ERCgIZokDflX/IBzKcqR3l7VlRgiIfHA== +"@babel/plugin-transform-react-jsx@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.25.7.tgz#f5e2af6020a562fe048dd343e571c4428e6c5632" + integrity sha512-vILAg5nwGlR9EXE8JIOX4NHXd49lrYbN8hnjffDtoULwpL9hUx/N55nqh2qd0q6FyNDfjl9V79ecKGvFbcSA0Q== dependencies: - "@babel/helper-annotate-as-pure" "^7.22.5" - "@babel/helper-module-imports" "^7.22.15" - "@babel/helper-plugin-utils" "^7.22.5" - "@babel/plugin-syntax-jsx" "^7.23.3" - "@babel/types" "^7.23.4" + "@babel/helper-annotate-as-pure" "^7.25.7" + "@babel/helper-module-imports" "^7.25.7" + "@babel/helper-plugin-utils" "^7.25.7" + "@babel/plugin-syntax-jsx" "^7.25.7" + "@babel/types" "^7.25.7" -"@babel/plugin-transform-react-pure-annotations@^7.24.1": - version "7.24.1" - resolved "https://registry.npmjs.org/@babel/plugin-transform-react-pure-annotations/-/plugin-transform-react-pure-annotations-7.24.1.tgz" - integrity sha512-+pWEAaDJvSm9aFvJNpLiM2+ktl2Sn2U5DdyiWdZBxmLc6+xGt88dvFqsHiAiDS+8WqUwbDfkKz9jRxK3M0k+kA== +"@babel/plugin-transform-react-pure-annotations@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-react-pure-annotations/-/plugin-transform-react-pure-annotations-7.25.7.tgz#6d0b8dadb2d3c5cbb8ade68c5efd49470b0d65f7" + integrity sha512-6YTHJ7yjjgYqGc8S+CbEXhLICODk0Tn92j+vNJo07HFk9t3bjFgAKxPLFhHwF2NjmQVSI1zBRfBWUeVBa2osfA== dependencies: - "@babel/helper-annotate-as-pure" "^7.22.5" - "@babel/helper-plugin-utils" "^7.24.0" + "@babel/helper-annotate-as-pure" "^7.25.7" + "@babel/helper-plugin-utils" "^7.25.7" -"@babel/plugin-transform-regenerator@^7.24.1": - version "7.24.1" - resolved "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.24.1.tgz" - integrity sha512-sJwZBCzIBE4t+5Q4IGLaaun5ExVMRY0lYwos/jNecjMrVCygCdph3IKv0tkP5Fc87e/1+bebAmEAGBfnRD+cnw== +"@babel/plugin-transform-regenerator@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.25.7.tgz#6eb006e6d26f627bc2f7844a9f19770721ad6f3e" + integrity sha512-mgDoQCRjrY3XK95UuV60tZlFCQGXEtMg8H+IsW72ldw1ih1jZhzYXbJvghmAEpg5UVhhnCeia1CkGttUvCkiMQ== dependencies: - "@babel/helper-plugin-utils" "^7.24.0" + "@babel/helper-plugin-utils" "^7.25.7" regenerator-transform "^0.15.2" -"@babel/plugin-transform-reserved-words@^7.24.1": - version "7.24.1" - resolved "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.24.1.tgz" - integrity sha512-JAclqStUfIwKN15HrsQADFgeZt+wexNQ0uLhuqvqAUFoqPMjEcFCYZBhq0LUdz6dZK/mD+rErhW71fbx8RYElg== +"@babel/plugin-transform-reserved-words@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.25.7.tgz#dc56b25e02afaabef3ce0c5b06b0916e8523e995" + integrity sha512-3OfyfRRqiGeOvIWSagcwUTVk2hXBsr/ww7bLn6TRTuXnexA+Udov2icFOxFX9abaj4l96ooYkcNN1qi2Zvqwng== dependencies: - "@babel/helper-plugin-utils" "^7.24.0" + "@babel/helper-plugin-utils" "^7.25.7" "@babel/plugin-transform-runtime@7.23.3": version "7.23.3" - resolved "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.23.3.tgz" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.23.3.tgz#0aa7485862b0b5cb0559c1a5ec08b4923743ee3b" integrity sha512-XcQ3X58CKBdBnnZpPaQjgVMePsXtSZzHoku70q9tUAQp02ggPQNM04BF3RvlW1GSM/McbSOQAzEK4MXbS7/JFg== dependencies: "@babel/helper-module-imports" "^7.22.15" @@ -959,172 +796,159 @@ babel-plugin-polyfill-regenerator "^0.5.3" semver "^6.3.1" -"@babel/plugin-transform-shorthand-properties@^7.24.1": - version "7.24.1" - resolved "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.24.1.tgz" - integrity sha512-LyjVB1nsJ6gTTUKRjRWx9C1s9hE7dLfP/knKdrfeH9UPtAGjYGgxIbFfx7xyLIEWs7Xe1Gnf8EWiUqfjLhInZA== +"@babel/plugin-transform-shorthand-properties@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.25.7.tgz#92690a9c671915602d91533c278cc8f6bf12275f" + integrity sha512-uBbxNwimHi5Bv3hUccmOFlUy3ATO6WagTApenHz9KzoIdn0XeACdB12ZJ4cjhuB2WSi80Ez2FWzJnarccriJeA== dependencies: - "@babel/helper-plugin-utils" "^7.24.0" + "@babel/helper-plugin-utils" "^7.25.7" -"@babel/plugin-transform-spread@^7.24.1": - version "7.24.1" - resolved "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.24.1.tgz" - integrity sha512-KjmcIM+fxgY+KxPVbjelJC6hrH1CgtPmTvdXAfn3/a9CnWGSTY7nH4zm5+cjmWJybdcPSsD0++QssDsjcpe47g== +"@babel/plugin-transform-spread@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-spread/-/plugin-transform-spread-7.25.7.tgz#df83e899a9fc66284ee601a7b738568435b92998" + integrity sha512-Mm6aeymI0PBh44xNIv/qvo8nmbkpZze1KvR8MkEqbIREDxoiWTi18Zr2jryfRMwDfVZF9foKh060fWgni44luw== dependencies: - "@babel/helper-plugin-utils" "^7.24.0" - "@babel/helper-skip-transparent-expression-wrappers" "^7.22.5" + "@babel/helper-plugin-utils" "^7.25.7" + "@babel/helper-skip-transparent-expression-wrappers" "^7.25.7" -"@babel/plugin-transform-sticky-regex@^7.24.1": - version "7.24.1" - resolved "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.24.1.tgz" - integrity sha512-9v0f1bRXgPVcPrngOQvLXeGNNVLc8UjMVfebo9ka0WF3/7+aVUHmaJVT3sa0XCzEFioPfPHZiOcYG9qOsH63cw== +"@babel/plugin-transform-sticky-regex@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.25.7.tgz#341c7002bef7f29037be7fb9684e374442dd0d17" + integrity sha512-ZFAeNkpGuLnAQ/NCsXJ6xik7Id+tHuS+NT+ue/2+rn/31zcdnupCdmunOizEaP0JsUmTFSTOPoQY7PkK2pttXw== dependencies: - "@babel/helper-plugin-utils" "^7.24.0" + "@babel/helper-plugin-utils" "^7.25.7" -"@babel/plugin-transform-template-literals@^7.24.1": - version "7.24.1" - resolved "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.24.1.tgz" - integrity sha512-WRkhROsNzriarqECASCNu/nojeXCDTE/F2HmRgOzi7NGvyfYGq1NEjKBK3ckLfRgGc6/lPAqP0vDOSw3YtG34g== +"@babel/plugin-transform-template-literals@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.25.7.tgz#e566c581bb16d8541dd8701093bb3457adfce16b" + integrity sha512-SI274k0nUsFFmyQupiO7+wKATAmMFf8iFgq2O+vVFXZ0SV9lNfT1NGzBEhjquFmD8I9sqHLguH+gZVN3vww2AA== dependencies: - "@babel/helper-plugin-utils" "^7.24.0" + "@babel/helper-plugin-utils" "^7.25.7" -"@babel/plugin-transform-typeof-symbol@^7.24.1": - version "7.24.1" - resolved "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.24.1.tgz" - integrity sha512-CBfU4l/A+KruSUoW+vTQthwcAdwuqbpRNB8HQKlZABwHRhsdHZ9fezp4Sn18PeAlYxTNiLMlx4xUBV3AWfg1BA== +"@babel/plugin-transform-typeof-symbol@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.25.7.tgz#debb1287182efd20488f126be343328c679b66eb" + integrity sha512-OmWmQtTHnO8RSUbL0NTdtpbZHeNTnm68Gj5pA4Y2blFNh+V4iZR68V1qL9cI37J21ZN7AaCnkfdHtLExQPf2uA== dependencies: - "@babel/helper-plugin-utils" "^7.24.0" + "@babel/helper-plugin-utils" "^7.25.7" -"@babel/plugin-transform-unicode-escapes@^7.24.1": - version "7.24.1" - resolved "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.24.1.tgz" - integrity sha512-RlkVIcWT4TLI96zM660S877E7beKlQw7Ig+wqkKBiWfj0zH5Q4h50q6er4wzZKRNSYpfo6ILJ+hrJAGSX2qcNw== +"@babel/plugin-transform-unicode-escapes@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.25.7.tgz#973592b6d13a914794e1de8cf1383e50e0f87f81" + integrity sha512-BN87D7KpbdiABA+t3HbVqHzKWUDN3dymLaTnPFAMyc8lV+KN3+YzNhVRNdinaCPA4AUqx7ubXbQ9shRjYBl3SQ== dependencies: - "@babel/helper-plugin-utils" "^7.24.0" + "@babel/helper-plugin-utils" "^7.25.7" -"@babel/plugin-transform-unicode-property-regex@^7.24.1": - version "7.24.1" - resolved "https://registry.npmjs.org/@babel/plugin-transform-unicode-property-regex/-/plugin-transform-unicode-property-regex-7.24.1.tgz" - integrity sha512-Ss4VvlfYV5huWApFsF8/Sq0oXnGO+jB+rijFEFugTd3cwSObUSnUi88djgR5528Csl0uKlrI331kRqe56Ov2Ng== +"@babel/plugin-transform-unicode-property-regex@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-property-regex/-/plugin-transform-unicode-property-regex-7.25.7.tgz#25349197cce964b1343f74fa7cfdf791a1b1919e" + integrity sha512-IWfR89zcEPQGB/iB408uGtSPlQd3Jpq11Im86vUgcmSTcoWAiQMCTOa2K2yNNqFJEBVICKhayctee65Ka8OB0w== dependencies: - "@babel/helper-create-regexp-features-plugin" "^7.22.15" - "@babel/helper-plugin-utils" "^7.24.0" + "@babel/helper-create-regexp-features-plugin" "^7.25.7" + "@babel/helper-plugin-utils" "^7.25.7" -"@babel/plugin-transform-unicode-regex@^7.24.1": - version "7.24.1" - resolved "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.24.1.tgz" - integrity sha512-2A/94wgZgxfTsiLaQ2E36XAOdcZmGAaEEgVmxQWwZXWkGhvoHbaqXcKnU8zny4ycpu3vNqg0L/PcCiYtHtA13g== +"@babel/plugin-transform-unicode-regex@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.25.7.tgz#f93a93441baf61f713b6d5552aaa856bfab34809" + integrity sha512-8JKfg/hiuA3qXnlLx8qtv5HWRbgyFx2hMMtpDDuU2rTckpKkGu4ycK5yYHwuEa16/quXfoxHBIApEsNyMWnt0g== dependencies: - "@babel/helper-create-regexp-features-plugin" "^7.22.15" - "@babel/helper-plugin-utils" "^7.24.0" + "@babel/helper-create-regexp-features-plugin" "^7.25.7" + "@babel/helper-plugin-utils" "^7.25.7" -"@babel/plugin-transform-unicode-sets-regex@^7.24.1": - version "7.24.1" - resolved "https://registry.npmjs.org/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.24.1.tgz" - integrity sha512-fqj4WuzzS+ukpgerpAoOnMfQXwUHFxXUZUE84oL2Kao2N8uSlvcpnAidKASgsNgzZHBsHWvcm8s9FPWUhAb8fA== +"@babel/plugin-transform-unicode-sets-regex@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.25.7.tgz#d1b3295d29e0f8f4df76abc909ad1ebee919560c" + integrity sha512-YRW8o9vzImwmh4Q3Rffd09bH5/hvY0pxg+1H1i0f7APoUeg12G7+HhLj9ZFNIrYkgBXhIijPJ+IXypN0hLTIbw== dependencies: - "@babel/helper-create-regexp-features-plugin" "^7.22.15" - "@babel/helper-plugin-utils" "^7.24.0" + "@babel/helper-create-regexp-features-plugin" "^7.25.7" + "@babel/helper-plugin-utils" "^7.25.7" "@babel/preset-env@^7.23.2": - version "7.24.4" - resolved "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.24.4.tgz" - integrity sha512-7Kl6cSmYkak0FK/FXjSEnLJ1N9T/WA2RkMhu17gZ/dsxKJUuTYNIylahPTzqpLyJN4WhDif8X0XK1R8Wsguo/A== - dependencies: - "@babel/compat-data" "^7.24.4" - "@babel/helper-compilation-targets" "^7.23.6" - "@babel/helper-plugin-utils" "^7.24.0" - "@babel/helper-validator-option" "^7.23.5" - "@babel/plugin-bugfix-firefox-class-in-computed-class-key" "^7.24.4" - "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression" "^7.24.1" - "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining" "^7.24.1" - "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly" "^7.24.1" + version "7.25.8" + resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.25.8.tgz#dc6b719627fb29cd9cccbbbe041802fd575b524c" + integrity sha512-58T2yulDHMN8YMUxiLq5YmWUnlDCyY1FsHM+v12VMx+1/FlrUj5tY50iDCpofFQEM8fMYOaY9YRvym2jcjn1Dg== + dependencies: + "@babel/compat-data" "^7.25.8" + "@babel/helper-compilation-targets" "^7.25.7" + "@babel/helper-plugin-utils" "^7.25.7" + "@babel/helper-validator-option" "^7.25.7" + "@babel/plugin-bugfix-firefox-class-in-computed-class-key" "^7.25.7" + "@babel/plugin-bugfix-safari-class-field-initializer-scope" "^7.25.7" + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression" "^7.25.7" + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining" "^7.25.7" + "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly" "^7.25.7" "@babel/plugin-proposal-private-property-in-object" "7.21.0-placeholder-for-preset-env.2" - "@babel/plugin-syntax-async-generators" "^7.8.4" - "@babel/plugin-syntax-class-properties" "^7.12.13" - "@babel/plugin-syntax-class-static-block" "^7.14.5" - "@babel/plugin-syntax-dynamic-import" "^7.8.3" - "@babel/plugin-syntax-export-namespace-from" "^7.8.3" - "@babel/plugin-syntax-import-assertions" "^7.24.1" - "@babel/plugin-syntax-import-attributes" "^7.24.1" - "@babel/plugin-syntax-import-meta" "^7.10.4" - "@babel/plugin-syntax-json-strings" "^7.8.3" - "@babel/plugin-syntax-logical-assignment-operators" "^7.10.4" - "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.3" - "@babel/plugin-syntax-numeric-separator" "^7.10.4" - "@babel/plugin-syntax-object-rest-spread" "^7.8.3" - "@babel/plugin-syntax-optional-catch-binding" "^7.8.3" - "@babel/plugin-syntax-optional-chaining" "^7.8.3" - "@babel/plugin-syntax-private-property-in-object" "^7.14.5" - "@babel/plugin-syntax-top-level-await" "^7.14.5" + "@babel/plugin-syntax-import-assertions" "^7.25.7" + "@babel/plugin-syntax-import-attributes" "^7.25.7" "@babel/plugin-syntax-unicode-sets-regex" "^7.18.6" - "@babel/plugin-transform-arrow-functions" "^7.24.1" - "@babel/plugin-transform-async-generator-functions" "^7.24.3" - "@babel/plugin-transform-async-to-generator" "^7.24.1" - "@babel/plugin-transform-block-scoped-functions" "^7.24.1" - "@babel/plugin-transform-block-scoping" "^7.24.4" - "@babel/plugin-transform-class-properties" "^7.24.1" - "@babel/plugin-transform-class-static-block" "^7.24.4" - "@babel/plugin-transform-classes" "^7.24.1" - "@babel/plugin-transform-computed-properties" "^7.24.1" - "@babel/plugin-transform-destructuring" "^7.24.1" - "@babel/plugin-transform-dotall-regex" "^7.24.1" - "@babel/plugin-transform-duplicate-keys" "^7.24.1" - "@babel/plugin-transform-dynamic-import" "^7.24.1" - "@babel/plugin-transform-exponentiation-operator" "^7.24.1" - "@babel/plugin-transform-export-namespace-from" "^7.24.1" - "@babel/plugin-transform-for-of" "^7.24.1" - "@babel/plugin-transform-function-name" "^7.24.1" - "@babel/plugin-transform-json-strings" "^7.24.1" - "@babel/plugin-transform-literals" "^7.24.1" - "@babel/plugin-transform-logical-assignment-operators" "^7.24.1" - "@babel/plugin-transform-member-expression-literals" "^7.24.1" - "@babel/plugin-transform-modules-amd" "^7.24.1" - "@babel/plugin-transform-modules-commonjs" "^7.24.1" - "@babel/plugin-transform-modules-systemjs" "^7.24.1" - "@babel/plugin-transform-modules-umd" "^7.24.1" - "@babel/plugin-transform-named-capturing-groups-regex" "^7.22.5" - "@babel/plugin-transform-new-target" "^7.24.1" - "@babel/plugin-transform-nullish-coalescing-operator" "^7.24.1" - "@babel/plugin-transform-numeric-separator" "^7.24.1" - "@babel/plugin-transform-object-rest-spread" "^7.24.1" - "@babel/plugin-transform-object-super" "^7.24.1" - "@babel/plugin-transform-optional-catch-binding" "^7.24.1" - "@babel/plugin-transform-optional-chaining" "^7.24.1" - "@babel/plugin-transform-parameters" "^7.24.1" - "@babel/plugin-transform-private-methods" "^7.24.1" - "@babel/plugin-transform-private-property-in-object" "^7.24.1" - "@babel/plugin-transform-property-literals" "^7.24.1" - "@babel/plugin-transform-regenerator" "^7.24.1" - "@babel/plugin-transform-reserved-words" "^7.24.1" - "@babel/plugin-transform-shorthand-properties" "^7.24.1" - "@babel/plugin-transform-spread" "^7.24.1" - "@babel/plugin-transform-sticky-regex" "^7.24.1" - "@babel/plugin-transform-template-literals" "^7.24.1" - "@babel/plugin-transform-typeof-symbol" "^7.24.1" - "@babel/plugin-transform-unicode-escapes" "^7.24.1" - "@babel/plugin-transform-unicode-property-regex" "^7.24.1" - "@babel/plugin-transform-unicode-regex" "^7.24.1" - "@babel/plugin-transform-unicode-sets-regex" "^7.24.1" + "@babel/plugin-transform-arrow-functions" "^7.25.7" + "@babel/plugin-transform-async-generator-functions" "^7.25.8" + "@babel/plugin-transform-async-to-generator" "^7.25.7" + "@babel/plugin-transform-block-scoped-functions" "^7.25.7" + "@babel/plugin-transform-block-scoping" "^7.25.7" + "@babel/plugin-transform-class-properties" "^7.25.7" + "@babel/plugin-transform-class-static-block" "^7.25.8" + "@babel/plugin-transform-classes" "^7.25.7" + "@babel/plugin-transform-computed-properties" "^7.25.7" + "@babel/plugin-transform-destructuring" "^7.25.7" + "@babel/plugin-transform-dotall-regex" "^7.25.7" + "@babel/plugin-transform-duplicate-keys" "^7.25.7" + "@babel/plugin-transform-duplicate-named-capturing-groups-regex" "^7.25.7" + "@babel/plugin-transform-dynamic-import" "^7.25.8" + "@babel/plugin-transform-exponentiation-operator" "^7.25.7" + "@babel/plugin-transform-export-namespace-from" "^7.25.8" + "@babel/plugin-transform-for-of" "^7.25.7" + "@babel/plugin-transform-function-name" "^7.25.7" + "@babel/plugin-transform-json-strings" "^7.25.8" + "@babel/plugin-transform-literals" "^7.25.7" + "@babel/plugin-transform-logical-assignment-operators" "^7.25.8" + "@babel/plugin-transform-member-expression-literals" "^7.25.7" + "@babel/plugin-transform-modules-amd" "^7.25.7" + "@babel/plugin-transform-modules-commonjs" "^7.25.7" + "@babel/plugin-transform-modules-systemjs" "^7.25.7" + "@babel/plugin-transform-modules-umd" "^7.25.7" + "@babel/plugin-transform-named-capturing-groups-regex" "^7.25.7" + "@babel/plugin-transform-new-target" "^7.25.7" + "@babel/plugin-transform-nullish-coalescing-operator" "^7.25.8" + "@babel/plugin-transform-numeric-separator" "^7.25.8" + "@babel/plugin-transform-object-rest-spread" "^7.25.8" + "@babel/plugin-transform-object-super" "^7.25.7" + "@babel/plugin-transform-optional-catch-binding" "^7.25.8" + "@babel/plugin-transform-optional-chaining" "^7.25.8" + "@babel/plugin-transform-parameters" "^7.25.7" + "@babel/plugin-transform-private-methods" "^7.25.7" + "@babel/plugin-transform-private-property-in-object" "^7.25.8" + "@babel/plugin-transform-property-literals" "^7.25.7" + "@babel/plugin-transform-regenerator" "^7.25.7" + "@babel/plugin-transform-reserved-words" "^7.25.7" + "@babel/plugin-transform-shorthand-properties" "^7.25.7" + "@babel/plugin-transform-spread" "^7.25.7" + "@babel/plugin-transform-sticky-regex" "^7.25.7" + "@babel/plugin-transform-template-literals" "^7.25.7" + "@babel/plugin-transform-typeof-symbol" "^7.25.7" + "@babel/plugin-transform-unicode-escapes" "^7.25.7" + "@babel/plugin-transform-unicode-property-regex" "^7.25.7" + "@babel/plugin-transform-unicode-regex" "^7.25.7" + "@babel/plugin-transform-unicode-sets-regex" "^7.25.7" "@babel/preset-modules" "0.1.6-no-external-plugins" babel-plugin-polyfill-corejs2 "^0.4.10" - babel-plugin-polyfill-corejs3 "^0.10.4" + babel-plugin-polyfill-corejs3 "^0.10.6" babel-plugin-polyfill-regenerator "^0.6.1" - core-js-compat "^3.31.0" + core-js-compat "^3.38.1" semver "^6.3.1" "@babel/preset-flow@^7.22.15": - version "7.24.1" - resolved "https://registry.npmjs.org/@babel/preset-flow/-/preset-flow-7.24.1.tgz" - integrity sha512-sWCV2G9pcqZf+JHyv/RyqEIpFypxdCSxWIxQjpdaQxenNog7cN1pr76hg8u0Fz8Qgg0H4ETkGcJnXL8d4j0PPA== + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/preset-flow/-/preset-flow-7.25.7.tgz#a9460677c182c2e105c32567a036d360c86668a9" + integrity sha512-q2x3g0YHzo/Ohsr51KOYS/BtZMsvkzVd8qEyhZAyTatYdobfgXCuyppTqTuIhdq5kR/P3nyyVvZ6H5dMc4PnCQ== dependencies: - "@babel/helper-plugin-utils" "^7.24.0" - "@babel/helper-validator-option" "^7.23.5" - "@babel/plugin-transform-flow-strip-types" "^7.24.1" + "@babel/helper-plugin-utils" "^7.25.7" + "@babel/helper-validator-option" "^7.25.7" + "@babel/plugin-transform-flow-strip-types" "^7.25.7" "@babel/preset-modules@0.1.6-no-external-plugins": version "0.1.6-no-external-plugins" - resolved "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.6-no-external-plugins.tgz" + resolved "https://registry.yarnpkg.com/@babel/preset-modules/-/preset-modules-0.1.6-no-external-plugins.tgz#ccb88a2c49c817236861fee7826080573b8a923a" integrity sha512-HrcgcIESLm9aIR842yhJ5RWan/gebQUJ6E/E5+rf0y9o6oj7w0Br+sWuL6kEQ/o/AdfvR1Je9jG18/gnpwjEyA== dependencies: "@babel/helper-plugin-utils" "^7.0.0" @@ -1132,93 +956,53 @@ esutils "^2.0.2" "@babel/preset-react@^7.22.15": - version "7.24.1" - resolved "https://registry.npmjs.org/@babel/preset-react/-/preset-react-7.24.1.tgz" - integrity sha512-eFa8up2/8cZXLIpkafhaADTXSnl7IsUFCYenRWrARBz0/qZwcT0RBXpys0LJU4+WfPoF2ZG6ew6s2V6izMCwRA== - dependencies: - "@babel/helper-plugin-utils" "^7.24.0" - "@babel/helper-validator-option" "^7.23.5" - "@babel/plugin-transform-react-display-name" "^7.24.1" - "@babel/plugin-transform-react-jsx" "^7.23.4" - "@babel/plugin-transform-react-jsx-development" "^7.22.5" - "@babel/plugin-transform-react-pure-annotations" "^7.24.1" - -"@babel/regjsgen@^0.8.0": - version "0.8.0" - resolved "https://registry.npmjs.org/@babel/regjsgen/-/regjsgen-0.8.0.tgz" - integrity sha512-x/rqGMdzj+fWZvCOYForTghzbtqPDZ5gPwaoNGHdgDfF2QA/XZbCBp4Moo5scrkAMPhB7z26XM/AaHuIJdgauA== - -"@babel/runtime@^7.23.2": - version "7.24.4" - resolved "https://registry.npmjs.org/@babel/runtime/-/runtime-7.24.4.tgz" - integrity sha512-dkxf7+hn8mFBwKjs9bvBlArzLVxVbS8usaPUDd5p2a9JCL9tB8OaOVN1isD4+Xyk4ns89/xeOmbQvgdK7IIVdA== - dependencies: - regenerator-runtime "^0.14.0" - -"@babel/runtime@^7.24.1": - version "7.24.5" - resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.24.5.tgz#230946857c053a36ccc66e1dd03b17dd0c4ed02c" - integrity sha512-Nms86NXrsaeU9vbBJKni6gXiEXZ4CVpYVzEjDH9Sb8vmZ3UljyA1GSOJl/6LGPO8EHLuSF9H+IxNXHPX8QHJ4g== - dependencies: - regenerator-runtime "^0.14.0" - -"@babel/runtime@^7.8.4": - version "7.23.9" - resolved "https://registry.npmjs.org/@babel/runtime/-/runtime-7.23.9.tgz" - integrity sha512-0CX6F+BI2s9dkUqr08KFrAIZgNFj75rdBU/DjCyYLIaV/quFjkk6T+EJ2LkZHyZTbEV4L5p97mNkUsHl2wLFAw== + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/preset-react/-/preset-react-7.25.7.tgz#081cbe1dea363b732764d06a0fdda67ffa17735d" + integrity sha512-GjV0/mUEEXpi1U5ZgDprMRRgajGMRW3G5FjMr5KLKD8nT2fTG8+h/klV3+6Dm5739QE+K5+2e91qFKAYI3pmRg== + dependencies: + "@babel/helper-plugin-utils" "^7.25.7" + "@babel/helper-validator-option" "^7.25.7" + "@babel/plugin-transform-react-display-name" "^7.25.7" + "@babel/plugin-transform-react-jsx" "^7.25.7" + "@babel/plugin-transform-react-jsx-development" "^7.25.7" + "@babel/plugin-transform-react-pure-annotations" "^7.25.7" + +"@babel/runtime@^7.23.2", "@babel/runtime@^7.24.1", "@babel/runtime@^7.8.4": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.25.7.tgz#7ffb53c37a8f247c8c4d335e89cdf16a2e0d0fb6" + integrity sha512-FjoyLe754PMiYsFaN5C94ttGiOmBNYTf6pLr4xXHAT5uctHb092PBszndLDR5XA/jghQvn4n7JMHl7dmTgbm9w== dependencies: regenerator-runtime "^0.14.0" -"@babel/template@^7.22.15": - version "7.23.9" - resolved "https://registry.npmjs.org/@babel/template/-/template-7.23.9.tgz" - integrity sha512-+xrD2BWLpvHKNmX2QbpdpsBaWnRxahMwJjO+KZk2JOElj5nSmKezyS1B4u+QbHMTX69t4ukm6hh9lsYQ7GHCKA== - dependencies: - "@babel/code-frame" "^7.23.5" - "@babel/parser" "^7.23.9" - "@babel/types" "^7.23.9" - -"@babel/template@^7.24.0": - version "7.24.0" - resolved "https://registry.npmjs.org/@babel/template/-/template-7.24.0.tgz" - integrity sha512-Bkf2q8lMB0AFpX0NFEqSbx1OkTHf0f+0j82mkw+ZpzBnkk7e9Ql0891vlfgi+kHwOk8tQjiQHpqh4LaSa0fKEA== - dependencies: - "@babel/code-frame" "^7.23.5" - "@babel/parser" "^7.24.0" - "@babel/types" "^7.24.0" - -"@babel/traverse@^7.24.1": - version "7.24.1" - resolved "https://registry.npmjs.org/@babel/traverse/-/traverse-7.24.1.tgz" - integrity sha512-xuU6o9m68KeqZbQuDt2TcKSxUw/mrsvavlEqQ1leZ/B+C9tk6E4sRWy97WaXgvq5E+nU3cXMxv3WKOCanVMCmQ== - dependencies: - "@babel/code-frame" "^7.24.1" - "@babel/generator" "^7.24.1" - "@babel/helper-environment-visitor" "^7.22.20" - "@babel/helper-function-name" "^7.23.0" - "@babel/helper-hoist-variables" "^7.22.5" - "@babel/helper-split-export-declaration" "^7.22.6" - "@babel/parser" "^7.24.1" - "@babel/types" "^7.24.0" +"@babel/template@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.25.7.tgz#27f69ce382855d915b14ab0fe5fb4cbf88fa0769" + integrity sha512-wRwtAgI3bAS+JGU2upWNL9lSlDcRCqD05BZ1n3X2ONLH1WilFP6O1otQjeMK/1g0pvYcXC7b/qVUB1keofjtZA== + dependencies: + "@babel/code-frame" "^7.25.7" + "@babel/parser" "^7.25.7" + "@babel/types" "^7.25.7" + +"@babel/traverse@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.25.7.tgz#83e367619be1cab8e4f2892ef30ba04c26a40fa8" + integrity sha512-jatJPT1Zjqvh/1FyJs6qAHL+Dzb7sTb+xr7Q+gM1b+1oBsMsQQ4FkVKb6dFlJvLlVssqkRzV05Jzervt9yhnzg== + dependencies: + "@babel/code-frame" "^7.25.7" + "@babel/generator" "^7.25.7" + "@babel/parser" "^7.25.7" + "@babel/template" "^7.25.7" + "@babel/types" "^7.25.7" debug "^4.3.1" globals "^11.1.0" -"@babel/types@^7.22.15", "@babel/types@^7.22.19", "@babel/types@^7.22.5", "@babel/types@^7.23.0", "@babel/types@^7.23.4", "@babel/types@^7.23.9", "@babel/types@^7.4.4": - version "7.23.9" - resolved "https://registry.npmjs.org/@babel/types/-/types-7.23.9.tgz" - integrity sha512-dQjSq/7HaSjRM43FFGnv5keM2HsxpmyV1PfaSVm0nzzjwwTmjOe6J4bC8e3+pTEIgHaHj+1ZlLThRJ2auc/w1Q== +"@babel/types@^7.24.7", "@babel/types@^7.25.7", "@babel/types@^7.25.8", "@babel/types@^7.4.4": + version "7.25.8" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.25.8.tgz#5cf6037258e8a9bcad533f4979025140cb9993e1" + integrity sha512-JWtuCu8VQsMladxVz/P4HzHUGCAwpuqacmowgXFs5XjxIgKuNjnLokQzuVjlTvIzODaDmpjT3oxcC48vyk9EWg== dependencies: - "@babel/helper-string-parser" "^7.23.4" - "@babel/helper-validator-identifier" "^7.22.20" - to-fast-properties "^2.0.0" - -"@babel/types@^7.24.0": - version "7.24.0" - resolved "https://registry.npmjs.org/@babel/types/-/types-7.24.0.tgz" - integrity sha512-+j7a5c253RfKh8iABBhywc8NSfP5LURe7Uh4qpsh6jc+aLJguvmIUBdjSdEMQv2bENrCR5MfRdjGo7vzS/ob7w== - dependencies: - "@babel/helper-string-parser" "^7.23.4" - "@babel/helper-validator-identifier" "^7.22.20" + "@babel/helper-string-parser" "^7.25.7" + "@babel/helper-validator-identifier" "^7.25.7" to-fast-properties "^2.0.0" "@bazel/runfiles@^5.8.1": @@ -1235,12 +1019,12 @@ "@devexpress/bin-v8-flags-filter@^1.3.0": version "1.3.0" - resolved "https://registry.npmjs.org/@devexpress/bin-v8-flags-filter/-/bin-v8-flags-filter-1.3.0.tgz" + resolved "https://registry.yarnpkg.com/@devexpress/bin-v8-flags-filter/-/bin-v8-flags-filter-1.3.0.tgz#3069f2525c0c5fb940810e9ec10fc592c47552db" integrity sha512-LWLNfYGwVJKYpmHUDoODltnlqxdEAl5Qmw7ha1+TSpsABeF94NKSWkQTTV1TB4CM02j2pZyqn36nHgaFl8z7qw== "@devexpress/callsite-record@^4.1.6": version "4.1.7" - resolved "https://registry.npmjs.org/@devexpress/callsite-record/-/callsite-record-4.1.7.tgz" + resolved "https://registry.yarnpkg.com/@devexpress/callsite-record/-/callsite-record-4.1.7.tgz#045ece71df8c574d7adc15c75eeaac6c6ca6c97d" integrity sha512-qr3VQYc0KopduFkEY6SxaOIi1Xhm0jIWQfrxxMVboI/p2rjF/Mj/iqaiUxQQP6F3ujpW/7l0mzhf17uwcFZhBA== dependencies: "@types/lodash" "^4.14.72" @@ -1252,10 +1036,11 @@ pinkie-promise "^2.0.0" "@electron/asar@^3.2.3": - version "3.2.8" - resolved "https://registry.npmjs.org/@electron/asar/-/asar-3.2.8.tgz" - integrity sha512-cmskk5M06ewHMZAplSiF4AlME3IrnnZhKnWbtwKVLRkdJkKyUVjMLhDIiPIx/+6zQWVlKX/LtmK9xDme7540Sg== + version "3.2.13" + resolved "https://registry.yarnpkg.com/@electron/asar/-/asar-3.2.13.tgz#56565ea423ead184465adfa72663b2c70d9835f2" + integrity sha512-pY5z2qQSwbFzJsBdgfJIzXf5ElHTVMutC2dxh0FD60njknMu3n1NnTABOcQwbb5/v5soqE79m9UjaJryBf3epg== dependencies: + "@types/glob" "^7.1.0" commander "^5.0.0" glob "^7.1.6" minimatch "^3.0.4" @@ -1358,18 +1143,9 @@ wrap-ansi "^8.1.0" wrap-ansi-cjs "npm:wrap-ansi@^7.0.0" -"@jridgewell/gen-mapping@^0.3.0": - version "0.3.3" - resolved "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz" - integrity sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ== - dependencies: - "@jridgewell/set-array" "^1.0.1" - "@jridgewell/sourcemap-codec" "^1.4.10" - "@jridgewell/trace-mapping" "^0.3.9" - "@jridgewell/gen-mapping@^0.3.5": version "0.3.5" - resolved "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz" + resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz#dcce6aff74bdf6dad1a95802b69b04a2fcb1fb36" integrity sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg== dependencies: "@jridgewell/set-array" "^1.2.1" @@ -1383,23 +1159,18 @@ "@jridgewell/resolve-uri@^3.1.0": version "3.1.2" - resolved "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz" + resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz#7a0ee601f60f99a20c7c7c5ff0c80388c1189bd6" integrity sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw== -"@jridgewell/set-array@^1.0.1": - version "1.1.2" - resolved "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz" - integrity sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw== - "@jridgewell/set-array@^1.2.1": version "1.2.1" - resolved "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz" + resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.2.1.tgz#558fb6472ed16a4c850b889530e6b36438c49280" integrity sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A== "@jridgewell/sourcemap-codec@^1.4.10", "@jridgewell/sourcemap-codec@^1.4.14": - version "1.4.15" - resolved "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz" - integrity sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg== + version "1.5.0" + resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz#3188bcb273a414b0d215fd22a58540b989b9409a" + integrity sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ== "@jridgewell/trace-mapping@0.3.9": version "0.3.9" @@ -1411,20 +1182,12 @@ "@jridgewell/trace-mapping@^0.3.24", "@jridgewell/trace-mapping@^0.3.25": version "0.3.25" - resolved "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz" + resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz#15f190e98895f3fc23276ee14bc76b675c2e50f0" integrity sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ== dependencies: "@jridgewell/resolve-uri" "^3.1.0" "@jridgewell/sourcemap-codec" "^1.4.14" -"@jridgewell/trace-mapping@^0.3.9": - version "0.3.22" - resolved "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.22.tgz" - integrity sha512-Wf963MzWtA2sjrNt+g18IAln9lKnlRp+K2eH4jjIoF1wYeq3aMREpG09xhlhdzS0EjwU7qmUJYangWa+151vZw== - dependencies: - "@jridgewell/resolve-uri" "^3.1.0" - "@jridgewell/sourcemap-codec" "^1.4.14" - "@msgpackr-extract/msgpackr-extract-darwin-arm64@3.0.3": version "3.0.3" resolved "https://registry.yarnpkg.com/@msgpackr-extract/msgpackr-extract-darwin-arm64/-/msgpackr-extract-darwin-arm64-3.0.3.tgz#9edec61b22c3082018a79f6d1c30289ddf3d9d11" @@ -1457,7 +1220,7 @@ "@nodelib/fs.scandir@2.1.5": version "2.1.5" - resolved "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz" + resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5" integrity sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g== dependencies: "@nodelib/fs.stat" "2.0.5" @@ -1465,12 +1228,12 @@ "@nodelib/fs.stat@2.0.5", "@nodelib/fs.stat@^2.0.2": version "2.0.5" - resolved "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz" + resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz#5bd262af94e9d25bd1e71b05deed44876a222e8b" integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A== "@nodelib/fs.walk@^1.2.3": version "1.2.8" - resolved "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz" + resolved "https://registry.yarnpkg.com/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz#e95737e8bb6746ddedf69c556953494f196fe69a" integrity sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg== dependencies: "@nodelib/fs.scandir" "2.1.5" @@ -1651,7 +1414,7 @@ "@types/estree@0.0.46": version "0.0.46" - resolved "https://registry.npmjs.org/@types/estree/-/estree-0.0.46.tgz" + resolved "https://registry.yarnpkg.com/@types/estree/-/estree-0.0.46.tgz#0fb6bfbbeabd7a30880504993369c4bf1deab1fe" integrity sha512-laIjwTQaD+5DukBZaygQ79K1Z0jb1bPEMRrkXSLjtCcZm+abyp5YbrqpSLzD42FwWW6gK/aS4NYpJ804nG2brg== "@types/estree@^1.0.6": @@ -1667,9 +1430,9 @@ "@types/jsonfile" "*" "@types/node" "*" -"@types/glob@^7.1.1": +"@types/glob@^7.1.0", "@types/glob@^7.1.1": version "7.2.0" - resolved "https://registry.npmjs.org/@types/glob/-/glob-7.2.0.tgz" + resolved "https://registry.yarnpkg.com/@types/glob/-/glob-7.2.0.tgz#bc1b5bf3aa92f25bd5dd39f35c57361bdce5b2eb" integrity sha512-ZUxbzKl0IfJILTS6t7ip5fQQM/J3TJYubDm3nMbgubNNYS62eXeUpoLUC8/7fJNiFYHTrGPQn7hspDUzIHX3UA== dependencies: "@types/minimatch" "*" @@ -1704,7 +1467,7 @@ "@types/minimatch@*": version "5.1.2" - resolved "https://registry.npmjs.org/@types/minimatch/-/minimatch-5.1.2.tgz" + resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-5.1.2.tgz#07508b45797cb81ec3f273011b054cd0755eddca" integrity sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA== "@types/node@*", "@types/node@20.3.1", "@types/node@>=13.7.0", "@types/node@^17.0.40", "@types/node@^20.14.5": @@ -1866,7 +1629,7 @@ abort-controller@^3.0.0: acorn-hammerhead@0.6.2: version "0.6.2" - resolved "https://registry.npmjs.org/acorn-hammerhead/-/acorn-hammerhead-0.6.2.tgz" + resolved "https://registry.yarnpkg.com/acorn-hammerhead/-/acorn-hammerhead-0.6.2.tgz#3ee37498a0548593d5152a4a2f1c76884958b7f8" integrity sha512-JZklfs1VVyjA1hf1y5qSzKSmK3K1UUUI7fQTuM/Zhv3rz4kFhdx4QwVnmU6tBEC8g/Ov6B+opfNFPeSZrlQfqA== dependencies: "@types/estree" "0.0.46" @@ -1919,7 +1682,7 @@ agentkeepalive@^4.1.3: aggregate-error@^3.0.0: version "3.1.0" - resolved "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz" + resolved "https://registry.yarnpkg.com/aggregate-error/-/aggregate-error-3.1.0.tgz#92670ff50f5359bdb7a3e0d40d0ec30c5737687a" integrity sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA== dependencies: clean-stack "^2.0.0" @@ -1937,14 +1700,14 @@ ajv@^6.12.4: ansi-escapes@^4.3.2: version "4.3.2" - resolved "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz" + resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-4.3.2.tgz#6b2291d1db7d98b6521d5f1efa42d0f3a9feb65e" integrity sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ== dependencies: type-fest "^0.21.3" ansi-regex@^5.0.1: version "5.0.1" - resolved "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== ansi-regex@^6.0.1: @@ -1954,14 +1717,14 @@ ansi-regex@^6.0.1: ansi-styles@^3.2.1: version "3.2.1" - resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== dependencies: color-convert "^1.9.0" ansi-styles@^4.0.0, ansi-styles@^4.1.0: version "4.3.0" - resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== dependencies: color-convert "^2.0.1" @@ -2030,7 +1793,7 @@ array-buffer-byte-length@^1.0.1: array-find@^1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/array-find/-/array-find-1.0.0.tgz" + resolved "https://registry.yarnpkg.com/array-find/-/array-find-1.0.0.tgz#6c8e286d11ed768327f8e62ecee87353ca3e78b8" integrity sha512-kO/vVCacW9mnpn3WPWbTVlEnOabK2L7LWi2HViURtCM46y1zb6I8UMjx4LgbiqadTgHnLInUronwn3ampNTJtQ== array-includes@^3.1.8: @@ -2047,19 +1810,19 @@ array-includes@^3.1.8: array-union@^1.0.1: version "1.0.2" - resolved "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz" + resolved "https://registry.yarnpkg.com/array-union/-/array-union-1.0.2.tgz#9a34410e4f4e3da23dea375be5be70f24778ec39" integrity sha512-Dxr6QJj/RdU/hCaBjOfxW+q6lyuVE6JFWIrAUpuOOhoJJoQ99cUn3igRaHVB5P9WrgFVN0FfArM3x0cueOU8ng== dependencies: array-uniq "^1.0.1" array-union@^2.1.0: version "2.1.0" - resolved "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz" + resolved "https://registry.yarnpkg.com/array-union/-/array-union-2.1.0.tgz#b798420adbeb1de828d84acd8a2e23d3efe85e8d" integrity sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw== array-uniq@^1.0.1: version "1.0.3" - resolved "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz" + resolved "https://registry.yarnpkg.com/array-uniq/-/array-uniq-1.0.3.tgz#af6ac877a25cc7f74e058894753858dfdb24fdb6" integrity sha512-MNha4BWQ6JbwhFhj03YK552f7cb3AzoE8SzeljgChvL1dl3IcvggXVz1DilzySZkCja+CXuZbdW7yATchWn8/Q== array.prototype.findlastindex@^1.2.5: @@ -2115,7 +1878,7 @@ asap@^2.0.0: assertion-error@^1.1.0: version "1.1.0" - resolved "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz" + resolved "https://registry.yarnpkg.com/assertion-error/-/assertion-error-1.1.0.tgz#e60b6b0e8f301bd97e5375215bda406c85118c0b" integrity sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw== ast-types@^0.13.4: @@ -2127,20 +1890,15 @@ ast-types@^0.13.4: async-exit-hook@^1.1.2: version "1.1.2" - resolved "https://registry.npmjs.org/async-exit-hook/-/async-exit-hook-1.1.2.tgz" + resolved "https://registry.yarnpkg.com/async-exit-hook/-/async-exit-hook-1.1.2.tgz#8095d75e488c29acee0551fe87252169d789cfba" integrity sha512-CeTSWB5Bou31xSHeO45ZKgLPRaJbV4I8csRcFYETDBehX7H+1GDO/v+v8G7fZmar1gOmYa6UTXn6d/WIiJbslw== async@3.2.3: version "3.2.3" - resolved "https://registry.npmjs.org/async/-/async-3.2.3.tgz" + resolved "https://registry.yarnpkg.com/async/-/async-3.2.3.tgz#ac53dafd3f4720ee9e8a160628f18ea91df196c9" integrity sha512-spZRyzKL5l5BZQrr/6m/SqFdBN0q3OCI0f9rjfBzCMBIP4p75P620rR3gTmaksNOhmzgdxcaxdNfMy6anrbM0g== -async@^3.2.0: - version "3.2.5" - resolved "https://registry.npmjs.org/async/-/async-3.2.5.tgz" - integrity sha512-baNZyqaaLhyLVKm/DlvdW051MSgO6b8eVfIezl9E5PqWxFgzLm/wQntEW4zOytVburDEr0JlALEpdOFwvErLsg== - -async@^3.2.4: +async@^3.2.0, async@^3.2.4: version "3.2.6" resolved "https://registry.yarnpkg.com/async/-/async-3.2.6.tgz#1b0728e14929d51b85b449b7f06e27c1145e38ce" integrity sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA== @@ -2184,24 +1942,24 @@ babel-plugin-module-resolver@5.0.0: babel-plugin-polyfill-corejs2@^0.4.10, babel-plugin-polyfill-corejs2@^0.4.6: version "0.4.11" - resolved "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.11.tgz" + resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.11.tgz#30320dfe3ffe1a336c15afdcdafd6fd615b25e33" integrity sha512-sMEJ27L0gRHShOh5G54uAAPaiCOygY/5ratXuiyb2G46FmlSpc9eFCzYVyDiPxfNbwzA7mYahmjQc5q+CZQ09Q== dependencies: "@babel/compat-data" "^7.22.6" "@babel/helper-define-polyfill-provider" "^0.6.2" semver "^6.3.1" -babel-plugin-polyfill-corejs3@^0.10.4: - version "0.10.4" - resolved "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.10.4.tgz" - integrity sha512-25J6I8NGfa5YkCDogHRID3fVCadIR8/pGl1/spvCkzb6lVn6SR3ojpx9nOn9iEBcUsjY24AmdKm5khcfKdylcg== +babel-plugin-polyfill-corejs3@^0.10.6: + version "0.10.6" + resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.10.6.tgz#2deda57caef50f59c525aeb4964d3b2f867710c7" + integrity sha512-b37+KR2i/khY5sKmWNVQAnitvquQbNdWy6lJdsr0kmquCKEEUgMKK4SboVM3HtfnZilfjr4MMQ7vY58FVWDtIA== dependencies: - "@babel/helper-define-polyfill-provider" "^0.6.1" - core-js-compat "^3.36.1" + "@babel/helper-define-polyfill-provider" "^0.6.2" + core-js-compat "^3.38.0" babel-plugin-polyfill-corejs3@^0.8.5: version "0.8.7" - resolved "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.8.7.tgz" + resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.8.7.tgz#941855aa7fdaac06ed24c730a93450d2b2b76d04" integrity sha512-KyDvZYxAzkC0Aj2dAPyDzi2Ym15e5JKZSK+maI7NAwSqofvuFglbSsxE7wUOvTg9oFVnHMzVzBKcqEb4PJgtOA== dependencies: "@babel/helper-define-polyfill-provider" "^0.4.4" @@ -2209,26 +1967,26 @@ babel-plugin-polyfill-corejs3@^0.8.5: babel-plugin-polyfill-regenerator@^0.5.3: version "0.5.5" - resolved "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.5.5.tgz" + resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.5.5.tgz#8b0c8fc6434239e5d7b8a9d1f832bb2b0310f06a" integrity sha512-OJGYZlhLqBh2DDHeqAxWB1XIvr49CxiJ2gIt61/PU55CQK4Z58OzMqjDe1zwQdQk+rBYsRc+1rJmdajM3gimHg== dependencies: "@babel/helper-define-polyfill-provider" "^0.5.0" babel-plugin-polyfill-regenerator@^0.6.1: version "0.6.2" - resolved "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.6.2.tgz" + resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.6.2.tgz#addc47e240edd1da1058ebda03021f382bba785e" integrity sha512-2R25rQZWP63nGwaAswvDazbPXfrM3HwVoBXK6HcqeKrSrL/JqcC/rDcf95l4r7LXLyxDXc8uQDa064GubtCABg== dependencies: "@babel/helper-define-polyfill-provider" "^0.6.2" babel-plugin-syntax-trailing-function-commas@^6.22.0: version "6.22.0" - resolved "https://registry.npmjs.org/babel-plugin-syntax-trailing-function-commas/-/babel-plugin-syntax-trailing-function-commas-6.22.0.tgz" + resolved "https://registry.yarnpkg.com/babel-plugin-syntax-trailing-function-commas/-/babel-plugin-syntax-trailing-function-commas-6.22.0.tgz#ba0360937f8d06e40180a43fe0d5616fff532cf3" integrity sha512-Gx9CH3Q/3GKbhs07Bszw5fPTlU+ygrOGfAhEt7W2JICwufpC4SuO0mG0+4NykPBSYPMJhqvVlDBU17qB1D+hMQ== balanced-match@^1.0.0: version "1.0.2" - resolved "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz" + resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== bare-events@^2.2.0: @@ -2271,17 +2029,17 @@ bl@^4.0.3: bowser@1.6.0: version "1.6.0" - resolved "https://registry.npmjs.org/bowser/-/bowser-1.6.0.tgz" + resolved "https://registry.yarnpkg.com/bowser/-/bowser-1.6.0.tgz#37fc387b616cb6aef370dab4d6bd402b74c5c54d" integrity sha512-Fk23J0+vRnI2eKDEDoUZXWtbMjijr098lKhuj4DKAfMKMCRVfJOuxXlbpxy0sTgbZ/Nr2N8MexmOir+GGI/ZMA== bowser@^2.8.1: version "2.11.0" - resolved "https://registry.npmjs.org/bowser/-/bowser-2.11.0.tgz" + resolved "https://registry.yarnpkg.com/bowser/-/bowser-2.11.0.tgz#5ca3c35757a7aa5771500c70a73a9f91ef420a8f" integrity sha512-AlcaJBi/pqqJBIQ8U9Mcpc9i8Aqxn88Skv5d+xBX006BY5u8N3mGLHa5Lgppa7L/HfwgwLgZ6NYs+Ag6uUmJRA== brace-expansion@^1.1.7: version "1.1.11" - resolved "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== dependencies: balanced-match "^1.0.0" @@ -2289,17 +2047,17 @@ brace-expansion@^1.1.7: brace-expansion@^2.0.1: version "2.0.1" - resolved "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-2.0.1.tgz#1edc459e0f0c548486ecf9fc99f2221364b9a0ae" integrity sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA== dependencies: balanced-match "^1.0.0" -braces@^3.0.2: - version "3.0.2" - resolved "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz" - integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A== +braces@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.3.tgz#490332f40919452272d55a8480adc0c441358789" + integrity sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA== dependencies: - fill-range "^7.0.1" + fill-range "^7.1.1" brotli-compress@^1.3.3: version "1.3.3" @@ -2322,15 +2080,15 @@ brotli-wasm@1.2.0: resolved "https://registry.yarnpkg.com/brotli-wasm/-/brotli-wasm-1.2.0.tgz#0f99b97b0020c8152308c277388aecf2a06b6e32" integrity sha512-PdDi7awF36zFujZyFJb9UNrP1l+If7iCgXhLKE1SpwqFQSK2yc7w2dysOmME7p325yQaZNvae7ruzypB3YhFxA== -browserslist@^4.22.2, browserslist@^4.22.3, browserslist@^4.23.0: - version "4.23.0" - resolved "https://registry.npmjs.org/browserslist/-/browserslist-4.23.0.tgz" - integrity sha512-QW8HiM1shhT2GuzkvklfjcKDiWFXHOeFCIA/huJPwHsslwcydgk7X+z2zXpEijP98UCY7HbubZt5J2Zgvf0CaQ== +browserslist@^4.23.3, browserslist@^4.24.0: + version "4.24.0" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.24.0.tgz#a1325fe4bc80b64fda169629fc01b3d6cecd38d4" + integrity sha512-Rmb62sR1Zpjql25eSanFGEhAxcFwfA1K0GuQcLoaJBAcENegrQut3hYdhXFF1obQfiDyqIW/cLM5HSJ/9k884A== dependencies: - caniuse-lite "^1.0.30001587" - electron-to-chromium "^1.4.668" - node-releases "^2.0.14" - update-browserslist-db "^1.0.13" + caniuse-lite "^1.0.30001663" + electron-to-chromium "^1.5.28" + node-releases "^2.0.18" + update-browserslist-db "^1.1.0" buffer-crc32@^1.0.0: version "1.0.0" @@ -2344,7 +2102,7 @@ buffer-crc32@~0.2.3: buffer-from@^1.0.0: version "1.1.2" - resolved "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz" + resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.2.tgz#2b146a6fd72e80b4f55d255f35ed59a3a9a41bd5" integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ== buffer@^5.5.0: @@ -2415,7 +2173,7 @@ call-bind@^1.0.5, call-bind@^1.0.6, call-bind@^1.0.7: callsite@^1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/callsite/-/callsite-1.0.0.tgz" + resolved "https://registry.yarnpkg.com/callsite/-/callsite-1.0.0.tgz#280398e5d664bd74038b6f0905153e6e8af1bc20" integrity sha512-0vdNRFXn5q+dtOqjfFtmtlI9N2eVZ7LMyEV2iKC5mEEFvSg/69Ml6b/WU2qF8W1nLRa0wiSrDT3Y5jOHZCwKPQ== callsites@^3.0.0: @@ -2423,14 +2181,14 @@ callsites@^3.0.0: resolved "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz" integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== -caniuse-lite@^1.0.30001587: - version "1.0.30001588" - resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001588.tgz" - integrity sha512-+hVY9jE44uKLkH0SrUTqxjxqNTOWHsbnQDIKjwkZ3lNTzUUVdBLBGXtj/q5Mp5u98r3droaZAewQuEDzjQdZlQ== +caniuse-lite@^1.0.30001663: + version "1.0.30001669" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001669.tgz#fda8f1d29a8bfdc42de0c170d7f34a9cf19ed7a3" + integrity sha512-DlWzFDJqstqtIVx1zeSpIMLjunf5SmwOw0N2Ck/QSQdS8PLS4+9HrLaYei4w8BIAL7IB/UEDu889d8vhCTPA0w== chai@4.3.4: version "4.3.4" - resolved "https://registry.npmjs.org/chai/-/chai-4.3.4.tgz" + resolved "https://registry.yarnpkg.com/chai/-/chai-4.3.4.tgz#b55e655b31e1eac7099be4c08c21964fce2e6c49" integrity sha512-yS5H68VYOCtN1cjfwumDSuzn/9c+yza4f3reKXlE5rUg7SFcCEy90gJvydNgOYtblyf4Zi6jIWRnXOgErta0KA== dependencies: assertion-error "^1.1.0" @@ -2442,7 +2200,7 @@ chai@4.3.4: chalk@^2.3.0, chalk@^2.4.0, chalk@^2.4.2: version "2.4.2" - resolved "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== dependencies: ansi-styles "^3.2.1" @@ -2464,7 +2222,7 @@ chance@1.1.12: check-error@^1.0.2: version "1.0.3" - resolved "https://registry.npmjs.org/check-error/-/check-error-1.0.3.tgz" + resolved "https://registry.yarnpkg.com/check-error/-/check-error-1.0.3.tgz#a6502e4312a7ee969f646e83bb3ddd56281bd694" integrity sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg== dependencies: get-func-name "^2.0.2" @@ -2481,7 +2239,7 @@ chownr@^2.0.0: chrome-remote-interface@^0.31.3: version "0.31.3" - resolved "https://registry.npmjs.org/chrome-remote-interface/-/chrome-remote-interface-0.31.3.tgz" + resolved "https://registry.yarnpkg.com/chrome-remote-interface/-/chrome-remote-interface-0.31.3.tgz#bd01b89f5f0e968f7eeb37b8b7c5ac20e6e1f4d0" integrity sha512-NTwb1YNPHXLTus1RjqsLxJmdViKwKJg/lrFEcM6pbyQy04Ow2QKWHXyPpxzwE+dFsJghWuvSAdTy4W0trluz1g== dependencies: commander "2.11.x" @@ -2489,7 +2247,7 @@ chrome-remote-interface@^0.31.3: chrome-remote-interface@^0.32.2: version "0.32.2" - resolved "https://registry.npmjs.org/chrome-remote-interface/-/chrome-remote-interface-0.32.2.tgz" + resolved "https://registry.yarnpkg.com/chrome-remote-interface/-/chrome-remote-interface-0.32.2.tgz#4c494b9d074997b45d49137232df48a355189278" integrity sha512-3UbFKtEmqApehPQnqdblcggx7KveQphEMKQmdJZsOguE9ylw2N2/9Z7arO7xS55+DBJ/hyP8RrayLt4MMdJvQg== dependencies: commander "2.11.x" @@ -2510,12 +2268,12 @@ chromedriver@^130.0.0: ci-info@^1.5.0: version "1.6.0" - resolved "https://registry.npmjs.org/ci-info/-/ci-info-1.6.0.tgz" + resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-1.6.0.tgz#2ca20dbb9ceb32d4524a683303313f0304b1e497" integrity sha512-vsGdkwSCDpWmP80ncATX7iea5DWQemg1UgCW5J8tqjU3lYw4FBYuj89J0CTVomA7BEfvSZd84GmHko+MxFQU2A== clean-stack@^2.0.0: version "2.2.0" - resolved "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz" + resolved "https://registry.yarnpkg.com/clean-stack/-/clean-stack-2.2.0.tgz#ee8472dbb129e727b31e8a10a427dee9dfe4008b" integrity sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A== cli-argument-parser@0.7.4: @@ -2533,31 +2291,31 @@ cluster-key-slot@1.1.2: coffeescript@^2.3.1: version "2.7.0" - resolved "https://registry.npmjs.org/coffeescript/-/coffeescript-2.7.0.tgz" + resolved "https://registry.yarnpkg.com/coffeescript/-/coffeescript-2.7.0.tgz#a43ec03be6885d6d1454850ea70b9409c391279c" integrity sha512-hzWp6TUE2d/jCcN67LrW1eh5b/rSDKQK6oD6VMLlggYVUUFexgTH9z3dNYihzX4RMhze5FTUsUmOXViJKFQR/A== color-convert@^1.9.0: version "1.9.3" - resolved "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== dependencies: color-name "1.1.3" color-convert@^2.0.1: version "2.0.1" - resolved "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== dependencies: color-name "~1.1.4" color-name@1.1.3: version "1.1.3" - resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" integrity sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw== color-name@~1.1.4: version "1.1.4" - resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== color-support@^1.1.3: @@ -2574,17 +2332,17 @@ combined-stream@^1.0.8: commander@2.11.x: version "2.11.0" - resolved "https://registry.npmjs.org/commander/-/commander-2.11.0.tgz" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.11.0.tgz#157152fd1e7a6c8d98a5b715cf376df928004563" integrity sha512-b0553uYA5YAEGgyYIGYROzKQ7X5RAqedkfjiZxwi0kL1g3bOaBNNZfYkzt/CL0umgD5wc9Jec2FbB98CjkMRvQ== commander@^5.0.0: version "5.1.0" - resolved "https://registry.npmjs.org/commander/-/commander-5.1.0.tgz" + resolved "https://registry.yarnpkg.com/commander/-/commander-5.1.0.tgz#46abbd1652f8e059bddaef99bbdcb2ad9cf179ae" integrity sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg== commander@^8.3.0: version "8.3.0" - resolved "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz" + resolved "https://registry.yarnpkg.com/commander/-/commander-8.3.0.tgz#4837ea1b2da67b9c616a67afbb0fafee567bca66" integrity sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww== compare-versions@^6.1.0: @@ -2610,7 +2368,7 @@ compress-commons@^6.0.2: concat-map@0.0.1: version "0.0.1" - resolved "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz" + resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg== console-control-strings@^1.1.0: @@ -2620,7 +2378,7 @@ console-control-strings@^1.1.0: convert-source-map@^2.0.0: version "2.0.0" - resolved "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz" + resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-2.0.0.tgz#4b560f649fc4e918dd0ab75cf4961e8bc882d82a" integrity sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg== cookiejar@^2.1.4: @@ -2628,23 +2386,16 @@ cookiejar@^2.1.4: resolved "https://registry.yarnpkg.com/cookiejar/-/cookiejar-2.1.4.tgz#ee669c1fea2cf42dc31585469d193fef0d65771b" integrity sha512-LDx6oHrK+PhzLKJU9j5S7/Y3jM/mUHvD/DeI1WQmJn652iPC5Y4TBzC9l+5OMOXlyTTA+SmVUPm0HQUwpD5Jqw== -core-js-compat@^3.31.0: - version "3.36.0" - resolved "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.36.0.tgz" - integrity sha512-iV9Pd/PsgjNWBXeq8XRtWVSgz2tKAfhfvBs7qxYty+RlRd+OCksaWmOnc4JKrTc1cToXL1N0s3l/vwlxPtdElw== +core-js-compat@^3.33.1, core-js-compat@^3.38.0, core-js-compat@^3.38.1: + version "3.38.1" + resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.38.1.tgz#2bc7a298746ca5a7bcb9c164bcb120f2ebc09a09" + integrity sha512-JRH6gfXxGmrzF3tZ57lFx97YARxCXPaMzPo6jELZhv88pBH5VXpQ+y0znKGlFnzuaihqhLbefxSJxWJMPtfDzw== dependencies: - browserslist "^4.22.3" - -core-js-compat@^3.33.1, core-js-compat@^3.36.1: - version "3.37.0" - resolved "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.37.0.tgz" - integrity sha512-vYq4L+T8aS5UuFg4UwDhc7YNRWVeVZwltad9C/jV3R2LgVOpS9BDr7l/WL6BN0dbV3k1XejPTHqqEzJgsa0frA== - dependencies: - browserslist "^4.23.0" + browserslist "^4.23.3" core-util-is@~1.0.0: version "1.0.3" - resolved "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz" + resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.3.tgz#a6042d3634c2b27e9328f837b965fac83808db85" integrity sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ== crc-32@^1.2.0: @@ -2674,7 +2425,7 @@ cross-env@^7.0.3: cross-spawn@^7.0.0, cross-spawn@^7.0.1, cross-spawn@^7.0.2, cross-spawn@^7.0.3: version "7.0.3" - resolved "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w== dependencies: path-key "^3.1.0" @@ -2683,7 +2434,7 @@ cross-spawn@^7.0.0, cross-spawn@^7.0.1, cross-spawn@^7.0.2, cross-spawn@^7.0.3: crypto-md5@^1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/crypto-md5/-/crypto-md5-1.0.0.tgz" + resolved "https://registry.yarnpkg.com/crypto-md5/-/crypto-md5-1.0.0.tgz#ccc8da750c753c7edcbabc542967472a384e86bb" integrity sha512-65Mtei8+EkSIK+5Ie4gpWXoJ/5bgpqPXFknHHXAyhDqKsEAAzUslGd8mOeawbfcuQ8fADNKcF4xQA3fqlZJ8Ig== data-uri-to-buffer@^6.0.2: @@ -2718,7 +2469,7 @@ data-view-byte-offset@^1.0.0: es-errors "^1.3.0" is-data-view "^1.0.1" -debug@4, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.3, debug@^4.3.4: +debug@4, debug@^4.3.3: version "4.3.4" resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== @@ -2727,7 +2478,7 @@ debug@4, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.3, debug@^4.3.4: debug@4.3.1: version "4.3.1" - resolved "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.1.tgz#f0d229c505e0c6d8c49ac553d1b13dc183f6b2ee" integrity sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ== dependencies: ms "2.1.2" @@ -2739,7 +2490,7 @@ debug@^3.2.7: dependencies: ms "^2.1.1" -debug@^4.3.2: +debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2, debug@^4.3.4: version "4.3.7" resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.7.tgz#87945b4151a011d76d95a198d7111c865c360a52" integrity sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ== @@ -2755,22 +2506,22 @@ decompress-response@^6.0.0: dedent@^0.4.0: version "0.4.0" - resolved "https://registry.npmjs.org/dedent/-/dedent-0.4.0.tgz" + resolved "https://registry.yarnpkg.com/dedent/-/dedent-0.4.0.tgz#87defd040bd4c1595d963282ec57f3c2a8525642" integrity sha512-25DJIXD6mCqYHIqI3/aBfAvFgJSY9jIx397eUQSofXbWVR4lcB21a17qQ5Bswj0Zv+3Nf06zNCyfkGyvo0AqqQ== dedent@^0.6.0: version "0.6.0" - resolved "https://registry.npmjs.org/dedent/-/dedent-0.6.0.tgz" + resolved "https://registry.yarnpkg.com/dedent/-/dedent-0.6.0.tgz#0e6da8f0ce52838ef5cec5c8f9396b0c1b64a3cb" integrity sha512-cSfRWjXJtZQeRuZGVvDrJroCR5V2UvBNUMHsPCdNYzuAG8b9V8aAy3KUcdQrGQPXs17Y+ojbPh1aOCplg9YR9g== dedent@^0.7.0: version "0.7.0" - resolved "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz" + resolved "https://registry.yarnpkg.com/dedent/-/dedent-0.7.0.tgz#2495ddbaf6eb874abb0e1be9df22d2e5a544326c" integrity sha512-Q6fKUPqnAHAyhiUgFU7BUzLiv0kd8saH9al7tnu5Q/okj6dnupxyTgFIBjVzJATdfIAm9NAsvXNzjaKa+bxVyA== deep-eql@^3.0.1: version "3.0.1" - resolved "https://registry.npmjs.org/deep-eql/-/deep-eql-3.0.1.tgz" + resolved "https://registry.yarnpkg.com/deep-eql/-/deep-eql-3.0.1.tgz#dfc9404400ad1c8fe023e7da1df1c147c4b444df" integrity sha512-+QeIQyN5ZuO+3Uk5DYh6/1eKO0m0YmJFGNmFHGACpf1ClL1nmlV/p4gNgbl2pJGxgXb4faqo6UE+M5ACEMyVcw== dependencies: type-detect "^4.0.0" @@ -2840,7 +2591,7 @@ degenerator@^5.0.0: del@^3.0.0: version "3.0.0" - resolved "https://registry.npmjs.org/del/-/del-3.0.0.tgz" + resolved "https://registry.yarnpkg.com/del/-/del-3.0.0.tgz#53ecf699ffcbcb39637691ab13baf160819766e5" integrity sha512-7yjqSoVSlJzA4t/VUwazuEagGeANEKB3f/aNI//06pfKgwoCb7f6Q1gETN1sZzYaj6chTQ0AhIwDiPdfOjko4A== dependencies: globby "^6.1.0" @@ -2852,7 +2603,7 @@ del@^3.0.0: del@^5.1.0: version "5.1.0" - resolved "https://registry.npmjs.org/del/-/del-5.1.0.tgz" + resolved "https://registry.yarnpkg.com/del/-/del-5.1.0.tgz#d9487c94e367410e6eff2925ee58c0c84a75b3a7" integrity sha512-wH9xOVHnczo9jN2IW68BabcecVPxacIA3g/7z6vhSU/4stOKQzeCRK0yD0A24WiAAUJmmVpWqrERcTxnLo3AnA== dependencies: globby "^10.0.1" @@ -2876,7 +2627,7 @@ delegates@^1.0.0: des.js@^1.0.1: version "1.1.0" - resolved "https://registry.npmjs.org/des.js/-/des.js-1.1.0.tgz" + resolved "https://registry.yarnpkg.com/des.js/-/des.js-1.1.0.tgz#1d37f5766f3bbff4ee9638e871a8768c173b81da" integrity sha512-r17GxjhUCjSRy8aiJpr8/UadFIzMzJGexI3Nmz4ADi9LYSFx4gTBp80+NaX/YsXWWLhpZ7v/v/ubEc/bCNfKwg== dependencies: inherits "^2.0.1" @@ -2894,7 +2645,7 @@ detect-libc@^2.0.1: device-specs@^1.0.0: version "1.0.1" - resolved "https://registry.npmjs.org/device-specs/-/device-specs-1.0.1.tgz" + resolved "https://registry.yarnpkg.com/device-specs/-/device-specs-1.0.1.tgz#b1a26c717a5339815238abf07f427e0b340d35ac" integrity sha512-rxns/NDZfbdYumnn801z9uo8kWIz3Eld7Bk/F0V9zw4sZemSoD93+gxHEonLdxYulkws4iCMt7ZP8zuM8EzUSg== dezalgo@^1.0.4: @@ -2912,7 +2663,7 @@ diff@^4.0.1, diff@^4.0.2: dir-glob@^3.0.1: version "3.0.1" - resolved "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz" + resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-3.0.1.tgz#56dbf73d992a4a93ba1584f4534063fd2e41717f" integrity sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA== dependencies: path-type "^4.0.0" @@ -2951,7 +2702,7 @@ eastasianwidth@^0.2.0: easy-stack@^1.0.1: version "1.0.1" - resolved "https://registry.npmjs.org/easy-stack/-/easy-stack-1.0.1.tgz" + resolved "https://registry.yarnpkg.com/easy-stack/-/easy-stack-1.0.1.tgz#8afe4264626988cabb11f3c704ccd0c835411066" integrity sha512-wK2sCs4feiiJeFXn3zvY0p41mdU5VUgbgs1rNsc/y5ngFUijdWd+iIN8eoyuZHKB8xN6BL4PdWmzqFmxNg6V2w== edit-json-file@1.8.0: @@ -2965,29 +2716,29 @@ edit-json-file@1.8.0: set-value "^4.1.0" w-json "^1.3.10" -electron-to-chromium@^1.4.668: - version "1.4.673" - resolved "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.673.tgz" - integrity sha512-zjqzx4N7xGdl5468G+vcgzDhaHkaYgVcf9MqgexcTqsl2UHSCmOj/Bi3HAprg4BZCpC7HyD8a6nZl6QAZf72gw== +electron-to-chromium@^1.5.28: + version "1.5.39" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.5.39.tgz#5cbe5200b43dff7b7c2bcb6bdacf65d514c76bb2" + integrity sha512-4xkpSR6CjuiaNyvwiWDI85N9AxsvbPawB8xc7yzLPonYTuP19BVgYweKyUMFtHEZgIcHWMt1ks5Cqx2m+6/Grg== elegant-spinner@^1.0.1: version "1.0.1" - resolved "https://registry.npmjs.org/elegant-spinner/-/elegant-spinner-1.0.1.tgz" + resolved "https://registry.yarnpkg.com/elegant-spinner/-/elegant-spinner-1.0.1.tgz#db043521c95d7e303fd8f345bedc3349cfb0729e" integrity sha512-B+ZM+RXvRqQaAmkMlO/oSe5nMUOaUnyfGYCEHoR8wrXsZR2mA0XVibsxV1bvTwxdRWah1PkQqso2EzhILGHtEQ== email-validator@^2.0.4: version "2.0.4" - resolved "https://registry.npmjs.org/email-validator/-/email-validator-2.0.4.tgz" + resolved "https://registry.yarnpkg.com/email-validator/-/email-validator-2.0.4.tgz#b8dfaa5d0dae28f1b03c95881d904d4e40bfe7ed" integrity sha512-gYCwo7kh5S3IDyZPLZf6hSS0MnZT8QmJFqYvbqlDZSbwdZlY6QZWxJ4i/6UhITOJ4XzyI647Bm2MXKCLqnJ4nQ== emittery@^0.4.1: version "0.4.1" - resolved "https://registry.npmjs.org/emittery/-/emittery-0.4.1.tgz" + resolved "https://registry.yarnpkg.com/emittery/-/emittery-0.4.1.tgz#abe9d3297389ba424ac87e53d1c701962ce7433d" integrity sha512-r4eRSeStEGf6M5SKdrQhhLK5bOwOBxQhIE3YSTnZE3GpKiLfnnhE+tPtrJE79+eDJgm39BM6LSoI8SCx4HbwlQ== emoji-regex@^8.0.0: version "8.0.0" - resolved "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz" + resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== emoji-regex@^9.2.2: @@ -3004,22 +2755,22 @@ encoding@^0.1.12: end-of-stream@^1.1.0, end-of-stream@^1.4.1: version "1.4.4" - resolved "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz" + resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.4.tgz#5ae64a5f45057baf3626ec14da0ca5e4b2431eb0" integrity sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q== dependencies: once "^1.4.0" endpoint-utils@^1.0.2: version "1.0.2" - resolved "https://registry.npmjs.org/endpoint-utils/-/endpoint-utils-1.0.2.tgz" + resolved "https://registry.yarnpkg.com/endpoint-utils/-/endpoint-utils-1.0.2.tgz#0808c3369a727cd7967a39ff34ebc926b88146a8" integrity sha512-s5IrlLvx7qVXPOjcxjF00CRBlybiQWOoGCNiIZ/Vin2WeJ3SHtfkWHRsyu7C1+6QAwYXf0ULoweylxUa19Khjg== dependencies: ip "^1.1.3" pinkie-promise "^1.0.0" -entities@^4.4.0: +entities@^4.5.0: version "4.5.0" - resolved "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz" + resolved "https://registry.yarnpkg.com/entities/-/entities-4.5.0.tgz#5d268ea5e7113ec74c4d033b79ea5a35a488fb48" integrity sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw== env-paths@^2.2.0: @@ -3034,7 +2785,7 @@ err-code@^2.0.2: error-stack-parser@^2.1.4: version "2.1.4" - resolved "https://registry.npmjs.org/error-stack-parser/-/error-stack-parser-2.1.4.tgz" + resolved "https://registry.yarnpkg.com/error-stack-parser/-/error-stack-parser-2.1.4.tgz#229cb01cdbfa84440bfa91876285b94680188286" integrity sha512-Sk5V6wVazPhq5MhpO+AUxJn5x7XSXGl1R93Vn7i+zS15KDVxQijejNCrz8340/2bgLBjR9GtEG8ZVKONDjcqGQ== dependencies: stackframe "^1.3.4" @@ -3142,14 +2893,14 @@ es-to-primitive@^1.2.1: is-date-object "^1.0.1" is-symbol "^1.0.2" -escalade@^3.1.1: - version "3.1.2" - resolved "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz" - integrity sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA== +escalade@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.2.0.tgz#011a3f69856ba189dffa7dc8fcce99d2a87903e5" + integrity sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA== escape-string-regexp@^1.0.5: version "1.0.5" - resolved "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" integrity sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg== escape-string-regexp@^4.0.0: @@ -3270,7 +3021,7 @@ eslint@9.12.0: esotope-hammerhead@0.6.8: version "0.6.8" - resolved "https://registry.npmjs.org/esotope-hammerhead/-/esotope-hammerhead-0.6.8.tgz" + resolved "https://registry.yarnpkg.com/esotope-hammerhead/-/esotope-hammerhead-0.6.8.tgz#98f3dbf533e859de8d54e5bab4a930214f505810" integrity sha512-2Zhg0c6NfrNA4QT5s4+QG5WJQtq3Se7GonNwtNwfr7sVIo/7L8rirPfh9yyloEmDA7R0yPgD10teFxhf2vWyIw== dependencies: "@types/estree" "0.0.46" @@ -3310,12 +3061,12 @@ estraverse@^5.1.0, estraverse@^5.2.0: esutils@^2.0.2: version "2.0.3" - resolved "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz" + resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== event-pubsub@4.3.0: version "4.3.0" - resolved "https://registry.npmjs.org/event-pubsub/-/event-pubsub-4.3.0.tgz" + resolved "https://registry.yarnpkg.com/event-pubsub/-/event-pubsub-4.3.0.tgz#f68d816bc29f1ec02c539dc58c8dd40ce72cb36e" integrity sha512-z7IyloorXvKbFx9Bpie2+vMJKKx1fH1EN5yiTfp8CiLOTptSYy1g8H4yDpGlEdshL1PBiFtBHepF2cNsqeEeFQ== event-target-shim@^5.0.0: @@ -3330,7 +3081,7 @@ events@^3.3.0: execa@^3.3.0: version "3.4.0" - resolved "https://registry.npmjs.org/execa/-/execa-3.4.0.tgz" + resolved "https://registry.yarnpkg.com/execa/-/execa-3.4.0.tgz#c08ed4550ef65d858fac269ffc8572446f37eb89" integrity sha512-r9vdGQk4bmCuK1yKQu1KTwcT2zwfWdbdaXfCtAh+5nU/4fSX+JAb7vZGvI5naJrQlvONrEB20jeruESI69530g== dependencies: cross-spawn "^7.0.0" @@ -3346,7 +3097,7 @@ execa@^3.3.0: execa@^4.0.3: version "4.1.0" - resolved "https://registry.npmjs.org/execa/-/execa-4.1.0.tgz" + resolved "https://registry.yarnpkg.com/execa/-/execa-4.1.0.tgz#4e5491ad1572f2f17a77d388c6c857135b22847a" integrity sha512-j5W0//W7f8UxAn8hXVnwG8tLwdiUy4FJLcSupCg6maBYZDpyBvTApK7KyuI4bKj8KOh1r2YH+6ucuYtJv1bTZA== dependencies: cross-spawn "^7.0.0" @@ -3361,7 +3112,7 @@ execa@^4.0.3: execa@^5.1.1: version "5.1.1" - resolved "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz" + resolved "https://registry.yarnpkg.com/execa/-/execa-5.1.1.tgz#f80ad9cbf4298f7bd1d4c9555c21e93741c411dd" integrity sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg== dependencies: cross-spawn "^7.0.3" @@ -3400,7 +3151,7 @@ fast-fifo@^1.2.0, fast-fifo@^1.3.2: resolved "https://registry.yarnpkg.com/fast-fifo/-/fast-fifo-1.3.2.tgz#286e31de96eb96d38a97899815740ba2a4f3640c" integrity sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ== -fast-glob@^3.0.3, fast-glob@^3.3.2: +fast-glob@^3.0.3, fast-glob@^3.2.9, fast-glob@^3.3.2: version "3.3.2" resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.3.2.tgz#a904501e57cfdd2ffcded45e99a54fef55e46129" integrity sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow== @@ -3411,17 +3162,6 @@ fast-glob@^3.0.3, fast-glob@^3.3.2: merge2 "^1.3.0" micromatch "^4.0.4" -fast-glob@^3.2.9: - version "3.2.12" - resolved "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz" - integrity sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w== - dependencies: - "@nodelib/fs.stat" "^2.0.2" - "@nodelib/fs.walk" "^1.2.3" - glob-parent "^5.1.2" - merge2 "^1.3.0" - micromatch "^4.0.4" - fast-json-stable-stringify@^2.0.0: version "2.1.0" resolved "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz" @@ -3438,9 +3178,9 @@ fast-safe-stringify@^2.1.1: integrity sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA== fastq@^1.6.0: - version "1.15.0" - resolved "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz" - integrity sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw== + version "1.17.1" + resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.17.1.tgz#2a523f07a4e7b1e81a42b91b8bf2254107753b47" + integrity sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w== dependencies: reusify "^1.0.4" @@ -3475,30 +3215,29 @@ file-uri-to-path@1.0.0: fill-keys@^1.0.2: version "1.0.2" - resolved "https://registry.npmjs.org/fill-keys/-/fill-keys-1.0.2.tgz" + resolved "https://registry.yarnpkg.com/fill-keys/-/fill-keys-1.0.2.tgz#9a8fa36f4e8ad634e3bf6b4f3c8882551452eb20" integrity sha512-tcgI872xXjwFF4xgQmLxi76GnwJG3g/3isB1l4/G5Z4zrbddGpBjqZCO9oEAcB5wX0Hj/5iQB3toxfO7in1hHA== dependencies: is-object "~1.0.1" merge-descriptors "~1.0.0" -fill-range@^7.0.1: - version "7.0.1" - resolved "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz" - integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ== +fill-range@^7.1.1: + version "7.1.1" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.1.1.tgz#44265d3cac07e3ea7dc247516380643754a05292" + integrity sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg== dependencies: to-regex-range "^5.0.1" find-babel-config@^2.0.0: - version "2.1.1" - resolved "https://registry.yarnpkg.com/find-babel-config/-/find-babel-config-2.1.1.tgz#93703fc8e068db5e4c57592900c5715dd04b7e5b" - integrity sha512-5Ji+EAysHGe1OipH7GN4qDjok5Z1uw5KAwDCbicU/4wyTZY7CqOCzcWbG7J5ad9mazq67k89fXlbc1MuIfl9uA== + version "2.1.2" + resolved "https://registry.yarnpkg.com/find-babel-config/-/find-babel-config-2.1.2.tgz#2841b1bfbbbcdb971e1e39df8cbc43dafa901716" + integrity sha512-ZfZp1rQyp4gyuxqt1ZqjFGVeVBvmpURMqdIWXbPRfB97Bf6BzdK/xSIbylEINzQ0kB5tlDQfn9HkNXXWsqTqLg== dependencies: json5 "^2.2.3" - path-exists "^4.0.0" find-up@^3.0.0: version "3.0.0" - resolved "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-3.0.0.tgz#49169f1d7993430646da61ecc5ae355c21c97b73" integrity sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg== dependencies: locate-path "^3.0.0" @@ -3574,7 +3313,7 @@ fs-constants@^1.0.0: fs-extra@^10.0.0: version "10.1.0" - resolved "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz" + resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-10.1.0.tgz#02873cfbc4084dde127eaa5f9905eef2325d1abf" integrity sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ== dependencies: graceful-fs "^4.2.0" @@ -3599,17 +3338,12 @@ fs-minipass@^2.0.0: fs.realpath@^1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz" + resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== -function-bind@^1.1.1: - version "1.1.1" - resolved "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz" - integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== - -function-bind@^1.1.2: +function-bind@^1.1.1, function-bind@^1.1.2: version "1.1.2" - resolved "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz" + resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.2.tgz#2c02d864d97f3ea6c8830c464cbd11ab6eab7a1c" integrity sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA== function.prototype.name@^1.1.6: @@ -3648,12 +3382,12 @@ generic-pool@3.9.0: gensync@^1.0.0-beta.2: version "1.0.0-beta.2" - resolved "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz" + resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0" integrity sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg== get-func-name@^2.0.0, get-func-name@^2.0.2: version "2.0.2" - resolved "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.2.tgz" + resolved "https://registry.yarnpkg.com/get-func-name/-/get-func-name-2.0.2.tgz#0d7cf20cd13fda808669ffa88f4ffc7a3943fc41" integrity sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ== get-intrinsic@^1.0.2, get-intrinsic@^1.1.1, get-intrinsic@^1.1.3: @@ -3679,7 +3413,7 @@ get-intrinsic@^1.2.1, get-intrinsic@^1.2.3, get-intrinsic@^1.2.4: get-os-info@^1.0.2: version "1.0.2" - resolved "https://registry.npmjs.org/get-os-info/-/get-os-info-1.0.2.tgz" + resolved "https://registry.yarnpkg.com/get-os-info/-/get-os-info-1.0.2.tgz#5f65df82d3fa16192d2363fc621f050f8a570864" integrity sha512-Nlgt85ph6OHZ4XvTcC8LMLDDFUzf7LAinYJZUwzrnc3WiO+vDEHDmNItTtzixBDLv94bZsvJGrrDRAE6uPs4MQ== dependencies: getos "^3.2.1" @@ -3689,7 +3423,7 @@ get-os-info@^1.0.2: get-stdin@^4.0.1: version "4.0.1" - resolved "https://registry.npmjs.org/get-stdin/-/get-stdin-4.0.1.tgz" + resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-4.0.1.tgz#b968c6b0a04384324902e8bf1a5df32579a450fe" integrity sha512-F5aQMywwJ2n85s4hJPTT9RPxGmubonuB10MNYo17/xph174n2MIR33HRguhzVag10O/npM7SPk73LMZNP+FaWw== get-stream@^5.0.0, get-stream@^5.1.0: @@ -3701,7 +3435,7 @@ get-stream@^5.0.0, get-stream@^5.1.0: get-stream@^6.0.0: version "6.0.1" - resolved "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz" + resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-6.0.1.tgz#a262d8eef67aced57c2852ad6167526a43cbf7b7" integrity sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg== get-symbol-description@^1.0.2: @@ -3725,7 +3459,7 @@ get-uri@^6.0.1: getos@^3.2.1: version "3.2.1" - resolved "https://registry.npmjs.org/getos/-/getos-3.2.1.tgz" + resolved "https://registry.yarnpkg.com/getos/-/getos-3.2.1.tgz#0134d1f4e00eb46144c5a9c0ac4dc087cbb27dc5" integrity sha512-U56CfOK17OKgTVqozZjUKNdkfEv6jk5WISBJ8SHoagjE6L69zOwl3Z+O8myjY9MEW3i2HPWQBt/LTbCgcC973Q== dependencies: async "^3.2.0" @@ -3737,7 +3471,7 @@ github-from-package@0.0.0: glob-parent@^5.1.2: version "5.1.2" - resolved "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== dependencies: is-glob "^4.0.1" @@ -3786,7 +3520,7 @@ glob@^8.0.3: globals@^11.1.0: version "11.12.0" - resolved "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz" + resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e" integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== globals@^14.0.0: @@ -3803,7 +3537,7 @@ globalthis@^1.0.3: globby@^10.0.1: version "10.0.2" - resolved "https://registry.npmjs.org/globby/-/globby-10.0.2.tgz" + resolved "https://registry.yarnpkg.com/globby/-/globby-10.0.2.tgz#277593e745acaa4646c3ab411289ec47a0392543" integrity sha512-7dUi7RvCoT/xast/o/dLN53oqND4yk0nsHkhRgn9w65C4PofCLOoJ39iSOg+qVDdWQPIEj+eszMHQ+aLVwwQSg== dependencies: "@types/glob" "^7.1.1" @@ -3817,7 +3551,7 @@ globby@^10.0.1: globby@^11.0.4: version "11.1.0" - resolved "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz" + resolved "https://registry.yarnpkg.com/globby/-/globby-11.1.0.tgz#bd4be98bb042f83d796f7e3811991fbe82a0d34b" integrity sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g== dependencies: array-union "^2.1.0" @@ -3829,7 +3563,7 @@ globby@^11.0.4: globby@^6.1.0: version "6.1.0" - resolved "https://registry.npmjs.org/globby/-/globby-6.1.0.tgz" + resolved "https://registry.yarnpkg.com/globby/-/globby-6.1.0.tgz#f5a6d70e8395e21c858fb0489d64df02424d506c" integrity sha512-KVbFv2TQtbzCoxAnfD6JcHZTYCzyliEaaeM/gH8qQdkKr5s0OP9scEgvdcngyk7AVdY6YVW/TJHd+lQ/Df3Daw== dependencies: array-union "^1.0.1" @@ -3847,7 +3581,7 @@ gopd@^1.0.1: graceful-fs@^4.1.11, graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.2, graceful-fs@^4.2.6: version "4.2.11" - resolved "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3" integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ== graphemer@^1.4.0: @@ -3857,7 +3591,7 @@ graphemer@^1.4.0: graphlib@^2.1.5: version "2.1.8" - resolved "https://registry.npmjs.org/graphlib/-/graphlib-2.1.8.tgz" + resolved "https://registry.yarnpkg.com/graphlib/-/graphlib-2.1.8.tgz#5761d414737870084c92ec7b5dbcb0592c9d35da" integrity sha512-jcLLfkpoVGmH7/InMC/1hIvOPSUh38oJtGhvrOFGzioE1DZ+0YW16RgmOJhHiuWTvGiJQ9Z1Ik43JvkRPRvE+A== dependencies: lodash "^4.17.15" @@ -3869,7 +3603,7 @@ has-bigints@^1.0.1, has-bigints@^1.0.2: has-flag@^3.0.0: version "3.0.0" - resolved "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" integrity sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw== has-flag@^4.0.0: @@ -3926,20 +3660,11 @@ has-unicode@^2.0.1: integrity sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ== has@^1.0.3: - version "1.0.3" - resolved "https://registry.npmjs.org/has/-/has-1.0.3.tgz" - integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw== - dependencies: - function-bind "^1.1.1" - -hasown@^2.0.0: - version "2.0.1" - resolved "https://registry.npmjs.org/hasown/-/hasown-2.0.1.tgz" - integrity sha512-1/th4MHjnwncwXsIW6QMzlvYL9kG5e/CpVvLRZe4XPa8TOUNbCELqmvhDmnkNsAjwaG4+I8gJJL0JBvTTLO9qA== - dependencies: - function-bind "^1.1.2" + version "1.0.4" + resolved "https://registry.yarnpkg.com/has/-/has-1.0.4.tgz#2eb2860e000011dae4f1406a86fe80e530fb2ec6" + integrity sha512-qdSAmqLF6209RFj4VVItywPMbm3vWylknmB3nvNiUIs72xAimcM8nVYxYr7ncvZq5qzk9MKIZR8ijqD/1QuYjQ== -hasown@^2.0.1, hasown@^2.0.2: +hasown@^2.0.0, hasown@^2.0.1, hasown@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/hasown/-/hasown-2.0.2.tgz#003eaf91be7adc372e84ec59dc37252cedb80003" integrity sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ== @@ -3953,7 +3678,7 @@ hexoid@^1.0.0: highlight-es@^1.0.0: version "1.0.3" - resolved "https://registry.npmjs.org/highlight-es/-/highlight-es-1.0.3.tgz" + resolved "https://registry.yarnpkg.com/highlight-es/-/highlight-es-1.0.3.tgz#12abc300a27e686f6f18010134e3a5c6d2fe6930" integrity sha512-s/SIX6yp/5S1p8aC/NRDC1fwEb+myGIfp8/TzZz0rtAv8fzsdX7vGl3Q1TrXCsczFq8DI3CBFBCySPClfBSdbg== dependencies: chalk "^2.4.0" @@ -3962,7 +3687,7 @@ highlight-es@^1.0.0: http-cache-semantics@^4.1.0: version "4.1.1" - resolved "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz" + resolved "https://registry.yarnpkg.com/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz#abe02fcb2985460bf0323be664436ec3476a6d5a" integrity sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ== http-proxy-agent@^4.0.1: @@ -3984,12 +3709,12 @@ http-proxy-agent@^7.0.0, http-proxy-agent@^7.0.1: http-status-codes@^2.2.0: version "2.3.0" - resolved "https://registry.npmjs.org/http-status-codes/-/http-status-codes-2.3.0.tgz" + resolved "https://registry.yarnpkg.com/http-status-codes/-/http-status-codes-2.3.0.tgz#987fefb28c69f92a43aecc77feec2866349a8bfc" integrity sha512-RJ8XvFvpPM/Dmc5SV+dC4y5PCeOhT3x1Hq0NU3rjGeg5a/CqlhZ7uudknPwZFz4aeAXDcbAyaeP7GAo9lvngtA== httpntlm@^1.8.10: version "1.8.13" - resolved "https://registry.npmjs.org/httpntlm/-/httpntlm-1.8.13.tgz" + resolved "https://registry.yarnpkg.com/httpntlm/-/httpntlm-1.8.13.tgz#4130e555701b58207303bf757a4e1e41c06835bd" integrity sha512-2F2FDPiWT4rewPzNMg3uPhNkP3NExENlUGADRUDPQvuftuUTGW98nLZtGemCIW3G40VhWZYgkIDcQFAwZ3mf2Q== dependencies: des.js "^1.0.1" @@ -3999,7 +3724,7 @@ httpntlm@^1.8.10: httpreq@>=0.4.22: version "1.1.1" - resolved "https://registry.npmjs.org/httpreq/-/httpreq-1.1.1.tgz" + resolved "https://registry.yarnpkg.com/httpreq/-/httpreq-1.1.1.tgz#b8818316cdfd6b1bfb0f68b822fa1306cd24be68" integrity sha512-uhSZLPPD2VXXOSN8Cni3kIsoFHaU2pT/nySEU/fHr/ePbqHYr0jeiQRmUKLEirC09SFPsdMoA7LU7UXMd/w0Kw== https-proxy-agent@^5.0.0: @@ -4020,18 +3745,18 @@ https-proxy-agent@^7.0.2, https-proxy-agent@^7.0.3: human-signals@^1.1.1: version "1.1.1" - resolved "https://registry.npmjs.org/human-signals/-/human-signals-1.1.1.tgz" + resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-1.1.1.tgz#c5b1cd14f50aeae09ab6c59fe63ba3395fe4dfa3" integrity sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw== human-signals@^2.1.0: version "2.1.0" - resolved "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz" + resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-2.1.0.tgz#dc91fcba42e4d06e4abaed33b3e7a3c02f514ea0" integrity sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw== humanize-duration@^3.25.0: - version "3.31.0" - resolved "https://registry.npmjs.org/humanize-duration/-/humanize-duration-3.31.0.tgz" - integrity sha512-fRrehgBG26NNZysRlTq1S+HPtDpp3u+Jzdc/d5A4cEzOD86YLAkDaJyJg8krSdCi7CJ+s7ht3fwRj8Dl+Btd0w== + version "3.32.1" + resolved "https://registry.yarnpkg.com/humanize-duration/-/humanize-duration-3.32.1.tgz#922beff5da36fb1cee3de26ada24c592b0fe519b" + integrity sha512-inh5wue5XdfObhu/IGEMiA1nUXigSGcaKNemcbLRKa7jXYGDZXr3LoT9pTIzq2hPEbld7w/qv9h+ikWGz8fL1g== humanize-ms@^1.2.1: version "1.2.1" @@ -4042,7 +3767,7 @@ humanize-ms@^1.2.1: iconv-lite@0.5.1: version "0.5.1" - resolved "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.5.1.tgz" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.5.1.tgz#b2425d3c7b18f7219f2ca663d103bddb91718d64" integrity sha512-ONHr16SQvKZNSqjQT9gy5z24Jw+uqfO02/ngBSBoqChZ+W8qXX7GPRa1RoUnzGADw8K63R1BXUMzarCVQBpY8Q== dependencies: safer-buffer ">= 2.1.2 < 3" @@ -4059,17 +3784,7 @@ ieee754@^1.1.13, ieee754@^1.2.1: resolved "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz" integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA== -ignore@^5.1.1: - version "5.3.1" - resolved "https://registry.npmjs.org/ignore/-/ignore-5.3.1.tgz" - integrity sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw== - -ignore@^5.2.0: - version "5.2.4" - resolved "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz" - integrity sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ== - -ignore@^5.3.1: +ignore@^5.1.1, ignore@^5.2.0, ignore@^5.3.1: version "5.3.2" resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.3.2.tgz#3cd40e729f3643fd87cb04e50bf0eb722bc596f5" integrity sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g== @@ -4089,7 +3804,7 @@ import-fresh@^3.2.1: import-lazy@^3.1.0: version "3.1.0" - resolved "https://registry.npmjs.org/import-lazy/-/import-lazy-3.1.0.tgz" + resolved "https://registry.yarnpkg.com/import-lazy/-/import-lazy-3.1.0.tgz#891279202c8a2280fdbd6674dbd8da1a1dfc67cc" integrity sha512-8/gvXvX2JMn0F+CDlSC4l6kOmVaLOO3XLkksI7CI3Ud95KDYJuYur2b9P/PUt/i/pDAMd/DulQsNbbbmRRsDIQ== imurmurhash@^0.1.4: @@ -4099,7 +3814,7 @@ imurmurhash@^0.1.4: indent-string@^1.2.2: version "1.2.2" - resolved "https://registry.npmjs.org/indent-string/-/indent-string-1.2.2.tgz" + resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-1.2.2.tgz#db99bcc583eb6abbb1e48dcbb1999a986041cb6b" integrity sha512-Z1vqf6lDC3f4N2mWqRywY6odjRatPNGDZgUr4DY9MLC14+Fp2/y+CI/RnNGlb8hD6ckscE/8DlZUwHUaiDBshg== dependencies: get-stdin "^4.0.1" @@ -4108,7 +3823,7 @@ indent-string@^1.2.2: indent-string@^4.0.0: version "4.0.0" - resolved "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz" + resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-4.0.0.tgz#624f8f4497d619b2d9768531d58f4122854d7251" integrity sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg== infer-owner@^1.0.4: @@ -4118,7 +3833,7 @@ infer-owner@^1.0.4: inflight@^1.0.4: version "1.0.6" - resolved "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz" + resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" integrity sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA== dependencies: once "^1.3.0" @@ -4126,7 +3841,7 @@ inflight@^1.0.4: inherits@2, inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.3: version "2.0.4" - resolved "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== ini@~1.3.0: @@ -4157,9 +3872,9 @@ ip-regex@^4.1.0: integrity sha512-B9ZWJxHHOHUhUjCPrMpLD4xEq35bUTClHM1S6CBU5ixQnkZmwipwgc96vAd7AAGM9TGHvJR+Uss+/Ak6UphK+Q== ip@^1.1.3: - version "1.1.8" - resolved "https://registry.npmjs.org/ip/-/ip-1.1.8.tgz" - integrity sha512-PuExPYUiu6qMBQb4l06ecm6T6ujzhmh+MeJcW9wa89PoAz5pvd4zPgN5WJV104mb6S2T1AwNIAaB70JNrLQWhg== + version "1.1.9" + resolved "https://registry.yarnpkg.com/ip/-/ip-1.1.9.tgz#8dfbcc99a754d07f425310b86a99546b1151e396" + integrity sha512-cyRxvOEpNHNtchU3Ln9KC/auJgup87llfQpQ+t5ghoC/UhL16SWzbueiCsdTnWmqAWl7LadfuwhlqmtOaqMHdQ== is-array-buffer@^3.0.4: version "3.0.4" @@ -4191,26 +3906,12 @@ is-callable@^1.1.3, is-callable@^1.1.4, is-callable@^1.2.7: is-ci@^1.0.10: version "1.2.1" - resolved "https://registry.npmjs.org/is-ci/-/is-ci-1.2.1.tgz" + resolved "https://registry.yarnpkg.com/is-ci/-/is-ci-1.2.1.tgz#e3779c8ee17fccf428488f6e281187f2e632841c" integrity sha512-s6tfsaQaQi3JNciBH6shVqEDvhGut0SUXr31ag8Pd8BBbVVlcGfWhpPmEOoM6RJ5TFhbypvf5yyRw/VXW1IiWg== dependencies: ci-info "^1.5.0" -is-core-module@^2.11.0: - version "2.12.1" - resolved "https://registry.npmjs.org/is-core-module/-/is-core-module-2.12.1.tgz" - integrity sha512-Q4ZuBAe2FUsKtyQJoQHlvP8OvBERxO3jEmy1I7hcRXcJBGGHFh/aJBswbXuS9sgrDH2QUO8ilkwNPHvHMd8clg== - dependencies: - has "^1.0.3" - -is-core-module@^2.13.0: - version "2.13.1" - resolved "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz" - integrity sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw== - dependencies: - hasown "^2.0.0" - -is-core-module@^2.15.1: +is-core-module@^2.13.0, is-core-module@^2.15.1: version "2.15.1" resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.15.1.tgz#a7363a25bee942fefab0de13bf6aa372c82dcc37" integrity sha512-z0vtXSwucUJtANQWldhbtbt7BnL0vxiFjIdDLAatwhDYty2bad6s+rijD6Ri4YuYJubLzIJLUidCh09e1djEVQ== @@ -4243,32 +3944,32 @@ is-docker@^3.0.0: is-es2016-keyword@^1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/is-es2016-keyword/-/is-es2016-keyword-1.0.0.tgz" + resolved "https://registry.yarnpkg.com/is-es2016-keyword/-/is-es2016-keyword-1.0.0.tgz#f6e54e110c5e4f8d265e69d2ed0eaf8cf5f47718" integrity sha512-JtZWPUwjdbQ1LIo9OSZ8MdkWEve198ors27vH+RzUUvZXXZkzXCxFnlUhzWYxy5IexQSRiXVw9j2q/tHMmkVYQ== is-extglob@^1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz" + resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-1.0.0.tgz#ac468177c4943405a092fc8f29760c6ffc6206c0" integrity sha512-7Q+VbVafe6x2T+Tu6NcOf6sRklazEPmBoB3IWk3WdGZM2iGUwU/Oe3Wtq5lSEkDTTlpp8yx+5t4pzO/i9Ty1ww== is-extglob@^2.1.1: version "2.1.1" - resolved "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz" + resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ== is-finite@^1.0.0: version "1.1.0" - resolved "https://registry.npmjs.org/is-finite/-/is-finite-1.1.0.tgz" + resolved "https://registry.yarnpkg.com/is-finite/-/is-finite-1.1.0.tgz#904135c77fb42c0641d6aa1bcdbc4daa8da082f3" integrity sha512-cdyMtqX/BOqqNBBiKlIVkytNHm49MtMlYyn1zxzvJKWmFMlGzm+ry5BBfYyeY9YmNKbRSo/o7OX9w9ale0wg3w== is-fullwidth-code-point@^3.0.0: version "3.0.0" - resolved "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== is-glob@^2.0.1: version "2.0.1" - resolved "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-2.0.1.tgz#d096f926a3ded5600f3fdfd91198cb0888c2d863" integrity sha512-a1dBeB19NXsf/E0+FHqkagizel/LQw2DjSQpvQrj3zT+jYPpaUCryPnrQajXKFLCMuf4I6FhRpaGtw4lPrG6Eg== dependencies: is-extglob "^1.0.0" @@ -4306,41 +4007,41 @@ is-number-object@^1.0.4: is-number@^7.0.0: version "7.0.0" - resolved "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz" + resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== is-object@~1.0.1: version "1.0.2" - resolved "https://registry.npmjs.org/is-object/-/is-object-1.0.2.tgz" + resolved "https://registry.yarnpkg.com/is-object/-/is-object-1.0.2.tgz#a56552e1c665c9e950b4a025461da87e72f86fcf" integrity sha512-2rRIahhZr2UWb45fIOuvZGpFtz0TyOZLf32KxBbSoUCeZR495zCKlWUKKUByk3geS2eAs7ZAABt0Y/Rx0GiQGA== is-path-cwd@^1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-1.0.0.tgz" + resolved "https://registry.yarnpkg.com/is-path-cwd/-/is-path-cwd-1.0.0.tgz#d225ec23132e89edd38fda767472e62e65f1106d" integrity sha512-cnS56eR9SPAscL77ik76ATVqoPARTqPIVkMDVxRaWH06zT+6+CzIroYRJ0VVvm0Z1zfAvxvz9i/D3Ppjaqt5Nw== is-path-cwd@^2.2.0: version "2.2.0" - resolved "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-2.2.0.tgz" + resolved "https://registry.yarnpkg.com/is-path-cwd/-/is-path-cwd-2.2.0.tgz#67d43b82664a7b5191fd9119127eb300048a9fdb" integrity sha512-w942bTcih8fdJPJmQHFzkS76NEP8Kzzvmw92cXsazb8intwLqPibPPdXf4ANdKV3rYMuuQYGIWtvz9JilB3NFQ== is-path-in-cwd@^1.0.0: version "1.0.1" - resolved "https://registry.npmjs.org/is-path-in-cwd/-/is-path-in-cwd-1.0.1.tgz" + resolved "https://registry.yarnpkg.com/is-path-in-cwd/-/is-path-in-cwd-1.0.1.tgz#5ac48b345ef675339bd6c7a48a912110b241cf52" integrity sha512-FjV1RTW48E7CWM7eE/J2NJvAEEVektecDBVBE5Hh3nM1Jd0kvhHtX68Pr3xsDf857xt3Y4AkwVULK1Vku62aaQ== dependencies: is-path-inside "^1.0.0" is-path-inside@^1.0.0: version "1.0.1" - resolved "https://registry.npmjs.org/is-path-inside/-/is-path-inside-1.0.1.tgz" + resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-1.0.1.tgz#8ef5b7de50437a3fdca6b4e865ef7aa55cb48036" integrity sha512-qhsCR/Esx4U4hg/9I19OVUAJkGWtjRYHMRgUMZE2TDdj+Ag+kttZanLupfddNyglzz50cUlmWzUaI37GDfNx/g== dependencies: path-is-inside "^1.0.1" is-path-inside@^3.0.1: version "3.0.3" - resolved "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz" + resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-3.0.3.tgz#d231362e53a07ff2b0e0ea7fed049161ffd16283" integrity sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ== is-plain-object@^2.0.4: @@ -4352,7 +4053,7 @@ is-plain-object@^2.0.4: is-podman@^1.0.1: version "1.0.1" - resolved "https://registry.npmjs.org/is-podman/-/is-podman-1.0.1.tgz" + resolved "https://registry.yarnpkg.com/is-podman/-/is-podman-1.0.1.tgz#284a7ba1e6987fff8af5d71d97a29d2a85b7996a" integrity sha512-+5vbtF5FIg262iUa7gOIseIWTx0740RHiax7oSmJMhbfSoBIMQ/IacKKgfnGj65JGeH9lGEVQcdkDwhn1Em1mQ== is-primitive@^3.0.1: @@ -4415,7 +4116,7 @@ is-url@^1.2.4: is-utf8@^0.2.0: version "0.2.1" - resolved "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz" + resolved "https://registry.yarnpkg.com/is-utf8/-/is-utf8-0.2.1.tgz#4b0da1442104d1b336340e80797e865cf39f7d72" integrity sha512-rMYPYvCzsXywIsldgLaSoPlw5PfoB/ssr7hY4pLfcodrA5M/eArza1a9VmTiNIBNMjOGr1Ow9mTyU2o69U6U9Q== is-weakref@^1.0.2: @@ -4448,12 +4149,12 @@ isarray@^2.0.5: isarray@~1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" integrity sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ== isexe@^2.0.0: version "2.0.0" - resolved "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz" + resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw== isobject@^3.0.1: @@ -4477,29 +4178,29 @@ jackspeak@^3.1.2: js-md4@^0.3.2: version "0.3.2" - resolved "https://registry.npmjs.org/js-md4/-/js-md4-0.3.2.tgz" + resolved "https://registry.yarnpkg.com/js-md4/-/js-md4-0.3.2.tgz#cd3b3dc045b0c404556c81ddb5756c23e59d7cf5" integrity sha512-/GDnfQYsltsjRswQhN9fhv3EMw2sCpUdrdxyWDOUK7eyD++r3gRhzgiQgc/x4MAv2i1iuQ4lxO5mvqM3vj4bwA== js-message@1.0.7: version "1.0.7" - resolved "https://registry.npmjs.org/js-message/-/js-message-1.0.7.tgz" + resolved "https://registry.yarnpkg.com/js-message/-/js-message-1.0.7.tgz#fbddd053c7a47021871bb8b2c95397cc17c20e47" integrity sha512-efJLHhLjIyKRewNS9EGZ4UpI8NguuL6fKkhRxVuMmrGV2xN/0APGdQYwLFky5w9naebSZ0OwAGp0G6/2Cg90rA== js-queue@2.0.2: version "2.0.2" - resolved "https://registry.npmjs.org/js-queue/-/js-queue-2.0.2.tgz" + resolved "https://registry.yarnpkg.com/js-queue/-/js-queue-2.0.2.tgz#0be590338f903b36c73d33c31883a821412cd482" integrity sha512-pbKLsbCfi7kriM3s1J4DDCo7jQkI58zPLHi0heXPzPlj0hjUsm+FesPUbE0DSbIVIK503A36aUBoCN7eMFedkA== dependencies: easy-stack "^1.0.1" js-tokens@^3.0.0: version "3.0.2" - resolved "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz" + resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-3.0.2.tgz#9866df395102130e38f7f996bceb65443209c25b" integrity sha512-RjTcuD4xjtthQkaWH7dFlH85L+QaVtSoOyGdZ3g6HFhS9dFNDfLyqgm2NFe2X6cQpeFmt0452FJjFG5UameExg== js-tokens@^4.0.0: version "4.0.0" - resolved "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz" + resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== js-yaml@^4.1.0: @@ -4514,15 +4215,10 @@ jsbn@1.1.0: resolved "https://registry.npmjs.org/jsbn/-/jsbn-1.1.0.tgz" integrity sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A== -jsesc@^2.5.1: - version "2.5.2" - resolved "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz" - integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA== - -jsesc@~0.5.0: - version "0.5.0" - resolved "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz" - integrity sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA== +jsesc@^3.0.2, jsesc@~3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-3.0.2.tgz#bb8b09a6597ba426425f2e4a07245c3d00b9343e" + integrity sha512-xKqzzWXDttJuOcawBt4KnKHHIf5oQ/Cxax+0PWFG+DFDgHNAdi+TXECADI+RYiFUMmx8792xsMbbgXj4CwnP4g== json-buffer@3.0.1: version "3.0.1" @@ -4548,12 +4244,12 @@ json5@^1.0.2: json5@^2.2.2, json5@^2.2.3: version "2.2.3" - resolved "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz" + resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.3.tgz#78cd6f1a19bdc12b73db5ad0c61efd66c1e29283" integrity sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg== jsonfile@^6.0.1: version "6.1.0" - resolved "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz" + resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-6.1.0.tgz#bc55b2634793c679ec6403094eb13698a6ec0aae" integrity sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ== dependencies: universalify "^2.0.0" @@ -4579,7 +4275,7 @@ keyv@^4.5.4: kleur@^3.0.3: version "3.0.3" - resolved "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz" + resolved "https://registry.yarnpkg.com/kleur/-/kleur-3.0.3.tgz#a79c9ecc86ee1ce3fa6206d1216c501f147fc07e" integrity sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w== lazystream@^1.0.0: @@ -4606,14 +4302,14 @@ lie@~3.3.0: linux-platform-info@^0.0.3: version "0.0.3" - resolved "https://registry.npmjs.org/linux-platform-info/-/linux-platform-info-0.0.3.tgz" + resolved "https://registry.yarnpkg.com/linux-platform-info/-/linux-platform-info-0.0.3.tgz#2dae324385e66e3d755bec83f86c7beea61ceb83" integrity sha512-FZhfFOIz0i4EGAvM4fQz+eayE9YzMuTx45tbygWYBttNapyiODg85BnAlQ1xnahEkvIM87T98XhXSfW8JAClHg== dependencies: os-family "^1.0.0" locate-path@^3.0.0: version "3.0.0" - resolved "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-3.0.0.tgz#dbec3b3ab759758071b58fe59fc41871af21400e" integrity sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A== dependencies: p-locate "^3.0.0" @@ -4628,7 +4324,7 @@ locate-path@^6.0.0: lodash.debounce@^4.0.8: version "4.0.8" - resolved "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz" + resolved "https://registry.yarnpkg.com/lodash.debounce/-/lodash.debounce-4.0.8.tgz#82d79bff30a67c4005ffd5e2515300ad9ca4d7af" integrity sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow== lodash.merge@^4.6.2: @@ -4638,12 +4334,12 @@ lodash.merge@^4.6.2: "lodash@4.6.1 || ^4.16.1", lodash@^4.14.0, lodash@^4.17.15, lodash@^4.17.21, lodash@^4.17.4: version "4.17.21" - resolved "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== log-update-async-hook@^2.0.7: version "2.0.7" - resolved "https://registry.npmjs.org/log-update-async-hook/-/log-update-async-hook-2.0.7.tgz" + resolved "https://registry.yarnpkg.com/log-update-async-hook/-/log-update-async-hook-2.0.7.tgz#48042bae63ed5ad1a67a6601d88934e60f1f38f8" integrity sha512-V9KpD1AZUBd/oiZ+/Xsgd5rRP9awhgtRiDv5Am4VQCixiDnAbXMdt/yKz41kCzYZtVbwC6YCxnWEF3zjNEwktA== dependencies: ansi-escapes "^4.3.2" @@ -4658,7 +4354,7 @@ long@^5.0.0: lru-cache@2.6.3: version "2.6.3" - resolved "https://registry.npmjs.org/lru-cache/-/lru-cache-2.6.3.tgz" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-2.6.3.tgz#51ccd0b4fc0c843587d7a5709ce4d3b7629bedc5" integrity sha512-qkisDmHMe8gxKujmC1BdaqgkoFlioLDCUwaFBA3lX8Ilhr3YzsasbGYaiADMjxQnj+aiZUKgGKe/BN3skMwXWw== lru-cache@^10.2.0: @@ -4668,14 +4364,14 @@ lru-cache@^10.2.0: lru-cache@^5.1.1: version "5.1.1" - resolved "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-5.1.1.tgz#1da27e6710271947695daf6848e847f01d84b920" integrity sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w== dependencies: yallist "^3.0.2" lru-cache@^6.0.0: version "6.0.0" - resolved "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94" integrity sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA== dependencies: yallist "^4.0.0" @@ -4691,13 +4387,13 @@ lz4js@^0.2.0: integrity sha512-gY2Ia9Lm7Ep8qMiuGRhvUq0Q7qUereeldZPP1PMEJxPtEWHJLqw9pgX68oHajBH0nzJK4MaZEA/YNV3jT8u8Bg== macos-release@^3.0.1: - version "3.2.0" - resolved "https://registry.npmjs.org/macos-release/-/macos-release-3.2.0.tgz" - integrity sha512-fSErXALFNsnowREYZ49XCdOHF8wOPWuFOGQrAhP7x5J/BqQv+B02cNsTykGpDgRVx43EKg++6ANmTaGTtW+hUA== + version "3.3.0" + resolved "https://registry.yarnpkg.com/macos-release/-/macos-release-3.3.0.tgz#92cb67bc66d67c3fde4a9e14f5f909afa418b072" + integrity sha512-tPJQ1HeyiU2vRruNGhZ+VleWuMQRro8iFtJxYgnS4NQe+EukKF6aGiIT+7flZhISAt2iaXBCfFGvAyif7/f8nQ== make-dir@^3.0.0: version "3.1.0" - resolved "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz" + resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-3.1.0.tgz#415e967046b3a7f1d185277d84aa58203726a13f" integrity sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw== dependencies: semver "^6.0.0" @@ -4731,31 +4427,31 @@ make-fetch-happen@^9.1.0: match-url-wildcard@0.0.4: version "0.0.4" - resolved "https://registry.npmjs.org/match-url-wildcard/-/match-url-wildcard-0.0.4.tgz" + resolved "https://registry.yarnpkg.com/match-url-wildcard/-/match-url-wildcard-0.0.4.tgz#c8533da7ec0901eddf01fc0893effa68d4e727d6" integrity sha512-R1XhQaamUZPWLOPtp4ig5j+3jctN+skhgRmEQTUamMzmNtRG69QEirQs0NZKLtHMR7tzWpmtnS4Eqv65DcgXUA== dependencies: escape-string-regexp "^1.0.5" merge-descriptors@~1.0.0: version "1.0.3" - resolved "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz" + resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.3.tgz#d80319a65f3c7935351e5cfdac8f9318504dbed5" integrity sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ== merge-stream@^1.0.1: version "1.0.1" - resolved "https://registry.npmjs.org/merge-stream/-/merge-stream-1.0.1.tgz" + resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-1.0.1.tgz#4041202d508a342ba00174008df0c251b8c135e1" integrity sha512-e6RM36aegd4f+r8BZCcYXlO2P3H6xbUM6ktL2Xmf45GAOit9bI4z6/3VU7JwllVO1L7u0UDSg/EhzQ5lmMLolA== dependencies: readable-stream "^2.0.1" merge-stream@^2.0.0: version "2.0.0" - resolved "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz" + resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60" integrity sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w== merge2@^1.2.3, merge2@^1.3.0, merge2@^1.4.1: version "1.4.1" - resolved "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz" + resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae" integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg== methods@^1.1.2: @@ -4764,18 +4460,23 @@ methods@^1.1.2: integrity sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w== micromatch@^4.0.4: - version "4.0.5" - resolved "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz" - integrity sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA== + version "4.0.8" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.8.tgz#d66fa18f3a47076789320b9b1af32bd86d9fa202" + integrity sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA== dependencies: - braces "^3.0.2" + braces "^3.0.3" picomatch "^2.3.1" -mime-db@1.52.0, mime-db@^1.41.0: +mime-db@1.52.0: version "1.52.0" resolved "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz" integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg== +mime-db@^1.41.0: + version "1.53.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.53.0.tgz#3cb63cd820fc29896d9d4e8c32ab4fcd74ccb447" + integrity sha512-oHlN/w+3MQ3rba9rqFr6V/ypF10LSkdwUysQL7GkXoTgIWeV+tcXGA852TBxH+gsh8UWoyhR1hKcoMJTuWflpg== + mime-types@^2.1.12: version "2.1.35" resolved "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz" @@ -4790,17 +4491,17 @@ mime@2.6.0: mime@~1.4.1: version "1.4.1" - resolved "https://registry.npmjs.org/mime/-/mime-1.4.1.tgz" + resolved "https://registry.yarnpkg.com/mime/-/mime-1.4.1.tgz#121f9ebc49e3766f311a76e1fa1c8003c4b03aa6" integrity sha512-KI1+qOZu5DcW6wayYHSzR/tXKCDC5Om4s1z2QJjDULzLcmf3DvzS7oluY4HCTrc+9FiKmWUgeNLg7W3uIQvxtQ== mimic-fn@^1.0.0: version "1.2.0" - resolved "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz" + resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-1.2.0.tgz#820c86a39334640e99516928bd03fca88057d022" integrity sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ== mimic-fn@^2.1.0: version "2.1.0" - resolved "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz" + resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg== mimic-response@^3.1.0: @@ -4810,7 +4511,7 @@ mimic-response@^3.1.0: minimalistic-assert@^1.0.0: version "1.0.1" - resolved "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz" + resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz#2e194de044626d4a10e7f7fbc00ce73e83e4d5c7" integrity sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A== minimatch@^3.0.4, minimatch@^3.1.1, minimatch@^3.1.2: @@ -4836,7 +4537,7 @@ minimatch@^9.0.4: minimist@^1.1.0, minimist@^1.2.0, minimist@^1.2.3, minimist@^1.2.6: version "1.2.8" - resolved "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.8.tgz#c1a464e7693302e082a075cee0c057741ac4772c" integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA== minipass-collect@^1.0.2: @@ -4910,7 +4611,7 @@ mkdirp-classic@^0.5.2, mkdirp-classic@^0.5.3: mkdirp@^0.5.1: version "0.5.6" - resolved "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.6.tgz#7def03d2432dcae4ba1d611445c48396062255f6" integrity sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw== dependencies: minimist "^1.2.6" @@ -4922,22 +4623,22 @@ mkdirp@^1.0.3, mkdirp@^1.0.4: module-not-found-error@^1.0.0: version "1.0.1" - resolved "https://registry.npmjs.org/module-not-found-error/-/module-not-found-error-1.0.1.tgz" + resolved "https://registry.yarnpkg.com/module-not-found-error/-/module-not-found-error-1.0.1.tgz#cf8b4ff4f29640674d6cdd02b0e3bc523c2bbdc0" integrity sha512-pEk4ECWQXV6z2zjhRZUongnLJNUeGQJ3w6OQ5ctGwD+i5o93qjRQUk2Rt6VdNeu3sEP0AB4LcfvdebpxBRVr4g== moment-duration-format-commonjs@^1.0.0: version "1.0.1" - resolved "https://registry.npmjs.org/moment-duration-format-commonjs/-/moment-duration-format-commonjs-1.0.1.tgz" + resolved "https://registry.yarnpkg.com/moment-duration-format-commonjs/-/moment-duration-format-commonjs-1.0.1.tgz#ca8776466dba736a30cb7cda4e07026b5aec8cf1" integrity sha512-KhKZRH21/+ihNRWrmdNFOyBptFi7nAWZFeFsRRpXkzgk/Yublb4fxyP0jU6EY1VDxUL/VUPdCmm/wAnpbfXdfw== moment@^2.14.1, moment@^2.29.4: version "2.30.1" - resolved "https://registry.npmjs.org/moment/-/moment-2.30.1.tgz" + resolved "https://registry.yarnpkg.com/moment/-/moment-2.30.1.tgz#f8c91c07b7a786e30c59926df530b4eac96974ae" integrity sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how== ms@2.1.2: version "2.1.2" - resolved "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== ms@^2.0.0, ms@^2.1.1, ms@^2.1.3: @@ -4973,7 +4674,7 @@ mustache@^2.1.1, mustache@^2.1.2, mustache@^2.2.1, mustache@^2.3.0: nanoid@^3.1.12, nanoid@^3.1.31: version "3.3.7" - resolved "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz" + resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.7.tgz#d0c301a691bc8d54efa0a2226ccf3fe2fd656bd8" integrity sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g== napi-build-utils@^1.0.1: @@ -5033,17 +4734,17 @@ node-gyp@8.x: node-ipc@9.2.1: version "9.2.1" - resolved "https://registry.npmjs.org/node-ipc/-/node-ipc-9.2.1.tgz" + resolved "https://registry.yarnpkg.com/node-ipc/-/node-ipc-9.2.1.tgz#b32f66115f9d6ce841dc4ec2009d6a733f98bb6b" integrity sha512-mJzaM6O3xHf9VT8BULvJSbdVbmHUKRNOH7zDDkCrA1/T+CVjq2WVIDfLt0azZRXpgArJtl3rtmEozrbXPZ9GaQ== dependencies: event-pubsub "4.3.0" js-message "1.0.7" js-queue "2.0.2" -node-releases@^2.0.14: - version "2.0.14" - resolved "https://registry.npmjs.org/node-releases/-/node-releases-2.0.14.tgz" - integrity sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw== +node-releases@^2.0.18: + version "2.0.18" + resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.18.tgz#f010e8d35e2fe8d6b2944f03f70213ecedc4ca3f" + integrity sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g== nopt@^5.0.0: version "5.0.0" @@ -5059,7 +4760,7 @@ normalize-path@^3.0.0: npm-run-path@^4.0.0, npm-run-path@^4.0.1: version "4.0.1" - resolved "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz" + resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-4.0.1.tgz#b7ecd1e5ed53da8e37a55e1c2269e0b97ed748ea" integrity sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw== dependencies: path-key "^3.0.0" @@ -5076,7 +4777,7 @@ npmlog@^6.0.0: object-assign@^4.0.1: version "4.1.1" - resolved "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz" + resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" integrity sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg== object-inspect@^1.13.1: @@ -5134,21 +4835,21 @@ object.values@^1.2.0: once@^1.3.0, once@^1.3.1, once@^1.4.0: version "1.4.0" - resolved "https://registry.npmjs.org/once/-/once-1.4.0.tgz" + resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w== dependencies: wrappy "1" onetime@^2.0.1: version "2.0.1" - resolved "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz" + resolved "https://registry.yarnpkg.com/onetime/-/onetime-2.0.1.tgz#067428230fd67443b2794b22bba528b6867962d4" integrity sha512-oyyPpiMaKARvvcgip+JV+7zci5L8D1W9RZIz2l1o08AM3pfspitVWnPt3mzHcBPp12oYMTy0pqrFs/C+m3EwsQ== dependencies: mimic-fn "^1.0.0" onetime@^5.1.0, onetime@^5.1.2: version "5.1.2" - resolved "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz" + resolved "https://registry.yarnpkg.com/onetime/-/onetime-5.1.2.tgz#d0e96ebb56b07476df1dd9c4806e5237985ca45e" integrity sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg== dependencies: mimic-fn "^2.1.0" @@ -5177,22 +4878,22 @@ optionator@^0.9.3: os-family@^1.0.0, os-family@^1.1.0: version "1.1.0" - resolved "https://registry.npmjs.org/os-family/-/os-family-1.1.0.tgz" + resolved "https://registry.yarnpkg.com/os-family/-/os-family-1.1.0.tgz#8a89cb617dd1631b8ef9506be830144f626c214e" integrity sha512-E3Orl5pvDJXnVmpaAA2TeNNpNhTMl4o5HghuWhOivBjEiTnJSrMYSa5uZMek1lBEvu8kKEsa2YgVcGFVDqX/9w== os-tmpdir@~1.0.1: version "1.0.2" - resolved "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz" + resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" integrity sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g== p-finally@^2.0.0: version "2.0.1" - resolved "https://registry.npmjs.org/p-finally/-/p-finally-2.0.1.tgz" + resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-2.0.1.tgz#bd6fcaa9c559a096b680806f4d657b3f0f240561" integrity sha512-vpm09aKwq6H9phqRQzecoDpD8TmVyGw70qmWlyq5onxY7tqyTTFVvxMykxQSQKILBSFlbXpypIw2T1Ml7+DDtw== p-limit@^2.0.0: version "2.3.0" - resolved "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.3.0.tgz#3dd33c647a214fdfffd835933eb086da0dc21db1" integrity sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w== dependencies: p-try "^2.0.0" @@ -5206,7 +4907,7 @@ p-limit@^3.0.2: p-locate@^3.0.0: version "3.0.0" - resolved "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-3.0.0.tgz#322d69a05c0264b25997d9f40cd8a891ab0064a4" integrity sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ== dependencies: p-limit "^2.0.0" @@ -5220,12 +4921,12 @@ p-locate@^5.0.0: p-map@^1.1.1: version "1.2.0" - resolved "https://registry.npmjs.org/p-map/-/p-map-1.2.0.tgz" + resolved "https://registry.yarnpkg.com/p-map/-/p-map-1.2.0.tgz#e4e94f311eabbc8633a1e79908165fca26241b6b" integrity sha512-r6zKACMNhjPJMTl8KcFH4li//gkrXWfbD6feV8l6doRHlzljFWGJ2AP6iKaCJXyZmAUMOPtvbW7EXkbWO/pLEA== p-map@^3.0.0: version "3.0.0" - resolved "https://registry.npmjs.org/p-map/-/p-map-3.0.0.tgz" + resolved "https://registry.yarnpkg.com/p-map/-/p-map-3.0.0.tgz#d704d9af8a2ba684e2600d9a215983d4141a979d" integrity sha512-d3qXVTF/s+W+CdJ5A29wywV2n8CQQYahlgz2bFiA+4eVNJbHJodPZ+/gXwPGh0bOqA+j8S+6+ckmvLGPk1QpxQ== dependencies: aggregate-error "^3.0.0" @@ -5239,7 +4940,7 @@ p-map@^4.0.0: p-try@^2.0.0: version "2.2.0" - resolved "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz" + resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== pac-proxy-agent@^7.0.1: @@ -5283,49 +4984,49 @@ parent-module@^1.0.0: parse5@^1.5.0: version "1.5.1" - resolved "https://registry.npmjs.org/parse5/-/parse5-1.5.1.tgz" + resolved "https://registry.yarnpkg.com/parse5/-/parse5-1.5.1.tgz#9b7f3b0de32be78dc2401b17573ccaf0f6f59d94" integrity sha512-w2jx/0tJzvgKwZa58sj2vAYq/S/K1QJfIB3cWYea/Iu1scFPDQQ3IQiVZTHWtRBwAjv2Yd7S/xeZf3XqLDb3bA== parse5@^2.1.5: version "2.2.3" - resolved "https://registry.npmjs.org/parse5/-/parse5-2.2.3.tgz" + resolved "https://registry.yarnpkg.com/parse5/-/parse5-2.2.3.tgz#0c4fc41c1000c5e6b93d48b03f8083837834e9f6" integrity sha512-yJQdbcT+hCt6HD+BuuUvjHUdNwerQIKSJSm7tXjtp6oIH5Mxbzlt/VIIeWxblsgcDt1+E7kxPeilD5McWswStA== parse5@^7.1.2: - version "7.1.2" - resolved "https://registry.npmjs.org/parse5/-/parse5-7.1.2.tgz" - integrity sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw== + version "7.2.0" + resolved "https://registry.yarnpkg.com/parse5/-/parse5-7.2.0.tgz#8a0591ce9b7c5e2027173ab737d4d3fc3d826fab" + integrity sha512-ZkDsAOcxsUMZ4Lz5fVciOehNcJ+Gb8gTzcA4yl3wnc273BAybYWrQ+Ks/OjCjSEpjvQkDSeZbybK9qj2VHHdGA== dependencies: - entities "^4.4.0" + entities "^4.5.0" path-exists@^3.0.0: version "3.0.0" - resolved "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz" + resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515" integrity sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ== path-exists@^4.0.0: version "4.0.0" - resolved "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz" + resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3" integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w== path-is-absolute@^1.0.0: version "1.0.1" - resolved "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz" + resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" integrity sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg== path-is-inside@^1.0.1: version "1.0.2" - resolved "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz" + resolved "https://registry.yarnpkg.com/path-is-inside/-/path-is-inside-1.0.2.tgz#365417dede44430d1c11af61027facf074bdfc53" integrity sha512-DUWJr3+ULp4zXmol/SZkFf3JGsS9/SIv+Y3Rt93/UjPpDpklB5f1er4O3POIbUuUJ3FXgqte2Q7SrU6zAqwk8w== path-key@^3.0.0, path-key@^3.1.0: version "3.1.1" - resolved "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz" + resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== path-parse@^1.0.7: version "1.0.7" - resolved "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz" + resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== path-scurry@^1.11.1: @@ -5338,12 +5039,12 @@ path-scurry@^1.11.1: path-type@^4.0.0: version "4.0.0" - resolved "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz" + resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b" integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw== pathval@^1.1.1: version "1.1.1" - resolved "https://registry.npmjs.org/pathval/-/pathval-1.1.1.tgz" + resolved "https://registry.yarnpkg.com/pathval/-/pathval-1.1.1.tgz#8534e77a77ce7ac5a2512ea21e0fdb8fcf6c3d8d" integrity sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ== pend@~1.2.0: @@ -5351,60 +5052,60 @@ pend@~1.2.0: resolved "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz" integrity sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg== -picocolors@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz" - integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ== +picocolors@^1.0.0, picocolors@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.1.0.tgz#5358b76a78cde483ba5cef6a9dc9671440b27d59" + integrity sha512-TQ92mBOW0l3LeMeyLV6mzy/kWr8lkd/hp3mTg7wYK7zJhuBStmGMBG0BdeDZS/dZx1IukaX6Bk11zcln25o1Aw== picomatch@^2.3.1: version "2.3.1" - resolved "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz" + resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== pify@^2.0.0, pify@^2.2.0, pify@^2.3.0: version "2.3.0" - resolved "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz" + resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" integrity sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog== pify@^3.0.0: version "3.0.0" - resolved "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz" + resolved "https://registry.yarnpkg.com/pify/-/pify-3.0.0.tgz#e5a4acd2c101fdf3d9a4d07f0dbc4db49dd28176" integrity sha512-C3FsVNH1udSEX48gGX1xfvwTWfsYWj5U+8/uK15BGzIGrKoUpghX8hWZwa/OFnakBiiVNmBvemTJR5mcy7iPcg== pinkie-promise@^1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-1.0.0.tgz" + resolved "https://registry.yarnpkg.com/pinkie-promise/-/pinkie-promise-1.0.0.tgz#d1da67f5482563bb7cf57f286ae2822ecfbf3670" integrity sha512-5mvtVNse2Ml9zpFKkWBpGsTPwm3DKhs+c95prO/F6E7d6DN0FPqxs6LONpLNpyD7Iheb7QN4BbUoKJgo+DnkQA== dependencies: pinkie "^1.0.0" pinkie-promise@^2.0.0: version "2.0.1" - resolved "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz" + resolved "https://registry.yarnpkg.com/pinkie-promise/-/pinkie-promise-2.0.1.tgz#2135d6dfa7a358c069ac9b178776288228450ffa" integrity sha512-0Gni6D4UcLTbv9c57DfxDGdr41XfgUjqWZu492f0cIGr16zDU06BWP/RAEvOuo7CQ0CNjHaLlM59YJJFm3NWlw== dependencies: pinkie "^2.0.0" pinkie@2.0.4, pinkie@^2.0.0, pinkie@^2.0.1, pinkie@^2.0.4: version "2.0.4" - resolved "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz" + resolved "https://registry.yarnpkg.com/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870" integrity sha512-MnUuEycAemtSaeFSjXKW/aroV7akBbY+Sv+RkyqFjgAe73F+MR0TBWKBRDkmfWq/HiFmdavfZ1G7h4SPZXaCSg== pinkie@^1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/pinkie/-/pinkie-1.0.0.tgz" + resolved "https://registry.yarnpkg.com/pinkie/-/pinkie-1.0.0.tgz#5a47f28ba1015d0201bda7bf0f358e47bec8c7e4" integrity sha512-VFVaU1ysKakao68ktZm76PIdOhvEfoNNRaGkyLln9Os7r0/MCxqHjHyBM7dT3pgTiBybqiPtpqKfpENwdBp50Q== pkg-up@^3.1.0: version "3.1.0" - resolved "https://registry.npmjs.org/pkg-up/-/pkg-up-3.1.0.tgz" + resolved "https://registry.yarnpkg.com/pkg-up/-/pkg-up-3.1.0.tgz#100ec235cc150e4fd42519412596a28512a0def5" integrity sha512-nDywThFk1i4BQK4twPQ6TA4RT8bDY96yeuCVBWL3ePARCiEKDRSrNGbFIgUJpLp+XeIR65v8ra7WuJOFUBtkMA== dependencies: find-up "^3.0.0" pngjs@^3.3.1: version "3.4.0" - resolved "https://registry.npmjs.org/pngjs/-/pngjs-3.4.0.tgz" + resolved "https://registry.yarnpkg.com/pngjs/-/pngjs-3.4.0.tgz#99ca7d725965fb655814eaf65f38f12bbdbf555f" integrity sha512-NCrCHhWmnQklfH4MtJMRjZ2a8c80qXeMlQMv2uVp9ISJMTt562SbGd6n2oq0PaPgKm7Z6pL9E2UlLIhC+SHL3w== possible-typed-array-names@^1.0.0: @@ -5437,12 +5138,12 @@ prelude-ls@^1.2.1: pretty-hrtime@^1.0.3: version "1.0.3" - resolved "https://registry.npmjs.org/pretty-hrtime/-/pretty-hrtime-1.0.3.tgz" + resolved "https://registry.yarnpkg.com/pretty-hrtime/-/pretty-hrtime-1.0.3.tgz#b7e3ea42435a4c9b2759d99e0f201eb195802ee1" integrity sha512-66hKPCr+72mlfiSjlEB1+45IjXSqvVAIy6mocupoww4tBFE9R9IhwwUGoI4G++Tc9Aq+2rxOt0RFU6gPcrte0A== process-nextick-args@~2.0.0: version "2.0.1" - resolved "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz" + resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2" integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag== process@^0.11.10: @@ -5465,14 +5166,14 @@ promise-retry@^2.0.1: promisify-event@^1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/promisify-event/-/promisify-event-1.0.0.tgz" + resolved "https://registry.yarnpkg.com/promisify-event/-/promisify-event-1.0.0.tgz#bd7523ea06b70162f370979016b53a686c60e90f" integrity sha512-mshw5LiFmdtphcuUGKyd3t6zmmgIVxrdZ8v4R1INAXHvMemUsDCqIUeq5QUIqqDfed8ZZ6uhov1PqhrdBvHOIA== dependencies: pinkie-promise "^2.0.0" prompts@^2.4.2: version "2.4.2" - resolved "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz" + resolved "https://registry.yarnpkg.com/prompts/-/prompts-2.4.2.tgz#7b57e73b3a48029ad10ebd44f74b01722a4cb069" integrity sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q== dependencies: kleur "^3.0.3" @@ -5517,7 +5218,7 @@ proxy-from-env@^1.1.0: proxyquire@^1.7.10: version "1.8.0" - resolved "https://registry.npmjs.org/proxyquire/-/proxyquire-1.8.0.tgz" + resolved "https://registry.yarnpkg.com/proxyquire/-/proxyquire-1.8.0.tgz#02d514a5bed986f04cbb2093af16741535f79edc" integrity sha512-mZZq4F50qaBkngvlf9paNfaSb5gtJ0mFPnBjda4NxCpXpMAaVfSLguRr9y2KXF6koOSBf4AanD2inuEQw3aCcA== dependencies: fill-keys "^1.0.2" @@ -5526,13 +5227,13 @@ proxyquire@^1.7.10: psl@^1.1.33: version "1.9.0" - resolved "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz" + resolved "https://registry.yarnpkg.com/psl/-/psl-1.9.0.tgz#d0df2a137f00794565fcaf3b2c00cd09f8d5a5a7" integrity sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag== pump@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz" - integrity sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww== + version "3.0.2" + resolved "https://registry.yarnpkg.com/pump/-/pump-3.0.2.tgz#836f3edd6bc2ee599256c924ffe0d88573ddcbf8" + integrity sha512-tUPXtzlGM8FE3P0ZL6DVs/3P58k9nk8/jZeQCurTJylQA8qFYzHFfhBJkuqyE0FifOsQ0uKWekiZ5g8wtr28cw== dependencies: end-of-stream "^1.1.0" once "^1.3.1" @@ -5544,12 +5245,12 @@ punycode@^2.1.0: punycode@^2.1.1: version "2.3.1" - resolved "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.3.1.tgz#027422e2faec0b25e1549c3e1bd8309b9133b6e5" integrity sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg== qrcode-terminal@^0.10.0: version "0.10.0" - resolved "https://registry.npmjs.org/qrcode-terminal/-/qrcode-terminal-0.10.0.tgz" + resolved "https://registry.yarnpkg.com/qrcode-terminal/-/qrcode-terminal-0.10.0.tgz#a76a48e2610a18f97fa3a2bd532b682acff86c53" integrity sha512-ZvWjbAj4MWAj6bnCc9CnculsXnJr7eoKsvH/8rVpZbqYxP2z05HNQa43ZVwe/dVRcFxgfFHE2CkUqn0sCyLfHw== qs@^6.11.0: @@ -5561,12 +5262,12 @@ qs@^6.11.0: querystringify@^2.1.1: version "2.2.0" - resolved "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz" + resolved "https://registry.yarnpkg.com/querystringify/-/querystringify-2.2.0.tgz#3345941b4153cb9d082d8eee4cda2016a9aef7f6" integrity sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ== queue-microtask@^1.2.2: version "1.2.3" - resolved "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz" + resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243" integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A== queue-tick@^1.0.1: @@ -5591,7 +5292,7 @@ rc@^1.2.7: read-file-relative@^1.2.0: version "1.2.0" - resolved "https://registry.npmjs.org/read-file-relative/-/read-file-relative-1.2.0.tgz" + resolved "https://registry.yarnpkg.com/read-file-relative/-/read-file-relative-1.2.0.tgz#98f7d96eaa21d2b4c7a2febd63d2fc8cf35e9f9b" integrity sha512-lwZUlN2tQyPa62/XmVtX1MeNLVutlRWwqvclWU8YpOCgjKdhg2zyNkeFjy7Rnjo3txhKCy5FGgAi+vx59gvkYg== dependencies: callsite "^1.0.0" @@ -5648,26 +5349,26 @@ redis@4.7.0: "@redis/search" "1.2.0" "@redis/time-series" "1.1.0" -regenerate-unicode-properties@^10.1.0: - version "10.1.1" - resolved "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.1.1.tgz" - integrity sha512-X007RyZLsCJVVrjgEFVpLUTZwyOZk3oiL75ZcuYjlIWd6rNJtOjkBwQc5AsRrpbKVkxN6sklw/k/9m2jJYOf8Q== +regenerate-unicode-properties@^10.2.0: + version "10.2.0" + resolved "https://registry.yarnpkg.com/regenerate-unicode-properties/-/regenerate-unicode-properties-10.2.0.tgz#626e39df8c372338ea9b8028d1f99dc3fd9c3db0" + integrity sha512-DqHn3DwbmmPVzeKj9woBadqmXxLvQoQIwu7nopMc72ztvxVmVk2SBhSnx67zuye5TP+lJsb/TBQsjLKhnDf3MA== dependencies: regenerate "^1.4.2" regenerate@^1.4.2: version "1.4.2" - resolved "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz" + resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.4.2.tgz#b9346d8827e8f5a32f7ba29637d398b69014848a" integrity sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A== regenerator-runtime@^0.14.0: version "0.14.1" - resolved "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz" + resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz#356ade10263f685dda125100cd862c1db895327f" integrity sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw== regenerator-transform@^0.15.2: version "0.15.2" - resolved "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.15.2.tgz" + resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.15.2.tgz#5bbae58b522098ebdf09bca2f83838929001c7a4" integrity sha512-hfMp2BoF0qOk3uc5V20ALGDS2ddjQaLrdl7xrGXvAIow7qeWRM2VA2HuCHkUKk9slq3VwEwLNK3DFBqDfPGYtg== dependencies: "@babel/runtime" "^7.8.4" @@ -5682,65 +5383,70 @@ regexp.prototype.flags@^1.5.2: es-errors "^1.3.0" set-function-name "^2.0.2" -regexpu-core@^5.3.1: - version "5.3.2" - resolved "https://registry.npmjs.org/regexpu-core/-/regexpu-core-5.3.2.tgz" - integrity sha512-RAM5FlZz+Lhmo7db9L298p2vHP5ZywrVXmVXpmAD9GuL5MPH6t9ROw1iA/wfHkQ76Qe7AaPF0nGuim96/IrQMQ== +regexpu-core@^6.1.1: + version "6.1.1" + resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-6.1.1.tgz#b469b245594cb2d088ceebc6369dceb8c00becac" + integrity sha512-k67Nb9jvwJcJmVpw0jPttR1/zVfnKf8Km0IPatrU/zJ5XeG3+Slx0xLXs9HByJSzXzrlz5EDvN6yLNMDc2qdnw== dependencies: - "@babel/regjsgen" "^0.8.0" regenerate "^1.4.2" - regenerate-unicode-properties "^10.1.0" - regjsparser "^0.9.1" + regenerate-unicode-properties "^10.2.0" + regjsgen "^0.8.0" + regjsparser "^0.11.0" unicode-match-property-ecmascript "^2.0.0" unicode-match-property-value-ecmascript "^2.1.0" -regjsparser@^0.9.1: - version "0.9.1" - resolved "https://registry.npmjs.org/regjsparser/-/regjsparser-0.9.1.tgz" - integrity sha512-dQUtn90WanSNl+7mQKcXAgZxvUe7Z0SqXlgzv0za4LwiUhyzBC58yQO3liFoUgu8GiJVInAhJjkj1N0EtQ5nkQ== +regjsgen@^0.8.0: + version "0.8.0" + resolved "https://registry.yarnpkg.com/regjsgen/-/regjsgen-0.8.0.tgz#df23ff26e0c5b300a6470cad160a9d090c3a37ab" + integrity sha512-RvwtGe3d7LvWiDQXeQw8p5asZUmfU1G/l6WbUXeHta7Y2PEIvBTwH6E2EfmYUK8pxcxEdEmaomqyp0vZZ7C+3Q== + +regjsparser@^0.11.0: + version "0.11.1" + resolved "https://registry.yarnpkg.com/regjsparser/-/regjsparser-0.11.1.tgz#ae55c74f646db0c8fcb922d4da635e33da405149" + integrity sha512-1DHODs4B8p/mQHU9kr+jv8+wIC9mtG4eBHxWxIq5mhjE3D5oORhCc6deRKzTjs9DcfRFmj9BHSDguZklqCGFWQ== dependencies: - jsesc "~0.5.0" + jsesc "~3.0.2" repeating@^1.1.0: version "1.1.3" - resolved "https://registry.npmjs.org/repeating/-/repeating-1.1.3.tgz" + resolved "https://registry.yarnpkg.com/repeating/-/repeating-1.1.3.tgz#3d4114218877537494f97f77f9785fab810fa4ac" integrity sha512-Nh30JLeMHdoI+AsQ5eblhZ7YlTsM9wiJQe/AHIunlK3KWzvXhXb36IJ7K1IOeRjIOtzMjdUHjwXUFxKJoPTSOg== dependencies: is-finite "^1.0.0" replicator@^1.0.5: version "1.0.5" - resolved "https://registry.npmjs.org/replicator/-/replicator-1.0.5.tgz" + resolved "https://registry.yarnpkg.com/replicator/-/replicator-1.0.5.tgz#f1e56df7e276a62afe80c2248b8ac03896f4708f" integrity sha512-saxS4y7NFkLMa92BR4bPHR41GD+f/qoDAwD2xZmN+MpDXgibkxwLO2qk7dCHYtskSkd/bWS8Jy6kC5MZUkg1tw== requires-port@^1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz" + resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff" integrity sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ== reselect@^4.1.7: version "4.1.8" - resolved "https://registry.npmjs.org/reselect/-/reselect-4.1.8.tgz" + resolved "https://registry.yarnpkg.com/reselect/-/reselect-4.1.8.tgz#3f5dc671ea168dccdeb3e141236f69f02eaec524" integrity sha512-ab9EmR80F/zQTMNeneUr4cv+jSwPJgIlvEmVwLerwrWVbpLlBuls9XHzIeTFy4cegU2NHBp3va0LKOzU5qFEYQ== resolve-cwd@^1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-1.0.0.tgz" + resolved "https://registry.yarnpkg.com/resolve-cwd/-/resolve-cwd-1.0.0.tgz#4eaeea41ed040d1702457df64a42b2b07d246f9f" integrity sha512-ac27EnKWWlc2yQ/5GCoCGecqVJ9MSmgiwvUYOS+9A+M0dn1FdP5mnsDZ9gwx+lAvh/d7f4RFn4jLfggRRYxPxw== dependencies: resolve-from "^2.0.0" resolve-from@^2.0.0: version "2.0.0" - resolved "https://registry.npmjs.org/resolve-from/-/resolve-from-2.0.0.tgz" + resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-2.0.0.tgz#9480ab20e94ffa1d9e80a804c7ea147611966b57" integrity sha512-qpFcKaXsq8+oRoLilkwyc7zHGF5i9Q2/25NIgLQQ/+VVv9rU4qvr6nXVAw1DsnXJyQkZsR4Ytfbtg5ehfcUssQ== resolve-from@^4.0.0: version "4.0.0" - resolved "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz" + resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6" integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g== -resolve@^1.14.2, resolve@^1.22.4: +resolve@^1.14.2, resolve@^1.22.1, resolve@^1.22.4: version "1.22.8" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.8.tgz#b6c87a9f2aa06dfab52e3d70ac8cde321fa5a48d" integrity sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw== @@ -5749,18 +5455,9 @@ resolve@^1.14.2, resolve@^1.22.4: path-parse "^1.0.7" supports-preserve-symlinks-flag "^1.0.0" -resolve@^1.22.1: - version "1.22.2" - resolved "https://registry.npmjs.org/resolve/-/resolve-1.22.2.tgz" - integrity sha512-Sb+mjNHOULsBv818T40qSPeRiuWLyaGMa5ewydRLFimneixmVy2zdivRl+AF6jaYPC8ERxGDmFSiqui6SfPd+g== - dependencies: - is-core-module "^2.11.0" - path-parse "^1.0.7" - supports-preserve-symlinks-flag "^1.0.0" - resolve@~1.1.7: version "1.1.7" - resolved "https://registry.npmjs.org/resolve/-/resolve-1.1.7.tgz" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.1.7.tgz#203114d82ad2c5ed9e8e0411b3932875e889e97b" integrity sha512-9znBF0vBcaSN3W2j7wKvdERPwqTxSpCq+if5C0WoTCyV9n24rua28jeuQ2pL/HOf+yUe/Mef+H/5p60K0Id3bg== retry@^0.12.0: @@ -5770,12 +5467,12 @@ retry@^0.12.0: reusify@^1.0.4: version "1.0.4" - resolved "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz" + resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76" integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw== rimraf@^2.2.8: version "2.7.1" - resolved "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.7.1.tgz#35797f13a7fdadc566142c29d4f07ccad483e3ec" integrity sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w== dependencies: glob "^7.1.3" @@ -5794,7 +5491,7 @@ run-applescript@^7.0.0: run-parallel@^1.1.9: version "1.2.0" - resolved "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz" + resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.2.0.tgz#66d1368da7bdf921eb9d95bd1a9229e7f21a43ee" integrity sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA== dependencies: queue-microtask "^1.2.2" @@ -5816,7 +5513,7 @@ safe-buffer@^5.0.1, safe-buffer@~5.2.0: safe-buffer@~5.1.0, safe-buffer@~5.1.1: version "5.1.2" - resolved "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== safe-regex-test@^1.0.3: @@ -5835,7 +5532,7 @@ safe-regex-test@^1.0.3: sanitize-filename@^1.6.0: version "1.6.3" - resolved "https://registry.npmjs.org/sanitize-filename/-/sanitize-filename-1.6.3.tgz" + resolved "https://registry.yarnpkg.com/sanitize-filename/-/sanitize-filename-1.6.3.tgz#755ebd752045931977e30b2025d340d7c9090378" integrity sha512-y/52Mcy7aw3gRm7IrcGDFx/bCk4AhRh2eI9luHOQM86nZsqwiRkkq2GekHXBBD+SmPidc8i2PqtYZl+pWJ8Oeg== dependencies: truncate-utf8-bytes "^1.0.0" @@ -5863,9 +5560,9 @@ set-blocking@^2.0.0: integrity sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw== set-cookie-parser@^2.5.1: - version "2.6.0" - resolved "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.6.0.tgz" - integrity sha512-RVnVQxTXuerk653XfuliOxBP81Sf0+qfQE73LIYKcyMYHG94AuH0kgrQpRDuTZnSmjpysHmzxJXKNfa6PjFhyQ== + version "2.7.0" + resolved "https://registry.yarnpkg.com/set-cookie-parser/-/set-cookie-parser-2.7.0.tgz#ef5552b56dc01baae102acb5fc9fb8cd060c30f9" + integrity sha512-lXLOiqpkUumhRdFF3k1osNXCy9akgx/dyPZ5p8qAg9seJzXr5ZrlqZuWIMuY6ejOsVLE6flJ5/h3lsn57fQ/PQ== set-function-length@^1.2.1: version "1.2.2" @@ -5904,14 +5601,14 @@ setimmediate@^1.0.5: shebang-command@^2.0.0: version "2.0.0" - resolved "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz" + resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea" integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA== dependencies: shebang-regex "^3.0.0" shebang-regex@^3.0.0: version "3.0.0" - resolved "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz" + resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== side-channel@^1.0.4: @@ -5959,12 +5656,12 @@ simple-get@^4.0.0: sisteransi@^1.0.5: version "1.0.5" - resolved "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz" + resolved "https://registry.yarnpkg.com/sisteransi/-/sisteransi-1.0.5.tgz#134d681297756437cc05ca01370d3a7a571075ed" integrity sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg== slash@^3.0.0: version "3.0.0" - resolved "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz" + resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634" integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q== smart-buffer@^4.2.0: @@ -6008,7 +5705,7 @@ socks@^2.7.1: source-map-support@^0.5.16: version "0.5.21" - resolved "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz" + resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.21.tgz#04fe7c7f9e1ed2d662233c28cb2b35b9f63f6e4f" integrity sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w== dependencies: buffer-from "^1.0.0" @@ -6045,7 +5742,7 @@ ssri@^8.0.0, ssri@^8.0.1: stackframe@^1.3.4: version "1.3.4" - resolved "https://registry.npmjs.org/stackframe/-/stackframe-1.3.4.tgz" + resolved "https://registry.yarnpkg.com/stackframe/-/stackframe-1.3.4.tgz#b881a004c8c149a5e8efef37d51b16e412943310" integrity sha512-oeVtt7eWQS+Na6F//S4kJ2K2VbRlS9D43mAlMyVpVWovy9o+jfgH8O9agzANzaiLjclA0oYzUXEM4PurhSUChw== streamx@^2.15.0: @@ -6070,7 +5767,7 @@ streamx@^2.15.0: "string-width@^1.0.2 || 2 || 3 || 4", string-width@^4.1.0, string-width@^4.2.3: version "4.2.3" - resolved "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== dependencies: emoji-regex "^8.0.0" @@ -6123,7 +5820,7 @@ string_decoder@^1.1.1, string_decoder@^1.3.0: string_decoder@~1.1.1: version "1.1.1" - resolved "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8" integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg== dependencies: safe-buffer "~5.1.0" @@ -6137,7 +5834,7 @@ string_decoder@~1.1.1: strip-ansi@^6.0.0, strip-ansi@^6.0.1: version "6.0.1" - resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== dependencies: ansi-regex "^5.0.1" @@ -6151,7 +5848,7 @@ strip-ansi@^7.0.1: strip-bom@^2.0.0: version "2.0.0" - resolved "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz" + resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-2.0.0.tgz#6219a85616520491f35788bdbf1447a99c7e6b0e" integrity sha512-kwrX1y7czp1E69n2ajbG65mIo9dqvJ+8aBQXOGVxqwvNbsXdFM6Lq37dLAY3mknUwru8CfcCbfOLL/gMo+fi3g== dependencies: is-utf8 "^0.2.0" @@ -6163,7 +5860,7 @@ strip-bom@^3.0.0: strip-final-newline@^2.0.0: version "2.0.0" - resolved "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz" + resolved "https://registry.yarnpkg.com/strip-final-newline/-/strip-final-newline-2.0.0.tgz#89b852fb2fcbe936f6f4b3187afb0a12c1ab58ad" integrity sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA== strip-json-comments@^3.1.1: @@ -6201,7 +5898,7 @@ supertest@^7.0.0: supports-color@^5.3.0: version "5.5.0" - resolved "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== dependencies: has-flag "^3.0.0" @@ -6215,7 +5912,7 @@ supports-color@^7.1.0: supports-preserve-symlinks-flag@^1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz" + resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09" integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w== tar-fs@^2.0.0: @@ -6270,7 +5967,7 @@ tcp-port-used@^1.0.2: testcafe-browser-provider-electron@0.0.21: version "0.0.21" - resolved "https://registry.npmjs.org/testcafe-browser-provider-electron/-/testcafe-browser-provider-electron-0.0.21.tgz" + resolved "https://registry.yarnpkg.com/testcafe-browser-provider-electron/-/testcafe-browser-provider-electron-0.0.21.tgz#9a85322b638347aa2c99364fb3b45103b1537436" integrity sha512-HL1NuyfZX+KGUuU1E8g96AXpUzTRJcfgwGEC8DO+xzK3xW4ROqp+zbOiSXexbSzXwtDbpiSwn7818BP2QoBX9Q== dependencies: "@babel/runtime" "^7.24.1" @@ -6289,7 +5986,7 @@ testcafe-browser-provider-electron@0.0.21: testcafe-browser-tools@2.0.26: version "2.0.26" - resolved "https://registry.npmjs.org/testcafe-browser-tools/-/testcafe-browser-tools-2.0.26.tgz" + resolved "https://registry.yarnpkg.com/testcafe-browser-tools/-/testcafe-browser-tools-2.0.26.tgz#38b5c0c2cd438895de12ee53cae11c64bd33aab9" integrity sha512-nTKSJhBzn9BmnOs0xVzXMu8dN2Gu13Ca3x3SJr/zF6ZdKjXO82JlbHu55dt5MFoWjzAQmwlqBkSxPaYicsTgUw== dependencies: array-find "^1.0.0" @@ -6342,9 +6039,9 @@ testcafe-hammerhead@31.7.2: ws "^7.4.6" testcafe-hammerhead@>=19.4.0: - version "31.7.1" - resolved "https://registry.npmjs.org/testcafe-hammerhead/-/testcafe-hammerhead-31.7.1.tgz" - integrity sha512-H162ruxCc0wIAkoVky7aQyEntiA6Np8OcWzOx0/2cSPY6BARFdFNd3spu2TB2j3qcpFIZ233IpEx+2sY+VFbjg== + version "31.7.3" + resolved "https://registry.yarnpkg.com/testcafe-hammerhead/-/testcafe-hammerhead-31.7.3.tgz#46e72e153a8ea7804571bb1e6adc48d2b60dff80" + integrity sha512-LmldhnuUUNcel66z8hjwPkxGrA6jaGt6K9B8iuxOVVRuhpqFfmP3do5MeplK9NyPbIjkAW6WsHDu+nUM88IUsA== dependencies: "@adobe/css-tools" "^4.3.0-rc.1" "@electron/asar" "^3.2.3" @@ -6403,12 +6100,12 @@ testcafe-reporter-json@2.2.0, testcafe-reporter-json@^2.1.0: testcafe-reporter-list@^2.2.0: version "2.2.0" - resolved "https://registry.npmjs.org/testcafe-reporter-list/-/testcafe-reporter-list-2.2.0.tgz" + resolved "https://registry.yarnpkg.com/testcafe-reporter-list/-/testcafe-reporter-list-2.2.0.tgz#57e77d8b7dd0b246454300d229e58b8ccec8ce48" integrity sha512-+6Q2CC+2B90OYED2Yx6GoBIMUYd5tADNUbOHu3Hgdd3qskzjBdKwpdDt0b7w0w7oYDO1/Uu4HDBTDud3lWpD4Q== testcafe-reporter-minimal@^2.2.0: version "2.2.0" - resolved "https://registry.npmjs.org/testcafe-reporter-minimal/-/testcafe-reporter-minimal-2.2.0.tgz" + resolved "https://registry.yarnpkg.com/testcafe-reporter-minimal/-/testcafe-reporter-minimal-2.2.0.tgz#d12624bb6f6b98543ca52512b01002cad23b657d" integrity sha512-iUSWI+Z+kVUAsGegMmEXKDiMPZHDxq+smo4utWwc3wI3Tk6jT8PbNvsROQAjwkMKDmnpo6To5vtyvzvK+zKGXA== testcafe-reporter-spec@2.2.0, testcafe-reporter-spec@^2.2.0: @@ -6418,17 +6115,17 @@ testcafe-reporter-spec@2.2.0, testcafe-reporter-spec@^2.2.0: testcafe-reporter-xunit@^2.2.1: version "2.2.3" - resolved "https://registry.npmjs.org/testcafe-reporter-xunit/-/testcafe-reporter-xunit-2.2.3.tgz" + resolved "https://registry.yarnpkg.com/testcafe-reporter-xunit/-/testcafe-reporter-xunit-2.2.3.tgz#3636884e0351867e4b1beacf00545febad939d3f" integrity sha512-aGyc+MZPsTNwd9SeKJSjFNwEZfILzFnObzOImaDbsf57disTQfEY+9japXWav/Ef5Cv04UEW24bTFl2Q4f8xwg== testcafe-safe-storage@^1.1.1: version "1.1.6" - resolved "https://registry.npmjs.org/testcafe-safe-storage/-/testcafe-safe-storage-1.1.6.tgz" + resolved "https://registry.yarnpkg.com/testcafe-safe-storage/-/testcafe-safe-storage-1.1.6.tgz#5a325c24aef538cf18843b430a1033cba8a32477" integrity sha512-WFm1UcmO3uZs+uW8lYtBBJpnrvgTKkMQMKG9BvTEKbjeqhonEXVTxOkGEs3DM1ZB/ylPuwh7Jux7qUtjcM/D2Q== testcafe-selector-generator@^0.1.0: version "0.1.0" - resolved "https://registry.npmjs.org/testcafe-selector-generator/-/testcafe-selector-generator-0.1.0.tgz" + resolved "https://registry.yarnpkg.com/testcafe-selector-generator/-/testcafe-selector-generator-0.1.0.tgz#852c86f71565e5d9320da625c2260d040cbed786" integrity sha512-MTw+RigHsEYmFgzUFNErDxui1nTYUk6nm2bmfacQiKPdhJ9AHW/wue4J/l44mhN8x3E8NgOUkHHOI+1TDFXiLQ== testcafe@3.6.2: @@ -6547,12 +6244,12 @@ text-table@^0.2.0: time-limit-promise@^1.0.2: version "1.0.4" - resolved "https://registry.npmjs.org/time-limit-promise/-/time-limit-promise-1.0.4.tgz" + resolved "https://registry.yarnpkg.com/time-limit-promise/-/time-limit-promise-1.0.4.tgz#33e928212273c70d52153c28ad2a7e3319b975f9" integrity sha512-FLHDDsIDducw7MBcRWlFtW2Tm50DoKOSFf0Nzx17qwXj8REXCte0eUkHrJl9QU3Bl9arG3XNYX0PcHpZ9xyuLw== tmp@0.0.28: version "0.0.28" - resolved "https://registry.npmjs.org/tmp/-/tmp-0.0.28.tgz" + resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.28.tgz#172735b7f614ea7af39664fa84cf0de4e515d120" integrity sha512-c2mmfiBmND6SOVxzogm1oda0OJ1HZVIk/5n26N59dDTh80MUeavpiCls4PGAdkX1PFkKokLpcf7prSjCeXLsJg== dependencies: os-tmpdir "~1.0.1" @@ -6564,19 +6261,19 @@ tmp@^0.2.3: to-fast-properties@^2.0.0: version "2.0.0" - resolved "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz" + resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e" integrity sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog== to-regex-range@^5.0.1: version "5.0.1" - resolved "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz" + resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ== dependencies: is-number "^7.0.0" tough-cookie@4.1.3: version "4.1.3" - resolved "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.3.tgz" + resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-4.1.3.tgz#97b9adb0728b42280aa3d814b6b999b2ff0318bf" integrity sha512-aX/y5pVRkfRnfmuX+OdbSdXvPe6ieKX/G2s7e98f4poJHnqH3281gDPm/metm6E/WRamfx7WC4HUqkWHfQHprw== dependencies: psl "^1.1.33" @@ -6586,12 +6283,12 @@ tough-cookie@4.1.3: tree-kill@^1.2.2: version "1.2.2" - resolved "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz" + resolved "https://registry.yarnpkg.com/tree-kill/-/tree-kill-1.2.2.tgz#4ca09a9092c88b73a7cdc5e8a01b507b0790a0cc" integrity sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A== truncate-utf8-bytes@^1.0.0: version "1.0.2" - resolved "https://registry.npmjs.org/truncate-utf8-bytes/-/truncate-utf8-bytes-1.0.2.tgz" + resolved "https://registry.yarnpkg.com/truncate-utf8-bytes/-/truncate-utf8-bytes-1.0.2.tgz#405923909592d56f78a5818434b0b78489ca5f2b" integrity sha512-95Pu1QXQvruGEhv62XCMO3Mm90GscOCClvrIUwCM0PYOXK3kaF3l3sIHxx71ThJfcbM2O5Au6SO3AWCSEfW4mQ== dependencies: utf8-byte-length "^1.0.1" @@ -6650,13 +6347,13 @@ type-check@^0.4.0, type-check@~0.4.0: prelude-ls "^1.2.1" type-detect@^4.0.0, type-detect@^4.0.5: - version "4.0.8" - resolved "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz" - integrity sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g== + version "4.1.0" + resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-4.1.0.tgz#deb2453e8f08dcae7ae98c626b13dddb0155906c" + integrity sha512-Acylog8/luQ8L7il+geoSxhEkazvkslg7PSNKOX59mbB9cOveP5aq9h74Y7YU8yDpJwetzQQrfIwtf4Wp4LKcw== type-fest@^0.21.3: version "0.21.3" - resolved "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.21.3.tgz#d260a24b0198436e133fa26a524a6d65fa3b2e37" integrity sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w== typed-array-buffer@^1.0.2: @@ -6705,7 +6402,7 @@ typed-array-length@^1.0.6: typescript@4.7.4: version "4.7.4" - resolved "https://registry.npmjs.org/typescript/-/typescript-4.7.4.tgz" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.7.4.tgz#1a88596d1cf47d59507a1bcdfb5b9dfe4d488235" integrity sha512-C0WQT0gezHuw6AdY1M2jxUO83Rjf0HP7Sk1DtXj6j1EwkQNZrHAg2XPWlq62oqEhYvONq5pkC2Y9oPljWToLmQ== typescript@5.6.3: @@ -6725,30 +6422,30 @@ unbox-primitive@^1.0.2: underscore@~1.12.1: version "1.12.1" - resolved "https://registry.npmjs.org/underscore/-/underscore-1.12.1.tgz" + resolved "https://registry.yarnpkg.com/underscore/-/underscore-1.12.1.tgz#7bb8cc9b3d397e201cf8553336d262544ead829e" integrity sha512-hEQt0+ZLDVUMhebKxL4x1BTtDY7bavVofhZ9KZ4aI26X9SRaE+Y3m83XUL1UP2jn8ynjndwCCpEHdUG+9pP1Tw== unicode-canonical-property-names-ecmascript@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz" - integrity sha512-yY5PpDlfVIU5+y/BSCxAJRBIS1Zc2dDG3Ujq+sR0U+JjUevW2JhocOF+soROYDSaAezOzOKuyyixhD6mBknSmQ== + version "2.0.1" + resolved "https://registry.yarnpkg.com/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.1.tgz#cb3173fe47ca743e228216e4a3ddc4c84d628cc2" + integrity sha512-dA8WbNeb2a6oQzAQ55YlT5vQAWGV9WXOsi3SskE3bcCdM0P4SDd+24zS/OCacdRq5BkdsRj9q3Pg6YyQoxIGqg== unicode-match-property-ecmascript@^2.0.0: version "2.0.0" - resolved "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz" + resolved "https://registry.yarnpkg.com/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz#54fd16e0ecb167cf04cf1f756bdcc92eba7976c3" integrity sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q== dependencies: unicode-canonical-property-names-ecmascript "^2.0.0" unicode-property-aliases-ecmascript "^2.0.0" unicode-match-property-value-ecmascript@^2.1.0: - version "2.1.0" - resolved "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.1.0.tgz" - integrity sha512-qxkjQt6qjg/mYscYMC0XKRn3Rh0wFPlfxB0xkt9CfyTvpX1Ra0+rAmdX2QyAobptSEvuy4RtpPRui6XkV+8wjA== + version "2.2.0" + resolved "https://registry.yarnpkg.com/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.2.0.tgz#a0401aee72714598f739b68b104e4fe3a0cb3c71" + integrity sha512-4IehN3V/+kkr5YeSSDDQG8QLqO26XpL2XP3GQtqwlT/QYSECAwFztxVHjlbh0+gjJ3XmNLS0zDsbgs9jWKExLg== unicode-property-aliases-ecmascript@^2.0.0: version "2.1.0" - resolved "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.1.0.tgz" + resolved "https://registry.yarnpkg.com/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.1.0.tgz#43d41e3be698bd493ef911077c9b131f827e8ccd" integrity sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w== unique-filename@^1.1.1: @@ -6767,26 +6464,26 @@ unique-slug@^2.0.0: universalify@^0.2.0: version "0.2.0" - resolved "https://registry.npmjs.org/universalify/-/universalify-0.2.0.tgz" + resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.2.0.tgz#6451760566fa857534745ab1dde952d1b1761be0" integrity sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg== universalify@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz" - integrity sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ== + version "2.0.1" + resolved "https://registry.yarnpkg.com/universalify/-/universalify-2.0.1.tgz#168efc2180964e6386d061e094df61afe239b18d" + integrity sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw== unquote@^1.1.1: version "1.1.1" - resolved "https://registry.npmjs.org/unquote/-/unquote-1.1.1.tgz" + resolved "https://registry.yarnpkg.com/unquote/-/unquote-1.1.1.tgz#8fded7324ec6e88a0ff8b905e7c098cdc086d544" integrity sha512-vRCqFv6UhXpWxZPyGDh/F3ZpNv8/qo7w6iufLpQg9aKnQ71qM4B5KiI7Mia9COcjEhrO9LueHpMYjYzsWH3OIg== -update-browserslist-db@^1.0.13: - version "1.0.13" - resolved "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz" - integrity sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg== +update-browserslist-db@^1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.1.1.tgz#80846fba1d79e82547fb661f8d141e0945755fe5" + integrity sha512-R8UzCaa9Az+38REPiJ1tXlImTJXlVfgHZsglwBD/k6nj76ctsH1E3q4doGrukiLQd3sGQYu56r5+lo5r94l29A== dependencies: - escalade "^3.1.1" - picocolors "^1.0.0" + escalade "^3.2.0" + picocolors "^1.1.0" uri-js@^4.2.2: version "4.4.1" @@ -6797,7 +6494,7 @@ uri-js@^4.2.2: url-parse@^1.5.3: version "1.5.10" - resolved "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz" + resolved "https://registry.yarnpkg.com/url-parse/-/url-parse-1.5.10.tgz#9d3c2f736c1d75dd3bd2be507dcc111f1e2ea9c1" integrity sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ== dependencies: querystringify "^2.1.1" @@ -6805,17 +6502,17 @@ url-parse@^1.5.3: url-to-options@^2.0.0: version "2.0.0" - resolved "https://registry.npmjs.org/url-to-options/-/url-to-options-2.0.0.tgz" + resolved "https://registry.yarnpkg.com/url-to-options/-/url-to-options-2.0.0.tgz#416bfe77868b168b8aa7b72d74e7c29a97dca69d" integrity sha512-mfONnc9dqO0J41wUh/El+plDskrIJRcyLcx6WjEGYW2K11RnjPDAgeoNFCallADaYJfcWIvAlYyZPBw02AbfIQ== utf8-byte-length@^1.0.1: - version "1.0.4" - resolved "https://registry.npmjs.org/utf8-byte-length/-/utf8-byte-length-1.0.4.tgz" - integrity sha512-4+wkEYLBbWxqTahEsWrhxepcoVOJ+1z5PGIjPZxRkytcdSUaNjIjBM7Xn8E+pdSuV7SzvWovBFA54FO0JSoqhA== + version "1.0.5" + resolved "https://registry.yarnpkg.com/utf8-byte-length/-/utf8-byte-length-1.0.5.tgz#f9f63910d15536ee2b2d5dd4665389715eac5c1e" + integrity sha512-Xn0w3MtiQ6zoz2vFyUVruaCL53O/DwUvkEeOvj+uulMm0BkUGYWmBYVyElqZaSLhY6ZD0ulfU3aBra2aVT4xfA== util-deprecate@^1.0.1, util-deprecate@~1.0.1: version "1.0.2" - resolved "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz" + resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw== v8-compile-cache-lib@^3.0.1: @@ -6841,7 +6538,7 @@ which-boxed-primitive@^1.0.2: which-promise@^1.0.0: version "1.0.0" - resolved "https://registry.npmjs.org/which-promise/-/which-promise-1.0.0.tgz" + resolved "https://registry.yarnpkg.com/which-promise/-/which-promise-1.0.0.tgz#20b721df05b35b706176ffa10b0909aba4603035" integrity sha512-15ahjtDr3H+RBtTrvBcKhOFhIEiN3RZSCevDPWtBys+QUivZX9cYyNJcyWNIrUMVsgGrEuIThif9jxeEAQFauw== dependencies: pify "^2.2.0" @@ -6861,14 +6558,14 @@ which-typed-array@^1.1.14, which-typed-array@^1.1.15: which@^1.1.2: version "1.3.1" - resolved "https://registry.npmjs.org/which/-/which-1.3.1.tgz" + resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ== dependencies: isexe "^2.0.0" which@^2.0.1, which@^2.0.2: version "2.0.2" - resolved "https://registry.npmjs.org/which/-/which-2.0.2.tgz" + resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== dependencies: isexe "^2.0.0" @@ -6882,7 +6579,7 @@ wide-align@^1.1.5: windows-release@^5.0.1: version "5.1.1" - resolved "https://registry.npmjs.org/windows-release/-/windows-release-5.1.1.tgz" + resolved "https://registry.yarnpkg.com/windows-release/-/windows-release-5.1.1.tgz#7ac7019f9baeaea6c00ec889b11824f46c12ee8d" integrity sha512-NMD00arvqcq2nwqc5Q6KtrSRHK+fVD31erE5FEMahAw5PmVCgD7MUXodq3pdZSUkqA9Cda2iWx6s1XYwiJWRmw== dependencies: execa "^5.1.1" @@ -6903,7 +6600,7 @@ word-wrap@1.2.4, word-wrap@^1.2.5: wrap-ansi@^7.0.0: version "7.0.0" - resolved "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== dependencies: ansi-styles "^4.0.0" @@ -6921,13 +6618,13 @@ wrap-ansi@^8.1.0: wrappy@1: version "1.0.2" - resolved "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz" + resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== ws@^7.2.0, ws@^7.4.6: - version "7.5.9" - resolved "https://registry.npmjs.org/ws/-/ws-7.5.9.tgz" - integrity sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q== + version "7.5.10" + resolved "https://registry.yarnpkg.com/ws/-/ws-7.5.10.tgz#58b5c20dc281633f6c19113f39b349bd8bd558d9" + integrity sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ== ws@^8.18.0: version "8.18.0" @@ -6936,12 +6633,12 @@ ws@^8.18.0: yallist@4.0.0, yallist@^4.0.0: version "4.0.0" - resolved "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== yallist@^3.0.2: version "3.1.1" - resolved "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.1.1.tgz#dbb7daf9bfd8bac9ab45ebf602b8cbad0d5d08fd" integrity sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g== yauzl@^2.10.0: From f054a0458dd0ff433aef60fe41a597d129e0f52c Mon Sep 17 00:00:00 2001 From: Roman Sergeenko Date: Wed, 16 Oct 2024 15:38:42 +0200 Subject: [PATCH 188/256] #RI-6222 - fix auto-suggest at first column * start refactoring --- .../components/query/Query/Query.tsx | 27 +++++-- .../components/query/QueryWrapper.tsx | 7 +- .../ui/src/pages/workbench/constants.ts | 8 --- .../ui/src/pages/workbench/utils/query.ts | 24 +++---- .../src/pages/workbench/utils/queryUtils.ts | 17 +++++ .../pages/workbench/utils/query_refactor.ts | 71 +++++++++++++++++++ .../workbench/utils/searchSuggestions.ts | 2 +- .../pages/workbench/utils/tests/query.spec.ts | 4 +- 8 files changed, 130 insertions(+), 30 deletions(-) create mode 100644 redisinsight/ui/src/pages/workbench/utils/queryUtils.ts create mode 100644 redisinsight/ui/src/pages/workbench/utils/query_refactor.ts diff --git a/redisinsight/ui/src/pages/workbench/components/query/Query/Query.tsx b/redisinsight/ui/src/pages/workbench/components/query/Query/Query.tsx index 82200d2e5d..67059c2088 100644 --- a/redisinsight/ui/src/pages/workbench/components/query/Query/Query.tsx +++ b/redisinsight/ui/src/pages/workbench/components/query/Query/Query.tsx @@ -1,4 +1,4 @@ -import React, { useContext, useEffect, useRef, useState } from 'react' +import React, { useContext, useEffect, useMemo, useRef, useState } from 'react' import { useDispatch, useSelector } from 'react-redux' import { compact, first } from 'lodash' import cx from 'classnames' @@ -32,7 +32,7 @@ import { addOwnTokenToArgs, findCurrentArgument, } from 'uiSrc/pages/workbench/u import { getRange, getRediSearchSignutureProvider, } from 'uiSrc/pages/workbench/utils/monaco' import { CursorContext } from 'uiSrc/pages/workbench/types' import { asSuggestionsRef, getCommandsSuggestions, isIndexComplete } from 'uiSrc/pages/workbench/utils/suggestions' -import { COMMANDS_TO_GET_INDEX_INFO, COMPOSITE_ARGS, EmptySuggestionsIds, } from 'uiSrc/pages/workbench/constants' +import { COMMANDS_TO_GET_INDEX_INFO, EmptySuggestionsIds, } from 'uiSrc/pages/workbench/constants' import { useDebouncedEffect } from 'uiSrc/services' import { fetchRedisearchInfoAction } from 'uiSrc/slices/browser/redisearch' import { findSuggestionsByArg } from 'uiSrc/pages/workbench/utils/searchSuggestions' @@ -106,7 +106,15 @@ const Query = (props: Props) => { const monacoObjects = useRef>(null) // TODO: need refactor to avoid this - const REDIS_COMMANDS = commands.map((command) => ({ ...addOwnTokenToArgs(command.name!, command) })) + const REDIS_COMMANDS = useMemo( + () => commands.map((command) => ({ ...addOwnTokenToArgs(command.name!, command) })), + [commands] + ) + + const COMPOSITE_ARGS = useMemo(() => commands + .filter((command) => command.name && command.name.includes(' ')) + .map(({ name }) => name), + [commands]) const { instanceId = '' } = useParams<{ instanceId: string }>() @@ -329,7 +337,13 @@ const Query = (props: Props) => { return } - const command = findCompleteQuery(model, e.position, REDIS_COMMANDS_SPEC, REDIS_COMMANDS_ARRAY, COMPOSITE_ARGS) + const command = findCompleteQuery( + model, + e.position, + REDIS_COMMANDS_SPEC, + REDIS_COMMANDS_ARRAY, + COMPOSITE_ARGS as string[] + ) handleSuggestions(editor, command) handleDslSyntax(e, command) } @@ -539,7 +553,7 @@ const Query = (props: Props) => { if (position.column === 1) { helpWidgetRef.current.isOpen = false if (command) return asSuggestionsRef([]) - return asSuggestionsRef(getCommandsSuggestions(commands, range), false) + return asSuggestionsRef(getCommandsSuggestions(commands, range), false, false) } if (!command) { @@ -569,7 +583,8 @@ const Query = (props: Props) => { helpWidgetRef.current = { isOpen, parent: parent || helpWidgetRef.current.parent, - currentArg: currentArg || helpWidgetRef.current.currentArg } + currentArg: currentArg || helpWidgetRef.current.currentArg + } } return suggestions diff --git a/redisinsight/ui/src/pages/workbench/components/query/QueryWrapper.tsx b/redisinsight/ui/src/pages/workbench/components/query/QueryWrapper.tsx index 033eabf914..f34b78ec2c 100644 --- a/redisinsight/ui/src/pages/workbench/components/query/QueryWrapper.tsx +++ b/redisinsight/ui/src/pages/workbench/components/query/QueryWrapper.tsx @@ -1,4 +1,4 @@ -import React, { useEffect } from 'react' +import React, { useEffect, useMemo } from 'react' import { useDispatch, useSelector } from 'react-redux' import { EuiLoadingContent } from '@elastic/eui' @@ -40,7 +40,10 @@ const QueryWrapper = (props: Props) => { const { data: indexes = [] } = useSelector(redisearchListSelector) const { spec: COMMANDS_SPEC } = useSelector(appRedisCommandsSelector) - const REDIS_COMMANDS = mergeRedisCommandsSpecs(COMMANDS_SPEC, SEARCH_COMMANDS_SPEC) + const REDIS_COMMANDS = useMemo( + () => mergeRedisCommandsSpecs(COMMANDS_SPEC, SEARCH_COMMANDS_SPEC), + [COMMANDS_SPEC, SEARCH_COMMANDS_SPEC] + ) const dispatch = useDispatch() diff --git a/redisinsight/ui/src/pages/workbench/constants.ts b/redisinsight/ui/src/pages/workbench/constants.ts index 86cdf3045c..645b11baf4 100644 --- a/redisinsight/ui/src/pages/workbench/constants.ts +++ b/redisinsight/ui/src/pages/workbench/constants.ts @@ -83,14 +83,6 @@ export const COMMANDS_WITHOUT_INDEX_PROPOSE = [ 'FT.CREATE' ] -export const COMPOSITE_ARGS = [ - 'LOAD *', - 'FT.CONFIG GET', - 'FT.CONFIG SET', - 'FT.CURSOR DEL', - 'FT.CURSOR READ', -] - export enum DefinedArgumentName { index = 'index', query = 'query', diff --git a/redisinsight/ui/src/pages/workbench/utils/query.ts b/redisinsight/ui/src/pages/workbench/utils/query.ts index 9120c3d876..d3ffba6480 100644 --- a/redisinsight/ui/src/pages/workbench/utils/query.ts +++ b/redisinsight/ui/src/pages/workbench/utils/query.ts @@ -3,6 +3,7 @@ import { findLastIndex, isNumber, toNumber } from 'lodash' import { generateArgsNames, Maybe, Nullable } from 'uiSrc/utils' import { CommandProvider, IRedisCommand, IRedisCommandTree, ICommandTokenType } from 'uiSrc/constants' +import { isStringsEqual } from 'uiSrc/pages/workbench/utils/queryUtils' import { ArgName, FoundCommandArgument } from '../types' export const findCurrentArgument = ( @@ -20,8 +21,7 @@ export const findCurrentArgument = ( return findCurrentArgument(currentArg.arguments, prev.slice(i), prev, currentWithParent) } - const tokenIndex = args.findIndex((cArg) => - cArg.token?.toLowerCase() === arg.toLowerCase()) + const tokenIndex = args.findIndex((cArg) => isStringsEqual(cArg.token, arg)) const token = args[tokenIndex] if (token) { @@ -79,9 +79,9 @@ const findStopArgumentInQuery = ( } if (!isBlockedOnCommand && currentCommandArg?.optional) { - const isNotToken = currentCommandArg?.token && currentCommandArg.token !== arg.toUpperCase() + const isNotToken = currentCommandArg?.token && !isStringsEqual(currentCommandArg.token, arg) const isNotOneOfToken = !currentCommandArg?.token && currentCommandArg?.type === ICommandTokenType.OneOf - && currentCommandArg?.arguments?.every(({ token }) => token !== arg.toUpperCase()) + && currentCommandArg?.arguments?.every(({ token }) => !isStringsEqual(token, arg)) if (isNotToken || isNotOneOfToken) { moveToNextCommandArg() @@ -99,8 +99,8 @@ const findStopArgumentInQuery = ( blockArguments = Array(nArgs).fill(currentCommandArg.arguments).flat() } - const currentQueryArg = queryArgs.slice(i)?.[0]?.toUpperCase() - const isBlockHasToken = blockArguments?.[0]?.token === currentQueryArg + const currentQueryArg = queryArgs.slice(i)?.[0] + const isBlockHasToken = isStringsEqual(blockArguments?.[0]?.token, currentQueryArg) if (currentCommandArg.token && !isBlockHasToken && currentQueryArg) { blockArguments.unshift({ @@ -132,7 +132,7 @@ const findStopArgumentInQuery = ( } // if we are on token - that requires one more argument - if (currentCommandArg?.token === arg.toUpperCase()) { + if (isStringsEqual(currentCommandArg?.token, arg)) { blockCommand() continue } @@ -153,7 +153,7 @@ const findStopArgumentInQuery = ( if (currentCommandArg?.type === ICommandTokenType.OneOf && currentCommandArg?.optional) { // if oneof is optional then we can switch to another argument - if (!currentCommandArg?.arguments?.some(({ token }) => token === arg)) { + if (!currentCommandArg?.arguments?.some(({ token }) => isStringsEqual(token, arg))) { moveToNextCommandArg() } @@ -303,7 +303,7 @@ export const getAllRestArguments = ( const currentToken = current?.type === ICommandTokenType.Block ? current?.arguments?.[0].token : current?.token const lastTokenIndex = findLastIndex( untilTokenArgs, - (arg) => arg?.toLowerCase() === currentToken?.toLowerCase() + (arg) => isStringsEqual(arg, currentToken) ) const currentLvlNextArgs = removeNotSuggestedArgs( untilTokenArgs.slice(lastTokenIndex > 0 ? lastTokenIndex : 0), @@ -331,7 +331,7 @@ export const removeNotSuggestedArgs = (args: string[], commandArgs: IRedisComman if (arg.type === ICommandTokenType.OneOf) { return !args .some((queryArg) => arg.arguments - ?.some((oneOfArg) => oneOfArg.token?.toUpperCase() === queryArg.toUpperCase())) + ?.some((oneOfArg) => isStringsEqual(oneOfArg.token, queryArg))) } if (arg.type === ICommandTokenType.Block) { @@ -373,8 +373,8 @@ export const fillArgsByType = (args: IRedisCommand[], expandBlock = true): IRedi export const findArgByToken = (list: IRedisCommand[], arg: string): Maybe => list.find((cArg) => (cArg.type === ICommandTokenType.OneOf - ? cArg.arguments?.some((oneOfArg: IRedisCommand) => oneOfArg?.token?.toLowerCase() === arg?.toLowerCase()) - : cArg.arguments?.[0]?.token?.toLowerCase() === arg?.toLowerCase())) + ? cArg.arguments?.some((oneOfArg: IRedisCommand) => isStringsEqual(oneOfArg?.token, arg)) + : isStringsEqual(cArg.arguments?.[0].token, arg))) export const generateDetail = (command: Maybe) => { if (!command) return '' diff --git a/redisinsight/ui/src/pages/workbench/utils/queryUtils.ts b/redisinsight/ui/src/pages/workbench/utils/queryUtils.ts new file mode 100644 index 0000000000..72617c0d7c --- /dev/null +++ b/redisinsight/ui/src/pages/workbench/utils/queryUtils.ts @@ -0,0 +1,17 @@ +import { ICommandTokenType, IRedisCommand } from 'uiSrc/constants' +import { Maybe } from 'uiSrc/utils' + +export const isStringsEqual = (str1?: string, str2?: string) => str1?.toLowerCase() === str2?.toLowerCase() + +export const isTokenEqualsArg = (token: IRedisCommand, arg: string) => { + if (token.type === ICommandTokenType.OneOf) { + return token.arguments + ?.some((oneOfArg: IRedisCommand) => isStringsEqual(oneOfArg?.token, arg)) + } + if (isStringsEqual(token.token, arg)) return true + if (token.type === ICommandTokenType.Block) return isStringsEqual(token.arguments?.[0]?.token, arg) + return false +} + +export const findArgByToken = (list: IRedisCommand[], arg: string): Maybe => + list.find((command) => isTokenEqualsArg(command, arg)) diff --git a/redisinsight/ui/src/pages/workbench/utils/query_refactor.ts b/redisinsight/ui/src/pages/workbench/utils/query_refactor.ts new file mode 100644 index 0000000000..5166fa2841 --- /dev/null +++ b/redisinsight/ui/src/pages/workbench/utils/query_refactor.ts @@ -0,0 +1,71 @@ +/* eslint-disable no-continue */ +import { ICommandTokenType, IRedisCommand } from 'uiSrc/constants' +import { Maybe } from 'uiSrc/utils' +import { isStringsEqual, isTokenEqualsArg } from 'uiSrc/pages/workbench/utils/queryUtils' + +interface BlockTokensTree { + queryArgs: string[] + command?: IRedisCommand + parent?: BlockTokensTree +} + +export const findSuggestionsByQueryArgs = ( + commands: IRedisCommand[], + queryArgs: string[], +) => { + const firstQueryArg = queryArgs[0] + const scopeCommand = firstQueryArg + ? commands.find((command) => isStringsEqual(command.token, firstQueryArg)) + : undefined + + const getLastBlock = ( + args: string[], + command?: IRedisCommand, + parent?: any, + ): BlockTokensTree => { + for (let i = args.length - 1; i >= 0; i--) { + const arg = args[i] + const currentArg = findArgByToken(command?.arguments || [], arg) + + if (currentArg?.type === ICommandTokenType.Block) { + return getLastBlock(args.slice(i), currentArg, { queryArgs: queryArgs.slice(i), command: currentArg, parent }) + } + } + + return parent + } + + const blockToken: BlockTokensTree = { queryArgs: queryArgs.slice(scopeCommand ? 1 : 0), command: scopeCommand } + const currentBlock = getLastBlock(queryArgs, scopeCommand, blockToken) + const stopArgument = findStopArgumentWithSuggestions(currentBlock) + + console.log(stopArgument) + + return null +} + +const getStopArgument = ( + queryArgs: string[], + command: Maybe +) => { + let currentCommandArgIndex = 0 + + for (let i = 0; i < queryArgs.length; i++) { + const arg = queryArgs[i] + const currentCommandArg = command?.arguments?.[currentCommandArgIndex] + + currentCommandArgIndex++ + } + + return null +} + +const findStopArgumentWithSuggestions = (currentBlock: BlockTokensTree) => { + console.log(currentBlock) + const stopArgument = getStopArgument(currentBlock.queryArgs, currentBlock.command) + + return null +} + +const findArgByToken = (list: IRedisCommand[], arg: string): Maybe => + list.find((command) => isTokenEqualsArg(command, arg)) diff --git a/redisinsight/ui/src/pages/workbench/utils/searchSuggestions.ts b/redisinsight/ui/src/pages/workbench/utils/searchSuggestions.ts index 3ca7542f9a..09e60723ca 100644 --- a/redisinsight/ui/src/pages/workbench/utils/searchSuggestions.ts +++ b/redisinsight/ui/src/pages/workbench/utils/searchSuggestions.ts @@ -182,7 +182,7 @@ const handleCommonSuggestions = ( const shouldHideSuggestions = isCursorInQuotes || nextCursorChar || (prevCursorChar && isEscaped) if (shouldHideSuggestions) { return { - helpWidget: { isOpen: true, parent: foundArg?.parent, currentArg: foundArg?.stopArg }, + helpWidget: { isOpen: !!foundArg, parent: foundArg?.parent, currentArg: foundArg?.stopArg }, suggestions: asSuggestionsRef([]) } } diff --git a/redisinsight/ui/src/pages/workbench/utils/tests/query.spec.ts b/redisinsight/ui/src/pages/workbench/utils/tests/query.spec.ts index a3ab9fc6fd..0f705de920 100644 --- a/redisinsight/ui/src/pages/workbench/utils/tests/query.spec.ts +++ b/redisinsight/ui/src/pages/workbench/utils/tests/query.spec.ts @@ -2,7 +2,6 @@ import { SearchCommand, TokenType } from 'uiSrc/pages/search/types' import { Maybe, splitQueryByArgs } from 'uiSrc/utils' import { MOCKED_REDIS_COMMANDS } from 'uiSrc/mocks/data/mocked_redis_commands' import { IRedisCommand } from 'uiSrc/constants' -import { COMPOSITE_ARGS } from 'uiSrc/pages/workbench/constants' import { commonfindCurrentArgumentCases, findArgumentftAggreageTests, @@ -16,6 +15,9 @@ const COMMANDS = Object.keys(MOCKED_REDIS_COMMANDS).map((name) => ({ name, ...MOCKED_REDIS_COMMANDS[name] })) +const COMPOSITE_ARGS = COMMANDS + .filter((command) => command.name && command.name.includes(' ')) + .map(({ name }) => name) describe('findCurrentArgument', () => { describe('with list of commands', () => { From df1af6e2d51def3b43b50772704a8e4b57eebf4c Mon Sep 17 00:00:00 2001 From: ArtemHoruzhenko Date: Wed, 16 Oct 2024 16:39:55 +0300 Subject: [PATCH 189/256] bump ip --- tests/e2e/package.json | 3 ++- tests/e2e/yarn.lock | 8 ++++---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/tests/e2e/package.json b/tests/e2e/package.json index 7b1e324780..da5e6a3d34 100644 --- a/tests/e2e/package.json +++ b/tests/e2e/package.json @@ -37,7 +37,8 @@ "@types/lodash": "4.14.192", "@types/node": "20.3.1", "word-wrap": "1.2.4", - "**/semver": "^7.5.2" + "**/semver": "^7.5.2", + "testcafe-browser-provider-electron/**/ip": "^2.0.1" }, "devDependencies": { "@types/archiver": "^6.0.2", diff --git a/tests/e2e/yarn.lock b/tests/e2e/yarn.lock index 06ecbacb52..9f590a1588 100644 --- a/tests/e2e/yarn.lock +++ b/tests/e2e/yarn.lock @@ -3871,10 +3871,10 @@ ip-regex@^4.1.0: resolved "https://registry.npmjs.org/ip-regex/-/ip-regex-4.3.0.tgz" integrity sha512-B9ZWJxHHOHUhUjCPrMpLD4xEq35bUTClHM1S6CBU5ixQnkZmwipwgc96vAd7AAGM9TGHvJR+Uss+/Ak6UphK+Q== -ip@^1.1.3: - version "1.1.9" - resolved "https://registry.yarnpkg.com/ip/-/ip-1.1.9.tgz#8dfbcc99a754d07f425310b86a99546b1151e396" - integrity sha512-cyRxvOEpNHNtchU3Ln9KC/auJgup87llfQpQ+t5ghoC/UhL16SWzbueiCsdTnWmqAWl7LadfuwhlqmtOaqMHdQ== +ip@^1.1.3, ip@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/ip/-/ip-2.0.1.tgz#e8f3595d33a3ea66490204234b77636965307105" + integrity sha512-lJUL9imLTNi1ZfXT+DU6rBBdbiKGBuay9B6xGSPVjUeQwaH1RIGqef8RZkUtHioLmSNpPR5M4HVKJGm1j8FWVQ== is-array-buffer@^3.0.4: version "3.0.4" From bb553adcf338ab46b39a33f59c25993e78570f7d Mon Sep 17 00:00:00 2001 From: Roman Sergeenko Date: Wed, 16 Oct 2024 15:46:56 +0200 Subject: [PATCH 190/256] fix pr comments --- .../ui/src/pages/workbench/utils/{queryUtils.ts => helpers.ts} | 0 redisinsight/ui/src/pages/workbench/utils/query.ts | 2 +- redisinsight/ui/src/pages/workbench/utils/query_refactor.ts | 2 +- 3 files changed, 2 insertions(+), 2 deletions(-) rename redisinsight/ui/src/pages/workbench/utils/{queryUtils.ts => helpers.ts} (100%) diff --git a/redisinsight/ui/src/pages/workbench/utils/queryUtils.ts b/redisinsight/ui/src/pages/workbench/utils/helpers.ts similarity index 100% rename from redisinsight/ui/src/pages/workbench/utils/queryUtils.ts rename to redisinsight/ui/src/pages/workbench/utils/helpers.ts diff --git a/redisinsight/ui/src/pages/workbench/utils/query.ts b/redisinsight/ui/src/pages/workbench/utils/query.ts index d3ffba6480..e0c633407f 100644 --- a/redisinsight/ui/src/pages/workbench/utils/query.ts +++ b/redisinsight/ui/src/pages/workbench/utils/query.ts @@ -3,7 +3,7 @@ import { findLastIndex, isNumber, toNumber } from 'lodash' import { generateArgsNames, Maybe, Nullable } from 'uiSrc/utils' import { CommandProvider, IRedisCommand, IRedisCommandTree, ICommandTokenType } from 'uiSrc/constants' -import { isStringsEqual } from 'uiSrc/pages/workbench/utils/queryUtils' +import { isStringsEqual } from './helpers' import { ArgName, FoundCommandArgument } from '../types' export const findCurrentArgument = ( diff --git a/redisinsight/ui/src/pages/workbench/utils/query_refactor.ts b/redisinsight/ui/src/pages/workbench/utils/query_refactor.ts index 5166fa2841..774892d4a3 100644 --- a/redisinsight/ui/src/pages/workbench/utils/query_refactor.ts +++ b/redisinsight/ui/src/pages/workbench/utils/query_refactor.ts @@ -1,7 +1,7 @@ /* eslint-disable no-continue */ import { ICommandTokenType, IRedisCommand } from 'uiSrc/constants' import { Maybe } from 'uiSrc/utils' -import { isStringsEqual, isTokenEqualsArg } from 'uiSrc/pages/workbench/utils/queryUtils' +import { isStringsEqual, isTokenEqualsArg } from './helpers' interface BlockTokensTree { queryArgs: string[] From bb7b78b35366192a034c3927b247dcf28e8e5e8b Mon Sep 17 00:00:00 2001 From: ArtemHoruzhenko Date: Wed, 16 Oct 2024 16:52:11 +0300 Subject: [PATCH 191/256] bump ts-node --- redisinsight/api/package.json | 2 +- redisinsight/api/yarn.lock | 80 +++++++++++++++++++++++++++++------ 2 files changed, 68 insertions(+), 14 deletions(-) diff --git a/redisinsight/api/package.json b/redisinsight/api/package.json index a5ff984946..51d16024a0 100644 --- a/redisinsight/api/package.json +++ b/redisinsight/api/package.json @@ -140,7 +140,7 @@ "ts-jest": "^29.2.5", "ts-loader": "^6.2.1", "ts-mocha": "^8.0.0", - "ts-node": "^9.1.1", + "ts-node": "^10.9.2", "tsconfig-paths": "^3.9.0", "tsconfig-paths-webpack-plugin": "^3.3.0", "typescript": "^4.8.2" diff --git a/redisinsight/api/yarn.lock b/redisinsight/api/yarn.lock index 3fb39d5320..3293458ef0 100644 --- a/redisinsight/api/yarn.lock +++ b/redisinsight/api/yarn.lock @@ -536,6 +536,13 @@ resolved "https://registry.yarnpkg.com/@colors/colors/-/colors-1.5.0.tgz#bb504579c1cae923e6576a4f5da43d25f97bdbd9" integrity sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ== +"@cspotcode/source-map-support@^0.8.0": + version "0.8.1" + resolved "https://registry.yarnpkg.com/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz#00629c35a688e05a88b1cda684fb9d5e73f000a1" + integrity sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw== + dependencies: + "@jridgewell/trace-mapping" "0.3.9" + "@dabh/diagnostics@^2.0.2": version "2.0.3" resolved "https://registry.yarnpkg.com/@dabh/diagnostics/-/diagnostics-2.0.3.tgz#7f7e97ee9a725dffc7808d93668cc984e1dc477a" @@ -980,7 +987,7 @@ resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz#2203b118c157721addfe69d47b70465463066d78" integrity sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w== -"@jridgewell/resolve-uri@^3.1.0": +"@jridgewell/resolve-uri@^3.0.3", "@jridgewell/resolve-uri@^3.1.0": version "3.1.2" resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz#7a0ee601f60f99a20c7c7c5ff0c80388c1189bd6" integrity sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw== @@ -1018,6 +1025,14 @@ resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz#3188bcb273a414b0d215fd22a58540b989b9409a" integrity sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ== +"@jridgewell/trace-mapping@0.3.9": + version "0.3.9" + resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz#6534fd5933a53ba7cbf3a17615e273a0d1273ff9" + integrity sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ== + dependencies: + "@jridgewell/resolve-uri" "^3.0.3" + "@jridgewell/sourcemap-codec" "^1.4.10" + "@jridgewell/trace-mapping@^0.3.12", "@jridgewell/trace-mapping@^0.3.18", "@jridgewell/trace-mapping@^0.3.20", "@jridgewell/trace-mapping@^0.3.24", "@jridgewell/trace-mapping@^0.3.25": version "0.3.25" resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz#15f190e98895f3fc23276ee14bc76b675c2e50f0" @@ -1423,6 +1438,26 @@ resolved "https://registry.yarnpkg.com/@tootallnate/once/-/once-1.1.2.tgz#ccb91445360179a04e7fe6aff78c00ffc1eeaf82" integrity sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw== +"@tsconfig/node10@^1.0.7": + version "1.0.11" + resolved "https://registry.yarnpkg.com/@tsconfig/node10/-/node10-1.0.11.tgz#6ee46400685f130e278128c7b38b7e031ff5b2f2" + integrity sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw== + +"@tsconfig/node12@^1.0.7": + version "1.0.11" + resolved "https://registry.yarnpkg.com/@tsconfig/node12/-/node12-1.0.11.tgz#ee3def1f27d9ed66dac6e46a295cffb0152e058d" + integrity sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag== + +"@tsconfig/node14@^1.0.0": + version "1.0.3" + resolved "https://registry.yarnpkg.com/@tsconfig/node14/-/node14-1.0.3.tgz#e4386316284f00b98435bf40f72f75a09dabf6c1" + integrity sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow== + +"@tsconfig/node16@^1.0.2": + version "1.0.4" + resolved "https://registry.yarnpkg.com/@tsconfig/node16/-/node16-1.0.4.tgz#0b92dcc0cc1c81f6f306a381f28e31b1a56536e9" + integrity sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA== + "@types/adm-zip@^0.5.0": version "0.5.0" resolved "https://registry.yarnpkg.com/@types/adm-zip/-/adm-zip-0.5.0.tgz#94c90a837ce02e256c7c665a6a1eb295906333c1" @@ -1929,21 +1964,28 @@ acorn-jsx@^5.3.1: resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937" integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ== +acorn-walk@^8.1.1: + version "8.3.4" + resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-8.3.4.tgz#794dd169c3977edf4ba4ea47583587c5866236b7" + integrity sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g== + dependencies: + acorn "^8.11.0" + acorn@^7.4.0: version "7.4.1" resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.4.1.tgz#feaed255973d2e77555b83dbc08851a6c63520fa" integrity sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A== +acorn@^8.11.0, acorn@^8.4.1, acorn@^8.8.2: + version "8.13.0" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.13.0.tgz#2a30d670818ad16ddd6a35d3842dacec9e5d7ca3" + integrity sha512-8zSiw54Oxrdym50NlZ9sUusyO1Z1ZchgRLWRaK6c86XJFClyCgFKetdowBg5bKxyp/u+CDBJG4Mpp0m3HLZl9w== + acorn@^8.7.1: version "8.8.2" resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.8.2.tgz#1b2f25db02af965399b9776b0c2c391276d37c4a" integrity sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw== -acorn@^8.8.2: - version "8.13.0" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.13.0.tgz#2a30d670818ad16ddd6a35d3842dacec9e5d7ca3" - integrity sha512-8zSiw54Oxrdym50NlZ9sUusyO1Z1ZchgRLWRaK6c86XJFClyCgFKetdowBg5bKxyp/u+CDBJG4Mpp0m3HLZl9w== - address@^1.0.1: version "1.2.2" resolved "https://registry.yarnpkg.com/address/-/address-1.2.2.tgz#2b5248dac5485a6390532c6a517fda2e3faac89e" @@ -7671,7 +7713,7 @@ source-map-support@0.5.13: buffer-from "^1.0.0" source-map "^0.6.0" -source-map-support@^0.5.17, source-map-support@^0.5.19, source-map-support@^0.5.6, source-map-support@~0.5.20: +source-map-support@^0.5.19, source-map-support@^0.5.6, source-map-support@~0.5.20: version "0.5.21" resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.21.tgz#04fe7c7f9e1ed2d662233c28cb2b35b9f63f6e4f" integrity sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w== @@ -8273,16 +8315,23 @@ ts-node@7.0.1: source-map-support "^0.5.6" yn "^2.0.0" -ts-node@^9.1.1: - version "9.1.1" - resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-9.1.1.tgz#51a9a450a3e959401bda5f004a72d54b936d376d" - integrity sha512-hPlt7ZACERQGf03M253ytLY3dHbGNGrAq9qIHWUY9XHYl1z7wYngSr3OQ5xmui8o2AaxsONxIzjafLUiWBo1Fg== - dependencies: +ts-node@^10.9.2: + version "10.9.2" + resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-10.9.2.tgz#70f021c9e185bccdca820e26dc413805c101c71f" + integrity sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ== + dependencies: + "@cspotcode/source-map-support" "^0.8.0" + "@tsconfig/node10" "^1.0.7" + "@tsconfig/node12" "^1.0.7" + "@tsconfig/node14" "^1.0.0" + "@tsconfig/node16" "^1.0.2" + acorn "^8.4.1" + acorn-walk "^8.1.1" arg "^4.1.0" create-require "^1.1.0" diff "^4.0.1" make-error "^1.1.1" - source-map-support "^0.5.17" + v8-compile-cache-lib "^3.0.1" yn "3.1.1" tsconfig-paths-webpack-plugin@4.1.0: @@ -8579,6 +8628,11 @@ uuid@^9.0.0: resolved "https://registry.yarnpkg.com/uuid/-/uuid-9.0.0.tgz#592f550650024a38ceb0c562f2f6aa435761efb5" integrity sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg== +v8-compile-cache-lib@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz#6336e8d71965cb3d35a1bbb7868445a7c05264bf" + integrity sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg== + v8-compile-cache@^2.0.3: version "2.3.0" resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz#2de19618c66dc247dcfb6f99338035d8245a2cee" From df81b23e0443f4544ba00be739a655f34b025fc6 Mon Sep 17 00:00:00 2001 From: ArtemHoruzhenko Date: Wed, 16 Oct 2024 17:08:48 +0300 Subject: [PATCH 192/256] fix minifying --- redisinsight/api/esbuild.js | 1 + 1 file changed, 1 insertion(+) diff --git a/redisinsight/api/esbuild.js b/redisinsight/api/esbuild.js index 67e824e73f..87e21ccd7b 100644 --- a/redisinsight/api/esbuild.js +++ b/redisinsight/api/esbuild.js @@ -14,6 +14,7 @@ const define = { const external = [ '@nestjs/microservices', + 'class-transformer/storage', '@fastify/static', // packages with binaries ...Object.keys(dependencies), From 57980314738cdac296fb0373516451d59bd2920b Mon Sep 17 00:00:00 2001 From: vlad-dargel Date: Wed, 16 Oct 2024 18:41:52 +0200 Subject: [PATCH 193/256] ts fixes --- tests/e2e/helpers/google-authorization.ts | 2 +- tests/e2e/helpers/keys.ts | 160 ++++++++++++---------- tests/e2e/package.json | 2 +- tests/e2e/tsconfig.json | 7 +- 4 files changed, 93 insertions(+), 78 deletions(-) diff --git a/tests/e2e/helpers/google-authorization.ts b/tests/e2e/helpers/google-authorization.ts index dedf82d64b..82e411bfc1 100644 --- a/tests/e2e/helpers/google-authorization.ts +++ b/tests/e2e/helpers/google-authorization.ts @@ -1,5 +1,4 @@ import { Builder, By, Key, until } from 'selenium-webdriver'; -import open = require('open'); import { googleUser, googleUserPassword } from './conf'; export async function processGoogleSSO(urlToUse: string): Promise { @@ -27,6 +26,7 @@ export async function processGoogleSSO(urlToUse: string): Promise { const redirectUrl = `${protocol + callbackUrl }?${ modifiedUrl}`; // Open Redis Insight electron app using deeplink + const open = (await import('open')).default; await open(redirectUrl, { app: { name: 'Redis Insight' } }); } catch (error) { diff --git a/tests/e2e/helpers/keys.ts b/tests/e2e/helpers/keys.ts index 20cc0a5936..a98fa6b5f1 100644 --- a/tests/e2e/helpers/keys.ts +++ b/tests/e2e/helpers/keys.ts @@ -91,21 +91,23 @@ export async function populateDBWithHashes(host: string, port: string, keyArgume const dbConf = { port: Number.parseInt(port), host, username: 'default' }; const client = createClient(dbConf); - await client.on('error', async function(error: string) { + client.on('error', (error: string) => { throw new Error(error); }); - await client.on('connect', async function() { - if (keyArguments.keysCount) { - for (let i = 0; i < keyArguments.keysCount; i++) { - const keyName = `${keyArguments.keyNameStartWith}${Common.generateWord(20)}`; - await client.hset([keyName, 'field1', 'Hello'], async(error: string) => { - if (error) { - throw error; - } - }); + + client.on('connect', async () => { + try { + if (keyArguments.keysCount) { + for (let i = 0; i < keyArguments.keysCount; i++) { + const keyName = `${keyArguments.keyNameStartWith}${Common.generateWord(20)}`; + await client.hSet(keyName, 'field1', 'Hello'); + } } + } catch (error) { + console.error('Error setting hash:', error); + } finally { + await client.quit(); } - await client.quit(); }); } @@ -118,25 +120,27 @@ export async function populateDBWithHashes(host: string, port: string, keyArgume export async function populateHashWithFields(host: string, port: string, keyArguments: AddKeyArguments): Promise { const dbConf = { port: Number.parseInt(port), host, username: 'default' }; const client = createClient(dbConf); - const fields: string[] = []; + const fields: Record = {}; // Using an object for field-value pairs - await client.on('error', async function(error: string) { + client.on('error', (error: string) => { throw new Error(error); }); - await client.on('connect', async function() { - if (keyArguments.fieldsCount) { - for (let i = 0; i < keyArguments.fieldsCount; i++) { - const field = `${keyArguments.fieldStartWith}${Common.generateWord(10)}`; - const fieldValue = `${keyArguments.fieldValueStartWith}${Common.generateWord(10)}`; - fields.push(field, fieldValue); + + client.on('connect', async () => { + try { + if (keyArguments.fieldsCount) { + for (let i = 0; i < keyArguments.fieldsCount; i++) { + const field = `${keyArguments.fieldStartWith}${Common.generateWord(10)}`; + const fieldValue = `${keyArguments.fieldValueStartWith}${Common.generateWord(10)}`; + fields[field] = fieldValue; + } } + await client.hSet(keyArguments.keyName!, fields); + } catch (error) { + console.error('Error setting hash fields:', error); + } finally { + await client.quit(); } - await client.hset(keyArguments.keyName, fields, async(error: string) => { - if (error) { - throw error; - } - }); - await client.quit(); }); } @@ -151,22 +155,25 @@ export async function populateListWithElements(host: string, port: string, keyAr const client = createClient(dbConf); const elements: string[] = []; - await client.on('error', async function(error: string) { + client.on('error', (error: string) => { throw new Error(error); }); - await client.on('connect', async function() { - if (keyArguments.elementsCount) { - for (let i = 0; i < keyArguments.elementsCount; i++) { - const element = `${keyArguments.elementStartWith}${Common.generateWord(10)}`; - elements.push(element); + + client.on('connect', async () => { + try { + if (keyArguments.elementsCount) { + for (let i = 0; i < keyArguments.elementsCount; i++) { + const element = `${keyArguments.elementStartWith}${Common.generateWord(10)}`; + elements.push(element); + } } + // Push all the elements to the list + await client.lPush(keyArguments.keyName!, elements); // Spread the elements array + } catch (error) { + console.error('Error pushing elements to list:', error); + } finally { + await client.quit(); } - await client.lpush(keyArguments.keyName, elements, async(error: string) => { - if (error) { - throw error; - } - }); - await client.quit(); }); } @@ -181,22 +188,25 @@ export async function populateSetWithMembers(host: string, port: string, keyArgu const client = createClient(dbConf); const members: string[] = []; - await client.on('error', async function(error: string) { + client.on('error', (error: string) => { throw new Error(error); }); - await client.on('connect', async function() { - if (keyArguments.membersCount) { - for (let i = 0; i < keyArguments.membersCount; i++) { - const member = `${keyArguments.memberStartWith}${Common.generateWord(10)}`; - members.push(member); + + client.on('connect', async () => { + try { + if (keyArguments.membersCount) { + for (let i = 0; i < keyArguments.membersCount; i++) { + const member = `${keyArguments.memberStartWith}${Common.generateWord(10)}`; + members.push(member); + } } + // Add all members to the set using sAdd + await client.sAdd(keyArguments.keyName!, members); + } catch (error) { + console.error('Error adding members to set:', error); + } finally { + await client.quit(); } - await client.sadd(keyArguments.keyName, members, async(error: string) => { - if (error) { - throw error; - } - }); - await client.quit(); }); } @@ -208,28 +218,30 @@ export async function populateSetWithMembers(host: string, port: string, keyArgu */ export async function populateZSetWithMembers(host: string, port: string, keyArguments: AddKeyArguments): Promise { const dbConf = { port: Number.parseInt(port), host, username: 'default' }; - let minScoreValue: -10; - let maxScoreValue: 10; + const minScoreValue = -10; + const maxScoreValue = 10; const client = createClient(dbConf); - const members: string[] = []; + const members: { score: number; value: string }[] = []; - await client.on('error', async function(error: string) { + client.on('error', (error: string) => { throw new Error(error); }); - await client.on('connect', async function() { - if (keyArguments.membersCount) { - for (let i = 0; i < keyArguments.membersCount; i++) { - const memberName = `${keyArguments.memberStartWith}${Common.generateWord(10)}`; - const scoreValue = random(minScoreValue, maxScoreValue).toString(2); - members.push(scoreValue, memberName); + + client.on('connect', async () => { + try { + if (keyArguments.membersCount) { + for (let i = 0; i < keyArguments.membersCount; i++) { + const memberName = `${keyArguments.memberStartWith}${Common.generateWord(10)}`; + const scoreValue = random(minScoreValue, maxScoreValue); + members.push({ score: scoreValue, value: memberName }); + } } + await client.zAdd(keyArguments.keyName!, members); + } catch (error) { + console.error('Error adding members to sorted set:', error); + } finally { + await client.quit(); } - await client.zadd(keyArguments.keyName, members, async(error: string) => { - if (error) { - throw error; - } - }); - await client.quit(); }); } @@ -242,16 +254,18 @@ export async function deleteAllKeysFromDB(host: string, port: string): Promise { throw new Error(error); }); - await client.on('connect', async function() { - await client.flushall((error: string) => { - if (error) { - throw error; - } - }); - await client.quit(); + + client.on('connect', async () => { + try { + await client.flushAll(); + } catch (error) { + console.error('Error flushing database:', error); + } finally { + await client.quit(); + } }); } diff --git a/tests/e2e/package.json b/tests/e2e/package.json index da5e6a3d34..4fa6148c5e 100644 --- a/tests/e2e/package.json +++ b/tests/e2e/package.json @@ -13,7 +13,7 @@ "build:ui": "yarn --cwd ../../ build:ui", "redis:last": "docker run --name redis-last-version -p 7777:6379 -d redislabs/redismod", "start:app": "cross-env yarn start:api", - "test:chrome": "testcafe --compiler-options typescript.configPath=tsconfig.testcafe.json --cache --allow-insecure-localhost --disable-multiple-windows --concurrency 1 chrome tests/ -r html:./report/report.html,spec -e -s takeOnFails=true,path=report/screenshots/,pathPattern=${OS}_${BROWSER}/${DATE}_${TIME}/${FIXTURE}_${TEST}_${FILE_INDEX}.png", + "test:chrome": "testcafe --compiler-options typescript.configPath=tsconfig.testcafe.json --cache --disable-multiple-windows --concurrency 1 chrome tests/ -r html:./report/report.html,spec -e -s takeOnFails=true,path=report/screenshots/,pathPattern=${OS}_${BROWSER}/${DATE}_${TIME}/${FIXTURE}_${TEST}_${FILE_INDEX}.png", "test:chrome:ci": "ts-node ./web.runner.ts", "test": "yarn test:chrome", "lint": "eslint . --ext .ts,.js,.tsx,.jsx", diff --git a/tests/e2e/tsconfig.json b/tests/e2e/tsconfig.json index 4e920cf41d..ec928c4add 100644 --- a/tests/e2e/tsconfig.json +++ b/tests/e2e/tsconfig.json @@ -1,12 +1,13 @@ { "compilerOptions": { - "target": "es2020", - "module": "commonjs", + "target": "ES2020", + "module": "CommonJS", "esModuleInterop": true, "forceConsistentCasingInFileNames": true, "strict": true, "skipLibCheck": true, - "sourceMap": true + "sourceMap": true, + "types": ["node"] }, "exclude": [ "./node_modules", From 273501d768b55c1b6bf001d65ff401e1a977d40d Mon Sep 17 00:00:00 2001 From: zalenskiSofteq Date: Wed, 16 Oct 2024 21:54:07 +0200 Subject: [PATCH 194/256] #RI-6213 - Migrate release workflows from CircleCI to Github Actions --- .github/virustotal-report.js | 45 +++++ .github/workflows/aws.yml | 176 +++++++++++++++++++ .github/workflows/build.yml | 44 +++-- .github/workflows/licenses-check.yml | 34 ++++ .github/workflows/nightly.yml | 9 + .github/workflows/pipeline-build-docker.yml | 48 ++++- .github/workflows/pipeline-build-linux.yml | 62 +++++-- .github/workflows/pipeline-build-macos.yml | 82 ++++++--- .github/workflows/pipeline-build-windows.yml | 39 +++- .github/workflows/release-docker.yml | 41 +++++ .github/workflows/release-prod.yml | 55 ++++++ .github/workflows/release-stage.yml | 40 +++++ .github/workflows/tests-backend.yml | 2 +- .github/workflows/tests-frontend.yml | 2 +- .github/workflows/tests.yml | 20 ++- .github/workflows/virustotal.yml | 168 ++++++++++++++++++ .github/workflows/weekly.yml | 9 + 17 files changed, 800 insertions(+), 76 deletions(-) create mode 100644 .github/virustotal-report.js create mode 100644 .github/workflows/aws.yml create mode 100644 .github/workflows/licenses-check.yml create mode 100644 .github/workflows/nightly.yml create mode 100644 .github/workflows/release-docker.yml create mode 100644 .github/workflows/release-prod.yml create mode 100644 .github/workflows/release-stage.yml create mode 100644 .github/workflows/virustotal.yml create mode 100644 .github/workflows/weekly.yml diff --git a/.github/virustotal-report.js b/.github/virustotal-report.js new file mode 100644 index 0000000000..333cad83f1 --- /dev/null +++ b/.github/virustotal-report.js @@ -0,0 +1,45 @@ +const fs = require('fs'); + +const fileName = process.env.FILE_NAME; +const buildName = process.env.BUILD_NAME; +const failed = process.env.FAILED === 'true'; + +const results = { + message: { + text: `*Virustotal checks* (Branch: *${process.env.GITHUB_REF_NAME}*)` + + `\n`, + attachments: [], + }, +}; + +const result = { + color: '#36a64f', + title: `Finished at: ${new Date().toISOString()}`, + text: `All builds were passed via virustotal checks`, + fields: [], +}; + +if (failed) { + results.passed = false; + result.color = '#cc0000'; + result.text = 'Build had failed virustotal checks'; + result.fields.push({ + title: 'Failed build', + value: buildName, + short: true, + }); +} + +results.message.attachments.push(result); + +if (failed === true) { + results.message.text = ' ' + results.message.text; +} + +console.log({'results.message': results.message}); + + +fs.writeFileSync(fileName, JSON.stringify({ + // channel: process.env.SLACK_VIRUSTOTAL_REPORT_CHANNEL, + ...results.message, +})); diff --git a/.github/workflows/aws.yml b/.github/workflows/aws.yml new file mode 100644 index 0000000000..2c7c1991fc --- /dev/null +++ b/.github/workflows/aws.yml @@ -0,0 +1,176 @@ +name: AWS + +on: + workflow_call: + +env: + # todo: check + # AWS_BUCKET_NAME: ${{ secrets.AWS_BUCKET_NAME }} + AWS_BUCKET_NAME: ${{ secrets.AWS_BUCKET_NAME_TEST }} + AWS_DISTRIBUTION_ID: ${{ secrets.AWS_DISTRIBUTION_ID }} + AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} + AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + + +jobs: + release-private: + name: Release s3 private + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Configure AWS Credentials + uses: aws-actions/configure-aws-credentials@v4 + with: + aws-region: ${{ secrets.AWS_REGION }} + aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} + aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + + - name: Download All Artifacts + uses: actions/download-artifact@v3 + with: + path: ./release + + - name: Publish private + run: | + chmod +x .circleci/build/sum_sha256.sh + .circleci/build/sum_sha256.sh + applicationVersion=$(jq -r '.version' redisinsight/package.json) + + aws s3 cp release/ s3://${AWS_BUCKET_NAME}/private/${applicationVersion} --recursive + + release-public: + name: Release s3 public + runs-on: ubuntu-latest + # todo: remove after test + if: ${{ '1' == '2' }} + needs: 'release-private' + environment: 'production-approve' + steps: + - uses: actions/checkout@v4 + + - name: Init variables + run: | + latestYmlFileName="latest.yml" + downloadLatestFolderPath="public/latest" + upgradeLatestFolderPath="public/upgrades" + releasesFolderPath="public/releases" + appName=$(jq -r '.productName' electron-builder.json) + appVersion=$(jq -r '.version' redisinsight/package.json) + + echo "export downloadLatestFolderPath=${downloadLatestFolderPath}" >> $BASH_ENV + echo "export upgradeLatestFolderPath=${upgradeLatestFolderPath}" >> $BASH_ENV + echo "export releasesFolderPath=${releasesFolderPath}" >> $BASH_ENV + echo "export applicationName=${appName}" >> $BASH_ENV + echo "export applicationVersion=${appVersion}" >> $BASH_ENV + echo "export appFileName=Redis-Insight" >> $BASH_ENV + + # download latest.yml file to get last public version + aws s3 cp s3://${AWS_BUCKET_NAME}/${downloadLatestFolderPath}/${latestYmlFileName} . + + versionLine=$(head -1 ${latestYmlFileName}) + versionLineArr=(${versionLine/:// }) + previousAppVersion=${versionLineArr[1]} + + echo "export previousApplicationVersion=${previousAppVersion}" >> $BASH_ENV + + - name: Publish AWS S3 + run: | + # remove previous build from the latest directory /public/latest + aws s3 rm s3://${AWS_BUCKET_NAME}/${downloadLatestFolderPath} --recursive + + # remove previous build from the upgrade directory /public/upgrades + aws s3 rm s3://${AWS_BUCKET_NAME}/${upgradeLatestFolderPath} --recursive + + # copy current version apps for download to /public/latest + aws s3 cp s3://${AWS_BUCKET_NAME}/private/${applicationVersion}/ \ + s3://${AWS_BUCKET_NAME}/${downloadLatestFolderPath} --recursive --exclude "*.zip" + + # copy current version apps for upgrades to /public/upgrades + aws s3 cp s3://${AWS_BUCKET_NAME}/private/${applicationVersion}/ \ + s3://${AWS_BUCKET_NAME}/${upgradeLatestFolderPath} --recursive + + # !MOVE current version apps to releases folder /public/releases + aws s3 mv s3://${AWS_BUCKET_NAME}/private/${applicationVersion}/ \ + s3://${AWS_BUCKET_NAME}/${releasesFolderPath}/${applicationVersion} --recursive + + # invalidate cloudfront cash + aws cloudfront create-invalidation --distribution-id ${AWS_DISTRIBUTION_ID} --paths "/*" + + - name: Add tags for all objects and create S3 metrics + run: | + + # declare all tags + declare -A tag0=( + [arch]='x64' + [platform]='macos' + [objectDownload]=${appFileName}'-mac-x64.dmg' + [objectUpgrade]=${appFileName}'-mac-x64.zip' + ) + + declare -A tag1=( + [arch]='arm64' + [platform]='macos' + [objectDownload]=${appFileName}'-mac-arm64.dmg' + [objectUpgrade]=${appFileName}'-mac-arm64.zip' + ) + + declare -A tag2=( + [arch]='x64' + [platform]='windows' + [objectDownload]=${appFileName}'-win-installer.exe' + ) + + declare -A tag3=( + [arch]='x64' + [platform]='linux_AppImage' + [objectDownload]=${appFileName}'-linux-x86_64.AppImage' + ) + + declare -A tag4=( + [arch]='x64' + [platform]='linux_deb' + [objectDownload]=${appFileName}'-linux-amd64.deb' + ) + + declare -A tag5=( + [arch]='x64' + [platform]='linux_rpm' + [objectDownload]=${appFileName}'-linux-x86_64.rpm' + ) + + # loop for add all tags to each app and create metrics + declare -n tag + for tag in ${!tag@}; do + + designation0="downloads" + designation1="upgrades" + + id0="${tag[platform]}_${tag[arch]}_${designation0}_${applicationVersion}" + id1="${tag[platform]}_${tag[arch]}_${designation1}_${applicationVersion}" + + # add tags to each app for download + aws s3api put-object-tagging \ + --bucket ${AWS_BUCKET_NAME} \ + --key ${downloadLatestFolderPath}/${tag[objectDownload]} \ + --tagging '{"TagSet": [{ "Key": "version", "Value": "'"${applicationVersion}"'" }, {"Key": "platform", "Value": "'"${tag[platform]}"'"}, {"Key": "arch", "Value": "'"${tag[arch]}"'"}, { "Key": "designation", "Value": "'"${designation0}"'" }]}' + + # add tags to each app for upgrades + aws s3api put-object-tagging \ + --bucket ${AWS_BUCKET_NAME} \ + --key ${upgradeLatestFolderPath}/${tag[objectUpgrade]:=${tag[objectDownload]}} \ + --tagging '{"TagSet": [{ "Key": "version", "Value": "'"${applicationVersion}"'" }, {"Key": "platform", "Value": "'"${tag[platform]}"'"}, {"Key": "arch", "Value": "'"${tag[arch]}"'"}, { "Key": "designation", "Value": "'"${designation1}"'" }]}' + + # Create metrics for all tags for downloads to S3 + aws s3api put-bucket-metrics-configuration \ + --bucket ${AWS_BUCKET_NAME} \ + --id ${id0} \ + --metrics-configuration '{"Id": "'"${id0}"'", "Filter": {"And": {"Tags": [{"Key": "platform", "Value": "'"${tag[platform]}"'"}, {"Key": "arch", "Value": "'"${tag[arch]}"'"}, {"Key": "designation", "Value": "'"${designation0}"'"}, {"Key": "version", "Value": "'"${applicationVersion}"'"} ]}}}' + + # Create metrics for all tags for upgrades to S3 + aws s3api put-bucket-metrics-configuration \ + --bucket ${AWS_BUCKET_NAME} \ + --id ${id1} \ + --metrics-configuration '{"Id": "'"${id1}"'", "Filter": {"And": {"Tags": [{"Key": "platform", "Value": "'"${tag[platform]}"'"}, {"Key": "arch", "Value": "'"${tag[arch]}"'"}, {"Key": "designation", "Value": "'"${designation1}"'"}, {"Key": "version", "Value": "'"${applicationVersion}"'"}]}}}' + + done diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 1a7a1c9aa3..008e24d9b0 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -1,6 +1,7 @@ name: Build on: + # Manual trigger build workflow_dispatch: inputs: target: @@ -12,13 +13,14 @@ on: - all - docker - windows:x64 - - macos - macos:x64 - macos:arm64 + - macos:all - linux:appimage:x64 - linux:deb:x64 - linux:rpm:x64 - linux:snap:x64 + - linux:all environment: description: Environment to run build @@ -26,28 +28,48 @@ on: default: 'staging' required: false + # Called for Release workflows + workflow_call: + inputs: + environment: + description: Environment to run build + type: string + default: 'staging' + required: false + target: + description: Build target + type: string + default: 'all' + required: false + jobs: - build_linux: - if: startsWith(inputs.target, 'linux') || inputs.target == 'all' + build-linux: + if: startsWith(inputs.target, 'linux') || endsWith(inputs.target, 'all') # concurrency: build uses: ./.github/workflows/pipeline-build-linux.yml secrets: inherit with: - target: ${{ inputs.target }} + environment: ${{ inputs.environment }} + target: ${{ (endsWith(inputs.target, 'all') && 'all') || inputs.target }} - build_macos: - if: startsWith(inputs.target, 'macos') || inputs.target == 'all' + build-macos: + if: startsWith(inputs.target, 'macos') || endsWith(inputs.target, 'all') uses: ./.github/workflows/pipeline-build-macos.yml secrets: inherit with: - target: ${{ inputs.target }} + environment: ${{ inputs.environment }} + target: ${{ (endsWith(inputs.target, 'all') && 'all') || inputs.target }} - build_windows: - if: startsWith(inputs.target, 'windows') || inputs.target == 'all' + build-windows: + if: startsWith(inputs.target, 'windows') || endsWith(inputs.target, 'all') uses: ./.github/workflows/pipeline-build-windows.yml secrets: inherit + with: + environment: ${{ inputs.environment }} - build_docker: - if: startsWith(inputs.target, 'docker') || inputs.target == 'all' + build-docker: + if: startsWith(inputs.target, 'docker') || endsWith(inputs.target, 'all') uses: ./.github/workflows/pipeline-build-docker.yml secrets: inherit + with: + environment: ${{ inputs.environment }} diff --git a/.github/workflows/licenses-check.yml b/.github/workflows/licenses-check.yml new file mode 100644 index 0000000000..e82705ffb3 --- /dev/null +++ b/.github/workflows/licenses-check.yml @@ -0,0 +1,34 @@ +name: Licenses check pipeline +on: + workflow_call: + workflow_dispatch: + +jobs: + licenses-check: + name: Licenses check + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Install all libs and dependencies + uses: ./.github/actions/install-all-build-libs + + - name: Install plugins dependencies + env: + pluginsOnlyInstall: 1 + run: yarn build:statics + + - name: Generate licenses csv files and send csv data to google sheet + env: + GOOGLE_ACCOUNT_SERVICE_KEY_BASE64: ${{ secrets.GOOGLE_ACCOUNT_SERVICE_KEY_BASE64 }} + GOOGLE_SPREADSHEET_DEPENDENCIES_ID: ${{ secrets.GOOGLE_SPREADSHEET_DEPENDENCIES_ID }} + run: | + npm i -g license-checker + echo "$GOOGLE_ACCOUNT_SERVICE_KEY_BASE64" | base64 -id > gasKey.json + SPREADSHEET_ID=$GOOGLE_SPREADSHEET_DEPENDENCIES_ID node .circleci/deps-licenses-report.js + + - uses: actions/upload-artifact@v4 + with: + name: licenses + path: licenses + if-no-files-found: error diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml new file mode 100644 index 0000000000..56833098ad --- /dev/null +++ b/.github/workflows/nightly.yml @@ -0,0 +1,9 @@ +name: Nightly jobs +on: + schedule: + - cron: '0 0 * * *' + +jobs: + virustotal-check: + uses: ./.github/workflows/virustotal.yml + secrets: inherit diff --git a/.github/workflows/pipeline-build-docker.yml b/.github/workflows/pipeline-build-docker.yml index 0747060f67..b85208ee4c 100644 --- a/.github/workflows/pipeline-build-docker.yml +++ b/.github/workflows/pipeline-build-docker.yml @@ -1,14 +1,20 @@ name: Build docker pipeline on: workflow_call: + inputs: + environment: + description: Environment for build + required: false + default: 'staging' + type: string jobs: build: - runs-on: ubuntu-24.04 name: Build doker job - + runs-on: ubuntu-24.04 + environment: ${{ inputs.environment }} steps: - - uses: actions/checkout@v4.1.0 + - uses: actions/checkout@v4 - name: Set up QEMU uses: docker/setup-qemu-action@v3 @@ -67,9 +73,37 @@ jobs: docker image save -o release/docker/docker-linux-alpine.amd64.tar redisinsight:amd64 docker image save -o release/docker/docker-linux-alpine.arm64.tar redisinsight:arm64 - - uses: actions/upload-artifact@v4.1.0 - name: Upload docker images + - uses: actions/upload-artifact@v4 + name: Upload docker amd64 images with: if-no-files-found: error - name: docker - path: ./release + name: docker-amd64 + path: ./release/docker/docker-linux-alpine.amd64.tar + + - uses: actions/upload-artifact@v4 + name: Upload docker arm64 images + with: + if-no-files-found: error + name: docker-arm64 + path: ./release/docker/docker-linux-alpine.arm64.tar + + env: + RI_AI_CONVAI_TOKEN: ${{ secrets.RI_AI_CONVAI_TOKEN }} + RI_AI_QUERY_PASS: ${{ secrets.RI_AI_QUERY_PASS }} + RI_AI_QUERY_USER: ${{ secrets.RI_AI_QUERY_USER }} + RI_CLOUD_API_URL: ${{ secrets.RI_CLOUD_API_URL }} + RI_CLOUD_CAPI_URL: ${{ secrets.RI_CLOUD_CAPI_URL }} + RI_CLOUD_IDP_AUTHORIZE_URL: ${{ secrets.RI_CLOUD_IDP_AUTHORIZE_URL }} + RI_CLOUD_IDP_CLIENT_ID: ${{ secrets.RI_CLOUD_IDP_CLIENT_ID }} + RI_CLOUD_IDP_GH_ID: ${{ secrets.RI_CLOUD_IDP_GH_ID }} + RI_CLOUD_IDP_GOOGLE_ID: ${{ secrets.RI_CLOUD_IDP_GOOGLE_ID }} + RI_CLOUD_IDP_ISSUER: ${{ secrets.RI_CLOUD_IDP_ISSUER }} + RI_CLOUD_IDP_REDIRECT_URI: ${{ secrets.RI_CLOUD_IDP_REDIRECT_URI }} + RI_CLOUD_IDP_TOKEN_URL: ${{ secrets.RI_CLOUD_IDP_TOKEN_URL }} + RI_SEGMENT_WRITE_KEY: ${{ secrets.RI_SEGMENT_WRITE_KEY }} + RI_SERVER_TLS_CERT: ${{ secrets.RI_SERVER_TLS_CERT }} + RI_SERVER_TLS_KEY: ${{ secrets.RI_SERVER_TLS_KEY }} + RI_FEATURES_CONFIG_URL: ${{ secrets.RI_FEATURES_CONFIG_URL }} + RI_UPGRADES_LINK: ${{ secrets.RI_UPGRADES_LINK }} + + diff --git a/.github/workflows/pipeline-build-linux.yml b/.github/workflows/pipeline-build-linux.yml index b167f4454d..ece1cc31c7 100644 --- a/.github/workflows/pipeline-build-linux.yml +++ b/.github/workflows/pipeline-build-linux.yml @@ -3,6 +3,12 @@ name: Build linux pipeline on: workflow_call: inputs: + environment: + description: Environment for build + required: false + default: 'staging' + type: string + target: description: Build target required: false @@ -11,11 +17,12 @@ on: jobs: build: - runs-on: ubuntu-24.04 name: Build linux job + runs-on: ubuntu-24.04 + environment: ${{ inputs.environment }} steps: - #TODO: some debug information + #TODO: some debug tools # - uses: crazy-max/ghaction-dump-context@v2 # - uses: hmarr/debug-action@v3 # ssh @@ -27,7 +34,7 @@ jobs: # limit-access-to-actor: true # limit-access-to-users: zalenskiSofteq - - uses: actions/checkout@v4.1.0 + - uses: actions/checkout@v4 - name: Install all libs and dependencies uses: ./.github/actions/install-all-build-libs @@ -52,15 +59,15 @@ jobs: run: yarn build:statics - name: Build linux packages (production) - if: vars.ENV == 'production' && inputs.target == 'all' + if: vars.ENV == 'production' && inputs.target == vars.ALL run: yarn package:prod - name: Build linux packages (staging) - if: (vars.ENV == 'staging' || vars.ENV == 'development') && inputs.target == 'all' + if: (vars.ENV == 'staging' || vars.ENV == 'development') && inputs.target == vars.ALL run: yarn package:stage - name: Build linux packages (development) - if: inputs.target != 'all' + if: inputs.target != vars.ALL run: | target="" if [ ${{ startsWith(inputs.target, 'linux:') }} == 'true' ]; then @@ -70,31 +77,56 @@ jobs: yarn package:stage --linux $target - - uses: actions/upload-artifact@v4.1.0 + - uses: actions/upload-artifact@v4 + name: Upload latest-linux.yml artifact + with: + name: linux-latest + path: | + ./release/latest-linux.yml + + - uses: actions/upload-artifact@v4 name: Upload AppImage artifact with: - name: 'linux-appimage-build' + name: linux-appimage-build path: | ./release/Redis-Insight*.AppImage - ./release/*-linux.yml - - uses: actions/upload-artifact@v4.1.0 + - uses: actions/upload-artifact@v4 name: Upload Deb artifact with: - name: 'linux-deb-build' + name: linux-deb-build path: | ./release/Redis-Insight*.deb - - uses: actions/upload-artifact@v4.1.0 + - uses: actions/upload-artifact@v4 name: Upload rpm artifacts with: - name: 'linux-rpm-build' + name: linux-rpm-build path: | ./release/Redis-Insight*.rpm - - uses: actions/upload-artifact@v4.1.0 + - uses: actions/upload-artifact@v4 name: Upload snap artifact with: - name: 'linux-snap-builds' + name: linux-snap-builds path: | ./release/Redis-Insight*.snap + + env: + RI_AI_CONVAI_TOKEN: ${{ secrets.RI_AI_CONVAI_TOKEN }} + RI_AI_QUERY_PASS: ${{ secrets.RI_AI_QUERY_PASS }} + RI_AI_QUERY_USER: ${{ secrets.RI_AI_QUERY_USER }} + RI_CLOUD_API_URL: ${{ secrets.RI_CLOUD_API_URL }} + RI_CLOUD_CAPI_URL: ${{ secrets.RI_CLOUD_CAPI_URL }} + RI_CLOUD_IDP_AUTHORIZE_URL: ${{ secrets.RI_CLOUD_IDP_AUTHORIZE_URL }} + RI_CLOUD_IDP_CLIENT_ID: ${{ secrets.RI_CLOUD_IDP_CLIENT_ID }} + RI_CLOUD_IDP_GH_ID: ${{ secrets.RI_CLOUD_IDP_GH_ID }} + RI_CLOUD_IDP_GOOGLE_ID: ${{ secrets.RI_CLOUD_IDP_GOOGLE_ID }} + RI_CLOUD_IDP_ISSUER: ${{ secrets.RI_CLOUD_IDP_ISSUER }} + RI_CLOUD_IDP_REDIRECT_URI: ${{ secrets.RI_CLOUD_IDP_REDIRECT_URI }} + RI_CLOUD_IDP_TOKEN_URL: ${{ secrets.RI_CLOUD_IDP_TOKEN_URL }} + RI_SEGMENT_WRITE_KEY: ${{ secrets.RI_SEGMENT_WRITE_KEY }} + RI_SERVER_TLS_CERT: ${{ secrets.RI_SERVER_TLS_CERT }} + RI_SERVER_TLS_KEY: ${{ secrets.RI_SERVER_TLS_KEY }} + RI_FEATURES_CONFIG_URL: ${{ secrets.RI_FEATURES_CONFIG_URL }} + RI_UPGRADES_LINK: ${{ secrets.RI_UPGRADES_LINK }} diff --git a/.github/workflows/pipeline-build-macos.yml b/.github/workflows/pipeline-build-macos.yml index 776930a1bb..5d92a381bd 100644 --- a/.github/workflows/pipeline-build-macos.yml +++ b/.github/workflows/pipeline-build-macos.yml @@ -2,6 +2,12 @@ name: Build macos pipeline on: workflow_call: inputs: + environment: + description: Environment for build + required: false + default: 'staging' + type: string + target: description: Build target required: false @@ -10,20 +16,11 @@ on: jobs: build: - runs-on: macos-14 name: Build macos job - env: - APPLE_ID: ${{ secrets.APPLE_ID }} - APPLE_ID_PASSWORD: ${{ secrets.APPLE_ID_PASSWORD }} - APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }} - APPLE_APP_SPECIFIC_PASSWORD: ${{ secrets.APPLE_APP_SPECIFIC_PASSWORD }} - USE_HARD_LINKS: ${{ vars.USE_HARD_LINKS }} - CSC_KEYCHAIN: ${{ vars.CSC_KEYCHAIN }} - CSC_IDENTITY_AUTO_DISCOVERY: ${{ vars.CSC_IDENTITY_AUTO_DISCOVERY }} - CSC_KEY_PASSWORD: ${{ secrets.CSC_KEY_PASSWORD }} - + runs-on: macos-14 + environment: ${{ inputs.environment }} steps: - - uses: actions/checkout@v4.1.0 + - uses: actions/checkout@v4 - name: Add certificates to the keychain uses: ./.github/actions/install-apple-certs @@ -45,7 +42,7 @@ jobs: run: yarn build:statics - name: Build macos dmg (prod) - if: vars.ENV == 'production' && inputs.target == 'all' + if: vars.ENV == 'production' && inputs.target == vars.ALL run: | unset CSC_LINK @@ -55,7 +52,7 @@ jobs: mv release/mas-universal/Redis-Insight-mac-universal-mas.pkg release/Redis-Insight-mac-universal-mas.pkg - name: Build macos dmg (staging) - if: (vars.ENV == 'staging' || vars.ENV == 'development') && inputs.target == 'all' + if: (vars.ENV == 'staging' || vars.ENV == 'development') && inputs.target == vars.ALL run: | unset CSC_LINK @@ -69,47 +66,76 @@ jobs: # handle manual builds - name: Build macos dmg (dev) - if: inputs.target != 'all' + if: inputs.target != vars.ALL run: | unset CSC_LINK yarn package:stage --mac ${{ inputs.target }} rm -rf release/mac - name: Repack dmg to tar - if: vars.ENV == 'staging' || vars.ENV == 'production' + if: vars.ENV == 'production' run: | ARCH=x64 ./.circleci/redisstack/dmg.repack.sh ARCH=arm64 ./.circleci/redisstack/dmg.repack.sh - name: Upload x64 packages - uses: actions/upload-artifact@v4.1.0 + uses: actions/upload-artifact@v4 + if: inputs.target == vars.ALL || endsWith(inputs.target, 'x64') with: - name: 'macos-x64-builds' + name: macos-x64-builds path: | ./release/Redis-Insight*x64.dmg - # ./release/Redis-Insight*x64.zip - # ./release/Redis-Insight*x64.dmg.blockmap + ./release/Redis-Insight*x64.dmg.blockmap - name: Upload ARM packages - uses: actions/upload-artifact@v4.1.0 + uses: actions/upload-artifact@v4 + if: inputs.target == vars.ALL || endsWith(inputs.target, 'arm64') with: - name: 'macos-arm-builds' + name: macos-arm-builds path: | ./release/Redis-Insight*arm64.dmg - # ./release/Redis-Insight*arm64.zip - # ./release/Redis-Insight*arm64.dmg.blockmap + ./release/Redis-Insight*arm64.dmg.blockmap - name: Upload MAS packages - uses: actions/upload-artifact@v4.1.0 + uses: actions/upload-artifact@v4 + if: inputs.target == vars.ALL with: - name: 'macos-mas-builds' + name: macos-mas-builds path: | ./release/Redis-Insight*.pkg - # ./release/*-mac.yml + ./release/*-mac.yml - name: Upload redis stack packages - uses: actions/upload-artifact@v4.1.0 + uses: actions/upload-artifact@v4 + if: vars.ENV == 'production' with: name: 'redistack-builds' path: | ./release/redisstack + + env: + APPLE_ID: ${{ secrets.APPLE_ID }} + APPLE_ID_PASSWORD: ${{ secrets.APPLE_ID_PASSWORD }} + APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }} + APPLE_APP_SPECIFIC_PASSWORD: ${{ secrets.APPLE_APP_SPECIFIC_PASSWORD }} + USE_HARD_LINKS: ${{ vars.USE_HARD_LINKS }} + CSC_KEYCHAIN: ${{ vars.CSC_KEYCHAIN }} + CSC_IDENTITY_AUTO_DISCOVERY: ${{ vars.CSC_IDENTITY_AUTO_DISCOVERY }} + CSC_KEY_PASSWORD: ${{ secrets.CSC_KEY_PASSWORD }} + RI_AI_CONVAI_TOKEN: ${{ secrets.RI_AI_CONVAI_TOKEN }} + RI_AI_QUERY_PASS: ${{ secrets.RI_AI_QUERY_PASS }} + RI_AI_QUERY_USER: ${{ secrets.RI_AI_QUERY_USER }} + RI_CLOUD_API_URL: ${{ secrets.RI_CLOUD_API_URL }} + RI_CLOUD_CAPI_URL: ${{ secrets.RI_CLOUD_CAPI_URL }} + RI_CLOUD_IDP_AUTHORIZE_URL: ${{ secrets.RI_CLOUD_IDP_AUTHORIZE_URL }} + RI_CLOUD_IDP_CLIENT_ID: ${{ secrets.RI_CLOUD_IDP_CLIENT_ID }} + RI_CLOUD_IDP_GH_ID: ${{ secrets.RI_CLOUD_IDP_GH_ID }} + RI_CLOUD_IDP_GOOGLE_ID: ${{ secrets.RI_CLOUD_IDP_GOOGLE_ID }} + RI_CLOUD_IDP_ISSUER: ${{ secrets.RI_CLOUD_IDP_ISSUER }} + RI_CLOUD_IDP_REDIRECT_URI: ${{ secrets.RI_CLOUD_IDP_REDIRECT_URI }} + RI_CLOUD_IDP_TOKEN_URL: ${{ secrets.RI_CLOUD_IDP_TOKEN_URL }} + RI_SEGMENT_WRITE_KEY: ${{ secrets.RI_SEGMENT_WRITE_KEY }} + RI_SERVER_TLS_CERT: ${{ secrets.RI_SERVER_TLS_CERT }} + RI_SERVER_TLS_KEY: ${{ secrets.RI_SERVER_TLS_KEY }} + RI_FEATURES_CONFIG_URL: ${{ secrets.RI_FEATURES_CONFIG_URL }} + RI_UPGRADES_LINK: ${{ secrets.RI_UPGRADES_LINK }} diff --git a/.github/workflows/pipeline-build-windows.yml b/.github/workflows/pipeline-build-windows.yml index 9b3dcbe060..1264ae72ca 100644 --- a/.github/workflows/pipeline-build-windows.yml +++ b/.github/workflows/pipeline-build-windows.yml @@ -1,17 +1,21 @@ name: Build windows pipeline on: workflow_call: + inputs: + environment: + description: Environment for build + required: false + default: 'staging' + type: string jobs: build: - runs-on: windows-2022 name: Build windows job - env: - WIN_CSC_LINK: ${{ secrets.WIN_CSC_LINK }} - WIN_CSC_KEY_PASSWORD: ${{ secrets.WIN_CSC_KEY_PASSWORD }} + runs-on: windows-2022 + environment: ${{ inputs.environment }} steps: - - uses: actions/checkout@v4.1.0 + - uses: actions/checkout@v4 - name: Install all libs and dependencies uses: ./.github/actions/install-all-build-libs @@ -38,11 +42,32 @@ jobs: rm -rf release/win-unpacked shell: bash - - uses: actions/upload-artifact@v4.1.0 + - uses: actions/upload-artifact@v4 with: - name: 'windows-builds' + name: windows-builds if-no-files-found: error path: | ./release/Redis-Insight*.exe ./release/Redis-Insight*.exe.blockmap ./release/*.yml + + env: + WIN_CSC_LINK: ${{ secrets.WIN_CSC_LINK }} + WIN_CSC_KEY_PASSWORD: ${{ secrets.WIN_CSC_KEY_PASSWORD }} + RI_AI_CONVAI_TOKEN: ${{ secrets.RI_AI_CONVAI_TOKEN }} + RI_AI_QUERY_PASS: ${{ secrets.RI_AI_QUERY_PASS }} + RI_AI_QUERY_USER: ${{ secrets.RI_AI_QUERY_USER }} + RI_CLOUD_API_URL: ${{ secrets.RI_CLOUD_API_URL }} + RI_CLOUD_CAPI_URL: ${{ secrets.RI_CLOUD_CAPI_URL }} + RI_CLOUD_IDP_AUTHORIZE_URL: ${{ secrets.RI_CLOUD_IDP_AUTHORIZE_URL }} + RI_CLOUD_IDP_CLIENT_ID: ${{ secrets.RI_CLOUD_IDP_CLIENT_ID }} + RI_CLOUD_IDP_GH_ID: ${{ secrets.RI_CLOUD_IDP_GH_ID }} + RI_CLOUD_IDP_GOOGLE_ID: ${{ secrets.RI_CLOUD_IDP_GOOGLE_ID }} + RI_CLOUD_IDP_ISSUER: ${{ secrets.RI_CLOUD_IDP_ISSUER }} + RI_CLOUD_IDP_REDIRECT_URI: ${{ secrets.RI_CLOUD_IDP_REDIRECT_URI }} + RI_CLOUD_IDP_TOKEN_URL: ${{ secrets.RI_CLOUD_IDP_TOKEN_URL }} + RI_SEGMENT_WRITE_KEY: ${{ secrets.RI_SEGMENT_WRITE_KEY }} + RI_SERVER_TLS_CERT: ${{ secrets.RI_SERVER_TLS_CERT }} + RI_SERVER_TLS_KEY: ${{ secrets.RI_SERVER_TLS_KEY }} + RI_FEATURES_CONFIG_URL: ${{ secrets.RI_FEATURES_CONFIG_URL }} + RI_UPGRADES_LINK: ${{ secrets.RI_UPGRADES_LINK }} diff --git a/.github/workflows/release-docker.yml b/.github/workflows/release-docker.yml new file mode 100644 index 0000000000..73a8098e50 --- /dev/null +++ b/.github/workflows/release-docker.yml @@ -0,0 +1,41 @@ +name: Release docker images + +on: + workflow_call: + +jobs: + publish: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Publish docker + env: + DOCKER_USER: ${{ secrets.DOCKER_USER }} + DOCKER_PASS: ${{ secrets.DOCKER_PASS }} + DOCKER_V1_USER: ${{ secrets.DOCKER_V1_USER }} + DOCKER_REPO: ${{ secrets.DOCKER_REPO }} + DOCKER_V1_REPO: ${{ secrets.DOCKER_V1_REPO }} + run: | + appVersion=$(jq -r '.version' redisinsight/package.json) + + docker login -u $DOCKER_USER -p $DOCKER_PASS + + ./.circleci/build/release-docker.sh \ + -d redisinsight \ + -r $DOCKER_REPO \ + -v $appVersion + + docker login -u $DOCKER_V1_USER -p $DOCKER_V1_PASS + + ./.circleci/build/release-docker.sh \ + -d redisinsight \ + -r $DOCKER_V1_REPO \ + -v $appVersion + + # - uses: actions/upload-artifact@v4 + # with: + # name: licenses + # path: licenses + # if-no-files-found: error + diff --git a/.github/workflows/release-prod.yml b/.github/workflows/release-prod.yml new file mode 100644 index 0000000000..8ac4bd4b3e --- /dev/null +++ b/.github/workflows/release-prod.yml @@ -0,0 +1,55 @@ +name: Release (prod) + +on: + push: + branches: + - 'latest' + # todo: remove after test + - 'test/prod/**' + +jobs: + tests-prod: + name: Run all tests + uses: ./.github/workflows/tests.yml + secrets: inherit + with: + all_tests: true + + builds-prod: + name: Create all builds for release + uses: ./.github/workflows/build.yml + needs: tests-prod + secrets: inherit + with: + environment: 'production' + target: 'all' + + virustotal-prod: + name: Check builds via virustotal + uses: ./.github/workflows/virustotal.yml + needs: builds-prod + secrets: inherit + with: + skip_report: true + + aws-prod: + name: Realse to AWS S3 + uses: ./.github/workflows/aws.yml + needs: virustotal-prod + secrets: inherit + + # todo: uncomment + # docker-prod: + # name: Release docker images + # uses: ./.github/workflows/release-docker.yml + # needs: aws-prod + # secrets: inherit + + # todo: e2e tests for release stage + # e2e-linux: + # uses: ./.github/workflows/build.yml + # needs: builds-prod + # secrets: inherit + # with: + # environment: 'staging' + # target: 'all' diff --git a/.github/workflows/release-stage.yml b/.github/workflows/release-stage.yml new file mode 100644 index 0000000000..9028fa5459 --- /dev/null +++ b/.github/workflows/release-stage.yml @@ -0,0 +1,40 @@ +name: Release (stage) + +on: + push: + branches: + - 'release/**' + # todo: remove after tests + - 'test/release/**' + +jobs: + tests: + name: Release stage tests + uses: ./.github/workflows/tests.yml + secrets: inherit + with: + all_tests: true + + builds: + name: Release stage builds + uses: ./.github/workflows/build.yml + needs: tests + secrets: inherit + with: + environment: 'staging' + target: 'all' + + + # todo: e2e tests for release stage + # e2e-linux: + # uses: ./.github/workflows/build.yml + # needs: builds + # secrets: inherit + # with: + # environment: 'staging' + # target: 'all' + + + + + diff --git a/.github/workflows/tests-backend.yml b/.github/workflows/tests-backend.yml index b9103d9ae1..d0ae3ff2d1 100644 --- a/.github/workflows/tests-backend.yml +++ b/.github/workflows/tests-backend.yml @@ -16,7 +16,7 @@ jobs: name: Unit tests Backend job runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4.1.0 + - uses: actions/checkout@v4 - name: Install all libs and dependencies for BE uses: ./.github/actions/install-all-build-libs diff --git a/.github/workflows/tests-frontend.yml b/.github/workflows/tests-frontend.yml index 71468608fe..0982632d12 100644 --- a/.github/workflows/tests-frontend.yml +++ b/.github/workflows/tests-frontend.yml @@ -10,7 +10,7 @@ jobs: runs-on: ubuntu-latest name: Unit tests Frontend job steps: - - uses: actions/checkout@v4.1.0 + - uses: actions/checkout@v4 - name: Install all libs and dependencies uses: ./.github/actions/install-all-build-libs diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 5d7165b690..7d752b306c 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -7,7 +7,15 @@ on: workflow_dispatch: inputs: - all-tests: + all_tests: + description: Run all tests (FE, BE, IT, E2E) + type: boolean + required: false + default: false + + workflow_call: + inputs: + all_tests: description: Run all tests (FE, BE, IT, E2E) type: boolean required: false @@ -22,7 +30,7 @@ jobs: desktop: ${{ steps.filter.outputs.desktop }} e2e: ${{ steps.filter.outputs.e2e }} steps: - - uses: actions/checkout@v4.1.0 + - uses: actions/checkout@v4 - uses: dorny/paths-filter@v3.0.2 id: filter with: @@ -41,14 +49,14 @@ jobs: # TODO: concurrency # concurrency: build needs: changes - if: needs.changes.outputs.frontend == 'true' || inputs.all-tests + if: needs.changes.outputs.frontend == 'true' || inputs.all_tests uses: ./.github/workflows/tests-frontend.yml - # secrets: inherit + secrets: inherit backend-tests: # TODO: concurrency # concurrency: build needs: changes - if: needs.changes.outputs.backend == 'true' || inputs.all-tests + if: needs.changes.outputs.backend == 'true' || inputs.all_tests uses: ./.github/workflows/tests-backend.yml - # secrets: inherit + secrets: inherit diff --git a/.github/workflows/virustotal.yml b/.github/workflows/virustotal.yml new file mode 100644 index 0000000000..f85e326864 --- /dev/null +++ b/.github/workflows/virustotal.yml @@ -0,0 +1,168 @@ +name: Virustotal Analyze + +on: + workflow_call: + inputs: + skip_report: + description: Skip report + required: false + default: false + type: boolean + +env: + VIRUSTOTAL_FILE_NAMES: ${{ vars.VIRUSTOTAL_FILE_NAMES }} + VIRUSTOTAL_API_KEY: ${{ secrets.VIRUSTOTAL_API_KEY }} + + # TODO: test on other slack chat + # SLACK_TEST_REPORT_KEY: ${{ secrets.SLACK_TEST_REPORT_KEY }} + +jobs: + download_artifacts: + runs-on: ubuntu-latest + outputs: + artifact_names: ${{ steps.list_artifacts.outputs.artifact_names }} + artifact_exists: ${{ steps.list_artifacts.outputs.artifact_exists }} + steps: + - name: Checkout Repository + uses: actions/checkout@v4 + + - name: Download All Artifacts + # TODO: Update to v4 after fix this issue: + # https://github.com/nektos/act/issues/2433 + uses: actions/download-artifact@v3 + with: + path: ./release + # pattern: '*-build' + # merge-multiple: true + + - run: ls -R ./release + + - name: List Artifact Files + id: list_artifacts + run: | + # If artifacts don't exist put array of app names for url check + if [ ! -d "./release" ]; then + echo "NO REALEASE FOLDER ${VIRUSTOTAL_FILE_NAMES}" + echo "artifact_exists=false" >> $GITHUB_OUTPUT + echo "artifact_names=$VIRUSTOTAL_FILE_NAMES" >> $GITHUB_OUTPUT + exit 0; + fi + + # Get list of artifacts + ARTIFACTS=$(ls ./release) + + # Conver list to json + ARTIFACTS_JSON=$(echo "$ARTIFACTS" | jq -R -s -c 'split("\n")[:-1]') + + echo "artifact_exists=true" >> $GITHUB_OUTPUT + echo "artifact_names=$ARTIFACTS_JSON" >> $GITHUB_OUTPUT + + analyze: + name: Analyze file + runs-on: ubuntu-latest + needs: download_artifacts + + strategy: + matrix: + artifact: ${{ fromJson(needs.download_artifacts.outputs.artifact_names) }} + + steps: + - name: Download Artifact ${{ matrix.artifact }} + if: needs.download_artifacts.outputs.artifact_exists == 'true' + # TODO: Update to v4 after fix this issue: + # https://github.com/nektos/act/issues/2433 + uses: actions/download-artifact@v3 + with: + name: ${{ matrix.artifact }} + path: ./release + + - name: Send File to scan + if: needs.download_artifacts.outputs.artifact_exists == 'true' + run: | + uploadFile="./release/${{ matrix.artifact }}.zip" + uploadUrl=$(curl -sq -XGET https://www.virustotal.com/api/v3/files/upload_url -H "x-apikey: $VIRUSTOTAL_API_KEY" | jq -r '.data') + + echo "File to upload: ${uploadFile}" + analysedId=$(curl -sq -XPOST "${uploadUrl}" -H "x-apikey: $VIRUSTOTAL_API_KEY" --form file=@"${uploadFile}" | jq -r '.data.id') + + if [ $analysedId == "null" ]; then + echo 'Status is null, something went wrong'; + exit 1; + fi + + echo "ANALYZED_ID=$analysedId" >> $GITHUB_ENV + echo "BUILD_NAME=${{ matrix.artifact }}" >> $GITHUB_ENV + + - name: Send Url to scan + if: needs.download_artifacts.outputs.artifact_exists == 'false' + run: | + url="https://download.redisinsight.redis.com/latest/${{ matrix.artifact }}" + + echo "Url to check: ${url}" + + analysedId=$(curl -sq -XPOST https://www.virustotal.com/api/v3/urls -H "x-apikey: $VIRUSTOTAL_API_KEY" --form url=${url} | jq -r '.data.id') + + if [ $analysedId == "null" ]; then + echo 'Status is null, something went wrong'; + exit 1; + fi + + echo "ANALYZED_ID=$analysedId" >> $GITHUB_ENV + + - name: Check analyze status + run: | + echo "Virustotal Analyzed id: ${ANALYZED_ID}" + countOperations="50" + intervalTime=30 + + until [ "$countOperations" == "0" ]; do + if [ "$analyzeStatus" == "completed" ] + then + echo "Current status: ${analyzeStatus}"; break; + else + echo "Current status: ${analyzeStatus}, retries left: ${countOperations} "; + analyzeStatus=$(curl -sq -XGET https://www.virustotal.com/api/v3/analyses/${ANALYZED_ID} -H "x-apikey: $VIRUSTOTAL_API_KEY" | jq -r '.data.attributes.status'); + + sleep $intervalTime; + countOperations=$[$countOperations - 1]; + fi + done + + if [ "$analyzeStatus" != "completed" ]; then + echo 'Analyse is not completed'; + exit 1; + fi + + - name: Validate analyze + id: validate + run: | + analyzeStats=$(curl -sq -XGET https://www.virustotal.com/api/v3/analyses/${ANALYZED_ID} -H "x-apikey: $VIRUSTOTAL_API_KEY" | jq -r '.data.attributes.stats') + analazedHarmless=$(echo ${analyzeStats} | jq '.harmless') + analazedMalicious=$(echo ${analyzeStats} | jq '.malicious') + analazedSuspicious=$(echo ${analyzeStats} | jq '.suspicious') + + echo "Results:" + echo "analazedMalicious: ${analazedMalicious}, analazedSuspicious: ${analazedSuspicious}, analazedHarmless: ${analazedHarmless}" + + if [ "$analazedMalicious" != "0" ] || [ "$analazedSuspicious" != "0" ]; then + echo "export FAILED=true" >> $GITHUB_ENV + echo 'Found dangers'; + fi + + echo "export FAILED=false" >> $GITHUB_ENV + echo "export skip_report=true" >> $GITHUB_ENV + echo 'Passed'; + + - name: Send Report + if: ${{ !steps.validate.outputs.skip_report && !inputs.skip_report }} + run: | + FILE_NAME=virustotal.report.json + BUILD_NAME=$BUILD_NAME FILE_NAME=$FILE_NAME VIRUS_CHECK_FAILED=$FAILED node .github/virustotal-report.js + + # BUILD_NAME=$BUILD_NAME FILE_NAME=$FILE_NAME VIRUS_CHECK_FAILED=$FAILED node .github/virustotal-report.js && + # curl -H "Content-type: application/json" --data @$FILE_NAME -H "Authorization: Bearer ${SLACK_TEST_REPORT_KEY}" -X POST https://slack.com/api/chat.postMessage + + if [ "$FAILED" == "true" ]; then + echo 'Found dangers'; + exit 1; + fi diff --git a/.github/workflows/weekly.yml b/.github/workflows/weekly.yml new file mode 100644 index 0000000000..c8c6f28f89 --- /dev/null +++ b/.github/workflows/weekly.yml @@ -0,0 +1,9 @@ +name: Weekly jobs +on: + schedule: + - cron: 0 0 * * 1 + +jobs: + licenses-check: + uses: ./.github/workflows/licenses-check.yml + secrets: inherit From 2738e33b1dc7ef289560843fd700d6d56e34a05e Mon Sep 17 00:00:00 2001 From: zalenskiSofteq Date: Wed, 16 Oct 2024 22:02:44 +0200 Subject: [PATCH 195/256] #RI-6213 - Migrate release workflows from CircleCI to Github Actions --- .github/workflows/aws.yml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/aws.yml b/.github/workflows/aws.yml index 2c7c1991fc..50ab0ffc75 100644 --- a/.github/workflows/aws.yml +++ b/.github/workflows/aws.yml @@ -19,12 +19,12 @@ jobs: steps: - uses: actions/checkout@v4 - - name: Configure AWS Credentials - uses: aws-actions/configure-aws-credentials@v4 - with: - aws-region: ${{ secrets.AWS_REGION }} - aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} - aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + # - name: Configure AWS Credentials + # uses: aws-actions/configure-aws-credentials@v4 + # with: + # aws-region: ${{ secrets.AWS_REGION }} + # aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} + # aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} - name: Download All Artifacts uses: actions/download-artifact@v3 From 90534056e037e4ff8ebc4f11afac6f84482e4c9f Mon Sep 17 00:00:00 2001 From: zalenskiSofteq Date: Wed, 16 Oct 2024 23:21:41 +0200 Subject: [PATCH 196/256] #RI-6213 - Migrate release workflows from CircleCI to Github Actions --- .github/workflows/pipeline-build-docker.yml | 2 +- .github/workflows/pipeline-build-linux.yml | 2 +- .github/workflows/pipeline-build-macos.yml | 2 +- .github/workflows/pipeline-build-windows.yml | 2 +- .github/workflows/release-prod.yml | 2 +- .github/workflows/tests-backend.yml | 2 +- .github/workflows/tests-frontend.yml | 2 +- .github/workflows/virustotal.yml | 1 + 8 files changed, 8 insertions(+), 7 deletions(-) diff --git a/.github/workflows/pipeline-build-docker.yml b/.github/workflows/pipeline-build-docker.yml index b85208ee4c..0cbce079b5 100644 --- a/.github/workflows/pipeline-build-docker.yml +++ b/.github/workflows/pipeline-build-docker.yml @@ -10,7 +10,7 @@ on: jobs: build: - name: Build doker job + name: Build docker runs-on: ubuntu-24.04 environment: ${{ inputs.environment }} steps: diff --git a/.github/workflows/pipeline-build-linux.yml b/.github/workflows/pipeline-build-linux.yml index ece1cc31c7..87f10b7264 100644 --- a/.github/workflows/pipeline-build-linux.yml +++ b/.github/workflows/pipeline-build-linux.yml @@ -17,7 +17,7 @@ on: jobs: build: - name: Build linux job + name: Build linux runs-on: ubuntu-24.04 environment: ${{ inputs.environment }} diff --git a/.github/workflows/pipeline-build-macos.yml b/.github/workflows/pipeline-build-macos.yml index 5d92a381bd..4acc4fa615 100644 --- a/.github/workflows/pipeline-build-macos.yml +++ b/.github/workflows/pipeline-build-macos.yml @@ -16,7 +16,7 @@ on: jobs: build: - name: Build macos job + name: Build macos runs-on: macos-14 environment: ${{ inputs.environment }} steps: diff --git a/.github/workflows/pipeline-build-windows.yml b/.github/workflows/pipeline-build-windows.yml index 1264ae72ca..9971ace9c1 100644 --- a/.github/workflows/pipeline-build-windows.yml +++ b/.github/workflows/pipeline-build-windows.yml @@ -10,7 +10,7 @@ on: jobs: build: - name: Build windows job + name: Build windows runs-on: windows-2022 environment: ${{ inputs.environment }} diff --git a/.github/workflows/release-prod.yml b/.github/workflows/release-prod.yml index 8ac4bd4b3e..f23dd03818 100644 --- a/.github/workflows/release-prod.yml +++ b/.github/workflows/release-prod.yml @@ -25,7 +25,7 @@ jobs: target: 'all' virustotal-prod: - name: Check builds via virustotal + name: Virustotal uses: ./.github/workflows/virustotal.yml needs: builds-prod secrets: inherit diff --git a/.github/workflows/tests-backend.yml b/.github/workflows/tests-backend.yml index d0ae3ff2d1..ddd7a41005 100644 --- a/.github/workflows/tests-backend.yml +++ b/.github/workflows/tests-backend.yml @@ -13,7 +13,7 @@ env: jobs: unit-tests: - name: Unit tests Backend job + name: Backend tests runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 diff --git a/.github/workflows/tests-frontend.yml b/.github/workflows/tests-frontend.yml index 0982632d12..c8969414d4 100644 --- a/.github/workflows/tests-frontend.yml +++ b/.github/workflows/tests-frontend.yml @@ -8,7 +8,7 @@ env: jobs: unit-tests: runs-on: ubuntu-latest - name: Unit tests Frontend job + name: Frontend tests steps: - uses: actions/checkout@v4 diff --git a/.github/workflows/virustotal.yml b/.github/workflows/virustotal.yml index f85e326864..fcea19b534 100644 --- a/.github/workflows/virustotal.yml +++ b/.github/workflows/virustotal.yml @@ -18,6 +18,7 @@ env: jobs: download_artifacts: + name: Download artifacts runs-on: ubuntu-latest outputs: artifact_names: ${{ steps.list_artifacts.outputs.artifact_names }} From 033d7f896cb9e7fdc8f8bbc30ce7508e71a05231 Mon Sep 17 00:00:00 2001 From: zalenskiSofteq Date: Wed, 16 Oct 2024 23:42:38 +0200 Subject: [PATCH 197/256] #RI-6213 - Migrate release workflows from CircleCI to Github Actions --- .github/workflows/aws.yml | 2 +- .github/workflows/virustotal.yml | 25 ++++++++++++++++--------- 2 files changed, 17 insertions(+), 10 deletions(-) diff --git a/.github/workflows/aws.yml b/.github/workflows/aws.yml index 50ab0ffc75..6fd73d2df2 100644 --- a/.github/workflows/aws.yml +++ b/.github/workflows/aws.yml @@ -27,7 +27,7 @@ jobs: # aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} - name: Download All Artifacts - uses: actions/download-artifact@v3 + uses: actions/download-artifact@v4 with: path: ./release diff --git a/.github/workflows/virustotal.yml b/.github/workflows/virustotal.yml index fcea19b534..9c3bc0ea04 100644 --- a/.github/workflows/virustotal.yml +++ b/.github/workflows/virustotal.yml @@ -28,11 +28,11 @@ jobs: uses: actions/checkout@v4 - name: Download All Artifacts - # TODO: Update to v4 after fix this issue: - # https://github.com/nektos/act/issues/2433 - uses: actions/download-artifact@v3 + uses: actions/download-artifact@v4 with: path: ./release + # TODO: enable pattern filter after fix: + # https://github.com/nektos/act/issues/2433 # pattern: '*-build' # merge-multiple: true @@ -70,9 +70,7 @@ jobs: steps: - name: Download Artifact ${{ matrix.artifact }} if: needs.download_artifacts.outputs.artifact_exists == 'true' - # TODO: Update to v4 after fix this issue: - # https://github.com/nektos/act/issues/2433 - uses: actions/download-artifact@v3 + uses: actions/download-artifact@v4 with: name: ${{ matrix.artifact }} path: ./release @@ -80,11 +78,18 @@ jobs: - name: Send File to scan if: needs.download_artifacts.outputs.artifact_exists == 'true' run: | - uploadFile="./release/${{ matrix.artifact }}.zip" + uploadZipFile="./release/${{ matrix.artifact }}.zip" + + # Compress artifactes + zip -r "${uploadZipFile}" "./release/${{ matrix.artifact }}" + + # Generate url to download zip file uploadUrl=$(curl -sq -XGET https://www.virustotal.com/api/v3/files/upload_url -H "x-apikey: $VIRUSTOTAL_API_KEY" | jq -r '.data') - echo "File to upload: ${uploadFile}" - analysedId=$(curl -sq -XPOST "${uploadUrl}" -H "x-apikey: $VIRUSTOTAL_API_KEY" --form file=@"${uploadFile}" | jq -r '.data.id') + echo "File to upload: ${uploadZipFile}" + + # Upload zip file to VirusTotal + analysedId=$(curl -sq -XPOST "${uploadUrl}" -H "x-apikey: $VIRUSTOTAL_API_KEY" --form file=@"${uploadZipFile}" | jq -r '.data.id') if [ $analysedId == "null" ]; then echo 'Status is null, something went wrong'; @@ -101,6 +106,7 @@ jobs: echo "Url to check: ${url}" + # Upload Url to VirusTotal analysedId=$(curl -sq -XPOST https://www.virustotal.com/api/v3/urls -H "x-apikey: $VIRUSTOTAL_API_KEY" --form url=${url} | jq -r '.data.id') if [ $analysedId == "null" ]; then @@ -160,6 +166,7 @@ jobs: FILE_NAME=virustotal.report.json BUILD_NAME=$BUILD_NAME FILE_NAME=$FILE_NAME VIRUS_CHECK_FAILED=$FAILED node .github/virustotal-report.js + # todo uncomment after testing # BUILD_NAME=$BUILD_NAME FILE_NAME=$FILE_NAME VIRUS_CHECK_FAILED=$FAILED node .github/virustotal-report.js && # curl -H "Content-type: application/json" --data @$FILE_NAME -H "Authorization: Bearer ${SLACK_TEST_REPORT_KEY}" -X POST https://slack.com/api/chat.postMessage From 1e8b6131bd9e1496e1a1925cd561307afc2bb394 Mon Sep 17 00:00:00 2001 From: zalenskiSofteq Date: Thu, 17 Oct 2024 00:35:41 +0200 Subject: [PATCH 198/256] #RI-6213 - Migrate release workflows from CircleCI to Github Actions --- .github/workflows/release-prod.yml | 16 +++++++++------- .github/workflows/virustotal.yml | 4 ++-- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/.github/workflows/release-prod.yml b/.github/workflows/release-prod.yml index f23dd03818..f1206ad979 100644 --- a/.github/workflows/release-prod.yml +++ b/.github/workflows/release-prod.yml @@ -8,17 +8,18 @@ on: - 'test/prod/**' jobs: - tests-prod: - name: Run all tests - uses: ./.github/workflows/tests.yml - secrets: inherit - with: - all_tests: true + # todo uncomment + # tests-prod: + # name: Run all tests + # uses: ./.github/workflows/tests.yml + # secrets: inherit + # with: + # all_tests: true builds-prod: name: Create all builds for release uses: ./.github/workflows/build.yml - needs: tests-prod + # needs: tests-prod secrets: inherit with: environment: 'production' @@ -35,6 +36,7 @@ jobs: aws-prod: name: Realse to AWS S3 uses: ./.github/workflows/aws.yml + if: ${{ always() }} needs: virustotal-prod secrets: inherit diff --git a/.github/workflows/virustotal.yml b/.github/workflows/virustotal.yml index 9c3bc0ea04..442c020fa6 100644 --- a/.github/workflows/virustotal.yml +++ b/.github/workflows/virustotal.yml @@ -78,10 +78,10 @@ jobs: - name: Send File to scan if: needs.download_artifacts.outputs.artifact_exists == 'true' run: | - uploadZipFile="./release/${{ matrix.artifact }}.zip" + uploadZipFile="./${{ matrix.artifact }}.zip" # Compress artifactes - zip -r "${uploadZipFile}" "./release/${{ matrix.artifact }}" + zip -r "${uploadZipFile}" "./release" # Generate url to download zip file uploadUrl=$(curl -sq -XGET https://www.virustotal.com/api/v3/files/upload_url -H "x-apikey: $VIRUSTOTAL_API_KEY" | jq -r '.data') From 2277f536c687b5178174c1ffad00732fb03e2c5a Mon Sep 17 00:00:00 2001 From: zalenskiSofteq Date: Thu, 17 Oct 2024 00:35:53 +0200 Subject: [PATCH 199/256] #RI-6213 - Migrate release workflows from CircleCI to Github Actions --- .circleci/build/build.sh | 3 ++- .github/workflows/pipeline-build-linux.yml | 5 +++-- .github/workflows/pipeline-build-macos.yml | 5 +++-- .github/workflows/pipeline-build-windows.yml | 5 +++-- 4 files changed, 11 insertions(+), 7 deletions(-) diff --git a/.circleci/build/build.sh b/.circleci/build/build.sh index 907587ced2..258a137b00 100755 --- a/.circleci/build/build.sh +++ b/.circleci/build/build.sh @@ -7,6 +7,7 @@ yarn --cwd redisinsight/api # build -yarn build:statics +# todo uncomment +# yarn build:statics yarn build:ui yarn --cwd ./redisinsight/api build:prod diff --git a/.github/workflows/pipeline-build-linux.yml b/.github/workflows/pipeline-build-linux.yml index 87f10b7264..c4855de724 100644 --- a/.github/workflows/pipeline-build-linux.yml +++ b/.github/workflows/pipeline-build-linux.yml @@ -55,8 +55,9 @@ jobs: # path: "." # - run: cp ./electron/package.json ./redisinsight/ - - name: Install plugins dependencies and build plugins - run: yarn build:statics + # todo uncomment + # - name: Install plugins dependencies and build plugins + # run: yarn build:statics - name: Build linux packages (production) if: vars.ENV == 'production' && inputs.target == vars.ALL diff --git a/.github/workflows/pipeline-build-macos.yml b/.github/workflows/pipeline-build-macos.yml index 4acc4fa615..4f2c43d764 100644 --- a/.github/workflows/pipeline-build-macos.yml +++ b/.github/workflows/pipeline-build-macos.yml @@ -38,8 +38,9 @@ jobs: keytar-host-mirror: ${{ secrets.NPM_CONFIG_KEYTAR_BINARY_HOST_MIRROR }} sqlite3-host-mirror: ${{ secrets.NPM_CONFIG_NODE_SQLITE3_BINARY_HOST_MIRROR }} - - name: Install plugins dependencies and build plugins - run: yarn build:statics + # todo uncomment + # - name: Install plugins dependencies and build plugins + # run: yarn build:statics - name: Build macos dmg (prod) if: vars.ENV == 'production' && inputs.target == vars.ALL diff --git a/.github/workflows/pipeline-build-windows.yml b/.github/workflows/pipeline-build-windows.yml index 9971ace9c1..4ce2a11557 100644 --- a/.github/workflows/pipeline-build-windows.yml +++ b/.github/workflows/pipeline-build-windows.yml @@ -25,8 +25,9 @@ jobs: with: WIN_CSC_PFX_BASE64: ${{ secrets.WIN_CSC_PFX_BASE64 }} - - name: Install plugins dependencies and build plugins - run: yarn build:statics:win + # todo uncomment + # - name: Install plugins dependencies and build plugins + # run: yarn build:statics:win - name: Build windows exe (production) if: vars.ENV == 'production' From c57a851bcbda6b4a4c0ab39ce8c81b7b528d1eef Mon Sep 17 00:00:00 2001 From: zalenskiSofteq Date: Thu, 17 Oct 2024 01:07:46 +0200 Subject: [PATCH 200/256] #RI-6213 - Migrate release workflows from CircleCI to Github Actions --- .github/workflows/aws.yml | 4 +++- .github/workflows/pipeline-build-linux.yml | 8 +------- .github/workflows/release-prod.yml | 17 +++++++++-------- 3 files changed, 13 insertions(+), 16 deletions(-) diff --git a/.github/workflows/aws.yml b/.github/workflows/aws.yml index 6fd73d2df2..b6328dd400 100644 --- a/.github/workflows/aws.yml +++ b/.github/workflows/aws.yml @@ -10,7 +10,7 @@ env: AWS_DISTRIBUTION_ID: ${{ secrets.AWS_DISTRIBUTION_ID }} AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} - + AWS_DEFAULT_REGION: ${{ secrets.AWS_DEFAULT_REGION }} jobs: release-private: @@ -31,6 +31,8 @@ jobs: with: path: ./release + - run: ls -R ./release + - name: Publish private run: | chmod +x .circleci/build/sum_sha256.sh diff --git a/.github/workflows/pipeline-build-linux.yml b/.github/workflows/pipeline-build-linux.yml index c4855de724..58dc8dd10e 100644 --- a/.github/workflows/pipeline-build-linux.yml +++ b/.github/workflows/pipeline-build-linux.yml @@ -78,13 +78,6 @@ jobs: yarn package:stage --linux $target - - uses: actions/upload-artifact@v4 - name: Upload latest-linux.yml artifact - with: - name: linux-latest - path: | - ./release/latest-linux.yml - - uses: actions/upload-artifact@v4 name: Upload AppImage artifact with: @@ -112,6 +105,7 @@ jobs: name: linux-snap-builds path: | ./release/Redis-Insight*.snap + ./release/latest-linux.yml env: RI_AI_CONVAI_TOKEN: ${{ secrets.RI_AI_CONVAI_TOKEN }} diff --git a/.github/workflows/release-prod.yml b/.github/workflows/release-prod.yml index f1206ad979..5fcd253d63 100644 --- a/.github/workflows/release-prod.yml +++ b/.github/workflows/release-prod.yml @@ -25,19 +25,20 @@ jobs: environment: 'production' target: 'all' - virustotal-prod: - name: Virustotal - uses: ./.github/workflows/virustotal.yml - needs: builds-prod - secrets: inherit - with: - skip_report: true + # virustotal-prod: + # name: Virustotal + # uses: ./.github/workflows/virustotal.yml + # needs: builds-prod + # secrets: inherit + # with: + # skip_report: true aws-prod: name: Realse to AWS S3 uses: ./.github/workflows/aws.yml if: ${{ always() }} - needs: virustotal-prod + # needs: virustotal-prod + needs: builds-prod secrets: inherit # todo: uncomment From cc56005169575eceebf5b38a7b06150751e289b6 Mon Sep 17 00:00:00 2001 From: zalenskiSofteq Date: Thu, 17 Oct 2024 08:50:02 +0200 Subject: [PATCH 201/256] #RI-6213 - Migrate release workflows from CircleCI to Github Actions --- .github/workflows/aws.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.github/workflows/aws.yml b/.github/workflows/aws.yml index b6328dd400..943b646c2b 100644 --- a/.github/workflows/aws.yml +++ b/.github/workflows/aws.yml @@ -44,8 +44,6 @@ jobs: release-public: name: Release s3 public runs-on: ubuntu-latest - # todo: remove after test - if: ${{ '1' == '2' }} needs: 'release-private' environment: 'production-approve' steps: From dc189704b90c7b5d975d14228cf5fcaa67c58b3f Mon Sep 17 00:00:00 2001 From: zalenskiSofteq Date: Thu, 17 Oct 2024 09:22:11 +0200 Subject: [PATCH 202/256] #RI-6213 - Migrate release workflows from CircleCI to Github Actions --- .github/workflows/aws.yml | 25 +++++++++++++++------ .github/workflows/pipeline-build-docker.yml | 19 +++++++++++----- 2 files changed, 31 insertions(+), 13 deletions(-) diff --git a/.github/workflows/aws.yml b/.github/workflows/aws.yml index 943b646c2b..e760f0380a 100644 --- a/.github/workflows/aws.yml +++ b/.github/workflows/aws.yml @@ -19,13 +19,6 @@ jobs: steps: - uses: actions/checkout@v4 - # - name: Configure AWS Credentials - # uses: aws-actions/configure-aws-credentials@v4 - # with: - # aws-region: ${{ secrets.AWS_REGION }} - # aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} - # aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} - - name: Download All Artifacts uses: actions/download-artifact@v4 with: @@ -35,6 +28,24 @@ jobs: - name: Publish private run: | + + # Define array of folders to exclude + exclude=("web" "web-mini", "redis-stack", "docker") + + # Iterate through first-level directories + for dir in */; do + dir_name=$(basename "$dir") + + # Check if the directory is not in the exclude list + if [[ ! " ${exclude[@]} " =~ " ${dir_name} " ]]; then + # Move all files from the subdirectory to the root directory + mv "$dir"* ./ + + # Remove the now-empty subdirectory + rmdir "$dir" + fi + done + chmod +x .circleci/build/sum_sha256.sh .circleci/build/sum_sha256.sh applicationVersion=$(jq -r '.version' redisinsight/package.json) diff --git a/.github/workflows/pipeline-build-docker.yml b/.github/workflows/pipeline-build-docker.yml index 0cbce079b5..55bc8e08c9 100644 --- a/.github/workflows/pipeline-build-docker.yml +++ b/.github/workflows/pipeline-build-docker.yml @@ -74,18 +74,25 @@ jobs: docker image save -o release/docker/docker-linux-alpine.arm64.tar redisinsight:arm64 - uses: actions/upload-artifact@v4 - name: Upload docker amd64 images + name: Upload docker images with: if-no-files-found: error - name: docker-amd64 - path: ./release/docker/docker-linux-alpine.amd64.tar + name: docker + path: ./release/docker/docker-linux-alpine.*64.tar - uses: actions/upload-artifact@v4 - name: Upload docker arm64 images + name: Upload web-mini artifacts with: if-no-files-found: error - name: docker-arm64 - path: ./release/docker/docker-linux-alpine.arm64.tar + name: web-mini + path: ./redisinsight/api/web-mini + + - uses: actions/upload-artifact@v4 + name: Upload web artifacts + with: + if-no-files-found: error + name: web + path: ./redisinsight/api/web env: RI_AI_CONVAI_TOKEN: ${{ secrets.RI_AI_CONVAI_TOKEN }} From c3534c73508b1fec0d43385f2f6d862a09065898 Mon Sep 17 00:00:00 2001 From: zalenskiSofteq Date: Thu, 17 Oct 2024 09:46:46 +0200 Subject: [PATCH 203/256] test --- .github/workflows/pipeline-build-docker.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/pipeline-build-docker.yml b/.github/workflows/pipeline-build-docker.yml index 55bc8e08c9..f27c42bc8d 100644 --- a/.github/workflows/pipeline-build-docker.yml +++ b/.github/workflows/pipeline-build-docker.yml @@ -85,14 +85,14 @@ jobs: with: if-no-files-found: error name: web-mini - path: ./redisinsight/api/web-mini + path: ./release/web-mini - uses: actions/upload-artifact@v4 name: Upload web artifacts with: if-no-files-found: error name: web - path: ./redisinsight/api/web + path: ./release/web env: RI_AI_CONVAI_TOKEN: ${{ secrets.RI_AI_CONVAI_TOKEN }} From aeb71e72eac42eb70bd5c4b91c08d7b25da10581 Mon Sep 17 00:00:00 2001 From: zalenskiSofteq Date: Thu, 17 Oct 2024 10:15:42 +0200 Subject: [PATCH 204/256] #RI-6213 - Migrate release workflows from CircleCI to Github Actions --- .github/workflows/aws.yml | 10 +++++----- .github/workflows/pipeline-build-windows.yml | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/aws.yml b/.github/workflows/aws.yml index e760f0380a..2e780a9992 100644 --- a/.github/workflows/aws.yml +++ b/.github/workflows/aws.yml @@ -30,16 +30,16 @@ jobs: run: | # Define array of folders to exclude - exclude=("web" "web-mini", "redis-stack", "docker") + exclude=("web" "web-mini" "redistack-builds") - # Iterate through first-level directories - for dir in */; do + # Iterate through first-level directories in ./release + for dir in ./release/*/; do dir_name=$(basename "$dir") # Check if the directory is not in the exclude list if [[ ! " ${exclude[@]} " =~ " ${dir_name} " ]]; then - # Move all files from the subdirectory to the root directory - mv "$dir"* ./ + # Move all files from the subdirectory to the release directory + mv "$dir"* ./release/ # Remove the now-empty subdirectory rmdir "$dir" diff --git a/.github/workflows/pipeline-build-windows.yml b/.github/workflows/pipeline-build-windows.yml index 4ce2a11557..8d72c309ac 100644 --- a/.github/workflows/pipeline-build-windows.yml +++ b/.github/workflows/pipeline-build-windows.yml @@ -50,7 +50,7 @@ jobs: path: | ./release/Redis-Insight*.exe ./release/Redis-Insight*.exe.blockmap - ./release/*.yml + ./release/latest.yml env: WIN_CSC_LINK: ${{ secrets.WIN_CSC_LINK }} From 326723c014d65205e5507ae37963959987d18baa Mon Sep 17 00:00:00 2001 From: Roman Sergeenko Date: Thu, 17 Oct 2024 10:16:16 +0200 Subject: [PATCH 205/256] #RI-6228 - fix load all, composite args --- .../pages/workbench/components/query/Query/Query.tsx | 12 +++++++----- redisinsight/ui/src/pages/workbench/constants.ts | 4 ++++ 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/redisinsight/ui/src/pages/workbench/components/query/Query/Query.tsx b/redisinsight/ui/src/pages/workbench/components/query/Query/Query.tsx index 67059c2088..6a8511b7e1 100644 --- a/redisinsight/ui/src/pages/workbench/components/query/Query/Query.tsx +++ b/redisinsight/ui/src/pages/workbench/components/query/Query/Query.tsx @@ -32,7 +32,7 @@ import { addOwnTokenToArgs, findCurrentArgument, } from 'uiSrc/pages/workbench/u import { getRange, getRediSearchSignutureProvider, } from 'uiSrc/pages/workbench/utils/monaco' import { CursorContext } from 'uiSrc/pages/workbench/types' import { asSuggestionsRef, getCommandsSuggestions, isIndexComplete } from 'uiSrc/pages/workbench/utils/suggestions' -import { COMMANDS_TO_GET_INDEX_INFO, EmptySuggestionsIds, } from 'uiSrc/pages/workbench/constants' +import { COMMANDS_TO_GET_INDEX_INFO, COMPOSITE_ARGS, EmptySuggestionsIds, } from 'uiSrc/pages/workbench/constants' import { useDebouncedEffect } from 'uiSrc/services' import { fetchRedisearchInfoAction } from 'uiSrc/slices/browser/redisearch' import { findSuggestionsByArg } from 'uiSrc/pages/workbench/utils/searchSuggestions' @@ -111,9 +111,11 @@ const Query = (props: Props) => { [commands] ) - const COMPOSITE_ARGS = useMemo(() => commands - .filter((command) => command.name && command.name.includes(' ')) - .map(({ name }) => name), + const compositeTokens = useMemo(() => + commands + .filter((command) => command.token && command.token.includes(' ')) + .map(({ token }) => token) + .concat(...COMPOSITE_ARGS), [commands]) const { instanceId = '' } = useParams<{ instanceId: string }>() @@ -342,7 +344,7 @@ const Query = (props: Props) => { e.position, REDIS_COMMANDS_SPEC, REDIS_COMMANDS_ARRAY, - COMPOSITE_ARGS as string[] + compositeTokens as string[] ) handleSuggestions(editor, command) handleDslSyntax(e, command) diff --git a/redisinsight/ui/src/pages/workbench/constants.ts b/redisinsight/ui/src/pages/workbench/constants.ts index 645b11baf4..1c732c67ce 100644 --- a/redisinsight/ui/src/pages/workbench/constants.ts +++ b/redisinsight/ui/src/pages/workbench/constants.ts @@ -83,6 +83,10 @@ export const COMMANDS_WITHOUT_INDEX_PROPOSE = [ 'FT.CREATE' ] +export const COMPOSITE_ARGS = [ + 'LOAD *', +] + export enum DefinedArgumentName { index = 'index', query = 'query', From e711c2a9d2555a66c7821710473f02cc24328b30 Mon Sep 17 00:00:00 2001 From: vlad-dargel Date: Thu, 17 Oct 2024 10:30:48 +0200 Subject: [PATCH 206/256] add ui tests --- .../utils/tests/test-cases/common.ts | 116 ++++++++++++++++++ 1 file changed, 116 insertions(+) diff --git a/redisinsight/ui/src/pages/workbench/utils/tests/test-cases/common.ts b/redisinsight/ui/src/pages/workbench/utils/tests/test-cases/common.ts index f7a9ff23b8..cc7a9ea168 100644 --- a/redisinsight/ui/src/pages/workbench/utils/tests/test-cases/common.ts +++ b/redisinsight/ui/src/pages/workbench/utils/tests/test-cases/common.ts @@ -226,4 +226,120 @@ export const commonfindCurrentArgumentCases = [ appendIncludes: ['TAGS', 'SUMMARIZE', 'DIALECT', 'FILTER', 'WITHSCORES', 'INKEYS'], appendNotIncludes: ['FIELDS'], }, + { + input: 'FT.SEARCH index "*" SORTBY price ', + result: expect.any(Object), + appendIncludes: ['ASC', 'DESC', 'FILTER', 'LIMIT', 'DIALECT', 'WITHSCORES', 'INFIELDS'], + appendNotIncludes: ['SORTBY'], + }, + { + input: 'FT.SEARCH textVehicles "(-@make:Toyota)" FILTER @year 2021 2022 ', + result: expect.any(Object), + appendIncludes: ['FILTER', 'GEOFILTER', 'TIMEOUT', 'WITHSORTKEYS'], + appendNotIncludes: ['AS', 'ASC'], + }, + { + input: 'FT.SEARCH textVehicles "*" GEOFILTER geo_field lon lat radius ', + result: expect.any(Object), + appendIncludes: ['ft', 'km', 'm', 'mi'], + appendNotIncludes: ['SORTBY', 'FILTER', 'LIMIT', 'DIALECT', 'AS', 'ASC'], + }, + { + input: 'FT.SEARCH textVehicles "*" RETURN 2 test ', + result: expect.any(Object), + appendIncludes: ['AS'], + appendNotIncludes: ['SORTBY', 'FILTER', 'LIMIT', 'DIALECT', 'AS', 'ASC'], + }, + { + input: 'FT.CREATE textVehicles ON ', + result: expect.any(Object), + appendIncludes: ['HASH', 'JSON'], + appendNotIncludes: ['SORTBY', 'FILTER', 'LIMIT', 'DIALECT', 'WITHSCORES', 'INFIELDS'], + }, + { + input: 'FT.CREATE textVehicles SCHEMA make ', + result: expect.any(Object), + appendIncludes: ['AS', 'GEO', 'NUMERIC', 'TAG', 'TEXT', 'VECTOR'], + appendNotIncludes: ['FILTER', 'LIMIT', 'DIALECT', 'WITHSCORES', 'INFIELDS'], + }, + { + input: 'FT.AGGREGATE \'idx:articles\' \'@body:(term) \' APPLY \'test\' ', + result: expect.any(Object), + appendIncludes: ['AS'], + appendNotIncludes: ['REDUCE', 'APPLY', 'LOAD', 'SORTBY', 'GROUPBY'], + }, + { + input: 'FT.AGGREGATE \'idx:articles\' \'@body:(term) \' APPLY \'test\' AS test1', + result: expect.any(Object), + appendIncludes: ['APPLY', 'LOAD', 'SORTBY', 'GROUPBY'], + }, + { + input: 'FT.AGGREGATE \'idx:articles\' \'@body:(term) \' LOAD * ', + result: expect.any(Object), + appendIncludes: ['APPLY', 'LOAD', 'SORTBY', 'GROUPBY'], + }, + { + input: 'FT.AGGREGATE \'idx:articles\' \'@body:(term) \' SORTBY nargs property ', + result: expect.any(Object), + appendIncludes: ['ASC', 'DESC'], + appendNotIncludes: ['REDUCE', 'APPLY', 'LOAD', 'SORTBY', 'GROUPBY'], + }, + { + input: 'FT.AGGREGATE \'idx:articles\' \'@body:(term) \' SORTBY nargs property ASC ', + result: expect.any(Object), + appendIncludes: ['MAX', 'APPLY', 'LOAD', 'SORTBY', 'GROUPBY'], + }, + { + input: 'FT.AGGREGATE \'idx:articles\' \'@body:(term) \' PARAMS 4 name1 value1 name2 value2 ', + result: expect.any(Object), + appendIncludes: ['APPLY', 'LOAD', 'SORTBY', 'GROUPBY'], + appendNotIncludes: ['PARAMS', 'REDUCE'], + }, + { + input: 'FT.ALTER index SCHEMA ADD sdfsd fsdfsd ', + result: expect.any(Object), + appendIncludes: [], + appendNotIncludes: ['SKIPINITIALSCAN', 'ADD', 'SCHEMA'], + }, + { + input: 'FT.DROPINDEX \'vd\' ', + result: expect.any(Object), + appendIncludes: ['DD'], + }, + { + input: 'FT.EXPLAIN index query ', + result: expect.any(Object), + appendIncludes: ['DIALECT'], + appendNotIncludes: ['SKIPINITIALSCAN', 'ADD', 'SCHEMA', 'APPLY', 'LOAD', 'SORTBY', 'GROUPBY'], + }, + { + input: 'FT.EXPLAINCLI index query ', + result: expect.any(Object), + appendIncludes: ['DIALECT'], + appendNotIncludes: ['SKIPINITIALSCAN', 'ADD', 'SCHEMA', 'APPLY', 'LOAD', 'SORTBY', 'GROUPBY'], + }, + { + input: 'FT.INFO index ', + result: expect.any(Object), + appendIncludes: [], + appendNotIncludes: ['ADD', 'SCHEMA', 'APPLY', 'LOAD', 'SORTBY', 'GROUPBY'], + }, + { + input: 'FT.PROFILE \'idx:schools\' ', + result: expect.any(Object), + appendIncludes: ['AGGREGATE', 'SEARCH'], + appendNotIncludes: ['LIMITED'], + }, + { + input: 'FT.SPELLCHECK \'idx:articles\' \'test\' DIALECT dialect DISTANCE distance TERMS ', + result: expect.any(Object), + appendIncludes: ['EXCLUDE', 'INCLUDE'], + appendNotIncludes: ['DIALECT', 'DISTANCE', 'TERMS'], + }, + { + input: 'FT.SYNUPDATE \'idx:products\' synonym_group_id ', + result: expect.any(Object), + appendIncludes: ['SKIPINITIALSCAN'], + appendNotIncludes: ['DIALECT', 'DISTANCE', 'TERMS', 'INCLUDE', 'SCHEMA', 'APPLY', 'LOAD', 'SORTBY', 'GROUPBY'], + }, ] From 09ec2ee6b84e11e14a29c05601210cd829a38ad0 Mon Sep 17 00:00:00 2001 From: vlad-dargel Date: Thu, 17 Oct 2024 10:49:54 +0200 Subject: [PATCH 207/256] fix --- .../ui/src/pages/workbench/utils/tests/test-cases/common.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/redisinsight/ui/src/pages/workbench/utils/tests/test-cases/common.ts b/redisinsight/ui/src/pages/workbench/utils/tests/test-cases/common.ts index cc7a9ea168..b39b3e5945 100644 --- a/redisinsight/ui/src/pages/workbench/utils/tests/test-cases/common.ts +++ b/redisinsight/ui/src/pages/workbench/utils/tests/test-cases/common.ts @@ -248,7 +248,7 @@ export const commonfindCurrentArgumentCases = [ input: 'FT.SEARCH textVehicles "*" RETURN 2 test ', result: expect.any(Object), appendIncludes: ['AS'], - appendNotIncludes: ['SORTBY', 'FILTER', 'LIMIT', 'DIALECT', 'AS', 'ASC'], + appendNotIncludes: ['SORTBY', 'FILTER', 'LIMIT', 'DIALECT', 'ASC'], }, { input: 'FT.CREATE textVehicles ON ', @@ -287,7 +287,8 @@ export const commonfindCurrentArgumentCases = [ { input: 'FT.AGGREGATE \'idx:articles\' \'@body:(term) \' SORTBY nargs property ASC ', result: expect.any(Object), - appendIncludes: ['MAX', 'APPLY', 'LOAD', 'SORTBY', 'GROUPBY'], + appendIncludes: ['MAX', 'APPLY', 'LOAD', 'GROUPBY'], + appendNotIncludes: ['SORTBY'], }, { input: 'FT.AGGREGATE \'idx:articles\' \'@body:(term) \' PARAMS 4 name1 value1 name2 value2 ', From f4cd8d636c23c396917f5a4365016c48bd5f8581 Mon Sep 17 00:00:00 2001 From: zalenskiSofteq Date: Thu, 17 Oct 2024 11:06:16 +0200 Subject: [PATCH 208/256] #RI-6213 - Migrate release workflows from CircleCI to Github Actions --- .github/workflows/aws.yml | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/.github/workflows/aws.yml b/.github/workflows/aws.yml index 2e780a9992..2d75bf7514 100644 --- a/.github/workflows/aws.yml +++ b/.github/workflows/aws.yml @@ -30,7 +30,7 @@ jobs: run: | # Define array of folders to exclude - exclude=("web" "web-mini" "redistack-builds") + exclude=("web" "web-mini" "redistack-builds", "docker") # Iterate through first-level directories in ./release for dir in ./release/*/; do @@ -69,12 +69,12 @@ jobs: appName=$(jq -r '.productName' electron-builder.json) appVersion=$(jq -r '.version' redisinsight/package.json) - echo "export downloadLatestFolderPath=${downloadLatestFolderPath}" >> $BASH_ENV - echo "export upgradeLatestFolderPath=${upgradeLatestFolderPath}" >> $BASH_ENV - echo "export releasesFolderPath=${releasesFolderPath}" >> $BASH_ENV - echo "export applicationName=${appName}" >> $BASH_ENV - echo "export applicationVersion=${appVersion}" >> $BASH_ENV - echo "export appFileName=Redis-Insight" >> $BASH_ENV + echo "export downloadLatestFolderPath=${downloadLatestFolderPath}" >> $GITHUB_ENV + echo "export upgradeLatestFolderPath=${upgradeLatestFolderPath}" >> $GITHUB_ENV + echo "export releasesFolderPath=${releasesFolderPath}" >> $GITHUB_ENV + echo "export applicationName=${appName}" >> $GITHUB_ENV + echo "export applicationVersion=${appVersion}" >> $GITHUB_ENV + echo "export appFileName=Redis-Insight" >> $GITHUB_ENV # download latest.yml file to get last public version aws s3 cp s3://${AWS_BUCKET_NAME}/${downloadLatestFolderPath}/${latestYmlFileName} . @@ -83,7 +83,7 @@ jobs: versionLineArr=(${versionLine/:// }) previousAppVersion=${versionLineArr[1]} - echo "export previousApplicationVersion=${previousAppVersion}" >> $BASH_ENV + echo "export previousApplicationVersion=${previousAppVersion}" >> $GITHUB_ENV - name: Publish AWS S3 run: | From 59e1956da42957c2f8a9f9b377611cd1bf9f319b Mon Sep 17 00:00:00 2001 From: zalenskiSofteq Date: Thu, 17 Oct 2024 12:00:17 +0200 Subject: [PATCH 209/256] #RI-6213 - Migrate release workflows from CircleCI to Github Actions --- .github/workflows/aws.yml | 112 +++++++++++++++++++------------------- 1 file changed, 56 insertions(+), 56 deletions(-) diff --git a/.github/workflows/aws.yml b/.github/workflows/aws.yml index 2d75bf7514..24a57257e9 100644 --- a/.github/workflows/aws.yml +++ b/.github/workflows/aws.yml @@ -69,12 +69,12 @@ jobs: appName=$(jq -r '.productName' electron-builder.json) appVersion=$(jq -r '.version' redisinsight/package.json) - echo "export downloadLatestFolderPath=${downloadLatestFolderPath}" >> $GITHUB_ENV - echo "export upgradeLatestFolderPath=${upgradeLatestFolderPath}" >> $GITHUB_ENV - echo "export releasesFolderPath=${releasesFolderPath}" >> $GITHUB_ENV - echo "export applicationName=${appName}" >> $GITHUB_ENV - echo "export applicationVersion=${appVersion}" >> $GITHUB_ENV - echo "export appFileName=Redis-Insight" >> $GITHUB_ENV + echo "downloadLatestFolderPath=${downloadLatestFolderPath}" >> $GITHUB_ENV + echo "upgradeLatestFolderPath=${upgradeLatestFolderPath}" >> $GITHUB_ENV + echo "releasesFolderPath=${releasesFolderPath}" >> $GITHUB_ENV + echo "applicationName=${appName}" >> $GITHUB_ENV + echo "applicationVersion=${appVersion}" >> $GITHUB_ENV + echo "appFileName=Redis-Insight" >> $GITHUB_ENV # download latest.yml file to get last public version aws s3 cp s3://${AWS_BUCKET_NAME}/${downloadLatestFolderPath}/${latestYmlFileName} . @@ -83,7 +83,7 @@ jobs: versionLineArr=(${versionLine/:// }) previousAppVersion=${versionLineArr[1]} - echo "export previousApplicationVersion=${previousAppVersion}" >> $GITHUB_ENV + echo "previousApplicationVersion=${previousAppVersion}" >> $GITHUB_ENV - name: Publish AWS S3 run: | @@ -113,75 +113,75 @@ jobs: # declare all tags declare -A tag0=( - [arch]='x64' - [platform]='macos' - [objectDownload]=${appFileName}'-mac-x64.dmg' - [objectUpgrade]=${appFileName}'-mac-x64.zip' + [arch]='x64' + [platform]='macos' + [objectDownload]=${appFileName}'-mac-x64.dmg' + [objectUpgrade]=${appFileName}'-mac-x64.zip' ) declare -A tag1=( - [arch]='arm64' - [platform]='macos' - [objectDownload]=${appFileName}'-mac-arm64.dmg' - [objectUpgrade]=${appFileName}'-mac-arm64.zip' + [arch]='arm64' + [platform]='macos' + [objectDownload]=${appFileName}'-mac-arm64.dmg' + [objectUpgrade]=${appFileName}'-mac-arm64.zip' ) declare -A tag2=( - [arch]='x64' - [platform]='windows' - [objectDownload]=${appFileName}'-win-installer.exe' + [arch]='x64' + [platform]='windows' + [objectDownload]=${appFileName}'-win-installer.exe' ) declare -A tag3=( - [arch]='x64' - [platform]='linux_AppImage' - [objectDownload]=${appFileName}'-linux-x86_64.AppImage' + [arch]='x64' + [platform]='linux_AppImage' + [objectDownload]=${appFileName}'-linux-x86_64.AppImage' ) declare -A tag4=( - [arch]='x64' - [platform]='linux_deb' - [objectDownload]=${appFileName}'-linux-amd64.deb' + [arch]='x64' + [platform]='linux_deb' + [objectDownload]=${appFileName}'-linux-amd64.deb' ) declare -A tag5=( - [arch]='x64' - [platform]='linux_rpm' - [objectDownload]=${appFileName}'-linux-x86_64.rpm' + [arch]='x64' + [platform]='linux_rpm' + [objectDownload]=${appFileName}'-linux-x86_64.rpm' ) # loop for add all tags to each app and create metrics declare -n tag for tag in ${!tag@}; do - designation0="downloads" - designation1="upgrades" - - id0="${tag[platform]}_${tag[arch]}_${designation0}_${applicationVersion}" - id1="${tag[platform]}_${tag[arch]}_${designation1}_${applicationVersion}" - - # add tags to each app for download - aws s3api put-object-tagging \ - --bucket ${AWS_BUCKET_NAME} \ - --key ${downloadLatestFolderPath}/${tag[objectDownload]} \ - --tagging '{"TagSet": [{ "Key": "version", "Value": "'"${applicationVersion}"'" }, {"Key": "platform", "Value": "'"${tag[platform]}"'"}, {"Key": "arch", "Value": "'"${tag[arch]}"'"}, { "Key": "designation", "Value": "'"${designation0}"'" }]}' - - # add tags to each app for upgrades - aws s3api put-object-tagging \ - --bucket ${AWS_BUCKET_NAME} \ - --key ${upgradeLatestFolderPath}/${tag[objectUpgrade]:=${tag[objectDownload]}} \ - --tagging '{"TagSet": [{ "Key": "version", "Value": "'"${applicationVersion}"'" }, {"Key": "platform", "Value": "'"${tag[platform]}"'"}, {"Key": "arch", "Value": "'"${tag[arch]}"'"}, { "Key": "designation", "Value": "'"${designation1}"'" }]}' - - # Create metrics for all tags for downloads to S3 - aws s3api put-bucket-metrics-configuration \ - --bucket ${AWS_BUCKET_NAME} \ - --id ${id0} \ - --metrics-configuration '{"Id": "'"${id0}"'", "Filter": {"And": {"Tags": [{"Key": "platform", "Value": "'"${tag[platform]}"'"}, {"Key": "arch", "Value": "'"${tag[arch]}"'"}, {"Key": "designation", "Value": "'"${designation0}"'"}, {"Key": "version", "Value": "'"${applicationVersion}"'"} ]}}}' - - # Create metrics for all tags for upgrades to S3 - aws s3api put-bucket-metrics-configuration \ - --bucket ${AWS_BUCKET_NAME} \ - --id ${id1} \ - --metrics-configuration '{"Id": "'"${id1}"'", "Filter": {"And": {"Tags": [{"Key": "platform", "Value": "'"${tag[platform]}"'"}, {"Key": "arch", "Value": "'"${tag[arch]}"'"}, {"Key": "designation", "Value": "'"${designation1}"'"}, {"Key": "version", "Value": "'"${applicationVersion}"'"}]}}}' + designation0="downloads" + designation1="upgrades" + + id0="${tag[platform]}_${tag[arch]}_${designation0}_${applicationVersion}" + id1="${tag[platform]}_${tag[arch]}_${designation1}_${applicationVersion}" + + # add tags to each app for download + aws s3api put-object-tagging \ + --bucket ${AWS_BUCKET_NAME} \ + --key ${downloadLatestFolderPath}/${tag[objectDownload]} \ + --tagging '{"TagSet": [{ "Key": "version", "Value": "'"${applicationVersion}"'" }, {"Key": "platform", "Value": "'"${tag[platform]}"'"}, {"Key": "arch", "Value": "'"${tag[arch]}"'"}, { "Key": "designation", "Value": "'"${designation0}"'" }]}' + + # add tags to each app for upgrades + aws s3api put-object-tagging \ + --bucket ${AWS_BUCKET_NAME} \ + --key ${upgradeLatestFolderPath}/${tag[objectUpgrade]:=${tag[objectDownload]}} \ + --tagging '{"TagSet": [{ "Key": "version", "Value": "'"${applicationVersion}"'" }, {"Key": "platform", "Value": "'"${tag[platform]}"'"}, {"Key": "arch", "Value": "'"${tag[arch]}"'"}, { "Key": "designation", "Value": "'"${designation1}"'" }]}' + + # Create metrics for all tags for downloads to S3 + aws s3api put-bucket-metrics-configuration \ + --bucket ${AWS_BUCKET_NAME} \ + --id ${id0} \ + --metrics-configuration '{"Id": "'"${id0}"'", "Filter": {"And": {"Tags": [{"Key": "platform", "Value": "'"${tag[platform]}"'"}, {"Key": "arch", "Value": "'"${tag[arch]}"'"}, {"Key": "designation", "Value": "'"${designation0}"'"}, {"Key": "version", "Value": "'"${applicationVersion}"'"} ]}}}' + + # Create metrics for all tags for upgrades to S3 + aws s3api put-bucket-metrics-configuration \ + --bucket ${AWS_BUCKET_NAME} \ + --id ${id1} \ + --metrics-configuration '{"Id": "'"${id1}"'", "Filter": {"And": {"Tags": [{"Key": "platform", "Value": "'"${tag[platform]}"'"}, {"Key": "arch", "Value": "'"${tag[arch]}"'"}, {"Key": "designation", "Value": "'"${designation1}"'"}, {"Key": "version", "Value": "'"${applicationVersion}"'"}]}}}' done From bc12f62c4a0b7359e43f0c0a0a280f188915a7e6 Mon Sep 17 00:00:00 2001 From: zalenskiSofteq Date: Thu, 17 Oct 2024 12:53:18 +0200 Subject: [PATCH 210/256] #RI-6213 - Migrate release workflows from CircleCI to Github Actions --- .github/workflows/pipeline-build-macos.yml | 8 ++++++++ .github/workflows/virustotal.yml | 6 +++--- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/.github/workflows/pipeline-build-macos.yml b/.github/workflows/pipeline-build-macos.yml index 4f2c43d764..c70105a761 100644 --- a/.github/workflows/pipeline-build-macos.yml +++ b/.github/workflows/pipeline-build-macos.yml @@ -88,6 +88,14 @@ jobs: ./release/Redis-Insight*x64.dmg ./release/Redis-Insight*x64.dmg.blockmap + - name: Upload zips packages + uses: actions/upload-artifact@v4 + if: inputs.target == vars.ALL || endsWith(inputs.target, 'x64') + with: + name: macos-x64-builds + path: | + ./release/Redis-Insight*.zip + - name: Upload ARM packages uses: actions/upload-artifact@v4 if: inputs.target == vars.ALL || endsWith(inputs.target, 'arm64') diff --git a/.github/workflows/virustotal.yml b/.github/workflows/virustotal.yml index 442c020fa6..093f2a3385 100644 --- a/.github/workflows/virustotal.yml +++ b/.github/workflows/virustotal.yml @@ -152,12 +152,12 @@ jobs: echo "analazedMalicious: ${analazedMalicious}, analazedSuspicious: ${analazedSuspicious}, analazedHarmless: ${analazedHarmless}" if [ "$analazedMalicious" != "0" ] || [ "$analazedSuspicious" != "0" ]; then - echo "export FAILED=true" >> $GITHUB_ENV + echo "FAILED=true" >> $GITHUB_ENV echo 'Found dangers'; fi - echo "export FAILED=false" >> $GITHUB_ENV - echo "export skip_report=true" >> $GITHUB_ENV + echo "FAILED=false" >> $GITHUB_ENV + echo "skip_report=true" >> $GITHUB_ENV echo 'Passed'; - name: Send Report From e2e369084a10a11fd2147163da16b007d9a33216 Mon Sep 17 00:00:00 2001 From: zalenskiSofteq Date: Thu, 17 Oct 2024 13:24:27 +0200 Subject: [PATCH 211/256] #RI-6213 - Migrate release workflows from CircleCI to Github Actions --- .github/workflows/pipeline-build-macos.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/pipeline-build-macos.yml b/.github/workflows/pipeline-build-macos.yml index c70105a761..ad6376141f 100644 --- a/.github/workflows/pipeline-build-macos.yml +++ b/.github/workflows/pipeline-build-macos.yml @@ -92,7 +92,7 @@ jobs: uses: actions/upload-artifact@v4 if: inputs.target == vars.ALL || endsWith(inputs.target, 'x64') with: - name: macos-x64-builds + name: macos-zip-builds path: | ./release/Redis-Insight*.zip From 655b2f3e1ccb6f7b2a7536007fc979d7e24ede8a Mon Sep 17 00:00:00 2001 From: zalenskiSofteq Date: Thu, 17 Oct 2024 13:56:03 +0200 Subject: [PATCH 212/256] #RI-6213 - Migrate release workflows from CircleCI to Github Actions --- .github/workflows/aws.yml | 2 +- .github/workflows/pipeline-build-macos.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/aws.yml b/.github/workflows/aws.yml index 24a57257e9..d4d2b58aaf 100644 --- a/.github/workflows/aws.yml +++ b/.github/workflows/aws.yml @@ -30,7 +30,7 @@ jobs: run: | # Define array of folders to exclude - exclude=("web" "web-mini" "redistack-builds", "docker") + exclude=("web" "web-mini" "redisstack", "docker") # Iterate through first-level directories in ./release for dir in ./release/*/; do diff --git a/.github/workflows/pipeline-build-macos.yml b/.github/workflows/pipeline-build-macos.yml index ad6376141f..ac084f0ed2 100644 --- a/.github/workflows/pipeline-build-macos.yml +++ b/.github/workflows/pipeline-build-macos.yml @@ -118,7 +118,7 @@ jobs: uses: actions/upload-artifact@v4 if: vars.ENV == 'production' with: - name: 'redistack-builds' + name: 'redisstack' path: | ./release/redisstack From f202275ac8963b200957c3abe32df1e70e2e17ea Mon Sep 17 00:00:00 2001 From: zalenskiSofteq Date: Thu, 17 Oct 2024 14:05:38 +0200 Subject: [PATCH 213/256] #RI-6213 - Migrate release workflows from CircleCI to Github Actions --- .github/workflows/release-docker.yml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/workflows/release-docker.yml b/.github/workflows/release-docker.yml index 73a8098e50..23aa113460 100644 --- a/.github/workflows/release-docker.yml +++ b/.github/workflows/release-docker.yml @@ -9,12 +9,18 @@ jobs: steps: - uses: actions/checkout@v4 + - name: Download Docker artifacts + uses: actions/download-artifact@v4 + with: + name: docker + path: ./release + - name: Publish docker env: DOCKER_USER: ${{ secrets.DOCKER_USER }} DOCKER_PASS: ${{ secrets.DOCKER_PASS }} - DOCKER_V1_USER: ${{ secrets.DOCKER_V1_USER }} DOCKER_REPO: ${{ secrets.DOCKER_REPO }} + DOCKER_V1_USER: ${{ secrets.DOCKER_V1_USER }} DOCKER_V1_REPO: ${{ secrets.DOCKER_V1_REPO }} run: | appVersion=$(jq -r '.version' redisinsight/package.json) @@ -33,9 +39,3 @@ jobs: -r $DOCKER_V1_REPO \ -v $appVersion - # - uses: actions/upload-artifact@v4 - # with: - # name: licenses - # path: licenses - # if-no-files-found: error - From f4b4d08eb8df52501dd527a7b51ebbaf6ee30399 Mon Sep 17 00:00:00 2001 From: zalenskiSofteq Date: Thu, 17 Oct 2024 14:26:48 +0200 Subject: [PATCH 214/256] #RI-6213 - Migrate release workflows from CircleCI to Github Actions --- .github/workflows/pipeline-build-macos.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/pipeline-build-macos.yml b/.github/workflows/pipeline-build-macos.yml index ac084f0ed2..668a42a242 100644 --- a/.github/workflows/pipeline-build-macos.yml +++ b/.github/workflows/pipeline-build-macos.yml @@ -120,7 +120,7 @@ jobs: with: name: 'redisstack' path: | - ./release/redisstack + ./release/Redis-Insight-app-darwin.*.tar.gz env: APPLE_ID: ${{ secrets.APPLE_ID }} From 227c35bea29018f01cf0400e15cc68ab197f37f0 Mon Sep 17 00:00:00 2001 From: zalenskiSofteq Date: Thu, 17 Oct 2024 15:11:36 +0200 Subject: [PATCH 215/256] #RI-6213 - Migrate release workflows from CircleCI to Github Actions --- .github/workflows/pipeline-build-macos.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/pipeline-build-macos.yml b/.github/workflows/pipeline-build-macos.yml index 668a42a242..86c94de4de 100644 --- a/.github/workflows/pipeline-build-macos.yml +++ b/.github/workflows/pipeline-build-macos.yml @@ -120,7 +120,7 @@ jobs: with: name: 'redisstack' path: | - ./release/Redis-Insight-app-darwin.*.tar.gz + ./release/*/Redis-Insight-app-darwin.*.tar.gz env: APPLE_ID: ${{ secrets.APPLE_ID }} From a3bc08b8f30ee0bcf301674ff0cbf368a7a78616 Mon Sep 17 00:00:00 2001 From: zalenskiSofteq Date: Thu, 17 Oct 2024 15:15:47 +0200 Subject: [PATCH 216/256] #RI-6213 - Migrate release workflows from CircleCI to Github Actions --- .github/workflows/pipeline-build-macos.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/pipeline-build-macos.yml b/.github/workflows/pipeline-build-macos.yml index 86c94de4de..6485e1b858 100644 --- a/.github/workflows/pipeline-build-macos.yml +++ b/.github/workflows/pipeline-build-macos.yml @@ -120,7 +120,7 @@ jobs: with: name: 'redisstack' path: | - ./release/*/Redis-Insight-app-darwin.*.tar.gz + ./release/redisstack/Redis-Insight-app-darwin.*.tar.gz env: APPLE_ID: ${{ secrets.APPLE_ID }} From 8bda3fcf9d4d9fbcb68fb8bb01492ca0dcc6c55c Mon Sep 17 00:00:00 2001 From: zalenskiSofteq Date: Thu, 17 Oct 2024 15:45:54 +0200 Subject: [PATCH 217/256] #RI-6213 - Migrate release workflows from CircleCI to Github Actions --- .github/workflows/aws.yml | 2 +- .github/workflows/tests.yml | 13 ++++++++----- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/.github/workflows/aws.yml b/.github/workflows/aws.yml index d4d2b58aaf..3c42527061 100644 --- a/.github/workflows/aws.yml +++ b/.github/workflows/aws.yml @@ -30,7 +30,7 @@ jobs: run: | # Define array of folders to exclude - exclude=("web" "web-mini" "redisstack", "docker") + exclude=("web" "web-mini" "redisstack" "docker") # Iterate through first-level directories in ./release for dir in ./release/*/; do diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 7d752b306c..8fae373c51 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -1,9 +1,12 @@ name: Tests on: - # push: - # branches-ignore: - # - main + push: + branches: + - 'fe/*' + - 'be/*' + # branches-ignore: + # - main workflow_dispatch: inputs: @@ -49,7 +52,7 @@ jobs: # TODO: concurrency # concurrency: build needs: changes - if: needs.changes.outputs.frontend == 'true' || inputs.all_tests + if: needs.changes.outputs.frontend == 'true' || inputs.all_tests || startsWith(github.ref_name, 'fe/') uses: ./.github/workflows/tests-frontend.yml secrets: inherit @@ -57,6 +60,6 @@ jobs: # TODO: concurrency # concurrency: build needs: changes - if: needs.changes.outputs.backend == 'true' || inputs.all_tests + if: needs.changes.outputs.backend == 'true' || inputs.all_tests || startsWith(github.ref_name, 'be/') uses: ./.github/workflows/tests-backend.yml secrets: inherit From 629bf4381b29dc5b1b250a25324859831b6ec7d3 Mon Sep 17 00:00:00 2001 From: zalenskiSofteq Date: Thu, 17 Oct 2024 16:15:32 +0200 Subject: [PATCH 218/256] #RI-6213 - Migrate release workflows from CircleCI to Github Actions --- .circleci/build/build.sh | 3 +- .github/build/release-docker.sh | 63 ++++++++++++++++++++ .github/workflows/pipeline-build-linux.yml | 5 +- .github/workflows/pipeline-build-macos.yml | 5 +- .github/workflows/pipeline-build-windows.yml | 5 +- .github/workflows/release-docker.yml | 4 +- .github/workflows/release-prod.yml | 52 +++++++--------- .github/workflows/virustotal.yml | 9 +-- 8 files changed, 95 insertions(+), 51 deletions(-) create mode 100755 .github/build/release-docker.sh diff --git a/.circleci/build/build.sh b/.circleci/build/build.sh index 258a137b00..907587ced2 100755 --- a/.circleci/build/build.sh +++ b/.circleci/build/build.sh @@ -7,7 +7,6 @@ yarn --cwd redisinsight/api # build -# todo uncomment -# yarn build:statics +yarn build:statics yarn build:ui yarn --cwd ./redisinsight/api build:prod diff --git a/.github/build/release-docker.sh b/.github/build/release-docker.sh new file mode 100755 index 0000000000..7c49f1e379 --- /dev/null +++ b/.github/build/release-docker.sh @@ -0,0 +1,63 @@ +#!/bin/bash +set -e + +HELP="Args: +-v - Semver (2.58.0) +-d - Build image repository (Ex: -d redisinsight) +-r - Target repository (Ex: -r redis/redisinsight) +" + +while getopts "v:d:r:h:" opt; do + case $opt in + v) VERSION="$OPTARG";; + d) DEV_REPO="$OPTARG";; + r) RELEASE_REPO="$OPTARG";; + h) echo "$HELP"; exit 0;; + ?) echo "$HELP" >&2; exit 1 ;; + esac +done + +V_ARR=( ${VERSION//./ } ) +TAGS[0]=$VERSION +TAGS[1]="${V_ARR[0]}.${V_ARR[1]}" +TAGS[2]="latest" + +DEV_IMAGE_AMD64=$DEV_REPO:amd64 +DEV_IMAGE_ARM64=$DEV_REPO:arm64 +RELEASE_IMAGE_AMD64=$RELEASE_REPO:$VERSION-amd64 +RELEASE_IMAGE_ARM64=$RELEASE_REPO:$VERSION-arm64 + +echo " + TAGS: [${TAGS[0]}, ${TAGS[1]}, ${TAGS[2]}] + DEV_REPO: $DEV_REPO + RELEASE_REPO: $RELEASE_REPO + + DEV_IMAGE_AMD64: $DEV_IMAGE_AMD64 + DEV_IMAGE_ARM64: $DEV_IMAGE_ARM64 + + RELEASE_IMAGE_AMD64: $RELEASE_IMAGE_AMD64 + RELEASE_IMAGE_ARM64: $RELEASE_IMAGE_ARM64 +" + +# Load images from tar archives +docker rmi $DEV_IMAGE_AMD64 || true +docker rmi $DEV_IMAGE_ARM64 || true +docker load -i release/docker-linux-alpine.amd64.tar +docker load -i release/docker-linux-alpine.arm64.tar + +echo "Push AMD64 image" +docker tag $DEV_IMAGE_AMD64 $RELEASE_IMAGE_AMD64 +docker push $RELEASE_IMAGE_AMD64 + +echo "Push ARM64 image" +docker tag $DEV_IMAGE_ARM64 $RELEASE_IMAGE_ARM64 +docker push $RELEASE_IMAGE_ARM64 + +for TAG in "${TAGS[@]}"; do + echo "Releasing: $RELEASE_REPO:$TAG" + docker manifest rm $RELEASE_REPO:$TAG || true + docker manifest create --amend "$RELEASE_REPO:$TAG" $RELEASE_IMAGE_AMD64 $RELEASE_IMAGE_ARM64 + docker manifest push "$RELEASE_REPO:$TAG" +done + +echo "Success" diff --git a/.github/workflows/pipeline-build-linux.yml b/.github/workflows/pipeline-build-linux.yml index 58dc8dd10e..d7fe413497 100644 --- a/.github/workflows/pipeline-build-linux.yml +++ b/.github/workflows/pipeline-build-linux.yml @@ -55,9 +55,8 @@ jobs: # path: "." # - run: cp ./electron/package.json ./redisinsight/ - # todo uncomment - # - name: Install plugins dependencies and build plugins - # run: yarn build:statics + - name: Install plugins dependencies and build plugins + run: yarn build:statics - name: Build linux packages (production) if: vars.ENV == 'production' && inputs.target == vars.ALL diff --git a/.github/workflows/pipeline-build-macos.yml b/.github/workflows/pipeline-build-macos.yml index 6485e1b858..05c1642dc5 100644 --- a/.github/workflows/pipeline-build-macos.yml +++ b/.github/workflows/pipeline-build-macos.yml @@ -38,9 +38,8 @@ jobs: keytar-host-mirror: ${{ secrets.NPM_CONFIG_KEYTAR_BINARY_HOST_MIRROR }} sqlite3-host-mirror: ${{ secrets.NPM_CONFIG_NODE_SQLITE3_BINARY_HOST_MIRROR }} - # todo uncomment - # - name: Install plugins dependencies and build plugins - # run: yarn build:statics + - name: Install plugins dependencies and build plugins + run: yarn build:statics - name: Build macos dmg (prod) if: vars.ENV == 'production' && inputs.target == vars.ALL diff --git a/.github/workflows/pipeline-build-windows.yml b/.github/workflows/pipeline-build-windows.yml index 8d72c309ac..506ab530e7 100644 --- a/.github/workflows/pipeline-build-windows.yml +++ b/.github/workflows/pipeline-build-windows.yml @@ -25,9 +25,8 @@ jobs: with: WIN_CSC_PFX_BASE64: ${{ secrets.WIN_CSC_PFX_BASE64 }} - # todo uncomment - # - name: Install plugins dependencies and build plugins - # run: yarn build:statics:win + - name: Install plugins dependencies and build plugins + run: yarn build:statics:win - name: Build windows exe (production) if: vars.ENV == 'production' diff --git a/.github/workflows/release-docker.yml b/.github/workflows/release-docker.yml index 23aa113460..7fc8587c66 100644 --- a/.github/workflows/release-docker.yml +++ b/.github/workflows/release-docker.yml @@ -27,14 +27,14 @@ jobs: docker login -u $DOCKER_USER -p $DOCKER_PASS - ./.circleci/build/release-docker.sh \ + ./.github/build/release-docker.sh \ -d redisinsight \ -r $DOCKER_REPO \ -v $appVersion docker login -u $DOCKER_V1_USER -p $DOCKER_V1_PASS - ./.circleci/build/release-docker.sh \ + ./.github/build/release-docker.sh \ -d redisinsight \ -r $DOCKER_V1_REPO \ -v $appVersion diff --git a/.github/workflows/release-prod.yml b/.github/workflows/release-prod.yml index 5fcd253d63..6a3a3b244c 100644 --- a/.github/workflows/release-prod.yml +++ b/.github/workflows/release-prod.yml @@ -8,51 +8,39 @@ on: - 'test/prod/**' jobs: - # todo uncomment - # tests-prod: - # name: Run all tests - # uses: ./.github/workflows/tests.yml - # secrets: inherit - # with: - # all_tests: true + tests-prod: + name: Run all tests + uses: ./.github/workflows/tests.yml + secrets: inherit + with: + all_tests: true builds-prod: name: Create all builds for release uses: ./.github/workflows/build.yml - # needs: tests-prod + needs: tests-prod secrets: inherit with: environment: 'production' target: 'all' - # virustotal-prod: - # name: Virustotal - # uses: ./.github/workflows/virustotal.yml - # needs: builds-prod - # secrets: inherit - # with: - # skip_report: true + virustotal-prod: + name: Virustotal + uses: ./.github/workflows/virustotal.yml + needs: builds-prod + secrets: inherit + with: + skip_report: true aws-prod: name: Realse to AWS S3 uses: ./.github/workflows/aws.yml + needs: virustotal-prod if: ${{ always() }} - # needs: virustotal-prod - needs: builds-prod secrets: inherit - # todo: uncomment - # docker-prod: - # name: Release docker images - # uses: ./.github/workflows/release-docker.yml - # needs: aws-prod - # secrets: inherit - - # todo: e2e tests for release stage - # e2e-linux: - # uses: ./.github/workflows/build.yml - # needs: builds-prod - # secrets: inherit - # with: - # environment: 'staging' - # target: 'all' + docker-prod: + name: Release docker images + uses: ./.github/workflows/release-docker.yml + needs: aws-prod + secrets: inherit diff --git a/.github/workflows/virustotal.yml b/.github/workflows/virustotal.yml index 093f2a3385..cb5fe09497 100644 --- a/.github/workflows/virustotal.yml +++ b/.github/workflows/virustotal.yml @@ -12,9 +12,7 @@ on: env: VIRUSTOTAL_FILE_NAMES: ${{ vars.VIRUSTOTAL_FILE_NAMES }} VIRUSTOTAL_API_KEY: ${{ secrets.VIRUSTOTAL_API_KEY }} - - # TODO: test on other slack chat - # SLACK_TEST_REPORT_KEY: ${{ secrets.SLACK_TEST_REPORT_KEY }} + SLACK_TEST_REPORT_KEY: ${{ secrets.SLACK_TEST_REPORT_KEY }} jobs: download_artifacts: @@ -166,9 +164,8 @@ jobs: FILE_NAME=virustotal.report.json BUILD_NAME=$BUILD_NAME FILE_NAME=$FILE_NAME VIRUS_CHECK_FAILED=$FAILED node .github/virustotal-report.js - # todo uncomment after testing - # BUILD_NAME=$BUILD_NAME FILE_NAME=$FILE_NAME VIRUS_CHECK_FAILED=$FAILED node .github/virustotal-report.js && - # curl -H "Content-type: application/json" --data @$FILE_NAME -H "Authorization: Bearer ${SLACK_TEST_REPORT_KEY}" -X POST https://slack.com/api/chat.postMessage + BUILD_NAME=$BUILD_NAME FILE_NAME=$FILE_NAME VIRUS_CHECK_FAILED=$FAILED node .github/virustotal-report.js && + curl -H "Content-type: application/json" --data @$FILE_NAME -H "Authorization: Bearer ${SLACK_TEST_REPORT_KEY}" -X POST https://slack.com/api/chat.postMessage if [ "$FAILED" == "true" ]; then echo 'Found dangers'; From 6b79df8e1e4f33eb09a2d64b46fd87c818a16528 Mon Sep 17 00:00:00 2001 From: zalenskiSofteq Date: Thu, 17 Oct 2024 16:46:53 +0200 Subject: [PATCH 219/256] #RI-6213 - Migrate release workflows from CircleCI to Github Actions --- .github/workflows/release-prod.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/release-prod.yml b/.github/workflows/release-prod.yml index 6a3a3b244c..76ad3bc286 100644 --- a/.github/workflows/release-prod.yml +++ b/.github/workflows/release-prod.yml @@ -36,7 +36,6 @@ jobs: name: Realse to AWS S3 uses: ./.github/workflows/aws.yml needs: virustotal-prod - if: ${{ always() }} secrets: inherit docker-prod: From 159f739b0f6d490ea5a8fa3e59ec611ce8470539 Mon Sep 17 00:00:00 2001 From: Roman Sergeenko Date: Thu, 17 Oct 2024 17:05:41 +0200 Subject: [PATCH 220/256] #RRI-6172 - remove search page --- .../main-router/constants/defaultRoutes.ts | 6 - .../main-router/constants/redisStackRoutes.ts | 7 - .../monaco-laguages/MonacoLanguages.tsx | 5 +- .../navigation-menu/NavigationMenu.spec.tsx | 1 - .../navigation-menu/NavigationMenu.tsx | 17 - .../components/query/query-card/QueryCard.tsx | 10 +- .../QueryCardCliPlugin/QueryCardCliPlugin.tsx | 5 +- .../QueryCardHeader/QueryCardHeader.tsx | 69 +- .../components/code-block/CodeBlock.spec.tsx | 1 - .../components/code-block/CodeBlock.tsx | 2 - .../enablement-area/EnablementAreaWrapper.tsx | 2 - .../ui/src/pages/search/SearchPage.spec.tsx | 79 - .../ui/src/pages/search/SearchPage.tsx | 128 -- .../constants/supported_commands.json | 1156 ------------- .../ui/src/pages/search/components/index.ts | 7 - .../query-wrapper/QueryWrapper.spec.tsx | 91 - .../components/query-wrapper/QueryWrapper.tsx | 135 -- .../components/query-wrapper/constants.ts | 16 - .../search/components/query-wrapper/index.ts | 3 - .../query-wrapper/styles.module.scss | 76 - .../search/components/query/Query.spec.tsx | 10 - .../pages/search/components/query/Query.tsx | 359 ---- .../search/components/query/constants.ts | 45 - .../pages/search/components/query/index.ts | 3 - .../components/query/styles.module.scss | 0 .../search/components/query/utils.spec.ts | 173 -- .../pages/search/components/query/utils.ts | 201 --- .../results-history/ResultsHistory.spec.tsx | 157 -- .../results-history/ResultsHistory.tsx | 172 -- .../components/results-history/index.ts | 3 - .../results-history/styles.module.scss | 44 - redisinsight/ui/src/pages/search/index.ts | 3 - .../ui/src/pages/search/mocks/mocks.ts | 1521 ----------------- .../ui/src/pages/search/styles.module.scss | 32 - redisinsight/ui/src/pages/search/types.ts | 45 - .../ui/src/pages/search/utils/index.ts | 2 - .../ui/src/pages/search/utils/monaco.ts | 64 - .../ui/src/pages/search/utils/query.ts | 479 ------ .../pages/search/utils/tests/monaco.spec.ts | 60 - .../pages/search/utils/tests/query.spec.ts | 188 -- .../search/utils/tests/test-cases/common.ts | 183 -- .../utils/tests/test-cases/ft-aggregate.ts | 267 --- .../utils/tests/test-cases/ft-search.ts | 283 --- .../search/utils/tests/test-cases/index.ts | 3 - .../ui/src/pages/workbench/WorkbenchPage.tsx | 9 +- .../components/wb-view/WBViewWrapper.tsx | 3 +- .../workbench/utils/tests/monaco.spec.ts | 7 +- .../pages/workbench/utils/tests/query.spec.ts | 17 +- .../utils/tests/test-cases/common.ts | 13 +- .../ui/src/slices/interfaces/workbench.ts | 1 - .../slices/tests/workbench/wb-results.spec.ts | 26 - .../ui/src/slices/workbench/wb-results.ts | 20 +- redisinsight/ui/src/telemetry/events.ts | 12 - .../monaco/monarchTokens/redisearchTokens.ts | 99 -- .../monarchTokens/redisearchTokensSubRedis.ts | 7 +- .../redisearchTokensTemplates.ts | 6 +- .../ui/src/utils/monaco/redisearch/utils.ts | 38 +- .../src/utils/monaco/redisearch/utils_old.ts | 143 -- .../cyber/monarchTokensProvider.spec.ts | 14 +- .../ui/src/utils/tests/routing.spec.ts | 2 - 60 files changed, 84 insertions(+), 6446 deletions(-) delete mode 100644 redisinsight/ui/src/pages/search/SearchPage.spec.tsx delete mode 100644 redisinsight/ui/src/pages/search/SearchPage.tsx delete mode 100644 redisinsight/ui/src/pages/search/components/constants/supported_commands.json delete mode 100644 redisinsight/ui/src/pages/search/components/index.ts delete mode 100644 redisinsight/ui/src/pages/search/components/query-wrapper/QueryWrapper.spec.tsx delete mode 100644 redisinsight/ui/src/pages/search/components/query-wrapper/QueryWrapper.tsx delete mode 100644 redisinsight/ui/src/pages/search/components/query-wrapper/constants.ts delete mode 100644 redisinsight/ui/src/pages/search/components/query-wrapper/index.ts delete mode 100644 redisinsight/ui/src/pages/search/components/query-wrapper/styles.module.scss delete mode 100644 redisinsight/ui/src/pages/search/components/query/Query.spec.tsx delete mode 100644 redisinsight/ui/src/pages/search/components/query/Query.tsx delete mode 100644 redisinsight/ui/src/pages/search/components/query/constants.ts delete mode 100644 redisinsight/ui/src/pages/search/components/query/index.ts delete mode 100644 redisinsight/ui/src/pages/search/components/query/styles.module.scss delete mode 100644 redisinsight/ui/src/pages/search/components/query/utils.spec.ts delete mode 100644 redisinsight/ui/src/pages/search/components/query/utils.ts delete mode 100644 redisinsight/ui/src/pages/search/components/results-history/ResultsHistory.spec.tsx delete mode 100644 redisinsight/ui/src/pages/search/components/results-history/ResultsHistory.tsx delete mode 100644 redisinsight/ui/src/pages/search/components/results-history/index.ts delete mode 100644 redisinsight/ui/src/pages/search/components/results-history/styles.module.scss delete mode 100644 redisinsight/ui/src/pages/search/index.ts delete mode 100644 redisinsight/ui/src/pages/search/mocks/mocks.ts delete mode 100644 redisinsight/ui/src/pages/search/styles.module.scss delete mode 100644 redisinsight/ui/src/pages/search/types.ts delete mode 100644 redisinsight/ui/src/pages/search/utils/index.ts delete mode 100644 redisinsight/ui/src/pages/search/utils/monaco.ts delete mode 100644 redisinsight/ui/src/pages/search/utils/query.ts delete mode 100644 redisinsight/ui/src/pages/search/utils/tests/monaco.spec.ts delete mode 100644 redisinsight/ui/src/pages/search/utils/tests/query.spec.ts delete mode 100644 redisinsight/ui/src/pages/search/utils/tests/test-cases/common.ts delete mode 100644 redisinsight/ui/src/pages/search/utils/tests/test-cases/ft-aggregate.ts delete mode 100644 redisinsight/ui/src/pages/search/utils/tests/test-cases/ft-search.ts delete mode 100644 redisinsight/ui/src/pages/search/utils/tests/test-cases/index.ts delete mode 100644 redisinsight/ui/src/utils/monaco/monarchTokens/redisearchTokens.ts delete mode 100644 redisinsight/ui/src/utils/monaco/redisearch/utils_old.ts diff --git a/redisinsight/ui/src/components/main-router/constants/defaultRoutes.ts b/redisinsight/ui/src/components/main-router/constants/defaultRoutes.ts index 600f89c5e5..030df4cf24 100644 --- a/redisinsight/ui/src/components/main-router/constants/defaultRoutes.ts +++ b/redisinsight/ui/src/components/main-router/constants/defaultRoutes.ts @@ -16,7 +16,6 @@ import RdiPage from 'uiSrc/pages/rdi/home' import RdiInstancePage from 'uiSrc/pages/rdi/instance' import RdiStatisticsPage from 'uiSrc/pages/rdi/statistics' import PipelineManagementPage from 'uiSrc/pages/rdi/pipeline-management' -import SearchPage from 'uiSrc/pages/search' import { ANALYTICS_ROUTES, RDI_PIPELINE_MANAGEMENT_ROUTES } from './sub-routes' import COMMON_ROUTES from './commonRoutes' @@ -32,11 +31,6 @@ const INSTANCE_ROUTES: IRoute[] = [ path: Pages.workbench(':instanceId'), component: WorkbenchPage, }, - { - pageName: PageNames.search, - path: Pages.search(':instanceId'), - component: SearchPage, - }, { pageName: PageNames.pubSub, path: Pages.pubSub(':instanceId'), diff --git a/redisinsight/ui/src/components/main-router/constants/redisStackRoutes.ts b/redisinsight/ui/src/components/main-router/constants/redisStackRoutes.ts index 9697c50110..88502af3bc 100644 --- a/redisinsight/ui/src/components/main-router/constants/redisStackRoutes.ts +++ b/redisinsight/ui/src/components/main-router/constants/redisStackRoutes.ts @@ -9,7 +9,6 @@ import EditConnection from 'uiSrc/pages/redis-stack/components/edit-connection' import ClusterDetailsPage from 'uiSrc/pages/cluster-details' import AnalyticsPage from 'uiSrc/pages/analytics' import DatabaseAnalysisPage from 'uiSrc/pages/database-analysis' -import SearchPage from 'uiSrc/pages/search' import COMMON_ROUTES from './commonRoutes' const ANALYTICS_ROUTES: IRoute[] = [ @@ -46,12 +45,6 @@ const INSTANCE_ROUTES: IRoute[] = [ path: Pages.workbench(':instanceId'), component: WorkbenchPage, }, - { - pageName: PageNames.search, - protected: true, - path: Pages.search(':instanceId'), - component: SearchPage, - }, { pageName: PageNames.pubSub, protected: true, diff --git a/redisinsight/ui/src/components/monaco-laguages/MonacoLanguages.tsx b/redisinsight/ui/src/components/monaco-laguages/MonacoLanguages.tsx index 568775e2d4..f5cc4c1003 100644 --- a/redisinsight/ui/src/components/monaco-laguages/MonacoLanguages.tsx +++ b/redisinsight/ui/src/components/monaco-laguages/MonacoLanguages.tsx @@ -3,7 +3,7 @@ import { useSelector } from 'react-redux' import { monaco } from 'react-monaco-editor' import { findIndex } from 'lodash' import { appRedisCommandsSelector } from 'uiSrc/slices/app/redis-commands' -import { MonacoLanguage, redisLanguageConfig, Theme } from 'uiSrc/constants' +import { MonacoLanguage, redisLanguageConfig, Theme, IRedisCommandTree } from 'uiSrc/constants' import { getRedisMonarchTokensProvider } from 'uiSrc/utils' import { darkTheme, lightTheme, MonacoThemes } from 'uiSrc/constants/monaco' import { ThemeContext } from 'uiSrc/contexts/themeContext' @@ -11,7 +11,6 @@ import { ThemeContext } from 'uiSrc/contexts/themeContext' import { getRediSearchSubRedisMonarchTokensProvider } from 'uiSrc/utils/monaco/monarchTokens/redisearchTokensSubRedis' import SEARCH_COMMANDS_SPEC from 'uiSrc/pages/workbench/data/supported_commands.json' import { mergeRedisCommandsSpecs } from 'uiSrc/utils/transformers/redisCommands' -import { SearchCommandTree } from 'uiSrc/pages/search/types' import { ModuleCommandPrefix } from 'uiSrc/pages/workbench/constants' const MonacoLanguages = () => { @@ -44,7 +43,7 @@ const MonacoLanguages = () => { } monaco.languages.setLanguageConfiguration(MonacoLanguage.Redis, redisLanguageConfig) - const REDIS_COMMANDS = mergeRedisCommandsSpecs(COMMANDS_SPEC, SEARCH_COMMANDS_SPEC) as SearchCommandTree[] + const REDIS_COMMANDS = mergeRedisCommandsSpecs(COMMANDS_SPEC, SEARCH_COMMANDS_SPEC) as IRedisCommandTree[] const REDIS_SEARCH_COMMANDS = REDIS_COMMANDS.filter(({ name }) => name?.startsWith(ModuleCommandPrefix.RediSearch)) monaco.languages.setMonarchTokensProvider( diff --git a/redisinsight/ui/src/components/navigation-menu/NavigationMenu.spec.tsx b/redisinsight/ui/src/components/navigation-menu/NavigationMenu.spec.tsx index c8a07c32a4..3e964542a5 100644 --- a/redisinsight/ui/src/components/navigation-menu/NavigationMenu.spec.tsx +++ b/redisinsight/ui/src/components/navigation-menu/NavigationMenu.spec.tsx @@ -129,7 +129,6 @@ describe('NavigationMenu', () => { expect(screen.getByTestId('browser-page-btn')).toBeTruthy() expect(screen.getByTestId('workbench-page-btn')).toBeTruthy() - expect(screen.getByTestId('search-page-btn')).toBeTruthy() }) it('should render public routes', () => { diff --git a/redisinsight/ui/src/components/navigation-menu/NavigationMenu.tsx b/redisinsight/ui/src/components/navigation-menu/NavigationMenu.tsx index ef97859d0d..9711375054 100644 --- a/redisinsight/ui/src/components/navigation-menu/NavigationMenu.tsx +++ b/redisinsight/ui/src/components/navigation-menu/NavigationMenu.tsx @@ -26,8 +26,6 @@ import BrowserSVG from 'uiSrc/assets/img/sidebar/browser.svg' import BrowserActiveSVG from 'uiSrc/assets/img/sidebar/browser_active.svg' import WorkbenchSVG from 'uiSrc/assets/img/sidebar/workbench.svg' import WorkbenchActiveSVG from 'uiSrc/assets/img/sidebar/workbench_active.svg' -import SearchSVG from 'uiSrc/assets/img/sidebar/search.svg' -import SearchActiveSVG from 'uiSrc/assets/img/sidebar/search_active.svg' import SlowLogSVG from 'uiSrc/assets/img/sidebar/slowlog.svg' import SlowLogActiveSVG from 'uiSrc/assets/img/sidebar/slowlog_active.svg' import PubSubSVG from 'uiSrc/assets/img/sidebar/pubsub.svg' @@ -124,21 +122,6 @@ const NavigationMenu = () => { }, onboard: ONBOARDING_FEATURES.BROWSER_PAGE }, - { - tooltipText: 'Search and Query', - pageName: PageNames.search, - ariaLabel: 'Search and Query page button', - onClick: () => handleGoPage(Pages.search(connectedInstanceId)), - dataTestId: 'search-page-btn', - connectedInstanceId, - isActivePage: activePage === `/${PageNames.search}`, - getClassName() { - return cx(styles.navigationButton, { [styles.active]: this.isActivePage }) - }, - getIconType() { - return this.isActivePage ? SearchSVG : SearchActiveSVG - }, - }, { tooltipText: 'Workbench', pageName: PageNames.workbench, diff --git a/redisinsight/ui/src/components/query/query-card/QueryCard.tsx b/redisinsight/ui/src/components/query/query-card/QueryCard.tsx index 29b9192bbe..3f778e6859 100644 --- a/redisinsight/ui/src/components/query/query-card/QueryCard.tsx +++ b/redisinsight/ui/src/components/query/query-card/QueryCard.tsx @@ -6,7 +6,7 @@ import { useParams } from 'react-router-dom' import { isNull } from 'lodash' import { DEFAULT_TEXT_VIEW_TYPE, ProfileQueryType, WBQueryType } from 'uiSrc/pages/workbench/constants' -import { CommandExecutionType, ResultsMode, ResultsSummary, RunQueryMode } from 'uiSrc/slices/interfaces/workbench' +import { ResultsMode, ResultsSummary, RunQueryMode } from 'uiSrc/slices/interfaces/workbench' import { getVisualizationsByCommand, getWBQueryType, isGroupResults, isSilentModeWithoutError, Maybe, } from 'uiSrc/utils' import { appPluginsSelector } from 'uiSrc/slices/app/plugins' import { CommandExecutionResult, IPluginVisualization } from 'uiSrc/slices/interfaces' @@ -30,7 +30,6 @@ export interface Props { activeResultsMode?: ResultsMode resultsMode?: ResultsMode emptyCommand?: boolean - executionType?: CommandExecutionType summary?: ResultsSummary createdAt?: Date loading?: boolean @@ -68,7 +67,6 @@ const QueryCard = (props: Props) => { mode, activeResultsMode, resultsMode, - executionType = CommandExecutionType.Workbench, summary, isOpen, createdAt, @@ -113,9 +111,7 @@ const QueryCard = (props: Props) => { const toggleFullScreen = () => { setIsFullScreen((isFull) => { sendEventTelemetry({ - event: executionType === CommandExecutionType.Search - ? TelemetryEvent.SEARCH_RESULTS_IN_FULL_SCREEN - : TelemetryEvent.WORKBENCH_RESULTS_IN_FULL_SCREEN, + event: TelemetryEvent.WORKBENCH_RESULTS_IN_FULL_SCREEN, eventData: { databaseId: instanceId, state: isFull ? 'Close' : 'Open' @@ -182,7 +178,6 @@ const QueryCard = (props: Props) => { mode={mode} resultsMode={resultsMode} activeResultsMode={activeResultsMode} - executionType={executionType} emptyCommand={emptyCommand} summary={summary} summaryText={getSummaryText(summary, resultsMode)} @@ -223,7 +218,6 @@ const QueryCard = (props: Props) => { result={result} query={command} mode={mode} - executionType={executionType} setMessage={setMessage} commandId={id} /> diff --git a/redisinsight/ui/src/components/query/query-card/QueryCardCliPlugin/QueryCardCliPlugin.tsx b/redisinsight/ui/src/components/query/query-card/QueryCardCliPlugin/QueryCardCliPlugin.tsx index 629b849408..edb4cdc390 100644 --- a/redisinsight/ui/src/components/query/query-card/QueryCardCliPlugin/QueryCardCliPlugin.tsx +++ b/redisinsight/ui/src/components/query/query-card/QueryCardCliPlugin/QueryCardCliPlugin.tsx @@ -7,7 +7,7 @@ import { pluginApi } from 'uiSrc/services/PluginAPI' import { ThemeContext } from 'uiSrc/contexts/themeContext' import { getBaseApiUrl, Nullable, formatToText, replaceEmptyValue } from 'uiSrc/utils' import { Theme } from 'uiSrc/constants' -import { CommandExecutionResult, CommandExecutionType, IPluginVisualization, RunQueryMode } from 'uiSrc/slices/interfaces' +import { CommandExecutionResult, IPluginVisualization, RunQueryMode } from 'uiSrc/slices/interfaces' import { PluginEvents } from 'uiSrc/plugins/pluginEvents' import { prepareIframeHtml } from 'uiSrc/plugins/pluginImport' import { @@ -28,7 +28,6 @@ export interface Props { setMessage: (text: string) => void commandId: string mode?: RunQueryMode - executionType?: CommandExecutionType } enum StylesNamePostfix { @@ -52,7 +51,6 @@ const QueryCardCliPlugin = (props: Props) => { setMessage, commandId, mode = RunQueryMode.Raw, - executionType } = props const { visualizations = [], staticPath } = useSelector(appPluginsSelector) const { modules = [] } = useSelector(connectedInstanceSelector) @@ -93,7 +91,6 @@ const QueryCardCliPlugin = (props: Props) => { dispatch( sendPluginCommandAction({ command, - executionType, onSuccessAction: (response) => { sendMessageToPlugin({ ...commonOptions, diff --git a/redisinsight/ui/src/components/query/query-card/QueryCardHeader/QueryCardHeader.tsx b/redisinsight/ui/src/components/query/query-card/QueryCardHeader/QueryCardHeader.tsx index 64df5b56b4..23a0fe5eb9 100644 --- a/redisinsight/ui/src/components/query/query-card/QueryCardHeader/QueryCardHeader.tsx +++ b/redisinsight/ui/src/components/query/query-card/QueryCardHeader/QueryCardHeader.tsx @@ -19,27 +19,21 @@ import { getCommandNameFromQuery, getVisualizationsByCommand, isGroupMode, - isGroupResults, + truncateText, + urlForAsset, + truncateMilliseconds, isRawMode, isSilentMode, isSilentModeWithoutError, - truncateMilliseconds, - truncateText, - urlForAsset, + isGroupResults, } from 'uiSrc/utils' import { numberWithSpaces } from 'uiSrc/utils/numbers' import { ThemeContext } from 'uiSrc/contexts/themeContext' import { appPluginsSelector } from 'uiSrc/slices/app/plugins' import { sendEventTelemetry, TelemetryEvent } from 'uiSrc/telemetry' -import { - getProfileViewTypeOptions, - getViewTypeOptions, - isCommandAllowedForProfile, - ProfileQueryType, - WBQueryType -} from 'uiSrc/pages/workbench/constants' -import { CommandExecutionType, IPluginVisualization } from 'uiSrc/slices/interfaces' -import { ResultsMode, ResultsSummary, RunQueryMode } from 'uiSrc/slices/interfaces/workbench' +import { getViewTypeOptions, WBQueryType, getProfileViewTypeOptions, ProfileQueryType, isCommandAllowedForProfile } from 'uiSrc/pages/workbench/constants' +import { IPluginVisualization } from 'uiSrc/slices/interfaces' +import { RunQueryMode, ResultsMode, ResultsSummary } from 'uiSrc/slices/interfaces/workbench' import { appRedisCommandsSelector } from 'uiSrc/slices/app/redis-commands' import { FormatedDate, FullScreen } from 'uiSrc/components' @@ -63,7 +57,6 @@ export interface Props { mode?: RunQueryMode resultsMode?: ResultsMode activeResultsMode?: ResultsMode - executionType?: CommandExecutionType summary?: ResultsSummary summaryText?: string queryType: WBQueryType @@ -109,7 +102,6 @@ const QueryCardHeader = (props: Props) => { createdAt, mode, resultsMode, - executionType, summary, activeResultsMode, summaryText, @@ -129,7 +121,6 @@ const QueryCardHeader = (props: Props) => { const { instanceId = '' } = useParams<{ instanceId: string }>() const { theme } = useContext(ThemeContext) - const isExecuteTypeSearch = executionType === CommandExecutionType.Search const eventStop = (event: React.MouseEvent) => { event.preventDefault() @@ -148,12 +139,7 @@ const QueryCardHeader = (props: Props) => { } const handleCopy = (event: React.MouseEvent, query: string) => { - sendEvent( - isExecuteTypeSearch - ? TelemetryEvent.SEARCH_COMMAND_COPIED - : TelemetryEvent.WORKBENCH_COMMAND_COPIED, - query - ) + sendEvent(TelemetryEvent.WORKBENCH_COMMAND_COPIED, query) eventStop(event) navigator.clipboard?.writeText?.(query) } @@ -168,29 +154,24 @@ const QueryCardHeader = (props: Props) => { const previousView = options.find(({ id }) => id === selectedValue) const type = currentView.value setSelectedValue(type as WBQueryType, initValue) - sendEvent(isExecuteTypeSearch - ? TelemetryEvent.SEARCH_RESULT_VIEW_CHANGED - : TelemetryEvent.WORKBENCH_RESULT_VIEW_CHANGED, - query, - { - rawMode: isRawMode(activeMode), - group: isGroupMode(activeResultsMode), - previousView: previousView?.name, - isPreviousViewInternal: !!previousView?.internal, - currentView: currentView?.name, - isCurrentViewInternal: !!currentView?.internal, - }) + sendEvent( + TelemetryEvent.WORKBENCH_RESULT_VIEW_CHANGED, + query, + { + rawMode: isRawMode(activeMode), + group: isGroupMode(activeResultsMode), + previousView: previousView?.name, + isPreviousViewInternal: !!previousView?.internal, + currentView: currentView?.name, + isCurrentViewInternal: !!currentView?.internal, + } + ) } const handleQueryDelete = (event: React.MouseEvent) => { eventStop(event) onQueryDelete() - sendEvent( - isExecuteTypeSearch - ? TelemetryEvent.SEARCH_CLEAR_RESULT_CLICKED - : TelemetryEvent.WORKBENCH_CLEAR_RESULT_CLICKED, - query - ) + sendEvent(TelemetryEvent.WORKBENCH_CLEAR_RESULT_CLICKED, query) } const handleQueryReRun = (event: React.MouseEvent) => { @@ -200,14 +181,8 @@ const QueryCardHeader = (props: Props) => { const handleToggleOpen = () => { if (!isFullScreen && !isSilentModeWithoutError(resultsMode, summary?.fail)) { - const collapsedEventName = isExecuteTypeSearch - ? TelemetryEvent.SEARCH_RESULTS_COLLAPSED - : TelemetryEvent.WORKBENCH_RESULTS_COLLAPSED - const expandedEventName = isExecuteTypeSearch - ? TelemetryEvent.SEARCH_RESULTS_EXPANDED - : TelemetryEvent.WORKBENCH_RESULTS_EXPANDED sendEvent( - isOpen ? collapsedEventName : expandedEventName, + isOpen ? TelemetryEvent.WORKBENCH_RESULTS_COLLAPSED : TelemetryEvent.WORKBENCH_RESULTS_EXPANDED, query ) } diff --git a/redisinsight/ui/src/components/side-panels/panels/ai-assistant/components/shared/markdown-message/components/code-block/CodeBlock.spec.tsx b/redisinsight/ui/src/components/side-panels/panels/ai-assistant/components/shared/markdown-message/components/code-block/CodeBlock.spec.tsx index 98bbebd6a9..df43dc81bb 100644 --- a/redisinsight/ui/src/components/side-panels/panels/ai-assistant/components/shared/markdown-message/components/code-block/CodeBlock.spec.tsx +++ b/redisinsight/ui/src/components/side-panels/panels/ai-assistant/components/shared/markdown-message/components/code-block/CodeBlock.spec.tsx @@ -29,7 +29,6 @@ describe('CodeBlock', () => { sendWBCommand({ commandId: expect.any(String), commands: ['info'], - executionType: CommandExecutionType.Workbench }), setDbIndexState(true) ]) diff --git a/redisinsight/ui/src/components/side-panels/panels/ai-assistant/components/shared/markdown-message/components/code-block/CodeBlock.tsx b/redisinsight/ui/src/components/side-panels/panels/ai-assistant/components/shared/markdown-message/components/code-block/CodeBlock.tsx index 582e9b94c8..eb319636af 100644 --- a/redisinsight/ui/src/components/side-panels/panels/ai-assistant/components/shared/markdown-message/components/code-block/CodeBlock.tsx +++ b/redisinsight/ui/src/components/side-panels/panels/ai-assistant/components/shared/markdown-message/components/code-block/CodeBlock.tsx @@ -4,7 +4,6 @@ import { CodeButtonParams } from 'uiSrc/constants' import { sendWbQueryAction } from 'uiSrc/slices/workbench/wb-results' import { CodeButtonBlock } from 'uiSrc/components/markdown' import { ButtonLang } from 'uiSrc/utils/formatters/markdown/remarkCode' -import { CommandExecutionType } from 'uiSrc/slices/interfaces' import { AdditionalRedisModule } from 'apiSrc/modules/database/models/additional.redis.module' export interface Props { @@ -25,7 +24,6 @@ const CodeBlock = (props: Props) => { children, null, params, - CommandExecutionType.Workbench, { afterAll: onFinish }, onFinish )) diff --git a/redisinsight/ui/src/components/side-panels/panels/enablement-area/EnablementAreaWrapper.tsx b/redisinsight/ui/src/components/side-panels/panels/enablement-area/EnablementAreaWrapper.tsx index e94b0ee661..a4816a17ad 100644 --- a/redisinsight/ui/src/components/side-panels/panels/enablement-area/EnablementAreaWrapper.tsx +++ b/redisinsight/ui/src/components/side-panels/panels/enablement-area/EnablementAreaWrapper.tsx @@ -7,7 +7,6 @@ import { workbenchCustomTutorialsSelector } from 'uiSrc/slices/workbench/wb-cust import { sendEventTelemetry, TELEMETRY_EMPTY_VALUE, TelemetryEvent } from 'uiSrc/telemetry' import { CodeButtonParams } from 'uiSrc/constants' import { sendWbQueryAction } from 'uiSrc/slices/workbench/wb-results' -import { CommandExecutionType } from 'uiSrc/slices/interfaces' import { getTutorialSection } from './EnablementArea/utils' import EnablementArea from './EnablementArea' @@ -31,7 +30,6 @@ const EnablementAreaWrapper = () => { script, null, params, - CommandExecutionType.Workbench, { afterAll: onFinish }, onFinish )) diff --git a/redisinsight/ui/src/pages/search/SearchPage.spec.tsx b/redisinsight/ui/src/pages/search/SearchPage.spec.tsx deleted file mode 100644 index c160ed2a87..0000000000 --- a/redisinsight/ui/src/pages/search/SearchPage.spec.tsx +++ /dev/null @@ -1,79 +0,0 @@ -import React from 'react' -import { cloneDeep } from 'lodash' -import { cleanup, fireEvent, mockedStore, render, screen } from 'uiSrc/utils/test-utils' - -import { loadWBHistory, sendWBCommand, setExecutionType } from 'uiSrc/slices/workbench/wb-results' -import { setDbIndexState } from 'uiSrc/slices/app/context' -import { sendPageViewTelemetry, TelemetryPageView } from 'uiSrc/telemetry' -import { CommandExecutionType } from 'uiSrc/slices/interfaces' -import SearchPage from './SearchPage' - -jest.mock('uiSrc/slices/app/context', () => ({ - ...jest.requireActual('uiSrc/slices/app/context'), - appContextSearchAndQuery: jest.fn().mockReturnValue({ - script: 'value', - panelSizes: { vertical: 100 } - }) -})) - -jest.mock('uiSrc/slices/instances/instances', () => ({ - ...jest.requireActual('uiSrc/slices/instances/instances'), - connectedInstanceSelector: jest.fn().mockReturnValue({ - name: 'db_name', - }), -})) - -jest.mock('uiSrc/telemetry', () => ({ - ...jest.requireActual('uiSrc/telemetry'), - sendEventTelemetry: jest.fn(), - sendPageViewTelemetry: jest.fn() -})) - -let store: typeof mockedStore -beforeEach(() => { - cleanup() - store = cloneDeep(mockedStore) - store.clearActions() -}) - -/** - * SearchPage tests - * - * @group component - */ -describe('SearchPage', () => { - it('should render', () => { - expect(render()).toBeTruthy() - }) - - it('should send page event', () => { - const sendPageViewTelemetryMock = jest.fn(); - (sendPageViewTelemetry as jest.Mock).mockImplementation(() => sendPageViewTelemetryMock) - - render() - - expect(sendPageViewTelemetry).toBeCalledWith({ - name: TelemetryPageView.SEARCH_AND_QUERY_PAGE, - eventData: { - databaseId: 'instanceId' - } - }) - }) - - it('should call proper actions on submit', () => { - render() - - fireEvent.click(screen.getByTestId('btn-submit')) - - expect(store.getActions()).toEqual([ - loadWBHistory(), - setExecutionType(CommandExecutionType.Search), - sendWBCommand({ - commandId: expect.any(String), - commands: ['value'], - executionType: CommandExecutionType.Search - }), - setDbIndexState(true) - ]) - }) -}) diff --git a/redisinsight/ui/src/pages/search/SearchPage.tsx b/redisinsight/ui/src/pages/search/SearchPage.tsx deleted file mode 100644 index 2ff8291b8a..0000000000 --- a/redisinsight/ui/src/pages/search/SearchPage.tsx +++ /dev/null @@ -1,128 +0,0 @@ -import React, { useCallback, useEffect, useRef, useState } from 'react' -import cx from 'classnames' -import { EuiResizableContainer } from '@elastic/eui' -import { useDispatch, useSelector } from 'react-redux' - -import { useParams } from 'react-router-dom' -import { appContextSearchAndQuery, setSQVerticalPanelSizes, } from 'uiSrc/slices/app/context' -import { QueryWrapper, ResultsHistory } from 'uiSrc/pages/search/components' - -import { sendWbQueryAction, setExecutionType } from 'uiSrc/slices/workbench/wb-results' -import { formatLongName, getDbIndex, Nullable, setTitle } from 'uiSrc/utils' - -import { connectedInstanceSelector } from 'uiSrc/slices/instances/instances' -import { sendPageViewTelemetry, TelemetryPageView } from 'uiSrc/telemetry' -import { CodeButtonParams } from 'uiSrc/constants' - -import { CommandExecutionType } from 'uiSrc/slices/interfaces' -import { appRedisCommandsSelector } from 'uiSrc/slices/app/redis-commands' -import styles from './styles.module.scss' - -const verticalPanelIds = { - firstPanelId: 'scriptingArea', - secondPanelId: 'resultsArea' -} - -const SearchPage = () => { - const { name: connectedInstanceName, db } = useSelector(connectedInstanceSelector) - const { commandsArray, spec } = useSelector(appRedisCommandsSelector) - - const { panelSizes: { vertical } } = useSelector(appContextSearchAndQuery) - const [isPageViewSent, setIsPageViewSent] = useState(false) - - const { instanceId } = useParams<{ instanceId: string }>() - const verticalSizesRef = useRef(vertical) - - const dispatch = useDispatch() - - setTitle(`${formatLongName(connectedInstanceName, 33, 0, '...')} ${getDbIndex(db)} - Search and Query`) - - useEffect(() => { - dispatch(setExecutionType(CommandExecutionType.Search)) - return () => { - dispatch(setSQVerticalPanelSizes(verticalSizesRef.current)) - } - }, []) - - useEffect(() => { - if (connectedInstanceName && !isPageViewSent) { - sendPageView(instanceId) - } - }, [connectedInstanceName, isPageViewSent]) - - const onVerticalPanelWidthChange = useCallback((newSizes: any) => { - verticalSizesRef.current = newSizes - }, []) - - const sendPageView = (instanceId: string) => { - sendPageViewTelemetry({ - name: TelemetryPageView.SEARCH_AND_QUERY_PAGE, - eventData: { - databaseId: instanceId - } - }) - setIsPageViewSent(true) - } - - const handleSubmit = ( - commandInit: string, - commandId?: Nullable, - executeParams: CodeButtonParams = {} - ) => { - dispatch(sendWbQueryAction( - commandInit, - commandId, - { - ...executeParams, - results: 'single', - }, - CommandExecutionType.Search - )) - } - - return ( -
-
-
- - {(EuiResizablePanel, EuiResizableButton) => ( - <> - - - - - - - - - - - )} - -
-
-
- ) -} - -export default SearchPage diff --git a/redisinsight/ui/src/pages/search/components/constants/supported_commands.json b/redisinsight/ui/src/pages/search/components/constants/supported_commands.json deleted file mode 100644 index fa08d11556..0000000000 --- a/redisinsight/ui/src/pages/search/components/constants/supported_commands.json +++ /dev/null @@ -1,1156 +0,0 @@ -{ - "FT.AGGREGATE": { - "summary": "Run a search query on an index and perform aggregate transformations on the results", - "complexity": "O(1)", - "arguments": [ - { - "name": "index", - "type": "string" - }, - { - "name": "query", - "type": "string" - }, - { - "name": "verbatim", - "type": "pure-token", - "token": "VERBATIM", - "optional": true - }, - { - "name": "load", - "type": "block", - "optional": true, - "arguments": [ - { - "name": "count", - "type": "string", - "token": "LOAD" - }, - { - "name": "field", - "type": "string", - "multiple": true - } - ] - }, - { - "name": "timeout", - "type": "integer", - "optional": true, - "token": "TIMEOUT" - }, - { - "name": "loadall", - "type": "pure-token", - "token": "LOAD *", - "optional": true - }, - { - "name": "groupby", - "type": "block", - "optional": true, - "multiple": true, - "arguments": [ - { - "name": "nargs", - "type": "integer", - "token": "GROUPBY" - }, - { - "name": "property", - "type": "string", - "multiple": true - }, - { - "name": "reduce", - "type": "block", - "optional": true, - "multiple": true, - "arguments": [ - { - "name": "reduce", - "token": "REDUCE", - "type": "pure-token" - }, - { - "name": "function", - "type": "oneof", - "arguments": [ - { - "name": "count", - "type": "pure-token", - "token": "COUNT" - }, - { - "name": "count_distinct", - "type": "pure-token", - "token": "COUNT_DISTINCT" - }, - { - "name": "count_distinctish", - "type": "pure-token", - "token": "COUNT_DISTINCTISH" - }, - { - "name": "sum", - "type": "pure-token", - "token": "SUM" - }, - { - "name": "min", - "type": "pure-token", - "token": "MIN" - }, - { - "name": "max", - "type": "pure-token", - "token": "MAX" - }, - { - "name": "avg", - "type": "pure-token", - "token": "AVG" - }, - { - "name": "stddev", - "type": "pure-token", - "token": "STDDEV" - }, - { - "name": "quantile", - "type": "pure-token", - "token": "QUANTILE" - }, - { - "name": "tolist", - "type": "pure-token", - "token": "TOLIST" - }, - { - "name": "first_value", - "type": "pure-token", - "token": "FIRST_VALUE" - }, - { - "name": "random_sample", - "type": "pure-token", - "token": "RANDOM_SAMPLE" - } - ] - }, - { - "name": "nargs", - "type": "integer" - }, - { - "name": "arg", - "type": "string", - "multiple": true - }, - { - "name": "name", - "type": "string", - "token": "AS", - "optional": true - } - ] - } - ] - }, - { - "name": "sortby", - "type": "block", - "optional": true, - "arguments": [ - { - "name": "nargs", - "type": "integer", - "token": "SORTBY" - }, - { - "name": "fields", - "type": "block", - "optional": true, - "multiple": true, - "arguments": [ - { - "name": "property", - "type": "string" - }, - { - "name": "order", - "type": "oneof", - "arguments": [ - { - "name": "asc", - "type": "pure-token", - "token": "ASC" - }, - { - "name": "desc", - "type": "pure-token", - "token": "DESC" - } - ] - } - ] - }, - { - "name": "num", - "type": "integer", - "token": "MAX", - "optional": true - } - ] - }, - { - "name": "apply", - "type": "block", - "optional": true, - "multiple": true, - "arguments": [ - { - "name": "expression", - "type": "string", - "expression": true, - "token": "APPLY", - "arguments": [ - { - "name": "exists", - "token": "exists", - "type": "function", - "summary": "Checks whether a field exists in a document.", - "arguments": [ - { - "token": "s" - } - ] - }, - { - "name": "log", - "token": "log", - "type": "function", - "summary": "Return the logarithm of a number, property or subexpression", - "arguments": [ - { - "token": "x" - } - ] - }, - { - "name": "abs", - "token": "abs", - "type": "function", - "summary": "Return the absolute number of a numeric expression", - "arguments": [ - { - "token": "x" - } - ] - }, - { - "name": "ceil", - "token": "ceil", - "type": "function", - "summary": "Round to the smallest value not less than x", - "arguments": [ - { - "token": "x" - } - ] - }, - { - "name": "floor", - "token": "floor", - "type": "function", - "summary": "Round to largest value not greater than x", - "arguments": [ - { - "token": "x" - } - ] - }, - { - "name": "log2", - "token": "log2", - "type": "function", - "summary": "Return the logarithm of x to base 2", - "arguments": [ - { - "token": "x" - } - ] - }, - { - "name": "exp", - "token": "exp", - "type": "function", - "summary": "Return the exponent of x, e.g., e^x", - "arguments": [ - { - "token": "x" - } - ] - }, - { - "name": "sqrt", - "token": "sqrt", - "type": "function", - "summary": "Return the square root of x", - "arguments": [ - { - "token": "x" - } - ] - }, - { - "name": "upper", - "token": "upper", - "type": "function", - "summary": "Return the uppercase conversion of s", - "arguments": [ - { - "token": "s" - } - ] - }, - { - "name": "lower", - "token": "lower", - "type": "function", - "summary": "Return the lowercase conversion of s", - "arguments": [ - { - "token": "s" - } - ] - }, - { - "name": "startswith", - "token": "startswith", - "type": "function", - "summary": "Return 1 if s2 is the prefix of s1, 0 otherwise.", - "arguments": [ - { - "token": "s1" - }, - { - "token": "s2" - } - ] - }, - { - "name": "contains", - "token": "contains", - "type": "function", - "summary": "Return the number of occurrences of s2 in s1, 0 otherwise. If s2 is an empty string, return length(s1) + 1.", - "arguments": [ - { - "token": "s1" - }, - { - "token": "s2" - } - ] - }, - { - "name": "strlen", - "token": "strlen", - "type": "function", - "summary": "Return the length of s", - "arguments": [ - { - "token": "s" - } - ] - }, - { - "name": "substr", - "token": "substr", - "type": "function", - "summary": "Return the substring of s, starting at offset and having count characters.If offset is negative, it represents the distance from the end of the string.If count is -1, it means \"the rest of the string starting at offset\".", - "arguments": [ - { - "token": "s" - }, - { - "token": "offset" - }, - { - "token": "count" - } - ] - }, - { - "name": "format", - "token": "format", - "type": "function", - "summary": "Use the arguments following fmt to format a string.Currently the only format argument supported is %s and it applies to all types of arguments.", - "arguments": [ - { - "token": "fmt" - } - ] - }, - { - "name": "matched_terms", - "token": "matched_terms", - "type": "function", - "summary": "Return the query terms that matched for each record (up to 100), as a list. If a limit is specified, Redis will return the first N matches found, based on query order.", - "arguments": [ - { - "token": "max_terms=100", - "optional": true - } - ] - }, - { - "name": "split", - "token": "split", - "type": "function", - "summary": "Split a string by any character in the string sep, and strip any characters in strip. If only s is specified, it is split by commas and spaces are stripped. The output is an array.", - "arguments": [ - { - "token": "s" - } - ] - }, - { - "name": "timefmt", - "token": "timefmt", - "type": "function", - "summary": "Return a formatted time string based on a numeric timestamp value x.", - "arguments": [ - { - "token": "x" - }, - { - "token": "fmt", - "optional": true - } - ] - }, - { - "name": "parsetime", - "token": "parsetime", - "type": "function", - "summary": "The opposite of timefmt() - parse a time format using a given format string", - "arguments": [ - { - "token": "timesharing" - }, - { - "token": "fmt", - "optional": true - } - ] - }, - { - "name": "day", - "token": "day", - "type": "function", - "summary": "Round a Unix timestamp to midnight (00:00) start of the current day.", - "arguments": [ - { - "token": "timestamp" - } - ] - }, - { - "name": "hour", - "token": "hour", - "type": "function", - "summary": "Round a Unix timestamp to the beginning of the current hour.", - "arguments": [ - { - "token": "timestamp" - } - ] - }, - { - "name": "minute", - "token": "minute", - "type": "function", - "summary": "Round a Unix timestamp to the beginning of the current minute.", - "arguments": [ - { - "token": "timestamp" - } - ] - }, - { - "name": "month", - "token": "month", - "type": "function", - "summary": "Round a unix timestamp to the beginning of the current month.", - "arguments": [ - { - "token": "timestamp" - } - ] - }, - { - "name": "dayofweek", - "token": "dayofweek", - "type": "function", - "summary": "Convert a Unix timestamp to the day number (Sunday = 0).", - "arguments": [ - { - "token": "timestamp" - } - ] - }, - { - "name": "dayofmonth", - "token": "dayofmonth", - "type": "function", - "summary": "Convert a Unix timestamp to the day of month number (1 .. 31).", - "arguments": [ - { - "token": "timestamp" - } - ] - }, - { - "name": "dayofyear", - "token": "dayofyear", - "type": "function", - "summary": "Convert a Unix timestamp to the day of year number (0 .. 365).", - "arguments": [ - { - "token": "timestamp" - } - ] - }, - { - "name": "year", - "token": "year", - "type": "function", - "summary": "Convert a Unix timestamp to the current year (e.g. 2018).", - "arguments": [ - { - "token": "timestamp" - } - ] - }, - { - "name": "monthofyear", - "token": "monthofyear", - "type": "function", - "summary": "Convert a Unix timestamp to the current month (0 .. 11).", - "arguments": [ - { - "token": "timestamp" - } - ] - }, - { - "name": "geodistance", - "token": "geodistance", - "type": "function", - "summary": "Return distance in meters.", - "arguments": [ - { - "token": "" - } - ] - } - ] - }, - { - "name": "name", - "type": "string", - "token": "AS" - } - ] - }, - { - "name": "limit", - "type": "block", - "optional": true, - "arguments": [ - { - "name": "limit", - "type": "pure-token", - "token": "LIMIT" - }, - { - "name": "offset", - "type": "integer" - }, - { - "name": "num", - "type": "integer" - } - ] - }, - { - "name": "filter", - "type": "string", - "optional": true, - "expression": true, - "token": "FILTER" - }, - { - "name": "cursor", - "type": "block", - "optional": true, - "arguments": [ - { - "name": "withcursor", - "type": "pure-token", - "token": "WITHCURSOR" - }, - { - "name": "read_size", - "type": "integer", - "optional": true, - "token": "COUNT" - }, - { - "name": "idle_time", - "type": "integer", - "optional": true, - "token": "MAXIDLE" - } - ] - }, - { - "name": "params", - "type": "block", - "optional": true, - "arguments": [ - { - "name": "params", - "type": "pure-token", - "token": "PARAMS" - }, - { - "name": "nargs", - "type": "integer" - }, - { - "name": "values", - "type": "block", - "multiple": true, - "arguments": [ - { - "name": "name", - "type": "string" - }, - { - "name": "value", - "type": "string" - } - ] - } - ] - }, - { - "name": "dialect", - "type": "integer", - "optional": true, - "token": "DIALECT", - "since": "2.4.3" - } - ], - "since": "1.1.0", - "group": "search", - "provider": "redisearch" - }, - "FT.EXPLAIN": { - "summary": "Returns the execution plan for a complex query", - "complexity": "O(1)", - "arguments": [ - { - "name": "index", - "type": "string" - }, - { - "name": "query", - "type": "string" - }, - { - "name": "dialect", - "type": "integer", - "optional": true, - "token": "DIALECT", - "since": "2.4.3" - } - ], - "since": "1.0.0", - "group": "search", - "provider": "redisearch" - }, - "FT.PROFILE": { - "summary": "Performs a `FT.SEARCH` or `FT.AGGREGATE` command and collects performance information", - "complexity": "O(N)", - "arguments": [ - { - "name": "index", - "type": "string" - }, - { - "name": "querytype", - "type": "oneof", - "arguments": [ - { - "name": "search", - "type": "pure-token", - "token": "SEARCH" - }, - { - "name": "aggregate", - "type": "pure-token", - "token": "AGGREGATE" - } - ] - }, - { - "name": "limited", - "type": "pure-token", - "token": "LIMITED", - "optional": true - }, - { - "name": "queryword", - "type": "pure-token", - "token": "QUERY", - "expression": true - }, - { - "name": "query", - "type": "string" - } - ], - "since": "2.2.0", - "group": "search", - "provider": "redisearch" - }, - "FT.SEARCH": { - "summary": "Searches the index with a textual query, returning either documents or just ids", - "complexity": "O(N)", - "history": [ - [ - "2.0.0", - "Deprecated `WITHPAYLOADS` and `PAYLOAD` arguments" - ] - ], - "arguments": [ - { - "name": "index", - "type": "string" - }, - { - "name": "query", - "type": "string" - }, - { - "name": "nocontent", - "type": "pure-token", - "token": "NOCONTENT", - "optional": true - }, - { - "name": "verbatim", - "type": "pure-token", - "token": "VERBATIM", - "optional": true - }, - { - "name": "nostopwords", - "type": "pure-token", - "token": "NOSTOPWORDS", - "optional": true - }, - { - "name": "withscores", - "type": "pure-token", - "token": "WITHSCORES", - "optional": true - }, - { - "name": "withpayloads", - "type": "pure-token", - "token": "WITHPAYLOADS", - "optional": true - }, - { - "name": "withsortkeys", - "type": "pure-token", - "token": "WITHSORTKEYS", - "optional": true - }, - { - "name": "filter", - "type": "block", - "optional": true, - "multiple": true, - "arguments": [ - { - "name": "numeric_field", - "type": "string", - "token": "FILTER" - }, - { - "name": "min", - "type": "double" - }, - { - "name": "max", - "type": "double" - } - ] - }, - { - "name": "geo_filter", - "type": "block", - "optional": true, - "multiple": true, - "arguments": [ - { - "name": "geo_field", - "type": "string", - "token": "GEOFILTER" - }, - { - "name": "lon", - "type": "double" - }, - { - "name": "lat", - "type": "double" - }, - { - "name": "radius", - "type": "double" - }, - { - "name": "radius_type", - "type": "oneof", - "arguments": [ - { - "name": "m", - "type": "pure-token", - "token": "m" - }, - { - "name": "km", - "type": "pure-token", - "token": "km" - }, - { - "name": "mi", - "type": "pure-token", - "token": "mi" - }, - { - "name": "ft", - "type": "pure-token", - "token": "ft" - } - ] - } - ] - }, - { - "name": "in_keys", - "type": "block", - "optional": true, - "arguments": [ - { - "name": "count", - "type": "string", - "token": "INKEYS" - }, - { - "name": "key", - "type": "string", - "multiple": true - } - ] - }, - { - "name": "in_fields", - "type": "block", - "optional": true, - "arguments": [ - { - "name": "count", - "type": "string", - "token": "INFIELDS" - }, - { - "name": "field", - "type": "string", - "multiple": true - } - ] - }, - { - "name": "return", - "type": "block", - "optional": true, - "arguments": [ - { - "name": "count", - "type": "string", - "token": "RETURN" - }, - { - "name": "identifiers", - "type": "block", - "multiple": true, - "arguments": [ - { - "name": "identifier", - "type": "string" - }, - { - "name": "property", - "type": "string", - "token": "AS", - "optional": true - } - ] - } - ] - }, - { - "name": "summarize", - "type": "block", - "optional": true, - "arguments": [ - { - "name": "summarize", - "type": "pure-token", - "token": "SUMMARIZE" - }, - { - "name": "fields", - "type": "block", - "optional": true, - "arguments": [ - { - "name": "count", - "type": "string", - "token": "FIELDS" - }, - { - "name": "field", - "type": "string", - "multiple": true - } - ] - }, - { - "name": "num", - "type": "integer", - "token": "FRAGS", - "optional": true - }, - { - "name": "fragsize", - "type": "integer", - "token": "LEN", - "optional": true - }, - { - "name": "separator", - "type": "string", - "token": "SEPARATOR", - "optional": true - } - ] - }, - { - "name": "highlight", - "type": "block", - "optional": true, - "arguments": [ - { - "name": "highlight", - "type": "pure-token", - "token": "HIGHLIGHT" - }, - { - "name": "fields", - "type": "block", - "optional": true, - "arguments": [ - { - "name": "count", - "type": "string", - "token": "FIELDS" - }, - { - "name": "field", - "type": "string", - "multiple": true - } - ] - }, - { - "name": "tags", - "type": "block", - "optional": true, - "arguments": [ - { - "name": "tags", - "type": "pure-token", - "token": "TAGS" - }, - { - "name": "open", - "type": "string" - }, - { - "name": "close", - "type": "string" - } - ] - } - ] - }, - { - "name": "slop", - "type": "integer", - "optional": true, - "token": "SLOP" - }, - { - "name": "timeout", - "type": "integer", - "optional": true, - "token": "TIMEOUT" - }, - { - "name": "inorder", - "type": "pure-token", - "token": "INORDER", - "optional": true - }, - { - "name": "language", - "type": "string", - "optional": true, - "token": "LANGUAGE" - }, - { - "name": "expander", - "type": "string", - "optional": true, - "token": "EXPANDER" - }, - { - "name": "scorer", - "type": "string", - "optional": true, - "token": "SCORER" - }, - { - "name": "explainscore", - "type": "pure-token", - "token": "EXPLAINSCORE", - "optional": true - }, - { - "name": "payload", - "type": "string", - "optional": true, - "token": "PAYLOAD" - }, - { - "name": "sortby", - "type": "block", - "optional": true, - "arguments": [ - { - "name": "sortby", - "type": "string", - "token": "SORTBY" - }, - { - "name": "order", - "type": "oneof", - "optional": true, - "arguments": [ - { - "name": "asc", - "type": "pure-token", - "token": "ASC" - }, - { - "name": "desc", - "type": "pure-token", - "token": "DESC" - } - ] - } - ] - }, - { - "name": "limit", - "type": "block", - "optional": true, - "arguments": [ - { - "name": "limit", - "type": "pure-token", - "token": "LIMIT" - }, - { - "name": "offset", - "type": "integer" - }, - { - "name": "num", - "type": "integer" - } - ] - }, - { - "name": "params", - "type": "block", - "optional": true, - "arguments": [ - { - "name": "params", - "type": "pure-token", - "token": "PARAMS" - }, - { - "name": "nargs", - "type": "integer" - }, - { - "name": "values", - "type": "block", - "multiple": true, - "arguments": [ - { - "name": "name", - "type": "string" - }, - { - "name": "value", - "type": "string" - } - ] - } - ] - }, - { - "name": "dialect", - "type": "integer", - "optional": true, - "token": "DIALECT", - "since": "2.4.3" - } - ], - "since": "1.0.0", - "group": "search", - "provider": "redisearch" - } -} diff --git a/redisinsight/ui/src/pages/search/components/index.ts b/redisinsight/ui/src/pages/search/components/index.ts deleted file mode 100644 index 0d65962608..0000000000 --- a/redisinsight/ui/src/pages/search/components/index.ts +++ /dev/null @@ -1,7 +0,0 @@ -import QueryWrapper from './query-wrapper' -import ResultsHistory from './results-history' - -export { - QueryWrapper, - ResultsHistory, -} diff --git a/redisinsight/ui/src/pages/search/components/query-wrapper/QueryWrapper.spec.tsx b/redisinsight/ui/src/pages/search/components/query-wrapper/QueryWrapper.spec.tsx deleted file mode 100644 index cb604dcca3..0000000000 --- a/redisinsight/ui/src/pages/search/components/query-wrapper/QueryWrapper.spec.tsx +++ /dev/null @@ -1,91 +0,0 @@ -import React from 'react' -import { cloneDeep } from 'lodash' -import { cleanup, mockedStore, render, fireEvent, screen } from 'uiSrc/utils/test-utils' - -import { loadList } from 'uiSrc/slices/browser/redisearch' -import { changeSQActiveRunQueryMode } from 'uiSrc/slices/search/searchAndQuery' -import { RunQueryMode } from 'uiSrc/slices/interfaces' -import { sendEventTelemetry, TelemetryEvent } from 'uiSrc/telemetry' -import QueryWrapper from './QueryWrapper' - -jest.mock('uiSrc/slices/instances/instances', () => ({ - ...jest.requireActual('uiSrc/slices/instances/instances'), - connectedInstanceSelector: jest.fn().mockReturnValue({ - id: '123', - connectionType: 'STANDALONE', - db: 0, - }), -})) - -jest.mock('uiSrc/slices/app/context', () => ({ - ...jest.requireActual('uiSrc/slices/app/context'), - appContextSearchAndQuery: jest.fn().mockReturnValue({ - script: 'value' - }) -})) - -jest.mock('uiSrc/telemetry', () => ({ - ...jest.requireActual('uiSrc/telemetry'), - sendEventTelemetry: jest.fn(), -})) - -let store: typeof mockedStore -beforeEach(() => { - cleanup() - store = cloneDeep(mockedStore) - store.clearActions() -}) - -describe('Query', () => { - it('should render', () => { - expect(render()).toBeTruthy() - }) - - it('should fetch list of indexes', () => { - render() - - expect(store.getActions()).toEqual([loadList()]) - }) - - it('should call proper actions after change mode', () => { - render() - - fireEvent.click(screen.getByTestId('btn-change-mode')) - - expect(store.getActions()).toEqual([loadList(), changeSQActiveRunQueryMode(RunQueryMode.Raw)]) - }) - - it('should call proper actions after submit', () => { - const sendEventTelemetryMock = jest.fn(); - (sendEventTelemetry as jest.Mock).mockImplementation(() => sendEventTelemetryMock) - - const onSubmit = jest.fn() - render() - - fireEvent.click(screen.getByTestId('btn-submit')) - - expect(onSubmit).toBeCalledWith('value', undefined, { mode: RunQueryMode.ASCII }) - - expect(sendEventTelemetry).toBeCalledWith({ - event: TelemetryEvent.SEARCH_COMMAND_SUBMITTED, - eventData: { - databaseId: 'instanceId', - mode: RunQueryMode.ASCII, - command: 'value' - } - }) - }) - - it('should call onSubmit with proper value', () => { - const sendEventTelemetryMock = jest.fn(); - (sendEventTelemetry as jest.Mock).mockImplementation(() => sendEventTelemetryMock) - - const onSubmit = jest.fn() - render() - - fireEvent.change(screen.getByTestId('monaco'), { target: { value: 'set\ra\rb\n\nc \nd' } }) - fireEvent.click(screen.getByTestId('btn-submit')) - - expect(onSubmit).toBeCalledWith('set a b c d', undefined, { mode: RunQueryMode.ASCII }) - }) -}) diff --git a/redisinsight/ui/src/pages/search/components/query-wrapper/QueryWrapper.tsx b/redisinsight/ui/src/pages/search/components/query-wrapper/QueryWrapper.tsx deleted file mode 100644 index accad99537..0000000000 --- a/redisinsight/ui/src/pages/search/components/query-wrapper/QueryWrapper.tsx +++ /dev/null @@ -1,135 +0,0 @@ -import React, { useEffect, useRef, useState } from 'react' -import { useDispatch, useSelector } from 'react-redux' -import { useParams } from 'react-router-dom' -import { QueryActions, QueryTutorials } from 'uiSrc/components/query' - -import { RunQueryMode } from 'uiSrc/slices/interfaces' -import { CodeButtonParams, ICommands } from 'uiSrc/constants' - -import { getCommandsFromQuery, Nullable } from 'uiSrc/utils' -import { changeSQActiveRunQueryMode, searchAndQuerySelector } from 'uiSrc/slices/search/searchAndQuery' -import { appContextSearchAndQuery, setSQScript } from 'uiSrc/slices/app/context' -import { sendEventTelemetry, TelemetryEvent } from 'uiSrc/telemetry' -import { fetchRedisearchListAction, redisearchListSelector } from 'uiSrc/slices/browser/redisearch' -import { connectedInstanceSelector } from 'uiSrc/slices/instances/instances' -import { SearchCommand } from 'uiSrc/pages/search/types' -import { ModuleCommandPrefix } from 'uiSrc/pages/workbench/constants' -import { TUTORIALS } from './constants' - -import REDIS_COMMANDS_SPEC from '../constants/supported_commands.json' - -import Query from '../query' - -import styles from './styles.module.scss' - -export interface Props { - commandsArray?: string[] - spec?: ICommands - onSubmit: ( - commandInit: string, - commandId?: Nullable, - executeParams?: CodeButtonParams - ) => void -} - -const QueryWrapper = (props: Props) => { - const { commandsArray = [], spec = {}, onSubmit } = props - - const { id: connectedIndstanceId } = useSelector(connectedInstanceSelector) - const { script: scriptContext } = useSelector(appContextSearchAndQuery) - const { activeRunQueryMode } = useSelector(searchAndQuerySelector) - const { data: indexes = [] } = useSelector(redisearchListSelector) - - const [value, setValue] = useState(scriptContext) - - const input = useRef(null) - const scriptRef = useRef('') - - const getCommandByName = (name: string) => - (name in REDIS_COMMANDS_SPEC ? REDIS_COMMANDS_SPEC[name] : (spec[name] || {})) - - const SUPPORTED_COMMANDS = commandsArray - .filter((item) => item.startsWith(ModuleCommandPrefix.RediSearch)) - .map((name) => ({ ...getCommandByName(name), name })) as unknown as SearchCommand[] - - const { instanceId } = useParams<{ instanceId: string }>() - - const dispatch = useDispatch() - - useEffect(() => () => { - dispatch(setSQScript(scriptRef.current)) - }, []) - - useEffect(() => { - if (!connectedIndstanceId) return - - // fetch indexes - dispatch(fetchRedisearchListAction()) - }, [connectedIndstanceId]) - - useEffect(() => { - scriptRef.current = value - }, [value]) - - const handleChangeQueryRunMode = () => { - dispatch(changeSQActiveRunQueryMode( - activeRunQueryMode === RunQueryMode.ASCII - ? RunQueryMode.Raw - : RunQueryMode.ASCII - )) - } - - const handleSubmit = () => { - const val = value - .replace(/[\r\n?]{2}|\n\n/g, ' ') - .replace(/\n/g, ' ') - if (!val) return - - onSubmit(val, undefined, { mode: activeRunQueryMode }) - sendEventTelemetry({ - event: TelemetryEvent.SEARCH_COMMAND_SUBMITTED, - eventData: { - databaseId: instanceId, - mode: activeRunQueryMode, - command: getCommandsFromQuery(value, commandsArray) || '' - } - }) - } - - const handleChange = (val: string) => { - setValue(val) - } - - return ( -
-
{}} - role="textbox" - tabIndex={0} - data-testid="main-input-container-area" - > -
- -
-
- - -
-
-
- ) -} - -export default React.memo(QueryWrapper) diff --git a/redisinsight/ui/src/pages/search/components/query-wrapper/constants.ts b/redisinsight/ui/src/pages/search/components/query-wrapper/constants.ts deleted file mode 100644 index 322307978f..0000000000 --- a/redisinsight/ui/src/pages/search/components/query-wrapper/constants.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { TutorialsIds } from 'uiSrc/constants' - -export const TUTORIALS = [ - { - id: TutorialsIds.ExactMatch, - title: 'Exact match' - }, - { - id: TutorialsIds.FullTextSearch, - title: 'Full-text search' - }, - { - id: TutorialsIds.IntroVectorSearch, - title: 'Intro to vector search' - }, -] diff --git a/redisinsight/ui/src/pages/search/components/query-wrapper/index.ts b/redisinsight/ui/src/pages/search/components/query-wrapper/index.ts deleted file mode 100644 index cf4185d43b..0000000000 --- a/redisinsight/ui/src/pages/search/components/query-wrapper/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -import QueryWrapper from './QueryWrapper' - -export default QueryWrapper diff --git a/redisinsight/ui/src/pages/search/components/query-wrapper/styles.module.scss b/redisinsight/ui/src/pages/search/components/query-wrapper/styles.module.scss deleted file mode 100644 index 18b46e1931..0000000000 --- a/redisinsight/ui/src/pages/search/components/query-wrapper/styles.module.scss +++ /dev/null @@ -1,76 +0,0 @@ -.wrapper { - position: relative; - height: 100%; - - :global(.editorBounder) { - bottom: 6px; - left: 18px; - right: 46px; - } -} - -.container { - display: flex; - flex-direction: column; - padding: 8px 16px; - width: 100%; - height: 100%; - word-break: break-word; - text-align: left; - letter-spacing: 0; - background-color: var(--rsInputWrapperColor); - color: var(--euiTextSubduedColor) !important; - border: 1px solid var(--euiColorLightShade); -} - -.disabled { - opacity: 0.8; -} - -.disabledActions { - pointer-events: none; - user-select: none; -} - -.containerPlaceholder { - display: flex; - padding: 8px 16px 8px 16px; - width: 100%; - height: 100%; - background-color: var(--rsInputWrapperColor); - color: var(--euiTextSubduedColor) !important; - border: 1px solid var(--euiColorLightShade); - > div { - border: 1px solid var(--euiColorLightShade); - background-color: var(--euiColorEmptyShade); - padding: 8px 20px; - width: 100%; - } -} - -.input { - // cannot use overflow since suggestions are absolute - max-height: calc(100% - 32px); - flex-grow: 1; - width: 100%; - border: 1px solid var(--euiColorLightShade); - background-color: var(--rsInputColor); -} - -.queryFooter { - display: flex; - align-items: center; - justify-content: space-between; - - margin-top: 8px; - flex-shrink: 0; -} - -#script { - font: normal normal bold 14px/17px Inconsolata !important; - color: var(--textColorShade); - caret-color: var(--euiColorFullShade); - min-width: 5px; - display: inline; -} - diff --git a/redisinsight/ui/src/pages/search/components/query/Query.spec.tsx b/redisinsight/ui/src/pages/search/components/query/Query.spec.tsx deleted file mode 100644 index 1f57ca4c4a..0000000000 --- a/redisinsight/ui/src/pages/search/components/query/Query.spec.tsx +++ /dev/null @@ -1,10 +0,0 @@ -import React from 'react' -import { render } from 'uiSrc/utils/test-utils' - -import Query from './Query' - -describe('Query', () => { - it('should render', () => { - expect(render()).toBeTruthy() - }) -}) diff --git a/redisinsight/ui/src/pages/search/components/query/Query.tsx b/redisinsight/ui/src/pages/search/components/query/Query.tsx deleted file mode 100644 index 20aae087c4..0000000000 --- a/redisinsight/ui/src/pages/search/components/query/Query.tsx +++ /dev/null @@ -1,359 +0,0 @@ -import React, { useContext, useEffect, useRef, useState } from 'react' -import MonacoEditor, { monaco as monacoEditor } from 'react-monaco-editor' -import { useDispatch } from 'react-redux' - -import { isNumber } from 'lodash' -import { MonacoLanguage, Theme } from 'uiSrc/constants' -import { ThemeContext } from 'uiSrc/contexts/themeContext' -import { Nullable } from 'uiSrc/utils' -import { IEditorMount } from 'uiSrc/pages/workbench/interfaces' -import { - addOwnTokenToArgs, - findCurrentArgument, - getRange, - getRediSearchSignutureProvider, - setCursorPositionAtTheEnd, - splitQueryByArgs -} from 'uiSrc/pages/search/utils' -import { CursorContext, FoundCommandArgument, SearchCommand, TokenType } from 'uiSrc/pages/search/types' -import { RedisResponseBuffer } from 'uiSrc/slices/interfaces' -import { fetchRedisearchInfoAction } from 'uiSrc/slices/browser/redisearch' -import { getRediSearchMonarchTokensProvider } from 'uiSrc/utils/monaco/monarchTokens/redisearchTokens' -import { useDebouncedEffect } from 'uiSrc/services' -import { - options, - DefinedArgumentName, - FIELD_START_SYMBOL, - COMMANDS_TO_GET_INDEX_INFO, - EmptySuggestionsIds -} from './constants' -import { - getFieldsSuggestions, - getIndexesSuggestions, - asSuggestionsRef, - getCommandsSuggestions, - isIndexComplete, - getGeneralSuggestions, - getFunctionsSuggestions, - getNoIndexesSuggestion, -} from './utils' - -export interface Props { - value: string - onChange: (val: string) => void - indexes: RedisResponseBuffer[] - supportedCommands?: SearchCommand[] -} - -const Query = (props: Props) => { - const { value, onChange, indexes, supportedCommands = [] } = props - - const [selectedCommand, setSelectedCommand] = useState('') - const [selectedIndex, setSelectedIndex] = useState('') - - const monacoObjects = useRef>(null) - const disposeCompletionItemProvider = useRef(() => {}) - const disposeSignatureHelpProvider = useRef(() => {}) - const suggestionsRef = useRef([]) - const helpWidgetRef = useRef({ - isOpen: false, - parent: null, - currentArg: null - }) - const indexesRef = useRef([]) - const attributesRef = useRef([]) - const isEscapedSuggestions = useRef(false) - - const COMMANDS_LIST = supportedCommands.map((command) => ({ - ...addOwnTokenToArgs(command.name!, command), - token: command.name!, - type: TokenType.Block - })) - - const { theme } = useContext(ThemeContext) - const dispatch = useDispatch() - - useEffect(() => () => { - disposeCompletionItemProvider.current?.() - disposeSignatureHelpProvider.current?.() - }, []) - - useEffect(() => { - indexesRef.current = indexes - }, [indexes]) - - useEffect(() => { - monacoEditor.languages.setMonarchTokensProvider( - MonacoLanguage.RediSearch, - getRediSearchMonarchTokensProvider(supportedCommands, selectedCommand) - ) - }, [selectedCommand]) - - useDebouncedEffect(() => { - attributesRef.current = [] - if (!isIndexComplete(selectedIndex)) return - - const index = selectedIndex.replace(/^(['"])(.*)\1$/, '$2') - dispatch(fetchRedisearchInfoAction(index, - (data: any) => { - attributesRef.current = data?.attributes || [] - })) - }, 200, [selectedIndex]) - - const editorDidMount = ( - editor: monacoEditor.editor.IStandaloneCodeEditor, - monaco: typeof monacoEditor - ) => { - monaco.languages.register({ id: MonacoLanguage.RediSearch }) - monacoObjects.current = { editor, monaco } - - monaco.languages.setMonarchTokensProvider( - MonacoLanguage.RediSearch, - getRediSearchMonarchTokensProvider(supportedCommands) - ) - - disposeSignatureHelpProvider.current?.() - disposeSignatureHelpProvider.current = monaco.languages.registerSignatureHelpProvider(MonacoLanguage.RediSearch, { - provideSignatureHelp: (): any => getRediSearchSignutureProvider(helpWidgetRef?.current) - }).dispose - - disposeCompletionItemProvider.current?.() - disposeCompletionItemProvider.current = monaco.languages.registerCompletionItemProvider(MonacoLanguage.RediSearch, { - provideCompletionItems: (): monacoEditor.languages.CompletionList => - ({ suggestions: suggestionsRef.current }) - }).dispose - - editor.onDidChangeCursorPosition(handleCursorChange) - editor.onKeyDown((e: monacoEditor.IKeyboardEvent) => { - if (e.keyCode === monacoEditor.KeyCode.Escape && isSuggestionsOpened()) { - isEscapedSuggestions.current = true - } - }) - - const suggestionWidget = editor.getContribution('editor.contrib.suggestController') - suggestionWidget?.onWillInsertSuggestItem(({ item }: Record<'item', any>) => { - if (item.completion.id === EmptySuggestionsIds.NoIndexes) { - updateHelpWidget(true) - editor.trigger('', 'hideSuggestWidget', null) - editor.trigger('', 'editor.action.triggerParameterHints', '') - } - }) - - suggestionsRef.current = getSuggestions(editor).data - if (value) { - setCursorPositionAtTheEnd(editor) - return - } - - const position = editor.getPosition() - if (position?.column === 1 && position?.lineNumber === 1) { - editor.focus() - triggerSuggestions() - } - } - - const isSuggestionsOpened = () => { - const { editor } = monacoObjects.current || {} - if (!editor) return false - const suggestController = editor.getContribution('editor.contrib.suggestController') - return suggestController?.model?.state === 1 - } - - const handleCursorChange = () => { - const { editor } = monacoObjects.current || {} - suggestionsRef.current = [] - - if (!editor) return - if (!editor.getSelection()?.isEmpty()) { - editor?.trigger('', 'hideSuggestWidget', null) - return - } - - const { data, forceHide, forceShow } = getSuggestions(editor) - suggestionsRef.current = data - - if (!forceShow) { - editor.trigger('', 'editor.action.triggerParameterHints', '') - return - } - - if (data.length) { - helpWidgetRef.current.isOpen = false - triggerSuggestions() - return - } - - editor.trigger('', 'editor.action.triggerParameterHints', '') - - if (forceHide) { - setTimeout(() => editor?.trigger('', 'hideSuggestWidget', null), 0) - } else { - helpWidgetRef.current.isOpen = !isSuggestionsOpened() && helpWidgetRef.current.isOpen - } - } - - const triggerSuggestions = () => { - const { editor } = monacoObjects.current || {} - setTimeout(() => editor?.trigger('', 'editor.action.triggerSuggest', { auto: false })) - } - - const updateHelpWidget = (isOpen: boolean, parent?: SearchCommand, currentArg?: SearchCommand) => { - helpWidgetRef.current = { - isOpen, - parent: parent || helpWidgetRef.current.parent, - currentArg: currentArg || helpWidgetRef.current.currentArg } - } - - const getSuggestions = ( - editor: monacoEditor.editor.IStandaloneCodeEditor - ): { - forceHide: boolean - forceShow: boolean - data: monacoEditor.languages.CompletionItem[] - } => { - const position = editor.getPosition() - const model = editor.getModel() - - if (!position || !model) return asSuggestionsRef([]) - - const value = editor.getValue() - const offset = model.getOffsetAt(position) - const word = model.getWordUntilPosition(position) - const range = getRange(position, word) - - const { args, cursor } = splitQueryByArgs(value, offset) - const { prevCursorChar } = cursor - - const allArgs = args.flat() - const [beforeOffsetArgs, [currentOffsetArg]] = args - const [firstArg] = beforeOffsetArgs - - if ((position.lineNumber === 1 && position.column === 1) || beforeOffsetArgs.length === 0) { - return asSuggestionsRef(getCommandsSuggestions(COMMANDS_LIST, range), false) - } - - const commandName = (firstArg || currentOffsetArg)?.toUpperCase() - const command = COMMANDS_LIST.find(({ name }) => commandName === name) - if (!command) { - helpWidgetRef.current.isOpen = false - return asSuggestionsRef([]) - } - - if (COMMANDS_TO_GET_INDEX_INFO.some((name) => name === commandName)) { - setSelectedIndex(allArgs[1] || '') - } - - setSelectedCommand(commandName) - - const cursorContext: CursorContext = { ...cursor, currentOffsetArg, offset } - const foundArg = findCurrentArgument(COMMANDS_LIST, beforeOffsetArgs) - - if (prevCursorChar === FIELD_START_SYMBOL) return handleFieldSuggestions(foundArg, range) - - switch (foundArg?.stopArg?.name) { - case DefinedArgumentName.index: { - return handleIndexSuggestions(command, foundArg, currentOffsetArg, range) - } - case DefinedArgumentName.query: { - return handleQuerySuggestions(command, foundArg) - } - default: { - return handleCommonSuggestions(value, foundArg, allArgs, cursorContext, range) - } - } - } - - const handleFieldSuggestions = (foundArg: Nullable, range: monacoEditor.IRange) => { - const isInQuery = foundArg?.stopArg?.name === DefinedArgumentName.query - const fieldSuggestions = getFieldsSuggestions(attributesRef.current, range, true, isInQuery) - return asSuggestionsRef(fieldSuggestions, true) - } - - const handleIndexSuggestions = ( - command: SearchCommand, - foundArg: FoundCommandArgument, - currentOffsetArg: Nullable, - range: monacoEditor.IRange - ) => { - const isIndex = indexesRef.current.length > 0 - updateHelpWidget(isIndex, command, foundArg?.stopArg) - - if (!isIndex) { - updateHelpWidget(!!currentOffsetArg) - return asSuggestionsRef(!currentOffsetArg ? getNoIndexesSuggestion(range) : [], true) - } - - if (!isIndex || currentOffsetArg) return asSuggestionsRef([], !currentOffsetArg) - - const argumentIndex = command?.arguments - ?.findIndex(({ name }) => foundArg?.stopArg?.name === name) - const isNextArgQuery = isNumber(argumentIndex) - && command?.arguments?.[argumentIndex + 1]?.name === DefinedArgumentName.query - - return asSuggestionsRef(getIndexesSuggestions(indexesRef.current, range, isNextArgQuery)) - } - - const handleQuerySuggestions = (command: SearchCommand, foundArg: FoundCommandArgument) => { - updateHelpWidget(true, command, foundArg?.stopArg) - return asSuggestionsRef([], false) - } - - const handleExpressionSuggestions = ( - value: string, - foundArg: FoundCommandArgument, - cursorContext: CursorContext, - range: monacoEditor.IRange - ) => { - updateHelpWidget(true, foundArg?.parent, foundArg?.stopArg) - - const { isCursorInQuotes, offset, argLeftOffset } = cursorContext - if (!isCursorInQuotes) return asSuggestionsRef([]) - - const stringBeforeCursor = value.substring(argLeftOffset, offset) || '' - const expression = stringBeforeCursor.replace(/^["']|["']$/g, '') - const { args } = splitQueryByArgs(expression, offset - argLeftOffset) - const [, [currentArg]] = args - - const functions = foundArg?.stopArg?.arguments ?? [] - const suggestions = getFunctionsSuggestions(functions, range) - const isStartsWithFunction = functions.some(({ token }) => token?.startsWith(currentArg)) - - return asSuggestionsRef(suggestions, true, isStartsWithFunction) - } - - const handleCommonSuggestions = ( - value: string, - foundArg: Nullable, - allArgs: string[], - cursorContext: CursorContext, - range: monacoEditor.IRange - ) => { - if (foundArg?.stopArg?.expression) return handleExpressionSuggestions(value, foundArg, cursorContext, range) - - const { prevCursorChar, nextCursorChar, isCursorInQuotes } = cursorContext - const shouldHideSuggestions = isCursorInQuotes || nextCursorChar || (prevCursorChar && isEscapedSuggestions.current) - if (shouldHideSuggestions) return asSuggestionsRef([]) - - const { - suggestions, - forceHide, - helpWidgetData - } = getGeneralSuggestions(foundArg, allArgs, range, attributesRef.current) - - if (helpWidgetData) updateHelpWidget(helpWidgetData.isOpen, helpWidgetData.parent, helpWidgetData.currentArg) - return asSuggestionsRef(suggestions, forceHide) - } - - return ( - - ) -} - -export default Query diff --git a/redisinsight/ui/src/pages/search/components/query/constants.ts b/redisinsight/ui/src/pages/search/components/query/constants.ts deleted file mode 100644 index 6617df7940..0000000000 --- a/redisinsight/ui/src/pages/search/components/query/constants.ts +++ /dev/null @@ -1,45 +0,0 @@ -import { merge } from 'lodash' -import { defaultMonacoOptions } from 'uiSrc/constants' - -export const options = merge(defaultMonacoOptions, - { - suggest: { - showWords: false, - showIcons: true, - insertMode: 'replace', - filterGraceful: false, - matchOnWordStartOnly: true - } - }) - -export const COMMANDS_TO_GET_INDEX_INFO = [ - 'FT.SEARCH', - 'FT.AGGREGATE', - 'FT.EXPLAIN', - 'FT.EXPLAINCLI', - 'FT.PROFILE', - 'FT.SPELLCHECK', - 'FT.TAGVALS', - 'FT.ALTER', - 'FT.CREATE' -] - -export const COMPOSITE_ARGS = [ - 'LOAD *', - 'FT.CONFIG GET', - 'FT.CONFIG SET', - 'FT.CURSOR DEL', - 'FT.CURSOR READ', -] - -export enum DefinedArgumentName { - index = 'index', - query = 'query', - field = 'field', - expression = 'expression' -} - -export const FIELD_START_SYMBOL = '@' -export enum EmptySuggestionsIds { - NoIndexes = 'no-indexes' -} diff --git a/redisinsight/ui/src/pages/search/components/query/index.ts b/redisinsight/ui/src/pages/search/components/query/index.ts deleted file mode 100644 index 611583bbb6..0000000000 --- a/redisinsight/ui/src/pages/search/components/query/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -import Query from './Query' - -export default Query diff --git a/redisinsight/ui/src/pages/search/components/query/styles.module.scss b/redisinsight/ui/src/pages/search/components/query/styles.module.scss deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/redisinsight/ui/src/pages/search/components/query/utils.spec.ts b/redisinsight/ui/src/pages/search/components/query/utils.spec.ts deleted file mode 100644 index 9e08a40283..0000000000 --- a/redisinsight/ui/src/pages/search/components/query/utils.spec.ts +++ /dev/null @@ -1,173 +0,0 @@ -import { - addFieldAttribute, - getFieldsSuggestions, - getGeneralSuggestions, - isIndexComplete -} from 'uiSrc/pages/search/components/query/utils' -import { MOCKED_SUPPORTED_COMMANDS } from 'uiSrc/pages/search/mocks/mocks' -import { addOwnTokenToArgs, buildSuggestion, findCurrentArgument } from 'uiSrc/pages/search/utils' -import { SearchCommand, TokenType } from 'uiSrc/pages/search/types' - -const ftAggregate = MOCKED_SUPPORTED_COMMANDS['FT.AGGREGATE'] - -const commands = Object.keys(MOCKED_SUPPORTED_COMMANDS) - .map((key) => ({ - ...addOwnTokenToArgs(key, MOCKED_SUPPORTED_COMMANDS[key]), - token: key, - type: TokenType.Block - })) - -const ftAggregateAppend = ftAggregate.arguments.slice(2) - .map((arg) => ({ ...arg, parent: ftAggregate })) - -const getGeneralSuggestionsTests = [ - { - input: { - foundArg: findCurrentArgument( - commands, - ['FT.AGGREGATE', '""', '""'] - ), - allArgs: ['FT.AGGREGATE', '""', '""'] - }, - result: { - helpWidgetData: expect.any(Object), - suggestions: ftAggregateAppend - .map((arg) => ({ - ...buildSuggestion(arg as SearchCommand, {} as any), - sortText: expect.any(String), - kind: undefined, - detail: expect.any(String) - })) - } - }, - { - input: { - foundArg: findCurrentArgument( - commands, - ['FT.AGGREGATE', '""', '""', 'APPLY', 'expression'] - ), - allArgs: ['FT.AGGREGATE', '""', '""', 'APPLY', 'expression'] - }, - result: { - helpWidgetData: expect.any(Object), - suggestions: [ - { - label: 'AS', - insertText: 'AS ', - insertTextRules: 4, - range: expect.any(Object), - kind: undefined, - detail: 'APPLY expression AS name', - } - ] - } - }, - { - input: { - foundArg: findCurrentArgument( - commands, - ['FT.PROFILE', '""'] - ), - allArgs: ['FT.PROFILE', '""'] - }, - result: { - helpWidgetData: expect.any(Object), - suggestions: [ - { - label: 'SEARCH', - insertText: 'SEARCH ', - insertTextRules: 4, - range: expect.any(Object), - kind: undefined, - detail: expect.any(String), - }, - { - label: 'AGGREGATE', - insertText: 'AGGREGATE ', - insertTextRules: 4, - range: expect.any(Object), - kind: undefined, - detail: expect.any(String), - } - ] - } - }, -] - -describe('getGeneralSuggestions', () => { - it.each(getGeneralSuggestionsTests)('should properly return suggestions', ({ input, result }) => { - const testResult = getGeneralSuggestions( - input.foundArg as any, - input.allArgs, - {} as any, - [] - ) - - expect(testResult).toEqual(result) - }) -}) - -const isIndexCompleteTests: Array<[string, boolean]> = [ - ['', false], - ['"', false], - ['\"\\"', false], - ['""', true], - ["'", false], - ["''", true], - ["'index\\'", false], - ["'index'", true], - ['"index \\\\"', true], - ['index', true], -] - -describe('isIndexComplete', () => { - it.each(isIndexCompleteTests)('should properly return value for %s', (index, result) => { - const testResult = isIndexComplete(index) - - expect(testResult).toEqual(result) - }) -}) - -const mockedFields = [ - { identifier: 'name', attribute: 'name', type: 'TEXT', WEIGHT: '1', SORTABLE: true, NOSTEM: true }, - { identifier: 'description', attribute: 'description', type: 'TEXT', WEIGHT: '1' }, - { identifier: 'class', attribute: 'class', type: 'TAG', SEPARATOR: ',' }, - { identifier: 'type', attribute: 'type', type: 'TAG', SEPARATOR: ';' }, - { identifier: 'address_city', attribute: 'city', type: 'TAG', SEPARATOR: ',' }, - { identifier: 'address_street', attribute: 'address', type: 'TEXT', WEIGHT: '1', NOSTEM: true }, - { identifier: 'students', attribute: 'students', type: 'NUMERIC', SORTABLE: true }, - { identifier: 'location', attribute: 'location', type: 'GEO' } -] - -const getFieldsSuggestionsTests = [ - [ - [mockedFields, {}], - mockedFields.map((field) => ({ - detail: field.attribute, - insertText: field.attribute, - insertTextRules: 4, - kind: undefined, - label: field.attribute, - range: expect.any(Object), - })) - ], - [ - [mockedFields, {}, false, true], - mockedFields.map((field) => ({ - detail: field.attribute, - insertText: addFieldAttribute(field.attribute, field.type), - insertTextRules: 4, - kind: undefined, - label: field.attribute, - range: expect.any(Object), - })) - ], -] - -describe('getFieldsSuggestions', () => { - it.each(getFieldsSuggestionsTests)('should properly return value for %s', (input, result) => { - const testResult = getFieldsSuggestions(...input) - - expect(testResult).toEqual(result) - }) -}) diff --git a/redisinsight/ui/src/pages/search/components/query/utils.ts b/redisinsight/ui/src/pages/search/components/query/utils.ts deleted file mode 100644 index 5ec9f867aa..0000000000 --- a/redisinsight/ui/src/pages/search/components/query/utils.ts +++ /dev/null @@ -1,201 +0,0 @@ -import { monaco } from 'react-monaco-editor' -import * as monacoEditor from 'monaco-editor' -import { RedisResponseBuffer } from 'uiSrc/slices/interfaces' -import { bufferToString, formatLongName, generateArgsForInsertText, getCommandMarkdown, Nullable } from 'uiSrc/utils' -import { - buildSuggestion, - generateDetail, - removeNotSuggestedArgs -} from 'uiSrc/pages/search/utils' -import { FoundCommandArgument, SearchCommand } from 'uiSrc/pages/search/types' -import { DefinedArgumentName, EmptySuggestionsIds } from 'uiSrc/pages/search/components/query/constants' -import { getUtmExternalLink } from 'uiSrc/utils/links' - -export const asSuggestionsRef = ( - suggestions: monacoEditor.languages.CompletionItem[], - forceHide = true, - forceShow = true -) => ({ - data: suggestions, - forceHide, - forceShow -}) - -const NO_INDEXES_DOC_LINK = getUtmExternalLink('https://redis.io/docs/latest/commands/ft.create/', { campaign: 'workbench' }) -export const getNoIndexesSuggestion = (range: monaco.IRange) => [ - { - id: EmptySuggestionsIds.NoIndexes, - label: 'No indexes to display', - kind: monacoEditor.languages.CompletionItemKind.Issue, - insertText: '', - insertTextRules: monacoEditor.languages.CompletionItemInsertTextRule.InsertAsSnippet, - range, - detail: 'Create an index', - documentation: { - value: `See the [documentation](${NO_INDEXES_DOC_LINK}) for detailed instructions on how to create an index.`, - } - } -] - -export const getIndexesSuggestions = (indexes: RedisResponseBuffer[], range: monaco.IRange, isNextArgQuery = true) => - indexes.map((index) => { - const value = formatLongName(bufferToString(index)) - const insertQueryQuotes = isNextArgQuery ? " '\${1:query to search}'" : '' - - return { - label: value || ' ', - kind: monacoEditor.languages.CompletionItemKind.Snippet, - insertText: `'${value}'${insertQueryQuotes} `, - insertTextRules: monacoEditor.languages.CompletionItemInsertTextRule.InsertAsSnippet, - range, - detail: value || ' ', - } - }) - -export const addFieldAttribute = (attribute: string, type: string) => { - switch (type) { - case 'TAG': return `${attribute}:{\${1:tag}}` - case 'TEXT': return `${attribute}:(\${1:term})` - case 'NUMERIC': return `${attribute}:[\${1:range}]` - case 'GEO': return `${attribute}:[\${1:lon} \${2:lat} \${3:radius} \${4:unit}]` - case 'VECTOR': return `${attribute} \\$\${1:vector}` - default: return attribute - } -} - -export const getFieldsSuggestions = ( - fields: any[], - range: monaco.IRange, - spaceAfter = false, - withType = false -) => - fields.map((field) => { - const { attribute, type } = field - const attibuteText = attribute.trim() ? attribute : `\\'${attribute}\\'` - const insertText = withType ? addFieldAttribute(attibuteText, type) : attibuteText - - return { - label: attribute || ' ', - kind: monacoEditor.languages.CompletionItemKind.Reference, - insertText: `${insertText}${spaceAfter ? ' ' : ''}`, - insertTextRules: monacoEditor.languages.CompletionItemInsertTextRule.InsertAsSnippet, - range, - detail: attribute || ' ', - } - }) - -const insertFunctionArguments = (args: SearchCommand[]) => - generateArgsForInsertText( - args.map(({ token, optional }) => (optional ? `[${token}]` : (token || ''))) as string[], - ', ' - ) - -export const getFunctionsSuggestions = (functions: SearchCommand[], range: monaco.IRange) => functions - .map(({ token, summary, arguments: args }) => ({ - label: token || '', - insertText: `${token}(${insertFunctionArguments(args || [])})`, - insertTextRules: monacoEditor.languages.CompletionItemInsertTextRule.InsertAsSnippet, - range, - kind: monacoEditor.languages.CompletionItemKind.Function, - detail: summary - })) - -export const getCommandsSuggestions = (commands: SearchCommand[], range: monaco.IRange) => - commands.map((command) => buildSuggestion(command, range, { - detail: generateDetail(command), - insertTextRules: monacoEditor.languages.CompletionItemInsertTextRule.InsertAsSnippet, - documentation: { - value: getCommandMarkdown(command as any) - }, - })) - -export const getMandatoryArgumentSuggestions = ( - foundArg: FoundCommandArgument, - fields: any[], - range: monaco.IRange -): monacoEditor.languages.CompletionItem[] => { - if (foundArg.stopArg?.name === DefinedArgumentName.field) { - if (!fields.length) return [] - return getFieldsSuggestions(fields, range, true) - } - - if (foundArg.isBlocked) return [] - if (foundArg.append?.length) { - return foundArg.append[0].map((arg: any) => buildSuggestion(arg, range, { - kind: monacoEditor.languages.CompletionItemKind.Property, - detail: generateDetail(foundArg?.parent) - })) - } - - return [] -} - -export const getCommandSuggestions = ( - foundArg: Nullable, - allArgs: string[], - range: monaco.IRange, -) => { - const appendCommands = foundArg?.append ?? [] - const suggestions = [] - - for (let i = 0; i < appendCommands.length; i++) { - const isLastLevel = i === appendCommands.length - 1 - const filteredFileldArgs = isLastLevel - ? removeNotSuggestedArgs(allArgs, appendCommands[i]) - : appendCommands[i] - - const leveledSuggestions = filteredFileldArgs - .map((arg) => buildSuggestion(arg, range, { - sortText: `${i}`, - kind: isLastLevel - ? monacoEditor.languages.CompletionItemKind.Reference - : monacoEditor.languages.CompletionItemKind.Property, - detail: generateDetail(arg?.parent) - })) - - suggestions.push(leveledSuggestions) - } - - return suggestions.flat() -} - -export const getGeneralSuggestions = ( - foundArg: Nullable, - allArgs: string[], - range: monacoEditor.IRange, - fields: any[] -): { - suggestions: monacoEditor.languages.CompletionItem[], - forceHide?: boolean - helpWidgetData?: any -} => { - if (foundArg && !foundArg.isComplete) { - return { - suggestions: getMandatoryArgumentSuggestions(foundArg, fields, range), - helpWidgetData: { isOpen: !!foundArg?.stopArg, parent: foundArg?.parent, currentArg: foundArg?.stopArg } - } - } - - return { - suggestions: getCommandSuggestions(foundArg, allArgs, range), - helpWidgetData: { isOpen: false } - } -} - -export const isIndexComplete = (index: string) => { - if (index.length === 0) return false - - const firstChar = index[0] - const lastChar = index[index.length - 1] - - if (firstChar !== '"' && firstChar !== "'") return true - if (index.length === 1 && (firstChar === '"' || firstChar === "'")) return false - if (firstChar !== lastChar) return false - - let escape = false - for (let i = 1; i < index.length - 1; i++) { - escape = index[i] === '\\' && !escape - } - - return !escape -} diff --git a/redisinsight/ui/src/pages/search/components/results-history/ResultsHistory.spec.tsx b/redisinsight/ui/src/pages/search/components/results-history/ResultsHistory.spec.tsx deleted file mode 100644 index a152317088..0000000000 --- a/redisinsight/ui/src/pages/search/components/results-history/ResultsHistory.spec.tsx +++ /dev/null @@ -1,157 +0,0 @@ -import React from 'react' -import { cloneDeep } from 'lodash' -import { cleanup, fireEvent, mockedStore, render, screen } from 'uiSrc/utils/test-utils' - -import { sendEventTelemetry, TelemetryEvent } from 'uiSrc/telemetry' -import { INSTANCE_ID_MOCK } from 'uiSrc/mocks/handlers/analytics/clusterDetailsHandlers' -import { - clearWbResults, - loadWBHistory, - processWBCommand, - workbenchResultsSelector -} from 'uiSrc/slices/workbench/wb-results' -import ResultsHistory from './ResultsHistory' - -jest.mock('uiSrc/telemetry', () => ({ - ...jest.requireActual('uiSrc/telemetry'), - sendEventTelemetry: jest.fn(), -})) - -jest.mock('uiSrc/slices/workbench/wb-results', () => ({ - ...jest.requireActual('uiSrc/slices/workbench/wb-results'), - workbenchResultsSelector: jest.fn().mockReturnValue({ - loading: false, - items: [] - }) -})) - -let store: typeof mockedStore -beforeEach(() => { - cleanup() - store = cloneDeep(mockedStore) - store.clearActions() -}) - -describe('ResultsHistory', () => { - it('should render', () => { - expect(render()).toBeTruthy() - }) - - it('should call proper actions on rerun', async () => { - const onSubmit = jest.fn() - const sendEventTelemetryMock = jest.fn(); - (sendEventTelemetry as jest.Mock).mockImplementation(() => sendEventTelemetryMock); - - (workbenchResultsSelector as jest.Mock).mockReturnValue({ - items: [ - { - mode: 'RAW', - resultsMode: 'DEFAULT', - id: '9dda0f6d-9265-4b15-b627-82d2eb867605', - databaseId: '18c37d1d-bc25-4e46-a20d-a1f9bf228946', - command: 'info', - summary: null, - createdAt: '2022-09-28T18:04:46.000Z', - emptyCommand: false - } - ] - }) - - render() - - fireEvent.click(screen.getByTestId('re-run-command')) - - expect(sendEventTelemetry).toBeCalledWith({ - event: TelemetryEvent.SEARCH_COMMAND_RUN_AGAIN, - eventData: { - command: 'INFO', - databaseId: INSTANCE_ID_MOCK, - mode: 'RAW' - } - }); - (sendEventTelemetry as jest.Mock).mockRestore() - - expect(onSubmit).toBeCalledWith( - 'info', - '9dda0f6d-9265-4b15-b627-82d2eb867605', - { mode: 'RAW' } - ) - }) - - it('should call proper actions on delete', async () => { - const onSubmit = jest.fn() - const sendEventTelemetryMock = jest.fn(); - (sendEventTelemetry as jest.Mock).mockImplementation(() => sendEventTelemetryMock); - - (workbenchResultsSelector as jest.Mock).mockReturnValue({ - items: [ - { - mode: 'RAW', - resultsMode: 'DEFAULT', - id: '9dda0f6d-9265-4b15-b627-82d2eb867605', - databaseId: '18c37d1d-bc25-4e46-a20d-a1f9bf228946', - command: 'info', - summary: null, - createdAt: '2022-09-28T18:04:46.000Z', - emptyCommand: false - } - ] - }) - - render() - - fireEvent.click(screen.getByTestId('delete-command')) - - expect(sendEventTelemetry).toBeCalledWith({ - event: TelemetryEvent.SEARCH_CLEAR_RESULT_CLICKED, - eventData: { - command: 'info', - databaseId: INSTANCE_ID_MOCK, - } - }); - (sendEventTelemetry as jest.Mock).mockRestore() - - expect(store.getActions()).toEqual([ - loadWBHistory(), - processWBCommand('9dda0f6d-9265-4b15-b627-82d2eb867605') - ]) - }) - - it('should call proper actions on clear all commands', async () => { - const onSubmit = jest.fn() - const sendEventTelemetryMock = jest.fn(); - (sendEventTelemetry as jest.Mock).mockImplementation(() => sendEventTelemetryMock); - - (workbenchResultsSelector as jest.Mock).mockReturnValue({ - items: [ - { - mode: 'RAW', - resultsMode: 'DEFAULT', - id: '9dda0f6d-9265-4b15-b627-82d2eb867605', - databaseId: '18c37d1d-bc25-4e46-a20d-a1f9bf228946', - command: 'info', - summary: null, - createdAt: '2022-09-28T18:04:46.000Z', - emptyCommand: false - } - ] - }) - - render() - - fireEvent.click(screen.getByTestId('clear-history-btn')) - - expect(sendEventTelemetry).toBeCalledWith({ - event: TelemetryEvent.SEARCH_CLEAR_ALL_RESULTS_CLICKED, - eventData: { - databaseId: INSTANCE_ID_MOCK, - } - }); - (sendEventTelemetry as jest.Mock).mockRestore() - - expect(store.getActions()).toEqual([ - loadWBHistory(), - clearWbResults() - ]) - }) -}) diff --git a/redisinsight/ui/src/pages/search/components/results-history/ResultsHistory.tsx b/redisinsight/ui/src/pages/search/components/results-history/ResultsHistory.tsx deleted file mode 100644 index ca85d28c35..0000000000 --- a/redisinsight/ui/src/pages/search/components/results-history/ResultsHistory.tsx +++ /dev/null @@ -1,172 +0,0 @@ -import React, { useEffect } from 'react' -import cx from 'classnames' - -import { useDispatch, useSelector } from 'react-redux' -import { useParams } from 'react-router-dom' - -import { EuiButtonEmpty, EuiProgress } from '@elastic/eui' -import { getCommandsFromQuery, Nullable } from 'uiSrc/utils' -import { QueryCard } from 'uiSrc/components/query' -import { - clearWbResultsAction, - deleteWBCommandAction, - fetchWBCommandAction, - fetchWBHistoryAction, - resetWBHistoryItems, - workbenchResultsSelector -} from 'uiSrc/slices/workbench/wb-results' -import { searchAndQuerySelector } from 'uiSrc/slices/search/searchAndQuery' - -import { CommandExecutionType, RunQueryMode } from 'uiSrc/slices/interfaces' -import { sendEventTelemetry, TelemetryEvent } from 'uiSrc/telemetry' -import { ProfileQueryType } from 'uiSrc/pages/workbench/constants' -import { generateProfileQueryForCommand } from 'uiSrc/pages/workbench/utils/profile' -import { CodeButtonParams } from 'uiSrc/constants' -import styles from './styles.module.scss' - -export interface Props { - commandsArray?: string[] - onSubmit: ( - commandInit: string, - commandId?: Nullable, - executeParams?: CodeButtonParams - ) => void -} - -const ResultsHistory = (props: Props) => { - const { commandsArray = [], onSubmit } = props - const { - items, - clearing, - isLoaded - } = useSelector(workbenchResultsSelector) - const { activeRunQueryMode } = useSelector(searchAndQuerySelector) - - const dispatch = useDispatch() - const { instanceId } = useParams<{ instanceId: string }>() - - useEffect(() => { - dispatch(fetchWBHistoryAction(instanceId, CommandExecutionType.Search)) - - return () => { - dispatch(resetWBHistoryItems()) - } - }, []) - - const handleQueryOpen = (commandId: string = '') => { - dispatch(fetchWBCommandAction(commandId)) - } - - const handleQueryDelete = (commandId: string) => { - dispatch(deleteWBCommandAction(commandId)) - } - - const handleAllQueriesDelete = () => { - dispatch(clearWbResultsAction(CommandExecutionType.Search)) - sendEventTelemetry({ - event: TelemetryEvent.SEARCH_CLEAR_ALL_RESULTS_CLICKED, - eventData: { - databaseId: instanceId, - } - }) - } - - const handleQueryReRun = ( - query: string, - commandId?: Nullable, - mode?: RunQueryMode - ) => { - sendEventTelemetry({ - event: TelemetryEvent.SEARCH_COMMAND_RUN_AGAIN, - eventData: { - databaseId: instanceId, - command: getCommandsFromQuery(query, commandsArray) || '', - mode - } - }) - onSubmit(query, commandId, { mode }) - } - - const handleQueryProfile = ( - profileType: ProfileQueryType, - commandExecution: { command: string, mode?: RunQueryMode } - ) => { - const { command, mode } = commandExecution - const profileQuery = generateProfileQueryForCommand(command, profileType) - if (profileQuery) { - onSubmit(profileQuery, null, { mode }) - } - } - - return ( -
- {!isLoaded && ( - - )} - {!!items?.length && ( -
- - Clear Results - -
- )} -
-
- {items?.length ? items.map(( - { - command = '', - isOpen = false, - result = undefined, - summary = undefined, - id = '', - loading, - createdAt, - mode, - emptyCommand, - isNotStored, - executionTime, - db, - } - ) => ( - - handleQueryProfile(profileType, { command, mode })} - onQueryOpen={() => handleQueryOpen(id)} - onQueryReRun={() => handleQueryReRun(command, id, mode)} - onQueryDelete={() => handleQueryDelete(id)} - /> - )) : null} -
-
- ) -} - -export default ResultsHistory diff --git a/redisinsight/ui/src/pages/search/components/results-history/index.ts b/redisinsight/ui/src/pages/search/components/results-history/index.ts deleted file mode 100644 index a38f637f57..0000000000 --- a/redisinsight/ui/src/pages/search/components/results-history/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -import ResultsHistory from './ResultsHistory' - -export default ResultsHistory diff --git a/redisinsight/ui/src/pages/search/components/results-history/styles.module.scss b/redisinsight/ui/src/pages/search/components/results-history/styles.module.scss deleted file mode 100644 index 84827c7662..0000000000 --- a/redisinsight/ui/src/pages/search/components/results-history/styles.module.scss +++ /dev/null @@ -1,44 +0,0 @@ -.wrapper { - flex: 1; - height: 100%; - width: 100%; - background-color: var(--euiColorEmptyShade); - border: 1px solid var(--euiColorLightShade); - - display: flex; - flex-direction: column; - - position: relative; -} - -.container { - @include eui.scrollBar; - color: var(--euiTextSubduedColor) !important; - - flex: 1; - width: 100%; - overflow: auto; -} - -.header { - height: 42px; - display: flex; - align-items: center; - justify-content: flex-end; - padding: 0 12px; - - flex-shrink: 0; - border-bottom: 1px solid var(--tableDarkestBorderColor); -} - -.clearAllBtn { - font-size: 14px !important; - - :global { - .euiIcon { - width: 14px !important; - height: 14px !important; - } - } -} - diff --git a/redisinsight/ui/src/pages/search/index.ts b/redisinsight/ui/src/pages/search/index.ts deleted file mode 100644 index 2f6b199b65..0000000000 --- a/redisinsight/ui/src/pages/search/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -import SearchPage from './SearchPage' - -export default SearchPage diff --git a/redisinsight/ui/src/pages/search/mocks/mocks.ts b/redisinsight/ui/src/pages/search/mocks/mocks.ts deleted file mode 100644 index 9ebacd0a47..0000000000 --- a/redisinsight/ui/src/pages/search/mocks/mocks.ts +++ /dev/null @@ -1,1521 +0,0 @@ -export const MOCKED_SUPPORTED_COMMANDS = { - 'FT.SEARCH': { - summary: 'Searches the index with a textual query, returning either documents or just ids', - complexity: 'O(N)', - history: [ - [ - '2.0.0', - 'Deprecated `WITHPAYLOADS` and `PAYLOAD` arguments' - ] - ], - arguments: [ - { - name: 'index', - type: 'string' - }, - { - name: 'query', - type: 'string' - }, - { - name: 'nocontent', - type: 'pure-token', - token: 'NOCONTENT', - optional: true - }, - { - name: 'verbatim', - type: 'pure-token', - token: 'VERBATIM', - optional: true - }, - { - name: 'nostopwords', - type: 'pure-token', - token: 'NOSTOPWORDS', - optional: true - }, - { - name: 'withscores', - type: 'pure-token', - token: 'WITHSCORES', - optional: true - }, - { - name: 'withpayloads', - type: 'pure-token', - token: 'WITHPAYLOADS', - optional: true - }, - { - name: 'withsortkeys', - type: 'pure-token', - token: 'WITHSORTKEYS', - optional: true - }, - { - name: 'filter', - type: 'block', - optional: true, - multiple: true, - arguments: [ - { - name: 'numeric_field', - type: 'string', - token: 'FILTER' - }, - { - name: 'min', - type: 'double' - }, - { - name: 'max', - type: 'double' - } - ] - }, - { - name: 'geo_filter', - type: 'block', - optional: true, - multiple: true, - arguments: [ - { - name: 'geo_field', - type: 'string', - token: 'GEOFILTER' - }, - { - name: 'lon', - type: 'double' - }, - { - name: 'lat', - type: 'double' - }, - { - name: 'radius', - type: 'double' - }, - { - name: 'radius_type', - type: 'oneof', - arguments: [ - { - name: 'm', - type: 'pure-token', - token: 'm' - }, - { - name: 'km', - type: 'pure-token', - token: 'km' - }, - { - name: 'mi', - type: 'pure-token', - token: 'mi' - }, - { - name: 'ft', - type: 'pure-token', - token: 'ft' - } - ] - } - ] - }, - { - name: 'in_keys', - type: 'block', - optional: true, - arguments: [ - { - name: 'count', - type: 'string', - token: 'INKEYS' - }, - { - name: 'key', - type: 'string', - multiple: true - } - ] - }, - { - name: 'in_fields', - type: 'block', - optional: true, - arguments: [ - { - name: 'count', - type: 'string', - token: 'INFIELDS' - }, - { - name: 'field', - type: 'string', - multiple: true - } - ] - }, - { - name: 'return', - type: 'block', - optional: true, - arguments: [ - { - name: 'count', - type: 'string', - token: 'RETURN' - }, - { - name: 'identifiers', - type: 'block', - multiple: true, - arguments: [ - { - name: 'identifier', - type: 'string' - }, - { - name: 'property', - type: 'string', - token: 'AS', - optional: true - } - ] - } - ] - }, - { - name: 'summarize', - type: 'block', - optional: true, - arguments: [ - { - name: 'summarize', - type: 'pure-token', - token: 'SUMMARIZE' - }, - { - name: 'fields', - type: 'block', - optional: true, - arguments: [ - { - name: 'count', - type: 'string', - token: 'FIELDS' - }, - { - name: 'field', - type: 'string', - multiple: true - } - ] - }, - { - name: 'num', - type: 'integer', - token: 'FRAGS', - optional: true - }, - { - name: 'fragsize', - type: 'integer', - token: 'LEN', - optional: true - }, - { - name: 'separator', - type: 'string', - token: 'SEPARATOR', - optional: true - } - ] - }, - { - name: 'highlight', - type: 'block', - optional: true, - arguments: [ - { - name: 'highlight', - type: 'pure-token', - token: 'HIGHLIGHT' - }, - { - name: 'fields', - type: 'block', - optional: true, - arguments: [ - { - name: 'count', - type: 'string', - token: 'FIELDS' - }, - { - name: 'field', - type: 'string', - multiple: true - } - ] - }, - { - name: 'tags', - type: 'block', - optional: true, - arguments: [ - { - name: 'tags', - type: 'pure-token', - token: 'TAGS' - }, - { - name: 'open', - type: 'string' - }, - { - name: 'close', - type: 'string' - } - ] - } - ] - }, - { - name: 'slop', - type: 'integer', - optional: true, - token: 'SLOP' - }, - { - name: 'timeout', - type: 'integer', - optional: true, - token: 'TIMEOUT' - }, - { - name: 'inorder', - type: 'pure-token', - token: 'INORDER', - optional: true - }, - { - name: 'language', - type: 'string', - optional: true, - token: 'LANGUAGE' - }, - { - name: 'expander', - type: 'string', - optional: true, - token: 'EXPANDER' - }, - { - name: 'scorer', - type: 'string', - optional: true, - token: 'SCORER' - }, - { - name: 'explainscore', - type: 'pure-token', - token: 'EXPLAINSCORE', - optional: true - }, - { - name: 'payload', - type: 'string', - optional: true, - token: 'PAYLOAD' - }, - { - name: 'sortby', - type: 'block', - optional: true, - arguments: [ - { - name: 'sortby', - type: 'string', - token: 'SORTBY' - }, - { - name: 'order', - type: 'oneof', - optional: true, - arguments: [ - { - name: 'asc', - type: 'pure-token', - token: 'ASC' - }, - { - name: 'desc', - type: 'pure-token', - token: 'DESC' - } - ] - } - ] - }, - { - name: 'limit', - type: 'block', - optional: true, - arguments: [ - { - name: 'limit', - type: 'pure-token', - token: 'LIMIT' - }, - { - name: 'offset', - type: 'integer' - }, - { - name: 'num', - type: 'integer' - } - ] - }, - { - name: 'params', - type: 'block', - optional: true, - arguments: [ - { - name: 'params', - type: 'pure-token', - token: 'PARAMS' - }, - { - name: 'nargs', - type: 'integer' - }, - { - name: 'values', - type: 'block', - multiple: true, - arguments: [ - { - name: 'name', - type: 'string' - }, - { - name: 'value', - type: 'string' - } - ] - } - ] - }, - { - name: 'dialect', - type: 'integer', - optional: true, - token: 'DIALECT', - since: '2.4.3' - } - ], - since: '1.0.0', - group: 'search' - }, - 'FT.AGGREGATE': { - summary: 'Run a search query on an index and perform aggregate transformations on the results', - complexity: 'O(1)', - arguments: [ - { - name: 'index', - type: 'string' - }, - { - name: 'query', - type: 'string' - }, - { - name: 'verbatim', - type: 'pure-token', - token: 'VERBATIM', - optional: true - }, - { - name: 'load', - type: 'block', - optional: true, - arguments: [ - { - name: 'count', - type: 'string', - token: 'LOAD' - }, - { - name: 'field', - type: 'string', - multiple: true - } - ] - }, - { - name: 'timeout', - type: 'integer', - optional: true, - token: 'TIMEOUT' - }, - { - name: 'loadall', - type: 'pure-token', - token: 'LOAD *', - optional: true - }, - { - name: 'groupby', - type: 'block', - optional: true, - multiple: true, - arguments: [ - { - name: 'nargs', - type: 'integer', - token: 'GROUPBY' - }, - { - name: 'property', - type: 'string', - multiple: true - }, - { - name: 'reduce', - type: 'block', - optional: true, - multiple: true, - arguments: [ - { - name: 'function', - type: 'string', - token: 'REDUCE' - }, - { - name: 'nargs', - type: 'integer' - }, - { - name: 'arg', - type: 'string', - multiple: true - }, - { - name: 'name', - type: 'string', - token: 'AS', - optional: true - } - ] - } - ] - }, - { - name: 'sortby', - type: 'block', - optional: true, - arguments: [ - { - name: 'nargs', - type: 'integer', - token: 'SORTBY' - }, - { - name: 'fields', - type: 'block', - optional: true, - multiple: true, - arguments: [ - { - name: 'property', - type: 'string' - }, - { - name: 'order', - type: 'oneof', - arguments: [ - { - name: 'asc', - type: 'pure-token', - token: 'ASC' - }, - { - name: 'desc', - type: 'pure-token', - token: 'DESC' - } - ] - } - ] - }, - { - name: 'num', - type: 'integer', - token: 'MAX', - optional: true - } - ] - }, - { - name: 'apply', - type: 'block', - optional: true, - multiple: true, - arguments: [ - { - name: 'expression', - type: 'string', - token: 'APPLY' - }, - { - name: 'name', - type: 'string', - token: 'AS' - } - ] - }, - { - name: 'limit', - type: 'block', - optional: true, - arguments: [ - { - name: 'limit', - type: 'pure-token', - token: 'LIMIT' - }, - { - name: 'offset', - type: 'integer' - }, - { - name: 'num', - type: 'integer' - } - ] - }, - { - name: 'filter', - type: 'string', - optional: true, - token: 'FILTER' - }, - { - name: 'cursor', - type: 'block', - optional: true, - arguments: [ - { - name: 'withcursor', - type: 'pure-token', - token: 'WITHCURSOR' - }, - { - name: 'read_size', - type: 'integer', - optional: true, - token: 'COUNT' - }, - { - name: 'idle_time', - type: 'integer', - optional: true, - token: 'MAXIDLE' - } - ] - }, - { - name: 'params', - type: 'block', - optional: true, - arguments: [ - { - name: 'params', - type: 'pure-token', - token: 'PARAMS' - }, - { - name: 'nargs', - type: 'integer' - }, - { - name: 'values', - type: 'block', - multiple: true, - arguments: [ - { - name: 'name', - type: 'string' - }, - { - name: 'value', - type: 'string' - } - ] - } - ] - }, - { - name: 'dialect', - type: 'integer', - optional: true, - token: 'DIALECT', - since: '2.4.3' - } - ], - since: '1.1.0', - group: 'search' - }, - 'FT.PROFILE': { - summary: 'Performs a `FT.SEARCH` or `FT.AGGREGATE` command and collects performance information', - complexity: 'O(N)', - arguments: [ - { - name: 'index', - type: 'string' - }, - { - name: 'querytype', - type: 'oneof', - arguments: [ - { - name: 'search', - type: 'pure-token', - token: 'SEARCH' - }, - { - name: 'aggregate', - type: 'pure-token', - token: 'AGGREGATE' - } - ] - }, - { - name: 'limited', - type: 'pure-token', - token: 'LIMITED', - optional: true - }, - { - name: 'queryword', - type: 'pure-token', - token: 'QUERY' - }, - { - name: 'query', - type: 'string' - } - ], - since: '2.2.0', - group: 'search', - provider: 'redisearch' - }, - 'FT.ALIASADD': { - summary: 'Adds an alias to the index', - complexity: 'O(1)', - arguments: [ - { - name: 'alias', - type: 'string' - }, - { - name: 'index', - type: 'string' - } - ], - since: '1.0.0', - group: 'search', - provider: 'redisearch' - }, - 'FT.ALIASDEL': { - summary: 'Deletes an alias from the index', - complexity: 'O(1)', - arguments: [ - { - name: 'alias', - type: 'string' - } - ], - since: '1.0.0', - group: 'search', - provider: 'redisearch' - }, - 'FT.ALIASUPDATE': { - summary: 'Adds or updates an alias to the index', - complexity: 'O(1)', - arguments: [ - { - name: 'alias', - type: 'string' - }, - { - name: 'index', - type: 'string' - } - ], - since: '1.0.0', - group: 'search', - provider: 'redisearch' - }, - 'FT.ALTER': { - summary: 'Adds a new field to the index', - complexity: 'O(N) where N is the number of keys in the keyspace', - arguments: [ - { - name: 'index', - type: 'string' - }, - { - name: 'skipinitialscan', - type: 'pure-token', - token: 'SKIPINITIALSCAN', - optional: true - }, - { - name: 'schema', - type: 'pure-token', - token: 'SCHEMA' - }, - { - name: 'add', - type: 'pure-token', - token: 'ADD' - }, - { - name: 'field', - type: 'string' - }, - { - name: 'options', - type: 'string' - } - ], - since: '1.0.0', - group: 'search', - provider: 'redisearch' - }, - 'FT.CONFIG GET': { - summary: 'Retrieves runtime configuration options', - complexity: 'O(1)', - arguments: [ - { - name: 'option', - type: 'string' - } - ], - since: '1.0.0', - group: 'search', - provider: 'redisearch' - }, - 'FT.CONFIG HELP': { - summary: 'Help description of runtime configuration options', - complexity: 'O(1)', - arguments: [ - { - name: 'option', - type: 'string' - } - ], - since: '1.0.0', - group: 'search', - provider: 'redisearch' - }, - 'FT.CONFIG SET': { - summary: 'Sets runtime configuration options', - complexity: 'O(1)', - arguments: [ - { - name: 'option', - type: 'string' - }, - { - name: 'value', - type: 'string' - } - ], - since: '1.0.0', - group: 'search', - provider: 'redisearch' - }, - 'FT.CREATE': { - summary: 'Creates an index with the given spec', - complexity: 'O(K) at creation where K is the number of fields, O(N) if scanning the keyspace is triggered, where N is the number of keys in the keyspace', - history: [ - [ - '2.0.0', - 'Added `PAYLOAD_FIELD` argument for backward support of `FT.SEARCH` deprecated `WITHPAYLOADS` argument' - ], - [ - '2.0.0', - 'Deprecated `PAYLOAD_FIELD` argument' - ] - ], - arguments: [ - { - name: 'index', - type: 'string' - }, - { - name: 'data_type', - token: 'ON', - type: 'oneof', - arguments: [ - { - name: 'hash', - type: 'pure-token', - token: 'HASH' - }, - { - name: 'json', - type: 'pure-token', - token: 'JSON' - } - ], - optional: true - }, - { - name: 'prefix', - type: 'block', - optional: true, - arguments: [ - { - name: 'count', - type: 'integer', - token: 'PREFIX' - }, - { - name: 'prefix', - type: 'string', - multiple: true - } - ] - }, - { - name: 'filter', - type: 'string', - optional: true, - token: 'FILTER' - }, - { - name: 'default_lang', - type: 'string', - token: 'LANGUAGE', - optional: true - }, - { - name: 'lang_attribute', - type: 'string', - token: 'LANGUAGE_FIELD', - optional: true - }, - { - name: 'default_score', - type: 'double', - token: 'SCORE', - optional: true - }, - { - name: 'score_attribute', - type: 'string', - token: 'SCORE_FIELD', - optional: true - }, - { - name: 'payload_attribute', - type: 'string', - token: 'PAYLOAD_FIELD', - optional: true - }, - { - name: 'maxtextfields', - type: 'pure-token', - token: 'MAXTEXTFIELDS', - optional: true - }, - { - name: 'seconds', - type: 'double', - token: 'TEMPORARY', - optional: true - }, - { - name: 'nooffsets', - type: 'pure-token', - token: 'NOOFFSETS', - optional: true - }, - { - name: 'nohl', - type: 'pure-token', - token: 'NOHL', - optional: true - }, - { - name: 'nofields', - type: 'pure-token', - token: 'NOFIELDS', - optional: true - }, - { - name: 'nofreqs', - type: 'pure-token', - token: 'NOFREQS', - optional: true - }, - { - name: 'stopwords', - type: 'block', - optional: true, - token: 'STOPWORDS', - arguments: [ - { - name: 'count', - type: 'integer' - }, - { - name: 'stopword', - type: 'string', - multiple: true, - optional: true - } - ] - }, - { - name: 'skipinitialscan', - type: 'pure-token', - token: 'SKIPINITIALSCAN', - optional: true - }, - { - name: 'schema', - type: 'pure-token', - token: 'SCHEMA' - }, - { - name: 'field', - type: 'block', - multiple: true, - arguments: [ - { - name: 'field_name', - type: 'string' - }, - { - name: 'alias', - type: 'string', - token: 'AS', - optional: true - }, - { - name: 'field_type', - type: 'oneof', - arguments: [ - { - name: 'text', - type: 'pure-token', - token: 'TEXT' - }, - { - name: 'tag', - type: 'pure-token', - token: 'TAG' - }, - { - name: 'numeric', - type: 'pure-token', - token: 'NUMERIC' - }, - { - name: 'geo', - type: 'pure-token', - token: 'GEO' - }, - { - name: 'vector', - type: 'pure-token', - token: 'VECTOR' - } - ] - }, - { - name: 'withsuffixtrie', - type: 'pure-token', - token: 'WITHSUFFIXTRIE', - optional: true - }, - { - name: 'INDEXEMPTY', - type: 'pure-token', - token: 'INDEXEMPTY', - optional: true - }, - { - name: 'indexmissing', - type: 'pure-token', - token: 'INDEXMISSING', - optional: true - }, - { - name: 'sortable', - type: 'block', - optional: true, - arguments: [ - { - name: 'sortable', - type: 'pure-token', - token: 'SORTABLE' - }, - { - name: 'UNF', - type: 'pure-token', - token: 'UNF', - optional: true - } - ] - }, - { - name: 'noindex', - type: 'pure-token', - token: 'NOINDEX', - optional: true - } - ] - } - ], - since: '1.0.0', - group: 'search', - provider: 'redisearch' - }, - 'FT.CURSOR DEL': { - summary: 'Deletes a cursor', - complexity: 'O(1)', - arguments: [ - { - name: 'index', - type: 'string' - }, - { - name: 'cursor_id', - type: 'integer' - } - ], - since: '1.1.0', - group: 'search', - provider: 'redisearch' - }, - 'FT.CURSOR READ': { - summary: 'Reads from a cursor', - complexity: 'O(1)', - arguments: [ - { - name: 'index', - type: 'string' - }, - { - name: 'cursor_id', - type: 'integer' - }, - { - name: 'read size', - type: 'integer', - optional: true, - token: 'COUNT' - } - ], - since: '1.1.0', - group: 'search', - provider: 'redisearch' - }, - 'FT.DICTADD': { - summary: 'Adds terms to a dictionary', - complexity: 'O(1)', - arguments: [ - { - name: 'dict', - type: 'string' - }, - { - name: 'term', - type: 'string', - multiple: true - } - ], - since: '1.4.0', - group: 'search', - provider: 'redisearch' - }, - 'FT.DICTDEL': { - summary: 'Deletes terms from a dictionary', - complexity: 'O(1)', - arguments: [ - { - name: 'dict', - type: 'string' - }, - { - name: 'term', - type: 'string', - multiple: true - } - ], - since: '1.4.0', - group: 'search', - provider: 'redisearch' - }, - 'FT.DICTDUMP': { - summary: 'Dumps all terms in the given dictionary', - complexity: 'O(N), where N is the size of the dictionary', - arguments: [ - { - name: 'dict', - type: 'string' - } - ], - since: '1.4.0', - group: 'search', - provider: 'redisearch' - }, - 'FT.DROPINDEX': { - summary: 'Deletes the index', - complexity: 'O(1) or O(N) if documents are deleted, where N is the number of keys in the keyspace', - arguments: [ - { - name: 'index', - type: 'string' - }, - { - name: 'delete docs', - type: 'oneof', - arguments: [ - { - name: 'delete docs', - type: 'pure-token', - token: 'DD' - } - ], - optional: true - } - ], - since: '2.0.0', - group: 'search', - provider: 'redisearch' - }, - 'FT.EXPLAIN': { - summary: 'Returns the execution plan for a complex query', - complexity: 'O(1)', - arguments: [ - { - name: 'index', - type: 'string' - }, - { - name: 'query', - type: 'string' - }, - { - name: 'dialect', - type: 'integer', - optional: true, - token: 'DIALECT', - since: '2.4.3' - } - ], - since: '1.0.0', - group: 'search', - provider: 'redisearch' - }, - 'FT.EXPLAINCLI': { - summary: 'Returns the execution plan for a complex query', - complexity: 'O(1)', - arguments: [ - { - name: 'index', - type: 'string' - }, - { - name: 'query', - type: 'string' - }, - { - name: 'dialect', - type: 'integer', - optional: true, - token: 'DIALECT', - since: '2.4.3' - } - ], - since: '1.0.0', - group: 'search', - provider: 'redisearch' - }, - 'FT.INFO': { - summary: 'Returns information and statistics on the index', - complexity: 'O(1)', - arguments: [ - { - name: 'index', - type: 'string' - } - ], - since: '1.0.0', - group: 'search', - provider: 'redisearch' - }, - 'FT.SPELLCHECK': { - summary: 'Performs spelling correction on a query, returning suggestions for misspelled terms', - complexity: 'O(1)', - arguments: [ - { - name: 'index', - type: 'string' - }, - { - name: 'query', - type: 'string' - }, - { - name: 'distance', - token: 'DISTANCE', - type: 'integer', - optional: true - }, - { - name: 'terms', - token: 'TERMS', - type: 'block', - optional: true, - arguments: [ - { - name: 'inclusion', - type: 'oneof', - arguments: [ - { - name: 'include', - type: 'pure-token', - token: 'INCLUDE' - }, - { - name: 'exclude', - type: 'pure-token', - token: 'EXCLUDE' - } - ] - }, - { - name: 'dictionary', - type: 'string' - }, - { - name: 'terms', - type: 'string', - multiple: true, - optional: true - } - ] - }, - { - name: 'dialect', - type: 'integer', - optional: true, - token: 'DIALECT', - since: '2.4.3' - } - ], - since: '1.4.0', - group: 'search', - provider: 'redisearch' - }, - 'FT.SUGADD': { - summary: 'Adds a suggestion string to an auto-complete suggestion dictionary', - complexity: 'O(1)', - history: [ - [ - '2.0.0', - 'Deprecated `PAYLOAD` argument' - ] - ], - arguments: [ - { - name: 'key', - type: 'string' - }, - { - name: 'string', - type: 'string' - }, - { - name: 'score', - type: 'double' - }, - { - name: 'increment score', - type: 'oneof', - arguments: [ - { - name: 'incr', - type: 'pure-token', - token: 'INCR' - } - ], - optional: true - }, - { - name: 'payload', - token: 'PAYLOAD', - type: 'string', - optional: true - } - ], - since: '1.0.0', - group: 'suggestion', - provider: 'redisearch' - }, - 'FT.SUGDEL': { - summary: 'Deletes a string from a suggestion index', - complexity: 'O(1)', - arguments: [ - { - name: 'key', - type: 'string' - }, - { - name: 'string', - type: 'string' - } - ], - since: '1.0.0', - group: 'suggestion', - provider: 'redisearch' - }, - 'FT.SUGGET': { - summary: 'Gets completion suggestions for a prefix', - complexity: 'O(1)', - history: [ - [ - '2.0.0', - 'Deprecated `WITHPAYLOADS` argument' - ] - ], - arguments: [ - { - name: 'key', - type: 'string' - }, - { - name: 'prefix', - type: 'string' - }, - { - name: 'fuzzy', - type: 'pure-token', - token: 'FUZZY', - optional: true - }, - { - name: 'withscores', - type: 'pure-token', - token: 'WITHSCORES', - optional: true - }, - { - name: 'withpayloads', - type: 'pure-token', - token: 'WITHPAYLOADS', - optional: true - }, - { - name: 'max', - token: 'MAX', - type: 'integer', - optional: true - } - ], - since: '1.0.0', - group: 'suggestion', - provider: 'redisearch' - }, - 'FT.SUGLEN': { - summary: 'Gets the size of an auto-complete suggestion dictionary', - complexity: 'O(1)', - arguments: [ - { - name: 'key', - type: 'string' - } - ], - since: '1.0.0', - group: 'suggestion', - provider: 'redisearch' - }, - 'FT.SYNDUMP': { - summary: 'Dumps the contents of a synonym group', - complexity: 'O(1)', - arguments: [ - { - name: 'index', - type: 'string' - } - ], - since: '1.2.0', - group: 'search', - provider: 'redisearch' - }, - 'FT.SYNUPDATE': { - summary: 'Creates or updates a synonym group with additional terms', - complexity: 'O(1)', - arguments: [ - { - name: 'index', - type: 'string' - }, - { - name: 'synonym_group_id', - type: 'string' - }, - { - name: 'skipinitialscan', - type: 'pure-token', - token: 'SKIPINITIALSCAN', - optional: true - }, - { - name: 'term', - type: 'string', - multiple: true - } - ], - since: '1.2.0', - group: 'search', - provider: 'redisearch' - }, - 'FT.TAGVALS': { - summary: 'Returns the distinct tags indexed in a Tag field', - complexity: 'O(N)', - arguments: [ - { - name: 'index', - type: 'string' - }, - { - name: 'field_name', - type: 'string' - } - ], - since: '1.0.0', - group: 'search', - provider: 'redisearch' - }, - 'FT._LIST': { - summary: 'Returns a list of all existing indexes', - complexity: 'O(1)', - since: '2.0.0', - group: 'search', - provider: 'redisearch' - }, -} diff --git a/redisinsight/ui/src/pages/search/styles.module.scss b/redisinsight/ui/src/pages/search/styles.module.scss deleted file mode 100644 index 160dcb9b75..0000000000 --- a/redisinsight/ui/src/pages/search/styles.module.scss +++ /dev/null @@ -1,32 +0,0 @@ -.container { - flex-grow: 1; - display: flex; - flex-direction: column; - max-height: 100%; -} - -.main { - display: flex; - flex: 1; - padding: 0 16px 0; - height: 100%; - width: 100%; -} - -.content { - display: flex; - flex-grow: 1; - width: 100%; -} - -.resizeButton { - z-index: 1 !important; -} - -.queryPanel { - padding-bottom: 8px; -} - -.queryResultsPanel { - padding-top: 8px; -} diff --git a/redisinsight/ui/src/pages/search/types.ts b/redisinsight/ui/src/pages/search/types.ts deleted file mode 100644 index f1d9287048..0000000000 --- a/redisinsight/ui/src/pages/search/types.ts +++ /dev/null @@ -1,45 +0,0 @@ -import { Maybe } from 'uiSrc/utils' - -export enum TokenType { - PureToken = 'pure-token', - Block = 'block', - OneOf = 'oneof', - String = 'string', -} - -export enum ArgName { - NArgs = 'nargs' -} - -export interface SearchCommand { - name?: string - summary?: string - expression?: boolean - type?: TokenType - token?: string - optional?: boolean - multiple?: boolean - arguments?: SearchCommand[] -} - -export interface SearchCommandTree extends SearchCommand { - parent?: SearchCommandTree -} - -export interface FoundCommandArgument { - isComplete: boolean - stopArg: Maybe - isBlocked: boolean - append: Maybe> - parent: Maybe -} - -export interface CursorContext { - prevCursorChar: string - nextCursorChar: string - isCursorInQuotes: boolean - currentOffsetArg: string - offset: number - argLeftOffset: number - argRightOffset: number -} diff --git a/redisinsight/ui/src/pages/search/utils/index.ts b/redisinsight/ui/src/pages/search/utils/index.ts deleted file mode 100644 index c820377353..0000000000 --- a/redisinsight/ui/src/pages/search/utils/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from './query' -export * from './monaco' diff --git a/redisinsight/ui/src/pages/search/utils/monaco.ts b/redisinsight/ui/src/pages/search/utils/monaco.ts deleted file mode 100644 index 4eda87a868..0000000000 --- a/redisinsight/ui/src/pages/search/utils/monaco.ts +++ /dev/null @@ -1,64 +0,0 @@ -import { monaco } from 'react-monaco-editor' -import * as monacoEditor from 'monaco-editor' -import { isString } from 'lodash' -import { generateDetail } from 'uiSrc/pages/search/utils/query' -import { SearchCommand, TokenType } from 'uiSrc/pages/search/types' -import { Maybe } from 'uiSrc/utils' - -export const setCursorPositionAtTheEnd = (editor: monacoEditor.editor.IStandaloneCodeEditor) => { - if (!editor) return - - const rows = editor.getValue().split('\n') - - editor.setPosition({ - column: rows[rows.length - 1].trimEnd().length + 1, - lineNumber: rows.length - }) - - editor.focus() -} - -export const getRange = (position: monaco.Position, word: monaco.editor.IWordAtPosition): monaco.IRange => ({ - startLineNumber: position.lineNumber, - endLineNumber: position.lineNumber, - endColumn: word.endColumn, - startColumn: word.startColumn, -}) - -export const buildSuggestion = (arg: SearchCommand, range: monaco.IRange, options: any = {}) => { - const extraQuotes = arg.expression ? '\'$1\'' : '' - return { - label: isString(arg) ? arg : arg.token || arg.arguments?.[0].token || arg.name || '', - insertText: `${arg.token || arg.arguments?.[0].token || arg.name?.toUpperCase() || ''} ${extraQuotes}`, - insertTextRules: monacoEditor.languages.CompletionItemInsertTextRule.InsertAsSnippet, - range, - kind: options?.kind || monacoEditor.languages.CompletionItemKind.Function, - ...options, - } -} - -export const getRediSearchSignutureProvider = (options: Maybe<{ - isOpen: boolean - currentArg: SearchCommand - parent: Maybe -}>) => { - const { isOpen, currentArg, parent } = options || {} - if (!isOpen) return null - - const label = generateDetail(parent) - const arg = currentArg?.type === TokenType.Block - ? currentArg?.arguments?.[0]?.name - : (currentArg?.name || currentArg?.type || '') - - return { - dispose: () => {}, - value: { - activeParameter: 0, - activeSignature: 0, - signatures: [{ - label: label || '', - parameters: [{ label: arg }] - }] - } - } -} diff --git a/redisinsight/ui/src/pages/search/utils/query.ts b/redisinsight/ui/src/pages/search/utils/query.ts deleted file mode 100644 index b3e0f984f6..0000000000 --- a/redisinsight/ui/src/pages/search/utils/query.ts +++ /dev/null @@ -1,479 +0,0 @@ -/* eslint-disable no-continue */ - -import { isNumber, toNumber } from 'lodash' -import { generateArgsNames, Maybe, Nullable } from 'uiSrc/utils' -import { CommandProvider } from 'uiSrc/constants' -import { COMPOSITE_ARGS } from 'uiSrc/pages/search/components/query/constants' -import { ArgName, FoundCommandArgument, SearchCommand, SearchCommandTree, TokenType } from '../types' - -export const splitQueryByArgs = (query: string, position: number = 0) => { - const args: [string[], string[]] = [[], []] - let arg = '' - let inQuotes = false - let escapeNextChar = false - let quoteChar = '' - let isCursorInQuotes = false - let lastArg = '' - let argLeftOffset = 0 - let argRightOffset = 0 - - const pushToProperTuple = (isAfterOffset: boolean, arg: string) => { - lastArg = arg - isAfterOffset ? args[1].push(arg) : args[0].push(arg) - } - - const updateLastArgument = (isAfterOffset: boolean, arg: string) => { - const argsBySide = args[isAfterOffset ? 1 : 0] - argsBySide[argsBySide.length - 1] = `${argsBySide[argsBySide.length - 1]} ${arg}` - } - - const updateArgOffsets = (left: number, right: number) => { - argLeftOffset = left - argRightOffset = right - } - - for (let i = 0; i < query.length; i++) { - const char = query[i] - const isAfterOffset = i >= position + (inQuotes ? -1 : 0) - - if (escapeNextChar) { - arg += char - escapeNextChar = !quoteChar - } else if (char === '\\') { - escapeNextChar = true - } else if (inQuotes) { - if (char === quoteChar) { - inQuotes = false - const argWithChat = arg + char - - if (isAfterOffset && !argLeftOffset) { - updateArgOffsets(i - arg.length, i + 1) - } - - if (isCompositeArgument(argWithChat, lastArg)) { - updateLastArgument(isAfterOffset, argWithChat) - } else { - pushToProperTuple(isAfterOffset, argWithChat) - } - - arg = '' - } else { - arg += char - } - } else if (char === '"' || char === "'") { - inQuotes = true - quoteChar = char - arg += char - } else if (char === ' ' || char === '\n') { - if (arg.length > 0) { - if (isAfterOffset && !argLeftOffset) { - updateArgOffsets(i - arg.length, i) - } - - if (isCompositeArgument(arg, lastArg)) { - updateLastArgument(isAfterOffset, arg) - } else { - pushToProperTuple(isAfterOffset, arg) - } - - arg = '' - } - } else { - arg += char - } - - if (i === position - 1) isCursorInQuotes = inQuotes - } - - if (arg.length > 0) { - if (!argLeftOffset) updateArgOffsets(query.length - arg.length, query.length) - pushToProperTuple(true, arg) - } - - const cursor = { - isCursorInQuotes, - prevCursorChar: query[position - 1]?.trim() || '', - nextCursorChar: query[position]?.trim() || '', - argLeftOffset, - argRightOffset - } - - return { args, cursor } -} - -export const findCurrentArgument = ( - args: SearchCommand[], - prev: string[], - parent?: SearchCommandTree -): Nullable => { - for (let i = prev.length - 1; i >= 0; i--) { - const arg = prev[i] - const currentArg = findArgByToken(args, arg) - const currentWithParent: SearchCommandTree = { ...currentArg, parent } - - if (currentArg?.arguments && currentArg?.type === TokenType.Block) { - return findCurrentArgument(currentArg.arguments, prev.slice(i), currentWithParent) - } - - const tokenIndex = args.findIndex((cArg) => - cArg.token?.toLowerCase() === arg.toLowerCase()) - const token = args[tokenIndex] - - if (token) { - const pastArgs = prev.slice(i) - const commandArgs = parent ? args.slice(tokenIndex, args.length) : [token] - - // getArgByRest - here we preparing the list of arguments which can be inserted, - // this is the main function which creates the list of arguments - return { - ...getArgumentSuggestions({ tokenArgs: pastArgs, levelArgs: prev }, commandArgs, parent), - parent: parent || token - } - } - } - - return null -} - -const findStopArgumentInQuery = ( - queryArgs: string[], - restCommandArgs: Maybe = [], -): { - restArguments: SearchCommand[] - stopArgIndex: number - argumentsIntered?: number - isBlocked: boolean - parent?: SearchCommand -} => { - let currentCommandArgIndex = 0 - let argumentsIntered = 0 - let isBlockedOnCommand = false - let multipleIndexStart = 0 - let multipleCountNumber = 0 - - const moveToNextCommandArg = () => { - currentCommandArgIndex++ - argumentsIntered++ - } - const blockCommand = () => { isBlockedOnCommand = true } - const unBlockCommand = () => { isBlockedOnCommand = false } - - const skipArg = () => { - argumentsIntered -= 1 - moveToNextCommandArg() - unBlockCommand() - } - - for (let i = 0; i < queryArgs.length; i++) { - const arg = queryArgs[i] - const currentCommandArg = restCommandArgs[currentCommandArgIndex] - - if (currentCommandArg?.type === TokenType.PureToken) { - skipArg() - continue - } - - if (!isBlockedOnCommand && currentCommandArg?.optional) { - const isNotToken = currentCommandArg?.token && currentCommandArg.token !== arg.toUpperCase() - const isNotOneOfToken = !currentCommandArg?.token && currentCommandArg?.type === TokenType.OneOf - && currentCommandArg?.arguments?.every(({ token }) => token !== arg.toUpperCase()) - - if (isNotToken || isNotOneOfToken) { - moveToNextCommandArg() - skipArg() - continue - } - } - - if (currentCommandArg?.type === TokenType.Block) { - let blockArguments = currentCommandArg.arguments ? [...currentCommandArg.arguments] : [] - const nArgs = toNumber(queryArgs[i - 1]) || 0 - - // if block is multiple - we duplicate nArgs inner arguments - if (currentCommandArg?.multiple && nArgs) { - blockArguments = Array(nArgs).fill(currentCommandArg.arguments).flat() - } - - const currentQueryArg = queryArgs.slice(i)?.[0]?.toUpperCase() - const isBlockHasToken = blockArguments?.[0]?.token === currentQueryArg - - if (currentCommandArg.token && !isBlockHasToken && currentQueryArg) { - blockArguments.unshift({ - type: TokenType.PureToken, - token: currentQueryArg - }) - } - - const blockSuggestion = findStopArgumentInQuery(queryArgs.slice(i), blockArguments) - const stopArg = blockSuggestion.restArguments?.[blockSuggestion.stopArgIndex] - const { argumentsIntered } = blockSuggestion - - if (nArgs && currentCommandArg?.multiple && isNumber(argumentsIntered) && argumentsIntered >= nArgs) { - i += queryArgs.slice(i).length - 1 - skipArg() - continue - } - - if (blockSuggestion.isBlocked || stopArg) { - return { - ...blockSuggestion, - parent: currentCommandArg - } - } - - i += queryArgs.slice(i).length - 1 - skipArg() - continue - } - - // if we are on token - that requires one more argument - if (currentCommandArg?.token === arg.toUpperCase()) { - blockCommand() - continue - } - - if (currentCommandArg?.name === ArgName.NArgs) { - const numberOfArgs = toNumber(arg) - - if (numberOfArgs === 0) { - moveToNextCommandArg() - skipArg() - continue - } - - moveToNextCommandArg() - blockCommand() - continue - } - - if (currentCommandArg?.type === TokenType.OneOf && currentCommandArg?.optional) { - // if oneof is optional then we can switch to another argument - if (!currentCommandArg?.arguments?.some(({ token }) => token === arg)) { - moveToNextCommandArg() - } - - skipArg() - continue - } - - if (currentCommandArg?.multiple) { - if (!multipleIndexStart) { - multipleCountNumber = toNumber(queryArgs[i - 1]) - multipleIndexStart = i - 1 - } - - if (i - multipleIndexStart >= multipleCountNumber) { - skipArg() - multipleIndexStart = 0 - continue - } - - blockCommand() - continue - } - - moveToNextCommandArg() - - isBlockedOnCommand = false - } - - return { - restArguments: restCommandArgs, - stopArgIndex: currentCommandArgIndex, - argumentsIntered, - isBlocked: isBlockedOnCommand - } -} - -export const getArgumentSuggestions = ( - { tokenArgs, levelArgs }: { - tokenArgs: string[], - levelArgs: string[] - }, - pastCommandArgs: SearchCommand[], - current?: SearchCommandTree -): { - isComplete: boolean - stopArg: Maybe, - isBlocked: boolean, - append: Array, -} => { - const { - restArguments, - stopArgIndex, - isBlocked: isWasBlocked, - parent - } = findStopArgumentInQuery(tokenArgs, pastCommandArgs) - - const prevArg = restArguments[stopArgIndex - 1] - const stopArgument = restArguments[stopArgIndex] - const restNotFilledArgs = restArguments.slice(stopArgIndex) - - const isOneOfArgument = stopArgument?.type === TokenType.OneOf - || (stopArgument?.type === TokenType.PureToken && current?.parent?.type === TokenType.OneOf) - - if (isWasBlocked) { - return { - isComplete: false, - stopArg: stopArgument, - isBlocked: !isOneOfArgument, - append: isOneOfArgument ? [stopArgument.arguments!] : [], - } - } - - const isPrevArgWasMandatory = prevArg && !prevArg.optional - if (isPrevArgWasMandatory && stopArgument && !stopArgument.optional) { - const isCanAppend = stopArgument?.token || isOneOfArgument - const append = isCanAppend ? [[isOneOfArgument ? stopArgument.arguments! : stopArgument].flat()] : [] - - return { - isComplete: false, - stopArg: stopArgument, - isBlocked: !isCanAppend, - append, - } - } - - // if we finished argument - stopArgument will be undefined, then we get it as token - const lastArgument = stopArgument ?? restArguments[0] - const isBlockHasParent = current?.arguments?.some(({ name }) => parent?.name && name === parent?.name) - const foundParent = isBlockHasParent ? { ...parent, parent: current } : (parent || current) - - const isBlockComplete = !stopArgument && current?.name === lastArgument?.name - const beforeMandatoryOptionalArgs = getAllRestArguments(foundParent, lastArgument, levelArgs, isBlockComplete) - const requiredArgsLength = restNotFilledArgs.filter((arg) => !arg.optional).length - - return { - isComplete: requiredArgsLength === 0, - stopArg: stopArgument, - isBlocked: false, - append: beforeMandatoryOptionalArgs, - } -} - -export const getRestArguments = ( - current: Maybe, - stopArgument: Nullable -): SearchCommandTree[] => { - const argumentIndexInArg = current?.arguments - ?.findIndex(({ name }) => name === stopArgument?.name) - const nextMandatoryIndex = argumentIndexInArg && argumentIndexInArg > -1 ? current?.arguments - ?.findIndex(({ optional }, i) => !optional && i > argumentIndexInArg) : -1 - const prevMandatory = current?.arguments?.slice(0, argumentIndexInArg).reverse() - .find(({ optional }) => !optional) - const prevMandatoryIndex = current?.arguments?.findIndex(({ name }) => name === prevMandatory?.name) - - const beforeMandatoryOptionalArgs = ( - nextMandatoryIndex && nextMandatoryIndex > -1 - ? current?.arguments?.slice(prevMandatoryIndex, nextMandatoryIndex) - : current?.arguments?.slice((prevMandatoryIndex || 0) + 1) - ) || [] - - const nextMandatoryArg = nextMandatoryIndex && nextMandatoryIndex > -1 - ? current?.arguments?.[nextMandatoryIndex] - : undefined - - if (nextMandatoryArg?.token) { - beforeMandatoryOptionalArgs.unshift(nextMandatoryArg) - } - - if (nextMandatoryArg?.type === TokenType.OneOf) { - beforeMandatoryOptionalArgs.unshift(...(nextMandatoryArg.arguments || [])) - } - - return beforeMandatoryOptionalArgs.map((arg) => ({ ...arg, parent: current })) -} - -export const getAllRestArguments = ( - current: Maybe, - stopArgument: Nullable, - prevStringArgs: string[] = [], - skipLevel = false -) => { - const appendArgs: Array = [] - const currentLvlNextArgs = removeNotSuggestedArgs( - prevStringArgs, - getRestArguments(current, stopArgument) - ) - - if (!skipLevel) { - appendArgs.push(fillArgsByType(currentLvlNextArgs)) - } - - if (current?.parent) { - const parentArgs = getAllRestArguments(current.parent, current, skipLevel ? prevStringArgs : []) - if (parentArgs?.length) { - appendArgs.push(...parentArgs) - } - } - - return appendArgs -} - -export const removeNotSuggestedArgs = (args: string[], commandArgs: SearchCommandTree[]) => - commandArgs.filter((arg) => { - if (arg.token && arg.multiple) return true - - if (arg.type === TokenType.OneOf) { - return !args - .some((queryArg) => arg.arguments - ?.some((oneOfArg) => oneOfArg.token?.toUpperCase() === queryArg.toUpperCase())) - } - - if (arg.type === TokenType.Block) { - return arg.arguments?.[0]?.token && !args.includes(arg.arguments?.[0]?.token?.toUpperCase()) - } - - return arg.token && !args.includes(arg.token) - }) - -export const fillArgsByType = (args: SearchCommand[], expandBlock = true): SearchCommandTree[] => { - const result: SearchCommandTree[] = [] - - for (let i = 0; i < args.length; i++) { - const currentArg = args[i] - - if (expandBlock && currentArg.type === TokenType.OneOf && !currentArg.token) { - result.push(...(currentArg?.arguments?.map((arg) => ({ ...arg, parent: currentArg })) || [])) - } - - if (currentArg.type === TokenType.Block) { - result.push({ - multiple: currentArg.multiple, - optional: currentArg.optional, - parent: currentArg, - ...(currentArg?.arguments?.[0] as SearchCommand || {}), - }) - } - if (currentArg.token) result.push(currentArg) - } - - return result -} - -export const findArgByToken = (list: SearchCommand[], arg: string): Maybe => - list.find((cArg) => - (cArg.type === TokenType.OneOf - ? cArg.arguments?.some((oneOfArg: SearchCommand) => oneOfArg?.token?.toLowerCase() === arg?.toLowerCase()) - : cArg.arguments?.[0]?.token?.toLowerCase() === arg.toLowerCase())) - -export const isCompositeArgument = (arg: string, prevArg?: string, args: string[] = []) => - args.includes([prevArg?.toUpperCase(), arg?.toUpperCase()].join(' ')) - -export const generateDetail = (command: Maybe) => { - if (!command) return '' - if (command.arguments) return generateArgsNames(CommandProvider.Main, command.arguments).join(' ') - if (command.token) { - if (command.type === TokenType.PureToken) return command.token - return `${command.token}` - } - - return '' -} - -export const addOwnTokenToArgs = (token: string, command: SearchCommand) => { - if (command.arguments) { - return ({ ...command, arguments: [{ token, type: TokenType.PureToken }, ...command.arguments] }) - } - return command -} diff --git a/redisinsight/ui/src/pages/search/utils/tests/monaco.spec.ts b/redisinsight/ui/src/pages/search/utils/tests/monaco.spec.ts deleted file mode 100644 index 48b9ff5c3e..0000000000 --- a/redisinsight/ui/src/pages/search/utils/tests/monaco.spec.ts +++ /dev/null @@ -1,60 +0,0 @@ -import { getRediSearchSignutureProvider } from 'uiSrc/pages/search/utils' -import { MOCKED_SUPPORTED_COMMANDS } from 'uiSrc/pages/search/mocks/mocks' -import { SearchCommand } from 'uiSrc/pages/search/types' - -const ftAggregateCommand = MOCKED_SUPPORTED_COMMANDS['FT.AGGREGATE'] - -const getRediSearchSignutureProviderTests = [ - { - input: { - isOpen: false, - currentArg: {}, - parent: {} - }, - result: null - }, - { - input: { - isOpen: true, - currentArg: ftAggregateCommand.arguments.find(({ name }) => name === 'groupby') as SearchCommand, - parent: null - }, - result: { - dispose: expect.any(Function), - value: { - activeParameter: 0, - activeSignature: 0, - signatures: [{ - label: '', - parameters: [{ label: 'nargs' }] - }] - } - } - }, - { - input: { - isOpen: true, - currentArg: { name: 'expression' }, - parent: ftAggregateCommand.arguments.find(({ name }) => name === 'apply') as SearchCommand - }, - result: { - dispose: expect.any(Function), - value: { - activeParameter: 0, - activeSignature: 0, - signatures: [{ - label: 'APPLY expression AS name', - parameters: [{ label: 'expression' }] - }] - } - } - } -] - -describe('getRediSearchSignutureProvider', () => { - it.each(getRediSearchSignutureProviderTests)('should properly return result', ({ input, result }) => { - const testResult = getRediSearchSignutureProvider(input) - - expect(result).toEqual(testResult) - }) -}) diff --git a/redisinsight/ui/src/pages/search/utils/tests/query.spec.ts b/redisinsight/ui/src/pages/search/utils/tests/query.spec.ts deleted file mode 100644 index 0c3fcd858d..0000000000 --- a/redisinsight/ui/src/pages/search/utils/tests/query.spec.ts +++ /dev/null @@ -1,188 +0,0 @@ -import { addOwnTokenToArgs, findCurrentArgument, generateDetail, splitQueryByArgs } from 'uiSrc/pages/search/utils' -import { SearchCommand, TokenType } from 'uiSrc/pages/search/types' -import { Maybe } from 'uiSrc/utils' -import { - commonfindCurrentArgumentCases, - findArgumentftAggreageTests, - findArgumentftSearchTests -} from './test-cases' -import { MOCKED_SUPPORTED_COMMANDS } from '../../mocks/mocks' - -const ftSearchCommand = MOCKED_SUPPORTED_COMMANDS['FT.SEARCH'] -const ftAggregateCommand = MOCKED_SUPPORTED_COMMANDS['FT.AGGREGATE'] -const COMMANDS = Object.keys(MOCKED_SUPPORTED_COMMANDS).map((name) => ({ - name, - ...MOCKED_SUPPORTED_COMMANDS[name] -})) - -describe('findCurrentArgument', () => { - describe('with list of commands', () => { - commonfindCurrentArgumentCases.forEach(({ input, result, appendIncludes, appendNotIncludes }) => { - it(`should return proper suggestions for ${input}`, () => { - const { args } = splitQueryByArgs(input) - const COMMANDS_LIST = COMMANDS.map((command) => ({ - ...addOwnTokenToArgs(command.name!, command), - token: command.name!, - type: TokenType.Block - })) - - const testResult = findCurrentArgument( - COMMANDS_LIST, - args.flat() - ) - expect(testResult).toEqual(result) - expect( - testResult?.append?.flat()?.map((arg) => arg.token) - ).toEqual( - expect.arrayContaining(appendIncludes) - ) - - if (appendNotIncludes) { - appendNotIncludes.forEach((token) => { - expect( - testResult?.append?.flat()?.map((arg) => arg.token) - ).not.toEqual( - expect.arrayContaining([token]) - ) - }) - } - }) - }) - }) - - describe('FT.AGGREGATE', () => { - findArgumentftAggreageTests.forEach(({ args, result: testResult }) => { - it(`should return proper suggestions for ${args.join(' ')}`, () => { - const result = findCurrentArgument( - ftAggregateCommand.arguments as SearchCommand[], - args - ) - expect(testResult).toEqual(result) - }) - }) - }) - - describe('FT.SEARCH', () => { - findArgumentftSearchTests.forEach(({ args, result: testResult }) => { - it(`should return proper suggestions for ${args.join(' ')}`, () => { - const result = findCurrentArgument( - ftSearchCommand.arguments as SearchCommand[], - args - ) - expect(testResult).toEqual(result) - }) - }) - }) -}) - -const splitQueryByArgsTests: Array<{ - input: [string, number?] - result: any -}> = [ - { - input: ['FT.SEARCH "idx:bicycle" "" WITHSORTKEYS'], - result: { - args: [[], ['FT.SEARCH', '"idx:bicycle"', '""', 'WITHSORTKEYS']], - cursor: { - argLeftOffset: 10, - argRightOffset: 23, - isCursorInQuotes: false, - nextCursorChar: 'F', - prevCursorChar: '' - } - } - }, - { - input: ['FT.SEARCH "idx:bicycle" "" WITHSORTKEYS', 17], - result: { - args: [['FT.SEARCH'], ['"idx:bicycle"', '""', 'WITHSORTKEYS']], - cursor: { - argLeftOffset: 10, - argRightOffset: 23, - isCursorInQuotes: true, - nextCursorChar: 'c', - prevCursorChar: 'i' - } - } - }, - { - input: ['FT.SEARCH "idx:bicycle" "" WITHSORTKEYS', 39], - result: { - args: [['FT.SEARCH', '"idx:bicycle"', '""'], ['WITHSORTKEYS']], - cursor: { - argLeftOffset: 27, - argRightOffset: 39, - isCursorInQuotes: false, - nextCursorChar: '', - prevCursorChar: 'S' - } - } - }, - { - input: ['FT.SEARCH "idx:bicycle" "" WITHSORTKEYS ', 40], - result: { - args: [['FT.SEARCH', '"idx:bicycle"', '""', 'WITHSORTKEYS'], []], - cursor: { - argLeftOffset: 0, - argRightOffset: 0, - isCursorInQuotes: false, - nextCursorChar: '', - prevCursorChar: '' - } - } - }, - { - input: ['FT.SEARCH "idx:bicycle \\" \\"" "" WITHSORTKEYS ', 46], - result: { - args: [['FT.SEARCH', '"idx:bicycle " ""', '""', 'WITHSORTKEYS'], []], - cursor: { - argLeftOffset: 0, - argRightOffset: 0, - isCursorInQuotes: false, - nextCursorChar: '', - prevCursorChar: '' - } - } - } -] - -describe('splitQueryByArgs', () => { - it.each(splitQueryByArgsTests)('should return for %input proper result', ({ input, result }) => { - const testResult = splitQueryByArgs(...input) - expect(testResult).toEqual(result) - }) -}) - -const generateDetailTests: Array<{ input: Maybe, result: any }> = [ - { - input: ftSearchCommand.arguments.find(({ name }) => name === 'nocontent') as SearchCommand, - result: 'NOCONTENT' - }, - { - input: ftSearchCommand.arguments.find(({ name }) => name === 'filter') as SearchCommand, - result: 'FILTER numeric_field min max' - }, - { - input: ftSearchCommand.arguments.find(({ name }) => name === 'geo_filter') as SearchCommand, - result: 'GEOFILTER geo_field lon lat radius m | km | mi | ft' - }, - { - input: ftAggregateCommand.arguments.find(({ name }) => name === 'groupby') as SearchCommand, - result: 'GROUPBY nargs property [property ...] [REDUCE function nargs arg [arg ...] [AS name] [REDUCE function nargs arg [arg ...] [AS name] ...]]' - }, -] - -describe('generateDetail', () => { - it.each(generateDetailTests)('should return for %input proper result', ({ input, result }) => { - const testResult = generateDetail(input) - expect(testResult).toEqual(result) - }) -}) - -describe('addOwnTokenToArgs', () => { - it('should add FT.SEARCH to args', () => { - const result = addOwnTokenToArgs('FT.SEARCH', { arguments: [] }) - - expect({ arguments: [{ token: 'FT.SEARCH', type: 'pure-token' }] }).toEqual(result) - }) -}) diff --git a/redisinsight/ui/src/pages/search/utils/tests/test-cases/common.ts b/redisinsight/ui/src/pages/search/utils/tests/test-cases/common.ts deleted file mode 100644 index 7946e4baa6..0000000000 --- a/redisinsight/ui/src/pages/search/utils/tests/test-cases/common.ts +++ /dev/null @@ -1,183 +0,0 @@ -// Common test cases -export const commonfindCurrentArgumentCases = [ - { - input: 'FT.SEARCH index "" DIALECT 1', - result: { - stopArg: undefined, - append: expect.any(Array), - isBlocked: false, - isComplete: true, - parent: expect.any(Object) - }, - appendIncludes: ['WITHSCORES', 'VERBATIM', 'FILTER', 'SORTBY', 'RETURN'], - appendNotIncludes: ['DIALECT'] - }, - { - input: 'FT.AGGREGATE "idx:schools" "" GROUPBY 1 p REDUCE AVG 1 a1 AS name ', - result: { - stopArg: undefined, - append: expect.any(Array), - isBlocked: false, - isComplete: true, - parent: expect.any(Object) - }, - appendIncludes: ['REDUCE', 'APPLY', 'SORTBY', 'GROUPBY'], - appendNotIncludes: ['AS'], - }, - { - input: 'FT.SEARCH "idx:bicycle" "*" ', - result: { - stopArg: expect.any(Object), - append: expect.any(Array), - isBlocked: false, - isComplete: true, - parent: expect.any(Object) - }, - appendIncludes: ['DIALECT', 'EXPANDER', 'INKEYS', 'LIMIT'], - appendNotIncludes: ['ASC'], - }, - { - input: 'FT.SEARCH "idx:bicycle" "*" DIALECT 2', - result: expect.any(Object), - appendIncludes: ['EXPANDER', 'INKEYS', 'LIMIT'], - appendNotIncludes: ['DIALECT'], - }, - { - input: 'FT.PROFILE \'idx:schools\' SEARCH ', - result: expect.any(Object), - appendIncludes: ['LIMITED', 'QUERY'], - appendNotIncludes: ['AGGREGATE', 'SEARCH'], - }, - { - input: 'FT.CREATE "idx:schools" ', - result: expect.any(Object), - appendIncludes: ['FILTER', 'ON', 'SCHEMA', 'SCORE', 'NOHL'], - appendNotIncludes: ['HASH', 'JSON'], - }, - { - input: 'FT.CREATE "idx:schools" ON', - result: expect.any(Object), - appendIncludes: ['HASH', 'JSON'], - appendNotIncludes: ['SCHEMA', 'SCORE', 'NOHL'], - }, - { - input: 'FT.CREATE "idx:schools" ON JSON NOFREQS', - result: expect.any(Object), - appendIncludes: ['TEMPORARY', 'NOFIELDS', 'PAYLOAD_FIELD', 'MAXTEXTFIELDS', 'PREFIX', 'SKIPINITIALSCAN'], - appendNotIncludes: ['ON', 'JSON', 'NOFREQS'], - }, - { - input: 'FT.CREATE "idx:schools" ON JSON NOFREQS SKIPINITIALSCAN', - result: expect.any(Object), - appendIncludes: ['TEMPORARY', 'NOFIELDS', 'PAYLOAD_FIELD', 'MAXTEXTFIELDS', 'PREFIX'], - appendNotIncludes: ['ON', 'JSON', 'NOFREQS', 'SKIPINITIALSCAN'], - }, - { - input: 'FT.CREATE "idx:schools" ON JSON SCHEMA address ', - result: { - stopArg: expect.any(Object), - append: expect.any(Array), - isBlocked: false, - isComplete: false, - parent: expect.any(Object) - }, - appendIncludes: ['AS', 'GEO', 'TEXT', 'VECTOR'], - appendNotIncludes: ['SCHEMA', 'SCORE', 'NOHL'], - }, - { - input: 'FT.CREATE "idx:schools" ON JSON SCHEMA address TEXT NOINDEX INDEXMISSING ', - result: { - stopArg: expect.any(Object), - append: expect.any(Array), - isBlocked: false, - isComplete: true, - parent: expect.any(Object) - }, - appendIncludes: ['INDEXEMPTY', 'SORTABLE', 'WITHSUFFIXTRIE'], - appendNotIncludes: ['SCHEMA', 'SCORE', 'NOHL'], - }, - { - input: 'FT.ALTER "idx:schools" ', - result: { - stopArg: expect.any(Object), - append: expect.any(Array), - isBlocked: false, - isComplete: false, - parent: expect.any(Object) - }, - appendIncludes: ['SCHEMA', 'SKIPINITIALSCAN'], - appendNotIncludes: ['ADD'], - }, - { - input: 'FT.ALTER "idx:schools" SCHEMA', - result: expect.any(Object), - appendIncludes: ['ADD'], - appendNotIncludes: ['SKIPINITIALSCAN'], - }, - { - input: 'FT.CONFIG SET ', - result: { - stopArg: { - name: 'option', - type: 'string' - }, - append: [], - isBlocked: true, - isComplete: false, - parent: expect.any(Object) - }, - appendIncludes: [], - appendNotIncludes: [expect.any(String)], - }, - { - input: 'FT.CURSOR READ "idx:schools" 1 ', - result: expect.any(Object), - appendIncludes: ['COUNT'], - }, - { - input: 'FT.DICTADD dict term1 ', - result: { - append: [], - isBlocked: true, - isComplete: false, - parent: expect.any(Object), - stopArg: { - multiple: true, - name: 'term', - type: 'string' - } - }, - appendIncludes: [], - }, - { - input: 'FT.SUGADD key string ', - result: { - append: [], - isBlocked: true, - isComplete: false, - parent: expect.any(Object), - stopArg: { - name: 'score', - type: 'double' - } - }, - appendIncludes: [], - }, - { - input: 'FT.SUGADD key string 1.0 ', - result: expect.any(Object), - appendIncludes: ['INCR', 'PAYLOAD'], - }, - { - input: 'FT.SUGADD key string 1.0 PAYLOAD 1 ', - result: expect.any(Object), - appendIncludes: ['INCR'], - appendNotIncludes: ['PAYLOAD'], - }, - { - input: 'FT.SUGGET k p FUZZY MAX 2 ', - result: expect.any(Object), - appendIncludes: ['WITHPAYLOADS', 'WITHSCORES'], - appendNotIncludes: ['FUZZY', 'MAX'], - }, -] diff --git a/redisinsight/ui/src/pages/search/utils/tests/test-cases/ft-aggregate.ts b/redisinsight/ui/src/pages/search/utils/tests/test-cases/ft-aggregate.ts deleted file mode 100644 index e1411809a9..0000000000 --- a/redisinsight/ui/src/pages/search/utils/tests/test-cases/ft-aggregate.ts +++ /dev/null @@ -1,267 +0,0 @@ -export const findArgumentftAggreageTests = [ - { args: [''], result: null }, - { args: ['', ''], result: null }, - { - args: ['index', '"query"', 'APPLY'], - result: { - stopArg: { name: 'expression', token: 'APPLY', type: 'string' }, - append: [], - isBlocked: true, - isComplete: false, - parent: expect.any(Object) - } - }, - { - args: ['index', '"query"', 'APPLY', 'expression'], - result: { - stopArg: { name: 'name', token: 'AS', type: 'string' }, - append: expect.any(Array), - isBlocked: false, - isComplete: false, - parent: expect.any(Object) - } - }, - { - args: ['index', '"query"', 'APPLY', 'expression', 'AS'], - result: { - stopArg: { name: 'name', token: 'AS', type: 'string' }, - append: expect.any(Array), - isBlocked: true, - isComplete: false, - parent: expect.any(Object) - } - }, - { - args: ['index', '"query"', 'APPLY', 'expression', 'AS', 'name'], - result: { - stopArg: undefined, - append: expect.any(Array), - isBlocked: false, - isComplete: true, - parent: expect.any(Object) - } - }, - { - args: ['""', '""', 'GROUPBY', '2', 'p1', 'p2', 'REDUCE', 'f'], - result: { - stopArg: { name: 'nargs', type: 'integer' }, - append: [], - isBlocked: true, - isComplete: false, - parent: expect.any(Object) - } - }, - { - args: ['""', '""', 'GROUPBY', '2', 'p1', 'p2', 'REDUCE', 'f', '0'], - result: { - stopArg: { - name: 'name', - type: 'string', - token: 'AS', - optional: true - }, - append: [ - [ - { - name: 'name', - type: 'string', - token: 'AS', - optional: true, - parent: { - name: 'reduce', - type: 'block', - optional: true, - multiple: true, - arguments: [ - { - name: 'function', - token: 'REDUCE', - type: 'string' - }, - { - name: 'nargs', - type: 'integer' - }, - { - name: 'arg', - type: 'string', - multiple: true - }, - { - name: 'name', - type: 'string', - token: 'AS', - optional: true - } - ], - parent: expect.any(Object) - } - } - ], - [ - { - name: 'function', - token: 'REDUCE', - type: 'string', - multiple: true, - optional: true, - parent: expect.any(Object) - } - ] - ], - isBlocked: false, - isComplete: true, - parent: expect.any(Object) - } - }, - { - args: ['""', '""', 'GROUPBY', '2', 'p1', 'p2', 'REDUCE', 'f', '1', 'AS', 'name'], - result: { - stopArg: undefined, - append: [ - [], - [ - { - name: 'function', - token: 'REDUCE', - type: 'string', - multiple: true, - optional: true, - parent: expect.any(Object) - } - ] - ], - isBlocked: false, - isComplete: true, - parent: expect.any(Object) - } - }, - { - args: ['index', '"query"', 'SORTBY'], - result: { - stopArg: { name: 'nargs', token: 'SORTBY', type: 'integer' }, - append: expect.any(Array), - isBlocked: true, - isComplete: false, - parent: expect.any(Object) - } - }, - { - args: ['index', '"query"', 'SORTBY', '1', 'p1'], - result: { - stopArg: { - name: 'num', - type: 'integer', - token: 'MAX', - optional: true - }, - append: [ - [ - { - name: 'num', - type: 'integer', - token: 'MAX', - optional: true, - parent: expect.any(Object) - } - ] - ], - isBlocked: false, - isComplete: true, - parent: expect.any(Object) - } - }, - { - args: ['index', '"query"', 'SORTBY', '2', 'p1', 'ASC'], - result: { - stopArg: { - name: 'num', - type: 'integer', - token: 'MAX', - optional: true - }, - append: [ - [ - { - name: 'num', - type: 'integer', - token: 'MAX', - optional: true, - parent: expect.any(Object) - } - ] - ], - isBlocked: false, - isComplete: true, - parent: expect.any(Object) - } - }, - { - args: ['index', '"query"', 'SORTBY', '0'], - result: { - stopArg: { - name: 'num', - type: 'integer', - token: 'MAX', - optional: true - }, - append: [ - [{ - name: 'num', - type: 'integer', - token: 'MAX', - optional: true, - parent: expect.any(Object) - }] - ], - isBlocked: false, - isComplete: true, - parent: expect.any(Object) - } - }, - { - args: ['index', '"query"', 'SORTBY', '2', 'p1', 'ASC', 'MAX'], - result: { - stopArg: { - name: 'num', - type: 'integer', - token: 'MAX', - optional: true - }, - append: [], - isBlocked: true, - isComplete: false, - parent: expect.any(Object) - } - }, - { - args: ['index', '"query"', 'LOAD', '4'], - result: { - stopArg: { multiple: true, name: 'field', type: 'string' }, - append: [], - isBlocked: true, - isComplete: false, - parent: expect.any(Object) - } - }, - { - args: ['index', '"query"', 'LOAD', '4', '1', '2', '3'], - result: { - stopArg: { multiple: true, name: 'field', type: 'string' }, - append: [], - isBlocked: true, - isComplete: false, - parent: expect.any(Object) - } - }, - { - args: ['index', '"query"', 'LOAD', '4', '1', '2', '3', '4'], - result: { - stopArg: undefined, - append: [[]], - isBlocked: false, - isComplete: true, - parent: expect.any(Object) - } - }, -] diff --git a/redisinsight/ui/src/pages/search/utils/tests/test-cases/ft-search.ts b/redisinsight/ui/src/pages/search/utils/tests/test-cases/ft-search.ts deleted file mode 100644 index 28137bf8e9..0000000000 --- a/redisinsight/ui/src/pages/search/utils/tests/test-cases/ft-search.ts +++ /dev/null @@ -1,283 +0,0 @@ -export const findArgumentftSearchTests = [ - { args: [''], result: null }, - { args: ['', ''], result: null }, - { - args: ['', '', 'SUMMARIZE'], - result: { - stopArg: { - name: 'fields', - type: 'block', - optional: true, - arguments: [ - { - name: 'count', - type: 'string', - token: 'FIELDS' - }, - { - name: 'field', - type: 'string', - multiple: true - } - ] - }, - append: [[ - { - name: 'count', - type: 'string', - token: 'FIELDS', - optional: true, - parent: expect.any(Object), - }, - { - name: 'num', - type: 'integer', - token: 'FRAGS', - optional: true, - parent: expect.any(Object) - }, - { - name: 'fragsize', - type: 'integer', - token: 'LEN', - optional: true, - parent: expect.any(Object) - }, - { - name: 'separator', - type: 'string', - token: 'SEPARATOR', - optional: true, - parent: expect.any(Object) - } - ]], - isBlocked: false, - isComplete: true, - parent: expect.any(Object) - } - }, - { - args: ['', '', 'SUMMARIZE', 'FIELDS'], - result: { - stopArg: { - name: 'count', - type: 'string', - token: 'FIELDS' - }, - append: [], - isBlocked: true, - isComplete: false, - parent: expect.any(Object) - } - }, - { - args: ['', '', 'SUMMARIZE', 'FIELDS', '1'], - result: { - stopArg: { - name: 'field', - type: 'string', - multiple: true - }, - append: [], - isBlocked: true, - isComplete: false, - parent: expect.any(Object) - } - }, - { - args: ['', '', 'SUMMARIZE', 'FIELDS', '1', 'f', 'FRAGS'], - result: { - stopArg: { - name: 'num', - type: 'integer', - token: 'FRAGS', - optional: true - }, - append: [], - isBlocked: true, - isComplete: false, - parent: expect.any(Object) - } - }, - { - args: ['', '', 'SUMMARIZE', 'FIELDS', '1', 'f', 'FRAGS', '10'], - result: { - stopArg: { - name: 'fragsize', - type: 'integer', - token: 'LEN', - optional: true - }, - append: [[ - { - name: 'fragsize', - type: 'integer', - token: 'LEN', - optional: true, - parent: expect.any(Object) - }, - { - name: 'separator', - type: 'string', - token: 'SEPARATOR', - optional: true, - parent: expect.any(Object) - } - ]], - isBlocked: false, - isComplete: true, - parent: expect.any(Object) - } - }, - { - args: ['', '', 'RETURN', '1', 'iden'], - result: { - stopArg: undefined, - append: [ - [] - ], - isBlocked: false, - isComplete: true, - parent: expect.any(Object) - } - }, - { - args: ['', '', 'RETURN', '2', 'iden'], - result: { - stopArg: { - name: 'property', - type: 'string', - token: 'AS', - optional: true - }, - append: [ - [ - { - name: 'property', - type: 'string', - token: 'AS', - optional: true, - parent: expect.any(Object) - } - ], - [] - ], - isBlocked: false, - isComplete: false, - parent: expect.any(Object) - } - }, - { - args: ['', '', 'RETURN', '2', 'iden', 'iden'], - result: { - stopArg: undefined, - append: [ - [] - ], - isBlocked: false, - isComplete: true, - parent: expect.any(Object) - } - }, - { - args: ['', '', 'RETURN', '3', 'iden', 'iden'], - result: { - stopArg: { - name: 'property', - type: 'string', - token: 'AS', - optional: true - }, - append: [ - [ - { - name: 'property', - type: 'string', - token: 'AS', - optional: true, - parent: expect.any(Object) - } - ], - [] - ], - isBlocked: false, - isComplete: false, - parent: expect.any(Object) - } - }, - { - args: ['', '', 'RETURN', '3', 'iden', 'iden', 'AS', 'iden2'], - result: { - stopArg: undefined, - append: [ - [] - ], - isBlocked: false, - isComplete: true, - parent: expect.any(Object) - } - }, - { - args: ['', '', 'SORTBY', 'f'], - result: { - stopArg: { - name: 'order', - type: 'oneof', - optional: true, - arguments: [ - { - name: 'asc', - type: 'pure-token', - token: 'ASC' - }, - { - name: 'desc', - type: 'pure-token', - token: 'DESC' - } - ] - }, - append: [ - [ - { - name: 'asc', - type: 'pure-token', - token: 'ASC', - parent: expect.any(Object) - }, - { - name: 'desc', - type: 'pure-token', - token: 'DESC', - parent: expect.any(Object) - } - ] - ], - isBlocked: false, - isComplete: true, - parent: expect.any(Object) - } - }, - { - args: ['', '', 'SORTBY', 'f', 'DESC'], - result: { - stopArg: undefined, - append: [], - isBlocked: false, - isComplete: true, - parent: expect.any(Object) - } - }, - { - args: ['', '', 'DIALECT', '1'], - result: { - stopArg: undefined, - append: [ - [] - ], - isBlocked: false, - isComplete: true, - parent: expect.any(Object) - } - }, -] diff --git a/redisinsight/ui/src/pages/search/utils/tests/test-cases/index.ts b/redisinsight/ui/src/pages/search/utils/tests/test-cases/index.ts deleted file mode 100644 index 42889e7be5..0000000000 --- a/redisinsight/ui/src/pages/search/utils/tests/test-cases/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -export * from './ft-aggregate' -export * from './ft-search' -export * from './common' diff --git a/redisinsight/ui/src/pages/workbench/WorkbenchPage.tsx b/redisinsight/ui/src/pages/workbench/WorkbenchPage.tsx index bdd0a14058..2e92e9c76b 100644 --- a/redisinsight/ui/src/pages/workbench/WorkbenchPage.tsx +++ b/redisinsight/ui/src/pages/workbench/WorkbenchPage.tsx @@ -1,12 +1,10 @@ import React, { useEffect, useState } from 'react' -import { useDispatch, useSelector } from 'react-redux' +import { useSelector } from 'react-redux' import { useParams } from 'react-router-dom' import { formatLongName, getDbIndex, setTitle } from 'uiSrc/utils' import { connectedInstanceSelector } from 'uiSrc/slices/instances/instances' import { sendPageViewTelemetry, TelemetryPageView } from 'uiSrc/telemetry' -import { CommandExecutionType } from 'uiSrc/slices/interfaces' -import { setExecutionType } from 'uiSrc/slices/workbench/wb-results' import WBViewWrapper from './components/wb-view' const WorkbenchPage = () => { @@ -15,14 +13,9 @@ const WorkbenchPage = () => { const { name: connectedInstanceName, db } = useSelector(connectedInstanceSelector) const { instanceId } = useParams<{ instanceId: string }>() - const dispatch = useDispatch() setTitle(`${formatLongName(connectedInstanceName, 33, 0, '...')} ${getDbIndex(db)} - Workbench`) - useEffect(() => { - dispatch(setExecutionType(CommandExecutionType.Workbench)) - }, []) - useEffect(() => { if (connectedInstanceName && !isPageViewSent) { sendPageView(instanceId) diff --git a/redisinsight/ui/src/pages/workbench/components/wb-view/WBViewWrapper.tsx b/redisinsight/ui/src/pages/workbench/components/wb-view/WBViewWrapper.tsx index bb050d7f89..cb3542ea1f 100644 --- a/redisinsight/ui/src/pages/workbench/components/wb-view/WBViewWrapper.tsx +++ b/redisinsight/ui/src/pages/workbench/components/wb-view/WBViewWrapper.tsx @@ -15,7 +15,7 @@ import { sendWbQueryAction, workbenchResultsSelector, } from 'uiSrc/slices/workbench/wb-results' -import { CommandExecutionType, Instance, IPluginVisualization } from 'uiSrc/slices/interfaces' +import { Instance, IPluginVisualization } from 'uiSrc/slices/interfaces' import { connectedInstanceSelector, initialState as instanceInitState } from 'uiSrc/slices/instances/instances' import { ResultsMode, RunQueryMode } from 'uiSrc/slices/interfaces/workbench' import { cliSettingsSelector, fetchBlockingCliCommandsAction } from 'uiSrc/slices/cli/cli-settings' @@ -165,7 +165,6 @@ const WBViewWrapper = () => { commandInit, commandId, executeParams, - CommandExecutionType.Workbench, { afterEach: () => { const isNewCommand = !commandId diff --git a/redisinsight/ui/src/pages/workbench/utils/tests/monaco.spec.ts b/redisinsight/ui/src/pages/workbench/utils/tests/monaco.spec.ts index c72864bc06..2ab897b97e 100644 --- a/redisinsight/ui/src/pages/workbench/utils/tests/monaco.spec.ts +++ b/redisinsight/ui/src/pages/workbench/utils/tests/monaco.spec.ts @@ -1,6 +1,5 @@ -import { getRediSearchSignutureProvider } from 'uiSrc/pages/search/utils' import { MOCKED_REDIS_COMMANDS } from 'uiSrc/mocks/data/mocked_redis_commands' -import { SearchCommand } from 'uiSrc/pages/search/types' +import { getRediSearchSignutureProvider } from 'uiSrc/pages/workbench/utils/monaco' const ftAggregateCommand = MOCKED_REDIS_COMMANDS['FT.AGGREGATE'] @@ -16,7 +15,7 @@ const getRediSearchSignatureProviderTests = [ { input: { isOpen: true, - currentArg: ftAggregateCommand.arguments.find(({ name }) => name === 'groupby') as SearchCommand, + currentArg: ftAggregateCommand.arguments.find(({ name }) => name === 'groupby'), parent: null }, result: { @@ -35,7 +34,7 @@ const getRediSearchSignatureProviderTests = [ input: { isOpen: true, currentArg: { name: 'expression' }, - parent: ftAggregateCommand.arguments.find(({ name }) => name === 'apply') as SearchCommand + parent: ftAggregateCommand.arguments.find(({ name }) => name === 'apply') }, result: { dispose: expect.any(Function), diff --git a/redisinsight/ui/src/pages/workbench/utils/tests/query.spec.ts b/redisinsight/ui/src/pages/workbench/utils/tests/query.spec.ts index 0f705de920..07010aaa38 100644 --- a/redisinsight/ui/src/pages/workbench/utils/tests/query.spec.ts +++ b/redisinsight/ui/src/pages/workbench/utils/tests/query.spec.ts @@ -1,7 +1,6 @@ -import { SearchCommand, TokenType } from 'uiSrc/pages/search/types' import { Maybe, splitQueryByArgs } from 'uiSrc/utils' import { MOCKED_REDIS_COMMANDS } from 'uiSrc/mocks/data/mocked_redis_commands' -import { IRedisCommand } from 'uiSrc/constants' +import { IRedisCommand, ICommandTokenType } from 'uiSrc/constants' import { commonfindCurrentArgumentCases, findArgumentftAggreageTests, @@ -23,11 +22,11 @@ describe('findCurrentArgument', () => { describe('with list of commands', () => { commonfindCurrentArgumentCases.forEach(({ input, result, appendIncludes, appendNotIncludes }) => { it(`should return proper suggestions for ${input}`, () => { - const { args } = splitQueryByArgs(input, 0, COMPOSITE_ARGS) + const { args } = splitQueryByArgs(input, 0, COMPOSITE_ARGS.concat('LOAD *')) const COMMANDS_LIST = COMMANDS.map((command) => ({ ...addOwnTokenToArgs(command.name!, command), token: command.name!, - type: TokenType.Block + type: ICommandTokenType.Block })) const testResult = findCurrentArgument( @@ -79,21 +78,21 @@ describe('findCurrentArgument', () => { }) }) -const generateDetailTests: Array<{ input: Maybe, result: any }> = [ +const generateDetailTests: Array<{ input: Maybe, result: any }> = [ { - input: ftSearchCommand.arguments.find(({ name }) => name === 'nocontent') as SearchCommand, + input: ftSearchCommand.arguments.find(({ name }) => name === 'nocontent') as IRedisCommand, result: 'NOCONTENT' }, { - input: ftSearchCommand.arguments.find(({ name }) => name === 'filter') as SearchCommand, + input: ftSearchCommand.arguments.find(({ name }) => name === 'filter') as IRedisCommand, result: 'FILTER numeric_field min max' }, { - input: ftSearchCommand.arguments.find(({ name }) => name === 'geo_filter') as SearchCommand, + input: ftSearchCommand.arguments.find(({ name }) => name === 'geo_filter') as IRedisCommand, result: 'GEOFILTER geo_field lon lat radius m | km | mi | ft' }, { - input: ftAggregateCommand.arguments.find(({ name }) => name === 'groupby') as SearchCommand, + input: ftAggregateCommand.arguments.find(({ name }) => name === 'groupby') as IRedisCommand, result: 'GROUPBY nargs property [property ...] [REDUCE function nargs arg [arg ...] [AS name] [REDUCE function nargs arg [arg ...] [AS name] ...]]' }, ] diff --git a/redisinsight/ui/src/pages/workbench/utils/tests/test-cases/common.ts b/redisinsight/ui/src/pages/workbench/utils/tests/test-cases/common.ts index b39b3e5945..0e6d18c670 100644 --- a/redisinsight/ui/src/pages/workbench/utils/tests/test-cases/common.ts +++ b/redisinsight/ui/src/pages/workbench/utils/tests/test-cases/common.ts @@ -244,12 +244,13 @@ export const commonfindCurrentArgumentCases = [ appendIncludes: ['ft', 'km', 'm', 'mi'], appendNotIncludes: ['SORTBY', 'FILTER', 'LIMIT', 'DIALECT', 'AS', 'ASC'], }, - { - input: 'FT.SEARCH textVehicles "*" RETURN 2 test ', - result: expect.any(Object), - appendIncludes: ['AS'], - appendNotIncludes: ['SORTBY', 'FILTER', 'LIMIT', 'DIALECT', 'ASC'], - }, + // skip + // { + // input: 'FT.SEARCH textVehicles "*" RETURN 2 test ', + // result: expect.any(Object), + // appendIncludes: ['AS'], + // appendNotIncludes: ['SORTBY', 'FILTER', 'LIMIT', 'DIALECT', 'ASC'], + // }, { input: 'FT.CREATE textVehicles ON ', result: expect.any(Object), diff --git a/redisinsight/ui/src/slices/interfaces/workbench.ts b/redisinsight/ui/src/slices/interfaces/workbench.ts index 4bb7378e84..94652c9768 100644 --- a/redisinsight/ui/src/slices/interfaces/workbench.ts +++ b/redisinsight/ui/src/slices/interfaces/workbench.ts @@ -9,7 +9,6 @@ export interface StateWorkbenchSettings { } export interface StateWorkbenchResults { - type: CommandExecutionType isLoaded: boolean loading: boolean processing: boolean diff --git a/redisinsight/ui/src/slices/tests/workbench/wb-results.spec.ts b/redisinsight/ui/src/slices/tests/workbench/wb-results.spec.ts index e5338ed994..e459ee3011 100644 --- a/redisinsight/ui/src/slices/tests/workbench/wb-results.spec.ts +++ b/redisinsight/ui/src/slices/tests/workbench/wb-results.spec.ts @@ -96,32 +96,6 @@ describe('workbench results slice', () => { }) }) - describe('sendWBCommand with another type', () => { - it('should properly set state', () => { - // Arrange - const mockPayload = { - commands: ['command', 'command2'], - commandId: '123', - executionType: CommandExecutionType.Search - } - const state = { - ...initialState, - items: [] - } - - // Act - const nextState = reducer(initialState, sendWBCommand(mockPayload)) - - // Assert - const rootState = Object.assign(initialStateDefault, { - workbench: { - results: nextState, - }, - }) - expect(workbenchResultsSelector(rootState)).toEqual(state) - }) - }) - describe('toggleOpenWBResult', () => { it('should properly set isOpen = true', () => { // Arrange diff --git a/redisinsight/ui/src/slices/workbench/wb-results.ts b/redisinsight/ui/src/slices/workbench/wb-results.ts index f3a9d177f8..526f416a25 100644 --- a/redisinsight/ui/src/slices/workbench/wb-results.ts +++ b/redisinsight/ui/src/slices/workbench/wb-results.ts @@ -7,7 +7,8 @@ import { addErrorNotification } from 'uiSrc/slices/app/notifications' import { CliOutputFormatterType } from 'uiSrc/constants/cliOutput' import { RunQueryMode, ResultsMode, CommandExecutionType } from 'uiSrc/slices/interfaces/workbench' import { - getApiErrorMessage, getCommandsForExecution, + getApiErrorMessage, + getCommandsForExecution, getExecuteParams, getMultiCommands, getUrl, @@ -29,7 +30,6 @@ import { } from '../interfaces' export const initialState: StateWorkbenchResults = { - type: CommandExecutionType.Workbench, isLoaded: false, loading: false, processing: false, @@ -47,10 +47,6 @@ const workbenchResultsSlice = createSlice({ reducers: { setWBResultsInitialState: () => initialState, - setExecutionType: (state, { payload }: PayloadAction) => { - state.type = payload - }, - // Fetch Workbench history loadWBHistory: (state) => { state.loading = true @@ -118,12 +114,10 @@ const workbenchResultsSlice = createSlice({ sendWBCommand: ( state, { - payload: { commands, commandId, executionType } + payload: { commands, commandId } }: - PayloadAction<{ commands: string[], commandId: string, executionType: CommandExecutionType }> + { payload: { commands: string[], commandId: string } } ) => { - if (executionType !== state.type) return - let newItems = [ ...commands.map((command, i) => ({ command, @@ -227,7 +221,6 @@ const workbenchResultsSlice = createSlice({ // Actions generated from the slice export const { setWBResultsInitialState, - setExecutionType, loadWBHistory, loadWBHistorySuccess, loadWBHistoryFailure, @@ -311,7 +304,6 @@ export function sendWBCommandAction({ dispatch(sendWBCommand({ commands: isGroupResults(resultsMode) ? [`${commands.length} - Command(s)`] : commands, commandId, - executionType })) dispatch(setDbIndexState(true)) @@ -378,7 +370,6 @@ export function sendWBCommandClusterAction({ dispatch(sendWBCommand({ commands: isGroupResults(resultsMode) ? [`${commands.length} - Commands`] : commands, commandId, - executionType })) const { data, status } = await apiService.post( @@ -527,7 +518,6 @@ export function sendWbQueryAction( queryInit: string, commandId?: Nullable, executeParams: CodeButtonParams = {}, - executionType?: CommandExecutionType, onSuccessAction?: { afterEach?: () => void, afterAll?: () => void @@ -563,7 +553,6 @@ export function sendWbQueryAction( commands, multiCommands, mode: activeRunQueryMode, - executionType, onSuccessAction: onSuccess, onFailAction: onFail })) @@ -586,7 +575,6 @@ export function sendWbQueryAction( mode: activeRunQueryMode, resultsMode, multiCommands, - executionType, onSuccessAction: onSuccess, onFailAction: onFail }) diff --git a/redisinsight/ui/src/telemetry/events.ts b/redisinsight/ui/src/telemetry/events.ts index 2ccbe4a3f6..b384e915f8 100644 --- a/redisinsight/ui/src/telemetry/events.ts +++ b/redisinsight/ui/src/telemetry/events.ts @@ -126,18 +126,6 @@ export enum TelemetryEvent { WORKBENCH_CLEAR_RESULT_CLICKED = 'WORKBENCH_CLEAR_RESULT_CLICKED', WORKBENCH_CLEAR_ALL_RESULTS_CLICKED = 'WORKBENCH_CLEAR_ALL_RESULTS_CLICKED', - SEARCH_COMMAND_SUBMITTED = 'SEARCH_COMMAND_SUBMITTED', - SEARCH_RESULT_VIEW_CHANGED = 'SEARCH_RESULT_VIEW_CHANGED', - SEARCH_COMMAND_COPIED = 'SEARCH_COMMAND_COPIED', - SEARCH_COMMAND_RUN_AGAIN = 'SEARCH_COMMAND_RUN_AGAIN', - SEARCH_RESULTS_IN_FULL_SCREEN = 'SEARCH_RESULTS_IN_FULL_SCREEN', - SEARCH_RESULTS_COLLAPSED = 'SEARCH_RESULTS_COLLAPSED', - SEARCH_RESULTS_EXPANDED = 'SEARCH_RESULTS_EXPANDED', - SEARCH_CLEAR_RESULT_CLICKED = 'SEARCH_CLEAR_RESULT_CLICKED', - SEARCH_CLEAR_ALL_RESULTS_CLICKED = 'SEARCH_CLEAR_ALL_RESULTS_CLICKED', - SEARCH_EXPAND_ALL_RESULTS = 'SEARCH_EXPAND_ALL_RESULTS', - SEARCH_FORMATTER_CHANGED = 'SEARCH_FORMATTER_CHANGED', - PROFILER_OPENED = 'PROFILER_OPENED', PROFILER_STARTED = 'PROFILER_STARTED', PROFILER_STOPPED = 'PROFILER_STOPPED', diff --git a/redisinsight/ui/src/utils/monaco/monarchTokens/redisearchTokens.ts b/redisinsight/ui/src/utils/monaco/monarchTokens/redisearchTokens.ts deleted file mode 100644 index e73734b113..0000000000 --- a/redisinsight/ui/src/utils/monaco/monarchTokens/redisearchTokens.ts +++ /dev/null @@ -1,99 +0,0 @@ -import { monaco as monacoEditor } from 'react-monaco-editor' -import { SearchCommand } from 'uiSrc/pages/search/types' -import { - generateKeywords, - generateTokens, - generateTokensWithFunctions, - getBlockTokens, isIndexAfterKeyword, - isQueryAfterIndex -} from 'uiSrc/utils/monaco/redisearch/utils_old' -import { generateQuery } from 'uiSrc/utils/monaco/monarchTokens/redisearchTokensTemplates' - -const STRING_DOUBLE = 'string.double' - -export const getRediSearchMonarchTokensProvider = ( - commands: SearchCommand[], - command?: string -): monacoEditor.languages.IMonarchLanguage => { - const currentCommand = commands.find(({ name }) => name === command) - - const keywords = generateKeywords(commands) - const isHighlightIndex = isIndexAfterKeyword(currentCommand) - const argTokens = generateTokens(currentCommand) - const isHighlightQuery = isQueryAfterIndex(currentCommand) - - return ( - { - defaultToken: '', - tokenPostfix: '.redisearch', - ignoreCase: true, - brackets: [ - { open: '[', close: ']', token: 'delimiter.square' }, - { open: '(', close: ')', token: 'delimiter.parenthesis' }, - ], - keywords, - tokenizer: { - root: [ - { include: '@fields' }, - { include: '@whitespace' }, - { include: '@numbers' }, - { include: '@strings' }, - { include: '@keyword' }, - [/LOAD\s+\*/, 'loadAll'], - { include: '@argument.block' }, - { include: '@argument.block.withFunctions' }, - [/[;,.]/, 'delimiter'], - [/[()]/, '@brackets'], - [ - /[\w@#$]+/, - { - cases: { - '@keywords': 'keyword', - '@default': 'identifier', - }, - }, - ], - [/[<>=!%&+\-*/|~^]/, 'operator'], - ], - keyword: [ - [`(${keywords.join('|')})\\b`, { token: 'keyword', next: isHighlightIndex ? '@index' : '@root' }] - ], - 'argument.block': getBlockTokens(argTokens?.pureTokens), - ...generateTokensWithFunctions(argTokens?.tokensWithQueryAfter), - index: [ - [/"([^"\\]|\\.)*"/, { token: 'index', next: isHighlightQuery ? '@query' : '@root' }], - [/'([^'\\]|\\.)*'/, { token: 'index', next: isHighlightQuery ? '@query' : '@root' }], - [/[\w:]+/, { token: 'index', next: isHighlightQuery ? '@query' : '@root' }], - { include: 'root' } // Fallback to the root state if nothing matches - ], - ...generateQuery(), - fields: [ - [/@\w+/, { token: 'field', }] - ], - whitespace: [ - [/\s+/, 'white'], - [/\/\/.*$/, 'comment'], - ], - numbers: [ - [/0[xX][0-9a-fA-F]*/, 'number'], - [/[$][+-]*\d*(\.\d*)?/, 'number'], - [/((\d+(\.\d*)?)|(\.\d+))([eE][-+]?\d+)?/, 'number'], - ], - strings: [ - [/'/, { token: 'string', next: '@string' }], - [/"/, { token: STRING_DOUBLE, next: '@stringDouble' }], - ], - string: [ - [/\\./, 'string'], - [/'/, { token: 'string', next: '@pop' }], - [/[^\\']+/, 'string'], - ], - stringDouble: [ - [/\\./, STRING_DOUBLE], - [/"/, { token: STRING_DOUBLE, next: '@pop' }], - [/[^\\"]+/, STRING_DOUBLE], - ], - }, - } - ) -} diff --git a/redisinsight/ui/src/utils/monaco/monarchTokens/redisearchTokensSubRedis.ts b/redisinsight/ui/src/utils/monaco/monarchTokens/redisearchTokensSubRedis.ts index 9be0444673..2454443781 100644 --- a/redisinsight/ui/src/utils/monaco/monarchTokens/redisearchTokensSubRedis.ts +++ b/redisinsight/ui/src/utils/monaco/monarchTokens/redisearchTokensSubRedis.ts @@ -1,11 +1,12 @@ import { monaco as monacoEditor } from 'react-monaco-editor' import { remove } from 'lodash' -import { SearchCommand } from 'uiSrc/pages/search/types' +import { IRedisCommandTree } from 'uiSrc/constants' import { generateKeywords, generateTokens, generateTokensWithFunctions, - getBlockTokens, isIndexAfterKeyword, + getBlockTokens, + isIndexAfterKeyword, isQueryAfterIndex } from 'uiSrc/utils/monaco/redisearch/utils' import { generateQuery } from 'uiSrc/utils/monaco/monarchTokens/redisearchTokensTemplates' @@ -13,7 +14,7 @@ import { generateQuery } from 'uiSrc/utils/monaco/monarchTokens/redisearchTokens const STRING_DOUBLE = 'string.double' export const getRediSearchSubRedisMonarchTokensProvider = ( - commands: SearchCommand[], + commands: IRedisCommandTree[], ): monacoEditor.languages.IMonarchLanguage => { const withoutIndexSuggestions = [...commands] const withNextIndexSuggestions = remove(withoutIndexSuggestions, isIndexAfterKeyword) diff --git a/redisinsight/ui/src/utils/monaco/monarchTokens/redisearchTokensTemplates.ts b/redisinsight/ui/src/utils/monaco/monarchTokens/redisearchTokensTemplates.ts index 9c2901029f..0ebc7c1d36 100644 --- a/redisinsight/ui/src/utils/monaco/monarchTokens/redisearchTokensTemplates.ts +++ b/redisinsight/ui/src/utils/monaco/monarchTokens/redisearchTokensTemplates.ts @@ -1,12 +1,12 @@ import { languages } from 'monaco-editor' import { curryRight } from 'lodash' -import { SearchCommand } from 'uiSrc/pages/search/types' import { Maybe } from 'uiSrc/utils' +import { IRedisCommand } from 'uiSrc/constants' const appendToken = (token: string, name: Maybe) => (name ? `${token}.${name}` : token) export const generateQuery = ( - argToken?: SearchCommand, - args?: SearchCommand[] + argToken?: IRedisCommand, + args?: IRedisCommand[] ): { [name: string]: languages.IMonarchLanguageRule[] } => { const curriedAppendToken = curryRight(appendToken) const appendTokenName = curriedAppendToken(argToken?.token) diff --git a/redisinsight/ui/src/utils/monaco/redisearch/utils.ts b/redisinsight/ui/src/utils/monaco/redisearch/utils.ts index 25b0fd0b19..36d05a7c01 100644 --- a/redisinsight/ui/src/utils/monaco/redisearch/utils.ts +++ b/redisinsight/ui/src/utils/monaco/redisearch/utils.ts @@ -1,27 +1,27 @@ import { isNumber, remove } from 'lodash' import { languages } from 'monaco-editor' -import { SearchCommand, TokenType } from 'uiSrc/pages/search/types' import { Maybe, Nullable } from 'uiSrc/utils' -import { DefinedArgumentName } from 'uiSrc/pages/search/components/query/constants' import { generateQuery } from 'uiSrc/utils/monaco/monarchTokens/redisearchTokensTemplates' +import { ICommandTokenType, IRedisCommand } from 'uiSrc/constants' +import { DefinedArgumentName } from 'uiSrc/pages/workbench/constants' -export const generateKeywords = (commands: SearchCommand[]) => commands.map(({ name }) => name) -export const generateTokens = (command?: SearchCommand): Nullable<{ - pureTokens: Array> - tokensWithQueryAfter: Array> +export const generateKeywords = (commands: IRedisCommand[]) => commands.map(({ name }) => name) +export const generateTokens = (command?: IRedisCommand): Nullable<{ + pureTokens: Array> + tokensWithQueryAfter: Array> }> => { if (!command) return null - const pureTokens: Array> = [] - const tokensWithQueryAfter: Array> = [] + const pureTokens: Array> = [] + const tokensWithQueryAfter: Array> = [] - function processArguments(args: SearchCommand[], level = 0) { + function processArguments(args: IRedisCommand[], level = 0) { if (!pureTokens[level]) pureTokens[level] = [] if (!tokensWithQueryAfter[level]) tokensWithQueryAfter[level] = [] args.forEach((arg) => { if (arg.token) pureTokens[level].push(arg) - if (arg.type === TokenType.Block && arg.arguments) { + if (arg.type === ICommandTokenType.Block && arg.arguments) { const blockToken = arg.arguments[0] const nextArgs = arg.arguments const isArgHasOwnSyntax = arg.arguments[0].expression && !!arg.arguments[0].arguments?.length @@ -30,7 +30,7 @@ export const generateTokens = (command?: SearchCommand): Nullable<{ if (isArgHasOwnSyntax) { tokensWithQueryAfter[level].push({ token: blockToken, - arguments: arg.arguments[0].arguments as SearchCommand[] + arguments: arg.arguments[0].arguments as IRedisCommand[] }) } else { pureTokens[level].push(blockToken) @@ -40,7 +40,7 @@ export const generateTokens = (command?: SearchCommand): Nullable<{ processArguments(blockToken ? nextArgs.slice(1, nextArgs.length) : nextArgs, level + 1) } - if (arg.type === TokenType.OneOf && arg.arguments) { + if (arg.type === ICommandTokenType.OneOf && arg.arguments) { arg.arguments.forEach((choice) => { if (choice?.token) pureTokens[level].push(choice) }) @@ -55,14 +55,14 @@ export const generateTokens = (command?: SearchCommand): Nullable<{ return { pureTokens, tokensWithQueryAfter } } -export const isIndexAfterKeyword = (command?: SearchCommand) => { +export const isIndexAfterKeyword = (command?: IRedisCommand) => { if (!command) return false const index = command.arguments?.findIndex(({ name }) => name === DefinedArgumentName.index) return isNumber(index) && index === 0 } -export const isQueryAfterIndex = (command?: SearchCommand) => { +export const isQueryAfterIndex = (command?: IRedisCommand) => { if (!command) return false const index = command.arguments?.findIndex(({ name }) => name === DefinedArgumentName.index) @@ -70,13 +70,13 @@ export const isQueryAfterIndex = (command?: SearchCommand) => { } export const appendTokenWithQuery = ( - args: Array<{ token: SearchCommand, arguments: SearchCommand[] }>, + args: Array<{ token: IRedisCommand, arguments: IRedisCommand[] }>, level: number ): languages.IMonarchLanguageRule[] => args.map(({ token }) => [`(${token.token})\\b`, { token: `argument.block.${level}`, next: `@query.${token.token}` }]) export const appendQueryWithNextFunctions = ( - tokens: Array<{ token: SearchCommand, arguments: SearchCommand[] }> + tokens: Array<{ token: IRedisCommand, arguments: IRedisCommand[] }> ): { [name: string]: languages.IMonarchLanguageRule[] } => { @@ -94,7 +94,7 @@ export const appendQueryWithNextFunctions = ( export const generateTokensWithFunctions = ( name: string = '', - tokens?: Array> + tokens?: Array> ): { [name: string]: languages.IMonarchLanguageRule[] } => { @@ -116,12 +116,12 @@ export const generateTokensWithFunctions = ( export const getBlockTokens = ( name: string = '', - pureTokens: Maybe[]> + pureTokens: Maybe[]> ): languages.IMonarchLanguageRule[] => { if (!pureTokens) return [] const getLeveledToken = ( - tokens: SearchCommand[], + tokens: IRedisCommand[], lvl: number ): languages.IMonarchLanguageRule[] => { const result: languages.IMonarchLanguageRule[] = [] diff --git a/redisinsight/ui/src/utils/monaco/redisearch/utils_old.ts b/redisinsight/ui/src/utils/monaco/redisearch/utils_old.ts deleted file mode 100644 index d04f47a717..0000000000 --- a/redisinsight/ui/src/utils/monaco/redisearch/utils_old.ts +++ /dev/null @@ -1,143 +0,0 @@ -import { isNumber, remove } from 'lodash' -import { languages } from 'monaco-editor' -import { SearchCommand, TokenType } from 'uiSrc/pages/search/types' -import { Maybe, Nullable } from 'uiSrc/utils' -import { DefinedArgumentName } from 'uiSrc/pages/search/components/query/constants' -import { generateQuery } from 'uiSrc/utils/monaco/monarchTokens/redisearchTokensTemplates' - -export const generateKeywords = (commands: SearchCommand[]) => commands.map(({ name }) => name) -export const generateTokens = (command?: SearchCommand): Nullable<{ - pureTokens: Array> - tokensWithQueryAfter: Array> -}> => { - if (!command) return null - const pureTokens: Array> = [] - const tokensWithQueryAfter: Array> = [] - - function processArguments(args: SearchCommand[], level = 0) { - if (!pureTokens[level]) pureTokens[level] = [] - if (!tokensWithQueryAfter[level]) tokensWithQueryAfter[level] = [] - - args.forEach((arg) => { - if (arg.token) pureTokens[level].push(arg) - - if (arg.type === TokenType.Block && arg.arguments) { - const blockToken = arg.arguments[0] - const nextArgs = arg.arguments - const isArgHasOwnSyntax = arg.arguments[0].expression && !!arg.arguments[0].arguments?.length - - if (blockToken?.token) { - if (isArgHasOwnSyntax) { - tokensWithQueryAfter[level].push({ - token: blockToken, - arguments: arg.arguments[0].arguments as SearchCommand[] - }) - } else { - pureTokens[level].push(blockToken) - } - } - - processArguments(blockToken ? nextArgs.slice(1, nextArgs.length) : nextArgs, level + 1) - } - - if (arg.type === TokenType.OneOf && arg.arguments) { - arg.arguments.forEach((choice) => { - if (choice?.token) pureTokens[level].push(choice) - }) - } - }) - } - - if (command.arguments) { - processArguments(command.arguments, 0) - } - - return { pureTokens, tokensWithQueryAfter } -} - -export const isIndexAfterKeyword = (command?: SearchCommand) => { - if (!command) return false - - const index = command.arguments?.findIndex(({ name }) => name === DefinedArgumentName.index) - return isNumber(index) && index === 0 -} - -export const isQueryAfterIndex = (command?: SearchCommand) => { - if (!command) return false - - const index = command.arguments?.findIndex(({ name }) => name === DefinedArgumentName.index) - return isNumber(index) && index > -1 ? command.arguments?.[index + 1]?.name === DefinedArgumentName.query : false -} - -export const appendTokenWithQuery = ( - args: Array<{ token: SearchCommand, arguments: SearchCommand[] }>, - level: number -): languages.IMonarchLanguageRule[] => - args.map(({ token }) => [`(${token.token})\\b`, { token: `argument.block.${level}`, next: `@query.${token.token}` }]) - -export const appendQueryWithNextFunctions = (tokens: Array<{ token: SearchCommand, arguments: SearchCommand[] }>): { - [name: string]: languages.IMonarchLanguageRule[] -} => { - let result: { [name: string]: languages.IMonarchLanguageRule[] } = {} - - tokens.forEach(({ token, arguments: args }) => { - result = { - ...result, - ...generateQuery(token, args) - } - }) - - return result -} - -export const generateTokensWithFunctions = ( - tokens?: Array> -): { - [name: string]: languages.IMonarchLanguageRule[] -} => { - if (!tokens) return { 'argument.block.withFunctions': [] } - - const actualTokens = tokens.filter((tokens) => tokens.length) - - return { - 'argument.block.withFunctions': [ - ...actualTokens - .map((tokens, lvl) => appendTokenWithQuery(tokens, lvl)) - .flat() - ], - ...appendQueryWithNextFunctions(actualTokens.flat()) - } -} - -export const getBlockTokens = ( - pureTokens: Maybe[]> -): languages.IMonarchLanguageRule[] => { - if (!pureTokens) return [] - - const getLeveledToken = ( - tokens: SearchCommand[], - lvl: number - ): languages.IMonarchLanguageRule[] => { - const result: languages.IMonarchLanguageRule[] = [] - const restTokens = [...tokens] - const tokensWithNextExpression = remove(restTokens, (({ expression }) => expression)) - - if (tokensWithNextExpression.length) { - result.push([ - `(${tokensWithNextExpression.map(({ token }) => token).join('|')})\\b`, - { - token: `argument.block.${lvl}`, - next: '@query' - }, - ]) - } - - if (restTokens.length) { - result.push([`(${restTokens.map(({ token }) => token).join('|')})\\b`, { token: `argument.block.${lvl}`, next: '@root' }]) - } - - return result - } - - return pureTokens.map((tokens, lvl) => getLeveledToken(tokens, lvl)).flat() -} diff --git a/redisinsight/ui/src/utils/tests/monaco/cyber/monarchTokensProvider.spec.ts b/redisinsight/ui/src/utils/tests/monaco/cyber/monarchTokensProvider.spec.ts index 711e7bba49..313fd10721 100644 --- a/redisinsight/ui/src/utils/tests/monaco/cyber/monarchTokensProvider.spec.ts +++ b/redisinsight/ui/src/utils/tests/monaco/cyber/monarchTokensProvider.spec.ts @@ -1,8 +1,8 @@ import { getCypherMonarchTokensProvider } from 'uiSrc/utils/monaco/monarchTokens/cypherTokens' import { getJmespathMonarchTokensProvider } from 'uiSrc/utils/monaco/monarchTokens/jmespathTokens' import { getSqliteFunctionsMonarchTokensProvider } from 'uiSrc/utils/monaco/monarchTokens/sqliteFunctionsTokens' -import { getRediSearchMonarchTokensProvider } from 'uiSrc/utils/monaco/monarchTokens/redisearchTokens' -import { MOCKED_SUPPORTED_COMMANDS } from 'uiSrc/pages/search/mocks/mocks' +import { getRediSearchSubRedisMonarchTokensProvider } from 'uiSrc/utils/monaco/monarchTokens/redisearchTokensSubRedis' +import { MOCKED_REDIS_COMMANDS } from 'uiSrc/mocks/data/mocked_redis_commands' describe('getCypherMonarchTokensProvider', () => { it('should be truthy', () => { @@ -24,15 +24,15 @@ describe('getSqliteFunctionsMonarchTokensProvider', () => { describe('getRediSearchMonarchTokensProvider', () => { it('should be truthy', () => { - expect(getRediSearchMonarchTokensProvider([])).toBeTruthy() + expect(getRediSearchSubRedisMonarchTokensProvider([])).toBeTruthy() }) it('should be truthy with command', () => { - const commands = Object.keys(MOCKED_SUPPORTED_COMMANDS) + const commands = Object.keys(MOCKED_REDIS_COMMANDS) .map((key) => ({ - ...MOCKED_SUPPORTED_COMMANDS[key], - name: key + ...MOCKED_REDIS_COMMANDS[key], + name: key, })) - expect(getRediSearchMonarchTokensProvider(commands, 'FT.AGGREGATE')).toBeTruthy() + expect(getRediSearchSubRedisMonarchTokensProvider(commands)).toBeTruthy() }) }) diff --git a/redisinsight/ui/src/utils/tests/routing.spec.ts b/redisinsight/ui/src/utils/tests/routing.spec.ts index 6f11ef1ae2..adc3a1a3b3 100644 --- a/redisinsight/ui/src/utils/tests/routing.spec.ts +++ b/redisinsight/ui/src/utils/tests/routing.spec.ts @@ -18,8 +18,6 @@ const getRedirectionPageTests = [ { input: ['/workbench', databaseId], expected: '/1/workbench' }, { input: ['browser', databaseId], expected: '/1/browser' }, { input: ['/browser', databaseId], expected: '/1/browser' }, - { input: ['search', databaseId], expected: '/1/search' }, - { input: ['/search', databaseId], expected: '/1/search' }, { input: ['/analytics/slowlog', databaseId], expected: '/1/analytics/slowlog' }, { input: ['/analytics/slowlog'], expected: null }, { input: ['/analytics', databaseId], expected: '/1/analytics' }, From 1d3ff632613498d2909e8a3bea937364b7b6438b Mon Sep 17 00:00:00 2001 From: vlad-dargel Date: Thu, 17 Oct 2024 20:38:56 +0200 Subject: [PATCH 221/256] fix2 --- tests/e2e/helpers/keys.ts | 228 +++++++++++++++++++++----------------- 1 file changed, 126 insertions(+), 102 deletions(-) diff --git a/tests/e2e/helpers/keys.ts b/tests/e2e/helpers/keys.ts index a98fa6b5f1..27aca7ed63 100644 --- a/tests/e2e/helpers/keys.ts +++ b/tests/e2e/helpers/keys.ts @@ -88,27 +88,28 @@ export async function deleteKeysViaCli(keyData: KeyData): Promise { * @param keyArguments The arguments of key */ export async function populateDBWithHashes(host: string, port: string, keyArguments: AddKeyArguments): Promise { - const dbConf = { port: Number.parseInt(port), host, username: 'default' }; - const client = createClient(dbConf); + const url = `redis://default@${host}:${port}`; + const client = createClient({ url }); - client.on('error', (error: string) => { - throw new Error(error); + client.on('error', (error: Error) => { + console.error('Redis Client Error', error); }); - client.on('connect', async () => { - try { - if (keyArguments.keysCount) { - for (let i = 0; i < keyArguments.keysCount; i++) { - const keyName = `${keyArguments.keyNameStartWith}${Common.generateWord(20)}`; - await client.hSet(keyName, 'field1', 'Hello'); - } + try { + await client.connect(); + + if (keyArguments.keysCount) { + for (let i = 0; i < keyArguments.keysCount; i++) { + const keyName = `${keyArguments.keyNameStartWith}${Common.generateWord(20)}`; + await client.hSet(keyName, 'field1', 'Hello'); } - } catch (error) { - console.error('Error setting hash:', error); - } finally { - await client.quit(); } - }); + + } catch (error) { + console.error('Error during Redis operations:', error); + } finally { + await client.disconnect(); + } } /** @@ -118,30 +119,36 @@ export async function populateDBWithHashes(host: string, port: string, keyArgume * @param keyArguments The arguments of key and its fields */ export async function populateHashWithFields(host: string, port: string, keyArguments: AddKeyArguments): Promise { - const dbConf = { port: Number.parseInt(port), host, username: 'default' }; - const client = createClient(dbConf); - const fields: Record = {}; // Using an object for field-value pairs + const url = `redis://default@${host}:${port}`; + const client = createClient({ url }); + const fields: Record = {}; - client.on('error', (error: string) => { - throw new Error(error); + client.on('error', (error: Error) => { + console.error('Redis Client Error', error); }); - client.on('connect', async () => { - try { - if (keyArguments.fieldsCount) { - for (let i = 0; i < keyArguments.fieldsCount; i++) { - const field = `${keyArguments.fieldStartWith}${Common.generateWord(10)}`; - const fieldValue = `${keyArguments.fieldValueStartWith}${Common.generateWord(10)}`; - fields[field] = fieldValue; - } + try { + await client.connect(); + + if (keyArguments.fieldsCount) { + for (let i = 0; i < keyArguments.fieldsCount; i++) { + const field = `${keyArguments.fieldStartWith}${Common.generateWord(10)}`; + const fieldValue = `${keyArguments.fieldValueStartWith}${Common.generateWord(10)}`; + fields[field] = fieldValue; } - await client.hSet(keyArguments.keyName!, fields); - } catch (error) { - console.error('Error setting hash fields:', error); - } finally { - await client.quit(); } - }); + + if (keyArguments.keyName) { + await client.hSet(keyArguments.keyName, fields); + } else { + throw new Error('keyName is required to populate the hash.'); + } + + } catch (error) { + console.error('Error setting hash fields:', error); + } finally { + await client.disconnect(); + } } /** @@ -151,30 +158,35 @@ export async function populateHashWithFields(host: string, port: string, keyArgu * @param keyArguments The arguments of key and its members */ export async function populateListWithElements(host: string, port: string, keyArguments: AddKeyArguments): Promise { - const dbConf = { port: Number.parseInt(port), host, username: 'default' }; - const client = createClient(dbConf); + const url = `redis://default@${host}:${port}`; + const client = createClient({ url }); const elements: string[] = []; - client.on('error', (error: string) => { - throw new Error(error); + client.on('error', (error: Error) => { + console.error('Redis Client Error', error); }); - client.on('connect', async () => { - try { - if (keyArguments.elementsCount) { - for (let i = 0; i < keyArguments.elementsCount; i++) { - const element = `${keyArguments.elementStartWith}${Common.generateWord(10)}`; - elements.push(element); - } + try { + await client.connect(); + + if (keyArguments.elementsCount) { + for (let i = 0; i < keyArguments.elementsCount; i++) { + const element = `${keyArguments.elementStartWith}${Common.generateWord(10)}`; + elements.push(element); } - // Push all the elements to the list - await client.lPush(keyArguments.keyName!, elements); // Spread the elements array - } catch (error) { - console.error('Error pushing elements to list:', error); - } finally { - await client.quit(); } - }); + + if (keyArguments.keyName) { + await client.lPush(keyArguments.keyName, elements); + } else { + throw new Error('keyName is required to populate the list.'); + } + + } catch (error) { + console.error('Error pushing elements to list:', error); + } finally { + await client.disconnect(); + } } /** @@ -184,30 +196,35 @@ export async function populateListWithElements(host: string, port: string, keyAr * @param keyArguments The arguments of key and its members */ export async function populateSetWithMembers(host: string, port: string, keyArguments: AddKeyArguments): Promise { - const dbConf = { port: Number.parseInt(port), host, username: 'default' }; - const client = createClient(dbConf); + const url = `redis://default@${host}:${port}`; + const client = createClient({ url }); const members: string[] = []; - client.on('error', (error: string) => { - throw new Error(error); + client.on('error', (error: Error) => { + console.error('Redis Client Error', error); }); - client.on('connect', async () => { - try { - if (keyArguments.membersCount) { - for (let i = 0; i < keyArguments.membersCount; i++) { - const member = `${keyArguments.memberStartWith}${Common.generateWord(10)}`; - members.push(member); - } + try { + await client.connect(); + + if (keyArguments.membersCount) { + for (let i = 0; i < keyArguments.membersCount; i++) { + const member = `${keyArguments.memberStartWith}${Common.generateWord(10)}`; + members.push(member); } - // Add all members to the set using sAdd - await client.sAdd(keyArguments.keyName!, members); - } catch (error) { - console.error('Error adding members to set:', error); - } finally { - await client.quit(); } - }); + + if (keyArguments.keyName) { + await client.sAdd(keyArguments.keyName, members); + } else { + throw new Error('keyName is required to populate the set.'); + } + + } catch (error) { + console.error('Error adding members to set:', error); + } finally { + await client.disconnect(); + } } /** @@ -217,32 +234,38 @@ export async function populateSetWithMembers(host: string, port: string, keyArgu * @param keyArguments The arguments of key and its members */ export async function populateZSetWithMembers(host: string, port: string, keyArguments: AddKeyArguments): Promise { - const dbConf = { port: Number.parseInt(port), host, username: 'default' }; + const url = `redis://default@${host}:${port}`; + const client = createClient({ url }); const minScoreValue = -10; const maxScoreValue = 10; - const client = createClient(dbConf); const members: { score: number; value: string }[] = []; - client.on('error', (error: string) => { - throw new Error(error); + client.on('error', (error: Error) => { + console.error('Redis Client Error', error); }); - client.on('connect', async () => { - try { - if (keyArguments.membersCount) { - for (let i = 0; i < keyArguments.membersCount; i++) { - const memberName = `${keyArguments.memberStartWith}${Common.generateWord(10)}`; - const scoreValue = random(minScoreValue, maxScoreValue); - members.push({ score: scoreValue, value: memberName }); - } + try { + await client.connect(); + + if (keyArguments.membersCount) { + for (let i = 0; i < keyArguments.membersCount; i++) { + const memberName = `${keyArguments.memberStartWith}${Common.generateWord(10)}`; + const scoreValue = random(minScoreValue, maxScoreValue); + members.push({ score: scoreValue, value: memberName }); } - await client.zAdd(keyArguments.keyName!, members); - } catch (error) { - console.error('Error adding members to sorted set:', error); - } finally { - await client.quit(); } - }); + + if (keyArguments.keyName) { + await client.zAdd(keyArguments.keyName, members); + } else { + throw new Error('keyName is required to populate the sorted set.'); + } + + } catch (error) { + console.error('Error adding members to sorted set:', error); + } finally { + await client.disconnect(); + } } /** @@ -251,22 +274,23 @@ export async function populateZSetWithMembers(host: string, port: string, keyArg * @param port The port of database */ export async function deleteAllKeysFromDB(host: string, port: string): Promise { - const dbConf = { port: Number.parseInt(port), host, username: 'default' }; - const client = createClient(dbConf); + const url = `redis://default@${host}:${port}`; + const client = createClient({ url }); - client.on('error', (error: string) => { - throw new Error(error); + client.on('error', (error: Error) => { + console.error('Redis Client Error', error); }); - client.on('connect', async () => { - try { - await client.flushAll(); - } catch (error) { - console.error('Error flushing database:', error); - } finally { - await client.quit(); - } - }); + try { + await client.connect(); + + await client.flushAll(); + + } catch (error) { + console.error('Error flushing database:', error); + } finally { + await client.disconnect(); + } } /** From 370238ba97864d2d38996edb3c5ba059186729aa Mon Sep 17 00:00:00 2001 From: ArtemHoruzhenko Date: Fri, 18 Oct 2024 12:16:01 +0300 Subject: [PATCH 222/256] rollback class-transform to 0.3.x (0.3.1) --- configs/webpack.config.base.ts | 2 +- redisinsight/api/package.json | 2 +- .../api/src/__mocks__/browser-history.ts | 4 ++-- redisinsight/api/src/__mocks__/cloud-user.ts | 4 ++-- .../client-metadata/client-metadata.decorator.ts | 4 ++-- .../decorators/data-as-json-string.decorator.ts | 4 ++-- .../api/src/common/decorators/default.ts | 2 +- .../common/decorators/hidden-field.decorator.ts | 2 +- .../common/decorators/object-as-map.decorator.ts | 14 +++++++------- .../session/session-metadata.decorator.ts | 4 ++-- .../middlewares/single-user-auth.middleware.ts | 6 +++--- .../any-to-redis-string.transformer.ts | 6 +++--- .../redis-string-to-ascii.transformer.ts | 6 +++--- .../redis-string-to-buffer.transformer.ts | 6 +++--- .../redis-string-to-utf8.transformer.ts | 6 +++--- redisinsight/api/src/dto/dto-transformer.spec.ts | 2 +- redisinsight/api/src/dto/dto-transformer.ts | 2 +- .../api/src/modules/ai/chat/ai-chat.service.ts | 6 +++--- .../api/src/modules/ai/query/ai-query.service.ts | 6 +++--- .../autodiscovery/autodiscovery.service.ts | 4 ++-- .../browser-history/browser-history.service.ts | 4 ++-- .../local.browser-history.repository.ts | 4 ++-- .../api/src/modules/browser/hash/hash.service.ts | 8 ++++---- .../src/modules/browser/keys/dto/get.keys.dto.ts | 2 +- .../api/src/modules/browser/keys/keys.service.ts | 12 ++++++------ .../api/src/modules/browser/list/list.service.ts | 12 ++++++------ .../browser/redisearch/redisearch.service.ts | 8 ++++---- .../api/src/modules/browser/set/set.service.ts | 4 ++-- .../stream/services/consumer-group.service.ts | 6 +++--- .../browser/stream/services/consumer.service.ts | 6 +++--- .../browser/stream/services/stream.service.ts | 8 ++++---- .../src/modules/browser/string/string.service.ts | 4 ++-- .../src/modules/browser/z-set/z-set.service.ts | 10 +++++----- .../auth/auth-strategy/cloud-auth.strategy.ts | 4 ++-- .../auth-strategy/sso-idp.cloud.auth-strategy.ts | 4 ++-- .../cloud/capi-key/cloud-capi-key.service.ts | 4 ++-- .../common/decorators/cloud-auth.decorator.ts | 4 ++-- .../cloud/database/utils/cloud-data-converter.ts | 4 ++-- .../src/modules/cloud/job/cloud-job.gateway.ts | 4 ++-- .../api/src/modules/cloud/job/jobs/cloud-job.ts | 6 +++--- .../cloud/session/cloud-session.service.ts | 8 ++++---- .../subscription/utils/cloud-data-converter.ts | 8 ++++---- .../cloud/task/utils/cloud-data-converter.ts | 4 ++-- .../in-session.cloud-user.repository.ts | 10 +++++----- .../cloud/user/utils/cloud-data-converter.ts | 4 ++-- .../strategies/abstract.info.strategy.ts | 4 ++-- .../custom-tutorial/custom-tutorial.service.ts | 6 +++--- .../custom-tutorial.manifest.provider.ts | 4 ++-- .../database-analysis.service.ts | 4 ++-- .../entities/database-analysis.entity.ts | 16 ++++++++-------- .../providers/database-analysis.provider.spec.ts | 4 ++-- .../providers/database-analysis.provider.ts | 6 +++--- .../database-import/database-import.service.ts | 6 +++--- .../dto/database-import.response.ts | 6 +++--- .../database-recommendation.service.ts | 4 ++-- .../providers/database-recommendation.emitter.ts | 4 ++-- .../local.database.recommendation.repository.ts | 8 ++++---- .../modules/database/entities/database.entity.ts | 8 ++++---- .../database/middleware/connection.middleware.ts | 4 ++-- .../feature/features-config.service.spec.ts | 6 +++--- .../modules/feature/features-config.service.ts | 4 ++-- .../feature/model/features-config.spec.ts | 6 +++--- .../local.features-config.repository.spec.ts | 4 ++-- .../local.features-config.repository.ts | 6 +++--- .../feature-config-filter.transformer.ts | 6 +++--- .../modules/notification/notification.service.ts | 6 +++--- .../providers/global-notification.provider.ts | 8 ++++---- .../providers/notification.emitter.ts | 4 ++-- .../api/src/modules/plugin/plugin.service.ts | 6 +++--- .../api/src/modules/rdi/client/api.rdi.client.ts | 4 ++-- .../request.rdi.client.metadata.decorator.ts | 4 ++-- .../api/src/modules/rdi/utils/pipeline.util.ts | 4 ++-- .../providers/single-user.session.provider.ts | 4 ++-- .../api/src/modules/workbench/plugins.service.ts | 4 ++-- .../local-command-execution.repository.ts | 4 ++-- .../local-plugin-state.repository.ts | 4 ++-- redisinsight/api/src/utils/class-transformer.ts | 10 +++++----- redisinsight/api/yarn.lock | 8 ++++---- 78 files changed, 215 insertions(+), 215 deletions(-) diff --git a/configs/webpack.config.base.ts b/configs/webpack.config.base.ts index 8a09570263..097389890d 100644 --- a/configs/webpack.config.base.ts +++ b/configs/webpack.config.base.ts @@ -61,7 +61,7 @@ const configuration: webpack.Configuration = { // 'reflect-metadata', // 'swagger-ui-express', // 'class-transformer', - 'class-transformer/storage', + // 'class-transformer/storage', // '@nestjs/websockets', // '@nestjs/core/adapters/http-adapter', // '@nestjs/core/helpers/router-method-factory', diff --git a/redisinsight/api/package.json b/redisinsight/api/package.json index 51d16024a0..e174e55f48 100644 --- a/redisinsight/api/package.json +++ b/redisinsight/api/package.json @@ -69,7 +69,7 @@ "axios": "^1.7.4", "body-parser": "^1.20.3", "busboy": "^1.6.0", - "class-transformer": "^0.5.1", + "class-transformer": "^0.3.1", "class-validator": "^0.14.1", "combined-stream": "^1.0.8", "connect-timeout": "^1.9.0", diff --git a/redisinsight/api/src/__mocks__/browser-history.ts b/redisinsight/api/src/__mocks__/browser-history.ts index f3017d69a2..6ea46029ce 100644 --- a/redisinsight/api/src/__mocks__/browser-history.ts +++ b/redisinsight/api/src/__mocks__/browser-history.ts @@ -1,4 +1,4 @@ -import { plainToInstance } from 'class-transformer'; +import { plainToClass } from 'class-transformer'; import { v4 as uuidv4 } from 'uuid'; import { mockDatabase, @@ -26,7 +26,7 @@ export const mockBrowserHistoryRepository = jest.fn(() => ({ export const mockCreateBrowserHistoryDto: CreateBrowserHistoryDto = { mode: BrowserHistoryMode.Pattern, - filter: plainToInstance(ScanFilter, { + filter: plainToClass(ScanFilter, { type: RedisDataType.String, match: 'key*', }), diff --git a/redisinsight/api/src/__mocks__/cloud-user.ts b/redisinsight/api/src/__mocks__/cloud-user.ts index 187abf9a19..0effd6aadd 100644 --- a/redisinsight/api/src/__mocks__/cloud-user.ts +++ b/redisinsight/api/src/__mocks__/cloud-user.ts @@ -7,7 +7,7 @@ import { ICloudCapiAccount, } from 'src/modules/cloud/user/models'; import config, { Config } from 'src/utils/config'; -import { instanceToPlain } from 'class-transformer'; +import { classToPlain } from 'class-transformer'; import { mockCloudApiCapiAccessKey, mockCloudCapiAuthDto, mockCloudCapiKey } from 'src/__mocks__/cloud-capi-key'; import { mockCloudApiAuthDto, mockCloudSession } from 'src/__mocks__/cloud-session'; @@ -102,7 +102,7 @@ export const mockCloudUser = Object.assign(new CloudUser(), { capiKey: mockCloudCapiKey, }); -export const mockCloudUserSafe = instanceToPlain(mockCloudUser); // omits all data in the "security" group +export const mockCloudUserSafe = classToPlain(mockCloudUser); // omits all data in the "security" group export const mockCloudApiAccount: ICloudApiAccount = { id: mockCloudCapiAccount.id, diff --git a/redisinsight/api/src/common/decorators/client-metadata/client-metadata.decorator.ts b/redisinsight/api/src/common/decorators/client-metadata/client-metadata.decorator.ts index ba32ea34a6..02c0beb8ee 100644 --- a/redisinsight/api/src/common/decorators/client-metadata/client-metadata.decorator.ts +++ b/redisinsight/api/src/common/decorators/client-metadata/client-metadata.decorator.ts @@ -1,5 +1,5 @@ import { BadRequestException, createParamDecorator, ExecutionContext } from '@nestjs/common'; -import { plainToInstance } from 'class-transformer'; +import { plainToClass } from 'class-transformer'; import { ClientContext, ClientMetadata } from 'src/common/models'; import { Validator } from 'class-validator'; import { API_HEADER_DATABASE_INDEX, API_PARAM_DATABASE_ID } from 'src/common/constants'; @@ -31,7 +31,7 @@ export const clientMetadataParamFactory = ( uniqueId = req.params?.[options.uniqueIdParam]; } - const clientMetadata = plainToInstance(ClientMetadata, { + const clientMetadata = plainToClass(ClientMetadata, { sessionMetadata: sessionMetadataFromRequestExecutionContext(undefined, ctx), databaseId, uniqueId, diff --git a/redisinsight/api/src/common/decorators/data-as-json-string.decorator.ts b/redisinsight/api/src/common/decorators/data-as-json-string.decorator.ts index 029f10e611..97c28eb085 100644 --- a/redisinsight/api/src/common/decorators/data-as-json-string.decorator.ts +++ b/redisinsight/api/src/common/decorators/data-as-json-string.decorator.ts @@ -3,9 +3,9 @@ import { Transform } from 'class-transformer'; export function DataAsJsonString() { return applyDecorators( - Transform(({ value }) => JSON.stringify(value), { toClassOnly: true }), + Transform((value) => JSON.stringify(value), { toClassOnly: true }), Transform( - ({ value }) => { + (value) => { try { return JSON.parse(value); } catch (e) { diff --git a/redisinsight/api/src/common/decorators/default.ts b/redisinsight/api/src/common/decorators/default.ts index 418ff32ed2..a29326db53 100644 --- a/redisinsight/api/src/common/decorators/default.ts +++ b/redisinsight/api/src/common/decorators/default.ts @@ -2,5 +2,5 @@ import { Transform } from 'class-transformer'; import { cloneDeep } from 'lodash'; export function Default(defaultValue: unknown): PropertyDecorator { - return Transform(({ value }) => value ?? cloneDeep(defaultValue)); + return Transform((value) => value ?? cloneDeep(defaultValue)); } diff --git a/redisinsight/api/src/common/decorators/hidden-field.decorator.ts b/redisinsight/api/src/common/decorators/hidden-field.decorator.ts index 542befbe51..9e7723db40 100644 --- a/redisinsight/api/src/common/decorators/hidden-field.decorator.ts +++ b/redisinsight/api/src/common/decorators/hidden-field.decorator.ts @@ -1,7 +1,7 @@ import { Transform } from 'class-transformer'; export function HiddenField(field: any): PropertyDecorator { - return Transform(({ value }) => (value ? field : undefined), { + return Transform((value) => (value ? field : undefined), { toPlainOnly: true, }); } diff --git a/redisinsight/api/src/common/decorators/object-as-map.decorator.ts b/redisinsight/api/src/common/decorators/object-as-map.decorator.ts index 212ef764e3..6fa6d23b15 100644 --- a/redisinsight/api/src/common/decorators/object-as-map.decorator.ts +++ b/redisinsight/api/src/common/decorators/object-as-map.decorator.ts @@ -1,17 +1,17 @@ import { forEach } from 'lodash'; import { applyDecorators } from '@nestjs/common'; -import { instanceToPlain, plainToInstance, Transform } from 'class-transformer'; -import { ClassConstructor } from 'class-transformer/types/interfaces'; +import { classToPlain, plainToClass, Transform } from 'class-transformer'; +import { ClassType } from 'class-transformer/ClassTransformer'; -export function ObjectAsMap(targetClass: ClassConstructor) { +export function ObjectAsMap(targetClass: ClassType) { return applyDecorators( Transform( - ({ value: object }): Map => { + (object): Map => { const result = new Map(); try { forEach(object, (value, key) => { - result.set(key, plainToInstance(targetClass, value)); + result.set(key, plainToClass(targetClass, value)); }); return result; @@ -22,12 +22,12 @@ export function ObjectAsMap(targetClass: ClassConstructor) { { toClassOnly: true }, ), Transform( - ({ value: map }): object => { + (map): object => { try { const result = {}; forEach(Array.from(map), ([key, value]) => { - result[key] = instanceToPlain(value); + result[key] = classToPlain(value); }); return result; diff --git a/redisinsight/api/src/common/decorators/session/session-metadata.decorator.ts b/redisinsight/api/src/common/decorators/session/session-metadata.decorator.ts index 5ed113e7bf..fd1b3476b0 100644 --- a/redisinsight/api/src/common/decorators/session/session-metadata.decorator.ts +++ b/redisinsight/api/src/common/decorators/session/session-metadata.decorator.ts @@ -1,5 +1,5 @@ import { BadRequestException, createParamDecorator, ExecutionContext } from '@nestjs/common'; -import { plainToInstance } from 'class-transformer'; +import { plainToClass } from 'class-transformer'; import { Validator } from 'class-validator'; import { Request } from 'express'; import { SessionMetadata } from 'src/common/models'; @@ -16,7 +16,7 @@ export const sessionMetadataFromRequest = (request: Request): SessionMetadata => }; // todo: do not forget to deal with session vs sessionMetadata property - const session = plainToInstance(SessionMetadata, requestSession); + const session = plainToClass(SessionMetadata, requestSession); const errors = validator.validateSync(session, { whitelist: false, // we need this to allow additional fields if needed for flexibility diff --git a/redisinsight/api/src/common/middlewares/single-user-auth.middleware.ts b/redisinsight/api/src/common/middlewares/single-user-auth.middleware.ts index a2dcc307f1..28d3784223 100644 --- a/redisinsight/api/src/common/middlewares/single-user-auth.middleware.ts +++ b/redisinsight/api/src/common/middlewares/single-user-auth.middleware.ts @@ -6,7 +6,7 @@ import { NextFunction, Request, Response } from 'express'; import { ISessionMetadata, Session, SessionMetadata } from 'src/common/models/session'; import { DEFAULT_SESSION_ID, DEFAULT_USER_ID } from 'src/common/constants'; import { SessionService } from 'src/modules/session/session.service'; -import { plainToInstance } from 'class-transformer'; +import { plainToClass } from 'class-transformer'; @Injectable() export class SingleUserAuthMiddleware implements NestMiddleware { @@ -16,7 +16,7 @@ export class SingleUserAuthMiddleware implements NestMiddleware { async use(req: Request, res: Response, next: NextFunction): Promise { if (!await this.sessionService.getSession(DEFAULT_SESSION_ID)) { - await this.sessionService.createSession(plainToInstance(Session, { + await this.sessionService.createSession(plainToClass(Session, { id: DEFAULT_SESSION_ID, userId: DEFAULT_USER_ID, data: { @@ -30,7 +30,7 @@ export class SingleUserAuthMiddleware implements NestMiddleware { } res.locals.session = { - data: Object.freeze(plainToInstance(SessionMetadata, { + data: Object.freeze(plainToClass(SessionMetadata, { userId: DEFAULT_USER_ID, sessionId: DEFAULT_SESSION_ID, })), diff --git a/redisinsight/api/src/common/transformers/redis-string/any-to-redis-string.transformer.ts b/redisinsight/api/src/common/transformers/redis-string/any-to-redis-string.transformer.ts index 25f31ba348..3a2ef96af9 100644 --- a/redisinsight/api/src/common/transformers/redis-string/any-to-redis-string.transformer.ts +++ b/redisinsight/api/src/common/transformers/redis-string/any-to-redis-string.transformer.ts @@ -3,7 +3,7 @@ import { isArray, isObject, isString } from 'lodash'; import { getBufferFromSafeASCIIString } from 'src/utils/cli-helper'; import { Transform } from 'class-transformer'; -const SingleToRedisStringTransformer = ({ value }): RedisString => { +const SingleToRedisStringTransformer = (value): RedisString => { if (value?.type === 'Buffer') { if (isArray(value.data)) { return Buffer.from(value); @@ -21,9 +21,9 @@ const SingleToRedisStringTransformer = ({ value }): RedisString => { return value; }; -const ArrayToRedisStringTransformer = ({ value }) => { +const ArrayToRedisStringTransformer = (value) => { if (isArray(value)) { - return value.map((val) => SingleToRedisStringTransformer({ value: val })); + return value.map(SingleToRedisStringTransformer); } return value; diff --git a/redisinsight/api/src/common/transformers/redis-string/redis-string-to-ascii.transformer.ts b/redisinsight/api/src/common/transformers/redis-string/redis-string-to-ascii.transformer.ts index 88a2935a25..2c15366250 100644 --- a/redisinsight/api/src/common/transformers/redis-string/redis-string-to-ascii.transformer.ts +++ b/redisinsight/api/src/common/transformers/redis-string/redis-string-to-ascii.transformer.ts @@ -3,7 +3,7 @@ import { getASCIISafeStringFromBuffer } from 'src/utils/cli-helper'; import { RedisStringTransformOptions } from 'src/common/constants'; import { Transform } from 'class-transformer'; -const SingleRedisStringToASCII = ({ value }) => { +const SingleRedisStringToASCII = (value) => { if (value instanceof Buffer) { return getASCIISafeStringFromBuffer(value); } @@ -12,9 +12,9 @@ const SingleRedisStringToASCII = ({ value }) => { return value; }; -const ArrayRedisStringToASCII = ({ value }) => { +const ArrayRedisStringToASCII = (value) => { if (isArray(value)) { - return value.map((val) => SingleRedisStringToASCII({ value: val })); + return value.map(SingleRedisStringToASCII); } return value; diff --git a/redisinsight/api/src/common/transformers/redis-string/redis-string-to-buffer.transformer.ts b/redisinsight/api/src/common/transformers/redis-string/redis-string-to-buffer.transformer.ts index 09961a9e47..f33a39a91b 100644 --- a/redisinsight/api/src/common/transformers/redis-string/redis-string-to-buffer.transformer.ts +++ b/redisinsight/api/src/common/transformers/redis-string/redis-string-to-buffer.transformer.ts @@ -2,7 +2,7 @@ import { isArray } from 'lodash'; import { RedisStringTransformOptions } from 'src/common/constants'; import { Transform } from 'class-transformer'; -const SingleRedisStringToBuffer = ({ value }) => { +const SingleRedisStringToBuffer = (value) => { if (value instanceof Buffer) { return value; } @@ -10,9 +10,9 @@ const SingleRedisStringToBuffer = ({ value }) => { return Buffer.from(value); }; -const ArrayRedisStringToBuffer = ({ value }) => { +const ArrayRedisStringToBuffer = (value) => { if (isArray(value)) { - return value.map((val) => SingleRedisStringToBuffer({ value: val })); + return value.map(SingleRedisStringToBuffer); } return Buffer.from(value); diff --git a/redisinsight/api/src/common/transformers/redis-string/redis-string-to-utf8.transformer.ts b/redisinsight/api/src/common/transformers/redis-string/redis-string-to-utf8.transformer.ts index 053dc03f97..533d0d6cf2 100644 --- a/redisinsight/api/src/common/transformers/redis-string/redis-string-to-utf8.transformer.ts +++ b/redisinsight/api/src/common/transformers/redis-string/redis-string-to-utf8.transformer.ts @@ -2,7 +2,7 @@ import { isArray } from 'lodash'; import { RedisStringTransformOptions } from 'src/common/constants'; import { Transform } from 'class-transformer'; -const SingleRedisStringToUTF8 = ({ value }) => { +const SingleRedisStringToUTF8 = (value) => { if (value instanceof Buffer) { return value.toString('utf8'); } @@ -10,9 +10,9 @@ const SingleRedisStringToUTF8 = ({ value }) => { return value; }; -const ArrayRedisStringToUTF8 = ({ value }) => { +const ArrayRedisStringToUTF8 = (value) => { if (isArray(value)) { - return value.map((val) => SingleRedisStringToUTF8({ value: val })); + return value.map(SingleRedisStringToUTF8); } return value; diff --git a/redisinsight/api/src/dto/dto-transformer.spec.ts b/redisinsight/api/src/dto/dto-transformer.spec.ts index 31d5cbd974..2f8ca87dd0 100644 --- a/redisinsight/api/src/dto/dto-transformer.spec.ts +++ b/redisinsight/api/src/dto/dto-transformer.spec.ts @@ -7,7 +7,7 @@ describe('pickDefinedAgreements', () => { ['undefined', true], ]); - const output = pickDefinedAgreements({ value }); + const output = pickDefinedAgreements(value); expect(output).toEqual(new Map([['eula', true]])); }); diff --git a/redisinsight/api/src/dto/dto-transformer.ts b/redisinsight/api/src/dto/dto-transformer.ts index 86568256af..eb5e5d4185 100644 --- a/redisinsight/api/src/dto/dto-transformer.ts +++ b/redisinsight/api/src/dto/dto-transformer.ts @@ -2,7 +2,7 @@ import { isMap } from 'lodash'; import * as AGREEMENTS_SPEC from 'src/constants/agreements-spec.json'; // Delete all keys from the validated Map that are not included in the settings specification. -export const pickDefinedAgreements = ({ value }) => { +export const pickDefinedAgreements = (value) => { if (isMap(value)) { for (const k of value?.keys()) { if (!AGREEMENTS_SPEC.agreements[k]) { diff --git a/redisinsight/api/src/modules/ai/chat/ai-chat.service.ts b/redisinsight/api/src/modules/ai/chat/ai-chat.service.ts index 01142e64ca..3d1802c54c 100644 --- a/redisinsight/api/src/modules/ai/chat/ai-chat.service.ts +++ b/redisinsight/api/src/modules/ai/chat/ai-chat.service.ts @@ -1,7 +1,7 @@ import { Injectable } from '@nestjs/common'; import { SessionMetadata } from 'src/common/models'; import { ConvAiProvider } from 'src/modules/ai/chat/providers/conv-ai.provider'; -import { plainToInstance } from 'class-transformer'; +import { plainToClass } from 'class-transformer'; import { AiChat } from 'src/modules/ai/chat/models'; import { SendAiChatMessageDto } from 'src/modules/ai/chat/dto/send.ai-chat.message.dto'; @@ -14,7 +14,7 @@ export class AiChatService { async create(sessionMetadata: SessionMetadata): Promise> { const id = await this.convAiProvider.auth(sessionMetadata); - return plainToInstance(AiChat, { id }); + return plainToClass(AiChat, { id }); } async postMessage(sessionMetadata: SessionMetadata, chatId: string, dto: SendAiChatMessageDto) { @@ -22,7 +22,7 @@ export class AiChatService { } async getHistory(sessionMetadata: SessionMetadata, chatId: string): Promise { - return plainToInstance(AiChat, { + return plainToClass(AiChat, { id: chatId, messages: await this.convAiProvider.getHistory(sessionMetadata, chatId), }); diff --git a/redisinsight/api/src/modules/ai/query/ai-query.service.ts b/redisinsight/api/src/modules/ai/query/ai-query.service.ts index bcd633d7b6..9f43609677 100644 --- a/redisinsight/api/src/modules/ai/query/ai-query.service.ts +++ b/redisinsight/api/src/modules/ai/query/ai-query.service.ts @@ -20,7 +20,7 @@ import { import { AiQueryMessageRepository } from 'src/modules/ai/query/repositories/ai-query.message.repository'; import { AiQueryAuthProvider } from 'src/modules/ai/query/providers/auth/ai-query-auth.provider'; import { classToClass, Config } from 'src/utils'; -import { plainToInstance } from 'class-transformer'; +import { plainToClass } from 'class-transformer'; import { AiQueryContextRepository } from 'src/modules/ai/query/repositories/ai-query.context.repository'; import config from 'src/utils/config'; @@ -197,14 +197,14 @@ export class AiQueryService { }); socket.on(AiQueryWsEvents.TOOL_CALL, async (data) => { - answer.steps.push(plainToInstance(AiQueryIntermediateStep, { + answer.steps.push(plainToClass(AiQueryIntermediateStep, { type: AiQueryIntermediateStepType.TOOL_CALL, data, })); }); socket.on(AiQueryWsEvents.TOOL_REPLY, async (data) => { - answer.steps.push(plainToInstance(AiQueryIntermediateStep, { + answer.steps.push(plainToClass(AiQueryIntermediateStep, { type: AiQueryIntermediateStepType.TOOL, data, })); diff --git a/redisinsight/api/src/modules/autodiscovery/autodiscovery.service.ts b/redisinsight/api/src/modules/autodiscovery/autodiscovery.service.ts index a9b21da163..ebb17ad424 100644 --- a/redisinsight/api/src/modules/autodiscovery/autodiscovery.service.ts +++ b/redisinsight/api/src/modules/autodiscovery/autodiscovery.service.ts @@ -8,7 +8,7 @@ import { Database } from 'src/modules/database/models/database'; import { DatabaseService } from 'src/modules/database/database.service'; import { ClientContext, ClientMetadata, SessionMetadata } from 'src/common/models'; import { RedisClientFactory } from 'src/modules/redis/redis.client.factory'; -import { plainToInstance } from 'class-transformer'; +import { plainToClass } from 'class-transformer'; import { ConstantsProvider } from 'src/modules/constants/providers/constants.provider'; const SERVER_CONFIG = config.get('server') as Config['server']; @@ -87,7 +87,7 @@ export class AutodiscoveryService implements OnModuleInit { context: ClientContext.Common, sessionMetadata, } as ClientMetadata, - plainToInstance(Database, endpoint), + plainToClass(Database, endpoint), { useRetry: false, connectionName: 'redisinsight-auto-discovery' }, ); diff --git a/redisinsight/api/src/modules/browser/browser-history/browser-history.service.ts b/redisinsight/api/src/modules/browser/browser-history/browser-history.service.ts index 893df82db2..6d400e6b89 100644 --- a/redisinsight/api/src/modules/browser/browser-history/browser-history.service.ts +++ b/redisinsight/api/src/modules/browser/browser-history/browser-history.service.ts @@ -1,7 +1,7 @@ import { HttpException, Injectable, Logger } from '@nestjs/common'; import { catchAclError } from 'src/utils'; import { sum } from 'lodash'; -import { plainToInstance } from 'class-transformer'; +import { plainToClass } from 'class-transformer'; import { ClientMetadata, SessionMetadata } from 'src/common/models'; import { BrowserHistoryMode } from 'src/common/constants'; import { @@ -29,7 +29,7 @@ export class BrowserHistoryService { dto: CreateBrowserHistoryDto, ): Promise { try { - const history = plainToInstance(BrowserHistory, { ...dto, databaseId: clientMetadata.databaseId }); + const history = plainToClass(BrowserHistory, { ...dto, databaseId: clientMetadata.databaseId }); return this.browserHistoryRepository.create(clientMetadata.sessionMetadata, history); } catch (e) { this.logger.error('Unable to create browser history item', e); diff --git a/redisinsight/api/src/modules/browser/browser-history/repositories/local.browser-history.repository.ts b/redisinsight/api/src/modules/browser/browser-history/repositories/local.browser-history.repository.ts index 25c15243ee..950343674c 100644 --- a/redisinsight/api/src/modules/browser/browser-history/repositories/local.browser-history.repository.ts +++ b/redisinsight/api/src/modules/browser/browser-history/repositories/local.browser-history.repository.ts @@ -4,7 +4,7 @@ import { import { InjectRepository } from '@nestjs/typeorm'; import { Repository } from 'typeorm'; import { EncryptionService } from 'src/modules/encryption/encryption.service'; -import { plainToInstance } from 'class-transformer'; +import { plainToClass } from 'class-transformer'; import { classToClass } from 'src/utils'; import config from 'src/utils/config'; import ERROR_MESSAGES from 'src/constants/error-messages'; @@ -38,7 +38,7 @@ export class LocalBrowserHistoryRepository extends BrowserHistoryRepository { * @param history */ async create(sessionMetadata: SessionMetadata, history: Partial): Promise { - const encryptedDto = await this.modelEncryptor.encryptEntity(plainToInstance(BrowserHistoryEntity, history)); + const encryptedDto = await this.modelEncryptor.encryptEntity(plainToClass(BrowserHistoryEntity, history)); const entity = await this.repository.save(encryptedDto); // cleanup history and ignore error if any diff --git a/redisinsight/api/src/modules/browser/hash/hash.service.ts b/redisinsight/api/src/modules/browser/hash/hash.service.ts index 4941d4e4ae..0cf230089a 100644 --- a/redisinsight/api/src/modules/browser/hash/hash.service.ts +++ b/redisinsight/api/src/modules/browser/hash/hash.service.ts @@ -10,7 +10,7 @@ import { RECOMMENDATION_NAMES, RedisErrorCodes } from 'src/constants'; import config, { Config } from 'src/utils/config'; import { ClientMetadata } from 'src/common/models'; import { BrowserToolHashCommands, BrowserToolKeysCommands } from 'src/modules/browser/constants/browser-tool-commands'; -import { plainToInstance } from 'class-transformer'; +import { plainToClass } from 'class-transformer'; import { DatabaseRecommendationService } from 'src/modules/database-recommendation/database-recommendation.service'; import { AddFieldsToHashDto, @@ -111,7 +111,7 @@ export class HashService { result.nextCursor = 0; const value = await client.sendCommand([BrowserToolHashCommands.HGet, keyName, field]); if (!isNull(value)) { - result.fields.push(plainToInstance(HashFieldDto, { field, value })); + result.fields.push(plainToClass(HashFieldDto, { field, value })); } } else { const scanResult = await this.scanHash(client, dto); @@ -144,7 +144,7 @@ export class HashService { ); this.logger.log('Succeed to get fields of the Hash data type.'); - return plainToInstance(GetHashFieldsResponse, result); + return plainToClass(GetHashFieldsResponse, result); } catch (error) { this.logger.error('Failed to get fields of the Hash data type.', error); if (error.message.includes(RedisErrorCodes.WrongType)) { @@ -278,7 +278,7 @@ export class HashService { const fields: HashFieldDto[] = chunk( fieldsArray, 2, - ).map(([field, value]: string[]) => plainToInstance(HashFieldDto, { field, value })); + ).map(([field, value]: string[]) => plainToClass(HashFieldDto, { field, value })); result = { ...result, nextCursor: parseInt(nextCursor, 10), diff --git a/redisinsight/api/src/modules/browser/keys/dto/get.keys.dto.ts b/redisinsight/api/src/modules/browser/keys/dto/get.keys.dto.ts index d51214981d..410ee51e5e 100644 --- a/redisinsight/api/src/modules/browser/keys/dto/get.keys.dto.ts +++ b/redisinsight/api/src/modules/browser/keys/dto/get.keys.dto.ts @@ -63,7 +63,7 @@ export class GetKeysDto { }) @IsBoolean() @IsOptional() - @Transform(({ value }) => value === true || value === 'true') + @Transform((value) => value === true || value === 'true') keysInfo?: boolean = true; @ApiPropertyOptional({ diff --git a/redisinsight/api/src/modules/browser/keys/keys.service.ts b/redisinsight/api/src/modules/browser/keys/keys.service.ts index cb49d3653f..a079c9459f 100644 --- a/redisinsight/api/src/modules/browser/keys/keys.service.ts +++ b/redisinsight/api/src/modules/browser/keys/keys.service.ts @@ -22,7 +22,7 @@ import { BrowserToolKeysCommands } from 'src/modules/browser/constants/browser-t import { ClientMetadata } from 'src/common/models'; import { Scanner } from 'src/modules/browser/keys/scanner/scanner'; import { BrowserHistoryMode, RedisString } from 'src/common/constants'; -import { plainToInstance } from 'class-transformer'; +import { plainToClass } from 'class-transformer'; import { DatabaseRecommendationService } from 'src/modules/database-recommendation/database-recommendation.service'; import { pick } from 'lodash'; import { BrowserHistoryService } from 'src/modules/browser/browser-history/browser-history.service'; @@ -58,7 +58,7 @@ export class KeysService { if (dto.match !== DEFAULT_MATCH) { await this.browserHistory.create( clientMetadata, - plainToInstance( + plainToClass( CreateBrowserHistoryDto, { filter: pick(dto, 'type', 'match'), mode: BrowserHistoryMode.Pattern }, ), @@ -71,7 +71,7 @@ export class KeysService { result[0]?.total, ); - return result.map((nodeResult) => plainToInstance(GetKeysWithDetailsResponse, nodeResult)); + return result.map((nodeResult) => plainToClass(GetKeysWithDetailsResponse, nodeResult)); } catch (error) { this.logger.error( `Failed to get keys with details info. ${error.message}.`, @@ -110,7 +110,7 @@ export class KeysService { { keys: result, client, databaseId: clientMetadata.databaseId }, ); - return plainToInstance(GetKeyInfoResponse, result); + return plainToClass(GetKeyInfoResponse, result); } catch (error) { this.logger.error(`Failed to get keys info: ${error.message}.`); throw catchAclError(error); @@ -159,7 +159,7 @@ export class KeysService { RECOMMENDATION_NAMES.COMPRESSION_FOR_LIST, result, ); - return plainToInstance(GetKeyInfoResponse, result); + return plainToClass(GetKeyInfoResponse, result); } catch (error) { this.logger.error('Failed to get key info.', error); throw catchAclError(error); @@ -222,7 +222,7 @@ export class KeysService { return Promise.reject(new BadRequestException(ERROR_MESSAGES.NEW_KEY_NAME_EXIST)); } this.logger.log('Succeed to rename key'); - return plainToInstance(RenameKeyResponse, { keyName: newKeyName }); + return plainToClass(RenameKeyResponse, { keyName: newKeyName }); } catch (error) { this.logger.error('Failed to rename key.', error); throw catchAclError(error); diff --git a/redisinsight/api/src/modules/browser/list/list.service.ts b/redisinsight/api/src/modules/browser/list/list.service.ts index aec54e2672..6f9b5f33e0 100644 --- a/redisinsight/api/src/modules/browser/list/list.service.ts +++ b/redisinsight/api/src/modules/browser/list/list.service.ts @@ -27,7 +27,7 @@ import { BrowserToolKeysCommands, BrowserToolListCommands, } from 'src/modules/browser/constants/browser-tool-commands'; -import { plainToInstance } from 'class-transformer'; +import { plainToClass } from 'class-transformer'; import { DatabaseClientFactory } from 'src/modules/database/providers/database.client.factory'; import { RedisClient, RedisClientCommandReply } from 'src/modules/redis/client'; import { checkIfKeyExists, checkIfKeyNotExists } from 'src/modules/browser/utils'; @@ -85,7 +85,7 @@ export class ListService { } this.logger.log(`Succeed to insert element at the ${destination} of the list data type.`); - return plainToInstance(PushListElementsResponse, { keyName, total }); + return plainToClass(PushListElementsResponse, { keyName, total }); } catch (error) { this.logger.error('Failed to inserts element to the list data type.', error); if (error.message.includes(RedisErrorCodes.WrongType)) { @@ -118,7 +118,7 @@ export class ListService { ]); this.logger.log('Succeed to get elements of the list.'); - return plainToInstance(GetListElementsResponse, { keyName, total, elements }); + return plainToClass(GetListElementsResponse, { keyName, total, elements }); } catch (error) { this.logger.error('Failed to to get elements of the list.', error); if (error?.message.includes(RedisErrorCodes.WrongType)) { @@ -153,7 +153,7 @@ export class ListService { } this.logger.log('Succeed to get List element by index.'); - return plainToInstance(GetListElementResponse, { keyName, value }); + return plainToClass(GetListElementResponse, { keyName, value }); } catch (error) { this.logger.error('Failed to to get List element by index.', error); if (error?.message.includes(RedisErrorCodes.WrongType)) { @@ -176,7 +176,7 @@ export class ListService { await client.sendCommand([BrowserToolListCommands.LSet, keyName, index, element]); this.logger.log('Succeed to set the list element at index.'); - return plainToInstance(SetListElementResponse, { index, element }); + return plainToClass(SetListElementResponse, { index, element }); } catch (error) { if (error?.message.includes(RedisErrorCodes.WrongType)) { throw new BadRequestException(error.message); @@ -215,7 +215,7 @@ export class ListService { return Promise.reject(new NotFoundException(ERROR_MESSAGES.KEY_NOT_EXIST)); } - return plainToInstance(DeleteListElementsResponse, { + return plainToClass(DeleteListElementsResponse, { elements: isArray(result) ? [...result] : [result], }); } catch (error) { diff --git a/redisinsight/api/src/modules/browser/redisearch/redisearch.service.ts b/redisinsight/api/src/modules/browser/redisearch/redisearch.service.ts index 98ffd04e9a..325b41b555 100644 --- a/redisinsight/api/src/modules/browser/redisearch/redisearch.service.ts +++ b/redisinsight/api/src/modules/browser/redisearch/redisearch.service.ts @@ -16,7 +16,7 @@ import { } from 'src/modules/browser/redisearch/dto'; import { GetKeysWithDetailsResponse } from 'src/modules/browser/keys/dto'; import { DEFAULT_MATCH, RedisErrorCodes } from 'src/constants'; -import { plainToInstance } from 'class-transformer'; +import { plainToClass } from 'class-transformer'; import { numberWithSpaces } from 'src/utils/base.helper'; import { BrowserHistoryMode, RedisString } from 'src/common/constants'; import { CreateBrowserHistoryDto } from 'src/modules/browser/browser-history/dto'; @@ -55,7 +55,7 @@ export class RedisearchService { ['FT._LIST'], ))); - return plainToInstance(ListRedisearchIndexesResponse, { + return plainToClass(ListRedisearchIndexesResponse, { indexes: ( uniq( ([].concat(...res)).map((idx) => idx.toString('hex')), @@ -200,14 +200,14 @@ export class RedisearchService { if (query !== DEFAULT_MATCH) { await this.browserHistory.create( clientMetadata, - plainToInstance( + plainToClass( CreateBrowserHistoryDto, { filter: { match: query, type: null }, mode: BrowserHistoryMode.Redisearch }, ), ); } - return plainToInstance(GetKeysWithDetailsResponse, { + return plainToClass(GetKeysWithDetailsResponse, { cursor: limit + offset >= total ? 0 : limit + offset, total, scanned: keyNames.length + offset, diff --git a/redisinsight/api/src/modules/browser/set/set.service.ts b/redisinsight/api/src/modules/browser/set/set.service.ts index 9e59b5e7c3..10dddc66fd 100644 --- a/redisinsight/api/src/modules/browser/set/set.service.ts +++ b/redisinsight/api/src/modules/browser/set/set.service.ts @@ -16,7 +16,7 @@ import { BrowserToolKeysCommands, BrowserToolSetCommands, } from 'src/modules/browser/constants/browser-tool-commands'; -import { plainToInstance } from 'class-transformer'; +import { plainToClass } from 'class-transformer'; import { AddMembersToSetDto, CreateSetWithExpireDto, @@ -103,7 +103,7 @@ export class SetService { } this.logger.log('Succeed to get members of the Set data type.'); - return plainToInstance(GetSetMembersResponse, result); + return plainToClass(GetSetMembersResponse, result); } catch (error) { this.logger.error('Failed to get members of the Set data type.', error); if (error?.message.includes(RedisErrorCodes.WrongType)) { diff --git a/redisinsight/api/src/modules/browser/stream/services/consumer-group.service.ts b/redisinsight/api/src/modules/browser/stream/services/consumer-group.service.ts index 05175a4e3b..f707cba066 100644 --- a/redisinsight/api/src/modules/browser/stream/services/consumer-group.service.ts +++ b/redisinsight/api/src/modules/browser/stream/services/consumer-group.service.ts @@ -20,7 +20,7 @@ import { DeleteConsumerGroupsResponse, UpdateConsumerGroupDto, } from 'src/modules/browser/stream/dto'; -import { plainToInstance } from 'class-transformer'; +import { plainToClass } from 'class-transformer'; import { RedisString } from 'src/common/constants'; import { ClientMetadata } from 'src/common/models'; import { DatabaseClientFactory } from 'src/modules/database/providers/database.client.factory'; @@ -91,7 +91,7 @@ export class ConsumerGroupService { group.name, ]); - return plainToInstance(ConsumerGroupDto, { + return plainToClass(ConsumerGroupDto, { ...group, smallestPendingId: info?.[1] || null, greatestPendingId: info?.[2] || null, @@ -277,7 +277,7 @@ export class ConsumerGroupService { const [,name,,consumers,,pending,,lastDeliveredId] = entry; - return plainToInstance(ConsumerGroupDto, { + return plainToClass(ConsumerGroupDto, { name, consumers, pending, diff --git a/redisinsight/api/src/modules/browser/stream/services/consumer.service.ts b/redisinsight/api/src/modules/browser/stream/services/consumer.service.ts index 332d3d7ed5..9b75a0fe33 100644 --- a/redisinsight/api/src/modules/browser/stream/services/consumer.service.ts +++ b/redisinsight/api/src/modules/browser/stream/services/consumer.service.ts @@ -22,7 +22,7 @@ import { GetPendingEntriesDto, PendingEntryDto, } from 'src/modules/browser/stream/dto'; -import { plainToInstance } from 'class-transformer'; +import { plainToClass } from 'class-transformer'; import { ClientMetadata } from 'src/common/models'; import { RedisClient } from 'src/modules/redis/client'; import { checkIfKeyNotExists } from 'src/modules/browser/utils'; @@ -304,7 +304,7 @@ export class ConsumerService { const [,name,,pending,,idle] = entry; - return plainToInstance(ConsumerDto, { + return plainToClass(ConsumerDto, { name, pending, idle, @@ -344,7 +344,7 @@ export class ConsumerService { return null; } - return plainToInstance(PendingEntryDto, { + return plainToClass(PendingEntryDto, { id: `${entry[0]}`, consumerName: entry[1], idle: +entry[2], diff --git a/redisinsight/api/src/modules/browser/stream/services/stream.service.ts b/redisinsight/api/src/modules/browser/stream/services/stream.service.ts index a051d0a0ce..ed97dd04d5 100644 --- a/redisinsight/api/src/modules/browser/stream/services/stream.service.ts +++ b/redisinsight/api/src/modules/browser/stream/services/stream.service.ts @@ -24,7 +24,7 @@ import { StreamEntryFieldDto, } from 'src/modules/browser/stream/dto'; import { RedisErrorCodes } from 'src/constants'; -import { plainToInstance } from 'class-transformer'; +import { plainToClass } from 'class-transformer'; import { ClientMetadata } from 'src/common/models'; import { DatabaseClientFactory } from 'src/modules/database/providers/database.client.factory'; import { RedisClient } from 'src/modules/redis/client'; @@ -70,7 +70,7 @@ export class StreamService { this.logger.log('Succeed to get entries from the stream.'); - return plainToInstance(GetStreamEntriesResponse, { + return plainToClass(GetStreamEntriesResponse, { keyName, total: info['length'], lastGeneratedId: info['last-generated-id'].toString(), @@ -240,7 +240,7 @@ export class StreamService { catchMultiTransactionError(transactionResults); this.logger.log('Succeed to add entries to the stream.'); - return plainToInstance(AddStreamEntriesResponse, { + return plainToClass(AddStreamEntriesResponse, { keyName, entries: transactionResults.map((entryResult) => entryResult[1].toString()), }); @@ -327,7 +327,7 @@ export class StreamService { return { id: entry[0].toString(), - fields: chunk(entry[1] || [], 2).map((field) => plainToInstance( + fields: chunk(entry[1] || [], 2).map((field) => plainToClass( StreamEntryFieldDto, { name: field[0], diff --git a/redisinsight/api/src/modules/browser/string/string.service.ts b/redisinsight/api/src/modules/browser/string/string.service.ts index e56807815a..876f992316 100644 --- a/redisinsight/api/src/modules/browser/string/string.service.ts +++ b/redisinsight/api/src/modules/browser/string/string.service.ts @@ -15,7 +15,7 @@ import { BrowserToolKeysCommands, BrowserToolStringCommands, } from 'src/modules/browser/constants/browser-tool-commands'; -import { plainToInstance } from 'class-transformer'; +import { plainToClass } from 'class-transformer'; import { GetKeyInfoDto } from 'src/modules/browser/keys/dto'; import { ClientMetadata } from 'src/common/models'; import { DatabaseRecommendationService } from 'src/modules/database-recommendation/database-recommendation.service'; @@ -100,7 +100,7 @@ export class StringService { ); this.logger.log('Succeed to get string value.'); - return plainToInstance(GetStringValueResponse, { value, keyName }); + return plainToClass(GetStringValueResponse, { value, keyName }); } catch (error) { this.logger.error('Failed to get string value.', error); if (error.message.includes(RedisErrorCodes.WrongType)) { diff --git a/redisinsight/api/src/modules/browser/z-set/z-set.service.ts b/redisinsight/api/src/modules/browser/z-set/z-set.service.ts index b240f1951e..4387998a2a 100644 --- a/redisinsight/api/src/modules/browser/z-set/z-set.service.ts +++ b/redisinsight/api/src/modules/browser/z-set/z-set.service.ts @@ -18,7 +18,7 @@ import { BrowserToolKeysCommands, BrowserToolZSetCommands, } from 'src/modules/browser/constants/browser-tool-commands'; -import { plainToInstance } from 'class-transformer'; +import { plainToClass } from 'class-transformer'; import { ClientMetadata } from 'src/common/models'; import { AddMembersToZSetDto, @@ -107,7 +107,7 @@ export class ZSetService { ); this.logger.log('Succeed to get members of the ZSet data type.'); - return plainToInstance(GetZSetResponse, { + return plainToClass(GetZSetResponse, { keyName, total, members, @@ -234,7 +234,7 @@ export class ZSetService { const formattedScore = isNaN(parseFloat(score)) ? String(score) : parseFloat(score); if (!isNull(score)) { - result.members.push(plainToInstance(ZSetMemberDto, { name: member, score: formattedScore })); + result.members.push(plainToClass(ZSetMemberDto, { name: member, score: formattedScore })); } } else { const scanResult = await this.scanZSet(client, dto); @@ -242,7 +242,7 @@ export class ZSetService { } this.logger.log('Succeed to search members of the ZSet data type.'); - return plainToInstance(SearchZSetMembersResponse, result); + return plainToClass(SearchZSetMembersResponse, result); } catch (error) { this.logger.error('Failed to search members of the ZSet data type.', error); if (error?.message.includes(RedisErrorCodes.WrongType)) { @@ -357,7 +357,7 @@ export class ZSetService { while (reply.length) { const member = reply.splice(0, 2); const score = isNaN(parseFloat(member[1])) ? String(member[1]) : parseFloat(member[1]); - result.push(plainToInstance(ZSetMemberDto, { + result.push(plainToClass(ZSetMemberDto, { name: member[0], score, })); diff --git a/redisinsight/api/src/modules/cloud/auth/auth-strategy/cloud-auth.strategy.ts b/redisinsight/api/src/modules/cloud/auth/auth-strategy/cloud-auth.strategy.ts index fcf4c2db9c..4cf64f1182 100644 --- a/redisinsight/api/src/modules/cloud/auth/auth-strategy/cloud-auth.strategy.ts +++ b/redisinsight/api/src/modules/cloud/auth/auth-strategy/cloud-auth.strategy.ts @@ -2,7 +2,7 @@ import { Injectable } from '@nestjs/common'; import { CloudAuthRequest, CloudAuthRequestOptions } from 'src/modules/cloud/auth/models/cloud-auth-request'; import { SessionMetadata } from 'src/common/models'; import { OktaAuth } from '@okta/okta-auth-js'; -import { plainToInstance } from 'class-transformer'; +import { plainToClass } from 'class-transformer'; @Injectable() export abstract class CloudAuthStrategy { @@ -18,7 +18,7 @@ export abstract class CloudAuthStrategy { const authClient = new OktaAuth(this.config); const tokenParams = await authClient.token.prepareTokenParams(this.config); - return plainToInstance(CloudAuthRequest, { + return plainToClass(CloudAuthRequest, { ...this.config, ...tokenParams, sessionMetadata, diff --git a/redisinsight/api/src/modules/cloud/auth/auth-strategy/sso-idp.cloud.auth-strategy.ts b/redisinsight/api/src/modules/cloud/auth/auth-strategy/sso-idp.cloud.auth-strategy.ts index 50cf0b160a..a2f0963394 100644 --- a/redisinsight/api/src/modules/cloud/auth/auth-strategy/sso-idp.cloud.auth-strategy.ts +++ b/redisinsight/api/src/modules/cloud/auth/auth-strategy/sso-idp.cloud.auth-strategy.ts @@ -7,7 +7,7 @@ import { CloudAuthRequestOptions, } from 'src/modules/cloud/auth/models/cloud-auth-request'; import { SessionMetadata } from 'src/common/models'; -import { plainToInstance } from 'class-transformer'; +import { plainToClass } from 'class-transformer'; import axios from 'axios'; import * as path from 'path'; import { @@ -67,7 +67,7 @@ export class SsoIdpCloudAuthStrategy extends CloudAuthStrategy { const authClient = new OktaAuth(this.config); const tokenParams = await authClient.token.prepareTokenParams(this.config); - return plainToInstance(CloudAuthRequest, { + return plainToClass(CloudAuthRequest, { ...this.config, ...tokenParams, idp, diff --git a/redisinsight/api/src/modules/cloud/capi-key/cloud-capi-key.service.ts b/redisinsight/api/src/modules/cloud/capi-key/cloud-capi-key.service.ts index fe871962bb..bcd6c3d3d8 100644 --- a/redisinsight/api/src/modules/cloud/capi-key/cloud-capi-key.service.ts +++ b/redisinsight/api/src/modules/cloud/capi-key/cloud-capi-key.service.ts @@ -9,7 +9,7 @@ import { CloudApiBadRequestException, CloudCapiUnauthorizedException } from 'src import { CloudSessionService } from 'src/modules/cloud/session/cloud-session.service'; import { CloudCapiKeyApiProvider } from 'src/modules/cloud/capi-key/cloud-capi-key.api.provider'; import { ServerService } from 'src/modules/server/server.service'; -import { plainToInstance } from 'class-transformer'; +import { plainToClass } from 'class-transformer'; import { CloudCapiKeyNotFoundException, CloudCapiKeyUnauthorizedException, @@ -83,7 +83,7 @@ export class CloudCapiKeyService { } as CloudCapiKey; capiKey.name = await this.generateName(capiKey); - capiKey = await this.repository.create(plainToInstance(CloudCapiKey, capiKey)); + capiKey = await this.repository.create(plainToClass(CloudCapiKey, capiKey)); this.analytics.sendCloudAccountKeyGenerated(); } catch (e) { diff --git a/redisinsight/api/src/modules/cloud/common/decorators/cloud-auth.decorator.ts b/redisinsight/api/src/modules/cloud/common/decorators/cloud-auth.decorator.ts index a72bcd2000..916036ce74 100644 --- a/redisinsight/api/src/modules/cloud/common/decorators/cloud-auth.decorator.ts +++ b/redisinsight/api/src/modules/cloud/common/decorators/cloud-auth.decorator.ts @@ -1,6 +1,6 @@ import { createParamDecorator, ExecutionContext, UnauthorizedException } from '@nestjs/common'; import { Validator } from 'class-validator'; -import { plainToInstance } from 'class-transformer'; +import { plainToClass } from 'class-transformer'; import { CloudCapiAuthDto } from 'src/modules/cloud/common/dto'; const validator = new Validator(); @@ -8,7 +8,7 @@ const validator = new Validator(); export const cloudAuthDtoFromRequestHeadersFactory = (data: unknown, ctx: ExecutionContext): CloudCapiAuthDto => { const request = ctx.switchToHttp().getRequest(); - const dto = plainToInstance(CloudCapiAuthDto, { + const dto = plainToClass(CloudCapiAuthDto, { capiKey: request.headers['x-cloud-api-key'], capiSecret: request.headers['x-cloud-api-secret'], }); diff --git a/redisinsight/api/src/modules/cloud/database/utils/cloud-data-converter.ts b/redisinsight/api/src/modules/cloud/database/utils/cloud-data-converter.ts index 5c24d7ee69..e493abf851 100644 --- a/redisinsight/api/src/modules/cloud/database/utils/cloud-data-converter.ts +++ b/redisinsight/api/src/modules/cloud/database/utils/cloud-data-converter.ts @@ -1,5 +1,5 @@ import { find, get, isArray } from 'lodash'; -import { plainToInstance } from 'class-transformer'; +import { plainToClass } from 'class-transformer'; import { CloudDatabase, CloudDatabaseMemoryStorage, CloudDatabasePersistencePolicy, CloudDatabaseProtocol, ICloudCapiDatabase, ICloudCapiSubscriptionDatabases, @@ -21,7 +21,7 @@ export const parseCloudDatabaseCapiResponse = ( databaseId, name, publicEndpoint, status, security, planMemoryLimit, memoryLimitMeasurementUnit, } = database; - return plainToInstance(CloudDatabase, { + return plainToClass(CloudDatabase, { subscriptionId, subscriptionType, databaseId, diff --git a/redisinsight/api/src/modules/cloud/job/cloud-job.gateway.ts b/redisinsight/api/src/modules/cloud/job/cloud-job.gateway.ts index 90a44ffe59..1d74ee8fba 100644 --- a/redisinsight/api/src/modules/cloud/job/cloud-job.gateway.ts +++ b/redisinsight/api/src/modules/cloud/job/cloud-job.gateway.ts @@ -14,7 +14,7 @@ import { CloudJobEvents } from 'src/modules/cloud/common/constants'; import { CloudJobService } from 'src/modules/cloud/job/cloud-job.service'; import { MonitorCloudJobDto } from 'src/modules/cloud/job/dto/monitor.cloud-job.dto'; import { Validator } from 'class-validator'; -import { plainToInstance } from 'class-transformer'; +import { plainToClass } from 'class-transformer'; import { CloudJobInfo } from 'src/modules/cloud/job/models'; import { SessionMetadata } from 'src/common/models'; import { WSSessionMetadata } from 'src/modules/auth/session-metadata/decorators/ws-session-metadata.decorator'; @@ -42,7 +42,7 @@ export class CloudJobGateway { @Body() data: MonitorCloudJobDto, ): Promise { try { - const dto = plainToInstance(MonitorCloudJobDto, data); + const dto = plainToClass(MonitorCloudJobDto, data); const errors = await this.validator.validate( dto, diff --git a/redisinsight/api/src/modules/cloud/job/jobs/cloud-job.ts b/redisinsight/api/src/modules/cloud/job/jobs/cloud-job.ts index 5eec99971e..05b1c4eb0e 100644 --- a/redisinsight/api/src/modules/cloud/job/jobs/cloud-job.ts +++ b/redisinsight/api/src/modules/cloud/job/jobs/cloud-job.ts @@ -8,7 +8,7 @@ import { CloudJobName } from 'src/modules/cloud/job/constants'; import { CloudRequestUtm } from 'src/modules/cloud/common/models'; import { debounce } from 'lodash'; import { CloudCapiAuthDto } from 'src/modules/cloud/common/dto'; -import { ClassConstructor } from 'class-transformer/types/interfaces'; +import { ClassType } from 'class-transformer/ClassTransformer'; const cloudConfig = config.get('cloud'); @@ -129,7 +129,7 @@ export abstract class CloudJob { }; } - public createChildJob(TargetJob: ClassConstructor, data: {}, options = {}): T { + public createChildJob(TargetJob: ClassType, data: {}, options = {}): T { return new TargetJob( { ...this.options, @@ -142,7 +142,7 @@ export abstract class CloudJob { ); } - public async runChildJob(TargetJob: ClassConstructor, data: {}, options: CloudJobOptions): Promise { + public async runChildJob(TargetJob: ClassType, data: {}, options: CloudJobOptions): Promise { const child = this.createChildJob(TargetJob, data, options); this.changeState({ child }); diff --git a/redisinsight/api/src/modules/cloud/session/cloud-session.service.ts b/redisinsight/api/src/modules/cloud/session/cloud-session.service.ts index 168d1ed5fc..877eb8fb72 100644 --- a/redisinsight/api/src/modules/cloud/session/cloud-session.service.ts +++ b/redisinsight/api/src/modules/cloud/session/cloud-session.service.ts @@ -1,7 +1,7 @@ import { Injectable } from '@nestjs/common'; import { SessionService } from 'src/modules/session/session.service'; import { CloudSession } from 'src/modules/cloud/session/models/cloud-session'; -import { instanceToPlain, plainToInstance } from 'class-transformer'; +import { classToPlain, plainToClass } from 'class-transformer'; import { TransformGroup } from 'src/common/constants'; @Injectable() @@ -19,9 +19,9 @@ export class CloudSessionService { const session = await this.getSession(id); return (await this.sessionService.updateSessionData(id, { - cloud: plainToInstance(CloudSession, { - ...instanceToPlain(session, { groups: [TransformGroup.Secure] }), - ...instanceToPlain(cloud, { groups: [TransformGroup.Secure] }), + cloud: plainToClass(CloudSession, { + ...classToPlain(session, { groups: [TransformGroup.Secure] }), + ...classToPlain(cloud, { groups: [TransformGroup.Secure] }), }, { groups: [TransformGroup.Secure] }), }))?.data?.cloud || null; } diff --git a/redisinsight/api/src/modules/cloud/subscription/utils/cloud-data-converter.ts b/redisinsight/api/src/modules/cloud/subscription/utils/cloud-data-converter.ts index 0ad6f212a8..a1938d8d32 100644 --- a/redisinsight/api/src/modules/cloud/subscription/utils/cloud-data-converter.ts +++ b/redisinsight/api/src/modules/cloud/subscription/utils/cloud-data-converter.ts @@ -2,12 +2,12 @@ import { get, toNumber } from 'lodash'; import { CloudSubscription, CloudSubscriptionPlan, CloudSubscriptionRegion, CloudSubscriptionType, ICloudCapiSubscription, ICloudApiSubscriptionCloudRegion, ICloudCapiSubscriptionPlan, } from 'src/modules/cloud/subscription/models'; -import { plainToInstance } from 'class-transformer'; +import { plainToClass } from 'class-transformer'; export const parseCloudSubscriptionCapiResponse = ( subscription: ICloudCapiSubscription, type: CloudSubscriptionType, -): CloudSubscription => plainToInstance(CloudSubscription, { +): CloudSubscription => plainToClass(CloudSubscription, { id: subscription.id, type, name: subscription.name, @@ -45,7 +45,7 @@ export const parseCloudSubscriptionsPlansCapiResponse = ( const result: CloudSubscriptionPlan[] = []; if (plans?.length) { plans?.forEach?.((plan): void => { - result.push(plainToInstance(CloudSubscriptionPlan, { + result.push(plainToClass(CloudSubscriptionPlan, { id: plan.id, type, name: plan.name, @@ -65,7 +65,7 @@ export const parseCloudSubscriptionsCloudRegionsApiResponse = ( const result: CloudSubscriptionRegion[] = []; if (regions?.length) { regions?.forEach?.((plan): void => { - result.push(plainToInstance(CloudSubscriptionRegion, { + result.push(plainToClass(CloudSubscriptionRegion, { id: toNumber(plan.id), name: plan.name, cloud: plan.cloud, diff --git a/redisinsight/api/src/modules/cloud/task/utils/cloud-data-converter.ts b/redisinsight/api/src/modules/cloud/task/utils/cloud-data-converter.ts index b819659318..b3f85d0d7f 100644 --- a/redisinsight/api/src/modules/cloud/task/utils/cloud-data-converter.ts +++ b/redisinsight/api/src/modules/cloud/task/utils/cloud-data-converter.ts @@ -1,6 +1,6 @@ -import { plainToInstance } from 'class-transformer'; +import { plainToClass } from 'class-transformer'; import { CloudTask, ICloudCapiTask } from 'src/modules/cloud/task/models'; export const parseCloudTaskCapiResponse = ( task: ICloudCapiTask, -): CloudTask => plainToInstance(CloudTask, task); +): CloudTask => plainToClass(CloudTask, task); diff --git a/redisinsight/api/src/modules/cloud/user/repositories/in-session.cloud-user.repository.ts b/redisinsight/api/src/modules/cloud/user/repositories/in-session.cloud-user.repository.ts index 4452873183..7a55be0ff4 100644 --- a/redisinsight/api/src/modules/cloud/user/repositories/in-session.cloud-user.repository.ts +++ b/redisinsight/api/src/modules/cloud/user/repositories/in-session.cloud-user.repository.ts @@ -1,5 +1,5 @@ import { Injectable } from '@nestjs/common'; -import { instanceToPlain, plainToInstance } from 'class-transformer'; +import { classToPlain, plainToClass } from 'class-transformer'; import { CloudUserRepository } from 'src/modules/cloud/user/repositories/cloud-user.repository'; import { CloudUser } from 'src/modules/cloud/user/models'; import { CloudSessionService } from 'src/modules/cloud/session/cloud-session.service'; @@ -20,7 +20,7 @@ export class InSessionCloudUserRepository extends CloudUserRepository { async get(sessionId: string): Promise { const session = await this.sessionService.getSession(sessionId); - return plainToInstance(CloudUser, session?.user, { groups: [TransformGroup.Secure] }) || null; + return plainToClass(CloudUser, session?.user, { groups: [TransformGroup.Secure] }) || null; } /** @@ -31,9 +31,9 @@ export class InSessionCloudUserRepository extends CloudUserRepository { async update(sessionId: string, data: Partial): Promise { const user = await this.get(sessionId); await this.sessionService.updateSessionData(sessionId, { - user: plainToInstance(CloudUser, { - ...instanceToPlain(user, { groups: [TransformGroup.Secure] }), - ...instanceToPlain(data, { groups: [TransformGroup.Secure] }), + user: plainToClass(CloudUser, { + ...classToPlain(user, { groups: [TransformGroup.Secure] }), + ...classToPlain(data, { groups: [TransformGroup.Secure] }), }, { groups: [TransformGroup.Secure] }), }); diff --git a/redisinsight/api/src/modules/cloud/user/utils/cloud-data-converter.ts b/redisinsight/api/src/modules/cloud/user/utils/cloud-data-converter.ts index 35d95a56c4..df507108f8 100644 --- a/redisinsight/api/src/modules/cloud/user/utils/cloud-data-converter.ts +++ b/redisinsight/api/src/modules/cloud/user/utils/cloud-data-converter.ts @@ -2,9 +2,9 @@ import { get } from 'lodash'; import { CloudAccountInfo, ICloudCapiAccount, } from 'src/modules/cloud/user/models'; -import { plainToInstance } from 'class-transformer'; +import { plainToClass } from 'class-transformer'; -export const parseCloudAccountCapiResponse = (account: ICloudCapiAccount): CloudAccountInfo => plainToInstance( +export const parseCloudAccountCapiResponse = (account: ICloudCapiAccount): CloudAccountInfo => plainToClass( CloudAccountInfo, { accountId: account.id, diff --git a/redisinsight/api/src/modules/cluster-monitor/strategies/abstract.info.strategy.ts b/redisinsight/api/src/modules/cluster-monitor/strategies/abstract.info.strategy.ts index e0b667207d..ea395c341e 100644 --- a/redisinsight/api/src/modules/cluster-monitor/strategies/abstract.info.strategy.ts +++ b/redisinsight/api/src/modules/cluster-monitor/strategies/abstract.info.strategy.ts @@ -2,7 +2,7 @@ import { IClusterInfo } from 'src/modules/cluster-monitor/strategies/cluster.inf import { convertRedisInfoReplyToObject, convertStringToNumber } from 'src/utils'; import { get, map, sum } from 'lodash'; import { ClusterDetails, ClusterNodeDetails } from 'src/modules/cluster-monitor/models'; -import { plainToInstance } from 'class-transformer'; +import { plainToClass } from 'class-transformer'; import { convertMultilineReplyToObject } from 'src/modules/redis/utils'; import { RedisClient } from 'src/modules/redis/client'; @@ -27,7 +27,7 @@ export abstract class AbstractInfoStrategy implements IClusterInfo { mode: get(nodes, '0.mode'), }; - return plainToInstance(ClusterDetails, clusterDetails); + return plainToClass(ClusterDetails, clusterDetails); } /** diff --git a/redisinsight/api/src/modules/custom-tutorial/custom-tutorial.service.ts b/redisinsight/api/src/modules/custom-tutorial/custom-tutorial.service.ts index e7d4373f01..e5367dfc96 100644 --- a/redisinsight/api/src/modules/custom-tutorial/custom-tutorial.service.ts +++ b/redisinsight/api/src/modules/custom-tutorial/custom-tutorial.service.ts @@ -6,7 +6,7 @@ import { v4 as uuidv4 } from 'uuid'; import { CustomTutorialRepository } from 'src/modules/custom-tutorial/repositories/custom-tutorial.repository'; import { CustomTutorial, CustomTutorialActions } from 'src/modules/custom-tutorial/models/custom-tutorial'; import { UploadCustomTutorialDto } from 'src/modules/custom-tutorial/dto/upload.custom-tutorial.dto'; -import { plainToInstance } from 'class-transformer'; +import { plainToClass } from 'class-transformer'; import ERROR_MESSAGES from 'src/constants/error-messages'; import { CustomTutorialFsProvider } from 'src/modules/custom-tutorial/providers/custom-tutorial.fs.provider'; import { @@ -51,7 +51,7 @@ export class CustomTutorialService { } const errors = await this.validator.validate( - plainToInstance(RootCustomTutorialManifest, manifest), + plainToClass(RootCustomTutorialManifest, manifest), { whitelist: true }, ); @@ -91,7 +91,7 @@ export class CustomTutorialService { await this.validateManifestJson(tmpPath); // create tutorial model - const model = plainToInstance(CustomTutorial, { + const model = plainToClass(CustomTutorial, { ...dto, id: uuidv4(), }); diff --git a/redisinsight/api/src/modules/custom-tutorial/providers/custom-tutorial.manifest.provider.ts b/redisinsight/api/src/modules/custom-tutorial/providers/custom-tutorial.manifest.provider.ts index a90911caa9..4ecc7fdd56 100644 --- a/redisinsight/api/src/modules/custom-tutorial/providers/custom-tutorial.manifest.provider.ts +++ b/redisinsight/api/src/modules/custom-tutorial/providers/custom-tutorial.manifest.provider.ts @@ -8,7 +8,7 @@ import { CustomTutorialManifestType, RootCustomTutorialManifest, } from 'src/modules/custom-tutorial/models/custom-tutorial.manifest'; -import { plainToInstance } from 'class-transformer'; +import { plainToClass } from 'class-transformer'; import { winPathToNormalPath } from 'src/utils'; const MANIFEST_FILE = 'manifest.json'; @@ -134,7 +134,7 @@ export class CustomTutorialManifestProvider { return null; } - return plainToInstance(RootCustomTutorialManifest, manifestJson, { excludeExtraneousValues: true }); + return plainToClass(RootCustomTutorialManifest, manifestJson, { excludeExtraneousValues: true }); } catch (e) { this.logger.warn('Unable to get manifest for tutorial'); return null; diff --git a/redisinsight/api/src/modules/database-analysis/database-analysis.service.ts b/redisinsight/api/src/modules/database-analysis/database-analysis.service.ts index ed38b8ec52..f81cc81645 100644 --- a/redisinsight/api/src/modules/database-analysis/database-analysis.service.ts +++ b/redisinsight/api/src/modules/database-analysis/database-analysis.service.ts @@ -4,7 +4,7 @@ import { RecommendationService } from 'src/modules/recommendation/recommendation import { catchAclError } from 'src/utils'; import { ONE_NODE_RECOMMENDATIONS } from 'src/constants'; import { DatabaseAnalyzer } from 'src/modules/database-analysis/providers/database-analyzer'; -import { plainToInstance } from 'class-transformer'; +import { plainToClass } from 'class-transformer'; import { DatabaseAnalysis, ShortDatabaseAnalysis } from 'src/modules/database-analysis/models'; import { DatabaseAnalysisProvider } from 'src/modules/database-analysis/providers/database-analysis.provider'; import { CreateDatabaseAnalysisDto, RecommendationVoteDto } from 'src/modules/database-analysis/dto'; @@ -80,7 +80,7 @@ export class DatabaseAnalysisService { jobsArray.push(foundedRecommendations); return flatten(jobsArray); }, Promise.resolve([])); - const analysis = plainToInstance(DatabaseAnalysis, await this.analyzer.analyze({ + const analysis = plainToClass(DatabaseAnalysis, await this.analyzer.analyze({ databaseId: clientMetadata.databaseId, db: await client?.getCurrentDbIndex(), ...dto, diff --git a/redisinsight/api/src/modules/database-analysis/entities/database-analysis.entity.ts b/redisinsight/api/src/modules/database-analysis/entities/database-analysis.entity.ts index 4605f5a7c8..99ef6ced49 100644 --- a/redisinsight/api/src/modules/database-analysis/entities/database-analysis.entity.ts +++ b/redisinsight/api/src/modules/database-analysis/entities/database-analysis.entity.ts @@ -49,9 +49,9 @@ export class DatabaseAnalysisEntity { totalMemory: string; @Column({ nullable: true, type: 'blob' }) - @Transform(({ value }) => JSON.stringify(value), { toClassOnly: true }) + @Transform((value) => JSON.stringify(value), { toClassOnly: true }) @Transform( - ({ value: str }) => { + (str) => { try { return JSON.parse(str).map((value) => ({ ...value, @@ -67,9 +67,9 @@ export class DatabaseAnalysisEntity { topKeysNsp: string; @Column({ nullable: true, type: 'blob' }) - @Transform(({ value }) => JSON.stringify(value), { toClassOnly: true }) + @Transform((value) => JSON.stringify(value), { toClassOnly: true }) @Transform( - ({ value: str }) => { + (str) => { try { return JSON.parse(str).map((value) => ({ ...value, @@ -85,9 +85,9 @@ export class DatabaseAnalysisEntity { topMemoryNsp: string; @Column({ nullable: true, type: 'blob' }) - @Transform(({ value }) => JSON.stringify(value), { toClassOnly: true }) + @Transform((value) => JSON.stringify(value), { toClassOnly: true }) @Transform( - ({ value: str }) => { + (str) => { try { return JSON.parse(str).map((value) => ({ ...value, @@ -103,9 +103,9 @@ export class DatabaseAnalysisEntity { topKeysLength: string; @Column({ nullable: true, type: 'blob' }) - @Transform(({ value }) => JSON.stringify(value), { toClassOnly: true }) + @Transform((value) => JSON.stringify(value), { toClassOnly: true }) @Transform( - ({ value: str }) => { + (str) => { try { return JSON.parse(str).map((value) => ({ ...value, diff --git a/redisinsight/api/src/modules/database-analysis/providers/database-analysis.provider.spec.ts b/redisinsight/api/src/modules/database-analysis/providers/database-analysis.provider.spec.ts index 83717a89c5..ef791fb78f 100644 --- a/redisinsight/api/src/modules/database-analysis/providers/database-analysis.provider.spec.ts +++ b/redisinsight/api/src/modules/database-analysis/providers/database-analysis.provider.spec.ts @@ -15,7 +15,7 @@ import { DatabaseAnalysisProvider } from 'src/modules/database-analysis/provider import { DatabaseAnalysis } from 'src/modules/database-analysis/models'; import { CreateDatabaseAnalysisDto, RecommendationVoteDto } from 'src/modules/database-analysis/dto'; import { RedisDataType } from 'src/modules/browser/keys/dto'; -import { plainToInstance } from 'class-transformer'; +import { plainToClass } from 'class-transformer'; import { ScanFilter } from 'src/modules/database-analysis/models/scan-filter'; import { DatabaseAnalysisEntity } from 'src/modules/database-analysis/entities/database-analysis.entity'; import { NotFoundException } from '@nestjs/common'; @@ -24,7 +24,7 @@ import { KeytarDecryptionErrorException } from 'src/modules/encryption/exception export const mockCreateDatabaseAnalysisDto: CreateDatabaseAnalysisDto = { delimiter: ':', - filter: plainToInstance(ScanFilter, { + filter: plainToClass(ScanFilter, { type: RedisDataType.String, match: 'key*', count: 15, diff --git a/redisinsight/api/src/modules/database-analysis/providers/database-analysis.provider.ts b/redisinsight/api/src/modules/database-analysis/providers/database-analysis.provider.ts index a576a35bf4..de816747f6 100644 --- a/redisinsight/api/src/modules/database-analysis/providers/database-analysis.provider.ts +++ b/redisinsight/api/src/modules/database-analysis/providers/database-analysis.provider.ts @@ -4,7 +4,7 @@ import { isUndefined } from 'lodash'; import { InjectRepository } from '@nestjs/typeorm'; import { Repository } from 'typeorm'; import { EncryptionService } from 'src/modules/encryption/encryption.service'; -import { plainToInstance } from 'class-transformer'; +import { plainToClass } from 'class-transformer'; import { DatabaseAnalysis, ShortDatabaseAnalysis } from 'src/modules/database-analysis/models'; import { RecommendationVoteDto } from 'src/modules/database-analysis/dto'; import { classToClass } from 'src/utils'; @@ -43,7 +43,7 @@ export class DatabaseAnalysisProvider { */ async create(analysis: Partial): Promise { const entity = await this.repository.save( - await this.encryptEntity(plainToInstance(DatabaseAnalysisEntity, analysis)), + await this.encryptEntity(plainToClass(DatabaseAnalysisEntity, analysis)), ); // cleanup history and ignore error if any @@ -91,7 +91,7 @@ export class DatabaseAnalysisProvider { entity.recommendations = entity.recommendations.map((recommendation) => ( recommendation.name === name ? { ...recommendation, vote } : recommendation)); - await this.repository.update(id, await this.encryptEntity(plainToInstance(DatabaseAnalysisEntity, entity))); + await this.repository.update(id, await this.encryptEntity(plainToClass(DatabaseAnalysisEntity, entity))); return entity; } diff --git a/redisinsight/api/src/modules/database-import/database-import.service.ts b/redisinsight/api/src/modules/database-import/database-import.service.ts index 467a6f95bc..ae75415f20 100644 --- a/redisinsight/api/src/modules/database-import/database-import.service.ts +++ b/redisinsight/api/src/modules/database-import/database-import.service.ts @@ -3,7 +3,7 @@ import { } from '@nestjs/common'; import { get, isArray, set } from 'lodash'; import { Database } from 'src/modules/database/models/database'; -import { plainToInstance } from 'class-transformer'; +import { plainToClass } from 'class-transformer'; import { ConnectionType, Compressor } from 'src/modules/database/entities/database.entity'; import { DatabaseRepository } from 'src/modules/database/repositories/database.repository'; import { @@ -123,7 +123,7 @@ export class DatabaseImportService { } })), Promise.resolve()); - response = plainToInstance(DatabaseImportResponse, response); + response = plainToClass(DatabaseImportResponse, response); this.analytics.sendImportResults(response); @@ -231,7 +231,7 @@ export class DatabaseImportService { errors.push(new InvalidCompressorException()); } - const dto = plainToInstance( + const dto = plainToClass( ImportDatabaseDto, // additionally replace empty strings ("") with null Object.keys(data) diff --git a/redisinsight/api/src/modules/database-import/dto/database-import.response.ts b/redisinsight/api/src/modules/database-import/dto/database-import.response.ts index e69facdbca..2ab95b2418 100644 --- a/redisinsight/api/src/modules/database-import/dto/database-import.response.ts +++ b/redisinsight/api/src/modules/database-import/dto/database-import.response.ts @@ -28,7 +28,7 @@ export class DatabaseImportResult { type: String, }) @Expose() - @Transform(({ value }) => (isString(value) ? value : undefined), { toPlainOnly: true }) + @Transform((value) => (isString(value) ? value : undefined), { toPlainOnly: true }) host?: string; @ApiPropertyOptional({ @@ -36,7 +36,7 @@ export class DatabaseImportResult { type: Number, }) @Expose() - @Transform(({ value }) => (isNumber(value) ? value : undefined), { toPlainOnly: true }) + @Transform((value) => (isNumber(value) ? value : undefined), { toPlainOnly: true }) port?: number; @ApiPropertyOptional({ @@ -45,7 +45,7 @@ export class DatabaseImportResult { }) @Expose() @Transform( - ({ value: e }) => { + (e) => { if (!e) { return undefined; } diff --git a/redisinsight/api/src/modules/database-recommendation/database-recommendation.service.ts b/redisinsight/api/src/modules/database-recommendation/database-recommendation.service.ts index 5a494f96ee..6ee9397395 100644 --- a/redisinsight/api/src/modules/database-recommendation/database-recommendation.service.ts +++ b/redisinsight/api/src/modules/database-recommendation/database-recommendation.service.ts @@ -1,6 +1,6 @@ import { Injectable, Logger } from '@nestjs/common'; import { sum } from 'lodash'; -import { plainToInstance } from 'class-transformer'; +import { plainToClass } from 'class-transformer'; import { DatabaseRecommendationRepository } from 'src/modules/database-recommendation/repositories/database-recommendation.repository'; import { DatabaseRecommendation } from 'src/modules/database-recommendation/models'; @@ -78,7 +78,7 @@ export class DatabaseRecommendationService { const recommendation = await this.scanner.determineRecommendation(recommendationName, data); if (recommendation) { - const entity = plainToInstance( + const entity = plainToClass( DatabaseRecommendation, { databaseId: newClientMetadata?.databaseId, ...recommendation }, ); diff --git a/redisinsight/api/src/modules/database-recommendation/providers/database-recommendation.emitter.ts b/redisinsight/api/src/modules/database-recommendation/providers/database-recommendation.emitter.ts index 18a1a288a1..87f677e712 100644 --- a/redisinsight/api/src/modules/database-recommendation/providers/database-recommendation.emitter.ts +++ b/redisinsight/api/src/modules/database-recommendation/providers/database-recommendation.emitter.ts @@ -1,6 +1,6 @@ import { Injectable, Logger } from '@nestjs/common'; import { EventEmitter2, OnEvent } from '@nestjs/event-emitter'; -import { plainToInstance } from 'class-transformer'; +import { plainToClass } from 'class-transformer'; import { ClientMetadata } from 'src/common/models'; import { RecommendationEvents, RecommendationServerEvents } from 'src/modules/database-recommendation/constants'; import { @@ -35,7 +35,7 @@ export class DatabaseRecommendationEmitter { this.eventEmitter.emit( RecommendationServerEvents.Recommendation, recommendations[0].databaseId, - plainToInstance( + plainToClass( DatabaseRecommendationsResponse, { totalUnread, diff --git a/redisinsight/api/src/modules/database-recommendation/repositories/local.database.recommendation.repository.ts b/redisinsight/api/src/modules/database-recommendation/repositories/local.database.recommendation.repository.ts index 3d2030db03..811800be3f 100644 --- a/redisinsight/api/src/modules/database-recommendation/repositories/local.database.recommendation.repository.ts +++ b/redisinsight/api/src/modules/database-recommendation/repositories/local.database.recommendation.repository.ts @@ -7,7 +7,7 @@ import { DatabaseRecommendationRepository } from 'src/modules/database-recommendation/repositories/database-recommendation.repository'; import { InjectRepository } from '@nestjs/typeorm'; import { Repository } from 'typeorm'; -import { plainToInstance } from 'class-transformer'; +import { plainToClass } from 'class-transformer'; import { DatabaseRecommendation } from 'src/modules/database-recommendation/models'; import { ModifyDatabaseRecommendationDto } from 'src/modules/database-recommendation/dto'; import { EncryptionService } from 'src/modules/encryption/encryption.service'; @@ -49,7 +49,7 @@ export class LocalDatabaseRecommendationRepository extends DatabaseRecommendatio try { const model = await this.repository.save( - await this.modelEncryptor.encryptEntity(plainToInstance(DatabaseRecommendationEntity, entity)), + await this.modelEncryptor.encryptEntity(plainToClass(DatabaseRecommendationEntity, entity)), ); const recommendation = classToClass( @@ -127,7 +127,7 @@ export class LocalDatabaseRecommendationRepository extends DatabaseRecommendatio ): Promise { this.logger.log(`Updating database recommendation with id:${id}`); const oldEntity = await this.modelEncryptor.decryptEntity(await this.repository.findOneBy({ id })); - const newEntity = plainToInstance(DatabaseRecommendationEntity, recommendation); + const newEntity = plainToClass(DatabaseRecommendationEntity, recommendation); if (!oldEntity) { this.logger.error(`Database recommendation with id:${id} was not Found`); @@ -197,7 +197,7 @@ export class LocalDatabaseRecommendationRepository extends DatabaseRecommendatio const sortedRecommendations = sortRecommendations(dbAnalysisRecommendations); for (let i = 0; i < sortedRecommendations.length; i += 1) { if (!await this.isExist(clientMetadata, sortedRecommendations[i].name)) { - const entity = plainToInstance( + const entity = plainToClass( DatabaseRecommendation, { databaseId: clientMetadata?.databaseId, diff --git a/redisinsight/api/src/modules/database/entities/database.entity.ts b/redisinsight/api/src/modules/database/entities/database.entity.ts index 992843638f..75e044bbca 100644 --- a/redisinsight/api/src/modules/database/entities/database.entity.ts +++ b/redisinsight/api/src/modules/database/entities/database.entity.ts @@ -84,27 +84,27 @@ export class DatabaseEntity { @Expose() @Column({ nullable: true }) - @Transform(({ obj }) => ( + @Transform((_, obj) => ( obj?.sentinelMaster?.name ), { toClassOnly: true }) sentinelMasterName: string; @Expose() @Column({ nullable: true }) - @Transform(({ obj }) => ( + @Transform((_, obj) => ( obj?.sentinelMaster?.username ), { toClassOnly: true }) sentinelMasterUsername: string; @Expose() @Column({ nullable: true }) - @Transform(({ obj }) => ( + @Transform((_, obj) => ( obj?.sentinelMaster?.password ), { toClassOnly: true }) sentinelMasterPassword: string; @Expose() - @Transform(({ obj }) => { + @Transform((_, obj) => { if (obj?.sentinelMasterName) { return { name: obj?.sentinelMasterName, diff --git a/redisinsight/api/src/modules/database/middleware/connection.middleware.ts b/redisinsight/api/src/modules/database/middleware/connection.middleware.ts index 2384514100..67ee6ed75d 100644 --- a/redisinsight/api/src/modules/database/middleware/connection.middleware.ts +++ b/redisinsight/api/src/modules/database/middleware/connection.middleware.ts @@ -10,7 +10,7 @@ import { NextFunction, Request, Response } from 'express'; import ERROR_MESSAGES from 'src/constants/error-messages'; import { RedisErrorCodes } from 'src/constants'; import { DatabaseService } from 'src/modules/database/database.service'; -import { plainToInstance } from 'class-transformer'; +import { plainToClass } from 'class-transformer'; import { sessionMetadataFromRequest } from 'src/common/decorators'; import { Database } from '../models/database'; @@ -28,7 +28,7 @@ export class ConnectionMiddleware implements NestMiddleware { const sessionMetadata = sessionMetadataFromRequest(req); if (instanceIdFromReq) { - timeout = plainToInstance( + timeout = plainToClass( Database, await this.databaseService.get(sessionMetadata, instanceIdFromReq), )?.timeout; diff --git a/redisinsight/api/src/modules/feature/features-config.service.spec.ts b/redisinsight/api/src/modules/feature/features-config.service.spec.ts index a022e742dd..77d7818b99 100644 --- a/redisinsight/api/src/modules/feature/features-config.service.spec.ts +++ b/redisinsight/api/src/modules/feature/features-config.service.spec.ts @@ -11,7 +11,7 @@ import { import { FeaturesConfigService } from 'src/modules/feature/features-config.service'; import { FeaturesConfigRepository } from 'src/modules/feature/repositories/features-config.repository'; import { EventEmitter2 } from '@nestjs/event-emitter'; -import { plainToInstance } from 'class-transformer'; +import { plainToClass } from 'class-transformer'; import { FeaturesConfigData } from 'src/modules/feature/model/features-config'; import { FeatureConfigConfigDestination, FeatureServerEvents, KnownFeatures } from 'src/modules/feature/constants'; import { FeatureAnalytics } from 'src/modules/feature/feature.analytics'; @@ -127,7 +127,7 @@ describe('FeaturesConfigService', () => { it('should update to the latest remote config', async () => { repository.getOrCreate.mockResolvedValue({ ...mockFeaturesConfig, - data: plainToInstance(FeaturesConfigData, defaultConfig), + data: plainToClass(FeaturesConfigData, defaultConfig), }); await service['sync'](); @@ -143,7 +143,7 @@ describe('FeaturesConfigService', () => { it('should not fail and not emit recalculate event in case of an error', async () => { repository.getOrCreate.mockResolvedValue({ ...mockFeaturesConfig, - data: plainToInstance(FeaturesConfigData, defaultConfig), + data: plainToClass(FeaturesConfigData, defaultConfig), }); repository.update.mockRejectedValueOnce(new Error('update error')); diff --git a/redisinsight/api/src/modules/feature/features-config.service.ts b/redisinsight/api/src/modules/feature/features-config.service.ts index b98a3d6325..f44176b3d4 100644 --- a/redisinsight/api/src/modules/feature/features-config.service.ts +++ b/redisinsight/api/src/modules/feature/features-config.service.ts @@ -7,7 +7,7 @@ import config from 'src/utils/config'; import { FeaturesConfigRepository } from 'src/modules/feature/repositories/features-config.repository'; import { FeatureConfigConfigDestination, FeatureServerEvents } from 'src/modules/feature/constants'; import { Validator } from 'class-validator'; -import { plainToInstance } from 'class-transformer'; +import { plainToClass } from 'class-transformer'; import { FeaturesConfigData } from 'src/modules/feature/model/features-config'; import { FeatureAnalytics } from 'src/modules/feature/feature.analytics'; import { UnableToFetchRemoteConfigException } from 'src/modules/feature/exceptions'; @@ -64,7 +64,7 @@ export class FeaturesConfigService implements OnApplicationBootstrap { remoteConfig = await this.fetchRemoteConfig(); // we should use default config in case when remote is invalid - await this.validator.validateOrReject(plainToInstance(FeaturesConfigData, remoteConfig)); + await this.validator.validateOrReject(plainToClass(FeaturesConfigData, remoteConfig)); if (remoteConfig?.version > defaultConfig?.version) { newConfig = { diff --git a/redisinsight/api/src/modules/feature/model/features-config.spec.ts b/redisinsight/api/src/modules/feature/model/features-config.spec.ts index 6ae01e03b3..33358a08fa 100644 --- a/redisinsight/api/src/modules/feature/model/features-config.spec.ts +++ b/redisinsight/api/src/modules/feature/model/features-config.spec.ts @@ -2,7 +2,7 @@ import { mockFeaturesConfig, mockFeaturesConfigComplex, mockFeaturesConfigEntity, mockFeaturesConfigEntityComplex, mockFeaturesConfigJson, mockFeaturesConfigJsonComplex, } from 'src/__mocks__'; -import { instanceToPlain, plainToInstance } from 'class-transformer'; +import { classToPlain, plainToClass } from 'class-transformer'; import { FeaturesConfig } from 'src/modules/feature/model/features-config'; import { classToClass } from 'src/utils'; import { FeaturesConfigEntity } from 'src/modules/feature/entities/features-config.entity'; @@ -50,8 +50,8 @@ describe('FeaturesConfig', () => { describe('transform', () => { testCases.forEach((tc) => { it(`input ${JSON.stringify(tc.plain)}`, async () => { - const modelFromPlain = plainToInstance(FeaturesConfig, tc.plain); - const plainFromModel = instanceToPlain(modelFromPlain); + const modelFromPlain = plainToClass(FeaturesConfig, tc.plain); + const plainFromModel = classToPlain(modelFromPlain); const entityFromModel = classToClass(FeaturesConfigEntity, modelFromPlain); const modelFromEntity = classToClass(FeaturesConfig, entityFromModel); diff --git a/redisinsight/api/src/modules/feature/repositories/local.features-config.repository.spec.ts b/redisinsight/api/src/modules/feature/repositories/local.features-config.repository.spec.ts index 43c2f4a3eb..75cf9d0cb7 100644 --- a/redisinsight/api/src/modules/feature/repositories/local.features-config.repository.spec.ts +++ b/redisinsight/api/src/modules/feature/repositories/local.features-config.repository.spec.ts @@ -9,7 +9,7 @@ import { } from 'src/__mocks__' import { LocalFeaturesConfigRepository } from 'src/modules/feature/repositories/local.features-config.repository'; import { FeaturesConfigEntity } from 'src/modules/feature/entities/features-config.entity'; -import { plainToInstance } from 'class-transformer'; +import { plainToClass } from 'class-transformer'; import * as defaultConfig from '../../../../config/features-config.json'; describe('LocalFeaturesConfigRepository', () => { @@ -109,7 +109,7 @@ describe('LocalFeaturesConfigRepository', () => { expect(result).toEqual(mockFeaturesConfig); expect(repository.update).toHaveBeenCalledWith( { id: service['id'] }, - plainToInstance(FeaturesConfigEntity, { id: service['id'], data: defaultConfig }), + plainToClass(FeaturesConfigEntity, { id: service['id'], data: defaultConfig }), ); }); }); diff --git a/redisinsight/api/src/modules/feature/repositories/local.features-config.repository.ts b/redisinsight/api/src/modules/feature/repositories/local.features-config.repository.ts index 1177d9232b..93922d053c 100644 --- a/redisinsight/api/src/modules/feature/repositories/local.features-config.repository.ts +++ b/redisinsight/api/src/modules/feature/repositories/local.features-config.repository.ts @@ -3,7 +3,7 @@ import { } from '@nestjs/common'; import { InjectRepository } from '@nestjs/typeorm'; import { Repository } from 'typeorm'; -import { plainToInstance } from 'class-transformer'; +import { plainToClass } from 'class-transformer'; import { classToClass } from 'src/utils'; import { FeaturesConfigRepository } from 'src/modules/feature/repositories/features-config.repository'; import { FeaturesConfigEntity } from 'src/modules/feature/entities/features-config.entity'; @@ -46,7 +46,7 @@ export class LocalFeaturesConfigRepository extends FeaturesConfigRepository { try { this.logger.log('Creating features config entity'); - entity = await this.repository.save(plainToInstance(FeaturesConfigEntity, { + entity = await this.repository.save(plainToClass(FeaturesConfigEntity, { id: this.id, data: defaultConfig, controlNumber: this.generateControlNumber(), @@ -69,7 +69,7 @@ export class LocalFeaturesConfigRepository extends FeaturesConfigRepository { async update(data: any): Promise { await this.repository.update( { id: this.id }, - plainToInstance(FeaturesConfigEntity, { data, id: this.id }), + plainToClass(FeaturesConfigEntity, { data, id: this.id }), ); return this.getOrCreate(); diff --git a/redisinsight/api/src/modules/feature/transformers/feature-config-filter.transformer.ts b/redisinsight/api/src/modules/feature/transformers/feature-config-filter.transformer.ts index db38fc9601..9bd8eba9ab 100644 --- a/redisinsight/api/src/modules/feature/transformers/feature-config-filter.transformer.ts +++ b/redisinsight/api/src/modules/feature/transformers/feature-config-filter.transformer.ts @@ -1,12 +1,12 @@ import { get, map } from 'lodash'; -import { plainToInstance } from 'class-transformer'; +import { plainToClass } from 'class-transformer'; import { FeatureConfigFilter, FeatureConfigFilterAnd, FeatureConfigFilterOr, } from 'src/modules/feature/model/features-config'; -export const featureConfigFilterTransformer = ({ value }) => map(value || [], (filter) => { +export const featureConfigFilterTransformer = (value) => map(value || [], (filter) => { let cls: any = FeatureConfigFilter; if (get(filter, 'and')) { @@ -17,5 +17,5 @@ export const featureConfigFilterTransformer = ({ value }) => map(value || [], (f cls = FeatureConfigFilterOr; } - return plainToInstance(cls, filter); + return plainToClass(cls, filter); }); diff --git a/redisinsight/api/src/modules/notification/notification.service.ts b/redisinsight/api/src/modules/notification/notification.service.ts index f0dd8b8d04..45f2f61c7a 100644 --- a/redisinsight/api/src/modules/notification/notification.service.ts +++ b/redisinsight/api/src/modules/notification/notification.service.ts @@ -1,5 +1,5 @@ import { Injectable, InternalServerErrorException, Logger } from '@nestjs/common'; -import { plainToInstance } from 'class-transformer'; +import { plainToClass } from 'class-transformer'; import { SessionMetadata } from 'src/common/models'; import { NotificationsDto, ReadNotificationsDto } from 'src/modules/notification/dto'; import { NotificationRepository } from './repositories/notification.repository'; @@ -21,7 +21,7 @@ export class NotificationService { this.notificationRepository.getTotalUnread(sessionMetadata), ]); - return plainToInstance(NotificationsDto, { + return plainToClass(NotificationsDto, { notifications, totalUnread, }); @@ -46,7 +46,7 @@ export class NotificationService { const notifications = await this.notificationRepository.readNotifications(sessionMetadata, type, timestamp); - return plainToInstance(NotificationsDto, { + return plainToClass(NotificationsDto, { notifications, totalUnread: await this.notificationRepository.getTotalUnread(sessionMetadata), }); diff --git a/redisinsight/api/src/modules/notification/providers/global-notification.provider.ts b/redisinsight/api/src/modules/notification/providers/global-notification.provider.ts index 6228b1b996..2e7baa14ad 100644 --- a/redisinsight/api/src/modules/notification/providers/global-notification.provider.ts +++ b/redisinsight/api/src/modules/notification/providers/global-notification.provider.ts @@ -5,7 +5,7 @@ import { Logger, } from '@nestjs/common'; import { EventEmitter2 } from '@nestjs/event-emitter'; -import { plainToInstance } from 'class-transformer'; +import { plainToClass } from 'class-transformer'; import { Validator } from 'class-validator'; import { forEach, keyBy, orderBy, values, @@ -55,7 +55,7 @@ export class GlobalNotificationProvider { await this.validatedNotifications(remoteNotificationsDto); const toInsert = keyBy( - remoteNotificationsDto.notifications.map((notification) => plainToInstance(Notification, { + remoteNotificationsDto.notifications.map((notification) => plainToClass(Notification, { ...notification, type: NotificationType.Global, read: false, @@ -108,7 +108,7 @@ export class GlobalNotificationProvider { this.logger.debug('Validating notifications from remote'); try { - const notificationsDto: CreateNotificationsDto = plainToInstance( + const notificationsDto: CreateNotificationsDto = plainToClass( CreateNotificationsDto, dto, ); @@ -128,7 +128,7 @@ export class GlobalNotificationProvider { const buffer = await getFile(NOTIFICATIONS_CONFIG.updateUrl); const serializedString = buffer.toString(); const json = JSON.parse(serializedString); - return plainToInstance(CreateNotificationsDto, json); + return plainToClass(CreateNotificationsDto, json); } catch (e) { this.logger.error( `Unable to download or parse notifications json. ${e.message}`, diff --git a/redisinsight/api/src/modules/notification/providers/notification.emitter.ts b/redisinsight/api/src/modules/notification/providers/notification.emitter.ts index 89ee6fe30e..b35c6269f4 100644 --- a/redisinsight/api/src/modules/notification/providers/notification.emitter.ts +++ b/redisinsight/api/src/modules/notification/providers/notification.emitter.ts @@ -4,7 +4,7 @@ import { SessionMetadata } from 'src/common/models'; import { NotificationEvents, NotificationServerEvents } from 'src/modules/notification/constants'; import { NotificationsDto } from 'src/modules/notification/dto'; import { Notification } from 'src/modules/notification/models/notification'; -import { plainToInstance } from 'class-transformer'; +import { plainToClass } from 'class-transformer'; import { NotificationRepository } from '../repositories/notification.repository'; @Injectable() @@ -27,7 +27,7 @@ export class NotificationEmitter { const totalUnread = await this.notificationRepository.getTotalUnread(sessionMetadata); - this.eventEmitter.emit(NotificationServerEvents.Notification, plainToInstance(NotificationsDto, { + this.eventEmitter.emit(NotificationServerEvents.Notification, plainToClass(NotificationsDto, { notifications, totalUnread, })); diff --git a/redisinsight/api/src/modules/plugin/plugin.service.ts b/redisinsight/api/src/modules/plugin/plugin.service.ts index 11c466bb3b..cca1353cd8 100644 --- a/redisinsight/api/src/modules/plugin/plugin.service.ts +++ b/redisinsight/api/src/modules/plugin/plugin.service.ts @@ -1,5 +1,5 @@ import { Injectable, Logger } from '@nestjs/common'; -import { plainToInstance } from 'class-transformer'; +import { plainToClass } from 'class-transformer'; import { Validator } from 'class-validator'; import { readdirSync, existsSync, readFileSync } from 'fs'; import config, { Config } from 'src/utils/config'; @@ -41,8 +41,8 @@ export class PluginService { readFileSync(path.join(pluginsFolder, pluginFolder, 'package.json'), 'utf8'), ); - // const plugin = plainToInstance(Plugin, manifest, { excludeExtraneousValues: true, strategy: 'exposeAll' }); - const plugin = plainToInstance(Plugin, manifest); + // const plugin = plainToClass(Plugin, manifest, { excludeExtraneousValues: true, strategy: 'exposeAll' }); + const plugin = plainToClass(Plugin, manifest); await this.validator.validateOrReject(plugin, { whitelist: true, }); diff --git a/redisinsight/api/src/modules/rdi/client/api.rdi.client.ts b/redisinsight/api/src/modules/rdi/client/api.rdi.client.ts index 99283097ac..62fb5a0b03 100644 --- a/redisinsight/api/src/modules/rdi/client/api.rdi.client.ts +++ b/redisinsight/api/src/modules/rdi/client/api.rdi.client.ts @@ -1,5 +1,5 @@ import axios, { AxiosInstance } from 'axios'; -import { plainToInstance } from 'class-transformer'; +import { plainToClass } from 'class-transformer'; import { RdiClient } from 'src/modules/rdi/client/rdi.client'; import { @@ -200,7 +200,7 @@ export class ApiRdiClient extends RdiClient { return { status: RdiStatisticsStatus.Success, - data: plainToInstance(RdiStatisticsData, convertKeysToCamelCase(data)), + data: plainToClass(RdiStatisticsData, convertKeysToCamelCase(data)), }; } catch (e) { const message: string = parseErrorMessage(e); diff --git a/redisinsight/api/src/modules/rdi/decorators/request.rdi.client.metadata.decorator.ts b/redisinsight/api/src/modules/rdi/decorators/request.rdi.client.metadata.decorator.ts index 0591e5b200..e4d92f0c47 100644 --- a/redisinsight/api/src/modules/rdi/decorators/request.rdi.client.metadata.decorator.ts +++ b/redisinsight/api/src/modules/rdi/decorators/request.rdi.client.metadata.decorator.ts @@ -1,6 +1,6 @@ import { BadRequestException, createParamDecorator, ExecutionContext } from '@nestjs/common'; import { sessionMetadataFromRequest } from 'src/common/decorators'; -import { plainToInstance } from 'class-transformer'; +import { plainToClass } from 'class-transformer'; import { RdiClientMetadata } from 'src/modules/rdi/models'; import { Validator } from 'class-validator'; import { ApiParam } from '@nestjs/swagger'; @@ -10,7 +10,7 @@ const validator = new Validator(); export const RequestRdiClientMetadata = createParamDecorator((_: unknown, ctx: ExecutionContext) => { const req = ctx.switchToHttp().getRequest(); - const rdiClientMetadata = plainToInstance(RdiClientMetadata, { + const rdiClientMetadata = plainToClass(RdiClientMetadata, { id: req.params?.['id'], sessionMetadata: sessionMetadataFromRequest(req), }); diff --git a/redisinsight/api/src/modules/rdi/utils/pipeline.util.ts b/redisinsight/api/src/modules/rdi/utils/pipeline.util.ts index f637e7576c..5bd339b3bf 100644 --- a/redisinsight/api/src/modules/rdi/utils/pipeline.util.ts +++ b/redisinsight/api/src/modules/rdi/utils/pipeline.util.ts @@ -1,7 +1,7 @@ import { isArray, unset, set, forEach, isObjectLike, isEmpty, } from 'lodash'; -import { plainToInstance } from 'class-transformer'; +import { plainToClass } from 'class-transformer'; import { RdiPipeline } from 'src/modules/rdi/models'; export const convertApiDataToRdiJobs = (jobs?: [Record]): Record => { @@ -41,7 +41,7 @@ export const convertApiDataToRdiPipeline = (data: Record = {}): Rdi // do not show jobs in the config area unset(pipeline, 'config.jobs'); - return plainToInstance(RdiPipeline, pipeline, { excludeExtraneousValues: true }); + return plainToClass(RdiPipeline, pipeline, { excludeExtraneousValues: true }); }; export const convertRdiJobsToApiPayload = (jobs: Record): Record[] => { diff --git a/redisinsight/api/src/modules/session/providers/single-user.session.provider.ts b/redisinsight/api/src/modules/session/providers/single-user.session.provider.ts index 10a46e32fc..9390651a0c 100644 --- a/redisinsight/api/src/modules/session/providers/single-user.session.provider.ts +++ b/redisinsight/api/src/modules/session/providers/single-user.session.provider.ts @@ -2,7 +2,7 @@ import { SessionProvider } from 'src/modules/session/providers/session.provider' import { Session } from 'src/common/models'; import { DEFAULT_SESSION_ID } from 'src/common/constants'; import { Injectable } from '@nestjs/common'; -import { plainToInstance } from 'class-transformer'; +import { plainToClass } from 'class-transformer'; @Injectable() export class SingleUserSessionProvider extends SessionProvider { @@ -11,7 +11,7 @@ export class SingleUserSessionProvider extends SessionProvider { } async createSession(session: Session): Promise { - return this.sessionStorage.createSession(plainToInstance(Session, { + return this.sessionStorage.createSession(plainToClass(Session, { ...session, id: DEFAULT_SESSION_ID, })); diff --git a/redisinsight/api/src/modules/workbench/plugins.service.ts b/redisinsight/api/src/modules/workbench/plugins.service.ts index 8be958f5cb..dda9d1b02b 100644 --- a/redisinsight/api/src/modules/workbench/plugins.service.ts +++ b/redisinsight/api/src/modules/workbench/plugins.service.ts @@ -4,7 +4,7 @@ import { CreateCommandExecutionDto } from 'src/modules/workbench/dto/create-comm import { CommandNotSupportedError } from 'src/modules/cli/constants/errors'; import ERROR_MESSAGES from 'src/constants/error-messages'; import { PluginCommandExecution } from 'src/modules/workbench/models/plugin-command-execution'; -import { plainToInstance } from 'class-transformer'; +import { plainToClass } from 'class-transformer'; import { PluginCommandsWhitelistProvider } from 'src/modules/workbench/providers/plugin-commands-whitelist.provider'; import { CommandExecutionStatus } from 'src/modules/cli/dto/cli.dto'; import { CommandExecutionResult } from 'src/modules/workbench/models/command-execution-result'; @@ -42,7 +42,7 @@ export class PluginsService { const result = await this.commandsExecutor.sendCommand(client, dto); - return plainToInstance(PluginCommandExecution, { + return plainToClass(PluginCommandExecution, { ...dto, databaseId: clientMetadata.databaseId, result, diff --git a/redisinsight/api/src/modules/workbench/repositories/local-command-execution.repository.ts b/redisinsight/api/src/modules/workbench/repositories/local-command-execution.repository.ts index 810bf782cc..be0f4c6e05 100644 --- a/redisinsight/api/src/modules/workbench/repositories/local-command-execution.repository.ts +++ b/redisinsight/api/src/modules/workbench/repositories/local-command-execution.repository.ts @@ -2,7 +2,7 @@ import { Injectable, Logger, NotFoundException } from '@nestjs/common'; import { InjectRepository } from '@nestjs/typeorm'; import { Repository } from 'typeorm'; import { filter, isNull } from 'lodash'; -import { plainToInstance } from 'class-transformer'; +import { plainToClass } from 'class-transformer'; import { EncryptionService } from 'src/modules/encryption/encryption.service'; import { CommandExecutionEntity } from 'src/modules/workbench/entities/command-execution.entity'; import { CommandExecution } from 'src/modules/workbench/models/command-execution'; @@ -41,7 +41,7 @@ export class LocalCommandExecutionRepository extends CommandExecutionRepository async createMany(_: SessionMetadata, commandExecutions: Partial[]): Promise { // todo: limit by 30 max to insert let entities = await Promise.all(commandExecutions.map(async (commandExecution) => { - const entity = plainToInstance(CommandExecutionEntity, commandExecution); + const entity = plainToClass(CommandExecutionEntity, commandExecution); // Do not store command execution result that exceeded limitation if (JSON.stringify(entity.result).length > WORKBENCH_CONFIG.maxResultSize) { diff --git a/redisinsight/api/src/modules/workbench/repositories/local-plugin-state.repository.ts b/redisinsight/api/src/modules/workbench/repositories/local-plugin-state.repository.ts index 7169b6476a..1236806b40 100644 --- a/redisinsight/api/src/modules/workbench/repositories/local-plugin-state.repository.ts +++ b/redisinsight/api/src/modules/workbench/repositories/local-plugin-state.repository.ts @@ -1,7 +1,7 @@ import { Injectable, Logger, NotFoundException } from '@nestjs/common'; import { InjectRepository } from '@nestjs/typeorm'; import { Repository } from 'typeorm'; -import { plainToInstance } from 'class-transformer'; +import { plainToClass } from 'class-transformer'; import { EncryptionService } from 'src/modules/encryption/encryption.service'; import ERROR_MESSAGES from 'src/constants/error-messages'; import { classToClass } from 'src/utils'; @@ -33,7 +33,7 @@ export class LocalPluginStateRepository extends PluginStateRepository { * @param pluginState */ async upsert(_: SessionMetadata, pluginState: Partial): Promise { - const entity = plainToInstance(PluginStateEntity, pluginState); + const entity = plainToClass(PluginStateEntity, pluginState); try { await this.repository.save(await this.modelEncryptor.encryptEntity(entity)); } catch (e) { diff --git a/redisinsight/api/src/utils/class-transformer.ts b/redisinsight/api/src/utils/class-transformer.ts index 45edcda29a..a251a84ae2 100644 --- a/redisinsight/api/src/utils/class-transformer.ts +++ b/redisinsight/api/src/utils/class-transformer.ts @@ -1,8 +1,8 @@ -import { ClassTransformOptions, instanceToPlain, plainToInstance } from 'class-transformer'; -import { ClassConstructor } from 'class-transformer/types/interfaces'; +import { ClassTransformOptions, classToPlain, plainToClass } from 'class-transformer'; +import { ClassType } from 'class-transformer/ClassTransformer'; export function classToClass( - targetClass: ClassConstructor, + targetClass: ClassType, classInstance: V, options?: ClassTransformOptions, ): T { @@ -16,7 +16,7 @@ export function classToClass( ...options, }; - return plainToInstance(targetClass, instanceToPlain(classInstance, transformOptions), transformOptions); + return plainToClass(targetClass, classToPlain(classInstance, transformOptions), transformOptions); } -export const cloneClassInstance = (entity: V): V => classToClass(entity.constructor as ClassConstructor, entity); +export const cloneClassInstance = (entity: V): V => classToClass(entity.constructor as ClassType, entity); diff --git a/redisinsight/api/yarn.lock b/redisinsight/api/yarn.lock index 3293458ef0..68ce2a7280 100644 --- a/redisinsight/api/yarn.lock +++ b/redisinsight/api/yarn.lock @@ -2745,10 +2745,10 @@ cjs-module-lexer@^1.0.0: resolved "https://registry.yarnpkg.com/cjs-module-lexer/-/cjs-module-lexer-1.4.1.tgz#707413784dbb3a72aa11c2f2b042a0bef4004170" integrity sha512-cuSVIHi9/9E/+821Qjdvngor+xpnlwnuwIyZOaLmHBVdXL+gP+I6QQB9VkO7RI77YIcTV+S1W9AreJ5eN63JBA== -class-transformer@^0.5.1: - version "0.5.1" - resolved "https://registry.yarnpkg.com/class-transformer/-/class-transformer-0.5.1.tgz#24147d5dffd2a6cea930a3250a677addf96ab336" - integrity sha512-SQa1Ws6hUbfC98vKGxZH3KFY0Y1lm5Zm0SY8XX9zbK7FJCyVEac3ATW0RIpwzW+oOfmHE5PMPufDG9hCfoEOMw== +class-transformer@^0.3.1: + version "0.3.1" + resolved "https://registry.yarnpkg.com/class-transformer/-/class-transformer-0.3.1.tgz#ee681a5439ff2230fc57f5056412d3befa70d597" + integrity sha512-cKFwohpJbuMovS8xVLmn8N2AUbAuc8pVo4zEfsUVo8qgECOogns1WVk/FkOZoxhOPTyTYFckuoH+13FO+MQ8GA== class-validator@^0.14.1: version "0.14.1" From 06bb4dd95c4cd9e01aed2ff0ff47a965503a9c36 Mon Sep 17 00:00:00 2001 From: ArtemHoruzhenko Date: Fri, 18 Oct 2024 12:23:14 +0300 Subject: [PATCH 223/256] upgrade nestjs + okta packages. cleanup resolutions --- redisinsight/api/package.json | 21 +++--- redisinsight/api/yarn.lock | 134 +++++++++++++++++++--------------- 2 files changed, 86 insertions(+), 69 deletions(-) diff --git a/redisinsight/api/package.json b/redisinsight/api/package.json index e174e55f48..f8aef5bf0c 100644 --- a/redisinsight/api/package.json +++ b/redisinsight/api/package.json @@ -43,27 +43,24 @@ "nanoid": "^3.1.31", "word-wrap": "1.2.4", "jest/**/micromatch": "^4.0.8", - "ts-loader/micromatch": "^4.0.8", "mocha/minimatch": "^3.0.5", "@nestjs/serve-static/path-to-regexp": "^1.9.0", - "@nestjs/platform-express/express": "^4.21.1", "@nestjs/platform-socket.io/socket.io": "^4.8.0", "@nestjs/cli/**/braces": "^3.0.3", - "@okta/okta-auth-js/**/jsonpath-plus": "^10.0.0", "**/semver": "^7.5.2", "winston-daily-rotate-file/**/file-stream-rotator": "^1.0.0" }, "dependencies": { - "@nestjs/common": "^10.4.4", - "@nestjs/core": "^10.4.4", + "@nestjs/common": "^10.4.5", + "@nestjs/core": "^10.4.5", "@nestjs/event-emitter": "^2.0.4", - "@nestjs/platform-express": "^10.4.4", - "@nestjs/platform-socket.io": "^10.4.4", + "@nestjs/platform-express": "^10.4.5", + "@nestjs/platform-socket.io": "^10.4.5", "@nestjs/serve-static": "^4.0.2", "@nestjs/swagger": "^7.4.2", "@nestjs/typeorm": "^10.0.2", - "@nestjs/websockets": "^10.4.4", - "@okta/okta-auth-js": "^7.8.0", + "@nestjs/websockets": "^10.4.5", + "@okta/okta-auth-js": "^7.8.1", "@segment/analytics-node": "^2.1.3", "adm-zip": "^0.5.9", "axios": "^1.7.4", @@ -84,7 +81,7 @@ "keytar": "^7.9.0", "lodash": "^4.17.20", "nest-winston": "^1.9.7", - "nestjs-form-data": "^1.9.91", + "nestjs-form-data": "^1.8.7", "node-version-compare": "^1.0.3", "quicktype-core": "^23.0.116", "redis": "^4.6.10", @@ -104,8 +101,8 @@ "devDependencies": { "@mochajs/json-file-reporter": "^1.3.0", "@nestjs/cli": "^10.4.5", - "@nestjs/schematics": "^10.1.4", - "@nestjs/testing": "^10.4.4", + "@nestjs/schematics": "^10.2.2", + "@nestjs/testing": "^10.4.5", "@types/adm-zip": "^0.5.0", "@types/express": "^4.17.3", "@types/jest": "^26.0.15", diff --git a/redisinsight/api/yarn.lock b/redisinsight/api/yarn.lock index 68ce2a7280..e015d8450c 100644 --- a/redisinsight/api/yarn.lock +++ b/redisinsight/api/yarn.lock @@ -10,6 +10,18 @@ "@jridgewell/gen-mapping" "^0.3.0" "@jridgewell/trace-mapping" "^0.3.9" +"@angular-devkit/core@17.3.10": + version "17.3.10" + resolved "https://registry.yarnpkg.com/@angular-devkit/core/-/core-17.3.10.tgz#c259052a891ad0bd1a7708d1081571683b3fa814" + integrity sha512-czdl54yxU5DOAGy/uUPNjJruoBDTgwi/V+eOgLNybYhgrc+TsY0f7uJ11yEk/pz5sCov7xIiS7RdRv96waS7vg== + dependencies: + ajv "8.12.0" + ajv-formats "2.1.1" + jsonc-parser "3.2.1" + picomatch "4.0.1" + rxjs "7.8.1" + source-map "0.7.4" + "@angular-devkit/core@17.3.8": version "17.3.8" resolved "https://registry.yarnpkg.com/@angular-devkit/core/-/core-17.3.8.tgz#8679cacf84cf79764f027811020e235ab32016d2" @@ -34,6 +46,17 @@ symbol-observable "4.0.0" yargs-parser "21.1.1" +"@angular-devkit/schematics@17.3.10": + version "17.3.10" + resolved "https://registry.yarnpkg.com/@angular-devkit/schematics/-/schematics-17.3.10.tgz#a3d62b33f82fd1fa51246d00ada92efe82a00ae7" + integrity sha512-FHcNa1ktYRd0SKExCsNJpR75RffsyuPIV8kvBXzXnLHmXMqvl25G2te3yYJ9yYqy9OLy/58HZznZTxWRyUdHOg== + dependencies: + "@angular-devkit/core" "17.3.10" + jsonc-parser "3.2.1" + magic-string "0.30.8" + ora "5.4.1" + rxjs "7.8.1" + "@angular-devkit/schematics@17.3.8": version "17.3.8" resolved "https://registry.yarnpkg.com/@angular-devkit/schematics/-/schematics-17.3.8.tgz#f853eb21682aadfb6667e090b5b509fc95ce8442" @@ -1049,16 +1072,6 @@ "@jridgewell/resolve-uri" "3.1.0" "@jridgewell/sourcemap-codec" "1.4.14" -"@jsep-plugin/assignment@^1.2.1": - version "1.2.1" - resolved "https://registry.yarnpkg.com/@jsep-plugin/assignment/-/assignment-1.2.1.tgz#07277bdd7862451a865d391e2142efba33f46c9b" - integrity sha512-gaHqbubTi29aZpVbBlECRpmdia+L5/lh2BwtIJTmtxdbecEyyX/ejAOg7eQDGNvGOUmPY7Z2Yxdy9ioyH/VJeA== - -"@jsep-plugin/regex@^1.0.3": - version "1.0.3" - resolved "https://registry.yarnpkg.com/@jsep-plugin/regex/-/regex-1.0.3.tgz#3aeaa2e5fa45d89de116aeafbfa41c95935b7f6d" - integrity sha512-XfZgry4DwEZvSFtS/6Y+R48D7qJYJK6R9/yJFyUFHCIUMEEHuJ4X95TDgJp5QkmzfLYvapMPzskV5HpIDrREug== - "@ljharb/through@^2.3.12": version "2.3.13" resolved "https://registry.yarnpkg.com/@ljharb/through/-/through-2.3.13.tgz#b7e4766e0b65aa82e529be945ab078de79874edc" @@ -1113,19 +1126,19 @@ webpack "5.94.0" webpack-node-externals "3.0.0" -"@nestjs/common@^10.4.4": - version "10.4.4" - resolved "https://registry.yarnpkg.com/@nestjs/common/-/common-10.4.4.tgz#673d0eca273e1ab3a4d3ec9e212114b9f4fbf6e8" - integrity sha512-0j2/zqRw9nvHV1GKTktER8B/hIC/Z8CYFjN/ZqUuvwayCH+jZZBhCR2oRyuvLTXdnlSmtCAg2xvQ0ULqQvzqhA== +"@nestjs/common@^10.4.5": + version "10.4.5" + resolved "https://registry.yarnpkg.com/@nestjs/common/-/common-10.4.5.tgz#00853da6ea7794743641aa0c098f23dc7480fc4f" + integrity sha512-N/yUyuYCBMb0+H6jHhntR7PURzji0usID/DByhOfooyk/aPGscI0aQKwOA6edlJlT92hHUvXYLJ5p3npj7KcjQ== dependencies: uid "2.0.2" iterare "1.2.1" tslib "2.7.0" -"@nestjs/core@^10.4.4": - version "10.4.4" - resolved "https://registry.yarnpkg.com/@nestjs/core/-/core-10.4.4.tgz#12cb1110da6d76e12ceccf0e92f6f5220fe27525" - integrity sha512-y9tjmAzU6LTh1cC/lWrRsCcOd80khSR0qAHAqwY2svbW+AhsR/XCzgpZrAAKJrm/dDfjLCZKyxJSayeirGcW5Q== +"@nestjs/core@^10.4.5": + version "10.4.5" + resolved "https://registry.yarnpkg.com/@nestjs/core/-/core-10.4.5.tgz#448ebfb315363fadc920b111acd99c702768d344" + integrity sha512-wk0KJ+6tuidqAdeemsQ40BCp1BgMsSuSLG577aqXLxXYoa8FQYPrdxoSzd05znYLwJYM55fisZWb3FLF9HT2qw== dependencies: uid "2.0.2" "@nuxtjs/opencollective" "0.3.2" @@ -1146,26 +1159,26 @@ resolved "https://registry.yarnpkg.com/@nestjs/mapped-types/-/mapped-types-2.0.5.tgz#485d6b44e19779c98d04e52bd1d2bcc7001df0ea" integrity sha512-bSJv4pd6EY99NX9CjBIyn4TVDoSit82DUZlL4I3bqNfy5Gt+gXTa86i3I/i0iIV9P4hntcGM5GyO+FhZAhxtyg== -"@nestjs/platform-express@^10.4.4": - version "10.4.4" - resolved "https://registry.yarnpkg.com/@nestjs/platform-express/-/platform-express-10.4.4.tgz#582d375272207f8d1528f77ff470ba815d9d9846" - integrity sha512-y52q1MxhbHaT3vAgWd08RgiYon0lJgtTa8U6g6gV0KI0IygwZhDQFJVxnrRDUdxQGIP5CKHmfQu3sk9gTNFoEA== +"@nestjs/platform-express@^10.4.5": + version "10.4.5" + resolved "https://registry.yarnpkg.com/@nestjs/platform-express/-/platform-express-10.4.5.tgz#bd58c8220712c7c1df0466aa20aa389d66d4e1e7" + integrity sha512-a629r8R8KC4skhdieQ0aIWH5vDBUFntWnWKFyDXQrll6/CllSchfWm87mWF39seaW6bXYtQtAEZY66JrngdrGA== dependencies: body-parser "1.20.3" cors "2.8.5" - express "4.21.0" + express "4.21.1" multer "1.4.4-lts.1" tslib "2.7.0" -"@nestjs/platform-socket.io@^10.4.4": - version "10.4.4" - resolved "https://registry.yarnpkg.com/@nestjs/platform-socket.io/-/platform-socket.io-10.4.4.tgz#ee505767102ab85890fdc3a7b0a7407f4b8b59a9" - integrity sha512-5GEYUA3sNbX2jOBP6FmrIK/zv9VCdvpdr4Sef1OKvt1U0qsV1YgmWPWDPumZM77n5DI0VHSJPyo7yjZaEKWOiQ== +"@nestjs/platform-socket.io@^10.4.5": + version "10.4.5" + resolved "https://registry.yarnpkg.com/@nestjs/platform-socket.io/-/platform-socket.io-10.4.5.tgz#be403766fcfb6c441a30d3e3bdb1771bc9daf66d" + integrity sha512-dHkHJQArhrpkX6qBdTW2ghuja3i3cCslwy4QHY6d46u+9UyANQlsNK9wt/lZnmXfCMaci8xAJvUpyODa6YtV7g== dependencies: socket.io "4.7.5" tslib "2.7.0" -"@nestjs/schematics@^10.0.1", "@nestjs/schematics@^10.1.4": +"@nestjs/schematics@^10.0.1": version "10.1.4" resolved "https://registry.yarnpkg.com/@nestjs/schematics/-/schematics-10.1.4.tgz#e445b856eefce9bd338c5fc1cf2c95f0985849cf" integrity sha512-QpY8ez9cTvXXPr3/KBrtSgXQHMSV6BkOUYy2c2TTe6cBqriEdGnCYqGl8cnfrQl3632q3lveQPaZ/c127dHsEw== @@ -1176,6 +1189,17 @@ jsonc-parser "3.3.1" pluralize "8.0.0" +"@nestjs/schematics@^10.2.2": + version "10.2.2" + resolved "https://registry.yarnpkg.com/@nestjs/schematics/-/schematics-10.2.2.tgz#917a9c1cbaff54003827ec10abb1a83e6f8c5799" + integrity sha512-D4pJ46E8llCA7WPr3cV6sfRqDlvnTjQWnF1fLyKYD3Ldl+KPtlLyIcxaqlLTB0YR9ItKNKIZTJzUehRxR7UUsQ== + dependencies: + "@angular-devkit/core" "17.3.10" + "@angular-devkit/schematics" "17.3.10" + comment-json "4.2.5" + jsonc-parser "3.3.1" + pluralize "8.0.0" + "@nestjs/serve-static@^4.0.2": version "4.0.2" resolved "https://registry.yarnpkg.com/@nestjs/serve-static/-/serve-static-4.0.2.tgz#f003bbd90922bdc73d0261edacf001dfef174c96" @@ -1195,10 +1219,10 @@ path-to-regexp "3.3.0" swagger-ui-dist "5.17.14" -"@nestjs/testing@^10.4.4": - version "10.4.4" - resolved "https://registry.yarnpkg.com/@nestjs/testing/-/testing-10.4.4.tgz#1f73f4b6c8d7a996a267ec498679e53763936963" - integrity sha512-qRGFj51A5RM7JqA8pcyEwSLA3Y0dle/PAZ8oxP0suimoCusRY3Tk7wYqutZdCNj1ATb678SDaUZDHk2pwSv9/g== +"@nestjs/testing@^10.4.5": + version "10.4.5" + resolved "https://registry.yarnpkg.com/@nestjs/testing/-/testing-10.4.5.tgz#18f9a7524ca5c487d7af995912b26db8e2051d0c" + integrity sha512-3NhmztE+fK3MuuOZhXihvMIhxm0QuDM2BneHvM5A0oVLG+STsAeGBqbDr/Ef2qsvqH5HaqvfGbVJ4N1DQnZE5A== dependencies: tslib "2.7.0" @@ -1209,10 +1233,10 @@ dependencies: uuid "9.0.1" -"@nestjs/websockets@^10.4.4": - version "10.4.4" - resolved "https://registry.yarnpkg.com/@nestjs/websockets/-/websockets-10.4.4.tgz#34a758bbe7ef7e61168682dc964cb14f95dc7898" - integrity sha512-ZHnak04i/iKBS0csjJa7K6D6xdsB0Yz6duJuCR7xGLItchFK+Ne21m9rEF8ffvW74U7UAYkQHBgD5242LBBYiQ== +"@nestjs/websockets@^10.4.5": + version "10.4.5" + resolved "https://registry.yarnpkg.com/@nestjs/websockets/-/websockets-10.4.5.tgz#626f2a9d45909e5c2ffca8f0fcbdd9ce59cd5f45" + integrity sha512-LbL/HRLWQUBTUPY7swojOHdvokyVGINIiuP/VmRdhob4T751r+9i09z2RqRpP71psuom9mnRHYI1+vT2FABrAw== dependencies: iterare "1.2.1" object-hash "3.0.0" @@ -1264,10 +1288,10 @@ consola "^2.15.0" node-fetch "^2.6.1" -"@okta/okta-auth-js@^7.8.0": - version "7.8.0" - resolved "https://registry.yarnpkg.com/@okta/okta-auth-js/-/okta-auth-js-7.8.0.tgz#1ab69c47cbf6fd7f3ce9f6caed2e05685f5bb22d" - integrity sha512-yFjv0wD9T5GYcFg6zzQ0M/WGdq2IMoaI/SK/0s9AqazZ6ILv6eyZq47L2nJJ7xld5DBFUhVewnD6BS3Ee7Im1A== +"@okta/okta-auth-js@^7.8.1": + version "7.8.1" + resolved "https://registry.yarnpkg.com/@okta/okta-auth-js/-/okta-auth-js-7.8.1.tgz#eb36ac8deb0290f59917ede239fae82d76cc2ab8" + integrity sha512-vrsh1QK2NxZQgOQHqIX33ykTsf+X3zcHIzdNjbPbxp1YvTZeyd9oNlcLh1cgp4m0xA/NXoj5xM4no6j3SFtnUw== dependencies: "@babel/runtime" "^7.12.5" "@peculiar/webcrypto" "^1.4.0" @@ -1279,7 +1303,6 @@ cross-fetch "^3.1.5" fast-text-encoding "^1.0.6" js-cookie "^3.0.1" - jsonpath-plus "^6.0.1" node-cache "^5.1.2" p-cancelable "^2.0.0" tiny-emitter "1.1.0" @@ -2954,6 +2977,17 @@ comment-json@4.2.3: has-own-prop "^2.0.0" repeat-string "^1.6.1" +comment-json@4.2.5: + version "4.2.5" + resolved "https://registry.yarnpkg.com/comment-json/-/comment-json-4.2.5.tgz#482e085f759c2704b60bc6f97f55b8c01bc41e70" + integrity sha512-bKw/r35jR3HGt5PEPm1ljsQQGyCrR8sFGNiN5L+ykDHdpO8Smxkrkla9Yi6NkQyUrb8V54PGhfMs6NrIwtxtdw== + dependencies: + array-timsort "^1.0.3" + core-util-is "^1.0.3" + esprima "^4.0.1" + has-own-prop "^2.0.0" + repeat-string "^1.6.1" + commondir@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/commondir/-/commondir-1.0.1.tgz#ddd800da0c66127393cca5950ea968a3aaf1253b" @@ -3967,7 +4001,7 @@ expect@^29.7.0: jest-message-util "^29.7.0" jest-util "^29.7.0" -express@4.21.0, express@^4.21.1: +express@4.21.1, express@^4.21.1: version "4.21.1" resolved "https://registry.yarnpkg.com/express/-/express-4.21.1.tgz#9dae5dda832f16b4eec941a4e44aa89ec481b281" integrity sha512-YSFlK1Ee0/GC8QaO91tHcDxJiE/X4FbpAyQWkxAvG6AXCuR65YzK8ua6D9hvi/TzUfZMpc+BwuM1IPw8fmQBiQ== @@ -5642,11 +5676,6 @@ jsbn@1.1.0: resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-1.1.0.tgz#b01307cb29b618a1ed26ec79e911f803c4da0040" integrity sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A== -jsep@^1.3.9: - version "1.3.9" - resolved "https://registry.yarnpkg.com/jsep/-/jsep-1.3.9.tgz#8ce42df80ee9c1b39e52d0dd062a465342f35440" - integrity sha512-i1rBX5N7VPl0eYb6+mHNp52sEuaS2Wi8CDYx1X5sn9naevL78+265XJqy1qENEk7mRKwS06NHpUqiBwR7qeodw== - jsesc@^2.5.1: version "2.5.2" resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4" @@ -5718,15 +5747,6 @@ jsonfile@^6.0.1: optionalDependencies: graceful-fs "^4.1.6" -jsonpath-plus@^10.0.0, jsonpath-plus@^6.0.1: - version "10.0.0" - resolved "https://registry.yarnpkg.com/jsonpath-plus/-/jsonpath-plus-10.0.0.tgz#7a747d47e20a27867dbbc80b57fd554788b91474" - integrity sha512-v7j76HGp/ibKlXYeZ7UrfCLSNDaBWuJMA0GaMjA4sZJtCtY89qgPyToDDcl2zdeHh4B5q/B3g2pQdW76fOg/dA== - dependencies: - "@jsep-plugin/assignment" "^1.2.1" - "@jsep-plugin/regex" "^1.0.3" - jsep "^1.3.9" - jsonwebtoken@^9.0.2: version "9.0.2" resolved "https://registry.yarnpkg.com/jsonwebtoken/-/jsonwebtoken-9.0.2.tgz#65ff91f4abef1784697d40952bb1998c504caaf3" @@ -6350,7 +6370,7 @@ nest-winston@^1.9.7: dependencies: fast-safe-stringify "^2.1.1" -nestjs-form-data@^1.9.91: +nestjs-form-data@^1.8.7: version "1.9.91" resolved "https://registry.yarnpkg.com/nestjs-form-data/-/nestjs-form-data-1.9.91.tgz#379812fb9b920cb505b50960433be38bc9bda72f" integrity sha512-g9PDq97UjOoDFjYnhtc/N5HIwTWiyp1DDA9iYs8suSXZK7Z17UE+Hw8HsKH9l2TXlUGUY/BrvaiACFZ472CXuw== From 4897a1b67199609f896054491e73dc56220517a5 Mon Sep 17 00:00:00 2001 From: ArtemHoruzhenko Date: Fri, 18 Oct 2024 12:59:58 +0300 Subject: [PATCH 224/256] degrade nest-form-data --- redisinsight/api/package.json | 2 +- redisinsight/api/yarn.lock | 9 +++++---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/redisinsight/api/package.json b/redisinsight/api/package.json index f8aef5bf0c..91933ab7f7 100644 --- a/redisinsight/api/package.json +++ b/redisinsight/api/package.json @@ -81,7 +81,7 @@ "keytar": "^7.9.0", "lodash": "^4.17.20", "nest-winston": "^1.9.7", - "nestjs-form-data": "^1.8.7", + "nestjs-form-data": "~1.8.7", "node-version-compare": "^1.0.3", "quicktype-core": "^23.0.116", "redis": "^4.6.10", diff --git a/redisinsight/api/yarn.lock b/redisinsight/api/yarn.lock index e015d8450c..548556ca5f 100644 --- a/redisinsight/api/yarn.lock +++ b/redisinsight/api/yarn.lock @@ -6370,12 +6370,13 @@ nest-winston@^1.9.7: dependencies: fast-safe-stringify "^2.1.1" -nestjs-form-data@^1.8.7: - version "1.9.91" - resolved "https://registry.yarnpkg.com/nestjs-form-data/-/nestjs-form-data-1.9.91.tgz#379812fb9b920cb505b50960433be38bc9bda72f" - integrity sha512-g9PDq97UjOoDFjYnhtc/N5HIwTWiyp1DDA9iYs8suSXZK7Z17UE+Hw8HsKH9l2TXlUGUY/BrvaiACFZ472CXuw== +nestjs-form-data@~1.8.7: + version "1.8.7" + resolved "https://registry.yarnpkg.com/nestjs-form-data/-/nestjs-form-data-1.8.7.tgz#ccdbc2060849e34018841bfba557de37ae64abdb" + integrity sha512-mk17APNXELILClea2nwffRrD/NK5Q6zulTJCzNPxwMWfWucHO2HD7Ftjwg2BVnwO27QgqILDLuaO6LEpP6Ng4w== dependencies: uid "^2.0.0" + append-field "^1.0.0" busboy "^1.6.0" concat-stream "^2.0.0" file-type "^16.5.4" From 059952b57d340985987f4f8946fb87b765d957d3 Mon Sep 17 00:00:00 2001 From: zalenskiSofteq Date: Fri, 18 Oct 2024 12:45:39 +0200 Subject: [PATCH 225/256] #RI-6213 - Migrate release workflows from CircleCI to Github Actions --- .github/actions/install-deps/action.yml | 6 +++--- .github/workflows/aws.yml | 5 +++++ 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/.github/actions/install-deps/action.yml b/.github/actions/install-deps/action.yml index 8a5433605c..62c3fa5ab4 100644 --- a/.github/actions/install-deps/action.yml +++ b/.github/actions/install-deps/action.yml @@ -26,8 +26,8 @@ runs: # SKIP_POSTINSTALL: ${{ inputs.skip-postinstall }} # run: yarn install run: | - export npm_config_keytar_binary_host_mirror=${{ inputs.keytar-host-mirror }} - export npm_config_node_sqlite3_binary_host_mirror=${{ inputs.sqlite3-host-mirror }} + # todo: uncomment after build our binaries + # export npm_config_keytar_binary_host_mirror=${{ inputs.keytar-host-mirror }} + # export npm_config_node_sqlite3_binary_host_mirror=${{ inputs.sqlite3-host-mirror }} yarn install - echo $SKIP_POSTINSTALL diff --git a/.github/workflows/aws.yml b/.github/workflows/aws.yml index 3c42527061..1bd9fea0a7 100644 --- a/.github/workflows/aws.yml +++ b/.github/workflows/aws.yml @@ -87,6 +87,11 @@ jobs: - name: Publish AWS S3 run: | + + # check if sub directories exists + if [[ -z "${!downloadLatestFolderPath}" || -z "${!upgradeLatestFolderPath}" ]]; then + exit 1; + fi # remove previous build from the latest directory /public/latest aws s3 rm s3://${AWS_BUCKET_NAME}/${downloadLatestFolderPath} --recursive From 3a34ad75d2cf8232c468bbb5058788db760468a6 Mon Sep 17 00:00:00 2001 From: zalenskiSofteq Date: Fri, 18 Oct 2024 14:24:19 +0200 Subject: [PATCH 226/256] test --- .github/workflows/aws.yml | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/.github/workflows/aws.yml b/.github/workflows/aws.yml index 1bd9fea0a7..4ceab7c9c3 100644 --- a/.github/workflows/aws.yml +++ b/.github/workflows/aws.yml @@ -4,9 +4,7 @@ on: workflow_call: env: - # todo: check - # AWS_BUCKET_NAME: ${{ secrets.AWS_BUCKET_NAME }} - AWS_BUCKET_NAME: ${{ secrets.AWS_BUCKET_NAME_TEST }} + AWS_BUCKET_NAME: ${{ secrets.AWS_BUCKET_NAME }} AWS_DISTRIBUTION_ID: ${{ secrets.AWS_DISTRIBUTION_ID }} AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} @@ -89,7 +87,7 @@ jobs: run: | # check if sub directories exists - if [[ -z "${!downloadLatestFolderPath}" || -z "${!upgradeLatestFolderPath}" ]]; then + if [[ -z "$downloadLatestFolderPath" || -z "$upgradeLatestFolderPath" ]]; then exit 1; fi # remove previous build from the latest directory /public/latest From 3656441547660a911f06d3c01bbd340cd3cbc70e Mon Sep 17 00:00:00 2001 From: zalenskiSofteq Date: Fri, 18 Oct 2024 18:02:57 +0200 Subject: [PATCH 227/256] #RI-6213 - Migrate release workflows from CircleCI to Github Actions --- .github/actions/install-all-build-libs/action.yml | 5 ----- .github/virustotal-report.js | 4 +--- .github/workflows/nightly.yml | 9 --------- .github/workflows/release-prod.yml | 2 -- .github/workflows/release-stage.yml | 2 -- 5 files changed, 1 insertion(+), 21 deletions(-) delete mode 100644 .github/workflows/nightly.yml diff --git a/.github/actions/install-all-build-libs/action.yml b/.github/actions/install-all-build-libs/action.yml index 8a7ef7d581..058f360f67 100644 --- a/.github/actions/install-all-build-libs/action.yml +++ b/.github/actions/install-all-build-libs/action.yml @@ -39,11 +39,6 @@ runs: cache: ${{ runner.os != 'Windows' && 'yarn' || '' }} cache-dependency-path: ${{ runner.os != 'Windows' && '**/yarn.lock' || '' }} - # - run: echo "inputs.skip-electron-deps" - # - run: echo "${{inputs.skip-electron-deps}}" - # - run: echo "inputs.skip-backend-deps" - # - run: echo "${{inputs.skip-backend-deps}}" - - name: Setup Python # if: ${{ contains(inputs.skip-electron-deps, '1') }} uses: actions/setup-python@v5 diff --git a/.github/virustotal-report.js b/.github/virustotal-report.js index 333cad83f1..f1f1c455eb 100644 --- a/.github/virustotal-report.js +++ b/.github/virustotal-report.js @@ -36,10 +36,8 @@ if (failed === true) { results.message.text = ' ' + results.message.text; } -console.log({'results.message': results.message}); - fs.writeFileSync(fileName, JSON.stringify({ - // channel: process.env.SLACK_VIRUSTOTAL_REPORT_CHANNEL, + channel: process.env.SLACK_VIRUSTOTAL_REPORT_CHANNEL, ...results.message, })); diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml deleted file mode 100644 index 56833098ad..0000000000 --- a/.github/workflows/nightly.yml +++ /dev/null @@ -1,9 +0,0 @@ -name: Nightly jobs -on: - schedule: - - cron: '0 0 * * *' - -jobs: - virustotal-check: - uses: ./.github/workflows/virustotal.yml - secrets: inherit diff --git a/.github/workflows/release-prod.yml b/.github/workflows/release-prod.yml index 76ad3bc286..bb24782ff6 100644 --- a/.github/workflows/release-prod.yml +++ b/.github/workflows/release-prod.yml @@ -4,8 +4,6 @@ on: push: branches: - 'latest' - # todo: remove after test - - 'test/prod/**' jobs: tests-prod: diff --git a/.github/workflows/release-stage.yml b/.github/workflows/release-stage.yml index 9028fa5459..d163c5e192 100644 --- a/.github/workflows/release-stage.yml +++ b/.github/workflows/release-stage.yml @@ -4,8 +4,6 @@ on: push: branches: - 'release/**' - # todo: remove after tests - - 'test/release/**' jobs: tests: From cc187ec01b6569b8bf350382bcfbcca5a1f5bd37 Mon Sep 17 00:00:00 2001 From: kchepikava Date: Mon, 21 Oct 2024 08:47:45 +0200 Subject: [PATCH 228/256] RI-6220 removed rdi pipeline template --- .../template-button/TemplateButton.spec.tsx | 73 +++++++++++++++++++ .../template-button/TemplateButton.tsx | 66 +++++++++++++++++ .../components/template-button/index.ts | 3 + .../template-button/styles.module.scss | 12 +++ .../template-form/TemplateForm.spec.tsx | 4 - .../components/template-form/TemplateForm.tsx | 6 +- .../rdi/pipeline-management/pages/job/Job.tsx | 23 +++--- .../pages/job/styles.module.scss | 6 ++ 8 files changed, 173 insertions(+), 20 deletions(-) create mode 100644 redisinsight/ui/src/pages/rdi/pipeline-management/components/template-button/TemplateButton.spec.tsx create mode 100644 redisinsight/ui/src/pages/rdi/pipeline-management/components/template-button/TemplateButton.tsx create mode 100644 redisinsight/ui/src/pages/rdi/pipeline-management/components/template-button/index.ts create mode 100644 redisinsight/ui/src/pages/rdi/pipeline-management/components/template-button/styles.module.scss diff --git a/redisinsight/ui/src/pages/rdi/pipeline-management/components/template-button/TemplateButton.spec.tsx b/redisinsight/ui/src/pages/rdi/pipeline-management/components/template-button/TemplateButton.spec.tsx new file mode 100644 index 0000000000..1cac9b94a0 --- /dev/null +++ b/redisinsight/ui/src/pages/rdi/pipeline-management/components/template-button/TemplateButton.spec.tsx @@ -0,0 +1,73 @@ +import React from 'react' +import { cloneDeep } from 'lodash' +import { instance, mock } from 'ts-mockito' + +import { fireEvent, render, cleanup, mockedStore, screen } from 'uiSrc/utils/test-utils' +import { TelemetryEvent, sendEventTelemetry } from 'uiSrc/telemetry' +import { RdiPipelineTabs } from 'uiSrc/slices/interfaces' +import { rdiPipelineStrategiesSelector } from 'uiSrc/slices/rdi/pipeline' +import TemplateButton, { TemplateButtonProps } from './TemplateButton' + +const mockedProps = mock() + +let store: typeof mockedStore +beforeEach(() => { + cleanup() + store = cloneDeep(mockedStore) + store.clearActions() +}) + +jest.mock('uiSrc/telemetry', () => ({ + ...jest.requireActual('uiSrc/telemetry'), + sendPageViewTelemetry: jest.fn(), + sendEventTelemetry: jest.fn(), +})) + +jest.mock('uiSrc/slices/rdi/pipeline', () => ({ + ...jest.requireActual('uiSrc/slices/rdi/pipeline'), + rdiPipelineStrategiesSelector: jest.fn().mockReturnValue({ + loading: false, + data: [{ + strategy: 'test' + }], + }), +})) + +describe('TemplateForm', () => { + it('should render', () => { + expect( + render() + ).toBeTruthy() + }) + + it('should be disabled if no templateOption', () => { + (rdiPipelineStrategiesSelector as jest.Mock).mockImplementationOnce(() => ({ + loading: false, + data: [] + })) + + render() + + expect(screen.getByTestId('template-btn')).toBeDisabled() + }) + + it('should send telemetry on Click', () => { + const sendEventTelemetryMock = jest.fn(); + (sendEventTelemetry as jest.Mock).mockImplementation(() => sendEventTelemetryMock) + + render() + + expect(screen.getByTestId('template-btn')).toBeEnabled() + + fireEvent.click(screen.getByTestId('template-btn')) + + expect(sendEventTelemetry).toBeCalledWith({ + event: TelemetryEvent.RDI_TEMPLATE_CLICKED, + eventData: { + id: 'rdiInstanceId', + page: RdiPipelineTabs.Jobs, + mode: 'test', + } + }) + }) +}) diff --git a/redisinsight/ui/src/pages/rdi/pipeline-management/components/template-button/TemplateButton.tsx b/redisinsight/ui/src/pages/rdi/pipeline-management/components/template-button/TemplateButton.tsx new file mode 100644 index 0000000000..875e567ff4 --- /dev/null +++ b/redisinsight/ui/src/pages/rdi/pipeline-management/components/template-button/TemplateButton.tsx @@ -0,0 +1,66 @@ +import React from 'react' +import { useDispatch, useSelector } from 'react-redux' +import { EuiButton, EuiToolTip } from '@elastic/eui' + +import { useParams } from 'react-router-dom' +import { sendEventTelemetry, TelemetryEvent } from 'uiSrc/telemetry' +import { fetchJobTemplate, rdiPipelineStrategiesSelector } from 'uiSrc/slices/rdi/pipeline' +import { RdiPipelineTabs } from 'uiSrc/slices/interfaces' +import { getTooltipContent } from '../template-form/TemplateForm' +import { INGEST_OPTION } from '../template-form/constants' +import styles from './styles.module.scss' + +export interface TemplateButtonProps { + value: string + setFieldValue: (template: string) => void +} + +const TemplateButton = ({ setFieldValue, value }: TemplateButtonProps) => { + const dispatch = useDispatch() + const { rdiInstanceId } = useParams<{ rdiInstanceId: string }>() + const { loading, data } = useSelector(rdiPipelineStrategiesSelector) + + const templateOption = data?.length + ? (data.find((strategy) => strategy.strategy === INGEST_OPTION)?.strategy || data[0].strategy) + : '' + + const handleApply = () => { + dispatch(fetchJobTemplate(rdiInstanceId, templateOption, (template: string) => { + setFieldValue(template) + })) + sendEventTelemetry({ + event: TelemetryEvent.RDI_TEMPLATE_CLICKED, + eventData: { + id: rdiInstanceId, + page: RdiPipelineTabs.Jobs, + mode: templateOption, + } + }) + } + + return ( + + + Insert template + + + ) +} + +export default TemplateButton diff --git a/redisinsight/ui/src/pages/rdi/pipeline-management/components/template-button/index.ts b/redisinsight/ui/src/pages/rdi/pipeline-management/components/template-button/index.ts new file mode 100644 index 0000000000..423ff2d2ed --- /dev/null +++ b/redisinsight/ui/src/pages/rdi/pipeline-management/components/template-button/index.ts @@ -0,0 +1,3 @@ +import TemplateButton from './TemplateButton' + +export default TemplateButton diff --git a/redisinsight/ui/src/pages/rdi/pipeline-management/components/template-button/styles.module.scss b/redisinsight/ui/src/pages/rdi/pipeline-management/components/template-button/styles.module.scss new file mode 100644 index 0000000000..3528eedf46 --- /dev/null +++ b/redisinsight/ui/src/pages/rdi/pipeline-management/components/template-button/styles.module.scss @@ -0,0 +1,12 @@ +.btn { + display: flex; + align-items: center; + color: var(--recommendationsCountBgColor) !important; + background-color: var(--tableRowSelectedColor) !important; + border-radius: 4px; + border-color: var(--tableRowSelectedColor) !important; + + > span { + color: var(--recommendationsCountBgColor) !important; + } +} diff --git a/redisinsight/ui/src/pages/rdi/pipeline-management/components/template-form/TemplateForm.spec.tsx b/redisinsight/ui/src/pages/rdi/pipeline-management/components/template-form/TemplateForm.spec.tsx index 59efd9f0f5..54ba20c36f 100644 --- a/redisinsight/ui/src/pages/rdi/pipeline-management/components/template-form/TemplateForm.spec.tsx +++ b/redisinsight/ui/src/pages/rdi/pipeline-management/components/template-form/TemplateForm.spec.tsx @@ -79,15 +79,12 @@ describe('TemplateForm', () => { it('should display db type select when source is "config"', () => { render() - expect(screen.getByTestId('pipeline-type-select')).toBeInTheDocument() expect(screen.getByTestId('db-type-select')).toBeInTheDocument() }) it('should not render db type select when source is "jobs"', () => { render() - expect(screen.getByTestId('pipeline-type-select')).toBeInTheDocument() - const dbTypeSelect = screen.queryByTestId('db-type-select') expect(dbTypeSelect).toBeNull() @@ -96,7 +93,6 @@ describe('TemplateForm', () => { it('should select "No template" value', () => { render() - expect(screen.getByTestId('pipeline-type-select')).toHaveTextContent(NO_TEMPLATE_LABEL) expect(screen.getByTestId('db-type-select')).toHaveTextContent(NO_TEMPLATE_LABEL) }) diff --git a/redisinsight/ui/src/pages/rdi/pipeline-management/components/template-form/TemplateForm.tsx b/redisinsight/ui/src/pages/rdi/pipeline-management/components/template-form/TemplateForm.tsx index 2556d4e5a7..6429b567b3 100644 --- a/redisinsight/ui/src/pages/rdi/pipeline-management/components/template-form/TemplateForm.tsx +++ b/redisinsight/ui/src/pages/rdi/pipeline-management/components/template-form/TemplateForm.tsx @@ -32,7 +32,7 @@ export interface Props { value: string } -const getTooltipContent = (value: string, isNoTemplateOptions: boolean) => { +export const getTooltipContent = (value: string, isNoTemplateOptions: boolean) => { if (isNoTemplateOptions) { return ( <> @@ -57,7 +57,7 @@ const TemplateForm = (props: Props) => { const { rdiInstanceId } = useParams<{ rdiInstanceId: string }>() - const [pipelineTypeOptions, setPipelineTypeOptions] = useState[]>(NO_OPTIONS) + const [pipelineTypeOptions, setPipelineTypeOptions] = useState[]>([]) const [dbTypeOptions, setDbTypeOptions] = useState[]>(NO_OPTIONS) const [selectedDbType, setSelectedDbType] = useState('') const [selectedPipelineType, setSelectedPipelineType] = useState('') @@ -144,6 +144,7 @@ const TemplateForm = (props: Props) => { + {(pipelineTypeOptions?.length > 1) && ( <>
Pipeline type
@@ -156,6 +157,7 @@ const TemplateForm = (props: Props) => { />
+ )} {source === RdiPipelineTabs.Config && ( <> diff --git a/redisinsight/ui/src/pages/rdi/pipeline-management/pages/job/Job.tsx b/redisinsight/ui/src/pages/rdi/pipeline-management/pages/job/Job.tsx index 4d234f23d1..d9bac37133 100644 --- a/redisinsight/ui/src/pages/rdi/pipeline-management/pages/job/Job.tsx +++ b/redisinsight/ui/src/pages/rdi/pipeline-management/pages/job/Job.tsx @@ -8,18 +8,18 @@ import { monaco as monacoEditor } from 'react-monaco-editor' import { sendEventTelemetry, TelemetryEvent } from 'uiSrc/telemetry' import { EXTERNAL_LINKS, UTM_MEDIUMS } from 'uiSrc/constants/links' -import { deleteChangedFile, rdiPipelineSelector, setChangedFile } from 'uiSrc/slices/rdi/pipeline' -import { FileChangeType, IPipeline, RdiPipelineTabs } from 'uiSrc/slices/interfaces' +import { deleteChangedFile, fetchPipelineStrategies, rdiPipelineSelector, setChangedFile } from 'uiSrc/slices/rdi/pipeline' +import { FileChangeType, IPipeline } from 'uiSrc/slices/interfaces' import MonacoYaml from 'uiSrc/components/monaco-editor/components/monaco-yaml' import DryRunJobPanel from 'uiSrc/pages/rdi/pipeline-management/components/jobs-panel' import { rdiErrorMessages } from 'uiSrc/pages/rdi/constants' import { DSL, KEYBOARD_SHORTCUTS } from 'uiSrc/constants' -import TemplatePopover from 'uiSrc/pages/rdi/pipeline-management/components/template-popover' import { createAxiosError, isEqualPipelineFile, Maybe, yamlToJson } from 'uiSrc/utils' import { getUtmExternalLink } from 'uiSrc/utils/links' import { KeyboardShortcut } from 'uiSrc/components' import { addErrorNotification } from 'uiSrc/slices/app/notifications' +import TemplateButton from '../../components/template-button' import styles from './styles.module.scss' export interface Props { @@ -34,7 +34,6 @@ const Job = (props: Props) => { const { name, value = '', deployedJobValue, jobIndex, rdiInstanceId } = props const [isPanelOpen, setIsPanelOpen] = useState(false) - const [isPopoverOpen, setIsPopoverOpen] = useState(false) const [shouldOpenDedicatedEditor, setShouldOpenDedicatedEditor] = useState(false) const dispatch = useDispatch() @@ -48,12 +47,12 @@ const Job = (props: Props) => { const { setFieldValue } = useFormikContext() useEffect(() => { - setIsPanelOpen(false) - }, [name]) + dispatch(fetchPipelineStrategies(rdiInstanceId)) + }, []) useEffect(() => { - setIsPopoverOpen(!value) - }, [value, name]) + setIsPanelOpen(false) + }, [name]) useEffect(() => { deployedJobValueRef.current = deployedJobValue @@ -147,7 +146,7 @@ const Job = (props: Props) => {
{name} -
+
{ SQL and JMESPath Editor - setFieldValue(`jobs.${jobIndexRef.current ?? -1}.value`, template)} - loading={loading} - source={RdiPipelineTabs.Jobs} />
diff --git a/redisinsight/ui/src/pages/rdi/pipeline-management/pages/job/styles.module.scss b/redisinsight/ui/src/pages/rdi/pipeline-management/pages/job/styles.module.scss index e4b43ac604..7d5972dc74 100644 --- a/redisinsight/ui/src/pages/rdi/pipeline-management/pages/job/styles.module.scss +++ b/redisinsight/ui/src/pages/rdi/pipeline-management/pages/job/styles.module.scss @@ -6,3 +6,9 @@ display: flex; align-items: baseline; } + +.actionContainer { + display: flex; + align-items: center; +} + From b5413eef8bd8588684fbb6aa5a8c8e6ef8abc8f6 Mon Sep 17 00:00:00 2001 From: ArtemHoruzhenko Date: Mon, 21 Oct 2024 09:55:35 +0300 Subject: [PATCH 229/256] upgrade webpack --- package.json | 2 +- yarn.lock | 666 ++++++++++++++++++++++++++------------------------- 2 files changed, 346 insertions(+), 322 deletions(-) diff --git a/package.json b/package.json index f3b6c84bff..69024ebfa1 100644 --- a/package.json +++ b/package.json @@ -199,7 +199,7 @@ "vite-plugin-electron-renderer": "^0.14.5", "vite-plugin-react-click-to-component": "^3.0.0", "vite-plugin-svgr": "^4.2.0", - "webpack": "^5.91.0", + "webpack": "^5.95.0", "webpack-bundle-analyzer": "^4.10.2", "webpack-cli": "^5.1.4", "webpack-merge": "^5.10.0", diff --git a/yarn.lock b/yarn.lock index 33c835f027..7079f006f1 100644 --- a/yarn.lock +++ b/yarn.lock @@ -13,12 +13,12 @@ integrity sha512-DA5a1C0gD/pLOvhv33YMrbf2FK3oUzwNl9oOJqE4XVjuEtt6XIakRcsd7eLiOSPkp1kTRQGICTA8cKra/vFbjw== "@ampproject/remapping@^2.2.0": - version "2.2.1" - resolved "https://registry.yarnpkg.com/@ampproject/remapping/-/remapping-2.2.1.tgz#99e8e11851128b8702cd57c33684f1d0f260b630" - integrity sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg== + version "2.3.0" + resolved "https://registry.yarnpkg.com/@ampproject/remapping/-/remapping-2.3.0.tgz#ed441b6fa600072520ce18b43d2c8cc8caecc7f4" + integrity sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw== dependencies: - "@jridgewell/gen-mapping" "^0.3.0" - "@jridgewell/trace-mapping" "^0.3.9" + "@jridgewell/gen-mapping" "^0.3.5" + "@jridgewell/trace-mapping" "^0.3.24" "@babel/code-frame@7.12.11": version "7.12.11" @@ -27,49 +27,49 @@ dependencies: "@babel/highlight" "^7.10.4" -"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.10.4", "@babel/code-frame@^7.12.13", "@babel/code-frame@^7.23.5", "@babel/code-frame@^7.24.1", "@babel/code-frame@^7.24.2": - version "7.24.2" - resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.24.2.tgz#718b4b19841809a58b29b68cde80bc5e1aa6d9ae" - integrity sha512-y5+tLQyV8pg3fsiln67BVLD1P13Eg4lh5RW9mF0zUuvLrv9uIQ4MCL+CRT+FTsBlBjcIan6PGsLcBN0m3ClUyQ== +"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.10.4", "@babel/code-frame@^7.12.13", "@babel/code-frame@^7.24.2", "@babel/code-frame@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.25.7.tgz#438f2c524071531d643c6f0188e1e28f130cebc7" + integrity sha512-0xZJFNE5XMpENsgfHYTw8FbX4kv53mFLn2i3XPoq69LyhYSCBJtitaHx9QnsVTrsogI4Z3+HtEfZ2/GFPOtf5g== dependencies: - "@babel/highlight" "^7.24.2" + "@babel/highlight" "^7.25.7" picocolors "^1.0.0" -"@babel/compat-data@^7.22.6", "@babel/compat-data@^7.23.5", "@babel/compat-data@^7.24.4": - version "7.24.4" - resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.24.4.tgz#6f102372e9094f25d908ca0d34fc74c74606059a" - integrity sha512-vg8Gih2MLK+kOkHJp4gBEIkyaIi00jgWot2D9QOmmfLC8jINSOzmCLta6Bvz/JSBCqnegV0L80jhxkol5GWNfQ== +"@babel/compat-data@^7.22.6", "@babel/compat-data@^7.23.5", "@babel/compat-data@^7.24.4", "@babel/compat-data@^7.25.7": + version "7.25.8" + resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.25.8.tgz#0376e83df5ab0eb0da18885c0140041f0747a402" + integrity sha512-ZsysZyXY4Tlx+Q53XdnOFmqwfB9QDTHYxaZYajWRoBLuLEAwI2UIbtxOjWh/cFaa9IKUlcB+DDuoskLuKu56JA== -"@babel/core@^7.11.6", "@babel/core@^7.12.3", "@babel/core@^7.21.3", "@babel/core@^7.23.5": - version "7.24.4" - resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.24.4.tgz#1f758428e88e0d8c563874741bc4ffc4f71a4717" - integrity sha512-MBVlMXP+kkl5394RBLSxxk/iLTeVGuXTV3cIDXavPpMMqnSnt6apKgan/U8O3USWZCWZT/TbgfEpKa4uMgN4Dg== +"@babel/core@^7.11.6", "@babel/core@^7.12.3", "@babel/core@^7.21.3", "@babel/core@^7.23.5", "@babel/core@^7.23.9": + version "7.25.8" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.25.8.tgz#a57137d2a51bbcffcfaeba43cb4dd33ae3e0e1c6" + integrity sha512-Oixnb+DzmRT30qu9d3tJSQkxuygWm32DFykT4bRoORPa9hZ/L4KhVB/XiRm6KG+roIEM7DBQlmg27kw2HZkdZg== dependencies: "@ampproject/remapping" "^2.2.0" - "@babel/code-frame" "^7.24.2" - "@babel/generator" "^7.24.4" - "@babel/helper-compilation-targets" "^7.23.6" - "@babel/helper-module-transforms" "^7.23.3" - "@babel/helpers" "^7.24.4" - "@babel/parser" "^7.24.4" - "@babel/template" "^7.24.0" - "@babel/traverse" "^7.24.1" - "@babel/types" "^7.24.0" + "@babel/code-frame" "^7.25.7" + "@babel/generator" "^7.25.7" + "@babel/helper-compilation-targets" "^7.25.7" + "@babel/helper-module-transforms" "^7.25.7" + "@babel/helpers" "^7.25.7" + "@babel/parser" "^7.25.8" + "@babel/template" "^7.25.7" + "@babel/traverse" "^7.25.7" + "@babel/types" "^7.25.8" convert-source-map "^2.0.0" debug "^4.1.0" gensync "^1.0.0-beta.2" json5 "^2.2.3" semver "^6.3.1" -"@babel/generator@^7.24.1", "@babel/generator@^7.24.4", "@babel/generator@^7.7.2": - version "7.24.4" - resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.24.4.tgz#1fc55532b88adf952025d5d2d1e71f946cb1c498" - integrity sha512-Xd6+v6SnjWVx/nus+y0l1sxMOTOMBkyL4+BIdbALyatQnAe/SRVjANeDPSCYaX+i1iJmuGSKf3Z+E+V/va1Hvw== +"@babel/generator@^7.24.4", "@babel/generator@^7.25.7", "@babel/generator@^7.7.2": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.25.7.tgz#de86acbeb975a3e11ee92dd52223e6b03b479c56" + integrity sha512-5Dqpl5fyV9pIAD62yK9P7fcA768uVPUyrQmqpqstHWgMma4feF1x/oFysBCVZLY5wJ2GkMUCdsNDnGZrPoR6rA== dependencies: - "@babel/types" "^7.24.0" + "@babel/types" "^7.25.7" "@jridgewell/gen-mapping" "^0.3.5" "@jridgewell/trace-mapping" "^0.3.25" - jsesc "^2.5.1" + jsesc "^3.0.2" "@babel/helper-annotate-as-pure@^7.22.5": version "7.22.5" @@ -85,14 +85,14 @@ dependencies: "@babel/types" "^7.22.15" -"@babel/helper-compilation-targets@^7.22.6", "@babel/helper-compilation-targets@^7.23.6": - version "7.23.6" - resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.23.6.tgz#4d79069b16cbcf1461289eccfbbd81501ae39991" - integrity sha512-9JB548GZoQVmzrFgp8o7KxdgkTGm6xs9DW0o/Pim72UDjzr5ObUQ6ZzYPqA+g9OTS2bBQoctLJrky0RDCAWRgQ== +"@babel/helper-compilation-targets@^7.22.6", "@babel/helper-compilation-targets@^7.23.6", "@babel/helper-compilation-targets@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.25.7.tgz#11260ac3322dda0ef53edfae6e97b961449f5fa4" + integrity sha512-DniTEax0sv6isaw6qSQSfV4gVRNtw2rte8HHM45t9ZR0xILaufBRNkpMifCRiAPyvL4ACD6v0gfCwCmtOQaV4A== dependencies: - "@babel/compat-data" "^7.23.5" - "@babel/helper-validator-option" "^7.23.5" - browserslist "^4.22.2" + "@babel/compat-data" "^7.25.7" + "@babel/helper-validator-option" "^7.25.7" + browserslist "^4.24.0" lru-cache "^5.1.1" semver "^6.3.1" @@ -132,24 +132,26 @@ resolve "^1.14.2" "@babel/helper-environment-visitor@^7.22.20": - version "7.22.20" - resolved "https://registry.yarnpkg.com/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz#96159db61d34a29dba454c959f5ae4a649ba9167" - integrity sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA== + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/helper-environment-visitor/-/helper-environment-visitor-7.24.7.tgz#4b31ba9551d1f90781ba83491dd59cf9b269f7d9" + integrity sha512-DoiN84+4Gnd0ncbBOM9AZENV4a5ZiL39HYMyZJGZ/AZEykHYdJw0wW3kdcsh9/Kn+BRXHLkkklZ51ecPKmI1CQ== + dependencies: + "@babel/types" "^7.24.7" "@babel/helper-function-name@^7.22.5", "@babel/helper-function-name@^7.23.0": - version "7.23.0" - resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz#1f9a3cdbd5b2698a670c30d2735f9af95ed52759" - integrity sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw== + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.24.7.tgz#75f1e1725742f39ac6584ee0b16d94513da38dd2" + integrity sha512-FyoJTsj/PEUWu1/TYRiXTIHc8lbw+TDYkZuoE43opPS5TrI7MyONBE1oNvfguEXAD9yhQRrVBnXdXzSLQl9XnA== dependencies: - "@babel/template" "^7.22.15" - "@babel/types" "^7.23.0" + "@babel/template" "^7.24.7" + "@babel/types" "^7.24.7" "@babel/helper-hoist-variables@^7.22.5": - version "7.22.5" - resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz#c01a007dac05c085914e8fb652b339db50d823bb" - integrity sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw== + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.24.7.tgz#b4ede1cde2fd89436397f30dc9376ee06b0f25ee" + integrity sha512-MJJwhkoGy5c4ehfoRyrJ/owKeMl19U54h27YYftT0o2teQ3FJ3nQUf/I3LlJsX4l3qlw7WRXUmiyajvHXoTubQ== dependencies: - "@babel/types" "^7.22.5" + "@babel/types" "^7.24.7" "@babel/helper-member-expression-to-functions@^7.23.0": version "7.23.0" @@ -158,23 +160,23 @@ dependencies: "@babel/types" "^7.23.0" -"@babel/helper-module-imports@^7.22.15", "@babel/helper-module-imports@^7.24.1": - version "7.24.3" - resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.24.3.tgz#6ac476e6d168c7c23ff3ba3cf4f7841d46ac8128" - integrity sha512-viKb0F9f2s0BCS22QSF308z/+1YWKV/76mwt61NBzS5izMzDPwdq1pTrzf+Li3npBWX9KdQbkeCt1jSAM7lZqg== +"@babel/helper-module-imports@^7.22.15", "@babel/helper-module-imports@^7.24.1", "@babel/helper-module-imports@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.25.7.tgz#dba00d9523539152906ba49263e36d7261040472" + integrity sha512-o0xCgpNmRohmnoWKQ0Ij8IdddjyBFE4T2kagL/x6M3+4zUgc+4qTOUBoNe4XxDskt1HPKO007ZPiMgLDq2s7Kw== dependencies: - "@babel/types" "^7.24.0" + "@babel/traverse" "^7.25.7" + "@babel/types" "^7.25.7" -"@babel/helper-module-transforms@^7.23.3": - version "7.23.3" - resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.23.3.tgz#d7d12c3c5d30af5b3c0fcab2a6d5217773e2d0f1" - integrity sha512-7bBs4ED9OmswdfDzpz4MpWgSrV7FXlc3zIagvLFjS5H+Mk7Snr21vQ6QwrsoCGMfNC4e4LQPdoULEt4ykz0SRQ== +"@babel/helper-module-transforms@^7.23.3", "@babel/helper-module-transforms@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.25.7.tgz#2ac9372c5e001b19bc62f1fe7d96a18cb0901d1a" + integrity sha512-k/6f8dKG3yDz/qCwSM+RKovjMix563SLxQFo0UhRNo239SP6n9u5/eLtKD6EAjwta2JHJ49CsD8pms2HdNiMMQ== dependencies: - "@babel/helper-environment-visitor" "^7.22.20" - "@babel/helper-module-imports" "^7.22.15" - "@babel/helper-simple-access" "^7.22.5" - "@babel/helper-split-export-declaration" "^7.22.6" - "@babel/helper-validator-identifier" "^7.22.20" + "@babel/helper-module-imports" "^7.25.7" + "@babel/helper-simple-access" "^7.25.7" + "@babel/helper-validator-identifier" "^7.25.7" + "@babel/traverse" "^7.25.7" "@babel/helper-optimise-call-expression@^7.22.5": version "7.22.5" @@ -183,10 +185,10 @@ dependencies: "@babel/types" "^7.22.5" -"@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.12.13", "@babel/helper-plugin-utils@^7.14.5", "@babel/helper-plugin-utils@^7.18.6", "@babel/helper-plugin-utils@^7.22.5", "@babel/helper-plugin-utils@^7.24.0", "@babel/helper-plugin-utils@^7.8.0", "@babel/helper-plugin-utils@^7.8.3": - version "7.24.0" - resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.24.0.tgz#945681931a52f15ce879fd5b86ce2dae6d3d7f2a" - integrity sha512-9cUznXMG0+FxRuJfvL82QlTqIzhVW9sL0KjMPHhAOOvpQGL8QtdxnBKILjBqxlHyliz0yCa1G903ZXI/FuHy2w== +"@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.12.13", "@babel/helper-plugin-utils@^7.14.5", "@babel/helper-plugin-utils@^7.18.6", "@babel/helper-plugin-utils@^7.22.5", "@babel/helper-plugin-utils@^7.24.0", "@babel/helper-plugin-utils@^7.25.7", "@babel/helper-plugin-utils@^7.8.0", "@babel/helper-plugin-utils@^7.8.3": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.25.7.tgz#8ec5b21812d992e1ef88a9b068260537b6f0e36c" + integrity sha512-eaPZai0PiqCi09pPs3pAFfl/zYgGaE6IdXtYvmf0qlcDTd3WCtO7JWCcRd64e0EQrcYgiHibEZnOGsSY4QSgaw== "@babel/helper-remap-async-to-generator@^7.22.20": version "7.22.20" @@ -206,12 +208,13 @@ "@babel/helper-member-expression-to-functions" "^7.23.0" "@babel/helper-optimise-call-expression" "^7.22.5" -"@babel/helper-simple-access@^7.22.5": - version "7.22.5" - resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.22.5.tgz#4938357dc7d782b80ed6dbb03a0fba3d22b1d5de" - integrity sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w== +"@babel/helper-simple-access@^7.22.5", "@babel/helper-simple-access@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.25.7.tgz#5eb9f6a60c5d6b2e0f76057004f8dacbddfae1c0" + integrity sha512-FPGAkJmyoChQeM+ruBGIDyrT2tKfZJO8NcxdC+CWNJi7N8/rZpSxK7yvBJ5O/nF1gfu5KzN7VKG3YVSLFfRSxQ== dependencies: - "@babel/types" "^7.22.5" + "@babel/traverse" "^7.25.7" + "@babel/types" "^7.25.7" "@babel/helper-skip-transparent-expression-wrappers@^7.22.5": version "7.22.5" @@ -221,26 +224,26 @@ "@babel/types" "^7.22.5" "@babel/helper-split-export-declaration@^7.22.6": - version "7.22.6" - resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz#322c61b7310c0997fe4c323955667f18fcefb91c" - integrity sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g== + version "7.24.7" + resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.24.7.tgz#83949436890e07fa3d6873c61a96e3bbf692d856" + integrity sha512-oy5V7pD+UvfkEATUKvIjvIAH/xCzfsFVw7ygW2SI6NClZzquT+mwdTfgfdbUiceh6iQO0CHtCPsyze/MZ2YbAA== dependencies: - "@babel/types" "^7.22.5" + "@babel/types" "^7.24.7" -"@babel/helper-string-parser@^7.23.4": - version "7.24.1" - resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.24.1.tgz#f99c36d3593db9540705d0739a1f10b5e20c696e" - integrity sha512-2ofRCjnnA9y+wk8b9IAREroeUP02KHp431N2mhKniy2yKIDKpbrHv9eXwm8cBeWQYcJmzv5qKCu65P47eCF7CQ== +"@babel/helper-string-parser@^7.23.4", "@babel/helper-string-parser@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.25.7.tgz#d50e8d37b1176207b4fe9acedec386c565a44a54" + integrity sha512-CbkjYdsJNHFk8uqpEkpCvRs3YRp9tY6FmFY7wLMSYuGYkrdUi7r2lc4/wqsvlHoMznX3WJ9IP8giGPq68T/Y6g== -"@babel/helper-validator-identifier@^7.22.20": - version "7.22.20" - resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz#c4ae002c61d2879e724581d96665583dbc1dc0e0" - integrity sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A== +"@babel/helper-validator-identifier@^7.22.20", "@babel/helper-validator-identifier@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.7.tgz#77b7f60c40b15c97df735b38a66ba1d7c3e93da5" + integrity sha512-AM6TzwYqGChO45oiuPqwL2t20/HdMC1rTPAesnBCgPCSF1x3oN9MVUwQV2iyz4xqWrctwK5RNC8LV22kaQCNYg== -"@babel/helper-validator-option@^7.23.5": - version "7.23.5" - resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.23.5.tgz#907a3fbd4523426285365d1206c423c4c5520307" - integrity sha512-85ttAOMLsr53VgXkTbkx8oA6YTfT4q7/HzXSLEYmjcSTJPMPQtvq1BD79Byep5xMUYbGRzEpDsjUf3dyp54IKw== +"@babel/helper-validator-option@^7.23.5", "@babel/helper-validator-option@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.25.7.tgz#97d1d684448228b30b506d90cace495d6f492729" + integrity sha512-ytbPLsm+GjArDYXJ8Ydr1c/KJuutjF2besPNbIZnZ6MKUxi/uTA22t2ymmA4WFjZFpjiAMO0xuuJPqK2nvDVfQ== "@babel/helper-wrap-function@^7.22.20": version "7.22.20" @@ -251,29 +254,30 @@ "@babel/template" "^7.22.15" "@babel/types" "^7.22.19" -"@babel/helpers@^7.24.4": - version "7.24.4" - resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.24.4.tgz#dc00907fd0d95da74563c142ef4cd21f2cb856b6" - integrity sha512-FewdlZbSiwaVGlgT1DPANDuCHaDMiOo+D/IDYRFYjHOuv66xMSJ7fQwwODwRNAPkADIO/z1EoF/l2BCWlWABDw== +"@babel/helpers@^7.24.4", "@babel/helpers@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.25.7.tgz#091b52cb697a171fe0136ab62e54e407211f09c2" + integrity sha512-Sv6pASx7Esm38KQpF/U/OXLwPPrdGHNKoeblRxgZRLXnAtnkEe4ptJPDtAZM7fBLadbc1Q07kQpSiGQ0Jg6tRA== dependencies: - "@babel/template" "^7.24.0" - "@babel/traverse" "^7.24.1" - "@babel/types" "^7.24.0" + "@babel/template" "^7.25.7" + "@babel/types" "^7.25.7" -"@babel/highlight@^7.10.4", "@babel/highlight@^7.24.2": - version "7.24.2" - resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.24.2.tgz#3f539503efc83d3c59080a10e6634306e0370d26" - integrity sha512-Yac1ao4flkTxTteCDZLEvdxg2fZfz1v8M4QpaGypq/WPDqg3ijHYbDfs+LG5hvzSoqaSZ9/Z9lKSP3CjZjv+pA== +"@babel/highlight@^7.10.4", "@babel/highlight@^7.24.2", "@babel/highlight@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.25.7.tgz#20383b5f442aa606e7b5e3043b0b1aafe9f37de5" + integrity sha512-iYyACpW3iW8Fw+ZybQK+drQre+ns/tKpXbNESfrhNnPLIklLbXr7MYJ6gPEd0iETGLOK+SxMjVvKb/ffmk+FEw== dependencies: - "@babel/helper-validator-identifier" "^7.22.20" + "@babel/helper-validator-identifier" "^7.25.7" chalk "^2.4.2" js-tokens "^4.0.0" picocolors "^1.0.0" -"@babel/parser@^7.1.0", "@babel/parser@^7.14.7", "@babel/parser@^7.20.7", "@babel/parser@^7.24.0", "@babel/parser@^7.24.1", "@babel/parser@^7.24.4": - version "7.24.4" - resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.24.4.tgz#234487a110d89ad5a3ed4a8a566c36b9453e8c88" - integrity sha512-zTvEBcghmeBma9QIGunWevvBAp4/Qu9Bdq+2k0Ot4fVMD6v3dsC9WOcRSKk7tRRyBM/53yKMJko9xOatGQAwSg== +"@babel/parser@^7.1.0", "@babel/parser@^7.14.7", "@babel/parser@^7.20.7", "@babel/parser@^7.23.9", "@babel/parser@^7.24.4", "@babel/parser@^7.25.7", "@babel/parser@^7.25.8": + version "7.25.8" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.25.8.tgz#f6aaf38e80c36129460c1657c0762db584c9d5e2" + integrity sha512-HcttkxzdPucv3nNFmfOOMfFf64KgdJVqm1KaCm25dPGMLElo9nsLvXeJECQg8UzPuBGLyTSA0ZzqCtDSzKTEoQ== + dependencies: + "@babel/types" "^7.25.8" "@babel/plugin-bugfix-firefox-class-in-computed-class-key@^7.24.4": version "7.24.4" @@ -326,7 +330,7 @@ dependencies: "@babel/helper-plugin-utils" "^7.8.0" -"@babel/plugin-syntax-class-properties@^7.12.13", "@babel/plugin-syntax-class-properties@^7.8.3": +"@babel/plugin-syntax-class-properties@^7.12.13": version "7.12.13" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz#b5c987274c4a3a82b89714796931a6b53544ae10" integrity sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA== @@ -361,14 +365,14 @@ dependencies: "@babel/helper-plugin-utils" "^7.24.0" -"@babel/plugin-syntax-import-attributes@^7.24.1": - version "7.24.1" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.24.1.tgz#c66b966c63b714c4eec508fcf5763b1f2d381093" - integrity sha512-zhQTMH0X2nVLnb04tz+s7AMuasX8U0FnpE+nHTOhSOINjWMnopoZTxtIKsd45n4GQ/HIZLyfIpoul8e2m0DnRA== +"@babel/plugin-syntax-import-attributes@^7.24.1", "@babel/plugin-syntax-import-attributes@^7.24.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.25.7.tgz#d78dd0499d30df19a598e63ab895e21b909bc43f" + integrity sha512-AqVo+dguCgmpi/3mYBdu9lkngOBlQ2w2vnNpa6gfiCxQZLzV4ZbhsXitJ2Yblkoe1VQwtHSaNmIaGll/26YWRw== dependencies: - "@babel/helper-plugin-utils" "^7.24.0" + "@babel/helper-plugin-utils" "^7.25.7" -"@babel/plugin-syntax-import-meta@^7.10.4", "@babel/plugin-syntax-import-meta@^7.8.3": +"@babel/plugin-syntax-import-meta@^7.10.4": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz#ee601348c370fa334d2207be158777496521fd51" integrity sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g== @@ -383,13 +387,13 @@ "@babel/helper-plugin-utils" "^7.8.0" "@babel/plugin-syntax-jsx@^7.23.3", "@babel/plugin-syntax-jsx@^7.24.1", "@babel/plugin-syntax-jsx@^7.7.2": - version "7.24.1" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.24.1.tgz#3f6ca04b8c841811dbc3c5c5f837934e0d626c10" - integrity sha512-2eCtxZXf+kbkMIsXS4poTvT4Yu5rXiRa+9xGVT56raghjmBTKMpFNc9R4IDiB4emao9eO22Ox7CxuJG7BgExqA== + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.25.7.tgz#5352d398d11ea5e7ef330c854dea1dae0bf18165" + integrity sha512-ruZOnKO+ajVL/MVx+PwNBPOkrnXTXoWMtte1MBpegfCArhqOe3Bj52avVj1huLLxNKYKXYaSxZ2F+woK1ekXfw== dependencies: - "@babel/helper-plugin-utils" "^7.24.0" + "@babel/helper-plugin-utils" "^7.25.7" -"@babel/plugin-syntax-logical-assignment-operators@^7.10.4", "@babel/plugin-syntax-logical-assignment-operators@^7.8.3": +"@babel/plugin-syntax-logical-assignment-operators@^7.10.4": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz#ca91ef46303530448b906652bac2e9fe9941f699" integrity sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig== @@ -403,7 +407,7 @@ dependencies: "@babel/helper-plugin-utils" "^7.8.0" -"@babel/plugin-syntax-numeric-separator@^7.10.4", "@babel/plugin-syntax-numeric-separator@^7.8.3": +"@babel/plugin-syntax-numeric-separator@^7.10.4": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz#b9b070b3e33570cd9fd07ba7fa91c0dd37b9af97" integrity sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug== @@ -438,7 +442,7 @@ dependencies: "@babel/helper-plugin-utils" "^7.14.5" -"@babel/plugin-syntax-top-level-await@^7.14.5", "@babel/plugin-syntax-top-level-await@^7.8.3": +"@babel/plugin-syntax-top-level-await@^7.14.5": version "7.14.5" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz#c1cfdadc35a646240001f06138247b741c34d94c" integrity sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw== @@ -446,11 +450,11 @@ "@babel/helper-plugin-utils" "^7.14.5" "@babel/plugin-syntax-typescript@^7.24.1", "@babel/plugin-syntax-typescript@^7.7.2": - version "7.24.1" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.24.1.tgz#b3bcc51f396d15f3591683f90239de143c076844" - integrity sha512-Yhnmvy5HZEnHUty6i++gcfH1/l68AHnItFHnaCv6hn9dNh0hQvvQJsxpi4BMBFN5DLeHBuucT/0DgzXif/OyRw== + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.25.7.tgz#bfc05b0cc31ebd8af09964650cee723bb228108b" + integrity sha512-rR+5FDjpCHqqZN2bzZm18bVYGaejGq5ZkpVCJLXor/+zlSrSoc4KWcHI0URVWjl/68Dyr1uwZUz/1njycEAv9g== dependencies: - "@babel/helper-plugin-utils" "^7.24.0" + "@babel/helper-plugin-utils" "^7.25.7" "@babel/plugin-syntax-unicode-sets-regex@^7.18.6": version "7.18.6" @@ -1050,38 +1054,35 @@ dependencies: regenerator-runtime "^0.13.11" -"@babel/template@^7.22.15", "@babel/template@^7.24.0", "@babel/template@^7.3.3": - version "7.24.0" - resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.24.0.tgz#c6a524aa93a4a05d66aaf31654258fae69d87d50" - integrity sha512-Bkf2q8lMB0AFpX0NFEqSbx1OkTHf0f+0j82mkw+ZpzBnkk7e9Ql0891vlfgi+kHwOk8tQjiQHpqh4LaSa0fKEA== - dependencies: - "@babel/code-frame" "^7.23.5" - "@babel/parser" "^7.24.0" - "@babel/types" "^7.24.0" - -"@babel/traverse@^7.24.1": - version "7.24.1" - resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.24.1.tgz#d65c36ac9dd17282175d1e4a3c49d5b7988f530c" - integrity sha512-xuU6o9m68KeqZbQuDt2TcKSxUw/mrsvavlEqQ1leZ/B+C9tk6E4sRWy97WaXgvq5E+nU3cXMxv3WKOCanVMCmQ== - dependencies: - "@babel/code-frame" "^7.24.1" - "@babel/generator" "^7.24.1" - "@babel/helper-environment-visitor" "^7.22.20" - "@babel/helper-function-name" "^7.23.0" - "@babel/helper-hoist-variables" "^7.22.5" - "@babel/helper-split-export-declaration" "^7.22.6" - "@babel/parser" "^7.24.1" - "@babel/types" "^7.24.0" +"@babel/template@^7.22.15", "@babel/template@^7.24.0", "@babel/template@^7.24.7", "@babel/template@^7.25.7", "@babel/template@^7.3.3": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.25.7.tgz#27f69ce382855d915b14ab0fe5fb4cbf88fa0769" + integrity sha512-wRwtAgI3bAS+JGU2upWNL9lSlDcRCqD05BZ1n3X2ONLH1WilFP6O1otQjeMK/1g0pvYcXC7b/qVUB1keofjtZA== + dependencies: + "@babel/code-frame" "^7.25.7" + "@babel/parser" "^7.25.7" + "@babel/types" "^7.25.7" + +"@babel/traverse@^7.24.1", "@babel/traverse@^7.25.7": + version "7.25.7" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.25.7.tgz#83e367619be1cab8e4f2892ef30ba04c26a40fa8" + integrity sha512-jatJPT1Zjqvh/1FyJs6qAHL+Dzb7sTb+xr7Q+gM1b+1oBsMsQQ4FkVKb6dFlJvLlVssqkRzV05Jzervt9yhnzg== + dependencies: + "@babel/code-frame" "^7.25.7" + "@babel/generator" "^7.25.7" + "@babel/parser" "^7.25.7" + "@babel/template" "^7.25.7" + "@babel/types" "^7.25.7" debug "^4.3.1" globals "^11.1.0" -"@babel/types@^7.0.0", "@babel/types@^7.20.7", "@babel/types@^7.21.3", "@babel/types@^7.22.15", "@babel/types@^7.22.19", "@babel/types@^7.22.5", "@babel/types@^7.23.0", "@babel/types@^7.23.4", "@babel/types@^7.24.0", "@babel/types@^7.3.3", "@babel/types@^7.4.4": - version "7.24.0" - resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.24.0.tgz#3b951f435a92e7333eba05b7566fd297960ea1bf" - integrity sha512-+j7a5c253RfKh8iABBhywc8NSfP5LURe7Uh4qpsh6jc+aLJguvmIUBdjSdEMQv2bENrCR5MfRdjGo7vzS/ob7w== +"@babel/types@^7.0.0", "@babel/types@^7.20.7", "@babel/types@^7.21.3", "@babel/types@^7.22.15", "@babel/types@^7.22.19", "@babel/types@^7.22.5", "@babel/types@^7.23.0", "@babel/types@^7.23.4", "@babel/types@^7.24.0", "@babel/types@^7.24.7", "@babel/types@^7.25.7", "@babel/types@^7.25.8", "@babel/types@^7.3.3", "@babel/types@^7.4.4": + version "7.25.8" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.25.8.tgz#5cf6037258e8a9bcad533f4979025140cb9993e1" + integrity sha512-JWtuCu8VQsMladxVz/P4HzHUGCAwpuqacmowgXFs5XjxIgKuNjnLokQzuVjlTvIzODaDmpjT3oxcC48vyk9EWg== dependencies: - "@babel/helper-string-parser" "^7.23.4" - "@babel/helper-validator-identifier" "^7.22.20" + "@babel/helper-string-parser" "^7.25.7" + "@babel/helper-validator-identifier" "^7.25.7" to-fast-properties "^2.0.0" "@bcoe/v8-coverage@^0.2.3": @@ -1422,7 +1423,7 @@ js-yaml "^3.13.1" resolve-from "^5.0.0" -"@istanbuljs/schema@^0.1.2": +"@istanbuljs/schema@^0.1.2", "@istanbuljs/schema@^0.1.3": version "0.1.3" resolved "https://registry.yarnpkg.com/@istanbuljs/schema/-/schema-0.1.3.tgz#e45e384e4b8ec16bce2fd903af78450f6bf7ec98" integrity sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA== @@ -1640,9 +1641,9 @@ "@jridgewell/trace-mapping" "^0.3.24" "@jridgewell/resolve-uri@^3.0.3", "@jridgewell/resolve-uri@^3.1.0": - version "3.1.1" - resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz#c08679063f279615a3326583ba3a90d1d82cc721" - integrity sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA== + version "3.1.2" + resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz#7a0ee601f60f99a20c7c7c5ff0c80388c1189bd6" + integrity sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw== "@jridgewell/set-array@^1.2.1": version "1.2.1" @@ -1658,9 +1659,9 @@ "@jridgewell/trace-mapping" "^0.3.9" "@jridgewell/sourcemap-codec@^1.4.10", "@jridgewell/sourcemap-codec@^1.4.14": - version "1.4.15" - resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz#d7c6e6755c78567a951e04ab52ef0fd26de59f32" - integrity sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg== + version "1.5.0" + resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz#3188bcb273a414b0d215fd22a58540b989b9409a" + integrity sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ== "@jridgewell/trace-mapping@0.3.9": version "0.3.9" @@ -1996,9 +1997,9 @@ integrity sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw== "@sinonjs/commons@^3.0.0": - version "3.0.0" - resolved "https://registry.yarnpkg.com/@sinonjs/commons/-/commons-3.0.0.tgz#beb434fe875d965265e04722ccfc21df7f755d72" - integrity sha512-jXBtWAF4vmdNmZgD5FoKsVLv3rPgDnLgPbU84LIJ3otV44vJlDRokVng5v8NFJdCf/da9legHcKaRuZs4L7faA== + version "3.0.1" + resolved "https://registry.yarnpkg.com/@sinonjs/commons/-/commons-3.0.1.tgz#1029357e44ca901a615585f6d27738dbc89084cd" + integrity sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ== dependencies: type-detect "4.0.8" @@ -2313,24 +2314,24 @@ "@types/babel__traverse" "*" "@types/babel__generator@*": - version "7.6.6" - resolved "https://registry.yarnpkg.com/@types/babel__generator/-/babel__generator-7.6.6.tgz#676f89f67dc8ddaae923f70ebc5f1fa800c031a8" - integrity sha512-66BXMKb/sUWbMdBNdMvajU7i/44RkrA3z/Yt1c7R5xejt8qh84iU54yUWCtm0QwGJlDcf/gg4zd/x4mpLAlb/w== + version "7.6.8" + resolved "https://registry.yarnpkg.com/@types/babel__generator/-/babel__generator-7.6.8.tgz#f836c61f48b1346e7d2b0d93c6dacc5b9535d3ab" + integrity sha512-ASsj+tpEDsEiFr1arWrlN6V3mdfjRMZt6LtK/Vp/kreFLnr5QH5+DhvD5nINYZXzwJvXeGq+05iUXcAzVrqWtw== dependencies: "@babel/types" "^7.0.0" "@types/babel__template@*": - version "7.4.3" - resolved "https://registry.yarnpkg.com/@types/babel__template/-/babel__template-7.4.3.tgz#db9ac539a2fe05cfe9e168b24f360701bde41f5f" - integrity sha512-ciwyCLeuRfxboZ4isgdNZi/tkt06m8Tw6uGbBSBgWrnnZGNXiEyM27xc/PjXGQLqlZ6ylbgHMnm7ccF9tCkOeQ== + version "7.4.4" + resolved "https://registry.yarnpkg.com/@types/babel__template/-/babel__template-7.4.4.tgz#5672513701c1b2199bc6dad636a9d7491586766f" + integrity sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A== dependencies: "@babel/parser" "^7.1.0" "@babel/types" "^7.0.0" "@types/babel__traverse@*", "@types/babel__traverse@^7.0.6": - version "7.20.3" - resolved "https://registry.yarnpkg.com/@types/babel__traverse/-/babel__traverse-7.20.3.tgz#a971aa47441b28ef17884ff945d0551265a2d058" - integrity sha512-Lsh766rGEFbaxMIDH7Qa+Yha8cMVI3qAK6CHt3OR0YfxOIn5Z54iHiyDRycHrBqeIiqGa20Kpsv1cavfBKkRSw== + version "7.20.6" + resolved "https://registry.yarnpkg.com/@types/babel__traverse/-/babel__traverse-7.20.6.tgz#8dc9f0ae0f202c08d8d4dab648912c8d6038e3f7" + integrity sha512-r1bzfrm0tomOI8g1SzvCaQHo6Lcv6zu0EA+W2kHrt8dyrHQxGzBBL4kdkzIS+jBMV+EYcMAEAqXqYaLJq5rOZg== dependencies: "@babel/types" "^7.20.7" @@ -2610,23 +2611,7 @@ dependencies: electron-store "*" -"@types/eslint-scope@^3.7.3": - version "3.7.4" - resolved "https://registry.yarnpkg.com/@types/eslint-scope/-/eslint-scope-3.7.4.tgz#37fc1223f0786c39627068a12e94d6e6fc61de16" - integrity sha512-9K4zoImiZc3HlIp6AVUDE4CWYx22a+lhSZMYNpbjW04+YF0KWj4pJXnEMjdnFTiQibFFmElcsasJXDbdI/EPhA== - dependencies: - "@types/eslint" "*" - "@types/estree" "*" - -"@types/eslint@*": - version "8.37.0" - resolved "https://registry.yarnpkg.com/@types/eslint/-/eslint-8.37.0.tgz#29cebc6c2a3ac7fea7113207bf5a828fdf4d7ef1" - integrity sha512-Piet7dG2JBuDIfohBngQ3rCt7MgO9xCO4xIMKxBThCq5PNRB91IjlJ10eJVwfoNtvTErmxLzwBZ7rHZtbOMmFQ== - dependencies: - "@types/estree" "*" - "@types/json-schema" "*" - -"@types/estree@*", "@types/estree@1.0.6", "@types/estree@^1.0.0", "@types/estree@^1.0.5": +"@types/estree@1.0.6", "@types/estree@^1.0.0", "@types/estree@^1.0.5": version "1.0.6" resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.6.tgz#628effeeae2064a1b4e79f78e81d87b7e5fc7b50" integrity sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw== @@ -2669,9 +2654,9 @@ integrity sha512-Nmh0K3iWQJzniTuPRcJn5hxXkfB1T1pgB89SBig5PlJQU5yocazeu4jATJlaA0GYFKWMqDdvYemoSnF2pXgLVA== "@types/graceful-fs@^4.1.3": - version "4.1.8" - resolved "https://registry.yarnpkg.com/@types/graceful-fs/-/graceful-fs-4.1.8.tgz#417e461e4dc79d957dc3107f45fe4973b09c2915" - integrity sha512-NhRH7YzWq8WiNKVavKPBmtLYZHxNY19Hh+az28O/phfp68CF45pMFud+ZzJ8ewnxnC5smIdF3dqFeiSUQ5I+pw== + version "4.1.9" + resolved "https://registry.yarnpkg.com/@types/graceful-fs/-/graceful-fs-4.1.9.tgz#2a06bc0f68a20ab37b3e36aa238be6abdf49e8b4" + integrity sha512-olP3sd1qOEe5dXTSaFvQG+02VdRXcdytWLAZsAq1PecU8uqQAhkrnbli7DagjtXKW/Bl7YJbUsa8MPcuc8LHEQ== dependencies: "@types/node" "*" @@ -2737,21 +2722,21 @@ integrity sha512-4j5G9Y5jljDSICQ1R2f/Rcyoj6DZmYGneny+p/cDkjep0rkqNg0W73Ty0bVjMUTZgLXHf8oiMjg1XC3CDwCz+g== "@types/istanbul-lib-coverage@*", "@types/istanbul-lib-coverage@^2.0.0", "@types/istanbul-lib-coverage@^2.0.1": - version "2.0.5" - resolved "https://registry.yarnpkg.com/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.5.tgz#fdfdd69fa16d530047d9963635bd77c71a08c068" - integrity sha512-zONci81DZYCZjiLe0r6equvZut0b+dBRPBN5kBDjsONnutYNtJMoWQ9uR2RkL1gLG9NMTzvf+29e5RFfPbeKhQ== + version "2.0.6" + resolved "https://registry.yarnpkg.com/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz#7739c232a1fee9b4d3ce8985f314c0c6d33549d7" + integrity sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w== "@types/istanbul-lib-report@*": - version "3.0.0" - resolved "https://registry.yarnpkg.com/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz#c14c24f18ea8190c118ee7562b7ff99a36552686" - integrity sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg== + version "3.0.3" + resolved "https://registry.yarnpkg.com/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.3.tgz#53047614ae72e19fc0401d872de3ae2b4ce350bf" + integrity sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA== dependencies: "@types/istanbul-lib-coverage" "*" "@types/istanbul-reports@^3.0.0": - version "3.0.1" - resolved "https://registry.yarnpkg.com/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz#9153fe98bba2bd565a63add9436d6f0d7f8468ff" - integrity sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw== + version "3.0.4" + resolved "https://registry.yarnpkg.com/@types/istanbul-reports/-/istanbul-reports-3.0.4.tgz#0f03e3d2f670fbdac586e34b433783070cc16f54" + integrity sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ== dependencies: "@types/istanbul-lib-report" "*" @@ -2796,7 +2781,7 @@ resolved "https://registry.yarnpkg.com/@types/json-bigint/-/json-bigint-1.0.1.tgz#201062a6990119a8cc18023cfe1fed12fc2fc8a7" integrity sha512-zpchZLNsNuzJHi6v64UBoFWAvQlPhch7XAi36FkH6tL1bbbmimIF+cS7vwkzY4u5RaSWMoflQfu+TshMPPw8uw== -"@types/json-schema@*", "@types/json-schema@^7.0.0", "@types/json-schema@^7.0.5", "@types/json-schema@^7.0.7", "@types/json-schema@^7.0.8", "@types/json-schema@^7.0.9": +"@types/json-schema@^7.0.0", "@types/json-schema@^7.0.5", "@types/json-schema@^7.0.7", "@types/json-schema@^7.0.8", "@types/json-schema@^7.0.9": version "7.0.15" resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.15.tgz#596a1747233694d50f6ad8a7869fcb6f56cf5841" integrity sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA== @@ -2840,12 +2825,12 @@ resolved "https://registry.yarnpkg.com/@types/ms/-/ms-0.7.31.tgz#31b7ca6407128a3d2bbc27fe2d21b345397f6197" integrity sha512-iiUgKzV9AuaEkZqkOLDIvlQiL6ltuZd9tGcW3gwpnX8JbuiuhFlEGmmFXEXkN50Cvq7Os88IY2v0dkDqXYWVgA== -"@types/node@*", "@types/node@>=13.7.0", "@types/node@^20.9.0": - version "20.14.8" - resolved "https://registry.yarnpkg.com/@types/node/-/node-20.14.8.tgz#45c26a2a5de26c3534a9504530ddb3b27ce031ac" - integrity sha512-DO+2/jZinXfROG7j7WKFn/3C6nFwxy2lLpgLjEXJz+0XKphZlTLJ14mo8Vfg8X5BWN6XjyESXq+LcYdT7tR3bA== +"@types/node@*", "@types/node@>=13.7.0": + version "22.7.7" + resolved "https://registry.yarnpkg.com/@types/node/-/node-22.7.7.tgz#6cd9541c3dccb4f7e8b141b491443f4a1570e307" + integrity sha512-SRxCrrg9CL/y54aiMCG3edPKdprgMVGDXjA3gB8UmmBW5TcXzRUYAh8EWzTnSJFAd1rgImPELza+A3bJ+qxz8Q== dependencies: - undici-types "~5.26.4" + undici-types "~6.19.2" "@types/node@14.14.10": version "14.14.10" @@ -2857,6 +2842,13 @@ resolved "https://registry.yarnpkg.com/@types/node/-/node-17.0.45.tgz#2c0fafd78705e7a18b7906b5201a522719dc5190" integrity sha512-w+tIMs3rq2afQdsPJlODhoUEKzFP1ayaoyl1CcnwtIlsVe7K7bA1NGm4s3PraqTLlXnbIN84zuBlxBWo1u9BLw== +"@types/node@^20.9.0": + version "20.14.8" + resolved "https://registry.yarnpkg.com/@types/node/-/node-20.14.8.tgz#45c26a2a5de26c3534a9504530ddb3b27ce031ac" + integrity sha512-DO+2/jZinXfROG7j7WKFn/3C6nFwxy2lLpgLjEXJz+0XKphZlTLJ14mo8Vfg8X5BWN6XjyESXq+LcYdT7tR3bA== + dependencies: + undici-types "~5.26.4" + "@types/normalize-package-data@^2.4.0": version "2.4.1" resolved "https://registry.yarnpkg.com/@types/normalize-package-data/-/normalize-package-data-2.4.1.tgz#d3357479a0fdfdd5907fe67e17e0a85c906e1301" @@ -3084,9 +3076,9 @@ "@types/node" "*" "@types/stack-utils@^2.0.0": - version "2.0.1" - resolved "https://registry.yarnpkg.com/@types/stack-utils/-/stack-utils-2.0.1.tgz#20f18294f797f2209b5f65c8e3b5c8e8261d127c" - integrity sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw== + version "2.0.3" + resolved "https://registry.yarnpkg.com/@types/stack-utils/-/stack-utils-2.0.3.tgz#6209321eb2c1712a7e7466422b8cb1fc0d9dd5d8" + integrity sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw== "@types/superagent@*": version "4.1.17" @@ -3141,9 +3133,9 @@ integrity sha512-I6e+9+HtWADAWeeJWDFQtdk4EVSAbj6Rtz4q8fJ7mSr1M0jzlFcs8/HZ+Xb5SHzVm1dxH7aUiI+A8kA8Gcrm0A== "@types/yargs-parser@*": - version "21.0.0" - resolved "https://registry.yarnpkg.com/@types/yargs-parser/-/yargs-parser-21.0.0.tgz#0c60e537fa790f5f9472ed2776c2b71ec117351b" - integrity sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA== + version "21.0.3" + resolved "https://registry.yarnpkg.com/@types/yargs-parser/-/yargs-parser-21.0.3.tgz#815e30b786d2e8f0dcd85fd5bcf5e1a04d008f15" + integrity sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ== "@types/yargs@^16.0.0": version "16.0.9" @@ -3153,9 +3145,9 @@ "@types/yargs-parser" "*" "@types/yargs@^17.0.8": - version "17.0.32" - resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-17.0.32.tgz#030774723a2f7faafebf645f4e5a48371dca6229" - integrity sha512-xQ67Yc/laOG5uMfX/093MRlGGCIBzZMarVa+gfNKJxWAIgykYpVGkBdbqEzGDDfCrVUj6Hiff4mTZ5BA6TmAog== + version "17.0.33" + resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-17.0.33.tgz#8c32303da83eec050a84b3c7ae7b9f922d13e32d" + integrity sha512-WpxBCKWPLr4xSsHgz511rFJAM+wS28w2zEO1QDNY5zM/S8ok70NNfztH0xwhqKyaK0OHCbN98LDAZuy1ctxDkA== dependencies: "@types/yargs-parser" "*" @@ -3488,10 +3480,10 @@ acorn-globals@^7.0.0: acorn "^8.1.0" acorn-walk "^8.0.2" -acorn-import-assertions@^1.9.0: - version "1.9.0" - resolved "https://registry.yarnpkg.com/acorn-import-assertions/-/acorn-import-assertions-1.9.0.tgz#507276249d684797c84e0734ef84860334cfb1ac" - integrity sha512-cmMwop9x+8KFhxvKrKfPYmN6/pKTYYHBqLa0DfvVZcKMJWNyWLnaqND7dx/qn66R7ewM1UX5XMaDVP5wlVTaVA== +acorn-import-attributes@^1.9.5: + version "1.9.5" + resolved "https://registry.yarnpkg.com/acorn-import-attributes/-/acorn-import-attributes-1.9.5.tgz#7eb1557b1ba05ef18b5ed0ec67591bfab04688ef" + integrity sha512-n02Vykv5uA3eHGM/Z2dQrcD56kL8TyDb2p1+0P83PClMnC/nc+anbQRhIOWnSq4Ke/KvDPrY3C9hDtC/A3eHnQ== acorn-jsx@^5.3.1: version "5.3.2" @@ -3973,22 +3965,25 @@ babel-plugin-polyfill-regenerator@^0.6.1: "@babel/helper-define-polyfill-provider" "^0.6.2" babel-preset-current-node-syntax@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz#b4399239b89b2a011f9ddbe3e4f401fc40cff73b" - integrity sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ== + version "1.1.0" + resolved "https://registry.yarnpkg.com/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.1.0.tgz#9a929eafece419612ef4ae4f60b1862ebad8ef30" + integrity sha512-ldYss8SbBlWva1bs28q78Ju5Zq1F+8BrqBZZ0VFhLBvhh6lCpC2o3gDJi/5DRLs9FgYZCnmPYIVFU4lRXCkyUw== dependencies: "@babel/plugin-syntax-async-generators" "^7.8.4" "@babel/plugin-syntax-bigint" "^7.8.3" - "@babel/plugin-syntax-class-properties" "^7.8.3" - "@babel/plugin-syntax-import-meta" "^7.8.3" + "@babel/plugin-syntax-class-properties" "^7.12.13" + "@babel/plugin-syntax-class-static-block" "^7.14.5" + "@babel/plugin-syntax-import-attributes" "^7.24.7" + "@babel/plugin-syntax-import-meta" "^7.10.4" "@babel/plugin-syntax-json-strings" "^7.8.3" - "@babel/plugin-syntax-logical-assignment-operators" "^7.8.3" + "@babel/plugin-syntax-logical-assignment-operators" "^7.10.4" "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.3" - "@babel/plugin-syntax-numeric-separator" "^7.8.3" + "@babel/plugin-syntax-numeric-separator" "^7.10.4" "@babel/plugin-syntax-object-rest-spread" "^7.8.3" "@babel/plugin-syntax-optional-catch-binding" "^7.8.3" "@babel/plugin-syntax-optional-chaining" "^7.8.3" - "@babel/plugin-syntax-top-level-await" "^7.8.3" + "@babel/plugin-syntax-private-property-in-object" "^7.14.5" + "@babel/plugin-syntax-top-level-await" "^7.14.5" babel-preset-jest@^29.6.3: version "29.6.3" @@ -4131,15 +4126,15 @@ browserify-zlib@^0.1.4: dependencies: pako "~0.2.0" -browserslist@^4.0.0, browserslist@^4.14.5, browserslist@^4.16.8, browserslist@^4.21.10, browserslist@^4.22.2, browserslist@^4.23.0: - version "4.23.0" - resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.23.0.tgz#8f3acc2bbe73af7213399430890f86c63a5674ab" - integrity sha512-QW8HiM1shhT2GuzkvklfjcKDiWFXHOeFCIA/huJPwHsslwcydgk7X+z2zXpEijP98UCY7HbubZt5J2Zgvf0CaQ== +browserslist@^4.0.0, browserslist@^4.14.5, browserslist@^4.16.8, browserslist@^4.21.10, browserslist@^4.22.2, browserslist@^4.23.0, browserslist@^4.24.0: + version "4.24.0" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.24.0.tgz#a1325fe4bc80b64fda169629fc01b3d6cecd38d4" + integrity sha512-Rmb62sR1Zpjql25eSanFGEhAxcFwfA1K0GuQcLoaJBAcENegrQut3hYdhXFF1obQfiDyqIW/cLM5HSJ/9k884A== dependencies: - caniuse-lite "^1.0.30001587" - electron-to-chromium "^1.4.668" - node-releases "^2.0.14" - update-browserslist-db "^1.0.13" + caniuse-lite "^1.0.30001663" + electron-to-chromium "^1.5.28" + node-releases "^2.0.18" + update-browserslist-db "^1.1.0" bs-logger@0.x: version "0.2.6" @@ -4325,10 +4320,10 @@ caniuse-api@^3.0.0: lodash.memoize "^4.1.2" lodash.uniq "^4.5.0" -caniuse-lite@^1.0.0, caniuse-lite@^1.0.30001251, caniuse-lite@^1.0.30001587: - version "1.0.30001612" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001612.tgz#d34248b4ec1f117b70b24ad9ee04c90e0b8a14ae" - integrity sha512-lFgnZ07UhaCcsSZgWW0K5j4e69dK1u/ltrL9lTUiFOwNHs12S3UMIEYgBV0Z6C6hRDev7iRnMzzYmKabYdXF9g== +caniuse-lite@^1.0.0, caniuse-lite@^1.0.30001251, caniuse-lite@^1.0.30001587, caniuse-lite@^1.0.30001663: + version "1.0.30001669" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001669.tgz#fda8f1d29a8bfdc42de0c170d7f34a9cf19ed7a3" + integrity sha512-DlWzFDJqstqtIVx1zeSpIMLjunf5SmwOw0N2Ck/QSQdS8PLS4+9HrLaYei4w8BIAL7IB/UEDu889d8vhCTPA0w== ccount@^1.0.0: version "1.1.0" @@ -4451,9 +4446,9 @@ ci-info@^3.2.0, ci-info@^3.7.0: integrity sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ== cjs-module-lexer@^1.0.0: - version "1.2.3" - resolved "https://registry.yarnpkg.com/cjs-module-lexer/-/cjs-module-lexer-1.2.3.tgz#6c370ab19f8a3394e318fe682686ec0ac684d107" - integrity sha512-0TNiGstbQmCFwt4akjjBg5pLRTSyj/PkWQ1ZoO2zntmg9yLqSRxwEa4iCfQLGjqhiqBfOJa7W/E8wfGrTDmlZQ== + version "1.4.1" + resolved "https://registry.yarnpkg.com/cjs-module-lexer/-/cjs-module-lexer-1.4.1.tgz#707413784dbb3a72aa11c2f2b042a0bef4004170" + integrity sha512-cuSVIHi9/9E/+821Qjdvngor+xpnlwnuwIyZOaLmHBVdXL+gP+I6QQB9VkO7RI77YIcTV+S1W9AreJ5eN63JBA== classnames@*, classnames@^2.2.6, classnames@^2.3.1: version "2.3.2" @@ -5332,11 +5327,11 @@ debounce@^1.2.1: integrity sha512-XRRe6Glud4rd/ZGQfiV1ruXSfbvfJedlV9Y6zOlP+2K04vBYiJEte6stfFkCP03aMnY5tsipamumUjL14fofug== debug@4, debug@^4.0.0, debug@^4.0.1, debug@^4.1.0, debug@^4.1.1, debug@^4.2.0, debug@^4.3.1, debug@^4.3.3, debug@^4.3.4, debug@~4.3.1, debug@~4.3.2: - version "4.3.4" - resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" - integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== + version "4.3.7" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.7.tgz#87945b4151a011d76d95a198d7111c865c360a52" + integrity sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ== dependencies: - ms "2.1.2" + ms "^2.1.3" debug@^3.1.0, debug@^3.2.7: version "3.2.7" @@ -5375,9 +5370,9 @@ dedent@^0.7.0: integrity sha512-Q6fKUPqnAHAyhiUgFU7BUzLiv0kd8saH9al7tnu5Q/okj6dnupxyTgFIBjVzJATdfIAm9NAsvXNzjaKa+bxVyA== dedent@^1.0.0: - version "1.5.1" - resolved "https://registry.yarnpkg.com/dedent/-/dedent-1.5.1.tgz#4f3fc94c8b711e9bb2800d185cd6ad20f2a90aff" - integrity sha512-+LxW+KLWxu3HW3M2w2ympwtqPrqYRzU8fqi6Fhd18fBALe15blJPI/I4+UHveMVG6lJqB4JNd4UG0S5cnVHwIg== + version "1.5.3" + resolved "https://registry.yarnpkg.com/dedent/-/dedent-1.5.3.tgz#99aee19eb9bae55a67327717b6e848d0bf777e5a" + integrity sha512-NHQtfOOW68WD8lgypbLA5oT+Bt0xXJhiYvoR6SmmNXZfpzOGXwdKWmcwG8N7PwVVWV3eF/68nmD9BaJSsTBhyQ== deep-equal@^2.0.5: version "2.2.1" @@ -5863,10 +5858,10 @@ electron-store@*, electron-store@^8.0.0: conf "^10.2.0" type-fest "^2.17.0" -electron-to-chromium@^1.4.668: - version "1.4.745" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.745.tgz#9c202ce9cbf18a5b5e0ca47145fd127cc4dd2290" - integrity sha512-tRbzkaRI5gbUn5DEvF0dV4TQbMZ5CLkWeTAXmpC9IrYT+GE+x76i9p+o3RJ5l9XmdQlI1pPhVtE9uNcJJ0G0EA== +electron-to-chromium@^1.4.668, electron-to-chromium@^1.5.28: + version "1.5.41" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.5.41.tgz#eae1ba6c49a1a61d84cf8263351d3513b2bcc534" + integrity sha512-dfdv/2xNjX0P8Vzme4cfzHqnPm5xsZXwsolTYr0eyW18IUmNyG08vL+fttvinTfhKfIKdRoqkDIC9e9iWQCNYQ== electron-updater@^6.3.9: version "6.3.9" @@ -5955,10 +5950,10 @@ enhanced-resolve@^0.9.1: memory-fs "^0.2.0" tapable "^0.1.8" -enhanced-resolve@^5.0.0, enhanced-resolve@^5.16.0, enhanced-resolve@^5.7.0: - version "5.17.0" - resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-5.17.0.tgz#d037603789dd9555b89aaec7eb78845c49089bc5" - integrity sha512-dwDPwZL0dmye8Txp2gzFmA6sxALaSvdRDjPH0viLcKrtlOL3tw62nWWweVD1SdILDTJrbrL6tdWVN58Wo6U3eA== +enhanced-resolve@^5.0.0, enhanced-resolve@^5.17.1, enhanced-resolve@^5.7.0: + version "5.17.1" + resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-5.17.1.tgz#67bfbbcc2f81d511be77d686a90267ef7f898a15" + integrity sha512-LMHl3dXhTcfv8gM4kEzIUeTQ+7fpdA0l2tUf34BddXPkz2A5xJ5L/Pchd5BL6rdccM9QGvu0sWZzK1Z1t4wwyg== dependencies: graceful-fs "^4.2.4" tapable "^2.2.0" @@ -6169,10 +6164,10 @@ esbuild@^0.21.3: "@esbuild/win32-ia32" "0.21.5" "@esbuild/win32-x64" "0.21.5" -escalade@^3.1.1: - version "3.1.1" - resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40" - integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw== +escalade@^3.1.1, escalade@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.2.0.tgz#011a3f69856ba189dffa7dc8fcce99d2a87903e5" + integrity sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA== escape-goat@^2.0.0: version "2.1.1" @@ -7727,9 +7722,9 @@ import-from-esm@^1.3.3: import-meta-resolve "^4.0.0" import-local@^3.0.2: - version "3.1.0" - resolved "https://registry.yarnpkg.com/import-local/-/import-local-3.1.0.tgz#b4479df8a5fd44f6cdce24070675676063c95cb4" - integrity sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg== + version "3.2.0" + resolved "https://registry.yarnpkg.com/import-local/-/import-local-3.2.0.tgz#c3d5c745798c02a6f8b897726aba5100186ee260" + integrity sha512-2SPlun1JUPWoM6t3F0dw0FkCF/jWY8kttcY4f599GLTSjh2OCuuhdTkJQsEcZzBqbXZGKMK2OqW1oZsjtf/gQA== dependencies: pkg-dir "^4.2.0" resolve-cwd "^3.0.0" @@ -7916,11 +7911,11 @@ is-ci@^3.0.0: ci-info "^3.2.0" is-core-module@^2.11.0, is-core-module@^2.13.0, is-core-module@^2.13.1: - version "2.13.1" - resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.13.1.tgz#ad0d7532c6fea9da1ebdc82742d74525c6273384" - integrity sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw== + version "2.15.1" + resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.15.1.tgz#a7363a25bee942fefab0de13bf6aa372c82dcc37" + integrity sha512-z0vtXSwucUJtANQWldhbtbt7BnL0vxiFjIdDLAatwhDYty2bad6s+rijD6Ri4YuYJubLzIJLUidCh09e1djEVQ== dependencies: - hasown "^2.0.0" + hasown "^2.0.2" is-data-view@^1.0.1: version "1.0.1" @@ -8201,9 +8196,9 @@ isobject@^3.0.1: integrity sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg== istanbul-lib-coverage@^3.0.0, istanbul-lib-coverage@^3.2.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz#189e7909d0a39fa5a3dfad5b03f71947770191d3" - integrity sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw== + version "3.2.2" + resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz#2d166c4b0644d43a39f04bf6c2edd1e585f31756" + integrity sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg== istanbul-lib-instrument@^5.0.4: version "5.2.1" @@ -8217,13 +8212,13 @@ istanbul-lib-instrument@^5.0.4: semver "^6.3.0" istanbul-lib-instrument@^6.0.0: - version "6.0.1" - resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-6.0.1.tgz#71e87707e8041428732518c6fb5211761753fbdf" - integrity sha512-EAMEJBsYuyyztxMxW3g7ugGPkrZsV57v0Hmv3mm1uQsmB+QnZuepg731CRaIgeUVSdmsTngOkSnauNF8p7FIhA== + version "6.0.3" + resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-6.0.3.tgz#fa15401df6c15874bcb2105f773325d78c666765" + integrity sha512-Vtgk7L/R2JHyyGW07spoFlB8/lpjiOLTjMdms6AFMraYt3BaJauod/NGrfnVG/y4Ix1JEuMRPDPEj2ua+zz1/Q== dependencies: - "@babel/core" "^7.12.3" - "@babel/parser" "^7.14.7" - "@istanbuljs/schema" "^0.1.2" + "@babel/core" "^7.23.9" + "@babel/parser" "^7.23.9" + "@istanbuljs/schema" "^0.1.3" istanbul-lib-coverage "^3.2.0" semver "^7.5.4" @@ -8246,9 +8241,9 @@ istanbul-lib-source-maps@^4.0.0: source-map "^0.6.1" istanbul-reports@^3.1.3: - version "3.1.6" - resolved "https://registry.yarnpkg.com/istanbul-reports/-/istanbul-reports-3.1.6.tgz#2544bcab4768154281a2f0870471902704ccaa1a" - integrity sha512-TLgnMkKg3iTDsQ9PbPTdpfAK2DzjF9mqUG7RMgcQl8oFjad8ob4laGxv5XV5U9MAfx8D6tSJiUyuAwzLicaxlg== + version "3.1.7" + resolved "https://registry.yarnpkg.com/istanbul-reports/-/istanbul-reports-3.1.7.tgz#daed12b9e1dca518e15c056e1e537e741280fa0b" + integrity sha512-BewmUXImeuRk2YY0PVbxgKAysvhRPUQE0h5QRM++nVWyubKGV0l8qQ5op8+B2DOmwSe63Jivj0BjkPQVf8fP5g== dependencies: html-escaper "^2.0.0" istanbul-lib-report "^3.0.0" @@ -8769,10 +8764,10 @@ jsdom@^20.0.0: ws "^8.11.0" xml-name-validator "^4.0.0" -jsesc@^2.5.1: - version "2.5.2" - resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4" - integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA== +jsesc@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-3.0.2.tgz#bb8b09a6597ba426425f2e4a07245c3d00b9343e" + integrity sha512-xKqzzWXDttJuOcawBt4KnKHHIf5oQ/Cxax+0PWFG+DFDgHNAdi+TXECADI+RYiFUMmx8792xsMbbgXj4CwnP4g== jsesc@~0.5.0: version "0.5.0" @@ -9769,9 +9764,9 @@ micromark@^3.0.0: uvu "^0.5.0" micromatch@^4.0.0, micromatch@^4.0.2, micromatch@^4.0.4: - version "4.0.7" - resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.7.tgz#33e8190d9fe474a9895525f5618eee136d46c2e5" - integrity sha512-LPP/3KorzCwBxfeUuZmaR6bG2kdeHSbe0P2tY3FLRU4vYrjYz5hI4QZwV0njUx3jeuKe67YukQ1LSPZBKDqO/Q== + version "4.0.8" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.8.tgz#d66fa18f3a47076789320b9b1af32bd86d9fa202" + integrity sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA== dependencies: braces "^3.0.3" picomatch "^2.3.1" @@ -10004,7 +9999,7 @@ ms@2.1.2: resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== -ms@^2.0.0, ms@^2.1.1: +ms@^2.0.0, ms@^2.1.1, ms@^2.1.3: version "2.1.3" resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== @@ -10148,10 +10143,10 @@ node-int64@^0.4.0: resolved "https://registry.yarnpkg.com/node-int64/-/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b" integrity sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw== -node-releases@^2.0.14: - version "2.0.14" - resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.14.tgz#2ffb053bceb8b2be8495ece1ab6ce600c4461b0b" - integrity sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw== +node-releases@^2.0.14, node-releases@^2.0.18: + version "2.0.18" + resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.18.tgz#f010e8d35e2fe8d6b2944f03f70213ecedc4ca3f" + integrity sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g== noms@0.0.0: version "0.0.0" @@ -10631,9 +10626,9 @@ pickleparser@^0.2.1: integrity sha512-kMzY3uFYcR6OjOqr7nV2nkaXaBsUEOafu3zgPxeD6s/2ueMfVQH8lrymcDWBPGx0OkVxGMikxQit6jgByXjwBg== picocolors@^1.0.0, picocolors@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.1.0.tgz#5358b76a78cde483ba5cef6a9dc9671440b27d59" - integrity sha512-TQ92mBOW0l3LeMeyLV6mzy/kWr8lkd/hp3mTg7wYK7zJhuBStmGMBG0BdeDZS/dZx1IukaX6Bk11zcln25o1Aw== + version "1.1.1" + resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.1.1.tgz#3d321af3eab939b083c8f929a1d12cda81c26b6b" + integrity sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA== picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.2.3, picomatch@^2.3.1: version "2.3.1" @@ -11095,9 +11090,9 @@ pupa@^2.0.1: escape-goat "^2.0.0" pure-rand@^6.0.0: - version "6.0.4" - resolved "https://registry.yarnpkg.com/pure-rand/-/pure-rand-6.0.4.tgz#50b737f6a925468679bff00ad20eade53f37d5c7" - integrity sha512-LA0Y9kxMYv47GIPJy6MI84fqTd2HmYZI83W/kM/SkKfDlajnZYfmXFTxkbY+xSBPkLJxltMa9hIkmdc29eguMA== + version "6.1.0" + resolved "https://registry.yarnpkg.com/pure-rand/-/pure-rand-6.1.0.tgz#d173cf23258231976ccbdb05247c9787957604f2" + integrity sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA== qs@^6.5.1, qs@^6.7.0: version "6.11.2" @@ -11272,9 +11267,9 @@ react-is@^17.0.1, react-is@^17.0.2: integrity sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w== react-is@^18.0.0: - version "18.2.0" - resolved "https://registry.yarnpkg.com/react-is/-/react-is-18.2.0.tgz#199431eeaaa2e09f86427efbb4f1473edb47609b" - integrity sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w== + version "18.3.1" + resolved "https://registry.yarnpkg.com/react-is/-/react-is-18.3.1.tgz#e83557dc12eae63a99e003a46388b1dcbb44db7e" + integrity sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg== react-is@~16.3.0: version "16.3.2" @@ -12607,7 +12602,16 @@ string-length@^4.0.1: char-regex "^1.0.2" strip-ansi "^6.0.0" -"string-width-cjs@npm:string-width@^4.2.0", "string-width@^1.0.2 || 2 || 3 || 4", string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: +"string-width-cjs@npm:string-width@^4.2.0": + version "4.2.3" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" + integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== + dependencies: + emoji-regex "^8.0.0" + is-fullwidth-code-point "^3.0.0" + strip-ansi "^6.0.1" + +"string-width@^1.0.2 || 2 || 3 || 4", string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: version "4.2.3" resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== @@ -12712,7 +12716,14 @@ stringify-object@^3.3.0: is-obj "^1.0.1" is-regexp "^1.0.0" -"strip-ansi-cjs@npm:strip-ansi@^6.0.1", strip-ansi@^6.0.0, strip-ansi@^6.0.1: +"strip-ansi-cjs@npm:strip-ansi@^6.0.1": + version "6.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" + integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== + dependencies: + ansi-regex "^5.0.1" + +strip-ansi@^6.0.0, strip-ansi@^6.0.1: version "6.0.1" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== @@ -13320,6 +13331,11 @@ undici-types@~5.26.4: resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-5.26.5.tgz#bcd539893d00b56e964fd2657a4866b221a65617" integrity sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA== +undici-types@~6.19.2: + version "6.19.8" + resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-6.19.8.tgz#35111c9d1437ab83a7cdc0abae2f26d88eda0a02" + integrity sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw== + unherit@^1.0.4: version "1.1.3" resolved "https://registry.yarnpkg.com/unherit/-/unherit-1.1.3.tgz#6c9b503f2b41b262330c80e91c8614abdaa69c22" @@ -13540,13 +13556,13 @@ unzip-crx-3@^0.2.0: mkdirp "^0.5.1" yaku "^0.16.6" -update-browserslist-db@^1.0.13: - version "1.0.13" - resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz#3c5e4f5c083661bd38ef64b6328c26ed6c8248c4" - integrity sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg== +update-browserslist-db@^1.0.13, update-browserslist-db@^1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.1.1.tgz#80846fba1d79e82547fb661f8d141e0945755fe5" + integrity sha512-R8UzCaa9Az+38REPiJ1tXlImTJXlVfgHZsglwBD/k6nj76ctsH1E3q4doGrukiLQd3sGQYu56r5+lo5r94l29A== dependencies: - escalade "^3.1.1" - picocolors "^1.0.0" + escalade "^3.2.0" + picocolors "^1.1.0" uri-js@^4.2.2: version "4.4.1" @@ -13659,9 +13675,9 @@ v8-compile-cache@^2.0.3: integrity sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA== v8-to-istanbul@^9.0.1: - version "9.1.3" - resolved "https://registry.yarnpkg.com/v8-to-istanbul/-/v8-to-istanbul-9.1.3.tgz#ea456604101cd18005ac2cae3cdd1aa058a6306b" - integrity sha512-9lDD+EVI2fjFsMWXc6dy5JJzBsVTcQ2fVkfBvncZ6xJWG9wtBhOldG+mHkSL0+V1K/xgZz0JDO5UT5hFwHUghg== + version "9.3.0" + resolved "https://registry.yarnpkg.com/v8-to-istanbul/-/v8-to-istanbul-9.3.0.tgz#b9572abfa62bd556c16d75fdebc1a411d5ff3175" + integrity sha512-kiGUalWN+rgBJ/1OHZsBtU4rXZOfj/7rKQxULKlIzwzQSvMJUUNgPwJEEh7gU6xEVxC0ahoOBvN2YI8GH6FNgA== dependencies: "@jridgewell/trace-mapping" "^0.3.12" "@types/istanbul-lib-coverage" "^2.0.1" @@ -13934,21 +13950,20 @@ webpack-sources@^3.2.3: resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-3.2.3.tgz#2d4daab8451fd4b240cc27055ff6a0c2ccea0cde" integrity sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w== -webpack@^5.91.0: - version "5.91.0" - resolved "https://registry.yarnpkg.com/webpack/-/webpack-5.91.0.tgz#ffa92c1c618d18c878f06892bbdc3373c71a01d9" - integrity sha512-rzVwlLeBWHJbmgTC/8TvAcu5vpJNII+MelQpylD4jNERPwpBJOE2lEcko1zJX3QJeLjTTAnQxn/OJ8bjDzVQaw== +webpack@^5.95.0: + version "5.95.0" + resolved "https://registry.yarnpkg.com/webpack/-/webpack-5.95.0.tgz#8fd8c454fa60dad186fbe36c400a55848307b4c0" + integrity sha512-2t3XstrKULz41MNMBF+cJ97TyHdyQ8HCt//pqErqDvNjU9YQBnZxIHa11VXsi7F3mb5/aO2tuDxdeTPdU7xu9Q== dependencies: - "@types/eslint-scope" "^3.7.3" "@types/estree" "^1.0.5" "@webassemblyjs/ast" "^1.12.1" "@webassemblyjs/wasm-edit" "^1.12.1" "@webassemblyjs/wasm-parser" "^1.12.1" acorn "^8.7.1" - acorn-import-assertions "^1.9.0" + acorn-import-attributes "^1.9.5" browserslist "^4.21.10" chrome-trace-event "^1.0.2" - enhanced-resolve "^5.16.0" + enhanced-resolve "^5.17.1" es-module-lexer "^1.2.1" eslint-scope "5.1.1" events "^3.2.0" @@ -14053,7 +14068,7 @@ word-wrap@1.2.4, word-wrap@^1.2.3, word-wrap@~1.2.3: resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.4.tgz#cb4b50ec9aca570abd1f52f33cd45b6c61739a9f" integrity sha512-2V81OA4ugVo5pRo46hAoD2ivUJx8jXmWXfUkY4KFNw0hEptvN0QfH3K4nHiwzGeKl5rFKedV48QVoqYavy4YpA== -"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0", wrap-ansi@^7.0.0: +"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0": version "7.0.0" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== @@ -14071,6 +14086,15 @@ wrap-ansi@^6.2.0: string-width "^4.1.0" strip-ansi "^6.0.0" +wrap-ansi@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" + integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== + dependencies: + ansi-styles "^4.0.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" + wrap-ansi@^8.1.0: version "8.1.0" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-8.1.0.tgz#56dc22368ee570face1b49819975d9b9a5ead214" From b09270073427fac51f28f6ba1a8c437cb79f5d11 Mon Sep 17 00:00:00 2001 From: ArtemHoruzhenko Date: Mon, 21 Oct 2024 10:01:41 +0300 Subject: [PATCH 230/256] upgrade msw/cookie --- package.json | 1 + yarn.lock | 41 ++++++++++++++++++----------------------- 2 files changed, 19 insertions(+), 23 deletions(-) diff --git a/package.json b/package.json index 69024ebfa1..e5da4cf33c 100644 --- a/package.json +++ b/package.json @@ -81,6 +81,7 @@ "rawproto/protobufjs": "^7.2.5", "webpack-bundle-analyzer/ws": "^7.5.10", "msw/path-to-regexp": "^6.3.0", + "msw/cookie": "^0.7.0", "react-router-dom/react-router/path-to-regexp": "^1.9.0" }, "devDependencies": { diff --git a/yarn.lock b/yarn.lock index 7079f006f1..2d1524bbb5 100644 --- a/yarn.lock +++ b/yarn.lock @@ -27,7 +27,7 @@ dependencies: "@babel/highlight" "^7.10.4" -"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.10.4", "@babel/code-frame@^7.12.13", "@babel/code-frame@^7.24.2", "@babel/code-frame@^7.25.7": +"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.10.4", "@babel/code-frame@^7.12.13", "@babel/code-frame@^7.25.7": version "7.25.7" resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.25.7.tgz#438f2c524071531d643c6f0188e1e28f130cebc7" integrity sha512-0xZJFNE5XMpENsgfHYTw8FbX4kv53mFLn2i3XPoq69LyhYSCBJtitaHx9QnsVTrsogI4Z3+HtEfZ2/GFPOtf5g== @@ -35,7 +35,7 @@ "@babel/highlight" "^7.25.7" picocolors "^1.0.0" -"@babel/compat-data@^7.22.6", "@babel/compat-data@^7.23.5", "@babel/compat-data@^7.24.4", "@babel/compat-data@^7.25.7": +"@babel/compat-data@^7.22.6", "@babel/compat-data@^7.24.4", "@babel/compat-data@^7.25.7": version "7.25.8" resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.25.8.tgz#0376e83df5ab0eb0da18885c0140041f0747a402" integrity sha512-ZsysZyXY4Tlx+Q53XdnOFmqwfB9QDTHYxaZYajWRoBLuLEAwI2UIbtxOjWh/cFaa9IKUlcB+DDuoskLuKu56JA== @@ -61,7 +61,7 @@ json5 "^2.2.3" semver "^6.3.1" -"@babel/generator@^7.24.4", "@babel/generator@^7.25.7", "@babel/generator@^7.7.2": +"@babel/generator@^7.25.7", "@babel/generator@^7.7.2": version "7.25.7" resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.25.7.tgz#de86acbeb975a3e11ee92dd52223e6b03b479c56" integrity sha512-5Dqpl5fyV9pIAD62yK9P7fcA768uVPUyrQmqpqstHWgMma4feF1x/oFysBCVZLY5wJ2GkMUCdsNDnGZrPoR6rA== @@ -230,7 +230,7 @@ dependencies: "@babel/types" "^7.24.7" -"@babel/helper-string-parser@^7.23.4", "@babel/helper-string-parser@^7.25.7": +"@babel/helper-string-parser@^7.25.7": version "7.25.7" resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.25.7.tgz#d50e8d37b1176207b4fe9acedec386c565a44a54" integrity sha512-CbkjYdsJNHFk8uqpEkpCvRs3YRp9tY6FmFY7wLMSYuGYkrdUi7r2lc4/wqsvlHoMznX3WJ9IP8giGPq68T/Y6g== @@ -254,7 +254,7 @@ "@babel/template" "^7.22.15" "@babel/types" "^7.22.19" -"@babel/helpers@^7.24.4", "@babel/helpers@^7.25.7": +"@babel/helpers@^7.25.7": version "7.25.7" resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.25.7.tgz#091b52cb697a171fe0136ab62e54e407211f09c2" integrity sha512-Sv6pASx7Esm38KQpF/U/OXLwPPrdGHNKoeblRxgZRLXnAtnkEe4ptJPDtAZM7fBLadbc1Q07kQpSiGQ0Jg6tRA== @@ -262,7 +262,7 @@ "@babel/template" "^7.25.7" "@babel/types" "^7.25.7" -"@babel/highlight@^7.10.4", "@babel/highlight@^7.24.2", "@babel/highlight@^7.25.7": +"@babel/highlight@^7.10.4", "@babel/highlight@^7.25.7": version "7.25.7" resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.25.7.tgz#20383b5f442aa606e7b5e3043b0b1aafe9f37de5" integrity sha512-iYyACpW3iW8Fw+ZybQK+drQre+ns/tKpXbNESfrhNnPLIklLbXr7MYJ6gPEd0iETGLOK+SxMjVvKb/ffmk+FEw== @@ -272,7 +272,7 @@ js-tokens "^4.0.0" picocolors "^1.0.0" -"@babel/parser@^7.1.0", "@babel/parser@^7.14.7", "@babel/parser@^7.20.7", "@babel/parser@^7.23.9", "@babel/parser@^7.24.4", "@babel/parser@^7.25.7", "@babel/parser@^7.25.8": +"@babel/parser@^7.1.0", "@babel/parser@^7.14.7", "@babel/parser@^7.20.7", "@babel/parser@^7.23.9", "@babel/parser@^7.25.7", "@babel/parser@^7.25.8": version "7.25.8" resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.25.8.tgz#f6aaf38e80c36129460c1657c0762db584c9d5e2" integrity sha512-HcttkxzdPucv3nNFmfOOMfFf64KgdJVqm1KaCm25dPGMLElo9nsLvXeJECQg8UzPuBGLyTSA0ZzqCtDSzKTEoQ== @@ -1063,7 +1063,7 @@ "@babel/parser" "^7.25.7" "@babel/types" "^7.25.7" -"@babel/traverse@^7.24.1", "@babel/traverse@^7.25.7": +"@babel/traverse@^7.25.7": version "7.25.7" resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.25.7.tgz#83e367619be1cab8e4f2892ef30ba04c26a40fa8" integrity sha512-jatJPT1Zjqvh/1FyJs6qAHL+Dzb7sTb+xr7Q+gM1b+1oBsMsQQ4FkVKb6dFlJvLlVssqkRzV05Jzervt9yhnzg== @@ -1076,7 +1076,7 @@ debug "^4.3.1" globals "^11.1.0" -"@babel/types@^7.0.0", "@babel/types@^7.20.7", "@babel/types@^7.21.3", "@babel/types@^7.22.15", "@babel/types@^7.22.19", "@babel/types@^7.22.5", "@babel/types@^7.23.0", "@babel/types@^7.23.4", "@babel/types@^7.24.0", "@babel/types@^7.24.7", "@babel/types@^7.25.7", "@babel/types@^7.25.8", "@babel/types@^7.3.3", "@babel/types@^7.4.4": +"@babel/types@^7.0.0", "@babel/types@^7.20.7", "@babel/types@^7.21.3", "@babel/types@^7.22.15", "@babel/types@^7.22.19", "@babel/types@^7.22.5", "@babel/types@^7.23.0", "@babel/types@^7.23.4", "@babel/types@^7.24.7", "@babel/types@^7.25.7", "@babel/types@^7.25.8", "@babel/types@^7.3.3", "@babel/types@^7.4.4": version "7.25.8" resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.25.8.tgz#5cf6037258e8a9bcad533f4979025140cb9993e1" integrity sha512-JWtuCu8VQsMladxVz/P4HzHUGCAwpuqacmowgXFs5XjxIgKuNjnLokQzuVjlTvIzODaDmpjT3oxcC48vyk9EWg== @@ -4126,7 +4126,7 @@ browserify-zlib@^0.1.4: dependencies: pako "~0.2.0" -browserslist@^4.0.0, browserslist@^4.14.5, browserslist@^4.16.8, browserslist@^4.21.10, browserslist@^4.22.2, browserslist@^4.23.0, browserslist@^4.24.0: +browserslist@^4.0.0, browserslist@^4.14.5, browserslist@^4.16.8, browserslist@^4.21.10, browserslist@^4.23.0, browserslist@^4.24.0: version "4.24.0" resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.24.0.tgz#a1325fe4bc80b64fda169629fc01b3d6cecd38d4" integrity sha512-Rmb62sR1Zpjql25eSanFGEhAxcFwfA1K0GuQcLoaJBAcENegrQut3hYdhXFF1obQfiDyqIW/cLM5HSJ/9k884A== @@ -4320,7 +4320,7 @@ caniuse-api@^3.0.0: lodash.memoize "^4.1.2" lodash.uniq "^4.5.0" -caniuse-lite@^1.0.0, caniuse-lite@^1.0.30001251, caniuse-lite@^1.0.30001587, caniuse-lite@^1.0.30001663: +caniuse-lite@^1.0.0, caniuse-lite@^1.0.30001251, caniuse-lite@^1.0.30001663: version "1.0.30001669" resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001669.tgz#fda8f1d29a8bfdc42de0c170d7f34a9cf19ed7a3" integrity sha512-DlWzFDJqstqtIVx1zeSpIMLjunf5SmwOw0N2Ck/QSQdS8PLS4+9HrLaYei4w8BIAL7IB/UEDu889d8vhCTPA0w== @@ -4719,10 +4719,10 @@ convert-source-map@^2.0.0: resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-2.0.0.tgz#4b560f649fc4e918dd0ab75cf4961e8bc882d82a" integrity sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg== -cookie@^0.4.2: - version "0.4.2" - resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.4.2.tgz#0e41f24de5ecf317947c82fc789e06a884824432" - integrity sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA== +cookie@^0.4.2, cookie@^0.7.0: + version "0.7.2" + resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.7.2.tgz#556369c472a2ba910f2979891b526b3436237ed7" + integrity sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w== cookiejar@^2.1.0: version "2.1.4" @@ -5858,7 +5858,7 @@ electron-store@*, electron-store@^8.0.0: conf "^10.2.0" type-fest "^2.17.0" -electron-to-chromium@^1.4.668, electron-to-chromium@^1.5.28: +electron-to-chromium@^1.5.28: version "1.5.41" resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.5.41.tgz#eae1ba6c49a1a61d84cf8263351d3513b2bcc534" integrity sha512-dfdv/2xNjX0P8Vzme4cfzHqnPm5xsZXwsolTYr0eyW18IUmNyG08vL+fttvinTfhKfIKdRoqkDIC9e9iWQCNYQ== @@ -9994,11 +9994,6 @@ mrmime@^2.0.0: resolved "https://registry.yarnpkg.com/mrmime/-/mrmime-2.0.0.tgz#151082a6e06e59a9a39b46b3e14d5cfe92b3abb4" integrity sha512-eu38+hdgojoyq63s+yTpN4XMBdt5l8HhMhc4VKLO9KM5caLIBvUm4thi7fFaxyTmCKeNnXZ5pAlBwCUnhA09uw== -ms@2.1.2: - version "2.1.2" - resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" - integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== - ms@^2.0.0, ms@^2.1.1, ms@^2.1.3: version "2.1.3" resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" @@ -10143,7 +10138,7 @@ node-int64@^0.4.0: resolved "https://registry.yarnpkg.com/node-int64/-/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b" integrity sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw== -node-releases@^2.0.14, node-releases@^2.0.18: +node-releases@^2.0.18: version "2.0.18" resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.18.tgz#f010e8d35e2fe8d6b2944f03f70213ecedc4ca3f" integrity sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g== @@ -13556,7 +13551,7 @@ unzip-crx-3@^0.2.0: mkdirp "^0.5.1" yaku "^0.16.6" -update-browserslist-db@^1.0.13, update-browserslist-db@^1.1.0: +update-browserslist-db@^1.1.0: version "1.1.1" resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.1.1.tgz#80846fba1d79e82547fb661f8d141e0945755fe5" integrity sha512-R8UzCaa9Az+38REPiJ1tXlImTJXlVfgHZsglwBD/k6nj76ctsH1E3q4doGrukiLQd3sGQYu56r5+lo5r94l29A== From 55dca6af1d05b2638678444d8d6ee082f514ab25 Mon Sep 17 00:00:00 2001 From: kchepikava Date: Mon, 21 Oct 2024 11:02:53 +0200 Subject: [PATCH 231/256] RI-6225 social button fix --- .../src/components/oauth/shared/oauth-form/OAuthForm.tsx | 4 ++++ .../shared/oauth-social-buttons/OAuthSocialButtons.tsx | 7 ++++--- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/redisinsight/ui/src/components/oauth/shared/oauth-form/OAuthForm.tsx b/redisinsight/ui/src/components/oauth/shared/oauth-form/OAuthForm.tsx index d2ad50d5dc..9670377127 100644 --- a/redisinsight/ui/src/components/oauth/shared/oauth-form/OAuthForm.tsx +++ b/redisinsight/ui/src/components/oauth/shared/oauth-form/OAuthForm.tsx @@ -25,6 +25,7 @@ const OAuthForm = ({ const dispatch = useDispatch() const [authStrategy, setAuthStrategy] = useState('') + const [disabled, setDisabled] = useState(false) const initOAuthProcess = (strategy: OAuthStrategy, action: string, data?: {}) => { dispatch(signIn()) @@ -32,6 +33,8 @@ const OAuthForm = ({ } const onSocialButtonClick = (authStrategy: OAuthStrategy) => { + setDisabled(true) + setTimeout(() => { setDisabled(false) }, 1000) dispatch(enableUserAnalyticsAction()) setAuthStrategy(authStrategy) onClick?.(authStrategy) @@ -83,6 +86,7 @@ const OAuthForm = ({ ) ) diff --git a/redisinsight/ui/src/components/oauth/shared/oauth-social-buttons/OAuthSocialButtons.tsx b/redisinsight/ui/src/components/oauth/shared/oauth-social-buttons/OAuthSocialButtons.tsx index 8c5fd4c33b..29227a53f6 100644 --- a/redisinsight/ui/src/components/oauth/shared/oauth-social-buttons/OAuthSocialButtons.tsx +++ b/redisinsight/ui/src/components/oauth/shared/oauth-social-buttons/OAuthSocialButtons.tsx @@ -1,4 +1,4 @@ -import React from 'react' +import React, { useState } from 'react' import { EuiButtonEmpty, EuiIcon, EuiText, EuiToolTip } from '@elastic/eui' import cx from 'classnames' import { useSelector } from 'react-redux' @@ -15,10 +15,11 @@ export interface Props { onClick: (authStrategy: OAuthStrategy) => void className?: string inline?: boolean + disabled?: boolean } const OAuthSocialButtons = (props: Props) => { - const { onClick, className, inline } = props + const { onClick, className, inline, disabled } = props const agreement = useSelector(oauthCloudPAgreementSelector) @@ -58,7 +59,7 @@ const OAuthSocialButtons = (props: Props) => { > <> { onClick(strategy) From 3e12d699247dfd2c2e80092223ce5870ae608800 Mon Sep 17 00:00:00 2001 From: vlad-dargel Date: Tue, 22 Oct 2024 11:14:25 +0200 Subject: [PATCH 232/256] e2e/feature/RI-6220_remove-rdi-pipeline-template --- tests/e2e/pageObjects/rdi-instance-page.ts | 12 +++------- .../web/critical-path/rdi/add-job.e2e.ts | 23 ++++++++----------- .../critical-path/rdi/configuration.e2e.ts | 17 +++++++------- .../web/critical-path/rdi/navigation.e2e.ts | 3 +-- 4 files changed, 21 insertions(+), 34 deletions(-) diff --git a/tests/e2e/pageObjects/rdi-instance-page.ts b/tests/e2e/pageObjects/rdi-instance-page.ts index 7f1bcc6746..960edfc335 100644 --- a/tests/e2e/pageObjects/rdi-instance-page.ts +++ b/tests/e2e/pageObjects/rdi-instance-page.ts @@ -52,7 +52,6 @@ export class RdiInstancePage extends BaseOverviewPage { templateButton = Selector('[data-testid^=template-trigger-]'); templateApplyButton = Selector('[data-testid=template-apply-btn]'); templateCancelButton = Selector('[data-testid=template-cancel-btn]'); - pipelineDropdown = Selector('[data-testid=pipeline-type-select]'); databaseDropdown = Selector('[data-testid=db-type-select]'); //dialog @@ -77,17 +76,12 @@ export class RdiInstancePage extends BaseOverviewPage { /** * Select value from template dropdowns - * @param pipeline value of pipeline dropdown * @param database value of database dropdown */ - async setTemplateDropdownValue(pipeline: RdiTemplatePipelineType, database?: RdiTemplateDatabaseType): Promise { - await t.click(this.pipelineDropdown); - let selector = Selector(`[id='${pipeline}']`); - await t.click(selector); + async setTemplateDropdownValue(database?: RdiTemplateDatabaseType): Promise { if(database != null) { await t.click(this.databaseDropdown); - selector = Selector(`[id='${database}']`); - await t.click(selector); + await t.click(Selector(`[id='${database}']`)); } await t.click(this.templateApplyButton); } @@ -97,8 +91,8 @@ export class RdiInstancePage extends BaseOverviewPage { * @param option option to select */ async selectStartPipelineOption(option: RdiPopoverOptions): Promise { - const selector = Selector(`[data-testid='${option}-source-pipeline-dialog']`); + await t.click(selector); } diff --git a/tests/e2e/tests/web/critical-path/rdi/add-job.e2e.ts b/tests/e2e/tests/web/critical-path/rdi/add-job.e2e.ts index b2f450dadb..6f25d2c020 100644 --- a/tests/e2e/tests/web/critical-path/rdi/add-job.e2e.ts +++ b/tests/e2e/tests/web/critical-path/rdi/add-job.e2e.ts @@ -80,29 +80,24 @@ test('Verify that user can add, edit and delete job', async() => { test('Verify that user insert template for jobs', async() => { const jobName = 'testJob'; const disabledAttribute = 'isDisabled'; - const defaultValue = 'ingest'; const templateWords = 'server_name: chinook'; - // should be empty config + const templateInsertedTooltip = 'Templates can be accessed only with the empty Editor to prevent potential data loss.'; + // Should be empty config await rdiInstancePage.PipelineManagementPanel.addJob(jobName); await rdiInstancePage.PipelineManagementPanel.openJobByName(jobName); - await t.expect(rdiInstancePage.templateApplyButton.visible).ok('the template popover is not expanded'); - const buttonClass = rdiInstancePage.templateApplyButton.getAttribute('class'); - await t.expect(buttonClass).notContains(disabledAttribute, 'Apply button is disabled'); - await t.click(rdiInstancePage.templateCancelButton); - await t.expect(rdiInstancePage.templateApplyButton.exists).notOk('the template popover is not closed'); - await t.click(rdiInstancePage.templateButton); - await t.expect(rdiInstancePage.templateApplyButton.visible).ok('the template popover is not expanded'); - await t.expect(rdiInstancePage.pipelineDropdown.textContent).eql(defaultValue, 'the default value is set incorrectly'); - await rdiInstancePage.setTemplateDropdownValue(RdiTemplatePipelineType.Ingest); - //verify uniq templates words - should be undated when templates are added + // Verify uniq templates words - should be undated when templates are added const enteredText = await rdiInstancePage.MonacoEditor.getTextFromMonaco(); + // Verify that user can see the template is inserted for the empty editor when clicking on the “Insert template” in jobs await t.expect(enteredText).contains(templateWords, 'template is incorrect'); - await t.click(rdiInstancePage.templateButton); - await t.expect(buttonClass).contains(disabledAttribute, 'Apply button is active'); + // Verify that user can see a standard validation on disabled Insert template button when the editor is not empty + await t.hover(myRedisDatabasePage.AddRedisDatabase.testConnectionBtn); + await rdiInstancePage.verifyTooltipContainsText(templateInsertedTooltip); + const buttonClass = rdiInstancePage.templateButton.getAttribute('class'); + await t.expect(buttonClass).contains(disabledAttribute, 'Insert Template button is not disabled'); }); test('Verify that user can change job config', async() => { const jobName = 'testJob'; diff --git a/tests/e2e/tests/web/critical-path/rdi/configuration.e2e.ts b/tests/e2e/tests/web/critical-path/rdi/configuration.e2e.ts index 9915947c65..21fab3e873 100644 --- a/tests/e2e/tests/web/critical-path/rdi/configuration.e2e.ts +++ b/tests/e2e/tests/web/critical-path/rdi/configuration.e2e.ts @@ -9,7 +9,6 @@ import { RdiInstancesListPage } from '../../../../pageObjects/rdi-instances-list import { RdiPopoverOptions, RdiTemplateDatabaseType, - RdiTemplatePipelineType, RedisOverviewPage, TextConnectionSection } from '../../../../helpers/constants'; @@ -132,27 +131,27 @@ test('Verify that link on configuration is valid', async() => { test('Verify that user can insert template', async() => { const disabledAttribute = 'isDisabled'; - const defaultValue = 'ingest'; + const defaultValue = 'mongodb'; const templateWords = 'type: mysql'; // should be empty config await myRedisDatabasePage.setActivePage(RedisOverviewPage.Rdi); await rdiInstancesListPage.clickRdiByName(rdiInstance.name); await rdiInstancePage.selectStartPipelineOption(RdiPopoverOptions.Pipeline); - await t.expect(rdiInstancePage.templateApplyButton.visible).ok('the template popover is not expanded'); + await t.expect(rdiInstancePage.templateApplyButton.visible).ok('The template popover is not expanded'); const buttonClass = rdiInstancePage.templateApplyButton.getAttribute('class'); await t.expect(buttonClass).notContains(disabledAttribute, 'Apply button is disabled'); await t.click(rdiInstancePage.templateCancelButton); - await t.expect(rdiInstancePage.templateApplyButton.exists).notOk('the template popover is not closed'); + await t.expect(rdiInstancePage.templateApplyButton.exists).notOk('The template popover is not closed'); await t.click(rdiInstancePage.templateButton); - await t.expect(rdiInstancePage.templateApplyButton.visible).ok('the template popover is not expanded'); - await t.expect(rdiInstancePage.pipelineDropdown.textContent).eql(defaultValue, 'the default value is set incorrectly'); - await rdiInstancePage.setTemplateDropdownValue(RdiTemplatePipelineType.Ingest, RdiTemplateDatabaseType.MySql); + await t.expect(rdiInstancePage.templateApplyButton.visible).ok('The template popover is not expanded'); + await t.expect(rdiInstancePage.databaseDropdown.textContent).eql(defaultValue, 'The default value is set incorrectly'); + await rdiInstancePage.setTemplateDropdownValue(RdiTemplateDatabaseType.MySql); const enteredText = await rdiInstancePage.MonacoEditor.getTextFromMonaco(); - await t.expect(enteredText).contains(templateWords, 'template is incorrect'); + await t.expect(enteredText).contains(templateWords, 'Template is incorrect'); await t.click(rdiInstancePage.templateButton); await t.expect(buttonClass).contains(disabledAttribute, 'Apply button is active'); - await t.expect(rdiInstancePage.pipelineDropdown.textContent).eql(defaultValue, 'the value is set incorrectly'); + await t.expect(rdiInstancePage.databaseDropdown.textContent).eql(defaultValue, 'the value is set incorrectly'); }); diff --git a/tests/e2e/tests/web/critical-path/rdi/navigation.e2e.ts b/tests/e2e/tests/web/critical-path/rdi/navigation.e2e.ts index 393db68b8b..89fe157636 100644 --- a/tests/e2e/tests/web/critical-path/rdi/navigation.e2e.ts +++ b/tests/e2e/tests/web/critical-path/rdi/navigation.e2e.ts @@ -7,7 +7,6 @@ import { MyRedisDatabasePage } from '../../../../pageObjects'; import { RdiPopoverOptions, RdiTemplateDatabaseType, - RdiTemplatePipelineType, RedisOverviewPage } from '../../../../helpers/constants'; import { RdiInstancesListPage } from '../../../../pageObjects/rdi-instances-list-page'; @@ -103,7 +102,7 @@ test('Verify that confirmation message is displayed, if there are unsaved change await t.click(rdiInstancePage.PipelineManagementPanel.configurationTabLink); await t.click(rdiInstancePage.templateButton); - await rdiInstancePage.setTemplateDropdownValue(RdiTemplatePipelineType.Ingest, RdiTemplateDatabaseType.MySql); + await rdiInstancePage.setTemplateDropdownValue(RdiTemplateDatabaseType.MySql); await t.click(rdiInstancePage.NavigationPanel.myRedisDBButton); await t.click(rdiInstancePage.proceedNavigateDialog); await t.expect(rdiInstancesListPage.rdiInstanceButton.exists).ok('the user is not navigated to the panel'); From 9e98e73089b393ad03f9340ad49e148c6f1272ee Mon Sep 17 00:00:00 2001 From: kchepikava Date: Wed, 23 Oct 2024 09:56:05 +0200 Subject: [PATCH 233/256] RI-6240 fix tooltip style --- .../components/template-button/TemplateButton.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/redisinsight/ui/src/pages/rdi/pipeline-management/components/template-button/TemplateButton.tsx b/redisinsight/ui/src/pages/rdi/pipeline-management/components/template-button/TemplateButton.tsx index 875e567ff4..123f6a0087 100644 --- a/redisinsight/ui/src/pages/rdi/pipeline-management/components/template-button/TemplateButton.tsx +++ b/redisinsight/ui/src/pages/rdi/pipeline-management/components/template-button/TemplateButton.tsx @@ -43,7 +43,6 @@ const TemplateButton = ({ setFieldValue, value }: TemplateButtonProps) => { content={getTooltipContent(value, !templateOption)} position="bottom" display="inlineBlock" - className={styles.btn} anchorClassName="flex-row" > Date: Wed, 23 Oct 2024 10:10:13 +0200 Subject: [PATCH 234/256] #RI-6234 - fix error showing when no indexes --- .../ui/src/pages/workbench/components/query/QueryWrapper.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/redisinsight/ui/src/pages/workbench/components/query/QueryWrapper.tsx b/redisinsight/ui/src/pages/workbench/components/query/QueryWrapper.tsx index f34b78ec2c..09242df622 100644 --- a/redisinsight/ui/src/pages/workbench/components/query/QueryWrapper.tsx +++ b/redisinsight/ui/src/pages/workbench/components/query/QueryWrapper.tsx @@ -51,7 +51,7 @@ const QueryWrapper = (props: Props) => { if (!connectedIndstanceId) return // fetch indexes - dispatch(fetchRedisearchListAction()) + dispatch(fetchRedisearchListAction(undefined, undefined, false)) }, [connectedIndstanceId]) const Placeholder = ( From a342240e2f9b717fec11e1d75149f36d70ee65af Mon Sep 17 00:00:00 2001 From: KIvanow Date: Wed, 23 Oct 2024 14:44:21 +0300 Subject: [PATCH 235/256] RI-6171 User cannot create vector index using form --- .../CreateRedisearchIndexWrapper.spec.tsx | 21 -------------- .../create-redisearch-index/constants.ts | 10 ------- redisinsight/ui/src/utils/redisearch.ts | 4 +-- .../ui/src/utils/tests/redisearch.spec.ts | 28 +++++++++---------- 4 files changed, 15 insertions(+), 48 deletions(-) diff --git a/redisinsight/ui/src/pages/browser/components/create-redisearch-index/CreateRedisearchIndexWrapper.spec.tsx b/redisinsight/ui/src/pages/browser/components/create-redisearch-index/CreateRedisearchIndexWrapper.spec.tsx index 0023850ea0..9d71c55cec 100644 --- a/redisinsight/ui/src/pages/browser/components/create-redisearch-index/CreateRedisearchIndexWrapper.spec.tsx +++ b/redisinsight/ui/src/pages/browser/components/create-redisearch-index/CreateRedisearchIndexWrapper.spec.tsx @@ -115,25 +115,4 @@ describe('CreateRedisearchIndexWrapper', () => { expect(screen.getByTestId('identifier-info-icon')).toBeInTheDocument() }) - - it('should not have geoshape option ', () => { - const { queryByText } = render() - - fireEvent.click(screen.getByTestId('field-type-0')) - - expect(queryByText('GEOSHAPE')).not.toBeInTheDocument() - }) - - it('should have geoshape option ', () => { - const connectedInstanceSelectorMock = jest.fn().mockReturnValueOnce({ - id: '1', - modules: [{ name: 'search', semanticVersion: '2.8.4' }] - }) - connectedInstanceSelector.mockImplementation(connectedInstanceSelectorMock) - - const { queryByText } = render() - fireEvent.click(screen.getByTestId('field-type-0')) - - expect(queryByText('GEOSHAPE')).toBeInTheDocument() - }) }) diff --git a/redisinsight/ui/src/pages/browser/components/create-redisearch-index/constants.ts b/redisinsight/ui/src/pages/browser/components/create-redisearch-index/constants.ts index bce64093c5..afde715b26 100644 --- a/redisinsight/ui/src/pages/browser/components/create-redisearch-index/constants.ts +++ b/redisinsight/ui/src/pages/browser/components/create-redisearch-index/constants.ts @@ -5,8 +5,6 @@ export enum FieldTypes { TAG = 'tag', NUMERIC = 'numeric', GEO = 'geo', - VECTOR = 'vector', - GEOSHAPE = 'geoshape', } export enum RedisearchIndexKeyType { @@ -44,12 +42,4 @@ export const FIELD_TYPE_OPTIONS = [ text: 'GEO', value: FieldTypes.GEO, }, - { - text: 'GEOSHAPE', - value: FieldTypes.GEOSHAPE, - }, - { - text: 'VECTOR', - value: FieldTypes.VECTOR, - } ] diff --git a/redisinsight/ui/src/utils/redisearch.ts b/redisinsight/ui/src/utils/redisearch.ts index 690fe6ddc4..79ad18dd76 100644 --- a/redisinsight/ui/src/utils/redisearch.ts +++ b/redisinsight/ui/src/utils/redisearch.ts @@ -4,7 +4,7 @@ import { REDISEARCH_GEOSHAPE_SEMANTIC_VERSION, REDISEARCH_GEOSHAPE_VERSION, } from 'uiSrc/constants' -import { FIELD_TYPE_OPTIONS, FieldTypes } from 'uiSrc/pages/browser/components/create-redisearch-index/constants' +import { FIELD_TYPE_OPTIONS } from 'uiSrc/pages/browser/components/create-redisearch-index/constants' import { AdditionalRedisModule } from 'apiSrc/modules/database/models/additional.redis.module' const isGeoshapeOptionAvailable = (modules: AdditionalRedisModule[]): boolean => @@ -17,7 +17,7 @@ const isGeoshapeOptionAvailable = (modules: AdditionalRedisModule[]): boolean => )))) export const getFieldTypeOptions = (modules: AdditionalRedisModule[] = []) => FIELD_TYPE_OPTIONS - .filter((option) => option.value !== FieldTypes.GEOSHAPE || isGeoshapeOptionAvailable(modules)) + .filter(() => isGeoshapeOptionAvailable(modules)) .map(({ value, text }) => ({ value, inputDisplay: text, diff --git a/redisinsight/ui/src/utils/tests/redisearch.spec.ts b/redisinsight/ui/src/utils/tests/redisearch.spec.ts index 703ba565a2..c6b0b567aa 100644 --- a/redisinsight/ui/src/utils/tests/redisearch.spec.ts +++ b/redisinsight/ui/src/utils/tests/redisearch.spec.ts @@ -12,31 +12,29 @@ const ALL_OPTIONS = FIELD_TYPE_OPTIONS.map(({ value, text }) => ({ inputDisplay: text, })) -const WITHOUT_GEOSHAPE_OPTIONS = ALL_OPTIONS.filter(({ value }) => value !== FieldTypes.GEOSHAPE) - const getFieldTypeOptionsTests: any[] = [ [[['1', '2.8.4'], [RedisDefaultModules.Search, '2.8.4']].map(nameAndVersionToModule), ALL_OPTIONS], - [[['1', '2.8.4'], [RedisDefaultModules.Search, '2.8.3']].map(nameAndVersionToModule), WITHOUT_GEOSHAPE_OPTIONS], + [[['1', '2.8.4'], [RedisDefaultModules.Search, '2.8.3']].map(nameAndVersionToModule), ALL_OPTIONS], [[['1', '2.8.3'], [RedisDefaultModules.SearchLight, '2.8.4']].map(nameAndVersionToModule), ALL_OPTIONS], - [[['1', '2.8.4'], [RedisDefaultModules.SearchLight, '2.8.3']].map(nameAndVersionToModule), WITHOUT_GEOSHAPE_OPTIONS], + [[['1', '2.8.4'], [RedisDefaultModules.SearchLight, '2.8.3']].map(nameAndVersionToModule), ALL_OPTIONS], [[['1', '2.8.3'], [RedisDefaultModules.FT, '2.8.4']].map(nameAndVersionToModule), ALL_OPTIONS], - [[['1', '2.8.4'], [RedisDefaultModules.FT, '2.8.3']].map(nameAndVersionToModule), WITHOUT_GEOSHAPE_OPTIONS], + [[['1', '2.8.4'], [RedisDefaultModules.FT, '2.8.3']].map(nameAndVersionToModule), ALL_OPTIONS], [[['1', '2.8.3'], [RedisDefaultModules.FTL, '2.8.4']].map(nameAndVersionToModule), ALL_OPTIONS], - [[['1', '2.8.4'], [RedisDefaultModules.FTL, '2.8.3']].map(nameAndVersionToModule), WITHOUT_GEOSHAPE_OPTIONS], - [[['1', '2.8.4'], [RedisDefaultModules.Gears, '2.8.4']].map(nameAndVersionToModule), WITHOUT_GEOSHAPE_OPTIONS], + [[['1', '2.8.4'], [RedisDefaultModules.FTL, '2.8.3']].map(nameAndVersionToModule), ALL_OPTIONS], + [[['1', '2.8.4'], [RedisDefaultModules.Gears, '2.8.4']].map(nameAndVersionToModule), ALL_OPTIONS], [[['1', '2.8.4'], [RedisDefaultModules.Search, undefined, 20804]].map(nameAndVersionToModule), ALL_OPTIONS], - [[['1', '2.8.4'], [RedisDefaultModules.Search, undefined, 20803]].map(nameAndVersionToModule), WITHOUT_GEOSHAPE_OPTIONS], + [[['1', '2.8.4'], [RedisDefaultModules.Search, undefined, 20803]].map(nameAndVersionToModule), ALL_OPTIONS], [[['1', '2.8.4'], [RedisDefaultModules.SearchLight, undefined, 20804]].map(nameAndVersionToModule), ALL_OPTIONS], - [[['1', '2.8.4'], [RedisDefaultModules.SearchLight, undefined, 20803]].map(nameAndVersionToModule), WITHOUT_GEOSHAPE_OPTIONS], + [[['1', '2.8.4'], [RedisDefaultModules.SearchLight, undefined, 20803]].map(nameAndVersionToModule), ALL_OPTIONS], [[['1', '2.8.4'], [RedisDefaultModules.SearchLight, undefined, 20804]].map(nameAndVersionToModule), ALL_OPTIONS], - [[['1', '2.8.4'], [RedisDefaultModules.SearchLight, undefined, 20803]].map(nameAndVersionToModule), WITHOUT_GEOSHAPE_OPTIONS], + [[['1', '2.8.4'], [RedisDefaultModules.SearchLight, undefined, 20803]].map(nameAndVersionToModule), ALL_OPTIONS], [[['1', '2.8.4'], [RedisDefaultModules.FT, undefined, 20804]].map(nameAndVersionToModule), ALL_OPTIONS], - [[['1', '2.8.4'], [RedisDefaultModules.FT, undefined, 20803]].map(nameAndVersionToModule), WITHOUT_GEOSHAPE_OPTIONS], + [[['1', '2.8.4'], [RedisDefaultModules.FT, undefined, 20803]].map(nameAndVersionToModule), ALL_OPTIONS], [[['1', '2.8.4'], [RedisDefaultModules.FTL, undefined, 20804]].map(nameAndVersionToModule), ALL_OPTIONS], - [[['1', '2.8.4'], [RedisDefaultModules.FTL, undefined, 20803]].map(nameAndVersionToModule), WITHOUT_GEOSHAPE_OPTIONS], - [[['1', '2.8.4'], [RedisDefaultModules.Gears, undefined, 20804]].map(nameAndVersionToModule), WITHOUT_GEOSHAPE_OPTIONS], - [[['1', '2.8.4'], [RedisDefaultModules.Gears, undefined, 20803]].map(nameAndVersionToModule), WITHOUT_GEOSHAPE_OPTIONS], - [[['1', '2.8.4'], [RedisDefaultModules.FTL, '2.8.3', 20803]].map(nameAndVersionToModule), WITHOUT_GEOSHAPE_OPTIONS], + [[['1', '2.8.4'], [RedisDefaultModules.FTL, undefined, 20803]].map(nameAndVersionToModule), ALL_OPTIONS], + [[['1', '2.8.4'], [RedisDefaultModules.Gears, undefined, 20804]].map(nameAndVersionToModule), ALL_OPTIONS], + [[['1', '2.8.4'], [RedisDefaultModules.Gears, undefined, 20803]].map(nameAndVersionToModule), ALL_OPTIONS], + [[['1', '2.8.4'], [RedisDefaultModules.FTL, '2.8.3', 20803]].map(nameAndVersionToModule), ALL_OPTIONS], [[['1', '2.8.4'], [RedisDefaultModules.FTL, '2.8.4', 20804]].map(nameAndVersionToModule), ALL_OPTIONS], ] From 44d223c33092b42c42f419d8349cba0b7c33447d Mon Sep 17 00:00:00 2001 From: vlad-dargel Date: Wed, 23 Oct 2024 14:45:01 +0200 Subject: [PATCH 236/256] e2e/bugfix/tsconfig-fix --- tests/e2e/helpers/api/api-common.ts | 2 +- .../files-auto-update/enablement-area-autoupdate.e2e.ts | 2 +- .../files-auto-update/promo-button-autoupdate.e2e.ts | 2 +- tests/e2e/tsconfig.json | 1 - tests/e2e/tsconfig.testcafe.json | 1 + 5 files changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/e2e/helpers/api/api-common.ts b/tests/e2e/helpers/api/api-common.ts index 81eed16088..7f45bf24b0 100644 --- a/tests/e2e/helpers/api/api-common.ts +++ b/tests/e2e/helpers/api/api-common.ts @@ -1,4 +1,4 @@ -import * as request from 'supertest'; +import request from 'supertest'; import { Common } from '../common'; const endpoint = Common.getEndpoint(); diff --git a/tests/e2e/tests/electron/critical-path/files-auto-update/enablement-area-autoupdate.e2e.ts b/tests/e2e/tests/electron/critical-path/files-auto-update/enablement-area-autoupdate.e2e.ts index d5b01945bb..e8baf805ab 100644 --- a/tests/e2e/tests/electron/critical-path/files-auto-update/enablement-area-autoupdate.e2e.ts +++ b/tests/e2e/tests/electron/critical-path/files-auto-update/enablement-area-autoupdate.e2e.ts @@ -1,7 +1,7 @@ // import { join } from 'path'; // import * as os from 'os'; import * as fs from 'fs'; -import * as editJsonFile from 'edit-json-file'; +import editJsonFile from 'edit-json-file'; import { DatabaseHelper } from '../../../../helpers/database'; import { MyRedisDatabasePage, WorkbenchPage } from '../../../../pageObjects'; import { commonUrl, ossStandaloneConfig, workingDirectory } from '../../../../helpers/conf'; diff --git a/tests/e2e/tests/electron/critical-path/files-auto-update/promo-button-autoupdate.e2e.ts b/tests/e2e/tests/electron/critical-path/files-auto-update/promo-button-autoupdate.e2e.ts index daedfdf294..01e522c9d3 100644 --- a/tests/e2e/tests/electron/critical-path/files-auto-update/promo-button-autoupdate.e2e.ts +++ b/tests/e2e/tests/electron/critical-path/files-auto-update/promo-button-autoupdate.e2e.ts @@ -1,6 +1,6 @@ import * as fs from 'fs'; import { Chance } from 'chance'; -import * as editJsonFile from 'edit-json-file'; +import editJsonFile from 'edit-json-file'; import { DatabaseHelper } from '../../../../helpers/database'; import { MyRedisDatabasePage } from '../../../../pageObjects'; import { commonUrl, workingDirectory } from '../../../../helpers/conf'; diff --git a/tests/e2e/tsconfig.json b/tests/e2e/tsconfig.json index ec928c4add..a0eff03eb1 100644 --- a/tests/e2e/tsconfig.json +++ b/tests/e2e/tsconfig.json @@ -6,7 +6,6 @@ "forceConsistentCasingInFileNames": true, "strict": true, "skipLibCheck": true, - "sourceMap": true, "types": ["node"] }, "exclude": [ diff --git a/tests/e2e/tsconfig.testcafe.json b/tests/e2e/tsconfig.testcafe.json index 56d9d8ed34..54c2cd3cd7 100644 --- a/tests/e2e/tsconfig.testcafe.json +++ b/tests/e2e/tsconfig.testcafe.json @@ -1,4 +1,5 @@ { + "extends": "./tsconfig.json", "compilerOptions": { "types": [] } From a7325cdacb170e1b7050dfd188d0522e38aad822 Mon Sep 17 00:00:00 2001 From: KIvanow Date: Wed, 23 Oct 2024 16:28:42 +0300 Subject: [PATCH 237/256] RI-6171 User cannot create vector index using form - updated tests --- .../CreateRedisearchIndex.tsx | 10 +++++++--- .../CreateRedisearchIndexWrapper.spec.tsx | 9 +++++++++ redisinsight/ui/src/utils/redisearch.ts | 19 +------------------ .../ui/src/utils/tests/redisearch.spec.ts | 8 +++----- 4 files changed, 20 insertions(+), 26 deletions(-) diff --git a/redisinsight/ui/src/pages/browser/components/create-redisearch-index/CreateRedisearchIndex.tsx b/redisinsight/ui/src/pages/browser/components/create-redisearch-index/CreateRedisearchIndex.tsx index 0f5e8c0edd..aca5ab6f4e 100644 --- a/redisinsight/ui/src/pages/browser/components/create-redisearch-index/CreateRedisearchIndex.tsx +++ b/redisinsight/ui/src/pages/browser/components/create-redisearch-index/CreateRedisearchIndex.tsx @@ -53,7 +53,11 @@ const keyTypeOptions = KEY_TYPE_OPTIONS.map((item) => { } }) -const initialFieldValue = (fieldTypeOptions: EuiSuperSelectOption[], id = 0) => ({ id, identifier: '', fieldType: fieldTypeOptions[0].value }) +const initialFieldValue = (fieldTypeOptions: EuiSuperSelectOption[], id = 0) => ({ + id, + identifier: '', + fieldType: fieldTypeOptions.length > 0 ? fieldTypeOptions[0].value : '' +}) const CreateRedisearchIndex = ({ onClosePanel, onCreateIndex }: Props) => { const { viewType } = useSelector(keysSelector) @@ -63,7 +67,7 @@ const CreateRedisearchIndex = ({ onClosePanel, onCreateIndex }: Props) => { const [keyTypeSelected, setKeyTypeSelected] = useState(keyTypeOptions[0].value) const [prefixes, setPrefixes] = useState([]) const [indexName, setIndexName] = useState('') - const [fieldTypeOptions, setFieldTypeOptions] = useState[]>(getFieldTypeOptions(modules)) + const [fieldTypeOptions, setFieldTypeOptions] = useState[]>(getFieldTypeOptions) const [fields, setFields] = useState([initialFieldValue(fieldTypeOptions)]) const [isInfoPopoverOpen, setIsInfoPopoverOpen] = useState(false) @@ -81,7 +85,7 @@ const CreateRedisearchIndex = ({ onClosePanel, onCreateIndex }: Props) => { }, [fields.length]) useEffect(() => { - setFieldTypeOptions(getFieldTypeOptions(modules)) + setFieldTypeOptions(getFieldTypeOptions) }, [modules]) const addField = () => { diff --git a/redisinsight/ui/src/pages/browser/components/create-redisearch-index/CreateRedisearchIndexWrapper.spec.tsx b/redisinsight/ui/src/pages/browser/components/create-redisearch-index/CreateRedisearchIndexWrapper.spec.tsx index 9d71c55cec..9e4bbddf9b 100644 --- a/redisinsight/ui/src/pages/browser/components/create-redisearch-index/CreateRedisearchIndexWrapper.spec.tsx +++ b/redisinsight/ui/src/pages/browser/components/create-redisearch-index/CreateRedisearchIndexWrapper.spec.tsx @@ -115,4 +115,13 @@ describe('CreateRedisearchIndexWrapper', () => { expect(screen.getByTestId('identifier-info-icon')).toBeInTheDocument() }) + + it('should not have geoshape option', () => { + const { queryByText } = render() + + fireEvent.click(screen.getByTestId('field-type-0')) + + expect(queryByText('GEOSHAPE')).not.toBeInTheDocument() + expect(queryByText('VECTOR')).not.toBeInTheDocument() + }) }) diff --git a/redisinsight/ui/src/utils/redisearch.ts b/redisinsight/ui/src/utils/redisearch.ts index 79ad18dd76..7a8fcd2bfb 100644 --- a/redisinsight/ui/src/utils/redisearch.ts +++ b/redisinsight/ui/src/utils/redisearch.ts @@ -1,23 +1,6 @@ -import { REDISEARCH_MODULES } from 'uiSrc/slices/interfaces' -import { isVersionHigherOrEquals } from 'uiSrc/utils' -import { - REDISEARCH_GEOSHAPE_SEMANTIC_VERSION, - REDISEARCH_GEOSHAPE_VERSION, -} from 'uiSrc/constants' import { FIELD_TYPE_OPTIONS } from 'uiSrc/pages/browser/components/create-redisearch-index/constants' -import { AdditionalRedisModule } from 'apiSrc/modules/database/models/additional.redis.module' -const isGeoshapeOptionAvailable = (modules: AdditionalRedisModule[]): boolean => - modules?.some(({ name, semanticVersion, version }) => - REDISEARCH_MODULES - .some((search) => ( - name === search && ( - isVersionHigherOrEquals(semanticVersion, REDISEARCH_GEOSHAPE_SEMANTIC_VERSION) - || (version && version >= REDISEARCH_GEOSHAPE_VERSION) - )))) - -export const getFieldTypeOptions = (modules: AdditionalRedisModule[] = []) => FIELD_TYPE_OPTIONS - .filter(() => isGeoshapeOptionAvailable(modules)) +export const getFieldTypeOptions = () => FIELD_TYPE_OPTIONS .map(({ value, text }) => ({ value, inputDisplay: text, diff --git a/redisinsight/ui/src/utils/tests/redisearch.spec.ts b/redisinsight/ui/src/utils/tests/redisearch.spec.ts index c6b0b567aa..ba2c91836b 100644 --- a/redisinsight/ui/src/utils/tests/redisearch.spec.ts +++ b/redisinsight/ui/src/utils/tests/redisearch.spec.ts @@ -1,6 +1,6 @@ import { getFieldTypeOptions } from 'uiSrc/utils' import { RedisDefaultModules } from 'uiSrc/slices/interfaces' -import { FIELD_TYPE_OPTIONS, FieldTypes } from +import { FIELD_TYPE_OPTIONS } from 'uiSrc/pages/browser/components/create-redisearch-index/constants' const nameAndVersionToModule = ([name, semanticVersion, version]: any[]) => ( @@ -26,8 +26,6 @@ const getFieldTypeOptionsTests: any[] = [ [[['1', '2.8.4'], [RedisDefaultModules.Search, undefined, 20803]].map(nameAndVersionToModule), ALL_OPTIONS], [[['1', '2.8.4'], [RedisDefaultModules.SearchLight, undefined, 20804]].map(nameAndVersionToModule), ALL_OPTIONS], [[['1', '2.8.4'], [RedisDefaultModules.SearchLight, undefined, 20803]].map(nameAndVersionToModule), ALL_OPTIONS], - [[['1', '2.8.4'], [RedisDefaultModules.SearchLight, undefined, 20804]].map(nameAndVersionToModule), ALL_OPTIONS], - [[['1', '2.8.4'], [RedisDefaultModules.SearchLight, undefined, 20803]].map(nameAndVersionToModule), ALL_OPTIONS], [[['1', '2.8.4'], [RedisDefaultModules.FT, undefined, 20804]].map(nameAndVersionToModule), ALL_OPTIONS], [[['1', '2.8.4'], [RedisDefaultModules.FT, undefined, 20803]].map(nameAndVersionToModule), ALL_OPTIONS], [[['1', '2.8.4'], [RedisDefaultModules.FTL, undefined, 20804]].map(nameAndVersionToModule), ALL_OPTIONS], @@ -40,8 +38,8 @@ const getFieldTypeOptionsTests: any[] = [ describe('getFieldTypeOptions', () => { it.each(getFieldTypeOptionsTests)('for input: %s (type), should be output: %s', - (type, expected) => { - const result = getFieldTypeOptions(type) + (_, expected) => { + const result = getFieldTypeOptions() expect(result).toEqual(expected) }) }) From 0077fd4d0c7eeb83af10344249dc7a2dc2f4c04a Mon Sep 17 00:00:00 2001 From: Kristiyan Ivanov Date: Thu, 24 Oct 2024 11:01:41 +0300 Subject: [PATCH 238/256] Simplified check based on suggestion from Roman --- .../create-redisearch-index/CreateRedisearchIndex.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/redisinsight/ui/src/pages/browser/components/create-redisearch-index/CreateRedisearchIndex.tsx b/redisinsight/ui/src/pages/browser/components/create-redisearch-index/CreateRedisearchIndex.tsx index aca5ab6f4e..dd9dbfc343 100644 --- a/redisinsight/ui/src/pages/browser/components/create-redisearch-index/CreateRedisearchIndex.tsx +++ b/redisinsight/ui/src/pages/browser/components/create-redisearch-index/CreateRedisearchIndex.tsx @@ -56,7 +56,7 @@ const keyTypeOptions = KEY_TYPE_OPTIONS.map((item) => { const initialFieldValue = (fieldTypeOptions: EuiSuperSelectOption[], id = 0) => ({ id, identifier: '', - fieldType: fieldTypeOptions.length > 0 ? fieldTypeOptions[0].value : '' + fieldType: fieldTypeOptions[0]?.value || '' }) const CreateRedisearchIndex = ({ onClosePanel, onCreateIndex }: Props) => { From e3f06e74cd229def9e38d9be9518bdac3738e4dc Mon Sep 17 00:00:00 2001 From: vlad-dargel Date: Thu, 24 Oct 2024 11:55:06 +0200 Subject: [PATCH 239/256] e2e/bugfix/fir-delete-all-keys-redis --- tests/e2e/helpers/keys.ts | 7 ++++++- tests/e2e/tests/web/regression/settings/settings.e2e.ts | 3 +-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/tests/e2e/helpers/keys.ts b/tests/e2e/helpers/keys.ts index 27aca7ed63..7252f152fc 100644 --- a/tests/e2e/helpers/keys.ts +++ b/tests/e2e/helpers/keys.ts @@ -275,7 +275,12 @@ export async function populateZSetWithMembers(host: string, port: string, keyArg */ export async function deleteAllKeysFromDB(host: string, port: string): Promise { const url = `redis://default@${host}:${port}`; - const client = createClient({ url }); + const client = createClient({ + url, + socket: { + connectTimeout: 10000 + } + }); client.on('error', (error: Error) => { console.error('Redis Client Error', error); diff --git a/tests/e2e/tests/web/regression/settings/settings.e2e.ts b/tests/e2e/tests/web/regression/settings/settings.e2e.ts index 53e0761f07..e283473795 100644 --- a/tests/e2e/tests/web/regression/settings/settings.e2e.ts +++ b/tests/e2e/tests/web/regression/settings/settings.e2e.ts @@ -5,7 +5,6 @@ import { } from '../../../../helpers/conf'; import { DatabaseAPIRequests } from '../../../../helpers/api/api-database'; import { Common, DatabaseHelper } from '../../../../helpers'; -import { deleteAllKeysFromDB } from '../../../../helpers/keys'; const browserPage = new BrowserPage(); const databaseAPIRequests = new DatabaseAPIRequests(); @@ -26,7 +25,7 @@ fixture `DataTime format setting` await databaseHelper.acceptLicenseTermsAndAddOSSClusterDatabase(ossClusterConfig); }) .afterEach(async t => { - await deleteAllKeysFromDB(ossClusterConfig.ossClusterPort, ossClusterConfig.ossClusterPort); + await browserPage.Cli.sendCommandInCli('flushdb'); await t.click(workbenchPage.NavigationPanel.settingsButton); await t.click(settingsPage.accordionAppearance); await t.click(settingsPage.commonRadioButton); From c5524cd8fc01b139b778107cbc8ac77b4267e02e Mon Sep 17 00:00:00 2001 From: Roman Sergeenko Date: Thu, 24 Oct 2024 13:12:31 +0200 Subject: [PATCH 240/256] #RI-6208 - improve switch between redis and search syntax, add command scope #RI-6211 - fix highlighting when there are several the same args --- .../components/query/Query/Query.tsx | 8 ++-- redisinsight/ui/src/pages/workbench/types.ts | 1 + .../ui/src/pages/workbench/utils/monaco.ts | 28 ++++++++--- .../ui/src/pages/workbench/utils/query.ts | 1 + .../workbench/utils/searchSuggestions.ts | 15 +++--- .../src/pages/workbench/utils/suggestions.ts | 16 ++++++- .../workbench/utils/tests/monaco.spec.ts | 18 ++++--- .../utils/tests/test-cases/common.ts | 28 +++++++---- .../utils/tests/test-cases/ft-aggregate.ts | 47 ++++++++++++------- .../utils/tests/test-cases/ft-search.ts | 36 +++++++++----- .../monacoRedisMonarchTokensProvider.ts | 9 +++- .../monarchTokens/redisearchTokensSubRedis.ts | 22 ++++++--- 12 files changed, 158 insertions(+), 71 deletions(-) diff --git a/redisinsight/ui/src/pages/workbench/components/query/Query/Query.tsx b/redisinsight/ui/src/pages/workbench/components/query/Query/Query.tsx index 6a8511b7e1..803549fa50 100644 --- a/redisinsight/ui/src/pages/workbench/components/query/Query/Query.tsx +++ b/redisinsight/ui/src/pages/workbench/components/query/Query/Query.tsx @@ -85,8 +85,7 @@ const Query = (props: Props) => { const suggestionsRef = useRef([]) const helpWidgetRef = useRef({ isOpen: false, - parent: null, - currentArg: null + data: {} }) const indexesRef = useRef([]) const attributesRef = useRef([]) @@ -581,11 +580,10 @@ const Query = (props: Props) => { ) if (helpWidget) { - const { isOpen, parent, currentArg } = helpWidget + const { isOpen, data } = helpWidget helpWidgetRef.current = { isOpen, - parent: parent || helpWidgetRef.current.parent, - currentArg: currentArg || helpWidgetRef.current.currentArg + data: data || helpWidgetRef.current.data } } diff --git a/redisinsight/ui/src/pages/workbench/types.ts b/redisinsight/ui/src/pages/workbench/types.ts index 7962623bbc..05c961c1a1 100644 --- a/redisinsight/ui/src/pages/workbench/types.ts +++ b/redisinsight/ui/src/pages/workbench/types.ts @@ -13,6 +13,7 @@ export interface FoundCommandArgument { isBlocked: boolean append: Maybe> parent: Maybe + token: Maybe } export interface CursorContext { diff --git a/redisinsight/ui/src/pages/workbench/utils/monaco.ts b/redisinsight/ui/src/pages/workbench/utils/monaco.ts index c6cd9bb58f..8f032ce262 100644 --- a/redisinsight/ui/src/pages/workbench/utils/monaco.ts +++ b/redisinsight/ui/src/pages/workbench/utils/monaco.ts @@ -2,7 +2,7 @@ import { monaco } from 'react-monaco-editor' import * as monacoEditor from 'monaco-editor' import { isString } from 'lodash' import { generateDetail } from 'uiSrc/pages/workbench/utils/query' -import { Maybe } from 'uiSrc/utils' +import { Maybe, Nullable } from 'uiSrc/utils' import { IRedisCommand, ICommandTokenType } from 'uiSrc/constants' export const setCursorPositionAtTheEnd = (editor: monacoEditor.editor.IStandaloneCodeEditor) => { @@ -39,17 +39,31 @@ export const buildSuggestion = (arg: IRedisCommand, range: monaco.IRange, option export const getRediSearchSignutureProvider = (options: Maybe<{ isOpen: boolean - currentArg: IRedisCommand - parent: Maybe + data: { + currentArg: IRedisCommand + parent: Maybe + token: Maybe + } }>) => { - const { isOpen, currentArg, parent } = options || {} + const { isOpen, data } = options || {} + const { currentArg, parent, token } = data || {} if (!isOpen) return null const label = generateDetail(parent) + let signaturePosition: Nullable<[number, number]> = null const arg = currentArg?.type === ICommandTokenType.Block - ? currentArg?.arguments?.[0]?.name + ? (currentArg?.arguments?.[0]?.name || currentArg?.token || '') : (currentArg?.name || currentArg?.type || '') + // we may have several the same args inside documentation, so we get proper arg after token + const numberOfArgsInside = label.split(arg).length - 1 + if (token && numberOfArgsInside > 1) { + const parentToken = token.token || token.arguments?.[0]?.token + const parentTokenPosition = parentToken ? label.indexOf(parentToken) : 0 + const startPosition = label.indexOf(arg, parentTokenPosition) + signaturePosition = [startPosition, startPosition + arg.length] + } + return { dispose: () => {}, value: { @@ -57,7 +71,9 @@ export const getRediSearchSignutureProvider = (options: Maybe<{ activeSignature: 0, signatures: [{ label: label || '', - parameters: [{ label: arg }] + parameters: [ + { label: signaturePosition || arg } + ], }] } } diff --git a/redisinsight/ui/src/pages/workbench/utils/query.ts b/redisinsight/ui/src/pages/workbench/utils/query.ts index e0c633407f..d5489e8e98 100644 --- a/redisinsight/ui/src/pages/workbench/utils/query.ts +++ b/redisinsight/ui/src/pages/workbench/utils/query.ts @@ -32,6 +32,7 @@ export const findCurrentArgument = ( // this is the main function which creates the list of arguments return { ...getArgumentSuggestions({ tokenArgs: pastArgs, untilTokenArgs }, commandArgs, parent), + token, parent: parent || token } } diff --git a/redisinsight/ui/src/pages/workbench/utils/searchSuggestions.ts b/redisinsight/ui/src/pages/workbench/utils/searchSuggestions.ts index 09e60723ca..3ef7caec10 100644 --- a/redisinsight/ui/src/pages/workbench/utils/searchSuggestions.ts +++ b/redisinsight/ui/src/pages/workbench/utils/searchSuggestions.ts @@ -36,11 +36,14 @@ export const findSuggestionsByArg = ( const { prevCursorChar } = cursor const [beforeOffsetArgs, [currentOffsetArg]] = args - const foundArg = findCurrentArgument(listOfCommands, beforeOffsetArgs) + const scopedList = command.name + ? listOfCommands.filter(({ name }) => name === command?.name) + : listOfCommands + const foundArg = findCurrentArgument(scopedList, beforeOffsetArgs) if (!command.name.startsWith(ModuleCommandPrefix.RediSearch)) { return { - helpWidget: { isOpen: !!foundArg, parent: foundArg?.parent, currentArg: foundArg?.stopArg }, + helpWidget: { isOpen: !!foundArg, data: { parent: foundArg?.parent, currentArg: foundArg?.stopArg } }, suggestions: asSuggestionsRef([]) } } @@ -94,7 +97,7 @@ const handleIndexSuggestions = ( cursorContext: CursorContext ) => { const isIndex = indexes.length > 0 - const helpWidget = { isOpen: isIndex, parent: command.info, currentArg: foundArg?.stopArg } + const helpWidget = { isOpen: isIndex, data: { parent: command.info, currentArg: foundArg?.stopArg } } const currentCommand = command.info if (COMMANDS_WITHOUT_INDEX_PROPOSE.includes(command.name || '')) { @@ -132,7 +135,7 @@ const handleIndexSuggestions = ( } const handleQuerySuggestions = (foundArg: FoundCommandArgument) => ({ - helpWidget: { isOpen: true, parent: foundArg?.parent, currentArg: foundArg?.stopArg }, + helpWidget: { isOpen: true, data: { parent: foundArg?.parent, currentArg: foundArg?.stopArg } }, suggestions: asSuggestionsRef([], false) }) @@ -141,7 +144,7 @@ const handleExpressionSuggestions = ( foundArg: FoundCommandArgument, cursorContext: CursorContext, ) => { - const helpWidget = { isOpen: true, parent: foundArg?.parent, currentArg: foundArg?.stopArg } + const helpWidget = { isOpen: true, data: { parent: foundArg?.parent, currentArg: foundArg?.stopArg } } const { isCursorInQuotes, offset, argLeftOffset } = cursorContext if (!isCursorInQuotes) { @@ -182,7 +185,7 @@ const handleCommonSuggestions = ( const shouldHideSuggestions = isCursorInQuotes || nextCursorChar || (prevCursorChar && isEscaped) if (shouldHideSuggestions) { return { - helpWidget: { isOpen: !!foundArg, parent: foundArg?.parent, currentArg: foundArg?.stopArg }, + helpWidget: { isOpen: !!foundArg, data: { parent: foundArg?.parent, currentArg: foundArg?.stopArg } }, suggestions: asSuggestionsRef([]) } } diff --git a/redisinsight/ui/src/pages/workbench/utils/suggestions.ts b/redisinsight/ui/src/pages/workbench/utils/suggestions.ts index b90823f0ff..e7e1f5c1cc 100644 --- a/redisinsight/ui/src/pages/workbench/utils/suggestions.ts +++ b/redisinsight/ui/src/pages/workbench/utils/suggestions.ts @@ -1,9 +1,15 @@ import { monaco } from 'react-monaco-editor' import * as monacoEditor from 'monaco-editor' +import { findIndex } from 'lodash' import { RedisResponseBuffer } from 'uiSrc/slices/interfaces' import { bufferToString, formatLongName, generateArgsForInsertText, getCommandMarkdown, Nullable } from 'uiSrc/utils' import { FoundCommandArgument } from 'uiSrc/pages/workbench/types' -import { DefinedArgumentName, EmptySuggestionsIds } from 'uiSrc/pages/workbench/constants' +import { + DefinedArgumentName, + EmptySuggestionsIds, + ModuleCommandPrefix, + SORTED_SEARCH_COMMANDS +} from 'uiSrc/pages/workbench/constants' import { getUtmExternalLink } from 'uiSrc/utils/links' import { IRedisCommand } from 'uiSrc/constants' import { generateDetail, removeNotSuggestedArgs } from './query' @@ -170,7 +176,13 @@ export const getGeneralSuggestions = ( if (foundArg && !foundArg.isComplete) { return { suggestions: getMandatoryArgumentSuggestions(foundArg, fields, range), - helpWidgetData: { isOpen: !!foundArg?.stopArg, parent: foundArg?.parent, currentArg: foundArg?.stopArg } + helpWidgetData: { isOpen: !!foundArg?.stopArg, + data: { + parent: foundArg?.parent, + currentArg: foundArg?.stopArg, + token: foundArg?.token + } + } } } diff --git a/redisinsight/ui/src/pages/workbench/utils/tests/monaco.spec.ts b/redisinsight/ui/src/pages/workbench/utils/tests/monaco.spec.ts index 2ab897b97e..01978197c0 100644 --- a/redisinsight/ui/src/pages/workbench/utils/tests/monaco.spec.ts +++ b/redisinsight/ui/src/pages/workbench/utils/tests/monaco.spec.ts @@ -7,16 +7,20 @@ const getRediSearchSignatureProviderTests = [ { input: { isOpen: false, - currentArg: {}, - parent: {} + data: { + currentArg: {}, + parent: {} + } }, result: null }, { input: { isOpen: true, - currentArg: ftAggregateCommand.arguments.find(({ name }) => name === 'groupby'), - parent: null + data: { + currentArg: ftAggregateCommand.arguments.find(({ name }) => name === 'groupby'), + parent: null + } }, result: { dispose: expect.any(Function), @@ -33,8 +37,10 @@ const getRediSearchSignatureProviderTests = [ { input: { isOpen: true, - currentArg: { name: 'expression' }, - parent: ftAggregateCommand.arguments.find(({ name }) => name === 'apply') + data: { + currentArg: { name: 'expression' }, + parent: ftAggregateCommand.arguments.find(({ name }) => name === 'apply') + } }, result: { dispose: expect.any(Function), diff --git a/redisinsight/ui/src/pages/workbench/utils/tests/test-cases/common.ts b/redisinsight/ui/src/pages/workbench/utils/tests/test-cases/common.ts index 0e6d18c670..02ace2613c 100644 --- a/redisinsight/ui/src/pages/workbench/utils/tests/test-cases/common.ts +++ b/redisinsight/ui/src/pages/workbench/utils/tests/test-cases/common.ts @@ -7,7 +7,8 @@ export const commonfindCurrentArgumentCases = [ append: expect.any(Array), isBlocked: false, isComplete: true, - parent: expect.any(Object) + parent: expect.any(Object), + token: expect.any(Object) }, appendIncludes: ['WITHSCORES', 'VERBATIM', 'FILTER', 'SORTBY', 'RETURN'], appendNotIncludes: ['DIALECT'] @@ -19,7 +20,8 @@ export const commonfindCurrentArgumentCases = [ append: expect.any(Array), isBlocked: false, isComplete: true, - parent: expect.any(Object) + parent: expect.any(Object), + token: expect.any(Object) }, appendIncludes: ['REDUCE', 'APPLY', 'SORTBY', 'GROUPBY'], appendNotIncludes: ['AS'], @@ -36,7 +38,8 @@ export const commonfindCurrentArgumentCases = [ append: expect.any(Array), isBlocked: false, isComplete: true, - parent: expect.any(Object) + parent: expect.any(Object), + token: expect.any(Object) }, appendIncludes: ['AS', 'REDUCE', 'APPLY', 'SORTBY', 'GROUPBY'], }, @@ -47,7 +50,8 @@ export const commonfindCurrentArgumentCases = [ append: expect.any(Array), isBlocked: false, isComplete: true, - parent: expect.any(Object) + parent: expect.any(Object), + token: expect.any(Object) }, appendIncludes: ['DIALECT', 'EXPANDER', 'INKEYS', 'LIMIT'], appendNotIncludes: ['ASC'], @@ -107,7 +111,8 @@ export const commonfindCurrentArgumentCases = [ append: expect.any(Array), isBlocked: false, isComplete: false, - parent: expect.any(Object) + parent: expect.any(Object), + token: expect.any(Object) }, appendIncludes: ['AS', 'GEO', 'TEXT', 'VECTOR'], appendNotIncludes: ['SCHEMA', 'SCORE', 'NOHL'], @@ -119,7 +124,8 @@ export const commonfindCurrentArgumentCases = [ append: expect.any(Array), isBlocked: false, isComplete: true, - parent: expect.any(Object) + parent: expect.any(Object), + token: expect.any(Object) }, appendIncludes: ['INDEXEMPTY', 'SORTABLE', 'WITHSUFFIXTRIE'], appendNotIncludes: ['SCHEMA', 'SCORE', 'NOHL'], @@ -131,7 +137,8 @@ export const commonfindCurrentArgumentCases = [ append: expect.any(Array), isBlocked: false, isComplete: false, - parent: expect.any(Object) + parent: expect.any(Object), + token: expect.any(Object) }, appendIncludes: ['SCHEMA', 'SKIPINITIALSCAN'], appendNotIncludes: ['ADD'], @@ -152,7 +159,8 @@ export const commonfindCurrentArgumentCases = [ append: [], isBlocked: true, isComplete: false, - parent: expect.any(Object) + parent: expect.any(Object), + token: expect.any(Object) }, appendIncludes: [], appendNotIncludes: [expect.any(String)], @@ -169,6 +177,7 @@ export const commonfindCurrentArgumentCases = [ isBlocked: true, isComplete: false, parent: expect.any(Object), + token: expect.any(Object), stopArg: { multiple: true, name: 'term', @@ -187,7 +196,8 @@ export const commonfindCurrentArgumentCases = [ stopArg: { name: 'score', type: 'double' - } + }, + token: expect.any(Object) }, appendIncludes: [], }, diff --git a/redisinsight/ui/src/pages/workbench/utils/tests/test-cases/ft-aggregate.ts b/redisinsight/ui/src/pages/workbench/utils/tests/test-cases/ft-aggregate.ts index fcee36b2c8..03211cafbe 100644 --- a/redisinsight/ui/src/pages/workbench/utils/tests/test-cases/ft-aggregate.ts +++ b/redisinsight/ui/src/pages/workbench/utils/tests/test-cases/ft-aggregate.ts @@ -8,7 +8,8 @@ export const findArgumentftAggreageTests = [ append: [], isBlocked: true, isComplete: false, - parent: expect.any(Object) + parent: expect.any(Object), + token: expect.any(Object) } }, { @@ -18,7 +19,8 @@ export const findArgumentftAggreageTests = [ append: expect.any(Array), isBlocked: false, isComplete: false, - parent: expect.any(Object) + parent: expect.any(Object), + token: expect.any(Object) } }, { @@ -28,7 +30,8 @@ export const findArgumentftAggreageTests = [ append: expect.any(Array), isBlocked: true, isComplete: false, - parent: expect.any(Object) + parent: expect.any(Object), + token: expect.any(Object) } }, { @@ -38,7 +41,8 @@ export const findArgumentftAggreageTests = [ append: expect.any(Array), isBlocked: false, isComplete: true, - parent: expect.any(Object) + parent: expect.any(Object), + token: expect.any(Object) } }, { @@ -48,7 +52,8 @@ export const findArgumentftAggreageTests = [ append: [], isBlocked: true, isComplete: false, - parent: expect.any(Object) + parent: expect.any(Object), + token: expect.any(Object) } }, { @@ -111,7 +116,8 @@ export const findArgumentftAggreageTests = [ ], isBlocked: false, isComplete: true, - parent: expect.any(Object) + parent: expect.any(Object), + token: expect.any(Object) } }, { @@ -133,7 +139,8 @@ export const findArgumentftAggreageTests = [ ], isBlocked: false, isComplete: true, - parent: expect.any(Object) + parent: expect.any(Object), + token: expect.any(Object) } }, { @@ -143,7 +150,8 @@ export const findArgumentftAggreageTests = [ append: expect.any(Array), isBlocked: true, isComplete: false, - parent: expect.any(Object) + parent: expect.any(Object), + token: expect.any(Object) } }, { @@ -168,7 +176,8 @@ export const findArgumentftAggreageTests = [ ], isBlocked: false, isComplete: true, - parent: expect.any(Object) + parent: expect.any(Object), + token: expect.any(Object) } }, { @@ -193,8 +202,9 @@ export const findArgumentftAggreageTests = [ ], isBlocked: false, isComplete: true, - parent: expect.any(Object) - } + parent: expect.any(Object), + token: expect.any(Object) + }, }, { args: ['index', '"query"', 'SORTBY', '0'], @@ -216,7 +226,8 @@ export const findArgumentftAggreageTests = [ ], isBlocked: false, isComplete: true, - parent: expect.any(Object) + parent: expect.any(Object), + token: expect.any(Object) } }, { @@ -231,7 +242,8 @@ export const findArgumentftAggreageTests = [ append: [], isBlocked: true, isComplete: false, - parent: expect.any(Object) + parent: expect.any(Object), + token: expect.any(Object) } }, { @@ -241,7 +253,8 @@ export const findArgumentftAggreageTests = [ append: [], isBlocked: true, isComplete: false, - parent: expect.any(Object) + parent: expect.any(Object), + token: expect.any(Object) } }, { @@ -251,7 +264,8 @@ export const findArgumentftAggreageTests = [ append: [], isBlocked: true, isComplete: false, - parent: expect.any(Object) + parent: expect.any(Object), + token: expect.any(Object) } }, { @@ -261,7 +275,8 @@ export const findArgumentftAggreageTests = [ append: [], isBlocked: false, isComplete: true, - parent: expect.any(Object) + parent: expect.any(Object), + token: expect.any(Object) } }, ] diff --git a/redisinsight/ui/src/pages/workbench/utils/tests/test-cases/ft-search.ts b/redisinsight/ui/src/pages/workbench/utils/tests/test-cases/ft-search.ts index a729a10fa5..436308a7a3 100644 --- a/redisinsight/ui/src/pages/workbench/utils/tests/test-cases/ft-search.ts +++ b/redisinsight/ui/src/pages/workbench/utils/tests/test-cases/ft-search.ts @@ -53,7 +53,8 @@ export const findArgumentftSearchTests = [ ]], isBlocked: false, isComplete: true, - parent: expect.any(Object) + parent: expect.any(Object), + token: expect.any(Object) } }, { @@ -67,7 +68,8 @@ export const findArgumentftSearchTests = [ append: [], isBlocked: true, isComplete: false, - parent: expect.any(Object) + parent: expect.any(Object), + token: expect.any(Object) } }, { @@ -81,7 +83,8 @@ export const findArgumentftSearchTests = [ append: [], isBlocked: true, isComplete: false, - parent: expect.any(Object) + parent: expect.any(Object), + token: expect.any(Object) } }, { @@ -96,7 +99,8 @@ export const findArgumentftSearchTests = [ append: [], isBlocked: true, isComplete: false, - parent: expect.any(Object) + parent: expect.any(Object), + token: expect.any(Object) } }, { @@ -126,7 +130,8 @@ export const findArgumentftSearchTests = [ ]], isBlocked: false, isComplete: true, - parent: expect.any(Object) + parent: expect.any(Object), + token: expect.any(Object) } }, { @@ -136,7 +141,8 @@ export const findArgumentftSearchTests = [ append: [], isBlocked: false, isComplete: true, - parent: expect.any(Object) + parent: expect.any(Object), + token: expect.any(Object) } }, { @@ -162,7 +168,8 @@ export const findArgumentftSearchTests = [ ], isBlocked: false, isComplete: false, - parent: expect.any(Object) + parent: expect.any(Object), + token: expect.any(Object) } }, { @@ -198,7 +205,8 @@ export const findArgumentftSearchTests = [ ], isBlocked: false, isComplete: false, - parent: expect.any(Object) + parent: expect.any(Object), + token: expect.any(Object) } }, { @@ -208,7 +216,8 @@ export const findArgumentftSearchTests = [ append: [], isBlocked: false, isComplete: true, - parent: expect.any(Object) + parent: expect.any(Object), + token: expect.any(Object) } }, { @@ -249,7 +258,8 @@ export const findArgumentftSearchTests = [ ], isBlocked: false, isComplete: true, - parent: expect.any(Object) + parent: expect.any(Object), + token: expect.any(Object) } }, { @@ -259,7 +269,8 @@ export const findArgumentftSearchTests = [ append: [[]], isBlocked: false, isComplete: true, - parent: expect.any(Object) + parent: expect.any(Object), + token: expect.any(Object) } }, { @@ -271,7 +282,8 @@ export const findArgumentftSearchTests = [ ], isBlocked: false, isComplete: true, - parent: expect.any(Object) + parent: expect.any(Object), + token: expect.any(Object) } }, ] diff --git a/redisinsight/ui/src/utils/monaco/monacoRedisMonarchTokensProvider.ts b/redisinsight/ui/src/utils/monaco/monacoRedisMonarchTokensProvider.ts index 0c4b914333..ee62d07d51 100644 --- a/redisinsight/ui/src/utils/monaco/monacoRedisMonarchTokensProvider.ts +++ b/redisinsight/ui/src/utils/monaco/monacoRedisMonarchTokensProvider.ts @@ -8,13 +8,14 @@ const STRING_DOUBLE = 'string.double' export const getRedisMonarchTokensProvider = (commands: IRedisCommand[]): monacoEditor.languages.IMonarchLanguage => { const commandRedisCommands = [...commands] const searchCommands = remove(commandRedisCommands, ({ token }) => token?.startsWith(ModuleCommandPrefix.RediSearch)) - const COMMON_COMMANDS_REGEX = `(${commandRedisCommands.map(({ token }) => token).join('|')})\\b` - const SEARCH_COMMANDS_REGEX = `(${searchCommands.map(({ token }) => token).join('|')})\\b` + const COMMON_COMMANDS_REGEX = `^\\s*(${commandRedisCommands.map(({ token }) => token).join('|')})\\b` + const SEARCH_COMMANDS_REGEX = `^\\s*(${searchCommands.map(({ token }) => token).join('|')})\\b` return { defaultToken: '', tokenPostfix: '.redis', ignoreCase: true, + includeLF: true, brackets: [ { open: '[', close: ']', token: 'delimiter.square' }, { open: '(', close: ')', token: 'delimiter.parenthesis' }, @@ -23,6 +24,7 @@ export const getRedisMonarchTokensProvider = (commands: IRedisCommand[]): monaco operators: [], tokenizer: { root: [ + { include: '@startOfLine' }, { include: '@whitespace' }, { include: '@numbers' }, { include: '@strings' }, @@ -71,6 +73,9 @@ export const getRedisMonarchTokensProvider = (commands: IRedisCommand[]): monaco // TODO: can be tokens or functions the same - need to think how to avoid wrong ending endRedisearch: [ [`^\\s*${COMMON_COMMANDS_REGEX}`, { token: '@rematch', next: '@root', nextEmbedded: '@pop', log: 'end' }], + ], + startOfLine: [ + [/\n/, { next: '@root', token: '@pop' }], ] }, } diff --git a/redisinsight/ui/src/utils/monaco/monarchTokens/redisearchTokensSubRedis.ts b/redisinsight/ui/src/utils/monaco/monarchTokens/redisearchTokensSubRedis.ts index 2454443781..01e02f9680 100644 --- a/redisinsight/ui/src/utils/monaco/monarchTokens/redisearchTokensSubRedis.ts +++ b/redisinsight/ui/src/utils/monaco/monarchTokens/redisearchTokensSubRedis.ts @@ -23,13 +23,17 @@ export const getRediSearchSubRedisMonarchTokensProvider = ( const generateTokensForCommands = () => { let commandTokens: any = {} - withNextIndexSuggestions.forEach((command) => { + commands.forEach((command) => { const isIndexAfterCommand = isIndexAfterKeyword(command) const argTokens = generateTokens(command) const tokenName = command.token?.replace(/(\.| )/g, '_') + const blockTokens = getBlockTokens(tokenName, argTokens?.pureTokens) + + if (blockTokens.length) { + commandTokens[`argument.block.${tokenName}`] = blockTokens + } if (isIndexAfterCommand) { - commandTokens[`argument.block.${tokenName}`] = getBlockTokens(tokenName, argTokens?.pureTokens) commandTokens = { ...commandTokens, ...generateTokensWithFunctions(tokenName, argTokens?.tokensWithQueryAfter) @@ -40,7 +44,6 @@ export const getRediSearchSubRedisMonarchTokensProvider = ( return commandTokens } - const keywords = generateKeywords(commands) const tokens = generateTokensForCommands() const includeTokens = () => { @@ -52,14 +55,16 @@ export const getRediSearchSubRedisMonarchTokensProvider = ( { defaultToken: '', tokenPostfix: '.redisearch', + includeLF: true, ignoreCase: true, brackets: [ { open: '[', close: ']', token: 'delimiter.square' }, { open: '(', close: ')', token: 'delimiter.parenthesis' }, ], - keywords, + keywords: [], tokenizer: { root: [ + { include: '@startOfLine' }, { include: '@keywords' }, ...includeTokens(), { include: '@fields' }, @@ -72,9 +77,9 @@ export const getRediSearchSubRedisMonarchTokensProvider = ( [/[\w@#$.]+/, 'identifier'] ], keywords: [ - [`(${generateKeywords(withNextQueryIndexSuggestions).join('|')})\\b`, { token: 'keyword', next: '@index.query' }], - [`(${generateKeywords(withNextIndexSuggestions).join('|')})\\b`, { token: 'keyword', next: '@index' }], - [`(${generateKeywords(withoutIndexSuggestions).join('|')})\\b`, { token: 'keyword', next: '@root' }], + [`^\\s*(${generateKeywords(withNextQueryIndexSuggestions).join('|')})\\b`, { token: 'keyword', next: '@index.query' }], + [`^\\s*(${generateKeywords(withNextIndexSuggestions).join('|')})\\b`, { token: 'keyword', next: '@index' }], + [`^\\s*(${generateKeywords(withoutIndexSuggestions).join('|')})\\b`, { token: 'keyword', next: '@root' }], ], ...tokens, ...generateQuery(), @@ -115,6 +120,9 @@ export const getRediSearchSubRedisMonarchTokensProvider = ( [/\\./, STRING_DOUBLE], [/"/, { token: STRING_DOUBLE, next: '@pop' }], [/[^\\"]+/, STRING_DOUBLE], + ], + startOfLine: [ + [/\n/, { next: '@keywords', token: '@pop' }] ] }, } From eebde4e78cdedbc71af8fbdb30bdb057cabde944 Mon Sep 17 00:00:00 2001 From: Roman Sergeenko Date: Thu, 24 Oct 2024 15:55:10 +0200 Subject: [PATCH 241/256] #RI-6226 - add sorting for list of commands #RI-6244 - fix finding of command --- redisinsight/ui/src/pages/workbench/constants.ts | 7 +++++++ .../pages/workbench/utils/searchSuggestions.ts | 4 ++-- .../ui/src/pages/workbench/utils/suggestions.ts | 12 +++++++++++- .../workbench/utils/tests/test-cases/ft-search.ts | 3 ++- redisinsight/ui/src/utils/monaco/monacoUtils.ts | 15 ++++++++------- 5 files changed, 30 insertions(+), 11 deletions(-) diff --git a/redisinsight/ui/src/pages/workbench/constants.ts b/redisinsight/ui/src/pages/workbench/constants.ts index 1c732c67ce..b894704f29 100644 --- a/redisinsight/ui/src/pages/workbench/constants.ts +++ b/redisinsight/ui/src/pages/workbench/constants.ts @@ -98,3 +98,10 @@ export const FIELD_START_SYMBOL = '@' export enum EmptySuggestionsIds { NoIndexes = 'no-indexes' } + +export const SORTED_SEARCH_COMMANDS = [ + 'FT.SEARCH', + 'FT.CREATE', + 'FT.EXPLAIN', + 'FT.PROFILE' +] diff --git a/redisinsight/ui/src/pages/workbench/utils/searchSuggestions.ts b/redisinsight/ui/src/pages/workbench/utils/searchSuggestions.ts index 3ef7caec10..0d408b170f 100644 --- a/redisinsight/ui/src/pages/workbench/utils/searchSuggestions.ts +++ b/redisinsight/ui/src/pages/workbench/utils/searchSuggestions.ts @@ -37,7 +37,7 @@ export const findSuggestionsByArg = ( const [beforeOffsetArgs, [currentOffsetArg]] = args const scopedList = command.name - ? listOfCommands.filter(({ name }) => name === command?.name) + ? listOfCommands.filter(({ token }) => token === command?.name) : listOfCommands const foundArg = findCurrentArgument(scopedList, beforeOffsetArgs) @@ -97,7 +97,7 @@ const handleIndexSuggestions = ( cursorContext: CursorContext ) => { const isIndex = indexes.length > 0 - const helpWidget = { isOpen: isIndex, data: { parent: command.info, currentArg: foundArg?.stopArg } } + const helpWidget = { isOpen: isIndex, data: { parent: foundArg.parent, currentArg: foundArg?.stopArg } } const currentCommand = command.info if (COMMANDS_WITHOUT_INDEX_PROPOSE.includes(command.name || '')) { diff --git a/redisinsight/ui/src/pages/workbench/utils/suggestions.ts b/redisinsight/ui/src/pages/workbench/utils/suggestions.ts index e7e1f5c1cc..9e443d3f06 100644 --- a/redisinsight/ui/src/pages/workbench/utils/suggestions.ts +++ b/redisinsight/ui/src/pages/workbench/utils/suggestions.ts @@ -104,6 +104,14 @@ export const getFunctionsSuggestions = (functions: IRedisCommand[], range: monac detail: summary })) +export const getSortingForCommand = (command: IRedisCommand) => { + if (!command.token?.startsWith(ModuleCommandPrefix.RediSearch)) return command.token + if (!SORTED_SEARCH_COMMANDS.includes(command.token)) return command.token + + const index = findIndex(SORTED_SEARCH_COMMANDS, (token) => token === command.token) + return `${ModuleCommandPrefix.RediSearch}_${index}` +} + export const getCommandsSuggestions = (commands: IRedisCommand[], range: monaco.IRange) => commands.map((command) => buildSuggestion(command, range, { detail: generateDetail(command), @@ -111,6 +119,7 @@ export const getCommandsSuggestions = (commands: IRedisCommand[], range: monaco. documentation: { value: getCommandMarkdown(command as any) }, + sortText: getSortingForCommand(command) })) export const getMandatoryArgumentSuggestions = ( @@ -176,7 +185,8 @@ export const getGeneralSuggestions = ( if (foundArg && !foundArg.isComplete) { return { suggestions: getMandatoryArgumentSuggestions(foundArg, fields, range), - helpWidgetData: { isOpen: !!foundArg?.stopArg, + helpWidgetData: { + isOpen: !!foundArg?.stopArg, data: { parent: foundArg?.parent, currentArg: foundArg?.stopArg, diff --git a/redisinsight/ui/src/pages/workbench/utils/tests/test-cases/ft-search.ts b/redisinsight/ui/src/pages/workbench/utils/tests/test-cases/ft-search.ts index 436308a7a3..a9d54d33e3 100644 --- a/redisinsight/ui/src/pages/workbench/utils/tests/test-cases/ft-search.ts +++ b/redisinsight/ui/src/pages/workbench/utils/tests/test-cases/ft-search.ts @@ -179,7 +179,8 @@ export const findArgumentftSearchTests = [ append: [], isBlocked: false, isComplete: true, - parent: expect.any(Object) + parent: expect.any(Object), + token: expect.any(Object) } }, { diff --git a/redisinsight/ui/src/utils/monaco/monacoUtils.ts b/redisinsight/ui/src/utils/monaco/monacoUtils.ts index db18fedb03..9a98e4dc5b 100644 --- a/redisinsight/ui/src/utils/monaco/monacoUtils.ts +++ b/redisinsight/ui/src/utils/monaco/monacoUtils.ts @@ -238,13 +238,6 @@ export const findCompleteQuery = ( fullQuery = `\n${fullQuery}` } - const matchedCommand = commandsArray - .find((command) => commandName?.trim().toUpperCase().startsWith(command.toUpperCase())) - - if (isUndefined(matchedCommand)) { - return null - } - const commandCursorPosition = fullQuery.length // find args in the next lines const linesCount = model.getLineCount() @@ -273,6 +266,14 @@ export const findCompleteQuery = ( compositeArgs, ) + const [[firstQueryArg]] = args + const matchedCommand = commandsArray + .find((command) => firstQueryArg?.toUpperCase() === command.toUpperCase()) + + if (isUndefined(matchedCommand)) { + return null + } + return { position, commandPosition, From d079e2e3b0e9979784438eea4fc8c3dcfa0b0704 Mon Sep 17 00:00:00 2001 From: vlad-dargel Date: Thu, 24 Oct 2024 16:55:36 +0200 Subject: [PATCH 242/256] e2e/feature/RI-6226_change_sorting_for_ft --- .../pageObjects/components/monaco-editor.ts | 24 ++++++++++++++++--- .../workbench}/no-indexes-suggestions.e2e.ts | 6 ++--- .../search-and-query-autocomplete.e2e.ts} | 6 ++++- 3 files changed, 29 insertions(+), 7 deletions(-) rename tests/e2e/tests/web/{regression/search-and-query => critical-path/workbench}/no-indexes-suggestions.e2e.ts (89%) rename tests/e2e/tests/web/{regression/search-and-query/search-and-query-tab.e2e.ts => critical-path/workbench/search-and-query-autocomplete.e2e.ts} (98%) diff --git a/tests/e2e/pageObjects/components/monaco-editor.ts b/tests/e2e/pageObjects/components/monaco-editor.ts index 007ebaf859..5bfff1b56d 100644 --- a/tests/e2e/pageObjects/components/monaco-editor.ts +++ b/tests/e2e/pageObjects/components/monaco-editor.ts @@ -23,7 +23,7 @@ export class MonacoEditor { async sendTextToMonaco(input: Selector, command: string, clean = true): Promise { await t.click(input); - if(clean) { + if (clean) { await t // remove text since replace doesn't work here .pressKey('ctrl+a') @@ -39,10 +39,10 @@ export class MonacoEditor { * @param depth level of depth of the object */ async insertTextByLines(input: Selector, lines: string[], depth: number): Promise { - for(let i = 0; i < lines.length; i++) { + for (let i = 0; i < lines.length; i++) { const line = lines[i]; - for(let j = 0; j < depth; j++) { + for (let j = 0; j < depth; j++) { await t.pressKey('shift+tab'); } @@ -61,4 +61,22 @@ export class MonacoEditor { const textAreaMonaco = Selector('[class^=view-lines ]'); return (await textAreaMonaco.textContent).replace(/\s+/g, ' '); } + + /** + * Get suggestions as ordered array from monaco from the beginning + * @param suggestions number of elements to get + */ + async getSuggestionsArrayFromMonaco(suggestions: number): Promise { + const textArray: string[] = []; + const suggestionElements = this.monacoSuggestion; + + for (let i = 0; i < suggestions; i++) { + const suggestionItem = suggestionElements.nth(i); + if (await suggestionItem.exists) { + textArray.push(await suggestionItem.textContent); + } + } + + return textArray; + } } diff --git a/tests/e2e/tests/web/regression/search-and-query/no-indexes-suggestions.e2e.ts b/tests/e2e/tests/web/critical-path/workbench/no-indexes-suggestions.e2e.ts similarity index 89% rename from tests/e2e/tests/web/regression/search-and-query/no-indexes-suggestions.e2e.ts rename to tests/e2e/tests/web/critical-path/workbench/no-indexes-suggestions.e2e.ts index ac2a27038c..b0a8d1cb23 100644 --- a/tests/e2e/tests/web/regression/search-and-query/no-indexes-suggestions.e2e.ts +++ b/tests/e2e/tests/web/critical-path/workbench/no-indexes-suggestions.e2e.ts @@ -1,7 +1,7 @@ import { DatabaseHelper } from '../../../../helpers/database'; import { BrowserPage, WorkbenchPage } from '../../../../pageObjects'; import { rte } from '../../../../helpers/constants'; -import { commonUrl, ossClusterConfig, ossStandaloneConfig, ossStandaloneRedisearch } from '../../../../helpers/conf'; +import { commonUrl, ossClusterConfig } from '../../../../helpers/conf'; import { DatabaseAPIRequests } from '../../../../helpers/api/api-database'; const browserPage = new BrowserPage(); @@ -14,11 +14,11 @@ fixture `Search and Query Raw mode` .page(commonUrl); test - .before(async t => { + .before(async () => { await databaseHelper.acceptLicenseTermsAndAddOSSClusterDatabase(ossClusterConfig); await browserPage.Cli.sendCommandInCli('flushdb'); }) - .after(async t => { + .after(async () => { await databaseAPIRequests.deleteOSSClusterDatabaseApi(ossClusterConfig); })('Verify suggestions when there are no indexes', async t => { diff --git a/tests/e2e/tests/web/regression/search-and-query/search-and-query-tab.e2e.ts b/tests/e2e/tests/web/critical-path/workbench/search-and-query-autocomplete.e2e.ts similarity index 98% rename from tests/e2e/tests/web/regression/search-and-query/search-and-query-tab.e2e.ts rename to tests/e2e/tests/web/critical-path/workbench/search-and-query-autocomplete.e2e.ts index 2bbb08ab01..19012b5824 100644 --- a/tests/e2e/tests/web/regression/search-and-query/search-and-query-tab.e2e.ts +++ b/tests/e2e/tests/web/critical-path/workbench/search-and-query-autocomplete.e2e.ts @@ -18,7 +18,7 @@ let indexName2: string; let indexName3: string; fixture `Autocomplete for entered commands in search and query` - .meta({ type: 'regression', rte: rte.standalone }) + .meta({ type: 'critical_path', rte: rte.standalone }) .page(commonUrl) .beforeEach(async t => { await databaseHelper.acceptLicenseTermsAndAddDatabaseApi(ossStandaloneConfig); @@ -84,8 +84,12 @@ test('Verify full commands suggestions with index and query for FT.AGGREGATE', a 'students', 'type' ]; + const ftSortedCommands = ['FT.SEARCH', 'FT.CREATE', 'FT.EXPLAIN', 'FT.PROFILE']; + // Verify basic commands suggestions FT.SEARCH and FT.AGGREGATE await t.typeText(workbenchPage.queryInput, 'FT', { replace: true }); + // Verify custom sorting for FT. commands + await t.expect(await workbenchPage.MonacoEditor.getSuggestionsArrayFromMonaco(4)).eql(ftSortedCommands, 'Wrong order of FT commands'); // Verify that the list with FT.SEARCH and FT.AGGREGATE auto-suggestions is displayed await t.expect(workbenchPage.MonacoEditor.monacoSuggestion.withText('FT._LIST').exists).ok('FT._LIST auto-suggestions are not displayed'); await t.expect(workbenchPage.MonacoEditor.monacoSuggestion.withText('FT.AGGREGATE').exists).ok('FT.AGGREGATE auto-suggestions are not displayed'); From 8cd844f758936e275452ff7963334e1db406c497 Mon Sep 17 00:00:00 2001 From: vlad-dargel Date: Thu, 24 Oct 2024 17:45:27 +0200 Subject: [PATCH 243/256] fix ts issue --- tests/e2e/tests/web/regression/database/github.e2e.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/e2e/tests/web/regression/database/github.e2e.ts b/tests/e2e/tests/web/regression/database/github.e2e.ts index ba2e4e4a91..a9bf329691 100644 --- a/tests/e2e/tests/web/regression/database/github.e2e.ts +++ b/tests/e2e/tests/web/regression/database/github.e2e.ts @@ -3,6 +3,7 @@ import { DatabaseHelper } from '../../../../helpers/database'; import { BrowserPage, MyRedisDatabasePage } from '../../../../pageObjects'; import { commonUrl, ossStandaloneConfig } from '../../../../helpers/conf'; import { DatabaseAPIRequests } from '../../../../helpers/api/api-database'; +import { Common } from '../../../../helpers/common'; const myRedisDatabasePage = new MyRedisDatabasePage(); const databaseHelper = new DatabaseHelper(); From 1d2d48e6acf01b315d934059cf25ad2fbe985b4c Mon Sep 17 00:00:00 2001 From: ArtemHoruzhenko Date: Fri, 25 Oct 2024 10:48:38 +0300 Subject: [PATCH 244/256] fix ITests --- .../repositories/local-command-execution.repository.spec.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/redisinsight/api/src/modules/workbench/repositories/local-command-execution.repository.spec.ts b/redisinsight/api/src/modules/workbench/repositories/local-command-execution.repository.spec.ts index 3769d6bd0a..e5143d7f67 100644 --- a/redisinsight/api/src/modules/workbench/repositories/local-command-execution.repository.spec.ts +++ b/redisinsight/api/src/modules/workbench/repositories/local-command-execution.repository.spec.ts @@ -70,9 +70,9 @@ describe('LocalCommandExecutionRepository', () => { }); when(encryptionService.decrypt) - .calledWith(mockCommandExecutionEntity.command, jasmine.anything()) + .calledWith(mockCommandExecutionEntity.command, expect.anything()) .mockResolvedValue(mockCommandExecution.command) - .calledWith(mockCommandExecutionEntity.result, jasmine.anything()) + .calledWith(mockCommandExecutionEntity.result, expect.anything()) .mockResolvedValue(JSON.stringify(mockCommandExecution.result)); repository.save.mockReturnValue(mockCommandExecutionEntity); From f3698a8e5f027d73454a7e5ed53ba1f78cc529bb Mon Sep 17 00:00:00 2001 From: Roman Sergeenko Date: Fri, 25 Oct 2024 10:49:01 +0200 Subject: [PATCH 245/256] fix detail token --- redisinsight/ui/src/pages/workbench/utils/query.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/redisinsight/ui/src/pages/workbench/utils/query.ts b/redisinsight/ui/src/pages/workbench/utils/query.ts index d5489e8e98..c9eceb774b 100644 --- a/redisinsight/ui/src/pages/workbench/utils/query.ts +++ b/redisinsight/ui/src/pages/workbench/utils/query.ts @@ -379,7 +379,10 @@ export const findArgByToken = (list: IRedisCommand[], arg: string): Maybe) => { if (!command) return '' - if (command.arguments) return generateArgsNames(CommandProvider.Main, command.arguments).join(' ') + if (command.arguments) { + const args = generateArgsNames(CommandProvider.Main, command.arguments).join(' ') + return command.token ? `${command.token} ${args}` : args + } if (command.token) { if (command.type === ICommandTokenType.PureToken) return command.token return `${command.token}` From 8ae91a2c9a90dc7cfea9e0a9f32925dc94c628e0 Mon Sep 17 00:00:00 2001 From: ArtemHoruzhenko Date: Fri, 25 Oct 2024 11:54:27 +0300 Subject: [PATCH 246/256] fix ITests --- .../api/redisearch/POST-databases-id-redisearch-info.test.ts | 2 +- .../api/test/api/ws/bulk-actions/bulk-actions-create.test.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/redisinsight/api/test/api/redisearch/POST-databases-id-redisearch-info.test.ts b/redisinsight/api/test/api/redisearch/POST-databases-id-redisearch-info.test.ts index a70d92e566..e963782cce 100644 --- a/redisinsight/api/test/api/redisearch/POST-databases-id-redisearch-info.test.ts +++ b/redisinsight/api/test/api/redisearch/POST-databases-id-redisearch-info.test.ts @@ -115,7 +115,7 @@ describe('POST /databases/:id/redisearch/info', () => { }, statusCode: 500, responseBody: { - message: 'Unknown index name', + message: 'Unknown Index name', error: 'Internal Server Error', statusCode: 500, }, diff --git a/redisinsight/api/test/api/ws/bulk-actions/bulk-actions-create.test.ts b/redisinsight/api/test/api/ws/bulk-actions/bulk-actions-create.test.ts index e709c362b8..ab964dd605 100644 --- a/redisinsight/api/test/api/ws/bulk-actions/bulk-actions-create.test.ts +++ b/redisinsight/api/test/api/ws/bulk-actions/bulk-actions-create.test.ts @@ -23,7 +23,7 @@ const createDto = { let client; describe('bulk-actions', function () { - this.timeout(10000); + this.timeout(20000); beforeEach(async () => { client = await getClient(); await rte.data.generateKeys(true); From 39faae46fb89a7f567e9fc3f6bc4c953895bccc8 Mon Sep 17 00:00:00 2001 From: vlad-dargel Date: Fri, 25 Oct 2024 12:38:59 +0200 Subject: [PATCH 247/256] release/2.60.0 --- .circleci/build/release-docker.sh | 2 +- .github/build/release-docker.sh | 2 +- redisinsight/api/config/default.ts | 2 +- redisinsight/api/config/swagger.ts | 2 +- redisinsight/api/package.json | 2 +- redisinsight/desktop/src/lib/aboutPanel/aboutPanel.ts | 2 +- redisinsight/package.json | 2 +- redisinsight/ui/package.json | 2 +- 8 files changed, 8 insertions(+), 8 deletions(-) diff --git a/.circleci/build/release-docker.sh b/.circleci/build/release-docker.sh index 32fb86bc36..85f4129a8c 100755 --- a/.circleci/build/release-docker.sh +++ b/.circleci/build/release-docker.sh @@ -2,7 +2,7 @@ set -e HELP="Args: --v - Semver (2.58.0) +-v - Semver (2.60.0) -d - Build image repository (Ex: -d redisinsight) -r - Target repository (Ex: -r redis/redisinsight) " diff --git a/.github/build/release-docker.sh b/.github/build/release-docker.sh index 7c49f1e379..4dd3d0fad3 100755 --- a/.github/build/release-docker.sh +++ b/.github/build/release-docker.sh @@ -2,7 +2,7 @@ set -e HELP="Args: --v - Semver (2.58.0) +-v - Semver (2.60.0) -d - Build image repository (Ex: -d redisinsight) -r - Target repository (Ex: -r redis/redisinsight) " diff --git a/redisinsight/api/config/default.ts b/redisinsight/api/config/default.ts index 2bcf430512..f71b592308 100644 --- a/redisinsight/api/config/default.ts +++ b/redisinsight/api/config/default.ts @@ -80,7 +80,7 @@ export default { migrateOldFolders: process.env.RI_MIGRATE_OLD_FOLDERS ? process.env.RI_MIGRATE_OLD_FOLDERS === 'true' : true, autoBootstrap: process.env.RI_AUTO_BOOTSTRAP ? process.env.RI_AUTO_BOOTSTRAP === 'true' : true, buildType: process.env.RI_BUILD_TYPE || 'DOCKER_ON_PREMISE', - appVersion: process.env.RI_APP_VERSION || '2.58.0', + appVersion: process.env.RI_APP_VERSION || '2.60.0', requestTimeout: parseInt(process.env.RI_REQUEST_TIMEOUT, 10) || 25000, excludeRoutes: [], excludeAuthRoutes: [], diff --git a/redisinsight/api/config/swagger.ts b/redisinsight/api/config/swagger.ts index 4b9dda297d..5a88b97c66 100644 --- a/redisinsight/api/config/swagger.ts +++ b/redisinsight/api/config/swagger.ts @@ -5,7 +5,7 @@ const SWAGGER_CONFIG: Omit = { info: { title: 'Redis Insight Backend API', description: 'Redis Insight Backend API', - version: '2.58.0', + version: '2.60.0', }, tags: [], }; diff --git a/redisinsight/api/package.json b/redisinsight/api/package.json index 91933ab7f7..e860b5a346 100644 --- a/redisinsight/api/package.json +++ b/redisinsight/api/package.json @@ -1,6 +1,6 @@ { "name": "redisinsight-api", - "version": "2.58.0", + "version": "2.60.0", "description": "Redis Insight API", "private": true, "author": { diff --git a/redisinsight/desktop/src/lib/aboutPanel/aboutPanel.ts b/redisinsight/desktop/src/lib/aboutPanel/aboutPanel.ts index 1ab732ad42..ba343769c5 100644 --- a/redisinsight/desktop/src/lib/aboutPanel/aboutPanel.ts +++ b/redisinsight/desktop/src/lib/aboutPanel/aboutPanel.ts @@ -8,7 +8,7 @@ const ICON_PATH = app.isPackaged export const AboutPanelOptions = { applicationName: 'Redis Insight', - applicationVersion: `${app.getVersion() || '2.58.0'}${ + applicationVersion: `${app.getVersion() || '2.60.0'}${ !config.isProduction ? `-dev-${process.getCreationTime()}` : '' }`, copyright: `Copyright © ${new Date().getFullYear()} Redis Ltd.`, diff --git a/redisinsight/package.json b/redisinsight/package.json index bf7c8e284a..69059207fe 100644 --- a/redisinsight/package.json +++ b/redisinsight/package.json @@ -3,7 +3,7 @@ "appName": "Redis Insight", "productName": "RedisInsight", "private": true, - "version": "2.58.0", + "version": "2.60.0", "description": "Redis Insight", "main": "./dist/main/main.js", "author": { diff --git a/redisinsight/ui/package.json b/redisinsight/ui/package.json index daad228819..7054878391 100644 --- a/redisinsight/ui/package.json +++ b/redisinsight/ui/package.json @@ -2,7 +2,7 @@ "name": "redisinsight", "appName": "Redis Insight", "productName": "RedisInsight", - "version": "2.58.0", + "version": "2.60.0", "description": "Redis Insight", "author": { "name": "Redis Ltd.", From fffbfc33c52b3fc50c4b6ef418cb20733e8852c7 Mon Sep 17 00:00:00 2001 From: ArtemHoruzhenko Date: Fri, 25 Oct 2024 14:14:33 +0300 Subject: [PATCH 248/256] run API UTests in a single process + disable oss standalone big env for Integration tests --- .circleci/config.yml | 3 ++- redisinsight/api/package.json | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 6803342714..250cc8ca72 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -121,7 +121,8 @@ aliases: - oss-st-5 # OSS Standalone v5 - oss-st-5-pass # OSS Standalone v5 with admin pass required - oss-st-6 # OSS Standalone v6 and all modules - - oss-st-big # OSS Standalone v6 and all modules and predefined amount of data inside (~3-4M) + # TODO: Investigate why it randomly fails + # - oss-st-big # OSS Standalone v6 and all modules and predefined amount of data inside (~3-4M) - mods-preview # OSS Standalone and all preview modules - oss-st-6-tls # OSS Standalone v6 with TLS enabled - oss-st-6-tls-auth # OSS Standalone v6 with TLS auth required diff --git a/redisinsight/api/package.json b/redisinsight/api/package.json index e860b5a346..a6270bb378 100644 --- a/redisinsight/api/package.json +++ b/redisinsight/api/package.json @@ -28,7 +28,7 @@ "start:prod": "cross-env NODE_ENV=production node dist/src/main", "test": "cross-env NODE_ENV=test ./node_modules/.bin/jest -w 1", "test:watch": "cross-env NODE_ENV=test jest --watch -w 1", - "test:cov": "cross-env NODE_ENV=test ./node_modules/.bin/jest --forceExit --coverage -w 4", + "test:cov": "cross-env NODE_ENV=test ./node_modules/.bin/jest --forceExit --coverage --runInBand", "test:debug": "node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand -w 1", "test:e2e": "jest --config ./test/jest-e2e.json -w 1", "typeorm": "ts-node -r tsconfig-paths/register ./node_modules/typeorm/cli.js -d ./config/ormconfig.ts", From eadb9fc1d95ae09ac228b71dc47d919ad309ba96 Mon Sep 17 00:00:00 2001 From: Roman Sergeenko Date: Fri, 25 Oct 2024 14:03:44 +0200 Subject: [PATCH 249/256] #RI-6170 - fix word pattern #RI-6246 - fix read more link --- redisinsight/ui/src/constants/monaco/monacoRedis.ts | 2 +- .../pages/workbench/components/query/Query/Query.tsx | 2 ++ .../ui/src/pages/workbench/utils/suggestions.ts | 11 +++++++++-- 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/redisinsight/ui/src/constants/monaco/monacoRedis.ts b/redisinsight/ui/src/constants/monaco/monacoRedis.ts index fe04e76ae4..25925611ae 100644 --- a/redisinsight/ui/src/constants/monaco/monacoRedis.ts +++ b/redisinsight/ui/src/constants/monaco/monacoRedis.ts @@ -1,7 +1,7 @@ import { monaco as monacoEditor } from 'react-monaco-editor' export const redisLanguageConfig: monacoEditor.languages.LanguageConfiguration = { - wordPattern: /(#?-?\d*\.\d\w*%?)|([@#!.:]?[\w-?]+%?)|[@#!.]/g, + wordPattern: /\w+\.?(\w?)+/g, comments: { lineComment: '//', // blockComment: ['/*', '*/'], diff --git a/redisinsight/ui/src/pages/workbench/components/query/Query/Query.tsx b/redisinsight/ui/src/pages/workbench/components/query/Query/Query.tsx index 803549fa50..ea98aa5f06 100644 --- a/redisinsight/ui/src/pages/workbench/components/query/Query/Query.tsx +++ b/redisinsight/ui/src/pages/workbench/components/query/Query/Query.tsx @@ -528,6 +528,8 @@ const Query = (props: Props) => { const setupMonacoRedisLang = (monaco: typeof monacoEditor) => { disposeCompletionItemProvider = monaco.languages.registerCompletionItemProvider(MonacoLanguage.Redis, { + // refactor/remove trigger function (TODO: after apply suggestion need trigger again) + // triggerCharacters: [' '], // Dot and space will trigger suggestions provideCompletionItems: (): monacoEditor.languages.CompletionList => ({ suggestions: suggestionsRef.current }) }).dispose diff --git a/redisinsight/ui/src/pages/workbench/utils/suggestions.ts b/redisinsight/ui/src/pages/workbench/utils/suggestions.ts index 9e443d3f06..997e0186d3 100644 --- a/redisinsight/ui/src/pages/workbench/utils/suggestions.ts +++ b/redisinsight/ui/src/pages/workbench/utils/suggestions.ts @@ -2,7 +2,14 @@ import { monaco } from 'react-monaco-editor' import * as monacoEditor from 'monaco-editor' import { findIndex } from 'lodash' import { RedisResponseBuffer } from 'uiSrc/slices/interfaces' -import { bufferToString, formatLongName, generateArgsForInsertText, getCommandMarkdown, Nullable } from 'uiSrc/utils' +import { + bufferToString, + formatLongName, + generateArgsForInsertText, + getCommandMarkdown, + getDocUrlForCommand, + Nullable +} from 'uiSrc/utils' import { FoundCommandArgument } from 'uiSrc/pages/workbench/types' import { DefinedArgumentName, @@ -117,7 +124,7 @@ export const getCommandsSuggestions = (commands: IRedisCommand[], range: monaco. detail: generateDetail(command), insertTextRules: monacoEditor.languages.CompletionItemInsertTextRule.InsertAsSnippet, documentation: { - value: getCommandMarkdown(command as any) + value: getCommandMarkdown(command as any, command.name ? getDocUrlForCommand(command.name) : '') }, sortText: getSortingForCommand(command) })) From ce4c4547ac6b78777ea597405175bbb7711af886 Mon Sep 17 00:00:00 2001 From: kchepikava Date: Mon, 28 Oct 2024 11:37:49 +0100 Subject: [PATCH 250/256] RI-6249 change general chatbot endpoint for staging --- redisinsight/api/config/default.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/redisinsight/api/config/default.ts b/redisinsight/api/config/default.ts index f71b592308..eb82353947 100644 --- a/redisinsight/api/config/default.ts +++ b/redisinsight/api/config/default.ts @@ -279,7 +279,7 @@ export default { }, }, ai: { - convAiApiUrl: process.env.RI_AI_CONVAI_API_URL || 'https://staging.redis.io/convai/api', + convAiApiUrl: process.env.RI_AI_CONVAI_API_URL || 'https://staging.learn.redis.com/convai/api', convAiToken: process.env.RI_AI_CONVAI_TOKEN, querySocketUrl: process.env.RI_AI_QUERY_SOCKET_URL || 'https://app-sm.k8s-cloudapi.sm-qa.qa.redislabs.com', querySocketPath: process.env.RI_AI_QUERY_SOCKET_PATH || '/api/v1/cloud-copilot-service/socket.io/', From ab73eb841fd7ae0e0c40d900b4a45e79ef2fccb3 Mon Sep 17 00:00:00 2001 From: kchepikava Date: Tue, 29 Oct 2024 10:43:34 +0100 Subject: [PATCH 251/256] RI-6248 fixed pub-sub styling --- .../messages-list/MessagesList/MessagesList.tsx | 2 +- .../messages-list/MessagesList/styles.module.scss | 9 ++++++++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/redisinsight/ui/src/pages/pub-sub/components/messages-list/MessagesList/MessagesList.tsx b/redisinsight/ui/src/pages/pub-sub/components/messages-list/MessagesList/MessagesList.tsx index 5d41879250..cfb8ab2ab7 100644 --- a/redisinsight/ui/src/pages/pub-sub/components/messages-list/MessagesList/MessagesList.tsx +++ b/redisinsight/ui/src/pages/pub-sub/components/messages-list/MessagesList/MessagesList.tsx @@ -130,7 +130,7 @@ const MessagesList = (props: Props) => {
{channel}
-
{message}
+
{message}
) } diff --git a/redisinsight/ui/src/pages/pub-sub/components/messages-list/MessagesList/styles.module.scss b/redisinsight/ui/src/pages/pub-sub/components/messages-list/MessagesList/styles.module.scss index 3cd780a1ce..54a6b9d8dd 100644 --- a/redisinsight/ui/src/pages/pub-sub/components/messages-list/MessagesList/styles.module.scss +++ b/redisinsight/ui/src/pages/pub-sub/components/messages-list/MessagesList/styles.module.scss @@ -12,12 +12,12 @@ .time { color: var(--defaultGreenColor); width: 150px; + padding-right: 4px; } .channel { color: var(--euiColorMediumShade); width: 220px; - max-height: 26px; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; @@ -29,12 +29,19 @@ overflow: hidden; white-space: nowrap; text-overflow: ellipsis; + display: inline-block; + vertical-align: middle; } .message { width: calc(100% - 372px); color: var(--htmlColor); word-break: break-word; + + span { + display: inline-block; + vertical-align: middle; + } } .header { From 73a57af5345ec2e525fb3c98fae7f88110192e92 Mon Sep 17 00:00:00 2001 From: ArtemHoruzhenko Date: Tue, 29 Oct 2024 13:28:18 +0200 Subject: [PATCH 252/256] add in progress auth requests pool --- .../api/src/modules/cloud/auth/cloud-auth.service.ts | 12 ++++++++++++ .../desktop/src/lib/cloud/cloud-oauth.handlers.ts | 9 +++++++++ 2 files changed, 21 insertions(+) diff --git a/redisinsight/api/src/modules/cloud/auth/cloud-auth.service.ts b/redisinsight/api/src/modules/cloud/auth/cloud-auth.service.ts index e290732ea7..a82fae6dd5 100644 --- a/redisinsight/api/src/modules/cloud/auth/cloud-auth.service.ts +++ b/redisinsight/api/src/modules/cloud/auth/cloud-auth.service.ts @@ -35,6 +35,8 @@ export class CloudAuthService { private authRequests: Map = new Map(); + private inProgressRequests: Map = new Map(); + constructor( private readonly sessionService: CloudSessionService, private readonly googleIdpAuthStrategy: GoogleIdpCloudAuthStrategy, @@ -185,6 +187,8 @@ export class CloudAuthService { // delete authRequest on this step // allow to redirect with authorization code only once this.authRequests.delete(query.state); + // Track in progress auth requests to avoid errors when for some reason many we receive many the same calls + this.inProgressRequests.set(query.state, authRequest); const tokens = await this.exchangeCode(authRequest, query.code); @@ -297,4 +301,12 @@ export class CloudAuthService { throw wrapHttpError(e); } } + + isRequestInProgress(query) { + return !!this.inProgressRequests.has(query?.state); + } + + finishInProgressRequest(query) { + this.inProgressRequests.delete(query?.state); + } } diff --git a/redisinsight/desktop/src/lib/cloud/cloud-oauth.handlers.ts b/redisinsight/desktop/src/lib/cloud/cloud-oauth.handlers.ts index 1a32a8040d..5c1f480c8c 100644 --- a/redisinsight/desktop/src/lib/cloud/cloud-oauth.handlers.ts +++ b/redisinsight/desktop/src/lib/cloud/cloud-oauth.handlers.ts @@ -76,6 +76,12 @@ export const initCloudOauthHandlers = () => { export const cloudOauthCallback = async (url: UrlWithParsedQuery) => { try { const authService: CloudAuthService = getBackendApp()?.get?.(CloudAuthService) + + // Ignore xdg-open when the same request is being processed. + if (authService.isRequestInProgress(url.query)) { + return + } + const result = await authService.handleCallback(url.query) if (result.status === CloudAuthStatus.Failed) { @@ -83,6 +89,9 @@ export const cloudOauthCallback = async (url: UrlWithParsedQuery) => { currentWindow?.webContents.send(IpcOnEvent.cloudOauthCallback, result) } + + // complete auth request processing + authService.finishInProgressRequest(url.query) } catch (e) { log.error(wrapErrorMessageSensitiveData(e as Error)) } From 63a0b572bdda1e8f9759d44c5837e383052234b7 Mon Sep 17 00:00:00 2001 From: Roman Sergeenko Date: Tue, 29 Oct 2024 14:01:53 +0100 Subject: [PATCH 253/256] #RI-6250 - fix form jumping #RI-6253 - fix highlighting #RI-6250 - fix suggestions #RI-6264 - do not show list of commands automatically #RI-6266 - fix help widget highlighted text --- .../ui/src/constants/monaco/monaco.ts | 4 + redisinsight/ui/src/constants/monaco/theme.ts | 6 +- .../DatabasesListWrapper.tsx | 73 ++++++++++--------- .../components/query/Query/Query.tsx | 11 +-- .../ui/src/pages/workbench/utils/monaco.ts | 3 +- .../ui/src/pages/workbench/utils/query.ts | 13 +++- .../ui/src/utils/monaco/monacoUtils.ts | 20 +++-- .../monarchTokens/redisearchTokensSubRedis.ts | 2 +- .../redisearchTokensTemplates.ts | 7 +- 9 files changed, 77 insertions(+), 62 deletions(-) diff --git a/redisinsight/ui/src/constants/monaco/monaco.ts b/redisinsight/ui/src/constants/monaco/monaco.ts index a8eea653d4..243931acd5 100644 --- a/redisinsight/ui/src/constants/monaco/monaco.ts +++ b/redisinsight/ui/src/constants/monaco/monaco.ts @@ -49,6 +49,10 @@ export const defaultMonacoOptions: monacoEditor.editor.IStandaloneEditorConstruc automaticLayout: true, formatOnPaste: false, glyphMargin: true, + bracketPairColorization: { + enabled: true, + independentColorPoolPerBracketType: true + }, stickyScroll: { enabled: true, defaultModel: 'indentationModel' diff --git a/redisinsight/ui/src/constants/monaco/theme.ts b/redisinsight/ui/src/constants/monaco/theme.ts index 9cb3e860af..a2633fa971 100644 --- a/redisinsight/ui/src/constants/monaco/theme.ts +++ b/redisinsight/ui/src/constants/monaco/theme.ts @@ -37,16 +37,14 @@ export const redisearchLightThemeRules = [ export const darkThemeRules = [ { token: 'function', foreground: 'BFBC4E' }, ...redisearchDarKThemeRules.map((rule) => ({ - ...rule, - token: `${rule.token}` + ...rule })) ] export const lightThemeRules = [ { token: 'function', foreground: '795E26' }, ...redisearchLightThemeRules.map((rule) => ({ - ...rule, - token: `${rule.token}.redisearch` + ...rule })) ] diff --git a/redisinsight/ui/src/pages/home/components/database-list-component/DatabasesListWrapper.tsx b/redisinsight/ui/src/pages/home/components/database-list-component/DatabasesListWrapper.tsx index 25088a0c8f..0e8b097bb7 100644 --- a/redisinsight/ui/src/pages/home/components/database-list-component/DatabasesListWrapper.tsx +++ b/redisinsight/ui/src/pages/home/components/database-list-component/DatabasesListWrapper.tsx @@ -22,7 +22,6 @@ import RediStackLightMin from 'uiSrc/assets/img/modules/redistack/RediStackLight import RediStackDarkLogo from 'uiSrc/assets/img/modules/redistack/RedisStackLogoDark.svg' import RediStackLightLogo from 'uiSrc/assets/img/modules/redistack/RedisStackLogoLight.svg' import CloudLinkIcon from 'uiSrc/assets/img/oauth/cloud_link.svg?react' -import { ShowChildByCondition } from 'uiSrc/components' import DatabaseListModules from 'uiSrc/components/database-list-modules/DatabaseListModules' import ItemList from 'uiSrc/components/item-list' import { BrowserStorageItem, Pages, Theme } from 'uiSrc/constants' @@ -68,7 +67,6 @@ const DatabasesListWrapper = ({ width, onEditInstance, editedInstance, onDeleteI const [, forceRerender] = useState({}) const deletingIdRef = useRef('') - const isLoadingRef = useRef(false) const closePopover = () => { if (deletingIdRef.current) { @@ -82,21 +80,32 @@ const DatabasesListWrapper = ({ width, onEditInstance, editedInstance, onDeleteI forceRerender({}) } + // useEffect(() => { + // const editInstanceId = new URLSearchParams(search).get('editInstance') + // if (editInstanceId && !instances.loading) { + // const instance = instances.data.find((item: Instance) => item.id === editInstanceId) + // if (instance) { + // handleClickEditInstance(instance) + // } + // setTimeout(() => { + // history.replace(Pages.home) + // }, 1000) + // } + // + // // isLoadingRef.current = instances.loading + // // forceRerender({}) + // }, [instances.loading, search]) + useEffect(() => { const editInstanceId = new URLSearchParams(search).get('editInstance') - if (editInstanceId && !instances.loading) { + if (editInstanceId && instances.data.length) { const instance = instances.data.find((item: Instance) => item.id === editInstanceId) if (instance) { handleClickEditInstance(instance) - } - setTimeout(() => { history.replace(Pages.home) - }, 1000) + } } - - isLoadingRef.current = instances.loading - forceRerender({}) - }, [instances.loading, search]) + }, [instances, search]) useEffect(() => { closePopover() @@ -235,32 +244,28 @@ const DatabasesListWrapper = ({ width, onEditInstance, editedInstance, onDeleteI return (
{newStatus && ( - - -
- - + +
+ )} - - + handleCheckConnectToInstance(e, instance)} + onKeyDown={(e: React.KeyboardEvent) => handleCheckConnectToInstance(e, instance)} > - handleCheckConnectToInstance(e, instance)} - onKeyDown={(e: React.KeyboardEvent) => handleCheckConnectToInstance(e, instance)} - > - - {cellContent} - - {` ${getDbIndex(db)}`} - - - + + {cellContent} + + {` ${getDbIndex(db)}`} + +
) }, diff --git a/redisinsight/ui/src/pages/workbench/components/query/Query/Query.tsx b/redisinsight/ui/src/pages/workbench/components/query/Query/Query.tsx index ea98aa5f06..8e014eb9ba 100644 --- a/redisinsight/ui/src/pages/workbench/components/query/Query/Query.tsx +++ b/redisinsight/ui/src/pages/workbench/components/query/Query/Query.tsx @@ -1,6 +1,6 @@ import React, { useContext, useEffect, useMemo, useRef, useState } from 'react' import { useDispatch, useSelector } from 'react-redux' -import { compact, first } from 'lodash' +import { compact, first, isFinite } from 'lodash' import cx from 'classnames' import MonacoEditor, { monaco as monacoEditor } from 'react-monaco-editor' import { useParams } from 'react-router-dom' @@ -423,7 +423,7 @@ const Query = (props: Props) => { command: Nullable ) => { const { editor } = monacoObjects?.current || {} - if (!command || !editor) { + if (!command?.info || !editor) { isWidgetEscaped.current = false return } @@ -471,6 +471,7 @@ const Query = (props: Props) => { } const triggerSuggestions = () => { + isEscapedSuggestions.current = false const { editor } = monacoObjects.current || {} setTimeout(() => editor?.trigger('', 'editor.action.triggerSuggest', { auto: false })) } @@ -555,12 +556,12 @@ const Query = (props: Props) => { if (position.column === 1) { helpWidgetRef.current.isOpen = false - if (command) return asSuggestionsRef([]) + if (command?.info) return asSuggestionsRef([]) return asSuggestionsRef(getCommandsSuggestions(commands, range), false, false) } - if (!command) { - return asSuggestionsRef(getCommandsSuggestions(commands, range), false) + if (!command?.info) { + return asSuggestionsRef(getCommandsSuggestions(commands, range), false, false) } const { allArgs, args, cursor } = command diff --git a/redisinsight/ui/src/pages/workbench/utils/monaco.ts b/redisinsight/ui/src/pages/workbench/utils/monaco.ts index 8f032ce262..de7be34b2c 100644 --- a/redisinsight/ui/src/pages/workbench/utils/monaco.ts +++ b/redisinsight/ui/src/pages/workbench/utils/monaco.ts @@ -60,7 +60,8 @@ export const getRediSearchSignutureProvider = (options: Maybe<{ if (token && numberOfArgsInside > 1) { const parentToken = token.token || token.arguments?.[0]?.token const parentTokenPosition = parentToken ? label.indexOf(parentToken) : 0 - const startPosition = label.indexOf(arg, parentTokenPosition) + const wordRegex = new RegExp(`\\b${arg}\\b`, 'g') + const startPosition = wordRegex.exec(label.slice(parentTokenPosition))?.index || 0 signaturePosition = [startPosition, startPosition + arg.length] } diff --git a/redisinsight/ui/src/pages/workbench/utils/query.ts b/redisinsight/ui/src/pages/workbench/utils/query.ts index c9eceb774b..1b55fb5389 100644 --- a/redisinsight/ui/src/pages/workbench/utils/query.ts +++ b/redisinsight/ui/src/pages/workbench/utils/query.ts @@ -336,11 +336,12 @@ export const removeNotSuggestedArgs = (args: string[], commandArgs: IRedisComman } if (arg.type === ICommandTokenType.Block) { - if (arg.token) return !args.includes(arg.token) || arg.multiple - return arg.arguments?.[0]?.token && (!args.includes(arg.arguments?.[0]?.token?.toUpperCase()) || arg.multiple) + if (arg.token) return !args.some((queryArg) => isStringsEqual(queryArg, arg.token)) || arg.multiple + return arg.arguments?.[0]?.token + && (!args.some(((queryArg) => isStringsEqual(queryArg, arg.arguments?.[0]?.token))) || arg.multiple) } - return arg.token && !args.includes(arg.token) + return arg.token && !args.some((queryArg) => isStringsEqual(queryArg, arg.token)) }) export const fillArgsByType = (args: IRedisCommand[], expandBlock = true): IRedisCommandTree[] => { @@ -380,7 +381,11 @@ export const findArgByToken = (list: IRedisCommand[], arg: string): Maybe) => { if (!command) return '' if (command.arguments) { - const args = generateArgsNames(CommandProvider.Main, command.arguments).join(' ') + const isTokenInArguemnts = command.token === command.arguments?.[0]?.token + const args = generateArgsNames( + CommandProvider.Main, + command.arguments.slice(isTokenInArguemnts ? 1 : 0) + ).join(' ') return command.token ? `${command.token} ${args}` : args } if (command.token) { diff --git a/redisinsight/ui/src/utils/monaco/monacoUtils.ts b/redisinsight/ui/src/utils/monaco/monacoUtils.ts index 9a98e4dc5b..99474bc2a8 100644 --- a/redisinsight/ui/src/utils/monaco/monacoUtils.ts +++ b/redisinsight/ui/src/utils/monaco/monacoUtils.ts @@ -266,22 +266,26 @@ export const findCompleteQuery = ( compositeArgs, ) - const [[firstQueryArg]] = args + const [[commandNameFromQuery]] = args const matchedCommand = commandsArray - .find((command) => firstQueryArg?.toUpperCase() === command.toUpperCase()) + .find((command) => commandNameFromQuery?.toUpperCase() === command.toUpperCase()) + + const cursorContext = { + position, + fullQuery, + args, + allArgs: args.flat(), + cursor, + } if (isUndefined(matchedCommand)) { - return null + return cursorContext as IMonacoQuery } return { - position, + ...cursorContext, commandPosition, commandCursorPosition, - fullQuery, - args, - cursor, - allArgs: args.flat(), name: matchedCommand, info: commandsSpec[matchedCommand] } as IMonacoQuery diff --git a/redisinsight/ui/src/utils/monaco/monarchTokens/redisearchTokensSubRedis.ts b/redisinsight/ui/src/utils/monaco/monarchTokens/redisearchTokensSubRedis.ts index 01e02f9680..a28e4264de 100644 --- a/redisinsight/ui/src/utils/monaco/monarchTokens/redisearchTokensSubRedis.ts +++ b/redisinsight/ui/src/utils/monaco/monarchTokens/redisearchTokensSubRedis.ts @@ -122,7 +122,7 @@ export const getRediSearchSubRedisMonarchTokensProvider = ( [/[^\\"]+/, STRING_DOUBLE], ], startOfLine: [ - [/\n/, { next: '@keywords', token: '@pop' }] + [/\s?\n/, { next: '@root', token: '@pop' }], ] }, } diff --git a/redisinsight/ui/src/utils/monaco/monarchTokens/redisearchTokensTemplates.ts b/redisinsight/ui/src/utils/monaco/monarchTokens/redisearchTokensTemplates.ts index 0ebc7c1d36..06af5ef3c5 100644 --- a/redisinsight/ui/src/utils/monaco/monarchTokens/redisearchTokensTemplates.ts +++ b/redisinsight/ui/src/utils/monaco/monarchTokens/redisearchTokensTemplates.ts @@ -27,6 +27,7 @@ export const generateQuery = ( [/\\"/, { token: 'query', next: appendTokenName('@query.inside.double') }], [/==|!=|<=|>=|<|>/, { token: 'query.operator' }], [/&&|\|\|/, { token: 'query.operator' }], + [/[()]/, 'delimiter.parenthesis'], getFunctionsTokens('@function.inside.double'), [/"/, { token: appendTokenName('query'), next: '@root' }], [/./, { token: appendTokenName('query'), next: appendTokenName('@query.inside.double') }], @@ -37,6 +38,7 @@ export const generateQuery = ( [/\\'/, { token: appendTokenName('query'), next: appendTokenName('query.inside.single') }], [/==|!=|<=|>=|<|>/, { token: 'query.operator' }], [/&&|\|\|/, { token: 'query.operator' }], + [/[()]/, 'delimiter.parenthesis'], getFunctionsTokens('@function.inside.single'), [/'/, { token: appendTokenName('query'), next: '@root' }], [/./, { token: appendTokenName('query'), next: appendTokenName('@query.inside.single') }], @@ -60,11 +62,6 @@ export const generateQuery = ( [/\(/, { token: 'delimiter.parenthesis', next: appendTokenName('@function.args.double') }], { include: appendTokenName('@query') } ], - [appendTokenName('function.inside.double')]: [ - [/\s+/, 'white'], // Handle whitespace - [/\(/, { token: 'delimiter.parenthesis', next: appendTokenName('@function.args.double') }], - { include: appendTokenName('@query') } - ], [appendTokenName('function.args.double')]: [ [/\)/, { token: 'delimiter.parenthesis', next: appendTokenName('@query.inside.double') }], [/,/, 'delimiter.comma'], // Match commas between arguments From 5458815cacc5b7ee86b3a0e480a6c121efcb2683 Mon Sep 17 00:00:00 2001 From: Roman Sergeenko Date: Tue, 29 Oct 2024 14:03:18 +0100 Subject: [PATCH 254/256] remove commented block --- .../DatabasesListWrapper.tsx | 18 +----------------- 1 file changed, 1 insertion(+), 17 deletions(-) diff --git a/redisinsight/ui/src/pages/home/components/database-list-component/DatabasesListWrapper.tsx b/redisinsight/ui/src/pages/home/components/database-list-component/DatabasesListWrapper.tsx index 0e8b097bb7..9de868da7a 100644 --- a/redisinsight/ui/src/pages/home/components/database-list-component/DatabasesListWrapper.tsx +++ b/redisinsight/ui/src/pages/home/components/database-list-component/DatabasesListWrapper.tsx @@ -80,25 +80,9 @@ const DatabasesListWrapper = ({ width, onEditInstance, editedInstance, onDeleteI forceRerender({}) } - // useEffect(() => { - // const editInstanceId = new URLSearchParams(search).get('editInstance') - // if (editInstanceId && !instances.loading) { - // const instance = instances.data.find((item: Instance) => item.id === editInstanceId) - // if (instance) { - // handleClickEditInstance(instance) - // } - // setTimeout(() => { - // history.replace(Pages.home) - // }, 1000) - // } - // - // // isLoadingRef.current = instances.loading - // // forceRerender({}) - // }, [instances.loading, search]) - useEffect(() => { const editInstanceId = new URLSearchParams(search).get('editInstance') - if (editInstanceId && instances.data.length) { + if (editInstanceId && instances?.data?.length) { const instance = instances.data.find((item: Instance) => item.id === editInstanceId) if (instance) { handleClickEditInstance(instance) From f152bf22158a6e4eec3bc6e5686ee800111f7677 Mon Sep 17 00:00:00 2001 From: kchepikava Date: Tue, 29 Oct 2024 20:24:06 +0100 Subject: [PATCH 255/256] RI-6273 fix pubsub not saved when switching between pages --- .../components/subscription-panel/SubscriptionPanel.tsx | 4 ++-- .../components/patternsInfo/PatternsInfo.tsx | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/redisinsight/ui/src/pages/pub-sub/components/subscription-panel/SubscriptionPanel.tsx b/redisinsight/ui/src/pages/pub-sub/components/subscription-panel/SubscriptionPanel.tsx index 7ce8aa500f..387753d57d 100644 --- a/redisinsight/ui/src/pages/pub-sub/components/subscription-panel/SubscriptionPanel.tsx +++ b/redisinsight/ui/src/pages/pub-sub/components/subscription-panel/SubscriptionPanel.tsx @@ -20,14 +20,14 @@ import ClickableAppendInfo from './components/clickable-append-info' import styles from './styles.module.scss' const SubscriptionPanel = () => { - const { messages, isSubscribed, loading, count } = useSelector(pubSubSelector) + const { messages, isSubscribed, subscriptions, loading, count } = useSelector(pubSubSelector) const dispatch = useDispatch() const { theme } = useContext(ThemeContext) const { instanceId = '' } = useParams<{ instanceId: string }>() - const [channels, setChannels] = useState(DEFAULT_SEARCH_MATCH) + const [channels, setChannels] = useState(subscriptions?.length ? subscriptions.map((sub) => sub.channel).join(' ') : DEFAULT_SEARCH_MATCH) const toggleSubscribe = () => { dispatch(toggleSubscribeTriggerPubSub(channels)) diff --git a/redisinsight/ui/src/pages/pub-sub/components/subscription-panel/components/patternsInfo/PatternsInfo.tsx b/redisinsight/ui/src/pages/pub-sub/components/subscription-panel/components/patternsInfo/PatternsInfo.tsx index 1e3f1f1112..f5068af61b 100644 --- a/redisinsight/ui/src/pages/pub-sub/components/subscription-panel/components/patternsInfo/PatternsInfo.tsx +++ b/redisinsight/ui/src/pages/pub-sub/components/subscription-panel/components/patternsInfo/PatternsInfo.tsx @@ -20,7 +20,7 @@ const PatternsInfo = ({ channels }: PatternsInfoProps) => { {channels?.trim().split(' ').map((ch) =>

{ch}

)}} + title={<>{channels?.trim().split(' ').map((ch) =>

{ch}

)}} > Date: Wed, 30 Oct 2024 12:41:39 +0100 Subject: [PATCH 256/256] add ft.aggregate to top list --- redisinsight/ui/src/pages/workbench/constants.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/redisinsight/ui/src/pages/workbench/constants.ts b/redisinsight/ui/src/pages/workbench/constants.ts index b894704f29..3dd802e518 100644 --- a/redisinsight/ui/src/pages/workbench/constants.ts +++ b/redisinsight/ui/src/pages/workbench/constants.ts @@ -101,6 +101,7 @@ export enum EmptySuggestionsIds { export const SORTED_SEARCH_COMMANDS = [ 'FT.SEARCH', + 'FT.AGGREGATE', 'FT.CREATE', 'FT.EXPLAIN', 'FT.PROFILE'