Repository: epam/ai-dial-chat
Pull request #3852: fix(chat): add breakpoints for talk to slider (Issues #3794, #3772, #3834)
Author: login: Alexander-Kezik
Labels: name: bug
description: Something isn't working
Created: 2025-05-16T09:43:26Z | Merged: 2025-05-16T18:21:39Z

**Description:**

add breakpoints for talk to slider

Issues:

- Issue #3794
- Issue #3772
- Issue #3834

**Checklist:**

- [x] the pull request name complies with [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/)
- [x] the pull request name starts with `fix(<scope>):`, `feat(<scope>):`, `feature(<scope>):`, `chore(<scope>):`, `hotfix(<scope>):` or `e2e(<scope>):`. If contains breaking changes then the pull request name must start with `fix(<scope>)!:`, `feat(<scope>)!:`, `feature(<scope>)!:`, `chore(<scope>)!:`, `hotfix(<scope>)!:` or `e2e(<scope>)!:` where `<scope>` is name of affected project: `chat`, `chat-e2e`, `overlay`, `shared`, `sandbox-overlay`, etc.
- [x] the pull request name ends with `(Issue #<TICKET_ID>)` (comma-separated list of issues)
- [x] I confirm that do not share any confidential information like API keys or any other secrets and private URLs



Diff:
diff --git a/apps/chat/src/components/Chat/Migration/MigrationFailedModal.tsx b/apps/chat/src/components/Chat/Migration/MigrationFailedModal.tsx
index cb4841fa87..a87da9e659 100644
--- a/apps/chat/src/components/Chat/Migration/MigrationFailedModal.tsx
+++ b/apps/chat/src/components/Chat/Migration/MigrationFailedModal.tsx
@@ -13,6 +13,7 @@ import { useRouter } from 'next/router';
 import classNames from 'classnames';
 
 import { useTranslation } from '@/src/hooks/useTranslation';
+import { useWindowResizeEvent } from '@/src/hooks/useWindowResizeEvent';
 
 import { BrowserStorage } from '@/src/utils/app/data/storages/browser-storage';
 import { isSmallScreen } from '@/src/utils/app/mobile';
@@ -181,12 +182,10 @@ export const MigrationFailedWindow = ({
     MigrationSelectors.selectIsChatsBackedUp,
   );
 
-  useEffect(() => {
-    const handleResize = () => setIsScreenSmall(isSmallScreen());
-    window.addEventListener('resize', handleResize);
-
-    return () => window.removeEventListener('resize', handleResize);
+  const handleResize = useCallback(() => {
+    setIsScreenSmall(isSmallScreen());
   }, []);
+  useWindowResizeEvent(handleResize);
 
   useEffect(() => {
     setConversationsToRetryIds(
diff --git a/apps/chat/src/components/Chat/TalkTo/SliderDots.tsx b/apps/chat/src/components/Chat/TalkTo/SliderDots.tsx
new file mode 100644
index 0000000000..e0cf7d627e
--- /dev/null
+++ b/apps/chat/src/components/Chat/TalkTo/SliderDots.tsx
@@ -0,0 +1,175 @@
+import { IconCaretLeftFilled, IconCaretRightFilled } from '@tabler/icons-react';
+import { useCallback, useEffect, useMemo } from 'react';
+
+import classNames from 'classnames';
+
+import { useScreenState } from '@/src/hooks/useScreenState';
+
+import { ScreenState } from '@/src/types/common';
+import { CardType } from '@/src/types/talkTo';
+
+import range from 'lodash-es/range';
+
+const getDotSizeClass = (
+  slideNumber: number,
+  activeSlide: number,
+  slidesCount: number,
+) => {
+  if (slideNumber === activeSlide) {
+    return 'h-2 w-8';
+  }
+
+  if (slidesCount < 7) {
+    return 'size-2';
+  }
+
+  const offsetActive = activeSlide - slideNumber;
+  const offsetLast = slidesCount - activeSlide;
+
+  if (
+    (offsetActive === 3 && activeSlide > 2 && offsetLast > 3) ||
+    (offsetLast === 3 && slideNumber < activeSlide - 3) ||
+    (offsetLast === 2 && slideNumber < activeSlide - 4) ||
+    (offsetLast === 1 && slideNumber < activeSlide - 5) ||
+    (activeSlide <= 3 && slideNumber === 6) ||
+    (activeSlide > 3 && slideNumber > activeSlide + 2)
+  ) {
+    return 'size-1';
+  }
+
+  if (
+    (offsetActive === 2 && activeSlide > 1 && offsetLast > 3) ||
+    (offsetLast === 3 && slideNumber < activeSlide - 2) ||
+    (offsetLast === 2 && slideNumber < activeSlide - 3) ||
+    (offsetLast === 1 && slideNumber < activeSlide - 4) ||
+    (activeSlide <= 3 && slideNumber === 5) ||
+    (activeSlide > 3 && slideNumber > activeSlide + 1)
+  ) {
+    return 'size-1.5';
+  }
+
+  return 'size-2';
+};
+
+const SLIDER_DOT_SIZE_WITH_GAPS = 24;
+const MAX_VISIBLE_SLIDER_DOTS = 7;
+
+interface Props {
+  activeSlide: number;
+  sliderGroups: CardType[][];
+  onSetActiveSlide: (slide: number) => void;
+}
+
+export const SliderDots: React.FC<Props> = ({
+  activeSlide,
+  sliderGroups,
+  onSetActiveSlide,
+}) => {
+  const screenState = useScreenState();
+
+  const isMobileOrTablet =
+    screenState === ScreenState.SM || screenState === ScreenState.MD;
+  const sliderDotsArray = useMemo(() => {
+    return range(0, sliderGroups.length);
+  }, [sliderGroups.length]);
+  const excessDots = sliderDotsArray.length - MAX_VISIBLE_SLIDER_DOTS;
+  const maxDotsTranslate = Math.max(0, excessDots * SLIDER_DOT_SIZE_WITH_GAPS);
+  const translateXValue = Math.max(
+    0,
+    Math.min(maxDotsTranslate, (activeSlide - 3) * SLIDER_DOT_SIZE_WITH_GAPS),
+  );
+
+  const handleClickRightArrow = useCallback(() => {
+    onSetActiveSlide(
+      activeSlide === sliderDotsArray.length - 1
+        ? activeSlide
+        : activeSlide + 1,
+    );
+  }, [activeSlide, onSetActiveSlide, sliderDotsArray.length]);
+
+  const handleClickLeftArrow = useCallback(() => {
+    onSetActiveSlide(activeSlide === 0 ? activeSlide : activeSlide - 1);
+  }, [activeSlide, onSetActiveSlide]);
+
+  const handleKeyDown = useCallback(
+    (e: KeyboardEvent) => {
+      if (e.key === 'ArrowRight') {
+        handleClickRightArrow();
+      } else if (e.key === 'ArrowLeft') {
+        handleClickLeftArrow();
+      }
+    },
+    [handleClickLeftArrow, handleClickRightArrow],
+  );
+
+  useEffect(() => {
+    window.addEventListener('keydown', handleKeyDown);
+
+    return () => {
+      window.removeEventListener('keydown', handleKeyDown);
+    };
+  }, [handleKeyDown]);
+
+  return (
+    <div className="mt-4 flex w-full items-center justify-center md:justify-end">
+      <div className="flex flex-col items-center md:h-5 md:w-1/2 md:flex-row md:justify-between">
+        <div className="relative flex items-center gap-4 md:-translate-x-1/2">
+          {sliderDotsArray.length <= 1 && screenState === ScreenState.SM && (
+            <span className="h-[18px] bg-transparent"></span>
+          )}
+          {sliderDotsArray.length > 1 && (
+            <>
+              {!isMobileOrTablet && (
+                <button
+                  onClick={handleClickLeftArrow}
+                  disabled={activeSlide === 0}
+                  className="text-secondary hover:text-accent-primary disabled:cursor-not-allowed disabled:hover:text-secondary"
+                >
+                  <IconCaretLeftFilled size={18} />
+                </button>
+              )}
+              <div className="flex max-w-[176px] overflow-hidden">
+                <div
+                  className="flex items-center gap-4  transition-all duration-200"
+                  style={{
+                    transform: `translateX(-${translateXValue}px)`,
+                  }}
+                >
+                  {sliderDotsArray.map((slideNumber) => {
+                    return (
+                      <div
+                        key={slideNumber}
+                        onClick={() => onSetActiveSlide(slideNumber)}
+                        className="flex min-w-2 items-center justify-center"
+                      >
+                        <button
+                          className={classNames(
+                            'rounded-full bg-controls-disable transition-all duration-200',
+                            getDotSizeClass(
+                              slideNumber,
+                              activeSlide,
+                              sliderDotsArray.length,
+                            ),
+                          )}
+                        />
+                      </div>
+                    );
+                  })}
+                </div>
+              </div>
+              {!isMobileOrTablet && (
+                <button
+                  onClick={handleClickRightArrow}
+                  disabled={activeSlide === sliderDotsArray.length - 1}
+                  className="text-secondary hover:text-accent-primary disabled:cursor-not-allowed disabled:hover:text-secondary"
+                >
+                  <IconCaretRightFilled size={18} />
+                </button>
+              )}
+            </>
+          )}
+        </div>
+      </div>
+    </div>
+  );
+};
diff --git a/apps/chat/src/components/Chat/TalkTo/TalkToCard.tsx b/apps/chat/src/components/Chat/TalkTo/TalkToCard.tsx
index 6ed5070fb8..c8b0e31f9b 100644
--- a/apps/chat/src/components/Chat/TalkTo/TalkToCard.tsx
+++ b/apps/chat/src/components/Chat/TalkTo/TalkToCard.tsx
@@ -83,7 +83,7 @@ export const TalkToCard = ({
           installedModelIds.has(model.reference) ||
           (isSelected && entity.reference === model.reference)),
     );
-  }, [allModels, entity, installedModelIds, isSelected]);
+  }, [allModels, entity, installedModelIds, isMyWorkspace, isSelected]);
 
   const handleSelectVersion = useCallback(
     (model: DialAIEntityModel) => {
diff --git a/apps/chat/src/components/Chat/TalkTo/TalkToModal.tsx b/apps/chat/src/components/Chat/TalkTo/TalkToModal.tsx
index 5364cd225f..3071c4b290 100644
--- a/apps/chat/src/components/Chat/TalkTo/TalkToModal.tsx
+++ b/apps/chat/src/components/Chat/TalkTo/TalkToModal.tsx
@@ -22,6 +22,7 @@ import { Conversation } from '@/src/types/chat';
 import { EntityType } from '@/src/types/common';
 import { ModalState } from '@/src/types/modal';
 import { DialAIEntityModel } from '@/src/types/models';
+import { CardType } from '@/src/types/talkTo';
 import { Translation } from '@/src/types/translation';
 
 import { ModelsActions } from '@/src/store/actions';
@@ -37,12 +38,13 @@ import {
   MarketplaceQueryParams,
   MarketplaceTabs,
 } from '@/src/constants/marketplace';
+import { SuggestedCard } from '@/src/constants/talkTo';
 
+import { TabButton } from '@/src/components/Buttons/TabButton';
+import { AgentDialogs } from '@/src/components/Common/AgentDialogs';
 import { Modal } from '@/src/components/Common/Modal';
 
-import { TabButton } from '../../Buttons/TabButton';
-import { AgentDialogs } from '../../Common/AgentDialogs';
-import { CardType, SuggestedCard, TalkToSlider } from './TalkToSlider';
+import { TalkToSlider } from './TalkToSlider';
 
 import { Feature } from '@epam/ai-dial-shared';
 import orderBy from 'lodash-es/orderBy';
@@ -78,6 +80,7 @@ const TalkToModalView = ({
   const { t } = useTranslation(Translation.Chat);
 
   const dispatch = useDispatch();
+
   const [tab, setTab] = useState(MarketplaceTabs.MY_WORKSPACE);
   const isMyWorkspace = tab === MarketplaceTabs.MY_WORKSPACE;
 
@@ -232,7 +235,14 @@ const TalkToModalView = ({
 
       onClose();
     },
-    [addonsMap, conversation, dispatch, modelsMap, onClose],
+    [
+      addonsMap,
+      conversation,
+      dispatch,
+      installedModelIdsSet,
+      modelsMap,
+      onClose,
+    ],
   );
 
   const handleGoToWorkspace = useCallback(
@@ -289,6 +299,7 @@ const TalkToModalView = ({
         isMyWorkspace={isMyWorkspace}
         onOpenMarketplaceTab={() => setTab(MarketplaceTabs.HOME)}
         isSearchMode={searchTerm.length > 0}
+        searchTerm={searchTerm}
       />
 
       {isMarketplaceEnabled && (
diff --git a/apps/chat/src/components/Chat/TalkTo/TalkToSlider.tsx b/apps/chat/src/components/Chat/TalkTo/TalkToSlider.tsx
index b384c96a59..ad0f172cf8 100644
--- a/apps/chat/src/components/Chat/TalkTo/TalkToSlider.tsx
+++ b/apps/chat/src/components/Chat/TalkTo/TalkToSlider.tsx
@@ -1,21 +1,31 @@
-import { IconCaretLeftFilled, IconCaretRightFilled } from '@tabler/icons-react';
-import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
+import {
+  memo,
+  useCallback,
+  useEffect,
+  useLayoutEffect,
+  useMemo,
+  useRef,
+  useState,
+} from 'react';
 
 import classNames from 'classnames';
 
 import { useScreenState } from '@/src/hooks/useScreenState';
 import { useSwipe } from '@/src/hooks/useSwipe';
 import { useTranslation } from '@/src/hooks/useTranslation';
+import { useWindowResizeEvent } from '@/src/hooks/useWindowResizeEvent';
 
 import {
   isPlaybackConversation,
   isReplayAsIsConversation,
 } from '@/src/utils/app/conversation';
+import { getScreenState } from '@/src/utils/app/mobile';
 import { PseudoModel, isPseudoModel } from '@/src/utils/server/api';
 
 import { Conversation } from '@/src/types/chat';
 import { ScreenState } from '@/src/types/common';
 import { DialAIEntityModel } from '@/src/types/models';
+import { CardType } from '@/src/types/talkTo';
 import { Translation } from '@/src/types/translation';
 
 import { useAppSelector } from '@/src/store/hooks';
@@ -23,282 +33,213 @@ import { ModelsSelectors } from '@/src/store/models/models.selectors';
 
 import { REPLAY_AS_IS_MODEL } from '@/src/constants/chat';
 import { ChangeAgentTabs, MarketplaceTabs } from '@/src/constants/marketplace';
+import { SuggestedCard } from '@/src/constants/talkTo';
 
 import { NoResultsFound } from '@/src/components/Common/NoResultsFound';
 
+import { SliderDots } from './SliderDots';
 import { TalkToCard } from './TalkToCard';
 
 import chunk from 'lodash-es/chunk';
-import range from 'lodash-es/range';
 
-const maxChunksCountConfig = {
-  [ScreenState.XL5]: {
-    cardHeight: 166,
-    maxRows: 3,
-    cols: 3,
-  },
-  [ScreenState.XL4]: {
-    cardHeight: 166,
-    maxRows: 3,
-    cols: 3,
-  },
-  [ScreenState.XL3]: {
-    cardHeight: 166,
-    maxRows: 3,
-    cols: 3,
-  },
-  [ScreenState.XL]: {
-    cardHeight: 166,
-    maxRows: 3,
-    cols: 3,
-  },
-  [ScreenState.MD]: {
-    cardHeight: 160,
-    maxRows: 4,
-    cols: 2,
-  },
-  [ScreenState.SM]: {
-    cardHeight: 98,
-    maxRows: 5,
-    cols: 1,
-  },
+const DEFAULT_SLIDER_CHUNKS_CONFIG = {
+  cardHeight: 166,
+  maxRows: 3,
+  cols: 3,
+};
+const TABLET_SLIDER_CHUNKS_CONFIG = {
+  cardHeight: 160,
+  maxRows: 4,
+  cols: 2,
+};
+const MOBILE_SLIDER_CHUNKS_CONFIG = {
+  cardHeight: 98,
+  maxRows: 5,
+  cols: 1,
 };
+const SLIDER_CHUNKS_CONFIG = {
+  [ScreenState.MD]: TABLET_SLIDER_CHUNKS_CONFIG,
+  [ScreenState.SM]: MOBILE_SLIDER_CHUNKS_CONFIG,
+};
+const getSliderChunksConfig = (screenState: ScreenState) =>
+  screenState === ScreenState.SM || screenState === ScreenState.MD
+    ? SLIDER_CHUNKS_CONFIG[screenState]
+    : DEFAULT_SLIDER_CHUNKS_CONFIG;
+
+const getStartSingleRowOffset = (screenState: ScreenState) =>
+  screenState === ScreenState.SM ? 255 : 217;
+
+const getGridGap = (screenState: ScreenState) =>
+  screenState === ScreenState.SM ? 12 : 16;
+
+const getRowsCount = () => {
+  const screenState = getScreenState();
+  const maxChunksCountConfig = getSliderChunksConfig(screenState);
+  const cardHeight = maxChunksCountConfig.cardHeight;
+  const gap = getGridGap(screenState);
+  const startSingleRowOffset = getStartSingleRowOffset(screenState);
+  let currentHeight = startSingleRowOffset + cardHeight * 2 + gap;
+  let currentRows = 1;
+
+  while (
+    currentHeight < window.innerHeight &&
+    currentRows + 1 <= maxChunksCountConfig.maxRows
+  ) {
+    currentRows++;
+    currentHeight += cardHeight + gap;
+  }
 
-const SLIDER_DOT_SIZE_WITH_GAPS = 24;
-const MAX_VISIBLE_SLIDER_DOTS = 7;
-const SLIDES_GAP = 16;
-const COMMON_GRID_TILES_GAP = 16;
-const MOBILE_GRID_TILES_GAP = 12;
+  return currentRows;
+};
 
+const GAP_BETWEEN_SLIDES = 16;
 const calculateTranslateX = (activeSlide: number, clientWidth?: number) => {
   if (!clientWidth) return 'none';
 
-  const offset = activeSlide * (clientWidth + SLIDES_GAP);
+  const offset = activeSlide * (clientWidth + GAP_BETWEEN_SLIDES);
 
   return `translateX(-${offset}px)`;
 };
 
-const getDotSizeClass = (
-  slideNumber: number,
-  activeSlide: number,
-  slidesCount: number,
-) => {
-  if (slideNumber === activeSlide) {
-    return 'h-2 w-8';
-  }
-
-  if (slidesCount < 7) {
-    return 'size-2';
-  }
-
-  const offsetActive = activeSlide - slideNumber;
-  const offsetLast = slidesCount - activeSlide;
-
-  if (
-    (offsetActive === 3 && activeSlide > 2 && offsetLast > 3) ||
-    (offsetLast === 3 && slideNumber < activeSlide - 3) ||
-    (offsetLast === 2 && slideNumber < activeSlide - 4) ||
-    (offsetLast === 1 && slideNumber < activeSlide - 5) ||
-    (activeSlide <= 3 && slideNumber === 6) ||
-    (activeSlide > 3 && slideNumber > activeSlide + 2)
-  ) {
-    return 'size-1';
-  }
-
-  if (
-    (offsetActive === 2 && activeSlide > 1 && offsetLast > 3) ||
-    (offsetLast === 3 && slideNumber < activeSlide - 2) ||
-    (offsetLast === 2 && slideNumber < activeSlide - 3) ||
-    (offsetLast === 1 && slideNumber < activeSlide - 4) ||
-    (activeSlide <= 3 && slideNumber === 5) ||
-    (activeSlide > 3 && slideNumber > activeSlide + 1)
-  ) {
-    return 'size-1.5';
-  }
-
-  return 'size-2';
-};
-
 interface SliderModelsGroupProps {
   modelsGroup: CardType[];
   conversation: Conversation;
-  screenState: ScreenState;
   rowsCount: number;
+  isMyWorkspace: boolean;
   onSelectModel: (entity: DialAIEntityModel) => void;
   onOpenMarketplaceTab: () => void;
-  isMyWorkspace: boolean;
 }
 
-const SliderModelsGroup = ({
-  modelsGroup,
-  conversation,
-  screenState,
-  rowsCount,
-  onSelectModel,
-  onOpenMarketplaceTab,
-  isMyWorkspace,
-  ...restProps
-}: SliderModelsGroupProps) => {
-  const { t } = useTranslation(Translation.Chat);
-  const modelsMap = useAppSelector(ModelsSelectors.selectModelsMap);
-
-  return (
-    <section
-      key={modelsGroup.map((model) => model.reference).join('.')}
-      className="h-full min-w-full"
-      data-qa="agents-section"
-    >
-      <div
-        className="grid"
-        style={{
-          gridTemplateColumns: `repeat(${maxChunksCountConfig[screenState].cols}, minmax(0, 1fr))`,
-          gridTemplateRows: `repeat(${rowsCount}, ${maxChunksCountConfig[screenState].cardHeight}px)`,
-          gap:
-            screenState === ScreenState.SM
-              ? MOBILE_GRID_TILES_GAP
-              : COMMON_GRID_TILES_GAP,
-        }}
+const SliderModelsGroup = memo(
+  ({
+    modelsGroup,
+    conversation,
+    rowsCount,
+    isMyWorkspace,
+    onSelectModel,
+    onOpenMarketplaceTab,
+    ...restProps
+  }: SliderModelsGroupProps) => {
+    const { t } = useTranslation(Translation.Chat);
+
+    const screenState = useScreenState();
+
+    const modelsMap = useAppSelector(ModelsSelectors.selectModelsMap);
+
+    const maxChunksCountConfig = getSliderChunksConfig(screenState);
+
+    return (
+      <section
+        key={modelsGroup.map((model) => model.reference).join('.')}
+        className="h-full min-w-full"
+        data-qa="agents-section"
       >
-        {modelsGroup.map((model) => {
-          const isNotPseudoModelSelected =
-            model.reference === conversation.model.id &&
-            !isPlaybackConversation(conversation) &&
-            !isReplayAsIsConversation(conversation);
-          const isPseudoModelSelected =
-            model.reference === PseudoModel.Playback ||
-            (model.reference === REPLAY_AS_IS_MODEL &&
-              isReplayAsIsConversation(conversation));
-
-          if (model === SuggestedCard) {
+        <div
+          className="grid"
+          style={{
+            gridTemplateColumns: `repeat(${maxChunksCountConfig.cols}, minmax(0, 1fr))`,
+            gridTemplateRows: `repeat(${rowsCount}, ${maxChunksCountConfig.cardHeight}px)`,
+            gap: getGridGap(screenState),
+          }}
+        >
+          {modelsGroup.map((model) => {
+            const isNotPseudoModelSelected =
+              model.reference === conversation.model.id &&
+              !isPlaybackConversation(conversation) &&
+              !isReplayAsIsConversation(conversation);
+            const isPseudoModelSelected =
+              model.reference === PseudoModel.Playback ||
+              (model.reference === REPLAY_AS_IS_MODEL &&
+                isReplayAsIsConversation(conversation));
+
+            if (model === SuggestedCard) {
+              return (
+                <div
+                  className="flex size-full cursor-pointer flex-col items-center justify-center gap-3 rounded-md border border-primary hover:bg-layer-3"
+                  onClick={onOpenMarketplaceTab}
+                  key={SuggestedCard.id}
+                >
+                  <h3 className="text-base">
+                    {t("Couldn't find what you need?")}
+                  </h3>
+                  <SuggestionButton />
+                </div>
+              );
+            }
+
             return (
-              <div
-                className="flex size-full cursor-pointer flex-col items-center justify-center gap-3 rounded-md border border-primary hover:bg-layer-3"
-                onClick={onOpenMarketplaceTab}
-                key={SuggestedCard.id}
-              >
-                <h3 className="text-base">
-                  {t("Couldn't find what you need?")}
-                </h3>
-                <SuggestionButton />
-              </div>
+              <TalkToCard
+                isSelected={isNotPseudoModelSelected || isPseudoModelSelected}
+                conversation={conversation}
+                isUnavailableModel={
+                  !modelsMap[model.reference] &&
+                  !isPseudoModel(model.id) &&
+                  model.reference !== REPLAY_AS_IS_MODEL
+                }
+                disabled={
+                  isPlaybackConversation(conversation) &&
+                  model.reference !== PseudoModel.Playback
+                }
+                key={model.id}
+                entity={model as DialAIEntityModel}
+                onClick={onSelectModel}
+                onSelectVersion={onSelectModel}
+                isMyWorkspace={isMyWorkspace}
+                {...restProps}
+              />
             );
-          }
-
-          return (
-            <TalkToCard
-              isSelected={isNotPseudoModelSelected || isPseudoModelSelected}
-              conversation={conversation}
-              isUnavailableModel={
-                !modelsMap[model.reference] &&
-                !isPseudoModel(model.id) &&
-                model.reference !== REPLAY_AS_IS_MODEL
-              }
-              disabled={
-                isPlaybackConversation(conversation) &&
-                model.reference !== PseudoModel.Playback
-              }
-              key={model.id}
-              entity={model as DialAIEntityModel}
-              onClick={onSelectModel}
-              onSelectVersion={onSelectModel}
-              isMyWorkspace={isMyWorkspace}
-              {...restProps}
-            />
-          );
-        })}
-      </div>
-    </section>
-  );
-};
-
-export const SuggestedCard = {
-  id: 'suggested',
-  reference: 'suggested',
-};
-
-export type CardType = DialAIEntityModel | typeof SuggestedCard;
+          })}
+        </div>
+      </section>
+    );
+  },
+);
+SliderModelsGroup.displayName = 'SliderModelsGroup';
 
 interface Props {
   conversation: Conversation;
   items: CardType[];
-  onSelectModel: (entity: DialAIEntityModel) => void;
-  onOpenMarketplaceTab: () => void;
   isMyWorkspace: boolean;
   isSearchMode: boolean;
+  searchTerm: string;
+  onSelectModel: (entity: DialAIEntityModel) => void;
+  onOpenMarketplaceTab: () => void;
 }
 
 export const TalkToSlider = ({
   conversation,
   items,
   isMyWorkspace,
+  searchTerm,
   onOpenMarketplaceTab,
   ...restProps
 }: Props) => {
   const { t } = useTranslation(Translation.Chat);
+
   const sliderRef = useRef<HTMLDivElement>(null);
 
   const [activeSlide, setActiveSlide] = useState(0);
-  const [sliderHeight, setSliderHeight] = useState(0);
+  const [sliderRowsCount, setSliderRowsCount] = useState(1);
+  const [resizeTime, setResizeTime] = useState(Date.now());
 
   const screenState = useScreenState();
 
-  const sliderRowsCount = useMemo(() => {
-    const availableRows =
-      Math.floor(sliderHeight / maxChunksCountConfig[screenState].cardHeight) ||
-      1;
-
-    const finalRows =
-      availableRows === 1
-        ? availableRows
-        : Math.floor(
-            (sliderHeight -
-              (availableRows - 1) *
-                (screenState === ScreenState.SM
-                  ? MOBILE_GRID_TILES_GAP
-                  : COMMON_GRID_TILES_GAP)) /
-              maxChunksCountConfig[screenState].cardHeight,
-          ) || 1;
-
-    return finalRows > maxChunksCountConfig[screenState].maxRows
-      ? maxChunksCountConfig[screenState].maxRows
-      : finalRows;
-  }, [screenState, sliderHeight]);
+  const handleResize = useCallback(() => {
+    setSliderRowsCount(getRowsCount());
+    setResizeTime(Date.now());
+  }, []);
+  useWindowResizeEvent(handleResize);
 
-  const sliderGroups = useMemo(() => {
-    return chunk(
-      items,
-      sliderRowsCount * maxChunksCountConfig[screenState].cols,
-    );
-  }, [items, screenState, sliderRowsCount]);
-
-  const sliderDotsArray = useMemo(() => {
-    return range(0, sliderGroups.length);
-  }, [sliderGroups.length]);
-
-  const handleKeyDown = useCallback(
-    (e: KeyboardEvent) => {
-      if (e.key === 'ArrowRight') {
-        setActiveSlide((activeSlide) =>
-          activeSlide === sliderDotsArray.length - 1
-            ? activeSlide
-            : activeSlide + 1,
-        );
-      } else if (e.key === 'ArrowLeft') {
-        setActiveSlide((activeSlide) =>
-          activeSlide === 0 ? activeSlide : activeSlide - 1,
-        );
-      }
-    },
-    [sliderDotsArray.length],
-  );
+  // Should calculate height before render
+  useLayoutEffect(() => {
+    handleResize();
+  }, [handleResize]);
 
-  useEffect(() => {
-    window.addEventListener('keydown', handleKeyDown);
+  const maxChunksCountConfig = getSliderChunksConfig(screenState);
 
-    return () => {
-      window.removeEventListener('keydown', handleKeyDown);
-    };
-  }, [handleKeyDown]);
+  const sliderGroups = useMemo(() => {
+    return chunk(items, sliderRowsCount * maxChunksCountConfig.cols);
+  }, [items, maxChunksCountConfig.cols, sliderRowsCount]);
 
   const swipeHandlers = useSwipe({
     onSwipedLeft: () => {
@@ -311,24 +252,6 @@ export const TalkToSlider = ({
     },
   });
 
-  useEffect(() => {
-    const handleResize = () => {
-      if (sliderRef.current) {
-        setSliderHeight(sliderRef.current.clientHeight);
-      }
-    };
-
-    const resizeObserver = new ResizeObserver(handleResize);
-
-    if (sliderRef.current) {
-      resizeObserver.observe(sliderRef.current);
-    }
-
-    return () => {
-      resizeObserver.disconnect();
-    };
-  }, []);
-
   useEffect(() => {
     if (!sliderGroups.length) {
       setActiveSlide(0);
@@ -337,33 +260,38 @@ export const TalkToSlider = ({
     }
   }, [activeSlide, sliderGroups]);
 
-  const excessDots = sliderDotsArray.length - MAX_VISIBLE_SLIDER_DOTS;
-  const maxDotsTranslate = Math.max(0, excessDots * SLIDER_DOT_SIZE_WITH_GAPS);
-  const translateXValue = Math.max(
-    0,
-    Math.min(maxDotsTranslate, (activeSlide - 3) * SLIDER_DOT_SIZE_WITH_GAPS),
-  );
-  const isMobileOrTablet =
-    screenState === ScreenState.SM || screenState === ScreenState.MD;
+  useEffect(() => {
+    setActiveSlide(0);
+  }, [searchTerm, isMyWorkspace]);
+
+  const gridGap = getGridGap(screenState);
+  const resizeDeltaTime = Date.now() - resizeTime;
 
   return (
     <>
       <div
         ref={sliderRef}
-        className="flex h-[428px] max-h-[428px] w-full flex-col overflow-y-auto overflow-x-hidden md:h-[688px] md:max-h-[688px] xl:h-[530px] xl:max-h-[530px]"
+        className="flex max-h-[538px] w-full flex-col overflow-y-auto overflow-x-hidden md:max-h-[688px] xl:max-h-[530px]"
+        style={{
+          height: `${
+            sliderRowsCount * (maxChunksCountConfig.cardHeight + gridGap) -
+            gridGap
+          }px`,
+        }}
       >
         <div
           {...swipeHandlers}
           className={classNames(
             'flex size-full',
-            sliderGroups.length && 'transition duration-1000 ease-out',
+            sliderGroups.length && 'transition ease-out',
+            resizeDeltaTime < 50 ? 'duration-0' : 'duration-1000',
           )}
           style={{
             transform: calculateTranslateX(
               activeSlide,
               sliderRef.current?.clientWidth,
             ),
-            gap: `${SLIDES_GAP}px`,
+            gap: `${GAP_BETWEEN_SLIDES}px`,
           }}
         >
           {sliderGroups.length ? (
@@ -372,10 +300,9 @@ export const TalkToSlider = ({
                 key={modelsGroup.map((model) => model.id).join('.')}
                 modelsGroup={modelsGroup}
                 conversation={conversation}
-                screenState={screenState}
                 rowsCount={sliderRowsCount}
-                onOpenMarketplaceTab={onOpenMarketplaceTab}
                 isMyWorkspace={isMyWorkspace}
+                onOpenMarketplaceTab={onOpenMarketplaceTab}
                 {...restProps}
               />
             ))
@@ -396,76 +323,11 @@ export const TalkToSlider = ({
           )}
         </div>
       </div>
-      <div className="mt-4 flex w-full items-center justify-center md:justify-end">
-        <div className="flex flex-col items-center md:h-5 md:w-1/2 md:flex-row md:justify-between">
-          <div className="relative flex items-center gap-4 md:-translate-x-1/2">
-            {sliderDotsArray.length <= 1 && screenState === ScreenState.SM && (
-              <span className="h-[18px] bg-transparent"></span>
-            )}
-            {sliderDotsArray.length > 1 && (
-              <>
-                {!isMobileOrTablet && (
-                  <button
-                    onClick={() =>
-                      setActiveSlide((activeSlide) =>
-                        activeSlide === 0 ? activeSlide : activeSlide - 1,
-                      )
-                    }
-                    disabled={activeSlide === 0}
-                    className="text-secondary hover:text-accent-primary disabled:cursor-not-allowed disabled:hover:text-secondary"
-                  >
-                    <IconCaretLeftFilled size={18} />
-                  </button>
-                )}
-                <div className="flex max-w-[176px] overflow-hidden">
-                  <div
-                    className="flex items-center gap-4  transition-all duration-200"
-                    style={{
-                      transform: `translateX(-${translateXValue}px)`,
-                    }}
-                  >
-                    {sliderDotsArray.map((slideNumber) => {
-                      return (
-                        <div
-                          key={slideNumber}
-                          onClick={() => setActiveSlide(slideNumber)}
-                          className="flex min-w-2 items-center justify-center"
-                        >
-                          <button
-                            className={classNames(
-                              'rounded-full bg-controls-disable transition-all duration-200',
-                              getDotSizeClass(
-                                slideNumber,
-                                activeSlide,
-                                sliderDotsArray.length,
-                              ),
-                            )}
-                          />
-                        </div>
-                      );
-                    })}
-                  </div>
-                </div>
-                {!isMobileOrTablet && (
-                  <button
-                    onClick={() =>
-                      setActiveSlide((activeSlide) =>
-                        activeSlide === sliderDotsArray.length - 1
-                          ? activeSlide
-                          : activeSlide + 1,
-                      )
-                    }
-                    disabled={activeSlide === sliderDotsArray.length - 1}
-                    className="text-secondary hover:text-accent-primary disabled:cursor-not-allowed disabled:hover:text-secondary"
-                  >
-                    <IconCaretRightFilled size={18} />
-                  </button>
-                )}
-              </>
-            )}
-          </div>
-        </div>
-      </div>
+      <SliderDots
+        activeSlide={activeSlide}
+        sliderGroups={sliderGroups}
+        onSetActiveSlide={setActiveSlide}
+      />
     </>
   );
 };
@@ -476,6 +338,7 @@ interface SuggestionButtonProps {
 
 const SuggestionButton = ({ onClick }: SuggestionButtonProps) => {
   const { t } = useTranslation(Translation.Chat);
+
   return (
     <button className="text-accent-primary" onClick={onClick}>
       {t(`See results from ${ChangeAgentTabs[MarketplaceTabs.HOME]}`)}
diff --git a/apps/chat/src/components/Header/Header.tsx b/apps/chat/src/components/Header/Header.tsx
index 9bb458fc31..1798bb79ac 100644
--- a/apps/chat/src/components/Header/Header.tsx
+++ b/apps/chat/src/components/Header/Header.tsx
@@ -1,4 +1,6 @@
-import { useCallback, useEffect, useState } from 'react';
+import { useCallback, useState } from 'react';
+
+import { useWindowResizeEvent } from '@/src/hooks/useWindowResizeEvent';
 
 import { isSmallScreen, isTabletScreen } from '@/src/utils/app/mobile';
 import { centralChatWidth, getNewSidebarWidth } from '@/src/utils/app/sidebar';
@@ -112,13 +114,10 @@ const Header = Inversify.register('Header', () => {
     ? OVERLAY_HEADER_ICON_SIZE
     : DEFAULT_HEADER_ICON_SIZE;
 
-  useEffect(() => {
-    const handleResize = () => setWindowWidth(window.innerWidth);
-
-    window.addEventListener('resize', handleResize);
-
-    return () => window.removeEventListener('resize', handleResize);
+  const handleResize = useCallback(() => {
+    setWindowWidth(window.innerWidth);
   }, []);
+  useWindowResizeEvent(handleResize);
 
   return (
     <BaseHeader
diff --git a/apps/chat/src/components/Sidebar/Sidebar.tsx b/apps/chat/src/components/Sidebar/Sidebar.tsx
index a1378f9b57..1297d83db8 100644
--- a/apps/chat/src/components/Sidebar/Sidebar.tsx
+++ b/apps/chat/src/components/Sidebar/Sidebar.tsx
@@ -2,7 +2,6 @@ import {
   DragEvent,
   ReactNode,
   useCallback,
-  useEffect,
   useMemo,
   useRef,
   useState,
@@ -12,6 +11,7 @@ import classNames from 'classnames';
 
 import { useScreenState } from '@/src/hooks/useScreenState';
 import { useTranslation } from '@/src/hooks/useTranslation';
+import { useWindowResizeEvent } from '@/src/hooks/useWindowResizeEvent';
 
 import { EnumMapper } from '@/src/utils/app/mappers';
 import { isSmallScreen, isTabletScreen } from '@/src/utils/app/mobile';
@@ -324,13 +324,10 @@ const Sidebar = <T,>({
     }
   };
 
-  useEffect(() => {
-    const handleResize = () => setWindowWidth(window.innerWidth);
-
-    window.addEventListener('resize', handleResize);
-
-    return () => window.removeEventListener('resize', handleResize);
+  const handleResize = useCallback(() => {
+    setWindowWidth(window.innerWidth);
   }, []);
+  useWindowResizeEvent(handleResize);
 
   const resizableWrapperClassName = classNames(
     '!fixed z-40 flex max-w-[95%] border-tertiary md:max-w-[45%] xl:!relative xl:top-0 xl:!h-full',
diff --git a/apps/chat/src/constants/talkTo.ts b/apps/chat/src/constants/talkTo.ts
new file mode 100644
index 0000000000..77fd6a7c90
--- /dev/null
+++ b/apps/chat/src/constants/talkTo.ts
@@ -0,0 +1,4 @@
+export const SuggestedCard = {
+  id: 'suggested',
+  reference: 'suggested',
+};
diff --git a/apps/chat/src/hooks/useSwipe.ts b/apps/chat/src/hooks/useSwipe.ts
index 63677abda9..bdce4efc8d 100644
--- a/apps/chat/src/hooks/useSwipe.ts
+++ b/apps/chat/src/hooks/useSwipe.ts
@@ -1,6 +1,6 @@
-import { useState } from 'react';
+import { useCallback, useState } from 'react';
 
-type SwipeEvent<T = Element> = React.TouchEvent<T> | React.PointerEvent<T>;
+import isNumber from 'lodash-es/isNumber';
 
 export const useSwipe = ({
   onSwipedLeft,
@@ -10,49 +10,34 @@ export const useSwipe = ({
   onSwipedRight: () => void;
 }) => {
   const [startX, setStartX] = useState<number>();
-  const [endX, setEndX] = useState<number>();
-
-  const onStart = (e: SwipeEvent) => {
-    if ('touches' in e) {
-      setStartX(e.targetTouches[0].clientX);
-    } else {
-      setStartX(e.clientX);
-    }
-    setEndX(undefined);
-  };
 
-  const onMove = (e: SwipeEvent) => {
-    if ('touches' in e) {
-      setEndX(e.targetTouches[0].clientX);
-    } else {
-      setEndX(e.clientX);
-    }
-  };
+  const onStart = useCallback((e: React.TouchEvent) => {
+    setStartX(e.targetTouches[0].clientX);
+  }, []);
 
-  const onEnd = () => {
-    if (startX === undefined || endX === undefined) return;
+  const onEnd = useCallback(
+    (e: React.TouchEvent) => {
+      const endX = e.changedTouches[0].clientX;
+      if (!isNumber(startX) || !isNumber(endX)) return;
 
-    const distance = startX - endX;
-    const minDistance = 50;
+      const distance = startX - endX;
+      const minDistance = 50;
 
-    if (distance > minDistance) {
-      onSwipedLeft();
-    }
+      if (distance > minDistance) {
+        onSwipedLeft();
+      }
 
-    if (distance < -minDistance) {
-      onSwipedRight();
-    }
+      if (distance < -minDistance) {
+        onSwipedRight();
+      }
 
-    setStartX(undefined);
-    setEndX(undefined);
-  };
+      setStartX(undefined);
+    },
+    [onSwipedLeft, onSwipedRight, startX],
+  );
 
   return {
     onTouchStart: onStart,
-    onTouchMove: onMove,
     onTouchEnd: onEnd,
-    onPointerDown: onStart,
-    onPointerMove: onMove,
-    onPointerUp: onEnd,
   };
 };
diff --git a/apps/chat/src/hooks/useWindowResizeEvent.ts b/apps/chat/src/hooks/useWindowResizeEvent.ts
new file mode 100644
index 0000000000..b29daf86da
--- /dev/null
+++ b/apps/chat/src/hooks/useWindowResizeEvent.ts
@@ -0,0 +1,11 @@
+import { useEffect } from 'react';
+
+type ResizeHandler = () => void;
+
+export const useWindowResizeEvent = (handleResize: ResizeHandler) => {
+  useEffect(() => {
+    window.addEventListener('resize', handleResize);
+
+    return () => window.removeEventListener('resize', handleResize);
+  }, [handleResize]);
+};
diff --git a/apps/chat/src/types/talkTo.ts b/apps/chat/src/types/talkTo.ts
new file mode 100644
index 0000000000..861ac4adf3
--- /dev/null
+++ b/apps/chat/src/types/talkTo.ts
@@ -0,0 +1,7 @@
+import { SuggestedCard } from '@/src/constants/talkTo';
+
+import { DialAIEntityModel } from './models';
+
+type SuggestedCardType = typeof SuggestedCard;
+
+export type CardType = DialAIEntityModel | SuggestedCardType;


Reviews:
user: login: IlyaBondar
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-16T15:50:52Z
user: login: Alexander-Kezik
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-05-16T15:59:04Z
user: login: Alexander-Kezik
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-05-16T15:59:20Z
user: login: Alexander-Kezik
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-05-16T16:00:14Z
user: login: IlyaBondar
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-16T16:46:13Z
user: login: IlyaBondar
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-16T16:46:22Z
user: login: IlyaBondar
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-16T16:49:40Z
user: login: denys-kolomiitsev
state: DISMISSED
author_association: CONTRIBUTOR
submitted_at: 2025-05-16T17:04:59Z
user: login: IlyaBondar
state: DISMISSED
author_association: CONTRIBUTOR
submitted_at: 2025-05-16T17:48:14Z
user: login: IlyaBondar
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-05-16T17:54:22Z

Review comments:
diff_hunk: @@ -31,44 +41,78 @@ import { TalkToCard } from './TalkToCard';
 import chunk from 'lodash-es/chunk';
 import range from 'lodash-es/range';
 
-const maxChunksCountConfig = {
-  [ScreenState.XL5]: {
-    cardHeight: 166,
-    maxRows: 3,
-    cols: 3,
-  },
-  [ScreenState.XL4]: {
-    cardHeight: 166,
-    maxRows: 3,
-    cols: 3,
-  },
-  [ScreenState.XL3]: {
-    cardHeight: 166,
-    maxRows: 3,
-    cols: 3,
-  },
-  [ScreenState.XL]: {
-    cardHeight: 166,
-    maxRows: 3,
-    cols: 3,
-  },
-  [ScreenState.MD]: {
-    cardHeight: 160,
-    maxRows: 4,
-    cols: 2,
-  },
-  [ScreenState.SM]: {
-    cardHeight: 98,
-    maxRows: 5,
-    cols: 1,
-  },
+const DEFAULT_MAX_CHUNKS_COUNT_CONFIG = {
+  cardHeight: 166,
+  maxRows: 3,
+  cols: 3,
+};
+const TABLET_MAX_CHUNKS_COUNT_CONFIG = {
+  cardHeight: 160,
+  maxRows: 4,
+  cols: 2,
+};
+const MOBILE_MAX_CHUNKS_COUNT_CONFIG = {
+  cardHeight: 98,
+  maxRows: 5,
+  cols: 1,
+};
+const MAX_CHUNKS_COUNT_CONFIG = {
+  [ScreenState.XL5]: DEFAULT_MAX_CHUNKS_COUNT_CONFIG,
+  [ScreenState.XL4]: DEFAULT_MAX_CHUNKS_COUNT_CONFIG,
+  [ScreenState.XL3]: DEFAULT_MAX_CHUNKS_COUNT_CONFIG,
+  [ScreenState.XL]: DEFAULT_MAX_CHUNKS_COUNT_CONFIG,
+  [ScreenState.MD]: TABLET_MAX_CHUNKS_COUNT_CONFIG,
+  [ScreenState.SM]: MOBILE_MAX_CHUNKS_COUNT_CONFIG,
+};
+
+const getMaxChunksCountConfig = (screenState: ScreenState) =>
+  MAX_CHUNKS_COUNT_CONFIG[screenState] ?? DEFAULT_MAX_CHUNKS_COUNT_CONFIG;
+
+const DEFAULT_SINGLE_ROW_OFFSET = 217;
+const MOBILE__SINGLE_ROW_OFFSET = 255;
+const START_SINGLE_ROW_OFFSET = {
+  [ScreenState.XL5]: DEFAULT_SINGLE_ROW_OFFSET,
+  [ScreenState.XL4]: DEFAULT_SINGLE_ROW_OFFSET,
+  [ScreenState.XL3]: DEFAULT_SINGLE_ROW_OFFSET,
+  [ScreenState.XL]: DEFAULT_SINGLE_ROW_OFFSET,
+  [ScreenState.MD]: DEFAULT_SINGLE_ROW_OFFSET,
+  [ScreenState.SM]: MOBILE__SINGLE_ROW_OFFSET,
 };
 
 const SLIDER_DOT_SIZE_WITH_GAPS = 24;
 const MAX_VISIBLE_SLIDER_DOTS = 7;
 const SLIDES_GAP = 16;
-const COMMON_GRID_TILES_GAP = 16;
-const MOBILE_GRID_TILES_GAP = 12;
+
+const getGridGap = (screenState: ScreenState) => {
+  const COMMON_GRID_TILES_GAP = 16;
+  const MOBILE_GRID_TILES_GAP = 12;
path: apps/chat/src/components/Chat/TalkTo/TalkToSlider.tsx
user: login: IlyaBondar
body: constants should be outside methods
created_at: 2025-05-16T15:44:42Z
author_association: CONTRIBUTOR
diff_hunk: @@ -31,44 +41,78 @@ import { TalkToCard } from './TalkToCard';
 import chunk from 'lodash-es/chunk';
 import range from 'lodash-es/range';
 
-const maxChunksCountConfig = {
-  [ScreenState.XL5]: {
-    cardHeight: 166,
-    maxRows: 3,
-    cols: 3,
-  },
-  [ScreenState.XL4]: {
-    cardHeight: 166,
-    maxRows: 3,
-    cols: 3,
-  },
-  [ScreenState.XL3]: {
-    cardHeight: 166,
-    maxRows: 3,
-    cols: 3,
-  },
-  [ScreenState.XL]: {
-    cardHeight: 166,
-    maxRows: 3,
-    cols: 3,
-  },
-  [ScreenState.MD]: {
-    cardHeight: 160,
-    maxRows: 4,
-    cols: 2,
-  },
-  [ScreenState.SM]: {
-    cardHeight: 98,
-    maxRows: 5,
-    cols: 1,
-  },
+const DEFAULT_MAX_CHUNKS_COUNT_CONFIG = {
+  cardHeight: 166,
+  maxRows: 3,
+  cols: 3,
+};
+const TABLET_MAX_CHUNKS_COUNT_CONFIG = {
+  cardHeight: 160,
+  maxRows: 4,
+  cols: 2,
+};
+const MOBILE_MAX_CHUNKS_COUNT_CONFIG = {
+  cardHeight: 98,
+  maxRows: 5,
+  cols: 1,
+};
+const MAX_CHUNKS_COUNT_CONFIG = {
+  [ScreenState.XL5]: DEFAULT_MAX_CHUNKS_COUNT_CONFIG,
+  [ScreenState.XL4]: DEFAULT_MAX_CHUNKS_COUNT_CONFIG,
+  [ScreenState.XL3]: DEFAULT_MAX_CHUNKS_COUNT_CONFIG,
+  [ScreenState.XL]: DEFAULT_MAX_CHUNKS_COUNT_CONFIG,
+  [ScreenState.MD]: TABLET_MAX_CHUNKS_COUNT_CONFIG,
+  [ScreenState.SM]: MOBILE_MAX_CHUNKS_COUNT_CONFIG,
+};
+
+const getMaxChunksCountConfig = (screenState: ScreenState) =>
+  MAX_CHUNKS_COUNT_CONFIG[screenState] ?? DEFAULT_MAX_CHUNKS_COUNT_CONFIG;
+
+const DEFAULT_SINGLE_ROW_OFFSET = 217;
+const MOBILE__SINGLE_ROW_OFFSET = 255;
+const START_SINGLE_ROW_OFFSET = {
+  [ScreenState.XL5]: DEFAULT_SINGLE_ROW_OFFSET,
+  [ScreenState.XL4]: DEFAULT_SINGLE_ROW_OFFSET,
+  [ScreenState.XL3]: DEFAULT_SINGLE_ROW_OFFSET,
+  [ScreenState.XL]: DEFAULT_SINGLE_ROW_OFFSET,
+  [ScreenState.MD]: DEFAULT_SINGLE_ROW_OFFSET,
path: apps/chat/src/components/Chat/TalkTo/TalkToSlider.tsx
user: login: IlyaBondar
body: don't need it because line 102
```typescirpt
START_SINGLE_ROW_OFFSET[screenState] ?? DEFAULT_SINGLE_ROW_OFFSET
```
created_at: 2025-05-16T15:46:15Z
author_association: CONTRIBUTOR
diff_hunk: @@ -31,44 +41,78 @@ import { TalkToCard } from './TalkToCard';
 import chunk from 'lodash-es/chunk';
 import range from 'lodash-es/range';
 
-const maxChunksCountConfig = {
-  [ScreenState.XL5]: {
-    cardHeight: 166,
-    maxRows: 3,
-    cols: 3,
-  },
-  [ScreenState.XL4]: {
-    cardHeight: 166,
-    maxRows: 3,
-    cols: 3,
-  },
-  [ScreenState.XL3]: {
-    cardHeight: 166,
-    maxRows: 3,
-    cols: 3,
-  },
-  [ScreenState.XL]: {
-    cardHeight: 166,
-    maxRows: 3,
-    cols: 3,
-  },
-  [ScreenState.MD]: {
-    cardHeight: 160,
-    maxRows: 4,
-    cols: 2,
-  },
-  [ScreenState.SM]: {
-    cardHeight: 98,
-    maxRows: 5,
-    cols: 1,
-  },
+const DEFAULT_MAX_CHUNKS_COUNT_CONFIG = {
+  cardHeight: 166,
+  maxRows: 3,
+  cols: 3,
+};
+const TABLET_MAX_CHUNKS_COUNT_CONFIG = {
+  cardHeight: 160,
+  maxRows: 4,
+  cols: 2,
+};
+const MOBILE_MAX_CHUNKS_COUNT_CONFIG = {
+  cardHeight: 98,
+  maxRows: 5,
+  cols: 1,
+};
+const MAX_CHUNKS_COUNT_CONFIG = {
+  [ScreenState.XL5]: DEFAULT_MAX_CHUNKS_COUNT_CONFIG,
+  [ScreenState.XL4]: DEFAULT_MAX_CHUNKS_COUNT_CONFIG,
+  [ScreenState.XL3]: DEFAULT_MAX_CHUNKS_COUNT_CONFIG,
+  [ScreenState.XL]: DEFAULT_MAX_CHUNKS_COUNT_CONFIG,
path: apps/chat/src/components/Chat/TalkTo/TalkToSlider.tsx
user: login: IlyaBondar
body: don't need it because `getMaxChunksCountConfig` uses `DEFAULT_MAX_CHUNKS_COUNT_CONFIG` as default
```typescript
MAX_CHUNKS_COUNT_CONFIG[screenState] ?? DEFAULT_MAX_CHUNKS_COUNT_CONFIG;
```
created_at: 2025-05-16T15:47:59Z
author_association: CONTRIBUTOR
diff_hunk: @@ -31,44 +41,78 @@ import { TalkToCard } from './TalkToCard';
 import chunk from 'lodash-es/chunk';
 import range from 'lodash-es/range';
 
-const maxChunksCountConfig = {
-  [ScreenState.XL5]: {
-    cardHeight: 166,
-    maxRows: 3,
-    cols: 3,
-  },
-  [ScreenState.XL4]: {
-    cardHeight: 166,
-    maxRows: 3,
-    cols: 3,
-  },
-  [ScreenState.XL3]: {
-    cardHeight: 166,
-    maxRows: 3,
-    cols: 3,
-  },
-  [ScreenState.XL]: {
-    cardHeight: 166,
-    maxRows: 3,
-    cols: 3,
-  },
-  [ScreenState.MD]: {
-    cardHeight: 160,
-    maxRows: 4,
-    cols: 2,
-  },
-  [ScreenState.SM]: {
-    cardHeight: 98,
-    maxRows: 5,
-    cols: 1,
-  },
+const DEFAULT_MAX_CHUNKS_COUNT_CONFIG = {
+  cardHeight: 166,
+  maxRows: 3,
+  cols: 3,
+};
+const TABLET_MAX_CHUNKS_COUNT_CONFIG = {
+  cardHeight: 160,
+  maxRows: 4,
+  cols: 2,
+};
+const MOBILE_MAX_CHUNKS_COUNT_CONFIG = {
+  cardHeight: 98,
+  maxRows: 5,
+  cols: 1,
+};
+const MAX_CHUNKS_COUNT_CONFIG = {
+  [ScreenState.XL5]: DEFAULT_MAX_CHUNKS_COUNT_CONFIG,
+  [ScreenState.XL4]: DEFAULT_MAX_CHUNKS_COUNT_CONFIG,
+  [ScreenState.XL3]: DEFAULT_MAX_CHUNKS_COUNT_CONFIG,
+  [ScreenState.XL]: DEFAULT_MAX_CHUNKS_COUNT_CONFIG,
path: apps/chat/src/components/Chat/TalkTo/TalkToSlider.tsx
user: login: Alexander-Kezik
body: It's convenient when you can just take a look and understand the config for all screen states
I don't think it's good idea to bring some obscurity here
created_at: 2025-05-16T15:59:04Z
author_association: COLLABORATOR
diff_hunk: @@ -31,44 +41,78 @@ import { TalkToCard } from './TalkToCard';
 import chunk from 'lodash-es/chunk';
 import range from 'lodash-es/range';
 
-const maxChunksCountConfig = {
-  [ScreenState.XL5]: {
-    cardHeight: 166,
-    maxRows: 3,
-    cols: 3,
-  },
-  [ScreenState.XL4]: {
-    cardHeight: 166,
-    maxRows: 3,
-    cols: 3,
-  },
-  [ScreenState.XL3]: {
-    cardHeight: 166,
-    maxRows: 3,
-    cols: 3,
-  },
-  [ScreenState.XL]: {
-    cardHeight: 166,
-    maxRows: 3,
-    cols: 3,
-  },
-  [ScreenState.MD]: {
-    cardHeight: 160,
-    maxRows: 4,
-    cols: 2,
-  },
-  [ScreenState.SM]: {
-    cardHeight: 98,
-    maxRows: 5,
-    cols: 1,
-  },
+const DEFAULT_MAX_CHUNKS_COUNT_CONFIG = {
+  cardHeight: 166,
+  maxRows: 3,
+  cols: 3,
+};
+const TABLET_MAX_CHUNKS_COUNT_CONFIG = {
+  cardHeight: 160,
+  maxRows: 4,
+  cols: 2,
+};
+const MOBILE_MAX_CHUNKS_COUNT_CONFIG = {
+  cardHeight: 98,
+  maxRows: 5,
+  cols: 1,
+};
+const MAX_CHUNKS_COUNT_CONFIG = {
+  [ScreenState.XL5]: DEFAULT_MAX_CHUNKS_COUNT_CONFIG,
+  [ScreenState.XL4]: DEFAULT_MAX_CHUNKS_COUNT_CONFIG,
+  [ScreenState.XL3]: DEFAULT_MAX_CHUNKS_COUNT_CONFIG,
+  [ScreenState.XL]: DEFAULT_MAX_CHUNKS_COUNT_CONFIG,
+  [ScreenState.MD]: TABLET_MAX_CHUNKS_COUNT_CONFIG,
+  [ScreenState.SM]: MOBILE_MAX_CHUNKS_COUNT_CONFIG,
+};
+
+const getMaxChunksCountConfig = (screenState: ScreenState) =>
+  MAX_CHUNKS_COUNT_CONFIG[screenState] ?? DEFAULT_MAX_CHUNKS_COUNT_CONFIG;
+
+const DEFAULT_SINGLE_ROW_OFFSET = 217;
+const MOBILE__SINGLE_ROW_OFFSET = 255;
+const START_SINGLE_ROW_OFFSET = {
+  [ScreenState.XL5]: DEFAULT_SINGLE_ROW_OFFSET,
+  [ScreenState.XL4]: DEFAULT_SINGLE_ROW_OFFSET,
+  [ScreenState.XL3]: DEFAULT_SINGLE_ROW_OFFSET,
+  [ScreenState.XL]: DEFAULT_SINGLE_ROW_OFFSET,
+  [ScreenState.MD]: DEFAULT_SINGLE_ROW_OFFSET,
path: apps/chat/src/components/Chat/TalkTo/TalkToSlider.tsx
user: login: Alexander-Kezik
body: It's convenient when you can just take a look and understand the row offset for all screen states
I don't think it's good idea to bring some obscurity here
created_at: 2025-05-16T15:59:20Z
author_association: COLLABORATOR
diff_hunk: @@ -31,44 +41,78 @@ import { TalkToCard } from './TalkToCard';
 import chunk from 'lodash-es/chunk';
 import range from 'lodash-es/range';
 
-const maxChunksCountConfig = {
-  [ScreenState.XL5]: {
-    cardHeight: 166,
-    maxRows: 3,
-    cols: 3,
-  },
-  [ScreenState.XL4]: {
-    cardHeight: 166,
-    maxRows: 3,
-    cols: 3,
-  },
-  [ScreenState.XL3]: {
-    cardHeight: 166,
-    maxRows: 3,
-    cols: 3,
-  },
-  [ScreenState.XL]: {
-    cardHeight: 166,
-    maxRows: 3,
-    cols: 3,
-  },
-  [ScreenState.MD]: {
-    cardHeight: 160,
-    maxRows: 4,
-    cols: 2,
-  },
-  [ScreenState.SM]: {
-    cardHeight: 98,
-    maxRows: 5,
-    cols: 1,
-  },
+const DEFAULT_MAX_CHUNKS_COUNT_CONFIG = {
+  cardHeight: 166,
+  maxRows: 3,
+  cols: 3,
+};
+const TABLET_MAX_CHUNKS_COUNT_CONFIG = {
+  cardHeight: 160,
+  maxRows: 4,
+  cols: 2,
+};
+const MOBILE_MAX_CHUNKS_COUNT_CONFIG = {
+  cardHeight: 98,
+  maxRows: 5,
+  cols: 1,
+};
+const MAX_CHUNKS_COUNT_CONFIG = {
+  [ScreenState.XL5]: DEFAULT_MAX_CHUNKS_COUNT_CONFIG,
+  [ScreenState.XL4]: DEFAULT_MAX_CHUNKS_COUNT_CONFIG,
+  [ScreenState.XL3]: DEFAULT_MAX_CHUNKS_COUNT_CONFIG,
+  [ScreenState.XL]: DEFAULT_MAX_CHUNKS_COUNT_CONFIG,
+  [ScreenState.MD]: TABLET_MAX_CHUNKS_COUNT_CONFIG,
+  [ScreenState.SM]: MOBILE_MAX_CHUNKS_COUNT_CONFIG,
+};
+
+const getMaxChunksCountConfig = (screenState: ScreenState) =>
+  MAX_CHUNKS_COUNT_CONFIG[screenState] ?? DEFAULT_MAX_CHUNKS_COUNT_CONFIG;
+
+const DEFAULT_SINGLE_ROW_OFFSET = 217;
+const MOBILE__SINGLE_ROW_OFFSET = 255;
+const START_SINGLE_ROW_OFFSET = {
+  [ScreenState.XL5]: DEFAULT_SINGLE_ROW_OFFSET,
+  [ScreenState.XL4]: DEFAULT_SINGLE_ROW_OFFSET,
+  [ScreenState.XL3]: DEFAULT_SINGLE_ROW_OFFSET,
+  [ScreenState.XL]: DEFAULT_SINGLE_ROW_OFFSET,
+  [ScreenState.MD]: DEFAULT_SINGLE_ROW_OFFSET,
+  [ScreenState.SM]: MOBILE__SINGLE_ROW_OFFSET,
 };
 
 const SLIDER_DOT_SIZE_WITH_GAPS = 24;
 const MAX_VISIBLE_SLIDER_DOTS = 7;
 const SLIDES_GAP = 16;
-const COMMON_GRID_TILES_GAP = 16;
-const MOBILE_GRID_TILES_GAP = 12;
+
+const getGridGap = (screenState: ScreenState) => {
+  const COMMON_GRID_TILES_GAP = 16;
+  const MOBILE_GRID_TILES_GAP = 12;
path: apps/chat/src/components/Chat/TalkTo/TalkToSlider.tsx
user: login: Alexander-Kezik
body: these constants are strictly bound to this method
i gave them a name to make it clear what are the values responsible for
created_at: 2025-05-16T16:00:14Z
author_association: COLLABORATOR
diff_hunk: @@ -31,44 +41,78 @@ import { TalkToCard } from './TalkToCard';
 import chunk from 'lodash-es/chunk';
 import range from 'lodash-es/range';
 
-const maxChunksCountConfig = {
-  [ScreenState.XL5]: {
-    cardHeight: 166,
-    maxRows: 3,
-    cols: 3,
-  },
-  [ScreenState.XL4]: {
-    cardHeight: 166,
-    maxRows: 3,
-    cols: 3,
-  },
-  [ScreenState.XL3]: {
-    cardHeight: 166,
-    maxRows: 3,
-    cols: 3,
-  },
-  [ScreenState.XL]: {
-    cardHeight: 166,
-    maxRows: 3,
-    cols: 3,
-  },
-  [ScreenState.MD]: {
-    cardHeight: 160,
-    maxRows: 4,
-    cols: 2,
-  },
-  [ScreenState.SM]: {
-    cardHeight: 98,
-    maxRows: 5,
-    cols: 1,
-  },
+const DEFAULT_MAX_CHUNKS_COUNT_CONFIG = {
+  cardHeight: 166,
+  maxRows: 3,
+  cols: 3,
+};
+const TABLET_MAX_CHUNKS_COUNT_CONFIG = {
+  cardHeight: 160,
+  maxRows: 4,
+  cols: 2,
+};
+const MOBILE_MAX_CHUNKS_COUNT_CONFIG = {
+  cardHeight: 98,
+  maxRows: 5,
+  cols: 1,
+};
+const MAX_CHUNKS_COUNT_CONFIG = {
+  [ScreenState.XL5]: DEFAULT_MAX_CHUNKS_COUNT_CONFIG,
+  [ScreenState.XL4]: DEFAULT_MAX_CHUNKS_COUNT_CONFIG,
+  [ScreenState.XL3]: DEFAULT_MAX_CHUNKS_COUNT_CONFIG,
+  [ScreenState.XL]: DEFAULT_MAX_CHUNKS_COUNT_CONFIG,
path: apps/chat/src/components/Chat/TalkTo/TalkToSlider.tsx
user: login: IlyaBondar
body:  it's mapping of custom values (not equal default). I suggest to rename it into `CUSTOM_MAX_CHUNKS_COUNT_CONFIGS`
created_at: 2025-05-16T16:46:13Z
author_association: CONTRIBUTOR
diff_hunk: @@ -31,44 +41,78 @@ import { TalkToCard } from './TalkToCard';
 import chunk from 'lodash-es/chunk';
 import range from 'lodash-es/range';
 
-const maxChunksCountConfig = {
-  [ScreenState.XL5]: {
-    cardHeight: 166,
-    maxRows: 3,
-    cols: 3,
-  },
-  [ScreenState.XL4]: {
-    cardHeight: 166,
-    maxRows: 3,
-    cols: 3,
-  },
-  [ScreenState.XL3]: {
-    cardHeight: 166,
-    maxRows: 3,
-    cols: 3,
-  },
-  [ScreenState.XL]: {
-    cardHeight: 166,
-    maxRows: 3,
-    cols: 3,
-  },
-  [ScreenState.MD]: {
-    cardHeight: 160,
-    maxRows: 4,
-    cols: 2,
-  },
-  [ScreenState.SM]: {
-    cardHeight: 98,
-    maxRows: 5,
-    cols: 1,
-  },
+const DEFAULT_MAX_CHUNKS_COUNT_CONFIG = {
+  cardHeight: 166,
+  maxRows: 3,
+  cols: 3,
+};
+const TABLET_MAX_CHUNKS_COUNT_CONFIG = {
+  cardHeight: 160,
+  maxRows: 4,
+  cols: 2,
+};
+const MOBILE_MAX_CHUNKS_COUNT_CONFIG = {
+  cardHeight: 98,
+  maxRows: 5,
+  cols: 1,
+};
+const MAX_CHUNKS_COUNT_CONFIG = {
+  [ScreenState.XL5]: DEFAULT_MAX_CHUNKS_COUNT_CONFIG,
+  [ScreenState.XL4]: DEFAULT_MAX_CHUNKS_COUNT_CONFIG,
+  [ScreenState.XL3]: DEFAULT_MAX_CHUNKS_COUNT_CONFIG,
+  [ScreenState.XL]: DEFAULT_MAX_CHUNKS_COUNT_CONFIG,
+  [ScreenState.MD]: TABLET_MAX_CHUNKS_COUNT_CONFIG,
+  [ScreenState.SM]: MOBILE_MAX_CHUNKS_COUNT_CONFIG,
+};
+
+const getMaxChunksCountConfig = (screenState: ScreenState) =>
+  MAX_CHUNKS_COUNT_CONFIG[screenState] ?? DEFAULT_MAX_CHUNKS_COUNT_CONFIG;
+
+const DEFAULT_SINGLE_ROW_OFFSET = 217;
+const MOBILE__SINGLE_ROW_OFFSET = 255;
+const START_SINGLE_ROW_OFFSET = {
+  [ScreenState.XL5]: DEFAULT_SINGLE_ROW_OFFSET,
+  [ScreenState.XL4]: DEFAULT_SINGLE_ROW_OFFSET,
+  [ScreenState.XL3]: DEFAULT_SINGLE_ROW_OFFSET,
+  [ScreenState.XL]: DEFAULT_SINGLE_ROW_OFFSET,
+  [ScreenState.MD]: DEFAULT_SINGLE_ROW_OFFSET,
path: apps/chat/src/components/Chat/TalkTo/TalkToSlider.tsx
user: login: IlyaBondar
body:  it's mapping of custom values (not equal default). I suggest to rename it into `CUSTOM_SINGLE_ROW_OFFSETS`
created_at: 2025-05-16T16:46:22Z
author_association: CONTRIBUTOR
diff_hunk: @@ -31,44 +41,78 @@ import { TalkToCard } from './TalkToCard';
 import chunk from 'lodash-es/chunk';
 import range from 'lodash-es/range';
 
-const maxChunksCountConfig = {
-  [ScreenState.XL5]: {
-    cardHeight: 166,
-    maxRows: 3,
-    cols: 3,
-  },
-  [ScreenState.XL4]: {
-    cardHeight: 166,
-    maxRows: 3,
-    cols: 3,
-  },
-  [ScreenState.XL3]: {
-    cardHeight: 166,
-    maxRows: 3,
-    cols: 3,
-  },
-  [ScreenState.XL]: {
-    cardHeight: 166,
-    maxRows: 3,
-    cols: 3,
-  },
-  [ScreenState.MD]: {
-    cardHeight: 160,
-    maxRows: 4,
-    cols: 2,
-  },
-  [ScreenState.SM]: {
-    cardHeight: 98,
-    maxRows: 5,
-    cols: 1,
-  },
+const DEFAULT_MAX_CHUNKS_COUNT_CONFIG = {
+  cardHeight: 166,
+  maxRows: 3,
+  cols: 3,
+};
+const TABLET_MAX_CHUNKS_COUNT_CONFIG = {
+  cardHeight: 160,
+  maxRows: 4,
+  cols: 2,
+};
+const MOBILE_MAX_CHUNKS_COUNT_CONFIG = {
+  cardHeight: 98,
+  maxRows: 5,
+  cols: 1,
+};
+const MAX_CHUNKS_COUNT_CONFIG = {
+  [ScreenState.XL5]: DEFAULT_MAX_CHUNKS_COUNT_CONFIG,
+  [ScreenState.XL4]: DEFAULT_MAX_CHUNKS_COUNT_CONFIG,
+  [ScreenState.XL3]: DEFAULT_MAX_CHUNKS_COUNT_CONFIG,
+  [ScreenState.XL]: DEFAULT_MAX_CHUNKS_COUNT_CONFIG,
+  [ScreenState.MD]: TABLET_MAX_CHUNKS_COUNT_CONFIG,
+  [ScreenState.SM]: MOBILE_MAX_CHUNKS_COUNT_CONFIG,
+};
+
+const getMaxChunksCountConfig = (screenState: ScreenState) =>
+  MAX_CHUNKS_COUNT_CONFIG[screenState] ?? DEFAULT_MAX_CHUNKS_COUNT_CONFIG;
+
+const DEFAULT_SINGLE_ROW_OFFSET = 217;
+const MOBILE__SINGLE_ROW_OFFSET = 255;
+const START_SINGLE_ROW_OFFSET = {
+  [ScreenState.XL5]: DEFAULT_SINGLE_ROW_OFFSET,
+  [ScreenState.XL4]: DEFAULT_SINGLE_ROW_OFFSET,
+  [ScreenState.XL3]: DEFAULT_SINGLE_ROW_OFFSET,
+  [ScreenState.XL]: DEFAULT_SINGLE_ROW_OFFSET,
+  [ScreenState.MD]: DEFAULT_SINGLE_ROW_OFFSET,
+  [ScreenState.SM]: MOBILE__SINGLE_ROW_OFFSET,
 };
 
 const SLIDER_DOT_SIZE_WITH_GAPS = 24;
 const MAX_VISIBLE_SLIDER_DOTS = 7;
 const SLIDES_GAP = 16;
-const COMMON_GRID_TILES_GAP = 16;
-const MOBILE_GRID_TILES_GAP = 12;
+
+const getGridGap = (screenState: ScreenState) => {
+  const COMMON_GRID_TILES_GAP = 16;
+  const MOBILE_GRID_TILES_GAP = 12;
path: apps/chat/src/components/Chat/TalkTo/TalkToSlider.tsx
user: login: IlyaBondar
body: in this case these constants don`t make sense because we have method name `getGridGap`
```typescript
return screenState === ScreenState.SM ? 12 : 16;
```
created_at: 2025-05-16T16:49:40Z
author_association: CONTRIBUTOR

PR comments:
user: login: Alexander-Kezik
created_at: 2025-05-16T09:44:28Z
body: /deploy-review
>Environment: [review-environment](https://chat-ai-dial-chat-pr-3852.nightly-test.deltixhub.io) | [pipeline](https://gitlab.deltixhub.com/Clients/deltix/nightly-test/dial/review/-/pipelines/611344)
>Overlay E2E tests status: [success](https://gitlab.deltixhub.com/Clients/deltix/nightly-test/dial/review/-/jobs/1856581)
>Chat E2E tests status: [failed](https://gitlab.deltixhub.com/Clients/deltix/nightly-test/dial/review/-/jobs/1856580)
author_association: COLLABORATOR
user: login: Alexander-Kezik
created_at: 2025-05-16T10:23:09Z
body: /deploy-review
>Environment: [review-environment](https://chat-ai-dial-chat-pr-3852.nightly-test.deltixhub.io) | [pipeline](https://gitlab.deltixhub.com/Clients/deltix/nightly-test/dial/review/-/pipelines/611390)
>Overlay E2E tests status: [success](https://gitlab.deltixhub.com/Clients/deltix/nightly-test/dial/review/-/jobs/1856813)
>Chat E2E tests status: [success](https://gitlab.deltixhub.com/Clients/deltix/nightly-test/dial/review/-/jobs/1856812)
author_association: COLLABORATOR
user: login: Alexander-Kezik
created_at: 2025-05-16T11:34:27Z
body: /deploy-review
>Environment: [review-environment](https://chat-ai-dial-chat-pr-3852.nightly-test.deltixhub.io) | [pipeline](https://gitlab.deltixhub.com/Clients/deltix/nightly-test/dial/review/-/pipelines/611481)
>Overlay E2E tests status: [success](https://gitlab.deltixhub.com/Clients/deltix/nightly-test/dial/review/-/jobs/1857295)
>Chat E2E tests status: [canceled](https://gitlab.deltixhub.com/Clients/deltix/nightly-test/dial/review/-/jobs/1857294)
author_association: COLLABORATOR
user: login: Alexander-Kezik
created_at: 2025-05-16T11:52:16Z
body: /deploy-review
>Environment: [review-environment](https://chat-ai-dial-chat-pr-3852.nightly-test.deltixhub.io) | [pipeline](https://gitlab.deltixhub.com/Clients/deltix/nightly-test/dial/review/-/pipelines/611502)
>Overlay E2E tests status: [success](https://gitlab.deltixhub.com/Clients/deltix/nightly-test/dial/review/-/jobs/1857380)
>Chat E2E tests status: [success](https://gitlab.deltixhub.com/Clients/deltix/nightly-test/dial/review/-/jobs/1857379)
author_association: COLLABORATOR
user: login: Alexander-Kezik
created_at: 2025-05-16T14:17:03Z
body: /deploy-review
>Environment: [review-environment](https://chat-ai-dial-chat-pr-3852.nightly-test.deltixhub.io) | [pipeline](https://gitlab.deltixhub.com/Clients/deltix/nightly-test/dial/review/-/pipelines/611710)
>Overlay E2E tests status: [success](https://gitlab.deltixhub.com/Clients/deltix/nightly-test/dial/review/-/jobs/1858276)
>Chat E2E tests status: [success](https://gitlab.deltixhub.com/Clients/deltix/nightly-test/dial/review/-/jobs/1858275)
author_association: COLLABORATOR
user: login: Alexander-Kezik
created_at: 2025-05-16T17:50:03Z
body: /deploy-review
>Environment: [review-environment](https://chat-ai-dial-chat-pr-3852.nightly-test.deltixhub.io) | [pipeline](https://gitlab.deltixhub.com/Clients/deltix/nightly-test/dial/review/-/pipelines/611921)
>Overlay E2E tests status: [success](https://gitlab.deltixhub.com/Clients/deltix/nightly-test/dial/review/-/jobs/1859285)
>Chat E2E tests status: [success](https://gitlab.deltixhub.com/Clients/deltix/nightly-test/dial/review/-/jobs/1859284)
author_association: COLLABORATOR