forked from Gitlink/forgeplus-react
devops
This commit is contained in:
parent
2f1bac24d5
commit
a411d2c111
File diff suppressed because one or more lines are too long
Binary file not shown.
File diff suppressed because one or more lines are too long
|
@ -5,6 +5,111 @@
|
|||
"css_prefix_text": "icon-",
|
||||
"description": "",
|
||||
"glyphs": [
|
||||
{
|
||||
"icon_id": "16609949",
|
||||
"name": "模版管理2",
|
||||
"font_class": "mobanguanli2",
|
||||
"unicode": "e7a6",
|
||||
"unicode_decimal": 59302
|
||||
},
|
||||
{
|
||||
"icon_id": "15852679",
|
||||
"name": "Last updated",
|
||||
"font_class": "Lastupdated",
|
||||
"unicode": "e7a5",
|
||||
"unicode_decimal": 59301
|
||||
},
|
||||
{
|
||||
"icon_id": "15852678",
|
||||
"name": "CONTACTS",
|
||||
"font_class": "CONTACTS",
|
||||
"unicode": "e7a4",
|
||||
"unicode_decimal": 59300
|
||||
},
|
||||
{
|
||||
"icon_id": "15852677",
|
||||
"name": "SPONSORS",
|
||||
"font_class": "SPONSORS",
|
||||
"unicode": "e7a3",
|
||||
"unicode_decimal": 59299
|
||||
},
|
||||
{
|
||||
"icon_id": "15852676",
|
||||
"name": "FINAL REPORTS",
|
||||
"font_class": "FINALREPORTS",
|
||||
"unicode": "e7a2",
|
||||
"unicode_decimal": 59298
|
||||
},
|
||||
{
|
||||
"icon_id": "15852675",
|
||||
"name": "STEERING COMMITTEE",
|
||||
"font_class": "STEERINGCOMMITTEE",
|
||||
"unicode": "e7a1",
|
||||
"unicode_decimal": 59297
|
||||
},
|
||||
{
|
||||
"icon_id": "15852674",
|
||||
"name": "ORGANIZING ICSE - MOU",
|
||||
"font_class": "ORGANIZINGICSE-MOU",
|
||||
"unicode": "e7a0",
|
||||
"unicode_decimal": 59296
|
||||
},
|
||||
{
|
||||
"icon_id": "15852673",
|
||||
"name": "INFLUENTIAL PAPERS",
|
||||
"font_class": "INFLUENTIALPAPERS",
|
||||
"unicode": "e79f",
|
||||
"unicode_decimal": 59295
|
||||
},
|
||||
{
|
||||
"icon_id": "15852672",
|
||||
"name": "BIBLIOGRAPHIES",
|
||||
"font_class": "BIBLIOGRAPHIES",
|
||||
"unicode": "e79e",
|
||||
"unicode_decimal": 59294
|
||||
},
|
||||
{
|
||||
"icon_id": "15852671",
|
||||
"name": "PROCEEDINGS",
|
||||
"font_class": "PROCEEDINGS",
|
||||
"unicode": "e79d",
|
||||
"unicode_decimal": 59293
|
||||
},
|
||||
{
|
||||
"icon_id": "15852670",
|
||||
"name": "HISTORY",
|
||||
"font_class": "HISTORY",
|
||||
"unicode": "e79c",
|
||||
"unicode_decimal": 59292
|
||||
},
|
||||
{
|
||||
"icon_id": "15852669",
|
||||
"name": "CONDUCT & SAFETY",
|
||||
"font_class": "CONDUCTSAFETY",
|
||||
"unicode": "e79b",
|
||||
"unicode_decimal": 59291
|
||||
},
|
||||
{
|
||||
"icon_id": "15852667",
|
||||
"name": "EDI STATEMENT",
|
||||
"font_class": "EDISTATEMENT",
|
||||
"unicode": "e79a",
|
||||
"unicode_decimal": 59290
|
||||
},
|
||||
{
|
||||
"icon_id": "15852666",
|
||||
"name": "MAILING LIST",
|
||||
"font_class": "MAILINGLIST",
|
||||
"unicode": "e799",
|
||||
"unicode_decimal": 59289
|
||||
},
|
||||
{
|
||||
"icon_id": "15852665",
|
||||
"name": "HOME",
|
||||
"font_class": "HOME",
|
||||
"unicode": "e798",
|
||||
"unicode_decimal": 59288
|
||||
},
|
||||
{
|
||||
"icon_id": "15792809",
|
||||
"name": "准备中",
|
||||
|
|
|
@ -20,6 +20,51 @@ Created by iconfont
|
|||
/>
|
||||
<missing-glyph />
|
||||
|
||||
<glyph glyph-name="mobanguanli2" unicode="" d="M1133.714286-120.685714H36.571429V201.142857h73.142857v-248.685714h950.857143V201.142857h73.142857zM943.542857 91.428571h-731.428571V896h731.428571v-804.571429z m-658.285714 73.142858h585.142857V822.857143h-585.142857v-658.285714zM416.914286 618.057143h343.771428v-73.142857H416.914286zM416.914286 420.571429h343.771428v-73.142858H416.914286z" horiz-adv-x="1170" />
|
||||
|
||||
|
||||
<glyph glyph-name="Lastupdated" unicode="" d="M512-107.52c-281.6 0-512 225.28-512 501.76S230.4 896 512 896s512-225.28 512-501.76-230.4-501.76-512-501.76z m0 931.84c-240.64 0-440.32-194.56-440.32-430.08s199.68-430.08 440.32-430.08 440.32 194.56 440.32 430.08-199.68 430.08-440.32 430.08zM547.84 102.4H476.16v215.04H261.12V389.12h215.04V609.28h71.68v-220.16h215.04v-71.68h-215.04z" horiz-adv-x="1024" />
|
||||
|
||||
|
||||
<glyph glyph-name="CONTACTS" unicode="" d="M599.771429-69.485714l-14.628572 68.266666c107.27619 19.504762 199.92381 87.771429 258.438095 190.171429l58.514286-34.133333c-68.266667-121.904762-180.419048-199.92381-302.323809-224.304762zM146.285714 452.266667l-68.266666 9.752381C107.27619 700.952381 297.447619 881.371429 521.752381 881.371429s414.47619-180.419048 443.733333-419.352381l-68.266666-4.876191c-24.380952 204.8-185.295238 355.961905-375.466667 355.961905-190.171429 0-351.085714-156.038095-375.466667-360.838095zM112.152381 159.695238c-48.761905 0-87.771429 39.009524-87.771429 87.771429v126.780952c0 48.761905 39.009524 87.771429 87.771429 87.771429s87.771429-39.009524 87.771429-87.771429v-131.657143c-4.87619-43.885714-43.885714-82.895238-87.771429-82.895238z m0 234.057143c-9.752381 0-19.504762-9.752381-19.504762-19.504762v-131.657143c0-9.752381 9.752381-19.504762 19.504762-19.504762s19.504762 9.752381 19.504762 19.504762v131.657143c-4.87619 9.752381-14.628571 19.504762-19.504762 19.504762zM536.380952-103.619048h-97.523809c-34.133333 0-63.390476 29.257143-63.390476 63.390477 0 34.133333 29.257143 63.390476 63.390476 63.390476h97.523809c34.133333 0 63.390476-29.257143 63.390477-63.390476 0-39.009524-29.257143-63.390476-63.390477-63.390477zM911.847619 159.695238c-48.761905 0-87.771429 39.009524-87.771429 87.771429v126.780952c0 48.761905 39.009524 87.771429 87.771429 87.771429s87.771429-39.009524 87.771429-87.771429v-131.657143c0-43.885714-39.009524-82.895238-87.771429-82.895238z m0 234.057143c-9.752381 0-19.504762-9.752381-19.504762-19.504762v-131.657143c0-9.752381 9.752381-19.504762 19.504762-19.504762s19.504762 9.752381 19.504762 19.504762v131.657143c0 9.752381-9.752381 19.504762-19.504762 19.504762z" horiz-adv-x="1024" />
|
||||
|
||||
|
||||
<glyph glyph-name="SPONSORS" unicode="" d="M489.73913 392.904348c-138.017391 0-253.773913 111.304348-253.773913 253.773913S347.269565 896 489.73913 896s253.773913-111.304348 253.773913-253.773913-115.756522-249.321739-253.773913-249.321739z m0 440.765217c-102.4 0-191.443478-84.591304-191.443478-191.443478S382.886957 455.234783 489.73913 455.234783c102.4 0 191.443478 84.591304 191.443479 191.443478s-89.043478 186.991304-191.443479 186.991304zM120.208696-105.73913L115.756522-83.478261c-8.904348 35.617391-13.356522 66.782609-13.356522 102.4 0 222.608696 182.53913 405.147826 405.147826 405.147826s405.147826-182.53913 405.147826-405.147826c0-31.165217-4.452174-66.782609-13.356522-97.947826l-4.452173-22.26087-774.678261-4.452173zM507.547826 361.73913c-186.991304 0-342.817391-155.826087-342.817391-342.817391 0-22.26087 0-44.521739 4.452174-62.330435L845.913043-38.956522c4.452174 17.808696 4.452174 40.069565 4.452174 57.878261 0 186.991304-155.826087 342.817391-342.817391 342.817391zM512-38.956522l-106.852174 289.391305 106.852174 120.208695 97.947826-120.208695L512-38.956522z m-31.165217 276.034783l31.165217-89.043478 31.165217 89.043478-31.165217 35.617391-31.165217-35.617391z" horiz-adv-x="1024" />
|
||||
|
||||
|
||||
<glyph glyph-name="FINALREPORTS" unicode="" d="M633.904762-98.742857H219.428571c-73.142857 0-131.657143 58.514286-131.657142 131.657143V749.714286C87.771429 822.857143 146.285714 881.371429 219.428571 881.371429h580.266667c73.142857 0 131.657143-58.514286 131.657143-131.657143v-516.876191l-297.447619-331.580952zM219.428571 813.104762c-34.133333 0-63.390476-29.257143-63.390476-63.390476v-716.8c0-34.133333 29.257143-63.390476 63.390476-63.390476h385.219048l263.314286 287.695238V749.714286c0 34.133333-29.257143 63.390476-63.390476 63.390476H219.428571zM653.409524-64.609524h-68.266667v341.333334h312.076191v-68.266667h-243.809524zM238.933333 652.190476h570.514286v-68.266666H238.933333zM238.933333 447.390476h570.514286v-68.266666H238.933333z" horiz-adv-x="1024" />
|
||||
|
||||
|
||||
<glyph glyph-name="STEERINGCOMMITTEE" unicode="" d="M409.6 389.389474C269.473684 389.389474 156.294737 502.568421 156.294737 642.694737S269.473684 896 409.6 896s253.305263-113.178947 253.305263-253.305263-113.178947-253.305263-253.305263-253.305263z m0 431.157894c-97.010526 0-177.852632-80.842105-177.852632-177.852631S312.589474 464.842105 409.6 464.842105s177.852632 80.842105 177.852632 177.852632-80.842105 177.852632-177.852632 177.852631zM689.852632 340.884211V416.336842c97.010526 0 177.852632 80.842105 177.852631 177.852632 0 75.452632-48.505263 140.126316-118.568421 167.073684l26.947369 70.063158c102.4-37.726316 167.073684-129.347368 167.073684-237.136842 0-140.126316-113.178947-253.305263-253.305263-253.305263zM1050.947368-30.989474l-75.452631 16.168421c5.389474 21.557895 5.389474 43.115789 5.389474 70.063158 0 156.294737-123.957895 280.252632-280.252632 280.252632V416.336842c194.021053 0 355.705263-161.684211 355.705263-355.705263 5.389474-32.336842 0-64.673684-5.389474-91.621053zM37.726316-122.610526l-5.389474 26.947368c-10.778947 32.336842-16.168421 70.063158-16.168421 107.789474 0 226.357895 183.242105 414.989474 409.6 414.989473 226.357895 0 409.6-188.631579 409.6-414.989473 0-32.336842-5.389474-64.673684-10.778947-97.010527l-5.389474-26.947368-781.473684-10.778947z m388.042105 474.273684c-183.242105 0-334.147368-150.905263-334.147368-339.536842 0-21.557895 0-37.726316 5.389473-59.284211l662.905263 5.389474c0 16.168421 5.389474 32.336842 5.389474 53.894737 0 188.631579-150.905263 339.536842-339.536842 339.536842z" horiz-adv-x="1077" />
|
||||
|
||||
|
||||
<glyph glyph-name="ORGANIZINGICSE-MOU" unicode="" d="M614.4 537.6H450.56C373.76 537.6 312.32 604.16 312.32 675.84V757.76C312.32 834.56 373.76 896 450.56 896H614.4c76.8 0 138.24-61.44 138.24-138.24v-81.92C752.64 604.16 691.2 537.6 614.4 537.6zM450.56 824.32c-35.84 0-66.56-30.72-66.56-66.56v-81.92c0-35.84 30.72-66.56 66.56-66.56H614.4c35.84 0 66.56 30.72 66.56 66.56V757.76c0 35.84-30.72 66.56-66.56 66.56H450.56zM302.08-92.16H138.24c-76.8 0-138.24 61.44-138.24 138.24V128c0 76.8 61.44 138.24 138.24 138.24h163.84c76.8 0 138.24-61.44 138.24-138.24v-81.92c0-76.8-61.44-138.24-138.24-138.24z m-163.84 286.72c-35.84 0-66.56-30.72-66.56-66.56v-81.92c0-35.84 30.72-66.56 66.56-66.56h163.84c35.84 0 66.56 30.72 66.56 66.56V128c0 35.84-30.72 66.56-66.56 66.56H138.24zM936.96-92.16h-163.84c-76.8 0-138.24 61.44-138.24 138.24V128c0 76.8 61.44 138.24 138.24 138.24h163.84c76.8 0 138.24-61.44 138.24-138.24v-81.92c0-76.8-61.44-138.24-138.24-138.24z m-163.84 286.72c-35.84 0-66.56-30.72-66.56-66.56v-81.92c0-35.84 30.72-66.56 66.56-66.56h163.84c35.84 0 66.56 30.72 66.56 66.56V128c0 35.84-30.72 66.56-66.56 66.56h-163.84zM890.88 266.24H819.2v107.52H256v-107.52H184.32V445.44h317.44V537.6h71.68v-92.16h317.44z" horiz-adv-x="1075" />
|
||||
|
||||
|
||||
<glyph glyph-name="INFLUENTIALPAPERS" unicode="" d="M791.272727-90.763636H232.727273C162.909091-90.763636 107.054545-34.909091 107.054545 34.909091V756.363636C107.054545 826.181818 162.909091 882.036364 232.727273 882.036364h428.218182l251.345454-209.454546v-637.672727c4.654545-69.818182-51.2-125.672727-121.018182-125.672727zM232.727273 816.872727c-32.581818 0-60.509091-27.927273-60.509091-60.509091v-721.454545c0-32.581818 27.927273-60.509091 60.509091-60.509091h558.545454c32.581818 0 60.509091 27.927273 60.509091 60.509091V644.654545l-209.454545 172.218182H232.727273zM307.2 672.581818H512v-65.163636H307.2zM377.018182 640h65.163636v-125.672727H377.018182zM512 528.290909h228.072727v-65.163636H512zM307.2 337.454545h432.872727v-65.163636H307.2zM307.2 146.618182h316.509091v-65.163637H307.2zM884.363636 626.036364h-265.309091V849.454545h65.163637v-158.254545H884.363636z" horiz-adv-x="1024" />
|
||||
|
||||
|
||||
<glyph glyph-name="BIBLIOGRAPHIES" unicode="" d="M156.038095 696.07619H87.771429V881.371429h629.028571c73.142857 0 131.657143-58.514286 131.657143-131.657143v-48.761905h-68.266667V749.714286c0 34.133333-29.257143 63.390476-63.390476 63.390476H156.038095v-117.028572zM804.571429-128H87.771429V735.085714H804.571429c73.142857 0 131.657143-58.514286 131.657142-131.657143v-599.771428c0-73.142857-63.390476-131.657143-131.657142-131.657143zM156.038095-59.733333H804.571429c34.133333 0 63.390476 29.257143 63.390476 63.390476V603.428571c0 34.133333-29.257143 63.390476-63.390476 63.390477H156.038095v-726.552381zM302.32381 486.4h380.342857v-68.266667H302.32381zM302.32381 325.485714H512v-68.266666H302.32381z" horiz-adv-x="1024" />
|
||||
|
||||
|
||||
<glyph glyph-name="PROCEEDINGS" unicode="" d="M481.28 138.24L204.8 445.44l384 358.4 276.48-312.32-384-353.28zM302.08 440.32l184.32-199.68 276.48 256-179.2 204.8-281.6-261.12zM906.24-71.68c-30.72 0-61.44 15.36-87.04 40.96L532.48 281.6l174.08 163.84 291.84-327.68c20.48-20.48 30.72-51.2 25.6-81.92 0-30.72-15.36-56.32-35.84-76.8-25.6-20.48-51.2-30.72-81.92-30.72z m-271.36 348.16l240.64-266.24c15.36-20.48 46.08-20.48 66.56-5.12 10.24 10.24 15.36 15.36 15.36 30.72 0 10.24-5.12 20.48-10.24 30.72l-240.64 276.48-71.68-66.56zM849.92 450.56c-30.72 0-61.44 10.24-87.04 35.84l-194.56 204.8c-46.08 51.2-46.08 128 5.12 174.08 20.48 20.48 51.2 30.72 87.04 30.72 30.72 0 61.44-15.36 87.04-40.96l194.56-204.8c46.08-51.2 40.96-122.88-5.12-163.84-30.72-25.6-61.44-35.84-87.04-35.84z m-194.56 373.76c-10.24 0-25.6-5.12-35.84-15.36-20.48-20.48-20.48-51.2 0-71.68l194.56-204.8c20.48-20.48 46.08-20.48 66.56 0 20.48 15.36 20.48 46.08 5.12 66.56l-194.56 209.92c-10.24 10.24-20.48 15.36-35.84 15.36zM399.36 51.2c-35.84 0-71.68 15.36-97.28 40.96L35.84 368.64 215.04 537.6l358.4-384-76.8-66.56c-30.72-20.48-66.56-35.84-97.28-35.84z m-266.24 317.44l215.04-225.28c25.6-25.6 66.56-25.6 92.16-5.12l20.48 20.48L204.8 435.2l-71.68-66.56zM0-35.84h624.64v-71.68H0z" horiz-adv-x="1025" />
|
||||
|
||||
|
||||
<glyph glyph-name="HISTORY" unicode="" d="M422.956522-61.217391H178.086957c-66.782609 0-120.208696 53.426087-120.208696 120.208695V762.434783C57.878261 829.217391 111.304348 882.643478 178.086957 882.643478h574.330434c66.782609 0 120.208696-53.426087 120.208696-120.208695v-396.243479h-62.330435V762.434783c0 31.165217-26.713043 57.878261-57.878261 57.87826H178.086957c-31.165217 0-57.878261-26.713043-57.878261-57.87826v-703.443479c0-31.165217 26.713043-57.878261 57.878261-57.878261h244.869565v-62.330434zM756.869565-119.095652c-115.756522 0-213.704348 93.495652-213.704348 209.252174s93.495652 209.252174 213.704348 209.252174 213.704348-93.495652 213.704348-209.252174-97.947826-209.252174-213.704348-209.252174z m0 356.173913c-84.591304 0-151.373913-66.782609-151.373913-146.921739 0-80.13913 66.782609-146.921739 151.373913-146.921739s151.373913 66.782609 151.373913 146.921739c-4.452174 80.13913-71.234783 146.921739-151.373913 146.921739zM828.104348 1.113043h-120.208696v169.182609h62.330435v-106.852174h57.878261zM218.156522 668.93913h503.095652v-62.330434H218.156522zM218.156522 450.782609h414.052174v-62.330435H218.156522zM218.156522 245.982609h249.321739V183.652174H218.156522z" horiz-adv-x="1024" />
|
||||
|
||||
|
||||
<glyph glyph-name="CONDUCTSAFETY" unicode="" d="M499.2-110.933333l-17.066667 8.533333c-166.4 98.133333-273.066667 192-324.266666 294.4C110.933333 290.133333 81.066667 448 76.8 678.4v25.6l25.6 4.266667c98.133333 21.333333 170.666667 46.933333 217.6 68.266666C366.933333 797.866667 422.4 832 482.133333 878.933333l17.066667 12.8 17.066667-12.8c72.533333-46.933333 132.266667-81.066667 179.2-102.4 46.933333-17.066667 119.466667-42.666667 217.6-68.266666l21.333333-4.266667V682.666667c21.333333-204.8 8.533333-354.133333-46.933333-452.266667-55.466667-98.133333-174.933333-204.8-371.2-332.8l-17.066667-8.533333z m-362.666667 768c8.533333-204.8 34.133333-354.133333 76.8-439.466667s140.8-170.666667 285.866667-260.266667c179.2 115.2 290.133333 217.6 337.066667 302.933334 46.933333 85.333333 59.733333 217.6 42.666666 396.8-93.866667 25.6-162.133333 46.933333-204.8 64-42.666667 17.066667-102.4 51.2-170.666666 93.866666-55.466667-42.666667-110.933333-72.533333-157.866667-93.866666-46.933333-21.333333-115.2-42.666667-209.066667-64zM536.405333 205.226667h-59.733333v153.6h-149.333333v59.733333h149.333333v153.6h59.733333v-153.6h153.6v-59.733333h-153.6z" horiz-adv-x="1024" />
|
||||
|
||||
|
||||
<glyph glyph-name="EDISTATEMENT" unicode="" d="M819.2-128H200.347826C133.565217-128 80.13913-74.573913 80.13913-7.791304V762.434783C80.13913 829.217391 133.565217 882.643478 200.347826 882.643478h618.852174c66.782609 0 120.208696-53.426087 120.208696-120.208695v-770.226087c0-66.782609-53.426087-120.208696-120.208696-120.208696zM200.347826 820.313043C169.182609 820.313043 142.469565 793.6 142.469565 762.434783v-770.226087c0-31.165217 26.713043-57.878261 57.878261-57.878261h618.852174c31.165217 0 57.878261 26.713043 57.878261 57.878261V762.434783c0 31.165217-26.713043 57.878261-57.878261 57.87826H200.347826zM267.130435 308.313043h507.547826v-62.330434H267.130435zM267.130435 107.965217h262.678261v-62.330434H267.130435zM498.643478 744.626087h62.330435v-218.156522H498.643478zM538.713043 441.878261m-44.521739 0a44.521739 44.521739 0 1 1 89.043479 0 44.521739 44.521739 0 1 1-89.043479 0Z" horiz-adv-x="1024" />
|
||||
|
||||
|
||||
<glyph glyph-name="MAILINGLIST" unicode="" d="M1070.08 66.56h-215.04v71.68h215.04c35.84 0 66.56 30.72 66.56 66.56V742.4c0 35.84-30.72 66.56-66.56 66.56H153.6c-35.84 0-66.56-30.72-66.56-66.56v-537.6c0-35.84 30.72-66.56 66.56-66.56h230.4v-71.68H153.6C76.8 66.56 15.36 128 15.36 204.8V742.4C15.36 819.2 76.8 880.64 153.6 880.64h916.48c76.8 0 138.24-61.44 138.24-138.24v-537.6c0-76.8-61.44-138.24-138.24-138.24zM614.4 394.24L138.24 727.04l40.96 56.32L614.4 481.28l424.96 302.08 46.08-56.32zM134.6048 223.8464L388.7104 483.84l51.2512-50.0736-254.1056-259.9424zM795.648 428.4928l51.2 50.1248 254.2592-259.84-51.2-50.176zM460.8 286.72h307.2v-71.68H460.8zM460.8 189.44h307.2v-71.68H460.8zM460.8 87.04h307.2v-71.68H460.8zM460.8-15.36h307.2v-71.68H460.8z" horiz-adv-x="1228" />
|
||||
|
||||
|
||||
<glyph glyph-name="HOME" unicode="" d="M828.952381-113.371429h-151.161905c-43.885714 0-82.895238 39.009524-82.895238 82.895239v263.314285H477.866667V-30.47619c0-43.885714-39.009524-82.895238-82.895238-82.895239h-146.285715c-43.885714 0-82.895238 39.009524-82.895238 82.895239v360.838095H87.771429c-24.380952 0-48.761905 9.752381-63.390477 29.257143-14.628571 19.504762-19.504762 39.009524-19.504762 58.514285 0 24.380952 14.628571 43.885714 29.257143 53.638096L487.619048 842.361905c29.257143 24.380952 73.142857 24.380952 107.27619 0l443.733333-370.590476c19.504762-14.628571 29.257143-39.009524 29.257143-63.390477 0-43.885714-39.009524-82.895238-82.895238-82.895238h-78.019047v-360.838095c4.87619-39.009524-34.133333-78.019048-78.019048-78.019048z m-419.352381 414.476191h253.561905V-30.47619c0-9.752381 4.87619-14.628571 14.628571-14.628572H828.952381c9.752381 0 14.628571 4.87619 14.628571 14.628572v429.104761h146.285715c9.752381 0 14.628571 4.87619 14.628571 14.628572 0 4.87619 0 9.752381-4.87619 9.752381l-443.733334 370.590476c-4.87619 4.87619-14.628571 4.87619-19.504762 0L82.895238 423.009524c-4.87619-4.87619-4.87619-9.752381-4.87619-9.752381s0-4.87619 4.87619-9.752381 4.87619-4.87619 9.752381-4.876191h146.285714V-30.47619c0-9.752381 4.87619-14.628571 14.628572-14.628572h146.285714c9.752381 0 14.628571 4.87619 14.628571 14.628572v331.580952z" horiz-adv-x="1072" />
|
||||
|
||||
|
||||
<glyph glyph-name="zhunbeizhong" unicode="" d="M512 384m-480 0a480 480 0 1 1 960 0 480 480 0 1 1-960 0ZM512-128c-281.6 0-512 230.4-512 512s230.4 512 512 512 512-230.4 512-512-230.4-512-512-512zM512 832C262.4 832 64 633.6 64 384s198.4-448 448-448 448 198.4 448 448-198.4 448-448 448zM320 384m-64 0a64 64 0 1 1 128 0 64 64 0 1 1-128 0ZM512 384m-64 0a64 64 0 1 1 128 0 64 64 0 1 1-128 0ZM704 384m-64 0a64 64 0 1 1 128 0 64 64 0 1 1-128 0Z" horiz-adv-x="1024" />
|
||||
|
||||
|
||||
|
|
Before Width: | Height: | Size: 506 KiB After Width: | Height: | Size: 522 KiB |
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -224,7 +224,7 @@ class App extends Component {
|
|||
<Switch>
|
||||
{/*项目*/}
|
||||
<Route
|
||||
path={"/projects/:projectId/ops/:opsId/detail"}
|
||||
path={"/projects/:owner/:projectId/devops/:opsId/detail"}
|
||||
render={
|
||||
(props) => {
|
||||
return (<OpsDetail {...this.props} {...props} {...this.state} />)
|
||||
|
|
|
@ -72,6 +72,7 @@ li.ant-menu-item{
|
|||
border-radius:11px;
|
||||
color: #fff;
|
||||
margin-left: 5px;
|
||||
font-size: 12px;
|
||||
&.running{
|
||||
background:#5091FF;
|
||||
color: #F1F8FF;
|
||||
|
@ -88,6 +89,10 @@ li.ant-menu-item{
|
|||
background:#F73030;
|
||||
color:#FCEEEE ;
|
||||
}
|
||||
&.killed{
|
||||
background:#eee;
|
||||
color:#999 ;
|
||||
}
|
||||
}
|
||||
.handleBox{
|
||||
position: fixed;
|
||||
|
|
|
@ -0,0 +1,61 @@
|
|||
import React , { useState , useEffect } from 'react';
|
||||
import { Select } from 'antd';
|
||||
import { getUrl } from 'educoder';
|
||||
|
||||
import axios from 'axios';
|
||||
const Option = Select.Option;
|
||||
|
||||
export default (({ language , select_language })=>{
|
||||
const [ six , setSix ] = useState(undefined);
|
||||
const [ languages , setLanguage ] = useState(undefined);
|
||||
|
||||
useEffect(()=>{
|
||||
const url = '/ci/languages.json';
|
||||
axios.get(url).then(result=>{
|
||||
if(result){
|
||||
setLanguage(result.data);
|
||||
}
|
||||
}).catch(error=>{
|
||||
console.log(error);
|
||||
})
|
||||
},[])
|
||||
|
||||
function changelanguage(value){
|
||||
let array = value ? languages.filter(item=>item.name === value) :undefined;
|
||||
select_language(value,array && array[0]);
|
||||
}
|
||||
|
||||
useEffect(()=>{
|
||||
const url = '/ci/languages/common.json';
|
||||
axios.get(url).then(result=>{
|
||||
if(result){
|
||||
setSix(result.data);
|
||||
}
|
||||
}).catch(error=>{
|
||||
console.log(error);
|
||||
})
|
||||
},[])
|
||||
|
||||
return(
|
||||
<React.Fragment>
|
||||
{
|
||||
six &&
|
||||
<ul className="language">
|
||||
{
|
||||
six.map((item,key)=>{
|
||||
return(
|
||||
key < 6 ? <li className={language ===item.name ? "active":""} onClick={()=>changelanguage(item.name)}><img alt="" src={item.cover_url && getUrl(item.cover_url)} /></li> : ""
|
||||
)
|
||||
})
|
||||
}
|
||||
</ul>
|
||||
}
|
||||
<Select showSearch={true} placeholder={"请选择文本语言"} style={{ width: 200 }} value={language} onChange={changelanguage}>
|
||||
<Option value={undefined}>请选择文本语言</Option>
|
||||
{languages && languages.map((item, key) => {
|
||||
return <Option value={item.name}>{item.name}</Option>;
|
||||
})}
|
||||
</Select>
|
||||
</React.Fragment>
|
||||
)
|
||||
})
|
|
@ -7,7 +7,7 @@ export const Tags = (status)=>{
|
|||
return(
|
||||
<span className="statusColor running">运行中</span>
|
||||
);
|
||||
case "failure":
|
||||
case "failure":case"error":
|
||||
return (
|
||||
<span className="statusColor failed">未通过</span>
|
||||
);
|
||||
|
@ -15,10 +15,14 @@ export const Tags = (status)=>{
|
|||
return (
|
||||
<span className="statusColor pass">已通过</span>
|
||||
);
|
||||
default:
|
||||
case "pending":
|
||||
return (
|
||||
<span className="statusColor Preparing">准备中</span>
|
||||
);
|
||||
case 'killed':
|
||||
return (
|
||||
<span className="statusColor killed">已撤销</span>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -28,7 +32,7 @@ export const TagsLine = (status)=>{
|
|||
return(
|
||||
<span className="statuslineColor running">运行中</span>
|
||||
);
|
||||
case "failure":
|
||||
case "failure":case "error":
|
||||
return (
|
||||
<span className="statuslineColor failed">未通过</span>
|
||||
);
|
||||
|
@ -36,9 +40,13 @@ export const TagsLine = (status)=>{
|
|||
return (
|
||||
<span className="statuslineColor pass">已通过</span>
|
||||
);
|
||||
default:
|
||||
case "pending":
|
||||
return (
|
||||
<span className="statuslineColor Preparing">准备中</span>
|
||||
);
|
||||
case 'killed':
|
||||
return (
|
||||
<span className="statuslineColor killed">已撤销</span>
|
||||
);
|
||||
}
|
||||
}
|
|
@ -3,7 +3,7 @@ import activate from "../Images/activate.png";
|
|||
import { Blueback } from "../Component/layout";
|
||||
import styled from "styled-components";
|
||||
import { Link } from "react-router-dom";
|
||||
import { Form, Input, Modal, Button } from "antd";
|
||||
import { Form, Input, Modal, Button , Spin } from "antd";
|
||||
import axios from "axios";
|
||||
|
||||
const P = styled.p`
|
||||
|
@ -18,11 +18,55 @@ const P = styled.p`
|
|||
}
|
||||
`;
|
||||
function About(props, ref) {
|
||||
const { form: { getFieldDecorator, validateFields } } = props;
|
||||
const [step, setStep] = useState(1);
|
||||
const { form: { getFieldDecorator, validateFields , setFieldsValue } } = props;
|
||||
const [isSpining, setIsSpining] = useState(false);
|
||||
//0: 标识未开启devops
|
||||
//1: 标识用户已填写了云服务器相关信息,但并未开启认证
|
||||
//2: 标识用户已开启了CI服务端的认证
|
||||
//3: 标识用户ci服务已初始化
|
||||
const [step, setStep] = useState(undefined);
|
||||
// step等于1时:不能修改服务器信息提示用户去认证
|
||||
const [visible, setVisible] = useState(false);
|
||||
// step大于1时:为true,不能再修改服务器信息
|
||||
const [firstCompleted, setFirstCompleted] = useState(false);
|
||||
|
||||
const [ redirectUrl ,setRedirectUrl ] = useState(undefined);
|
||||
const [ cloudAccount , setCloudAccount ] = useState(undefined);
|
||||
|
||||
const owner = props.match.params.owner;
|
||||
const projectsId = props.match.params.projectsId;
|
||||
|
||||
useEffect(()=>{
|
||||
auth('get');
|
||||
},[])
|
||||
|
||||
function auth(type){
|
||||
const url = `/${owner}/${projectsId}/ci_authorize.json`;
|
||||
axios({
|
||||
method:`${type}`,
|
||||
url
|
||||
}).then(result=>{
|
||||
if(result && result.data ){
|
||||
let s = result.data.step;
|
||||
setStep(s);
|
||||
if(s >= 1){
|
||||
setFirstCompleted(true);
|
||||
if(s===1){
|
||||
setVisible(true);
|
||||
}
|
||||
let cloud_account = result.data.cloud_account;
|
||||
setCloudAccount(cloud_account);
|
||||
setRedirectUrl(cloud_account.authenticate_url);
|
||||
cloud_account && setFieldsValue({
|
||||
...cloud_account,
|
||||
ip_num:cloud_account.ip
|
||||
});
|
||||
}
|
||||
}
|
||||
}).catch(error=>{
|
||||
console.log(error);
|
||||
})
|
||||
}
|
||||
|
||||
const helper = useCallback(
|
||||
(label, name, rules, widget, isRequired) => (
|
||||
|
@ -38,137 +82,177 @@ function About(props, ref) {
|
|||
// 下一步
|
||||
function goStep() {
|
||||
if (!firstCompleted) {
|
||||
let projectsId = props.match.params.projectsId;
|
||||
setIsSpining(true);
|
||||
props.showNotification("服务器连接绑定中,请耐心等候!");
|
||||
validateFields((error, values) => {
|
||||
if (!error) {
|
||||
const url = `/dev_ops/cloud_accounts.json`;
|
||||
axios.post(url, {
|
||||
...values,
|
||||
project_id: projectsId,
|
||||
})
|
||||
.then((result) => {
|
||||
if (result && result.data.redirect_url) {
|
||||
setVisible(true);
|
||||
setFirstCompleted(true);
|
||||
// window.location.href = result.data.redirect_url;
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
console.log(error);
|
||||
});
|
||||
const url = `/${owner}/${projectsId}/cloud_accounts.json`;
|
||||
axios.post(url, {...values})
|
||||
.then((result) => {
|
||||
setIsSpining(false);
|
||||
if (result && result.data.redirect_url) {
|
||||
setVisible(true);
|
||||
setFirstCompleted(true);
|
||||
setRedirectUrl(result.data.redirect_url);
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
console.log(error);
|
||||
setVisible(false);
|
||||
});
|
||||
}
|
||||
});
|
||||
} else {
|
||||
setStep(2);
|
||||
setVisible(true);
|
||||
}
|
||||
}
|
||||
// 弹框确定
|
||||
function sure(){
|
||||
setVisible(false)
|
||||
setStep(2);
|
||||
setVisible(false);
|
||||
minusPlus(1);
|
||||
auth('put');
|
||||
}
|
||||
|
||||
function minusPlus(num,flag){
|
||||
let s = 0;
|
||||
if(flag){
|
||||
s=step-num;
|
||||
}else{
|
||||
s=step+num;
|
||||
}
|
||||
console.log(s);
|
||||
setStep(s);
|
||||
}
|
||||
|
||||
// 开始激活
|
||||
function startActive(){
|
||||
validateFields((error, values) => {
|
||||
if(!values){
|
||||
|
||||
if(!error){
|
||||
setIsSpining(true);
|
||||
const url = `/${owner}/${projectsId}/cloud_accounts/${cloudAccount && cloudAccount.id}/activate`;
|
||||
axios.post(url,{
|
||||
...values
|
||||
}).then(result=>{
|
||||
setIsSpining(false);
|
||||
if(result && result.data.status === 0){
|
||||
props.history.push(`/projects/${owner}/${projectsId}/devops/dispose`);
|
||||
// 需要将顶部的open_devops修改
|
||||
let { changeOpenDevops } = props;
|
||||
changeOpenDevops && changeOpenDevops(true);
|
||||
}else{
|
||||
props.showNotification('激活失败,请稍后再试!');
|
||||
}
|
||||
}).catch(error=>{
|
||||
console.log(error);
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
// 完成
|
||||
function complete(){
|
||||
props.history.push(`/projects/${owner}/${projectsId}/devops/dispose`);
|
||||
}
|
||||
return (
|
||||
<div className="activatePanel">
|
||||
<Modal
|
||||
title="提示"
|
||||
visible={visible}
|
||||
closable={true}
|
||||
onCancel={() => setVisible(false)}
|
||||
footer={
|
||||
<Spin spinning={isSpining}>
|
||||
<div className="activatePanel">
|
||||
<Modal
|
||||
title="提示"
|
||||
visible={visible}
|
||||
closable={true}
|
||||
onCancel={() => setVisible(false)}
|
||||
footer={
|
||||
<React.Fragment>
|
||||
<Button onClick={() => setVisible(false)}>取消</Button>
|
||||
<Button
|
||||
onClick={sure}
|
||||
type={"primary"}
|
||||
className="ml20"
|
||||
>
|
||||
确定
|
||||
</Button>
|
||||
</React.Fragment>
|
||||
}
|
||||
>
|
||||
<div style={{ display: "flex", justifyContent: "center" }}>
|
||||
<p style={{ maxWidth: "260px" }}>
|
||||
初始化配置已完成,请前往:
|
||||
<br />
|
||||
<a
|
||||
target="_blank"
|
||||
href={redirectUrl}
|
||||
className="color-blue"
|
||||
>
|
||||
{redirectUrl}
|
||||
</a>
|
||||
<br />
|
||||
进入认证
|
||||
</p>
|
||||
</div>
|
||||
</Modal>
|
||||
<img src={activate} alt="" width="250px" />
|
||||
<P>定义DevOps工作流,帮助您检测bug、发布代码…</P>
|
||||
<Link to={""} style={{ color: "#5091FF", marginBottom: "20px" }}>
|
||||
了解什么是DevOps?
|
||||
</Link>
|
||||
{step <=1?
|
||||
<React.Fragment>
|
||||
<Button onClick={() => setVisible(false)}>取消</Button>
|
||||
<Button
|
||||
onClick={sure}
|
||||
type={"primary"}
|
||||
className="ml20"
|
||||
>
|
||||
确定
|
||||
</Button>
|
||||
<Form>
|
||||
<p className="mb20" style={{width:"370px"}}>请仔细核对您的服务器信息,一旦确认提交将无法修改</p>
|
||||
{helper(
|
||||
"服务器IP地址:",
|
||||
"ip_num",
|
||||
[{ required: true, message: "请输入服务器IP地址" }],
|
||||
<Input
|
||||
placeholder="请输入服务器IP地址"
|
||||
style={{ width: "368px" }}
|
||||
size="large"
|
||||
disabled={firstCompleted}
|
||||
/>,
|
||||
true
|
||||
)}
|
||||
{helper(
|
||||
"服务器用户名:",
|
||||
"account",
|
||||
[{ required: true, message: "请输入服务器用户名" }],
|
||||
<Input placeholder="请输入服务器用户名" size="large" disabled={firstCompleted} />,
|
||||
true
|
||||
)}
|
||||
{helper(
|
||||
"服务器密码:",
|
||||
"secret",
|
||||
[{ required: true, message: "请输入服务器密码" }],
|
||||
<Input.Password placeholder="请输入服务器密码" size="large" disabled={firstCompleted}/>,
|
||||
true
|
||||
)}
|
||||
</Form>
|
||||
<Blueback onClick={goStep}>下一步</Blueback>
|
||||
</React.Fragment>
|
||||
}
|
||||
>
|
||||
<div style={{ display: "flex", justifyContent: "center" }}>
|
||||
<p style={{ maxWidth: "260px" }}>
|
||||
初始化配置已完成,请前往:
|
||||
<br />
|
||||
<a
|
||||
target="_blank"
|
||||
href="http://ip:80/login/oauth/authorize"
|
||||
className="color-blue"
|
||||
>
|
||||
http://ip:80/login/oauth/authorize
|
||||
</a>
|
||||
<br />
|
||||
进入认证
|
||||
</p>
|
||||
</div>
|
||||
</Modal>
|
||||
<img src={activate} alt="" width="250px" />
|
||||
<P>定义DevOps工作流,帮助您检测bug、发布代码…</P>
|
||||
<Link to={""} style={{ color: "#5091FF", marginBottom: "20px" }}>
|
||||
了解什么是DevOps?
|
||||
</Link>
|
||||
{step === 1 ? (
|
||||
<React.Fragment>
|
||||
<Form>
|
||||
<p className="mb20" style={{width:"370px"}}>请仔细核对您的服务器信息,一旦确认提交将无法修改</p>
|
||||
{helper(
|
||||
"服务器IP地址:",
|
||||
"ip_num",
|
||||
[{ required: true, message: "请输入服务器IP地址" }],
|
||||
<Input
|
||||
placeholder="请输入服务器IP地址"
|
||||
style={{ width: "368px" }}
|
||||
size="large"
|
||||
disabled={firstCompleted}
|
||||
/>,
|
||||
true
|
||||
)}
|
||||
{helper(
|
||||
"服务器用户名:",
|
||||
"account",
|
||||
[{ required: true, message: "请输入服务器用户名" }],
|
||||
<Input placeholder="请输入服务器用户名" size="large" disabled={firstCompleted} />,
|
||||
true
|
||||
)}
|
||||
{helper(
|
||||
"服务器密码:",
|
||||
"secret",
|
||||
[{ required: true, message: "请输入服务器密码" }],
|
||||
<Input.Password placeholder="请输入服务器密码" size="large" disabled={firstCompleted}/>,
|
||||
true
|
||||
)}
|
||||
</Form>
|
||||
<Blueback onClick={goStep}>下一步</Blueback>
|
||||
</React.Fragment>
|
||||
) : (
|
||||
<div>
|
||||
<Form>
|
||||
<p className="mb20" style={{width:"370px"}}>认证成功后,请前往<a target="_blank" href="http://ip:80/account" className="color-blue">http://ip:80/account</a>获取token值,并将获取的token值填入输入框</p>
|
||||
{helper(
|
||||
"token值:",
|
||||
"token",
|
||||
[{ required: true, message: "请输入token值" }],
|
||||
<Input placeholder="请输入token值" size="large" />,
|
||||
true
|
||||
)}
|
||||
<div style={{ display: "flex", justifyContent: "center" }}>
|
||||
<Button onClick={()=>setStep(1)}>返回上一步</Button>
|
||||
<Blueback onClick={startActive} className="ml20">开始激活</Blueback>
|
||||
:""}
|
||||
|
||||
{step >= 2 &&(
|
||||
<div>
|
||||
<Form>
|
||||
<p className="mb20" style={{width:"370px"}}>认证成功后,请前往<a target="_blank" href={cloudAccount && cloudAccount.get_drone_token_url} className="color-blue">{cloudAccount && cloudAccount.get_drone_token_url}</a>获取token值,并将获取的token值填入输入框</p>
|
||||
{helper(
|
||||
"token值:",
|
||||
"drone_token",
|
||||
[{ required: true, message: "请输入token值" }],
|
||||
<Input placeholder="请输入token值" size="large" />,
|
||||
true
|
||||
)}
|
||||
<div style={{ display: "flex", justifyContent: "center" }}>
|
||||
{
|
||||
step === 2?
|
||||
<Blueback onClick={startActive} className="ml20">开始激活</Blueback>
|
||||
:
|
||||
<Blueback onClick={complete}>完成</Blueback>
|
||||
}
|
||||
</div>
|
||||
</Form>
|
||||
</div>
|
||||
</Form>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</Spin>
|
||||
);
|
||||
}
|
||||
export default Form.create()(forwardRef(About));
|
||||
|
|
|
@ -1,13 +1,15 @@
|
|||
import React , { useState , useEffect } from 'react';
|
||||
import { Spin } from 'antd';
|
||||
import { Blueback } from '../Component/layout';
|
||||
import Editor from "react-monaco-editor";
|
||||
import Modals from './DisposeModal';
|
||||
import FileLanguage from '../Component/FileLanguage';
|
||||
import FileLanguage from '../Component/OpsFileLanguage';
|
||||
import axios from 'axios';
|
||||
|
||||
|
||||
function Dispose(props){
|
||||
const [ info , setInfo ] = useState(undefined);
|
||||
const [ spining , setSpining ] = useState(true);
|
||||
const [ info , setInfo ] = useState('.trustie-pipeline.yml');
|
||||
const [ visible , setVisible ] = useState(false);
|
||||
const [ ymlValue , setYmlValue ] = useState("");
|
||||
const [ six , setSix ] = useState(undefined);
|
||||
|
@ -19,35 +21,25 @@ function Dispose(props){
|
|||
|
||||
useEffect(()=>{
|
||||
if(projectsId){
|
||||
const url = '/dev_ops/builds/get_trustie_pipeline.json';
|
||||
const url = `/${owner}/${projectsId}/get_trustie_pipeline.json`;
|
||||
axios.get(url,{
|
||||
params:{
|
||||
project_id:projectsId
|
||||
}
|
||||
}).then(result=>{
|
||||
if(result && result.data.content){
|
||||
setInfo(result.data);
|
||||
setInfo(result.data.name);
|
||||
setYmlValue(result.data.content);
|
||||
setFirst(true);
|
||||
}else{
|
||||
setFirst(false);
|
||||
}
|
||||
setSpining(false);
|
||||
}).catch(error=>{
|
||||
console.log(error);
|
||||
})
|
||||
}
|
||||
},[])
|
||||
|
||||
useEffect(()=>{
|
||||
const url = '/dev_ops/languages/common.json';
|
||||
axios.get(url).then(result=>{
|
||||
if(result){
|
||||
setSix(result.data);
|
||||
}
|
||||
}).catch(error=>{
|
||||
console.log(error);
|
||||
})
|
||||
},[])
|
||||
},[projectsId])
|
||||
|
||||
// 修改文件内容
|
||||
function changeEditor(value){
|
||||
|
@ -57,7 +49,6 @@ function Dispose(props){
|
|||
// 切换语言
|
||||
function select_language(value,array){
|
||||
setFileLanguage(value);
|
||||
// console.log(array);
|
||||
setYmlValue( array && array.content);
|
||||
}
|
||||
|
||||
|
@ -67,12 +58,12 @@ function Dispose(props){
|
|||
let params = {
|
||||
branch: "master",
|
||||
content:ymlValue,
|
||||
filepath:info && info.name,
|
||||
filepath:info,
|
||||
message:''
|
||||
}
|
||||
if(first){
|
||||
// 为true,则是编辑否则是新建
|
||||
url = `/${owner}/${projectsId}/update_file.json`;
|
||||
url = `/${owner}/${projectsId}/update_trustie_pipeline.json`;
|
||||
axios.put(url,{
|
||||
...params,
|
||||
sha:info && info.sha
|
||||
|
@ -95,32 +86,21 @@ function Dispose(props){
|
|||
}
|
||||
}
|
||||
function suresubmit(){
|
||||
props.history.push(`/projects/${owner}/${projectsId}/ops/list`);
|
||||
props.history.push(`/projects/${owner}/${projectsId}/devops/list`);
|
||||
}
|
||||
|
||||
return(
|
||||
<React.Fragment>
|
||||
<Spin spinning={spining}>
|
||||
<Modals visible={visible} closeFunc={(flag)=>setVisible(flag)} sureFunc={suresubmit}></Modals>
|
||||
<p>编程语言:</p>
|
||||
{
|
||||
six &&
|
||||
<ul className="language">
|
||||
{
|
||||
six && six.map((item,key)=>{
|
||||
return(
|
||||
key < 6 ? <li><img alt="" src={item.cover_url} /></li> : ""
|
||||
)
|
||||
})
|
||||
}
|
||||
</ul>
|
||||
}
|
||||
|
||||
<div className="mt20 mb20">
|
||||
<FileLanguage language={fileLanguage} select_language={select_language}/>
|
||||
</div>
|
||||
<p>配置脚本:</p>
|
||||
<div className="editorBody">
|
||||
<p className="editorHead">
|
||||
<span>{info && info.name}</span>
|
||||
<span>{info}</span>
|
||||
<a><i className="iconfont icon-bianji6 font-14"></i></a>
|
||||
</p>
|
||||
<Editor
|
||||
|
@ -134,7 +114,7 @@ function Dispose(props){
|
|||
></Editor>
|
||||
</div>
|
||||
<Blueback onClick={submit}>确定提交</Blueback>
|
||||
</React.Fragment>
|
||||
</Spin>
|
||||
)
|
||||
}
|
||||
export default Dispose;
|
|
@ -18,17 +18,17 @@ export default ((props)=>{
|
|||
return(
|
||||
<WhiteBack className="opsPanel">
|
||||
<Switch {...props}>
|
||||
<Route path="/projects/:projectsId/ops/dispose"
|
||||
<Route path="/projects/:owner/:projectsId/devops/dispose"
|
||||
render={
|
||||
() => (<Infos {...props} />)
|
||||
}
|
||||
></Route>
|
||||
<Route path="/projects/:projectsId/ops/list"
|
||||
<Route path="/projects/:owner/:projectsId/devops/list"
|
||||
render={
|
||||
() => (<Infos {...props} />)
|
||||
}
|
||||
></Route>
|
||||
<Route path="/projects/:projectsId/ops"
|
||||
<Route path="/projects/:owner/:projectsId/devops"
|
||||
render={
|
||||
() => (<About {...props} />)
|
||||
}
|
||||
|
|
|
@ -11,27 +11,27 @@ const Div = styled.div`{
|
|||
padding:24px 30px;
|
||||
}`;
|
||||
export default ((props)=>{
|
||||
const [ menu , setMenu ] = useState(undefined);
|
||||
const [ menu , setMenu ] = useState(false);
|
||||
|
||||
const path = props.location.pathname;
|
||||
const owner = props.match.params.owner;
|
||||
const projectsId = props.match.params.projectsId;
|
||||
useEffect(()=>{
|
||||
// console.log(props.match.params.projectsId)
|
||||
if(path === `/projects/${props.match.params.projectsId}/ops/list`){
|
||||
if(path === `/projects/${owner}/${projectsId}/devops/list`){
|
||||
setMenu(true);
|
||||
}else{
|
||||
setMenu(false);
|
||||
}
|
||||
},[path])
|
||||
|
||||
return(
|
||||
<div className="disposePanel">
|
||||
<Banner>
|
||||
<Link to={`/projects/${props.match.params.projectsId}/ops/dispose`}>工作流配置</Link>
|
||||
{ menu ? <Link to={`/projects/${props.match.params.projectsId}/ops/list`} style={{ marginLeft:"66px",color:"#5091FF" }}>构建列表</Link>:""}
|
||||
<Link to={`/projects/${owner}/${props.match.params.projectsId}/devops/dispose`} className={menu===false && "color-blue"}>工作流配置</Link>
|
||||
<Link to={`/projects/${owner}/${props.match.params.projectsId}/devops/list`}className={menu===true && "color-blue"} style={{ marginLeft:"66px"}}>构建列表</Link>
|
||||
</Banner>
|
||||
<Div>
|
||||
{ menu && menu === true && <Structure {...props}/> }
|
||||
{ menu && menu === false && <Dispost {...props}/> }
|
||||
{ menu === true && <Structure {...props}/> }
|
||||
{ menu === false && <Dispost {...props}/> }
|
||||
</Div>
|
||||
</div>
|
||||
)
|
||||
|
|
|
@ -5,6 +5,7 @@ import { Menu, Popconfirm } from "antd";
|
|||
import { TagsLine } from "../Component/OpsStatus";
|
||||
import { Time } from "../Utils/Time";
|
||||
import { truncateCommitId } from "../common/util";
|
||||
import { getUrl } from 'educoder';
|
||||
|
||||
const SubMenu = Menu.SubMenu;
|
||||
const Img = styled.img`
|
||||
|
@ -15,7 +16,7 @@ const Img = styled.img`
|
|||
margin-right: 10px;
|
||||
}
|
||||
`;
|
||||
export default ({ data, repeatSet }) => {
|
||||
export default ({ data, repeatSet , chooseSteps }) => {
|
||||
const [tamp, setTamp] = useState(undefined);
|
||||
const [sha, setSha] = useState(undefined);
|
||||
useEffect(() => {
|
||||
|
@ -29,113 +30,97 @@ export default ({ data, repeatSet }) => {
|
|||
}
|
||||
}, [data]);
|
||||
|
||||
function renderMenu() {
|
||||
if (data.stages && data.stages.length > 0) {
|
||||
data.stages.map((item, key) => {
|
||||
return item.steps && item.steps.length > 0 ? (
|
||||
<SubMenu
|
||||
title={
|
||||
<div>
|
||||
<i className="iconfont icon-gongzuoliu font-14 mr4"></i>
|
||||
<span>{item.name}</span>
|
||||
</div>
|
||||
}
|
||||
>
|
||||
{item.steps.map((i, k) => {
|
||||
return (
|
||||
<Menu.Item>
|
||||
<FlexAJ>
|
||||
<span>
|
||||
{i.name} {i.status ? TagsLine(i.status) : ""}
|
||||
</span>
|
||||
<span>
|
||||
{i.stopped
|
||||
? parseInt(parseInt(i.stopped) - parseInt(i.started))
|
||||
: "0"}
|
||||
s
|
||||
</span>
|
||||
</FlexAJ>
|
||||
</Menu.Item>
|
||||
);
|
||||
})}
|
||||
</SubMenu>
|
||||
) : (
|
||||
""
|
||||
);
|
||||
});
|
||||
function renderStatusBtn() {
|
||||
let status = data && data.status;
|
||||
let number = data && data.number;
|
||||
if (status === "failure" || status === "error" || status === "success") {
|
||||
return "";
|
||||
}else if(status === "killed"){
|
||||
return(
|
||||
<Popconfirm
|
||||
title="确认重新构建?"
|
||||
onConfirm={(e) => repeatSet(e,'repeat',number)}
|
||||
onCancel={(e)=>{e.stopPropagation()}}
|
||||
cancelText="取消"
|
||||
okText="确定"
|
||||
>
|
||||
<Blueline onClick={(e)=>{e.stopPropagation()}}>重新构建</Blueline>
|
||||
</Popconfirm>
|
||||
);
|
||||
} else {
|
||||
return (
|
||||
<Popconfirm
|
||||
title="确认撤销构建?"
|
||||
onConfirm={(e) => repeatSet(e,'cancel',number)}
|
||||
onCancel={(e)=>{e.stopPropagation()}}
|
||||
cancelText="取消"
|
||||
okText="确定"
|
||||
>
|
||||
<Blueline onClick={(e)=>{e.stopPropagation()}}>撤销构建</Blueline>
|
||||
</Popconfirm>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function titleClick(e,index){
|
||||
console.log(index);
|
||||
function clickSub(e,stageN,stepN,stageName){
|
||||
chooseSteps(stageN,stepN,stageName);
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
<FlexAJ className="leftheader">
|
||||
<AlignCenter>
|
||||
<Img src={data && data.author_avatar} />
|
||||
{data && data.started ? (
|
||||
<Img src={getUrl(`/images/${data && data.author && data.author.image_url}`)} />
|
||||
{data && data.started &&
|
||||
<span className="nest">
|
||||
开始时间:<span> {tamp}</span>
|
||||
开始时间:<span> {data.started}</span>
|
||||
</span>
|
||||
) : (
|
||||
""
|
||||
)}
|
||||
<span className="nest">
|
||||
运行时间:<span>{data && data.timestamp}s</span>
|
||||
</span>
|
||||
}
|
||||
{
|
||||
data && data.duration_time &&
|
||||
<span className="nest">
|
||||
运行时间:<span>{data.duration_time}</span>
|
||||
</span>
|
||||
}
|
||||
</AlignCenter>
|
||||
<Popconfirm
|
||||
title="是否重新创建?"
|
||||
okText="确定"
|
||||
cancelText="取消"
|
||||
onConfirm={repeatSet}
|
||||
>
|
||||
<Blueline>重新创建</Blueline>
|
||||
</Popconfirm>
|
||||
{renderStatusBtn()}
|
||||
</FlexAJ>
|
||||
<div className="leftMainContent">
|
||||
<AlignCenter className="contentBranch">
|
||||
<i className="iconfont icon-fenzhi1"></i>
|
||||
<span>分支:</span>
|
||||
<span className="branchname">{data && data.source}</span>
|
||||
<span className="branchsha">{sha}</span>
|
||||
<span className="branchname">{data && data.branch_target}</span>
|
||||
<span className="branchsha">{data && truncateCommitId(data.build_after_sha)}</span>
|
||||
</AlignCenter>
|
||||
</div>
|
||||
<Menu mode="inline" className="leftMenu">
|
||||
{data && data.stages
|
||||
? data.stages.map((item, key) => {
|
||||
return item.steps && item.steps.length > 0 ? (
|
||||
<SubMenu
|
||||
title={
|
||||
<div>
|
||||
<i className="iconfont icon-gongzuoliu font-14 mr4"></i>
|
||||
<span>{item.name}</span>
|
||||
</div>
|
||||
}
|
||||
onTitleClick={(e)=>titleClick(e,key)}
|
||||
>
|
||||
{item.steps.map((i, k) => {
|
||||
return (
|
||||
<Menu.Item>
|
||||
<FlexAJ>
|
||||
<span>
|
||||
{i.name} {i.status ? TagsLine(i.status) : ""}
|
||||
</span>
|
||||
<span>
|
||||
{i.stopped ? (parseInt(i.stopped) - parseInt(i.started)): "0"}s
|
||||
</span>
|
||||
</FlexAJ>
|
||||
</Menu.Item>
|
||||
);
|
||||
})}
|
||||
</SubMenu>
|
||||
) : (
|
||||
""
|
||||
);
|
||||
})
|
||||
: ""}
|
||||
<Menu mode="inline" className="leftMenu" defaultSelectedKeys={[0]}>
|
||||
{data && data.stages ? data.stages.map((item, key) => {
|
||||
return item.steps && item.steps.length > 0 ?
|
||||
<SubMenu
|
||||
title={
|
||||
<div>
|
||||
<i className="iconfont icon-gongzuoliu font-14 mr4"></i>
|
||||
<span>{item.name}</span>
|
||||
</div>
|
||||
}
|
||||
key={key}
|
||||
>
|
||||
{item.steps.map((i, k) => {
|
||||
return (
|
||||
<Menu.Item onClick={(e)=>clickSub(e,item.number,i.id,item.name)}>
|
||||
<FlexAJ>
|
||||
<span>
|
||||
{i.name} {i.status ? TagsLine(i.status) : ""}
|
||||
</span>
|
||||
<span>{i.duration_time}</span>
|
||||
</FlexAJ>
|
||||
</Menu.Item>
|
||||
);
|
||||
})}
|
||||
</SubMenu>
|
||||
: "";
|
||||
})
|
||||
: ""}
|
||||
</Menu>
|
||||
</div>
|
||||
);
|
||||
|
|
|
@ -1,31 +1,62 @@
|
|||
import React, {useState,useEffect} from "react";
|
||||
import { Spin } from 'antd';
|
||||
import { FlexAJ, AlignCenter } from "../Component/layout";
|
||||
import axios from 'axios';
|
||||
|
||||
export default ({ stages }) => {
|
||||
const [ list , setList ] = useState(undefined);
|
||||
export default (({ step , stageNumber , stageName , projectId , owner , opsId , rightSpin }) => {
|
||||
const [ coders , setCoders ] = useState(undefined);
|
||||
const [ empty , setEmpty ] = useState(false);
|
||||
const [ spining , setSpining ] = useState(true);
|
||||
useEffect(()=>{
|
||||
if(stages){
|
||||
console.log(stages.steps);
|
||||
setList(stages.steps);
|
||||
setSpining(rightSpin);
|
||||
},[rightSpin])
|
||||
useEffect(()=>{
|
||||
if(projectId && stageNumber && step){
|
||||
const url = `/${owner}/${projectId}/builds/${opsId}/logs/${stageNumber}/${step && step.number}.json`;
|
||||
axios.get(url).then(result=>{
|
||||
if(result){
|
||||
setCoders(result.data);
|
||||
setSpining(false);
|
||||
}else{
|
||||
setEmpty(true);
|
||||
}
|
||||
}).catch(error=>{
|
||||
console.log(error);
|
||||
})
|
||||
}
|
||||
},[stages])
|
||||
},[projectId , stageNumber, step])
|
||||
|
||||
return (
|
||||
<div className="rightMainContent">
|
||||
{list && list.length>0 ? list.map((item, key) => {
|
||||
return (
|
||||
<div>
|
||||
<FlexAJ className="items">
|
||||
<span>{item.name}</span>
|
||||
<AlignCenter>
|
||||
{ item.stopped ? (parseInt(item.stopped) - parseInt(item.started)) : "0" }
|
||||
<i className="iconfont icon-triangle"></i>
|
||||
</AlignCenter>
|
||||
</FlexAJ>
|
||||
</div>
|
||||
);
|
||||
}):"1111"
|
||||
}
|
||||
</div>
|
||||
<Spin spinning={spining}>
|
||||
<div className="rightMainContent">
|
||||
<div>
|
||||
<FlexAJ className="items">
|
||||
<span>{step && step.name}</span>
|
||||
<AlignCenter>
|
||||
{ step && step.duration_time}
|
||||
<i className="iconfont icon-sanjiaoxing-down"></i>
|
||||
</AlignCenter>
|
||||
</FlexAJ>
|
||||
<div>
|
||||
{
|
||||
coders && coders.length>0 ? coders.map((item,key)=>{
|
||||
return(
|
||||
<div className="opsDetailOut">
|
||||
<span>{key+1}</span>
|
||||
<p>{item.out}</p>
|
||||
</div>
|
||||
)
|
||||
}):
|
||||
empty ?
|
||||
<div className="opsDetailOut">
|
||||
<span>1</span>
|
||||
<p>{stageName} – {step && step.name}: Skipped</p>
|
||||
</div>
|
||||
:""
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Spin>
|
||||
);
|
||||
};
|
||||
});
|
||||
|
|
|
@ -2,80 +2,69 @@ import React, { useState, useEffect } from "react";
|
|||
import { FlexAJ, AlignCenter, Blueback } from "../Component/layout";
|
||||
import { Table, Pagination, Popconfirm } from "antd";
|
||||
import { truncateCommitId } from "../common/util";
|
||||
import {getUrl} from 'educoder';
|
||||
import styled from "styled-components";
|
||||
import axios from "axios";
|
||||
import { Time } from "../Utils/Time";
|
||||
|
||||
const STATUS = [
|
||||
{ name: "所有", value: "1" },
|
||||
{ name: "准备中", value: "2" },
|
||||
{ name: "运行中", value: "3" },
|
||||
{ name: "已完成", value: "4" },
|
||||
{ name: "所有"},
|
||||
{ name: "准备中", value: "pending" },
|
||||
{ name: "构建失败", value: "failure" },
|
||||
{ name: "运行中", value: "running" },
|
||||
{ name: "已完成", value: "success" },
|
||||
];
|
||||
const LIMIT = 15;
|
||||
const Img = styled.img`
|
||||
{
|
||||
border-radius: 50%;
|
||||
margin-rigth: 10px;
|
||||
width: 25px;
|
||||
height: 25px;
|
||||
}
|
||||
`;
|
||||
export default (props) => {
|
||||
const [status, setStatus] = useState("1");
|
||||
const [status, setStatus] = useState(undefined);
|
||||
const [page, setPage] = useState(1);
|
||||
const [total, setTotal] = useState(10);
|
||||
const [total, setTotal] = useState(0);
|
||||
const [data, setData] = useState(undefined);
|
||||
const [tableLoading, setTableLoading] = useState(true);
|
||||
|
||||
let projectsId = props.match.params.projectsId;
|
||||
let projectsId = props.match.params.projectsId;
|
||||
let owner = props.match.params.owner;
|
||||
|
||||
useEffect(() => {
|
||||
if (projectsId) {
|
||||
Init();
|
||||
}
|
||||
}, []);
|
||||
|
||||
function Init() {
|
||||
const url = "/dev_ops/builds.json";
|
||||
axios
|
||||
.get(url, {
|
||||
params: {
|
||||
project_id: projectsId,
|
||||
},
|
||||
})
|
||||
.then((result) => {
|
||||
if (result) {
|
||||
let list =
|
||||
result.data &&
|
||||
result.data.map((item, key) => {
|
||||
return {
|
||||
status: item.status,
|
||||
author: item.sender,
|
||||
message: {
|
||||
branch: item.source,
|
||||
image: item.author_avatar,
|
||||
message: item.message,
|
||||
sha: truncateCommitId(item.after),
|
||||
},
|
||||
started: item.started
|
||||
? Time(parseInt(item.started) * 1000)
|
||||
: "--",
|
||||
timestamp: item.timestamp,
|
||||
number: item.number,
|
||||
id:item.id
|
||||
};
|
||||
});
|
||||
setData(list);
|
||||
setTableLoading(false);
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
console.log(error);
|
||||
});
|
||||
let current_user = props.current_user;
|
||||
function Init(status) {
|
||||
const url = `/${owner}/${projectsId}/builds.json`;
|
||||
axios.get(url,{
|
||||
params:{
|
||||
search:status,
|
||||
page,limit:LIMIT
|
||||
}
|
||||
}).then((result) => {
|
||||
if (result && result.data) {
|
||||
console.log(result);
|
||||
let list = result.data.builds && result.data.builds.map((item, key) => {
|
||||
return {
|
||||
...item,
|
||||
author:item.author && item.author.name,
|
||||
message: {
|
||||
branch: item.branch_target,
|
||||
message: item.message,
|
||||
sha: truncateCommitId(item.build_after_sha),
|
||||
},
|
||||
started: item.started || "--"
|
||||
};
|
||||
});
|
||||
setTotal(result.data.total_count);
|
||||
setData(list);
|
||||
setTableLoading(false);
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
console.log(error);
|
||||
});
|
||||
}
|
||||
|
||||
function ChangeStatus(value) {
|
||||
setStatus(value);
|
||||
Init(value);
|
||||
}
|
||||
// 切换分页
|
||||
function ChangePage(page) {
|
||||
|
@ -98,8 +87,10 @@ export default (props) => {
|
|||
);
|
||||
}
|
||||
function renderStatusBtn(status, number) {
|
||||
if (status === "failure" || status === "success") {
|
||||
return (
|
||||
if (status === "failure" || status === "error" || status === "success") {
|
||||
return "";
|
||||
}else if(status === "killed"){
|
||||
return(
|
||||
<Popconfirm
|
||||
title="确认重新构建?"
|
||||
onConfirm={(e) => repeatSet(e,number)}
|
||||
|
@ -128,36 +119,32 @@ export default (props) => {
|
|||
function repeatSet(e,number) {
|
||||
e.stopPropagation();
|
||||
setTableLoading(true);
|
||||
const url = `/dev_ops/builds/${number}.json`;
|
||||
axios.post(url, { project_id: projectsId })
|
||||
.then((result) => {
|
||||
if (result) {
|
||||
props.showNotification("工作流正在重新构建!");
|
||||
Init();
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
console.log(error);
|
||||
});
|
||||
const url = `/${owner}/${projectsId}/builds/${number}/restart.json`;
|
||||
axios.post(url).then((result) => {
|
||||
if (result) {
|
||||
props.showNotification("工作流正在重新构建!");
|
||||
Init();
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
console.log(error);
|
||||
});
|
||||
}
|
||||
|
||||
// 撤销构建
|
||||
function cancelSet(e,number) {
|
||||
e.stopPropagation();
|
||||
setTableLoading(true);
|
||||
const url = `/dev_ops/builds/${number}.json`;
|
||||
axios.delete(url, {
|
||||
params:{project_id: projectsId}
|
||||
})
|
||||
.then((result) => {
|
||||
if (result) {
|
||||
props.showNotification("撤销构建成功!");
|
||||
Init(projectsId);
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
console.log(error);
|
||||
});
|
||||
const url = `/${owner}/${projectsId}/builds/${number}/stop.json`;
|
||||
axios.delete(url).then((result) => {
|
||||
if (result) {
|
||||
props.showNotification("撤销构建成功!");
|
||||
Init(projectsId);
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
console.log(error);
|
||||
});
|
||||
}
|
||||
|
||||
function renderTableStatus(status) {
|
||||
|
@ -168,7 +155,7 @@ export default (props) => {
|
|||
<i className="iconfont icon-yunhangzhong"></i>运行中
|
||||
</span>
|
||||
);
|
||||
case "failure":
|
||||
case "failure": case 'error':
|
||||
return (
|
||||
<span className="statusTag failed">
|
||||
<i className="iconfont icon-weitongguo"></i>未通过
|
||||
|
@ -180,7 +167,13 @@ export default (props) => {
|
|||
<i className="iconfont icon-yitongguo"></i>已通过
|
||||
</span>
|
||||
);
|
||||
default:
|
||||
case 'killed':
|
||||
return (
|
||||
<span className="statusTag killed">
|
||||
<i className="iconfont icon-weitongguo"></i>已撤销
|
||||
</span>
|
||||
);
|
||||
case 'pending':
|
||||
return (
|
||||
<span className="statusTag Preparing">
|
||||
<i className="iconfont icon-zhunbeizhong"></i>准备中
|
||||
|
@ -190,7 +183,7 @@ export default (props) => {
|
|||
}
|
||||
|
||||
function clickRows(event,e){
|
||||
props.history.push(`/projects/${projectsId}/ops/${e.number}/detail`);
|
||||
props.history.push(`/projects/${owner}/${projectsId}/devops/${e.number}/detail`);
|
||||
}
|
||||
const column = [
|
||||
{
|
||||
|
@ -199,6 +192,7 @@ export default (props) => {
|
|||
key: "number",
|
||||
width: "8%",
|
||||
render: ( value, item, key) => {
|
||||
console.log(item);
|
||||
return <span>#{value}</span>;
|
||||
},
|
||||
},
|
||||
|
@ -237,7 +231,7 @@ export default (props) => {
|
|||
{meg.sha && <span className="color-orange">{meg.sha}</span>}
|
||||
</div>
|
||||
<AlignCenter>
|
||||
<Img src={meg.image} />
|
||||
<img style={{borderRadius:"50%",marginRight:"10px",width:"25px",height:"25px"}} src={`${current_user && getUrl(`/images/${current_user.image_url}`)}`} />
|
||||
<div className="task-hide ml5" style={{ maxWidth: "300px" }}>
|
||||
{meg.message}
|
||||
</div>
|
||||
|
@ -257,11 +251,11 @@ export default (props) => {
|
|||
},
|
||||
{
|
||||
title: "运行时间",
|
||||
dataIndex: "timestamp",
|
||||
key: "timestamp",
|
||||
dataIndex: "duration_time",
|
||||
key: "duration_time",
|
||||
width: "15%",
|
||||
render: (value, item, key) => {
|
||||
return <span>{value || value === 0 ? `${value}s` : "--"}</span>;
|
||||
return <span>{value || "--"}</span>;
|
||||
},
|
||||
},
|
||||
{
|
||||
|
@ -277,16 +271,14 @@ export default (props) => {
|
|||
<div className="listPart">
|
||||
<FlexAJ>
|
||||
{renderStatus()}
|
||||
<span>
|
||||
<Blueback className="mr30">手动创建</Blueback>
|
||||
<span className="mr30">
|
||||
<Blueback>手动创建</Blueback>
|
||||
{/* <span className="mr30">
|
||||
<i className="iconfont icon-fenzhi1 font-16 mr5 color-blue"></i>分支
|
||||
</span>
|
||||
<span>
|
||||
<i className="iconfont icon-biaoqian3 font-16 mr5 color-blue"></i>
|
||||
标签
|
||||
</span>
|
||||
</span>
|
||||
</span> */}
|
||||
</FlexAJ>
|
||||
<Table
|
||||
onRow={(record,index)=>{
|
||||
|
|
|
@ -12,8 +12,14 @@
|
|||
.disposePanel{
|
||||
.language{
|
||||
display: flex;
|
||||
margin-bottom: 20px;
|
||||
li{
|
||||
margin-right: 20px;
|
||||
cursor: pointer;
|
||||
border:1px solid #fff;
|
||||
&.active{
|
||||
border:1px solid #5091FF;
|
||||
}
|
||||
}
|
||||
}
|
||||
.editorBody{
|
||||
|
@ -36,6 +42,7 @@
|
|||
top:7px;
|
||||
}
|
||||
.listPart{
|
||||
min-height: 400px;
|
||||
.listNav{
|
||||
display: flex;
|
||||
li{
|
||||
|
@ -63,6 +70,7 @@
|
|||
.ant-table-thead > tr > th, .ant-table-tbody > tr > td{
|
||||
padding:10px 5px;
|
||||
color:#333;
|
||||
cursor: pointer;
|
||||
}
|
||||
.ant-table-thead{
|
||||
border:1px solid rgba(238,238,238,1)
|
||||
|
@ -106,6 +114,11 @@
|
|||
border:1px solid #F73030;
|
||||
color:#F73030 ;
|
||||
}
|
||||
&.killed{
|
||||
background:#eee;
|
||||
border:1px solid #999;
|
||||
color:#999 ;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -208,6 +221,10 @@
|
|||
border:1px solid rgba(255,110,33,1);
|
||||
color:rgba(255,110,33,1);
|
||||
}
|
||||
&.killed{
|
||||
border:1px solid #999;
|
||||
color:#999;
|
||||
}
|
||||
}
|
||||
}
|
||||
&.rightSection{
|
||||
|
@ -215,6 +232,8 @@
|
|||
background-color: #081930;
|
||||
.rightMainContent{
|
||||
padding:24px 30px;
|
||||
height:100vh;
|
||||
overflow-y: auto;
|
||||
& > div{
|
||||
margin-bottom: 12px;
|
||||
.items{
|
||||
|
@ -267,4 +286,20 @@
|
|||
cursor: col-resize;
|
||||
}
|
||||
}
|
||||
}
|
||||
.opsDetailOut{
|
||||
display: flex;
|
||||
color: #fff;
|
||||
line-height: 22px;
|
||||
align-items: flex-start;
|
||||
margin-top: 5px;
|
||||
&>span{
|
||||
margin-right: 10px;
|
||||
min-width: 20px;
|
||||
text-align: left;
|
||||
padding-left: 3px;
|
||||
}
|
||||
&>p{
|
||||
margin-bottom: 0px;
|
||||
}
|
||||
}
|
|
@ -12,9 +12,14 @@ import { Link } from "react-router-dom";
|
|||
export default (props) => {
|
||||
const [data, setData] = useState(undefined);
|
||||
const [stages, setStages] = useState(undefined);
|
||||
const [ rightStageName , setRightStageName ] = useState(undefined);
|
||||
const [rightStep, setRightStep] = useState(undefined);
|
||||
const [rightSpin, setRightSpin] = useState(false);
|
||||
const [rightStageNumber, setRightStageNumber] = useState(undefined);
|
||||
const [spinning, setSpinning] = useState(true);
|
||||
|
||||
let projectId = props.match.params.projectId;
|
||||
let owner = props.match.params.owner;
|
||||
let opsId = props.match.params.opsId;
|
||||
|
||||
useEffect(() => {
|
||||
|
@ -24,40 +29,66 @@ export default (props) => {
|
|||
}, [opsId]);
|
||||
|
||||
function Init() {
|
||||
const url = `/dev_ops/builds/${opsId}.json`;
|
||||
axios
|
||||
.get(url, {
|
||||
params: {
|
||||
project_id: projectId,
|
||||
},
|
||||
})
|
||||
.then((result) => {
|
||||
const url = `/${owner}/${projectId}/builds/${opsId}.json`;
|
||||
axios.get(url).then((result) => {
|
||||
if (result && result.data) {
|
||||
setSpinning(false);
|
||||
setData(result.data);
|
||||
let stages = result.data.stages;
|
||||
setStages(stages);
|
||||
let firstStage = stages && stages.length > 0 && stages[0];
|
||||
let firstStep = firstStage && firstStage.steps && firstStage.steps.length>0 && firstStage.steps[0];
|
||||
setRightStep(firstStep);
|
||||
setRightSpin(true);
|
||||
setRightStageName(firstStage && firstStage.name);
|
||||
setRightStageNumber(firstStage && firstStage.number);
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
console.log(error);
|
||||
setSpinning(false);
|
||||
});
|
||||
}
|
||||
|
||||
// 重新构建
|
||||
function repeatSet(e,type,number) {
|
||||
if(type==="repeat"){
|
||||
// 重新构建
|
||||
const url = `/${owner}/${projectId}/builds/${number}/restart.json`;
|
||||
axios.post(url).then((result) => {
|
||||
if (result && result.data) {
|
||||
setSpinning(false);
|
||||
setData(result.data);
|
||||
setStages(
|
||||
result.data.stages && result.data.stages.length > 0 ? result.data.stages[0] : undefined
|
||||
);
|
||||
props.showNotification("工作流正在重新构建!");
|
||||
props.history.push(`/projects/${owner}/${projectId}/devops/${result.data.number}/detail`);
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
console.log(error);
|
||||
});
|
||||
}
|
||||
|
||||
// 重新构建
|
||||
function repeatSet() {
|
||||
const url = `/dev_ops/builds/${data && data.number}.json`;
|
||||
axios
|
||||
.post(url, { project_id: projectId })
|
||||
.then((result) => {
|
||||
}else{
|
||||
// 撤销构建
|
||||
const url = `/${owner}/${projectId}/builds/${number}/stop.json`;
|
||||
axios.delete(url).then((result) => {
|
||||
if (result) {
|
||||
props.showNotification("撤销构建成功!");
|
||||
Init();
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
console.log(error);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function chooseSteps(stageN,stepN,stageName){
|
||||
if(stageN && stepN && stages){
|
||||
let stage = stages && stages.length>0 && stages.filter(item=>item.number===stageN)[0];
|
||||
let s = stage.steps && stage.steps.length > 0 && stage.steps.filter(item=>item.id===stepN);
|
||||
|
||||
s && s.length>0 && setRightStep(s[0]);
|
||||
setRightStageNumber(stageN);
|
||||
setRightStageName(stageName);
|
||||
setRightSpin(true);
|
||||
}
|
||||
}
|
||||
return (
|
||||
<Spin spinning={spinning}>
|
||||
|
@ -70,9 +101,9 @@ export default (props) => {
|
|||
</AlignCenter>
|
||||
<Link
|
||||
style={{ color: "#ddd" }}
|
||||
to={`/projects/${projectId}/ops/list`}
|
||||
to={`/projects/${owner}/${projectId}/devops/list`}
|
||||
>
|
||||
<i className="iconfont icon-yiguanbi font-15 mr5"></i>退出
|
||||
<i className="iconfont icon-yiguanbi font-15 mr5"></i>退出
|
||||
</Link>
|
||||
</FlexAJ>
|
||||
<div className="opsSection">
|
||||
|
@ -84,10 +115,10 @@ export default (props) => {
|
|||
defaultSize="40%"
|
||||
>
|
||||
<section className="leftSection">
|
||||
<LeftPanel data={data} repeatSet={repeatSet} />
|
||||
<LeftPanel data={data} repeatSet={repeatSet} chooseSteps={chooseSteps} />
|
||||
</section>
|
||||
<section className="rightSection">
|
||||
<RightPanel stages={stages} />
|
||||
<RightPanel stageName={rightStageName} rightSpin={rightSpin} step={rightStep} stageNumber = {rightStageNumber} owner={owner} projectId={projectId} opsId={opsId} />
|
||||
</section>
|
||||
</SplitPane>
|
||||
</div>
|
||||
|
|
|
@ -134,6 +134,8 @@ function checkPathname(pathname){
|
|||
name="activity"
|
||||
}else if(pathname.indexOf("/setting")>-1){
|
||||
name="setting"
|
||||
}else if(pathname.indexOf("/devops")>-1){
|
||||
name="devops"
|
||||
}
|
||||
}
|
||||
return name;
|
||||
|
@ -159,6 +161,7 @@ class Detail extends Component {
|
|||
project: null,
|
||||
firstSync:false,
|
||||
secondSync:false,
|
||||
open_devops:false,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -180,8 +183,21 @@ class Detail extends Component {
|
|||
axios.get(url).then((result) => {
|
||||
if (result && result.data) {
|
||||
this.setState({
|
||||
project: result.data
|
||||
project: result.data,
|
||||
open_devops:result.data.open_devops
|
||||
})
|
||||
|
||||
// 工作流:两种状态进入的链接不同
|
||||
const pathname = this.props.history.location.pathname;
|
||||
let p = checkPathname(pathname);
|
||||
if(p==="devops"){
|
||||
if(result.data.open_devops && pathname === `/projects/${owner}/${projectsId}/devops`){
|
||||
this.props.history.push(`/projects/${owner}/${projectsId}/devops/list`);
|
||||
}else if(result.data.open_devops===false && pathname !== `/projects/${owner}/${projectsId}/devops`){
|
||||
this.props.history.push(`/projects/${owner}/${projectsId}/devops`);
|
||||
}
|
||||
}
|
||||
|
||||
if (result.data.type !== 0 && result.data.mirror_status === 1) {
|
||||
console.log("--------start channel --------");
|
||||
// 是镜像项目,且未完成迁移
|
||||
|
@ -207,6 +223,13 @@ class Detail extends Component {
|
|||
}
|
||||
})
|
||||
}
|
||||
|
||||
// 工作流激活后修改状态
|
||||
changeOpenDevops=(flag)=>{
|
||||
this.setState({
|
||||
open_devops:flag
|
||||
})
|
||||
}
|
||||
canvasChannel = () => {
|
||||
const name = window.location.hostname === "localhost" ? "testforgeplus.trustie.net" : window.location.hostname;
|
||||
const actioncable = require("actioncable");
|
||||
|
@ -234,7 +257,7 @@ class Detail extends Component {
|
|||
const { projectsId , owner } = this.props.match.params;
|
||||
const url = `/${owner}/${projectsId}.json`;
|
||||
axios.get(url).then((result) => {
|
||||
if (result) {
|
||||
if (result && result.data) {
|
||||
this.setState({
|
||||
projectDetail: result.data,
|
||||
project_id: result.data.project_id,
|
||||
|
@ -337,7 +360,11 @@ class Detail extends Component {
|
|||
|
||||
|
||||
render() {
|
||||
const { projectDetail, watchers_count, praises_count, forked_count, firstSync , secondSync , isManager, watched, praised, project } = this.state;
|
||||
const { projectDetail, watchers_count, praises_count,
|
||||
forked_count, firstSync , secondSync ,
|
||||
isManager, watched, praised,
|
||||
project , open_devops } = this.state;
|
||||
|
||||
const url = this.props.history.location.pathname;
|
||||
const urlArr = url.split("/");
|
||||
const urlFlag = (urlArr.length === 3);
|
||||
|
@ -361,7 +388,8 @@ class Detail extends Component {
|
|||
|
||||
|
||||
const common = {
|
||||
getDetail: this.getDetail
|
||||
getDetail: this.getDetail,
|
||||
changeOpenDevops:this.changeOpenDevops
|
||||
}
|
||||
return (
|
||||
<div>
|
||||
|
@ -391,10 +419,11 @@ class Detail extends Component {
|
|||
projectDetail.type === 2 ?
|
||||
<Tooltip title={"镜像自: " + projectDetail.mirror_url} className="ml5" placement={'right'}>
|
||||
<i className="iconfont icon-banbenku font-18 mt6" style={{ color: "#8D90E3" }}/>
|
||||
</Tooltip>:
|
||||
</Tooltip>
|
||||
:
|
||||
<Tooltip title={"镜像自: " + projectDetail.mirror_url} className="ml5" placement={'right'}>
|
||||
<i className="iconfont icon-jingxiang font-18 color-green mt6" />
|
||||
</Tooltip>
|
||||
<i className="iconfont icon-jingxiang font-18 color-green mt6" />
|
||||
</Tooltip>
|
||||
:""
|
||||
}
|
||||
</span>
|
||||
|
@ -458,12 +487,12 @@ class Detail extends Component {
|
|||
</Link>
|
||||
</li>
|
||||
}
|
||||
{/* <li className={url.indexOf("/ops") > -1 ? "active" : ""}>
|
||||
<Link to={{ pathname: `/projects/${owner}/${projectsId}/ops`, state }}>
|
||||
<li className={pathname==="devops" ? "active" : ""}>
|
||||
<Link to={{ pathname: `/projects/${owner}/${projectsId}/devops${open_devops ? `/dispose`:""}`, state }}>
|
||||
<i className="iconfont icon-gongzuoliu font-13 mr8"></i>工作流
|
||||
{projectDetail && projectDetail.ops_count ? <span>{projectDetail.ops_count}</span> : ""}
|
||||
</Link>
|
||||
</li> */}
|
||||
</li>
|
||||
<li className={pathname==="milestones" ? "active" : ""}>
|
||||
<Link to={{ pathname: `/projects/${owner}/${projectsId}/milestones`, state }}>
|
||||
<img alt="" src={img_milepost} width="16" />里程碑
|
||||
|
@ -494,7 +523,7 @@ class Detail extends Component {
|
|||
<Spin spinning={secondSync} className="spinstyle" tip="正在同步镜像" size="large">
|
||||
<Switch {...this.props}>
|
||||
{/* 工作流 */}
|
||||
<Route path="/projects/:owner/:projectsId/ops"
|
||||
<Route path="/projects/:owner/:projectsId/devops"
|
||||
render={
|
||||
() => (<DevIndex {...this.props} {...this.state} {...common} />)
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue