mirror of
https://gitee.com/arthas/arthas.git
synced 2024-12-01 19:58:30 +08:00
copy webui build result to core module. #2145
This commit is contained in:
parent
bd9e85e55a
commit
ab3337f8af
@ -99,6 +99,10 @@
|
||||
<copy overwrite="true" todir="${project.build.directory}/tmp_out/com/taobao/arthas/core/command/logger">
|
||||
<fileset dir="${project.build.directory}/classes/com/taobao/arthas/core/command/logger" />
|
||||
</copy>
|
||||
<!-- 从web-ui复制打包好的js/html -->
|
||||
<copy overwrite="true" todir="${project.build.directory}/tmp_out/com/taobao/arthas/core/http/">
|
||||
<fileset dir="${project.build.directory}/../../Web-UI/arthasWebConsole/dist/" />
|
||||
</copy>
|
||||
<zip basedir="${project.build.directory}/tmp_out" destfile="${project.build.directory}/${project.build.finalName}-shade.${project.packaging}" />
|
||||
</tasks>
|
||||
</configuration>
|
||||
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
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
Binary file not shown.
Before Width: | Height: | Size: 542 B |
@ -1,103 +0,0 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<!-- Required meta tags -->
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
|
||||
<!-- Bootstrap CSS -->
|
||||
<link rel="stylesheet" href="bootstrap-4.2.1.min.css">
|
||||
|
||||
<!-- Optional JavaScript -->
|
||||
<!-- jQuery first, then Popper.js, then Bootstrap JS -->
|
||||
<script src="jquery-3.3.1.slim.min.js"></script>
|
||||
<script src="popper-1.14.6.min.js"></script>
|
||||
<script src="bootstrap-4.2.1.min.js"></script>
|
||||
|
||||
|
||||
<script type="text/javascript">
|
||||
window.addEventListener('resize', function () {
|
||||
if(ws !== undefined && ws !== null){
|
||||
let terminalSize = getTerminalSize();
|
||||
ws.send(JSON.stringify({ action: 'resize', cols: terminalSize.cols, rows: terminalSize.rows }));
|
||||
xterm.resize(terminalSize.cols, terminalSize.rows);
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<link href="xterm.css" rel="stylesheet" />
|
||||
<link href="main.css" rel="stylesheet" />
|
||||
<script src="xterm.js" type="text/javascript"></script>
|
||||
<script src="web-console.js"></script>
|
||||
<title>Arthas Console</title>
|
||||
</head>
|
||||
|
||||
<body style="background: black;">
|
||||
<nav class="navbar navbar-expand navbar-light bg-light flex-column flex-md-row bd-navbar">
|
||||
<a href="https://github.com/alibaba/arthas" target="_blank" title="" class="navbar-brand"><img src="logo.png"
|
||||
alt="Arthas" title="Welcome to Arthas web console" style="height: 25px;" class="img-responsive"></a>
|
||||
|
||||
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarSupportedContent"
|
||||
aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
|
||||
<div class="collapse navbar-collapse" id="navbarSupportedContent">
|
||||
<ul class="navbar-nav mr-auto">
|
||||
<li class="nav-item active">
|
||||
<a class="nav-link" href="https://arthas.aliyun.com/doc" target="_blank">Documentation
|
||||
<span class="sr-only">(current)</span></a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="https://arthas.aliyun.com/doc/arthas-tutorials.html" target="_blank">Online Tutorials</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="https://github.com/alibaba/arthas" target="_blank">Github</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<form class="form-inline my-2 my-lg-0">
|
||||
<div class="col">
|
||||
<div class="input-group ">
|
||||
<div class="input-group-prepend">
|
||||
<span class="input-group-text" id="ip-addon">IP</span>
|
||||
</div>
|
||||
<input value="127.0.0.1" v-model="ip" type="text" class="form-control" name="ip" id="ip"
|
||||
placeholder="please enter ip address" aria-label="ip" aria-describedby="ip-addon">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col">
|
||||
<div class="input-group ">
|
||||
<div class="input-group-prepend">
|
||||
<span class="input-group-text" id="port-addon">Port</span>
|
||||
</div>
|
||||
<input value="3658" v-model="port" type="text" class="form-control" name="port" id="port"
|
||||
placeholder="please enter port" aria-label="port" aria-describedby="port-addon">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-inline">
|
||||
<button title="connect" type="button" class="btn btn-info form-control" onclick="startConnect()">Connect</button>
|
||||
<button title="disconnect" type="button" class="btn btn-info form-control" onclick="disconnect()">Disconnect</button>
|
||||
<a target="_blank" href="arthas-output/" class="btn btn-info" role="button">Arthas Output</a>
|
||||
</div>
|
||||
|
||||
</form>
|
||||
|
||||
</nav>
|
||||
|
||||
<div class="container-fluid px-0">
|
||||
<div class="col px-0" id="terminal-card">
|
||||
<div id="terminal"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div title="fullscreen" id="fullSc" class="fullSc">
|
||||
<button id="fullScBtn" onclick="xtermFullScreen()"><img src="fullsc.png"></button>
|
||||
</div>
|
||||
</body>
|
||||
|
||||
</html>
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Binary file not shown.
Before Width: | Height: | Size: 6.2 KiB |
@ -1,20 +0,0 @@
|
||||
#terminal:-webkit-full-screen{
|
||||
background-color: rgb(255, 255, 12);
|
||||
}
|
||||
.container {
|
||||
width: 100%;
|
||||
min-height: 600px;
|
||||
}
|
||||
.fullSc {
|
||||
z-index: 10000;
|
||||
position: fixed;
|
||||
top: 25%;
|
||||
left: 90%;
|
||||
display: none;
|
||||
}
|
||||
#fullScBtn {
|
||||
border-radius:17px;
|
||||
border: 0;
|
||||
cursor: pointer;
|
||||
background-color: black;
|
||||
}
|
File diff suppressed because one or more lines are too long
@ -1,121 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Arthas WebUI</title>
|
||||
</head>
|
||||
<body>
|
||||
<script src="../lib/vue/vue-2.6.11.js"></script>
|
||||
<script src="../lib/vue/vue-router-3.1.6.js"></script>
|
||||
<script src="../lib/axios-0.19.2.min.js"></script>
|
||||
<script src="../element-ui@2.13.0/lib/index.js"></script>
|
||||
<link rel="stylesheet" href="../element-ui@2.13.0/lib/theme-chalk/index.css">
|
||||
<link rel="stylesheet" href="ui.css">
|
||||
|
||||
<div id="app">
|
||||
<router-view/>
|
||||
</div>
|
||||
|
||||
<template id="session-view">
|
||||
<div>
|
||||
<el-container class="container">
|
||||
<el-header class="header">
|
||||
<el-row >
|
||||
<el-col :span="12">
|
||||
<div class="logo">
|
||||
<a href="https://github.com/alibaba/arthas" target="_blank">
|
||||
<img src="../logo.png" height="25px">
|
||||
</a>
|
||||
</div>
|
||||
<div class="logo">
|
||||
<a class="nav-link" href="https://arthas.aliyun.com/doc" target="_blank">Documentation</a>
|
||||
<a class="nav-link" href="https://arthas.aliyun.com/doc-tutorials" target="_blank">Online Tutorials</a>
|
||||
<a class="nav-link" href="https://arthas.aliyun.com/doc" target="_blank">Github</a>
|
||||
</div>
|
||||
</el-col>
|
||||
<el-col :span="12" class="header-right">
|
||||
<el-button type="primary" size="mini" @click="openNewSession">New</el-button>
|
||||
<el-button type="primary" size="mini">Share</el-button>
|
||||
<el-button type="primary" size="mini">Close</el-button>
|
||||
<el-button type="primary" size="mini">Shutdown</el-button>
|
||||
<div class="user-info">
|
||||
<i class="el-icon-s-custom user-icon"></i>
|
||||
<span>Tom</span>
|
||||
</div>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-header>
|
||||
<el-main id="main-body" class="main-body">
|
||||
<div v-for="result in commandResults" >
|
||||
<el-card class="resultMsg" v-bind:class="messageClass(result)">
|
||||
{{JSON.stringify(result)}}
|
||||
</el-card>
|
||||
<div class="min-gap"></div>
|
||||
</div>
|
||||
</el-main>
|
||||
|
||||
<!-- 底部 -->
|
||||
<el-footer class="footer-row">
|
||||
<div class="footer-left">
|
||||
<div>Command:</div>
|
||||
</div>
|
||||
<div class="footer-input">
|
||||
<el-input ref="commandInput"
|
||||
placeholder="Enter command"
|
||||
autosize
|
||||
clearable
|
||||
@keyup.enter.native="executeCommand"
|
||||
:disabled="inputStatus!='ALLOW_INPUT'"
|
||||
v-model="commandLine">
|
||||
</el-input>
|
||||
</div>
|
||||
<div class="footer-button">
|
||||
<el-button v-if="inputStatus=='ALLOW_INPUT'" type="primary" size="mini" @click="executeCommand">Execute</el-button>
|
||||
<el-button v-if="inputStatus=='ALLOW_INTERRUPT'" type="danger" size="mini" @click="interruptJob">Interrupt</el-button>
|
||||
</div>
|
||||
</el-footer>
|
||||
</el-container>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template id="history-view">
|
||||
<div>
|
||||
<el-container class="container">
|
||||
<el-header class="header">
|
||||
<el-row >
|
||||
<el-col :span="12">
|
||||
<div class="logo">
|
||||
<a href="https://github.com/alibaba/arthas" target="_blank">
|
||||
<img src="../logo.png" height="25px">
|
||||
</a>
|
||||
</div>
|
||||
<div class="logo">
|
||||
<a class="nav-link" href="https://arthas.aliyun.com/doc" target="_blank">Documentation</a>
|
||||
<a class="nav-link" href="https://arthas.aliyun.com/doc-tutorials" target="_blank">Online Tutorials</a>
|
||||
<a class="nav-link" href="https://arthas.aliyun.com/doc" target="_blank">Github</a>
|
||||
</div>
|
||||
</el-col>
|
||||
<el-col :span="12" class="header-right">
|
||||
<el-button type="primary" size="mini">New</el-button>
|
||||
<el-button type="primary" size="mini">Share</el-button>
|
||||
<el-button type="primary" size="mini">Close</el-button>
|
||||
<el-button type="primary" size="mini">Shutdown</el-button>
|
||||
<div class="user-info">
|
||||
<i class="el-icon-s-custom user-icon"></i>
|
||||
<span>Tom</span>
|
||||
</div>
|
||||
</el-col>
|
||||
</el-row>
|
||||
</el-header>
|
||||
<el-main>
|
||||
</el-main>
|
||||
</el-container>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template id="search-view">
|
||||
</template>
|
||||
|
||||
<script src="ui.js"></script>
|
||||
</body>
|
||||
</html>
|
@ -1,116 +0,0 @@
|
||||
|
||||
body {
|
||||
margin: 0px;
|
||||
overflow: hidden;
|
||||
}
|
||||
h4 {
|
||||
margin: 0 5px 5px 5px;
|
||||
}
|
||||
p {
|
||||
margin: 0px;
|
||||
}
|
||||
|
||||
.min-gap {
|
||||
height: 6px;
|
||||
}
|
||||
|
||||
.logo {
|
||||
vertical-align: middle;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.user-info {
|
||||
margin-left: 10px;
|
||||
vertical-align: middle;
|
||||
display: inline-block;
|
||||
}
|
||||
.user-icon {
|
||||
font-size: 24px;
|
||||
}
|
||||
|
||||
a.nav-link:active, a.nav-link:hover, a.nav-link:visited {
|
||||
color: rgba(0,0,0,.9);
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.nav-link {
|
||||
color: rgba(0,0,0,.5);
|
||||
display: inline-block;
|
||||
padding: .5rem 0.3rem;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.container {
|
||||
display: flex;
|
||||
flex-direction:column;
|
||||
height: 100vh;
|
||||
}
|
||||
.header {
|
||||
flex: 0 0 auto;
|
||||
padding: 8px;
|
||||
border-bottom: #cccccc 1px solid;
|
||||
}
|
||||
.header-right {
|
||||
text-align: right;
|
||||
}
|
||||
.main-body {
|
||||
/*height: 80vh;*/
|
||||
flex: 1 1 auto;
|
||||
overflow-y: auto;
|
||||
}
|
||||
.footer-row {
|
||||
flex: 0 0 auto;
|
||||
display: flex;
|
||||
padding-top: 5px;
|
||||
height: 45px !important;
|
||||
vertical-align: middle;
|
||||
border-top: #cccccc 1px solid;
|
||||
}
|
||||
.footer-left {
|
||||
/*width: 100px;*/
|
||||
vertical-align: middle;
|
||||
padding: 0.5em;
|
||||
}
|
||||
.footer-input {
|
||||
flex: 1;
|
||||
margin: 0 10px;
|
||||
}
|
||||
.footer-input .el-input__inner {
|
||||
height: 35px;
|
||||
}
|
||||
.footer-button {
|
||||
/*width: 100px;*/
|
||||
}
|
||||
|
||||
.main-body pre {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.errorMsg {
|
||||
color: #c82333;
|
||||
}
|
||||
|
||||
.resultMsg {
|
||||
background-color: #f0f0f0;
|
||||
}
|
||||
|
||||
.commandMsg {
|
||||
background-color: #d9ecff !important;
|
||||
}
|
||||
/*****************************/
|
||||
/* override element-ui class*/
|
||||
/*****************************/
|
||||
|
||||
.el-card__body {
|
||||
/*margin: 2px;*/
|
||||
padding: 8px;
|
||||
/*background-color: #cccccc;*/
|
||||
}
|
||||
.el-main {
|
||||
padding: 10px;
|
||||
/*background-color: #f7f8f9;*/
|
||||
}
|
||||
.el-header {
|
||||
padding: 10px;
|
||||
background-color: #f7f8f9;
|
||||
}
|
@ -1,363 +0,0 @@
|
||||
const InputStatus= {
|
||||
/**
|
||||
* Allow input new commands
|
||||
*/
|
||||
ALLOW_INPUT: 'ALLOW_INPUT',
|
||||
|
||||
/**
|
||||
* Allow interrupt running job
|
||||
*/
|
||||
ALLOW_INTERRUPT: 'ALLOW_INTERRUPT',
|
||||
|
||||
/**
|
||||
* Disable input and interrupt
|
||||
*/
|
||||
DISABLED: 'DISABLED'
|
||||
};
|
||||
|
||||
//session data
|
||||
function getDefaultSessionData() {
|
||||
return {
|
||||
sessionId: null,
|
||||
consumerId: null,
|
||||
lastPullResultTime: 0,
|
||||
commandLine: '',
|
||||
commandLineDisabled: true,
|
||||
commandResults: [],
|
||||
executingJobId: null,
|
||||
lastFinishedJobId: 0,
|
||||
inputStatus: InputStatus.DISABLED,
|
||||
startPullResults: false,
|
||||
};
|
||||
}
|
||||
|
||||
let sessionData = getDefaultSessionData();
|
||||
|
||||
//session view
|
||||
let SessionView = Vue.component('session-view',{
|
||||
template: '#session-view',
|
||||
data() {
|
||||
return sessionData;
|
||||
},
|
||||
methods: {
|
||||
resetData: function () {
|
||||
Object.assign(this.$data, getDefaultSessionData());
|
||||
},
|
||||
messageClass(item){
|
||||
return {
|
||||
commandMsg: item.command!=null,
|
||||
errorMsg: item.state == 'FAILED' || item.state == 'REFUSED',
|
||||
}
|
||||
},
|
||||
onSessionReady(){
|
||||
this.commandLineDisabled = false;
|
||||
},
|
||||
openNewSession(){
|
||||
window.open("/ui/", "_blank");
|
||||
},
|
||||
initPage(){
|
||||
console.log("initPage");
|
||||
let sessionId = this.$route.params.sessionId;
|
||||
if (sessionId && sessionId!='undefined'){
|
||||
//join_session, init new consumerId
|
||||
axios
|
||||
.post('/api',{
|
||||
"action": "join_session",
|
||||
"sessionId": sessionId
|
||||
})
|
||||
.then(response => {
|
||||
let apiResponse = response.data;
|
||||
if (apiResponse.state == "SUCCEEDED" && sessionId == apiResponse.sessionId){
|
||||
this.sessionId = apiResponse.sessionId;
|
||||
this.consumerId = apiResponse.consumerId;
|
||||
this.pullResults();
|
||||
this.onSessionReady();
|
||||
}else {
|
||||
//加入会话失败,创建新会话
|
||||
this.askForNewSession(true);
|
||||
}
|
||||
})
|
||||
.catch(error => { // 请求失败处理
|
||||
console.log(error);
|
||||
this.$alert('Connect to server failed: '+error.message, {
|
||||
type: 'error'
|
||||
});
|
||||
});
|
||||
} else {
|
||||
this.askForNewSession(false);
|
||||
}
|
||||
},
|
||||
|
||||
askForNewSession(showAlert){
|
||||
if (showAlert) {
|
||||
this.$alert('The session does not exist, new session will be opened', {
|
||||
type: 'warning',
|
||||
callback: action => {
|
||||
if (action == 'confirm') {
|
||||
this.initSession();
|
||||
}
|
||||
}
|
||||
});
|
||||
} else {
|
||||
this.initSession();
|
||||
}
|
||||
},
|
||||
|
||||
initSession(){
|
||||
console.log("initSession");
|
||||
this.resetData();
|
||||
axios
|
||||
.post('/api',{
|
||||
"action": "init_session"
|
||||
})
|
||||
.then(response => {
|
||||
let apiResponse = response.data;
|
||||
if (apiResponse.state == "SUCCEEDED"){
|
||||
this.sessionId = apiResponse.sessionId;
|
||||
this.consumerId = apiResponse.consumerId;
|
||||
this.$router.push("/session/"+this.sessionId);
|
||||
this.pullResults();
|
||||
this.onSessionReady();
|
||||
}
|
||||
})
|
||||
.catch(error => { // 请求失败处理
|
||||
console.log(error);
|
||||
this.$alert('Init session failed: '+error.message, {
|
||||
type: 'error'
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
interruptJob(){
|
||||
console.log("interruptJob");
|
||||
axios
|
||||
.post('/api',{
|
||||
"action": "interrupt_job",
|
||||
"sessionId": this.sessionId,
|
||||
})
|
||||
.then(response => {
|
||||
let apiResponse = response.data;
|
||||
if (apiResponse.state == "SUCCEEDED"){
|
||||
this.onSessionReady();
|
||||
}
|
||||
})
|
||||
.catch(error =>{ // 请求失败处理
|
||||
console.log(error);
|
||||
this.$message.error('Interrupt current job failed: '+error.message);
|
||||
});
|
||||
},
|
||||
|
||||
pullResults(){
|
||||
//保证只有一个拉取消息的timer
|
||||
if (this.startPullResults){
|
||||
return;
|
||||
}
|
||||
this.startPullResults = true;
|
||||
this.lastPullResultTime = new Date().getTime();
|
||||
//接收消息推送
|
||||
axios
|
||||
.post('/api',{
|
||||
"action": "pull_results",
|
||||
"sessionId": this.sessionId,
|
||||
"consumerId": this.consumerId
|
||||
})
|
||||
.then(response => {
|
||||
this.pullResultFailedCount = 0;
|
||||
let apiResponse = response.data;
|
||||
if (apiResponse.state == "SUCCEEDED"){
|
||||
this.appendResults(apiResponse.body.results);
|
||||
this.delayPullResults();
|
||||
} else {
|
||||
console.error("Pull results failed: ", apiResponse);
|
||||
this.inputStatus = InputStatus.DISABLED;
|
||||
this.$alert('Pull results failed: '+apiResponse.message, {
|
||||
type: 'error'
|
||||
});
|
||||
}
|
||||
})
|
||||
.catch(error => { // 请求失败处理
|
||||
console.log(error);
|
||||
if(++this.pullResultFailedCount > 10){
|
||||
this.inputStatus = InputStatus.DISABLED;
|
||||
//show pull error
|
||||
this.$alert('Pull results failed: '+error.message, {
|
||||
type: 'error'
|
||||
});
|
||||
} else {
|
||||
this.delayPullResults(2000);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
delayPullResults(delay) {
|
||||
this.startPullResults = false;
|
||||
if(!delay){
|
||||
delay = (new Date().getTime() - this.lastPullResultTime < 500)?500 : 50;
|
||||
}
|
||||
setTimeout(this.pullResults.bind(this), delay);
|
||||
},
|
||||
|
||||
appendResults(results) {
|
||||
if (!results || !results.length || results.length == 0){
|
||||
return;
|
||||
}
|
||||
//split results
|
||||
while(results.length > 0){
|
||||
//Restrict command results
|
||||
while(this.commandResults.length > 500){
|
||||
this.commandResults.shift();
|
||||
}
|
||||
let result = results.shift();
|
||||
console.log("result: ", result);
|
||||
if (result.type == 'input_status') {
|
||||
this.inputStatus = result.inputStatus;
|
||||
continue;
|
||||
}
|
||||
if (result.type == "status" && result.statusCode!=null){
|
||||
//命令执行完毕后允许输入
|
||||
this.setFinishedJobId(result.jobId);
|
||||
if (result.message) {
|
||||
this.commandResults.push(result);
|
||||
}
|
||||
} else {
|
||||
this.commandResults.push(result);
|
||||
}
|
||||
}
|
||||
|
||||
this.scrollContentToBottom();
|
||||
},
|
||||
|
||||
// appendCommand(response){
|
||||
// if (response && response.state) {
|
||||
// //Restrict command results
|
||||
// while(this.commandResults.length > 500){
|
||||
// this.commandResults.shift();
|
||||
// }
|
||||
// response.body.state = response.state;
|
||||
// if (response.message) {
|
||||
// response.body.message = response.message;
|
||||
// }
|
||||
// if ( response.state == 'SCHEDULED' || response.state == 'SUCCEEDED' ){
|
||||
// } else {
|
||||
// }
|
||||
// this.commandResults.push(response.body)
|
||||
// }
|
||||
// },
|
||||
|
||||
executeCommand(event) {
|
||||
this.commandLine = this.commandLine.trim();
|
||||
if (this.commandLine == ''){
|
||||
return;
|
||||
}
|
||||
|
||||
console.log("executing command: ", this.commandLine);
|
||||
axios
|
||||
.post('/api',{
|
||||
"action": "async_exec",
|
||||
"sessionId": this.sessionId,
|
||||
"consumerId": this.consumerId,
|
||||
"command": this.commandLine,
|
||||
})
|
||||
.then(response => {
|
||||
let apiResponse = response.data;
|
||||
if (apiResponse.state == "SCHEDULED" ){
|
||||
//设置当前任务jobId,禁止输入
|
||||
this.setExecutingJobId(apiResponse.body.jobId);
|
||||
} else {
|
||||
//command process error or refused
|
||||
this.setExecutingJobId(null);
|
||||
}
|
||||
//this.appendCommand(apiResponse);
|
||||
|
||||
})
|
||||
.catch(error =>{ // 请求失败处理
|
||||
console.log(error);
|
||||
//this.setExecutingJobId(null);
|
||||
this.$message.error('Execute command failed: '+error.message);
|
||||
});
|
||||
|
||||
|
||||
//disable input
|
||||
this.commandLineDisabled = true;
|
||||
},
|
||||
|
||||
setExecutingJobId(jobId) {
|
||||
if (jobId!=null && jobId > this.lastFinishedJobId) {
|
||||
this.executingJobId = jobId;
|
||||
} else {
|
||||
this.executingJobId = null;
|
||||
this.setFocusCommandInput();
|
||||
}
|
||||
},
|
||||
|
||||
setFinishedJobId(jobId) {
|
||||
this.lastFinishedJobId = jobId;
|
||||
if (this.executingJobId && jobId >= this.executingJobId){
|
||||
this.setExecutingJobId(null);
|
||||
}
|
||||
},
|
||||
|
||||
scrollContentToBottom(){
|
||||
setTimeout(function () {
|
||||
var container = this.$el.querySelector("#main-body");
|
||||
container.scrollTop = container.scrollHeight;
|
||||
}.bind(this), 50);
|
||||
},
|
||||
|
||||
setFocusCommandInput() {
|
||||
this.commandLine = '';
|
||||
this.commandLineDisabled = false;
|
||||
setTimeout(function () {
|
||||
this.$refs.commandInput.focus();
|
||||
}.bind(this), 50);
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
'$route'(to, from){
|
||||
console.log('route: ', to, from);
|
||||
this.initPage();
|
||||
}
|
||||
},
|
||||
created(){
|
||||
this.initPage();
|
||||
},
|
||||
updated(){
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
let HistoryView = Vue.component('history-view', {
|
||||
template: '#history-view',
|
||||
data() {
|
||||
return {
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
//页面路由
|
||||
const routes = [
|
||||
{ path: '/', redirect: '/session/' },
|
||||
//{ path: '/', component: HistoryView },
|
||||
{ path: '/session', component: SessionView },
|
||||
{ path: '/session/:sessionId', component: SessionView },
|
||||
{ path: '/history', component: HistoryView },
|
||||
];
|
||||
|
||||
const router = new VueRouter({
|
||||
routes
|
||||
});
|
||||
|
||||
new Vue({
|
||||
el: '#app',
|
||||
router,
|
||||
data: {
|
||||
sessionData
|
||||
},
|
||||
methods: {
|
||||
},
|
||||
watch: {
|
||||
},
|
||||
created(){
|
||||
|
||||
}
|
||||
});
|
@ -1,187 +0,0 @@
|
||||
var ws;
|
||||
var xterm;
|
||||
const DEFAULT_SCROLL_BACK = 1000
|
||||
const MAX_SCROLL_BACK = 9999999
|
||||
const MIN_SCROLL_BACK = 1
|
||||
|
||||
$(function () {
|
||||
var url = window.location.href;
|
||||
var ip = getUrlParam('ip');
|
||||
var port = getUrlParam('port');
|
||||
|
||||
if (ip != '' && ip != null) {
|
||||
$('#ip').val(ip);
|
||||
} else {
|
||||
$('#ip').val(window.location.hostname);
|
||||
}
|
||||
if (port != '' && port != null) {
|
||||
$('#port').val(port);
|
||||
}
|
||||
if (port == null && location.port == "8563") {
|
||||
$('#port').val(8563);
|
||||
}
|
||||
|
||||
var iframe = getUrlParam('iframe');
|
||||
if (iframe != null && iframe != 'false') {
|
||||
$("nav").hide()
|
||||
}
|
||||
|
||||
startConnect(true);
|
||||
});
|
||||
|
||||
/** get params in url **/
|
||||
function getUrlParam (name, url) {
|
||||
if (!url) url = window.location.href;
|
||||
name = name.replace(/[\[\]]/g, '\\$&');
|
||||
var regex = new RegExp('[?&]' + name + '(=([^&#]*)|&|#|$)'),
|
||||
results = regex.exec(url);
|
||||
if (!results) return null;
|
||||
if (!results[2]) return '';
|
||||
return decodeURIComponent(results[2].replace(/\+/g, ' '));
|
||||
}
|
||||
|
||||
function getCharSize () {
|
||||
var tempDiv = $('<div />').attr({'role': 'listitem'});
|
||||
var tempSpan = $('<div />').html('qwertyuiopasdfghjklzxcvbnm');
|
||||
tempDiv.append(tempSpan);
|
||||
$("html body").append(tempDiv);
|
||||
var size = {
|
||||
width: tempSpan.outerWidth() / 26,
|
||||
height: tempSpan.outerHeight(),
|
||||
left: tempDiv.outerWidth() - tempSpan.outerWidth(),
|
||||
top: tempDiv.outerHeight() - tempSpan.outerHeight(),
|
||||
};
|
||||
tempDiv.remove();
|
||||
return size;
|
||||
}
|
||||
|
||||
function getWindowSize () {
|
||||
var e = window;
|
||||
var a = 'inner';
|
||||
if (!('innerWidth' in window )) {
|
||||
a = 'client';
|
||||
e = document.documentElement || document.body;
|
||||
}
|
||||
var terminalDiv = document.getElementById("terminal-card");
|
||||
var terminalDivRect = terminalDiv.getBoundingClientRect();
|
||||
return {
|
||||
width: terminalDivRect.width,
|
||||
height: e[a + 'Height'] - terminalDivRect.top
|
||||
};
|
||||
}
|
||||
|
||||
function getTerminalSize () {
|
||||
var charSize = getCharSize();
|
||||
var windowSize = getWindowSize();
|
||||
console.log('charsize');
|
||||
console.log(charSize);
|
||||
console.log('windowSize');
|
||||
console.log(windowSize);
|
||||
return {
|
||||
cols: Math.floor((windowSize.width - charSize.left) / 10),
|
||||
rows: Math.floor((windowSize.height - charSize.top) / 17)
|
||||
};
|
||||
}
|
||||
|
||||
/** init websocket **/
|
||||
function initWs (ip, port) {
|
||||
var path = 'ws://' + ip + ':' + port + '/ws';
|
||||
ws = new WebSocket(path);
|
||||
}
|
||||
|
||||
/** init xterm **/
|
||||
function initXterm (cols, rows,scrollback) {
|
||||
let scrollNumber = parseInt(scrollback,10)
|
||||
xterm = new Terminal({
|
||||
cols: cols,
|
||||
rows: rows,
|
||||
screenReaderMode: false,
|
||||
rendererType: 'canvas',
|
||||
convertEol: true,
|
||||
scrollback: isValidNumber(scrollNumber) ? scrollNumber : DEFAULT_SCROLL_BACK
|
||||
});
|
||||
}
|
||||
|
||||
function isValidNumber(scrollNumber){
|
||||
return scrollNumber >= MIN_SCROLL_BACK &&
|
||||
scrollNumber <= MAX_SCROLL_BACK;
|
||||
}
|
||||
|
||||
/** begin connect **/
|
||||
function startConnect (silent) {
|
||||
var ip = $('#ip').val();
|
||||
var port = $('#port').val();
|
||||
if (ip == '' || port == '') {
|
||||
alert('Ip or port can not be empty');
|
||||
return;
|
||||
}
|
||||
if (ws != null) {
|
||||
alert('Already connected');
|
||||
return;
|
||||
}
|
||||
// init webSocket
|
||||
initWs(ip, port);
|
||||
ws.onerror = function () {
|
||||
ws.close();
|
||||
ws = null;
|
||||
!silent && alert('Connect error');
|
||||
};
|
||||
ws.onopen = function () {
|
||||
console.log('open');
|
||||
$('#fullSc').show();
|
||||
var terminalSize = getTerminalSize()
|
||||
let scrollback = getUrlParam('scrollback');
|
||||
console.log('terminalSize')
|
||||
console.log(terminalSize)
|
||||
// init xterm
|
||||
initXterm(terminalSize.cols, terminalSize.rows, scrollback)
|
||||
ws.onmessage = function (event) {
|
||||
if (event.type === 'message') {
|
||||
var data = event.data;
|
||||
xterm.write(data);
|
||||
}
|
||||
};
|
||||
xterm.open(document.getElementById('terminal'));
|
||||
xterm.on('data', function (data) {
|
||||
ws.send(JSON.stringify({action: 'read', data: data}))
|
||||
});
|
||||
ws.send(JSON.stringify({action: 'resize', cols: terminalSize.cols, rows: terminalSize.rows}));
|
||||
window.setInterval(function () {
|
||||
if (ws != null && ws.readyState === 1) {
|
||||
ws.send(JSON.stringify({action: 'read', data: ""}));
|
||||
}
|
||||
}, 30000);
|
||||
}
|
||||
}
|
||||
|
||||
function disconnect () {
|
||||
try {
|
||||
ws.close();
|
||||
ws.onmessage = null;
|
||||
ws.onclose = null;
|
||||
ws = null;
|
||||
xterm.destroy();
|
||||
$('#fullSc').hide();
|
||||
alert('Connection was closed successfully!');
|
||||
} catch (e) {
|
||||
alert('No connection, please start connect first.');
|
||||
}
|
||||
}
|
||||
|
||||
/** full screen show **/
|
||||
function xtermFullScreen () {
|
||||
var ele = document.getElementById('terminal-card');
|
||||
requestFullScreen(ele);
|
||||
}
|
||||
|
||||
function requestFullScreen (element) {
|
||||
var requestMethod = element.requestFullScreen || element.webkitRequestFullScreen || element.mozRequestFullScreen || element.msRequestFullScreen;
|
||||
if (requestMethod) {
|
||||
requestMethod.call(element);
|
||||
} else if (typeof window.ActiveXObject !== "undefined") {
|
||||
var wscript = new ActiveXObject("WScript.Shell");
|
||||
if (wscript !== null) {
|
||||
wscript.SendKeys("{F11}");
|
||||
}
|
||||
}
|
||||
}
|
@ -1,164 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2014 The xterm.js authors. All rights reserved.
|
||||
* Copyright (c) 2012-2013, Christopher Jeffrey (MIT License)
|
||||
* https://github.com/chjj/term.js
|
||||
* @license MIT
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* Originally forked from (with the author's permission):
|
||||
* Fabrice Bellard's javascript vt100 for jslinux:
|
||||
* http://bellard.org/jslinux/
|
||||
* Copyright (c) 2011 Fabrice Bellard
|
||||
* The original design remains. The terminal itself
|
||||
* has been extended to include xterm CSI codes, among
|
||||
* other features.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Default styles for xterm.js
|
||||
*/
|
||||
|
||||
.xterm {
|
||||
font-family: courier-new, courier, monospace;
|
||||
font-feature-settings: "liga" 0;
|
||||
position: relative;
|
||||
user-select: none;
|
||||
-ms-user-select: none;
|
||||
-webkit-user-select: none;
|
||||
}
|
||||
|
||||
.xterm.focus,
|
||||
.xterm:focus {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.xterm .xterm-helpers {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
/**
|
||||
* The z-index of the helpers must be higher than the canvases in order for
|
||||
* IMEs to appear on top.
|
||||
*/
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
.xterm .xterm-helper-textarea {
|
||||
/*
|
||||
* HACK: to fix IE's blinking cursor
|
||||
* Move textarea out of the screen to the far left, so that the cursor is not visible.
|
||||
*/
|
||||
position: absolute;
|
||||
opacity: 0;
|
||||
left: -9999em;
|
||||
top: 0;
|
||||
width: 0;
|
||||
height: 0;
|
||||
z-index: -10;
|
||||
/** Prevent wrapping so the IME appears against the textarea at the correct position */
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
resize: none;
|
||||
}
|
||||
|
||||
.xterm .composition-view {
|
||||
/* TODO: Composition position got messed up somewhere */
|
||||
background: #000;
|
||||
color: #FFF;
|
||||
display: none;
|
||||
position: absolute;
|
||||
white-space: nowrap;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.xterm .composition-view.active {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.xterm .xterm-viewport {
|
||||
/* On OS X this is required in order for the scroll bar to appear fully opaque */
|
||||
background-color: #000;
|
||||
overflow-y: scroll;
|
||||
cursor: default;
|
||||
position: absolute;
|
||||
right: 0;
|
||||
left: 0;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
}
|
||||
|
||||
.xterm .xterm-screen {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.xterm .xterm-screen canvas {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
}
|
||||
|
||||
.xterm .xterm-scroll-area {
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
.xterm-char-measure-element {
|
||||
display: inline-block;
|
||||
visibility: hidden;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: -9999em;
|
||||
line-height: normal;
|
||||
}
|
||||
|
||||
.xterm {
|
||||
cursor: text;
|
||||
}
|
||||
|
||||
.xterm.enable-mouse-events {
|
||||
/* When mouse events are enabled (eg. tmux), revert to the standard pointer cursor */
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.xterm.xterm-cursor-pointer {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.xterm.column-select.focus {
|
||||
/* Column selection mode */
|
||||
cursor: crosshair;
|
||||
}
|
||||
|
||||
.xterm .xterm-accessibility,
|
||||
.xterm .xterm-message {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
z-index: 100;
|
||||
color: transparent;
|
||||
}
|
||||
|
||||
.xterm .live-region {
|
||||
position: absolute;
|
||||
left: -9999px;
|
||||
width: 1px;
|
||||
height: 1px;
|
||||
overflow: hidden;
|
||||
}
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user