ui: shrink icons when no space, adjust player area for events export … (#3217)

* ui: shrink icons when no space, adjust player area for events export panel, fix panel size

* ui: rm log
This commit is contained in:
Delirium 2025-03-26 16:37:45 +01:00 committed by Delirium
parent bef91a6136
commit 1d6fb0ae9e
10 changed files with 85 additions and 28 deletions

View file

@ -91,7 +91,7 @@ function PlayerBlockHeader(props: Props) {
)}
</div>
</div>
<div className="relative border-l" style={{ minWidth: '270px' }}>
<div className="relative border-l" style={{ minWidth: activeTab === 'EXPORT' ? '360px' : '270px' }}>
<Tabs
tabs={TABS}
active={activeTab}

View file

@ -61,7 +61,7 @@ function PlayerContent({
className="w-full"
style={
activeTab && !fullscreen
? { maxWidth: 'calc(100% - 270px)' }
? { maxWidth: `calc(100% - ${activeTab === 'EXPORT' ? '360px' : '270px'})` }
: undefined
}
>

View file

@ -126,7 +126,7 @@ function PlayerBlockHeader(props: any) {
</div>
<div
className="px-2 relative border-l border-l-gray-lighter"
style={{ minWidth: '270px' }}
style={{ minWidth: activeTab === 'EXPORT' ? '360px' : '270px' }}
>
<Tabs
tabs={TABS}

View file

@ -65,7 +65,7 @@ function PlayerContent({
className="w-full"
style={
activeTab && !fullscreen
? { maxWidth: 'calc(100% - 270px)' }
? { maxWidth: `calc(100% - ${activeTab === 'EXPORT' ? '360px' : '270px'})` }
: undefined
}
>

View file

@ -182,6 +182,7 @@ function Player(props: IProps) {
setActiveTab={(tab: string) =>
activeTab === tab ? props.setActiveTab('') : props.setActiveTab(tab)
}
activeTab={activeTab}
speedDown={playerContext.player.speedDown}
speedUp={playerContext.player.speedUp}
jump={playerContext.player.jump}

View file

@ -7,13 +7,16 @@ import { Icon } from 'UI';
function LogsButton({
integrated,
onClick,
shorten,
}: {
integrated: string[];
onClick: () => void;
shorten?: boolean;
}) {
return (
<ControlButton
label="Traces"
label={shorten ? null : "Traces"}
customKey="traces"
customTags={
<Avatar.Group>
{integrated.map((name) => (

View file

@ -4,7 +4,7 @@ import { Popover, Button } from 'antd';
import stl from './controlButton.module.css';
interface IProps {
label: string;
label: React.ReactNode;
icon?: string;
disabled?: boolean;
onClick?: () => void;
@ -18,6 +18,7 @@ interface IProps {
noIcon?: boolean;
popover?: React.ReactNode;
customTags?: React.ReactNode;
customKey?: string;
}
function ControlButton({
@ -28,29 +29,28 @@ function ControlButton({
active = false,
popover = undefined,
customTags,
customKey,
}: IProps) {
return (
<Popover content={popover} open={popover ? undefined : false}>
<Button
size="small"
onClick={onClick}
id={`control-button-${label.toLowerCase()}`}
id={`control-button-${customKey ? customKey.toLowerCase() : label!.toString().toLowerCase()}`}
disabled={disabled}
>
{customTags}
{hasErrors && (
<div className={stl.labels}>
<div className={stl.errorSymbol} />
</div>
<div className="w-2 h-2 rounded-full bg-red" />
)}
<span
{label && <span
className={cn(
'font-semibold hover:text-main',
active ? 'color-main' : 'color-gray-darkest',
)}
>
{label}
</span>
</span>}
</Button>
</Popover>
);

View file

@ -32,6 +32,8 @@ import {
} from 'App/mstore/uiPlayerStore';
import { Icon } from 'UI';
import LogsButton from 'App/components/Session/Player/SharedComponents/BackendLogs/LogsButton';
import { CodeOutlined, DashboardOutlined, ClusterOutlined } from '@ant-design/icons';
import { ArrowDownUp, ListCollapse, Merge, Waypoints } from 'lucide-react'
import ControlButton from './ControlButton';
import Timeline from './Timeline';
@ -52,23 +54,23 @@ export const SKIP_INTERVALS = {
function getStorageName(type: any) {
switch (type) {
case STORAGE_TYPES.REDUX:
return 'Redux';
return { name: 'Redux', icon: <Icon name='integrations/redux' size={14} /> };
case STORAGE_TYPES.MOBX:
return 'Mobx';
return { name: 'Mobx', icon: <Icon name='integrations/mobx' size={14} /> };
case STORAGE_TYPES.VUEX:
return 'Vuex';
return { name: 'Vuex', icon: <Icon name='integrations/vuejs' size={14} /> };
case STORAGE_TYPES.NGRX:
return 'NgRx';
return { name: 'NgRx', icon: <Icon name='integrations/ngrx' size={14} /> };
case STORAGE_TYPES.ZUSTAND:
return 'Zustand';
return { name: 'Zustand', icon: <Icon name='integrations/zustand' size={14} /> };
case STORAGE_TYPES.NONE:
return 'State';
return { name: 'State', icon: <ClusterOutlined size={14} /> };
default:
return 'State';
return { name: 'State', icon: <ClusterOutlined size={14} /> };
}
}
function Controls({ setActiveTab }: any) {
function Controls({ setActiveTab, activeTab }: any) {
const { player, store } = React.useContext(PlayerContext);
const {
uxtestingStore,
@ -191,6 +193,7 @@ function Controls({ setActiveTab }: any) {
bottomBlock={bottomBlock}
disabled={disabled}
events={events}
activeTab={activeTab}
/>
)}
@ -212,6 +215,7 @@ interface IDevtoolsButtons {
bottomBlock: number;
disabled: boolean;
events: any[];
activeTab?: string;
}
const DevtoolsButtons = observer(
@ -221,6 +225,7 @@ const DevtoolsButtons = observer(
bottomBlock,
disabled,
events,
activeTab,
}: IDevtoolsButtons) => {
const { t } = useTranslation();
const { aiSummaryStore, integrationsStore } = useStore();
@ -262,6 +267,36 @@ const DevtoolsButtons = observer(
const possibleAudio = events.filter((e) => e.name.includes('media/audio'));
const integratedServices =
integrationsStore.integrations.backendLogIntegrations;
const showIcons = activeTab === 'EXPORT'
const labels = {
console: {
icon: <CodeOutlined size={14} />,
label: t('Console'),
},
performance: {
icon: <DashboardOutlined size={14} />,
label: t('Performance'),
},
network: {
icon: <ArrowDownUp size={14} strokeWidth={2} />,
label: t('Network'),
},
events: {
icon: <ListCollapse size={14} strokeWidth={2} />,
label: t('Events'),
},
state: {
icon: getStorageName(storageType).icon,
label: getStorageName(storageType).name,
},
graphql: {
icon: <Merge size={14} strokeWidth={2} />,
label: 'Graphql',
}
}
// @ts-ignore
const getLabel = (block: string) => labels[block][showIcons ? 'icon' : 'label']
return (
<>
{isSaas ? <SummaryButton onClick={showSummary} /> : null}
@ -274,6 +309,7 @@ const DevtoolsButtons = observer(
</div>
</div>
}
customKey="xray"
label="X-Ray"
onClick={() => toggleBottomTools(OVERVIEW)}
active={bottomBlock === OVERVIEW && !inspectorMode}
@ -286,10 +322,11 @@ const DevtoolsButtons = observer(
<div>{t('Launch Console')}</div>
</div>
}
customKey="console"
disabled={disableButtons}
onClick={() => toggleBottomTools(CONSOLE)}
active={bottomBlock === CONSOLE && !inspectorMode}
label={t('Console')}
label={getLabel('console')}
hasErrors={logRedCount > 0 || showExceptions}
/>
@ -300,10 +337,11 @@ const DevtoolsButtons = observer(
<div>{t('Launch Network')}</div>
</div>
}
customKey="network"
disabled={disableButtons}
onClick={() => toggleBottomTools(NETWORK)}
active={bottomBlock === NETWORK && !inspectorMode}
label={t('Network')}
label={getLabel('network')}
hasErrors={resourceRedCount > 0}
/>
@ -314,10 +352,11 @@ const DevtoolsButtons = observer(
<div>{t('Launch Performance')}</div>
</div>
}
customKey="performance"
disabled={disableButtons}
onClick={() => toggleBottomTools(PERFORMANCE)}
active={bottomBlock === PERFORMANCE && !inspectorMode}
label="Performance"
label={getLabel('performance')}
/>
{showGraphql && (
@ -325,7 +364,8 @@ const DevtoolsButtons = observer(
disabled={disableButtons}
onClick={() => toggleBottomTools(GRAPHQL)}
active={bottomBlock === GRAPHQL && !inspectorMode}
label="Graphql"
label={getLabel('graphql')}
customKey="graphql"
/>
)}
@ -337,10 +377,11 @@ const DevtoolsButtons = observer(
<div>{t('Launch State')}</div>
</div>
}
customKey="state"
disabled={disableButtons}
onClick={() => toggleBottomTools(STORAGE)}
active={bottomBlock === STORAGE && !inspectorMode}
label={getStorageName(storageType) as string}
label={getLabel('state')}
/>
)}
<ControlButton
@ -350,14 +391,16 @@ const DevtoolsButtons = observer(
<div>{t('Launch Events')}</div>
</div>
}
customKey="events"
disabled={disableButtons}
onClick={() => toggleBottomTools(STACKEVENTS)}
active={bottomBlock === STACKEVENTS && !inspectorMode}
label={t('Events')}
label={getLabel('events')}
hasErrors={stackRedCount > 0}
/>
{showProfiler && (
<ControlButton
customKey="profiler"
disabled={disableButtons}
onClick={() => toggleBottomTools(PROFILER)}
active={bottomBlock === PROFILER && !inspectorMode}
@ -368,6 +411,7 @@ const DevtoolsButtons = observer(
<LogsButton
integrated={integratedServices.map((service) => service.name)}
onClick={() => toggleBottomTools(BACKENDLOGS)}
shorten={showIcons}
/>
) : null}
{possibleAudio.length ? (

View file

@ -202,7 +202,7 @@ function UnitStepsModal({ onClose }: Props) {
<div className={'w-full'}>
<CodeBlock
width={340}
height={'calc(100vh - 146px)'}
height={'calc(100vh - 174px)'}
extra={`${events.length} Events`}
copy
code={eventStr}

View file

@ -5,6 +5,15 @@ import { Tooltip } from 'antd';
import cn from 'classnames';
import { useTranslation } from 'react-i18next';
interface Props {
code?: string;
extra?: string;
language?: string;
copy?: boolean;
width?: string;
height?: string;
}
export default function CodeBlock({
code = '',
extra = '',
@ -12,7 +21,7 @@ export default function CodeBlock({
copy = false,
width = undefined,
height = undefined,
}) {
}: Props) {
const { t } = useTranslation();
useEffect(() => {
setTimeout(() => {