@daiyu-5577/quickbuild
Version:
front-end build service
275 lines (274 loc) • 18.2 kB
JavaScript
var _a;
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
import React, { useState, useRef, useEffect } from "react";
import { io } from "socket.io-client";
import dayjs from "dayjs";
let baseRoute = '/quick';
if (((_a = process === null || process === void 0 ? void 0 : process.env) === null || _a === void 0 ? void 0 : _a.NODE_ENV) == 'development') {
baseRoute = '';
}
const getFromatTime = (t = +dayjs(), format = 'YYYY-MM-DD HH:mm:ss') => {
return dayjs(t).format(format);
};
function replaceErrorMsg(msg) {
const txt = msg
.replace(/warn/ig, `<b style="color: yellow;">Warn</b>`)
.replace(/error/ig, `<b style="color: red;">Error</b>`);
return txt;
}
const useIsScrollBottom = (dom, onScrollEnd) => {
const isScroll = useRef(true);
const buildScrollToBottom = (isForce = false) => {
if (!isScroll.current && !isForce)
return;
setTimeout(() => {
var _a, _b;
(_a = dom === null || dom === void 0 ? void 0 : dom.current) === null || _a === void 0 ? void 0 : _a.scrollTo({
left: 0,
top: (_b = dom === null || dom === void 0 ? void 0 : dom.current) === null || _b === void 0 ? void 0 : _b.scrollHeight,
behavior: 'smooth'
});
}, 200);
};
useEffect(() => {
var _a;
if (!dom)
return;
const chatScrollFn = () => {
const { offsetHeight, scrollHeight, scrollTop } = dom.current;
isScroll.current = scrollHeight - offsetHeight - scrollTop < 100;
if (isScroll.current) {
onScrollEnd === null || onScrollEnd === void 0 ? void 0 : onScrollEnd();
}
};
(_a = dom === null || dom === void 0 ? void 0 : dom.current) === null || _a === void 0 ? void 0 : _a.addEventListener('scroll', chatScrollFn);
}, []);
return [isScroll, buildScrollToBottom];
};
export default function Home() {
var _a, _b, _c;
const userId = useRef('');
const chatScrollDOM = useRef(null);
const buildScrollDOM = useRef(null);
const socket = useRef(null);
const [unreaChatMsg, setUnreaChatMsg,] = useState(0);
const [unreaCBuildMsg, setUnreaBuilddMsg] = useState(0);
const [isChatScroll, chatScrollToBottom] = useIsScrollBottom(chatScrollDOM, () => setUnreaChatMsg(0));
const [isBuildScroll, buildScrollToBottom] = useIsScrollBottom(buildScrollDOM, () => setUnreaBuilddMsg(0));
const [ipt, setIpt] = useState('');
const [chatMsgList, setChatMsgList] = useState([]);
const [buildMsgList, setBuildMsgList] = useState([]);
const [commandList, setCommandList] = useState([]);
const [isShowImgUrl, setIsShowImgUrl] = useState('');
const [pkgList, setPkgList] = useState([]);
const [choosePkgs, setChoose] = useState(new Set());
const [chooseBranch, setChooseBranch] = useState(((_a = process === null || process === void 0 ? void 0 : process.env) === null || _a === void 0 ? void 0 : _a.NODE_ENV) == 'development' ? 'dev' : 'master');
const [isShowPkg, setIsShowPkg] = useState(false);
const [logList, setlogList] = useState([]);
const [curLogTab, setCurLogTab] = useState(0);
const [isShowLog, setisShowLog] = useState(false);
const handleCommand = (command) => {
var _a;
if (!((_a = socket.current) === null || _a === void 0 ? void 0 : _a.id) && !command)
return;
handleSend(command);
};
const handleSend = (val) => {
var _a;
const msg = val || ipt;
if (!((_a = socket.current) === null || _a === void 0 ? void 0 : _a.id) || !msg)
return;
socket.current.emit('on:msg-chat', {
ctxType: 'ctx:txt',
msg: msg || ipt
});
setIpt('');
};
const handleSendImg = (e) => {
var _a;
const files = e.target.files;
if (!((_a = socket.current) === null || _a === void 0 ? void 0 : _a.id) || !(files === null || files === void 0 ? void 0 : files.length))
return;
const list = Array.from(files).map(v => ({
file: v,
name: v.name,
size: v.size,
type: v.type,
}));
socket.current.emit('on:msg-chat', {
ctxType: 'ctx:imgs',
files: list,
});
e.target.value = '';
};
const handleShowPkg = (v) => {
setIsShowPkg(v);
};
const handleBuild = () => {
if (choosePkgs.size == 0) {
alert('请选择仓库');
return;
}
if (chooseBranch == '') {
alert('请选择分支');
return;
}
fetch(`${baseRoute}/api/addTask`, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
packagePaths: Array.from(choosePkgs),
branch: chooseBranch,
})
})
.then(res => res.json())
.then(res => {
if (!(res === null || res === void 0 ? void 0 : res.success)) {
alert(`${(res === null || res === void 0 ? void 0 : res.message) || '任务添加失败'}`);
return;
}
setIsShowPkg(false);
setChoose(new Set());
})
.catch(err => {
alert(`${(err === null || err === void 0 ? void 0 : err.message) || '任务添加失败'}`);
});
};
const httpGetAllPkg = () => {
fetch(`${baseRoute}/api/getAllPackage`)
.then(res => res.json())
.then(res => {
var _a;
setPkgList(((_a = res === null || res === void 0 ? void 0 : res.list) === null || _a === void 0 ? void 0 : _a.sort()) || []);
});
};
const httpGetAllLog = () => {
fetch(`${baseRoute}/api/getLogFiles`)
.then(res => res.json())
.then(res => {
setlogList((res === null || res === void 0 ? void 0 : res.tabs) || []);
});
};
const httpGetAllCommand = () => {
fetch(`${baseRoute}/api/getAllCommand`)
.then(res => res.json())
.then(res => {
setCommandList((res === null || res === void 0 ? void 0 : res.list) || []);
});
};
useEffect(() => {
console.log('useEffect - home');
const localToken = localStorage.getItem('token');
const localUserId = localStorage.getItem('userId');
userId.current = localUserId || '';
socket.current = io('/', {
path: `${baseRoute}/ws/`,
reconnectionDelayMax: 10000,
auth: {
lastChatId: 0,
lastMBuildId: 0,
token: localToken
}
});
socket.current.on('connect_error', (error) => {
console.log('connect_error', error);
if ((error === null || error === void 0 ? void 0 : error.message) == 'invalid token') {
localStorage.removeItem('token');
localStorage.removeItem('userId');
window.location.href = `${baseRoute}/page/login`;
}
});
socket.current.on('on:msg-getAllChat', (res) => {
setChatMsgList([...chatMsgList, ...res]);
chatScrollToBottom();
});
socket.current.on('on:msg-getAllBuild', (res) => {
setBuildMsgList([...buildMsgList, ...res]);
buildScrollToBottom();
});
socket.current.on('on:msg-chat', (res) => {
setChatMsgList((old => {
if (isChatScroll.current) {
chatScrollToBottom();
}
else {
setUnreaChatMsg(v => v + 1);
}
socket.current.auth.lastChatId = res.id;
return [...old, res];
}));
});
socket.current.on('on:msg-build', (res) => {
setBuildMsgList((old => {
const curMsg = old.find(v => v.taskId == res.taskId);
if (curMsg) {
curMsg.msg = curMsg.msg + res.msg;
curMsg.status = res.status;
return [...old];
}
if (isBuildScroll.current) {
buildScrollToBottom();
}
else {
setUnreaBuilddMsg(v => v + 1);
}
socket.current.auth.lastMBuildId = res.id;
return [...old, res];
}));
});
}, []);
useEffect(() => {
const enterFn = (e) => {
if (e.keyCode == 13 && e.ctrlKey) {
handleSend();
}
};
window.addEventListener('keydown', enterFn);
return () => {
window.removeEventListener('keydown', enterFn);
};
}, [ipt]);
useEffect(() => {
httpGetAllPkg();
httpGetAllCommand();
}, []);
return (_jsxs(React.Fragment, { children: [_jsxs("div", { className: "home", children: [_jsx("div", { className: "opts", children: _jsxs("div", { className: "opt-scroll", children: [_jsx("div", { onClick: () => { location.reload(); }, className: "opt-item cursor", children: "\u5237\u65B0" }), _jsx("div", { onClick: () => { handleShowPkg(true); }, className: "opt-item cursor", children: "\u6784\u5EFA" }), _jsx("div", { onClick: () => {
httpGetAllLog();
setisShowLog(true);
}, className: "opt-item cursor", children: "logs" })] }) }), _jsxs("div", { className: "buildBox", children: [_jsx("div", { className: "title", children: _jsx("span", { children: "build notice" }) }), _jsxs("div", { className: "buildNoticeBox", children: [!isBuildScroll.current && unreaCBuildMsg > 0 &&
_jsxs("div", { onClick: () => {
setUnreaBuilddMsg(0);
buildScrollToBottom(true);
}, className: "unreadChatMsg", children: ["\u672A\u8BFB\u6D88\u606F x", unreaCBuildMsg] }), _jsx("div", { ref: buildScrollDOM, className: "buildNoticeBoxScroll", children: buildMsgList.map((v, i) => (_jsxs("div", { className: "msg-item", children: [_jsxs("div", { className: "item-name", children: [_jsxs("div", { className: "item-name-txt", children: [_jsx("span", { children: v.name }), " - ", _jsxs("span", { className: "name-txt-branch", children: [v.branch, "\u5206\u652F"] })] }), _jsx("div", { className: "item-time-txt", children: getFromatTime(v.timestamp) })] }), _jsxs("div", { className: "item-ctx-wrap", children: [_jsxs("div", { className: "item-info", children: [_jsxs("div", { className: "info-txt", children: ["\u5206\u652F\uFF1A", v.branch] }), _jsxs("div", { className: "info-txt", children: ["\u6784\u5EFAtaskId\uFF1A", v.taskId] }), _jsxs("div", { className: "info-txt", children: ["\u6784\u5EFApackagePath\uFF1A", v.task.packagePath] }), _jsxs("div", { className: "info-txt", children: ["\u6784\u5EFAcommit\uFF1A", v.task.commit] }), _jsxs("div", { className: "info-txt", children: ["\u4EFB\u52A1\u521B\u5EFA\u65F6\u95F4\uFF1A", v.task.time] }), v.buildLogPath && _jsxs("div", { className: "info-txt", children: ["\u6784\u5EFAlog\uFF1A", _jsx("a", { target: "_blank", href: v.buildLogPath, children: "\u67E5\u770B\u65E5\u5FD7" })] })] }), _jsx("pre", { dangerouslySetInnerHTML: { __html: replaceErrorMsg(v.msg) }, className: "item-msg" }), _jsx("div", { className: `status status-${v.status}`, children: v.status == 1 ? '构建中...' : v.status == 2 ? '构建成功' : '构建失败' })] })] }, i))) })] })] }), _jsxs("div", { className: "chatBox", children: [_jsx("div", { className: "title", children: "chat room" }), _jsxs("div", { className: "msgBox", children: [!isChatScroll.current && unreaChatMsg > 0 &&
_jsxs("div", { onClick: () => {
setUnreaChatMsg(0);
chatScrollToBottom(true);
}, className: "unreadChatMsg", children: ["\u672A\u8BFB\u6D88\u606F x", unreaChatMsg] }), _jsx("div", { ref: chatScrollDOM, className: "msgBoxScroll", children: chatMsgList.map((v, i) => {
var _a, _b;
return (_jsxs("div", { className: `msg-item ${v.userId == userId.current ? 'msg-item-self' : ''}`, children: [_jsxs("div", { className: "item-name", children: [_jsx("div", { className: "item-name-txt", children: v.name || v.id }), _jsx("div", { className: "item-time-txt", children: getFromatTime(v.timestamp) })] }), (v === null || v === void 0 ? void 0 : v.msg) && _jsx("pre", { className: "item-msg", children: v.msg }), !!((_a = v === null || v === void 0 ? void 0 : v.files) === null || _a === void 0 ? void 0 : _a.length) &&
_jsx("div", { className: "item-imgs", children: v.ctxType == 'ctx:imgs' && ((_b = v.files) === null || _b === void 0 ? void 0 : _b.map((v, i) => {
return ['.mp4', '.avi', '.mov', '.mkv', '.flv', '.wmv'].some(suffix => v.endsWith(suffix)) ?
_jsx("video", { loop: true, muted: true, autoPlay: true, "webkit-playsinline": 'true', playsInline: true, onClick: () => setIsShowImgUrl(v), src: v }, i) :
_jsx("img", { onClick: () => setIsShowImgUrl(v), src: v }, i);
})) })] }, i));
}) })] }), _jsxs("div", { className: "command-list", children: [_jsxs("select", { onChange: (e) => handleCommand(e.target.value), value: 0, className: "commands", children: [_jsx("option", { value: "", children: "\u5FEB\u6377\u547D\u4EE4" }), commandList.map((v, i) => {
return _jsxs("option", { value: v.command, children: [v.command, "-", v.desc] }, i);
})] }), _jsx("div", { onClick: () => handleShowPkg(true), className: "aad-build aad-img cursor atouch", children: "\u9009\u62E9\u6784\u5EFA" }), _jsxs("div", { className: "aad-img cursor atouch", children: ["\u9009\u62E9\u56FE\u7247", _jsx("input", { onChange: (e) => handleSendImg(e), type: "file", accept: "image/*", multiple: true })] })] }), _jsxs("div", { className: "textareaBox", children: [_jsx("pre", { className: "textarea-auto-height", children: ipt }), _jsxs("div", { className: "textarea-ctx", children: [_jsx("textarea", { onChange: (e) => setIpt(e.currentTarget.value), value: ipt }), _jsxs("button", { onClick: () => handleSend(), className: `btn-send ${!!ipt.length ? '' : 'btn-disabled'}`, children: ["\u53D1\u9001", _jsx("br", {}), "ctr + enter"] })] })] })] }), !!isShowImgUrl &&
_jsxs("div", { className: "showImg", children: [_jsx("div", { className: "prewiew", children: ['.mp4', '.avi', '.mov', '.mkv', '.flv', '.wmv'].some(suffix => isShowImgUrl.endsWith(suffix)) ?
_jsx("video", { loop: true, autoPlay: true, "webkit-playsinline": 'true', playsInline: true, src: isShowImgUrl }) :
_jsx("img", { src: isShowImgUrl }) }), _jsx("div", { onClick: () => setIsShowImgUrl(''), className: "exit cursor", children: "X" })] }), !!isShowPkg &&
_jsx("div", { className: "pkgBox", children: _jsxs("div", { className: "pkgBox-cnt", children: [_jsx("div", { className: "pkgBox-title", children: "\u5206\u652F" }), _jsx("div", { className: "pkgBox-ipt", children: _jsx("input", { value: chooseBranch, onInput: e => setChooseBranch(e.currentTarget.value.trim()), type: "text" }) }), _jsx("div", { className: "pkgBox-title", children: "\u4ED3\u5E93" }), _jsx("div", { className: "pkgBox-list", children: pkgList.map((v, i) => {
return _jsx("div", { onClick: () => {
if (choosePkgs.has(v)) {
choosePkgs.delete(v);
}
else {
choosePkgs.add(v);
}
setChoose(new Set(choosePkgs));
}, className: `pkgBox-list-item cursor ${choosePkgs.has(v) ? 'active' : ''}`, children: v }, i);
}) }), _jsx("div", { onClick: handleBuild, className: "btn-build cursor", children: "\u6784\u5EFA" }), _jsx("div", { onClick: () => setIsShowPkg(false), className: "exit cursor", children: "X" })] }) }), !!isShowLog &&
_jsx("div", { className: "logBox", children: _jsxs("div", { className: "pkgBox-cnt", children: [_jsx("div", { className: "pkgBox-title", children: "logs" }), _jsx("div", { className: "tabs", children: logList.map((v, i) => (_jsx("div", { onClick: () => setCurLogTab(i), className: `tab-item cursor ${curLogTab == i ? 'active' : ''}`, children: v.title }, i))) }), _jsx("div", { className: "pkgBox-list", children: (_c = (_b = logList[curLogTab]) === null || _b === void 0 ? void 0 : _b.list) === null || _c === void 0 ? void 0 : _c.map((cv, ci) => (_jsx("div", { className: `pkgBox-list-item`, children: _jsx("a", { target: "_blank", href: cv.path, children: cv === null || cv === void 0 ? void 0 : cv.name }) }, ci))) }), _jsx("div", { onClick: () => setisShowLog(false), className: "exit cursor", children: "X" })] }) })] }), _jsx("link", { rel: "stylesheet/less", type: "text/css", href: `${baseRoute}/static/pages/home.less` })] }));
}