Skip to content

Commit

Permalink
feat(common): add card list and refactor msp overview (#2268)
Browse files Browse the repository at this point in the history
* feat(common): add card list and refactor msp overview

feat(common): add card list and refactor msp overview

* feat(common): add empty holdere

feat(common): adjust shadow color
  • Loading branch information
Zero-Rock authored Dec 13, 2021
1 parent 30fc6d8 commit 1c59a1c
Show file tree
Hide file tree
Showing 5 changed files with 209 additions and 77 deletions.
120 changes: 120 additions & 0 deletions shell/app/common/components/card-list/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
// Copyright (c) 2021 Terminus, Inc.
//
// This program is free software: you can use, redistribute, and/or modify
// it under the terms of the GNU Affero General Public License, version 3
// or later ("AGPL"), as published by the Free Software Foundation.
//
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.

import React from 'react';
import { Col, Row, Spin } from 'antd';
import { RowProps } from 'antd/es/row';
import { ColProps } from 'antd/es/col';
import classnames from 'classnames';
import EmptyHolder from 'common/components/empty-holder';

interface CardColumnsProps<T> {
dataIndex: keyof T;
colProps?: ColProps;
render?: (text: any, record: T, index: number) => React.ReactNode;
children?: {
rowProps?: RowProps;
columns: CardColumnsProps<T>[];
};
}

interface IProps<T = Record<string, any>> {
size?: 'default' | 'small' | 'large';
loading?: boolean;
rowKey?: string | ((record: T) => string);
rowClick?: (record: T) => void;
dataSource: T[];
slot?: React.ReactNode;
rowClassName?: string;
columns: CardColumnsProps<T>[];
emptyHolder?: React.ReactNode;
}

const renderChild = <T,>(record: T, columns: CardColumnsProps<T>[], index: number) => {
return columns.map((column) => {
let nodes: React.ReactNode = record[column.dataIndex];
if (column.render) {
nodes = column.render(nodes, record, index);
}
if (column.children?.columns.length) {
nodes = (
<Row className="flex-1" gutter={8} {...column.children.rowProps}>
{renderChild<T>(record, column.children.columns, index)}
</Row>
);
}
return (
<Col key={column.dataIndex as string} span={12} {...column.colProps}>
{nodes}
</Col>
);
});
};

const CardList = <T,>({
loading,
dataSource,
rowKey = 'key',
rowClassName,
columns,
rowClick,
slot,
size = 'default',
emptyHolder,
}: IProps<T>) => {
return (
<div className="card-list flex flex-1 flex-col bg-white shadow pb-2">
<div className="card-list-header px-4 py-2 h-12 bg-lotion flex justify-between items-center">
<div>{slot}</div>
</div>
<div className="card-list-body px-2 mt-2">
<Spin spinning={!!loading}>
{dataSource.length
? dataSource.map((record, index) => {
let rowId;
if (typeof rowKey === 'function') {
rowId = rowKey(record);
} else {
rowId = record[rowKey];
}
const rowClass = classnames(
'card-shadow mb-4 mx-2 px-4 rounded-sm transition-all duration-300 hover:bg-grey',
{
'py-8': size === 'large',
'py-6': size === 'default',
'py-4': size === 'small',
[rowClassName as string]: !!rowClassName,
'cursor-pointer': rowClick,
},
);
return (
<Row
onClick={() => {
rowClick?.(record);
}}
key={rowId}
className={rowClass}
>
{renderChild<T>(record, columns, index)}
</Row>
);
})
: emptyHolder || <EmptyHolder relative />}
</Spin>
</div>
</div>
);
};

export default CardList;
export { CardColumnsProps };
2 changes: 2 additions & 0 deletions shell/app/common/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -109,3 +109,5 @@ export { default as Intro } from './components/intro';
export { default as ErdaAlert } from './components/erda-alert';
export { default as Badge } from './components/badge';
export type { IBadgeProps } from './components/badge';
export { default as CardList } from './components/card-list';
export type { CardColumnsProps } from './components/card-list';
158 changes: 84 additions & 74 deletions shell/app/modules/msp/pages/micro-service/overview.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,9 @@
// along with this program. If not, see <http://www.gnu.org/licenses/>.

import React from 'react';
import { Col, Input, Row, Spin, Tag } from 'antd';
import { Input, Tag } from 'antd';
import { useUpdate } from 'common/use-hooks';
import { getMspProjectList } from 'msp/services';
import EmptyHolder from 'common/components/empty-holder';
import ErdaIcon from 'common/components/erda-icon';
import { fromNow, goTo } from 'common/utils';
import { debounce, last } from 'lodash';
Expand All @@ -28,6 +27,7 @@ import middleImg from 'app/images/msp/microservice-governance-middle.svg';
import bottomImg from 'app/images/msp/microservice-governance-bottom.svg';
import backgroundImg from 'app/images/msp/microservice-governance-background.svg';
import decorationImg from 'app/images/msp/microservice-governance-decoration.svg';
import CardList, { CardColumnsProps } from 'common/components/card-list';
import i18n from 'i18n';
import './overview.scss';

Expand Down Expand Up @@ -56,6 +56,29 @@ const iconMap: {
},
};

const metric: { dataIndex: keyof MS_INDEX.IMspProject; name: string; renderData: (data: any) => React.ReactNode }[] = [
{
dataIndex: 'relationship',
name: i18n.t('env'),
renderData: (data: MS_INDEX.IMspRelationship[]) => data.length,
},
{
dataIndex: 'serviceCount',
name: i18n.t('service'),
renderData: (data: number) => data ?? 0,
},
{
dataIndex: 'last24hAlertCount',
name: i18n.t('msp:last 1 day alarm'),
renderData: (data: number) => data ?? 0,
},
{
dataIndex: 'lastActiveTime',
name: i18n.t('msp:last active time'),
renderData: (data: number) => (data ? fromNow(data) : '-'),
},
];

const Overview = () => {
const [{ data, loading, filterKey }, updater] = useUpdate<IState>({
data: [],
Expand Down Expand Up @@ -95,6 +118,52 @@ const Overview = () => {
return data.filter((item) => item.displayName.toLowerCase().includes(filterKey));
}, [data, filterKey]);

const columns: CardColumnsProps<MS_INDEX.IMspProject>[] = [
{
dataIndex: 'displayName',
colProps: {
className: 'flex items-center',
},
render: (displayName: string, { logo, desc, type }) => {
const { icon, color, tag } = iconMap[type];
return (
<>
<div className="w-14 h-14 mr-2">
{logo ? <img src={logo} width={56} height={56} /> : <ErdaIcon type={icon} size={56} />}
</div>
<div>
<p className="mb-0 font-medium text-xl leading-8">{displayName}</p>
<Tag className="mb-0.5 text-xs leading-5 border-0" color={color}>
{tag}
</Tag>
<div className="text-xs leading-5 desc">{desc || i18n.t('no description yet')}</div>
</div>
</>
);
},
},
{
dataIndex: 'id',
colProps: {
className: 'flex items-center',
},
children: {
columns: metric.map((item) => ({
dataIndex: item.dataIndex,
colProps: {
span: 6,
},
render: (text) => (
<>
<p className="mb-0 text-xl leading-8 font-number">{item.renderData(text)}</p>
<p className="mb-0 text-xs leading-5 desc">{item.name}</p>
</>
),
})),
},
},
];

return (
<div className="msp-overview p-6 flex flex-col pt-0">
<div className="msp-overview-header relative overflow-hidden flex content-center justify-center pl-4 flex-col">
Expand All @@ -120,87 +189,28 @@ const Overview = () => {
<img src={decorationImg} className="absolute decoration-img top" />
</div>
</div>
<div className="flex flex-1 flex-col min-h-0 bg-white shadow pb-2">
<div className="px-4 pt-2 bg-lotion">
<CardList<MS_INDEX.IMspProject>
rowKey="id"
size="large"
loading={loading}
columns={columns}
dataSource={list}
rowClick={({ relationship, id }) => {
handleClick(relationship, id);
}}
slot={
<Input
prefix={<ErdaIcon type="search1" />}
bordered={false}
allowClear
placeholder={i18n.t('msp:search by project name')}
className="bg-hover-gray-bg mb-3 w-72"
className="bg-hover-gray-bg w-72"
onChange={(e) => {
handleSearch(e.target.value);
}}
/>
</div>
<div className="px-2 flex-1 overflow-y-auto">
<Spin spinning={loading}>
{list.length ? (
list.map(
({
type,
desc,
displayName,
id,
relationship,
serviceCount,
last24hAlertCount,
lastActiveTime,
logo,
}) => {
const { icon, color, tag } = iconMap[type];
return (
<Row
key={id}
className="project-item card-shadow mb-2 mx-2 px-4 flex py-8 rounded-sm cursor-pointer transition-all duration-300 hover:bg-grey"
onClick={() => {
handleClick(relationship, id);
}}
>
<Col span={12} className="flex items-center">
<div className="w-14 h-14 mr-2">
{logo ? <img src={logo} width={56} height={56} /> : <ErdaIcon type={icon} size={56} />}
</div>
<div>
<p className="mb-0 font-medium text-xl leading-8">{displayName}</p>
<Tag className="mb-0.5 text-xs leading-5 border-0" color={color}>
{tag}
</Tag>
<div className="text-xs leading-5 desc">{desc || i18n.t('no description yet')}</div>
</div>
</Col>
<Col span={12} className="flex items-center">
<Row gutter={8} className="flex-1">
<Col span={6}>
<p className="mb-0 text-xl leading-8 font-number">{relationship.length}</p>
<p className="mb-0 text-xs leading-5 desc">{i18n.t('env')}</p>
</Col>
<Col span={6}>
<p className="mb-0 text-xl leading-8 font-number">{serviceCount ?? 0}</p>
<p className="mb-0 text-xs leading-5 desc">{i18n.t('service')}</p>
</Col>
<Col span={6}>
<p className="mb-0 text-xl leading-8 font-number">{last24hAlertCount ?? 0}</p>
<p className="mb-0 text-xs leading-5 desc">{i18n.t('msp:last 1 day alarm')}</p>
</Col>
<Col span={6}>
<p className="mb-0 text-xl leading-8 font-number">
{lastActiveTime ? fromNow(lastActiveTime) : '-'}
</p>
<p className="mb-0 text-xs leading-5 desc">{i18n.t('msp:last active time')}</p>
</Col>
</Row>
</Col>
</Row>
);
},
)
) : (
<EmptyHolder relative />
)}
</Spin>
</div>
</div>
}
/>
</div>
);
};
Expand Down
2 changes: 1 addition & 1 deletion shell/app/styles/_color.scss
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ $color-input-bg: #efeef0;

// color new list
$color-box-shadow: rgba($color-text-sub, 0.1);
$color-card-shadow: rgba(85, 77, 104, 0.08);
$color-card-shadow: rgba(48, 38, 71, 0.16);
$color-card-hover-shadow: rgba(85, 77, 104, 0.16);

// new assistant color
Expand Down
4 changes: 2 additions & 2 deletions shell/app/styles/util.scss
Original file line number Diff line number Diff line change
Expand Up @@ -343,10 +343,10 @@
}

.card-shadow {
box-shadow: 0 2px 4px 0 $color-card-shadow;
box-shadow: 0 1px 4px 0 $color-card-shadow;

&:hover {
box-shadow: 0 2px 4px 0 $color-card-hover-shadow;
box-shadow: 0 2px 4px 0 $color-card-shadow;
}
}

Expand Down

0 comments on commit 1c59a1c

Please sign in to comment.