diff --git a/src/App.js b/src/App.js
index 5182f18..f5df433 100644
--- a/src/App.js
+++ b/src/App.js
@@ -1,7 +1,6 @@
import React from "react";
-import { makeStyles, Paper, IconButton, Snackbar } from "@material-ui/core";
+import { makeStyles, Paper, Snackbar } from "@material-ui/core";
import TextField from "@material-ui/core/TextField";
-import SearchIcon from "@material-ui/icons/Search";
import MuiAlert from "@material-ui/lab/Alert";
import Autocomplete from "@material-ui/lab/Autocomplete";
import Tabs from "@material-ui/core/Tabs";
@@ -9,18 +8,20 @@ import Tab from "@material-ui/core/Tab";
import PropTypes from "prop-types";
import Typography from "@material-ui/core/Typography";
import Box from "@material-ui/core/Box";
-import Button from "@material-ui/core/Button";
+import IconButton from "@material-ui/core/IconButton";
+import InputAdornment from "@material-ui/core/InputAdornment";
+import SearchIcon from "@material-ui/icons/Search";
+import cloneDeep from "lodash.clonedeep";
import ContirbutorLineChart from "./components/contributor";
import ActivityChart from "./components/activity";
import { getParameterByName } from "./utils";
+import CompareComponent from "./components/compare";
const Alert = props => {
return ;
};
-const ALLOW_MERGE_LIST = ["skywalking", "apisix"];
-
const useStyles = makeStyles(theme => ({
button: {
margin: theme.spacing(1)
@@ -37,11 +38,11 @@ const useStyles = makeStyles(theme => ({
display: "flex",
flexWrap: "wrap",
alignItems: "center",
- width: 600
+ width: "100%"
},
autocomplete: {
- marginLeft: theme.spacing(1),
- flex: 1
+ flex: 1,
+ paddingTop: "5px"
},
iconButton: {
padding: 10
@@ -85,14 +86,6 @@ function a11yProps(index) {
};
}
-const useTabStyles = makeStyles(theme => ({
- root: {
- flexGrow: 1,
- width: "100%",
- backgroundColor: theme.palette.background.paper
- }
-}));
-
const App = () => {
const [repo, setRepo] = React.useState("apache/apisix");
const [message, setMessage] = React.useState("");
@@ -100,12 +93,8 @@ const App = () => {
const [alertType, setAlertType] = React.useState("success");
const [searchOption, setSearchOption] = React.useState([]);
const [contributorRepoList, setContributorRepoList] = React.useState([]);
- const classesTable = useTabStyles();
const [value, setValue] = React.useState(0);
const [tabdisabled, setTabDisabled] = React.useState(false);
- const [showMergeButton, setShowMergeButton] = React.useState(false);
- const [mergeStatus, setMergeStatus] = React.useState(false);
- const [mergeRepo, setMergeRepo] = React.useState("apache/apisix");
const handleChange = (event, newValue) => {
setValue(newValue);
@@ -128,10 +117,6 @@ const App = () => {
};
const updateChart = repo => {
- const index = ALLOW_MERGE_LIST.findIndex(item => repo.includes(item));
- if (index === -1) {
- setMergeStatus(false);
- }
if (!contributorRepoList.includes(repo)) {
setContributorRepoList([...contributorRepoList, repo]);
}
@@ -158,25 +143,14 @@ const App = () => {
React.useEffect(() => {
getSearchOptions();
const repo = getParameterByName("repo") || "apache/apisix";
+ const repoArr = repo.split(",").filter(Boolean);
+ setContributorRepoList(repoArr);
+
const chart = getParameterByName("chart");
if (chart === "contributorMonthlyActivity") {
setValue(1);
} else {
- const merge = getParameterByName("merge");
- setRepo(repo);
- const index = ALLOW_MERGE_LIST.findIndex(item => repo.includes(item));
- if (merge === "true" && index !== -1) {
- setTimeout(() => {
- setMergeStatus(true);
- setShowMergeButton(true);
- }, 500);
- }
- }
- if (repo) {
- const repoArr = repo.split(",").filter(Boolean);
- setContributorRepoList(repoArr);
- } else {
- setContributorRepoList(["apache/apisix"]);
+ setValue(0);
}
}, []);
@@ -190,26 +164,6 @@ const App = () => {
);
}, [value]);
- React.useEffect(() => {
- const index = ALLOW_MERGE_LIST.findIndex(item => repo.includes(item));
- if (index !== -1) {
- setShowMergeButton(true);
- } else {
- setShowMergeButton(false);
- setMergeStatus(false);
- }
- if (contributorRepoList.length === 0) {
- setMergeStatus(false);
- setShowMergeButton(false);
- }
- if (repo.includes("skywalking")) {
- setMergeRepo("apache/skywalking");
- }
- if (repo.includes("apisix")) {
- setMergeRepo("apache/apisix");
- }
- }, [repo, contributorRepoList]);
-
return (
<>
{
-
+
+
+ {
+ if (reason === "reset") {
+ setRepo(value);
+ updateChart(value);
+ }
+ }}
+ renderInput={params => (
+ {
+ setRepo(e.target.value);
+ }}
+ onKeyPress={ev => {
+ if (ev.key === "Enter") {
+ updateChart(repo);
+ ev.preventDefault();
+ }
+ }}
+ InputProps={{
+ ...params.InputProps,
+ endAdornment: (
+
+ {
+ updateChart(repo);
+ }}
+ >
+
+
+
+ )
+ }}
+ />
+ )}
+ />
+
+
+ {
+ const clonedContributorRepoList = cloneDeep(
+ contributorRepoList
+ );
+ const newContributorRepoList = clonedContributorRepoList.filter(
+ item => item !== e
+ );
+ setContributorRepoList(newContributorRepoList);
+ }}
+ />
+
+
+
{
justifyContent: "center",
flexDirection: "column"
}}
- >
-
- {
- if (reason === "reset") {
- setRepo(value);
- updateChart(value);
- }
- }}
- renderInput={params => (
- {
- setRepo(e.target.value);
- }}
- onKeyPress={ev => {
- if (ev.key === "Enter") {
- updateChart(repo);
- ev.preventDefault();
- }
- }}
- InputProps={{ ...params.InputProps, type: "search" }}
- />
- )}
- />
- {
- updateChart(repo);
- }}
- >
-
-
-
- {Boolean(!value) && Boolean(showMergeButton) && (
-
{
- setMergeStatus(!mergeStatus);
- }}
- style={{ width: "260px", marginLeft: "8px" }}
- >
- {Boolean(!mergeStatus)
- ? `View all repos related to ${
- repo.includes("skywalking")
- ? "apache/skywalking"
- : "apache/apisix"
- }`
- : "Cancel merge view"}
-
- )}
-
+ >
-
+
@@ -340,17 +314,11 @@ const App = () => {
{
setTabDisabled(e);
}}
onDelete={e => {
- if (mergeStatus) {
- setMergeStatus(false);
- return;
- }
setContributorRepoList(
contributorRepoList.filter(item => item !== e)
);
diff --git a/src/components/activity/index.js b/src/components/activity/index.js
index 3f62918..64dafe7 100644
--- a/src/components/activity/index.js
+++ b/src/components/activity/index.js
@@ -5,7 +5,6 @@ import * as echarts from "echarts";
import ReactECharts from "echarts-for-react";
import omit from "lodash.omit";
-import CompareComponent from "../compare";
import { DEFAULT_ACTIVITY_OPTIONS, DEFAULT_COLOR } from "../../constants";
const ActivityChart = ({
@@ -171,29 +170,6 @@ const ActivityChart = ({
});
};
- const updateChart = repo => {
- if (dataSource[repo]) return;
- setLoading(true);
- fetchData(repo)
- .then(myJson => {
- const { Contributors = [] } = myJson;
- const data = Contributors.map(item => ({
- repo,
- contributorNum: item.Num,
- date: item.Month
- }));
-
- const clonedDatasource = cloneDeep(dataSource);
- if (!clonedDatasource[repo]) {
- setDataSource({ ...clonedDatasource, ...{ [repo]: data } });
- }
- setLoading(false);
- })
- .catch(() => {
- setLoading(false);
- });
- };
-
React.useEffect(() => {
updateSeries(xAxis);
window.parent.postMessage({ legend: Object.keys(dataSource) }, "*");
@@ -254,22 +230,7 @@ const ActivityChart = ({
}}
>
-
- {
- const clonedDataSource = cloneDeep(dataSource);
- const newDataSource = omit(clonedDataSource, [e]);
- setDataSource(newDataSource);
- onDelete(e);
- }}
- onConfirm={e => {
- if (!e) return;
- updateChart(e);
- }}
- />
-
-
+
@@ -284,7 +245,7 @@ const ActivityChart = ({
window.echartInstance = echartInstance;
}
}}
- style={{ height: 700, width: "100%" }}
+ style={{ height: 550 }}
showLoading={loading}
notMerge
/>
diff --git a/src/components/chip.js b/src/components/chip.js
index ff7a3b0..c1544aa 100644
--- a/src/components/chip.js
+++ b/src/components/chip.js
@@ -10,7 +10,7 @@ const useStyles = makeStyles(theme => ({
"& > *": {
margin: theme.spacing(0.5)
}
- }
+ },
}));
export default function OutlinedChips({ list = [], onDelete }) {
@@ -23,6 +23,7 @@ export default function OutlinedChips({ list = [], onDelete }) {
icon={ }
label={item}
key={item}
+ size="small"
onDelete={() => onDelete(item)}
color="primary"
variant="outlined"
diff --git a/src/components/compare.js b/src/components/compare.js
index 340b6a3..ef9c763 100644
--- a/src/components/compare.js
+++ b/src/components/compare.js
@@ -10,7 +10,7 @@ const useStyles = makeStyles(theme => ({
flexWrap: "wrap",
flexGrow: 1,
"& > *": {
- margin: theme.spacing(1),
+ margin: '0 0 8px 0',
width: "100%",
height: theme.spacing(8)
}
diff --git a/src/components/contributor/index.js b/src/components/contributor/index.js
index 7c07981..f2c56c4 100644
--- a/src/components/contributor/index.js
+++ b/src/components/contributor/index.js
@@ -1,23 +1,23 @@
import React from "react";
import cloneDeep from "lodash.clonedeep";
-import { Row, Col, Tab } from "react-bootstrap";
import ReactECharts from "echarts-for-react";
+import * as echarts from "echarts";
import omit from "lodash.omit";
-import CompareComponent from "../../components/compare";
import { Button, ButtonGroup } from "@material-ui/core";
-import { getMonths } from "../../utils";
+import { getMonths, getParameterByName } from "../../utils";
import { generateDefaultOption } from "../../constants";
import { fetchData, fetchMergeContributor } from "./service";
import CustomizedDialogs from "../shareDialog";
+import { DEFAULT_COLOR } from "../../constants";
+import SyntaxHighlighter from "react-syntax-highlighter/dist/esm/default-highlight";
+import { a11yDark } from "react-syntax-highlighter/dist/esm/styles/hljs";
const ContributorLineChart = ({
- repoList = ["apache/apisix"],
+ repoList = [],
showAlert,
onDelete,
- onLoading,
- isMerge = false,
- mergeRepo = ""
+ onLoading
}) => {
const [loading, setLoading] = React.useState(false);
const [dataSource, setDataSource] = React.useState({});
@@ -32,8 +32,52 @@ const ContributorLineChart = ({
})
);
+ const [viewMerge, setViewMerge] = React.useState(false);
+ const [mergeRepo, setMergerRepo] = React.useState("");
+
+ const showMergeButton = React.useMemo(() => {
+ const lastItem = repoList[repoList.length - 1];
+ return lastItem === "apache/apisix" || lastItem === "apache/skywalking";
+ }, [repoList]);
+
+ const SHARE_BASE_URL = "https://www.apiseven.com/en/contributor-graph";
+ const IMG_BASE_URL =
+ "https://contributor-graph-api.apiseven.com/contributors-svg";
+
+ const MarkdownLink = ({ params = "" }) => {
+ return (
+
+
+ You can include the chart on your repository's README.md as follows:
+
+
+ {`
+ ## Contributor over time
+
+ [[${SHARE_BASE_URL +
+ params}]]`}
+
+
+ );
+ };
+
+ React.useEffect(() => {
+ if (showMergeButton) {
+ setMergerRepo(repoList[repoList.length - 1]);
+ return;
+ }
+ setMergerRepo("");
+ }, [repoList, showMergeButton]);
+
+ React.useEffect(() => {
+ // reset viewmerge when repo list change
+ if (!showMergeButton) {
+ setViewMerge(false);
+ }
+ }, [repoList.length]);
+
const getShareParams = () => {
- if (isMerge) {
+ if (viewMerge) {
return `?chart=contributorOverTime&repo=${mergeRepo}&merge=true`;
}
return `?chart=contributorOverTime&repo=${repoList.join(",")}`;
@@ -108,6 +152,29 @@ const ContributorLineChart = ({
}
}));
+ if (series.length === 1) {
+ series[0].areaStyle = {
+ color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
+ {
+ offset: 0,
+ color: DEFAULT_COLOR + "80"
+ },
+ {
+ offset: 1,
+ color: DEFAULT_COLOR + "00"
+ }
+ ])
+ };
+ series[0].itemStyle = {
+ normal: {
+ color: DEFAULT_COLOR,
+ lineStyle: {
+ color: DEFAULT_COLOR
+ }
+ }
+ };
+ }
+
newClonedOption.dataset = [
{
id: "dataset_raw",
@@ -169,7 +236,7 @@ const ContributorLineChart = ({
return;
}
- if (!isMerge) {
+ if (!viewMerge) {
setLoading(true);
Promise.all(repoList.map(item => fetchData(item, showAlert, onDelete)))
.then(data => {
@@ -196,28 +263,40 @@ const ContributorLineChart = ({
} else {
if (!mergeRepo.length) return;
setLoading(true);
- fetchMergeContributor(mergeRepo, showAlert, onDelete)
+ fetchMergeContributor([mergeRepo], showAlert, onDelete)
.then(_data => {
const tmpDataSouce = {};
const { Contributors = [], repo } = _data;
const data = Contributors.map(item => ({
- repo,
+ repo: repo.join(","),
contributorNum: item.idx,
date: item.date
}));
- if (!tmpDataSouce[_data.repo]) {
- tmpDataSouce[repo] = data;
+ if (!tmpDataSouce[repo.join(",")]) {
+ tmpDataSouce[repo.join(",")] = data;
}
setDataSource(tmpDataSouce);
setLoading(false);
})
- .catch(() => {
+ .catch(e => {
setLoading(false);
});
}
- }, [repoList, isMerge]);
+ }, [repoList, viewMerge]);
+
+ React.useEffect(() => {
+ const merge = getParameterByName("merge");
+ const repo = getParameterByName("repo");
+ if (
+ (merge === "true" && repo === "apache/apisix") ||
+ repo === "apache/skywalking"
+ ) {
+ setMergerRepo(repo);
+ setViewMerge(true);
+ }
+ }, []);
return (
<>
@@ -229,105 +308,98 @@ const ContributorLineChart = ({
}}
>
-
-
-
{
- const clonedDataSource = cloneDeep(dataSource);
- const newDataSource = omit(clonedDataSource, [e]);
- setDataSource(newDataSource);
- onDelete(e);
+
+
+
670 ? "flex" : "unset",
+ justifyContent: "space-between"
}}
+ >
+
+ {
+ setActiveDate(e.currentTarget.value);
+ }}
+ >
+ 1 Month
+
+ {
+ setActiveDate(e.currentTarget.value);
+ }}
+ >
+ 3 Months
+
+ {
+ setActiveDate(e.currentTarget.value);
+ }}
+ >
+ 6 Months
+
+ {
+ setActiveDate(e.currentTarget.value);
+ }}
+ >
+ 1 Year
+
+ {
+ setActiveDate(e.currentTarget.value);
+ }}
+ >
+ Max
+
+
+
+ {showMergeButton && (
+ {
+ setViewMerge(viewMerge => !viewMerge);
+ }}
+ >
+ {!viewMerge
+ ? `view all repos related to ${mergeRepo}`
+ : "cancel merge view"}
+
+ )}
+
+
{
+ if (e) {
+ const echartInstance = e.getEchartsInstance();
+ // then you can use any API of echarts.
+ window.echartInstance = echartInstance;
+ }
+ }}
+ style={{ height: 550 }}
+ showLoading={loading}
+ notMerge
/>
-
-
-
-
-
-
-
-
-
- {
- setActiveDate(e.currentTarget.value);
- }}
- >
- 1 Month
-
- {
- setActiveDate(e.currentTarget.value);
- }}
- >
- 3 Months
-
- {
- setActiveDate(e.currentTarget.value);
- }}
- >
- 6 Months
-
- {
- setActiveDate(e.currentTarget.value);
- }}
- >
- 1 Year
-
- {
- setActiveDate(e.currentTarget.value);
- }}
- >
- Max
-
-
-
- {
- if (e) {
- const echartInstance = e.getEchartsInstance();
- // then you can use any API of echarts.
- window.echartInstance = echartInstance;
- }
- }}
- style={{ height: 700, width: "100%" }}
- showLoading={loading}
- notMerge
- />
-
-
-
-
-
+
diff --git a/src/components/contributor/service.js b/src/components/contributor/service.js
index 86ad0bd..4e09674 100644
--- a/src/components/contributor/service.js
+++ b/src/components/contributor/service.js
@@ -1,6 +1,5 @@
import moment from "moment";
import { isSameDay } from "../../utils";
-import { getGithubRepoList } from "../../api/service";
export const fetchData = (repo, showAlert, onDelete) => {
if (repo === "null" || repo === null) {
@@ -89,37 +88,36 @@ export const fetchData = (repo, showAlert, onDelete) => {
export const fetchMergeContributor = (repo, showAlert) => {
return new Promise((resolve, reject) => {
- getGithubRepoList(repo).then(data => {
- fetch(
- `https://contributor-graph-api.apiseven.com/contributors-multi?repo=${data.join(
- ","
- )}`
- )
- .then(response => {
- if (!response.ok) {
- let message = "";
- switch (response.status) {
- case 403:
- message = "Hit rate limit";
- break;
- case 404:
- message = "Repo format error / Repo not found";
- break;
- default:
- message = "Request Error";
- break;
- }
- throw message;
+ fetch(
+ `https://contributor-graph-api.apiseven.com/contributors-multi?repo=${repo.join(
+ ","
+ )}`
+ )
+ .then(response => {
+ if (!response.ok) {
+ let message = "";
+ switch (response.status) {
+ case 403:
+ message = "Hit rate limit";
+ break;
+ case 404:
+ message = "Repo format error / Repo not found";
+ break;
+ default:
+ message = "Request Error";
+ break;
}
- return response.json();
- })
- .then(myJson => {
- resolve({ repo, ...myJson });
- })
- .catch(e => {
- showAlert(e, "error");
- reject();
- });
- });
+ throw message;
+ }
+ return response.json();
+ })
+ .then(myJson => {
+ console.log('myJson: ', myJson);
+ resolve({ repo, ...myJson });
+ })
+ .catch(e => {
+ showAlert(e, "error");
+ reject();
+ });
});
};
diff --git a/src/components/shareDialog/index.css b/src/components/shareDialog/index.css
new file mode 100644
index 0000000..eaaef66
--- /dev/null
+++ b/src/components/shareDialog/index.css
@@ -0,0 +1,3 @@
+.shareInput .MuiOutlinedInput-root {
+ border-radius: 0px;
+}
diff --git a/src/components/shareDialog/index.js b/src/components/shareDialog/index.js
index d2602ac..caf915c 100644
--- a/src/components/shareDialog/index.js
+++ b/src/components/shareDialog/index.js
@@ -9,13 +9,12 @@ import Typography from "@material-ui/core/Typography";
import Paper from "@material-ui/core/Paper";
import Grid from "@material-ui/core/Grid";
import { makeStyles } from "@material-ui/core/styles";
-import SyntaxHighlighter from "react-syntax-highlighter";
-import { a11yDark } from "react-syntax-highlighter/dist/esm/styles/hljs";
import Button from "@material-ui/core/Button";
import TextField from "@material-ui/core/TextField";
import copy from "copy-to-clipboard";
import { inIframe } from "../../utils";
+import "./index.css";
const styles = theme => ({
root: {
@@ -43,13 +42,15 @@ const ShareLink = ({ params = "" }) => {
id="standard-basic"
label="Share Link"
variant="outlined"
+ className="shareInput"
value={`${SHARE_BASE_URL}${params}`}
size="small"
- style={{ width: "400px" }}
+ style={{ width: "400px", borderRadius: "0px" }}
/>
{
copy(SHARE_BASE_URL + params);
}}
@@ -59,9 +60,9 @@ const ShareLink = ({ params = "" }) => {
{
{
copy(IMG_BASE_URL + params);
}}
@@ -166,23 +168,6 @@ function CenteredGrid({ params = "" }) {
);
}
-const MarkdownLink = ({ params = "" }) => {
- return (
-
-
- You can include the chart on your repository's README.md as follows:
-
-
- {`
-## Contributor over time
-
-[[${SHARE_BASE_URL +
- params}]]`}
-
-
- );
-};
-
const DialogTitle = withStyles(styles)(props => {
const { children, classes, onClose, ...other } = props;
return (
@@ -228,7 +213,6 @@ export default function CustomizedDialogs({
-
diff --git a/src/constants.js b/src/constants.js
index de029e0..075e7a1 100644
--- a/src/constants.js
+++ b/src/constants.js
@@ -5,7 +5,7 @@ export const generateDefaultOption = ({ handleShareClick = () => {} }) => {
top: "5%",
data: [],
textStyle: {
- fontSize: 16
+ fontSize: 14
}
},
toolbox: {
@@ -18,10 +18,6 @@ export const generateDefaultOption = ({ handleShareClick = () => {} }) => {
onclick: function() {
handleShareClick();
}
- },
- saveAsImage: {
- show: true,
- type: "png"
}
}
},
@@ -51,26 +47,26 @@ export const generateDefaultOption = ({ handleShareClick = () => {} }) => {
}
}
},
- series: []
+ series: [],
+ grid: {
+ x: 40,
+ x2: 15,
+ y: 80
+ }
};
};
export const DEFAULT_ACTIVITY_OPTIONS = {
color: ["#39a85a", "#4385ee", "#fabc37", "#2dc1dd", "#f972cf", "#8331c8"],
legend: {
- top: "5%",
+ top: "10%",
data: [],
textStyle: {
fontSize: 16
}
},
toolbox: {
- feature: {
- saveAsImage: {
- show: true,
- type: "png"
- }
- }
+ feature: {}
},
dataset: [],
title: {
@@ -100,7 +96,12 @@ export const DEFAULT_ACTIVITY_OPTIONS = {
}
}
},
- series: []
+ series: [],
+ grid: {
+ x: 31,
+ x2: 13,
+ y: 80
+ }
};
export const DEFAULT_COLOR = "#39a85a";