Files
devstar/templates/repo/devcontainer/details.tmpl

428 lines
15 KiB
Handlebars
Raw Normal View History

{{template "base/head" .}}
<div role="main" aria-label="{{.Title}}" class="page-content repository wiki pages">
{{template "repo/header" .}}
<div class="ui container">
{{template "base/alert" .}}
<!-- 开始Dev Container 正文 -->
<div class="issue-content">
<!-- 开始Dev Container 正文内容 - 左侧主展示区 -->
<div class="issue-content-left">
{{if not .HasDevContainerConfiguration}}
<div class="empty-placeholder">
{{svg "octicon-container" 48}}
<h2>{{ctx.Locale.Tr "repo.dev_container_empty"}}</h2>
{{if .isAdmin}}
<form method="get" action="{{.CreateDevcontainerSettingUrl}}" class="ui edit form">
<button class="ui primary button" type="submit">Create</button>
</form>
{{end}}
</div>
{{else}}
<div class="ui container">
<form class="ui edit form">
<div class="repo-editor-header">
<div class="ui breadcrumb field">
<a class="section" href="{{$.BranchLink}}">{{.Repository.Name}}</a>
{{range $i, $v := .TreeNames}}
<div class="breadcrumb-divider">/</div>
<span class="section"><a href="{{$.BranchLink}}/{{index $.TreePaths $i | PathEscapeSegments}}">{{$v}}</a></span>
{{end}}
</div>
<a href="{{.EditDevcontainerConfigurationUrl}}"><div class="ui primary button" style="margin-left: 10px;width: 4em;height: 1em;">Edit</div></a>
</div>
</form>
<iframe id="webTerminalContainer" src="{{.WebSSHUrl}}" width="100%" style="height: 100vh; display: none;" frameborder="0">您的浏览器不支持iframe</iframe>
</div>
{{end}}
</div>
<!-- 结束Dev Container 正文内容 - 左侧主展示区 -->
<!-- 开始Dev Container 正文内容 - 右侧展示区 -->
<div class="issue-content-right ui segment">
<strong>{{ctx.Locale.Tr "repo.dev_container_control"}}</strong>
<div class="ui relaxed list">
{{if .HasDevContainer}}
<div style=" display: none;" id="deleteContainer" class="item"><a class="delete-button flex-text-inline" data-modal="#delete-repo-devcontainer-of-user-modal" href="#" data-url="{{.Repository.Link}}/devcontainer/delete">{{svg "octicon-trash" 14}}{{ctx.Locale.Tr "repo.dev_container_control.delete"}}</a></div>
{{if .isAdmin}}
<div style=" display: none;" id="updateContainer" class="item"><a class="delete-button flex-text-inline" style="color:black; " data-modal-id="updatemodal" href="#">{{svg "octicon-database"}}{{ctx.Locale.Tr "repo.dev_container_control.update"}}</a></div>
{{end}}
<div style=" display: none;" id="restartContainer" class="item"><button class="flex-text-inline" style="color:black; " >{{svg "octicon-terminal" 14 "tw-mr-2"}}{{ctx.Locale.Tr "repo.dev_container_control.start"}}</button></div>
<div style=" display: none;" id="stopContainer" class="item"><button class="flex-text-inline" style="color:black; " >{{svg "octicon-terminal" 14 "tw-mr-2"}}{{ctx.Locale.Tr "repo.dev_container_control.stop"}} </button></div>
<div style=" display: none;" id="webTerminal" class="item"><a class="flex-text-inline" style="color:black; " href="{{.WebSSHUrl}}" target="_blank">{{svg "octicon-code" 14}}open with WebTerminal</a></div>
<div style=" display: none;" id="vsTerminal" class="item"><a class="flex-text-inline" style="color:black; " onclick="window.location.href = '{{.VSCodeUrl}}'">{{svg "octicon-code" 14}}open with VSCode</a ></div>
<div style=" display: none;" id="cursorTerminal" class="item"><a class="flex-text-inline" style="color:black; " onclick="window.location.href = '{{.CursorUrl}}'">{{svg "octicon-code" 14}}open with Cursor</a ></div>
<div style=" display: none;" id="windsurfTerminal" class="item"><a class="flex-text-inline" style="color:black;" onclick="window.location.href = '{{.WindsurfUrl}}'">{{svg "octicon-code" 14}}open with Windsurf</a ></div>
{{end}}
{{if .ValidateDevContainerConfiguration}}
<div style=" display: none;" id="createContainer" class="item">
<div>
<form method="get" action="{{.Repository.Link}}/devcontainer/create" class="ui edit form">
<button class="flex-text-inline" type="submit">{{svg "octicon-terminal" 14 "tw-mr-2"}} Create Dev Container</button>
</form>
</div>
</div>
<div id="loading" class="loading"></div>
{{end}}
{{if not .ValidateDevContainerConfiguration}}
<div class="item">{{svg "octicon-alert" 16 "tw-mr-2"}} {{ctx.Locale.Tr "repo.dev_container_invalid_config_prompt"}} </div>
{{end}}
</div>
</div>
<!-- 结束Dev Container 正文内容 - 右侧展示区 -->
</div>
<!-- 结束Dev Container 正文内容 -->
</div>
</div>
<!-- 确认删除 Dev Container 模态对话框 -->
<div class="ui g-modal-confirm delete modal" id="delete-repo-devcontainer-of-user-modal">
<div class="header">
{{svg "octicon-trash"}}
{{ctx.Locale.Tr "repo.dev_container_control.delete"}}
</div>
<div class="content">
<p>{{ctx.Locale.Tr "repo.dev_container_control.deletion_desc"}}</p>
</div>
{{template "base/modal_actions_confirm" .}}
</div>
<!-- 确认 Dev Container 模态对话框 -->
<div class="ui g-modal-confirm delete modal" style="width: 35%" id="updatemodal">
<div class="header">
{{ctx.Locale.Tr "repo.dev_container_control.update"}}
</div>
<div class="content">
<form class="ui form tw-max-w-2xl tw-m-auto" id="updateForm" onsubmit="submitForm(event)">
<div class="inline field">
<div class="ui checkbox">
{{if not .HasDevContainerDockerfile}}
<input type="checkbox" id="SaveMethod" name="SaveMethod" disabled>
{{else}}
<input type="checkbox" id="SaveMethod" name="SaveMethod" value="on">
{{end}}
<label for="SaveMethod">Build From Dockerfile</label>
</div>
</div>
<div class="required field ">
<label for="RepositoryAddress">Registry:</label>
<input style="border: 1px solid black;" type="text" id="RepositoryAddress" name="RepositoryAddress" value="{{.RepositoryAddress}}">
</div>
<div class="required field ">
<label for="RepositoryUsername">Registry Username:</label>
<input style="border: 1px solid black;" type="text" id="RepositoryUsername" name="RepositoryUsername" value="{{.RepositoryUsername}}">
</div>
<div class="required field ">
<label for="RepositoryPassword">Registry Password:</label>
<input style="border: 1px solid black;" type="text" id="RepositoryPassword" name="RepositoryPassword" required>
</div>
<div class="required field ">
<label for="ImageName">Image(name:tag):</label>
<input style="border: 1px solid black;" type="text" id="ImageName" name="ImageName" value="{{.ImageName}}">
</div>
<div class="actions">
<button class="ui primary button" type="submit" id="updateSubmitButton" >Submit</button>
<button class="ui cancel button" id="updateCloseButton">Close</button>
</div>
</form>
</div>
</div>
<script>
var status = '-1'
var intervalID
const createContainer = document.getElementById('createContainer');
const deleteContainer = document.getElementById('deleteContainer');
const updateContainer = document.getElementById('updateContainer');
const restartContainer = document.getElementById('restartContainer');
const stopContainer = document.getElementById('stopContainer');
const webTerminal = document.getElementById('webTerminal');
const vsTerminal = document.getElementById('vsTerminal');
const cursorTerminal = document.getElementById('cursorTerminal');
const windsurfTerminal = document.getElementById('windsurfTerminal');
const webTerminalContainer = document.getElementById('webTerminalContainer');
const loadingElement = document.getElementById('loading');
function concealElement(){
if (createContainer){
createContainer.style.display = 'none';
}
if (deleteContainer){
deleteContainer.style.display = 'none';
}
if (updateContainer) {
updateContainer.style.display = 'none';
}
if (restartContainer) {
restartContainer.style.display = 'none';
}
if (stopContainer) {
stopContainer.style.display = 'none';
}
if (webTerminal) {
webTerminal.style.display = 'none';
}
if (vsTerminal) {
vsTerminal.style.display = 'none';
}
if (cursorTerminal) {
cursorTerminal.style.display = 'none';
}
if (windsurfTerminal) {
windsurfTerminal.style.display = 'none';
}
if (webTerminalContainer) {
webTerminalContainer.style.display = 'none';
}
}
function displayElement(){
if (deleteContainer){
deleteContainer.style.display = 'block';
}
if (updateContainer) {
updateContainer.style.display = 'block';
}
if (restartContainer) {
restartContainer.style.display = 'block';
}
if (stopContainer) {
stopContainer.style.display = 'block';
}
if (webTerminal) {
webTerminal.style.display = 'block';
}
if (vsTerminal) {
vsTerminal.style.display = 'block';
}
if (cursorTerminal) {
cursorTerminal.style.display = 'block';
}
if (windsurfTerminal) {
windsurfTerminal.style.display = 'block';
}
if (webTerminalContainer) {
webTerminalContainer.style.display = 'block';
}
}
function getStatus() {
fetch(
'{{.Repository.Link}}'+'/devcontainer/status'
)
.then(response => response.json())
.then(data => {
if(status !== '9' && status !== '-1' && data.status == '9'){
window.location.reload();
}
if(status !== '-1' && data.status == '-1'){
window.location.reload();
}
if(status !== '4' && status !== '-1' && data.status == '4'){
window.location.reload();
}
if (data.status == '-1' || data.status == '') {
if (loadingElement) {
loadingElement.style.display = 'none';
}
if (createContainer){
createContainer.style.display = 'block';
}
clearInterval(intervalID);
} else if (data.status == '0' || data.status == '1' || data.status == '2') {
concealElement();
if (webTerminalContainer) {
webTerminalContainer.style.display = 'block';
}
if (deleteContainer){
deleteContainer.style.display = 'block';
}
if (loadingElement) {
loadingElement.style.display = 'block';
}
}else if (data.status == '3') {
concealElement();
if (deleteContainer){
deleteContainer.style.display = 'block';
}
if (webTerminalContainer) {
webTerminalContainer.style.display = 'block';
}
if (loadingElement) {
loadingElement.style.display = 'block';
}
}else if (data.status == '4') {
displayElement();
if (loadingElement) {
loadingElement.style.display = 'none';
}
if (restartContainer) {
restartContainer.style.display = 'none';
}
clearInterval(intervalID);
}else if (data.status == '5') {
concealElement();
if (loadingElement) {
loadingElement.style.display = 'block';
}
}else if (data.status == '6') {
concealElement();
if (deleteContainer){
deleteContainer.style.display = 'block';
}
if (updateContainer) {
updateContainer.style.display = 'block';
}
if (loadingElement) {
loadingElement.style.display = 'block';
}
}else if (data.status == '7') {
concealElement();
if (deleteContainer){
deleteContainer.style.display = 'block';
}
if (updateContainer) {
updateContainer.style.display = 'block';
}
if (loadingElement) {
loadingElement.style.display = 'block';
}
}else if (data.status == '8') {
concealElement();
if (deleteContainer){
deleteContainer.style.display = 'block';
}
if (updateContainer) {
updateContainer.style.display = 'block';
}
if (restartContainer) {
restartContainer.style.display = 'block';
}
if (loadingElement) {
loadingElement.style.display = 'none';
}
clearInterval(intervalID);
}else if (data.status == '9') {
concealElement();
if (loadingElement) {
loadingElement.style.display = 'block';
}
}
status = data.status
})
.catch(error => {
console.error('Error:', error);
});
}
intervalID = setInterval(getStatus, 3000);
if (restartContainer) {
restartContainer.addEventListener('click', function(event) {
// 处理点击逻辑
concealElement();
if (loadingElement) {
loadingElement.style.display = 'block';
}
fetch('{{.Repository.Link}}' + '/devcontainer/restart')
.then(response => {intervalID = setInterval(getStatus, 3000);})
});
}
if (stopContainer) {
stopContainer.addEventListener('click', function(event) {
concealElement();
if (loadingElement) {
loadingElement.style.display = 'block';
}
// 处理点击逻辑
fetch('{{.Repository.Link}}' + '/devcontainer/stop')
.then(response => {intervalID = setInterval(getStatus, 3000);})
});
}
if (deleteContainer) {
deleteContainer.addEventListener('click', function(event) {
setInterval(getStatus, 3000);
});
}
function submitForm(event) {
event.preventDefault(); // 阻止默认的表单提交行为
const {csrfToken} = window.config;
const {appSubUrl} = window.config;
const form = document.getElementById('updateForm');
const submitButton = document.getElementById('updateSubmitButton');
const closeButton = document.getElementById('updateCloseButton');
submitButton.disabled = true;
const formData = new FormData(form);
fetch('{{.Repository.Link}}'+'/devcontainer/update', {
method: 'POST',
headers: {
'x-csrf-token': csrfToken, // 如果需要认证
'content-type' : 'application/json',
},
body: JSON.stringify({
RepositoryAddress: formData.get('RepositoryAddress'),
RepositoryUsername: formData.get('RepositoryUsername'),
RepositoryPassword: formData.get('RepositoryPassword'),
SaveMethod: formData.get('SaveMethod'),
ImageName: formData.get('ImageName'),
})
})
.then(response => response.json())
.then(data => {
submitButton.disabled = false;
alert(data.message);
if(data.redirect){
closeButton.click()
}
intervalID = setInterval(getStatus, 3000);
})
.catch((error) => {
submitButton.disabled = false;
alert('提交失败,请重试。');
});
}
</script>
<style>
.loading{
width:60px;
height:60px;
border-radius:150px;
border:8px solid #fff;
border-top-color:rgba(0,0,0,0.3);
box-sizing:border-box;
margin-left:calc(50% - 30px);
animation:loading 1.2s linear infinite;
-webkit-animation:loading 1.2s linear infinite;
}
@keyframes loading{
0%{transform:rotate(0deg)}
100%{transform:rotate(360deg)}
}
@-webkit-keyframes loading{
0%{-webkit-transform:rotate(0deg)}
100%{-webkit-transform:rotate(360deg)}
}
</style>
{{template "base/footer" .}}