Merge branch 'gitlink_ssr_head' of https://gitlink.org.cn/Gitlink/forgeplus-react into pre_gitlink_ssr

This commit is contained in:
谢思 2025-09-19 15:59:13 +08:00
commit fb40e14c5d
5 changed files with 136 additions and 123 deletions

View File

@ -1,65 +1,40 @@
import fetch from './fetch';
export function addPipelines(owner, repo, data) {
return fetch({
url:`/v1/${ owner }/${ repo }/pipelines`,
method: 'POST',
data
})
import axios from 'axios';
export async function addPipelines(owner, repo, data) {
const res = await axios.post(`/v1/${ owner }/${ repo }/pipelines`, data);
return res.data;
}
export function getCardList(owner, repo, params) {
return fetch({
url:`/v1/${ owner }/${ repo }/pipelines`,
method: 'get',
params
})
export async function getCardList(owner, repo, params) {
const res = await axios.get(`/v1/${owner}/${repo}/pipelines`, { params });
return res.data;
}
export function getTemplateList() {
return fetch({
url:`/action/templates.json`,
method: 'get',
})
export async function getTemplateList() {
const res = await axios.get(`/action/templates.json`);
return res.data;
}
export function getProjectBranch(owner, repo) {
return fetch({
url:`/${ owner }/${ repo }/branches.json`,
method: 'GET',
})
export async function getProjectBranch(owner, repo) {
const res = await axios.get(`/${ owner }/${ repo }/branches.json`);
return res.data;
}
export function runPipeline(owner, repo, params) {
return fetch({
url:`/v1/${ owner }/${ repo }/actions/runs.json`,
method: 'post',
data: params
})
export async function runPipeline(owner, repo, params) {
const res = await axios.get(`/v1/${ owner }/${ repo }/actions/runs.json`, { params });
return res.data;
}
export function delPipelines(owner, repo, id) {
return fetch({
url:`/v1/${ owner }/${ repo }/pipelines/${ id }.json`,
method: 'DELETE',
})
export async function delPipelines(owner, repo, id) {
const res = await axios.delete(`/v1/${ owner }/${ repo }/pipelines/${ id }.json`);
return res.data;
}
export function stopPipelines(owner, repo, params) {
return fetch({
url:`/v1/${ owner }/${ repo }/actions/disable.json`,
method: 'POST',
data: params
})
export async function stopPipelines(owner, repo, data) {
const res = await axios.post(`/v1/${ owner }/${ repo }/actions/disable.json`, data);
return res.data;
}
export function startPipelines(owner, repo, params) {
return fetch({
url:`/v1/${ owner }/${ repo }/actions/enable.json`,
method: 'POST',
data: params
})
}
export async function startPipelines(owner, repo, data) {
const res = await axios.post(`/v1/${ owner }/${ repo }/actions/enable.json`, data);
return res.data;
}

View File

@ -1,7 +0,0 @@
import javaFetch from '../../javaFetch';
// let settings = JSON.parse(localStorage.chromesetting);
const service = javaFetch('/api');
export default service;
export const TokenKey = 'autologin_trustie';

View File

@ -1,25 +1,28 @@
import { message, Popover, Button, Divider, Switch, Modal, Pagination } from "antd";
import React, { useEffect, useState } from "react";
import React, { useEffect, useState, useRef } from "react";
import './index.scss';
import { secondsToTimeFormat, timeAgo } from "../../../common/DateUtil";
import { runPipeline, delPipelines, stopPipelines, startPipelines, getCardList } from './api'
import Nodata from "../../Nodata";
import New from "./newModal";
import devops from '../../Images/devops.png';
const { confirm } = Modal;
function CardDevops(props) {
const { project, match } = props || {};
function CardDevops(props) {
const { project, match, isManager, isDeveloper, isReporter } = props || {};
const {owner, projectsId} = match.params;
const [list, setList] = useState([])
const [ visible , setVisible ] = useState(false);
const [ pageNum , setPageNum ] = useState(1);
const [ total , setTotal ] = useState(0);
const pageSize = 20;
const intervalRef = useRef(null);
let settings = localStorage.chromesetting && JSON.parse(localStorage.chromesetting);
let pipelineUrl = settings && settings.common.pipeline;
const isMember = isManager || isDeveloper || isReporter;
useEffect(() => {
document.title = `流水线-${owner}/${projectsId}`;
@ -27,21 +30,38 @@ function CardDevops(props) {
useEffect(()=>{
getList();
const intervalId = setInterval(() => {
getList();
}, 10000);
return () => clearInterval(intervalId);
}, [pageNum])
if (intervalRef.current) {
clearInterval(intervalRef.current);
}
if(isMember){
intervalRef.current = setInterval(() => {
getList();
}, 10000);
}
return () => {
if (intervalRef.current) {
clearInterval(intervalRef.current);
}
};
}, [isMember, pageNum])
function getList(){
getCardList(owner, projectsId, { limit: pageSize, page: pageNum }).then(res => {
isMember && getCardList(owner, projectsId, { limit: pageSize, page: pageNum }).then(res => {
if (res.status === 0) {
setList(res.pipelines.map(e => {
e.run_data = e.run_data || {}
return e
}))
setTotal(res.count)
}
}else{
if (intervalRef.current) {
clearInterval(intervalRef.current);
intervalRef.current = null;
}
}
})
}
@ -114,64 +134,72 @@ function CardDevops(props) {
onCancel={()=>setVisible(false)}
onOk={()=>{setVisible(false);getList()}}
/>
<Button onClick={()=>{setVisible(true)}} type='primary' className="mb20" >新建流水线</Button>
<div className="listData">
{list && list.map(e=>{
if (!e.run_data.status && e.run_data.status !== 0) {
e.run_data.status = (!e.json && !e.yaml) ? -1 : 0
}
return <div className={`card developStatus${e.run_data.status}`} >
<div className="statusBar"></div>
<div className="cardContent">
<div onClick={()=>{
// window.location.href = `${mygetHelmetapi && mygetHelmetapi.common.zone}/${owner}/pipeline/${e.id}`
window.open(`${ pipelineUrl }/devops/${owner}/${projectsId}/${e.id}`)
}}>
<div className="cartHead">
<div className={e.pipeline_type === 1 ? "f36" : ''}>{listType[e.pipeline_type]}</div>
<Popover content={e.pipeline_name} ><span className="task-hide weight">{e.pipeline_name}</span></Popover>
</div>
<div className="cardBody">
<p>
<div className={`statusIcon developStatus${e.run_data.status}`}></div>
{statusEnum[+e.run_data.status] || ((!e.json && !e.yaml) ? "待设计" : "待启动")}
{!!e.run_data.total && <span>#{e.run_data.total} &nbsp;&nbsp;&nbsp;{timeAgo(e.run_data.stopped)}&nbsp;执行时长{secondsToTimeFormat(e.run_data.length)}</span>}
</p>
<p className="mt5"><i className="iconfont icon-a-fenzhi1 font-12 mr4 mb3"></i> 分支{e.branch}</p>
<div className="mt5">{e.run_data.schedule && <span className="scheduleBox mr10">定时</span>}历史共执行{e.run_data.total || 0}成功{e.run_data.success || 0}失败{e.run_data.failure || 0}</div>
</div>
</div>
<Divider dashed/>
<div className="cartBottom" >
<div className="leftButton">
<img src={ require('../../../images/devOps/start.png') } alt="" onClick={ () => run(e) }/>
<img src={ require('../../../images/devOps/edit.png') } alt="" onClick={ () => window.open(`${ pipelineUrl }/devops/${owner}/${projectsId}/${e.id}/edit`) }/>
<img src={ require('../../../images/devOps/delete.png') } alt="" onClick={ () => delPipelineFunc(e.id) }/>
{isMember ? <React.Fragment>
<Button onClick={()=>{setVisible(true)}} type='primary' className="mb20" >新建流水线</Button>
<div className="listData">
{list && list.map(e=>{
if (!e.run_data.status && e.run_data.status !== 0) {
e.run_data.status = (!e.json && !e.yaml) ? -1 : 0
}
return <div className={`card developStatus${e.run_data.status}`} >
<div className="statusBar"></div>
<div className="cardContent">
<div onClick={()=>{
window.open(`${ pipelineUrl }/devops/${owner}/${projectsId}/${e.id}`)
}}>
<div className="cartHead">
<div className={e.pipeline_type === 1 ? "f36" : ''}>{listType[e.pipeline_type]}</div>
<Popover content={e.pipeline_name} ><span className="task-hide weight">{e.pipeline_name}</span></Popover>
</div>
<div className="rightButton">
<div className="status-switch">
<Switch size="small" className='mr10' checked={ !e.disable } onChange={()=>stopPipelineFunc(e.id, e.disable, e.file_name)} />
{ e.disable? '禁用' : '启用' }
<div className="cardBody">
<p>
<div className={`statusIcon developStatus${e.run_data.status}`}></div>
{statusEnum[+e.run_data.status] || ((!e.json && !e.yaml) ? "待设计" : "待启动")}
{!!e.run_data.total && <span>#{e.run_data.total} &nbsp;&nbsp;&nbsp;{timeAgo(e.run_data.stopped)}&nbsp;执行时长{secondsToTimeFormat(e.run_data.length)}</span>}
</p>
<p className="mt5"><i className="iconfont icon-a-fenzhi1 font-12 mr4 mb3"></i> 分支{e.branch}</p>
<div className="mt5">{e.run_data.schedule && <span className="scheduleBox mr10">定时</span>}历史共执行{e.run_data.total || 0}成功{e.run_data.success || 0}失败{e.run_data.failure || 0}</div>
</div>
</div>
<Divider dashed/>
<div className="cartBottom" >
<div className="leftButton">
<img src={ require('../../../images/devOps/start.png') } alt="" onClick={ () => run(e) }/>
<img src={ require('../../../images/devOps/edit.png') } alt="" onClick={ () => window.open(`${ pipelineUrl }/devops/${owner}/${projectsId}/${e.id}/edit`) }/>
<img src={ require('../../../images/devOps/delete.png') } alt="" onClick={ () => delPipelineFunc(e.id) }/>
</div>
<div className="rightButton">
<div className="status-switch">
<Switch size="small" className='mr10' checked={ !e.disable } onChange={()=>stopPipelineFunc(e.id, e.disable, e.file_name)} />
{ e.disable? '禁用' : '启用' }
</div>
</div>
</div>
</div>
</div>
</div>
</div>
})}
{list && !list.length && <div style={{margin: '100px auto'}}><Nodata _html="暂无数据"/></div>}
</div>
{
total > pageSize &&
<div style={{textAlign:'right',paddingTop:20}}>
<Pagination
simple
defaultCurrent={pageNum}
total={total}
pageSize={pageSize}
onChange={setPageNum}
></Pagination>
})}
{list && !list.length && <div style={{margin: '100px auto'}}><Nodata _html="暂无数据"/></div>}
</div>
}
{
total > pageSize &&
<div style={{textAlign:'right',paddingTop:20}}>
<Pagination
simple
defaultCurrent={pageNum}
total={total}
pageSize={pageSize}
onChange={setPageNum}
></Pagination>
</div>
}
</React.Fragment> : <React.Fragment>
<div className='unJurisdictionBox'>
<div className='jurCont mt25'>
<img src={devops} alt="" width={110}/>
<div className='font-18 mt30'>暂无权限仅仓库成员可访问</div>
</div>
</div>
</React.Fragment>}
</div>
}

View File

@ -243,3 +243,21 @@
}
}
}
.unJurisdictionBox{
color:#333333;
.jurTil{
width:1200px;
padding: 15px 16px;
background-color:#fafcff;
border:1px solid rgba(42, 97, 255, 0.23);
border-radius:3px 3px 0px 0px;
}
.jurCont{
width:1200px;
height:317px;
padding-top: 45px;
background-color:#fafcff;
border-radius:4px 4px 0px 0px;
text-align: center;
}
}

View File

@ -93,7 +93,6 @@ function DetailBanner({ history,list , owner , projectsId ,showNotification , ur
</Link>
</li>:""
}
{/* 引擎仅对当前仓库管理员可见 */}
{
item.menu_name === "devops" ?
<Dropdown overlay={