2025-09-02 21:03:35 +08:00
|
|
|
import { bind } from 'decko';
|
|
|
|
|
import { Component, h } from 'preact';
|
|
|
|
|
import { Xterm, XtermOptions } from './xterm';
|
|
|
|
|
|
|
|
|
|
import '@xterm/xterm/css/xterm.css';
|
|
|
|
|
import { Modal } from '../modal';
|
|
|
|
|
|
|
|
|
|
interface Props extends XtermOptions {
|
|
|
|
|
id: string;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
interface State {
|
|
|
|
|
modal: boolean;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export class Terminal extends Component<Props, State> {
|
|
|
|
|
private container: HTMLElement;
|
|
|
|
|
private xterm: Xterm;
|
2025-10-18 16:35:39 +08:00
|
|
|
private intervalID: NodeJS.Timeout;
|
|
|
|
|
private currentDevcontainer = {
|
|
|
|
|
title: 'Devcontainer Info',
|
|
|
|
|
detail: 'No Devcontainer Created yet',
|
|
|
|
|
port: '',
|
|
|
|
|
ip:'',
|
|
|
|
|
steps: [
|
|
|
|
|
// {
|
|
|
|
|
// summary: '',
|
|
|
|
|
// duration: '',
|
|
|
|
|
// status: '',
|
|
|
|
|
// logs:{
|
|
|
|
|
// },
|
|
|
|
|
// }
|
|
|
|
|
],
|
|
|
|
|
};
|
2025-09-02 21:03:35 +08:00
|
|
|
constructor(props: Props) {
|
|
|
|
|
super();
|
|
|
|
|
this.xterm = new Xterm(props, this.showModal);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async componentDidMount() {
|
|
|
|
|
await this.xterm.refreshToken();
|
2025-10-18 16:35:39 +08:00
|
|
|
const options = new URLSearchParams(decodeURIComponent(window.location.search));
|
|
|
|
|
|
|
|
|
|
const params = new URLSearchParams({
|
|
|
|
|
repo: options.get('repoid') as string,
|
|
|
|
|
user: options.get('userid') as string,
|
|
|
|
|
});
|
|
|
|
|
fetch('http://' +
|
|
|
|
|
options.get('domain') +
|
|
|
|
|
':'+
|
|
|
|
|
options.get('port') +
|
|
|
|
|
'/' +
|
|
|
|
|
options.get('user') +
|
|
|
|
|
'/' +
|
|
|
|
|
options.get('repo') +
|
|
|
|
|
'/devcontainer/status?' +
|
|
|
|
|
params
|
|
|
|
|
)
|
|
|
|
|
.then(response => response.json())
|
|
|
|
|
.then(data => {
|
|
|
|
|
if (data.status !== '-1') {
|
|
|
|
|
if (options.get('type') === 'docker') {
|
|
|
|
|
this.xterm.open(this.container);
|
|
|
|
|
this.xterm.connect();
|
|
|
|
|
} else {
|
2025-10-29 08:32:18 +08:00
|
|
|
this.intervalID = setInterval(this.loadOutput, 8000);
|
2025-10-18 16:35:39 +08:00
|
|
|
this.xterm.open(this.container);
|
|
|
|
|
this.xterm.changeUrl(this.currentDevcontainer.ip, this.currentDevcontainer.port)
|
|
|
|
|
this.xterm.changeStatus(true);
|
|
|
|
|
this.xterm.connect();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
.catch(error => {
|
|
|
|
|
console.error('Error:', error);
|
|
|
|
|
});
|
|
|
|
|
|
2025-09-02 21:03:35 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
componentWillUnmount() {
|
|
|
|
|
this.xterm.dispose();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
render({ id }: Props, { modal }: State) {
|
|
|
|
|
return (
|
|
|
|
|
<div id={id} ref={c => (this.container = c as HTMLElement)}>
|
|
|
|
|
<Modal show={modal}>
|
|
|
|
|
<label class="file-label">
|
|
|
|
|
<input onChange={this.sendFile} class="file-input" type="file" multiple />
|
|
|
|
|
<span class="file-cta">Choose files…</span>
|
|
|
|
|
</label>
|
|
|
|
|
</Modal>
|
|
|
|
|
</div>
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@bind
|
|
|
|
|
showModal() {
|
|
|
|
|
this.setState({ modal: true });
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@bind
|
|
|
|
|
sendFile(event: Event) {
|
|
|
|
|
this.setState({ modal: false });
|
|
|
|
|
const files = (event.target as HTMLInputElement).files;
|
|
|
|
|
if (files) this.xterm.sendFile(files);
|
|
|
|
|
}
|
2025-10-18 16:35:39 +08:00
|
|
|
|
|
|
|
|
@bind
|
|
|
|
|
private loadOutput() {
|
|
|
|
|
const options = new URLSearchParams(decodeURIComponent(window.location.search));
|
|
|
|
|
const params = new URLSearchParams({
|
|
|
|
|
repo: options.get('repoid') as string,
|
|
|
|
|
user: options.get('userid') as string,
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
fetch(
|
|
|
|
|
'http://' + options.get('domain') + ':'+ options.get('port') +'/' +
|
|
|
|
|
options.get('user') +
|
|
|
|
|
'/' +
|
|
|
|
|
options.get('repo') +
|
|
|
|
|
'/devcontainer/output?' +
|
|
|
|
|
params
|
|
|
|
|
)
|
|
|
|
|
.then(response => response.json())
|
|
|
|
|
.then(job => {
|
|
|
|
|
if (!job) {
|
|
|
|
|
clearInterval(this.intervalID);
|
|
|
|
|
this.intervalID = null as any;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if(this.currentDevcontainer.steps.length < job.currentDevcontainer.steps.length){
|
|
|
|
|
for(let i = this.currentDevcontainer.steps.length; i < job.currentDevcontainer.steps.length; i++) {
|
|
|
|
|
this.xterm.writeData(job.currentDevcontainer.steps[i].summary);
|
|
|
|
|
this.xterm.writeData('\r\n');
|
|
|
|
|
for(let j = 0; j < job.currentDevcontainer.steps[i].logs.length; j++) {
|
|
|
|
|
this.xterm.writeData(job.currentDevcontainer.steps[i].logs[j].message.replace(/\r\n/g, '\n').replace(/\n/g, '\r\n'));
|
|
|
|
|
this.xterm.writeData('\r\n');
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
this.currentDevcontainer = job.currentDevcontainer;
|
|
|
|
|
if (this.currentDevcontainer.detail === '4' && this.intervalID) {
|
|
|
|
|
clearInterval(this.intervalID);
|
|
|
|
|
this.intervalID = null as any;
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
.catch(error => {
|
|
|
|
|
console.error('Error:', error);
|
|
|
|
|
});
|
|
|
|
|
}
|
2025-09-02 21:03:35 +08:00
|
|
|
}
|