diff --git a/apps/web/i18n b/apps/web/i18n index 3a9f4ed8..b1ae5306 160000 --- a/apps/web/i18n +++ b/apps/web/i18n @@ -1 +1 @@ -Subproject commit 3a9f4ed8f4c9e0ed258180931ff4f72a35f81e32 +Subproject commit b1ae5306b3852206a8a5febc0ff5cc947d79fba3 diff --git a/apps/web/src/modules/analyze/DataView/MetricDetail/MetricContributor/ContributorTable/ContributorDropdown.tsx b/apps/web/src/modules/analyze/DataView/MetricDetail/MetricContributor/ContributorTable/ContributorDropdown.tsx new file mode 100644 index 00000000..7bd547e0 --- /dev/null +++ b/apps/web/src/modules/analyze/DataView/MetricDetail/MetricContributor/ContributorTable/ContributorDropdown.tsx @@ -0,0 +1,48 @@ +import React, { useState } from 'react'; +// import { AiOutlineSearch } from 'react-icons/ai'; +import { Button, Input } from 'antd'; +import { useTranslation } from 'next-i18next'; + +const ContributorDropdown = ({ selectedKeys, setSelectedKeys, confirm }) => { + const { t } = useTranslation(); + const [contributor, setContributor] = useState(selectedKeys); + + const handleSearch = () => { + setSelectedKeys(contributor); + confirm(); + }; + const handleReset = () => { + setContributor([]); + }; + return ( +
e.stopPropagation()}> + setContributor([e.target.value])} + onPressEnter={() => handleSearch()} + style={{ marginBottom: 8, display: 'block' }} + /> +
+ + +
+
+ ); +}; + +export default ContributorDropdown; diff --git a/apps/web/src/modules/analyze/DataView/MetricDetail/MetricContributor/ContributorTable/ContributorName.tsx b/apps/web/src/modules/analyze/DataView/MetricDetail/MetricContributor/ContributorTable/ContributorName.tsx index a4be48e0..4d62f434 100644 --- a/apps/web/src/modules/analyze/DataView/MetricDetail/MetricContributor/ContributorTable/ContributorName.tsx +++ b/apps/web/src/modules/analyze/DataView/MetricDetail/MetricContributor/ContributorTable/ContributorName.tsx @@ -4,15 +4,37 @@ import Image from 'next/image'; const DomainPersona = ({ name, origin }) => { let icon = getIcons(origin, name); - + let url = getHubUrl(origin, name); return (
{icon}
- {name} + {url ? ( + + {name} + + ) : ( + name + )}
); }; +const getHubUrl = (origin, name) => { + switch (origin) { + case 'github': + return 'https://github.com/' + name; + case 'gitee': + return 'https://gitee.com/' + name; + // return ; + default: + return null; + } +}; const getIcons = (origin, name) => { switch (origin) { case 'github': @@ -51,7 +73,6 @@ const getIcons = (origin, name) => { /> ); - // return ; default: return ; } diff --git a/apps/web/src/modules/analyze/DataView/MetricDetail/MetricContributor/ContributorTable/index.tsx b/apps/web/src/modules/analyze/DataView/MetricDetail/MetricContributor/ContributorTable/index.tsx index c99df7f7..c1779462 100644 --- a/apps/web/src/modules/analyze/DataView/MetricDetail/MetricContributor/ContributorTable/index.tsx +++ b/apps/web/src/modules/analyze/DataView/MetricDetail/MetricContributor/ContributorTable/index.tsx @@ -17,17 +17,19 @@ import { getMaxDomain } from '../utils'; import { getContributorPolling, getContributorExport } from './tableDownload'; import DomainPersona from './DomainPersona'; import ContributorName from './ContributorName'; +import ContributorDropdown from './ContributorDropdown'; import { useTranslation } from 'next-i18next'; import Download from '@common/components/Table/Download'; import { useRouter } from 'next/router'; import { useHandleQueryParams } from '@modules/analyze/hooks/useHandleQueryParams'; import Dialog from '@common/components/Dialog'; import Tooltip from '@common/components/Tooltip'; -import { FiEdit } from 'react-icons/fi'; -import { GrClose } from 'react-icons/gr'; import ManageOrgEdit from '@common/components/OrgEdit/ManageOrgEdit'; import useVerifyDetailRange from '@modules/analyze/hooks/useVerifyDetailRange'; import { useIsCurrentUser } from '@modules/analyze/hooks/useIsCurrentUser'; +import { FiEdit } from 'react-icons/fi'; +import { GrClose } from 'react-icons/gr'; +import { AiOutlineSearch } from 'react-icons/ai'; import type { ColumnsType, TablePaginationConfig } from 'antd/es/table'; import type { FilterValue, SorterResult } from 'antd/es/table/interface'; @@ -90,13 +92,12 @@ const MetricTable: React.FC<{ return `${t('analyze:total_people', { total })} `; }, }, - filterOpts: filterOpts, sortOpts: defaultSortOpts, }); const query = { page: tableParams.pagination.current, per: tableParams.pagination.pageSize, - filterOpts: [...tableParams.filterOpts, mileageFilter], + filterOpts: [...filterOpts, mileageFilter], sortOpts: tableParams.sortOpts, label, level, @@ -113,7 +114,7 @@ const MetricTable: React.FC<{ { onSuccess: (data) => { const items = data.contributorsDetailList.items; - const hasTypeFilter = tableParams.filterOpts.find( + const hasTypeFilter = filterOpts.find( (i) => i.type === 'contribution_type' ); if (hasTypeFilter) { @@ -149,14 +150,14 @@ const MetricTable: React.FC<{ for (const key in filters) { if (filters.hasOwnProperty(key)) { const transformedObj = { - type: filterMap[key], + type: filterMap[key] || key, values: filters[key] as string[], }; filters[key] && filterOpts.push(transformedObj); } } if (filterOpts.find((i) => i.type === 'contribution_type')) { - sortOpts = sorter.field && { + sortOpts = sorter.order && { type: sorter.field === 'contribution' ? 'contribution_filterd' @@ -164,14 +165,14 @@ const MetricTable: React.FC<{ direction: sorter.order === 'ascend' ? 'asc' : 'desc', }; } else { - sortOpts = sorter.field && { + sortOpts = sorter.order && { type: sorter.field, direction: sorter.order === 'ascend' ? 'asc' : 'desc', }; } handleQueryParams({ - filterOpts: JSON.stringify(filterOpts), - sortOpts: JSON.stringify(sortOpts), + filterOpts: filterOpts.length > 0 ? JSON.stringify(filterOpts) : null, + sortOpts: sortOpts && JSON.stringify(sortOpts), }); setFilterOpts(filterOpts); setTableParams({ @@ -180,7 +181,6 @@ const MetricTable: React.FC<{ ...pagination, }, sortOpts, - filterOpts, }); }; @@ -190,11 +190,27 @@ const MetricTable: React.FC<{ dataIndex: 'contributor', align: 'left', width: '200px', - sorter: true, fixed: 'left', render: (name) => { return ; }, + filterIcon: (filtered: boolean) => ( + + ), + defaultFilteredValue: + defaultFilterOpts.find((i) => i.type === 'contributor')?.values || null, + filterDropdown: ({ selectedKeys, setSelectedKeys, confirm }) => { + return ( + + ); + }, }, { title: t('analyze:metric_detail:role_persona'), diff --git a/apps/web/src/modules/analyze/DataView/MetricDetail/MetricDashboard.tsx b/apps/web/src/modules/analyze/DataView/MetricDetail/MetricDashboard.tsx index dfb275ae..e877f7e8 100644 --- a/apps/web/src/modules/analyze/DataView/MetricDetail/MetricDashboard.tsx +++ b/apps/web/src/modules/analyze/DataView/MetricDetail/MetricDashboard.tsx @@ -120,15 +120,10 @@ const MetricBoxContributors: React.FC<{
-
- {getUserIcons( - data.highestContributionContributor.origin, - data.highestContributionContributor.name - )} -
-
- {data.highestContributionContributor.name || '/'} -
+ {getTopUser( + data.highestContributionContributor.origin, + data.highestContributionContributor.name + )}
{t('analyze:metric_detail:top_contributor')} @@ -328,44 +323,74 @@ const getIcons = (type: string) => { return ; } }; -const getUserIcons = (type, name) => { - switch (type) { - case 'github': - return ( -
- (e.currentTarget.src = '/images/github.png')} - unoptimized - fill={true} - style={{ - objectFit: 'cover', - }} - alt="icon" - placeholder="blur" - blurDataURL="/images/github.png" - /> -
- ); - case 'gitee': - return ( -
- - (e.currentTarget.src = '/images/logos/gitee-red.svg') - } - unoptimized - fill={true} - alt="icon" - placeholder="blur" - blurDataURL="/images/logos/gitee-red.svg" - /> -
- ); - // return ; - default: - return ; +const getTopUser = (type, name) => { + let url = null; + let userIcon = null; + if (!name) { + userIcon = ; + } else { + switch (type) { + case 'github': + url = 'https://github.com/' + name; + userIcon = ( +
+ (e.currentTarget.src = '/images/github.png')} + unoptimized + fill={true} + style={{ + objectFit: 'cover', + }} + alt="icon" + placeholder="blur" + blurDataURL="/images/github.png" + /> +
+ ); + break; + case 'gitee': + url = 'https://gitee.com/' + name; + userIcon = ( +
+ + (e.currentTarget.src = '/images/logos/gitee-red.svg') + } + unoptimized + fill={true} + alt="icon" + placeholder="blur" + blurDataURL="/images/logos/gitee-red.svg" + /> +
+ ); + break; + default: + userIcon = ; + break; + } } + + return ( + <> +
{userIcon}
+
+ {url ? ( + + {name} + + ) : ( + name || '/' + )} +
+ + ); }; export default MetricDashboard; diff --git a/apps/web/src/modules/analyze/hooks/useHandleQueryParams.ts b/apps/web/src/modules/analyze/hooks/useHandleQueryParams.ts index 537bc0e5..bab4560d 100644 --- a/apps/web/src/modules/analyze/hooks/useHandleQueryParams.ts +++ b/apps/web/src/modules/analyze/hooks/useHandleQueryParams.ts @@ -1,11 +1,19 @@ import { useRouter } from 'next/router'; // 修改或新增查询参数 +const clearEmptyProperties = (obj) => { + Object.keys(obj).forEach(function (key) { + if (obj[key] === null || obj[key] === undefined || obj[key] === '') { + delete obj[key]; + } + }); +}; export const useHandleQueryParams = () => { const router = useRouter(); const handleQueryParams = (newParams) => { const { pathname, query } = router; const newQueryParams = { ...query, ...newParams }; + clearEmptyProperties(newQueryParams); router.push({ pathname, query: newQueryParams, diff --git a/apps/web/src/styles/antd.scss b/apps/web/src/styles/antd.scss index de02d82f..238f6b3c 100644 --- a/apps/web/src/styles/antd.scss +++ b/apps/web/src/styles/antd.scss @@ -1,6 +1,9 @@ -.ant-table-filter-dropdown-btns { +.ant-table-filter-dropdown { .ant-btn-primary { background-color: #1677ff !important; + // :hover { + // background-color: #4096ff !important; + // } } } .ant-progress-bg {