This commit is contained in:
caishi 2020-08-26 16:09:27 +08:00
parent 2f1bac24d5
commit a411d2c111
22 changed files with 862 additions and 411 deletions

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

View File

@ -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": "准备中",

View File

@ -20,6 +20,51 @@ Created by iconfont
/>
<missing-glyph />
<glyph glyph-name="mobanguanli2" unicode="&#59302;" 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="&#59301;" 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="&#59300;" 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="&#59299;" 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="&#59298;" 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="&#59297;" 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="&#59296;" 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="&#59295;" 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="&#59294;" 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="&#59293;" 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="&#59292;" 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="&#59291;" 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="&#59290;" 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="&#59289;" 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="&#59288;" 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="&#59287;" 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.

View File

@ -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} />)

View File

@ -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;

View File

@ -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>
)
})

View File

@ -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>
);
}
}

View File

@ -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);
// step1
const [visible, setVisible] = useState(false);
// step1true
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>tokentoken</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));

View File

@ -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;

View File

@ -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} />)
}

View File

@ -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>
)

View File

@ -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>
);

View File

@ -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>
);
};
});

View File

@ -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)=>{

View File

@ -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;
}
}

View File

@ -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>

View File

@ -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} />)
}