ui: fixes for kai and network tooltips
This commit is contained in:
parent
ddb47631b6
commit
0a5d4413ca
10 changed files with 176 additions and 101 deletions
|
|
@ -50,7 +50,8 @@ function KaiChat() {
|
|||
React.useEffect(() => {
|
||||
if (
|
||||
activeSiteId &&
|
||||
parseInt(activeSiteId, 10) !== parseInt(location.pathname.split('/')[1], 10)
|
||||
parseInt(activeSiteId, 10) !==
|
||||
parseInt(location.pathname.split('/')[1], 10)
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
|
@ -120,7 +121,6 @@ function KaiChat() {
|
|||
<ChatLog
|
||||
threadId={threadId}
|
||||
projectId={activeSiteId}
|
||||
userId={userId}
|
||||
userLetter={userLetter}
|
||||
onTitleChange={setTitle}
|
||||
initialMsg={initialMsg}
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ import AiService from '@/services/AiService';
|
|||
export default class KaiService extends AiService {
|
||||
getKaiChats = async (
|
||||
projectId: string,
|
||||
): Promise<{ title: string; threadId: string }[]> => {
|
||||
): Promise<{ title: string; thread_id: string }[]> => {
|
||||
const r = await this.client.get(`/kai/${projectId}/chats`);
|
||||
if (!r.ok) {
|
||||
throw new Error('Failed to fetch chats');
|
||||
|
|
@ -27,7 +27,13 @@ export default class KaiService extends AiService {
|
|||
projectId: string,
|
||||
threadId: string,
|
||||
): Promise<
|
||||
{ role: string; content: string; message_id: any; duration?: number }[]
|
||||
{
|
||||
role: string;
|
||||
content: string;
|
||||
message_id: any;
|
||||
duration?: number;
|
||||
feedback: boolean | null;
|
||||
}[]
|
||||
> => {
|
||||
const r = await this.client.get(`/kai/${projectId}/chats/${threadId}`);
|
||||
if (!r.ok) {
|
||||
|
|
|
|||
|
|
@ -81,11 +81,10 @@ class KaiStore {
|
|||
deleteAtIndex = (indexes: number[]) => {
|
||||
if (!indexes.length) return;
|
||||
const messages = this.messages.filter((_, i) => !indexes.includes(i));
|
||||
console.log(messages, indexes)
|
||||
runInAction(() => {
|
||||
this.messages = messages;
|
||||
})
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
getChat = async (projectId: string, threadId: string) => {
|
||||
this.setLoadingChat(true);
|
||||
|
|
@ -100,6 +99,7 @@ class KaiStore {
|
|||
isUser: isUser,
|
||||
messageId: m.message_id,
|
||||
duration: m.duration,
|
||||
feedback: m.feedback,
|
||||
};
|
||||
}),
|
||||
);
|
||||
|
|
@ -117,7 +117,11 @@ class KaiStore {
|
|||
setTitle: (title: string) => void,
|
||||
initialMsg: string | null,
|
||||
) => {
|
||||
const token = kaiService.client.getJwt()
|
||||
const token = kaiService.client.getJwt();
|
||||
if (!token) {
|
||||
console.error('No token found');
|
||||
return;
|
||||
}
|
||||
this.chatManager = new ChatManager({ ...settings, token });
|
||||
this.chatManager.setOnMsgHook({
|
||||
msgCallback: (msg) => {
|
||||
|
|
@ -127,10 +131,10 @@ class KaiStore {
|
|||
content: 'Processing your request...',
|
||||
stage: 'chart',
|
||||
messageId: Date.now().toPrecision(),
|
||||
duration: msg.start_time ? Date.now() - msg.start_time : 0
|
||||
})
|
||||
duration: msg.start_time ? Date.now() - msg.start_time : 0,
|
||||
});
|
||||
} else {
|
||||
this.setProcessingStage(null)
|
||||
this.setProcessingStage(null);
|
||||
}
|
||||
} else {
|
||||
if (msg.stage === 'start') {
|
||||
|
|
@ -147,8 +151,9 @@ class KaiStore {
|
|||
text: msg.content,
|
||||
isUser: false,
|
||||
messageId: msg.messageId,
|
||||
duration: msg.duration
|
||||
}
|
||||
duration: msg.duration,
|
||||
feedback: null,
|
||||
};
|
||||
this.addMessage(msgObj);
|
||||
this.setProcessingStage(null);
|
||||
}
|
||||
|
|
@ -171,32 +176,46 @@ class KaiStore {
|
|||
this.chatManager.sendMessage(message, this.replacing);
|
||||
}
|
||||
if (this.replacing) {
|
||||
console.log(this.lastHumanMessage, this.lastKaiMessage, 'replacing these two')
|
||||
const deleting = []
|
||||
console.log(
|
||||
this.lastHumanMessage,
|
||||
this.lastKaiMessage,
|
||||
'replacing these two',
|
||||
);
|
||||
const deleting = [];
|
||||
if (this.lastHumanMessage.index !== null) {
|
||||
deleting.push(this.lastHumanMessage.index);
|
||||
}
|
||||
if (this.lastKaiMessage.index !== null) {
|
||||
deleting.push(this.lastKaiMessage.index)
|
||||
deleting.push(this.lastKaiMessage.index);
|
||||
}
|
||||
this.deleteAtIndex(deleting);
|
||||
this.setReplacing(false)
|
||||
this.setReplacing(false);
|
||||
}
|
||||
this.addMessage({
|
||||
text: message,
|
||||
isUser: true,
|
||||
messageId: Date.now().toString(),
|
||||
feedback: null,
|
||||
duration: 0,
|
||||
});
|
||||
};
|
||||
|
||||
sendMsgFeedback = (feedback: string, messageId: string) => {
|
||||
const settings = { projectId: '2325', userId: '0' };
|
||||
sendMsgFeedback = (
|
||||
feedback: string,
|
||||
messageId: string,
|
||||
projectId: string,
|
||||
) => {
|
||||
this.messages = this.messages.map((msg) => {
|
||||
if (msg.messageId === messageId) {
|
||||
return {
|
||||
...msg,
|
||||
feedback: feedback === 'like' ? true : false,
|
||||
};
|
||||
}
|
||||
return msg;
|
||||
});
|
||||
aiService
|
||||
.feedback(
|
||||
feedback === 'like',
|
||||
messageId,
|
||||
settings.projectId,
|
||||
)
|
||||
.feedback(feedback === 'like', messageId, projectId)
|
||||
.then(() => {
|
||||
toast.success('Feedback saved.');
|
||||
})
|
||||
|
|
@ -206,15 +225,21 @@ class KaiStore {
|
|||
});
|
||||
};
|
||||
|
||||
cancelGeneration = async (settings: { projectId: string; userId: string; threadId: string }) => {
|
||||
cancelGeneration = async (settings: {
|
||||
projectId: string;
|
||||
userId: string;
|
||||
threadId: string;
|
||||
}) => {
|
||||
try {
|
||||
await kaiService.cancelGeneration(settings.projectId, settings.threadId, settings.userId)
|
||||
this.setProcessingStage(null)
|
||||
await kaiService.cancelGeneration(settings.projectId, settings.threadId);
|
||||
this.setProcessingStage(null);
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
toast.error('Failed to cancel the response generation, please try again later.')
|
||||
console.error(e);
|
||||
toast.error(
|
||||
'Failed to cancel the response generation, please try again later.',
|
||||
);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
clearChat = () => {
|
||||
this.setMessages([]);
|
||||
|
|
|
|||
|
|
@ -100,6 +100,7 @@ export interface Message {
|
|||
isUser: boolean;
|
||||
messageId: string;
|
||||
duration?: number;
|
||||
feedback: boolean | null;
|
||||
}
|
||||
|
||||
export interface SentMessage extends Message {
|
||||
|
|
|
|||
|
|
@ -2,12 +2,11 @@ import React from 'react';
|
|||
import ChatInput from './ChatInput';
|
||||
import { ChatMsg, ChatNotice } from './ChatMsg';
|
||||
import { Loader } from 'UI';
|
||||
import { kaiStore } from '../KaiStore'
|
||||
import { kaiStore } from '../KaiStore';
|
||||
import { observer } from 'mobx-react-lite';
|
||||
|
||||
function ChatLog({
|
||||
projectId,
|
||||
userId,
|
||||
threadId,
|
||||
userLetter,
|
||||
onTitleChange,
|
||||
|
|
@ -15,7 +14,6 @@ function ChatLog({
|
|||
setInitialMsg,
|
||||
}: {
|
||||
projectId: string;
|
||||
userId: string;
|
||||
threadId: any;
|
||||
userLetter: string;
|
||||
onTitleChange: (title: string | null) => void;
|
||||
|
|
@ -30,10 +28,10 @@ function ChatLog({
|
|||
React.useEffect(() => {
|
||||
const settings = { projectId, threadId };
|
||||
if (threadId && !initialMsg) {
|
||||
void kaiStore.getChat(settings.projectId, threadId)
|
||||
void kaiStore.getChat(settings.projectId, threadId);
|
||||
}
|
||||
if (threadId) {
|
||||
kaiStore.createChatManager(settings, onTitleChange, initialMsg)
|
||||
kaiStore.createChatManager(settings, onTitleChange, initialMsg);
|
||||
}
|
||||
return () => {
|
||||
kaiStore.clearChat();
|
||||
|
|
@ -42,7 +40,7 @@ function ChatLog({
|
|||
}, [threadId]);
|
||||
|
||||
const onSubmit = (text: string) => {
|
||||
kaiStore.sendMessage(text)
|
||||
kaiStore.sendMessage(text);
|
||||
};
|
||||
|
||||
React.useEffect(() => {
|
||||
|
|
@ -71,10 +69,15 @@ function ChatLog({
|
|||
messageId={msg.messageId}
|
||||
isLast={index === lastHumanMsgInd}
|
||||
duration={msg.duration}
|
||||
feedback={msg.feedback}
|
||||
siteId={projectId}
|
||||
/>
|
||||
))}
|
||||
{processingStage ? (
|
||||
<ChatNotice content={processingStage.content} duration={processingStage.duration} />
|
||||
<ChatNotice
|
||||
content={processingStage.content}
|
||||
duration={processingStage.duration}
|
||||
/>
|
||||
) : null}
|
||||
</div>
|
||||
<div className={'sticky bottom-0 pt-6 w-2/3'}>
|
||||
|
|
|
|||
|
|
@ -23,6 +23,8 @@ export function ChatMsg({
|
|||
messageId,
|
||||
isLast,
|
||||
duration,
|
||||
feedback,
|
||||
siteId,
|
||||
}: {
|
||||
text: string;
|
||||
isUser: boolean;
|
||||
|
|
@ -30,6 +32,8 @@ export function ChatMsg({
|
|||
userName?: string;
|
||||
isLast?: boolean;
|
||||
duration?: number;
|
||||
feedback: boolean | null;
|
||||
siteId: string;
|
||||
}) {
|
||||
const [isProcessing, setIsProcessing] = React.useState(false);
|
||||
const bodyRef = React.useRef<HTMLDivElement>(null);
|
||||
|
|
@ -37,7 +41,7 @@ export function ChatMsg({
|
|||
kaiStore.editMessage(text);
|
||||
};
|
||||
const onFeedback = (feedback: 'like' | 'dislike', messageId: string) => {
|
||||
kaiStore.sendMsgFeedback(feedback, messageId);
|
||||
kaiStore.sendMsgFeedback(feedback, messageId, siteId);
|
||||
};
|
||||
|
||||
const onExport = () => {
|
||||
|
|
@ -115,12 +119,14 @@ export function ChatMsg({
|
|||
{duration ? <MsgDuration duration={duration} /> : null}
|
||||
<div className="ml-auto" />
|
||||
<IconButton
|
||||
active={feedback === true}
|
||||
tooltip="Like this answer"
|
||||
onClick={() => onFeedback('like', messageId)}
|
||||
>
|
||||
<ThumbsUp size={16} />
|
||||
</IconButton>
|
||||
<IconButton
|
||||
active={feedback === false}
|
||||
tooltip="Dislike this answer"
|
||||
onClick={() => onFeedback('dislike', messageId)}
|
||||
>
|
||||
|
|
@ -151,17 +157,19 @@ function IconButton({
|
|||
onClick,
|
||||
tooltip,
|
||||
processing,
|
||||
active,
|
||||
}: {
|
||||
children: React.ReactNode;
|
||||
onClick?: () => void;
|
||||
tooltip?: string;
|
||||
processing?: boolean;
|
||||
active?: boolean;
|
||||
}) {
|
||||
return (
|
||||
<Tooltip title={tooltip}>
|
||||
<Button
|
||||
onClick={onClick}
|
||||
type="text"
|
||||
type={active ? 'primary' : 'text'}
|
||||
icon={children}
|
||||
size="small"
|
||||
loading={processing}
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ import React, {
|
|||
useCallback,
|
||||
useRef,
|
||||
} from 'react';
|
||||
import i18n from 'App/i18n'
|
||||
import i18n from 'App/i18n';
|
||||
|
||||
import { useModal } from 'App/components/Modal';
|
||||
import {
|
||||
|
|
@ -23,10 +23,7 @@ import { useStore } from 'App/mstore';
|
|||
import { formatBytes, debounceCall } from 'App/utils';
|
||||
import { Icon, NoContent, Tabs } from 'UI';
|
||||
import { Tooltip, Input, Switch, Form } from 'antd';
|
||||
import {
|
||||
SearchOutlined,
|
||||
InfoCircleOutlined,
|
||||
} from '@ant-design/icons';
|
||||
import { SearchOutlined, InfoCircleOutlined } from '@ant-design/icons';
|
||||
|
||||
import FetchDetailsModal from 'Shared/FetchDetailsModal';
|
||||
|
||||
|
|
@ -37,7 +34,7 @@ import TimeTable from '../TimeTable';
|
|||
import useAutoscroll, { getLastItemTime } from '../useAutoscroll';
|
||||
import WSPanel from './WSPanel';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { mergeListsWithZoom, processInChunks } from './utils'
|
||||
import { mergeListsWithZoom, processInChunks } from './utils';
|
||||
|
||||
// Constants remain the same
|
||||
const INDEX_KEY = 'network';
|
||||
|
|
@ -84,9 +81,22 @@ export function renderType(r: any) {
|
|||
}
|
||||
|
||||
export function renderName(r: any) {
|
||||
const maxTtipUrlLength = 800;
|
||||
const tooltipUrl =
|
||||
r.url && r.url.length > maxTtipUrlLength
|
||||
? `${r.url.slice(0, maxTtipUrlLength / 2)}......${r.url.slice(-maxTtipUrlLength / 2)}`
|
||||
: r.url;
|
||||
|
||||
return (
|
||||
<Tooltip style={{ width: '100%' }} title={<div>{r.url}</div>}>
|
||||
<div>{r.name}</div>
|
||||
<Tooltip
|
||||
style={{ width: '100%', maxWidth: 1024 }}
|
||||
title={<div>{tooltipUrl}</div>}
|
||||
>
|
||||
<div
|
||||
style={{ maxWidth: 250, overflow: 'hidden', textOverflow: 'ellipsis' }}
|
||||
>
|
||||
{r.name}
|
||||
</div>
|
||||
</Tooltip>
|
||||
);
|
||||
}
|
||||
|
|
@ -94,7 +104,7 @@ export function renderName(r: any) {
|
|||
function renderSize(r: any) {
|
||||
const t = i18n.t;
|
||||
const notCaptured = t('Not captured');
|
||||
const resSizeStr = t('Resource size')
|
||||
const resSizeStr = t('Resource size');
|
||||
let triggerText;
|
||||
let content;
|
||||
if (r.responseBodySize) {
|
||||
|
|
@ -185,7 +195,6 @@ function renderStatus({
|
|||
);
|
||||
}
|
||||
|
||||
|
||||
// Main component for Network Panel
|
||||
function NetworkPanelCont({ panelHeight }: { panelHeight: number }) {
|
||||
const { player, store } = React.useContext(PlayerContext);
|
||||
|
|
@ -433,11 +442,11 @@ export const NetworkPanelComp = observer(
|
|||
|
||||
// Heaviest operation here, will create a final merged network list
|
||||
const processData = async () => {
|
||||
const fetchUrlMap: Record<string, number[]> = {}
|
||||
const fetchUrlMap: Record<string, number[]> = {};
|
||||
const len = fetchList.length;
|
||||
for (let i = 0; i < len; i++) {
|
||||
const ft = fetchList[i] as any;
|
||||
const key = `${ft.name}-${Math.round(ft.time / 10)}-${Math.round(ft.duration / 10)}`
|
||||
const key = `${ft.name}-${Math.round(ft.time / 10)}-${Math.round(ft.duration / 10)}`;
|
||||
if (fetchUrlMap[key]) {
|
||||
fetchUrlMap[key].push(i);
|
||||
}
|
||||
|
|
@ -445,21 +454,23 @@ export const NetworkPanelComp = observer(
|
|||
}
|
||||
|
||||
// We want to get resources that aren't in fetch list
|
||||
const filteredResources = await processInChunks(resourceList, (chunk) => {
|
||||
const clearChunk = [];
|
||||
for (const res of chunk) {
|
||||
const key = `${res.name}-${Math.floor(res.time / 10)}-${Math.floor(res.duration / 10)}`;
|
||||
const possibleRequests = fetchUrlMap[key]
|
||||
if (possibleRequests && possibleRequests.length) {
|
||||
for (const i of possibleRequests) {
|
||||
fetchList[i].timings = res.timings;
|
||||
const filteredResources = await processInChunks(
|
||||
resourceList,
|
||||
(chunk) => {
|
||||
const clearChunk = [];
|
||||
for (const res of chunk) {
|
||||
const key = `${res.name}-${Math.floor(res.time / 10)}-${Math.floor(res.duration / 10)}`;
|
||||
const possibleRequests = fetchUrlMap[key];
|
||||
if (possibleRequests && possibleRequests.length) {
|
||||
for (const i of possibleRequests) {
|
||||
fetchList[i].timings = res.timings;
|
||||
}
|
||||
fetchUrlMap[key] = [];
|
||||
} else {
|
||||
clearChunk.push(res);
|
||||
}
|
||||
fetchUrlMap[key] = [];
|
||||
} else {
|
||||
clearChunk.push(res);
|
||||
}
|
||||
}
|
||||
return clearChunk;
|
||||
return clearChunk;
|
||||
},
|
||||
// chunk.filter((res: any) => {
|
||||
// const key = `${res.name}-${Math.floor(res.time / 100)}-${Math.floor(res.duration / 100)}`;
|
||||
|
|
@ -484,8 +495,12 @@ export const NetworkPanelComp = observer(
|
|||
filteredResources as Timed[],
|
||||
fetchList,
|
||||
processedSockets as Timed[],
|
||||
{ enabled: Boolean(zoomEnabled), start: zoomStartTs ?? 0, end: zoomEndTs ?? 0 }
|
||||
)
|
||||
{
|
||||
enabled: Boolean(zoomEnabled),
|
||||
start: zoomStartTs ?? 0,
|
||||
end: zoomEndTs ?? 0,
|
||||
},
|
||||
);
|
||||
|
||||
originalListRef.current = mergedList;
|
||||
setTotalItems(mergedList.length);
|
||||
|
|
@ -509,19 +524,21 @@ export const NetworkPanelComp = observer(
|
|||
|
||||
const calculateResourceStats = (resourceList: Record<string, any>) => {
|
||||
setTimeout(() => {
|
||||
let resourcesSize = 0
|
||||
let transferredSize = 0
|
||||
resourceList.forEach(({ decodedBodySize, headerSize, encodedBodySize }: any) => {
|
||||
resourcesSize += decodedBodySize || 0
|
||||
transferredSize += (headerSize || 0) + (encodedBodySize || 0)
|
||||
})
|
||||
let resourcesSize = 0;
|
||||
let transferredSize = 0;
|
||||
resourceList.forEach(
|
||||
({ decodedBodySize, headerSize, encodedBodySize }: any) => {
|
||||
resourcesSize += decodedBodySize || 0;
|
||||
transferredSize += (headerSize || 0) + (encodedBodySize || 0);
|
||||
},
|
||||
);
|
||||
|
||||
setSummaryStats({
|
||||
resourcesSize,
|
||||
transferredSize,
|
||||
});
|
||||
}, 0);
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (originalListRef.current.length === 0) return;
|
||||
|
|
@ -530,27 +547,33 @@ export const NetworkPanelComp = observer(
|
|||
let filteredItems: any[] = originalListRef.current;
|
||||
|
||||
filteredItems = await processInChunks(filteredItems, (chunk) =>
|
||||
chunk.filter(
|
||||
(it) => {
|
||||
let valid = true;
|
||||
if (showOnlyErrors) {
|
||||
valid = parseInt(it.status) >= 400 || !it.success || it.error
|
||||
}
|
||||
if (filter) {
|
||||
try {
|
||||
const regex = new RegExp(filter, 'i');
|
||||
valid = valid && regex.test(it.status) || regex.test(it.name) || regex.test(it.type) || regex.test(it.method);
|
||||
} catch (e) {
|
||||
valid = valid && String(it.status).includes(filter) || it.name.includes(filter) || it.type.includes(filter) || (it.method && it.method.includes(filter));
|
||||
}
|
||||
}
|
||||
if (activeTab !== ALL) {
|
||||
valid = valid && TYPE_TO_TAB[it.type] === activeTab;
|
||||
chunk.filter((it) => {
|
||||
let valid = true;
|
||||
if (showOnlyErrors) {
|
||||
valid = parseInt(it.status) >= 400 || !it.success || it.error;
|
||||
}
|
||||
if (filter) {
|
||||
try {
|
||||
const regex = new RegExp(filter, 'i');
|
||||
valid =
|
||||
(valid && regex.test(it.status)) ||
|
||||
regex.test(it.name) ||
|
||||
regex.test(it.type) ||
|
||||
regex.test(it.method);
|
||||
} catch (e) {
|
||||
valid =
|
||||
(valid && String(it.status).includes(filter)) ||
|
||||
it.name.includes(filter) ||
|
||||
it.type.includes(filter) ||
|
||||
(it.method && it.method.includes(filter));
|
||||
}
|
||||
}
|
||||
if (activeTab !== ALL) {
|
||||
valid = valid && TYPE_TO_TAB[it.type] === activeTab;
|
||||
}
|
||||
|
||||
return valid;
|
||||
},
|
||||
),
|
||||
return valid;
|
||||
}),
|
||||
);
|
||||
|
||||
// Update displayed items
|
||||
|
|
@ -587,7 +610,7 @@ export const NetworkPanelComp = observer(
|
|||
};
|
||||
|
||||
const onFilterChange = ({ target: { value } }) => {
|
||||
setInputFilterValue(value)
|
||||
setInputFilterValue(value);
|
||||
debouncedFilter(value);
|
||||
};
|
||||
|
||||
|
|
@ -855,11 +878,11 @@ export const NetworkPanelComp = observer(
|
|||
ref={loadingRef}
|
||||
className="flex justify-center items-center text-xs text-gray-500"
|
||||
>
|
||||
<div className="flex items-center">
|
||||
<div className="animate-spin rounded-full h-4 w-4 border-b-2 border-gray-600 mr-2"></div>
|
||||
Loading more data ({totalItems - displayedItems.length}{' '}
|
||||
remaining)
|
||||
</div>
|
||||
<div className="flex items-center">
|
||||
<div className="animate-spin rounded-full h-4 w-4 border-b-2 border-gray-600 mr-2"></div>
|
||||
Loading more data ({totalItems - displayedItems.length}{' '}
|
||||
remaining)
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -355,7 +355,7 @@ function RowRenderer({
|
|||
);
|
||||
}
|
||||
|
||||
const RowColumns = React.memo(({ columns, row }: any) => {
|
||||
const RowColumns = ({ columns, row }: any) => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
return columns.map(({ dataKey, render, width, label }: any) => (
|
||||
|
|
@ -371,6 +371,6 @@ const RowColumns = React.memo(({ columns, row }: any) => {
|
|||
)}
|
||||
</div>
|
||||
));
|
||||
});
|
||||
};
|
||||
|
||||
export default observer(TimeTable);
|
||||
|
|
|
|||
|
|
@ -13,6 +13,11 @@ function FetchBasicDetails({ resource, timestamp }: Props) {
|
|||
const _duration = parseInt(resource.duration);
|
||||
const { t } = useTranslation();
|
||||
|
||||
const maxUrlLength = 800;
|
||||
const displayUrl =
|
||||
resource.url && resource.url.length > maxUrlLength
|
||||
? `${resource.url.slice(0, maxUrlLength / 2)}......${resource.url.slice(-maxUrlLength / 2)}`
|
||||
: resource.url;
|
||||
return (
|
||||
<div>
|
||||
<div className="flex items-start py-1">
|
||||
|
|
@ -22,7 +27,7 @@ function FetchBasicDetails({ resource, timestamp }: Props) {
|
|||
bordered={false}
|
||||
style={{ maxWidth: '300px' }}
|
||||
>
|
||||
<div>{resource.url}</div>
|
||||
<div>{displayUrl}</div>
|
||||
</Tag>
|
||||
</div>
|
||||
|
||||
|
|
|
|||
|
|
@ -425,3 +425,7 @@ svg {
|
|||
width: 1em;
|
||||
margin-left: -1em;
|
||||
}
|
||||
|
||||
.ant-tooltip {
|
||||
max-width: 640px;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue