@@ -16,16 +16,21 @@ export function PredictPrice({ token, isChatBot = false }: { token: number; isCh const modifier = isChatBot ? tierModifierClass(token) : '' const isHighCost = isChatBot && token >= 150 - return ( - -
- - {token} -
-
- ) + + if (token && token>0) { + return ( + +
+ + {token} +
+
+ ) + } + + return <> } @@ -1,13 +1,12 @@ -import React, { useState } from 'react' -import { ClickAwayListener, Tooltip, useMediaQuery } from '@mui/material' +import React from 'react' +import { Tooltip } from '@mui/material' interface Props { title?: string children: React.ReactNode className?: string maxWidth?: string - /** By default tooltip stops click propagation (useful inside buttons/menus). Set false when parent needs the click. */ - stopClickPropagation?: boolean + wrapperWidth?: string placement?: | 'bottom-end' | 'bottom-start' @@ -21,49 +20,15 @@ interface Props { | 'top-end' | 'top-start' | 'top' - /** Растянуть триггер на 100% ширины родителя (flex/grid + disabled-кнопка). */ - fullWidthTrigger?: boolean - /** На устройствах без hover (тач) открывать/закрывать по нажатию, снаружи — закрытие. */ - tapToOpenOnMobile?: boolean } -/** Выше оверлеев модалок (см. template.module.scss — 9999) */ -const TOOLTIP_POPPER_Z_INDEX = 10050 - -export const TooltipCustom: React.FC = ({ - children, - title, - placement, - className, - maxWidth, - stopClickPropagation = true, - fullWidthTrigger = false, - tapToOpenOnMobile = false, -}) => { - const isTouchPrimary = useMediaQuery('(hover: none)', { noSsr: true }) - const tapMode = Boolean(tapToOpenOnMobile && isTouchPrimary) - const [tapOpen, setTapOpen] = useState(false) - - const triggerSpanStyle: React.CSSProperties | undefined = fullWidthTrigger - ? { display: 'flex', width: '100%', minWidth: 0 } - : undefined - - const tooltip = ( +export const TooltipCustom: React.FC = ({ children, title, placement, className, maxWidth, wrapperWidth }) => { + return ( setTapOpen(false) : undefined} - disableHoverListener={tapMode} - disableFocusListener={tapMode} - disableTouchListener={tapMode} - onClick={stopClickPropagation ? (e: React.MouseEvent) => e.stopPropagation() : undefined} + onClick={(e) => e.stopPropagation()} PopperProps={{ - sx: { zIndex: TOOLTIP_POPPER_Z_INDEX }, - ...(stopClickPropagation - ? { - onClick(e: React.MouseEvent) { - e.stopPropagation() - }, - } - : {}), + onClick(e) { + e.stopPropagation() + }, }} componentsProps={{ tooltip: { @@ -86,21 +51,9 @@ export const TooltipCustom: React.FC = ({ arrow placement={placement} > - { - if (stopClickPropagation) e.stopPropagation() - setTapOpen((v) => !v) - } - : undefined - } - > +
{children} - +
) - - return tapMode ? setTapOpen(false)}>{tooltip} : tooltip } @@ -228,15 +228,19 @@ export const ImageMessagesList: React.FC = memo(({ device, images, (device === 'mobile' ? 35 : 30) ? message.content : ''} + wrapperWidth={device === 'desktop' ? '250px' : '291px'} + title={message.content} > message.content.length > 0 && onPromptClick?.(message.content)} sx={{ fontSize: '15px', - maxWidth: device === 'desktop' ? '250px' : '100%', + width: '100%', marginTop: '12px', color: '#A4AAB5', + whiteSpace: 'nowrap', + overflow: 'hidden', + textOverflow: 'ellipsis', cursor: onPromptClick && message.content.length > 0 ? 'pointer' : 'default', }} > @@ -138,24 +138,27 @@ export const VideoMessagesList: React.FC = memo(({ device, videos, 30 ? message.content : ''} + wrapperWidth={device === 'desktop' ? '250px' : '291px'} + title={message.content} > message.content.length > 0 && onPromptClick?.(message.content)} sx={{ fontSize: '15px', - maxWidth: device === 'desktop' ? '250px' : '100%', + width: '100%', marginTop: '12px', color: '#A4AAB5', + whiteSpace: 'nowrap', + overflow: 'hidden', + textOverflow: 'ellipsis', cursor: onPromptClick && message.content.length > 0 ? 'pointer' : 'default', }} > {!loadedVideos.has(message.uid) ? '' : message.content.length > 0 - ? message?.content.replaceAll('"', '').slice(0, 27) + ? message?.content.replaceAll('"', '') : 'описание отсутствует'} - {message?.content.length > 27 && loadedVideos.has(message.uid) && '...'} @@ -9,6 +9,8 @@ default: build: stage: Build + variables: + IMAGE_TAG: $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA script: - cp $BUILD_ENV .env - docker compose build --push @@ -22,6 +24,7 @@ build: services: - docker:dind variables: + IMAGE_TAG: $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA ENVIRONMENT: $CI_ENVIRONMENT_TIER DOCKER_TLS_VERIFY: 1 DOCKER_CERT_PATH: "/certs" @@ -40,7 +43,7 @@ build: script: - sort -u -t '=' -k 1,1 $ENV $BUILD_ENV <(echo "RELEASE=$(echo -n $(date '+%D %X'))") > .env - if [ "$(docker info --format '{{.Swarm.LocalNodeState}}' 2>/dev/null)" = "active" ]; then - docker stack deploy --prune --with-registry-auth -c <(docker compose config | grep -v "^name:") $COMPOSE_PROJECT_NAME; + docker stack deploy --with-registry-auth --prune --resolve-image always -c <(docker compose config | grep -v "^name:") $COMPOSE_PROJECT_NAME; else docker compose up -d; fi @@ -1,6 +1,6 @@ services: app: - image: ${CI_REGISTRY_IMAGE:-air/ui/web}:${CI_COMMIT_SHA:-latest} + image: ${IMAGE_TAG:-air/ui/web:latest} build: context: . dockerfile: Dockerfile