22581b2f创建于 2025年12月16日历史提交
/*
 * -------------------------------------------------------------------------
 * This file is part of the MindStudio project.
 * Copyright (c) 2025 Huawei Technologies Co.,Ltd.
 *
 * MindStudio is licensed under Mulan PSL v2.
 * You can use this software according to the terms and conditions of the Mulan PSL v2.
 * You may obtain a copy of Mulan PSL v2 at:
 *
 *          http://license.coscl.org.cn/MulanPSL2
 *
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 * See the Mulan PSL v2 for more details.
 * -------------------------------------------------------------------------
 */
import React, { useEffect, useState } from 'react';
import { observer } from 'mobx-react';
import { useTranslation } from 'react-i18next';
import { type Icondition } from './Filter';
import { queryMemoryTable } from '../../RequestUtils';
import { LimitHit } from '../../LimitSet';
import { ResizeTable } from '@insight/lib/resize';
import { firstLetterUpper, Hit } from '@insight/lib/utils';
import { type Session } from '../../../entity/session';
import { CompareData } from '../../../utils/interface';
import { type Theme, useTheme } from '@emotion/react';
import { getContextElement, renderExpandColumn } from '../../Common';

interface ItableDetail {
    tableName: string;
    headerName: string[];
    row: Array<CompareData<RowDetail>>;
}

interface RowDetail {
    name: string;
    value: string[];
}

interface ItableConfig {
    cols: any[];
    dataset: Array<Record<string, string | Array<Record<string, string>>>>;
}

interface Ilimit {
    overlimit: boolean;
    maxSize: number;
    current: number;
}

function getFullCols({ headerName, tDetails, isCompared, setExpandedKeys, theme }: { headerName: string[]; tDetails: any;
    isCompared: boolean; setExpandedKeys: React.Dispatch<React.SetStateAction<string[]>>; theme: Theme; }): any[] {
    const dataColumns: any[] = headerName.map((item, index) => (
        {
            key: item,
            title: index === 0 ? item : tDetails(firstLetterUpper(item)),
            dataIndex: item,
            ellipsis: true,
            render: (text: string, record: any): JSX.Element => getContextElement(text, record, theme, tDetails),
        }
    ));
    if (isCompared) {
        dataColumns.push({
            key: 'action',
            title: tDetails('Details'),
            dataIndex: 'action',
            ellipsis: true,
            fixed: 'right',
            render: (_: any, record: any): JSX.Element => {
                return renderExpandColumn(record, setExpandedKeys, tDetails);
            },
        });
        dataColumns.splice(1, 0, {
            key: 'source',
            title: tDetails('Source'),
            dataIndex: 'source',
            ellipsis: true,
        });
    }
    return dataColumns;
}

function covertRowToRecord(row: RowDetail, headerName: string[]): Record<string, string> {
    const arr = [row.name, ...row.value];
    const obj: Record<string, string> = {};
    headerName.forEach((header, index) => {
        obj[header] = arr[index];
    });
    return obj;
}

function wrapData({ data, limit, tDetails, isCompared, setExpandedKeys, theme }: { data: ItableDetail[]; limit: Ilimit;
    tDetails: any; isCompared: boolean; setExpandedKeys: React.Dispatch<React.SetStateAction<string[]>>; theme: Theme; }):
    { tablelist: ItableConfig[] ;limit: Ilimit} {
    let count = 0;
    const tablelist = data.reduce<ItableConfig[]>((pre, tableDetail) => {
        if (count > limit.maxSize) {
            count += tableDetail?.row?.length ?? 0;
            return pre;
        }
        const { headerName = [], row = [], tableName = '' } = tableDetail ?? {};
        headerName[0] = tableName;
        const cols = getFullCols({ headerName, tDetails, isCompared, setExpandedKeys, theme });
        let dataset = row.map(item => {
            const compare: Record<string, string> = covertRowToRecord(item.compare, headerName);
            if (!isCompared) {
                return compare;
            }
            const res: Record<string, string | Array<Record<string, string>>> = covertRowToRecord(item.diff, headerName);
            res.source = tDetails('Difference');
            compare.source = tDetails('Comparison');
            const baseline: Record<string, string> = covertRowToRecord(item.baseline, headerName);
            baseline.source = tDetails('Baseline');
            res.children = [compare, baseline] as Array<Record<string, string>>;
            return res;
        });

        if (count + data.length > limit.maxSize) {
            dataset = dataset.slice(0, count + data.length - limit.maxSize);
        }
        count += dataset.length;
        pre.push({ cols, dataset });
        return pre;
    }, []);
    return { tablelist, limit: { ...limit, current: count, overlimit: count > limit.maxSize } };
}

async function getMemoryData(condition: Icondition): Promise<{data: ItableDetail[];advice: string[]}> {
    if (condition.blockId === '') {
        return { data: [], advice: [] };
    }

    const res = await queryMemoryTable(condition);
    const data = (res?.memoryTable?.[0]?.tableDetail ?? []) as ItableDetail[];
    const advice = (res?.memoryTable?.[0]?.advice ?? []) as string[];
    return { data, advice };
}

const defaultLimit = { overlimit: false, maxSize: 1000, current: 0 };
const memoryTable = observer(({ condition, session }: {condition: Icondition;session: Session}): JSX.Element => {
    const [data, setData] = useState<ItableDetail[]>([]);
    const [advice, setAdvice] = useState<string[]>([]);
    const [tablelist, setTablelist] = useState<ItableConfig[]>([]);
    const [limit, setLimit] = useState<Ilimit>(defaultLimit);
    const { t: tDetails } = useTranslation('details');
    const [expandedRowKeys, setExpandedKeys] = React.useState<string[]>([]);
    const theme = useTheme();
    const updateData = async(): Promise<void> => {
        const { data: newData, advice: newAdvice } = await getMemoryData(condition);
        setData(newData);
        setAdvice(newAdvice);
    };

    useEffect(() => {
        if (!session.parseStatus) {
            setTablelist([]);
            setAdvice([]);
            setLimit(defaultLimit);
            return;
        }
        updateData();
    }, [condition, session.parseStatus]);
    useEffect(() => {
        const { tablelist: newTablelist, limit: newLimit } =
            wrapData({ data, limit, tDetails, isCompared: session.dirInfo.isCompare, setExpandedKeys, theme });
        setTablelist(newTablelist);
        setLimit(newLimit);
    }, [data, tDetails]);
    return (
        <div>
            {advice.length > 0 && (<Hit text={advice} style={{ marginBottom: '10px' }} type={'alarm'} data-testId="memoryWorkloadAdvice"/>) }
            {tablelist.length === 0 && (<div style={{ textAlign: 'center', color: 'var(--grey15) ' }}>No data</div>) }
            {limit.overlimit && <LimitHit maxSize={limit.maxSize} name={`${tDetails('Memory Workload Table Records')}(${limit.current})`}/>}
            <div data-testId={'memoryWorkloadTable'}>
                {tablelist.map((item, index) => (
                    <ResizeTable
                        key={`memoryTable${index}`}
                        size="small"
                        columns={item.cols ?? []}
                        dataSource={item.dataset.map((row, rowIndex) => { return { ...row, key: `memoryTable${index}_${rowIndex}` }; })}
                        scroll={item.dataset.length > 10 ? { y: 500 } : undefined}
                        pagination={false}
                        expandable={{
                            expandIcon: () => <></>,
                            expandedRowKeys,
                        }}
                    />
                ))}
            </div>

        </div>
    );
});

export default memoryTable;