Compare commits
455 Commits
v3.1.5
...
pre_develo
Author | SHA1 | Date |
---|---|---|
|
d5b4c5425f | |
|
56946f94e8 | |
![]() |
61ee3fe36f | |
|
7b77c46915 | |
|
746f552a21 | |
|
7872d5ecab | |
|
60da6bd110 | |
|
aeff357660 | |
|
0e6cb3954a | |
|
ae12618c0c | |
|
12f97cce62 | |
|
2f90ccab3c | |
|
035296732a | |
|
cc62bde5b4 | |
|
5ef02c698d | |
![]() |
13c58faad8 | |
|
6435b09982 | |
|
a0081bf3b1 | |
|
a542ed3dcd | |
![]() |
057881097d | |
![]() |
d47c725b96 | |
|
be3e2b6936 | |
![]() |
76c2d205eb | |
![]() |
2c867f9856 | |
![]() |
7b74564ecc | |
|
b31503ee0d | |
|
eadec88e0c | |
|
31af77e704 | |
|
6ff27a559f | |
|
fe1bacb984 | |
|
573ec813a6 | |
|
11b92ac52b | |
|
e992849723 | |
|
0c52ea22a7 | |
|
b6b19eabe9 | |
|
edbd47ea0f | |
![]() |
644e3c3f73 | |
![]() |
e7a322e038 | |
|
a2c5c1ea6f | |
![]() |
dfa9b3d835 | |
|
e744714da0 | |
|
14df994cd6 | |
![]() |
e9546951c9 | |
![]() |
9de7ac7c90 | |
|
3e3e9f3681 | |
|
4b2651339b | |
|
4b9cc26d9c | |
|
66108083fd | |
![]() |
adfd2ae66c | |
|
f78eecd775 | |
![]() |
b30f2169e4 | |
![]() |
8ace7da3a7 | |
![]() |
35110b7db4 | |
![]() |
95050bb3bd | |
|
f97c90f20e | |
![]() |
afd2cec4f2 | |
![]() |
0903edfd2c | |
![]() |
1aa6c05869 | |
|
94fd500423 | |
|
90cfac4436 | |
![]() |
db2c3b707a | |
![]() |
bb1175de01 | |
|
c45a6ffe1a | |
![]() |
c0f2c77e1a | |
![]() |
c386bcf5e7 | |
|
0b4baa1d03 | |
|
c0afc7a052 | |
|
1826c1923f | |
![]() |
76d8c4b67a | |
![]() |
fbbb3c3aa6 | |
|
2f06288507 | |
|
47b6c3d948 | |
|
f6b59e0a3a | |
|
bb6fe08c54 | |
|
a7283b5567 | |
|
05eb0367ba | |
![]() |
3ca38e76a1 | |
|
7b180560a6 | |
|
17cf0412cd | |
|
f65781b49b | |
|
82d8a0d198 | |
![]() |
0d7805fc9d | |
|
68b34ab418 | |
![]() |
5223a84dac | |
|
4afb131aef | |
|
5d19f6c06b | |
|
a4902739f2 | |
|
bfcf714822 | |
|
fc305ae952 | |
|
095e27fcc3 | |
|
5c819070bb | |
|
8e3bd741cb | |
|
baba177244 | |
|
38c553d87c | |
|
de79518e0d | |
|
a7c2120cf3 | |
|
8dcc6c6d59 | |
![]() |
fe4c5a79d2 | |
|
fd21cc6d00 | |
|
2fc59748b4 | |
|
2060e28ca2 | |
![]() |
94ceec26e9 | |
|
e5787e3e66 | |
|
8ae34b8f32 | |
![]() |
6244ad3323 | |
![]() |
1fbe6671b1 | |
|
cda7311fa1 | |
|
4c25aed9a0 | |
![]() |
b578383e8d | |
|
d05829ac80 | |
|
e726ba40ea | |
|
279d358be9 | |
|
50f785bf42 | |
|
a09d330a7e | |
|
9812761b47 | |
|
c037712b3e | |
|
19b7381120 | |
|
a54f1b6e1a | |
|
8b186467a4 | |
|
4902a26646 | |
![]() |
c282a1e034 | |
|
112aacb6a1 | |
|
0a81bc6e6e | |
|
1406b30a54 | |
|
fd58c70c54 | |
|
8cb0e32afa | |
![]() |
6837be3104 | |
|
539fa64358 | |
|
63a74cc076 | |
|
1c5b5a66d8 | |
|
898e3f3256 | |
|
bcbd915bd1 | |
|
1ed49e7221 | |
|
5bbec01c1c | |
|
8bdd619dde | |
![]() |
82f6e03ca7 | |
|
e04496f662 | |
|
ed548d16e8 | |
|
66c5662d01 | |
![]() |
9e390cf878 | |
![]() |
cd30082956 | |
|
7a8540045b | |
|
8a6ed077d1 | |
![]() |
9600d52a80 | |
![]() |
07049cbbc6 | |
|
208c1de930 | |
|
873ab992bc | |
|
4e3215c6f9 | |
![]() |
b0d1379281 | |
![]() |
7a50c73040 | |
|
92fb98e303 | |
|
8e1fb80f96 | |
|
825cee4eac | |
|
dcb597ea37 | |
|
dc6bad6b3e | |
|
756e3f0416 | |
![]() |
7130a05b23 | |
![]() |
08b5f7edc0 | |
|
26d1b2edc8 | |
|
f6c5fd7550 | |
|
860f52e7e1 | |
|
1b9602df77 | |
|
1684e5c04f | |
|
d7ab95eccc | |
|
5a88a1a4e6 | |
|
a489271a2f | |
|
c73b1c9e29 | |
|
9be6116cb8 | |
|
170977432e | |
![]() |
bc158891e7 | |
![]() |
68caf0751e | |
|
8a8f8693fe | |
|
da7ff8c749 | |
|
aa0280d57a | |
|
9b4f1b7cd9 | |
![]() |
6f57261c85 | |
![]() |
c2f0462811 | |
![]() |
078a453dcf | |
|
3be536d37a | |
|
256ab53e90 | |
![]() |
bdf6c7afe4 | |
![]() |
e9619542ea | |
|
e7b977cc6b | |
![]() |
f0778614ba | |
![]() |
4a5d4ea288 | |
|
843b8f2894 | |
|
5195f22f00 | |
|
5c529e6521 | |
![]() |
202cec92e9 | |
|
58287f488f | |
|
fb05890701 | |
|
f989e62702 | |
![]() |
15b02d9d08 | |
![]() |
bba4745381 | |
|
2b5443d74c | |
|
0ad1af9f51 | |
|
633a540fe7 | |
|
e0c8552c1e | |
|
63dc5b5572 | |
|
aaea118d65 | |
|
5dedc2d6bc | |
![]() |
b226495277 | |
|
299c0d4abe | |
|
1a393d8e9f | |
|
1ee20877ec | |
![]() |
766c6ea68b | |
![]() |
7b4e7d3542 | |
|
0080a07734 | |
|
a91fb41ef0 | |
|
a400046c91 | |
![]() |
437253e2eb | |
![]() |
a76ca41446 | |
![]() |
676914cc9d | |
|
9ce86f4102 | |
![]() |
a6675d6c3f | |
![]() |
dfd7d9f03f | |
|
464b9a2be2 | |
|
30acf6ed34 | |
![]() |
68a5ca9380 | |
|
4c0f059ae5 | |
![]() |
0fea52b923 | |
![]() |
5b2198ce4c | |
|
29ced2aded | |
|
7a06e21933 | |
|
3d3c0b5095 | |
|
6d1b410ba1 | |
|
71670f1214 | |
|
b7fe034faf | |
|
030c6ad61f | |
|
0b3444b37e | |
|
4db06a9fd7 | |
![]() |
1a5f81887a | |
![]() |
d51bea4928 | |
![]() |
11053da351 | |
|
0629d87a9f | |
|
4ad7042a93 | |
|
c42d249fd9 | |
|
08047fb002 | |
|
20c0f76043 | |
|
5726969431 | |
|
9ebdbec859 | |
|
1750544c0d | |
|
30512cb4f4 | |
|
9be808e37f | |
![]() |
27f62f4455 | |
|
f34b8f8756 | |
|
f23d00167e | |
|
dd62dd1704 | |
|
68b1e0c704 | |
|
79f486dcd2 | |
|
fc26e362d0 | |
|
79afad5006 | |
|
e2b2836a87 | |
|
9e322cff79 | |
|
8818bafad2 | |
|
28bc235b0b | |
|
50627aba6b | |
|
89bfb3a986 | |
|
a64887d420 | |
|
cd3a82195b | |
|
7d3c6bd4f5 | |
|
aaf6bcb320 | |
|
73ca563a0f | |
|
724c110437 | |
|
ca7ab2ebe0 | |
|
e0a5e4348e | |
|
e5bb8d10b2 | |
|
3b3cc7f639 | |
|
44d529e867 | |
|
55f3bc6201 | |
|
26de781181 | |
|
295d0dbe5c | |
|
1402029bfe | |
|
5d83c85b2d | |
|
d91d4e5ef8 | |
|
c70c3f9a7a | |
|
f208972bb8 | |
|
2777ebcda2 | |
|
a80a20ef6e | |
|
ab351fd8f8 | |
|
3a816ce5e5 | |
|
abc04a28a7 | |
|
9d6235b08c | |
|
4079765edb | |
|
76ffd0e8b9 | |
|
975dfad4aa | |
|
465ae57b07 | |
|
e1372fdd02 | |
|
628606480a | |
|
cd949d4f2a | |
|
78014b02bf | |
|
a299b9a841 | |
|
bcde15cec1 | |
![]() |
23b423a32d | |
|
993b1bde40 | |
|
d45e87d46f | |
|
cdc2ca755e | |
|
d7242f0fa1 | |
|
a1c8440fe2 | |
![]() |
6cfb56e6ca | |
![]() |
a5c3cd168e | |
|
44dc10ff8c | |
|
0d9d9887f4 | |
|
def926bff0 | |
|
94a7cf1e6c | |
![]() |
09a75bc77c | |
![]() |
25186132f2 | |
|
7e683ac6bb | |
|
7cf0ae4e67 | |
|
0462b28abf | |
|
ff1ffc120f | |
|
7158eca4f6 | |
![]() |
917374ba11 | |
![]() |
f6ec470070 | |
![]() |
0b2a5a910b | |
|
23ccaadba2 | |
|
4bb1b8d538 | |
|
06314a51a6 | |
|
49fad4b8bc | |
|
4e8657357f | |
|
dcbba90c18 | |
|
ec65ac3cef | |
|
49c66c73a7 | |
|
6ca0e48697 | |
|
52c5187d0e | |
|
6430ed76a6 | |
|
c1ea865f1e | |
|
480fcc1f8e | |
|
ee6a40a5d9 | |
|
aaa58e532b | |
|
ebf927dc46 | |
|
9b6ad6340f | |
|
f6a98e4169 | |
|
9050c5ca2b | |
|
71438d1030 | |
|
0e31deb88c | |
|
d55242f7e8 | |
|
9852bb14c3 | |
|
c0a4432c18 | |
|
9ea8ec422d | |
|
7fbd76630c | |
|
bc11ac3d79 | |
|
c5bb61cb9a | |
|
f30903072e | |
|
dabe7d6551 | |
![]() |
5c81abb253 | |
|
3598225cac | |
|
1b21d9e3fb | |
|
875d715e58 | |
|
4eae7e68b8 | |
|
3f33e03549 | |
|
c3546a66cd | |
|
4795de938e | |
![]() |
8c0757c942 | |
![]() |
41af42ce6f | |
![]() |
0ffa5e0cae | |
![]() |
747ae8ccd5 | |
|
6eb9108aa7 | |
![]() |
828de5d770 | |
![]() |
007feded68 | |
|
5f90b85c1d | |
![]() |
f1a4f7c68f | |
|
98ca09e64b | |
![]() |
3e9c9ea6d1 | |
![]() |
3a16c4be8a | |
![]() |
81623b38f7 | |
![]() |
06f3eacb9d | |
![]() |
93736781c5 | |
|
5bfb6ee4c1 | |
|
baf9a3f4a8 | |
![]() |
eb89f6a6a7 | |
![]() |
a24132412e | |
![]() |
d558443c22 | |
|
495e11fb4c | |
|
c477fbe89a | |
|
e07e435557 | |
![]() |
a4475e995b | |
![]() |
e0aeab0e20 | |
|
8e17efb9c6 | |
|
ef7cc1ebd6 | |
|
9e1ce515a8 | |
|
1e1f2a0e2f | |
|
19afa410b1 | |
|
fbb73968c9 | |
![]() |
0768ab2970 | |
![]() |
46e8135585 | |
|
540553199a | |
|
1c8ad3dc60 | |
|
b3c9eb3c33 | |
![]() |
64b1c51fad | |
|
22b5859b62 | |
|
e0d1de7a53 | |
|
fc274f09e9 | |
|
f8075ccb2f | |
![]() |
46c604bf92 | |
![]() |
daf81be4f6 | |
![]() |
030c779103 | |
|
3c5c4266cd | |
|
94fbc972be | |
|
ca51702799 | |
|
e721399e17 | |
|
244881f142 | |
|
b6cf496efa | |
|
6665a15aa3 | |
|
a667f41ec1 | |
|
5424973c52 | |
|
258de069e4 | |
|
cb58481daf | |
|
548cdee35b | |
![]() |
488d04284c | |
|
01f1a5c68c | |
|
6f80d439c3 | |
|
6696222c02 | |
|
4acfb88ee5 | |
|
97e6a5d5f2 | |
|
b26f300832 | |
|
349851dc59 | |
|
09e9f01f7e | |
|
da657e559b | |
|
53fa18907d | |
|
9d4893eb49 | |
|
6e849aa800 | |
|
194f6af412 | |
|
d5652fba18 | |
|
fbe5da1014 | |
|
478b080d45 | |
|
dcef7e7872 | |
|
2882289267 | |
|
37f608cdb8 | |
|
984856a29c | |
|
cbfb73d1cb | |
|
411b4e9de6 | |
|
b611308f3c | |
|
154225d229 | |
|
c859a16837 | |
|
33a669a940 | |
|
7b2d842ac2 | |
|
245086cf47 | |
|
a90eeac318 | |
|
1764fbdb88 | |
![]() |
22ccc3c974 | |
|
4d652d238d | |
|
6da4dbc165 | |
|
f65f4c273a | |
|
1af504825c | |
|
e94cf68cc5 | |
|
5fa2fd99b9 | |
|
20ab8a6683 | |
|
a7f709a663 | |
|
63c2cfed70 | |
|
80cd6fbae0 | |
|
49d3db6746 | |
|
bc11ec68e3 | |
|
2d2deec224 | |
|
8c58f77afb |
1190
.idea/workspace.xml
1190
.idea/workspace.xml
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,2 @@
|
||||||
|
{
|
||||||
|
}
|
|
@ -3425,9 +3425,9 @@
|
||||||
"integrity": "sha512-GRMWDxpOB6Dgk2E5Uo+3eEBvtOOlimMmpbFiKuLFnQzYDavtLFY3K5ona41jgN/WdRZtG7utuVSVTL4HbZHGkw=="
|
"integrity": "sha512-GRMWDxpOB6Dgk2E5Uo+3eEBvtOOlimMmpbFiKuLFnQzYDavtLFY3K5ona41jgN/WdRZtG7utuVSVTL4HbZHGkw=="
|
||||||
},
|
},
|
||||||
"clipboard": {
|
"clipboard": {
|
||||||
"version": "2.0.6",
|
"version": "2.0.8",
|
||||||
"resolved": "https://registry.npmjs.org/clipboard/-/clipboard-2.0.6.tgz",
|
"resolved": "https://registry.npmjs.org/clipboard/-/clipboard-2.0.8.tgz",
|
||||||
"integrity": "sha512-g5zbiixBRk/wyKakSwCKd7vQXDjFnAMGHoEyBogG/bw9kTD9GvdAvaoRR1ALcEzt3pVKxZR0pViekPMIS0QyGg==",
|
"integrity": "sha512-Y6WO0unAIQp5bLmk1zdThRhgJt/x3ks6f30s3oE3H1mgIEU33XyQjEf8gsf6DxC7NPX8Y1SsNWjUjL/ywLnnbQ==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"good-listener": "^1.2.2",
|
"good-listener": "^1.2.2",
|
||||||
"select": "^1.1.2",
|
"select": "^1.1.2",
|
||||||
|
@ -3875,6 +3875,52 @@
|
||||||
"warning": "^4.0.3"
|
"warning": "^4.0.3"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"cross-env": {
|
||||||
|
"version": "7.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/cross-env/-/cross-env-7.0.3.tgz",
|
||||||
|
"integrity": "sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw==",
|
||||||
|
"requires": {
|
||||||
|
"cross-spawn": "^7.0.1"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"cross-spawn": {
|
||||||
|
"version": "7.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
|
||||||
|
"integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==",
|
||||||
|
"requires": {
|
||||||
|
"path-key": "^3.1.0",
|
||||||
|
"shebang-command": "^2.0.0",
|
||||||
|
"which": "^2.0.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"path-key": {
|
||||||
|
"version": "3.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
|
||||||
|
"integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q=="
|
||||||
|
},
|
||||||
|
"shebang-command": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
|
||||||
|
"integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==",
|
||||||
|
"requires": {
|
||||||
|
"shebang-regex": "^3.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"shebang-regex": {
|
||||||
|
"version": "3.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
|
||||||
|
"integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A=="
|
||||||
|
},
|
||||||
|
"which": {
|
||||||
|
"version": "2.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
|
||||||
|
"integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
|
||||||
|
"requires": {
|
||||||
|
"isexe": "^2.0.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"cross-fetch": {
|
"cross-fetch": {
|
||||||
"version": "3.1.4",
|
"version": "3.1.4",
|
||||||
"resolved": "https://registry.nlark.com/cross-fetch/download/cross-fetch-3.1.4.tgz",
|
"resolved": "https://registry.nlark.com/cross-fetch/download/cross-fetch-3.1.4.tgz",
|
||||||
|
@ -4885,7 +4931,7 @@
|
||||||
},
|
},
|
||||||
"dom-closest": {
|
"dom-closest": {
|
||||||
"version": "0.2.0",
|
"version": "0.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/dom-closest/-/dom-closest-0.2.0.tgz",
|
"resolved": "https://registry.npm.taobao.org/dom-closest/download/dom-closest-0.2.0.tgz",
|
||||||
"integrity": "sha1-69n5HRvyLo1vR3h2u80+yQIWwM8=",
|
"integrity": "sha1-69n5HRvyLo1vR3h2u80+yQIWwM8=",
|
||||||
"requires": {
|
"requires": {
|
||||||
"dom-matches": ">=1.0.1"
|
"dom-matches": ">=1.0.1"
|
||||||
|
@ -4929,7 +4975,7 @@
|
||||||
},
|
},
|
||||||
"dom-matches": {
|
"dom-matches": {
|
||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/dom-matches/-/dom-matches-2.0.0.tgz",
|
"resolved": "https://registry.npm.taobao.org/dom-matches/download/dom-matches-2.0.0.tgz",
|
||||||
"integrity": "sha1-0nKLQWqHUzmA6wibhI0lPPI6dYw="
|
"integrity": "sha1-0nKLQWqHUzmA6wibhI0lPPI6dYw="
|
||||||
},
|
},
|
||||||
"dom-scroll-into-view": {
|
"dom-scroll-into-view": {
|
||||||
|
@ -5187,7 +5233,7 @@
|
||||||
},
|
},
|
||||||
"enquire.js": {
|
"enquire.js": {
|
||||||
"version": "2.1.6",
|
"version": "2.1.6",
|
||||||
"resolved": "https://registry.npmjs.org/enquire.js/-/enquire.js-2.1.6.tgz",
|
"resolved": "https://registry.npm.taobao.org/enquire.js/download/enquire.js-2.1.6.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fenquire.js%2Fdownload%2Fenquire.js-2.1.6.tgz",
|
||||||
"integrity": "sha1-PoeAybi4NQhMP2DhZtvDwqPImBQ="
|
"integrity": "sha1-PoeAybi4NQhMP2DhZtvDwqPImBQ="
|
||||||
},
|
},
|
||||||
"entities": {
|
"entities": {
|
||||||
|
@ -5706,7 +5752,7 @@
|
||||||
},
|
},
|
||||||
"eventlistener": {
|
"eventlistener": {
|
||||||
"version": "0.0.1",
|
"version": "0.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/eventlistener/-/eventlistener-0.0.1.tgz",
|
"resolved": "https://registry.npm.taobao.org/eventlistener/download/eventlistener-0.0.1.tgz",
|
||||||
"integrity": "sha1-7Suqu4UiJ68rz4iRUscsY8pTLrg="
|
"integrity": "sha1-7Suqu4UiJ68rz4iRUscsY8pTLrg="
|
||||||
},
|
},
|
||||||
"events": {
|
"events": {
|
||||||
|
@ -8040,7 +8086,7 @@
|
||||||
},
|
},
|
||||||
"hammerjs": {
|
"hammerjs": {
|
||||||
"version": "2.0.8",
|
"version": "2.0.8",
|
||||||
"resolved": "https://registry.npmjs.org/hammerjs/-/hammerjs-2.0.8.tgz",
|
"resolved": "https://registry.npm.taobao.org/hammerjs/download/hammerjs-2.0.8.tgz",
|
||||||
"integrity": "sha1-BO93hiz/K7edMPdpIJWTAiK/YPE="
|
"integrity": "sha1-BO93hiz/K7edMPdpIJWTAiK/YPE="
|
||||||
},
|
},
|
||||||
"handle-thing": {
|
"handle-thing": {
|
||||||
|
@ -8881,7 +8927,7 @@
|
||||||
},
|
},
|
||||||
"immutable": {
|
"immutable": {
|
||||||
"version": "3.7.6",
|
"version": "3.7.6",
|
||||||
"resolved": "https://registry.npmjs.org/immutable/-/immutable-3.7.6.tgz",
|
"resolved": "https://registry.npm.taobao.org/immutable/download/immutable-3.7.6.tgz",
|
||||||
"integrity": "sha1-E7TTyxK++hVIKib+Gy665kAHHks="
|
"integrity": "sha1-E7TTyxK++hVIKib+Gy665kAHHks="
|
||||||
},
|
},
|
||||||
"import-fresh": {
|
"import-fresh": {
|
||||||
|
@ -10486,7 +10532,7 @@
|
||||||
},
|
},
|
||||||
"lodash.throttle": {
|
"lodash.throttle": {
|
||||||
"version": "4.1.1",
|
"version": "4.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/lodash.throttle/-/lodash.throttle-4.1.1.tgz",
|
"resolved": "https://registry.npm.taobao.org/lodash.throttle/download/lodash.throttle-4.1.1.tgz",
|
||||||
"integrity": "sha1-wj6RtxAkKscMN/HhzaknTMOb8vQ="
|
"integrity": "sha1-wj6RtxAkKscMN/HhzaknTMOb8vQ="
|
||||||
},
|
},
|
||||||
"lodash.uniq": {
|
"lodash.uniq": {
|
||||||
|
@ -16586,6 +16632,11 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"save-dev": {
|
||||||
|
"version": "0.0.1-security",
|
||||||
|
"resolved": "https://registry.npmjs.org/save-dev/-/save-dev-0.0.1-security.tgz",
|
||||||
|
"integrity": "sha512-k6knZTDNK8PKKbIqnvxiOveJinuw2LcQjqDoaorZWP9M5AR2EPsnpDeSbeoZZ0pHr5ze1uoaKdK8NBGQrJ34Uw=="
|
||||||
|
},
|
||||||
"sax": {
|
"sax": {
|
||||||
"version": "1.2.4",
|
"version": "1.2.4",
|
||||||
"resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz",
|
"resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz",
|
||||||
|
|
|
@ -22,10 +22,11 @@
|
||||||
"case-sensitive-paths-webpack-plugin": "2.1.1",
|
"case-sensitive-paths-webpack-plugin": "2.1.1",
|
||||||
"chalk": "1.1.3",
|
"chalk": "1.1.3",
|
||||||
"classnames": "^2.2.5",
|
"classnames": "^2.2.5",
|
||||||
"clipboard": "^2.0.6",
|
"clipboard": "^2.0.8",
|
||||||
"code-prettify": "^0.1.0",
|
"code-prettify": "^0.1.0",
|
||||||
"codemirror": "^5.53.0",
|
"codemirror": "^5.53.0",
|
||||||
"connected-react-router": "4.4.1",
|
"connected-react-router": "4.4.1",
|
||||||
|
"cross-env": "^7.0.3",
|
||||||
"css-loader": "^3.5.2",
|
"css-loader": "^3.5.2",
|
||||||
"dompurify": "^2.0.15",
|
"dompurify": "^2.0.15",
|
||||||
"dotenv": "4.0.0",
|
"dotenv": "4.0.0",
|
||||||
|
@ -103,6 +104,7 @@
|
||||||
"redux-thunk": "2.3.0",
|
"redux-thunk": "2.3.0",
|
||||||
"rsuite": "^4.3.4",
|
"rsuite": "^4.3.4",
|
||||||
"sass-loader": "7.3.1",
|
"sass-loader": "7.3.1",
|
||||||
|
"save-dev": "0.0.1-security",
|
||||||
"scroll-into-view": "^1.14.2",
|
"scroll-into-view": "^1.14.2",
|
||||||
"showdown": "^1.9.1",
|
"showdown": "^1.9.1",
|
||||||
"showdown-katex": "^0.8.0",
|
"showdown-katex": "^0.8.0",
|
||||||
|
@ -122,8 +124,8 @@
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "node --max_old_space_size=15360 scripts/start.js",
|
"start": "node --max_old_space_size=15360 scripts/start.js",
|
||||||
"build": "NODE_ENV=production node --max_old_space_size=15360 scripts/build.js",
|
"build": "cross-env NODE_ENV=production node --max_old_space_size=15360 scripts/build.js",
|
||||||
"test-build": "NODE_ENV=testBuild node --max_old_space_size=15360 scripts/build.js",
|
"test-build": "cross-env NODE_ENV=testBuild node --max_old_space_size=15360 scripts/build.js",
|
||||||
"pre-build": "NODE_ENV=preBuild node --max_old_space_size=15360 scripts/build.js",
|
"pre-build": "NODE_ENV=preBuild node --max_old_space_size=15360 scripts/build.js",
|
||||||
"gen_stats": "NODE_ENV=production webpack --profile --config=./config/webpack.config.prod.js --json > stats.json",
|
"gen_stats": "NODE_ENV=production webpack --profile --config=./config/webpack.config.prod.js --json > stats.json",
|
||||||
"ana": "webpack-bundle-analyzer ./stats.json",
|
"ana": "webpack-bundle-analyzer ./stats.json",
|
||||||
|
@ -193,6 +195,7 @@
|
||||||
"babel-core": "^6.26.0",
|
"babel-core": "^6.26.0",
|
||||||
"babel-plugin-import": "^1.13.0",
|
"babel-plugin-import": "^1.13.0",
|
||||||
"babel-plugin-transform-runtime": "^6.23.0",
|
"babel-plugin-transform-runtime": "^6.23.0",
|
||||||
|
"babel-polyfill": "^6.26.0",
|
||||||
"babel-preset-es2015": "^6.24.1",
|
"babel-preset-es2015": "^6.24.1",
|
||||||
"babel-preset-react": "^6.24.1",
|
"babel-preset-react": "^6.24.1",
|
||||||
"babel-preset-stage-2": "^6.24.1",
|
"babel-preset-stage-2": "^6.24.1",
|
||||||
|
|
|
@ -114,14 +114,6 @@ a:visited {
|
||||||
color: #898989;
|
color: #898989;
|
||||||
}
|
}
|
||||||
|
|
||||||
a:hover {
|
|
||||||
color: #FF7500;
|
|
||||||
}
|
|
||||||
|
|
||||||
a:hover.fa {
|
|
||||||
color: #FF7500;
|
|
||||||
}
|
|
||||||
|
|
||||||
input,
|
input,
|
||||||
textarea,
|
textarea,
|
||||||
select {
|
select {
|
||||||
|
|
|
@ -97,10 +97,6 @@ a:visited {
|
||||||
color: #05101a;
|
color: #05101a;
|
||||||
}
|
}
|
||||||
|
|
||||||
a:hover {
|
|
||||||
color: #459be5;
|
|
||||||
}
|
|
||||||
|
|
||||||
ol,
|
ol,
|
||||||
ul,
|
ul,
|
||||||
li {
|
li {
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
@charset "utf-8";
|
||||||
/* 头部 */
|
/* 头部 */
|
||||||
.header {
|
.header {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
@ -1271,7 +1272,7 @@ html body {
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
line-height: 2.0;
|
line-height: 2.0;
|
||||||
background: #fafafa;
|
background: #fafafa;
|
||||||
font-family: "微软雅黑", "宋体";
|
font-family: "Microsoft YaHei", "SimSun";
|
||||||
color: #05101a;
|
color: #05101a;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
position: relative;
|
position: relative;
|
||||||
|
@ -1307,6 +1308,7 @@ td,
|
||||||
span {
|
span {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
|
margin-bottom: 0px!important;
|
||||||
}
|
}
|
||||||
|
|
||||||
table,
|
table,
|
||||||
|
@ -1363,10 +1365,6 @@ a:visited {
|
||||||
color: #05101a;
|
color: #05101a;
|
||||||
}
|
}
|
||||||
|
|
||||||
a:hover {
|
|
||||||
color: #459be5;
|
|
||||||
}
|
|
||||||
|
|
||||||
ol,
|
ol,
|
||||||
ul,
|
ul,
|
||||||
li {
|
li {
|
||||||
|
@ -1473,7 +1471,7 @@ a.edu-txt-w80,
|
||||||
|
|
||||||
/*隐藏*/
|
/*隐藏*/
|
||||||
.none {
|
.none {
|
||||||
display: none
|
display: none!important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.block {
|
.block {
|
||||||
|
@ -1522,7 +1520,15 @@ a.edu-txt-w80,
|
||||||
.font-16 {
|
.font-16 {
|
||||||
font-size: 16px !important;
|
font-size: 16px !important;
|
||||||
}
|
}
|
||||||
|
.weight400{
|
||||||
|
font-weight: 400;
|
||||||
|
}
|
||||||
|
.weight500{
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
.weight{
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
.font-17 {
|
.font-17 {
|
||||||
font-size: 17px !important;
|
font-size: 17px !important;
|
||||||
}
|
}
|
||||||
|
@ -1542,6 +1548,9 @@ a.edu-txt-w80,
|
||||||
.font-25 {
|
.font-25 {
|
||||||
font-size: 25px !important;
|
font-size: 25px !important;
|
||||||
}
|
}
|
||||||
|
.font-26 {
|
||||||
|
font-size: 26px !important;
|
||||||
|
}
|
||||||
|
|
||||||
.font-24 {
|
.font-24 {
|
||||||
font-size: 24px !important;
|
font-size: 24px !important;
|
||||||
|
@ -1563,6 +1572,9 @@ a.edu-txt-w80,
|
||||||
font-size: 36px !important;
|
font-size: 36px !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.font-40 {
|
||||||
|
font-size: 40px !important;
|
||||||
|
}
|
||||||
.font-50 {
|
.font-50 {
|
||||||
font-size: 50px !important;
|
font-size: 50px !important;
|
||||||
}
|
}
|
||||||
|
@ -1748,6 +1760,14 @@ a.decoration {
|
||||||
margin-bottom: 10px;
|
margin-bottom: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.mb12 {
|
||||||
|
margin-bottom: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mb13 {
|
||||||
|
margin-bottom: 13px;
|
||||||
|
}
|
||||||
|
|
||||||
.mb14 {
|
.mb14 {
|
||||||
margin-bottom: 14px;
|
margin-bottom: 14px;
|
||||||
}
|
}
|
||||||
|
@ -2436,7 +2456,11 @@ a.hoverLine:hover{
|
||||||
|
|
||||||
|
|
||||||
.color-grey-9 {
|
.color-grey-9 {
|
||||||
color: #999999 !important;
|
color: #999 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
a:hover{
|
||||||
|
color: #466AFF !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.color-grey-98 {
|
.color-grey-98 {
|
||||||
|
@ -2471,33 +2495,23 @@ a.hoverLine:hover{
|
||||||
a.color-grey-name:hover,
|
a.color-grey-name:hover,
|
||||||
a.color-dark:hover,
|
a.color-dark:hover,
|
||||||
a.color-grey-6:hover,
|
a.color-grey-6:hover,
|
||||||
a.color-grey-3:hover {
|
a.color-grey-3:hover,a.color-ooo:hover {
|
||||||
color: #4cacff !important;
|
color: #2A61FF !important;
|
||||||
}
|
|
||||||
|
|
||||||
a.color-grey-9:hover,
|
|
||||||
a.color-grey-8:hover,
|
|
||||||
a.color-grey-c:hover {
|
|
||||||
color: #111C24 !important;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*蓝色*/
|
/*蓝色*/
|
||||||
.color-blue {
|
.color-blue {
|
||||||
color: #4CACFF !important;
|
color: #2A61FF !important;
|
||||||
|
}
|
||||||
|
.color-blue-file {
|
||||||
|
color: #4598FA!important;
|
||||||
}
|
}
|
||||||
/* 绿色 */
|
/* 绿色 */
|
||||||
.color-green-file{
|
|
||||||
color: #28BD6C;
|
|
||||||
}
|
|
||||||
/*主*/
|
/*主*/
|
||||||
.color-blue_4C {
|
.color-blue_4C {
|
||||||
color: #4CACFF !important;
|
color: #4CACFF !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
a.color-blue:hover,
|
|
||||||
a.color-blue_4C:hover {
|
|
||||||
color: #459BE6 !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*橙色*/
|
/*橙色*/
|
||||||
.color-orange {
|
.color-orange {
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
@font-face {
|
@font-face {
|
||||||
font-family: "iconfont"; /* Project id 2340181 */
|
font-family: "iconfont"; /* Project id 2340181 */
|
||||||
src: url('iconfont.woff2?t=1630632852475') format('woff2'),
|
src: url('iconfont.woff2?t=1632964996877') format('woff2'),
|
||||||
url('iconfont.woff?t=1630632852475') format('woff'),
|
url('iconfont.woff?t=1632964996877') format('woff'),
|
||||||
url('iconfont.ttf?t=1630632852475') format('truetype');
|
url('iconfont.ttf?t=1632964996877') format('truetype');
|
||||||
}
|
}
|
||||||
|
|
||||||
.iconfont {
|
.iconfont {
|
||||||
|
@ -13,6 +13,82 @@
|
||||||
-moz-osx-font-smoothing: grayscale;
|
-moz-osx-font-smoothing: grayscale;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.icon-wenjian7:before {
|
||||||
|
content: "\e8e0";
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-xiangyoujiantou:before {
|
||||||
|
content: "\e8de";
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-xiangzuojiantou:before {
|
||||||
|
content: "\e8df";
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-a-liulanicon2x:before {
|
||||||
|
content: "\e8dd";
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-wenjianicon:before {
|
||||||
|
content: "\e8dc";
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-a-yuanquan2x:before {
|
||||||
|
content: "\e8db";
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-xiangmubiaoqian:before {
|
||||||
|
content: "\e8da";
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-icon:before {
|
||||||
|
content: "\e8ce";
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-tar:before {
|
||||||
|
content: "\e8cf";
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-a-fuzhi2:before {
|
||||||
|
content: "\e8d0";
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-fujian1:before {
|
||||||
|
content: "\e8d1";
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-a-bianji1:before {
|
||||||
|
content: "\e8d2";
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-banbenicon:before {
|
||||||
|
content: "\e8d3";
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-shanchuicon2:before {
|
||||||
|
content: "\e8d4";
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-a-lajitong_icon3x:before {
|
||||||
|
content: "\e8d5";
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-xialaanniu2:before {
|
||||||
|
content: "\e8d6";
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-xiazai-icon:before {
|
||||||
|
content: "\e8d7";
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-master_icon1:before {
|
||||||
|
content: "\e8d8";
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-shangchuanicon:before {
|
||||||
|
content: "\e8d9";
|
||||||
|
}
|
||||||
|
|
||||||
.icon-gerenziliao1:before {
|
.icon-gerenziliao1:before {
|
||||||
content: "\e8c7";
|
content: "\e8c7";
|
||||||
}
|
}
|
||||||
|
|
File diff suppressed because one or more lines are too long
|
@ -5,6 +5,139 @@
|
||||||
"css_prefix_text": "icon-",
|
"css_prefix_text": "icon-",
|
||||||
"description": "",
|
"description": "",
|
||||||
"glyphs": [
|
"glyphs": [
|
||||||
|
{
|
||||||
|
"icon_id": "24656750",
|
||||||
|
"name": "文件",
|
||||||
|
"font_class": "wenjian7",
|
||||||
|
"unicode": "e8e0",
|
||||||
|
"unicode_decimal": 59616
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"icon_id": "630094",
|
||||||
|
"name": "向右箭头",
|
||||||
|
"font_class": "xiangyoujiantou",
|
||||||
|
"unicode": "e8de",
|
||||||
|
"unicode_decimal": 59614
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"icon_id": "630095",
|
||||||
|
"name": "向左箭头",
|
||||||
|
"font_class": "xiangzuojiantou",
|
||||||
|
"unicode": "e8df",
|
||||||
|
"unicode_decimal": 59615
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"icon_id": "24600282",
|
||||||
|
"name": "浏览icon@2x",
|
||||||
|
"font_class": "a-liulanicon2x",
|
||||||
|
"unicode": "e8dd",
|
||||||
|
"unicode_decimal": 59613
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"icon_id": "24567893",
|
||||||
|
"name": "文件icon",
|
||||||
|
"font_class": "wenjianicon",
|
||||||
|
"unicode": "e8dc",
|
||||||
|
"unicode_decimal": 59612
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"icon_id": "24527422",
|
||||||
|
"name": "圆圈@2x",
|
||||||
|
"font_class": "a-yuanquan2x",
|
||||||
|
"unicode": "e8db",
|
||||||
|
"unicode_decimal": 59611
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"icon_id": "24378423",
|
||||||
|
"name": "项目标签",
|
||||||
|
"font_class": "xiangmubiaoqian",
|
||||||
|
"unicode": "e8da",
|
||||||
|
"unicode_decimal": 59610
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"icon_id": "24368060",
|
||||||
|
"name": "icon",
|
||||||
|
"font_class": "icon",
|
||||||
|
"unicode": "e8ce",
|
||||||
|
"unicode_decimal": 59598
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"icon_id": "24368061",
|
||||||
|
"name": "tar",
|
||||||
|
"font_class": "tar",
|
||||||
|
"unicode": "e8cf",
|
||||||
|
"unicode_decimal": 59599
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"icon_id": "24289113",
|
||||||
|
"name": "复制 (2)",
|
||||||
|
"font_class": "a-fuzhi2",
|
||||||
|
"unicode": "e8d0",
|
||||||
|
"unicode_decimal": 59600
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"icon_id": "24289114",
|
||||||
|
"name": "附件",
|
||||||
|
"font_class": "fujian1",
|
||||||
|
"unicode": "e8d1",
|
||||||
|
"unicode_decimal": 59601
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"icon_id": "24289115",
|
||||||
|
"name": "编 辑",
|
||||||
|
"font_class": "a-bianji1",
|
||||||
|
"unicode": "e8d2",
|
||||||
|
"unicode_decimal": 59602
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"icon_id": "24289116",
|
||||||
|
"name": "版本icon",
|
||||||
|
"font_class": "banbenicon",
|
||||||
|
"unicode": "e8d3",
|
||||||
|
"unicode_decimal": 59603
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"icon_id": "24289117",
|
||||||
|
"name": "删除icon",
|
||||||
|
"font_class": "shanchuicon2",
|
||||||
|
"unicode": "e8d4",
|
||||||
|
"unicode_decimal": 59604
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"icon_id": "24289118",
|
||||||
|
"name": "垃圾桶_icon@3x",
|
||||||
|
"font_class": "a-lajitong_icon3x",
|
||||||
|
"unicode": "e8d5",
|
||||||
|
"unicode_decimal": 59605
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"icon_id": "24289119",
|
||||||
|
"name": "下拉按钮",
|
||||||
|
"font_class": "xialaanniu2",
|
||||||
|
"unicode": "e8d6",
|
||||||
|
"unicode_decimal": 59606
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"icon_id": "24289120",
|
||||||
|
"name": "下载-icon",
|
||||||
|
"font_class": "xiazai-icon",
|
||||||
|
"unicode": "e8d7",
|
||||||
|
"unicode_decimal": 59607
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"icon_id": "24289121",
|
||||||
|
"name": "master_icon",
|
||||||
|
"font_class": "master_icon1",
|
||||||
|
"unicode": "e8d8",
|
||||||
|
"unicode_decimal": 59608
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"icon_id": "24289122",
|
||||||
|
"name": "上传icon",
|
||||||
|
"font_class": "shangchuanicon",
|
||||||
|
"unicode": "e8d9",
|
||||||
|
"unicode_decimal": 59609
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"icon_id": "24059956",
|
"icon_id": "24059956",
|
||||||
"name": "个人资料",
|
"name": "个人资料",
|
||||||
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -3319,9 +3319,9 @@
|
||||||
text = text.replace(emailReg, function ($1, $2, $3, $4) {
|
text = text.replace(emailReg, function ($1, $2, $3, $4) {
|
||||||
return $1.replace(/@/g, "_#_@_#_");
|
return $1.replace(/@/g, "_#_@_#_");
|
||||||
});
|
});
|
||||||
|
// " + editormd.urls.atLinkBase + "" + $2 + "
|
||||||
text = text.replace(atLinkReg, function ($1, $2) {
|
text = text.replace(atLinkReg, function ($1, $2) {
|
||||||
return "<a href=\"" + editormd.urls.atLinkBase + "" + $2 + "\" title=\"@" + $2 + "\" class=\"at-link\">" + $1 + "</a>";
|
return "<span title=\"@" + $2 + "\" class=\"at-link\"> " + $1 + " </span>";
|
||||||
}).replace(/_#_@_#_/g, "@");
|
}).replace(/_#_@_#_/g, "@");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
24
src/App.js
24
src/App.js
|
@ -19,7 +19,7 @@ import moment from 'moment'
|
||||||
import { MuiThemeProvider, createMuiTheme } from 'material-ui/styles';
|
import { MuiThemeProvider, createMuiTheme } from 'material-ui/styles';
|
||||||
import SiderBar from './forge/Component/SiderBar'
|
import SiderBar from './forge/Component/SiderBar'
|
||||||
|
|
||||||
import { SnackbarHOC } from 'educoder'
|
import { SnackbarHOC } from 'educoder';
|
||||||
import { initAxiosInterceptors } from './AppConfig'
|
import { initAxiosInterceptors } from './AppConfig'
|
||||||
import { Provider } from 'react-redux';
|
import { Provider } from 'react-redux';
|
||||||
import configureStore from './redux/stores/configureStore';
|
import configureStore from './redux/stores/configureStore';
|
||||||
|
@ -39,6 +39,11 @@ const Projects = Loadable({
|
||||||
loader: () => import('./forge/Index'),
|
loader: () => import('./forge/Index'),
|
||||||
loading: Loading,
|
loading: Loading,
|
||||||
})
|
})
|
||||||
|
// forge项目详情
|
||||||
|
const ProjectDetail = Loadable({
|
||||||
|
loader: () => import("./forge/Main/DetailAdaptor"),
|
||||||
|
loading: Loading,
|
||||||
|
});
|
||||||
//forge安全设置
|
//forge安全设置
|
||||||
const Security = Loadable({
|
const Security = Loadable({
|
||||||
loader: () => import('./forge/SecuritySetting/Index'),
|
loader: () => import('./forge/SecuritySetting/Index'),
|
||||||
|
@ -92,8 +97,13 @@ const ProjectIndex = Loadable({
|
||||||
loading: Loading,
|
loading: Loading,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// const CreateMerge = Loadable({
|
||||||
|
// loader: () => import('./forge/Merge/NewMerge'),
|
||||||
|
// loading: Loading,
|
||||||
|
// })
|
||||||
|
|
||||||
// 此处仅维护前端可能的一级路由,不用进行项目或者组织判断的字段。
|
// 此处仅维护前端可能的一级路由,不用进行项目或者组织判断的字段。
|
||||||
const keyWord = ["explore", "settings", "setting", "CCF", "mulan", "wiki", "issues", "setting", "trending", "code", "projects", "pulls", "mine", "login", "register", "email", "export", "nopage", "404", "403", "500", "501", "search"];
|
const keyWord = ["explore", "settings", "setting", "mulan", "wiki", "issues", "setting", "trending", "code", "projects", "pulls", "mine", "login", "register", "email", "export", "nopage", "404", "403", "500", "501", "search", "organize"];
|
||||||
|
|
||||||
class App extends Component {
|
class App extends Component {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
|
@ -268,6 +278,13 @@ class App extends Component {
|
||||||
}
|
}
|
||||||
} />
|
} />
|
||||||
|
|
||||||
|
{/* 项目PR */}
|
||||||
|
<Route path="/:owner/:projectsId/compare"
|
||||||
|
render={
|
||||||
|
(props) => (<ProjectDetail {...this.props} {...props} {...this.state} />)
|
||||||
|
}
|
||||||
|
></Route>
|
||||||
|
|
||||||
{/*项目*/}
|
{/*项目*/}
|
||||||
<Route
|
<Route
|
||||||
path={"/:owner/:projectId/devops/:opsId/detail"}
|
path={"/:owner/:projectId/devops/:opsId/detail"}
|
||||||
|
@ -348,7 +365,7 @@ class App extends Component {
|
||||||
return (<OrganizeIndex {...props} {...this.props} {...this.state} />)
|
return (<OrganizeIndex {...props} {...this.props} {...this.state} />)
|
||||||
}
|
}
|
||||||
}>
|
}>
|
||||||
</Route> : pathType === '404' ? <Route path="/" component={Shixunnopage} /> :
|
</Route> : pathType === '404' ? <Route component={Shixunnopage} />:
|
||||||
<Route exact path="/"
|
<Route exact path="/"
|
||||||
render={
|
render={
|
||||||
(props) => (
|
(props) => (
|
||||||
|
@ -360,6 +377,7 @@ class App extends Component {
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
// <Route path="/" component={Loading} />
|
// <Route path="/" component={Loading} />
|
||||||
|
// <Route path="/" component={Shixunnopage} />
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -11,9 +11,9 @@ broadcastChannelOnmessage('refreshPage', () => {
|
||||||
})
|
})
|
||||||
|
|
||||||
function locationurl(list) {
|
function locationurl(list) {
|
||||||
// if (window.location.port !== "3007") {
|
if (window.location.port !== "3007") {
|
||||||
window.location.href = list
|
window.location.href = list
|
||||||
// }
|
}
|
||||||
}
|
}
|
||||||
// TODO 开发期多个身份切换
|
// TODO 开发期多个身份切换
|
||||||
let debugType = ""
|
let debugType = ""
|
||||||
|
@ -86,7 +86,7 @@ export function initAxiosInterceptors(props) {
|
||||||
|
|
||||||
if (response.data.status === 404) {
|
if (response.data.status === 404) {
|
||||||
let responseURL = response.request ? response.request.responseURL:'';
|
let responseURL = response.request ? response.request.responseURL:'';
|
||||||
if (responseURL.indexOf('/api/users/') === -1 && responseURL.indexOf('/api/organizations/') === -1 && responseURL.indexOf('/api/owners/') === -1) {
|
if (responseURL.indexOf('/api/users/') === -1 && responseURL.indexOf('/api/organizations/') === -1 ) {
|
||||||
locationurl('/nopage');
|
locationurl('/nopage');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -218,7 +218,7 @@ a:hover {
|
||||||
}
|
}
|
||||||
|
|
||||||
.color-blue {
|
.color-blue {
|
||||||
color: #4CACFF;
|
color: #2A61FF;
|
||||||
}
|
}
|
||||||
|
|
||||||
.color-huang {
|
.color-huang {
|
||||||
|
|
|
@ -69,7 +69,7 @@ export function appendFileSizeToUploadFile(item) {
|
||||||
}
|
}
|
||||||
export function appendFileSizeToUploadFileAll(fileList) {
|
export function appendFileSizeToUploadFileAll(fileList) {
|
||||||
return fileList.map(item => {
|
return fileList.map(item => {
|
||||||
if (item.name.indexOf(uploadNameSizeSeperator) == -1) {
|
if (item.name.indexOf(uploadNameSizeSeperator) === -1) {
|
||||||
return Object.assign({}, item, { name: `${item.name}${uploadNameSizeSeperator}${bytesToSize(item.size)}` })
|
return Object.assign({}, item, { name: `${item.name}${uploadNameSizeSeperator}${bytesToSize(item.size)}` })
|
||||||
}
|
}
|
||||||
return item
|
return item
|
||||||
|
|
|
@ -18,6 +18,23 @@ export function getImageUrl(path) {
|
||||||
return `${path}`;
|
return `${path}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function numFormat(num, digits){
|
||||||
|
let d = digits || 1;
|
||||||
|
var si = [
|
||||||
|
{ value: 1, symbol: "" },
|
||||||
|
{ value: 1E3, symbol: "k" },
|
||||||
|
{ value: 1E4, symbol: "W" }
|
||||||
|
];
|
||||||
|
var rx = /\.0+$|(\.[0-9]*[1-9])0+$/;
|
||||||
|
var i;
|
||||||
|
for (i = si.length - 1; i > 0; i--) {
|
||||||
|
if (num >= si[i].value) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return (num / si[i].value).toFixed(d).replace(rx, "$1") + si[i].symbol;
|
||||||
|
}
|
||||||
|
|
||||||
export function getImage(path) {
|
export function getImage(path) {
|
||||||
// https://www.educoder.net
|
// https://www.educoder.net
|
||||||
// https://testbdweb.trustie.net
|
// https://testbdweb.trustie.net
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
// export { default as OrderStateUtil } from '../routes/Order/components/OrderStateUtil';
|
// export { default as OrderStateUtil } from '../routes/Order/components/OrderStateUtil';
|
||||||
|
|
||||||
export {
|
export {
|
||||||
getUploadLogoActionUrl as getUploadLogoActionUrl,
|
getUploadLogoActionUrl as getUploadLogoActionUrl,numFormat as numFormat,
|
||||||
getImageUrl as getImageUrl,getImage as getImage, getmyUrl as getmyUrl, getRandomNumber as getRandomNumber, getUrl as getUrl, publicSearchs as publicSearchs, getRandomcode as getRandomcode, getUrlmys as getUrlmys, getUrl2 as getUrl2, setImagesUrl as setImagesUrl
|
getImageUrl as getImageUrl,getImage as getImage, getmyUrl as getmyUrl, getRandomNumber as getRandomNumber, getUrl as getUrl, publicSearchs as publicSearchs, getRandomcode as getRandomcode, getUrlmys as getUrlmys, getUrl2 as getUrl2, setImagesUrl as setImagesUrl
|
||||||
, getUploadActionUrl as getUploadActionUrl, getUploadActionUrltwo as getUploadActionUrltwo, getUploadActionUrlthree as getUploadActionUrlthree, getUploadActionUrlOfAuth as getUploadActionUrlOfAuth
|
, getUploadActionUrl as getUploadActionUrl, getUploadActionUrltwo as getUploadActionUrltwo, getUploadActionUrlthree as getUploadActionUrlthree, getUploadActionUrlOfAuth as getUploadActionUrlOfAuth
|
||||||
, getTaskUrlById as getTaskUrlById, TEST_HOST, htmlEncode as htmlEncode, getupload_git_file as getupload_git_file, getcdnImageUrl as getcdnImageUrl
|
, getTaskUrlById as getTaskUrlById, TEST_HOST, htmlEncode as htmlEncode, getupload_git_file as getupload_git_file, getcdnImageUrl as getcdnImageUrl
|
||||||
|
|
|
@ -10,6 +10,10 @@ import ActivityItem from './ActivityItem';
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
const LIMIT = 15;
|
const LIMIT = 15;
|
||||||
const ARRAY = [
|
const ARRAY = [
|
||||||
|
{
|
||||||
|
id:"",
|
||||||
|
name:'全部'
|
||||||
|
},
|
||||||
{
|
{
|
||||||
id:1,
|
id:1,
|
||||||
name:'1天'
|
name:'1天'
|
||||||
|
@ -32,10 +36,15 @@ class Activity extends Component{
|
||||||
constructor(props){
|
constructor(props){
|
||||||
super(props);
|
super(props);
|
||||||
this.state={
|
this.state={
|
||||||
time:'30',
|
time:undefined,
|
||||||
type:undefined,
|
type:undefined,
|
||||||
state:undefined,
|
state:undefined,
|
||||||
page:1,
|
page:1,
|
||||||
|
pr_count:undefined,
|
||||||
|
new_pr_count:undefined,
|
||||||
|
close_issues_count:undefined,
|
||||||
|
open_issues_count:undefined,
|
||||||
|
pr_all_count:undefined,issues_count:undefined,
|
||||||
|
|
||||||
data:undefined,
|
data:undefined,
|
||||||
project_trends:undefined,
|
project_trends:undefined,
|
||||||
|
@ -63,8 +72,15 @@ class Activity extends Component{
|
||||||
this.setState({
|
this.setState({
|
||||||
data:result.data,
|
data:result.data,
|
||||||
project_trends:result.data.project_trends,
|
project_trends:result.data.project_trends,
|
||||||
isSpin:false
|
isSpin:false,
|
||||||
|
pr_count:result.data.pr_count,
|
||||||
|
new_pr_count:result.data.new_pr_count,
|
||||||
|
close_issues_count:result.data.close_issues_count,
|
||||||
|
open_issues_count:result.data.open_issues_count,
|
||||||
|
pr_all_count:result.data.pr_all_count,
|
||||||
|
issues_count:result.data.issues_count,
|
||||||
})
|
})
|
||||||
|
window.scrollTo(0,0);
|
||||||
}
|
}
|
||||||
}).catch(error=>{
|
}).catch(error=>{
|
||||||
console.log(error);
|
console.log(error);
|
||||||
|
@ -74,19 +90,19 @@ class Activity extends Component{
|
||||||
// 切换周期
|
// 切换周期
|
||||||
changeTime=(e)=>{
|
changeTime=(e)=>{
|
||||||
this.setState({
|
this.setState({
|
||||||
time:e.key,
|
time:e.key ==="item_0"?undefined:e.key,
|
||||||
isSpin:true
|
isSpin:true
|
||||||
})
|
})
|
||||||
const { type,status,page } = this.state;
|
const { type,status,page } = this.state;
|
||||||
this.getInfo(e.key,type,status,page);
|
this.getInfo(e.key ==="item_0"?undefined:e.key,type,status,page);
|
||||||
}
|
}
|
||||||
//筛选
|
//筛选
|
||||||
changeTrends=(type,status)=>{
|
changeTrends=(type,status)=>{
|
||||||
this.setState({
|
this.setState({
|
||||||
type,status
|
type,status,page:1
|
||||||
})
|
})
|
||||||
const {time,page}=this.state;
|
const {time}=this.state;
|
||||||
this.getInfo(time,type,status,page);
|
this.getInfo(time,type,status,1);
|
||||||
}
|
}
|
||||||
// 分页
|
// 分页
|
||||||
ChangePage=(page)=>{
|
ChangePage=(page)=>{
|
||||||
|
@ -108,12 +124,14 @@ class Activity extends Component{
|
||||||
</Menu>
|
</Menu>
|
||||||
)
|
)
|
||||||
render(){
|
render(){
|
||||||
const { time , data , page , project_trends , isSpin } = this.state;
|
const { time , data , page , project_trends , isSpin , pr_count , new_pr_count , close_issues_count , open_issues_count , pr_all_count ,issues_count } = this.state;
|
||||||
|
let name = time ? ARRAY.filter(item=>item.id === parseInt(time)) :[{name:"全部"}];
|
||||||
|
|
||||||
|
const first_per = pr_all_count > 0 ? `${parseFloat(pr_count/pr_all_count).toFixed(2)*100}%` :"50%";
|
||||||
|
const second_per =pr_all_count > 0 ? `${parseFloat(new_pr_count/pr_all_count).toFixed(2)*100}%` :"50%";
|
||||||
|
const third_per =issues_count > 0 ?`${parseFloat(close_issues_count/issues_count).toFixed(2)*100}%` :"50%";
|
||||||
|
const fourth_per =issues_count > 0 ?`${parseFloat(open_issues_count/issues_count).toFixed(2)*100}%` :"50%";
|
||||||
|
|
||||||
let name = time && ARRAY.filter(item=>item.id === parseInt(time)) ;
|
|
||||||
const second_per = (parseInt(data && data.close_issues_count)/parseInt(data && data.issues_count)*100)+'%';
|
|
||||||
const third_per = (parseInt(data && data.close_issues_count)/parseInt(data && data.issues_count)*100)+'%';
|
|
||||||
const fourth_per = (parseInt(data && data.open_issues_count)/parseInt(data && data.issues_count)*100)+'%';
|
|
||||||
return(
|
return(
|
||||||
<div className="main">
|
<div className="main">
|
||||||
|
|
||||||
|
@ -122,7 +140,7 @@ class Activity extends Component{
|
||||||
<div className="orderInfo">
|
<div className="orderInfo">
|
||||||
<div>
|
<div>
|
||||||
<div className="percentLine prPercent">
|
<div className="percentLine prPercent">
|
||||||
<p className="percent_purple" style={{width:'100%'}}></p>
|
<p className="percent_purple" style={{width:first_per}}></p>
|
||||||
<p className="percent_green resetStyle" style={{width:`${second_per}`}}></p>
|
<p className="percent_green resetStyle" style={{width:`${second_per}`}}></p>
|
||||||
</div>
|
</div>
|
||||||
<span>{data && data.pr_all_count}合并请求</span>
|
<span>{data && data.pr_all_count}合并请求</span>
|
||||||
|
@ -132,25 +150,25 @@ class Activity extends Component{
|
||||||
<p className="percent_red" style={{width:`${third_per}`}}></p>
|
<p className="percent_red" style={{width:`${third_per}`}}></p>
|
||||||
<p className="percent_green" style={{width:`${fourth_per}`}}></p>
|
<p className="percent_green" style={{width:`${fourth_per}`}}></p>
|
||||||
</div>
|
</div>
|
||||||
<span>{data && data.issues_count}任务</span>
|
<span>{data && data.issues_count}易修</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<ul className="percentBox">
|
<ul className="percentBox">
|
||||||
<li>
|
<li>
|
||||||
<span className="purple">{data && data.pr_count}</span>
|
<span className="purple">{data && data.pr_count}</span>
|
||||||
<span className="change" onClick={()=>this.changeTrends("PullRequest","close")}>已处理的合并请求</span>
|
<span className="change" onClick={()=>this.changeTrends("PullRequest","delay")}>已处理的合并请求</span>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<span className="green">{data && data.new_pr_count}</span>
|
<span className="green">{data && data.new_pr_count}</span>
|
||||||
<span className="change" onClick={()=>this.changeTrends("PullRequest","create")}>未处理的合并请求</span>
|
<span className="change" onClick={()=>this.changeTrends("PullRequest","not_delay")}>未处理的合并请求</span>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<span className="red">{data && data.close_issues_count}</span>
|
<span className="red">{data && data.close_issues_count}</span>
|
||||||
<span className="change" onClick={()=>this.changeTrends("Issue","close")}>已关闭的任务</span>
|
<span className="change" onClick={()=>this.changeTrends("Issue","delay")}>已关闭的易修</span>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<span className="green">{data && data.open_issues_count}</span>
|
<span className="green">{data && data.open_issues_count}</span>
|
||||||
<span className="change" onClick={()=>this.changeTrends("Issue","create")}>未处理的任务</span>
|
<span className="change" onClick={()=>this.changeTrends("Issue","not_delay")}>未处理的易修</span>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -27,7 +27,7 @@ class ActivityItem extends Component {
|
||||||
:
|
:
|
||||||
// 如果是合并请求
|
// 如果是合并请求
|
||||||
<p className="itemLine">
|
<p className="itemLine">
|
||||||
<Link to={`/${owner}/${projectsId}/pulls/${item.trend_id}/Messagecount`} className="color-blue font-16">{item.name}</Link>
|
<Link to={`/${owner}/${projectsId}/pulls/${item.trend_id}`} className="color-blue font-16">{item.name}</Link>
|
||||||
<span className="activity_type">{item.trend_type}</span>
|
<span className="activity_type">{item.trend_type}</span>
|
||||||
</p >
|
</p >
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,7 @@ function CloneAddress({http_url , ssh_url , zip_url , tar_url}) {
|
||||||
const [ key , setKey ] = useState("HTTP");
|
const [ key , setKey ] = useState("HTTP");
|
||||||
return (
|
return (
|
||||||
<div className="downMenu">
|
<div className="downMenu">
|
||||||
<div style={{padding:"10px 20px 20px 20px",borderBottom:"1px solid #eee"}}>
|
<div style={{borderBottom:"1px solid #eee"}}>
|
||||||
<Menu className="urlMenu" selectedKeys={[key]} mode={"horizontal"}>
|
<Menu className="urlMenu" selectedKeys={[key]} mode={"horizontal"}>
|
||||||
<Menu.Item key="HTTP" onClick={(e)=>{setKey(e.key)}}>HTTP</Menu.Item>
|
<Menu.Item key="HTTP" onClick={(e)=>{setKey(e.key)}}>HTTP</Menu.Item>
|
||||||
<Menu.Item key="SSH" onClick={(e)=>{setKey(e.key)}}>SSH</Menu.Item>
|
<Menu.Item key="SSH" onClick={(e)=>{setKey(e.key)}}>SSH</Menu.Item>
|
||||||
|
|
|
@ -1,116 +1,65 @@
|
||||||
import React , { useState , useEffect } from 'react';
|
import React , { useState , useEffect , useRef } from 'react';
|
||||||
import { Popover , Input , Spin } from 'antd';
|
import { Dropdown} from 'antd';
|
||||||
import './branch.scss';
|
import './branch.scss';
|
||||||
import { getBranch , getTag } from '../GetData/getData';
|
import SelectOverlay from './SelectOverlay';
|
||||||
|
import { findDOMNode } from 'react-dom';
|
||||||
|
|
||||||
export default (({ projectsId , branch , owner , changeBranch , branchList , tagflag = true })=>{
|
export default (({ projectsId , branch , owner , changeBranch , branchList , tagflag = true })=>{
|
||||||
const [ showValue , setShowValue ] = useState(branch);
|
const [ showValue , setShowValue ] = useState(branch);
|
||||||
const [ inputValue , setInputValue] = useState(undefined);
|
const [ visible , setVisible ] = useState(false);
|
||||||
const [ nav , setNav ] = useState(0);
|
|
||||||
const [ isSpin , setIsSpin ] = useState(true);
|
|
||||||
const [ flag , setFlag ] = useState(false);
|
|
||||||
|
|
||||||
const [ data , setData ] = useState(undefined);
|
const refFa = useRef(null);
|
||||||
const [ datas , setDatas ] = useState(undefined);
|
const refBox = useRef(null);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
document.addEventListener('click', clickMe , false);
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
const clickMe = ({ target }) => {
|
||||||
|
// 查找父组件
|
||||||
|
const faComponent = findDOMNode(refFa.current);
|
||||||
|
const boxComponent = findDOMNode(refBox.current);
|
||||||
|
|
||||||
|
if (faComponent && boxComponent) {
|
||||||
|
const isChild = faComponent.contains(target);
|
||||||
|
const isBox = boxComponent.contains(target);
|
||||||
|
if(!isChild && !isBox){
|
||||||
|
setVisible(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
useEffect(()=>{
|
useEffect(()=>{
|
||||||
setShowValue(branch);
|
setShowValue(branch);
|
||||||
},[branch])
|
},[branch])
|
||||||
|
|
||||||
useEffect(()=>{
|
function ChangeB(params) {
|
||||||
document.body.addEventListener('click', e => {
|
setVisible(false);
|
||||||
let name = e.target.className;
|
changeBranch(params);
|
||||||
let turn = name === "ant-input OptionsInput" || name === "navli active"|| name === "navli" || name === "padding10 bor-bottom-greyE";
|
|
||||||
if(turn){
|
|
||||||
return;
|
|
||||||
}else{
|
|
||||||
setFlag(false);
|
|
||||||
}
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
useEffect(()=>{
|
|
||||||
if(branchList){
|
|
||||||
setData(branchList);
|
|
||||||
setDatas(branchList);
|
|
||||||
setIsSpin(false);
|
|
||||||
}
|
|
||||||
},[branchList])
|
|
||||||
|
|
||||||
|
|
||||||
async function getBranchs(id,owner){
|
|
||||||
let result = await getBranch(id,owner);
|
|
||||||
setData(result);
|
|
||||||
setDatas(result);
|
|
||||||
setIsSpin(false);
|
|
||||||
}
|
}
|
||||||
async function getTags(id,owner){
|
|
||||||
let result = await getTag(id,owner);
|
|
||||||
setData(result);
|
|
||||||
setDatas(result);
|
|
||||||
setIsSpin(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
function changeInputValue(e){
|
|
||||||
setInputValue(e.target.value);
|
|
||||||
let filter = e.target.value ? data && data.length>0 && data.filter(item=>item.name.indexOf(e.target.value)>-1) : data;
|
|
||||||
setDatas(filter);
|
|
||||||
}
|
|
||||||
|
|
||||||
function changeNav(nav){
|
|
||||||
setNav(nav);
|
|
||||||
setIsSpin(true);
|
|
||||||
if(nav === 0){
|
|
||||||
getBranchs(projectsId,owner);
|
|
||||||
}else{
|
|
||||||
getTags(projectsId,owner);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
function chooseitem(value){
|
|
||||||
// setShowValue(value);
|
|
||||||
changeBranch(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
const menu = (
|
const menu = (
|
||||||
<div>
|
<div ref={refFa}>
|
||||||
<div className="padding10 bor-bottom-greyE">
|
<SelectOverlay
|
||||||
<Input
|
visible={visible}
|
||||||
placeholder="请输入分支或标签名称搜索"
|
changeBranch={ChangeB}
|
||||||
autocomplete="off" className="OptionsInput" value={inputValue}
|
tagflag={tagflag}
|
||||||
onChange={changeInputValue} style={{width:"220px"}}
|
projectsId={projectsId}
|
||||||
/>
|
owner={owner}
|
||||||
<ul className="navUl">
|
branchList={branchList}
|
||||||
<li className={nav === 0?"navli active":"navli"} onClick={()=>changeNav(0)}><i className="iconfont icon-fenzhi1 font-14 mr3"></i>分支列表</li>
|
/>
|
||||||
{ tagflag && <li className={nav === 1?"navli active":"navli"} onClick={()=>changeNav(1)}><i className="iconfont icon-biaoqian3 font-14 mr3"></i>标签列表</li> }
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
<Spin spinning={isSpin}>
|
|
||||||
<ul className="OptionsUl" id="ul-btn">
|
|
||||||
{
|
|
||||||
datas && datas.length>0 ?
|
|
||||||
datas.map((item,key)=>{
|
|
||||||
return(
|
|
||||||
<li key={key} onClick={()=>chooseitem(item.name)}><a className="task-hide ulALink">{item.name}</a></li>
|
|
||||||
)
|
|
||||||
}):
|
|
||||||
<p className="listTips">暂无{inputValue}{nav === 0 ?"分支":"标签"}~</p>
|
|
||||||
}
|
|
||||||
</ul>
|
|
||||||
</Spin>
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
return(
|
return(
|
||||||
<Popover placement='bottomLeft' visible={flag} content={menu} onClick={()=>setFlag(!flag)} overlayClassName="branch-tagBox-list">
|
<Dropdown placement='bottomLeft' visible={visible} overlay={menu} overlayClassName="branch-tagBox-list" trigger={['click']} >
|
||||||
<div className="branch-tagBox">
|
<div className="branch-tagBox" ref={refBox} onClick={()=>setVisible(visible ? false : true)}>
|
||||||
{/* {nav === 0 ?"分支":"标签"} */}
|
{/* {nav === 0 ?"分支":"标签"} */}
|
||||||
<span className="color-grey-9 mr3 ml8"><i className="iconfont icon-fenzhi2 font-18"></i></span>
|
<span className="color-grey-9 mr3 ml8"><i className="iconfont icon-fenzhi2 font-18"></i></span>
|
||||||
<a className="ant-dropdown-link">
|
<span className="ant-dropdown-link task-hide" style={{fontWeight:"500",minWidth:"45px",maxWidth:"270px"}}>
|
||||||
{showValue}
|
{showValue}
|
||||||
</a>
|
</span>
|
||||||
<i className="showtag iconfont icon-xiajiantou font-14 color-grey-9 mr8" />
|
<i className="showtag iconfont icon-sanjiaoxing-down font-15 color-grey-9 mr5 ml5 mt1" />
|
||||||
</div>
|
</div>
|
||||||
</Popover>
|
</Dropdown>
|
||||||
)
|
)
|
||||||
})
|
})
|
|
@ -0,0 +1,90 @@
|
||||||
|
import React , { useState , useEffect } from 'react';
|
||||||
|
import { Input , Spin , Menu } from 'antd';
|
||||||
|
import { getBranch , getTag } from '../GetData/getData';
|
||||||
|
|
||||||
|
function SelectOverlay({ changeBranch , tagflag , projectsId , owner , visible }) {
|
||||||
|
const [ inputValue , setInputValue] = useState(undefined);
|
||||||
|
const [ nav , setNav ] = useState(0);
|
||||||
|
const [ isSpin , setIsSpin ] = useState(true);
|
||||||
|
|
||||||
|
const [ data , setData ] = useState(undefined);
|
||||||
|
const [ datas , setDatas ] = useState(undefined);
|
||||||
|
const [ keys ,setKeys] = useState("branch");
|
||||||
|
|
||||||
|
useEffect(()=>{
|
||||||
|
if(visible){
|
||||||
|
setKeys("branch");
|
||||||
|
getBranchs(projectsId,owner);
|
||||||
|
setIsSpin(true);
|
||||||
|
}
|
||||||
|
},[visible])
|
||||||
|
|
||||||
|
async function getBranchs(id,owner){
|
||||||
|
let result = await getBranch(id,owner);
|
||||||
|
setData(result);
|
||||||
|
setDatas(result);
|
||||||
|
setIsSpin(false);
|
||||||
|
}
|
||||||
|
async function getTags(id,owner){
|
||||||
|
let result = await getTag(id,owner);
|
||||||
|
setData(result);
|
||||||
|
setDatas(result);
|
||||||
|
setIsSpin(false);
|
||||||
|
}
|
||||||
|
function chooseitem(value){
|
||||||
|
changeBranch(value);
|
||||||
|
}
|
||||||
|
function changeInputValue(e){
|
||||||
|
setInputValue(e.target.value);
|
||||||
|
let filter = e.target.value ? data && data.length>0 && data.filter(item=>item.name.indexOf(e.target.value)>-1) : data;
|
||||||
|
setDatas(filter);
|
||||||
|
}
|
||||||
|
|
||||||
|
function changeNav(e){
|
||||||
|
setKeys(e.key);
|
||||||
|
setIsSpin(true);
|
||||||
|
if(e.key === "branch"){
|
||||||
|
getBranchs(projectsId,owner);
|
||||||
|
setNav(0);
|
||||||
|
}else{
|
||||||
|
getTags(projectsId,owner);
|
||||||
|
setNav(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return(
|
||||||
|
<div className="overlayBranch">
|
||||||
|
<div className="padding15" style={{paddingBottom:"0px"}}>
|
||||||
|
<Input
|
||||||
|
prefix={<i className="iconfont icon-sousuo_icon1 font-14"></i>}
|
||||||
|
placeholder={`请输入分支${tagflag ? "或标签" :""}名称搜索`}
|
||||||
|
autocomplete="off" className="OptionsInput"
|
||||||
|
value={inputValue}
|
||||||
|
onChange={changeInputValue}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<Menu mode="horizontal" className="navUl" selectedKeys={[keys]} onClick={changeNav}>
|
||||||
|
<Menu.Item key={"branch"}>分支</Menu.Item>
|
||||||
|
{ tagflag && <Menu.Item key={"tag"}>标签</Menu.Item> }
|
||||||
|
</Menu>
|
||||||
|
<Spin spinning={isSpin}>
|
||||||
|
<ul className="OptionsUl" id="ul-btn">
|
||||||
|
{
|
||||||
|
datas && datas.length>0 &&
|
||||||
|
datas.map((item,key)=>{
|
||||||
|
return(
|
||||||
|
<li key={key} onClick={()=>chooseitem(item.name)}><a className="task-hide ulALink">{item.name}</a></li>
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
}
|
||||||
|
{
|
||||||
|
datas && datas.length === 0 &&
|
||||||
|
<p className="listTips">暂无{inputValue}{nav === 0 ?"分支":"标签"}~</p>
|
||||||
|
}
|
||||||
|
</ul>
|
||||||
|
</Spin>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
export default SelectOverlay;
|
|
@ -23,14 +23,16 @@
|
||||||
max-height: 300px;
|
max-height: 300px;
|
||||||
}
|
}
|
||||||
.OptionsUl{
|
.OptionsUl{
|
||||||
|
min-height: 50px;
|
||||||
max-height: 220px;
|
max-height: 220px;
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
}
|
}
|
||||||
.OptionsUl li{
|
.OptionsUl li{
|
||||||
height: 35px;
|
height: 30px;
|
||||||
line-height: 35px;
|
line-height: 30px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
padding:0px 10px;
|
padding:0px 20px;
|
||||||
|
margin:5px 0px;
|
||||||
}
|
}
|
||||||
.OptionsUl li:hover{
|
.OptionsUl li:hover{
|
||||||
background-color: #F0F0F0;
|
background-color: #F0F0F0;
|
||||||
|
@ -45,38 +47,56 @@
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
.branch-tagBox{
|
.branch-tagBox{
|
||||||
border:1px solid #eee;
|
border:1px solid #D0D0D0;
|
||||||
border-radius: 3px;
|
border-radius: 3px;
|
||||||
height: 40px;
|
height: 32px;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
min-width: 140px;
|
min-width: 104px;
|
||||||
}
|
}
|
||||||
.branch-tagBox-list .ant-popover-arrow{
|
.branch-tagBox:hover{
|
||||||
display: none;
|
background-color: #F3F4F6;
|
||||||
}
|
}
|
||||||
.branch-tagBox-list.ant-popover.ant-popover-placement-bottom{
|
.branch-tagBox-list{
|
||||||
padding-top:0px;
|
background: #FFFFFF;
|
||||||
|
box-shadow: 0px 4px 8px 2px rgba(212, 212, 212, 0.5);
|
||||||
|
border-radius: 4px;
|
||||||
|
.ant-popover-arrow{
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
&.ant-popover.ant-popover-placement-bottom{
|
||||||
|
padding-top:0px;
|
||||||
|
}
|
||||||
|
.branch-tagBox .ant-dropdown-link{
|
||||||
|
display: block;
|
||||||
|
flex:1;
|
||||||
|
max-width: 105px;
|
||||||
|
}
|
||||||
|
.ant-popover-inner-content{
|
||||||
|
padding:0px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
.branch-tagBox .ant-dropdown-link{
|
.overlayBranch{
|
||||||
display: block;
|
width: 325px;
|
||||||
flex:1;
|
.navUl{
|
||||||
}
|
margin-top: 8px;
|
||||||
.branch-tagBox-list .ant-popover-inner-content{
|
height: 30px;
|
||||||
padding:0px;
|
line-height: 30px;
|
||||||
}
|
li{
|
||||||
.navUl{
|
height: 30px;
|
||||||
display: flex;
|
line-height: 30px;
|
||||||
justify-content: space-between;
|
padding:0px 5px;
|
||||||
align-items: center;
|
margin-left: 20px!important;
|
||||||
margin-top: 5px;
|
&.ant-menu-item-selected{
|
||||||
}
|
border-color:#466aff!important;
|
||||||
.navUl li{
|
color:#466aff!important;
|
||||||
cursor: pointer;
|
}
|
||||||
}
|
&.ant-menu-item-active{
|
||||||
.navUl li.active{
|
border-color:transparent ;
|
||||||
color:#5091FF;
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
.listTips{
|
.listTips{
|
||||||
padding:20px 0px;
|
padding:20px 0px;
|
||||||
|
@ -86,6 +106,7 @@
|
||||||
.urlMenu{
|
.urlMenu{
|
||||||
line-height: 30px;
|
line-height: 30px;
|
||||||
margin-bottom: 10px;
|
margin-bottom: 10px;
|
||||||
|
padding:15px 20px 0px 20px;
|
||||||
border-bottom: none;
|
border-bottom: none;
|
||||||
li.ant-menu-item{
|
li.ant-menu-item{
|
||||||
height: 30px;
|
height: 30px;
|
||||||
|
@ -96,7 +117,7 @@
|
||||||
color: #333;
|
color: #333;
|
||||||
}
|
}
|
||||||
&.ant-menu-item-selected{
|
&.ant-menu-item-selected{
|
||||||
border-color:#1890ff!important;
|
border-color:#466aff!important;
|
||||||
}
|
}
|
||||||
&.ant-menu-item-active{
|
&.ant-menu-item-active{
|
||||||
border-color:transparent ;
|
border-color:transparent ;
|
||||||
|
|
|
@ -113,7 +113,14 @@ li.ant-menu-item{
|
||||||
z-index: 10000;
|
z-index: 10000;
|
||||||
}
|
}
|
||||||
.laterest{
|
.laterest{
|
||||||
color: #05690d;
|
background-color: #EF3131;
|
||||||
|
color: #fff;
|
||||||
|
font-size: 12px;
|
||||||
|
margin-left: 10px;
|
||||||
|
padding:0px 5px;
|
||||||
|
border-radius: 2px;
|
||||||
|
height: 18px;
|
||||||
|
line-height: 18px;
|
||||||
}
|
}
|
||||||
|
|
||||||
@media screen and (max-width: 1800px){
|
@media screen and (max-width: 1800px){
|
||||||
|
@ -155,41 +162,112 @@ li.ant-menu-item{
|
||||||
margin:0px 20px!important;
|
margin:0px 20px!important;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.hoverA{
|
||||||
|
display:flex;
|
||||||
|
align-items: center;
|
||||||
|
max-width: 78px;
|
||||||
|
&:hover a{
|
||||||
|
color:#2A61FF !important ;
|
||||||
|
}
|
||||||
|
}
|
||||||
.menuPanels{
|
.menuPanels{
|
||||||
width: 240px;
|
width: 295px;
|
||||||
height: 180px;
|
.leftline{
|
||||||
|
position: relative;
|
||||||
|
color: #666;
|
||||||
|
height: 16px;
|
||||||
|
margin-left: 14px;
|
||||||
|
font-size: 12px;
|
||||||
|
&::before{
|
||||||
|
position: absolute;
|
||||||
|
left: -7px;
|
||||||
|
top:3px;
|
||||||
|
height: 12px;
|
||||||
|
width: 1px;
|
||||||
|
background-color: #999;
|
||||||
|
content: "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.ant-btn{
|
||||||
|
height: 36px;
|
||||||
|
line-height: 34px;
|
||||||
|
width: 83px;
|
||||||
|
text-align: center;
|
||||||
|
padding:0px ;
|
||||||
|
font-weight: 500;
|
||||||
|
font-size: 14px;
|
||||||
|
&.currentBtn{
|
||||||
|
cursor: default;
|
||||||
|
color: #333;
|
||||||
|
&:hover{
|
||||||
|
color: #333;
|
||||||
|
border-color: #d0d0d0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.ant-btn-default{
|
||||||
|
color: #333;
|
||||||
|
border-color: #d0d0d0;
|
||||||
|
&:hover{
|
||||||
|
background: #F3F4F6;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.ant-btn{
|
||||||
|
width: 102px;
|
||||||
|
height: 32px;
|
||||||
|
line-height: 30px;
|
||||||
|
}
|
||||||
|
.ant-btn-primary{
|
||||||
|
color: #fff;
|
||||||
|
background-color: #466AFF;
|
||||||
|
border:none;
|
||||||
|
&:hover{
|
||||||
|
background-color: rgba(70,106,255,0.85);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.focusPanelHeadInfo{
|
||||||
|
padding:14px 16px;
|
||||||
|
border-bottom: 1px solid #eee;
|
||||||
|
}
|
||||||
.ant-popover-content,.ant-popover-inner{
|
.ant-popover-content,.ant-popover-inner{
|
||||||
height: 100%;
|
height: 100%;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
.ant-popover-inner-content{
|
||||||
|
padding:0px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
.halfs{
|
.halfs{
|
||||||
margin-top: 24px;
|
margin-top: 24px;
|
||||||
padding:24px 0px 0px 0px;
|
padding:24px 0px 0px 0px;
|
||||||
border-top: 1px solid #e8e8e8;
|
border-top: 1px solid #e8e8e8;
|
||||||
.attrPerson{
|
}
|
||||||
padding-bottom: 24px;
|
.aboutSubTitle{
|
||||||
}
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
.menuMaininfos{
|
||||||
|
padding:10px 16px 14px;
|
||||||
|
border-bottom: 1px solid #eee;
|
||||||
}
|
}
|
||||||
.menuinfos{
|
.menuinfos{
|
||||||
padding:15px 0px;
|
padding:10px 20px 16px;
|
||||||
&>a{
|
&>a{
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
border-right: 1px solid #eee;
|
|
||||||
flex: 1;
|
flex: 1;
|
||||||
& >span:first-child{
|
& >span:first-child{
|
||||||
font-size: 18px;
|
font-size: 16px;
|
||||||
font-weight: 400;
|
font-weight: 500;
|
||||||
color: #333;
|
color: #333;
|
||||||
|
line-height: 22px;
|
||||||
}
|
}
|
||||||
& >span:last-child{
|
& >span:last-child{
|
||||||
color: #666;
|
color: #666;
|
||||||
}
|
font-weight: 400;
|
||||||
&:last-child{
|
line-height: 20px;
|
||||||
border-right: none;
|
margin-top: 6px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
import React, { useEffect, useState } from 'react';
|
import React, { useEffect, useState } from 'react';
|
||||||
import { AlignCenter , FlexAJ } from '../Component/layout';
|
import { AlignCenter , FlexAJ } from '../Component/layout';
|
||||||
import { Link } from 'react-router-dom';
|
import { Link } from 'react-router-dom';
|
||||||
import { Popover , Spin } from 'antd';
|
import { Popover , Spin , Button } from 'antd';
|
||||||
import { getImageUrl } from 'educoder';
|
import { getImageUrl } from 'educoder';
|
||||||
import './Component.scss';
|
import './Component.scss';
|
||||||
import { getUser } from '../GetData/getData';
|
import { getUser } from '../GetData/getData';
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
|
|
||||||
function Contributors({contributors,owner,projectsId}){
|
function Contributors({contributors,owner,projectsId,currentLogin}){
|
||||||
const [ menuList ,setMenuList ]= useState([]);
|
const [ menuList ,setMenuList ]= useState([]);
|
||||||
const [ list , setList ]= useState(undefined);
|
const [ list , setList ]= useState(undefined);
|
||||||
const [ total , setTotal ]= useState(0);
|
const [ total , setTotal ]= useState(0);
|
||||||
|
@ -46,46 +46,60 @@ function Contributors({contributors,owner,projectsId}){
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function renderOrganize(list) {
|
||||||
|
let str = "";
|
||||||
|
list.map(i=>{
|
||||||
|
str = str+i.name + "、";
|
||||||
|
})
|
||||||
|
return str && str.substr(0,str.length - 1);
|
||||||
|
}
|
||||||
|
|
||||||
function setMenusFunc(data){
|
function setMenusFunc(data){
|
||||||
if(data){
|
if(data){
|
||||||
let ele = (
|
let ele = (
|
||||||
<Spin spinning={isSpin}>
|
<Spin spinning={isSpin}>
|
||||||
<FlexAJ>
|
<FlexAJ className="menuMaininfos">
|
||||||
<AlignCenter>
|
<AlignCenter>
|
||||||
<Link to={`/${data.login}`}><img src={getImageUrl(`/${data.image_url}`)} alt="" className="radius" width="38px" height="38px"/></Link>
|
<Link to={`/${data.login}`}><img src={getImageUrl(`/${data.image_url}`)} alt="" className="radius" width="38px" height="38px"/></Link>
|
||||||
<Link to={`/${data.login}`} className="ml10">{data.name}</Link>
|
|
||||||
</AlignCenter>
|
<div className="ml10">
|
||||||
{
|
<Link to={`/${data.login}`}>{data.name}</Link>
|
||||||
data.is_watch ? <a className="color-grey-9" onClick={()=>FocusFunc(false,data.login)}>取消关注</a>:<a className="color-blue" onClick={()=>FocusFunc(true,data.login)}>关注</a>
|
{ data.location && <span className="leftline">{data.location}</span> }
|
||||||
}
|
{
|
||||||
</FlexAJ>
|
data.organizations && data.organizations.length>0&&
|
||||||
<AlignCenter className="menuinfos">
|
<p className="task-hide" style={{maxWidth:"215px"}}>
|
||||||
<a href={data.projects_url}>
|
所属组织:{renderOrganize(data.organizations)}
|
||||||
<span>{data.projects_count}</span>
|
</p>
|
||||||
<span>项目数</span>
|
}
|
||||||
</a>
|
|
||||||
<a href={data.followers_url}>
|
|
||||||
<span>{data.followers_count}</span>
|
|
||||||
<span>粉丝数</span>
|
|
||||||
</a>
|
|
||||||
<a href={data.following_url}>
|
|
||||||
<span>{data.following_count}</span>
|
|
||||||
<span>关注数</span>
|
|
||||||
</a>
|
|
||||||
</AlignCenter>
|
|
||||||
{
|
|
||||||
data.organizations && data.organizations.length > 0 ?
|
|
||||||
<AlignCenter className="font-12 pt4 pb4">
|
|
||||||
<span>所属组织:</span>
|
|
||||||
<div className="task-hide flex1">
|
|
||||||
{renderArray(data.organizations)}
|
|
||||||
</div>
|
</div>
|
||||||
</AlignCenter>
|
</AlignCenter>
|
||||||
:""
|
</FlexAJ>
|
||||||
}
|
<AlignCenter className="menuinfos">
|
||||||
{
|
<Link to={`/${data.login}/projects`}>
|
||||||
data.location && <AlignCenter className="font-12 pt4 pb4"><span>所在地址:</span><span className="ml5">{data.location}</span></AlignCenter>
|
<span>{data.projects_count}</span>
|
||||||
}
|
<span>项目数</span>
|
||||||
|
</Link>
|
||||||
|
<Link to={`/${data.login}/followers`}>
|
||||||
|
<span>{data.followers_count}</span>
|
||||||
|
<span>粉丝数</span>
|
||||||
|
</Link>
|
||||||
|
<Link to={`/${data.login}/following`}>
|
||||||
|
<span>{data.following_count}</span>
|
||||||
|
<span>关注数</span>
|
||||||
|
</Link>
|
||||||
|
</AlignCenter>
|
||||||
|
<div className={"pb20"} style={{display:"flex",justifyContent:'center'}}>
|
||||||
|
{
|
||||||
|
currentLogin && (currentLogin === data.login)
|
||||||
|
?
|
||||||
|
<Button className="currentBtn">当前用户</Button>
|
||||||
|
:
|
||||||
|
data.is_watch ?
|
||||||
|
<Button type={"default"} onClick={()=>FocusFunc(false,data.login)}>已关注</Button>
|
||||||
|
:
|
||||||
|
<Button type={"primary"} onClick={()=>FocusFunc(true,data.login)}>关注TA</Button>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
</Spin>
|
</Spin>
|
||||||
)
|
)
|
||||||
setMenu(ele);
|
setMenu(ele);
|
||||||
|
@ -135,10 +149,10 @@ function Contributors({contributors,owner,projectsId}){
|
||||||
|
|
||||||
return(
|
return(
|
||||||
<div className="halfs">
|
<div className="halfs">
|
||||||
<FlexAJ>
|
<Link to={`/${owner}/${projectsId}/contribute`} className="font-16 color-ooo hoverA">
|
||||||
<AlignCenter><span className="font-16 color-grey-6">贡献者</span>{ contributors && contributors.total_count > 0 && <span className="infoCount">{contributors.total_count}</span>}</AlignCenter>
|
<span>贡献者</span>
|
||||||
<Link className="font-12 color-grey-9" to={`/${owner}/${projectsId}/contribute`}>全部</Link>
|
{ contributors && contributors.total_count > 0 && <span className="infoCount">{contributors.total_count}</span>}
|
||||||
</FlexAJ>
|
</Link>
|
||||||
<div className="attrPerson" onMouseLeave={()=>setVisibleFunc(false)}>
|
<div className="attrPerson" onMouseLeave={()=>setVisibleFunc(false)}>
|
||||||
{
|
{
|
||||||
total > 0 ?
|
total > 0 ?
|
||||||
|
|
|
@ -2,7 +2,7 @@ import React, { useState, useCallback, memo } from 'react';
|
||||||
import { Tooltip } from 'antd';
|
import { Tooltip } from 'antd';
|
||||||
|
|
||||||
CopyTool.defaultProps = {
|
CopyTool.defaultProps = {
|
||||||
beforeText: '复制', //浮动过去显示的文字
|
beforeText: '复制链接', //浮动过去显示的文字
|
||||||
afterText: '复制成功', //点击后显示的文字
|
afterText: '复制成功', //点击后显示的文字
|
||||||
className: '', //传给svg的class
|
className: '', //传给svg的class
|
||||||
inputId: 'copyText', //要复制的文本的ID
|
inputId: 'copyText', //要复制的文本的ID
|
||||||
|
@ -26,6 +26,7 @@ function CopyTool({ beforeText, afterText, className , inputId , timeOut }) {
|
||||||
if (document.execCommand('copy')) {
|
if (document.execCommand('copy')) {
|
||||||
document.execCommand('copy');
|
document.execCommand('copy');
|
||||||
}
|
}
|
||||||
|
document.getSelection().removeAllRanges();
|
||||||
|
|
||||||
setTitle(afterText);
|
setTitle(afterText);
|
||||||
if(timeOut){
|
if(timeOut){
|
||||||
|
|
|
@ -25,7 +25,7 @@ function LanguagePower({languages}){
|
||||||
}
|
}
|
||||||
return(
|
return(
|
||||||
<div>
|
<div>
|
||||||
<p className="font-16 color-grey-6">开发语言</p>
|
<p className="font-16 color-ooo aboutSubTitle">开发语言</p>
|
||||||
<div className="progress">
|
<div className="progress">
|
||||||
{
|
{
|
||||||
array && array.map((item,key)=>{
|
array && array.map((item,key)=>{
|
||||||
|
|
|
@ -0,0 +1,125 @@
|
||||||
|
/* eslint-disable react/jsx-no-duplicate-props */
|
||||||
|
import React, { useState } from 'react';
|
||||||
|
import * as ReactDOM from 'react-dom';
|
||||||
|
import { Modal, Button } from 'antd';
|
||||||
|
import './index.scss';
|
||||||
|
|
||||||
|
// 函数式调用删除、通知等模态框
|
||||||
|
|
||||||
|
InitModal.defaultProps = {
|
||||||
|
okText: '确认', //确定按钮的文字
|
||||||
|
cancelText: '取消', //取消按钮的文字
|
||||||
|
className: '', //传入的模态框类名
|
||||||
|
inputId: 'copyText', //要复制的文本的ID
|
||||||
|
onCancel:()=>{}, //取消的回调
|
||||||
|
onOk:()=>{}, //确认的回调
|
||||||
|
title:'提示', //模态框名字
|
||||||
|
contentTitle:'', //内容标题
|
||||||
|
content:'', //详细内容
|
||||||
|
afterClose:()=>{}, //关闭模态框以后的回调
|
||||||
|
};
|
||||||
|
|
||||||
|
// 使用函数调用删除组件
|
||||||
|
export default function DelModal(props) {
|
||||||
|
renderModal({ ...props, type: 'delete' })
|
||||||
|
}
|
||||||
|
|
||||||
|
// 使用函数调用选择模态框组件
|
||||||
|
export function Confirm(props) {
|
||||||
|
renderModal({ ...props, type: 'confirm' })
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderModal(props) {
|
||||||
|
const { type, afterClose } = props;
|
||||||
|
const div = document.createElement('div');
|
||||||
|
document.body.appendChild(div);
|
||||||
|
|
||||||
|
function destroy() {
|
||||||
|
afterClose && afterClose();
|
||||||
|
const unmountResult = ReactDOM.unmountComponentAtNode(div);
|
||||||
|
if (unmountResult && div.parentNode) {
|
||||||
|
div.parentNode.removeChild(div);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function modalType(type) {
|
||||||
|
if (type === 'delete') {
|
||||||
|
return <InitModal
|
||||||
|
title="删除"
|
||||||
|
contentTitle="确定要删除吗?"
|
||||||
|
okText="确认删除"
|
||||||
|
{...props}
|
||||||
|
|
||||||
|
afterClose={destroy}
|
||||||
|
contentTitle={<React.Fragment>
|
||||||
|
<i className="red-circle iconfont icon-shanchu_tc_icon mr3"></i>
|
||||||
|
{props.contentTitle}
|
||||||
|
</React.Fragment>}
|
||||||
|
/>
|
||||||
|
} else if (type === 'confirm') {
|
||||||
|
return <InitModal title="选择" afterClose={destroy} {...props} />
|
||||||
|
} else {
|
||||||
|
return <InitModal title="选择" afterClose={destroy} {...props} />
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function render() {
|
||||||
|
setTimeout(() => {
|
||||||
|
ReactDOM.render(
|
||||||
|
modalType(type),
|
||||||
|
div,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
render();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 选择模态框组件
|
||||||
|
function InitModal({
|
||||||
|
onCancel,
|
||||||
|
onOk,
|
||||||
|
title,
|
||||||
|
contentTitle,
|
||||||
|
content,
|
||||||
|
okText,
|
||||||
|
cancelText,
|
||||||
|
afterClose,
|
||||||
|
className,
|
||||||
|
}) {
|
||||||
|
|
||||||
|
const [visible, setVisible] = useState(true);
|
||||||
|
|
||||||
|
function onCancelModal() {
|
||||||
|
setVisible(false);
|
||||||
|
onCancel && onCancel()
|
||||||
|
}
|
||||||
|
|
||||||
|
function onSuccess() {
|
||||||
|
setVisible(false);
|
||||||
|
onOk && onOk();
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Modal
|
||||||
|
visible={visible}
|
||||||
|
onCancel={onCancelModal}
|
||||||
|
afterClose={afterClose}
|
||||||
|
title={title}
|
||||||
|
className={`myself-modal ${className}`}
|
||||||
|
centered
|
||||||
|
footer={[
|
||||||
|
<Button type="default" key="back" onClick={onCancelModal}>
|
||||||
|
{cancelText}
|
||||||
|
</Button>,
|
||||||
|
<Button className="foot-submit" key="submit" onClick={onSuccess}>
|
||||||
|
{okText}
|
||||||
|
</Button>,
|
||||||
|
]}
|
||||||
|
>
|
||||||
|
<div>
|
||||||
|
{contentTitle && <p className="content-title">{contentTitle}</p>}
|
||||||
|
<p className="content-descibe">{content}</p>
|
||||||
|
</div>
|
||||||
|
</Modal>
|
||||||
|
)
|
||||||
|
}
|
|
@ -0,0 +1,63 @@
|
||||||
|
.myself-modal {
|
||||||
|
.ant-modal-header {
|
||||||
|
padding: 9px 24px;
|
||||||
|
background: #f8f8f8;
|
||||||
|
border-bottom: 1px solid #eee;
|
||||||
|
}
|
||||||
|
.ant-modal-title {
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
.ant-modal-close {
|
||||||
|
top: 0px !important;
|
||||||
|
}
|
||||||
|
.ant-modal-close-x {
|
||||||
|
font-size: 24px;
|
||||||
|
}
|
||||||
|
.ant-modal-body {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
.content-title {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
margin: 2rem 0 1rem !important;
|
||||||
|
font-size: 16px;
|
||||||
|
color: #333;
|
||||||
|
letter-spacing: 0;
|
||||||
|
line-height: 29px;
|
||||||
|
font-weight: 400;
|
||||||
|
}
|
||||||
|
.red-circle {
|
||||||
|
align-self: flex-start;
|
||||||
|
color: #ca0002;
|
||||||
|
font-size: 1.5rem !important;
|
||||||
|
}
|
||||||
|
.content-descibe {
|
||||||
|
font-size: 14px;
|
||||||
|
color: #666;
|
||||||
|
line-height: 33px;
|
||||||
|
font-weight: 400;
|
||||||
|
}
|
||||||
|
.ant-modal-footer {
|
||||||
|
padding: 2rem 0;
|
||||||
|
text-align: center;
|
||||||
|
border: 0;
|
||||||
|
.ant-btn {
|
||||||
|
width: 6rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.foot-submit {
|
||||||
|
margin-left: 3rem;
|
||||||
|
color: #df0002;
|
||||||
|
&:hover {
|
||||||
|
border-color: #df0002;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.ant-btn-default:hover,
|
||||||
|
.ant-btn-default:active,
|
||||||
|
.ant-btn-default:focus {
|
||||||
|
background: #f3f4f6;
|
||||||
|
color: #333;
|
||||||
|
border-color: #d0d0d0;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,90 @@
|
||||||
|
.systemBox{
|
||||||
|
.ant-modal-body{
|
||||||
|
padding:1px 0px 0px 0px;
|
||||||
|
.sysBox{
|
||||||
|
background-image: url('./bg.png');
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
background-size: 100% 334px;
|
||||||
|
margin-top: -55px;
|
||||||
|
}
|
||||||
|
.sysnoticeBox{
|
||||||
|
width: 100%;
|
||||||
|
padding:80px 0px 34px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
width: 780px;
|
||||||
|
margin: 0px auto;
|
||||||
|
p.ntitle{
|
||||||
|
height: 33px;
|
||||||
|
font-size: 24px;
|
||||||
|
font-weight: 500;
|
||||||
|
color: #31FFF7;
|
||||||
|
line-height: 33px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
p.nSubtitle{
|
||||||
|
height: 25px;
|
||||||
|
line-height: 25px;
|
||||||
|
font-size: 18px;
|
||||||
|
font-weight: 500;
|
||||||
|
color: #FFFFFF;
|
||||||
|
margin-top: 60px;
|
||||||
|
padding-left: 20px;
|
||||||
|
}
|
||||||
|
.markdown-body{
|
||||||
|
box-shadow: 0px 0px 17px rgba(0,0,0,0.2);
|
||||||
|
border-radius: 4px;
|
||||||
|
margin-top: 17px!important;
|
||||||
|
}
|
||||||
|
.nContent{
|
||||||
|
padding:20px 34px;
|
||||||
|
background-color: #fff;
|
||||||
|
line-height: 30px;
|
||||||
|
font-size: 15px;
|
||||||
|
font-weight: 400;
|
||||||
|
color: #333;
|
||||||
|
.realmName{
|
||||||
|
margin-top: 20px;
|
||||||
|
display: flex;
|
||||||
|
ul{
|
||||||
|
width: 50%;
|
||||||
|
padding-left: 0px!important;
|
||||||
|
li{
|
||||||
|
font-size: 15px;
|
||||||
|
font-weight: 500;
|
||||||
|
line-height: 32px;
|
||||||
|
text-align: left;
|
||||||
|
color: #000;
|
||||||
|
list-style-type: none!important;
|
||||||
|
&:first-child{
|
||||||
|
color: #E65714;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.nSubdesc{
|
||||||
|
font-size: 15px;
|
||||||
|
font-weight: 400;
|
||||||
|
color: #000000;
|
||||||
|
line-height: 31px;
|
||||||
|
margin-top: 20px;
|
||||||
|
}
|
||||||
|
.nInfo{
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 400;
|
||||||
|
color: #333333;
|
||||||
|
text-align: right;
|
||||||
|
margin-top: 25px;
|
||||||
|
p{
|
||||||
|
height: 20px;
|
||||||
|
line-height: 20px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.nBtn{
|
||||||
|
text-align: center;
|
||||||
|
margin-top: 33px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,76 @@
|
||||||
|
import React , { useEffect , useState } from 'react';
|
||||||
|
import { Modal , Button } from 'antd';
|
||||||
|
import './Index.scss';
|
||||||
|
import '../../css/index.scss';
|
||||||
|
import RenderHtml from '../../../components/render-html';
|
||||||
|
import cookie from 'react-cookies';
|
||||||
|
|
||||||
|
function SystemNotice({system_notification,history}){
|
||||||
|
const [ visible , setVisible ] = useState(false);
|
||||||
|
|
||||||
|
useEffect(()=>{
|
||||||
|
if(system_notification && !cookie.load('notice_stage')){
|
||||||
|
setVisible(true);
|
||||||
|
}
|
||||||
|
},[system_notification,history.location])
|
||||||
|
|
||||||
|
function sureContinue() {
|
||||||
|
cookie.remove('notice_stage');
|
||||||
|
|
||||||
|
let inFifteenMinutes = new Date(new Date().getTime() + 24 * 3600 * 1000);//一天
|
||||||
|
// let inFifteenMinutes = new Date(new Date().getTime() + 60 * 1000);//一分钟
|
||||||
|
cookie.save('notice_stage', true,{ expires: inFifteenMinutes,path:"/" });
|
||||||
|
|
||||||
|
setVisible(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Modal
|
||||||
|
visible = {visible}
|
||||||
|
width="1000px"
|
||||||
|
footer={false}
|
||||||
|
title={false}
|
||||||
|
centered={true}
|
||||||
|
closable={false}
|
||||||
|
wrapClassName={'systemBox'}
|
||||||
|
>
|
||||||
|
<div className="sysBox">
|
||||||
|
<div className="sysnoticeBox">
|
||||||
|
<p className="ntitle">{system_notification && system_notification.subject}</p>
|
||||||
|
<p className="nSubtitle">{system_notification && system_notification.sub_subject}</p>
|
||||||
|
{/* <div className="nContent">
|
||||||
|
<div className="nMaindesc">
|
||||||
|
为了给用户提供更加稳定、优质的服务,我们即将对平台门户首页、平台名称、平台域名进行一次全面升级与变更。原平台名称:Trustie(中文名:确实)将于2021年10月xx日统一更改为Gitlink(中文名:确实开源)。届时平台域名将统一进行更换,更换规则如下
|
||||||
|
</div>
|
||||||
|
<div className="realmName">
|
||||||
|
<ul>
|
||||||
|
<li>原域名:</li>
|
||||||
|
<li>官网顶级域名https://www.trustie.net</li>
|
||||||
|
<li>版本库子域名https://forgeplus.trustie.net</li>
|
||||||
|
<li>论坛子域名https://forum.trustie.net/forums</li>
|
||||||
|
</ul>
|
||||||
|
<ul>
|
||||||
|
<li>更换后域名:</li>
|
||||||
|
<li>官网顶级域名https://www.gitlink.org.cn</li>
|
||||||
|
<li>版本库子域名https://www.git.gitlink.org.cn</li>
|
||||||
|
<li>论坛子域名https://forum.gitlink.org.cn</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<div className="nSubdesc">
|
||||||
|
自2021年10月xx日起,旧域名将停止访问。因平台名称与域名变更给您带来的不便,我们深表歉意!非常感谢您一直以来对本平台的信任与支持,我们将一如既往地为您提供优质的服务。 特此通知!
|
||||||
|
</div>
|
||||||
|
<div className="nInfo">
|
||||||
|
<p>Gitlink运营团队</p>
|
||||||
|
<p>2021年10月xx日</p>
|
||||||
|
</div>
|
||||||
|
</div> */}
|
||||||
|
<RenderHtml className="break_word_comments imageLayerParent" value={system_notification && system_notification.content} url={history.location}/>
|
||||||
|
<div className="nBtn">
|
||||||
|
<Button type="primary" className="btnblue" onClick={sureContinue}>确认并继续</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Modal>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
export default SystemNotice;
|
Binary file not shown.
After Width: | Height: | Size: 280 KiB |
|
@ -1,38 +1,35 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { AlignCenter , AlignTop , FlexAJ } from '../Component/layout';
|
import { AlignTop } from '../Component/layout';
|
||||||
import { Link } from 'react-router-dom';
|
import { Link } from 'react-router-dom';
|
||||||
|
|
||||||
function Releases({owner,projectsId,releaseVersions , baseOperate , projectType}){
|
function Releases({ owner, projectsId, releaseVersions, distribution }) {
|
||||||
|
|
||||||
return(
|
return(
|
||||||
<div>
|
<div>
|
||||||
<FlexAJ>
|
<Link to={`/${owner}/${projectsId}/releases`} className="font-16 color-ooo hoverA">
|
||||||
<AlignCenter><span className="font-16 color-grey-6">发行版</span>
|
<span>发行版</span>
|
||||||
{ releaseVersions && releaseVersions.total_count > 0 && <span className="infoCount">{releaseVersions.total_count}</span>}
|
{ releaseVersions && releaseVersions.total_count > 0 && <span className="infoCount">{releaseVersions.total_count}</span>}
|
||||||
</AlignCenter>
|
</Link>
|
||||||
{ (releaseVersions && releaseVersions.total_count > 0) || projectType ===2 ?
|
|
||||||
<Link className="font-12 color-grey-9" to={`/${owner}/${projectsId}/releases`}>全部</Link>
|
|
||||||
:
|
|
||||||
baseOperate && <Link className="font-12 color-blue" to={`/${owner}/${projectsId}/releases/new`}>新建</Link>
|
|
||||||
}
|
|
||||||
</FlexAJ>
|
|
||||||
{
|
{
|
||||||
releaseVersions && releaseVersions.total_count>0 ?
|
releaseVersions && releaseVersions.total_count>0 ?
|
||||||
releaseVersions.list.map((item,key)=>{
|
releaseVersions.list.map((item,key)=>{
|
||||||
return(
|
return(
|
||||||
key === 0 &&<AlignTop className="mt10">
|
key === 0 &&<AlignTop className="mt10">
|
||||||
<i className="iconfont icon-biaoqian3 color-grey-6 font-18 mr10"></i>
|
|
||||||
<div>
|
<div>
|
||||||
<p className="font-16 color-grey-6">
|
<p className="font-16 color-grey-6" style={{display:'flex',alignItems:'center'}}>
|
||||||
<Link to={`/${owner}/${projectsId}/releases`}>{item.name}</Link>
|
{/* 如果是点击最新则发行版列表页只展示最新的一个 */}
|
||||||
|
<Link to={{pathname:`/${owner}/${projectsId}/releases`,query:{turnFromNew:true}}} style={{maxWidth:'200px',overflow: 'hidden',whiteSpace: 'nowrap',textOverflow:'ellipsis'}}>{item.name}</Link>
|
||||||
<span className="font-12 laterest ml5">最新</span>
|
<span className="font-12 laterest ml5">最新</span>
|
||||||
</p>
|
</p>
|
||||||
<p className="color-grey-9 font-13">{item.created_at}</p>
|
<p className="color-grey-3 font-12">{item.created_at}</p>
|
||||||
</div>
|
</div>
|
||||||
</AlignTop>
|
</AlignTop>
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
:""
|
:
|
||||||
|
<div className="mt8">
|
||||||
|
您暂未发布任何版本
|
||||||
|
{distribution && <Link className="color-blue ml20" to={{pathname:`/${owner}/${projectsId}/releases/new`,state:{stable:true}}}>创建新版本</Link>}
|
||||||
|
</div>
|
||||||
}
|
}
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -2,9 +2,9 @@ import React from 'react';
|
||||||
import {Popover} from 'antd';
|
import {Popover} from 'antd';
|
||||||
import './Component.scss';
|
import './Component.scss';
|
||||||
|
|
||||||
export default (({menu , children})=>{
|
export default (({menu , children, overlayClassName})=>{
|
||||||
return(
|
return(
|
||||||
<Popover content={menu} trigger={['click']} placement='bottom'>
|
<Popover content={menu} trigger={['click']} placement='bottom' overlayClassName={overlayClassName}>
|
||||||
{children}
|
{children}
|
||||||
</Popover>
|
</Popover>
|
||||||
)
|
)
|
||||||
|
|
|
@ -5,6 +5,7 @@ import { Link } from 'react-router-dom';
|
||||||
export default ({ url , name , column , id , login })=>{
|
export default ({ url , name , column , id , login })=>{
|
||||||
const Img = styled.span`
|
const Img = styled.span`
|
||||||
display:flex;
|
display:flex;
|
||||||
|
font-weight: bold;
|
||||||
${column && "flex-direction: column;text-align:center;"}
|
${column && "flex-direction: column;text-align:center;"}
|
||||||
align-items: center;
|
align-items: center;
|
||||||
& img{
|
& img{
|
||||||
|
|
|
@ -51,7 +51,7 @@ function PipelineName({visible,onCancel,onOk,value ,branchList}){
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
</Select>
|
</Select>
|
||||||
<Select mode="multiple" allowClear value={eventValue} dropdownClassName="chooseCon" style={{width:"180px",marginLeft:"10px"}} onChange={(e)=>{console.log(e);setEventValue(e)}}>
|
<Select mode="multiple" allowClear value={eventValue} dropdownClassName="chooseCon" style={{width:"180px",marginLeft:"10px"}} onChange={(e)=>{setEventValue(e)}}>
|
||||||
{
|
{
|
||||||
EVENT.map((item,key)=>{
|
EVENT.map((item,key)=>{
|
||||||
return(
|
return(
|
||||||
|
|
|
@ -24,7 +24,6 @@ function onLayout(term, el) {
|
||||||
entry.target.offsetHeight,
|
entry.target.offsetHeight,
|
||||||
term,
|
term,
|
||||||
);
|
);
|
||||||
console.log('cols, rows', cols, rows);
|
|
||||||
term.resize(cols, rows);
|
term.resize(cols, rows);
|
||||||
mediator.publish('ssh-xterm-resize', {
|
mediator.publish('ssh-xterm-resize', {
|
||||||
columns: cols,
|
columns: cols,
|
||||||
|
@ -139,12 +138,10 @@ export default ({ sshConfigData, sid }) => {
|
||||||
}, 1000);
|
}, 1000);
|
||||||
}
|
}
|
||||||
isFirstConnected.current = true;
|
isFirstConnected.current = true;
|
||||||
console.log('event:', event);
|
|
||||||
|
|
||||||
const data = Base64.decode(event.data.toString());
|
const data = Base64.decode(event.data.toString());
|
||||||
let w = term._core._renderService.dimensions.actualCellWidth || 9.5;
|
let w = term._core._renderService.dimensions.actualCellWidth || 9.5;
|
||||||
|
|
||||||
console.log('data:', data, w, term);
|
|
||||||
term.write(data);
|
term.write(data);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -46,14 +46,11 @@ function DivertModal({form , visible , onSuccess , onCancel,owner,repo}){
|
||||||
Axios.post(url,{
|
Axios.post(url,{
|
||||||
...values
|
...values
|
||||||
}).then(result=>{
|
}).then(result=>{
|
||||||
if(result){
|
if(result && result.data.id){
|
||||||
if(result.data.status === 0){
|
onSuccess(result.data && result.data.owner);
|
||||||
onSuccess(result.data && result.data.owner);
|
}else{
|
||||||
}else{
|
onSuccess();
|
||||||
onSuccess();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}).catch(error=>{})
|
}).catch(error=>{})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
|
@ -0,0 +1,108 @@
|
||||||
|
import React, { Component } from 'react';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import { Icon } from 'antd';
|
||||||
|
import _ from 'lodash';
|
||||||
|
import Nodata from '../Nodata';
|
||||||
|
|
||||||
|
|
||||||
|
class PullRefresh extends Component {
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
this.state = {
|
||||||
|
}
|
||||||
|
this.pullRef = {};
|
||||||
|
// 节流
|
||||||
|
this.onScrollList = _.throttle(this.handleScroll, 200, {
|
||||||
|
leading: false,
|
||||||
|
trailing: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidMount() {
|
||||||
|
let dom = document.querySelector('.pull-refresh-wrap');
|
||||||
|
dom && dom.addEventListener('scroll', this.onScrollList);
|
||||||
|
}
|
||||||
|
|
||||||
|
componentWillUnmount() {
|
||||||
|
let dom = document.querySelector('.pull-refresh-wrap');
|
||||||
|
dom && dom.removeEventListener('scroll', this.onScrollList)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
handleScroll = () => {
|
||||||
|
if (this.props.count < this.props.pageSize) return;
|
||||||
|
if (this.props.type === 1 || this.props.type === 2) return;
|
||||||
|
const wrap = this.pullRef;
|
||||||
|
const currentScroll = wrap.scrollTop + wrap.clientHeight
|
||||||
|
|
||||||
|
// 触底
|
||||||
|
if (currentScroll >= (wrap.scrollHeight - 200)) {
|
||||||
|
this.loadData()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
handleLoadClick = () => {
|
||||||
|
this.loadData();
|
||||||
|
}
|
||||||
|
|
||||||
|
loadData = () => {
|
||||||
|
this.props.onPullRefresh()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
renderLoading() {
|
||||||
|
switch (this.props.type) {
|
||||||
|
case 0: // 加载更多
|
||||||
|
return <div className='text-center' onClick={this.handleLoadClick}>显示更多</div>
|
||||||
|
case 1: // 加载中
|
||||||
|
return (
|
||||||
|
<div className='text-center'>
|
||||||
|
<Icon type="loading" />
|
||||||
|
<span className='text-center'>加载中...</span>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
case 2: // 无样式
|
||||||
|
return <div className='text-center'>没有更多了</div>
|
||||||
|
default:
|
||||||
|
return <div className='text-center'>没有更多了</div>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const { className, count, children } = this.props;
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
className={`pull-refresh-wrap ${className}`}
|
||||||
|
ref={dom => { this.pullRef = dom }}
|
||||||
|
>
|
||||||
|
|
||||||
|
{children}
|
||||||
|
|
||||||
|
{
|
||||||
|
count < 1 && <Nodata _html="暂无未读消息"/>
|
||||||
|
}
|
||||||
|
|
||||||
|
{/* 大于分页数据才显示loading */}
|
||||||
|
{/* {this.props.count >= this.props.pageSize ? this.renderLoading() : null} */}
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
PullRefresh.propTypes = {
|
||||||
|
className: PropTypes.string,
|
||||||
|
children: PropTypes.any,
|
||||||
|
onPullRefresh: PropTypes.func.isRequired,
|
||||||
|
type: PropTypes.oneOf([0, 1, 2]),
|
||||||
|
count: PropTypes.number.isRequired,
|
||||||
|
pageSize: PropTypes.number.isRequired,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export default PullRefresh
|
|
@ -19,7 +19,7 @@ function Footer(){
|
||||||
|
|
||||||
return(
|
return(
|
||||||
<div>
|
<div>
|
||||||
<div style={{height:"497px"}}></div>
|
<div style={{height:"543px"}}></div>
|
||||||
<div className="newFooter edu-txt-center">
|
<div className="newFooter edu-txt-center">
|
||||||
{value && showhtml(value)}
|
{value && showhtml(value)}
|
||||||
{/* <div className="footerInfos">
|
{/* <div className="footerInfos">
|
||||||
|
|
|
@ -2,7 +2,7 @@ import React, { Component } from 'react';
|
||||||
import AccountProfile from "../../modules/user/AccountProfile";
|
import AccountProfile from "../../modules/user/AccountProfile";
|
||||||
import { getImageUrl } from 'educoder'
|
import { getImageUrl } from 'educoder'
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
import { Input , notification , Dropdown , Menu } from 'antd';
|
import { Input , notification , Dropdown ,Popover, Menu,Badge, Button } from 'antd';
|
||||||
import { Link } from 'react-router-dom';
|
import { Link } from 'react-router-dom';
|
||||||
|
|
||||||
import LoginDialog from '../../modules/login/LoginDialog';
|
import LoginDialog from '../../modules/login/LoginDialog';
|
||||||
|
@ -13,6 +13,7 @@ import '../../modules/tpm/TPMIndex.css';
|
||||||
import CheckProfile from '../Component/ProfileModal/Profile';
|
import CheckProfile from '../Component/ProfileModal/Profile';
|
||||||
|
|
||||||
import './header.scss';
|
import './header.scss';
|
||||||
|
import NoticeContent from './NoticeContent';
|
||||||
const $ = window.$
|
const $ = window.$
|
||||||
// TODO 这部分脚本从公共脚本中直接调用
|
// TODO 这部分脚本从公共脚本中直接调用
|
||||||
const { Search } = Input;
|
const { Search } = Input;
|
||||||
|
@ -47,6 +48,7 @@ class NewHeader extends Component {
|
||||||
settings: null,
|
settings: null,
|
||||||
visiblemyss: false,
|
visiblemyss: false,
|
||||||
openSearch:false,
|
openSearch:false,
|
||||||
|
visible:false, //浮动消息框展示控制
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
|
@ -92,9 +94,6 @@ class NewHeader extends Component {
|
||||||
this.setState({
|
this.setState({
|
||||||
user: newProps.user
|
user: newProps.user
|
||||||
})
|
})
|
||||||
if (newProps.Headertop !== undefined) {
|
|
||||||
old_url = newProps.Headertop.old_url
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
educoderlogin = () => {
|
educoderlogin = () => {
|
||||||
|
@ -121,7 +120,6 @@ class NewHeader extends Component {
|
||||||
})
|
})
|
||||||
};
|
};
|
||||||
HideAddcoursestypess = (i) => {
|
HideAddcoursestypess = (i) => {
|
||||||
console.log("调用了");
|
|
||||||
this.setState({
|
this.setState({
|
||||||
Addcoursestypes: false,
|
Addcoursestypes: false,
|
||||||
mydisplay: true,
|
mydisplay: true,
|
||||||
|
@ -255,6 +253,7 @@ class NewHeader extends Component {
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
renderMenu=(personal)=>{
|
renderMenu=(personal)=>{
|
||||||
const { current_user } = this.props;
|
const { current_user } = this.props;
|
||||||
return(
|
return(
|
||||||
|
@ -269,14 +268,18 @@ class NewHeader extends Component {
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
<li><Link to={`/settings/profile`}>设置</Link></li>
|
{/* <li><Link to={`/settings/profile`}>设置</Link></li> */}
|
||||||
<Menu.Item><a onClick={() => this.educoderloginysl()}>退出</a></Menu.Item>
|
<Menu.Item><a onClick={() => this.educoderloginysl()}>退出</a></Menu.Item>
|
||||||
</Menu>
|
</Menu>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
handleVisibleChange = visible => {
|
||||||
|
this.setState({ visible });
|
||||||
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { match} = this.props;
|
const { match ,resetUserInfo ,showNotification} = this.props;
|
||||||
let current_user = this.props.user;
|
let current_user = this.props.user;
|
||||||
let {
|
let {
|
||||||
AccountProfiletype,
|
AccountProfiletype,
|
||||||
|
@ -285,6 +288,7 @@ class NewHeader extends Component {
|
||||||
headtypesonClickbool,
|
headtypesonClickbool,
|
||||||
headtypess,
|
headtypess,
|
||||||
settings,
|
settings,
|
||||||
|
visible,
|
||||||
} = this.state;
|
} = this.state;
|
||||||
/*用户名称 用户头像url*/
|
/*用户名称 用户头像url*/
|
||||||
let activeIndex = false;
|
let activeIndex = false;
|
||||||
|
@ -363,7 +367,6 @@ class NewHeader extends Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
let search_url = settings && settings.common && settings.common.search;
|
let search_url = settings && settings.common && settings.common.search;
|
||||||
let notice_url = settings && settings.common && settings.common.notice;
|
|
||||||
return (
|
return (
|
||||||
<div className="newHeaders" id="nHeader">
|
<div className="newHeaders" id="nHeader">
|
||||||
<div className="headerContent">
|
<div className="headerContent">
|
||||||
|
@ -395,7 +398,7 @@ class NewHeader extends Component {
|
||||||
{
|
{
|
||||||
settings.navbar && settings.navbar.map((item, key) => {
|
settings.navbar && settings.navbar.map((item, key) => {
|
||||||
var new_link = item.link;
|
var new_link = item.link;
|
||||||
var user_login = this.props.user && this.props.user.login;
|
var user_login = current_user && current_user.login;
|
||||||
var is_hidden = item.hidden
|
var is_hidden = item.hidden
|
||||||
if (new_link && (new_link.indexOf("courses") > -1 || new_link.indexOf("contests") > -1)) {
|
if (new_link && (new_link.indexOf("courses") > -1 || new_link.indexOf("contests") > -1)) {
|
||||||
if (user_login) {
|
if (user_login) {
|
||||||
|
@ -426,25 +429,30 @@ class NewHeader extends Component {
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
<div className="head-right">
|
<div className="head-right">
|
||||||
{/* {search_url ? this.SearchInput(openSearch,search_url):""} */}
|
|
||||||
{ search_url && <HeadSearch {...this.props}/>}
|
{ search_url && <HeadSearch {...this.props}/>}
|
||||||
{
|
{
|
||||||
current_user && (current_user.main_site || current_user.login) && (settings && settings.add && settings.add.length>0)?
|
current_user && (current_user.main_site || current_user.login) && (settings && settings.add && settings.add.length>0)?
|
||||||
<Dropdown overlay={this.addMenu(settings && settings.add)} placement="bottomRight">
|
<Dropdown overlay={this.addMenu(settings && settings.add)} placement="bottomRight">
|
||||||
<i className="iconfont icon-tianjiafangda color-grey-6 ml30"></i>
|
<i className="iconfont icon-tianjiafangda color-grey-6 ml30 mr15"></i>
|
||||||
</Dropdown>:""
|
</Dropdown>:""
|
||||||
}
|
}
|
||||||
|
|
||||||
{this.props.user && this.props.user.login && notice_url ?
|
{ (settings && settings.common && settings.common.notice) && (current_user && current_user.login)?
|
||||||
<div className="ml30 edu-menu-panel">
|
<Popover
|
||||||
{user && user.login &&
|
overlayClassName="notice-popover"
|
||||||
<a href={`${notice_url}`} style={{ position: 'relative' }}>
|
placement={`bottomRight`}
|
||||||
<i className="iconfont icon-xiaoxilingdang color-grey-6"></i>
|
content={<NoticeContent visible={visible} current_user={current_user} showNotification={showNotification} resetUserInfo={resetUserInfo}/>}
|
||||||
<span className="newslight" style={{ display: this.props.Headertop === undefined ? "none" : this.props.Headertop.new_message === true ? "block" : "none" }}>
|
visible={visible}
|
||||||
</span>
|
onVisibleChange={this.handleVisibleChange}
|
||||||
</a>
|
destroyTooltipOnHide
|
||||||
}
|
>
|
||||||
</div>:""
|
<Link to={"/settings/notice"} className="message-icon">
|
||||||
|
{current_user && <Badge count={current_user.message_unread_total}>
|
||||||
|
<i className="iconfont icon-xiaoxilingdang color-grey-6 ml15 mr15"></i>
|
||||||
|
</Badge>}
|
||||||
|
</Link>
|
||||||
|
</Popover>
|
||||||
|
: ""
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
{!user || (user && !user.login) ?
|
{!user || (user && !user.login) ?
|
||||||
|
|
|
@ -0,0 +1,262 @@
|
||||||
|
import React, { useEffect, useState } from 'react';
|
||||||
|
import { Badge, Menu } from 'antd';
|
||||||
|
import { Link } from 'react-router-dom';
|
||||||
|
import axios from 'axios';
|
||||||
|
import AppPullRefresh from './AppPullRefresh';
|
||||||
|
import { noticeSourceType } from '../common/static';
|
||||||
|
import './header.scss';
|
||||||
|
import '../SecuritySetting/notice/manager/Index.scss';
|
||||||
|
import '../SecuritySetting/Index.scss';
|
||||||
|
import '../SecuritySetting/notice/myNotice/Index.scss';
|
||||||
|
|
||||||
|
|
||||||
|
function NoticeContent({ visible, showNotification, resetUserInfo, current_user: { login } }) {
|
||||||
|
const [initialize, setInitialize] = useState(true);
|
||||||
|
const [noticeType, setNoticeType] = useState("notification");
|
||||||
|
const [letterUnreadCount, setLetterUnreadCount] = useState(0);//未读私信数量
|
||||||
|
|
||||||
|
const [noticeUnreadCount, setNoticeUnreadCount] = useState(0);//未读系统通知数量
|
||||||
|
const [noticePage, setNoticePage] = useState(0);
|
||||||
|
const [noticeUnreadList, setNoticeUnreadList] = useState([]);//未读系统通知列表
|
||||||
|
|
||||||
|
const [atUnreadCount, setAtUnreadCount] = useState();//未读@我数量
|
||||||
|
const [atPage, setAtPage] = useState(0);
|
||||||
|
const [atUnreadList, setAtUnreadList] = useState([]);//未读@我列表
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
resetUserInfo();
|
||||||
|
}, [noticeUnreadCount,atUnreadCount]);
|
||||||
|
|
||||||
|
useEffect(()=>{
|
||||||
|
setNoticePage(0);
|
||||||
|
setAtPage(0);
|
||||||
|
},[visible])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const params = {
|
||||||
|
type: noticeType,
|
||||||
|
limit: 10,
|
||||||
|
page: noticeType === "notification" ? noticePage : noticeType === "atme" ? atPage : "",
|
||||||
|
status: 1,
|
||||||
|
}
|
||||||
|
getMessageList(params);
|
||||||
|
}, [noticePage, atPage]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const params = {
|
||||||
|
type: noticeType,
|
||||||
|
limit: 10,
|
||||||
|
page: 0,
|
||||||
|
status: 1,
|
||||||
|
};
|
||||||
|
if (initialize) {
|
||||||
|
params.type = "atme"
|
||||||
|
}
|
||||||
|
visible && getMessageList(params);
|
||||||
|
}, [visible]);
|
||||||
|
|
||||||
|
|
||||||
|
function getMessageList(params) {
|
||||||
|
axios.get(`/users/${login}/messages.json`, {
|
||||||
|
params: params,
|
||||||
|
}).then((response) => {
|
||||||
|
if (response && response.data) {
|
||||||
|
setNoticeUnreadCount(response.data.unread_notification);
|
||||||
|
setAtUnreadCount(response.data.unread_atme);
|
||||||
|
if (params.type === "notification") {
|
||||||
|
let list = response.data.messages;
|
||||||
|
if (params.page !== 0) {
|
||||||
|
list = [...noticeUnreadList, ...list];
|
||||||
|
}
|
||||||
|
setNoticeUnreadList(list);
|
||||||
|
if (initialize) {
|
||||||
|
// 如果是第一次加载,根据数据量判断是否切换tab栏
|
||||||
|
setInitialize(false);
|
||||||
|
if (response.data.unread_notification === 0 && response.data.unread_atme !== 0) {
|
||||||
|
setNoticeType("atme");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (params.type === "atme") {
|
||||||
|
let list = response.data.messages;
|
||||||
|
if (params.page !== 0) {
|
||||||
|
list = [...atUnreadList, ...list];
|
||||||
|
}
|
||||||
|
setAtUnreadList(list);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function readAll() {
|
||||||
|
axios.post(`/users/${login}/messages/read.json`, {
|
||||||
|
type: noticeType,
|
||||||
|
ids: [-1]
|
||||||
|
}).then((response) => {
|
||||||
|
let data = response.data;
|
||||||
|
if (!data) return;
|
||||||
|
if (data.status === 0) {
|
||||||
|
changeReadMarkAll(noticeType);
|
||||||
|
} else {
|
||||||
|
showNotification(data.message);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function changeReadMarkAll(noticeType) {
|
||||||
|
if (noticeType === "notification") {
|
||||||
|
let list = noticeUnreadList.slice();
|
||||||
|
list.forEach(item => {
|
||||||
|
item.status = 2;
|
||||||
|
})
|
||||||
|
setNoticeUnreadList(list);
|
||||||
|
setNoticeUnreadCount(0);
|
||||||
|
} else if (noticeType === "atme") {
|
||||||
|
let list = atUnreadList.slice();
|
||||||
|
list.forEach(item => {
|
||||||
|
item.status = 2;
|
||||||
|
})
|
||||||
|
setAtUnreadList(list);
|
||||||
|
setAtUnreadCount(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// const [letter_unread_list, setLetter_unread_list] = useState([
|
||||||
|
// {
|
||||||
|
// id: 122,
|
||||||
|
// read: 0, //是否已读,0未读,1已读
|
||||||
|
// send_name: "蒋宇航", //消息发送人
|
||||||
|
// send_login: "jiangYuHang", //消息发送人的login,前端根据这个跳转到消息内页
|
||||||
|
// content: "私信内容", //最近一条未读消息的内容
|
||||||
|
// create_time: "2019-03-04 18:08", //发送时间
|
||||||
|
// },
|
||||||
|
// ]);
|
||||||
|
|
||||||
|
function readItem(item) {
|
||||||
|
axios.post(`/users/${login}/messages/read.json`, {
|
||||||
|
type: noticeType,
|
||||||
|
ids: [item.id]
|
||||||
|
}).then((response) => {
|
||||||
|
let data = response.data;
|
||||||
|
if (!data) return;
|
||||||
|
if (data.status === 0) {
|
||||||
|
changeReadMark(item);
|
||||||
|
item.notification_url && window.open(item.notification_url);
|
||||||
|
} else {
|
||||||
|
showNotification(data.message);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function changeReadMark(item) {
|
||||||
|
if (item.type === "notification") {
|
||||||
|
let list = noticeUnreadList.slice();
|
||||||
|
let index = noticeUnreadList.indexOf(item);
|
||||||
|
list[index].status = 2;
|
||||||
|
setNoticeUnreadList(list);
|
||||||
|
if (noticeUnreadCount > 0) {
|
||||||
|
setNoticeUnreadCount(noticeUnreadCount - 1);
|
||||||
|
}
|
||||||
|
} else if (item.type === "atme") {
|
||||||
|
let list = atUnreadList.slice();
|
||||||
|
let index = atUnreadList.indexOf(item);
|
||||||
|
list[index].status = 2;
|
||||||
|
setAtUnreadList(list);
|
||||||
|
if (atUnreadCount > 0) {
|
||||||
|
setAtUnreadCount(atUnreadCount - 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="messageHoverDiv notice01">
|
||||||
|
<div className="sshHead hoverNotice-head">
|
||||||
|
<Menu mode="horizontal" selectedKeys={noticeType} onClick={(e) => setNoticeType(e.key)}>
|
||||||
|
<Menu.Item key="notification"><Badge count={noticeUnreadCount}>系统通知</Badge></Menu.Item>
|
||||||
|
{/* <Menu.Item key="1" id="item-private"><Badge count={letterUnreadCount}>私信</Badge></Menu.Item> */}
|
||||||
|
<Menu.Item key="atme"><Badge count={atUnreadCount}>@我</Badge></Menu.Item>
|
||||||
|
</Menu>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* 系统通知 */}
|
||||||
|
{noticeType === "notification" && <AppPullRefresh
|
||||||
|
className='hoverNotice-body' // 外部添加className加以区分
|
||||||
|
onPullRefresh={() => { setNoticePage(noticePage + 1); }} //触发加载ajax的function
|
||||||
|
// type={2} // 传送加载组件的状态
|
||||||
|
count={noticeUnreadList.length} // 数据当前的总数量
|
||||||
|
pageSize={10} //
|
||||||
|
>
|
||||||
|
{
|
||||||
|
noticeUnreadList.map(item => {
|
||||||
|
return (
|
||||||
|
<div key={item.id + Math.random()} className="noticeCont-back" onClick={() => { readItem(item) }}>
|
||||||
|
<div className={`noticeCont ${item.notification_url?'pointer':''}`}>
|
||||||
|
<span style={{ visibility: item.status === 1 ? 'visible' : 'hidden' }}>
|
||||||
|
<Badge color="#FA2020" />
|
||||||
|
</span>
|
||||||
|
<i className={"iconfont " + noticeSourceType[item.source]}></i>
|
||||||
|
<div className="noticeCont-text">
|
||||||
|
<span className="content-span notice-cont-span" dangerouslySetInnerHTML={{ __html: item.content }}></span>
|
||||||
|
<span className="timeSpan">{item.time_ago}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
</AppPullRefresh>
|
||||||
|
}
|
||||||
|
|
||||||
|
{/* @我 */}
|
||||||
|
{noticeType === "atme" && <AppPullRefresh
|
||||||
|
className='hoverNotice-body' // 外部添加className加以区分
|
||||||
|
onPullRefresh={() => { setAtPage(atPage + 1); }} //触发加载ajax的function
|
||||||
|
// type={1} // 传送加载组件的状态
|
||||||
|
count={atUnreadList.length} // 数据当前的总数量
|
||||||
|
pageSize={10} //
|
||||||
|
>
|
||||||
|
{atUnreadList.map(item => {
|
||||||
|
return (
|
||||||
|
<div key={item.id + Math.random()} className="noticeCont-back" onClick={() => { readItem(item) }}>
|
||||||
|
<div className="noticeCont">
|
||||||
|
<span style={{ visibility: item.status === 1 ? 'visible' : 'hidden' }}>
|
||||||
|
<Badge color="#FA2020" />
|
||||||
|
</span>
|
||||||
|
<div className="noticeCont-text">
|
||||||
|
<span className="content-span atme-cont-span" dangerouslySetInnerHTML={{ __html: "<b>" + (item.sender ? item.sender.name : '') + "</b> " + item.content + " 中@我" }}></span>
|
||||||
|
<span className="timeSpan">{item.time_ago}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
</AppPullRefresh>
|
||||||
|
}
|
||||||
|
|
||||||
|
{/* 私信 */}
|
||||||
|
{/* {noticeType === "1" ? letter_unread_list.length > 0 ? letter_unread_list.map(item => {
|
||||||
|
return (
|
||||||
|
<div className="noticeCont-back">
|
||||||
|
<div className="noticeCont" style={{ height: item.content.length >= 30 && item.content.length <= 34 ? '65px' : "" }}>
|
||||||
|
<Badge color="#FA2020" />
|
||||||
|
<div className="noticeCont-text">
|
||||||
|
<span>{item.send_name}:</span>
|
||||||
|
<span className="boldSpan" dangerouslySetInnerHTML={{ __html: item.content.length >= 50 ? item.content.substr(0, 50) + "..." : item.content }}></span>
|
||||||
|
<span className="timeSpan">{item.create_time ? timeAgo(item.create_time) : "刚刚"}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}) : "暂无数据" : ""} */}
|
||||||
|
<div className="hoverNotice-buttom">
|
||||||
|
<Link to={{pathname:"/settings/notice",query:{noticeType:noticeType}}}>全部消息</Link>
|
||||||
|
{noticeUnreadCount > 0 && noticeType === "notification" && <a onClick={readAll}>所有系统消息一键已读</a>}
|
||||||
|
{atUnreadCount > 0 && noticeType === "atme" && <a onClick={readAll}>所有@我一键已读</a>}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
)
|
||||||
|
}
|
||||||
|
export default NoticeContent;
|
|
@ -24,8 +24,9 @@
|
||||||
width: 34px;
|
width: 34px;
|
||||||
height: 34px;
|
height: 34px;
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
margin-left: 30px;
|
margin-left: 15px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.currentMenu{
|
.currentMenu{
|
||||||
width: 120px;
|
width: 120px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
@ -127,3 +128,138 @@
|
||||||
text-align: right;
|
text-align: right;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 右上角小铃铛单独样式
|
||||||
|
.notice-popover{
|
||||||
|
//popover小尖尖
|
||||||
|
.ant-popover-arrow{
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
//popover框
|
||||||
|
.ant-popover-inner-content {
|
||||||
|
width: 386px;
|
||||||
|
height: 446px;
|
||||||
|
box-shadow: 0px 4px 8px 2px rgba(212, 212, 212, 0.5);
|
||||||
|
border-radius: 4px;
|
||||||
|
margin-top: -10px;
|
||||||
|
padding: 12px 1px 12px 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.messageHoverDiv .ant-menu-item{
|
||||||
|
margin-right: 24px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hoverNotice-head{
|
||||||
|
margin-left: 18px;
|
||||||
|
|
||||||
|
& .ant-badge{
|
||||||
|
font-size: 14px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
&>.ant-menu-horizontal {
|
||||||
|
border-bottom: 1px solid #e8e8e8 !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.hoverNotice-body{
|
||||||
|
height: 342px;
|
||||||
|
overflow-y: scroll;
|
||||||
|
|
||||||
|
& b{
|
||||||
|
font-weight: 400;
|
||||||
|
text-shadow: 0.5px 0 0 #333;
|
||||||
|
}
|
||||||
|
|
||||||
|
.none_panels{
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.message-icon{
|
||||||
|
position: relative;
|
||||||
|
.ant-scroll-number{
|
||||||
|
right:12px;
|
||||||
|
padding: 0 0px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
.hoverNotice-buttom{
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
padding: 12px 18px;
|
||||||
|
a{
|
||||||
|
color: #466AFF;
|
||||||
|
&:hover{
|
||||||
|
opacity:0.85;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.noticeCont-back{
|
||||||
|
.pointer{
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
&:hover{
|
||||||
|
background: #F3F4F6;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.noticeCont{
|
||||||
|
display: flex;
|
||||||
|
margin: 0 16px 0 18px;
|
||||||
|
padding: 12px 0 10px 0;
|
||||||
|
line-height: 24px;
|
||||||
|
border-bottom: 1px solid #EEEEEE;
|
||||||
|
cursor: default;
|
||||||
|
i{
|
||||||
|
font-size: 14px !important;
|
||||||
|
margin-right: 6px;
|
||||||
|
color: #333333;
|
||||||
|
}
|
||||||
|
|
||||||
|
.boldSpan{
|
||||||
|
font-weight: 400;
|
||||||
|
text-shadow: 0.5px 0 0 #333;
|
||||||
|
}
|
||||||
|
|
||||||
|
.noticeCont-text{
|
||||||
|
display: flex;
|
||||||
|
color:#333333;
|
||||||
|
flex:auto;
|
||||||
|
justify-content: space-between;
|
||||||
|
|
||||||
|
& .content-span{
|
||||||
|
word-break: break-all;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
display: -webkit-box;
|
||||||
|
-webkit-box-orient: vertical;
|
||||||
|
-webkit-line-clamp: 2;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
& .atme-cont-span{
|
||||||
|
width: 272px;
|
||||||
|
}
|
||||||
|
|
||||||
|
& .notice-cont-span{
|
||||||
|
width: 255px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.timeSpan{
|
||||||
|
font-size: 12px;
|
||||||
|
color: #666666;
|
||||||
|
}
|
||||||
|
|
||||||
|
.at-name{
|
||||||
|
margin-right: 12px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.text-center{
|
||||||
|
text-align: center;
|
||||||
|
}
|
|
@ -1,8 +1,9 @@
|
||||||
import React , { useEffect , useState } from 'react';
|
import React , { useEffect , useState } from 'react';
|
||||||
import { WhiteBack , Box , LongWidth , ShortWidth , Gap , AlignCenter , FlexAJ } from '../Component/layout';
|
import { WhiteBack , Box , LongWidth , ShortWidth , Gap , AlignCenter , FlexAJ } from '../Component/layout';
|
||||||
import { Dropdown , Menu , Divider , Spin, Button } from 'antd';
|
import { Dropdown , Menu , Divider , Spin, Button , Typography } from 'antd';
|
||||||
import { getImageUrl } from "educoder";
|
import { getImageUrl } from "educoder";
|
||||||
import { Link } from 'react-router-dom';
|
import { Link } from 'react-router-dom';
|
||||||
|
import { truncateCommitId } from "../common/util";
|
||||||
import CloneAddress from '../Branch/CloneAddress';
|
import CloneAddress from '../Branch/CloneAddress';
|
||||||
|
|
||||||
import SelectBranch from '../Branch/Select';
|
import SelectBranch from '../Branch/Select';
|
||||||
|
@ -21,10 +22,11 @@ import UpdateDescModal from './sub/UpdateDescModal';
|
||||||
import Nodata from '../Nodata';
|
import Nodata from '../Nodata';
|
||||||
import Invite from './sub/Invite';
|
import Invite from './sub/Invite';
|
||||||
import CheckProfile from '../Component/ProfileModal/Profile';
|
import CheckProfile from '../Component/ProfileModal/Profile';
|
||||||
|
import RenderHtml from '../../components/render-html';
|
||||||
/**
|
/**
|
||||||
* projectDetail.type:0是托管项目,1是镜像项目,2是同步镜像项目(为2时不支持在线创建、在线上传、在线修改、在线删除、创建合并请求等功能)
|
* projectDetail.type:0是托管项目,1是镜像项目,2是同步镜像项目(为2时不支持在线创建、在线上传、在线修改、在线删除、创建合并请求等功能)
|
||||||
*/
|
*/
|
||||||
|
const { Paragraph } = Typography;
|
||||||
function turnbar(str){
|
function turnbar(str){
|
||||||
if(str && str.length>0 && str.indexOf("/")>-1){
|
if(str && str.length>0 && str.indexOf("/")>-1){
|
||||||
return str.replaceAll('/','%2F');
|
return str.replaceAll('/','%2F');
|
||||||
|
@ -66,6 +68,7 @@ function CoderDepot(props){
|
||||||
const [ editReadme , setEditReadme ] = useState(false);
|
const [ editReadme , setEditReadme ] = useState(false);
|
||||||
const [ pullsFlag , setPullsFlag ] = useState(true);
|
const [ pullsFlag , setPullsFlag ] = useState(true);
|
||||||
const [ issuesFlag , setIssuesFlag ] = useState(true);
|
const [ issuesFlag , setIssuesFlag ] = useState(true);
|
||||||
|
const [ releaseVersions , setReleaseVersions] = useState(undefined);
|
||||||
|
|
||||||
const owner = props.match.params.owner;
|
const owner = props.match.params.owner;
|
||||||
const projectsId = props.match.params.projectsId;
|
const projectsId = props.match.params.projectsId;
|
||||||
|
@ -73,7 +76,8 @@ function CoderDepot(props){
|
||||||
branchName = returnbar(branchName);
|
branchName = returnbar(branchName);
|
||||||
const details = props.projectDetail;
|
const details = props.projectDetail;
|
||||||
let pathname = props.history.location.pathname;
|
let pathname = props.history.location.pathname;
|
||||||
|
//distribution:判断此用户是否可以创建发行版
|
||||||
|
const distribution = details && details.type != 2 && (details.permission === "Admin" || details.permission === "Owner" || details.permission === "Manager");
|
||||||
const { bannerList } = props;
|
const { bannerList } = props;
|
||||||
|
|
||||||
useEffect(()=>{
|
useEffect(()=>{
|
||||||
|
@ -118,14 +122,47 @@ function CoderDepot(props){
|
||||||
setTreeValue(url);
|
setTreeValue(url);
|
||||||
getFileInfo(url,branchName);
|
getFileInfo(url,branchName);
|
||||||
setType("file");
|
setType("file");
|
||||||
|
// getReadmeInfo(url,branchName);
|
||||||
|
// setReadme(undefined);
|
||||||
}else{
|
}else{
|
||||||
setTreeValue(undefined);
|
setTreeValue(undefined);
|
||||||
getDirInfo(branchName || defaultBranch);
|
getDirInfo(branchName || defaultBranch);
|
||||||
setType("dir");
|
setType("dir");
|
||||||
|
// getReadmeInfo('', branchName || defaultBranch);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},[projectsId,owner,pathname,defaultBranch])
|
},[projectsId,owner,pathname,defaultBranch])
|
||||||
|
|
||||||
|
useEffect(()=>{
|
||||||
|
axios.get(`/${owner}/${projectsId}/releases.json`).then((result)=>{
|
||||||
|
if(result && result.data){
|
||||||
|
const release = {
|
||||||
|
"list":result.data.releases,
|
||||||
|
"total_count":result.data.releases.length
|
||||||
|
}
|
||||||
|
setReleaseVersions(release);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},[])
|
||||||
|
|
||||||
|
// 获取readme信息
|
||||||
|
function getReadmeInfo(path, ref) {
|
||||||
|
axios.get(`/${owner}/${projectsId}/readme.json`, {
|
||||||
|
params:{
|
||||||
|
owner: owner,
|
||||||
|
repo: projectsId,
|
||||||
|
filepath:path,
|
||||||
|
ref:ref || branchName
|
||||||
|
}
|
||||||
|
}).then((result) => {
|
||||||
|
if (result) {
|
||||||
|
setReadme(result.data);
|
||||||
|
} else {
|
||||||
|
setReadme(undefined);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
// 获取主目录列表
|
// 获取主目录列表
|
||||||
function getDirInfo(branch){
|
function getDirInfo(branch){
|
||||||
setIsSpin(true);
|
setIsSpin(true);
|
||||||
|
@ -145,10 +182,10 @@ function CoderDepot(props){
|
||||||
setLastCommitAuthor(c && c.committer);
|
setLastCommitAuthor(c && c.committer);
|
||||||
setMainFlag(true);
|
setMainFlag(true);
|
||||||
setReadOnly(true);
|
setReadOnly(true);
|
||||||
setReadme(result.data.readme);
|
// setReadme(result.data.readme);
|
||||||
setEditReadme(false);
|
setEditReadme(false);
|
||||||
setHide(true);
|
setHide(true);
|
||||||
console.log("dddd:",result.data.entries);
|
getReadmeInfo('', branchName || defaultBranch);
|
||||||
}
|
}
|
||||||
setTimeout(function(){setIsSpin(false);},500);
|
setTimeout(function(){setIsSpin(false);},500);
|
||||||
}).catch(error=>{setIsSpin(false);})
|
}).catch(error=>{setIsSpin(false);})
|
||||||
|
@ -160,7 +197,7 @@ function CoderDepot(props){
|
||||||
let ele = document.getElementById("ptxt");
|
let ele = document.getElementById("ptxt");
|
||||||
if(ele){
|
if(ele){
|
||||||
let h = ele.offsetHeight;
|
let h = ele.offsetHeight;
|
||||||
if( h > 18 ) setHideBtn(true);
|
if( h > 35 ) setHideBtn(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},[projectDetail,lastCommit])
|
},[projectDetail,lastCommit])
|
||||||
|
@ -181,15 +218,18 @@ function CoderDepot(props){
|
||||||
setDirInfo(undefined);
|
setDirInfo(undefined);
|
||||||
setFileInfo(en);
|
setFileInfo(en);
|
||||||
setType(en.type);
|
setType(en.type);
|
||||||
|
setReadme(undefined);
|
||||||
}else{
|
}else{
|
||||||
setFileInfo(undefined);
|
setFileInfo(undefined);
|
||||||
setDirInfo(en);
|
setDirInfo(en);
|
||||||
setType("dir");
|
setType("dir");
|
||||||
|
getReadmeInfo(path, branchName || defaultBranch);
|
||||||
}
|
}
|
||||||
let c = result.data.last_commit
|
let c = result.data.last_commit
|
||||||
setLastCommit(c && c.commit);
|
setLastCommit(c && c.commit);
|
||||||
setLastCommitAuthor(c && c.committer);
|
setLastCommitAuthor(c && c.committer);
|
||||||
setMainFlag(false);
|
setMainFlag(false);
|
||||||
|
setReadOnly(true);
|
||||||
setReadOnly(!editReadme);
|
setReadOnly(!editReadme);
|
||||||
setHide(true);
|
setHide(true);
|
||||||
}
|
}
|
||||||
|
@ -209,7 +249,7 @@ function CoderDepot(props){
|
||||||
let b = branchName || defaultBranch;
|
let b = branchName || defaultBranch;
|
||||||
let checkvalue = turnbar(b);
|
let checkvalue = turnbar(b);
|
||||||
return (
|
return (
|
||||||
<Menu>
|
<Menu className="fileMenu">
|
||||||
<Menu.Item>
|
<Menu.Item>
|
||||||
<CheckProfile {...props} sureFunc={()=>urlLink(`/${owner}/${projectsId}/${checkvalue}/uploadfile${treeValue === undefined ? "" : `/${treeValue}`}`)}>上传文件</CheckProfile>
|
<CheckProfile {...props} sureFunc={()=>urlLink(`/${owner}/${projectsId}/${checkvalue}/uploadfile${treeValue === undefined ? "" : `/${treeValue}`}`)}>上传文件</CheckProfile>
|
||||||
</Menu.Item>
|
</Menu.Item>
|
||||||
|
@ -301,8 +341,10 @@ function CoderDepot(props){
|
||||||
const mdFlag = n && n.substring(n.length-3,n.length) === ".md";
|
const mdFlag = n && n.substring(n.length-3,n.length) === ".md";
|
||||||
|
|
||||||
const { current_user } = props;
|
const { current_user } = props;
|
||||||
const baseOperate = projectDetail && projectDetail.permission && projectDetail.permission !=="Reporter";
|
const baseOper = current_user && current_user.login && issuesFlag;
|
||||||
|
const baseOperate = projectDetail && projectDetail.permission && projectDetail.permission !=="Reporter" && projectDetail.type !== 2 && pullsFlag;
|
||||||
const fileOperate = type === "dir" && projectDetail && projectDetail.type !== 2 && ((projectDetail.permission && projectDetail.permission !=="Reporter") || (current_user && current_user.admin));
|
const fileOperate = type === "dir" && projectDetail && projectDetail.type !== 2 && ((projectDetail.permission && projectDetail.permission !=="Reporter") || (current_user && current_user.admin));
|
||||||
|
|
||||||
return(
|
return(
|
||||||
<WhiteBack>
|
<WhiteBack>
|
||||||
<UpdateDescModal desc={desc} website={website} lesson_url={lesson_url} visible={openModal} onCancel={()=>setOpenModal(false)} onOk={okUpdate}/>
|
<UpdateDescModal desc={desc} website={website} lesson_url={lesson_url} visible={openModal} onCancel={()=>setOpenModal(false)} onOk={okUpdate}/>
|
||||||
|
@ -321,7 +363,7 @@ function CoderDepot(props){
|
||||||
list = {mainFlag ? dirInfo : undefined}
|
list = {mainFlag ? dirInfo : undefined}
|
||||||
/>
|
/>
|
||||||
<div className="drawerBtn" onClick={()=>setVisible(true)}>
|
<div className="drawerBtn" onClick={()=>setVisible(true)}>
|
||||||
<i className="iconfont icon-youjiantou font-16"></i>
|
<i className="iconfont icon-zuohuaicon font-14"></i>
|
||||||
<span>目录</span>
|
<span>目录</span>
|
||||||
</div>
|
</div>
|
||||||
</React.Fragment>
|
</React.Fragment>
|
||||||
|
@ -334,7 +376,7 @@ function CoderDepot(props){
|
||||||
<div className="panelmenu">
|
<div className="panelmenu">
|
||||||
<FlexAJ>
|
<FlexAJ>
|
||||||
<AlignCenter>
|
<AlignCenter>
|
||||||
<div className="mr20">
|
<div className="mr30">
|
||||||
{
|
{
|
||||||
props && props.platform ?
|
props && props.platform ?
|
||||||
<SelectBranch
|
<SelectBranch
|
||||||
|
@ -350,41 +392,61 @@ function CoderDepot(props){
|
||||||
<span>分支:<span className="color-grey-6">{branchName || defaultBranch}</span></span>
|
<span>分支:<span className="color-grey-6">{branchName || defaultBranch}</span></span>
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
<AlignCenter className="mr20">
|
{
|
||||||
<Link to={`/${owner}/${projectsId}/branches`} className="color-grey-9">
|
treeValuePath && treeValuePath.length > 0 ?
|
||||||
<i className="iconfont icon-fenzhi2 font-18 color-grey-9 mr3"></i>
|
<Path
|
||||||
<span className="color-grey-6 mr3">{projectDetail && projectDetail.branches && projectDetail.branches.total_count}个</span>分支
|
identifier={projectDetail && projectDetail.identifier}
|
||||||
</Link>
|
treeValuePath={treeValuePath}
|
||||||
</AlignCenter>
|
returnUlr={returnUlr}
|
||||||
<AlignCenter className="mr20">
|
returnMain={returnMain}
|
||||||
<Link to={`/${owner}/${projectsId}/tags`} className="color-grey-9">
|
getPathUrl={getPathUrl}
|
||||||
<i className="iconfont icon-biaoqian3 font-16 color-grey-9 mr3"></i>
|
/>
|
||||||
<span className="color-grey-6 mr3">{projectDetail && projectDetail.tags && projectDetail.tags.total_count}个</span>标签
|
:
|
||||||
</Link>
|
<React.Fragment>
|
||||||
</AlignCenter>
|
<AlignCenter className="mr20">
|
||||||
|
<Link to={`/${owner}/${projectsId}/branches`} className="iconBtn">
|
||||||
|
<i className="iconfont icon-master_icon font-16"></i>
|
||||||
|
<span>分支</span>
|
||||||
|
<span>{projectDetail && projectDetail.branches_count}</span>
|
||||||
|
</Link>
|
||||||
|
</AlignCenter>
|
||||||
|
<AlignCenter className="mr20">
|
||||||
|
<Link to={`/${owner}/${projectsId}/tags`} className="iconBtn">
|
||||||
|
<i className="iconfont icon-biaoqianicon font-16"></i>
|
||||||
|
<span>标签</span>
|
||||||
|
<span>{projectDetail && projectDetail.tags_count}</span>
|
||||||
|
</Link>
|
||||||
|
</AlignCenter>
|
||||||
|
</React.Fragment>
|
||||||
|
}
|
||||||
</AlignCenter>
|
</AlignCenter>
|
||||||
<AlignCenter>
|
<AlignCenter className="depotBtn">
|
||||||
{
|
{
|
||||||
baseOperate && ((projectDetail.type !== 2 && pullsFlag) || issuesFlag )&&
|
(baseOperate || baseOper) &&
|
||||||
<div className="mr20 addOptionBtn">
|
<div className="addOptionBtn">
|
||||||
{
|
{
|
||||||
projectDetail.type !== 2 && pullsFlag &&
|
baseOperate &&
|
||||||
<CheckProfile {...props} sureFunc={()=>urlLink(`/${owner}/${projectsId}/pulls/new`)} >+ 合并请求</CheckProfile>
|
<CheckProfile {...props} sureFunc={()=>urlLink(`/${owner}/${projectsId}/compare/master...${branchName || defaultBranch}`)} >+ 合并请求</CheckProfile>
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
issuesFlag &&
|
baseOper &&
|
||||||
<CheckProfile {...props} sureFunc={()=>urlLink(`/${owner}/${projectsId}/issues/new`)} >+ 任务</CheckProfile>
|
<CheckProfile {...props} sureFunc={()=>urlLink(`/${owner}/${projectsId}/issues/new`)} >+ 易修</CheckProfile>
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
{ fileOperate &&
|
{ fileOperate &&
|
||||||
<Dropdown overlay={fileMenu()} className="mr20" trigger={['click']}>
|
<Dropdown
|
||||||
<Button type="default">文件 <i className="iconfont icon-sanjiaoxing-down ml3 font-14 color-grey-9"></i></Button>
|
overlay={fileMenu()}
|
||||||
|
className="mr10"
|
||||||
|
trigger={['click']}
|
||||||
|
getPopupContainer={document.parentNode}
|
||||||
|
>
|
||||||
|
<a>文件 <i className="iconfont icon-sanjiaoxing-down ml3 font-14 color-grey-6 mr-5"></i></a>
|
||||||
</Dropdown>
|
</Dropdown>
|
||||||
}
|
}
|
||||||
|
|
||||||
<Dropdown overlay={downloadMenu} placement="bottomRight" trigger={['click']}>
|
<Dropdown overlay={downloadMenu} placement="bottomRight" trigger={['click']}>
|
||||||
<Button type={'primary'}>下载 <i className="iconfont icon-sanjiaoxing-down ml3 font-14 color-white"></i></Button>
|
<Button type={'primary'}>下载 <i className="iconfont icon-sanjiaoxing-down ml3 font-14 color-white mr-3"></i></Button>
|
||||||
</Dropdown>
|
</Dropdown>
|
||||||
</AlignCenter>
|
</AlignCenter>
|
||||||
</FlexAJ>
|
</FlexAJ>
|
||||||
|
@ -396,27 +458,20 @@ function CoderDepot(props){
|
||||||
<div className="listtablehead">
|
<div className="listtablehead">
|
||||||
<User url={getImageUrl(`/${lastCommitAuthor && lastCommitAuthor.image_url}`)} name={lastCommitAuthor && lastCommitAuthor.name} id={lastCommitAuthor && lastCommitAuthor.id} login={lastCommitAuthor && lastCommitAuthor.login}/>
|
<User url={getImageUrl(`/${lastCommitAuthor && lastCommitAuthor.image_url}`)} name={lastCommitAuthor && lastCommitAuthor.name} id={lastCommitAuthor && lastCommitAuthor.id} login={lastCommitAuthor && lastCommitAuthor.login}/>
|
||||||
<div className={hideBtn && hide ? "ellipsistxt hidetxt" :"ellipsistxt"}>
|
<div className={hideBtn && hide ? "ellipsistxt hidetxt" :"ellipsistxt"}>
|
||||||
<pre id="ptxt">{lastCommit && lastCommit.message}</pre>
|
<pre id="ptxt"><Link to={`/${owner}/${projectsId}/commits/${truncateCommitId(lastCommit.sha)}`}><RenderHtml value={lastCommit.message}/></Link></pre>
|
||||||
</div>
|
</div>
|
||||||
{ hideBtn && <span className="ellipsis" onClick={()=>changeHide(hide)}><i className="iconfont icon-shenglvehao"></i></span> }
|
{ hideBtn && <span className="ellipsis" onClick={()=>changeHide(hide)}><i className="iconfont icon-shenglvehao"></i></span> }
|
||||||
|
|
||||||
<span className="ml12 color-grey-9 mt3">{lastCommit && lastCommit.time_from_now}</span>
|
<span className="ml20 color-grey-6 font-12 mt3">{lastCommit.time_from_now}</span>
|
||||||
{ commitCount ? <Link to={`/${owner}/${projectsId}/commits/branch/${turnbar(branchName || defaultBranch)}`} className="ml12 color-grey-9">
|
{
|
||||||
<i className="iconfont icon-tijiao mr3 font-17 color-grey-9"></i>{commitCount}次提交
|
commitCount ?
|
||||||
</Link>:"" }
|
<Link to={`/${owner}/${projectsId}/commits/branch/${turnbar(branchName || defaultBranch)}`} className="ml20 color-grey-3"style={{height:"28px",lineHeight:"28px"}}>
|
||||||
|
<i className="iconfont icon-tijiaoicon mr3 font-16"></i><span style={{fontWeight:"500"}}>{commitCount}次提交</span>
|
||||||
|
</Link>:""
|
||||||
|
}
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
<ul className="listtablebody">
|
<ul className="listtablebody">
|
||||||
{
|
|
||||||
treeValuePath && treeValuePath.length > 0 &&
|
|
||||||
<Path
|
|
||||||
identifier={projectDetail && projectDetail.identifier}
|
|
||||||
treeValuePath={treeValuePath}
|
|
||||||
returnUlr={returnUlr}
|
|
||||||
returnMain={returnMain}
|
|
||||||
getPathUrl={getPathUrl}
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
{
|
{
|
||||||
dirInfo && dirInfo.length > 0 &&
|
dirInfo && dirInfo.length > 0 &&
|
||||||
dirInfo.map((item,key)=>{
|
dirInfo.map((item,key)=>{
|
||||||
|
@ -450,81 +505,80 @@ function CoderDepot(props){
|
||||||
(dirInfo && dirInfo.length === 0) && !fileInfo ? <Nodata _html="暂未发现文件"/> :""
|
(dirInfo && dirInfo.length === 0) && !fileInfo ? <Nodata _html="暂未发现文件"/> :""
|
||||||
}
|
}
|
||||||
{/* readme文件显示(显示文件详情时不显示readme文件) */}
|
{/* readme文件显示(显示文件详情时不显示readme文件) */}
|
||||||
{ dirInfo && (readme && readme.content) ? <ReadMe ChangeFile={ChangeFile} readme={readme} operate={props && (props.isManager || props.isDeveloper) && projectDetail.type !==2 } history={props.history} /> :"" }
|
{ (readme && readme.content) ? <ReadMe ChangeFile={ChangeFile} readme={readme} operate={props && (props.isManager || props.isDeveloper) && projectDetail.type !==2 } history={props.history} /> :"" }
|
||||||
</div>
|
</div>
|
||||||
</LongWidth>
|
</LongWidth>
|
||||||
{
|
{
|
||||||
!fileInfo &&
|
(!(treeValuePath && treeValuePath.length > 0) && !fileInfo) &&
|
||||||
<ShortWidth>
|
<ShortWidth>
|
||||||
<Gap style={{paddingLeft:"30px"}}>
|
<Gap style={{paddingLeft:"30px"}}>
|
||||||
<div className="panelmenu">
|
<div className="panelmenu">
|
||||||
<FlexAJ className="font-18 color-grey-6 mb20" style={{lineHeight:"28px"}}>简介
|
<FlexAJ className="font-18 color-ooo mb20" style={{lineHeight:"28px"}}>关于
|
||||||
{
|
{
|
||||||
projectDetail.permission && (projectDetail.permission==="Admin" || projectDetail.permission==="Owner" || projectDetail.permission==="Manager") &&
|
projectDetail.permission && (projectDetail.permission==="Admin" || projectDetail.permission==="Owner" || projectDetail.permission==="Manager") &&
|
||||||
<i onClick={()=>setOpenModal(true)} className="iconfont icon-anquanshezhi color-grey-9 font-15"></i>
|
<i onClick={()=>setOpenModal(true)} className="iconfont icon-a-shezhi color-grey-9 font-15"></i>
|
||||||
}
|
}
|
||||||
</FlexAJ>
|
</FlexAJ>
|
||||||
{desc && <p className="font-14 color-grey-9 mb15 task-hide-2" style={{lineHeight:"22px",WebkitLineClamp:"4",textAlign:"justify",wordBreak:"break-all"}}>{desc}</p>}
|
{desc && <p className="font-14 color-grey-3 mb15 task-hide-2" style={{lineHeight:"24px",WebkitLineClamp:"4",textAlign:"justify",wordBreak:"break-all"}}>{desc}</p>}
|
||||||
{
|
{
|
||||||
website &&
|
website &&
|
||||||
<p className="color-grey-6 df">
|
<div className="color-grey-6 df pinfos mb5">
|
||||||
<i className="iconfont icon-lianjie2 font-15 mr10 color-grey-9"></i>
|
<i className="iconfont icon-lianjie2 font-15 mr10"></i>
|
||||||
<a href={website} className="color-grey-6" target="_blank" style={{wordBreak:"break-all",lineHeight:"20px",marginTop:"5px",textDecoration:"underline"}}>{website}</a>
|
<a href={website} target="_blank" style={{wordBreak:"break-all",lineHeight:"20px",marginTop:"5px",textDecoration:"underline"}}>{website}</a>
|
||||||
</p>
|
</div>
|
||||||
}
|
}
|
||||||
<p>
|
<div className="pinfos mb5">
|
||||||
<i className="iconfont icon-wenjian4 font-15 mr10 color-grey-9"></i>
|
<i className="iconfont icon-zishuwenjian_icon font-15 mr10"></i>
|
||||||
<a href="#readme" className="color-grey-6">README.md</a>
|
<a href="#readme">README.md</a>
|
||||||
</p>
|
</div>
|
||||||
<p className="color-grey-6">
|
<div className="color-grey-6 mb5">
|
||||||
<i className="iconfont icon-dataBase font-15 mr10 color-grey-6"></i>
|
<i className="iconfont icon-neicunicon font-15 mr10"></i>
|
||||||
<span>{projectDetail && projectDetail.size}</span>
|
<span>{projectDetail && projectDetail.size}</span>
|
||||||
</p>
|
</div>
|
||||||
{
|
{
|
||||||
projectDetail && projectDetail.license_name &&
|
projectDetail && projectDetail.license_name &&
|
||||||
<p className="color-grey-6">
|
<div className="pinfos">
|
||||||
<i className="iconfont icon-tianping font-16 mr10 color-grey-3"></i>
|
<i className="iconfont icon-xieyiicon font-16 mr10"></i>
|
||||||
<span>{projectDetail.license_name}</span>
|
<Link to={`/${owner}/${projectsId}/tree/${branchName || defaultBranch}/LICENSE`} className="color-grey-6">{projectDetail.license_name}</Link>
|
||||||
</p>
|
</div>
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
{
|
{
|
||||||
inviteCode &&
|
inviteCode &&
|
||||||
<div>
|
<div>
|
||||||
<Divider />
|
<Divider />
|
||||||
<Invite code={inviteCode} className={"detailsCode"}/>
|
<Invite code={inviteCode}/>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
lesson_url &&
|
lesson_url &&
|
||||||
<div>
|
<div>
|
||||||
<Divider />
|
<Divider />
|
||||||
<p className="font-16 color-grey-6">实践课程</p>
|
<p className="font-16 color-ooo">实践课程</p>
|
||||||
<a href={lesson_url} target="_blank" className="color-grey-6" style={{textDecoration:"underline",wordBreak:"break-all"}}>{lesson_url}</a>
|
<a href={lesson_url} target="_blank" className="color-grey-6" style={{textDecoration:"underline",wordBreak:"break-all"}}>{lesson_url}</a>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
{/* 发布 */}
|
{/* 发布 */}
|
||||||
{
|
{
|
||||||
projectDetail && projectDetail.release_versions &&
|
releaseVersions &&
|
||||||
<React.Fragment>
|
<React.Fragment>
|
||||||
<Divider />
|
<Divider />
|
||||||
<Releases
|
<Releases
|
||||||
owner={owner}
|
owner={owner}
|
||||||
projectsId={projectsId}
|
projectsId={projectsId}
|
||||||
releaseVersions={projectDetail.release_versions}
|
releaseVersions={releaseVersions}
|
||||||
history={props.history}
|
history={props.history}
|
||||||
baseOperate={baseOperate}
|
distribution={distribution}
|
||||||
projectType={projectDetail.type}
|
|
||||||
/>
|
/>
|
||||||
</React.Fragment>
|
</React.Fragment>
|
||||||
}
|
}
|
||||||
{/* 贡献者 */}
|
{/* 贡献者 */}
|
||||||
{
|
{
|
||||||
projectDetail && projectDetail.contributors && projectDetail.contributors.length >0 &&
|
projectDetail && projectDetail.contributors && projectDetail.contributors.total_count >0 &&
|
||||||
<Contributors contributors={projectDetail && projectDetail.contributors} owner={owner} projectsId={projectsId} />
|
<Contributors contributors={projectDetail.contributors} owner={owner} projectsId={projectsId} />
|
||||||
}
|
}
|
||||||
{/* 语言 */}
|
{/* 语言 */}
|
||||||
{ projectDetail && projectDetail.languages && projectDetail.languages.length >0 &&
|
{ projectDetail && projectDetail.languages &&
|
||||||
<React.Fragment>
|
<React.Fragment>
|
||||||
<Divider />
|
<Divider />
|
||||||
<LanguagePower languages={projectDetail.languages}/>
|
<LanguagePower languages={projectDetail.languages}/>
|
||||||
|
|
|
@ -4,8 +4,8 @@ import { truncateCommitId } from '../common/util';
|
||||||
|
|
||||||
const typeIco = {
|
const typeIco = {
|
||||||
"submodule":"icon-file-submodule font-17",
|
"submodule":"icon-file-submodule font-17",
|
||||||
"file":'icon-wenjia font-15',
|
"file":'icon-wenjian6 font-15 color-blue-file',
|
||||||
"dir":"icon-wenjianjia1 font-15"
|
"dir":"icon-wenjianjia4 font-15 color-blue_4C"
|
||||||
}
|
}
|
||||||
|
|
||||||
function CoderDepotCatalogue({item , goToSubRoot , owner , projectsId }){
|
function CoderDepotCatalogue({item , goToSubRoot , owner , projectsId }){
|
||||||
|
@ -13,7 +13,7 @@ function CoderDepotCatalogue({item , goToSubRoot , owner , projectsId }){
|
||||||
<li>
|
<li>
|
||||||
<span>
|
<span>
|
||||||
<a onClick={()=>goToSubRoot(item.path,item.type,item.name)} className={item.type === "submodule" && "submoduleStyle"}>
|
<a onClick={()=>goToSubRoot(item.path,item.type,item.name)} className={item.type === "submodule" && "submoduleStyle"}>
|
||||||
<i className={`iconfont ${typeIco[`${item.type}`]} color-green-file mr5`}></i>{item.name}
|
<i className={`iconfont ${typeIco[`${item.type}`]} mr8`}></i>{item.name}
|
||||||
</a>
|
</a>
|
||||||
</span>
|
</span>
|
||||||
<span title="init project">
|
<span title="init project">
|
||||||
|
@ -21,7 +21,7 @@ function CoderDepotCatalogue({item , goToSubRoot , owner , projectsId }){
|
||||||
{item.commit && item.commit.message}
|
{item.commit && item.commit.message}
|
||||||
</Link>
|
</Link>
|
||||||
</span>
|
</span>
|
||||||
<span>{item.commit && item.commit.time_from_now}</span>
|
<span title={item.commit && item.commit.created_at}>{item.commit && item.commit.time_from_now}</span>
|
||||||
</li>
|
</li>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
import { result } from 'lodash';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
import React, { useEffect, useState } from 'react';
|
import React, { useEffect, useState } from 'react';
|
||||||
import RenderHtml from '../../components/render-html';
|
import RenderHtml from '../../components/render-html';
|
||||||
import { AlignCenter } from '../Component/layout';
|
import { AlignCenter } from '../Component/layout';
|
||||||
import { Dropdown , Menu , Spin } from 'antd';
|
import { Dropdown , Anchor , Spin } from 'antd';
|
||||||
import { Link } from 'react-router-dom';
|
|
||||||
|
import ReadmeCatelogue from './sub/ReadmeCatelogue';
|
||||||
const $ = window.$;
|
const $ = window.$;
|
||||||
|
|
||||||
function CoderDepotReadme({ operate , history , readme , ChangeFile }){
|
function CoderDepotReadme({ operate , history , readme , ChangeFile }){
|
||||||
|
@ -23,49 +24,45 @@ function CoderDepotReadme({ operate , history , readme , ChangeFile }){
|
||||||
const anchor = el.id;
|
const anchor = el.id;
|
||||||
const level = el.tagName.replace("H", "");
|
const level = el.tagName.replace("H", "");
|
||||||
const href = `#${anchor}`;
|
const href = `#${anchor}`;
|
||||||
return { href:`${path}${href}`,text:el.textContent , level:level }
|
return { href:`${href}`,text:el.textContent , level:level }
|
||||||
});
|
});
|
||||||
setMenuList(items);
|
setMenuList(items);
|
||||||
},[content])
|
},[content])
|
||||||
|
|
||||||
function menu(){
|
function menu(){
|
||||||
if(menuList && menuList.length > 0){
|
if(menuList && menuList.length > 0){
|
||||||
let hash = history.location.hash;
|
|
||||||
return(
|
return(
|
||||||
<Menu className="menuslist">
|
<ReadmeCatelogue menuList={menuList} hash={history.location.hash}/>
|
||||||
{
|
|
||||||
menuList.map((item,key)=>{
|
|
||||||
return(
|
|
||||||
<Menu.Item key={item.id} className={decodeURI(hash).indexOf(item.text)>-1 ?"active":""}><Link to={`${item.href}`} style={{paddingLeft:`${item.level *10}px`}} title={item.text}>{item.text}</Link></Menu.Item>
|
|
||||||
)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
</Menu>
|
|
||||||
)
|
)
|
||||||
}else{
|
}else{
|
||||||
return <Spin />
|
return <Spin />
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return(
|
return(
|
||||||
<div className="commonBox" id="readme">
|
<div className="commonBox readBox" id="readme">
|
||||||
<div className="commonBox-title boxTitle">
|
<Anchor offsetTop={70} targetOffset={160}>
|
||||||
<AlignCenter>
|
<div className="commonBox-title boxTitle">
|
||||||
<Dropdown overlay={menu()}>
|
<AlignCenter>
|
||||||
<span className="catelogue">
|
<Dropdown overlay={menu()} trigger={['hover']} overlayClassName="menuslist">
|
||||||
<i className="iconfont icon-zhangjie1 font-14 mr5"></i>
|
<span className="catelogue">
|
||||||
<span>目录</span>
|
<i className="iconfont icon-muluicon font-12 mr5"></i>
|
||||||
</span>
|
<span>目录</span>
|
||||||
</Dropdown>
|
</span>
|
||||||
<span className="commonBox-title-read">README.md</span>
|
</Dropdown>
|
||||||
</AlignCenter>
|
|
||||||
{
|
<span className="commonBox-title-read"><a href="#readme ">README.md</a></span>
|
||||||
operate ?
|
|
||||||
<a className="ml20 pull-right" onClick={() =>ChangeFile(readme && readme.path, false)}>
|
</AlignCenter>
|
||||||
<i className="iconfont icon-bianji6 font-16 color-blue"></i>
|
{
|
||||||
</a>
|
operate ?
|
||||||
:""
|
<a className="ml20 pull-right" onClick={() =>ChangeFile(readme && readme.path, false)}>
|
||||||
}
|
<i className="iconfont icon-a-bianji font-17 color-grey-6"></i>
|
||||||
</div>
|
</a>
|
||||||
|
:""
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
</Anchor>
|
||||||
{
|
{
|
||||||
content &&
|
content &&
|
||||||
<div className="commonBox-info">
|
<div className="commonBox-info">
|
||||||
|
|
|
@ -1,92 +0,0 @@
|
||||||
import React , { useState, useEffect } from 'react';
|
|
||||||
import { Link } from "react-router-dom";
|
|
||||||
import { Dropdown , Menu , Icon , Tooltip , Spin } from 'antd';
|
|
||||||
import { truncateCommitId } from '../common/util';
|
|
||||||
import { getBranch } from '../GetData/getData';
|
|
||||||
import Nodata from '../Nodata';
|
|
||||||
import './list.css';
|
|
||||||
|
|
||||||
function turnbar(str){
|
|
||||||
if(str && str.length>0 && str.indexOf("/")>-1){
|
|
||||||
return str.replaceAll('/','%2F');
|
|
||||||
}
|
|
||||||
return str;
|
|
||||||
}
|
|
||||||
export default ((props)=>{
|
|
||||||
const [ data , setData ] =useState(undefined);
|
|
||||||
const [ isSpin , setIsSpin ] =useState(true);
|
|
||||||
|
|
||||||
const { projectsId , owner } = props.match.params;
|
|
||||||
const { isManager , isDeveloper , projectDetail } = props;
|
|
||||||
useEffect(()=>{
|
|
||||||
getBranchs(projectsId, owner);
|
|
||||||
},[projectsId])
|
|
||||||
|
|
||||||
async function getBranchs(id,owner){
|
|
||||||
let result = await getBranch(id,owner);
|
|
||||||
setData(result);
|
|
||||||
setIsSpin(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
const list =()=>{
|
|
||||||
if(data && data.length>0){
|
|
||||||
return(
|
|
||||||
<React.Fragment>
|
|
||||||
<ul className="branchUl">
|
|
||||||
{
|
|
||||||
data.map((item,key)=>{
|
|
||||||
return(
|
|
||||||
<li key={key}>
|
|
||||||
<div>
|
|
||||||
<Link to={`/${owner}/${projectsId}/tree/${turnbar(item.name)}`} className="color-blue font-15" style={{"maxWidth":"100px"}}>{item.name}</Link>
|
|
||||||
<p className="f-wrap-alignCenter mt15">
|
|
||||||
<Link to={`/${owner}/${projectsId}/commits/${truncateCommitId(`${item.last_commit.sha}`)}`} className="mr5 commitKey" style={{marginLeft:0}}>{item.last_commit && truncateCommitId(item.last_commit.sha)}</Link>
|
|
||||||
<span className="color-grey-3 hide-1 messages leftPoint">{item.last_commit && item.last_commit.message}</span>
|
|
||||||
<span className="color-grey-8 ml30">最后更新于{item.last_commit && item.last_commit.time_from_now}</span>
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
<span>
|
|
||||||
{
|
|
||||||
(isManager || isDeveloper) && (projectDetail && projectDetail.type!==2) &&
|
|
||||||
<Link to={`/${owner}/${projectsId}/pulls/new/${item.name}`} className="mr20 color-blue mr30">创建合并请求</Link>
|
|
||||||
}
|
|
||||||
<Dropdown overlay={menu(item.zip_url,item.tar_url)} trigger={['click']} placement="bottomRight" className="color-green-file">
|
|
||||||
<a className="ant-dropdown-link">
|
|
||||||
<Tooltip title={`下载分支${item.name}`}><Icon type="cloud-download" className="font-18"/></Tooltip>
|
|
||||||
</a>
|
|
||||||
</Dropdown>
|
|
||||||
</span>
|
|
||||||
</li>
|
|
||||||
)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
</ul>
|
|
||||||
</React.Fragment>
|
|
||||||
)
|
|
||||||
}else if(data && data.length === 0){
|
|
||||||
return ( <Nodata _html="暂无数据"/>)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const menu =(zip_url,tar_url)=> (
|
|
||||||
<Menu>
|
|
||||||
<Menu.Item key={'0'}><a href={zip_url}>ZIP</a></Menu.Item>
|
|
||||||
<Menu.Item key={'1'}><a href={tar_url}>TAR.GZ</a></Menu.Item>
|
|
||||||
</Menu>
|
|
||||||
)
|
|
||||||
|
|
||||||
return(
|
|
||||||
<React.Fragment>
|
|
||||||
<div className="main">
|
|
||||||
<Spin spinning={isSpin}>
|
|
||||||
<div className="branchTable">
|
|
||||||
<p className="branchTitle bor-bottom-greyE">分支列表</p>
|
|
||||||
<div style={{minHeight:"400px"}}>{list()}</div>
|
|
||||||
</div>
|
|
||||||
</Spin>
|
|
||||||
</div>
|
|
||||||
</React.Fragment>
|
|
||||||
)
|
|
||||||
})
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,13 +1,19 @@
|
||||||
import React , { Component } from 'react';
|
import React , { Component } from 'react';
|
||||||
import { Spin , Pagination } from 'antd';
|
import { Spin , Pagination, Timeline } from 'antd';
|
||||||
import { getImageUrl } from 'educoder';
|
import { getImageUrl } from 'educoder';
|
||||||
import { truncateCommitId } from '../common/util';
|
import { truncateCommitId ,timeFormat } from '../common/util';
|
||||||
import { AlignTop } from '../Component/layout';
|
import { AlignTop } from '../Component/layout';
|
||||||
import SelectBranch from '../Branch/Select';
|
import SelectBranch from '../Branch/Select';
|
||||||
import Nodata from '../Nodata';
|
import Nodata from '../Nodata';
|
||||||
|
|
||||||
|
import User from '../Component/User';
|
||||||
|
import RenderHtml from '../../components/render-html.jsx';
|
||||||
|
import Tree from './img/tree.png';
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
import {Link} from "react-router-dom";
|
import {Link} from "react-router-dom";
|
||||||
|
import CopyTool from '../Component/CopyTool';
|
||||||
|
|
||||||
|
import './tree/Index.scss'
|
||||||
|
|
||||||
function returnbar(str){
|
function returnbar(str){
|
||||||
if(str && str.length>0 && str.indexOf("%2F")>-1){
|
if(str && str.length>0 && str.indexOf("%2F")>-1){
|
||||||
|
@ -15,14 +21,16 @@ function returnbar(str){
|
||||||
}
|
}
|
||||||
return str;
|
return str;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//代码库--提交页面
|
||||||
class CoderRootCommit extends Component{
|
class CoderRootCommit extends Component{
|
||||||
constructor(props){
|
constructor(props){
|
||||||
super(props)
|
super(props);
|
||||||
this.state={
|
this.state={
|
||||||
commitDatas:undefined,
|
commitDatas:undefined,
|
||||||
dataCount:undefined,
|
dataCount:undefined,
|
||||||
limit:20,
|
limit:10,
|
||||||
page:1,
|
page: 1,
|
||||||
isSpining:false,
|
isSpining:false,
|
||||||
branchList:undefined
|
branchList:undefined
|
||||||
}
|
}
|
||||||
|
@ -50,20 +58,34 @@ class CoderRootCommit extends Component{
|
||||||
this.Init();
|
this.Init();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
UrlParamHash(url){
|
||||||
|
const params = {};
|
||||||
|
let h;
|
||||||
|
let hash = url.slice(url.indexOf('?')+1).split('&');
|
||||||
|
for(let i = 0; i<hash.length;i++){
|
||||||
|
h = hash[i].split('=');
|
||||||
|
params[h[0]] = h[1];
|
||||||
|
}
|
||||||
|
return params;
|
||||||
|
}
|
||||||
|
|
||||||
Init =()=>{
|
Init =()=>{
|
||||||
const { branchName } = this.props.match.params;
|
const { branchName } = this.props.match.params;
|
||||||
const { page , limit } = this.state;
|
const { limit } = this.state;
|
||||||
|
const {search} = this.props.location;
|
||||||
|
const realPage = (search && this.UrlParamHash(search).page) ? parseInt(this.UrlParamHash(search).page) : 1;
|
||||||
this.setState({
|
this.setState({
|
||||||
isSpining:true
|
isSpining:true,
|
||||||
|
page:realPage
|
||||||
})
|
})
|
||||||
this.getCommitList( branchName , page , limit );
|
this.getCommitList( branchName , realPage , limit );
|
||||||
}
|
}
|
||||||
|
|
||||||
getCommitList=(branch , page , limit)=>{
|
getCommitList=(branch , page , limit)=>{
|
||||||
this.setState({
|
this.setState({
|
||||||
isSpining:true
|
isSpining:true
|
||||||
})
|
})
|
||||||
console.log(returnbar(branch));
|
|
||||||
const { projectsId , owner } = this.props.match.params;
|
const { projectsId , owner } = this.props.match.params;
|
||||||
const url = `/${owner}/${projectsId}/commits.json`;
|
const url = `/${owner}/${projectsId}/commits.json`;
|
||||||
axios.get(url,{
|
axios.get(url,{
|
||||||
|
@ -86,7 +108,8 @@ class CoderRootCommit extends Component{
|
||||||
image_url:item.author && item.author.image_url,
|
image_url:item.author && item.author.image_url,
|
||||||
sha:item.sha,
|
sha:item.sha,
|
||||||
time_from_now:item.time_from_now,
|
time_from_now:item.time_from_now,
|
||||||
message:item.message
|
message:item.message,
|
||||||
|
timestamp:item.timestamp
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
this.setState({
|
this.setState({
|
||||||
|
@ -105,10 +128,9 @@ class CoderRootCommit extends Component{
|
||||||
}
|
}
|
||||||
|
|
||||||
ChangePage=(page)=>{
|
ChangePage=(page)=>{
|
||||||
const { branchName } = this.props.match.params;
|
this.props.history.push({pathname: this.props.history.location.pathname,search: `page=${page}`})
|
||||||
const { limit } = this.state;
|
|
||||||
this.getCommitList(branchName , page , limit);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
render(){
|
render(){
|
||||||
const { commitDatas , dataCount , limit , page , isSpining , branchList } = this.state;
|
const { commitDatas , dataCount , limit , page , isSpining , branchList } = this.state;
|
||||||
const { projectDetail, commit_class , defaultBranch } = this.props;
|
const { projectDetail, commit_class , defaultBranch } = this.props;
|
||||||
|
@ -129,46 +151,50 @@ class CoderRootCommit extends Component{
|
||||||
></SelectBranch>
|
></SelectBranch>
|
||||||
</div>
|
</div>
|
||||||
<Spin spinning={isSpining}>
|
<Spin spinning={isSpining}>
|
||||||
<div className="commonBox">
|
<Timeline className="commitList">
|
||||||
<div className="commonBox-title">
|
{
|
||||||
<div className="f-wrap-between" style={{alignItems:"center"}}>
|
commitDatas && commitDatas.length > 0 && commitDatas.map((item,k)=>{
|
||||||
<span className="font-16">{dataCount}次提交代码({branch})</span>
|
return(
|
||||||
</div>
|
<Timeline.Item key={k} dot={page ===1 && k===0 ?<span className="new-conmmit">最新</span>:<i className="iconfont icon-a-yuanquan2x"></i>}>
|
||||||
</div>
|
<div className="commitList-item f-wrap-between">
|
||||||
<div className="commitList">
|
<div>
|
||||||
{
|
<AlignTop>
|
||||||
commitDatas && commitDatas.length > 0 && commitDatas.map((item,k)=>{
|
<div className="commitDesc"><Link to={`/${owner}/${projectsId}/commits/${truncateCommitId(`${item.sha}`)}`} className="font-14 color-grey-3 font-bd"><RenderHtml value={item.message}/></Link></div>
|
||||||
return(
|
</AlignTop>
|
||||||
<div key={k}>
|
<p className="f-wrap-alignCenter mt15 pb5">
|
||||||
<AlignTop>
|
<User
|
||||||
<Link to={`/${owner}/${projectsId}/commits/${truncateCommitId(`${item.sha}`)}`} className="commitKey" style={{marginLeft:0,marginTop:"3px"}}>{truncateCommitId(`${item.sha}`)}</Link>
|
id={item.id}
|
||||||
<Link to={`/${owner}/${projectsId}/commits/${truncateCommitId(`${item.sha}`)}`} className="commitDesc">{item.message}</Link>
|
url={(item.image_url && getImageUrl(`/${item.image_url}`)) || "https://dss3.bdstatic.com/70cFv8Sh_Q1YnxGkpoWK1HF6hhy/it/u=3025493530,1989042357&fm=26&gp=0.jpg"}
|
||||||
</AlignTop>
|
name={item.name}
|
||||||
<p className="f-wrap-alignCenter mt15">
|
login={item.login}
|
||||||
{
|
/>
|
||||||
item.id ?
|
{item.timestamp && <label className="font-14 color-grey-3 ml3">提交于 {timeFormat(item.timestamp)}</label>}
|
||||||
<Link to={`/${item.login}`} className="show-user-link">
|
</p>
|
||||||
{item.image_url?<img src={getImageUrl(`/${item.image_url}`)} alt="" width="28px" height="28px" className="mr15 radius"/>:""}
|
</div>
|
||||||
<label className="font-14 color-grey-6" style={{verticalAlign:'middle'}}>{item.name ?`${item.name}:`:""}提交于 {item.time_from_now}</label>
|
<div>
|
||||||
</Link>:
|
<div className="treecopy">
|
||||||
<span className="show-user-link">
|
<div>
|
||||||
{item.image_url?<img src={getImageUrl(`/${item.image_url}`)} alt="" width="28px" height="28px" className="mr15 radius"/>:""}
|
<span className="treecopy-cont shadow">
|
||||||
<label className="font-14 color-grey-6" style={{verticalAlign:'middle'}}>{item.name ?`${item.name}:`:""}提交于 {item.time_from_now}</label>
|
<img src={Tree} alt="sha" width={"16px"}/>
|
||||||
</span>
|
<Link to={`/${owner}/${projectsId}/commits/${truncateCommitId(`${item.sha}`)}`}>{truncateCommitId(`${item.sha}`)}</Link>
|
||||||
}
|
<input type="text" id={`value${k}`} value={`${truncateCommitId(`${item.sha}`)}`}/>
|
||||||
|
</span>
|
||||||
</p>
|
<CopyTool beforeText="复制commit id" afterText="复制成功" inputId={`value${k}`}/>
|
||||||
|
</div>
|
||||||
|
<button className="btn-83" onClick={()=>{window.location.href=`/${owner}/${projectsId}/tree/${truncateCommitId(item.sha)}`}}>浏览文件</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)
|
</Timeline.Item>
|
||||||
})
|
)
|
||||||
}
|
})
|
||||||
{commitDatas && commitDatas.length === 0 && <Nodata _html="暂无数据"/>}
|
}
|
||||||
</div>
|
{commitDatas && commitDatas.length === 0 && <Nodata _html="暂无数据"/>}
|
||||||
</div>
|
</Timeline>
|
||||||
{
|
{
|
||||||
dataCount > limit ?
|
dataCount > limit ?
|
||||||
<div className="edu-txt-center pt30 mb30">
|
<div className="edu-txt-center pt30 mb30">
|
||||||
<Pagination simple defaultCurrent={page} total={dataCount} pageSize={limit} onChange={this.ChangePage}></Pagination>
|
<Pagination simple current={page} total={dataCount} pageSize={limit} onChange={this.ChangePage}></Pagination>
|
||||||
</div>
|
</div>
|
||||||
:""
|
:""
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,12 @@
|
||||||
import React, { Component } from "react";
|
import React, { Component } from "react";
|
||||||
import { Popconfirm , Select } from "antd";
|
import { Popconfirm , Select , Dropdown , Spin , Anchor } from "antd";
|
||||||
import "./list.css";
|
import "./list.scss";
|
||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
import Meditor from "../Newfile/m_editor";
|
import Meditor from "../Newfile/m_editor";
|
||||||
import RenderHtml from "../../components/render-html";
|
import RenderHtml from "../../components/render-html";
|
||||||
|
import ReadmeCatelogue from "./sub/ReadmeCatelogue";
|
||||||
|
|
||||||
|
const $ = window.$;
|
||||||
function bytesToSize(bytes) {
|
function bytesToSize(bytes) {
|
||||||
if (bytes === 0) return "0 B";
|
if (bytes === 0) return "0 B";
|
||||||
let k = 1024,
|
let k = 1024,
|
||||||
|
@ -19,11 +21,13 @@ class CoderRootFileDetail extends Component {
|
||||||
value: undefined,
|
value: undefined,
|
||||||
language: undefined,
|
language: undefined,
|
||||||
languages: undefined,
|
languages: undefined,
|
||||||
description: props.detail.content
|
description: props.detail.content,
|
||||||
|
menuList:undefined
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidMount = () => {
|
componentDidMount = () => {
|
||||||
|
window.scrollTo(0, 0);
|
||||||
const { detail , mdFlag } = this.props;
|
const { detail , mdFlag } = this.props;
|
||||||
this.setState({
|
this.setState({
|
||||||
value: detail.content,
|
value: detail.content,
|
||||||
|
@ -169,6 +173,31 @@ class CoderRootFileDetail extends Component {
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
renderMenulist=()=>{
|
||||||
|
const { description } = this.state;
|
||||||
|
if(description){
|
||||||
|
const items = $.map($("#files-md").find("h1,h2,h3,h4,h5,h6"), function (el, _) {
|
||||||
|
const anchor = el.id;
|
||||||
|
const level = el.tagName.replace("H", "");
|
||||||
|
const href = `#${anchor}`;
|
||||||
|
return { href:`${href}`,text:el.textContent , level:level }
|
||||||
|
});
|
||||||
|
return items;
|
||||||
|
}
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
menu=()=>{
|
||||||
|
const menuList = this.renderMenulist();
|
||||||
|
if(menuList && menuList.length > 0){
|
||||||
|
return(
|
||||||
|
<ReadmeCatelogue menuList={menuList} hash={this.props.history.location.hash}/>
|
||||||
|
)
|
||||||
|
}else{
|
||||||
|
return <Spin />
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const {
|
const {
|
||||||
readOnly,
|
readOnly,
|
||||||
|
@ -186,79 +215,88 @@ class CoderRootFileDetail extends Component {
|
||||||
const Option = Select.Option;
|
const Option = Select.Option;
|
||||||
return (
|
return (
|
||||||
<React.Fragment>
|
<React.Fragment>
|
||||||
<div className="grid-item branchTitle">
|
<Anchor className="griditemAnchor" offsetTop={70}>
|
||||||
<div className="grid-item">
|
<div className="griditemCate">
|
||||||
<span className="ml20 color-grey-6 font-16">
|
{
|
||||||
|
md && readOnly &&
|
||||||
|
<Dropdown overlay={this.menu()} trigger={['hover']} overlayClassName="menuslist">
|
||||||
|
<span className="catelogue mr20">
|
||||||
|
<i className="iconfont icon-muluicon font-12 mr5"></i>
|
||||||
|
<span>目录</span>
|
||||||
|
</span>
|
||||||
|
</Dropdown>
|
||||||
|
}
|
||||||
|
<span className="color-grey-6 font-16">
|
||||||
{bytesToSize(detail && detail.size)}
|
{bytesToSize(detail && detail.size)}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<p className="text-right">
|
<p className="text-right">
|
||||||
{flag && platform && (
|
{flag && platform && (
|
||||||
<div>
|
<div>
|
||||||
{readOnly ? (
|
{readOnly ? (
|
||||||
<span>
|
<span>
|
||||||
{
|
{
|
||||||
!detail.direct_download?
|
!detail.direct_download?
|
||||||
<span>
|
<span>
|
||||||
<a onClick={() => this.DownLoadFile(detail.download_url)} className="ml20">
|
<a onClick={() => this.DownLoadFile(detail.download_url)} className="ml20">
|
||||||
<i className="iconfont icon-xiazai1 font-15 color-grey-6"></i>
|
<i className="iconfont icon-xiazai1 font-15 color-grey-6"></i>
|
||||||
</a>
|
|
||||||
{
|
|
||||||
type !==2 &&
|
|
||||||
<a onClick={() => this.EditFile(false)} className="ml20">
|
|
||||||
<i className="iconfont icon-bianji1 font-15 color-grey-6"></i>
|
|
||||||
</a>
|
</a>
|
||||||
}
|
{
|
||||||
</span>:""
|
type !==2 &&
|
||||||
}
|
<a onClick={() => this.EditFile(false)} className="ml20">
|
||||||
</span>
|
<i className="iconfont icon-bianji1 font-15 color-grey-6"></i>
|
||||||
) : (
|
</a>
|
||||||
<React.Fragment>
|
}
|
||||||
<Select
|
</span>:""
|
||||||
showSearch={true}
|
}
|
||||||
placeholder={"请选择文本语言"}
|
</span>
|
||||||
style={{ width: 200 }}
|
) : (
|
||||||
value={language}
|
<React.Fragment>
|
||||||
onChange={this.select_language}
|
<Select
|
||||||
>
|
showSearch={true}
|
||||||
<Option value={undefined}>请选择文本语言</Option>
|
placeholder={"请选择文本语言"}
|
||||||
{languages &&
|
style={{ width: 200 }}
|
||||||
languages.map((item, key) => {
|
value={language}
|
||||||
return (
|
onChange={this.select_language}
|
||||||
<Option value={item} key={key}>
|
>
|
||||||
{item}
|
<Option value={undefined}>请选择文本语言</Option>
|
||||||
</Option>
|
{languages &&
|
||||||
);
|
languages.map((item, key) => {
|
||||||
})}
|
return (
|
||||||
</Select>
|
<Option value={item} key={key}>
|
||||||
<button
|
{item}
|
||||||
type="button"
|
</Option>
|
||||||
className="ant-btn ant-btn-sm ml20"
|
);
|
||||||
onClick={() => this.EditFile(true)}
|
})}
|
||||||
>
|
</Select>
|
||||||
<span>取 消</span>
|
<button
|
||||||
</button>
|
type="button"
|
||||||
</React.Fragment>
|
className="ant-btn ant-btn-sm ml20"
|
||||||
)}
|
onClick={() => this.EditFile(true)}
|
||||||
{
|
>
|
||||||
type !==2 &&
|
<span>取 消</span>
|
||||||
<Popconfirm
|
</button>
|
||||||
title="确认删除这个文件?"
|
</React.Fragment>
|
||||||
className="ml20"
|
)}
|
||||||
okText="确定"
|
{
|
||||||
cancelText="取消"
|
type !==2 &&
|
||||||
onConfirm={this.deleteFile}
|
<Popconfirm
|
||||||
>
|
title="确认删除这个文件?"
|
||||||
<a>
|
className="ml20"
|
||||||
<i className="iconfont icon-shanchu font-15 color-grey-6"></i>
|
okText="确定"
|
||||||
</a>
|
cancelText="取消"
|
||||||
</Popconfirm>
|
onConfirm={this.deleteFile}
|
||||||
}
|
>
|
||||||
|
<a>
|
||||||
|
<i className="iconfont icon-shanchu font-15 color-grey-6"></i>
|
||||||
|
</a>
|
||||||
|
</Popconfirm>
|
||||||
|
}
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</Anchor>
|
||||||
<div>
|
<div>
|
||||||
{detail.image_type ? (
|
{detail.image_type ? (
|
||||||
<div className="edu-txt-center pt20 pb20">
|
<div className="edu-txt-center pt20 pb20">
|
||||||
|
@ -272,7 +310,7 @@ class CoderRootFileDetail extends Component {
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
md && readOnly ?
|
md && readOnly ?
|
||||||
<div className="files-md">
|
<div className="files-md" id="files-md">
|
||||||
<RenderHtml className="file-md imageLayerParent" value={description} url={this.props.history.location}/>
|
<RenderHtml className="file-md imageLayerParent" value={description} url={this.props.history.location}/>
|
||||||
</div>
|
</div>
|
||||||
:
|
:
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
import React , { Component } from 'react';
|
import React , { Component } from 'react';
|
||||||
import { Route , Switch } from 'react-router-dom';
|
import { Route , Switch } from 'react-router-dom';
|
||||||
import Top from './DetailTop';
|
// import Top from './DetailTop';
|
||||||
import Loadable from 'react-loadable';
|
import Loadable from 'react-loadable';
|
||||||
import Loading from '../../Loading';
|
import Loading from '../../Loading';
|
||||||
import axios from 'axios';
|
import './Index.scss';
|
||||||
|
|
||||||
const FileNew = Loadable({
|
const FileNew = Loadable({
|
||||||
loader: () => import('../Newfile/Index'),
|
loader: () => import('../Newfile/Index'),
|
||||||
|
@ -18,25 +18,25 @@ const CoderRootCommit = Loadable({
|
||||||
loading: Loading,
|
loading: Loading,
|
||||||
})
|
})
|
||||||
const CoderRootBranch = Loadable({
|
const CoderRootBranch = Loadable({
|
||||||
loader: () => import('./CoderRootBranch'),
|
loader: () => import('./tree/Index'),
|
||||||
loading: Loading,
|
loading: Loading,
|
||||||
})
|
})
|
||||||
const CoderRootTag = Loadable({
|
const CoderRootTag = Loadable({
|
||||||
loader: () => import('./CoderRootTag'),
|
loader: () => import('./tag/Index'),
|
||||||
loading: Loading,
|
loading: Loading,
|
||||||
})
|
})
|
||||||
const CoderRootVersion = Loadable({
|
const CoderRootVersion = Loadable({
|
||||||
loader: () => import('../Version/version'),
|
loader: () => import('./version/Index'),
|
||||||
loading: Loading,
|
|
||||||
})
|
|
||||||
const CoderRootVersionNew = Loadable({
|
|
||||||
loader: () => import('../Version/New'),
|
|
||||||
loading: Loading,
|
|
||||||
})
|
|
||||||
const CoderRootVersionUpdate = Loadable({
|
|
||||||
loader: () => import('../Version/New'),
|
|
||||||
loading: Loading,
|
loading: Loading,
|
||||||
})
|
})
|
||||||
|
// const CoderRootVersionNew = Loadable({
|
||||||
|
// loader: () => import('./version/New'),
|
||||||
|
// loading: Loading,
|
||||||
|
// })
|
||||||
|
// const CoderRootVersionUpdate = Loadable({
|
||||||
|
// loader: () => import('./version/New'),
|
||||||
|
// loading: Loading,
|
||||||
|
// })
|
||||||
const Diff = Loadable({
|
const Diff = Loadable({
|
||||||
loader: () => import('./Diff'),
|
loader: () => import('./Diff'),
|
||||||
loading: Loading,
|
loading: Loading,
|
||||||
|
@ -50,41 +50,41 @@ class CoderRootIndex extends Component{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidMount=()=>{
|
// componentDidMount=()=>{
|
||||||
this.Init();
|
// this.Init();
|
||||||
}
|
// }
|
||||||
componentDidUpdate=(prevProps)=>{
|
// componentDidUpdate=(prevProps)=>{
|
||||||
const { location } = this.props;
|
// const { location } = this.props;
|
||||||
const prevlocation = prevProps && prevProps.location;
|
// const prevlocation = prevProps && prevProps.location;
|
||||||
if (location !== prevlocation) {
|
// if (location !== prevlocation) {
|
||||||
this.Init();
|
// this.Init();
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
Init=()=>{
|
// Init=()=>{
|
||||||
const { branchName } = this.props.match.params;
|
// const { branchName } = this.props.match.params;
|
||||||
const { defaultBranch } = this.props;
|
// const { defaultBranch } = this.props;
|
||||||
this.getTopCount(branchName || defaultBranch);
|
// this.getTopCount(branchName || defaultBranch);
|
||||||
}
|
// }
|
||||||
|
|
||||||
// 获取<Top />组件里要显示的数据
|
// 获取<Top />组件里要显示的数据
|
||||||
getTopCount=(branch)=>{
|
// getTopCount=(branch)=>{
|
||||||
const { projectsId , owner } = this.props.match.params;
|
// const { projectsId , owner } = this.props.match.params;
|
||||||
const url = `/${owner}/${projectsId}/top_counts.json`;
|
// const url = `/${owner}/${projectsId}/top_counts.json`;
|
||||||
axios.get(url,{params:{
|
// axios.get(url,{params:{
|
||||||
ref:branch
|
// ref:branch
|
||||||
}}).then(result=>{
|
// }}).then(result=>{
|
||||||
if(result){
|
// if(result){
|
||||||
this.setState({
|
// this.setState({
|
||||||
coderCount:result.data
|
// coderCount:result.data
|
||||||
})
|
// })
|
||||||
}
|
// }
|
||||||
}).catch(error=>{console.log(error);})
|
// }).catch(error=>{console.log(error);})
|
||||||
}
|
// }
|
||||||
render(){
|
render(){
|
||||||
return(
|
return(
|
||||||
<div>
|
<div className="coderSubPage">
|
||||||
<Top {...this.props} {...this.state}/>
|
{/* <Top {...this.props} {...this.state}/> */}
|
||||||
<Switch {...this.props}>
|
<Switch {...this.props}>
|
||||||
{/* 新建文件 */}
|
{/* 新建文件 */}
|
||||||
<Route path="/:owner/:projectsId/:branch/newfile/:path"
|
<Route path="/:owner/:projectsId/:branch/newfile/:path"
|
||||||
|
@ -99,12 +99,12 @@ class CoderRootIndex extends Component{
|
||||||
></Route>
|
></Route>
|
||||||
<Route path="/:owner/:projectsId/:branch/newfile"
|
<Route path="/:owner/:projectsId/:branch/newfile"
|
||||||
render={
|
render={
|
||||||
(props) => (<FileNew {...this.props} {...props} {...this.state} getTopCount={this.getTopCount} />)
|
(props) => (<FileNew {...this.props} {...props} {...this.state} />)
|
||||||
}
|
}
|
||||||
></Route>
|
></Route>
|
||||||
<Route path="/:owner/:projectsId/commits/branch/:branchName"
|
<Route path="/:owner/:projectsId/commits/branch/:branchName"
|
||||||
render={
|
render={
|
||||||
() => (<CoderRootCommit {...this.props} {...this.state} commit_class="main" getTopCount={this.getTopCount} />)
|
() => (<CoderRootCommit {...this.props} {...this.state} commit_class="main" />)
|
||||||
}
|
}
|
||||||
></Route>
|
></Route>
|
||||||
<Route path="/:owner/:projectsId/commits/:sha"
|
<Route path="/:owner/:projectsId/commits/:sha"
|
||||||
|
@ -114,10 +114,10 @@ class CoderRootIndex extends Component{
|
||||||
></Route>
|
></Route>
|
||||||
<Route path="/:owner/:projectsId/commits"
|
<Route path="/:owner/:projectsId/commits"
|
||||||
render={
|
render={
|
||||||
() => (<CoderRootCommit {...this.props} {...this.state} commit_class="main" getTopCount={this.getTopCount} />)
|
() => (<CoderRootCommit {...this.props} {...this.state} commit_class="main" />)
|
||||||
}
|
}
|
||||||
></Route>
|
></Route>
|
||||||
<Route path="/:owner/:projectsId/releases/:versionId/update"
|
{/* <Route path="/:owner/:projectsId/releases/:versionId/update"
|
||||||
render={
|
render={
|
||||||
(props) => (<CoderRootVersionUpdate {...this.props} {...this.state} {...props} />)
|
(props) => (<CoderRootVersionUpdate {...this.props} {...this.state} {...props} />)
|
||||||
}
|
}
|
||||||
|
@ -126,7 +126,7 @@ class CoderRootIndex extends Component{
|
||||||
render={
|
render={
|
||||||
() => (<CoderRootVersionNew {...this.props} {...this.state} />)
|
() => (<CoderRootVersionNew {...this.props} {...this.state} />)
|
||||||
}
|
}
|
||||||
></Route>
|
></Route> */}
|
||||||
<Route path="/:owner/:projectsId/releases"
|
<Route path="/:owner/:projectsId/releases"
|
||||||
render={
|
render={
|
||||||
() => (<CoderRootVersion {...this.props} {...this.state} />)
|
() => (<CoderRootVersion {...this.props} {...this.state} />)
|
||||||
|
|
|
@ -34,7 +34,7 @@ export default (( props, { projectDetail }) => {
|
||||||
<div className="div_table">
|
<div className="div_table">
|
||||||
<ul className="ul_thead">
|
<ul className="ul_thead">
|
||||||
<li>
|
<li>
|
||||||
<span className="flex1">标签名</span>
|
<span className="flex1">标记名</span>
|
||||||
<span>提交信息</span>
|
<span>提交信息</span>
|
||||||
<span className="ul_tbody_forth">下载</span>
|
<span className="ul_tbody_forth">下载</span>
|
||||||
</li>
|
</li>
|
||||||
|
|
|
@ -1,10 +1,13 @@
|
||||||
import React, { Component } from 'react';
|
import React, { Component } from 'react';
|
||||||
import { Spin, Tooltip, Button } from 'antd';
|
import { Spin, Tooltip } from 'antd';
|
||||||
import { Link, Route, Switch } from 'react-router-dom';
|
import { Link, Route, Switch } from 'react-router-dom';
|
||||||
import { Content, AlignTop } from '../Component/layout';
|
import { Content, AlignTop } from '../Component/layout';
|
||||||
import DetailBanner from './sub/DetailBanner';
|
import DetailBanner from './sub/DetailBanner';
|
||||||
import '../css/index.scss'
|
import '../css/index.scss'
|
||||||
import './list.css';
|
import './list.scss';
|
||||||
|
|
||||||
|
import { ImageLayerOfCommentHOC } from "../../modules/page/layers/ImageLayerOfCommentHOC";
|
||||||
|
|
||||||
|
|
||||||
import Loadable from 'react-loadable';
|
import Loadable from 'react-loadable';
|
||||||
import Loading from '../../Loading';
|
import Loading from '../../Loading';
|
||||||
|
@ -67,7 +70,7 @@ const MergeIndexDetail = Loadable({
|
||||||
})
|
})
|
||||||
|
|
||||||
const CreateMerge = Loadable({
|
const CreateMerge = Loadable({
|
||||||
loader: () => import('../Merge/NewMerge'),
|
loader: () => import('../Merge/CreateMerge'),
|
||||||
loading: Loading,
|
loading: Loading,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -142,12 +145,14 @@ const WikiEdit = Loadable({
|
||||||
function checkPathname(projectsId, owner, pathname) {
|
function checkPathname(projectsId, owner, pathname) {
|
||||||
let name = "";
|
let name = "";
|
||||||
if (pathname && pathname !== `/${owner}/${projectsId}`) {
|
if (pathname && pathname !== `/${owner}/${projectsId}`) {
|
||||||
let url = pathname.split(`/${owner}/${projectsId}`)[1];
|
let url = pathname.split(`/${owner}/${projectsId}`)[1] || "";
|
||||||
if (url.indexOf("/about") > -1) {
|
if (url.indexOf("/about") > -1) {
|
||||||
name = "about"
|
name = "about"
|
||||||
} else if (url.indexOf("/issues") > -1 || url.indexOf("Milepost") > 0) {
|
} else if (url.indexOf("/issues") > -1 || url.indexOf("Milepost") > 0) {
|
||||||
name = "issues";
|
name = "issues";
|
||||||
} else if (url.indexOf("/pulls") > -1) {
|
} else if (url.indexOf("/pulls") > -1 || url.indexOf("/compare") > -1) {
|
||||||
|
// /pulls,合并请求除新建合并请求外,
|
||||||
|
// /compare,新建合并请求
|
||||||
name = "pulls"
|
name = "pulls"
|
||||||
} else if (url.indexOf("/milestones") > -1) {
|
} else if (url.indexOf("/milestones") > -1) {
|
||||||
name = "milestones"
|
name = "milestones"
|
||||||
|
@ -252,7 +257,11 @@ class Detail extends Component {
|
||||||
open_devops: flag
|
open_devops: flag
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
canvasChannel = () => {
|
/**
|
||||||
|
*
|
||||||
|
* @param {*} deleteFlag :同步镜像需要提示成功,且未成功的情况下不需要删除项目
|
||||||
|
*/
|
||||||
|
canvasChannel = (deleteFlag) => {
|
||||||
const name = window.location.hostname === "localhost" ? "testforgeplus.trustie.net" : window.location.hostname;
|
const name = window.location.hostname === "localhost" ? "testforgeplus.trustie.net" : window.location.hostname;
|
||||||
const actioncable = require("actioncable");
|
const actioncable = require("actioncable");
|
||||||
var project = this.state.project;
|
var project = this.state.project;
|
||||||
|
@ -269,10 +278,15 @@ class Detail extends Component {
|
||||||
console.log(`###### ---received data--- ######`);
|
console.log(`###### ---received data--- ######`);
|
||||||
console.log(data);
|
console.log(data);
|
||||||
if (data) {
|
if (data) {
|
||||||
if ( data.project && data.project.mirror_status === 2) {
|
if(deleteFlag){
|
||||||
this.deleteProjectBack();
|
this.props.showNotification("镜像同步成功!");
|
||||||
|
window.location.reload();
|
||||||
|
}else{
|
||||||
|
if (data.project && data.project.mirror_status === 2) {
|
||||||
|
this.deleteProjectBack();
|
||||||
|
}
|
||||||
|
this.getDetail();
|
||||||
}
|
}
|
||||||
this.getDetail();
|
|
||||||
this.setState({
|
this.setState({
|
||||||
firstSync: false,
|
firstSync: false,
|
||||||
secondSync: false
|
secondSync: false
|
||||||
|
@ -306,6 +320,9 @@ class Detail extends Component {
|
||||||
const url = `/${owner}/${projectsId}/detail.json`;
|
const url = `/${owner}/${projectsId}/detail.json`;
|
||||||
axios.get(url).then((result) => {
|
axios.get(url).then((result) => {
|
||||||
if (result && result.data) {
|
if (result && result.data) {
|
||||||
|
if (result.data.status === 404) {
|
||||||
|
this.props.history.push('/nopage');
|
||||||
|
}
|
||||||
this.setState({
|
this.setState({
|
||||||
projectDetail: result.data,
|
projectDetail: result.data,
|
||||||
project_id: result.data.project_id,
|
project_id: result.data.project_id,
|
||||||
|
@ -425,8 +442,10 @@ class Detail extends Component {
|
||||||
const url = `/${owner}/${projectsId}/sync_mirror.json`;
|
const url = `/${owner}/${projectsId}/sync_mirror.json`;
|
||||||
axios.post(url).then(result => {
|
axios.post(url).then(result => {
|
||||||
if (result && result.data && result.data.status === 0) {
|
if (result && result.data && result.data.status === 0) {
|
||||||
this.props.showNotification("镜像同步成功!");
|
this.setState({
|
||||||
this.getProject(2);
|
secondSync:true
|
||||||
|
})
|
||||||
|
this.canvasChannel(true);
|
||||||
} else {
|
} else {
|
||||||
this.props.showNotification("镜像同步失败!");
|
this.props.showNotification("镜像同步失败!");
|
||||||
}
|
}
|
||||||
|
@ -471,7 +490,7 @@ class Detail extends Component {
|
||||||
<div>
|
<div>
|
||||||
<div className="detailHeader-wrapper">
|
<div className="detailHeader-wrapper">
|
||||||
<div className="normal">
|
<div className="normal">
|
||||||
<AlignTop style={{ padding: "20px 0px 10px", justifyContent: "space-between" }}>
|
<AlignTop style={{ padding: "18px 0px 10px", justifyContent: "space-between" }}>
|
||||||
<div>
|
<div>
|
||||||
<AlignTop>
|
<AlignTop>
|
||||||
<div className="projectallName">
|
<div className="projectallName">
|
||||||
|
@ -489,11 +508,6 @@ class Detail extends Component {
|
||||||
this.textFunc(projectDetail.forked_from_project_id, projectDetail.fork_info)
|
this.textFunc(projectDetail.forked_from_project_id, projectDetail.fork_info)
|
||||||
: ""
|
: ""
|
||||||
}
|
}
|
||||||
{
|
|
||||||
projectDetail && projectDetail.type && projectDetail.type !== 0 ?
|
|
||||||
<span className="color-grey-9">镜像自 <a className="color-grey-6" target="_blank" href={projectDetail.mirror_url}>{projectDetail.mirror_url}</a></span>
|
|
||||||
: ""
|
|
||||||
}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
|
@ -504,7 +518,7 @@ class Detail extends Component {
|
||||||
((current_user && current_user.admin) || isManager) && (projectDetail && projectDetail.type && projectDetail.type === 2) ?
|
((current_user && current_user.admin) || isManager) && (projectDetail && projectDetail.type && projectDetail.type === 2) ?
|
||||||
<a className="synchronism ml30" onClick={this.synchronismMirror}>同步镜像</a> : ""
|
<a className="synchronism ml30" onClick={this.synchronismMirror}>同步镜像</a> : ""
|
||||||
}
|
}
|
||||||
<Button className="detail_tag_btn">
|
<span className="detail_tag_btn">
|
||||||
<a className="detail_tag_btn_name" style={{ cursor: platform ? "pointer" : "default" }} onClick={() => this.focusFunc(watched)}>
|
<a className="detail_tag_btn_name" style={{ cursor: platform ? "pointer" : "default" }} onClick={() => this.focusFunc(watched)}>
|
||||||
<i className={watched ? "iconfont icon-shixing color-orange font-16 mr3" : "iconfont icon-kongxing color-grey-9 font-16 mr3"}></i>
|
<i className={watched ? "iconfont icon-shixing color-orange font-16 mr3" : "iconfont icon-kongxing color-grey-9 font-16 mr3"}></i>
|
||||||
<span>{watched ? '取消关注' : '关注'}</span>
|
<span>{watched ? '取消关注' : '关注'}</span>
|
||||||
|
@ -512,15 +526,15 @@ class Detail extends Component {
|
||||||
{
|
{
|
||||||
watchers_count > 0 ?
|
watchers_count > 0 ?
|
||||||
platform ?
|
platform ?
|
||||||
<Link className="detail_tag_btn_count" style={{ color: `${watched ? "#2878FF" : "#666"}` }} to={platform ? { pathname: `/${owner}/${projectsId}/following`, state } : ""}>
|
<Link className="detail_tag_btn_count" style={{ color: `#666` }} to={platform ? { pathname: `/${owner}/${projectsId}/following`, state } : ""}>
|
||||||
{watchers_count}
|
{watchers_count}
|
||||||
</Link>
|
</Link>
|
||||||
:
|
:
|
||||||
<span className="detail_tag_btn_count">{watchers_count}</span>
|
<span className="detail_tag_btn_count">{watchers_count}</span>
|
||||||
: ""
|
: ""
|
||||||
}
|
}
|
||||||
</Button>
|
</span>
|
||||||
<Button className="detail_tag_btn">
|
<span className="detail_tag_btn">
|
||||||
<a className="detail_tag_btn_name" style={{ cursor: platform ? "pointer" : "default" }} onClick={() => this.pariseFunc(praised)}>
|
<a className="detail_tag_btn_name" style={{ cursor: platform ? "pointer" : "default" }} onClick={() => this.pariseFunc(praised)}>
|
||||||
<i className={praised ? "iconfont icon-weibiaoti105 color-orange font-14 mr3" : "iconfont icon-guanzhu color-grey-9 font-14 mr3"}></i>
|
<i className={praised ? "iconfont icon-weibiaoti105 color-orange font-14 mr3" : "iconfont icon-guanzhu color-grey-9 font-14 mr3"}></i>
|
||||||
<span>{praised ? '取消点赞' : '点赞'}</span>
|
<span>{praised ? '取消点赞' : '点赞'}</span>
|
||||||
|
@ -528,17 +542,17 @@ class Detail extends Component {
|
||||||
{
|
{
|
||||||
praises_count > 0 ?
|
praises_count > 0 ?
|
||||||
platform ?
|
platform ?
|
||||||
<Link className="detail_tag_btn_count" style={{ color: `${praised ? "#2878FF" : "#666"}` }} to={{ pathname: `/${owner}/${projectsId}/stargazers`, state }}>
|
<Link className="detail_tag_btn_count" style={{ color: `#666` }} to={{ pathname: `/${owner}/${projectsId}/stargazers`, state }}>
|
||||||
{praises_count}
|
{praises_count}
|
||||||
</Link> :
|
</Link> :
|
||||||
<span className="detail_tag_btn_count">{praises_count}</span>
|
<span className="detail_tag_btn_count">{praises_count}</span>
|
||||||
: ""
|
: ""
|
||||||
}
|
}
|
||||||
</Button>
|
</span>
|
||||||
<Button className="detail_tag_btn" loading={forkSpin}>
|
<span className="detail_tag_btn" loading={forkSpin}>
|
||||||
<Tooltip title="复刻是fork的中文名,即复制代码仓库" placement="bottom">
|
<Tooltip title="复刻是fork的中文名,即复制代码仓库" placement="bottom">
|
||||||
<a className="detail_tag_btn_name" style={{ cursor: platform ? "pointer" : "default" }} onClick={this.forkFunc}>
|
<a className="detail_tag_btn_name" style={{ cursor: platform ? "pointer" : "default" }} onClick={this.forkFunc}>
|
||||||
<i className="iconfont icon-fork color-grey-9 mr3"></i>复刻
|
<i className="iconfont icon-fork color-grey-9 mr3 font-16"></i><span>复刻(Fork)</span>
|
||||||
</a>
|
</a>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
{
|
{
|
||||||
|
@ -551,7 +565,7 @@ class Detail extends Component {
|
||||||
<span className="detail_tag_btn_count">{forked_count}</span>
|
<span className="detail_tag_btn_count">{forked_count}</span>
|
||||||
: ""
|
: ""
|
||||||
}
|
}
|
||||||
</Button>
|
</span>
|
||||||
</span>
|
</span>
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
|
@ -667,18 +681,19 @@ class Detail extends Component {
|
||||||
(props) => (<OrderNew {...this.props} {...props} {...this.state} {...common} />)
|
(props) => (<OrderNew {...this.props} {...props} {...this.state} {...common} />)
|
||||||
}
|
}
|
||||||
></Route>
|
></Route>
|
||||||
{/* 修改详情 */}
|
{/* 修改详情 updatedetail*/}
|
||||||
<Route path="/:owner/:projectsId/issues/:orderId/updatedetail"
|
<Route path="/:owner/:projectsId/issues/:orderId/:operateName"
|
||||||
render={
|
render={
|
||||||
(props) => (<OrderupdateDetail {...this.props} {...props} {...this.state} {...common} />)
|
(props) => (<OrderupdateDetail {...this.props} {...props} {...this.state} {...common} />)
|
||||||
}
|
}
|
||||||
></Route>
|
></Route>
|
||||||
{/* 复制详情 */}
|
{/* 复制详情 copyetail*/}
|
||||||
<Route path="/:owner/:projectsId/issues/:orderId/copyetail"
|
<Route path="/:owner/:projectsId/issues/:orderId/copyetail"
|
||||||
render={
|
render={
|
||||||
(props) => (<OrdercopyDetail {...this.props} {...props} {...this.state} {...common} />)
|
(props) => (<OrderupdateDetail {...this.props} {...props} {...this.state} {...common} />)
|
||||||
}
|
}
|
||||||
></Route>
|
></Route>
|
||||||
|
|
||||||
{/* 任务详情 */}
|
{/* 任务详情 */}
|
||||||
<Route path="/:owner/:projectsId/issues/:orderId"
|
<Route path="/:owner/:projectsId/issues/:orderId"
|
||||||
render={
|
render={
|
||||||
|
@ -698,22 +713,32 @@ class Detail extends Component {
|
||||||
}
|
}
|
||||||
></Route>
|
></Route>
|
||||||
{/* 新建合并请求 */}
|
{/* 新建合并请求 */}
|
||||||
<Route path="/:owner/:projectsId/pulls/new/:branch"
|
{/* <Route path="/:owner/:projectsId/compare/:branch"
|
||||||
|
render={
|
||||||
|
(props) => (<CreateMerge {...this.props} {...props} {...this.state} {...common} is_fork={true} />)
|
||||||
|
}
|
||||||
|
></Route> */}
|
||||||
|
<Route path="/:owner/:projectsId/compare"
|
||||||
render={
|
render={
|
||||||
(props) => (<CreateMerge {...this.props} {...props} {...this.state} {...common} is_fork={true} />)
|
(props) => (<CreateMerge {...this.props} {...props} {...this.state} {...common} is_fork={true} />)
|
||||||
}
|
}
|
||||||
></Route>
|
></Route>
|
||||||
<Route path="/:owner/:projectsId/pulls/new"
|
<Route path="/:owner/:projectsId/pulls/:mergeId/edit"
|
||||||
render={
|
|
||||||
(props) => (<CreateMerge {...this.props} {...props} {...this.state} {...common} is_fork={true} />)
|
|
||||||
}
|
|
||||||
></Route>
|
|
||||||
<Route path="/:owner/:projectsId/pulls/:mergeId/UpdateMerge"
|
|
||||||
render={
|
render={
|
||||||
(props) => (<UpdateMerge {...this.props} {...props} {...this.state} {...common} />)
|
(props) => (<UpdateMerge {...this.props} {...props} {...this.state} {...common} />)
|
||||||
}
|
}
|
||||||
></Route>
|
></Route>
|
||||||
<Route path="/:owner/:projectsId/pulls/:mergeId/Messagecount"
|
<Route path="/:owner/:projectsId/pulls/:mergeId"
|
||||||
|
render={
|
||||||
|
(props) => (<MessageCount {...this.props} {...props} {...this.state} {...common} />)
|
||||||
|
}
|
||||||
|
></Route>
|
||||||
|
<Route path="/:owner/:projectsId/pulls/:mergeId/commits"
|
||||||
|
render={
|
||||||
|
(props) => (<MessageCount {...this.props} {...props} {...this.state} {...common} />)
|
||||||
|
}
|
||||||
|
></Route>
|
||||||
|
<Route path="/:owner/:projectsId/pulls/:mergeId/files"
|
||||||
render={
|
render={
|
||||||
(props) => (<MessageCount {...this.props} {...props} {...this.state} {...common} />)
|
(props) => (<MessageCount {...this.props} {...props} {...this.state} {...common} />)
|
||||||
}
|
}
|
||||||
|
@ -780,4 +805,7 @@ class Detail extends Component {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default Detail;
|
export default ImageLayerOfCommentHOC({
|
||||||
|
imgSelector: ".imageLayerParent img, .imageLayerParent .imageTarget",
|
||||||
|
parentSelector: ".newContainer",
|
||||||
|
})(Detail);
|
||||||
|
|
|
@ -0,0 +1,28 @@
|
||||||
|
import React from 'react';
|
||||||
|
import { Route, Switch } from "react-router-dom";
|
||||||
|
import { withRouter } from "react-router";
|
||||||
|
import Loadable from "react-loadable";
|
||||||
|
import Loading from "../../Loading";
|
||||||
|
import { SnackbarHOC } from "educoder";
|
||||||
|
import { CNotificationHOC } from "../../modules/courses/common/CNotificationHOC";
|
||||||
|
import { TPMIndexHOC } from "../../modules/tpm/TPMIndexHOC";
|
||||||
|
|
||||||
|
// forge项目详情
|
||||||
|
const ProjectDetail = Loadable({
|
||||||
|
loader: () => import("../Main/Detail"),
|
||||||
|
loading: Loading,
|
||||||
|
});
|
||||||
|
export default withRouter(
|
||||||
|
(CNotificationHOC()(SnackbarHOC()(TPMIndexHOC((props) => {
|
||||||
|
return (
|
||||||
|
<Switch>
|
||||||
|
<Route
|
||||||
|
path="/:owner/:projectsId"
|
||||||
|
render={(p) => (
|
||||||
|
<ProjectDetail {...props} {...p} />
|
||||||
|
)}
|
||||||
|
></Route>
|
||||||
|
</Switch>
|
||||||
|
)
|
||||||
|
}))))
|
||||||
|
)
|
|
@ -1,35 +1,65 @@
|
||||||
import React, { useEffect, useState } from "react";
|
import React, { useEffect, useState } from "react";
|
||||||
import styled from "styled-components";
|
import styled from "styled-components";
|
||||||
import { Button ,Spin } from "antd";
|
import { Button ,Spin } from "antd";
|
||||||
import { truncateCommitId } from '../common/util';
|
import { timeFormat, truncateCommitId } from '../common/util';
|
||||||
import { getImageUrl } from 'educoder';
|
import { getImageUrl } from 'educoder';
|
||||||
import Files from '../Merge/Files';
|
import Files from '../Merge/Files';
|
||||||
|
import Tree from "./img/tree.png";
|
||||||
import User from "../Component/User";
|
import User from "../Component/User";
|
||||||
import Keys from "../Component/Keys";
|
import RenderHtml from "../../components/render-html";
|
||||||
|
|
||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
|
import { Link } from "react-router-dom";
|
||||||
|
|
||||||
const Infos = styled.div`
|
const Infos = styled.div`
|
||||||
border: 1px solid #dddddd;
|
border: 1px solid #FAFCFF;
|
||||||
margin-bottom:15px;
|
margin-bottom:15px;
|
||||||
& .commitinfos {
|
& .commitinfos {
|
||||||
background-color: #f1f8ff;
|
background-color: #f1f8ff;
|
||||||
border-bottom: 1px solid #ddd;
|
border: 1px solid rgba(42, 97, 255, 0.23);
|
||||||
padding: 20px;
|
border-radius: 3px 3px 0px 0px;
|
||||||
|
padding: 10px 20px 10px 16px;
|
||||||
|
& .markdown-body table{
|
||||||
|
background: #f1f8ff;
|
||||||
|
}
|
||||||
|
& .btnblue{
|
||||||
|
margin-top: 12px;
|
||||||
|
}
|
||||||
|
& .task-hide{
|
||||||
|
width: 65rem;
|
||||||
|
overflow:hidden;
|
||||||
|
white-space:normal;
|
||||||
|
word-break:break-all;
|
||||||
|
font-weight: bold;
|
||||||
|
color: #333333;
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
& > .f-wrap-between {
|
& > .f-wrap-between {
|
||||||
padding: 10px 20px;
|
padding: 14px 20px 14px 16px;
|
||||||
|
border-radius: 3px 3px 0px 0px;
|
||||||
|
border: 1px solid #D0D0D0;
|
||||||
|
.df{
|
||||||
|
align-items: center;
|
||||||
|
& .underline:hover{
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
function turnbar(str){
|
||||||
export default ({ match , history }) => {
|
if(str && str.length>0 && str.indexOf("/")>-1){
|
||||||
|
return str.replaceAll('/','%2F');
|
||||||
|
}
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
//提交详情页
|
||||||
|
export default (props) => {
|
||||||
|
const {match , history } = props;
|
||||||
const [data, setData] = useState({undefined});
|
const [data, setData] = useState({undefined});
|
||||||
const [commit, setCommit] = useState(undefined);
|
const [commit, setCommit] = useState(undefined);
|
||||||
const [parents, setParents] = useState(undefined);
|
const [parents, setParents] = useState(undefined);
|
||||||
const [committer, setCommitter] = useState(undefined);
|
const [committer, setCommitter] = useState(undefined);
|
||||||
const [isSpin, setIsSpin] = useState(true);
|
const [isSpin, setIsSpin] = useState(true);
|
||||||
|
|
||||||
const { sha , projectsId, owner } = match.params;
|
const { sha , projectsId, owner } = match.params;
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (projectsId && owner && sha) {
|
if (projectsId && owner && sha) {
|
||||||
|
@ -43,6 +73,7 @@ export default ({ match , history }) => {
|
||||||
setParents(result.data.parents);
|
setParents(result.data.parents);
|
||||||
setCommitter(result.data.committer || (result.data.commit && result.data.commit.committer));
|
setCommitter(result.data.committer || (result.data.commit && result.data.commit.committer));
|
||||||
setIsSpin(false);
|
setIsSpin(false);
|
||||||
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.catch(error => {
|
.catch(error => {
|
||||||
|
@ -56,29 +87,42 @@ export default ({ match , history }) => {
|
||||||
<Infos>
|
<Infos>
|
||||||
<div className="commitinfos">
|
<div className="commitinfos">
|
||||||
<div className="f-wrap-between">
|
<div className="f-wrap-between">
|
||||||
{commit && commit.message &&
|
<div>
|
||||||
<pre className="task-hide" style={{marginBottom:"0px",height:"28px",whiteSpace:"pre-wrap"}}>{commit.message}</pre>
|
{commit && commit.message &&
|
||||||
}
|
<RenderHtml className="task-hide" value={commit.message}/>
|
||||||
<Button type="primary" onClick={()=>{history.push(`/${owner}/${projectsId}/tree/${truncateCommitId(sha)}`)}} className="ml30">浏览代码</Button>
|
}
|
||||||
|
<Link to={`/${owner}/${projectsId}/tree/${data.branch}`}><i className="iconfont icon-fenzhi2 font-18"></i>{data.branch}</Link>
|
||||||
|
</div>
|
||||||
|
<Button type="primary" onClick={()=>{history.push(`/${owner}/${projectsId}/tree/${truncateCommitId(sha)}`)}} className="btnblue" style={{height:"36px"}}>浏览文件</Button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="f-wrap-between" style={{ alignItems: "center" }}>
|
<div className="f-wrap-between" style={{ alignItems: "center" }}>
|
||||||
<ul className="df">
|
<ul className="df">
|
||||||
<User
|
<User
|
||||||
url={(committer && getImageUrl(`/${committer.image_url}`))|| "https://dss3.bdstatic.com/70cFv8Sh_Q1YnxGkpoWK1HF6hhy/it/u=3025493530,1989042357&fm=26&gp=0.jpg"}
|
id = {committer && committer.id}
|
||||||
|
url={(committer && getImageUrl(`/${committer.image_url}`))}
|
||||||
name={committer && committer.name}
|
name={committer && committer.name}
|
||||||
|
login={committer && committer.login}
|
||||||
/>
|
/>
|
||||||
{committer && committer.time_from_now && <li className="ml20 mt2">{committer.time_from_now}</li>}
|
{commit && commit.timestamp && <li className="ml4">提交于{timeFormat(commit.timestamp)}</li>}
|
||||||
</ul>
|
</ul>
|
||||||
<li className="df">
|
<li className="df">
|
||||||
{
|
{
|
||||||
parents && parents.length > 0 && parents.map((item,key)=>{
|
parents && parents.length > 0 && parents.map((item,key)=>{
|
||||||
return(
|
return(
|
||||||
<Keys title="父节点" value={truncateCommitId(item.sha)} key={key} className="mr20"></Keys>
|
<div className="ml40 f-wrap-alignCenter">
|
||||||
|
<label className="mr8">父节点</label>
|
||||||
|
<img src={Tree} alt="sha" width={"16px"} className="mr4"/>
|
||||||
|
<Link to={`/${owner}/${projectsId}/commits/${truncateCommitId(`${item.sha}`)}/${data.branch}`} className="underline">{truncateCommitId(item.sha)}</Link>
|
||||||
|
</div>
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
<Keys title="当前节点" value={truncateCommitId(sha)}></Keys>
|
<div className="ml40 f-wrap-alignCenter">
|
||||||
|
<label className="mr8">当前节点</label>
|
||||||
|
<img src={Tree} alt="sha" width={"16px"} className="mr4"/>
|
||||||
|
<span>{truncateCommitId(sha)}</span>
|
||||||
|
</div>
|
||||||
</li>
|
</li>
|
||||||
</div>
|
</div>
|
||||||
</Infos>
|
</Infos>
|
||||||
|
@ -87,6 +131,7 @@ export default ({ match , history }) => {
|
||||||
data={data}
|
data={data}
|
||||||
owner={owner}
|
owner={owner}
|
||||||
projectsId={projectsId}
|
projectsId={projectsId}
|
||||||
|
parentsSha={parents && parents.length > 0 && parents[0].sha}
|
||||||
/>
|
/>
|
||||||
</Spin>
|
</Spin>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -5,7 +5,7 @@ import { getImageUrl } from 'educoder';
|
||||||
import "slick-carousel/slick/slick.css";
|
import "slick-carousel/slick/slick.css";
|
||||||
import "slick-carousel/slick/slick-theme.css";
|
import "slick-carousel/slick/slick-theme.css";
|
||||||
import '../css/index.scss'
|
import '../css/index.scss'
|
||||||
import './list.css';
|
import './list.scss';
|
||||||
import './Index.scss';
|
import './Index.scss';
|
||||||
import ListItem from './IndexItem'
|
import ListItem from './IndexItem'
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
|
@ -255,14 +255,14 @@ class Index extends Component {
|
||||||
|
|
||||||
newItem = ()=>{
|
newItem = ()=>{
|
||||||
return(
|
return(
|
||||||
<Menu>
|
<ul>
|
||||||
<Menu.Item key="created_mirror">
|
<li>
|
||||||
<CheckProfile {...this.props} sureFunc={()=>{this.props.history.push('/projects/mirror/new')}}>新建镜像项目</CheckProfile>
|
<CheckProfile {...this.props} sureFunc={()=>{this.props.history.push('/projects/deposit/new')}}>新建项目</CheckProfile>
|
||||||
</Menu.Item>
|
</li>
|
||||||
<Menu.Item key="created_deposit">
|
<li>
|
||||||
<CheckProfile {...this.props} sureFunc={()=>{this.props.history.push('/projects/deposit/new')}}>新建托管项目</CheckProfile>
|
<CheckProfile {...this.props} sureFunc={()=>{this.props.history.push('/projects/mirror/new')}}>导入项目</CheckProfile>
|
||||||
</Menu.Item>
|
</li>
|
||||||
</Menu>
|
</ul>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -392,7 +392,13 @@ class Index extends Component {
|
||||||
<div>
|
<div>
|
||||||
{
|
{
|
||||||
current_user && current_user.login &&
|
current_user && current_user.login &&
|
||||||
<Popover content={this.newItem()} trigger={["click"]} placement='bottom' className="mr50">
|
<Popover
|
||||||
|
overlayClassName="newPopUl"
|
||||||
|
content={this.newItem()}
|
||||||
|
trigger={["click"]}
|
||||||
|
placement='bottom'
|
||||||
|
className="mr50"
|
||||||
|
>
|
||||||
<a className="ant-dropdown-link">
|
<a className="ant-dropdown-link">
|
||||||
<span className="color-blue font-16"><img src={img_new} alt="" width="13px" /> 新建</span>
|
<span className="color-blue font-16"><img src={img_new} alt="" width="13px" /> 新建</span>
|
||||||
</a>
|
</a>
|
||||||
|
|
|
@ -13,6 +13,21 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.iconBtn{
|
||||||
|
i{
|
||||||
|
color: #666;
|
||||||
|
}
|
||||||
|
span{
|
||||||
|
margin-left: 4px;
|
||||||
|
color: #333!important;
|
||||||
|
&:last-child{
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&:hover span,&:hover i{
|
||||||
|
color: #466AFF!important;
|
||||||
|
}
|
||||||
|
}
|
||||||
/* recommandProjects */
|
/* recommandProjects */
|
||||||
.recommandProjects.slick-slider{
|
.recommandProjects.slick-slider{
|
||||||
width: 1230px;
|
width: 1230px;
|
||||||
|
@ -108,63 +123,94 @@
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
.panelmenu{
|
.panelmenu{
|
||||||
padding-top:30px;
|
padding-top:30px;
|
||||||
|
.depotBtn{
|
||||||
|
.mr-5{
|
||||||
|
margin-right: -5px;
|
||||||
|
}
|
||||||
|
.ant-btn{
|
||||||
|
height: 32px;
|
||||||
|
line-height: 32px;
|
||||||
|
width: 83px;
|
||||||
|
text-align: center;
|
||||||
|
padding:0px ;
|
||||||
|
font-weight: 500;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
.ant-btn-default{
|
||||||
|
color: #333;
|
||||||
|
border-color: #d0d0d0;
|
||||||
|
&:hover{
|
||||||
|
background: #F3F4F6;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.ant-btn-primary{
|
||||||
|
color: #fff;
|
||||||
|
background-color: #466AFF;
|
||||||
|
border: none;
|
||||||
|
&:hover{
|
||||||
|
background-color: rgba(70,106,255,0.85);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
.addOptionBtn{
|
.depotBtn,.addOptionBtn{
|
||||||
height: 32px;
|
|
||||||
line-height: 30px;
|
|
||||||
display: flex;
|
display: flex;
|
||||||
border:1px solid #d9d9d9;
|
|
||||||
border-radius: 2px;
|
|
||||||
a{
|
a{
|
||||||
padding:0px 13px;
|
color: #333!important;
|
||||||
color: rgba(0, 0, 0, 0.65);
|
font-weight: 500!important;
|
||||||
cursor: pointer;
|
border-radius: 5px;
|
||||||
}
|
width: 83px;
|
||||||
& > a:first-child{
|
height: 32px;
|
||||||
border-right: 1px solid #d9d9d9;
|
line-height: 30px;
|
||||||
}
|
background: #fff;
|
||||||
& > a:last-child{
|
border: 1px solid #D0D0D0;
|
||||||
border-right: none;
|
margin-right: 10px;
|
||||||
|
text-align: center;
|
||||||
|
&:hover,&:active{
|
||||||
|
background: #F3F4F6;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.infoCount{
|
.infoCount{
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
padding:0px 5px;
|
width: 24px;
|
||||||
height: 16px;
|
text-align: center;
|
||||||
line-height: 16px;
|
height: 24px;
|
||||||
background-color: #eee;
|
line-height: 24px;
|
||||||
color:#999;
|
background-color:rgba(153, 153, 153, 0.13);;
|
||||||
|
color:#666;
|
||||||
border-radius: 12px;
|
border-radius: 12px;
|
||||||
margin-left: 10px;
|
margin-left: 6px;
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
}
|
}
|
||||||
.attrPerson{
|
.attrPerson{
|
||||||
padding-top: 15px;
|
padding-top: 12px;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
|
padding-bottom: 2px;
|
||||||
a{
|
a{
|
||||||
margin: 10px 10px 0px 0px;
|
margin: 0px 17px 10px 0px;
|
||||||
img{
|
img{
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
width: 35px;
|
width: 40px;
|
||||||
height: 35px;
|
height: 40px;
|
||||||
}
|
}
|
||||||
&:nth-child(6){
|
&:nth-child(5n){
|
||||||
margin-right: 0px;
|
margin-right: 0px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.progress{
|
.progress{
|
||||||
display: flex;
|
display: flex;
|
||||||
border-radius: 10px;
|
border-radius: 2px;
|
||||||
height: 7px;
|
height: 11px;
|
||||||
margin-top: 12px;
|
margin-top: 12px;
|
||||||
span{
|
span{
|
||||||
&:first-child{
|
&:first-child{
|
||||||
border-radius: 10px 0px 0px 10px;
|
border-radius: 2px 0px 0px 2px;
|
||||||
}
|
}
|
||||||
&:last-child{
|
&:last-child{
|
||||||
border-radius: 0px 10px 10px 0px;
|
border-radius: 0px 2px 2px 0px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -178,16 +224,17 @@
|
||||||
height: 8px;
|
height: 8px;
|
||||||
width: 8px;
|
width: 8px;
|
||||||
left: 0px;
|
left: 0px;
|
||||||
top:10px
|
top:8px;
|
||||||
}
|
}
|
||||||
&>span{
|
&>span{
|
||||||
padding-left: 15px;
|
padding-left: 15px;
|
||||||
position: relative;
|
position: relative;
|
||||||
min-width: 33.5%;
|
min-width: 33.5%;
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: 400;
|
||||||
|
color: #666;
|
||||||
span{
|
span{
|
||||||
color: #666;
|
|
||||||
&:last-child{
|
&:last-child{
|
||||||
color: #999;
|
|
||||||
margin-left: 5px;
|
margin-left: 5px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -195,18 +242,24 @@
|
||||||
}
|
}
|
||||||
.listtable{
|
.listtable{
|
||||||
margin-top: 20px;
|
margin-top: 20px;
|
||||||
border:1px solid #d9d9d9;
|
|
||||||
border-radius: 4px;
|
|
||||||
.listtablehead{
|
.listtablehead{
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
align-items: flex-start;
|
align-items: flex-start;
|
||||||
border-bottom: 1px solid #d9d9d9;
|
border-bottom: 1px solid #d9d9d9;
|
||||||
padding:7px 20px;
|
padding:12px 20px 11px;
|
||||||
border-radius: 4px 4px 0px 0px;
|
border-radius: 4px 4px 0px 0px;
|
||||||
background-color: #FAFBFC;
|
border: 1px solid rgba(42, 97, 255, 0.23);
|
||||||
|
background-color: #FAFCFF;
|
||||||
.ellipsistxt{
|
.ellipsistxt{
|
||||||
margin-top: 6px;
|
&:hover .markdown-body{
|
||||||
|
color: #466AFF;
|
||||||
|
& a{
|
||||||
|
color: #466AFF;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
margin-top: 2px;
|
||||||
|
// cursor: pointer;
|
||||||
#ptxt{
|
#ptxt{
|
||||||
margin-bottom: 0px;
|
margin-bottom: 0px;
|
||||||
word-break: break-all;
|
word-break: break-all;
|
||||||
|
@ -216,6 +269,27 @@
|
||||||
white-space:-pre-wrap; /* Opera 4-6 */
|
white-space:-pre-wrap; /* Opera 4-6 */
|
||||||
white-space:-o-pre-wrap; /* Opera 7 */
|
white-space:-o-pre-wrap; /* Opera 7 */
|
||||||
word-wrap:break-word;
|
word-wrap:break-word;
|
||||||
|
.markdown-body{
|
||||||
|
line-height: 10px;
|
||||||
|
font-size: 14px;
|
||||||
|
& p {
|
||||||
|
margin: 1px 0px 0px !important;
|
||||||
|
font-size: 14px !important;
|
||||||
|
}
|
||||||
|
& ol,ul{
|
||||||
|
padding-bottom: 3px;
|
||||||
|
& li{
|
||||||
|
min-height: 18px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
& table{
|
||||||
|
line-height: 1;
|
||||||
|
background: #FAFCFF;
|
||||||
|
}
|
||||||
|
&:first-child {
|
||||||
|
margin-top: -1px !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
margin-left: 13px;
|
margin-left: 13px;
|
||||||
line-height:18px;
|
line-height:18px;
|
||||||
|
@ -223,36 +297,41 @@
|
||||||
width: 0;
|
width: 0;
|
||||||
color: #666;
|
color: #666;
|
||||||
&.hidetxt{
|
&.hidetxt{
|
||||||
height: 18px;
|
height: 24px;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
position: relative;
|
position: relative;
|
||||||
padding-right:8px;
|
padding-right:8px;
|
||||||
&::after{
|
// &::after{
|
||||||
position: absolute;
|
// position: absolute;
|
||||||
right: 0px;
|
// right: 0px;
|
||||||
bottom: 0px;
|
// bottom: 0px;
|
||||||
content:"...";
|
// content:"...";
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.ellipsis{
|
.ellipsis{
|
||||||
margin-left: 8px;
|
margin-left: 8px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
border-radius: 2px;
|
border-radius: 2px;
|
||||||
background-color: #c1c1c1;
|
height: 16px;
|
||||||
|
background: rgba(153, 153, 153, 0.2);
|
||||||
|
border-radius: 2px;
|
||||||
padding:0px 4px;
|
padding:0px 4px;
|
||||||
height: 14px;
|
height: 14px;
|
||||||
line-height: 14px;
|
line-height: 14px;
|
||||||
margin-top: 9px;
|
margin-top: 9px;
|
||||||
i{
|
i{
|
||||||
font-size: 15px!important;
|
font-size: 15px!important;
|
||||||
color: #fff;
|
color: #333;
|
||||||
height: 14px;
|
height: 14px;
|
||||||
line-height: 14px;
|
line-height: 14px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.listtablebody{
|
.listtablebody{
|
||||||
|
border-radius:0px 0px 4px 4px ;
|
||||||
|
border: 1px solid #D0D0D0;
|
||||||
|
border-top: none;
|
||||||
li.listtablepath{
|
li.listtablepath{
|
||||||
a{color: #40a9ff;}
|
a{color: #40a9ff;}
|
||||||
p{
|
p{
|
||||||
|
@ -260,12 +339,15 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
& > li{
|
& > li{
|
||||||
height: 42px;
|
height: 38px;
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
border-bottom: 1px solid #d9d9d9;
|
border-bottom: 1px solid #d9d9d9;
|
||||||
padding:0px 20px 0px 24px;
|
padding:0px 20px 0px 24px;
|
||||||
|
&:hover{
|
||||||
|
background-color: #F3F4F6;
|
||||||
|
}
|
||||||
& > span:first-child{
|
& > span:first-child{
|
||||||
width: 30%;
|
width: 30%;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
@ -292,8 +374,10 @@
|
||||||
.drawerBtn{
|
.drawerBtn{
|
||||||
position: fixed;
|
position: fixed;
|
||||||
left: -13px;
|
left: -13px;
|
||||||
border:1px solid rgb(207,205,223);
|
width: 33px;
|
||||||
width: 34px;
|
background: #FFFFFF;
|
||||||
|
box-shadow: 0px 0px 8px 3px rgba(0, 0, 0, 0.09);
|
||||||
|
border: 1px solid #666666;
|
||||||
border-radius: 0px 12px 12px 0px;
|
border-radius: 0px 12px 12px 0px;
|
||||||
height: 70px;
|
height: 70px;
|
||||||
top:50%;
|
top:50%;
|
||||||
|
@ -301,36 +385,49 @@
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
align-items: flex-end;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
|
padding-left: 7px;
|
||||||
&:hover{
|
&:hover{
|
||||||
box-shadow: 1px 0px 7px rgba(0,0,0,0.1);
|
box-shadow: 0px 0px 8px 3px rgba(0, 0, 0, 0.09);
|
||||||
}
|
}
|
||||||
span{
|
span{
|
||||||
writing-mode: vertical-lr;
|
writing-mode: vertical-lr;
|
||||||
color: #202429;
|
color: #333;
|
||||||
width: 25px;
|
width: 25px;
|
||||||
|
font-size: 14px;
|
||||||
}
|
}
|
||||||
i{
|
i{
|
||||||
color: #24292e;
|
color: #333;
|
||||||
height: 18px;
|
height: 14px;
|
||||||
line-height: 18px;
|
line-height: 14px;
|
||||||
width: 18px;
|
width: 14px;
|
||||||
|
margin-left: 2px;
|
||||||
|
margin-bottom: 3px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.downMenu{
|
.downMenu{
|
||||||
width: 330px;
|
width: 329px;
|
||||||
box-shadow: 0px 0px 9px rgba(134, 134, 134,0.4);
|
|
||||||
background-color: #fff;
|
background-color: #fff;
|
||||||
.ant-menu-vertical .ant-menu-item:hover{
|
box-shadow: 0px 1px 8px 1px rgba(212, 212, 212, 0.5);
|
||||||
background-color: #e6f7ff;
|
padding-bottom: 14px;
|
||||||
|
.ant-menu-item{
|
||||||
|
height: 50px;
|
||||||
|
line-height: 50px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.fileMenu{
|
||||||
|
width: 83px;
|
||||||
|
li{
|
||||||
|
padding:6px 0px!important;
|
||||||
|
text-align: center;
|
||||||
|
width: 100%;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.menuslist{
|
.catelogue{
|
||||||
max-height: 200px;
|
cursor: pointer;
|
||||||
overflow-y: auto;
|
background: #FAFBFC;
|
||||||
padding:10px 15px;
|
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
.ant-dropdown-menu-item{
|
.ant-dropdown-menu-item{
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
|
@ -342,22 +439,19 @@
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.ant-dropdown-menu-item.active{
|
border: 1px solid #D0D0D0;
|
||||||
background-color: #e6f7ff;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.catelogue{
|
|
||||||
border:1px solid rgb(211, 211, 211);
|
|
||||||
font-size: 15px;
|
font-size: 15px;
|
||||||
font-weight: normal;
|
font-weight: normal;
|
||||||
border-radius: 5px;
|
margin-right: 12px;
|
||||||
margin-right: 10px;
|
|
||||||
padding:0px 10px;
|
padding:0px 10px;
|
||||||
height: 30px;
|
height: 30px;
|
||||||
line-height: 30px;
|
line-height: 30px;
|
||||||
color: #666!important;
|
color: #666!important;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
&:hover{
|
||||||
|
background-color: #F3F4F6;
|
||||||
|
}
|
||||||
span{
|
span{
|
||||||
margin-top: 1px;
|
margin-top: 1px;
|
||||||
}
|
}
|
||||||
|
@ -371,3 +465,47 @@
|
||||||
color: #05101a;
|
color: #05101a;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.pinfos{
|
||||||
|
i,a{color: #666;}
|
||||||
|
&:hover i,&:hover a{
|
||||||
|
color: #2A61FF!important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.graph{
|
||||||
|
flex:1;
|
||||||
|
margin:0px 12px;
|
||||||
|
.ant-typography{
|
||||||
|
white-space: pre-wrap;
|
||||||
|
margin-bottom: 0px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.ant-anchor-wrapper{
|
||||||
|
padding-left: 2px!important;
|
||||||
|
.ant-anchor-ink::before{
|
||||||
|
background-color: #fff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.coderSubPage{
|
||||||
|
width: 1200px;
|
||||||
|
margin:0px auto;
|
||||||
|
}
|
||||||
|
.griditemAnchor{
|
||||||
|
margin-left: 0px!important;
|
||||||
|
padding: 0px!important;
|
||||||
|
border-bottom: 1px solid #ddd;
|
||||||
|
.ant-anchor{
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
padding: 10px 20px;
|
||||||
|
}
|
||||||
|
.griditemCate{
|
||||||
|
color: #333;
|
||||||
|
font-size: 16px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
.catelogue{
|
||||||
|
margin-left: 0px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -5,7 +5,7 @@ import { AlignCenter } from '../Component/layout';
|
||||||
import { Link } from 'react-router-dom';
|
import { Link } from 'react-router-dom';
|
||||||
import '../css/index.scss';
|
import '../css/index.scss';
|
||||||
import Nodata from '../Nodata';
|
import Nodata from '../Nodata';
|
||||||
import './list.css';
|
import './list.scss';
|
||||||
import img_parise from '../Images/parise.png';
|
import img_parise from '../Images/parise.png';
|
||||||
|
|
||||||
class IndexItem extends Component {
|
class IndexItem extends Component {
|
||||||
|
@ -41,23 +41,17 @@ class IndexItem extends Component {
|
||||||
{ !item.is_public && <span className="privateTag">私有</span> }
|
{ !item.is_public && <span className="privateTag">私有</span> }
|
||||||
{
|
{
|
||||||
item.forked_from_project_id ?
|
item.forked_from_project_id ?
|
||||||
<span className="ml5">
|
<Tooltip title="该项目是一个fork仓库" className="ml5">
|
||||||
<i className="iconfont icon-fork font-18 color-orange" />
|
<i className="iconfont icon-fork font-18 color-orange" />
|
||||||
</span>
|
</Tooltip>
|
||||||
: ""
|
: ""
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
item.type && item.type === 2 ?
|
item.type && item.type === 2 ?
|
||||||
<Tooltip title="该项目是一个镜像" className="ml5">
|
<Tooltip title="该项目是一个同步镜像仓库" className="ml5">
|
||||||
<i className="iconfont icon-banbenku font-18 color-green" />
|
<i className="iconfont icon-banbenku font-18 color-green" />
|
||||||
</Tooltip>:""
|
</Tooltip>:""
|
||||||
}
|
}
|
||||||
{
|
|
||||||
item.type && item.type === 1 ?
|
|
||||||
<span className="ml5">
|
|
||||||
<i className="iconfont icon-jingxiang font-18 color-green" />
|
|
||||||
</span>:""
|
|
||||||
}
|
|
||||||
</AlignCenter>
|
</AlignCenter>
|
||||||
<span className="p-r-tags">
|
<span className="p-r-tags">
|
||||||
{
|
{
|
||||||
|
|
Binary file not shown.
After Width: | Height: | Size: 631 B |
Binary file not shown.
After Width: | Height: | Size: 590 B |
|
@ -218,74 +218,92 @@
|
||||||
}
|
}
|
||||||
/* -----------详情------------ */
|
/* -----------详情------------ */
|
||||||
.detailHeader-wrapper{
|
.detailHeader-wrapper{
|
||||||
background-color:#FAFBFC;
|
background-color:#FBFCFF;
|
||||||
/* background: url(../Images/forgeBanner.jpg) no-repeat center; */
|
border-bottom:1px solid #e2e2e2;
|
||||||
/* background-size:cover; */
|
|
||||||
}
|
}
|
||||||
.headerMenu-wrapper{
|
.headerMenu-wrapper{
|
||||||
font-size: 16px;
|
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
}
|
cursor: pointer;
|
||||||
.headerMenu-wrapper li{
|
li{
|
||||||
position: relative;
|
text-align: center;
|
||||||
text-align: center;
|
padding:0px;
|
||||||
height: 40px;
|
margin-right: 40px;
|
||||||
line-height: 28px;
|
display: flex;
|
||||||
margin-right: 40px;
|
& > a{
|
||||||
}
|
position: relative;
|
||||||
.headerMenu-wrapper li a{
|
font-size: 14px;
|
||||||
color: #666;
|
height: 36px;
|
||||||
}
|
line-height: 24px;
|
||||||
.headerMenu-wrapper li a > img{
|
display: block;
|
||||||
margin-right: 8px;
|
color: #000!important;
|
||||||
}
|
&> span.num{
|
||||||
.headerMenu-wrapper li a > span.num{
|
line-height: 24px;
|
||||||
height: 28px;
|
margin-left: 5px;
|
||||||
line-height: 29px;
|
font-size: 12px;
|
||||||
margin-left: 8px;
|
float: right;
|
||||||
font-size: 12px;
|
color: #666!important;
|
||||||
color: #2878FF;
|
background-color: rgba(153, 153, 153, 0.13);;
|
||||||
float: right;
|
border-radius: 50%;
|
||||||
}
|
width: 24px;
|
||||||
.headerMenu-wrapper li.active::after{
|
height: 24px;
|
||||||
position: absolute;
|
}
|
||||||
bottom:0px;
|
}
|
||||||
height:2px;
|
|
||||||
background-color: #5091FF;
|
&.active a::after,&:hover a::after{
|
||||||
content:'';
|
position: absolute;
|
||||||
left: 0px;
|
bottom:0px;
|
||||||
width:100%;
|
height:2px;
|
||||||
|
background-color:rgba(153, 153, 153, 0.2);
|
||||||
|
content:'';
|
||||||
|
left: 0px;
|
||||||
|
width:100%;
|
||||||
|
}
|
||||||
|
&.active span{
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
&.active a::after{
|
||||||
|
background-color: #466AFF;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
.detail_tag_btn{
|
.detail_tag_btn{
|
||||||
height:26px;
|
height:32px;
|
||||||
line-height: 26px;
|
line-height: 32px;
|
||||||
border-radius:5px;
|
border-radius:5px;
|
||||||
border:1px solid #f1f1f1;
|
border:1px solid #D0D0D0;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
margin-left: 30px;
|
margin-left: 10px;
|
||||||
padding:0px;
|
padding:0px;
|
||||||
background-color: transparent;
|
background-color:#FAFBFC;
|
||||||
box-shadow: none;
|
box-shadow: none;
|
||||||
|
.detail_tag_btn_name{
|
||||||
|
padding:0px 10px;
|
||||||
|
text-align: center;
|
||||||
|
height: 30px;
|
||||||
|
line-height: 30px;
|
||||||
|
border-radius:5px 0px 0px 5px;
|
||||||
|
&:hover
|
||||||
|
{
|
||||||
|
background-color: #F3F4F6;
|
||||||
|
}
|
||||||
|
span{
|
||||||
|
color: #333!important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.detail_tag_btn_count{
|
||||||
|
width: 42px;
|
||||||
|
text-align: center;
|
||||||
|
background: #fff;
|
||||||
|
border-radius: 0px 4px 4px 0px;
|
||||||
|
height:100%;
|
||||||
|
border-left: 1px solid #D0D0D0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
.ant-tooltip {
|
.ant-tooltip {
|
||||||
max-width: fit-content!important;
|
max-width: fit-content!important;
|
||||||
}
|
}
|
||||||
.detail_tag_btn_name{
|
|
||||||
padding:0px 10px;
|
|
||||||
color: #666!important;
|
|
||||||
}
|
|
||||||
.detail_tag_btn_name img{
|
|
||||||
margin-right: 10px;
|
|
||||||
}
|
|
||||||
.detail_tag_btn_count{
|
|
||||||
padding:0px 10px;
|
|
||||||
background: #fff;
|
|
||||||
border-radius: 0px 4px 4px 0px;
|
|
||||||
font-size: 12px;
|
|
||||||
height:100%;
|
|
||||||
}
|
|
||||||
.files-md{
|
.files-md{
|
||||||
padding:20px;
|
padding:20px;
|
||||||
}
|
}
|
||||||
|
@ -336,6 +354,7 @@
|
||||||
|
|
||||||
|
|
||||||
.gitAddressClone{
|
.gitAddressClone{
|
||||||
|
margin:14px 20px!important;
|
||||||
display: flex;
|
display: flex;
|
||||||
height: 40px;
|
height: 40px;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
@ -407,14 +426,15 @@
|
||||||
border-right: none;
|
border-right: none;
|
||||||
}
|
}
|
||||||
.gitAddressClone > input{
|
.gitAddressClone > input{
|
||||||
border:none;
|
|
||||||
outline: none;
|
outline: none;
|
||||||
padding:0px 8px;
|
padding: 0px 8px;
|
||||||
height: 40px;
|
height: 38px;
|
||||||
line-height: 40px;
|
line-height: 38px;
|
||||||
border-radius: 0px;
|
border: none!important;
|
||||||
border: 1px solid #eee;
|
border-right: 1px solid #eee!important;
|
||||||
flex:1;
|
border-radius: 4px 0px 0px 4px;
|
||||||
|
flex: 1;
|
||||||
|
max-width: 249px;
|
||||||
}
|
}
|
||||||
.wrap-commit-table .ant-table-small > .ant-table-content > .ant-table-body{
|
.wrap-commit-table .ant-table-small > .ant-table-content > .ant-table-body{
|
||||||
margin:0px;
|
margin:0px;
|
||||||
|
@ -499,7 +519,7 @@
|
||||||
}
|
}
|
||||||
.addFile a{
|
.addFile a{
|
||||||
display: block;
|
display: block;
|
||||||
background-color: rgb(76, 172, 255,0.8);
|
background-color: rgba(76, 172, 255,0.8);
|
||||||
color: #fff;
|
color: #fff;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
height: 32px;
|
height: 32px;
|
||||||
|
@ -514,7 +534,7 @@
|
||||||
border-left: 1px solid rgba(247, 247, 247, 0.3);
|
border-left: 1px solid rgba(247, 247, 247, 0.3);
|
||||||
}
|
}
|
||||||
.addFile a:active{
|
.addFile a:active{
|
||||||
background-color: rgb(76, 172, 255,1);
|
background-color: rgba(76, 172, 255,1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -553,8 +573,11 @@
|
||||||
}
|
}
|
||||||
.commonBox{
|
.commonBox{
|
||||||
border:1px solid #ddd;
|
border:1px solid #ddd;
|
||||||
margin-top: 30px;
|
margin-top: 18px;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
|
.ant-anchor-wrapper{
|
||||||
|
overflow: unset!important;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
.commonBox .commonBox-title{
|
.commonBox .commonBox-title{
|
||||||
padding:0px 20px;
|
padding:0px 20px;
|
||||||
|
@ -567,14 +590,28 @@
|
||||||
border-bottom: 1px solid #d9d9d9;
|
border-bottom: 1px solid #d9d9d9;
|
||||||
border-radius: 4px 4px 0px 0px;
|
border-radius: 4px 4px 0px 0px;
|
||||||
}
|
}
|
||||||
|
.readBox{
|
||||||
|
border:none;
|
||||||
|
&.commonBox .commonBox-info{
|
||||||
|
border:1px solid #D0D0D0;
|
||||||
|
border-top: none;
|
||||||
|
border-radius: 0px 0px 4px 4px;
|
||||||
|
padding:20px 38px;
|
||||||
|
}
|
||||||
|
}
|
||||||
.commonBox .commonBox-title.boxTitle{
|
.commonBox .commonBox-title.boxTitle{
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
|
height: 55px;
|
||||||
|
line-height: 55px;
|
||||||
|
background: #FAFCFF;
|
||||||
|
border-radius: 4px 4px 0px 0px;
|
||||||
|
border: 1px solid rgba(42, 97, 255, 0.23);
|
||||||
}
|
}
|
||||||
.synchronism{
|
.synchronism{
|
||||||
display: block;
|
display: block;
|
||||||
height: 26px;
|
height: 34px;
|
||||||
line-height: 26px;
|
line-height: 34px;
|
||||||
padding:0px 15px;
|
padding:0px 15px;
|
||||||
color: #fff!important;
|
color: #fff!important;
|
||||||
background-color: #28BD6C;
|
background-color: #28BD6C;
|
||||||
|
@ -583,10 +620,19 @@
|
||||||
.files_info{
|
.files_info{
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
.commonBox .commonBox-info{
|
.commonBox {
|
||||||
padding:20px 15px;
|
.commonBox-info{
|
||||||
|
padding:20px 15px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.commonBox-title-read{
|
||||||
|
vertical-align: middle;
|
||||||
|
color: #000;
|
||||||
|
font-size: 14px;
|
||||||
|
&:hover {
|
||||||
|
color: #466AFF;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
.commonBox-title-read{vertical-align: middle;color: #666;}
|
|
||||||
|
|
||||||
@media screen and (max-width: 370px){
|
@media screen and (max-width: 370px){
|
||||||
.p-r-tags,.p-r-btn{
|
.p-r-tags,.p-r-btn{
|
||||||
|
@ -627,9 +673,7 @@
|
||||||
.item:last-child{
|
.item:last-child{
|
||||||
border-bottom:none;
|
border-bottom:none;
|
||||||
}
|
}
|
||||||
.gitAddressClone{
|
|
||||||
margin: 0 !important;
|
|
||||||
}
|
|
||||||
.item_title small{
|
.item_title small{
|
||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
margin-left: 10px;
|
margin-left: 10px;
|
||||||
|
@ -678,12 +722,84 @@ a.color-grey-ccc:hover{
|
||||||
padding:0px 30px;
|
padding:0px 30px;
|
||||||
min-height: 400px;
|
min-height: 400px;
|
||||||
}
|
}
|
||||||
.commitList > div{
|
|
||||||
border-bottom: 1px solid #EEEEEE;
|
.main{
|
||||||
padding:16px 0px;
|
margin: 30px auto;
|
||||||
}
|
.ant-timeline{
|
||||||
.commitList > div:last-child{
|
margin-top: 28px;
|
||||||
border-bottom: none;
|
.commitList-item{
|
||||||
|
position: relative;
|
||||||
|
padding: 20px 20px;
|
||||||
|
background: #FAFCFF;
|
||||||
|
border: 1px solid rgba(42, 97, 255, 0.23);
|
||||||
|
border-radius: 4px;
|
||||||
|
margin-left: 16px;
|
||||||
|
& .treecopy{
|
||||||
|
margin-top: 20px;
|
||||||
|
}
|
||||||
|
& .markdown-body table{
|
||||||
|
background: #FAFCFF;
|
||||||
|
}
|
||||||
|
&:after,&:before{
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
left: -10px;
|
||||||
|
top: 10px;
|
||||||
|
border-top: 6px solid transparent;
|
||||||
|
border-bottom: 6px solid transparent;
|
||||||
|
border-right: 10px solid rgba(42, 97, 255, 0.23);
|
||||||
|
}
|
||||||
|
&:after{
|
||||||
|
left: -8px;
|
||||||
|
border-right: 10px solid #FAFCFF;
|
||||||
|
&:hover{
|
||||||
|
border-right: 10px solid #EEF6FF;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&:hover{
|
||||||
|
background: #EEF6FF;
|
||||||
|
border: 1px solid rgba(42, 97, 255, 0.58);
|
||||||
|
&:after{
|
||||||
|
border-right: 10px solid #EEF6FF;
|
||||||
|
}
|
||||||
|
&:before{
|
||||||
|
border-right: 10px solid rgba(42, 97, 255, 0.58);
|
||||||
|
}
|
||||||
|
& .markdown-body table{
|
||||||
|
background: #EEF6FF;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.treecopy-cont{
|
||||||
|
padding: 4px 15px;
|
||||||
|
}
|
||||||
|
.btn-83{
|
||||||
|
margin-left: 20px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.ant-timeline-item{
|
||||||
|
padding: 8px 0 20px;
|
||||||
|
}
|
||||||
|
.ant-timeline-item-tail{
|
||||||
|
height: calc(100% - 20px);
|
||||||
|
border-left: 2px solid #EEEEEE;
|
||||||
|
top: 12px;
|
||||||
|
&:after{
|
||||||
|
content: ' ';
|
||||||
|
height: 0;
|
||||||
|
position: absolute;
|
||||||
|
width: 0;
|
||||||
|
border: 7px solid transparent;
|
||||||
|
border-top-color: #EEEEEE;
|
||||||
|
top: 100%;
|
||||||
|
left: 50%;
|
||||||
|
margin-left: -8px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.ant-timeline-item-head-custom{
|
||||||
|
top:20px;
|
||||||
|
padding: 0 1px;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -733,3 +849,12 @@ a.color-grey-ccc:hover{
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
}
|
}
|
||||||
|
.depotNum{
|
||||||
|
color: #666!important;
|
||||||
|
span:last-child{
|
||||||
|
color: #333;
|
||||||
|
}
|
||||||
|
&:hover span:last-child{
|
||||||
|
color: #2A61FF;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,6 +1,7 @@
|
||||||
import React, { useEffect, useState } from 'react';
|
import React, { useEffect, useState } from 'react';
|
||||||
import { Skeleton , Tooltip} from 'antd';
|
import { Skeleton , Tooltip} from 'antd';
|
||||||
import { Link } from 'react-router-dom';
|
import { Link } from 'react-router-dom';
|
||||||
|
import { numFormat } from 'educoder';
|
||||||
|
|
||||||
function DetailBanner({ history,list , owner , projectsId , isManager , url , pathname , state , urlFlag , projectDetail , platform ,open_devops }){
|
function DetailBanner({ history,list , owner , projectsId , isManager , url , pathname , state , urlFlag , projectDetail , platform ,open_devops }){
|
||||||
const [ menuName , setMenuName ] = useState(undefined);
|
const [ menuName , setMenuName ] = useState(undefined);
|
||||||
|
@ -17,7 +18,7 @@ function DetailBanner({ history,list , owner , projectsId , isManager , url , pa
|
||||||
}
|
}
|
||||||
},[list]);
|
},[list]);
|
||||||
return(
|
return(
|
||||||
<div className="f-wrap-between mt15">
|
<div className="f-wrap-between mt25">
|
||||||
{
|
{
|
||||||
menuName && projectDetail ?
|
menuName && projectDetail ?
|
||||||
<ul className="headerMenu-wrapper">
|
<ul className="headerMenu-wrapper">
|
||||||
|
@ -29,39 +30,39 @@ function DetailBanner({ history,list , owner , projectsId , isManager , url , pa
|
||||||
item.menu_name === "home" &&
|
item.menu_name === "home" &&
|
||||||
<li className={pathname==="about" ? "active" : ""}>
|
<li className={pathname==="about" ? "active" : ""}>
|
||||||
<Link to={{ pathname: `/${owner}/${projectsId}/about`, state }}>
|
<Link to={{ pathname: `/${owner}/${projectsId}/about`, state }}>
|
||||||
<i className={(pathname==="" || urlFlag) ? "iconfont icon-zhuye1 color-grey-3 mr5 font-14":"iconfont icon-zhuye1 color-grey-6 font-14 mr5"}></i>
|
<i className={"iconfont icon-zhuye-fill color-grey-3 mr5 font-14"}></i>
|
||||||
<span>主页</span>
|
<span>主页</span>
|
||||||
</Link>
|
</Link>
|
||||||
</li>
|
</li>
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
item.menu_name === "code" &&
|
item.menu_name === "code" &&
|
||||||
<li className={(pathname==="" || urlFlag) ? "active" : ""}>
|
<li className={(pathname==="" || urlFlag) ? "active" : ""}>
|
||||||
<Link to={{ pathname: `/${owner}/${projectsId}`, state }}>
|
<Link to={{ pathname: `/${owner}/${projectsId}`, state }}>
|
||||||
<i className={(pathname==="" || urlFlag) ? "iconfont icon-daimaku color-grey-3 mr5 font-14":"iconfont icon-daimaku color-grey-6 font-14 mr5"}></i>
|
<i className={"iconfont icon-daimakuicon1 color-grey-3 mr5 font-14"}></i>
|
||||||
<span>代码库</span>
|
<span>代码库</span>
|
||||||
</Link>
|
</Link>
|
||||||
</li>
|
</li>
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
item.menu_name === "issues" &&
|
item.menu_name === "issues" &&
|
||||||
<li className={pathname==="issues" ? "active" : ""}>
|
<li className={pathname==="issues" ? "active" : ""}>
|
||||||
<Tooltip title="易修是Issue的中文名,即问题列表" placement="bottom">
|
|
||||||
<Link to={{ pathname: `/${owner}/${projectsId}/issues`, state }}>
|
<Link to={{ pathname: `/${owner}/${projectsId}/issues`, state }}>
|
||||||
<i className={pathname==="issues" ? "iconfont icon-renwu color-grey-3 mr5 font-14":"iconfont icon-renwu color-grey-6 font-14 mr5"}></i>
|
<Tooltip title="易修是Issue的中文名,即问题列表" placement="bottom">
|
||||||
<span>易修</span>
|
<i className={"iconfont icon-yixiuicon1 color-grey-3 mr5 font-14"}></i>
|
||||||
{projectDetail && projectDetail.issues_count ? <span className="num">{projectDetail.issues_count}</span> : ""}
|
<span>易修(Issue)</span>
|
||||||
|
</Tooltip>
|
||||||
|
{projectDetail && projectDetail.issues_count ? <span className="num">{numFormat(projectDetail.issues_count)}</span> : ""}
|
||||||
</Link>
|
</Link>
|
||||||
</Tooltip>
|
|
||||||
</li>
|
</li>
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
item.menu_name === "pulls" && projectDetail && parseInt(projectDetail.type) !== 2 && platform ?
|
item.menu_name === "pulls" && projectDetail && parseInt(projectDetail.type) !== 2 && platform ?
|
||||||
<li className={pathname==="pulls" ? "active" : ""}>
|
<li className={pathname==="pulls" ? "active" : ""}>
|
||||||
<Link to={{ pathname: `/${owner}/${projectsId}/pulls`, state }}>
|
<Link to={{ pathname: `/${owner}/${projectsId}/pulls`, state }}>
|
||||||
<i className={pathname==="pulls" ? "iconfont icon-hebingqingqiu1 color-grey-3 mr5 font-14":"iconfont icon-hebingqingqiu1 color-grey-6 font-14 mr5"}></i>
|
<i className={"iconfont icon-hebingqingqiu1 color-grey-3 mr5 font-14"}></i>
|
||||||
<span>合并请求</span>
|
<span>合并请求</span>
|
||||||
{projectDetail && projectDetail.pull_requests_count ? <span className="num">{projectDetail.pull_requests_count}</span> : ""}
|
{projectDetail && projectDetail.pull_requests_count ? <span className="num">{numFormat(projectDetail.pull_requests_count)}</span> : ""}
|
||||||
</Link>
|
</Link>
|
||||||
</li>:""
|
</li>:""
|
||||||
}
|
}
|
||||||
|
@ -69,7 +70,7 @@ function DetailBanner({ history,list , owner , projectsId , isManager , url , pa
|
||||||
item.menu_name === "wiki" &&
|
item.menu_name === "wiki" &&
|
||||||
<li className={pathname === "wiki" ? "active" : ""}>
|
<li className={pathname === "wiki" ? "active" : ""}>
|
||||||
<Link to={{ pathname: `/${owner}/${projectsId}/wiki`, state }}>
|
<Link to={{ pathname: `/${owner}/${projectsId}/wiki`, state }}>
|
||||||
<i className={pathname==="wiki" ? "iconfont icon-wiki_icon color-grey-3 mr5 font-14":"iconfont icon-wiki_icon color-grey-6 font-14 mr5"}></i>
|
<i className={"iconfont icon-a-wikiicon1 color-grey-3 mr5 font-14"}></i>
|
||||||
<span>Wiki</span>
|
<span>Wiki</span>
|
||||||
</Link>
|
</Link>
|
||||||
</li>
|
</li>
|
||||||
|
@ -79,29 +80,29 @@ function DetailBanner({ history,list , owner , projectsId , isManager , url , pa
|
||||||
<li className={pathname==="devops" ? "active" : ""}>
|
<li className={pathname==="devops" ? "active" : ""}>
|
||||||
{/* <Link to={{ pathname: `/${owner}/${projectsId}/devops${open_devops ? `/dispose`:""}`, state }}> */}
|
{/* <Link to={{ pathname: `/${owner}/${projectsId}/devops${open_devops ? `/dispose`:""}`, state }}> */}
|
||||||
<Link to={{ pathname: `/${owner}/${projectsId}/devops`, state:{...state,open_devops} }}>
|
<Link to={{ pathname: `/${owner}/${projectsId}/devops`, state:{...state,open_devops} }}>
|
||||||
<i className="iconfont icon-gongzuoliu font-13 mr8"></i>工作流(beta版)
|
<i className="iconfont icon-gongzuoliuicon font-13 mr5 color-grey-3"></i>工作流(beta版)
|
||||||
{projectDetail && projectDetail.ops_count ? <span>{projectDetail.ops_count}</span> : ""}
|
{projectDetail && projectDetail.ops_count ? <span>{projectDetail.ops_count}</span> : ""}
|
||||||
</Link>
|
</Link>
|
||||||
</li>
|
</li>
|
||||||
:""
|
:""
|
||||||
}
|
}
|
||||||
{
|
{/* {
|
||||||
// item.menu_name === "resources" &&
|
item.menu_name === "resources" &&
|
||||||
// <li className={pathname==="source" ? "active" : ""}>
|
<li className={pathname==="source" ? "active" : ""}>
|
||||||
// <Link to={{ pathname: `/${owner}/${projectsId}/source`, state }}>
|
<Link to={{ pathname: `/${owner}/${projectsId}/source`, state }}>
|
||||||
// <i className={pathname==="source" ? "iconfont icon-ziyuanpaihanghetuijian color-grey-3 mr5 font-14":"iconfont icon-ziyuanpaihanghetuijian color-grey-6 font-14 mr5"}></i>
|
<i className={pathname==="source" ? "iconfont icon-ziyuanpaihanghetuijian color-grey-3 mr5 font-14":"iconfont icon-ziyuanpaihanghetuijian color-grey-6 font-14 mr5"}></i>
|
||||||
// <span>资源库</span>
|
<span>资源库</span>
|
||||||
// {projectDetail && projectDetail.source_count ? <span className="num">{projectDetail.source_count}</span> :""}
|
{projectDetail && projectDetail.source_count ? <span className="num">{projectDetail.source_count}</span> :""}
|
||||||
// </Link>
|
</Link>
|
||||||
// </li>
|
</li>
|
||||||
}
|
} */}
|
||||||
{
|
{
|
||||||
item.menu_name === "versions" &&
|
item.menu_name === "versions" &&
|
||||||
<li className={pathname==="milestones" ? "active" : ""}>
|
<li className={pathname==="milestones" ? "active" : ""}>
|
||||||
<Link to={{ pathname: `/${owner}/${projectsId}/milestones`, state }}>
|
<Link to={{ pathname: `/${owner}/${projectsId}/milestones`, state }}>
|
||||||
<i className={pathname==="milestones" ? "iconfont icon-lichengbei color-grey-3 mr5 font-14":"iconfont icon-lichengbei color-grey-6 font-14 mr5"}></i>
|
<i className={pathname==="milestones" ? "iconfont icon-lichengbeiicon color-grey-3 mr5 font-14":"iconfont icon-lichengbeiicon color-grey-6 font-14 mr5"}></i>
|
||||||
<span>里程碑</span>
|
<span>里程碑</span>
|
||||||
{projectDetail && projectDetail.versions_count ? <span className="num">{projectDetail.versions_count}</span> :""}
|
{projectDetail && projectDetail.versions_count ? <span className="num">{numFormat(projectDetail.versions_count)}</span> :""}
|
||||||
</Link>
|
</Link>
|
||||||
</li>
|
</li>
|
||||||
}
|
}
|
||||||
|
@ -109,7 +110,7 @@ function DetailBanner({ history,list , owner , projectsId , isManager , url , pa
|
||||||
item.menu_name === "activity" &&
|
item.menu_name === "activity" &&
|
||||||
<li className={pathname==="activity" ? "active" : ""}>
|
<li className={pathname==="activity" ? "active" : ""}>
|
||||||
<Link to={{ pathname: `/${owner}/${projectsId}/activity`, state }}>
|
<Link to={{ pathname: `/${owner}/${projectsId}/activity`, state }}>
|
||||||
<i className={pathname==="activity" ? "iconfont icon-tongzhi color-grey-3 mr5 font-14":"iconfont icon-tongzhi color-grey-6 font-14 mr5"}></i>
|
<i className={pathname==="activity" ? "iconfont icon-dongtaiicon color-grey-3 mr5 font-14":"iconfont icon-dongtaiicon color-grey-6 font-14 mr5"}></i>
|
||||||
<span>动态</span>
|
<span>动态</span>
|
||||||
</Link>
|
</Link>
|
||||||
</li>
|
</li>
|
||||||
|
@ -118,7 +119,7 @@ function DetailBanner({ history,list , owner , projectsId , isManager , url , pa
|
||||||
item.menu_name === "settings" &&
|
item.menu_name === "settings" &&
|
||||||
<li className={pathname === "settings" ? "active" : ""}>
|
<li className={pathname === "settings" ? "active" : ""}>
|
||||||
<Link to={`/${owner}/${projectsId}/settings`}>
|
<Link to={`/${owner}/${projectsId}/settings`}>
|
||||||
<i className={url && url.indexOf("/settings") > 0 ? "iconfont icon-cangku color-grey-3 mr5 font-14":"iconfont icon-cangku color-grey-6 font-14 mr5"}></i>
|
<i className={url && url.indexOf("/settings") > 0 ? "iconfont icon-cangkushezhiicon color-grey-3 mr5 font-14":"iconfont icon-cangkushezhiicon color-grey-6 font-14 mr5"}></i>
|
||||||
<span>仓库设置</span>
|
<span>仓库设置</span>
|
||||||
</Link>
|
</Link>
|
||||||
</li>
|
</li>
|
||||||
|
|
|
@ -6,7 +6,7 @@ function Invite({code,className}) {
|
||||||
|
|
||||||
return(
|
return(
|
||||||
<div className={className}>
|
<div className={className}>
|
||||||
<span className="font-16 color-grey-6">邀请码</span>
|
<span className="font-16 color-ooo">邀请码</span>
|
||||||
<div>
|
<div>
|
||||||
<input value={code} id="devitecode" style={{width:"62px",border:"none",cursor:"default"}} readOnly/>
|
<input value={code} id="devitecode" style={{width:"62px",border:"none",cursor:"default"}} readOnly/>
|
||||||
<CopyTool timeOut={true} beforeText={<p className="edu-txt-center">可以通过邀请码邀请成员加入项目<br/>点击复制邀请码。</p>} className="ml8 font-16" inputId="devitecode"/>
|
<CopyTool timeOut={true} beforeText={<p className="edu-txt-center">可以通过邀请码邀请成员加入项目<br/>点击复制邀请码。</p>} className="ml8 font-16" inputId="devitecode"/>
|
||||||
|
|
|
@ -0,0 +1,57 @@
|
||||||
|
import React , { useState } from 'react';
|
||||||
|
import { Anchor , Input } from 'antd';
|
||||||
|
import './sub.scss';
|
||||||
|
import { useEffect } from 'react';
|
||||||
|
|
||||||
|
const { Link } = Anchor;
|
||||||
|
|
||||||
|
function ReadmeCatelogue({ menuList , hash }) {
|
||||||
|
const [ goHref , setGoHref ] = useState("");
|
||||||
|
const [ value , setValue ] = useState("");
|
||||||
|
const [ menu , setMenu] = useState(menuList);
|
||||||
|
|
||||||
|
|
||||||
|
function onChange(link){
|
||||||
|
setGoHref(link);
|
||||||
|
};
|
||||||
|
|
||||||
|
function changeValue(e) {
|
||||||
|
setValue(e.target.value);
|
||||||
|
if(e.target.value){
|
||||||
|
let m = menuList.filter(i=>i.text.toLowerCase().indexOf(e.target.value.toLowerCase())>-1);
|
||||||
|
setMenu(m);
|
||||||
|
}else{
|
||||||
|
setMenu(menuList);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return(
|
||||||
|
<div>
|
||||||
|
<div className="searchBox">
|
||||||
|
<Input
|
||||||
|
placeholder={"请输入关键字"}
|
||||||
|
value={value}
|
||||||
|
onChange={changeValue}
|
||||||
|
prefix={<i className="iconfont icon-sousuo_icon1 font-14"></i>}/>
|
||||||
|
</div>
|
||||||
|
{
|
||||||
|
menu && menu.length>0?
|
||||||
|
<div className="anchorBox">
|
||||||
|
<Anchor affix={false} onChange={onChange}>
|
||||||
|
{
|
||||||
|
menu.map((item,key)=>{
|
||||||
|
return(
|
||||||
|
<div style={{paddingLeft:`${item.level *10}px`}} className={goHref===item.href?"items active":"items"}>
|
||||||
|
<Link href={`#${item.text}`} title={item.text} />
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
</Anchor>
|
||||||
|
</div>
|
||||||
|
:""
|
||||||
|
}
|
||||||
|
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
export default ReadmeCatelogue;
|
|
@ -0,0 +1,13 @@
|
||||||
|
import React from 'react';
|
||||||
|
import { Link } from 'react-router-dom';
|
||||||
|
import'./sub.scss'
|
||||||
|
|
||||||
|
function SubMenu({tab,owner,projectsId}) {
|
||||||
|
return(
|
||||||
|
<ul className="subMenu">
|
||||||
|
<Link to={`/${owner}/${projectsId}/tags`} className={tab==="tags"?"active":""}>标签</Link>
|
||||||
|
<Link to={`/${owner}/${projectsId}/releases`} className={tab==="releases"?"active":""}>发行版</Link>
|
||||||
|
</ul>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
export default SubMenu;
|
|
@ -53,7 +53,7 @@ function UpdateDescModal({form , visible , onCancel , onOk,desc,website,lesson_u
|
||||||
{getFieldDecorator("lesson_url",{
|
{getFieldDecorator("lesson_url",{
|
||||||
rules:[]
|
rules:[]
|
||||||
})(
|
})(
|
||||||
<Input placeholder="实践课程链接"/>
|
<Input placeholder="实践课程链接" />
|
||||||
)}
|
)}
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
</Form>
|
</Form>
|
||||||
|
|
|
@ -24,7 +24,68 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.detailsCode{
|
.menuslist{
|
||||||
display: flex;
|
z-index: 100;
|
||||||
justify-content: space-between;
|
width: 297px;
|
||||||
|
background: #FFFFFF;
|
||||||
|
box-shadow: 0px 4px 8px 2px rgba(212, 212, 212, 0.5);
|
||||||
|
border-radius: 4px;
|
||||||
|
.searchBox{
|
||||||
|
padding:15px;
|
||||||
|
border-bottom: 1px solid #eee;
|
||||||
|
}
|
||||||
|
.ant-anchor-wrapper{
|
||||||
|
margin-left: 0px;
|
||||||
|
padding:5px 15px;
|
||||||
|
max-height: 255px!important;
|
||||||
|
.items{
|
||||||
|
border-radius: 4px;
|
||||||
|
margin-bottom: 5px;
|
||||||
|
cursor: pointer;
|
||||||
|
.ant-anchor-link-title{
|
||||||
|
color: #333333!important;
|
||||||
|
}
|
||||||
|
&:hover{
|
||||||
|
background-color: #F3F4F6;
|
||||||
|
}
|
||||||
|
&.active{
|
||||||
|
background-color: #2A61FF;
|
||||||
|
.ant-anchor-link-title{
|
||||||
|
color: #fff!important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.ant-anchor-link{
|
||||||
|
padding:0px;
|
||||||
|
height: 30px;
|
||||||
|
line-height: 30px;
|
||||||
|
}
|
||||||
|
.ant-anchor-ink::before{
|
||||||
|
background-color: #fff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.subMenu{
|
||||||
|
display: flex;
|
||||||
|
padding-top: 30px;
|
||||||
|
a{
|
||||||
|
width: 83px;
|
||||||
|
font-weight: 500;
|
||||||
|
line-height: 30px;
|
||||||
|
height: 32px;
|
||||||
|
color: #333333!important;
|
||||||
|
text-align: center;
|
||||||
|
border: 1px solid #D0D0D0;
|
||||||
|
border-radius: 0px 4px 4px 0px;
|
||||||
|
background: rgba(250, 251, 252, 0);
|
||||||
|
&:first-child{
|
||||||
|
border-right: none;
|
||||||
|
border-radius: 4px 0px 0px 4px;
|
||||||
|
}
|
||||||
|
&.active{
|
||||||
|
background-color: #466AFF;
|
||||||
|
color: #fff!important;
|
||||||
|
border-color: #466AFF;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -0,0 +1,138 @@
|
||||||
|
import React,{ useEffect , useState } from 'react';
|
||||||
|
import SubMenu from '../sub/SubMenu';
|
||||||
|
import { Table , Tooltip , Spin } from 'antd';
|
||||||
|
import axios from 'axios';
|
||||||
|
import { Link } from 'react-router-dom';
|
||||||
|
import { truncateCommitId } from '../../common/util';
|
||||||
|
import { getImageUrl } from 'educoder';
|
||||||
|
import Nonedata from '../../Nodata';
|
||||||
|
import './Index.scss';
|
||||||
|
import Tree from '../img/tree.png'
|
||||||
|
import moment from 'moment';
|
||||||
|
|
||||||
|
function Tags(props) {
|
||||||
|
|
||||||
|
const [ source , setSource ] = useState(undefined);
|
||||||
|
const [ isSpin , setIsSpin ] = useState(true);
|
||||||
|
|
||||||
|
const { projectsId , owner } = props.match.params;
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (projectsId) {
|
||||||
|
const url = `/${owner}/${projectsId}/tags.json`;
|
||||||
|
axios.get(url).then((result) => {
|
||||||
|
if (result) {
|
||||||
|
setSource(result.data);
|
||||||
|
setIsSpin(false);
|
||||||
|
}
|
||||||
|
}).catch(error => {})
|
||||||
|
}
|
||||||
|
}, [owner, projectsId]);
|
||||||
|
|
||||||
|
const columns=[
|
||||||
|
{
|
||||||
|
title:"标签名",
|
||||||
|
dataIndex:"name",
|
||||||
|
key:1,
|
||||||
|
ellipsis:true,
|
||||||
|
width:"200px",
|
||||||
|
render:(txt,item)=>{
|
||||||
|
return(
|
||||||
|
<div className="tagBranch">
|
||||||
|
<Link className="hover tagClass" to={`/${owner}/${projectsId}/tree/${item.name}`}>{item.name}</Link>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title:"创建时间",
|
||||||
|
dataIndex:"time_ago",
|
||||||
|
key:2,
|
||||||
|
ellipsis:true,
|
||||||
|
render:(txt,item)=>{
|
||||||
|
return (
|
||||||
|
<span className="color-grey-3 tagModel">
|
||||||
|
{
|
||||||
|
item.tagger &&
|
||||||
|
<Tooltip placement="top" title={item.tagger.name}>
|
||||||
|
{
|
||||||
|
item.tagger.id ?
|
||||||
|
<Link className="mr3 tagModelImg" to={`/${item.tagger.login}`} >
|
||||||
|
<img src={getImageUrl(`/${item.tagger && item.tagger.image_url}`)} alt=""/>
|
||||||
|
</Link>
|
||||||
|
:
|
||||||
|
<span className="mr3 tagModelImg" style={{cursor:"default"}}>
|
||||||
|
<img src={getImageUrl(`/${item.tagger && item.tagger.image_url}`)} alt=""/>
|
||||||
|
</span>
|
||||||
|
}
|
||||||
|
</Tooltip>
|
||||||
|
}
|
||||||
|
<span>创建于{txt}</span>
|
||||||
|
</span>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title:"提交ID",
|
||||||
|
dataIndex:"id",
|
||||||
|
key:3,
|
||||||
|
ellipsis:true,
|
||||||
|
render:(txt,item)=>{
|
||||||
|
return (
|
||||||
|
<Tooltip placement="top" title={`最后提交日期:${item.created_at_unix ? moment(item.created_at_unix*1000).format('YYYY-MM-DD'):''}`}>
|
||||||
|
<img src={Tree} alt="提交ID" width="22px" className="mr4"/>
|
||||||
|
<Link className="hover color-blue" to={`/${owner}/${projectsId}/commits/${truncateCommitId(`${item.id}`)}`}>{truncateCommitId(item.id)}</Link>
|
||||||
|
</Tooltip>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title:"描述信息",
|
||||||
|
dataIndex:"message",
|
||||||
|
key:4,
|
||||||
|
ellipsis:true,
|
||||||
|
render:(txt,item)=>{
|
||||||
|
return item.message || "--"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title:"下载",
|
||||||
|
dataIndex:"stage_type",
|
||||||
|
key:5,
|
||||||
|
ellipsis:true,
|
||||||
|
align:"center",
|
||||||
|
width:"204px",
|
||||||
|
render:(txt,item)=>{
|
||||||
|
return (
|
||||||
|
<React.Fragment>
|
||||||
|
<a href={`${item.tarball_url}`} download className="btn-83">
|
||||||
|
<i className="iconfont icon-xiazai-icon font-16 mr5"></i>TAR
|
||||||
|
</a>
|
||||||
|
<a href={`${item.zipball_url}`} download className="btn-83">
|
||||||
|
<i className="iconfont icon-xiazai-icon font-16 mr5"></i>ZIP
|
||||||
|
</a>
|
||||||
|
</React.Fragment>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
return(
|
||||||
|
<div>
|
||||||
|
<SubMenu tab={"tags"} projectsId={projectsId} owner={owner}/>
|
||||||
|
<Spin spinning={isSpin}>
|
||||||
|
<div className="tagSpin">
|
||||||
|
{
|
||||||
|
source && source.length > 0 &&
|
||||||
|
<Table
|
||||||
|
className="tagTable"
|
||||||
|
dataSource={source} columns={columns} pagination={false}></Table>
|
||||||
|
}
|
||||||
|
{
|
||||||
|
source && source.length === 0 && <Nonedata _html={'暂无数据~'}/>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
</Spin>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
export default Tags;
|
|
@ -0,0 +1,58 @@
|
||||||
|
.tagTable{
|
||||||
|
margin-top: 30px;
|
||||||
|
thead{
|
||||||
|
tr th{
|
||||||
|
background-color: #fff;
|
||||||
|
padding:5px 0px;
|
||||||
|
width: 172px;
|
||||||
|
.ant-table-column-title{
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 500;
|
||||||
|
color: #333333;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
tbody{
|
||||||
|
.btn-83{
|
||||||
|
margin:0px 8px;
|
||||||
|
}
|
||||||
|
tr{
|
||||||
|
&:hover td{
|
||||||
|
background-color: #fff!important;
|
||||||
|
}
|
||||||
|
td{
|
||||||
|
padding:0px;
|
||||||
|
height: 69px;
|
||||||
|
line-height: 69px;
|
||||||
|
color:#333333;
|
||||||
|
div{
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&:last-child{
|
||||||
|
td{
|
||||||
|
border-bottom: none!important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.tagSpin{
|
||||||
|
min-height: 300px;
|
||||||
|
}
|
||||||
|
.tagBranch{
|
||||||
|
padding-right: 15px;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
overflow: hidden;
|
||||||
|
.tagClass{
|
||||||
|
color:#333333;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.tagModel{
|
||||||
|
font-weight: 400;
|
||||||
|
.tagModelImg img{
|
||||||
|
width: 25px;
|
||||||
|
height: 25px;
|
||||||
|
border-radius: 50%;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,114 @@
|
||||||
|
import React , { useEffect , useState } from 'react';
|
||||||
|
import CopyTool from '../../Component/CopyTool';
|
||||||
|
import { truncateCommitId } from '../../common/util';
|
||||||
|
import { Link } from 'react-router-dom';
|
||||||
|
import { getImageUrl } from 'educoder';
|
||||||
|
import { Dropdown , Menu , Spin } from 'antd';
|
||||||
|
import './Index.scss';
|
||||||
|
|
||||||
|
import Tree from '../img/tree.png';
|
||||||
|
import Axios from 'axios';
|
||||||
|
|
||||||
|
function turnbar(str){
|
||||||
|
if(str && str.length>0 && str.indexOf("/")>-1){
|
||||||
|
return str.replaceAll('/','%2F');
|
||||||
|
}
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
function Index(props) {
|
||||||
|
const [ list , setList ] = useState([]);
|
||||||
|
const [ isSpin , setIsSpin ] = useState(true);
|
||||||
|
|
||||||
|
const { projectsId , owner } = props.match.params;
|
||||||
|
const { isManager , isDeveloper , projectDetail } = props;
|
||||||
|
|
||||||
|
useEffect(()=>{
|
||||||
|
getList();
|
||||||
|
},[])
|
||||||
|
|
||||||
|
|
||||||
|
const menu =(zip_url,tar_url)=> (
|
||||||
|
<Menu>
|
||||||
|
<Menu.Item key={'0'}><a href={zip_url}>ZIP</a></Menu.Item>
|
||||||
|
<Menu.Item key={'1'}><a href={tar_url}>TAR.GZ</a></Menu.Item>
|
||||||
|
</Menu>
|
||||||
|
)
|
||||||
|
|
||||||
|
function getList() {
|
||||||
|
const url = `/${owner}/${projectsId}/branches_slice.json`;
|
||||||
|
Axios.get(url).then(result=>{
|
||||||
|
if(result){
|
||||||
|
setList(result.data);
|
||||||
|
}
|
||||||
|
setIsSpin(false);
|
||||||
|
}).catch(error=>{setIsSpin(false);})
|
||||||
|
}
|
||||||
|
|
||||||
|
return(
|
||||||
|
<Spin spinning={isSpin}>
|
||||||
|
<div style={{paddingTop:"10px",minHeight:"400px"}}>
|
||||||
|
{
|
||||||
|
list && list.length>0 && list.map((item,key)=>{
|
||||||
|
return(
|
||||||
|
<React.Fragment>
|
||||||
|
<p className="branchSort">{item.branch_type === "default" ? "默认分支" : item.branch_type==="protected"?"保护分支":"其它分支"}</p>
|
||||||
|
{
|
||||||
|
item.list && item.list.length>0 &&
|
||||||
|
<ul className="treeUl">
|
||||||
|
{
|
||||||
|
item.list.map((i,k)=>{
|
||||||
|
let last_commit = i.last_commit;
|
||||||
|
return(
|
||||||
|
<li>
|
||||||
|
<div className="treeinfo">
|
||||||
|
<Link to={`/${owner}/${projectsId}/tree/${turnbar(i.name)}`} className="task-hide">{i.name}</Link>
|
||||||
|
<div>
|
||||||
|
{
|
||||||
|
last_commit && last_commit.committer && last_commit.committer.id?
|
||||||
|
<Link to={`/${ last_commit.committer.login}`}>
|
||||||
|
<img style={{borderRadius:"50%"}} src={getImageUrl(`/${ last_commit.committer.image_url}`)} alt=""/>
|
||||||
|
<span className="mr3 color-grey-3" style={{fontWeight:"500"}}>{last_commit && last_commit.committer && last_commit.committer.name}</span>
|
||||||
|
</Link>
|
||||||
|
:
|
||||||
|
<React.Fragment>
|
||||||
|
<img style={{borderRadius:"50%"}} src={getImageUrl(`/${ last_commit.committer.image_url}`)} alt=""/>
|
||||||
|
<span className="mr3 color-grey-3" style={{fontWeight:"500"}}>{last_commit && last_commit.committer && last_commit.committer.name}</span>
|
||||||
|
</React.Fragment>
|
||||||
|
}
|
||||||
|
<span className="color-grey-3">更新于{last_commit && last_commit.time_from_now}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="treecopy">
|
||||||
|
<div>
|
||||||
|
<span>
|
||||||
|
<img src={Tree} alt="sha" width={"16px"}/>
|
||||||
|
<Link to={`/${owner}/${projectsId}/commits/${truncateCommitId(last_commit && last_commit.sha)}`}>{truncateCommitId(last_commit && last_commit.sha)}</Link>
|
||||||
|
<input type="text" id={`value${key}${k}`} value={`${truncateCommitId(last_commit && last_commit.sha)}`}/>
|
||||||
|
</span>
|
||||||
|
<CopyTool beforeText="复制commit id" afterText="复制成功" inputId={`value${key}${k}`}/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="treeabout">
|
||||||
|
{
|
||||||
|
(isManager || isDeveloper) && (projectDetail && projectDetail.type!==2) &&
|
||||||
|
<Link to={`/${owner}/${projectsId}/compare/master...${i.name}`} className="btn-83">+ 合并请求</Link>
|
||||||
|
}
|
||||||
|
<Dropdown overlay={menu(i.zip_url,i.tar_url)} trigger={['click']} placement="bottomRight">
|
||||||
|
<a className="btn-83 ml15">下载<i className="iconfont icon-sanjiaoxing-down font-14"></i></a>
|
||||||
|
</Dropdown>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
</ul>
|
||||||
|
}
|
||||||
|
</React.Fragment>
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
</Spin>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
export default Index;
|
|
@ -0,0 +1,101 @@
|
||||||
|
.branchSort{
|
||||||
|
font-weight: 500;
|
||||||
|
color: #333333;
|
||||||
|
font-size: 15px;
|
||||||
|
height: 20px;
|
||||||
|
line-height: 20px;
|
||||||
|
padding-left: 10px;
|
||||||
|
margin-top: 20px;
|
||||||
|
margin-bottom: 6px!important;
|
||||||
|
}
|
||||||
|
.treeUl{
|
||||||
|
background: #FAFCFF;
|
||||||
|
border-radius: 4px;
|
||||||
|
border: 1px solid rgba(42, 97, 255, 0.23);
|
||||||
|
li{
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
padding: 12px 20px;
|
||||||
|
border-bottom: 1px solid rgba(42, 97, 255, 0.23);
|
||||||
|
&:last-child{
|
||||||
|
border-bottom: none;
|
||||||
|
}
|
||||||
|
.treeinfo{
|
||||||
|
width: 399px;
|
||||||
|
flex:1;
|
||||||
|
flex-direction: column;
|
||||||
|
&>a{
|
||||||
|
display: block;
|
||||||
|
width: 399px;
|
||||||
|
|
||||||
|
}
|
||||||
|
a:hover{
|
||||||
|
span{
|
||||||
|
color: #466AFF!important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
img{
|
||||||
|
height: 20px;
|
||||||
|
width: 20px;
|
||||||
|
margin-right: 5px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.treeabout{
|
||||||
|
flex:1;
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.treecopy{
|
||||||
|
flex:1;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
&>div{
|
||||||
|
height: 32px;
|
||||||
|
background: #FAFBFC;
|
||||||
|
border-radius: 4px;
|
||||||
|
border: 1px solid #D0D0D0;
|
||||||
|
position: relative;
|
||||||
|
z-index: 1;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
&>span{
|
||||||
|
padding:0px 15px;
|
||||||
|
border-right: 1px solid rgba(153, 153, 153, 0.4);
|
||||||
|
height: 100%;
|
||||||
|
img{
|
||||||
|
margin-right: 4px;
|
||||||
|
}
|
||||||
|
a{
|
||||||
|
color: #466AFF;
|
||||||
|
&:hover{
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&>i{
|
||||||
|
margin:0px 12px;
|
||||||
|
color: #333!important;
|
||||||
|
}
|
||||||
|
input{
|
||||||
|
position: absolute;
|
||||||
|
z-index: 0;
|
||||||
|
opacity: 0;
|
||||||
|
top: 32px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.new-conmmit{
|
||||||
|
width: 30px;
|
||||||
|
height: 18px;
|
||||||
|
line-height: 18px;
|
||||||
|
display: block;
|
||||||
|
background: #FF6832;
|
||||||
|
color: white;
|
||||||
|
font-size: 12px;
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
|
.icon-a-yuanquan2x{
|
||||||
|
color: #466AFF;
|
||||||
|
}
|
|
@ -0,0 +1,22 @@
|
||||||
|
import { Button } from 'antd';
|
||||||
|
import React from 'react';
|
||||||
|
import './version.scss';
|
||||||
|
|
||||||
|
function Empty({operation,addFunc}) {
|
||||||
|
return(
|
||||||
|
<div className="emptyPanel color-grey-3">
|
||||||
|
<i className="iconfont icon-banbenicon font-50 color-grey-3" style={{height:"50px",lineHeight:"50px",marginBottom:"13px"}}></i>
|
||||||
|
<span className="weight font-26 mb15">这里暂未发布过任何版本</span>
|
||||||
|
<span className="weight400" style={{textAlign:"center",lineHeight:"20px"}}>发行版功能基于仓库中的历史标记<br/>建议使用类似 V1.0 的版本标记作为发布点</span>
|
||||||
|
<div className="operation">
|
||||||
|
{
|
||||||
|
operation ?
|
||||||
|
<Button type={"primary"} onClick={addFunc} className="btnblue" style={{width:"118px",height:"36px"}}>发布新版本</Button>
|
||||||
|
:
|
||||||
|
<span className="color-grey-3 weight font-16">该项目暂时没有发布版本</span>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
export default Empty;
|
|
@ -0,0 +1,41 @@
|
||||||
|
import React from 'react';
|
||||||
|
import { Switch , Route } from 'react-router';
|
||||||
|
import Loadable from 'react-loadable';
|
||||||
|
import Loading from '../../../Loading';
|
||||||
|
import SubMenu from '../sub/SubMenu';
|
||||||
|
import "./version.scss";
|
||||||
|
|
||||||
|
const CoderRootVersion = Loadable({
|
||||||
|
loader: () => import('./version'),
|
||||||
|
loading: Loading,
|
||||||
|
})
|
||||||
|
const CoderRootVersionNew = Loadable({
|
||||||
|
loader: () => import('./New'),
|
||||||
|
loading: Loading,
|
||||||
|
})
|
||||||
|
function Index(props) {
|
||||||
|
const { projectsId , owner } = props.match.params;
|
||||||
|
return(
|
||||||
|
<div>
|
||||||
|
<SubMenu tab={"releases"} projectsId={projectsId} owner={owner}/>
|
||||||
|
<Switch>
|
||||||
|
<Route path="/:owner/:projectsId/releases/:versionId/update"
|
||||||
|
render={
|
||||||
|
(p) => (<CoderRootVersionNew {...props} {...p} />)
|
||||||
|
}
|
||||||
|
></Route>
|
||||||
|
<Route path="/:owner/:projectsId/releases/new"
|
||||||
|
render={
|
||||||
|
(p) => (<CoderRootVersionNew {...props} {...p} />)
|
||||||
|
}
|
||||||
|
></Route>
|
||||||
|
<Route path="/:owner/:projectsId/releases"
|
||||||
|
render={
|
||||||
|
(p) => (<CoderRootVersion {...props} {...p} />)
|
||||||
|
}
|
||||||
|
></Route>
|
||||||
|
</Switch>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
export default Index;
|
|
@ -0,0 +1,266 @@
|
||||||
|
import React, { useState, useEffect, forwardRef } from "react";
|
||||||
|
import styled from "styled-components";
|
||||||
|
import { AutoComplete , Input, Checkbox, Button, Form } from "antd";
|
||||||
|
import SelectBranch from '../../Branch/Select';
|
||||||
|
|
||||||
|
import Editor from "../../../modules/tpm/challengesnew/tpm-md-editor";
|
||||||
|
import Upload from "../../Upload/Index";
|
||||||
|
import Attachments from "../../Upload/attachment";
|
||||||
|
import axios from "axios";
|
||||||
|
import "./version.scss";
|
||||||
|
import { trim } from "lodash";
|
||||||
|
|
||||||
|
const { Option } = AutoComplete;
|
||||||
|
|
||||||
|
const Span = styled.span`
|
||||||
|
margin: 0px 15px;
|
||||||
|
color: #bbb;
|
||||||
|
line-height: 35px;
|
||||||
|
font-size:16px;
|
||||||
|
font-weight:400;
|
||||||
|
color:#666;
|
||||||
|
`;
|
||||||
|
export default Form.create()(
|
||||||
|
forwardRef(
|
||||||
|
(
|
||||||
|
{ form, projectDetail , match, showNotification, history },
|
||||||
|
ref
|
||||||
|
) => {
|
||||||
|
const { getFieldDecorator, validateFields, setFieldsValue } = form;
|
||||||
|
const [tagList, setTagList] = useState(undefined);
|
||||||
|
const [desc, setDesc] = useState(null);
|
||||||
|
const [branch, setBranch ] = useState(null);
|
||||||
|
const [fileList, setFileList] = useState(undefined);
|
||||||
|
const [attachment, setAttachment] = useState(undefined);
|
||||||
|
const [options , setOptions] = useState(undefined);
|
||||||
|
const stable = history && history.location && history.location.state.stable;
|
||||||
|
const { projectsId, versionId , owner } = match.params;
|
||||||
|
|
||||||
|
useEffect(()=>{
|
||||||
|
if(projectDetail && projectDetail.default_branch){
|
||||||
|
setBranch(projectDetail.default_branch);
|
||||||
|
}
|
||||||
|
},[projectDetail])
|
||||||
|
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (versionId) {
|
||||||
|
const url = `/${owner}/${projectsId}/releases/${versionId}/edit.json`;
|
||||||
|
axios.get(url).then(result => {
|
||||||
|
if (result) {
|
||||||
|
setFieldsValue(result.data);
|
||||||
|
setDesc(result.data.body);
|
||||||
|
setAttachment(result.data.attachments);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, [versionId]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (projectsId) {
|
||||||
|
const url = `/${owner}/${projectsId}/tags.json`;
|
||||||
|
axios
|
||||||
|
.get(url,{params:{
|
||||||
|
limit:1000
|
||||||
|
}})
|
||||||
|
.then(result => {
|
||||||
|
if (result) {
|
||||||
|
setTagList(result.data);
|
||||||
|
setOptions(renderTagList(result.data));
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
console.log(error);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, [projectsId]);
|
||||||
|
|
||||||
|
function renderTagList(list) {
|
||||||
|
if (list) {
|
||||||
|
let array = list.map((item, key) => {
|
||||||
|
return (
|
||||||
|
<Option key={key} value={item.name}>
|
||||||
|
{item.name}
|
||||||
|
</Option>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
return array || undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function submit() {
|
||||||
|
validateFields((err, value) => {
|
||||||
|
if(err)return;
|
||||||
|
if (versionId) {
|
||||||
|
let url = `/${owner}/${projectsId}/releases/${versionId}.json`;
|
||||||
|
axios
|
||||||
|
.put(url, {
|
||||||
|
...value,
|
||||||
|
body: desc,
|
||||||
|
attachment_ids: fileList,
|
||||||
|
target_commitish:branch
|
||||||
|
})
|
||||||
|
.then(result => {
|
||||||
|
if (result) {
|
||||||
|
showNotification("版本修改成功!");
|
||||||
|
history.push(`/${owner}/${projectsId}/releases`);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
let url = `/${owner}/${projectsId}/releases.json`;
|
||||||
|
axios.post(url, {
|
||||||
|
...value,
|
||||||
|
body: desc,
|
||||||
|
attachment_ids: fileList
|
||||||
|
})
|
||||||
|
.then(result => {
|
||||||
|
if (result) {
|
||||||
|
showNotification("版本发布成功!");
|
||||||
|
history.push(`/${owner}/${projectsId}/releases`);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
// 输入标签名
|
||||||
|
function changeAuto(value){
|
||||||
|
let l = tagList.filter(item=>item.name.indexOf(value) > -1);
|
||||||
|
setOptions(renderTagList(l));
|
||||||
|
}
|
||||||
|
|
||||||
|
function changeBranch(params) {
|
||||||
|
setBranch(params);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="df pt15">
|
||||||
|
<Form className="versionForm">
|
||||||
|
<div className="itemInline">
|
||||||
|
<Form.Item>
|
||||||
|
{getFieldDecorator("tag_name",
|
||||||
|
{ rules:[
|
||||||
|
{ required: true, message: "请输入获取或选择一个标签" },
|
||||||
|
{ validator: (rule,val,callback) =>{
|
||||||
|
if(val.length>30 || val.indexOf(' ')>0 || val.match(/^\s+$/) || trim(val).length!=val.length){
|
||||||
|
callback('无效的标签名称,请参考右侧建议命名标签并确认长度在1~30个字符之间');
|
||||||
|
}else{
|
||||||
|
callback();
|
||||||
|
}
|
||||||
|
}}],
|
||||||
|
validateFirst: true
|
||||||
|
})(
|
||||||
|
<AutoComplete
|
||||||
|
placeholder="标记一个版本"
|
||||||
|
onChange={changeAuto}
|
||||||
|
style={{ width: "200px" }}
|
||||||
|
>
|
||||||
|
{options}
|
||||||
|
</AutoComplete>
|
||||||
|
)}
|
||||||
|
</Form.Item>
|
||||||
|
<Span>@</Span>
|
||||||
|
<SelectBranch
|
||||||
|
repo_id={projectDetail && projectDetail.repo_id}
|
||||||
|
projectsId={projectsId}
|
||||||
|
branch={branch}
|
||||||
|
changeBranch={changeBranch}
|
||||||
|
owner={owner}
|
||||||
|
history={history}
|
||||||
|
tagflag={false}
|
||||||
|
branchList={projectDetail && projectDetail.branches && projectDetail.branches.list}
|
||||||
|
></SelectBranch>
|
||||||
|
<p className="font-12 color-grey-6 weight400">选择一个已经存在的标签,或者在发布时新建一个标签</p>
|
||||||
|
</div>
|
||||||
|
<Form.Item className="pt20">
|
||||||
|
{getFieldDecorator("name",
|
||||||
|
{ rules:[
|
||||||
|
{ required: true, message: "请输入发行版的标题" },
|
||||||
|
{ validator: (rule,val,callback) =>{
|
||||||
|
if(val.length>50){
|
||||||
|
callback('标题长度在1~50个字符之间');
|
||||||
|
}else{
|
||||||
|
callback();
|
||||||
|
}
|
||||||
|
}}],
|
||||||
|
validateFirst: true
|
||||||
|
})(
|
||||||
|
<Input placeholder="发行版的标题" />
|
||||||
|
)}
|
||||||
|
</Form.Item>
|
||||||
|
<Editor
|
||||||
|
placeholder={"描述此发行版"}
|
||||||
|
height={200}
|
||||||
|
mdID={`version-comments-description`}
|
||||||
|
initValue={desc}
|
||||||
|
onChange={setDesc}
|
||||||
|
noStorage={true}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<div className="mt5 dragBox">
|
||||||
|
<Upload
|
||||||
|
className="versionStyle"
|
||||||
|
isComplete={true}
|
||||||
|
load={setFileList}
|
||||||
|
icon={
|
||||||
|
<i className="iconfont icon-shangchuanicon dragIcon" />
|
||||||
|
}
|
||||||
|
size={100}
|
||||||
|
showNotification={showNotification}
|
||||||
|
/>
|
||||||
|
{versionId && attachment && attachment.length > 0 ? (
|
||||||
|
<Attachments
|
||||||
|
attachments={attachment}
|
||||||
|
showNotification={showNotification}
|
||||||
|
canDelete={true}
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
""
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
<Form.Item className="prerelease">
|
||||||
|
{getFieldDecorator("prerelease",
|
||||||
|
{ rules:[],
|
||||||
|
validateFirst: true
|
||||||
|
})(
|
||||||
|
<Checkbox defaultChecked={!stable}>这是一个预览版本</Checkbox>
|
||||||
|
)}
|
||||||
|
</Form.Item>
|
||||||
|
<p className="pt20" style={{borderTop:"1px solid #eee"}}>
|
||||||
|
<Button onClick={submit} type="primary" className="mr30 btnblue">
|
||||||
|
{versionId ? "保存" : "创建"}发行版
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
onClick={() =>history.push(`/${owner}/${projectsId}/releases`)} className="btngrey"
|
||||||
|
>取消</Button>
|
||||||
|
</p>
|
||||||
|
</Form>
|
||||||
|
<div className="versionTips">
|
||||||
|
<div className="infosTip">
|
||||||
|
<p className="font-16 mb14 weight">标签命名建议</p>
|
||||||
|
<p className="mb15">
|
||||||
|
通常的做法是在版本名称前加上字母 v 前缀, v1.0 或者 v2.3.4。
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
如果标签不适合在生产环境下使用,请在版本名称后添加预发行版本。例如:v0.2-alpha
|
||||||
|
或者 v5.9-beta.3。
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div className="infosTip">
|
||||||
|
<p className="font-16 mb14 weight">语义化版本</p>
|
||||||
|
<p>
|
||||||
|
如果你是第一次发布版本,我们强烈建议你阅读<a href='https://semver.org/lang/zh-CN' target='_blank' className="color-blue">语义化版本</a>。
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div className="infosTip">
|
||||||
|
<p className="font-16 mb14 weight">附件大小说明</p>
|
||||||
|
<p>
|
||||||
|
单个附件不能超过 100M(GVP 项目200M),每个仓库总附件不可超过
|
||||||
|
1G(推荐项目不可超过 5G;GVP 项目不可超过
|
||||||
|
20G)。附件总容量统计包括仓库附件和发行版附件。
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
)
|
||||||
|
);
|
|
@ -0,0 +1,150 @@
|
||||||
|
import React, { useEffect , useState } from "react";
|
||||||
|
import { Link } from 'react-router-dom';
|
||||||
|
import { Spin , Button } from 'antd';
|
||||||
|
import { getImageUrl } from 'educoder';
|
||||||
|
import {truncateCommitId} from '../../common/util';
|
||||||
|
import Empty from './Empty';
|
||||||
|
import './version.scss';
|
||||||
|
import axios from 'axios';
|
||||||
|
import Tree from '../img/tree-black.png';
|
||||||
|
import RenderHtml from '../../../components/render-html';
|
||||||
|
import User from "../../Component/User";
|
||||||
|
|
||||||
|
function version(props) {
|
||||||
|
const [ data , setData ] = useState(undefined);
|
||||||
|
const [ releases , setReleases ] = useState(undefined);
|
||||||
|
const [ isSpin , setIsSpin ] = useState(true);
|
||||||
|
const { projectsId ,owner } = props.match.params;
|
||||||
|
const { location } = props;
|
||||||
|
const type = props.projectDetail && props.projectDetail.type;
|
||||||
|
const turnFromNew = location && location.query && location.query.turnFromNew;
|
||||||
|
useEffect(()=>{
|
||||||
|
getIssueList();
|
||||||
|
},[])
|
||||||
|
// 获取列表数据
|
||||||
|
function getIssueList(){
|
||||||
|
const url = `/${owner}/${projectsId}/releases.json`;
|
||||||
|
axios.get(url).then((result) => {
|
||||||
|
if (result) {
|
||||||
|
setData(result.data);
|
||||||
|
const { releases = [] } = result.data;
|
||||||
|
//默认第一个展开(body参数)
|
||||||
|
releases.length && (releases[0].bodyshow = true);
|
||||||
|
setReleases(result.data.releases);
|
||||||
|
setIsSpin(false);
|
||||||
|
}
|
||||||
|
}).catch((error) => {
|
||||||
|
console.log(error);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
// 显示版本描述
|
||||||
|
function showBody(key,flag){
|
||||||
|
var lists = releases.concat();
|
||||||
|
lists[key].bodyshow = !flag ? true : false;
|
||||||
|
lists.splice();
|
||||||
|
setReleases(lists);
|
||||||
|
}
|
||||||
|
//删除
|
||||||
|
function deleteRelease(releaseId) {
|
||||||
|
if(releaseId){
|
||||||
|
axios.delete(`/${owner}/${projectsId}/releases/${releaseId}.json`).then((result)=>{
|
||||||
|
if(result){
|
||||||
|
getIssueList();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function release(item,key){
|
||||||
|
return (
|
||||||
|
<div className="versionInfo" key={key}>
|
||||||
|
<span className="versionInfo_left">
|
||||||
|
<span className={`${item.draft === "稳定" ?"versionTag green":"versionTag orange"}`}>{item.draft}</span>
|
||||||
|
<span className="color-grey-3 mt15 font-12">
|
||||||
|
<i className="iconfont icon-biaoqianicon mr3 font-14"></i>
|
||||||
|
<Link className="hover" to={`/${owner}/${projectsId}/tree/${item.tag_name}`} >{item.tag_name}</Link>
|
||||||
|
</span>
|
||||||
|
<span className="color-grey-3 font-12">
|
||||||
|
<img src={Tree} width="16px" color="#333333" className="mr3"/>
|
||||||
|
<Link className="hover" to={`/${owner}/${projectsId}/commits/${truncateCommitId(`${item.sha}`)}`}>{truncateCommitId(item.sha)}</Link>
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
<div className="versionInfo_right">
|
||||||
|
<div className="versionName">
|
||||||
|
<Link to={`/${owner}/${projectsId}/tree/${item.tag_name}`} className="task-hide color-blue hover font-18">{item.name}</Link>
|
||||||
|
<span>
|
||||||
|
{data && data.user_admin_permission && type !== 2 && <Link to={{pathname:`/${owner}/${projectsId}/releases/${item.version_id}/update`,state:{"stable":item.draft==="稳定"}}} className="ml15"><i className="iconfont icon-a-bianji1 font-16 color-grey-6"></i></Link>}
|
||||||
|
{data && data.user_admin_permission && type !== 2 && <i className ="iconfont icon-shanchuicon1 font-16 ml15" onClick={()=>{deleteRelease(item.version_id)}}></i>}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<span className="color-grey-3 mb15 version-user">
|
||||||
|
<i className={`${item.bodyshow ? "iconfont icon-sanjiaoxing-down color-grey-8 mr3 font-14":"iconfont icon-triangle color-grey-8 mr3 font-14"}`} onClick={()=>showBody(key,item.bodyshow)}></i>
|
||||||
|
<User
|
||||||
|
id={item.id}
|
||||||
|
url={(item.image_url && getImageUrl(`/${item.image_url}`)) || "https://dss3.bdstatic.com/70cFv8Sh_Q1YnxGkpoWK1HF6hhy/it/u=3025493530,1989042357&fm=26&gp=0.jpg"}
|
||||||
|
name={item.user_name}
|
||||||
|
login={item.user_login}
|
||||||
|
/>
|
||||||
|
<span className="ml5">发布于{item.created_at}</span>
|
||||||
|
</span>
|
||||||
|
{
|
||||||
|
item.bodyshow &&
|
||||||
|
<div className="body-show">
|
||||||
|
<RenderHtml className="break_word_comments imageLayerParent" value={item.body || ''} url={props.history.location}/>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
<RenderHtml />
|
||||||
|
<p className="versionFile">
|
||||||
|
{/* 发行版附件下载 */}
|
||||||
|
{item.attachments && item.attachments.map((item)=>{
|
||||||
|
return(<a href={item.url}><i className="iconfont icon-wenjian7 font-14 mr10 color-grey-3"></i>下载 {item.title}</a>)
|
||||||
|
})}
|
||||||
|
{/* 发行版下载包 */}
|
||||||
|
<a href={item.tarball_url}><i className="iconfont icon-wenjian7 font-14 mr10 color-grey-3"></i>下载 {item.tag_name}.TAR.gz</a>
|
||||||
|
<a href={item.zipball_url}><i className="iconfont icon-wenjian7 font-14 mr10 color-grey-3"></i>下载 {item.tag_name}.ZIP</a>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
function renderList(releases){
|
||||||
|
if (releases && releases.length > 0) {
|
||||||
|
return (
|
||||||
|
<React.Fragment>
|
||||||
|
{
|
||||||
|
data && data.user_admin_permission && type !== 2 &&
|
||||||
|
<div className="addReleaseBtn">
|
||||||
|
<Button type={"primary"} onClick={addFunc} className="btnblue" style={{height:"36px"}}>发布新版本</Button>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
<div>
|
||||||
|
{!turnFromNew ? releases.map((item, key) => release(item,key)) : release(releases[0],0)}
|
||||||
|
</div>
|
||||||
|
</React.Fragment>
|
||||||
|
)
|
||||||
|
} else if (releases && releases.length === 0) {
|
||||||
|
return (
|
||||||
|
<Empty
|
||||||
|
operation={data && data.user_admin_permission && type !== 2}
|
||||||
|
addFunc={addFunc}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
} else{
|
||||||
|
return (<div></div>)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function addFunc(){
|
||||||
|
props.history.push({pathname:`/${owner}/${projectsId}/releases/new`,state:{stable:true}});
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="releaseIndex">
|
||||||
|
<div className="releasesVersion">
|
||||||
|
<Spin spinning={isSpin}>
|
||||||
|
{renderList(releases)}
|
||||||
|
</Spin>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
export default version;
|
|
@ -0,0 +1,357 @@
|
||||||
|
.topWrapper {
|
||||||
|
padding: 20px 0;
|
||||||
|
box-sizing: border-box;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
border-bottom: 1px solid #EEEEEE;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
.topWrapper_btn_new {
|
||||||
|
background: #fff;
|
||||||
|
color: #5091FF!important;
|
||||||
|
padding:0px 12px;
|
||||||
|
text-align: center;
|
||||||
|
height: 32px;
|
||||||
|
line-height: 32px;
|
||||||
|
border-radius: 4px;
|
||||||
|
border:1px solid #5091FF;
|
||||||
|
}
|
||||||
|
.versionInfo{
|
||||||
|
display: flex;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
.versionInfo_left{
|
||||||
|
display: flex;
|
||||||
|
width: 182px;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: flex-end;
|
||||||
|
padding-right: 15px;
|
||||||
|
&>.color-grey-3{
|
||||||
|
max-width: 10rem;
|
||||||
|
overflow: hidden;
|
||||||
|
white-space: nowrap;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.versionInfo_right{
|
||||||
|
flex: 1;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: flex-start;
|
||||||
|
border-left: 1px solid #eee;
|
||||||
|
position: relative;
|
||||||
|
padding: 0px 30px 60px 24px;
|
||||||
|
&::before{
|
||||||
|
position: absolute;
|
||||||
|
left: -4px;
|
||||||
|
top:0px;
|
||||||
|
content: '';
|
||||||
|
width: 8px;
|
||||||
|
height: 8px;
|
||||||
|
background-color: #466AFF;
|
||||||
|
border-radius: 50%;
|
||||||
|
}
|
||||||
|
.sendAuthorImg{
|
||||||
|
width: 20px;
|
||||||
|
height: 20px;
|
||||||
|
border-radius: 50%;
|
||||||
|
margin-right: 5px;
|
||||||
|
}
|
||||||
|
.body-show{
|
||||||
|
padding: 5px 10px 10px 10px;
|
||||||
|
}
|
||||||
|
& .version-user>a>span{
|
||||||
|
display: inline-block;
|
||||||
|
& img{
|
||||||
|
width: 20px;
|
||||||
|
height: 20px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.versionTag{
|
||||||
|
display: inline;
|
||||||
|
padding:0px 9px;
|
||||||
|
color: #fff;
|
||||||
|
position: relative;
|
||||||
|
margin-top: -8px;
|
||||||
|
height: 22px;
|
||||||
|
line-height: 20px;
|
||||||
|
border-radius: 4px;
|
||||||
|
&::before{
|
||||||
|
position: absolute;
|
||||||
|
content: "";
|
||||||
|
width: 0;
|
||||||
|
height: 0px;
|
||||||
|
border-left: 4px solid #cccccc;
|
||||||
|
border-top: 4px solid transparent;
|
||||||
|
border-bottom: 4px solid transparent;
|
||||||
|
border-right: 4px solid transparent;
|
||||||
|
z-index: 9;
|
||||||
|
top: 6px;
|
||||||
|
right: -9px;
|
||||||
|
}
|
||||||
|
&:after{
|
||||||
|
width: 0px;
|
||||||
|
height: 0px;
|
||||||
|
top:6px;
|
||||||
|
right: -7px;
|
||||||
|
position: absolute;
|
||||||
|
border-left:4px solid #fff;
|
||||||
|
border-top:4px solid transparent;
|
||||||
|
border-bottom:4px solid transparent;
|
||||||
|
border-right:4px solid transparent;
|
||||||
|
content:'';
|
||||||
|
z-index:10;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.versionFile{
|
||||||
|
margin-top: 5px;
|
||||||
|
padding-top: 20px;
|
||||||
|
border-top: 1px solid #eee;
|
||||||
|
// width: 100%;
|
||||||
|
a{
|
||||||
|
display: block;
|
||||||
|
color: #333;
|
||||||
|
font-weight: 400;
|
||||||
|
height: 20px;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.versionTag.yellow{
|
||||||
|
border: 1px solid #FBBC06;
|
||||||
|
color: #FBBC06;
|
||||||
|
&::before{
|
||||||
|
border-left-color: #FBBC06;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.versionTag.green{
|
||||||
|
border: 1px solid #2DB44D;
|
||||||
|
color: #2DB44D;
|
||||||
|
&::before{
|
||||||
|
border-left-color: #2DB44D;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.versionTag.orange{
|
||||||
|
border: 1px solid #FF6E23;
|
||||||
|
color: #FF6E23;
|
||||||
|
&::before{
|
||||||
|
border-left-color: #FF6E23;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.addReleaseBtn{
|
||||||
|
text-align: right;
|
||||||
|
margin-bottom: 30px;
|
||||||
|
}
|
||||||
|
.versionName{
|
||||||
|
font-size: 16px;
|
||||||
|
color: #333;
|
||||||
|
margin-bottom: 15px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
width: 100%;
|
||||||
|
height: 18px;
|
||||||
|
line-height: 18px;
|
||||||
|
margin-top: -5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.versionmilepostleft{
|
||||||
|
padding: 15px;
|
||||||
|
margin-right: 50px;
|
||||||
|
width: 80%;
|
||||||
|
}
|
||||||
|
.topWrapper_btn_close {
|
||||||
|
background: #504b4b;
|
||||||
|
color: #FFFFFF!important;
|
||||||
|
padding:0px 12px;
|
||||||
|
text-align: center;
|
||||||
|
height: 32px;
|
||||||
|
line-height: 32px;
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.topWrapper_btn_delete {
|
||||||
|
background: #da1010;
|
||||||
|
color: #FFFFFF!important;
|
||||||
|
padding:0px 12px;
|
||||||
|
text-align: center;
|
||||||
|
height: 32px;
|
||||||
|
line-height: 32px;
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.versionrighe{
|
||||||
|
flex: 2;
|
||||||
|
}
|
||||||
|
.versionleft{
|
||||||
|
flex: 1;
|
||||||
|
text-align: right;
|
||||||
|
display: flex;
|
||||||
|
justify-content: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* .version_line{
|
||||||
|
display: flex;
|
||||||
|
height: 30px;
|
||||||
|
margin: auto;
|
||||||
|
border-left:1px solid #eee;
|
||||||
|
} */
|
||||||
|
.version_line_one{
|
||||||
|
display: flex;
|
||||||
|
height: 45px;
|
||||||
|
margin: auto;
|
||||||
|
border-left:1px solid #eee;
|
||||||
|
}
|
||||||
|
|
||||||
|
.version_line_tpw{
|
||||||
|
display: flex;
|
||||||
|
height: 80px;
|
||||||
|
margin: auto;
|
||||||
|
border-left:1px solid #eee;
|
||||||
|
}
|
||||||
|
|
||||||
|
.versiondiv{
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
.verwinth{
|
||||||
|
width: 80%;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*开启中 关闭中*/
|
||||||
|
.opendversionetail{
|
||||||
|
display: inline-block;
|
||||||
|
background: #21ba45;
|
||||||
|
color: #ffffff!important;
|
||||||
|
padding:0px 5px;
|
||||||
|
text-align: center;
|
||||||
|
height: 25px;
|
||||||
|
/*width: 110px;*/
|
||||||
|
border-radius: 4px;
|
||||||
|
line-height: 25px;
|
||||||
|
}
|
||||||
|
.closedversionetail{
|
||||||
|
display: inline-block;
|
||||||
|
background: #e60b0b;
|
||||||
|
color: #ffffff!important;
|
||||||
|
padding:0px 5px;
|
||||||
|
text-align: center;
|
||||||
|
height: 25px;
|
||||||
|
/*width: 110px;*/
|
||||||
|
border-radius: 4px;
|
||||||
|
line-height: 25px;
|
||||||
|
}
|
||||||
|
.versionrectangle {
|
||||||
|
width: 8px;
|
||||||
|
height: 8px;
|
||||||
|
border-radius: 100%;
|
||||||
|
margin-top: 15px;
|
||||||
|
margin-left: -4px;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
background: rgb(83, 81, 81);
|
||||||
|
}
|
||||||
|
.ver-middle{
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
/* new */
|
||||||
|
.versionForm{
|
||||||
|
flex:1;
|
||||||
|
padding-right: 40px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
.ant-select-auto-complete.ant-select .ant-input:hover,.ant-input:hover {
|
||||||
|
border-color: rgba(153, 153, 153, 0.8);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.versionTips{
|
||||||
|
width:268px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
.infosTip{
|
||||||
|
border-bottom: 1px solid #EEEEEE;
|
||||||
|
color: #333;
|
||||||
|
padding-bottom: 26px;
|
||||||
|
margin-bottom: 26px;
|
||||||
|
font-weight: 400;
|
||||||
|
text-align: justify;
|
||||||
|
&:last-child{
|
||||||
|
border-bottom: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.dragBox{
|
||||||
|
background: rgba(153, 153, 153, 0.04);
|
||||||
|
border-radius: 4px;
|
||||||
|
border: 1px dashed #d9d9d9;
|
||||||
|
padding:20px;
|
||||||
|
.versionStyle{
|
||||||
|
border: none!important;
|
||||||
|
padding-bottom:20px;
|
||||||
|
.dragIcon{
|
||||||
|
font-size: 40px!important;
|
||||||
|
color: #666!important;
|
||||||
|
line-height: 40px;
|
||||||
|
height: 40px;
|
||||||
|
margin-bottom: 14px;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.ant-upload-list-item:hover .ant-upload-list-item-info {
|
||||||
|
background-color: rgba(239, 244, 255, 1);
|
||||||
|
}
|
||||||
|
.ant-upload-list-item-info{
|
||||||
|
padding:0px 20px 0px 8px;
|
||||||
|
&>span{
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.set-ant-row .ant-row{
|
||||||
|
display: flex;
|
||||||
|
height: 20px;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
.itemInline{
|
||||||
|
display: flex;
|
||||||
|
align-items: flex-start;
|
||||||
|
position: relative;
|
||||||
|
&>p{
|
||||||
|
position: absolute;
|
||||||
|
bottom: -5px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.itemInline .ant-row{
|
||||||
|
margin-bottom: 0px;
|
||||||
|
}
|
||||||
|
.prerelease{
|
||||||
|
padding-top: 20px;
|
||||||
|
.ant-form-item-control{
|
||||||
|
height: 20px;
|
||||||
|
line-height: 20px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.releaseIndex{
|
||||||
|
margin: 30px auto;
|
||||||
|
width: 1200px;
|
||||||
|
}
|
||||||
|
.emptyPanel{
|
||||||
|
width: 100%;
|
||||||
|
background: #FAFCFF;
|
||||||
|
border-radius: 4px;
|
||||||
|
border: 1px solid rgba(42, 97, 255, 0.23);
|
||||||
|
min-height: 418px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
.operation{
|
||||||
|
width: 400px;
|
||||||
|
border-top: 1px solid #eee;
|
||||||
|
padding-top: 34px;
|
||||||
|
text-align: center;
|
||||||
|
margin-top: 30px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.ant-form-item-control{
|
||||||
|
line-height: initial;
|
||||||
|
}
|
|
@ -0,0 +1,448 @@
|
||||||
|
import React, { Component } from 'react';
|
||||||
|
import { Input, Select, Spin, Alert } from 'antd';
|
||||||
|
import axios from 'axios';
|
||||||
|
import MergeForm from './merge_form';
|
||||||
|
import MergeFooter from './merge_footer';
|
||||||
|
|
||||||
|
import '../Order/order.css';
|
||||||
|
import './merge.css';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据url获取目标仓库、目标分支、源仓库、源分支
|
||||||
|
* 路由规则:owner/projectId/compare/merge...pullowner:pullBranch
|
||||||
|
* 可能存在的情况
|
||||||
|
* 1、代码库首页跳转,仓库相同,目标分支为默认分支,owner/projectId/compare/pullBranch
|
||||||
|
* 2、代码库分支列表,仓库相同,目标分支为默认分支,owner/projectId/compare/pullBranch
|
||||||
|
* 3、合并请求列表页(新建、无数据时的提示),仓库相同,源、目标都为默认分支,owner/projectId/compare
|
||||||
|
* 4、新建页面,切换分支、切换目标仓库、刷新页面等,存在所有可能情况
|
||||||
|
*/
|
||||||
|
function getBranchParams(pathname) {
|
||||||
|
const result = {
|
||||||
|
// 目标仓库所有者
|
||||||
|
mergeOwner: undefined,
|
||||||
|
// 目标分支
|
||||||
|
mergeBranch: 'master',
|
||||||
|
// 源仓库所有者
|
||||||
|
pullOwner: undefined,
|
||||||
|
// 源分支
|
||||||
|
pullBranch: 'master',
|
||||||
|
// 仓库名称
|
||||||
|
projectId: undefined,
|
||||||
|
};
|
||||||
|
// 去掉第一个字符/
|
||||||
|
const _pathname = pathname.slice(1);
|
||||||
|
const [ownerProject, branchUrl] = _pathname.split('/compare');
|
||||||
|
const [mergeOwner, projectId] = ownerProject.split('/');
|
||||||
|
// 同仓库时
|
||||||
|
result.mergeOwner = mergeOwner;
|
||||||
|
result.pullOwner = mergeOwner;
|
||||||
|
result.projectId = projectId;
|
||||||
|
if (branchUrl) {
|
||||||
|
// 如果存在具体的分支
|
||||||
|
const _branchUrl = branchUrl.slice(1);
|
||||||
|
if (_branchUrl.indexOf('...') > -1) {
|
||||||
|
// 存在源分支与目标分支
|
||||||
|
const [mergeBranch, pullObj] = _branchUrl.split('...');
|
||||||
|
result.mergeBranch = mergeBranch;
|
||||||
|
if (pullObj.indexOf(':') > -1) {
|
||||||
|
// 存在源仓库
|
||||||
|
const [pullOwner, pullBranch] = pullObj.split(':');
|
||||||
|
result.pullOwner = pullOwner;
|
||||||
|
result.pullBranch = pullBranch;
|
||||||
|
} else {
|
||||||
|
result.pullBranch = pullObj;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
result.pullBranch = _branchUrl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Option = Select.Option;
|
||||||
|
|
||||||
|
class CreateMerge extends Component {
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
const { pullBranch, mergeBranch } = getBranchParams(
|
||||||
|
this.props.location.pathname
|
||||||
|
);
|
||||||
|
this.state = {
|
||||||
|
data: undefined,
|
||||||
|
pullBranches: undefined,
|
||||||
|
mergeBranches: undefined,
|
||||||
|
mergeProjects: undefined,
|
||||||
|
merge: mergeBranch || 'master',
|
||||||
|
pull: pullBranch || 'master',
|
||||||
|
id: undefined,
|
||||||
|
// isFork: false,
|
||||||
|
projects_names: undefined,
|
||||||
|
isSpin: true,
|
||||||
|
showMessage: false,
|
||||||
|
merge_head: false, // 是否向fork后的源项目发起合并请求
|
||||||
|
defaultMessage: '必须选择不同的分支',
|
||||||
|
project_id: undefined, // 当前项目的id,也即开始发送合并请求的源项目id
|
||||||
|
merge_project_user: undefined,
|
||||||
|
comparesData: undefined, //提交和文件的内容,保存compare接口返回的数据
|
||||||
|
// 比较分支时的加载效果
|
||||||
|
isCompareSpin: true,
|
||||||
|
// 是否是初次加载,用这个字段来控制提示组件和文件组件的显示、隐藏比直接用isCompareSpin交互友好些
|
||||||
|
isFirstLoading: true,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidMount = () => {
|
||||||
|
// 初始化时根据url获取目标仓库、分支,源仓库、分支;
|
||||||
|
// 再获取对应的仓库列表、分支列表
|
||||||
|
// 再调用比较接口
|
||||||
|
const branchParams = getBranchParams(this.props.location.pathname);
|
||||||
|
this.getMergeInfo(branchParams);
|
||||||
|
};
|
||||||
|
|
||||||
|
componentDidUpdate = (preProps) => {
|
||||||
|
// url变化触发时(切换源分支、切换目标仓库、切换目标分支;回退)
|
||||||
|
const oldPathname = preProps.location.pathname;
|
||||||
|
const newPathname = this.props.location.pathname;
|
||||||
|
if (oldPathname !== newPathname) {
|
||||||
|
const branchParams = getBranchParams(newPathname);
|
||||||
|
this.getMergeInfo(branchParams);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
//获取新建合并请求数据
|
||||||
|
getMergeInfo = (branchParams) => {
|
||||||
|
this.setState({ isSpin: true });
|
||||||
|
const { pullOwner, pullBranch, mergeOwner, mergeBranch, projectId } =
|
||||||
|
branchParams;
|
||||||
|
const url = `/${pullOwner}/${projectId}/pulls/new.json`;
|
||||||
|
axios
|
||||||
|
.get(url)
|
||||||
|
.then((result) => {
|
||||||
|
if (result) {
|
||||||
|
// 如果url上的分支不存在,取默认值master
|
||||||
|
const noMergeBranch =
|
||||||
|
(result.data.branches || []).filter(
|
||||||
|
(branch) => branch.name === mergeBranch
|
||||||
|
).length === 0;
|
||||||
|
const noPullBranch =
|
||||||
|
(result.data.branches || []).filter(
|
||||||
|
(branch) => branch.name === pullBranch
|
||||||
|
).length === 0;
|
||||||
|
this.setState({
|
||||||
|
// isFork: result.data.is_fork,
|
||||||
|
projects_names: result.data.projects_names,
|
||||||
|
mergeProjects: result.data.merge_projects,
|
||||||
|
pullBranches: result.data.branches,
|
||||||
|
mergeBranches: result.data.branches,
|
||||||
|
project_id: result.data.project_id,
|
||||||
|
id: result.data.id,
|
||||||
|
merge: mergeBranch,
|
||||||
|
pull: pullBranch,
|
||||||
|
});
|
||||||
|
|
||||||
|
//判断源分支是否存在
|
||||||
|
if(noPullBranch){
|
||||||
|
this.setState({
|
||||||
|
showMessage: true,
|
||||||
|
defaultMessage:'源分支不存在',
|
||||||
|
isCompareSpin: false,
|
||||||
|
});
|
||||||
|
}else{
|
||||||
|
if(pullOwner === mergeOwner){
|
||||||
|
if (!noMergeBranch) {
|
||||||
|
this.compareProject(true, branchParams);
|
||||||
|
} else {
|
||||||
|
this.setState({
|
||||||
|
showMessage: true,
|
||||||
|
defaultMessage:'目标分支不存在',
|
||||||
|
isCompareSpin: false,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
this.getBranchList(branchParams);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.setState({ isSpin: false });
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
this.setState({ isSpin: false });
|
||||||
|
console.log(error);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// compare接口,获取分支对比信息
|
||||||
|
compareProject = (sameProject, branchParams) => {
|
||||||
|
// const { project } = this.props;
|
||||||
|
// const { owner, projectsId } = this.props.match.params;
|
||||||
|
const { pullOwner, pullBranch, mergeOwner, mergeBranch, projectId } =
|
||||||
|
branchParams;
|
||||||
|
|
||||||
|
let url = `/${mergeOwner}/${projectId}/compare`;
|
||||||
|
if (sameProject) {
|
||||||
|
url += `/${pullBranch}...${mergeBranch}.json`;
|
||||||
|
} else {
|
||||||
|
url += `/${mergeBranch}...${pullOwner}/${projectId}:${pullBranch}.json`;
|
||||||
|
}
|
||||||
|
this.setState({ isSpin: false, isCompareSpin: true });
|
||||||
|
axios
|
||||||
|
.get(url)
|
||||||
|
.then((result) => {
|
||||||
|
if (result) {
|
||||||
|
if (result.data.status === 0) {
|
||||||
|
this.setState({
|
||||||
|
showMessage: false,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
this.setState({
|
||||||
|
showMessage: true,
|
||||||
|
defaultMessage: result.data.message,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
this.setState({
|
||||||
|
comparesData: result.data,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
this.setState({
|
||||||
|
isFirstLoading: false,
|
||||||
|
isSpin: false,
|
||||||
|
isCompareSpin: false,
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
this.setState({ isSpin: false, isCompareSpin: false });
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// 根据所有者、仓库名,获取分支列表,目前仅涉及目标仓库分支查询
|
||||||
|
getBranchList = (branchParams) => {
|
||||||
|
const { mergeOwner, projectId, mergeBranch } = branchParams;
|
||||||
|
this.setState({ isSpin: true });
|
||||||
|
const url = `/${mergeOwner}/${projectId}/pulls/get_branches.json`;
|
||||||
|
axios
|
||||||
|
.get(url)
|
||||||
|
.then((result) => {
|
||||||
|
if (result) {
|
||||||
|
const noMergeBranch =
|
||||||
|
(result.data || []).filter((branch) => branch.name === mergeBranch)
|
||||||
|
.length === 0;
|
||||||
|
this.setState({
|
||||||
|
mergeBranches: result.data,
|
||||||
|
showMessage: noMergeBranch,
|
||||||
|
defaultMessage: '目标分支不存在',
|
||||||
|
isCompareSpin: false,
|
||||||
|
});
|
||||||
|
!noMergeBranch && this.compareProject(false, branchParams);
|
||||||
|
}
|
||||||
|
this.setState({ isSpin: false });
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
this.setState({ isSpin: false });
|
||||||
|
console.log(error);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// 切换分支事件
|
||||||
|
selectBrach = (type, value) => {
|
||||||
|
const { pullOwner, pullBranch, mergeOwner, mergeBranch, projectId } =
|
||||||
|
getBranchParams(this.props.location.pathname);
|
||||||
|
let _url = `/${mergeOwner}/${projectId}/compare/`;
|
||||||
|
// type为pull时,pullBranch取value,否则取原有值
|
||||||
|
// type为pull时,mergeBranch取原有值,否则取value
|
||||||
|
let _pullBranch = type === 'pull' ? value : pullBranch;
|
||||||
|
let _mergeBranch = type === 'pull' ? mergeBranch : value;
|
||||||
|
if (pullOwner === mergeOwner) {
|
||||||
|
// 如果仓库相同, compare/目标分支...源分支
|
||||||
|
_url += `${_mergeBranch}...${_pullBranch}`;
|
||||||
|
} else {
|
||||||
|
// 如果仓库不同, compare/目标分支...源分支
|
||||||
|
_url += `${_mergeBranch}...${pullOwner}:${_pullBranch}`;
|
||||||
|
}
|
||||||
|
this.props.history.push(_url);
|
||||||
|
};
|
||||||
|
|
||||||
|
// 切换仓库响应事件,目前仅目标分支可切换仓库
|
||||||
|
selectProjectName = (value) => {
|
||||||
|
const { projects_names, id } = this.state;
|
||||||
|
const { pullOwner, pullBranch } = getBranchParams(
|
||||||
|
this.props.location.pathname
|
||||||
|
);
|
||||||
|
let arr =
|
||||||
|
projects_names && projects_names.filter((item) => item.id === value);
|
||||||
|
let identifier = arr && arr[0].project_id;
|
||||||
|
let login = arr && arr[0].project_user_login;
|
||||||
|
// 目标仓库与源仓库不是一个仓库
|
||||||
|
let is_fork = parseInt(value, 10) !== parseInt(id, 10);
|
||||||
|
this.setState({
|
||||||
|
isSpin: true,
|
||||||
|
// merge_head: is_fork,
|
||||||
|
data: {
|
||||||
|
is_original: is_fork,
|
||||||
|
fork_project_id: is_fork ? id : '',
|
||||||
|
merge_user_login: is_fork
|
||||||
|
? projects_names[0].project_user_login
|
||||||
|
: undefined,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
if (login === pullOwner) {
|
||||||
|
// 如果切换后, 仓库与源仓库一致了
|
||||||
|
this.props.history.push(
|
||||||
|
`/${login}/${identifier}/compare/master...${pullBranch}`
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
this.props.history.push(
|
||||||
|
`/${login}/${identifier}/compare/master...${pullOwner}:${pullBranch}`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
// this.newMergelist(login, identifier);
|
||||||
|
};
|
||||||
|
|
||||||
|
// 渲染分支列表
|
||||||
|
renderBrances = (list) => {
|
||||||
|
if (list && list.length > 0) {
|
||||||
|
return list.map((item, key) => {
|
||||||
|
return (
|
||||||
|
<Option key={key + 1} value={item.name}>
|
||||||
|
{item.name}
|
||||||
|
</Option>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 渲染项目列表
|
||||||
|
renderProjectNames = (list) => {
|
||||||
|
if (list && list.length > 0) {
|
||||||
|
return list.map((item, key) => {
|
||||||
|
return (
|
||||||
|
<Option key={key + 1} value={item.id}>
|
||||||
|
{item.project_name}
|
||||||
|
</Option>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// 渲染html内容
|
||||||
|
withHtml = (html) => {
|
||||||
|
return <div dangerouslySetInnerHTML={{ __html: html }}></div>;
|
||||||
|
};
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const {
|
||||||
|
data,
|
||||||
|
pullBranches,
|
||||||
|
mergeBranches,
|
||||||
|
mergeProjects,
|
||||||
|
pull,
|
||||||
|
merge,
|
||||||
|
isSpin,
|
||||||
|
isCompareSpin,
|
||||||
|
isFirstLoading,
|
||||||
|
showMessage,
|
||||||
|
defaultMessage,
|
||||||
|
projects_names,
|
||||||
|
id,
|
||||||
|
comparesData,
|
||||||
|
} = this.state;
|
||||||
|
|
||||||
|
let { project } = this.props;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<Spin spinning={isSpin || isCompareSpin}>
|
||||||
|
<div className="main">
|
||||||
|
<div className="merge-header width100 inline-block">
|
||||||
|
<div className="width40 pull-left">
|
||||||
|
<div className="color-grey-3 mb10 fwb">源分支:</div>
|
||||||
|
<Input.Group compact className="display-flex">
|
||||||
|
<Select
|
||||||
|
value={id}
|
||||||
|
className="hide-1 task-hide flex1"
|
||||||
|
disabled
|
||||||
|
>
|
||||||
|
{this.renderProjectNames(projects_names)}
|
||||||
|
</Select>
|
||||||
|
<Select
|
||||||
|
value={pull}
|
||||||
|
onSelect={(e) => this.selectBrach('pull', e)}
|
||||||
|
showSearch
|
||||||
|
className="merge-flex1 flex1 matchwidth"
|
||||||
|
dropdownMatchSelectWidth={false}
|
||||||
|
dropdownClassName="overlihide"
|
||||||
|
>
|
||||||
|
{this.renderBrances(pullBranches)}
|
||||||
|
</Select>
|
||||||
|
</Input.Group>
|
||||||
|
</div>
|
||||||
|
<div className="width10 pull-left text-center mt25">
|
||||||
|
<i
|
||||||
|
className={'iconfont icon-youjiang color-grey-c font-32'}
|
||||||
|
></i>
|
||||||
|
</div>
|
||||||
|
<div className="width40 pull-left">
|
||||||
|
<div>
|
||||||
|
<div className="color-grey-3 mb10 fwb">目标分支:</div>
|
||||||
|
<Input.Group compact className="display-flex">
|
||||||
|
<Select
|
||||||
|
value={project && project.id}
|
||||||
|
className="hide-1 task-hide flex1"
|
||||||
|
onSelect={(e) => this.selectProjectName(e)}
|
||||||
|
>
|
||||||
|
{this.renderProjectNames(mergeProjects)}
|
||||||
|
</Select>
|
||||||
|
<Select
|
||||||
|
value={merge}
|
||||||
|
onSelect={(e) => this.selectBrach('merge', e)}
|
||||||
|
showSearch
|
||||||
|
className="merge-flex1 flex1 matchwidth"
|
||||||
|
dropdownMatchSelectWidth={false}
|
||||||
|
dropdownClassName="overlihide"
|
||||||
|
>
|
||||||
|
{this.renderBrances(mergeBranches)}
|
||||||
|
</Select>
|
||||||
|
</Input.Group>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{/* 非加载状态且有提示 */}
|
||||||
|
{!isCompareSpin && showMessage && (
|
||||||
|
<div className="mb20">
|
||||||
|
<Alert
|
||||||
|
description={this.withHtml(defaultMessage)}
|
||||||
|
type="error"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
{/* 非加载状态且可以提交 */}
|
||||||
|
{!isCompareSpin && !showMessage && (
|
||||||
|
<MergeForm
|
||||||
|
{...this.props}
|
||||||
|
merge_type="new"
|
||||||
|
data={data}
|
||||||
|
merge={merge}
|
||||||
|
pull={pull}
|
||||||
|
files_count={
|
||||||
|
comparesData &&
|
||||||
|
comparesData.diff &&
|
||||||
|
comparesData.diff.files_count
|
||||||
|
}
|
||||||
|
commits_count={comparesData && comparesData.commits_count}
|
||||||
|
></MergeForm>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
{!isFirstLoading && (
|
||||||
|
<MergeFooter
|
||||||
|
{...this.props}
|
||||||
|
merge={merge}
|
||||||
|
pull={pull}
|
||||||
|
comparesData={comparesData}
|
||||||
|
></MergeFooter>
|
||||||
|
)}
|
||||||
|
</Spin>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default CreateMerge;
|
|
@ -1,17 +1,24 @@
|
||||||
import React ,{useEffect,useState } from 'react';
|
import React ,{useEffect,useState } from 'react';
|
||||||
import { truncateCommitId } from '../common/util';
|
import { truncateCommitId } from '../common/util';
|
||||||
import { AlignCenter , FlexAJ } from '../Component/layout';
|
import { AlignCenter , FlexAJ } from '../Component/layout';
|
||||||
import { Button } from 'antd';
|
import { Tooltip,Progress } from 'antd';
|
||||||
import './merge.css';
|
import './merge.css';
|
||||||
|
import './Index.scss';
|
||||||
|
|
||||||
function Files({data,history,owner,projectsId}){
|
function Files({ data,history,owner,projectsId , parentsSha }){
|
||||||
const [ files , setFiles ] = useState(data && data.files);
|
const [ files , setFiles ] = useState(data && data.files);
|
||||||
|
const [ copyfileTipTitle, setCopyfileTipTitle] = useState("复制文件路径");
|
||||||
|
const [ isOpen, setIsOpen] = useState(false);
|
||||||
|
|
||||||
useEffect(()=>{
|
useEffect(()=>{
|
||||||
if(data){
|
if(data){
|
||||||
setFiles(data.files);
|
setFiles(data.files);
|
||||||
}
|
}
|
||||||
},[data])
|
},[data]);
|
||||||
|
|
||||||
|
useEffect(()=>{
|
||||||
|
document.addEventListener('click',()=>{setIsOpen(false)})
|
||||||
|
})
|
||||||
|
|
||||||
function showDown(flag,index,isBin){
|
function showDown(flag,index,isBin){
|
||||||
if(!isBin){
|
if(!isBin){
|
||||||
|
@ -22,35 +29,86 @@ function Files({data,history,owner,projectsId}){
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function copyFileName(fileName){
|
||||||
|
var copyCont = document.createElement('input');
|
||||||
|
copyCont.defaultValue = fileName;
|
||||||
|
document.body.appendChild(copyCont);
|
||||||
|
copyCont.select(); // 选择对象
|
||||||
|
document.execCommand("Copy"); // 执行浏览器复制命令
|
||||||
|
copyCont.className = 'copyCont';
|
||||||
|
copyCont.style.display='none';
|
||||||
|
setCopyfileTipTitle("复制成功");
|
||||||
|
}
|
||||||
|
|
||||||
|
const folderOpen = (
|
||||||
|
<div className="folders">
|
||||||
|
<div className="folderList">
|
||||||
|
{files && files.map((item, key) => {
|
||||||
|
return (
|
||||||
|
<a href={`#value${key}`}>
|
||||||
|
<FlexAJ className="filesInfo" key={key} onClick={() => {item.flag && showDown(item.flag, key, item.isBin);setIsOpen(false);}}>
|
||||||
|
<AlignCenter>
|
||||||
|
<i className="iconfont icon-wenjianicon mr4"></i>
|
||||||
|
<span className="cursor-pointer" data-clipboard-text={item.name}>{item.name}</span>
|
||||||
|
</AlignCenter>
|
||||||
|
<div className="see-file">
|
||||||
|
<Tooltip placement="top" title={`${item.addition+item.deletion}处更改${item.addition + item.deletion > 0 ? ":":""}${item.addition>0?item.addition+"处添加":""}${item.addition>0 && item.deletion>0 ?"和":""}${item.deletion>0?item.deletion+"处删除":""}`}>
|
||||||
|
<Progress showInfo = {false} strokeColor = "#2DB44D" size="small" percent={item.addition/(item.addition+item.deletion)*100} />
|
||||||
|
{item.addition >0 && <span className="color-green ml10">+{item.addition}</span>}
|
||||||
|
{item.deletion >0 && <span className="color-red ml10">-{item.deletion}</span>}
|
||||||
|
</Tooltip>
|
||||||
|
</div>
|
||||||
|
</FlexAJ>
|
||||||
|
</a>
|
||||||
|
)
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
|
||||||
return(
|
return(
|
||||||
<div>
|
<div onClick={(e)=>{e.nativeEvent.stopImmediatePropagation()}}>
|
||||||
<AlignCenter className="color-grey-9 pb10" style={{borderBottom:"1px solid #eee"}}>
|
<AlignCenter className="color-grey-9" style={{position:'relative'}}>
|
||||||
<i className="iconfont icon-sanjiaoxing-down mr5"></i>
|
<div onClick={()=>{setIsOpen(!isOpen)}}>
|
||||||
<span>
|
<i className={`iconfont mr5 ${isOpen? "font-18 icon-sanjiaoxing-down":"font-16 icon-triangle"}`}></i>
|
||||||
共有<span className="color-grey-3"> {data && data.files_count} 个文件被更改</span>,包括
|
<span className="color-grey-6 update-file-count">
|
||||||
|
共有<span className="color-grey-3"> {data && data.files_count} 个文件 </span>被更改,包括
|
||||||
{ data && data.total_addition ? <span className="color-green"> {data && data.total_addition} 次插入</span>:"" }
|
{ data && data.total_addition ? <span className="color-green"> {data && data.total_addition} 次插入</span>:"" }
|
||||||
{ data && data.total_addition && data.total_deletion ? " 和 ":""}
|
{ data && data.total_addition && data.total_deletion ? " 和 ":""}
|
||||||
{ data && data.total_deletion ? <span className="color-red"> {data && data.total_deletion} 次删除</span>:""}
|
{ data && data.total_deletion ? <span className="color-red"> {data && data.total_deletion} 次删除</span>:""}
|
||||||
</span>
|
</span>
|
||||||
|
</div>
|
||||||
|
{isOpen && folderOpen}
|
||||||
</AlignCenter>
|
</AlignCenter>
|
||||||
{
|
{
|
||||||
files && files.length>0 &&
|
files && files.length>0 &&
|
||||||
<div>
|
<div className="fileList">
|
||||||
{
|
{
|
||||||
files.map((item,key)=>{
|
files.map((item,key)=>{
|
||||||
return(
|
return(
|
||||||
<div className="files" key={key}>
|
<div className="files" key={key}>
|
||||||
<FlexAJ className="filesInfo" style={{cursor:item.isBin ? "default":"pointer"}} onClick={()=>showDown(item.flag,key,item.isBin)}>
|
<a id= {`value${key}`} className="anchorPoint"></a>
|
||||||
|
<FlexAJ className="filesInfo">
|
||||||
<AlignCenter>
|
<AlignCenter>
|
||||||
{!item.isBin ? <i className={!item.flag?"iconfont icon-xiajiantou font-16 mr15 color-grey-9":"iconfont icon-youjiantou font-16 mr15 color-grey-9"}></i>:""}
|
{!item.isBin ? <i className={!item.flag?"iconfont icon-sanjiaoxing-down color-grey-9 mt4":"iconfont icon-triangle font-15 color-grey-9"} onClick={()=>showDown(item.flag,key,item.isBin)}></i>:""}
|
||||||
<i className="iconfont icon-wenjia font-16 mr8 color-grey-9"></i>
|
<span className="cursor-pointer" data-clipboard-text={item.name} onClick={()=>showDown(item.flag,key,item.isBin)}>{item.name}</span>
|
||||||
<span>{item.name}</span>
|
<Tooltip
|
||||||
|
title={copyfileTipTitle}
|
||||||
|
onVisibleChange={()=>setCopyfileTipTitle("复制文件路径")}
|
||||||
|
>
|
||||||
|
<i className="iconfont icon-fuzhiicon ml6" onClick={()=>copyFileName(item.name)}></i>
|
||||||
|
</Tooltip>
|
||||||
</AlignCenter>
|
</AlignCenter>
|
||||||
<span>
|
<div className="see-file">
|
||||||
<Button className="mr20" onClick={()=>{history.push(`/${owner}/${projectsId}/tree/${truncateCommitId(item.sha)}/${item.name}`)}}>查看文件</Button>
|
<Tooltip placement="top" title={`${item.addition + item.deletion}处更改${item.addition + item.deletion > 0 ? ":":""} ${item.addition > 0 ? item.addition + "处添加" : ""}${item.addition > 0 && item.deletion > 0 ? "和" : ""}${item.deletion > 0 ? item.deletion + "处删除" : ""}`}>
|
||||||
<span className="color-green">+{item.addition}</span>
|
<Progress showInfo = {false} strokeColor = "#2DB44D" size="small" percent={item.addition/(item.addition+item.deletion)*100} />
|
||||||
<span className="color-red ml20">-{item.deletion}</span>
|
<span className="ml10">{item.addition+item.deletion}处</span>
|
||||||
</span>
|
</Tooltip>
|
||||||
|
{
|
||||||
|
!item.isSubmodule &&
|
||||||
|
<span className="see-file-btn" onClick={()=>{history.push(`/${owner}/${projectsId}${item.isDeleted ? `/commits/${truncateCommitId(parentsSha)}`:`/tree/${truncateCommitId(item.sha)}/${item.name}`}`)}}>查看文件</span>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
</FlexAJ>
|
</FlexAJ>
|
||||||
{
|
{
|
||||||
item.sections && item.sections.length >= 1 && !item.flag &&
|
item.sections && item.sections.length >= 1 && !item.flag &&
|
||||||
|
|
|
@ -19,3 +19,85 @@
|
||||||
border:1px solid #FA6400;
|
border:1px solid #FA6400;
|
||||||
color: #FA6400;
|
color: #FA6400;
|
||||||
}
|
}
|
||||||
|
.update-file-count{
|
||||||
|
cursor: pointer;
|
||||||
|
& .color-grey-3{
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.fileList{
|
||||||
|
.sc-bxivhb{
|
||||||
|
width: 55rem;
|
||||||
|
overflow: hidden;
|
||||||
|
white-space: normal;
|
||||||
|
word-break: break-all;
|
||||||
|
}
|
||||||
|
.see-file{
|
||||||
|
width: 14rem;
|
||||||
|
.ml10{
|
||||||
|
display: inline-block;
|
||||||
|
width: 4.5rem;
|
||||||
|
cursor: default;
|
||||||
|
}
|
||||||
|
span{
|
||||||
|
width: 7%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.anchorPoint{
|
||||||
|
position: relative;
|
||||||
|
top: -5rem;
|
||||||
|
display: block;
|
||||||
|
height: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.filesInfo{
|
||||||
|
background: #FAFCFF;
|
||||||
|
border-color:rgba(42, 97, 255, 0.23);
|
||||||
|
.ant-progress-line {
|
||||||
|
width: 5rem;
|
||||||
|
}
|
||||||
|
.ant-progress-inner{
|
||||||
|
background-color: #D14A4A;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.folders,.ant-anchor{
|
||||||
|
margin-left: 0;
|
||||||
|
padding-left: 0;
|
||||||
|
}
|
||||||
|
.folders{
|
||||||
|
position: absolute;
|
||||||
|
z-index: 2;
|
||||||
|
left: 0px;
|
||||||
|
top: 37px;
|
||||||
|
color: #333333;
|
||||||
|
width: 75rem;
|
||||||
|
box-shadow: 0px 4px 8px 2px rgba(212, 212, 212, 0.5);
|
||||||
|
border-radius: 4px;
|
||||||
|
border: 1px solid rgba(153, 153, 153, 0.32);
|
||||||
|
.ant-anchor-link-active > .ant-anchor-link-title {
|
||||||
|
color: #466AFF;
|
||||||
|
}
|
||||||
|
.ant-anchor-link {
|
||||||
|
padding: 0px;
|
||||||
|
}
|
||||||
|
.folderList{
|
||||||
|
max-height: 275px;
|
||||||
|
overflow:auto;
|
||||||
|
.files{
|
||||||
|
border: 0px;
|
||||||
|
}
|
||||||
|
.filesInfo {
|
||||||
|
padding: 10px 18px 10px 15px;
|
||||||
|
height: 55px;
|
||||||
|
background: #FFF;
|
||||||
|
border-bottom: 1px solid #EEEEEE;
|
||||||
|
&:hover{
|
||||||
|
background: #F3F4F6;
|
||||||
|
}
|
||||||
|
.color-green,.color-red{
|
||||||
|
width: 3%;
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -228,7 +228,7 @@ class MergeDetail extends Component {
|
||||||
<div>
|
<div>
|
||||||
{
|
{
|
||||||
data && data.issue.user_permission ?
|
data && data.issue.user_permission ?
|
||||||
<Link to={`/${owner}/${projectsId}/pulls/${mergeid}/updatemerge`} className="color-blue fr">编辑</Link>
|
<Link to={`/${owner}/${projectsId}/pulls/${mergeid}/edit`} className="color-blue fr">编辑</Link>
|
||||||
: ''
|
: ''
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -62,9 +62,9 @@ class MergeItem extends Component {
|
||||||
<p className="mb15 df" style={{ alignItems: "center" }}>
|
<p className="mb15 df" style={{ alignItems: "center" }}>
|
||||||
<i className={`iconfont icon-hebingqingqiu1 font-14 mr3 i_${status}`}></i>
|
<i className={`iconfont icon-hebingqingqiu1 font-14 mr3 i_${status}`}></i>
|
||||||
<Link
|
<Link
|
||||||
to={`/${owner}/${projectsId}/pulls/${item.pull_request_id}/Messagecount`}
|
to={`/${owner}/${projectsId}/pulls/${item.pull_request_id}`}
|
||||||
className="hide-1 font-15 color-grey-3 fwb lineh-30 mr10"
|
className="hide-1 font-15 color-grey-3 fwb lineh-30 mr10"
|
||||||
style={{ maxWidth: "300px" }}
|
style={{ maxWidth: "600px" }}
|
||||||
>
|
>
|
||||||
{item.name}
|
{item.name}
|
||||||
</Link>
|
</Link>
|
||||||
|
@ -110,7 +110,7 @@ class MergeItem extends Component {
|
||||||
<Tag className="pr-branch-tag">
|
<Tag className="pr-branch-tag">
|
||||||
<Link
|
<Link
|
||||||
to={`/${item.is_original ? item.fork_project_user : owner}/${ item.is_original ? item.fork_project_identifier : projectsId }/tree/${turnbar(item.pull_request_head)}`}
|
to={`/${item.is_original ? item.fork_project_user : owner}/${ item.is_original ? item.fork_project_identifier : projectsId }/tree/${turnbar(item.pull_request_head)}`}
|
||||||
className="maxW200px hide-1 ver-middle"
|
className="maxW200px task-hide ver-middle" style={{maxWidth:"200px"}}
|
||||||
>
|
>
|
||||||
{item.is_original
|
{item.is_original
|
||||||
? item.fork_project_user
|
? item.fork_project_user
|
||||||
|
@ -134,7 +134,7 @@ class MergeItem extends Component {
|
||||||
<Tag className="pr-branch-tag">
|
<Tag className="pr-branch-tag">
|
||||||
<Link
|
<Link
|
||||||
to={`/${owner}/${projectsId}/tree/${turnbar(item.pull_request_base)}`}
|
to={`/${owner}/${projectsId}/tree/${turnbar(item.pull_request_base)}`}
|
||||||
className="maxW200px hide-1 ver-middle"
|
className="maxW200px task-hide ver-middle" style={{maxWidth:"200px"}}
|
||||||
>
|
>
|
||||||
{/* {item.is_fork ? item.pull_request_base : `${item.author_name}:${item.pull_request_base}`} */}
|
{/* {item.is_fork ? item.pull_request_base : `${item.author_name}:${item.pull_request_base}`} */}
|
||||||
{project_author_name}:{item.pull_request_base}
|
{project_author_name}:{item.pull_request_base}
|
||||||
|
@ -175,7 +175,7 @@ class MergeItem extends Component {
|
||||||
{item.journals_count ? (
|
{item.journals_count ? (
|
||||||
<Link
|
<Link
|
||||||
className="mr5 color-grey-8"
|
className="mr5 color-grey-8"
|
||||||
to={`/${owner}/${projectsId}/pulls/${item.pull_request_id}/Messagecount`}
|
to={`/${owner}/${projectsId}/pulls/${item.pull_request_id}`}
|
||||||
>
|
>
|
||||||
<i className="iconfont icon-huifu1 font-15 mr5 ver-middle"></i>
|
<i className="iconfont icon-huifu1 font-15 mr5 ver-middle"></i>
|
||||||
{item.journals_count}
|
{item.journals_count}
|
||||||
|
@ -196,7 +196,7 @@ class MergeItem extends Component {
|
||||||
>
|
>
|
||||||
<div className="grid-item mr15 color-grey-9">
|
<div className="grid-item mr15 color-grey-9">
|
||||||
<Link
|
<Link
|
||||||
to={`/${owner}/${projectsId}/pulls/${item.pull_request_id}/updatemerge`}
|
to={`/${owner}/${projectsId}/pulls/${item.pull_request_id}/edit`}
|
||||||
className="color-grey-9"
|
className="color-grey-9"
|
||||||
>
|
>
|
||||||
<i className="iconfont icon-bianji3 font-14 mr5"></i>
|
<i className="iconfont icon-bianji3 font-14 mr5"></i>
|
||||||
|
|
|
@ -0,0 +1,210 @@
|
||||||
|
import React, { Component } from 'react';
|
||||||
|
import { Tabs, Spin } from 'antd';
|
||||||
|
import { Link } from 'react-router-dom';
|
||||||
|
import axios from 'axios';
|
||||||
|
|
||||||
|
import Commits from './Commits';
|
||||||
|
import Comments from '../comments/comments';
|
||||||
|
import Files from './Files';
|
||||||
|
|
||||||
|
import '../Order/order.css';
|
||||||
|
import './merge.css';
|
||||||
|
|
||||||
|
const { TabPane } = Tabs;
|
||||||
|
|
||||||
|
class MergeFooter extends Component {
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
this.state = {
|
||||||
|
commitsData: [],
|
||||||
|
filesData: undefined,
|
||||||
|
isSpin: false,
|
||||||
|
activeKey: '1',
|
||||||
|
commitCount: 0,
|
||||||
|
filesCount: 0,
|
||||||
|
// 总评论数量,包含回复
|
||||||
|
commentsTotalCount: 0,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
componentDidMount() {
|
||||||
|
this.Init();
|
||||||
|
// 为父组件绑定当前,以方便调用方法
|
||||||
|
this.props.bindFootRef && this.props.bindFootRef(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidUpdate(prevProps) {
|
||||||
|
// 解决切换tab后浏览器回退不刷新的问题、点击tab后url变化但tab未切换的问题
|
||||||
|
const newPathname = this.props.location.pathname;
|
||||||
|
const prevPathname = prevProps.location.pathname;
|
||||||
|
if (newPathname !== prevPathname) {
|
||||||
|
this.Init(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Init = (isTabChange) => {
|
||||||
|
const { data, location, match } = this.props;
|
||||||
|
const { pathname } = location;
|
||||||
|
const { projectsId, owner, mergeId } = match.params;
|
||||||
|
|
||||||
|
let activeKey = '1';
|
||||||
|
if (pathname.indexOf('commits') > -1) {
|
||||||
|
activeKey = '2';
|
||||||
|
this.getCommit(owner, projectsId, mergeId);
|
||||||
|
} else if (pathname.indexOf('files') > -1) {
|
||||||
|
activeKey = '3';
|
||||||
|
this.getFile(owner, projectsId, mergeId);
|
||||||
|
}
|
||||||
|
if (isTabChange && activeKey === '1') {
|
||||||
|
this.refreshComment();
|
||||||
|
}
|
||||||
|
this.setState({
|
||||||
|
activeKey: activeKey,
|
||||||
|
commitCount: data && data.commits_count,
|
||||||
|
filesCount: data && data.files_count,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
bindCommentRef = (commentRef) => {
|
||||||
|
this.childComment = commentRef;
|
||||||
|
}
|
||||||
|
|
||||||
|
refreshComment = () => {
|
||||||
|
this.childComment && this.childComment.getjournalslist();
|
||||||
|
}
|
||||||
|
|
||||||
|
getCommit = (owner, projectsId, mergeId) => {
|
||||||
|
this.setState({ isSpin: true });
|
||||||
|
const url = `/${owner}/${projectsId}/pulls/${mergeId}/commits.json`;
|
||||||
|
axios
|
||||||
|
.get(url)
|
||||||
|
.then((result) => {
|
||||||
|
if (result) {
|
||||||
|
this.setState({
|
||||||
|
commitsData: result.data.commits,
|
||||||
|
commitCount: result.data.commits_count,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
this.setState({ isSpin: false });
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
this.setState({ isSpin: false });
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
getFile = (owner, projectsId, mergeId) => {
|
||||||
|
this.setState({ isSpin: true });
|
||||||
|
const url = `/${owner}/${projectsId}/pulls/${mergeId}/files.json`;
|
||||||
|
axios
|
||||||
|
.get(url)
|
||||||
|
.then((result) => {
|
||||||
|
if (result) {
|
||||||
|
this.setState({
|
||||||
|
filesData: result.data,
|
||||||
|
filesCount: result.data.files_count,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
this.setState({ isSpin: false });
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
this.setState({ isSpin: false });
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const { projectsId, owner, mergeId } = this.props.match.params;
|
||||||
|
|
||||||
|
const { order_id, data = {} } = this.props;
|
||||||
|
const {
|
||||||
|
isSpin,
|
||||||
|
activeKey,
|
||||||
|
filesCount,
|
||||||
|
commitCount,
|
||||||
|
filesData,
|
||||||
|
commitsData = [],
|
||||||
|
} = this.state;
|
||||||
|
|
||||||
|
// 评论数量优先取Comment组件中列表接口返回的,其次取合并请求详情接口中的,都没有取默认值0
|
||||||
|
const commentsTotalCount = parseInt(
|
||||||
|
this.state.commentsTotalCount || data.comments_total_count || 0,
|
||||||
|
10
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="main mergeRequest" style={{ paddingTop: '0px' }}>
|
||||||
|
<Spin spinning={isSpin}>
|
||||||
|
<Tabs
|
||||||
|
activeKey={activeKey}
|
||||||
|
className="custom-commit-tabs"
|
||||||
|
animated={false}
|
||||||
|
>
|
||||||
|
<TabPane
|
||||||
|
tab={
|
||||||
|
<Link to={`/${owner}/${projectsId}/pulls/${mergeId}`}>
|
||||||
|
<span className="font-16">评论</span>
|
||||||
|
{commentsTotalCount > 0 && (
|
||||||
|
<span className="tabNum">{commentsTotalCount}</span>
|
||||||
|
)}
|
||||||
|
</Link>
|
||||||
|
}
|
||||||
|
key="1"
|
||||||
|
>
|
||||||
|
<Comments
|
||||||
|
order_id={order_id}
|
||||||
|
showNotification={this.props.showNotification}
|
||||||
|
only_show_content={true}
|
||||||
|
updateCommentsNum={(commentsCount) => {
|
||||||
|
this.setState({ commentsTotalCount: commentsCount || 0 });
|
||||||
|
}}
|
||||||
|
{...this.props}
|
||||||
|
bindCommentRef={this.bindCommentRef}
|
||||||
|
/>
|
||||||
|
</TabPane>
|
||||||
|
{commitCount > 0 && (
|
||||||
|
<TabPane
|
||||||
|
tab={
|
||||||
|
<Link to={`/${owner}/${projectsId}/pulls/${mergeId}/commits`}>
|
||||||
|
<span className="font-16">提交</span>
|
||||||
|
{commitCount > 0 && (
|
||||||
|
<span className="tabNum">{commitCount}</span>
|
||||||
|
)}
|
||||||
|
</Link>
|
||||||
|
}
|
||||||
|
key="2"
|
||||||
|
>
|
||||||
|
{commitsData.length > 0 && (
|
||||||
|
<Commits
|
||||||
|
{...this.props}
|
||||||
|
commits={commitsData}
|
||||||
|
projectsId={projectsId}
|
||||||
|
owner={owner}
|
||||||
|
></Commits>
|
||||||
|
)}
|
||||||
|
</TabPane>
|
||||||
|
)}
|
||||||
|
{filesCount > 0 && (
|
||||||
|
<TabPane
|
||||||
|
tab={
|
||||||
|
<Link to={`/${owner}/${projectsId}/pulls/${mergeId}/files`}>
|
||||||
|
<span className="font-16">文件</span>
|
||||||
|
{filesCount > 0 && (
|
||||||
|
<span className="tabNum">{filesCount}</span>
|
||||||
|
)}
|
||||||
|
</Link>
|
||||||
|
}
|
||||||
|
key="3"
|
||||||
|
>
|
||||||
|
<Files
|
||||||
|
{...this.props}
|
||||||
|
data={filesData}
|
||||||
|
projectsId={projectsId}
|
||||||
|
owner={owner}
|
||||||
|
/>
|
||||||
|
</TabPane>
|
||||||
|
)}
|
||||||
|
</Tabs>
|
||||||
|
</Spin>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
export default MergeFooter;
|
|
@ -1,7 +1,6 @@
|
||||||
import React, { Component } from "react";
|
import React, { Component } from "react";
|
||||||
import { Tabs } from 'antd';
|
import { Tabs } from 'antd';
|
||||||
import { Link } from "react-router-dom";
|
import { Link } from "react-router-dom";
|
||||||
import { AlignCenter } from '../Component/layout';
|
|
||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
import { getImageUrl } from "educoder";
|
import { getImageUrl } from "educoder";
|
||||||
import {
|
import {
|
||||||
|
@ -11,7 +10,6 @@ import {
|
||||||
Dropdown,
|
Dropdown,
|
||||||
Icon,
|
Icon,
|
||||||
Menu,
|
Menu,
|
||||||
Select,
|
|
||||||
Tag,
|
Tag,
|
||||||
Button,
|
Button,
|
||||||
Alert,
|
Alert,
|
||||||
|
@ -19,9 +17,8 @@ import {
|
||||||
import "./merge.css";
|
import "./merge.css";
|
||||||
import RenderHtml from "../../components/render-html";
|
import RenderHtml from "../../components/render-html";
|
||||||
import "../Order/order.css";
|
import "../Order/order.css";
|
||||||
import MergeFooter from "./merge_footer";
|
import MergeLinkFooter from "./MergeLinkFooter";
|
||||||
|
|
||||||
const Option = Select.Option;
|
|
||||||
const TextArea = Input.TextArea;
|
const TextArea = Input.TextArea;
|
||||||
|
|
||||||
function turnbar(str){
|
function turnbar(str){
|
||||||
|
@ -61,6 +58,11 @@ class MessageCount extends Component {
|
||||||
|
|
||||||
// this.clickBody();
|
// this.clickBody();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
bindFootRef = (footRef) => {
|
||||||
|
this.footRef = footRef;
|
||||||
|
}
|
||||||
|
|
||||||
clickBody=()=>{
|
clickBody=()=>{
|
||||||
document.body.addEventListener('click', e => {
|
document.body.addEventListener('click', e => {
|
||||||
let name = e.target.className;
|
let name = e.target.className;
|
||||||
|
@ -150,6 +152,8 @@ class MessageCount extends Component {
|
||||||
});
|
});
|
||||||
const { getDetail } = this.props;
|
const { getDetail } = this.props;
|
||||||
getDetail && getDetail();
|
getDetail && getDetail();
|
||||||
|
// 调用子组件的方法刷新评论列表
|
||||||
|
this.footRef && this.footRef.refreshComment();
|
||||||
} else {
|
} else {
|
||||||
this.setState({ SpinMerge: false });
|
this.setState({ SpinMerge: false });
|
||||||
}
|
}
|
||||||
|
@ -283,13 +287,13 @@ class MessageCount extends Component {
|
||||||
conflict_files && conflict_files.length>0 &&
|
conflict_files && conflict_files.length>0 &&
|
||||||
<div>
|
<div>
|
||||||
<p className="mt10 font-16 pt10" style={{borderTop:"1px solid #f9d7d5"}}>如下文件有代码冲突:</p>
|
<p className="mt10 font-16 pt10" style={{borderTop:"1px solid #f9d7d5"}}>如下文件有代码冲突:</p>
|
||||||
<p>
|
<div>
|
||||||
{
|
{
|
||||||
conflict_files.map((i,k)=>{
|
conflict_files.map((i,k)=>{
|
||||||
return <p>{i}</p>
|
return <p key={k}>{i}</p>
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
</p>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
|
@ -336,11 +340,11 @@ class MessageCount extends Component {
|
||||||
<div>
|
<div>
|
||||||
<div className="main">
|
<div className="main">
|
||||||
<div>
|
<div>
|
||||||
<div className="grid-item-top pb20 border-1f">
|
<div className="pb20 border-1f df">
|
||||||
<div>
|
<div className="flex1">
|
||||||
<div className="ver-middle">
|
<div className="ver-middle">
|
||||||
<span className="mr10 ver-middle">
|
<span className="mr10 ver-middle">
|
||||||
<span className="font-18 fwb">
|
<span className="font-18 fwb" style={{wordBreak:"break-all"}}>
|
||||||
{data.issue.subject}
|
{data.issue.subject}
|
||||||
</span>
|
</span>
|
||||||
</span>
|
</span>
|
||||||
|
@ -362,9 +366,9 @@ class MessageCount extends Component {
|
||||||
<Tag className="pr-branch-tag">
|
<Tag className="pr-branch-tag">
|
||||||
<Link
|
<Link
|
||||||
to={`/${data.pull_request.is_original ? data.pull_request.fork_project_user : data.issue.project_author_name}/${data.pull_request.is_original?data.project_identifier:projectsId}/tree/${turnbar(data.pull_request && data.pull_request.head)}`}
|
to={`/${data.pull_request.is_original ? data.pull_request.fork_project_user : data.issue.project_author_name}/${data.pull_request.is_original?data.project_identifier:projectsId}/tree/${turnbar(data.pull_request && data.pull_request.head)}`}
|
||||||
className="ver-middle"
|
className="ver-middle task-hide" style={{maxWidth:"200px"}} title={`${data.pull_request.is_original ? data.pull_request.fork_project_user : data.issue.project_author_name}: ${data.pull_request && data.pull_request.head}`}
|
||||||
>
|
>
|
||||||
{data.pull_request.is_original ? data.pull_request.fork_project_user : data.issue.project_author_name}: {turnbar(data.pull_request && data.pull_request.head)}
|
{data.pull_request.is_original ? data.pull_request.fork_project_user : data.issue.project_author_name}: {data.pull_request && data.pull_request.head}
|
||||||
</Link>
|
</Link>
|
||||||
</Tag>
|
</Tag>
|
||||||
<span className="mr8 ver-middle">
|
<span className="mr8 ver-middle">
|
||||||
|
@ -377,7 +381,7 @@ class MessageCount extends Component {
|
||||||
<Tag className="pr-branch-tag">
|
<Tag className="pr-branch-tag">
|
||||||
<Link
|
<Link
|
||||||
to={`/${owner}/${projectsId}/tree/${data.pull_request.base}`}
|
to={`/${owner}/${projectsId}/tree/${data.pull_request.base}`}
|
||||||
className="ver-middle"
|
className="ver-middle task-hide" style={{maxWidth:"200px"}} title={`${data.issue.project_author_name}:${data.pull_request.base}`}
|
||||||
>
|
>
|
||||||
{data.issue.project_author_name}:{data.pull_request.base}
|
{data.issue.project_author_name}:{data.pull_request.base}
|
||||||
</Link>
|
</Link>
|
||||||
|
@ -424,7 +428,7 @@ class MessageCount extends Component {
|
||||||
</span>
|
</span>
|
||||||
</span>
|
</span>
|
||||||
<span className="ml25">
|
<span className="ml25">
|
||||||
<span className="color-grey-8">标签:</span>
|
<span className="color-grey-8">标记:</span>
|
||||||
<span className="color-grey-3">
|
<span className="color-grey-3">
|
||||||
{data.issue.issue_tags &&
|
{data.issue.issue_tags &&
|
||||||
data.issue.issue_tags.length > 0
|
data.issue.issue_tags.length > 0
|
||||||
|
@ -441,14 +445,13 @@ class MessageCount extends Component {
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="ml10">
|
<div className="ml10 text-right">
|
||||||
<div className="mt15 text-right" style={{display:"flex",justifyContent:"flex-end"}}>
|
|
||||||
{operate && (
|
{operate && (
|
||||||
<Button
|
<Button
|
||||||
type="green"
|
type="green"
|
||||||
ghost
|
ghost
|
||||||
className="ml20"
|
className="ml20"
|
||||||
onClick={()=>{this.props.history.push(`/${owner}/${projectsId}/pulls/${mergeId}/UpdateMerge`);}}
|
onClick={()=>{this.props.history.push(`/${owner}/${projectsId}/pulls/${mergeId}/edit`);}}
|
||||||
>
|
>
|
||||||
编辑
|
编辑
|
||||||
</Button>
|
</Button>
|
||||||
|
@ -465,7 +468,6 @@ class MessageCount extends Component {
|
||||||
</Button>
|
</Button>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
{
|
{
|
||||||
data.issue.description ?
|
data.issue.description ?
|
||||||
|
@ -543,7 +545,7 @@ class MessageCount extends Component {
|
||||||
onChange={this.changbodypr}
|
onChange={this.changbodypr}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<p
|
<div
|
||||||
className="clearfix mt15"
|
className="clearfix mt15"
|
||||||
style={{ display: this.state.buttonshow }}
|
style={{ display: this.state.buttonshow }}
|
||||||
>
|
>
|
||||||
|
@ -558,19 +560,19 @@ class MessageCount extends Component {
|
||||||
取消
|
取消
|
||||||
</Button>
|
</Button>
|
||||||
</Spin>
|
</Spin>
|
||||||
</p>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Spin>
|
</Spin>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<MergeFooter
|
<MergeLinkFooter
|
||||||
footer_type={true}
|
|
||||||
order_id={data && data.issue.id}
|
order_id={data && data.issue.id}
|
||||||
{...this.props}
|
{...this.props}
|
||||||
{...this.state}
|
{...this.state}
|
||||||
></MergeFooter>
|
bindFootRef={this.bindFootRef}
|
||||||
|
></MergeLinkFooter>
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
""
|
""
|
||||||
|
|
|
@ -6,6 +6,11 @@ import "./merge.css";
|
||||||
import MergeForm from "./merge_form";
|
import MergeForm from "./merge_form";
|
||||||
import MergeFooter from "./merge_footer";
|
import MergeFooter from "./merge_footer";
|
||||||
const Option = Select.Option;
|
const Option = Select.Option;
|
||||||
|
/**
|
||||||
|
* 此文件已废弃,新文件为CreateMerge.js
|
||||||
|
* 2021.10.12
|
||||||
|
*/
|
||||||
|
|
||||||
class NewMerge extends Component {
|
class NewMerge extends Component {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
|
@ -48,8 +53,10 @@ class NewMerge extends Component {
|
||||||
this.compareProject(this.state.id,pull,"master");
|
this.compareProject(this.state.id,pull,"master");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 页面销毁取消监听
|
// 页面销毁取消监听
|
||||||
componentWillUnmount () {
|
componentWillUnmount () {
|
||||||
|
console.log('----------destoyed---------');
|
||||||
window.removeEventListener('popstate', this.handleBack, false);
|
window.removeEventListener('popstate', this.handleBack, false);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -60,8 +67,11 @@ class NewMerge extends Component {
|
||||||
|
|
||||||
//获取新建分支数据
|
//获取新建分支数据
|
||||||
getmergelist = (projectsId) => {
|
getmergelist = (projectsId) => {
|
||||||
this.setState({isSpin: true})
|
this.setState({isSpin: true});
|
||||||
const { owner } = this.props.match.params;
|
// const { owner } = this.props.match.params;
|
||||||
|
let owner =this.props.history.location.pathname.split('/')[1];
|
||||||
|
console.log('owner:'+owner);
|
||||||
|
console.log(this.props);
|
||||||
const url = `/${owner}/${projectsId}/pulls/new.json`;
|
const url = `/${owner}/${projectsId}/pulls/new.json`;
|
||||||
axios
|
axios
|
||||||
.get(url)
|
.get(url)
|
||||||
|
@ -105,6 +115,7 @@ class NewMerge extends Component {
|
||||||
const { author , identifier } =oldProject;
|
const { author , identifier } =oldProject;
|
||||||
url += `/${mergeBranch}...${author && author.login}/${identifier}:${localBranch}.json`;
|
url += `/${mergeBranch}...${author && author.login}/${identifier}:${localBranch}.json`;
|
||||||
}
|
}
|
||||||
|
this.setState({isSpin: true});
|
||||||
axios.get(url).then(result=>{
|
axios.get(url).then(result=>{
|
||||||
if(result){
|
if(result){
|
||||||
if (result.data.status === 0) {
|
if (result.data.status === 0) {
|
||||||
|
@ -123,7 +134,9 @@ class NewMerge extends Component {
|
||||||
comparesData:result.data
|
comparesData:result.data
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}).catch(error=>{})
|
}).catch(error=>{
|
||||||
|
this.setState({isSpin: false});
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -186,7 +199,7 @@ class NewMerge extends Component {
|
||||||
// this.ischeckmerge();
|
// this.ischeckmerge();
|
||||||
let { id ,merge , pull } = this.state;
|
let { id ,merge , pull } = this.state;
|
||||||
if(type==="pull"){
|
if(type==="pull"){
|
||||||
this.props.history.push(`/${owner}/${projectsId}/pulls/new/${pull}`)
|
this.props.history.push(`/${owner}/${projectsId}/compare/${pull}`)
|
||||||
this.compareProject(id,value,merge);
|
this.compareProject(id,value,merge);
|
||||||
}else{
|
}else{
|
||||||
this.compareProject(id,pull,value);
|
this.compareProject(id,pull,value);
|
||||||
|
@ -208,7 +221,7 @@ class NewMerge extends Component {
|
||||||
merge_user_login: is_fork_id ? projects_names[0].project_user_login : undefined
|
merge_user_login: is_fork_id ? projects_names[0].project_user_login : undefined
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
this.props.history.push(`/${login}/${identifier}/pulls/new`);
|
this.props.history.push(`/${login}/${identifier}/compare`);
|
||||||
this.newMergelist(login,identifier);
|
this.newMergelist(login,identifier);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -264,7 +277,9 @@ class NewMerge extends Component {
|
||||||
show_message,
|
show_message,
|
||||||
default_message,
|
default_message,
|
||||||
merge_head,
|
merge_head,
|
||||||
projects_names,id,comparesData
|
projects_names,
|
||||||
|
id,
|
||||||
|
comparesData
|
||||||
} = this.state;
|
} = this.state;
|
||||||
|
|
||||||
const renderBrances = (list, type) => {
|
const renderBrances = (list, type) => {
|
||||||
|
@ -298,6 +313,7 @@ class NewMerge extends Component {
|
||||||
return <div dangerouslySetInnerHTML={{ __html: html }}></div>;
|
return <div dangerouslySetInnerHTML={{ __html: html }}></div>;
|
||||||
};
|
};
|
||||||
let { project } = this.props;
|
let { project } = this.props;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<div className="main">
|
<div className="main">
|
||||||
|
|
|
@ -64,12 +64,12 @@ class UpdateMerge extends Component {
|
||||||
<div className="color-grey-3 mb10 fwb">源分支:</div>
|
<div className="color-grey-3 mb10 fwb">源分支:</div>
|
||||||
|
|
||||||
<Input.Group compact className="display-flex">
|
<Input.Group compact className="display-flex">
|
||||||
<Button className="merge-header-button maxW50 hide-1 task-hide">
|
<Button className="merge-header-button flex1 maxW50 hide-1 task-hide" disabled>
|
||||||
{data.is_original ? `${data.fork_project_user_name}/${data.fork_project_identifier}` : `${data.project_author}/${data.project_name}`}
|
{data.is_original ? `${data.fork_project_user_name}/${data.fork_project_identifier}` : `${data.project_author}/${data.project_name}`}
|
||||||
</Button>
|
</Button>
|
||||||
<Select
|
<Select
|
||||||
defaultValue={data.is_original ? `${data.fork_project_user}:${pull}` : `${pull}`}
|
defaultValue={data.is_original ? `${data.fork_project_user}:${pull}` : `${pull}`}
|
||||||
className="minW50 merge-flex1"
|
className="minW50 merge-flex1 flex1 matchwidth"
|
||||||
disabled
|
disabled
|
||||||
></Select>{" "}
|
></Select>{" "}
|
||||||
</Input.Group>{" "}
|
</Input.Group>{" "}
|
||||||
|
@ -83,12 +83,12 @@ class UpdateMerge extends Component {
|
||||||
<div>
|
<div>
|
||||||
<div className="color-grey-3 mb10 fwb"> 目标分支 : </div>{" "}
|
<div className="color-grey-3 mb10 fwb"> 目标分支 : </div>{" "}
|
||||||
<Input.Group compact className="display-flex">
|
<Input.Group compact className="display-flex">
|
||||||
<Button className="merge-header-button maxW50 hide-1 task-hide">
|
<Button className="merge-header-button flex1 maxW50 hide-1 task-hide" disabled>
|
||||||
{`${data.project_author}/${data.project_name}`}
|
{`${data.project_author}/${data.project_name}`}
|
||||||
</Button>
|
</Button>
|
||||||
<Select
|
<Select
|
||||||
defaultValue={data.is_original ? `${data.project_login}:${merge}` : `${merge}`}
|
defaultValue={data.is_original ? `${data.project_login}:${merge}` : `${merge}`}
|
||||||
className="minW50 merge-flex1"
|
className="minW50 merge-flex1 flex1 matchwidth"
|
||||||
disabled
|
disabled
|
||||||
></Select>{" "}
|
></Select>{" "}
|
||||||
</Input.Group>{" "}
|
</Input.Group>{" "}
|
||||||
|
|
|
@ -40,6 +40,7 @@ form .ant-cascader-picker, form .ant-select {
|
||||||
}
|
}
|
||||||
.merge-header-button{
|
.merge-header-button{
|
||||||
background:rgba(241,248,255,1);
|
background:rgba(241,248,255,1);
|
||||||
|
text-align: left;
|
||||||
}
|
}
|
||||||
.width70{
|
.width70{
|
||||||
width:70%;
|
width:70%;
|
||||||
|
@ -152,13 +153,23 @@ form .ant-cascader-picker, form .ant-select {
|
||||||
margin-top: 15px;
|
margin-top: 15px;
|
||||||
border-radius: 2px;
|
border-radius: 2px;
|
||||||
}
|
}
|
||||||
|
.see-file-btn{
|
||||||
|
color: #466AFF;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
.filesInfo{
|
.filesInfo{
|
||||||
padding:10px 15px;
|
padding:10px 15px;
|
||||||
background-color: #fafafa;
|
background-color: #fafafa;
|
||||||
}
|
}
|
||||||
|
.filesInfo .cursor-pointer{
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
.filesContent{
|
.filesContent{
|
||||||
border-top: 1px solid #ddd;
|
border-top: 1px solid #ddd;
|
||||||
}
|
}
|
||||||
|
.icon-fuzhiicon:hover{
|
||||||
|
color: #466AFF;
|
||||||
|
}
|
||||||
.linesContent{
|
.linesContent{
|
||||||
display: flex;
|
display: flex;
|
||||||
min-height: 30px;
|
min-height: 30px;
|
||||||
|
@ -199,3 +210,16 @@ form .ant-cascader-picker, form .ant-select {
|
||||||
.linesContent.add{
|
.linesContent.add{
|
||||||
background: rgba(48, 232, 132, 0.15);
|
background: rgba(48, 232, 132, 0.15);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.mergeRequest .folders{
|
||||||
|
/* width: 72rem; */
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.matchwidth .ant-select-selection__rendered{
|
||||||
|
width: 200px;
|
||||||
|
}
|
||||||
|
.overlihide li{
|
||||||
|
max-width: 450px;
|
||||||
|
|
||||||
|
}
|
|
@ -43,7 +43,7 @@ class merge extends Component {
|
||||||
//设置选择高亮
|
//设置选择高亮
|
||||||
openselect: 1,
|
openselect: 1,
|
||||||
closeselect: undefined,
|
closeselect: undefined,
|
||||||
issue_tag_ids: "标签",
|
issue_tag_ids: "标记",
|
||||||
fixed_version_ids: "里程碑",
|
fixed_version_ids: "里程碑",
|
||||||
assigned_to_ids: "审查人员",
|
assigned_to_ids: "审查人员",
|
||||||
paix: "排序",
|
paix: "排序",
|
||||||
|
@ -198,7 +198,7 @@ class merge extends Component {
|
||||||
});
|
});
|
||||||
this.setState({
|
this.setState({
|
||||||
status_type: type,
|
status_type: type,
|
||||||
issue_tag_ids: "标签",
|
issue_tag_ids: "标记",
|
||||||
fixed_version_ids: "里程碑",
|
fixed_version_ids: "里程碑",
|
||||||
assigned_to_ids: "审查人员",
|
assigned_to_ids: "审查人员",
|
||||||
paix: "排序",
|
paix: "排序",
|
||||||
|
@ -213,7 +213,7 @@ class merge extends Component {
|
||||||
|
|
||||||
checkOperation() {
|
checkOperation() {
|
||||||
const { projectsId,owner } = this.props.match.params;
|
const { projectsId,owner } = this.props.match.params;
|
||||||
this.props.history.push(`/${owner}/${projectsId}/pulls/new`);
|
this.props.history.push(`/${owner}/${projectsId}/compare/master...master`);
|
||||||
}
|
}
|
||||||
render() {
|
render() {
|
||||||
const { projectsId , owner } = this.props.match.params;
|
const { projectsId , owner } = this.props.match.params;
|
||||||
|
@ -321,7 +321,7 @@ class merge extends Component {
|
||||||
className="topWrapperSelect"
|
className="topWrapperSelect"
|
||||||
overlay={this.renderMenu(
|
overlay={this.renderMenu(
|
||||||
issue_chosen && issue_chosen.issue_tag,
|
issue_chosen && issue_chosen.issue_tag,
|
||||||
"标签",
|
"标记",
|
||||||
"issue_tag_id"
|
"issue_tag_id"
|
||||||
)}
|
)}
|
||||||
trigger={["click"]}
|
trigger={["click"]}
|
||||||
|
|
|
@ -1,169 +1,84 @@
|
||||||
import React, { Component } from "react";
|
import React, { Component } from 'react';
|
||||||
import { Tabs, Spin } from "antd";
|
import { Tabs } from 'antd';
|
||||||
import "../Order/order.css";
|
import Commits from './Commits';
|
||||||
import "./merge.css";
|
import Files from './Files';
|
||||||
import Commits from "./Commits";
|
|
||||||
import Comments from "../comments/comments";
|
import '../Order/order.css';
|
||||||
import Files from "./Files";
|
import './merge.css';
|
||||||
import axios from 'axios';
|
|
||||||
const { TabPane } = Tabs;
|
const { TabPane } = Tabs;
|
||||||
|
|
||||||
class MergeFooter extends Component {
|
class MergeFooter extends Component {
|
||||||
constructor(props){
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
this.state={
|
this.state = {
|
||||||
pageData:undefined,
|
activeKey: '1',
|
||||||
commitsData:undefined,
|
};
|
||||||
filesData:undefined,
|
|
||||||
isSpin:false,
|
|
||||||
activeKey:"1",
|
|
||||||
commitCount:0,
|
|
||||||
filesCount:0
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
componentDidMount=()=>{
|
|
||||||
const { footer_type ,data } = this.props;
|
changeTab = (index) => {
|
||||||
if(footer_type){
|
|
||||||
const { projectsId , owner , mergeId } = this.props.match.params;
|
|
||||||
this.getCommit(owner,projectsId,mergeId);
|
|
||||||
this.getFile(owner,projectsId,mergeId);
|
|
||||||
}
|
|
||||||
this.setState({
|
this.setState({
|
||||||
activeKey:footer_type ? "1" : "2",
|
activeKey: index,
|
||||||
commitCount:data && data.commits_count,
|
});
|
||||||
filesCount:data && data.files_count
|
};
|
||||||
})
|
|
||||||
}
|
|
||||||
componentDidUpdate=(prevProps)=>{
|
|
||||||
const { comparesData } = this.props;
|
|
||||||
const { footer_type } = this.props;
|
|
||||||
if(footer_type){
|
|
||||||
const { data } = this.props;
|
|
||||||
if(data !== prevProps.data){
|
|
||||||
this.setState({
|
|
||||||
commitCount:data && data.commits_count,
|
|
||||||
filesCount:data && data.files_count
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(comparesData !== prevProps.comparesData){
|
|
||||||
this.setState({
|
|
||||||
activeKey:footer_type ? "1" : "2"
|
|
||||||
})
|
|
||||||
this.changeTab(footer_type ? "1" : "2");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
changeTab=(index)=>{
|
|
||||||
this.setState({
|
|
||||||
isSpin:true
|
|
||||||
})
|
|
||||||
this.setState({
|
|
||||||
activeKey:index
|
|
||||||
})
|
|
||||||
const { footer_type , comparesData } = this.props;
|
|
||||||
const { projectsId , owner , mergeId } = this.props.match.params;
|
|
||||||
|
|
||||||
if(footer_type){
|
|
||||||
if(index === "2"){
|
|
||||||
this.getCommit(owner,projectsId,mergeId);
|
|
||||||
}else if(index === "3"){
|
|
||||||
this.getFile(owner,projectsId,mergeId);
|
|
||||||
}else{
|
|
||||||
this.setState({
|
|
||||||
isSpin:false
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}else{
|
|
||||||
this.setState({
|
|
||||||
commitsData:comparesData.commits,
|
|
||||||
filesData:comparesData.diff,
|
|
||||||
commitCount:comparesData.commits_count,
|
|
||||||
filesCount:comparesData.diff && comparesData.diff.files_count,
|
|
||||||
isSpin:false
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
getCommit =(owner,projectsId,mergeId)=>{
|
|
||||||
const url = `/${owner}/${projectsId}/pulls/${mergeId}/commits.json`;
|
|
||||||
axios.get(url).then(result=>{
|
|
||||||
if(result){
|
|
||||||
this.setState({
|
|
||||||
commitsData:result.data.commits,
|
|
||||||
isSpin:false,
|
|
||||||
commitCount:result.data.commits_count
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}).catch(error=>{})
|
|
||||||
}
|
|
||||||
|
|
||||||
getFile =(owner,projectsId,mergeId)=>{
|
|
||||||
const url = `/${owner}/${projectsId}/pulls/${mergeId}/files.json`;
|
|
||||||
axios.get(url).then(result=>{
|
|
||||||
if(result){
|
|
||||||
this.setState({
|
|
||||||
filesData:result.data,
|
|
||||||
isSpin:false,
|
|
||||||
filesCount:result.data.files_count,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}).catch(error=>{})
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { projectsId , owner } = this.props.match.params;
|
const { projectsId, owner } = this.props.match.params;
|
||||||
|
const { comparesData = {} } = this.props;
|
||||||
|
const { commits, diff, commits_count } = comparesData;
|
||||||
|
const { activeKey } = this.state;
|
||||||
|
|
||||||
const { footer_type, order_id, data , comparesData } = this.props;
|
return (commits && commits.length === 0) || !diff ? (
|
||||||
let { isSpin , activeKey , filesCount, commitCount , filesData , commitsData } = this.state;
|
''
|
||||||
|
) : (
|
||||||
return (
|
<div className="main mergeRequest" style={{ paddingTop: '0px' }}>
|
||||||
!footer_type && !comparesData || (comparesData && ((comparesData.commits && comparesData.commits.length===0)||(comparesData && !comparesData.diff)) )?"":
|
<Tabs
|
||||||
<div className="main" style={{paddingTop:"0px"}}>
|
activeKey={activeKey}
|
||||||
<Spin spinning={isSpin}>
|
className="custom-commit-tabs"
|
||||||
<Tabs
|
animated={false}
|
||||||
activeKey={activeKey}
|
onChange={this.changeTab}
|
||||||
className="custom-commit-tabs"
|
>
|
||||||
animated={false}
|
{commits && commits.length > 0 && (
|
||||||
onChange={this.changeTab}
|
<TabPane
|
||||||
>
|
tab={
|
||||||
{
|
<span>
|
||||||
footer_type &&
|
<span className="font-16">提交</span>
|
||||||
<TabPane
|
{commits_count > 0 && (
|
||||||
tab={
|
<span className="tabNum">{commits_count}</span>
|
||||||
<span><span className="font-16">评论</span>
|
)}
|
||||||
{data && parseInt(data.comments_count) > 0 && <span className="tabNum">{data.comments_count}</span>}
|
</span>
|
||||||
</span>
|
}
|
||||||
} key="1">
|
key="1"
|
||||||
<Comments
|
>
|
||||||
order_id={order_id}
|
<Commits
|
||||||
showNotification={this.props.showNotification}
|
{...this.props}
|
||||||
only_show_content={true}
|
commits={commits}
|
||||||
{...this.props}
|
projectsId={projectsId}
|
||||||
/>
|
owner={owner}
|
||||||
</TabPane>
|
></Commits>
|
||||||
}
|
</TabPane>
|
||||||
{
|
)}
|
||||||
commitsData && commitsData.length > 0 &&
|
{diff && diff.files && diff.files.length > 0 && (
|
||||||
<TabPane tab={<span><span className="font-16">提交</span>
|
<TabPane
|
||||||
{commitCount > 0 && <span className="tabNum">{commitCount}</span>}
|
tab={
|
||||||
</span>} key="2">
|
<span>
|
||||||
<Commits {...this.props} commits={commitsData} projectsId={projectsId} owner={owner}></Commits>
|
<span className="font-16">文件</span>
|
||||||
</TabPane>
|
{diff.files_count > 0 && (
|
||||||
}
|
<span className="tabNum">{diff.files_count}</span>
|
||||||
{
|
)}
|
||||||
filesData && filesData.files && filesData.files.length>0 &&
|
</span>
|
||||||
<TabPane tab={
|
}
|
||||||
<span><span className="font-16">文件</span>
|
key="3"
|
||||||
{filesCount > 0 && <span className="tabNum">{filesCount}</span>}
|
>
|
||||||
</span>
|
<Files
|
||||||
} key="3">
|
{...this.props}
|
||||||
<Files {...this.props} data={filesData} projectsId={projectsId} owner={owner}/>
|
data={diff}
|
||||||
</TabPane>
|
projectsId={projectsId}
|
||||||
}
|
owner={owner}
|
||||||
|
/>
|
||||||
</Tabs>
|
</TabPane>
|
||||||
</Spin>
|
)}
|
||||||
|
</Tabs>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -165,7 +165,8 @@ class MergeForm extends Component {
|
||||||
this.setState({
|
this.setState({
|
||||||
isSpin: false,
|
isSpin: false,
|
||||||
});
|
});
|
||||||
this.props.history.push(`/${owner}/${projectsId}/pulls`);
|
const { pull_request_id } = result.data;
|
||||||
|
this.props.history.push(`/${owner}/${projectsId}/pulls/${pull_request_id}`);
|
||||||
const { getDetail } = this.props;
|
const { getDetail } = this.props;
|
||||||
getDetail && getDetail();
|
getDetail && getDetail();
|
||||||
} else {
|
} else {
|
||||||
|
@ -195,7 +196,7 @@ class MergeForm extends Component {
|
||||||
isSpin: false,
|
isSpin: false,
|
||||||
});
|
});
|
||||||
this.props.history.push(
|
this.props.history.push(
|
||||||
`/${owner}/${projectsId}/pulls/${mergeId}/Messagecount`
|
`/${owner}/${projectsId}/pulls/${mergeId}`
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
this.setState({
|
this.setState({
|
||||||
|
@ -264,7 +265,7 @@ class MergeForm extends Component {
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
initialValue: title,
|
initialValue: title,
|
||||||
})(<Input placeholder="标题" maxLength={50} />)}
|
})(<Input placeholder="标题" maxLength={200} />)}
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<MDEditor
|
<MDEditor
|
||||||
placeholder={"请输入合并请求的描述..."}
|
placeholder={"请输入合并请求的描述..."}
|
||||||
|
@ -287,7 +288,7 @@ class MergeForm extends Component {
|
||||||
type="default"
|
type="default"
|
||||||
className="ml30"
|
className="ml30"
|
||||||
onClick={()=>{
|
onClick={()=>{
|
||||||
this.props.history.push(merge_type === "new" ? `/${owner}/${projectsId}/pulls` : `/${owner}/${projectsId}/pulls/${mergeId}/detail`)
|
this.props.history.push(merge_type === "new" ? `/${owner}/${projectsId}/pulls` : `/${owner}/${projectsId}/pulls/${mergeId}`)
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<span className="plr10">取消</span>
|
<span className="plr10">取消</span>
|
||||||
|
@ -300,7 +301,8 @@ class MergeForm extends Component {
|
||||||
{getFieldDecorator("assigned_to_id", {
|
{getFieldDecorator("assigned_to_id", {
|
||||||
initialValue: assigned_to_id,
|
initialValue: assigned_to_id,
|
||||||
})(
|
})(
|
||||||
<Select placeholder="审查人员" showSearch>
|
<Select placeholder="未选择审查人员" showSearch>
|
||||||
|
<Option key={0} value={""}>未选择审查人员</Option>
|
||||||
{this.renderSelect(members)}
|
{this.renderSelect(members)}
|
||||||
</Select>
|
</Select>
|
||||||
)}
|
)}
|
||||||
|
@ -311,12 +313,11 @@ class MergeForm extends Component {
|
||||||
})(
|
})(
|
||||||
<Select
|
<Select
|
||||||
placeholder={
|
placeholder={
|
||||||
issue_versions && issue_versions.length > 0
|
issue_versions && issue_versions.length > 0? "未选择里程碑": "请添加里程碑"
|
||||||
? "未选择里程碑"
|
|
||||||
: "请添加里程碑"
|
|
||||||
}
|
}
|
||||||
showSearch
|
showSearch
|
||||||
>
|
>
|
||||||
|
<Option key={0} value={""}>{issue_versions && issue_versions.length > 0? "未选择里程碑": "请添加里程碑"}</Option>
|
||||||
{this.renderSelect(issue_versions)}
|
{this.renderSelect(issue_versions)}
|
||||||
</Select>
|
</Select>
|
||||||
)}
|
)}
|
||||||
|
@ -327,12 +328,11 @@ class MergeForm extends Component {
|
||||||
})(
|
})(
|
||||||
<Select
|
<Select
|
||||||
placeholder={
|
placeholder={
|
||||||
issue_tags && issue_tags.length > 0
|
issue_tags && issue_tags.length > 0 ? "未选择标记" : "请在仓库设置里添加标记"
|
||||||
? "未选择标签"
|
|
||||||
: "请在仓库设置里添加标签"
|
|
||||||
}
|
}
|
||||||
showSearch
|
showSearch
|
||||||
>
|
>
|
||||||
|
<Option key={0} value={""}>{issue_tags && issue_tags.length > 0 ? "未选择标记" : "请在仓库设置里添加标记"}</Option>
|
||||||
{this.renderSelect(issue_tags)}
|
{this.renderSelect(issue_tags)}
|
||||||
</Select>
|
</Select>
|
||||||
)}
|
)}
|
||||||
|
|
|
@ -12,7 +12,7 @@ class Nodata extends Component{
|
||||||
<h3>欢迎使用合并请求!</h3>
|
<h3>欢迎使用合并请求!</h3>
|
||||||
|
|
||||||
<div className="color-grey-8">
|
<div className="color-grey-8">
|
||||||
合并请求可以帮助您与他人协作编写代码。在使用之前,请先创建一个 <Link className="color-blue" to={`/${owner}/${projectsId}/pulls/new`}>合并请求</Link>
|
合并请求可以帮助您与他人协作编写代码。在使用之前,请先创建一个 <Link className="color-blue" to={`/${owner}/${projectsId}/compare/master...master`}>合并请求</Link>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -2,9 +2,10 @@ import React, { Component } from 'react';
|
||||||
import { Link } from 'react-router-dom';
|
import { Link } from 'react-router-dom';
|
||||||
import { Input , Form , Select , Checkbox , Button , Spin , AutoComplete, Modal } from 'antd';
|
import { Input , Form , Select , Checkbox , Button , Spin , AutoComplete, Modal } from 'antd';
|
||||||
import { Base64 } from 'js-base64';
|
import { Base64 } from 'js-base64';
|
||||||
|
import { AlignCenter } from '../Component/layout';
|
||||||
|
|
||||||
import '../css/index.scss';
|
import '../css/index.scss';
|
||||||
import './new.css'
|
import './new.scss'
|
||||||
|
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
const Option = Select.Option;
|
const Option = Select.Option;
|
||||||
|
@ -44,7 +45,12 @@ class Index extends Component {
|
||||||
project_category_name: undefined,
|
project_category_name: undefined,
|
||||||
license_name: undefined,
|
license_name: undefined,
|
||||||
ignore_name: undefined,
|
ignore_name: undefined,
|
||||||
descNum:0
|
descNum:0,
|
||||||
|
|
||||||
|
categoreFlag:false,
|
||||||
|
languageFlag:false,
|
||||||
|
ignoreFlag:false,
|
||||||
|
licenseFlag:false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
componentDidMount = () => {
|
componentDidMount = () => {
|
||||||
|
@ -149,7 +155,7 @@ class Index extends Component {
|
||||||
if (mirror_status === 2 && sessionStorage.newProjectValue) {
|
if (mirror_status === 2 && sessionStorage.newProjectValue) {
|
||||||
Modal.warning({
|
Modal.warning({
|
||||||
title: '警告',
|
title: '警告',
|
||||||
content: '镜像项目创建失败!请按操作规范重新创建项目!',
|
content: '项目导入失败!请按操作规范重新导入项目!',
|
||||||
});
|
});
|
||||||
let newProjectValue = JSON.parse(sessionStorage.newProjectValue);
|
let newProjectValue = JSON.parse(sessionStorage.newProjectValue);
|
||||||
if (newProjectValue) {
|
if (newProjectValue) {
|
||||||
|
@ -189,12 +195,16 @@ class Index extends Component {
|
||||||
|
|
||||||
subMitFrom = () => {
|
subMitFrom = () => {
|
||||||
this.props.form.validateFieldsAndScroll((err, values) => {
|
this.props.form.validateFieldsAndScroll((err, values) => {
|
||||||
|
console.log(values);
|
||||||
if (!err) {
|
if (!err) {
|
||||||
this.setState({
|
this.setState({
|
||||||
isSpin: true
|
isSpin: true
|
||||||
})
|
})
|
||||||
const { projectsType } = this.props.match.params;
|
const { projectsType } = this.props.match.params;
|
||||||
const { project_language_id, project_category_id, license_id, ignore_id , owners_id , owners_name } = this.state;
|
const {
|
||||||
|
project_language_id, project_category_id, license_id, ignore_id , owners_id ,
|
||||||
|
ignoreFlag,licenseFlag,categoreFlag,languageFlag
|
||||||
|
} = this.state;
|
||||||
const decoderPass = Base64.encode(values.password);
|
const decoderPass = Base64.encode(values.password);
|
||||||
const url = (projectsType && projectsType === "mirror") ? "/projects/migrate.json" : "/projects.json";
|
const url = (projectsType && projectsType === "mirror") ? "/projects/migrate.json" : "/projects.json";
|
||||||
// 新建项目的时候,暂存数据,如果失败,返回的时候可以重新赋值
|
// 新建项目的时候,暂存数据,如果失败,返回的时候可以重新赋值
|
||||||
|
@ -202,14 +212,14 @@ class Index extends Component {
|
||||||
axios.post(url, {
|
axios.post(url, {
|
||||||
...values,
|
...values,
|
||||||
auth_password:decoderPass,
|
auth_password:decoderPass,
|
||||||
project_language_id,
|
project_language_id:languageFlag ? project_language_id : undefined,
|
||||||
project_category_id,
|
project_category_id:categoreFlag ? project_category_id : undefined,
|
||||||
license_id,
|
license_id:licenseFlag ? license_id : undefined,
|
||||||
ignore_id,
|
ignore_id:ignoreFlag ? ignore_id : undefined,
|
||||||
user_id:owners_id
|
user_id:owners_id
|
||||||
}).then((result) => {
|
}).then((result) => {
|
||||||
if (result && result.data.id) {
|
if (result && result.data.id) {
|
||||||
projectsType && projectsType !== "mirror" && this.props.showNotification(`托管项目创建成功!`);
|
projectsType && projectsType !== "mirror" && this.props.showNotification(`项目创建成功!`);
|
||||||
this.props.history.push(`/${result.data.login}/${result.data.identifier}`);
|
this.props.history.push(`/${result.data.login}/${result.data.identifier}`);
|
||||||
}
|
}
|
||||||
this.setState({
|
this.setState({
|
||||||
|
@ -275,12 +285,16 @@ class Index extends Component {
|
||||||
if(value.indexOf("/") > -1){
|
if(value.indexOf("/") > -1){
|
||||||
let arr = value.split("/");
|
let arr = value.split("/");
|
||||||
let first = arr[arr.length-1];
|
let first = arr[arr.length-1];
|
||||||
if(first.indexOf(".git") > -1){
|
if(first.indexOf(".") > -1){
|
||||||
let second = first.split('.')[0];
|
let second = first.split('.')[0];
|
||||||
if(!second)return;
|
if(!second)return;
|
||||||
this.props.form.setFieldsValue({
|
this.props.form.setFieldsValue({
|
||||||
repository_name:second
|
repository_name:second
|
||||||
})
|
})
|
||||||
|
}else{
|
||||||
|
this.props.form.setFieldsValue({
|
||||||
|
repository_name:first
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -313,48 +327,35 @@ class Index extends Component {
|
||||||
|
|
||||||
mirrorCheck,
|
mirrorCheck,
|
||||||
|
|
||||||
descNum
|
descNum,
|
||||||
|
|
||||||
|
ignoreFlag,
|
||||||
|
licenseFlag,
|
||||||
|
languageFlag,
|
||||||
|
categoreFlag
|
||||||
} = this.state;
|
} = this.state;
|
||||||
return (
|
return (
|
||||||
<div className="main back-white" style={{padding:"0px",border:"none"}}>
|
<div className="main back-white" style={{padding:"0px",border:"none"}}>
|
||||||
<div className="newPanel">
|
<div className="newPanel">
|
||||||
<div className="newPanel_title">创建{projectsType && projectsType === "mirror" ? "镜像" : "托管"}项目</div>
|
<div className="newPanel_title">{projectsType && projectsType === "mirror" ? "导入" : "新建"}项目</div>
|
||||||
<Spin spinning={isSpin}>
|
<Spin spinning={isSpin}>
|
||||||
<Form>
|
<Form>
|
||||||
<div className="newPanel_content">
|
<div className="newPanel_content">
|
||||||
<Form.Item
|
|
||||||
label="拥有者"
|
{
|
||||||
>
|
|
||||||
{getFieldDecorator('user_id', {
|
|
||||||
rules: [{
|
|
||||||
required: true, message: '请选择拥有者'
|
|
||||||
},{
|
|
||||||
validator:(rule, value, callback) => this.checkId(rule, value, callback, OwnerList, '拥有者')
|
|
||||||
}],
|
|
||||||
})(
|
|
||||||
<AutoComplete
|
|
||||||
placeholder="请选择拥有者"
|
|
||||||
onChange={(value, e) => this.ChangePlatform(value, e, 'owners', OwnerList)}
|
|
||||||
className="plateAutoComplete"
|
|
||||||
onBlur={(value) => this.blurCategory(value, OwnerList, "owners")}
|
|
||||||
>
|
|
||||||
{owners_list}
|
|
||||||
</AutoComplete>
|
|
||||||
)}
|
|
||||||
</Form.Item>
|
|
||||||
{
|
|
||||||
projectsType && projectsType === "mirror" &&
|
projectsType && projectsType === "mirror" &&
|
||||||
<React.Fragment>
|
<React.Fragment>
|
||||||
<Form.Item
|
<Form.Item
|
||||||
label="镜像版本库地址"
|
label="导入仓库URL"
|
||||||
style={{ marginBottom: "0px" }}
|
style={{ marginBottom: "0px" }}
|
||||||
|
colon={false}
|
||||||
>
|
>
|
||||||
{getFieldDecorator('clone_addr', {
|
{getFieldDecorator('clone_addr', {
|
||||||
rules: [{
|
rules: [{
|
||||||
required: true, message: '请填写镜像版本库地址'
|
required: true, message: '请填写镜像版本库地址'
|
||||||
}],
|
}],
|
||||||
})(
|
})(
|
||||||
<Input placeholder="输入需要同步到本项目的镜像版本库地址" onChange={this.ChangeAddr} />
|
<Input placeholder="请输入需要导入到本项目的仓库地址" onBlur={this.ChangeAddr} />
|
||||||
)}
|
)}
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<p className="formTip color-orange">示例:https://github.com/facebook/reack.git</p>
|
<p className="formTip color-orange">示例:https://github.com/facebook/reack.git</p>
|
||||||
|
@ -362,14 +363,16 @@ class Index extends Component {
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
projectsType && projectsType === "mirror" &&
|
projectsType && projectsType === "mirror" &&
|
||||||
<React.Fragment>
|
<div className="pb10">
|
||||||
<p className="mt10 mb10 color-grey-3 pointer" onClick={this.changeMirrorCheck}>
|
<p className="mt10 mb10 color-grey-3 pointer" onClick={this.changeMirrorCheck}>
|
||||||
需要授权验证<i className={mirrorCheck?"iconfont icon-xiajiantou font-13 ml10 color-grey-8":"iconfont icon-youjiantou font-13 ml10 color-grey-8"}></i>
|
需要授权验证<i className={mirrorCheck ? "iconfont icon-xiajiantou font-13 ml10 color-grey-8":"iconfont icon-youjiantou font-13 ml10 color-grey-8"}></i>
|
||||||
<span className="ml20 font-12 color-red">如果源项目为公有仓库,禁止填写用户名密码。如果源项目为私有仓库,则必须填写正确的用户名和密码!</span></p>
|
<span className="ml20 font-12 color-red">如果导入项目为私有仓库,则必须填写相应平台正确的用户名和密码</span>
|
||||||
|
</p>
|
||||||
{
|
{
|
||||||
mirrorCheck &&
|
mirrorCheck &&
|
||||||
<div className="df mb20" style={{alignItems:'center'}}>
|
<div className="df mb10" style={{alignItems:'center'}}>
|
||||||
<span className="mr10">用户名</span>
|
<span className="mr10">用户名</span>
|
||||||
|
<input type="password" style={{display:"none"}} />
|
||||||
<Form.Item
|
<Form.Item
|
||||||
style={{ marginBottom: "0px" }}
|
style={{ marginBottom: "0px" }}
|
||||||
label=""
|
label=""
|
||||||
|
@ -383,153 +386,153 @@ class Index extends Component {
|
||||||
<span className="mr10">密码</span>
|
<span className="mr10">密码</span>
|
||||||
<Form.Item
|
<Form.Item
|
||||||
style={{ marginBottom: "0px" }}
|
style={{ marginBottom: "0px" }}
|
||||||
label=""
|
|
||||||
>
|
>
|
||||||
{getFieldDecorator('password', {
|
{getFieldDecorator('password', {
|
||||||
rules: [],
|
rules: [],
|
||||||
})(
|
})(
|
||||||
<Input placeholder="请输入对应平台的登录密码" type="password" style={{width:"240px"}}/>
|
<Input.Password placeholder="请输入对应平台的登录密码" autocomplete='new-password' style={{width:"240px"}}/>
|
||||||
)}
|
)}
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
</React.Fragment>
|
</div>
|
||||||
}
|
}
|
||||||
|
<AlignCenter>
|
||||||
|
<Form.Item
|
||||||
|
label="拥有者"
|
||||||
|
style={{width:"260px"}}
|
||||||
|
colon={false}
|
||||||
|
className="explainPos"
|
||||||
|
>
|
||||||
|
{getFieldDecorator('user_id', {
|
||||||
|
rules: [{
|
||||||
|
required: true, message: '请选择拥有者'
|
||||||
|
},{
|
||||||
|
validator:(rule, value, callback) => this.checkId(rule, value, callback, OwnerList, '拥有者')
|
||||||
|
}],
|
||||||
|
})(
|
||||||
|
<AutoComplete
|
||||||
|
style={{width:"260px",height:"35px"}}
|
||||||
|
placeholder="请选择拥有者"
|
||||||
|
onChange={(value, e) => this.ChangePlatform(value, e, 'owners', OwnerList)}
|
||||||
|
className="plateAutoComplete"
|
||||||
|
onBlur={(value) => this.blurCategory(value, OwnerList, "owners")}
|
||||||
|
>
|
||||||
|
{owners_list}
|
||||||
|
</AutoComplete>
|
||||||
|
)}
|
||||||
|
</Form.Item>
|
||||||
|
<span className="ml10 mr10 mt10 font-18">/</span>
|
||||||
|
<Form.Item
|
||||||
|
label="项目名称"
|
||||||
|
className="flex1 explainPos"
|
||||||
|
colon={false}
|
||||||
|
>
|
||||||
|
{getFieldDecorator('name', {
|
||||||
|
rules: [{
|
||||||
|
required: true, message: '请填写项目名称'
|
||||||
|
}],
|
||||||
|
})(
|
||||||
|
<Input placeholder="例如:团队协作方法与研究" maxLength={50}/>
|
||||||
|
)}
|
||||||
|
</Form.Item>
|
||||||
|
</AlignCenter>
|
||||||
<Form.Item
|
<Form.Item
|
||||||
label="项目名称"
|
label={<span>项目标识 <span className="color-grey-9">(项目url标识部分)</span></span>}
|
||||||
|
colon={false}
|
||||||
>
|
>
|
||||||
{getFieldDecorator('name', {
|
{getFieldDecorator('repository_name', {
|
||||||
rules: [{
|
rules: [{
|
||||||
required: true, message: '请填写项目名称'
|
required: true, message: '请填写项目标识'
|
||||||
}],
|
}],
|
||||||
})(
|
})(
|
||||||
<Input placeholder="例如:团队协作方法与研究" maxLength={50}/>
|
<Input placeholder="项目标识请使用与项目相关的英文关键字" maxLength={100} />
|
||||||
)}
|
)}
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
<div className="pr">
|
<div className="pr">
|
||||||
<span className="toprightNum">{descNum}/200</span>
|
<span className="toprightNum">{descNum}/200</span>
|
||||||
<Form.Item
|
<Form.Item
|
||||||
label="项目简介"
|
label="项目简介"
|
||||||
|
colon={false}
|
||||||
|
style={{marginBottom:"0px"}}
|
||||||
>
|
>
|
||||||
{getFieldDecorator('description', {
|
{getFieldDecorator('description', {
|
||||||
rules: [{
|
rules: [],
|
||||||
required: true, message: '请填写项目简介'
|
|
||||||
}],
|
|
||||||
})(
|
})(
|
||||||
<Input.TextArea maxLength={200} placeholder="项目的介绍" autoSize={{ minRows: 2, maxRows: 6 }} onChange={this.changeDesc}/>
|
<Input.TextArea maxLength={200} placeholder="项目的介绍" autoSize={{ minRows: 2, maxRows: 6 }} onChange={this.changeDesc}/>
|
||||||
)}
|
)}
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
</div>
|
</div>
|
||||||
<Form.Item
|
|
||||||
label="仓库名称"
|
|
||||||
>
|
|
||||||
{getFieldDecorator('repository_name', {
|
|
||||||
rules: [{
|
|
||||||
required: true, message: '请填写仓库名称'
|
|
||||||
}],
|
|
||||||
})(
|
|
||||||
<Input placeholder="仓库名称请使用与项目相关的英文关键字" maxLength={100} />
|
|
||||||
)}
|
|
||||||
</Form.Item>
|
|
||||||
<Form.Item
|
|
||||||
label="项目类别"
|
|
||||||
>
|
|
||||||
{getFieldDecorator('project_category', {
|
|
||||||
rules: [{
|
|
||||||
required: true, message: '请选择大类别',
|
|
||||||
}, {
|
|
||||||
validator: (rule, value, callback) => this.checkId(rule, value, callback, CategoryList, '项目类别')
|
|
||||||
}],
|
|
||||||
})(
|
|
||||||
<AutoComplete
|
|
||||||
placeholder="请选择项目类别"
|
|
||||||
onChange={(value, e) => this.ChangePlatform(value, e, 'project_category', CategoryList)}
|
|
||||||
className="plateAutoComplete"
|
|
||||||
onBlur={(value) => this.blurCategory(value, CategoryList, "project_category")}
|
|
||||||
>
|
|
||||||
{project_category_list}
|
|
||||||
</AutoComplete>
|
|
||||||
)}
|
|
||||||
</Form.Item>
|
|
||||||
<Form.Item
|
|
||||||
label="项目语言"
|
|
||||||
>
|
|
||||||
{getFieldDecorator('project_language', {
|
|
||||||
rules: [{
|
|
||||||
required: true, message: '请选择项目语言'
|
|
||||||
}, {
|
|
||||||
validator: (rule, value, callback) => this.checkId(rule, value, callback, LanguageList, '项目语言')
|
|
||||||
}],
|
|
||||||
})(
|
|
||||||
<AutoComplete
|
|
||||||
placeholder="请选择项目语言"
|
|
||||||
onChange={(value, e) => this.ChangePlatform(value, e, 'project_language', LanguageList)}
|
|
||||||
className="plateAutoComplete"
|
|
||||||
onBlur={(value) => this.blurCategory(value, LanguageList, "project_language")}
|
|
||||||
>
|
|
||||||
{project_language_list}
|
|
||||||
</AutoComplete>
|
|
||||||
)}
|
|
||||||
</Form.Item>
|
|
||||||
{
|
{
|
||||||
(projectsType === "deposit" || !projectsType) &&
|
(projectsType === "deposit" || !projectsType) &&
|
||||||
<React.Fragment>
|
<React.Fragment>
|
||||||
<Form.Item
|
<Form.Item
|
||||||
label=".gitignore"
|
className="privatePart"
|
||||||
>
|
>
|
||||||
{getFieldDecorator('ignore', {
|
{getFieldDecorator('ignoreFlag')(
|
||||||
rules: [{
|
<Checkbox checked={ignoreFlag} onChange={(e)=>this.setState({ignoreFlag:e.target.checked})}>.gitignore</Checkbox>
|
||||||
required: true, message: '请选择gitignore'
|
|
||||||
}, {
|
|
||||||
validator: (rule, value, callback) => this.checkId(rule, value, callback, GitignoreList, 'gitignore')
|
|
||||||
}],
|
|
||||||
})(
|
|
||||||
<AutoComplete
|
|
||||||
placeholder="请选择gitignore,用来定义哪些文件不需要添加到版本管理中"
|
|
||||||
onChange={(value, e) => this.ChangePlatform(value, e, 'ignore', GitignoreList)}
|
|
||||||
className="plateAutoComplete"
|
|
||||||
onBlur={(value) => this.blurCategory(value, GitignoreList, "ignore")}
|
|
||||||
>
|
|
||||||
{ignore_list}
|
|
||||||
</AutoComplete>
|
|
||||||
)}
|
)}
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
|
{ ignoreFlag &&
|
||||||
|
<Form.Item>
|
||||||
|
{getFieldDecorator('ignore', {
|
||||||
|
rules: [{
|
||||||
|
required: ignoreFlag, message: '请选择gitignore'
|
||||||
|
}, {
|
||||||
|
validator: (rule, value, callback) => this.checkId(rule, value, callback, GitignoreList, 'gitignore')
|
||||||
|
}],
|
||||||
|
})(
|
||||||
|
<AutoComplete
|
||||||
|
placeholder="请选择gitignore,用来定义哪些文件不需要添加到版本管理中"
|
||||||
|
onChange={(value, e) => this.ChangePlatform(value, e, 'ignore', GitignoreList)}
|
||||||
|
className="plateAutoComplete"
|
||||||
|
onBlur={(value) => this.blurCategory(value, GitignoreList, "ignore")}
|
||||||
|
>
|
||||||
|
{ignore_list}
|
||||||
|
</AutoComplete>
|
||||||
|
)}
|
||||||
|
</Form.Item>
|
||||||
|
}
|
||||||
<Form.Item
|
<Form.Item
|
||||||
label="开源许可证"
|
className="privatePart"
|
||||||
>
|
>
|
||||||
{getFieldDecorator('license', {
|
{getFieldDecorator('licenseFlag')(
|
||||||
rules: [{
|
<Checkbox checked={licenseFlag} onChange={(e)=>this.setState({licenseFlag:e.target.checked})}>开源许可证</Checkbox>
|
||||||
required: true, message: '请选择开源许可证'
|
|
||||||
}, {
|
|
||||||
validator: (rule, value, callback) => this.checkId(rule, value, callback, LicensesList, '开源许可证')
|
|
||||||
}],
|
|
||||||
})(
|
|
||||||
<AutoComplete
|
|
||||||
placeholder="请选择开源许可证"
|
|
||||||
onChange={(value, e) => this.ChangePlatform(value, e, 'license', LicensesList)}
|
|
||||||
className="plateAutoComplete"
|
|
||||||
onBlur={(value) => this.blurCategory(value, LicensesList, "license")}
|
|
||||||
>
|
|
||||||
{license_list}
|
|
||||||
</AutoComplete>
|
|
||||||
)}
|
)}
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
|
{ licenseFlag &&
|
||||||
|
<Form.Item>
|
||||||
|
{getFieldDecorator('license', {
|
||||||
|
rules: [{
|
||||||
|
required: licenseFlag, message: '请选择开源许可证'
|
||||||
|
}, {
|
||||||
|
validator: (rule, value, callback) => this.checkId(rule, value, callback, LicensesList, '开源许可证')
|
||||||
|
}],
|
||||||
|
})(
|
||||||
|
<AutoComplete
|
||||||
|
placeholder="请选择开源许可证"
|
||||||
|
onChange={(value, e) => this.ChangePlatform(value, e, 'license', LicensesList)}
|
||||||
|
className="plateAutoComplete"
|
||||||
|
onBlur={(value) => this.blurCategory(value, LicensesList, "license")}
|
||||||
|
>
|
||||||
|
{license_list}
|
||||||
|
</AutoComplete>
|
||||||
|
)}
|
||||||
|
</Form.Item>
|
||||||
|
}
|
||||||
</React.Fragment>
|
</React.Fragment>
|
||||||
}
|
}
|
||||||
<Form.Item
|
<Form.Item
|
||||||
label="可见性"
|
|
||||||
style={{ margin: "0px" }}
|
|
||||||
className="privatePart"
|
className="privatePart"
|
||||||
>
|
>
|
||||||
{getFieldDecorator('private')(
|
{getFieldDecorator('private')(
|
||||||
<Checkbox value="limit">将项目设为私有<span className="ml15 font-13 color-grey-9">(只有项目所有人或拥有权限的项目成员才能看到)</span></Checkbox>
|
<Checkbox value="limit">将项目设为私有<span className="font-13 color-grey-9">(只有项目所有人或拥有权限的项目成员才能看到)</span></Checkbox>
|
||||||
)}
|
)}
|
||||||
</Form.Item >
|
</Form.Item >
|
||||||
{
|
{
|
||||||
projectsType && projectsType === "mirror" &&
|
projectsType && projectsType === "mirror" &&
|
||||||
<Form.Item
|
<Form.Item
|
||||||
label="迁移类型:"
|
|
||||||
style={{ margin: "0px" }}
|
|
||||||
className="privatePart"
|
className="privatePart"
|
||||||
>
|
>
|
||||||
{getFieldDecorator('is_mirror')(
|
{getFieldDecorator('is_mirror')(
|
||||||
|
@ -537,12 +540,69 @@ class Index extends Component {
|
||||||
)}
|
)}
|
||||||
</Form.Item >
|
</Form.Item >
|
||||||
}
|
}
|
||||||
<div>
|
<Form.Item
|
||||||
|
style={{ margin: "0px" }}
|
||||||
|
className="privatePart"
|
||||||
|
>
|
||||||
|
{getFieldDecorator('categoreFlag')(
|
||||||
|
<Checkbox checked={categoreFlag} onChange={(e)=>this.setState({categoreFlag:e.target.checked})}>项目类别</Checkbox>
|
||||||
|
)}
|
||||||
|
</Form.Item>
|
||||||
|
{categoreFlag &&
|
||||||
|
<Form.Item
|
||||||
|
className="privatePart"
|
||||||
|
>
|
||||||
|
{getFieldDecorator('project_category', {
|
||||||
|
rules: [{
|
||||||
|
required: categoreFlag, message: '请选择项目类别',
|
||||||
|
}, {
|
||||||
|
validator: (rule, value, callback) => this.checkId(rule, value, callback, CategoryList, '项目类别')
|
||||||
|
}],
|
||||||
|
})(
|
||||||
|
<AutoComplete
|
||||||
|
placeholder="请选择项目类别"
|
||||||
|
onChange={(value, e) => this.ChangePlatform(value, e, 'project_category', CategoryList)}
|
||||||
|
className="plateAutoComplete"
|
||||||
|
onBlur={(value) => this.blurCategory(value, CategoryList, "project_category")}
|
||||||
|
>
|
||||||
|
{project_category_list}
|
||||||
|
</AutoComplete>
|
||||||
|
)}
|
||||||
|
</Form.Item>
|
||||||
|
}
|
||||||
|
<Form.Item
|
||||||
|
className="privatePart"
|
||||||
|
>
|
||||||
|
{getFieldDecorator('languageFlag')(
|
||||||
|
<Checkbox checked={languageFlag} onChange={(e)=>this.setState({languageFlag:e.target.checked})}>项目语言</Checkbox>
|
||||||
|
)}
|
||||||
|
</Form.Item>
|
||||||
|
{languageFlag &&
|
||||||
|
<Form.Item>
|
||||||
|
{getFieldDecorator('project_language', {
|
||||||
|
rules: [{
|
||||||
|
required: languageFlag, message: '请选择项目语言'
|
||||||
|
}, {
|
||||||
|
validator: (rule, value, callback) => this.checkId(rule, value, callback, LanguageList, '项目语言')
|
||||||
|
}],
|
||||||
|
})(
|
||||||
|
<AutoComplete
|
||||||
|
placeholder="请选择项目语言"
|
||||||
|
onChange={(value, e) => this.ChangePlatform(value, e, 'project_language', LanguageList)}
|
||||||
|
className="plateAutoComplete"
|
||||||
|
onBlur={(value) => this.blurCategory(value, LanguageList, "project_language")}
|
||||||
|
>
|
||||||
|
{project_language_list}
|
||||||
|
</AutoComplete>
|
||||||
|
)}
|
||||||
|
</Form.Item>
|
||||||
|
}
|
||||||
|
<div className="mt20">
|
||||||
注:<span className="ant-form-item-required"></span> 为必填项,否则为选填
|
注:<span className="ant-form-item-required"></span> 为必填项,否则为选填
|
||||||
</div>
|
</div>
|
||||||
<Form.Item className="formTip mt20">
|
<Form.Item className="formTip mt20">
|
||||||
<Button type="primary" onClick={this.subMitFrom} className="mr20">创建项目</Button>
|
<Button type="primary" onClick={this.subMitFrom} className="mr20">{projectsType && projectsType === "mirror" ? "导入" : "创建"}项目</Button>
|
||||||
<Link to={'/projects'} className="btn_32">取消</Link>
|
<Link to={'/explore'} className="btn_32">取消</Link>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
</div>
|
</div>
|
||||||
</Form>
|
</Form>
|
||||||
|
|
|
@ -12,7 +12,13 @@
|
||||||
border-bottom: 1px solid #f0f0f0
|
border-bottom: 1px solid #f0f0f0
|
||||||
}
|
}
|
||||||
.newPanel_content{
|
.newPanel_content{
|
||||||
padding:1rem 2rem;
|
padding:2rem;
|
||||||
|
}
|
||||||
|
.newPanel_content form .ant-row.ant-form-item{
|
||||||
|
margin-bottom: 25px;
|
||||||
|
}
|
||||||
|
.newPanel_content .ant-form-item-label label{
|
||||||
|
font-size: 16px;
|
||||||
}
|
}
|
||||||
.newPanel_content .ant-form-item-control-wrapper{
|
.newPanel_content .ant-form-item-control-wrapper{
|
||||||
flex: 1;
|
flex: 1;
|
||||||
|
@ -25,24 +31,35 @@
|
||||||
height: 35px;
|
height: 35px;
|
||||||
line-height: 35px;
|
line-height: 35px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.newContent_inline{
|
.newContent_inline{
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
align-items:flex-end
|
align-items:flex-end
|
||||||
}
|
}
|
||||||
|
.explainPos{
|
||||||
|
.ant-form-explain{
|
||||||
|
position: absolute;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.newContent_inline > .ant-form-item:nth-child(2){
|
.newContent_inline > .ant-form-item:nth-child(2){
|
||||||
margin-left: 20px;
|
margin-left: 20px;
|
||||||
}
|
}
|
||||||
.newPanel_content .privatePart .ant-form-item-label{
|
.privatePart{
|
||||||
margin-left: 0px;
|
margin-bottom: 0px!important;
|
||||||
|
.ant-form-item-label{
|
||||||
|
margin-left: 0px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
.newPanel_content .ant-form-item-label{
|
.newPanel_content .ant-form-item-label{
|
||||||
line-height: 25px;
|
line-height: 25px;
|
||||||
height: 25px;
|
height: 25px;
|
||||||
margin-left: -0.8rem;
|
}
|
||||||
|
.plateAutoComplete{
|
||||||
|
.ant-input{
|
||||||
|
height: 34px!important;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@media screen and (max-width: 750px){
|
@media screen and (max-width: 750px){
|
||||||
.newPanel_content{
|
.newPanel_content{
|
|
@ -65,16 +65,18 @@ class Index extends Component {
|
||||||
<FileLanguage language={language} select_language={this.select_language}></FileLanguage>
|
<FileLanguage language={language} select_language={this.select_language}></FileLanguage>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<Meditor
|
<div className="editorBorder">
|
||||||
{...this.props}
|
<Meditor
|
||||||
{...this.state}
|
{...this.props}
|
||||||
filepath={`${file_path}`}
|
{...this.state}
|
||||||
language = {language}
|
filepath={`${file_path}`}
|
||||||
content={undefined}
|
language = {language}
|
||||||
readOnly={false}
|
content={undefined}
|
||||||
editorType="new"
|
readOnly={false}
|
||||||
descName={filename && `Add ${filename}`}
|
editorType="new"
|
||||||
></Meditor>
|
descName={filename && `Add ${filename}`}
|
||||||
|
></Meditor>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</React.Fragment>
|
</React.Fragment>
|
||||||
|
|
|
@ -83,8 +83,8 @@ class UserSubmitComponent extends Component {
|
||||||
if (result.data && result.data.name) {
|
if (result.data && result.data.name) {
|
||||||
this.props.showNotification("文件新建成功!");
|
this.props.showNotification("文件新建成功!");
|
||||||
if(submitType === "1"){
|
if(submitType === "1"){
|
||||||
const { getTopCount } = this.props;
|
const { getDetail } = this.props;
|
||||||
getTopCount && getTopCount(values.branchname);
|
getDetail && getDetail();
|
||||||
}
|
}
|
||||||
let url = `/${owner}/${projectsId}${values.branchname ? `/tree/${turnbar(values.branchname)}`: (branch ? `/tree/${turnbar(branch)}` : "")}`;
|
let url = `/${owner}/${projectsId}${values.branchname ? `/tree/${turnbar(values.branchname)}`: (branch ? `/tree/${turnbar(branch)}` : "")}`;
|
||||||
this.props.history.push(url);
|
this.props.history.push(url);
|
||||||
|
@ -147,6 +147,7 @@ class UserSubmitComponent extends Component {
|
||||||
const { current_user, filepath, projectDetail , currentBranch } = this.props;
|
const { current_user, filepath, projectDetail , currentBranch } = this.props;
|
||||||
const { editor_type } = this.props;
|
const { editor_type } = this.props;
|
||||||
let b = currentBranch || branch;
|
let b = currentBranch || branch;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<span className="df" style={{ alignItems: "center" }}>
|
<span className="df" style={{ alignItems: "center" }}>
|
||||||
|
|
|
@ -8,7 +8,13 @@
|
||||||
border: 1px solid #d9d9d9!important;
|
border: 1px solid #d9d9d9!important;
|
||||||
border-right: none!important;
|
border-right: none!important;
|
||||||
}
|
}
|
||||||
|
.editorBorder .editorBorderBox{
|
||||||
|
border:1px solid #eee;
|
||||||
|
border-radius: 2px;
|
||||||
|
}
|
||||||
|
.editorBorder .editorBorderSubmitBox{
|
||||||
|
padding:20px 0px!important;
|
||||||
|
}
|
||||||
.userScrew{
|
.userScrew{
|
||||||
margin:20px 0px;
|
margin:20px 0px;
|
||||||
border:1px solid #f4f4f4;
|
border:1px solid #f4f4f4;
|
||||||
|
@ -39,7 +45,7 @@
|
||||||
z-index: 1;
|
z-index: 1;
|
||||||
}
|
}
|
||||||
.ant-input-group .ant-input:focus{
|
.ant-input-group .ant-input:focus{
|
||||||
border-right: 1px solid #d9d9d9!important;
|
border-right: 1px solid rgba(70, 106, 255, 1)!important;
|
||||||
}
|
}
|
||||||
.ant-btn-primary.grey{
|
.ant-btn-primary.grey{
|
||||||
border:1px solid #BBBBBB;
|
border:1px solid #BBBBBB;
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
import React, { Component } from "react";
|
import React, { Component } from "react";
|
||||||
import Editor from "react-monaco-editor";
|
import Editor from "react-monaco-editor";
|
||||||
|
// import {UnControlled as CodeMirror} from 'react-codemirror2'
|
||||||
|
|
||||||
import UserSubmitComponent from "./UserSubmitComponent";
|
import UserSubmitComponent from "./UserSubmitComponent";
|
||||||
|
|
||||||
import "./index.css";
|
import "./index.css";
|
||||||
|
@ -10,6 +12,7 @@ class m_editor extends Component {
|
||||||
super(props);
|
super(props);
|
||||||
this.state = {
|
this.state = {
|
||||||
editorValue: this.props.content,
|
editorValue: this.props.content,
|
||||||
|
prevHeight:0
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
componentDidUpdate=(prevProps)=>{
|
componentDidUpdate=(prevProps)=>{
|
||||||
|
@ -41,42 +44,92 @@ class m_editor extends Component {
|
||||||
folding: true,
|
folding: true,
|
||||||
foldingStrategy: "indentation", // 代码可分小段折叠
|
foldingStrategy: "indentation", // 代码可分小段折叠
|
||||||
automaticLayout: true, // 自适应布局
|
automaticLayout: true, // 自适应布局
|
||||||
// overviewRulerBorder: false, // 不要滚动条的边框
|
overviewRulerBorder: false, // 不要滚动条的边框
|
||||||
// scrollBeyondLastLine: false, // 取消代码后面一大段空白
|
scrollBeyondLastLine: false, // 取消代码后面一大段空白
|
||||||
minimap: {
|
minimap: {
|
||||||
// 不要小地图
|
// 不要小地图
|
||||||
enabled: false,
|
enabled: false,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleEditorMount = (editor, monaco) => {
|
||||||
|
editor.onDidChangeModelDecorations(() => {
|
||||||
|
requestAnimationFrame(updateEditorHeight); // folding
|
||||||
|
});
|
||||||
|
|
||||||
|
const updateEditorHeight = () => {
|
||||||
|
const editorElement = editor.getDomNode();
|
||||||
|
|
||||||
|
if (!editorElement) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const padding = 40;
|
||||||
|
|
||||||
|
const lineHeight = editor.getOption(
|
||||||
|
monaco.editor.EditorOption.lineHeight
|
||||||
|
);
|
||||||
|
|
||||||
|
const lineCount = editor.getModel().getLineCount() || 1;
|
||||||
|
let height =
|
||||||
|
editor.getTopForLineNumber(lineCount + 1) +
|
||||||
|
lineHeight +
|
||||||
|
padding ;
|
||||||
|
|
||||||
|
if(height<400){height = 400;}
|
||||||
|
|
||||||
|
if (this.state.prevHeight !== height) {
|
||||||
|
this.setState({
|
||||||
|
prevHeight:height
|
||||||
|
})
|
||||||
|
// setPrevHeight(height);
|
||||||
|
editorElement.style.height = `${height}px`;
|
||||||
|
editor.layout();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
updateEditorHeight(); // typing
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<React.Fragment>
|
<React.Fragment>
|
||||||
<div>
|
<div className="editorBorderBox">
|
||||||
<div className="branchTable" style={{border:"1px solid #eee"}}>
|
<Editor
|
||||||
<Editor
|
language={language ? language : "plaintext"}
|
||||||
height="400px"
|
theme={"vs-grey"}
|
||||||
language={language ? language : "plaintext"}
|
placeholder="请输入内容"
|
||||||
theme={"vs-grey"}
|
value={editorValue}
|
||||||
placeholder="请输入内容"
|
options={editor_options}
|
||||||
value={editorValue}
|
onChange={this.changeEditor}
|
||||||
options={editor_options}
|
editorWillMount={this.editorWillMount}
|
||||||
onChange={this.changeEditor}
|
editorDidMount={handleEditorMount}
|
||||||
editorWillMount={this.editorWillMount}
|
/>
|
||||||
/>
|
{/* <CodeMirror
|
||||||
</div>
|
value={editorValue}
|
||||||
{!readOnly && (
|
options={{
|
||||||
<div style={{marginTop:"20px",padding:"20px"}}>
|
theme: 'monokai',
|
||||||
<UserSubmitComponent
|
mode: 'JavaScript',
|
||||||
{...this.props}
|
extraKeys: {"Ctrl": "autocomplete"},//ctrl可以弹出提示
|
||||||
{...this.state}
|
styleActiveLine: true,
|
||||||
filepath={`${this.props.filepath}`}
|
lineNumbers: true,
|
||||||
content={editorValue}
|
readOnly:true
|
||||||
editor_type={editorType}
|
}}
|
||||||
currentBranch={currentBranch}
|
/> */}
|
||||||
descName={descName}
|
</div>
|
||||||
></UserSubmitComponent>
|
{!readOnly && (
|
||||||
</div>
|
<div className="editorBorderSubmitBox" style={{marginTop:"20px",padding:"20px"}}>
|
||||||
)}
|
<UserSubmitComponent
|
||||||
</div>
|
{...this.props}
|
||||||
|
{...this.state}
|
||||||
|
filepath={`${this.props.filepath}`}
|
||||||
|
content={editorValue}
|
||||||
|
editor_type={editorType}
|
||||||
|
currentBranch={currentBranch}
|
||||||
|
descName={descName}
|
||||||
|
></UserSubmitComponent>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</React.Fragment>
|
</React.Fragment>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import React , { Component } from 'react';
|
import React , { Component } from 'react';
|
||||||
|
|
||||||
import nodata from './Images/nodata.png';
|
import nodata from './Images/nodata.png';
|
||||||
|
import './css/index.scss';
|
||||||
class Nodata extends Component{
|
class Nodata extends Component{
|
||||||
render(){
|
render(){
|
||||||
const { _html , small } = this.props;
|
const { _html , small } = this.props;
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue