-
- {
- setTab(v);
- handleQueryParams({ card: v });
- }}
- aria-label="Tabs where selection follows focus"
- selectionFollowsFocus
- >
-
-
-
-
-
-
-
+
+
setIsBot(v)}
+ onRepoChange={(v) => setRepoList(v)}
+ />
+
{t('analyze:metric_detail:milestone_persona_filter')}
{
+
+
+
+ {
+ setTab(v);
+ handleQueryParams({ card: v });
+ }}
+ aria-label="Tabs where selection follows focus"
+ selectionFollowsFocus
+ >
+
+
+
+
+
{source}
-
+
);
};
diff --git a/apps/web/src/modules/analyze/DataView/MetricDetail/MetricIssue/IssueTable.tsx b/apps/web/src/modules/analyze/DataView/MetricDetail/MetricIssue/IssueTable.tsx
index d3b9b699..49fedd0b 100644
--- a/apps/web/src/modules/analyze/DataView/MetricDetail/MetricIssue/IssueTable.tsx
+++ b/apps/web/src/modules/analyze/DataView/MetricDetail/MetricIssue/IssueTable.tsx
@@ -48,6 +48,7 @@ const MetricTable: React.FC<{
direction: 'desc',
},
});
+
const query = {
page: tableParams.pagination.current,
per: tableParams.pagination.pageSize,
@@ -187,7 +188,7 @@ const MetricTable: React.FC<{
];
return (
<>
-
+
{
const router = useRouter();
@@ -19,7 +19,12 @@ const MetricIssue = () => {
const { label, level } = verifiedItems[0];
const { t } = useTranslation();
const queryCard = router.query?.card as string;
+ const [isBot, setIsBot] = useState(true);
const [tab, setTab] = useState(queryCard || '1');
+ const commonFilterOpts = useMemo(() => {
+ let opts = [];
+ return opts;
+ }, [isBot]);
let source;
switch (tab) {
case '1': {
@@ -68,11 +73,11 @@ const MetricIssue = () => {
}
}
return (
-
+
{
{source}
-
+
);
};
diff --git a/apps/web/src/modules/analyze/DataView/MetricDetail/MetricPr/PrTable.tsx b/apps/web/src/modules/analyze/DataView/MetricDetail/MetricPr/PrTable.tsx
index 824b437d..9bac7089 100644
--- a/apps/web/src/modules/analyze/DataView/MetricDetail/MetricPr/PrTable.tsx
+++ b/apps/web/src/modules/analyze/DataView/MetricDetail/MetricPr/PrTable.tsx
@@ -194,7 +194,7 @@ const MetricTable: React.FC<{
];
return (
<>
-
+
{
const { t } = useTranslation();
@@ -20,6 +20,14 @@ const MetricPr = () => {
const queryCard = router.query?.card as string;
const [tab, setTab] = useState(queryCard || '1');
const { timeStart, timeEnd } = useVerifyDateRange();
+ const [repoList, setRepoList] = useState([]);
+ const commonFilterOpts = useMemo(() => {
+ let opts = [];
+ if (repoList.length > 0) {
+ opts.push({ type: 'repo_urls', values: repoList });
+ }
+ return opts;
+ }, [repoList]);
let source;
switch (tab) {
case '1': {
@@ -68,11 +76,11 @@ const MetricPr = () => {
}
}
return (
-
+
{
/>
{source}
-
+
);
};
diff --git a/apps/web/src/modules/analyze/components/MetricDetail/CommunityFilter.tsx b/apps/web/src/modules/analyze/components/MetricDetail/CommunityFilter.tsx
new file mode 100644
index 00000000..20ef6085
--- /dev/null
+++ b/apps/web/src/modules/analyze/components/MetricDetail/CommunityFilter.tsx
@@ -0,0 +1,93 @@
+import React, { useMemo, useRef, useState } from 'react';
+import { Select, Checkbox, Divider } from 'antd';
+import { useCommunityReposSearchQuery } from '@oss-compass/graphql';
+import client from '@common/gqlClient';
+import { getLastPathSegment } from '@common/utils';
+import { useTranslation } from 'next-i18next';
+
+interface UserValue {
+ label: string;
+ value: string;
+}
+
+const CommunityFilter = ({ label, onRepoChange }) => {
+ const [value, setValue] = useState
([]);
+ const [options, setOptions] = useState([]);
+ const [selectState, setSelectState] = useState(true);
+ const { t } = useTranslation();
+ const { isLoading } = useCommunityReposSearchQuery(
+ client,
+ { label: label, page: 1, per: 9999 },
+ {
+ onSuccess: (data) => {
+ if (data) {
+ let items = data.communityRepos.items;
+ let opts = items.map((z) => ({
+ label: getLastPathSegment(z.label),
+ value: z.label,
+ }));
+ setOptions(opts);
+ setValue(opts.map((item) => item.value));
+ }
+ console.log(data);
+ },
+ }
+ );
+
+ return (
+
+ selectState ? (
+ {t('analyze:metric_detail:all_repos')}
+ ) : (
+ '+' + value.length
+ // label).join(', ')}>
+ // Hover Me
+ //
+ )
+ }
+ options={options}
+ onChange={(newValue) => {
+ setValue(newValue);
+ if (newValue.length === options.length) {
+ setSelectState(true);
+ onRepoChange([]);
+ } else {
+ setSelectState(false);
+ onRepoChange(newValue);
+ }
+ }}
+ style={{ width: 130 }}
+ // allowClear
+ dropdownRender={(menu) => (
+
+ {menu}
+
+
+ {
+ if (e.target.checked === true) {
+ setSelectState(true); //选中时 给 checked 改变状态
+ // 当选的时候 把所有列表值赋值给 functionIds
+ setValue(options.map((item) => item.value));
+ } else {
+ setSelectState(false);
+ setValue([]);
+ }
+ onRepoChange([]);
+ }}
+ >
+ {t('analyze:metric_detail:select_all')}
+
+
+
+ )}
+ />
+ );
+};
+
+export default CommunityFilter;
diff --git a/apps/web/src/modules/analyze/components/MetricDetail/DetailHeaderFilter.tsx b/apps/web/src/modules/analyze/components/MetricDetail/DetailHeaderFilter.tsx
new file mode 100644
index 00000000..26034095
--- /dev/null
+++ b/apps/web/src/modules/analyze/components/MetricDetail/DetailHeaderFilter.tsx
@@ -0,0 +1,59 @@
+import React, { useState } from 'react';
+import { Select } from 'antd';
+import { useTranslation } from 'next-i18next';
+import CommunityFilter from './CommunityFilter';
+
+const DetailHeaderFilter: React.FC<{
+ type: string;
+ level: string;
+ label: string;
+ isBot?: boolean;
+ onBotChange?: (v) => void;
+ onRepoChange?: (v) => void;
+}> = ({ type, label, isBot, onBotChange, onRepoChange }) => {
+ const { t } = useTranslation();
+
+ const isBotOptions = [
+ {
+ label: t('analyze:metric_detail:include_robot'),
+ value: true,
+ },
+ {
+ label: t('analyze:metric_detail:exclude_robot'),
+ value: false,
+ },
+ ];
+ if (type == 'issue') {
+ return (
+ <>
+
+ {t('analyze:metric_detail:issues')}
+
+ >
+ );
+ } else if (type == 'pr') {
+ return (
+ <>
+
+ {t('analyze:metric_detail:pull_requests')}
+
+ >
+ );
+ }
+ return (
+
+ onRepoChange(v)} />
+ {
+ onBotChange(v);
+ // handleQueryParams({ tab: v });
+ }}
+ value={isBot}
+ options={isBotOptions}
+ />
+
+ );
+};
+
+export default DetailHeaderFilter;
diff --git a/apps/web/src/styles/antd.scss b/apps/web/src/styles/antd.scss
index 238f6b3c..05a6beba 100644
--- a/apps/web/src/styles/antd.scss
+++ b/apps/web/src/styles/antd.scss
@@ -53,8 +53,15 @@
.ant-form-item-explain-error {
font-size: 12px !important;
}
-.ant-picker-clear {
- // inset-inline-end: 16px !important;
+.ant-select-selector {
+ border-radius: 0 !important;
+ // border-color: #cccccc !important;
+}
+.ant-select-dropdown {
+ border-radius: 0 !important;
+ .ant-select-item {
+ border-radius: 0 !important;
+ }
}
// .ant-spin-nested-loading {
// height: 100%;
diff --git a/packages/graphql/src/generated.ts b/packages/graphql/src/generated.ts
index feb0bec7..82649fa3 100644
--- a/packages/graphql/src/generated.ts
+++ b/packages/graphql/src/generated.ts
@@ -1526,6 +1526,8 @@ export type Query = {
collectionList: CollectionPage;
/** Get overview data of a community */
communityOverview: CommunityOverview;
+ /** Get repos list of a community */
+ communityRepos: RepoPage;
/** Get contributors detail list of a repo or community */
contributorsDetailList: ContributorDetailPage;
/** Get overview data of a contributor detail */
@@ -1672,6 +1674,13 @@ export type QueryCommunityOverviewArgs = {
type?: InputMaybe;
};
+export type QueryCommunityReposArgs = {
+ label: Scalars['String'];
+ page?: InputMaybe;
+ per?: InputMaybe;
+ type?: InputMaybe;
+};
+
export type QueryContributorsDetailListArgs = {
beginDate?: InputMaybe;
endDate?: InputMaybe;
@@ -1975,6 +1984,14 @@ export type Repo = {
watchersCount?: Maybe;
};
+export type RepoPage = {
+ __typename?: 'RepoPage';
+ count?: Maybe;
+ items?: Maybe>;
+ page?: Maybe;
+ totalPage?: Maybe;
+};
+
export type Report = {
__typename?: 'Report';
/** metric model object identification */
@@ -2085,6 +2102,11 @@ export type SortOptionInput = {
type: Scalars['String'];
};
+export type SubRepo = {
+ __typename?: 'SubRepo';
+ label?: Maybe;
+};
+
export type SubjectSubscriptionCount = {
__typename?: 'SubjectSubscriptionCount';
count: Scalars['Int'];
@@ -3961,6 +3983,24 @@ export type CommunityReposQuery = {
};
};
+export type CommunityReposSearchQueryVariables = Exact<{
+ label: Scalars['String'];
+ page?: InputMaybe;
+ per?: InputMaybe;
+ type?: InputMaybe;
+}>;
+
+export type CommunityReposSearchQuery = {
+ __typename?: 'Query';
+ communityRepos: {
+ __typename?: 'RepoPage';
+ count?: number | null;
+ page?: number | null;
+ totalPage?: number | null;
+ items?: Array<{ __typename?: 'SubRepo'; label?: string | null }> | null;
+ };
+};
+
export type MetricQueryVariables = Exact<{
label: Scalars['String'];
level?: InputMaybe;
@@ -7530,6 +7570,52 @@ useCommunityReposQuery.fetcher = (
variables,
headers
);
+export const CommunityReposSearchDocument = /*#__PURE__*/ `
+ query communityReposSearch($label: String!, $page: Int, $per: Int, $type: String) {
+ communityRepos(label: $label, page: $page, per: $per, type: $type) {
+ count
+ items {
+ label
+ }
+ page
+ totalPage
+ }
+}
+ `;
+export const useCommunityReposSearchQuery = <
+ TData = CommunityReposSearchQuery,
+ TError = unknown
+>(
+ client: GraphQLClient,
+ variables: CommunityReposSearchQueryVariables,
+ options?: UseQueryOptions,
+ headers?: RequestInit['headers']
+) =>
+ useQuery(
+ ['communityReposSearch', variables],
+ fetcher(
+ client,
+ CommunityReposSearchDocument,
+ variables,
+ headers
+ ),
+ options
+ );
+
+useCommunityReposSearchQuery.getKey = (
+ variables: CommunityReposSearchQueryVariables
+) => ['communityReposSearch', variables];
+useCommunityReposSearchQuery.fetcher = (
+ client: GraphQLClient,
+ variables: CommunityReposSearchQueryVariables,
+ headers?: RequestInit['headers']
+) =>
+ fetcher(
+ client,
+ CommunityReposSearchDocument,
+ variables,
+ headers
+ );
export const MetricDocument = /*#__PURE__*/ `
query metric($label: String!, $level: String = "repo", $start: ISO8601DateTime, $end: ISO8601DateTime, $repoType: String) {
metricCodequality(
diff --git a/packages/graphql/src/gql/query.graphql b/packages/graphql/src/gql/query.graphql
index a680299d..93a948ee 100644
--- a/packages/graphql/src/gql/query.graphql
+++ b/packages/graphql/src/gql/query.graphql
@@ -105,7 +105,21 @@ query communityRepos($label: String!, $page: Int, $per: Int, $type: String) {
}
}
}
-
+query communityReposSearch(
+ $label: String!
+ $page: Int
+ $per: Int
+ $type: String
+) {
+ communityRepos(label: $label, page: $page, per: $per, type: $type) {
+ count
+ items {
+ label
+ }
+ page
+ totalPage
+ }
+}
query metric(
$label: String!
$level: String = "repo"