lodash#round TypeScript Examples
The following examples show how to use
lodash#round.
You can vote up the ones you like or vote down the ones you don't like,
and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: machine-table.tsx From erda-ui with GNU Affero General Public License v3.0 | 6 votes |
ProgressItem = ({ percent, used, total, unit, unitType }: any) => (
<div className="machine-percent">
<Tooltip
placement="top"
title={
unitType
? `${getFormatter(unitType).format(used)} / ${getFormatter(unitType).format(total)}`
: `${round(used, 2)} ${unit} / ${round(total, 2)} ${unit}`
}
>
<div
className={classNames({
'cursor-pointer': true,
'machine-percent-bar': true,
'machine-percent-error-bar': percent >= 100,
})}
style={{ width: `${percent}%` }}
>
<span>{`${percent}%`}</span>
</div>
</Tooltip>
</div>
)
Example #2
Source File: apiDelayPanel.tsx From erda-ui with GNU Affero General Public License v3.0 | 6 votes |
apiDelayPanel = ({ data, reload }: { data: object; reload: Function }) => {
const list = get(data, 'list');
const columns = [
{
title: 'API Path',
dataIndex: 'name',
key: 'name',
render: (value: string) => (
<IF check={value.length > 30}>
<Tooltip title={value}>
<Copy copyText={value}>{`${value.substr(0, 30)}...`}</Copy>
</Tooltip>
<IF.ELSE />
<Copy>{value}</Copy>
</IF>
),
},
{
title: i18n.t('msp:time-consuming(ms)'),
dataIndex: 'time',
key: 'time',
render: (time: number) => round(time, 3),
},
];
// only show 10 pieces of data,not need pagination
return <ErdaTable columns={columns} dataSource={list} pagination={false} onReload={reload} />;
}
Example #3
Source File: apiSizePanel.tsx From erda-ui with GNU Affero General Public License v3.0 | 6 votes |
apiSizePanel = ({ data, reload }: { data: object; reload: Function }) => {
const list = get(data, 'list');
const columns = [
{
title: 'API Path',
dataIndex: 'name',
key: 'name',
render: (value: string) => (
<IF check={value.length > 30}>
<Tooltip title={value}>
<Copy copyText={value}>{`${value.substr(0, 30)}...`}</Copy>
</Tooltip>
<IF.ELSE />
<Copy>{value}</Copy>
</IF>
),
},
{
title: i18n.t('msp:transport bytes(KBytes)'),
dataIndex: 'size',
key: 'size',
render: (size: number) => round(size, 3),
},
];
// only show 10 pieces of data,not need pagination
return <ErdaTable columns={columns} dataSource={list} pagination={false} onReload={reload} />;
}
Example #4
Source File: formatQCMissingData.ts From nextclade with MIT License | 6 votes |
export function formatQCMissingData<TFunction extends TFunctionInterface>(
t: TFunction,
missingData?: DeepReadonly<QcResultMissingData>,
) {
if (!missingData || missingData.status === QcStatus.good) {
return undefined
}
const { score, totalMissing, missingDataThreshold, status } = missingData
let message = t('Missing data found')
if (status === QcStatus.bad) {
message = t('Too much missing data found')
}
return t('{{message}}. Total Ns: {{total}} ({{allowed}} allowed). QC score: {{score}}', {
message,
total: totalMissing,
allowed: missingDataThreshold,
score: round(score),
})
}
Example #5
Source File: formatQCMixedSites.ts From nextclade with MIT License | 6 votes |
export function formatQCMixedSites<TFunction extends TFunctionInterface>(
t: TFunction,
mixedSites?: DeepReadonly<QcResultMixedSites>,
) {
if (!mixedSites || mixedSites.status === QcStatus.good) {
return undefined
}
const { score, totalMixedSites, mixedSitesThreshold, status } = mixedSites
let message = t('Mixed sites found')
if (status === QcStatus.bad) {
message = t('Too many mixed sites found')
}
return t('{{message}}: total {{total}} ({{allowed}} allowed). QC score: {{score}}', {
message,
total: totalMixedSites,
allowed: mixedSitesThreshold,
score: round(score),
})
}
Example #6
Source File: formatQCPrivateMutations.ts From nextclade with MIT License | 6 votes |
export function formatQCPrivateMutations<TFunction extends TFunctionInterface>(
t: TFunction,
privateMutations?: DeepReadonly<QcResultPrivateMutations>,
) {
if (!privateMutations || privateMutations.status === QcStatus.good) {
return undefined
}
const {
score,
numReversionSubstitutions,
numLabeledSubstitutions,
numUnlabeledSubstitutions,
totalDeletionRanges,
weightedTotal,
} = privateMutations
return t(
'QC score: {{score}}. ' +
'Reverted substitutions: {{numReversionSubstitutions}}, ' +
'Labeled substitutions: {{numLabeledSubstitutions}}, ' +
'Unlabeled substitutions: {{numUnlabeledSubstitutions}}, ' +
'Deletion ranges: {{totalDeletionRanges}}. ' +
'Weighted total: {{weightedTotal}}',
{
score: round(score),
numReversionSubstitutions,
numLabeledSubstitutions,
numUnlabeledSubstitutions,
totalDeletionRanges,
weightedTotal,
},
)
}
Example #7
Source File: formatQCSNPClusters.ts From nextclade with MIT License | 6 votes |
export function formatQCSNPClusters<TFunction extends TFunctionInterface>(
t: TFunction,
snpClusters?: DeepReadonly<QcResultSnpClusters>,
) {
if (!snpClusters || snpClusters.status === QcStatus.good) {
return undefined
}
const { score, clusteredSNPs, totalSNPs, status } = snpClusters
let message = t('Mutation clusters found')
if (status === QcStatus.bad) {
message = t('Too many mutation clusters found')
}
return t('{{message}}. Seen {{nClusters}} mutation clusters with total of {{total}} mutations. QC score: {{score}}', {
message,
total: totalSNPs,
nClusters: clusteredSNPs.length,
score: round(score),
})
}
Example #8
Source File: index.tsx From nebula-dashboard with Apache License 2.0 | 6 votes |
updateChart = () => {
const { data } = this.state;
if (data.length > 0) {
const total = last(data)!.count;
const chartData = data.slice(0, data.length - 1).map(item => ({
type: item.name,
value: round(item.count / total, 2),
}));
this.chartInstance.data(chartData).render();
}
};
Example #9
Source File: index.tsx From nebula-dashboard with Apache License 2.0 | 6 votes |
updateChart = () => {
const { data } = this.state;
if (data.length > 0) {
const total = sum(data.map(i => i.count));
const chartData = data.map(item => ({
type: item.name,
value: round(item.count / total, 2),
}));
this.chartInstance.data(chartData).render();
}
};
Example #10
Source File: index.tsx From nebula-dashboard with Apache License 2.0 | 6 votes |
updateChart = () => {
const { data } = this.props;
const versionList = groupBy(data, 'version');
const chartData = Object.keys(versionList).map(key => ({
type: key,
value: round(versionList[key].length / data.length, 2),
}));
this.chartInstance.data(chartData).render();
};
Example #11
Source File: analyzer.ts From CIAnalyzer with MIT License | 5 votes |
secRound = (sec: number) => {
const PRECISION = 3
return round(sec, PRECISION)
}
Example #12
Source File: machine-table.tsx From erda-ui with GNU Affero General Public License v3.0 | 5 votes |
DoubleProgressItem = ({ usedPercent, requestPercent, usage, request, total, unit, unitType }: any) => {
const requestEle = (
<Tooltip
key="request"
placement="top"
title={
unitType
? `${i18n.t('cmp:allocation')}: ${getFormatter(unitType).format(request)} / ${getFormatter(unitType).format(
total,
)}`
: `${i18n.t('cmp:allocation')}: ${round(request, 2)} ${unit} / ${round(total, 2)} ${unit}`
}
>
<div
className="machine-percent-bar machine-percent-bottom-bar cursor-pointer"
style={{ width: `${requestPercent}%` }}
>
<span>{`${requestPercent}%`}</span>
</div>
</Tooltip>
);
const usedEle = (
<Tooltip
key="used"
placement="top"
title={
unitType
? `${i18n.t('usage')}${getFormatter(unitType).format(usage)} / ${getFormatter(unitType).format(total)}`
: `${i18n.t('usage')}${round(usage, 2)} ${unit} / ${round(total, 2)} ${unit}`
}
>
<div
className={classNames({
'cursor-pointer': true,
'machine-percent-bar': true,
'machine-percent-top-bar': true,
'machine-percent-error-bar': usedPercent >= requestPercent,
})}
style={{ width: `${usedPercent}%` }}
>
<span>{`${usedPercent}%`}</span>
</div>
</Tooltip>
);
return (
<div className="machine-percent double-machine-percent">
{usedPercent > requestPercent ? [usedEle, requestEle] : [requestEle, usedEle]}
</div>
);
}
Example #13
Source File: service-list.tsx From erda-ui with GNU Affero General Public License v3.0 | 5 votes |
countPercent = (used: number, total: number) => {
const percent = total && round((used / total) * 100, 2);
const statusClass = compareClass(percent || 0);
return { percent, statusClass };
}
Example #14
Source File: ListOfQcIsuues.tsx From nextclade with MIT License | 5 votes |
export function ListOfQcIssues({ qc }: ListOfQcIssuesProps) {
const { t } = useTranslation()
const {
overallScore,
overallStatus,
privateMutations,
snpClusters,
mixedSites,
missingData,
frameShifts,
stopCodons,
} = qc
const rules = [
{ name: t('Missing Data'), shortName: 'N', value: missingData, message: formatQCMissingData(t, missingData) }, // prettier-ignore
{ name: t('Mixed Sites'), shortName: 'M', value: mixedSites, message: formatQCMixedSites(t, mixedSites) }, // prettier-ignore
{ name: t('Private Mutations'), shortName: 'P', value: privateMutations, message: formatQCPrivateMutations(t, privateMutations) }, // prettier-ignore
{ name: t('Mutation Clusters'), shortName: 'C', value: snpClusters, message: formatQCSNPClusters(t, snpClusters) }, // prettier-ignore
{ name: t('Frame shifts'), shortName: 'F', value: frameShifts, message: formatQCFrameShifts(t, frameShifts) }, // prettier-ignore
{ name: t('Stop codons'), shortName: 'S', value: stopCodons, message: formatQCStopCodons(t, stopCodons) }, // prettier-ignore
].filter((value) => notUndefined(value))
const issues = rules.map(({ name, shortName, value, message }) => {
if (!value) {
return undefined
}
return (
<QcListItem key={name} status={value.status} text={shortName}>
<div>
<span>
<b>{name}</b>
</span>
<span>{': '}</span>
<span>{value.status}</span>
</div>
{message ?? t('No issues')}
</QcListItem>
)
})
return (
<>
<div>{t('Overall QC score: {{score}}', { score: round(overallScore) })}</div>
<div>{t('Overall QC status: {{status}}', { status: overallStatus })}</div>
<div>
{t('Detailed QC assessment:')}
<QcList>{issues}</QcList>
</div>
</>
)
}
Example #15
Source File: index.tsx From erda-ui with GNU Affero General Public License v3.0 | 4 votes |
ClusterDashboard = () => {
const [filterGroup, groupInfos, unGroupInfo, clusterList, selectedGroups] = clusterDashboardStore.useStore((s) => [
s.filterGroup,
s.groupInfos,
s.unGroupInfo,
s.clusterList,
s.selectedGroups,
]);
const { getFilterTypes, getGroupInfos } = clusterDashboardStore.effects;
const { setSelectedGroups, clearClusterList } = clusterDashboardStore.reducers;
const [loading] = useLoading(clusterDashboardStore, ['getGroupInfos']);
const [groupContainerWidthHolder, groupContainerWidth] = useComponentWidth();
const [machineContainerWidthHolder, machineContainerWidth] = useComponentWidth();
const [groupGridClass, setGroupGridClass] = useState();
const [machineGridClass, setMachineGridClass] = useState('machine-list-ct-g4');
const [selectedFilters, setSelectedFilters] = useState();
const [selectedColour, setSelectedColour] = useState('load');
const [activeMachine, setActiveMachine] = useState({ ip: '', clusterName: '' });
const [activeMachineTab, setActiveMachineTab] = useState();
const [activeGroup, setActiveGroup] = useState('');
const [groupMap, setGroupMap] = useState({});
const [allMachines, setAllMachines] = useState();
const [activeMachineList, setActiveMachineList] = useState();
const [colorMark, setColorMark] = React.useState('load');
const [isClickState, setIsClickState] = React.useState(false);
const [isMounted, setIsMounted] = React.useState(false);
useMount(async () => {
await getFilterTypes();
setIsMounted(true);
});
useUnmount(() => {
setSelectedGroups([]);
clearClusterList();
});
useEffect(() => {
if (!isEmpty(clusterList)) {
getGroupInfos({
groups: selectedGroups,
clusters: map(clusterList, (cl: any) => ({ clusterName: cl.name })),
filters: getFilters(selectedFilters),
});
}
}, [clusterList, getGroupInfos, selectedFilters, selectedGroups]);
const unitGroups = React.useMemo(() => {
const tempList = [...selectedGroups, '', ''].slice(0, 2);
return tempList.map((item) => UNIT_MAP[item] || '');
}, [selectedGroups]);
useEffect(() => {
const groupInfoMap = reduce(
groupInfos,
(result, item) => {
let subResult = {};
if (item.groups) {
subResult = reduce(
item.groups,
(acc, subItem) => ({
...acc,
[`${item.name + unitGroups[0]}-${subItem.name + unitGroups[1]}`]: subItem,
}),
{},
);
}
return {
...result,
...subResult,
[item.name + unitGroups[0]]: item,
};
},
{},
);
setGroupMap(groupInfoMap);
}, [groupInfos, unitGroups]);
useEffect(() => {
if (isEmpty(groupInfos)) {
setAllMachines(unGroupInfo.machines || []);
} else {
let results: any[] = [];
const getAllMachines = (groups: ORG_DASHBOARD.IGroupInfo[]) => {
forEach(groups, ({ groups: subGroups, machines }: ORG_DASHBOARD.IGroupInfo) => {
if (isEmpty(subGroups)) {
results = [...results, ...(machines || [])];
} else {
getAllMachines(subGroups || []);
}
});
};
getAllMachines(groupInfos);
setAllMachines(results);
}
}, [unGroupInfo.machines, groupInfos]);
useEffect(() => {
if (!activeGroup) {
return setActiveMachineList(allMachines);
}
let machineList: any[] = [];
if (isEmpty(groupMap[activeGroup])) {
setActiveMachineList(machineList);
return;
}
const { groups, machines } = groupMap[activeGroup];
if (!isEmpty(groups)) {
machineList = reduce(groups, (result, { machines: subMachines }) => [...result, ...subMachines], []);
} else {
machineList = machines || [];
}
setActiveMachineList(machineList);
}, [activeGroup, allMachines, groupMap]);
useEffect(() => {
if (groupContainerWidth !== Infinity) {
setGroupGridClass(getGroupGridClass(groupContainerWidth as number));
}
}, [groupContainerWidth]);
useEffect(() => {
if (machineContainerWidth !== Infinity) {
setMachineGridClass(getMachineGridClass(machineContainerWidth as number));
}
}, [machineContainerWidth]);
const getFilters = (filters: string[]) => {
const filterMap = {};
forEach(filters, (item) => {
const [key, value] = item.split(':');
filterMap[key] = filterMap[key] ? [...filterMap[key], value] : [value];
});
return map(filterMap, (values, key) => ({ key, values }));
};
const getMachineColourValue = ({
cpuUsage,
cpuAllocatable,
memUsage,
memAllocatable,
diskUsage,
diskTotal,
cpuRequest,
memRequest,
load5,
}: any) => {
const getPercent = (used: number, total: number) => round((used / total) * 100, 2);
const machineColourNameMap = {
load: {
name: COLOUR_MAP.load,
value: load5,
},
cpu: {
name: COLOUR_MAP.cpu,
value: getPercent(cpuUsage, cpuAllocatable),
},
mem: {
name: COLOUR_MAP.mem,
value: getPercent(memUsage, memAllocatable),
},
disk: {
name: COLOUR_MAP.disk,
value: getPercent(diskUsage, diskTotal),
},
scheduledCPU: {
name: COLOUR_MAP.scheduledCPU,
value: getPercent(cpuRequest, cpuAllocatable),
},
scheduledMEM: {
name: COLOUR_MAP.scheduledMEM,
value: getPercent(memRequest, memAllocatable),
},
};
return machineColourNameMap[selectedColour];
};
const getMachineColourClass = (machineInfo: Partial<ORG_MACHINE.IMachine>) =>
getDegreeColourClass(getMachineColourValue(machineInfo).value, selectedColour);
const handleChangeGroups = (groups: string[]) => {
if (groups.length > 2) {
message.warning(i18n.t('cmp:up to 2 optional groups'));
return;
}
setActiveGroup('');
setSelectedGroups(groups);
};
const handleChangeFilters = (filters: string[]) => {
setSelectedFilters(filters);
};
const handleActiveMachine = (record: any, key?: string) => {
setActiveMachine(record);
setActiveMachineTab(key);
};
const getMachineGroupContent = (item: ORG_DASHBOARD.IGroupInfo) => {
if (isEmpty(item)) return null;
const { name, displayName, machines, metric, groups, clusterStatus }: ORG_DASHBOARD.IGroupInfo = item;
const groupName = displayName || name;
const activeGroupItem = clusterList.find((c) => c.name === name);
const activeGroupDisplayName = activeGroupItem?.displayName || activeGroupItem?.name;
const {
machines: machineNum,
cpuUsage,
cpuAllocatable,
memUsage,
memAllocatable,
diskUsage,
diskTotal,
} = metric || {};
const isClusterGroup = selectedGroups?.[0] === 'cluster';
return (
<Holder when={isEmpty(machines) && isEmpty(groups)}>
<IF check={selectedGroups.length}>
<div className="group-header flex justify-between items-center">
<h3
className={`group-title ${isClusterGroup ? 'cluster-group' : ''}`}
onClick={() => {
isClusterGroup && goTo(goTo.pages.cmpClustersDetail, { clusterName: name });
}}
>
{activeGroupDisplayName || groupName + unitGroups[0]}
</h3>
<IF check={activeGroup}>
<span className="group-unactived-op hover-active">
<CustomIcon type="shink" />
</span>
<IF.ELSE />
<span className="group-actived-op hover-active">
<CustomIcon type="grow" />
</span>
</IF>
</div>
</IF>
<p className="group-info">
<span>
{i18n.t('Machines')}:{machineNum}
</span>
<span>CPU:{round((cpuUsage / cpuAllocatable) * 100, 2)}%</span>
<span>
{i18n.t('memory')}:{round((memUsage / memAllocatable) * 100, 2)}%
</span>
<span>
{i18n.t('Disk')}:{round((diskUsage / diskTotal) * 100, 2)}%
</span>
</p>
<IF check={!isEmpty(groups)}>
<SubMachineGroup
groups={groups}
isClusterGroup={selectedGroups?.[1] === 'cluster'}
unitGroups={unitGroups}
groupName={groupName}
activeMachine={activeMachine}
setActiveMachine={setActiveMachine}
setActiveGroup={setActiveGroup}
getMachineColourClass={getMachineColourClass}
getMachineColourValue={getMachineColourValue}
/>
<IF.ELSE />
<div
className={classnames({
'machine-list-ct': true,
[`${machineGridClass}`]: true,
'machine-actived': !!activeMachine.ip,
})}
>
{map(machines, ({ ip, clusterName, ...rest }) => {
const { name: colourName, value: colourValue } = getMachineColourValue(rest);
return (
<Tooltip
placement="bottom"
title={`${ip} (${colourName}: ${colourValue}%)`}
key={`${clusterName}-${ip}`}
>
<div
className={classnames({
'machine-item': true,
'hover-active': true,
[`${getMachineColourClass(rest)}`]: true,
active: ip === activeMachine.ip && clusterName === activeMachine.clusterName,
})}
onClick={(e) => {
e.stopPropagation();
setActiveMachine({ ip, clusterName, ...rest });
}}
>
<span
className="cancel-active"
onClick={(e) => {
e.stopPropagation();
setActiveMachine({});
}}
>
<CustomIcon type="gb" />
</span>
</div>
</Tooltip>
);
})}
</div>
</IF>
</Holder>
);
};
const getMachineGroupWrapper = (item?: ORG_DASHBOARD.IGroupInfo, gridClass?: any) => {
return (
<div
key={item && item.name ? item.name : ''}
className={classnames({
'machine-group': true,
'actived-machine-group': !!activeGroup,
'no-machine-group': isEmpty(selectedGroups) || isEmpty(item),
})}
onClick={(e) => {
if (isEmpty(selectedGroups) || isEmpty(item)) return;
e.stopPropagation();
setIsClickState(!isClickState);
setActiveGroup(activeGroup ? '' : (item && item.name ? item.name : '') + unitGroups[0]);
}}
>
<Holder when={isEmpty(item) || !gridClass}>{getMachineGroupContent(item)}</Holder>
{machineContainerWidthHolder}
</div>
);
};
const Bottom = React.useMemo(
() => (
<IF check={activeMachine.ip}>
<div className="content-title mb-2">{activeMachine.ip}</div>
<MachineTabs activeMachine={activeMachine} activeMachineTab={activeMachineTab} />
<IF.ELSE />
<GroupTabs
activedGroup={activeGroup}
machineList={activeMachineList}
onActiveMachine={handleActiveMachine}
isClickState={isClickState}
/>
</IF>
),
[activeMachine, activeMachineList, activeMachineTab, activeGroup, isClickState],
);
const handleOptionMouseEnter = (value: string, e: React.MouseEvent<HTMLDivElement>) => {
e.stopPropagation();
setColorMark(value);
};
const handleSelectedColour = (val: string) => {
setSelectedColour(val);
setColorMark(val);
};
return (
<>
{groupContainerWidthHolder}
<Choose>
<When condition={!clusterList.length && !loading && isMounted}>
<div className="flex flex-col justify-center items-center h-full">
<div className="font-medium text-2xl mb-2">{i18n.t('cmp:quick start')}</div>
<div className="text-desc">
{interpolationComp(
i18n.t(
'cmp:no cluster currently exists, you can click <CreateClusterLink />, you can also view <DocumentationHref /> to learn more',
),
{
CreateClusterLink: (
<Link to={`${goTo.resolve.cmpClusters()}?autoOpen=true`}>{i18n.t('cmp:create cluster')}</Link>
),
DocumentationHref: (
<a href={DOC_CMP_CLUSTER_CREATE} target="__blank">
{i18n.t('documentation')}
</a>
),
},
)}
</div>
<img className="w-80 h-80" src={noClusterPng} />
</div>
</When>
<Otherwise>
<div className="cluster-dashboard-top mb-4">
<div className="filter-group-ct mb-4">
<Row gutter={20}>
<Col span={8} className="filter-item flex justify-between items-center">
<div className="filter-item-label">{i18n.t('Group')}</div>
<Select
value={selectedGroups}
placeholder={firstCharToUpper(i18n.t('cmp:no more than 2 groups'))}
className="filter-item-content"
style={{ width: '100%' }}
showArrow
allowClear
mode="multiple"
onChange={handleChangeGroups}
>
{map(
filter(filterGroup, ({ key: group }) => ['cpus', 'mem', 'cluster'].includes(group)),
({ key, name }) => (
<Option key={key}>{name}</Option>
),
)}
</Select>
</Col>
<Col span={8} className="filter-item flex justify-between items-center">
<div className="filter-item-label">{i18n.t('Filter')}</div>
<TreeSelect
className="filter-item-content"
style={{ width: '100%' }}
value={selectedFilters}
dropdownStyle={{ maxHeight: 400, overflow: 'auto' }}
allowClear
multiple
// treeDefaultExpandAll
placeholder={firstCharToUpper(i18n.t('cmp:input to search'))}
onChange={handleChangeFilters}
>
{map(filterGroup, ({ name, key, values, unit, prefix }: ORG_DASHBOARD.IFilterType) => (
<TreeNode className="filter-item-node" title={`${name}(${key})`} key={key} value={key} disabled>
{map(values, (subItem: any) => (
<TreeNode
value={`${key}:${subItem}`}
title={`${prefix ? `${prefix}:` : ''}${subItem} ${unit || ''}`}
key={`${key}-${subItem}`}
/>
))}
</TreeNode>
))}
</TreeSelect>
</Col>
<Col span={8} className="filter-item flex justify-between items-center">
<div className="filter-item-label">{i18n.t('Colour')}</div>
<Select
className="filter-item-content"
style={{ width: '100%' }}
value={selectedColour}
onChange={handleSelectedColour}
dropdownRender={(menu) => {
return (
<div className="colour-select-dropdown">
<div className="menu">{menu}</div>
<div className="comments">
<ul className="colour-comment-list">
{map(DEGREE_COLOUR_MAP[colorMark], (value, color) => (
<li className="colour-comment-item flex justify-between items-center" key={color}>
<span className="colour-comment-value">{value.text}</span>
<div className={`color-block ${color}`} />
</li>
))}
</ul>
</div>
</div>
);
}}
>
{map(COLOUR_MAP, (name, key) => (
<Option value={key} key={key}>
<div
onMouseEnter={(e) => {
handleOptionMouseEnter(key, e);
}}
>
{name}
</div>
</Option>
))}
</Select>
</Col>
</Row>
</div>
<Spin spinning={!groupGridClass || loading}>
<Choose>
<When condition={isEmpty(selectedGroups) || isEmpty(groupInfos)}>
<div className="machine-group-ct machine-group-ct-g1">
{getMachineGroupWrapper(unGroupInfo, groupGridClass)}
</div>
</When>
<Otherwise>
<div className={`machine-group-ct ${activeGroup ? 'machine-group-ct-g1' : groupGridClass}`}>
<Choose>
<When condition={!!activeGroup}>
{getMachineGroupWrapper(groupMap[activeGroup], groupGridClass)}
</When>
<When condition={!groupGridClass}>{getMachineGroupWrapper()}</When>
<Otherwise>{map(groupInfos, (item) => getMachineGroupWrapper(item, true))}</Otherwise>
</Choose>
</div>
</Otherwise>
</Choose>
</Spin>
</div>
<div className="cluster-dashboard-bottom">{Bottom}</div>
</Otherwise>
</Choose>
</>
);
}
Example #16
Source File: service-list.tsx From erda-ui with GNU Affero General Public License v3.0 | 4 votes |
function ServiceList({
containerList,
serviceList,
depth,
into,
haveMetrics,
onReload,
haveHost = true,
haveStatus = true,
slot,
extraQuery,
}: IProps) {
const [renderOp, drawer] = useInstanceOperation<IInstance>({
log: true,
console: true,
monitor: true,
getProps(type, record) {
return {
console: {
host: record.host_private_addr || record.host,
clusterName: extraQuery.filter_cluster_name,
},
log: {
fetchApi: '/api/orgCenter/logs',
extraQuery: { clusterName: record.clusterName },
},
monitor: {
api: '/api/orgCenter/metrics',
extraQuery,
},
}[type];
},
});
let list = [];
let cols = [];
if (depth && depth < 5) {
list = serviceList;
// 设一个id作为rocord的key,避免切换rowKey时新数据还没拿到引起rowKey和record的key不一致
list.forEach((item: any, i: number) => {
set(item, 'id', item.id || item.name || i);
});
const titleMap = ['', 'PROJECT', 'APPLICATION', 'RUNTIME', 'SERVICE', 'CONTAINER'];
const titleCnMap = {
'': '',
PROJECT: i18n.t('project'),
APPLICATION: i18n.t('application'),
RUNTIME: i18n.t('App instance'),
SERVICE: i18n.t('Microservice'),
CONTAINER: 'CONTAINER',
};
const iconMap = ['', 'project', 'wenjianjia', 'fengchao', 'atom'];
cols = [
{
title: titleCnMap[titleMap[depth]],
dataIndex: 'id',
key: 'id',
// width: 320,
render: (text: string, record: any) => (
<span className="font-bold hover-table-text" onClick={() => into({ q: text, name: record.name })}>
<CustomIcon type={iconMap[depth]} />
{record.name}
</span>
),
},
{
title: i18n.t('Number of instances'),
dataIndex: 'instance',
key: 'instance',
width: 176,
},
{
title: 'CPU',
dataIndex: 'cpu',
key: 'cpu',
width: 125,
sorter: (a: any, b: any) => {
if (!haveMetrics) return Number(a.cpu) - Number(b.cpu);
const use_a = getMetricsInfo(a, 'cpuUsagePercent') || 0;
const use_b = getMetricsInfo(b, 'cpuUsagePercent') || 0;
return Number(use_a / a.cpu) - Number(use_b / b.cpu);
},
render: (total: number, record: any) => {
if (!haveMetrics) return `${total} ${i18n.t('core')}`;
const parsedTotal = total * 1000;
const used = +(getMetricsInfo(record, 'cpuUsagePercent') || 0).toFixed(4) * 1000;
const { percent, statusClass } = countPercent(used, parsedTotal);
return ProgressItem(percent, round(used, 2), parsedTotal, i18n.t('millicore'), statusClass);
},
},
{
title: i18n.t('memory'),
dataIndex: 'memory',
key: 'memory',
width: 125,
sorter: (a: any, b: any) => {
if (!haveMetrics) return Number(a.memory) - Number(b.memory);
const use_a = getMetricsInfo(a, 'memUsage') || 0;
const use_b = getMetricsInfo(b, 'memUsage') || 0;
return Number(use_a / 1048576 / a.memory) - Number(use_b / 1048576 / b.memory);
},
render: (total: number, record: any) => {
if (!haveMetrics) return `${total} MB`;
const used = +((getMetricsInfo(record, 'memUsage') || 0) / 1048576).toFixed(2);
const { percent, statusClass } = countPercent(used, total);
return ProgressItem(percent, used, total, 'MB', statusClass);
},
},
{
title: i18n.t('Disk'),
dataIndex: 'disk',
key: 'disk',
width: 125,
sorter: (a: any, b: any) => Number(a.disk) - Number(b.disk),
render: (size: string) => getFormatter('STORAGE', 'MB').format(size),
},
{
title: i18n.t('Status'),
dataIndex: 'unhealthy',
width: 100,
align: 'center',
render: (num: number) => (
<span>
<IF check={!!num}>
<span>
<Badge status="error" /> {num}
</span>
<IF.ELSE />
<Badge status="success" />
</IF>
</span>
),
},
];
// if (includes(['RUNTIME', 'SERVICE'], titleMap[depth])) { // runtime和service级别,需要展示状态
// (cols as any[]).push({
// title: '状态',
// dataIndex: 'status',
// width: 100,
// align: 'center',
// render: (text: string) => {
// const stateObj = get(statusConfig, `${titleMap[depth]}.${text}`) || statusConfig.Unknown;
// return <Tooltip title={text || 'Unknown'}><Badge status={stateObj.state} /></Tooltip>;
// },
// });
// }
} else {
list = containerList;
cols = [
{
title: 'IP',
key: 'ip_addr',
width: 120,
sorter: (a: any, b: any) =>
Number((a.ip_addr || a.ipAddress || '').replace(/\./g, '')) -
Number((b.ip_addr || b.ipAddress || '').replace(/\./g, '')),
render: (record: any) => record.ip_addr || record.ipAddress || i18n.t('cmp:no ip address'),
},
haveHost
? {
title: i18n.t('cmp:Host address'),
key: 'host_private_addr',
width: 120,
render: (record: any) => record.host_private_addr || record.host || i18n.t('cmp:no host address'),
}
: null,
{
title: i18n.t('Image'),
key: 'image',
// width: 400,
className: 'item-image',
render: (record: any) => {
const text = record.image_name || record.image;
if (!text) {
return null;
}
return (
<Tooltip title={`${i18n.t('click to copy')}:${text}`} overlayClassName="tooltip-word-break">
<span
className="image-name for-copy-image w-[400px]"
data-clipboard-tip={i18n.t('Image name')}
data-clipboard-text={text}
>
{getImageText(text)}
</span>
</Tooltip>
);
},
},
{
title: 'CPU',
dataIndex: 'cpu',
key: 'cpu',
width: 120,
sorter: (a: any, b: any) => {
if (!haveMetrics) return Number(a.cpu) - Number(b.cpu);
const use_a = getMetricsInfo(a, 'cpuUsagePercent') || 0;
const use_b = getMetricsInfo(b, 'cpuUsagePercent') || 0;
return Number(use_a / a.cpu) - Number(use_b / b.cpu);
},
render: (total: number, record: any) => {
if (!haveMetrics) return total;
const parsedTotal = total * 1000;
const used = +(getMetricsInfo(record, 'cpuUsagePercent') || 0).toFixed(4) * 1000;
const { percent, statusClass } = countPercent(used, parsedTotal);
return ProgressItem(percent, round(used, 2), parsedTotal, i18n.t('millicore'), statusClass);
},
},
{
title: i18n.t('memory'),
dataIndex: 'memory',
key: 'memory',
width: 120,
sorter: (a: any, b: any) => {
if (!haveMetrics) return Number(a.memory) - Number(b.memory);
const use_a = getMetricsInfo(a, 'memUsage') || 0;
const use_b = getMetricsInfo(b, 'memUsage') || 0;
return Number(use_a / 1048576 / a.memory) - Number(use_b / 1048576 / b.memory);
},
render: (total: number, record: any) => {
if (!haveMetrics) return getFormatter('STORAGE', 'MB').format(total);
const used = getMetricsInfo(record, 'memUsage') || 0;
const { percent, statusClass } = countPercent(used, total);
return ProgressItem(percent, used, total, '', statusClass);
},
},
{
title: i18n.t('Disk'),
dataIndex: 'disk',
key: 'disk',
width: 120,
sorter: (a: any, b: any) => Number(a.disk) - Number(b.disk),
render: (size: number) => getFormatter('STORAGE', 'MB').format(size),
},
// TODO: 集群组件目前无状态,3.5暂时去除,后续提供后打开
haveStatus
? {
title: i18n.t('Status'),
dataIndex: 'status',
key: 'status',
width: 100,
align: 'center',
render: (text: string) => {
const stateObj = get(statusConfig, `CONTAINER.${text}`) || statusConfig.Unknown;
return (
<Tooltip title={text || 'Unknown'}>
<Badge status={stateObj.state} />
</Tooltip>
);
},
}
: null,
{
title: i18n.t('operations'),
key: 'operation',
width: 180,
render: renderOp,
},
];
if (depth === 3) {
cols.splice(2, {
title: i18n.t('Number of instances'),
dataIndex: 'instance',
key: 'instance',
} as any);
}
}
remove(cols as any, (item) => item === null);
return (
<div className="service-table">
<ErdaTable
slot={slot}
rowKey={(record: any, i: number) => `${i}${record.id}`}
pagination={false}
columns={cols as Array<ColumnProps<any>>}
dataSource={list}
onReload={onReload}
scroll={{ x: 1100 }}
/>
<Copy selector=".for-copy-image" />
{drawer}
</div>
);
}