里程碑

This commit is contained in:
caishi 2020-07-27 18:45:18 +08:00
parent 904da46b8c
commit d4e9d0128b
10 changed files with 287 additions and 240 deletions

View File

@ -1,6 +1,6 @@
import React from 'react';
import React , { useState , useEffect } from 'react';
import { Select } from 'antd';
import axios from 'axios';
const Option = Select.Option;
const LANGUAGE = [
"apex",
@ -54,12 +54,31 @@ const LANGUAGE = [
"xml",
"yaml",
];
export default (({ language , select_language })=>{
const [ languages , setLanguage ] = useState(undefined);
useEffect(()=>{
const url = '/dev_ops/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]);
}
return(
<Select showSearch={true} placeholder={"请选择文本语言"} style={{ width: 200 }} value={language} onChange={select_language}>
<Select showSearch={true} placeholder={"请选择文本语言"} style={{ width: 200 }} value={language} onChange={changelanguage}>
<Option value={undefined}>请选择文本语言</Option>
{LANGUAGE.map((item, key) => {
return <Option value={item}>{item}</Option>;
{languages && languages.map((item, key) => {
return <Option value={item.name}>{item.name}</Option>;
})}
</Select>
)

View File

@ -17,6 +17,7 @@ const P = styled.p`{
}`;
function About( props , ref){
const { form: { getFieldDecorator , validateFields } } = props;
const helper = useCallback(
(label, name, rules, widget, isRequired) => (
<React.Fragment>
@ -30,15 +31,16 @@ function About( props , ref){
);
function startActive(){
console.log(props);
let projectsId = props.match.params.projectsId;
validateFields((error,values)=>{
if(!error){
const url = `/dev_ops/cloud_accounts.json`;
axios.post(url,{
...values,
project_id:projectsId
}).then(result=>{
if(result){
if(result && result.data.redirect_url){
window.location.href = result.data.redirect_url;
}
}).catch(error=>{
console.log(error);

View File

@ -1,91 +1,139 @@
import React , { forwardRef , useCallback , useState } from 'react';
import { Form , AutoComplete } from 'antd';
import React , { useState , useEffect } from 'react';
import { Blueback } from '../Component/layout';
import Editor from "react-monaco-editor";
import Modals from './DisposeModal';
import FileLanguage from '../Component/FileLanguage';
import docker from '../Images/docker.png';
import gradle from '../Images/gradle.png';
import java from '../Images/java.png';
import js from '../Images/js.png';
import php from '../Images/php.png';
import python from '../Images/python.png';
import axios from 'axios';
const Option = AutoComplete.Option;
export default Form.create()(
forwardRef(({ form })=>{
const [ visible , setVisible ] = useState(false);
const [ ymlValue , setYmlValue ] = useState("class Main 1111");
const [ fileLanguage , setFileLanguage ] = useState(undefined);
function Dispose(props){
const [ info , setInfo ] = useState(undefined);
const [ visible , setVisible ] = useState(false);
const [ ymlValue , setYmlValue ] = useState("");
const [ six , setSix ] = useState(undefined);
const [ fileLanguage , setFileLanguage ] = useState(undefined);
const [ first , setFirst ] = useState(false);
const { getFieldDecorator , validateFields } = form;
let projectsId = props.match.params.projectsId;
const helper = useCallback(
(label, name, rules, widget, isRequired = false) => (
<React.Fragment>
<span required={isRequired}>{label}</span>
<Form.Item>
{getFieldDecorator(name, { rules, validateFirst: true })(widget)}
</Form.Item>
</React.Fragment>
),
[]
)
//
function changeEditor(value){
setYmlValue(value);
}
//
function select_language(value){
setFileLanguage(value);
}
//
function submit(){
validateFields((error,value)=>{
if(!error){
console.log(value);
useEffect(()=>{
if(projectsId){
const url = '/dev_ops/builds/get_trustie_pipeline.json';
axios.get(url,{
params:{
project_id:projectsId
}
}).then(result=>{
if(result && result.data.content){
setInfo(result.data);
setYmlValue(result.data.content);
setFirst(true);
}else{
setFirst(false);
}
}).catch(error=>{
console.log(error);
})
}
return(
<React.Fragment>
<Modals visible={visible} closeFunc={(flag)=>setVisible(flag)}></Modals>
<Form>
<p>编程语言</p>
<ul className="language">
<li><img alt="" src={docker} /></li>
<li><img alt="" src={gradle} /></li>
<li><img alt="" src={java} /></li>
<li><img alt="" src={js} /></li>
<li><img alt="" src={php} /></li>
<li><img alt="" src={python} /></li>
</ul>
<div className="mt20 mb20">
<FileLanguage language={fileLanguage} select_language={select_language}/>
</div>
<p>配置脚本</p>
<div className="editorBody">
<p className="editorHead">
<span>.trustie-pipeline.yml</span>
<a><i className="iconfont icon-bianji6 font-14"></i></a>
</p>
<Editor
height="300px"
language={"java"}
theme={"vs-grey"}
defaultValue="请输入内容"
value={ymlValue}
options={"editor_options"}
onChange={changeEditor}
></Editor>
</div>
<Blueback onClick={submit}>确定提交</Blueback>
</Form>
</React.Fragment>
)
})
)
},[])
useEffect(()=>{
const url = '/dev_ops/languages/common.json';
axios.get(url).then(result=>{
if(result){
setSix(result.data);
}
}).catch(error=>{
console.log(error);
})
},[])
//
function changeEditor(value){
setYmlValue(value);
}
//
function select_language(value,array){
setFileLanguage(value);
// console.log(array);
setYmlValue( array && array.content);
}
//
function submit(){
let url = '';
let params = {
branch: "master",
content:ymlValue,
filepath:info && info.name,
message:''
}
if(first){
// true
url = `/repositories/${projectsId}/update_file.json`;
axios.put(url,{
...params,
sha:info && info.sha
}).then(result=>{
if(result){
setVisible(true);
}
}).catch(error=>{
console.log(error);
})
}else{
url = `/repositories/${projectsId}/create_file.json`;
axios.post(url,params).then(result=>{
if(result){
setVisible(true);
}
}).catch(error=>{
console.log(error);
})
}
}
function suresubmit(){
props.history.push(`/projects/${projectsId}/ops/list`);
}
return(
<React.Fragment>
<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>
<a><i className="iconfont icon-bianji6 font-14"></i></a>
</p>
<Editor
height="300px"
language={"java"}
theme={"vs-grey"}
defaultValue="请输入内容"
value={ymlValue}
options={"editor_options"}
onChange={changeEditor}
></Editor>
</div>
<Blueback onClick={submit}>确定提交</Blueback>
</React.Fragment>
)
}
export default Dispose;

View File

@ -8,7 +8,7 @@ const Div = styled.div`{
text-align:center;
color:#333;
}`
export default (({visible , closeFunc})=>{
export default (({visible , closeFunc , suresubmit})=>{
return(
<Modal
title="提示"
@ -17,7 +17,7 @@ export default (({visible , closeFunc})=>{
footer={
<div>
<Button onClick={()=>closeFunc(false)}>取消</Button>
<Button type={"primary"} onClick={()=>closeFunc(false)} style={{marginLeft:"20px"}}>确定</Button>
<Button type={"primary"} onClick={suresubmit} style={{marginLeft:"20px"}}>确定</Button>
</div>
}
onCancel={()=>closeFunc(false)}

View File

@ -11,11 +11,11 @@ const Div = styled.div`{
padding:24px 30px;
}`;
export default ((props)=>{
const [ menu , setMenu ] = useState(false);
const [ menu , setMenu ] = useState(undefined);
const path = props.location.pathname;
useEffect(()=>{
console.log(props.match.params.projectsId)
// console.log(props.match.params.projectsId)
if(path === `/projects/${props.match.params.projectsId}/ops/list`){
setMenu(true);
}else{
@ -30,12 +30,8 @@ export default ((props)=>{
{ menu ? <Link to={`/projects/${props.match.params.projectsId}/ops/list`} style={{ marginLeft:"66px",color:"#5091FF" }}>构建列表</Link>:""}
</Banner>
<Div>
{
menu ?
<Structure {...props}/>
:
<Dispost {...props}/>
}
{ menu && menu === true && <Structure {...props}/> }
{ menu && menu === false && <Dispost {...props}/> }
</Div>
</div>
)

View File

@ -1,7 +1,10 @@
import React , { useState } from 'react';
import { FlexAJ , Blueback } from '../Component/layout';
import React , { useState , useEffect } from 'react';
import { FlexAJ , AlignCenter , Blueback } from '../Component/layout';
import { Table , Pagination } from 'antd';
import { truncateCommitId } from '../common/util';
import styled from 'styled-components';
import axios from 'axios';
const STATUS = [
{name:"所有",value:"1"},
{name:"准备中",value:"2"},
@ -42,11 +45,44 @@ const Img = styled.img`{
width:25px;
height:25px;
}`
export default (()=>{
export default ((props)=>{
const [ status ,setStatus ] = useState("1");
const [ page ,setPage ] = useState(1);
const [ total ,setTotal ] = useState(10);
const [ data , setData ] = useState(undefined);
let projectsId = props.match.params.projectsId;
useEffect(()=>{
if(projectsId){
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,
timestamp:item.timestamp
}
})
setData(list);
}
}).catch(error=>{
console.log(error);
})
}
},[])
function ChangeStatus(value){
setStatus(value)
@ -67,7 +103,7 @@ export default (()=>{
)
}
function renderStatusBtn(status){
if(status >1 && status <=3){
if(status === "failure" || status ==="success"){
return(
<a className="color-blue">重新构建</a>
)
@ -79,15 +115,15 @@ export default (()=>{
}
function renderTableStatus (status){
switch (status){
case 1:
case "running":
return(
<span className="statusTag running"><i className="iconfont icon-yunhangzhong"></i>运行中</span>
);
case 2:
case "failure":
return (
<span className="statusTag failed"><i className="iconfont icon-weitongguo"></i>未通过</span>
);
case 3:
case "success":
return (
<span className="statusTag pass"><i className="iconfont icon-yitongguo"></i>已通过</span>
);
@ -138,18 +174,18 @@ export default (()=>{
{ meg.branch && <span className="mr10 color-grey-8"><i className="iconfont icon-fenzhi1 font-16 mr5"></i>分支{meg.branch}</span>}
{ meg.sha && <span className="color-orange">{meg.sha}</span>}
</div>
<FlexAJ>
<AlignCenter>
<Img src={meg.image} />
<div className="task-hide" style={{maxWidth:"300px"}}>{meg.message}</div>
</FlexAJ>
<div className="task-hide ml5" style={{maxWidth:"300px"}}>{meg.message}</div>
</AlignCenter>
</React.Fragment>
)
}
},
{
title:'开始时间',
dataIndex:"begin",
key:"begin",
dataIndex:"started",
key:"started",
width:"15%",
render:(value,item,key)=>{
return (
@ -159,12 +195,12 @@ export default (()=>{
},
{
title:'运行时间',
dataIndex:"run",
key:"run",
dataIndex:"timestamp",
key:"timestamp",
width:"15%",
render:(value,item,key)=>{
return (
<span>{value || "--"}</span>
<span>{value || value === 0 ? `${value}s` : "--"}</span>
)
}
},
@ -190,7 +226,7 @@ export default (()=>{
<Table
columns={column}
className="normalTable"
dataSource={datasource}
dataSource={data}
pagination={false}
></Table>
{

View File

@ -39,32 +39,31 @@ class UserSubmitComponent extends Component {
this.props.form.validateFieldsAndScroll((err, values) => {
if (!err) {
const url = `/repositories/${projectsId}/create_file.json`;
axios
.post(url, {
filepath: filename ? filename : path,
branch: branch,
new_branch: submitType === "1" ? values.branchname : undefined,
content,
message: values.desc,
})
.then((result) => {
this.setState({ isSpin: false });
if (result.data && result.data.name) {
this.props.showNotification("文件新建成功!");
if(submitType === "1"){
const { getTopCount } = this.props;
getTopCount && getTopCount(values.branchname);
}
let url = values.branchname
? `/projects/${projectsId}/coders?branch=${values.branchname}`
: `/projects/${projectsId}/coders`;
this.props.history.push(url);
axios.post(url, {
filepath: filename ? filename : path,
branch: branch,
new_branch: submitType === "1" ? values.branchname : undefined,
content,
message: values.desc,
})
.then((result) => {
this.setState({ isSpin: false });
if (result.data && result.data.name) {
this.props.showNotification("文件新建成功!");
if(submitType === "1"){
const { getTopCount } = this.props;
getTopCount && getTopCount(values.branchname);
}
})
.catch((error) => {
this.setState({ isSpin: false });
console.log(error);
});
let url = values.branchname
? `/projects/${projectsId}/coders?branch=${values.branchname}`
: `/projects/${projectsId}/coders`;
this.props.history.push(url);
}
})
.catch((error) => {
this.setState({ isSpin: false });
console.log(error);
});
} else {
this.setState({ isSpin: false });
}

View File

@ -13,7 +13,6 @@ import axios from 'axios';
* data:列表接口返回的所有数据,
* issues:列表数组,
* isSpin:加载中,
* search:搜索关键字,
* author_id:发布者id,
* assigned_to_id:指派给的id
* limit:每页条数,
@ -30,8 +29,8 @@ class MilepostDetail extends Component {
data: undefined,
issues: undefined,
isSpin: true,
search: undefined,
author_id: undefined,
status_id: undefined,
assigned_to_id: undefined,
limit: 15,
page: 1,
@ -42,10 +41,10 @@ class MilepostDetail extends Component {
openselect: 1,
closeselect: undefined,
issue_tag_ids: '标签',
tracker_ids: '所有分类',
tracker_ids: '',
author_ids: '发布人',
assigned_to_ids: '指派人',
priority_ids: '优先度',
assigned_to_ids: '负责人',
status_ids: "状态",
done_ratios: '完成度',
paix: '排序'
}
@ -53,7 +52,8 @@ class MilepostDetail extends Component {
componentDidMount = () => {
this.getSelectList();
this.getIssueList();
const { page } = this.state;
this.getIssueList(page);
}
getSelectList = () => {
@ -71,14 +71,20 @@ class MilepostDetail extends Component {
}
// 获取列表数据
getIssueList = (page, limit, search, author_id, assigned_to_id, status_type, id, value, order_name, order_type) => {
getIssueList = ( page , item , value , update , updateValue ) => {
const { projectsId, meilid } = this.props.match.params;
const { limit , order_name , order_type , issue_tag_id , author_id , assigned_to_id , tracker_id , status_id , done_ratio} = this.state;
const url = `/projects/${projectsId}/versions/${meilid}.json`;
let params = update ? {
page, limit , order_name:value , order_type:updateValue , issue_tag_id ,
author_id , assigned_to_id , tracker_id , status_id , done_ratio,
}:{
page, limit , order_name , order_type , issue_tag_id ,
author_id , assigned_to_id , tracker_id , status_id , done_ratio,
[item]:value
}
axios.get(url, {
params: {
page, limit, search, author_id, assigned_to_id, status_type, order_name, order_type,
[id]: value
}
params: params
}).then((result) => {
if (result) {
this.setState({
@ -94,85 +100,41 @@ class MilepostDetail extends Component {
}
getOption = (e, id, name) => {
if (id + 's' === "issue_tag_ids") {
this.setState({
[id]: e.key,
issue_tag_ids: name
})
}
if (id + 's' === "tracker_ids") {
this.setState({
[id]: e.key,
tracker_ids: name
})
}
if (id + 's' === "author_ids") {
this.setState({
[id]: e.key,
author_ids: name
})
}
if (id + 's' === "assigned_to_ids") {
this.setState({
[id]: e.key,
assigned_to_ids: name
})
}
if (id + 's' === "priority_ids") {
this.setState({
[id]: e.key,
priority_ids: name
})
}
if (id + 's' === "done_ratios") {
this.setState({
[id]: e.key,
done_ratios: name
})
}
console.log(e.key);
if (e.key === "created_on") {
if (e.item.props.value === "desc") {
this.setState({
[id]: e.key,
paix: '最新创建'
})
} else {
this.setState({
[id]: e.key,
paix: '最早创建'
})
}
} else if (e.key === "updated_on") {
if (e.item.props.value === "desc") {
this.setState({
[id]: e.key,
paix: '最新更新'
})
} else {
this.setState({
[id]: e.key,
paix: '最早更新'
})
}
}
this.setState({
[id]: e.key
[id]: e.key,
[id+"s"]:name,
page:1
})
const { page, limit, search, author_id, assigned_to_id, status_type } = this.state;
if (e.key === "all") {
this.getIssueList(page, limit, search, author_id, assigned_to_id, status_type, id);
} else if (e.key === "created_on" || e.key === "updated_on") {
if (e.key === "created_on" || e.key === "updated_on") {
this.setState({
order_name: e.key,
order_type: e.item.props.value
})
this.getIssueList(page, limit, search, author_id, assigned_to_id, status_type, id, undefined, undefined, e.key, e.item.props.value);
}
else {
this.getIssueList(page, limit, search, author_id, assigned_to_id, status_type, id, e.key);
this.getIssueList(1,id,e.key,true,e.item.props.value);
}else{
this.getIssueList(1,id,e.key);
}
}
@ -197,23 +159,12 @@ class MilepostDetail extends Component {
page,
isSpin: true
})
const { limit, search, status_type, author_id, assigned_to_id } = this.state;
this.getIssueList(page, limit, search, author_id, assigned_to_id, status_type);
}
// 搜索
searchFunc = (value) => {
this.setState({
search: value,
isSpin: true
})
const { page, limit, status_type, author_id, assigned_to_id } = this.state;
this.getIssueList(page, limit, value, author_id, assigned_to_id, status_type);
const { limit, status_type, author_id, assigned_to_id } = this.state;
this.getIssueList(page);
}
openorder = (type) => {
if (type) {
const { current_user } = this.props;
if (type === 1) {
this.setState({
@ -221,14 +172,14 @@ class MilepostDetail extends Component {
openselect: current_user.user_id,
closeselect: undefined,
issue_tag_ids: '标签',
tracker_ids: '所有分类',
tracker_ids: '',
author_ids: '发布人',
assigned_to_ids: '指派人',
priority_ids: '优先度',
assigned_to_ids: '负责人',
status_ids: "状态",
done_ratios: '完成度',
paix: '排序'
})
this.getIssueList("", "", "", "", "", 1, "");
this.getIssueList(1);
} else {
this.setState({
@ -236,27 +187,18 @@ class MilepostDetail extends Component {
openselect: undefined,
closeselect: current_user.user_id,
issue_tag_ids: '标签',
tracker_ids: '所有分类',
tracker_ids: '',
author_ids: '发布人',
assigned_to_ids: '指派人',
priority_ids: '优先度',
assigned_to_ids: '负责人',
status_ids: "状态",
done_ratios: '完成度',
paix: '排序'
})
this.getIssueList("", "", "", "", "", 2, "");
this.getIssueList(1);
}
}
}
Paginations = (search_count) => {
const { limit, page } = this.state;
if(search_count > limit)
return <div className="mt30 mb50 edu-txt-center">
<Pagination simple defaultCurrent={page} total={search_count} pageSize={limit} onChange={this.ChangePage}></Pagination>
</div>;
};
render() {
const { issue_chosen, issues, limit, page, search_count, data, isSpin, openselect, closeselect } = this.state;
@ -320,13 +262,13 @@ class MilepostDetail extends Component {
</Dropdown>
</li>
<li>
<Dropdown className="topWrapperSelect" overlay={this.renderMenu(issue_chosen && issue_chosen.tracker, '所有分类', 'tracker_id')} trigger={['click']} placement="bottomCenter">
<Dropdown className="topWrapperSelect" overlay={this.renderMenu(issue_chosen && issue_chosen.tracker, '', 'tracker_id')} trigger={['click']} placement="bottomCenter">
<span>{this.state.tracker_ids}<Icon type="caret-down" className="ml5" /></span>
</Dropdown>
</li>
<li>
<Dropdown className="topWrapperSelect" overlay={this.renderMenu(issue_chosen && issue_chosen.priority, '优先度', 'priority_id')} trigger={['click']} placement="bottomCenter">
<span>{this.state.priority_ids}<Icon type="caret-down" className="ml5" /></span>
<Dropdown className="topWrapperSelect" overlay={this.renderMenu(issue_chosen && issue_chosen.issue_status, '状态', 'status_id')} trigger={['click']} placement="bottomCenter">
<span>{this.state.status_ids}<Icon type="caret-down" className="ml5" /></span>
</Dropdown>
</li>
<li>
@ -347,13 +289,17 @@ class MilepostDetail extends Component {
:
issues && issues.length>0 && issues.map((item,key)=>{
return(
<OrderItem key={key} item={item} mile search_count={search_count} page={page} limit={limit} {...this.props} {...this.state}></OrderItem>
<OrderItem key={key} mile item={item} search_count={search_count} page={page} limit={limit} {...this.props} {...this.state}></OrderItem>
)
})
}
{this.Paginations(search_count)}
{
search_count > limit?
<div className="mt30 mb50 edu-txt-center">
<Pagination simple current={page} total={search_count} pageSize={limit} onChange={this.ChangePage}></Pagination>
</div>:""
}
</Spin>
</div>
)
}

View File

@ -181,10 +181,9 @@
height: 30px;
}
.title_overflow {
max-width: 220px;
max-width: 160px;
white-space: nowrap;
overflow: hidden;
display: inline-flex;
white-space: nowrap;
-o-text-overflow: ellipsis;
text-overflow: ellipsis;

View File

@ -2,5 +2,7 @@
export function truncateCommitId(str) {
if (str && str.length > 11) {
return str.substring(0, 10)
}else{
return undefined
}
}