Multiple Dockge instances (#200)

This commit is contained in:
Louis Lam
2023-12-26 04:12:44 +08:00
committed by GitHub
parent 80e885e85d
commit de2de0573b
38 changed files with 1525 additions and 597 deletions

View File

@@ -137,7 +137,7 @@
<script>
import { defineComponent } from "vue";
import { FontAwesomeIcon } from "@fortawesome/vue-fontawesome";
import { parseDockerPort } from "../../../backend/util-common";
import { parseDockerPort } from "../../../common/util-common";
export default defineComponent({
components: {
@@ -189,14 +189,34 @@ export default defineComponent({
},
terminalRouteLink() {
return {
name: "containerTerminal",
params: {
stackName: this.stackName,
serviceName: this.name,
type: "bash",
},
};
if (this.endpoint) {
return {
name: "containerTerminalEndpoint",
params: {
endpoint: this.endpoint,
stackName: this.stackName,
serviceName: this.name,
type: "bash",
},
};
} else {
return {
name: "containerTerminal",
params: {
stackName: this.stackName,
serviceName: this.name,
type: "bash",
},
};
}
},
endpoint() {
return this.$parent.$parent.endpoint;
},
stack() {
return this.$parent.$parent.stack;
},
stackName() {
@@ -254,8 +274,7 @@ export default defineComponent({
},
methods: {
parsePort(port) {
let hostname = this.$root.info.primaryHostname || location.hostname;
return parseDockerPort(port, hostname);
return parseDockerPort(port, this.stack.primaryHostname);
},
remove() {
delete this.jsonObject.services[this.name];

View File

@@ -65,6 +65,10 @@ export default {
editorFocus() {
return this.$parent.$parent.editorFocus;
},
endpoint() {
return this.$parent.$parent.endpoint;
},
},
watch: {
"jsonConfig.networks": {
@@ -134,7 +138,7 @@ export default {
},
loadExternalNetworkList() {
this.$root.getSocket().emit("getDockerNetworkList", (res) => {
this.$root.emitAgent(this.endpoint, "getDockerNetworkList", (res) => {
if (res.ok) {
this.externalNetworkList = res.dockerNetworkList.filter((n) => {
// Filter out this stack networks

View File

@@ -43,7 +43,7 @@
</div>
</div>
<div ref="stackList" class="stack-list" :class="{ scrollbar: scrollbar }" :style="stackListStyle">
<div v-if="Object.keys($root.stackList).length === 0" class="text-center mt-3">
<div v-if="Object.keys(sortedStackList).length === 0" class="text-center mt-3">
<router-link to="/compose">{{ $t("addFirstStackMsg") }}</router-link>
</div>
@@ -67,7 +67,7 @@
<script>
import Confirm from "../components/Confirm.vue";
import StackListItem from "../components/StackListItem.vue";
import { CREATED_FILE, CREATED_STACK, EXITED, RUNNING, UNKNOWN } from "../../../backend/util-common";
import { CREATED_FILE, CREATED_STACK, EXITED, RUNNING, UNKNOWN } from "../../../common/util-common";
export default {
components: {
@@ -120,7 +120,7 @@ export default {
* @returns {Array} The sorted list of stacks.
*/
sortedStackList() {
let result = Object.values(this.$root.stackList);
let result = Object.values(this.$root.completeStackList);
result = result.filter(stack => {
// filter by search text
@@ -160,6 +160,7 @@ export default {
return 1;
}
// sort by status
if (m1.status !== m2.status) {
if (m2.status === RUNNING) {
return 1;

View File

@@ -1,12 +1,14 @@
<template>
<router-link :to="`/compose/${stack.name}`" :class="{ 'dim' : !stack.isManagedByDockge }" class="item">
<router-link :to="url" :class="{ 'dim' : !stack.isManagedByDockge }" class="item">
<Uptime :stack="stack" :fixed-width="true" class="me-2" />
<span class="title">{{ stackName }}</span>
<div class="title">
<span>{{ stackName }}</span>
<div v-if="$root.agentCount > 1" class="endpoint">{{ endpointDisplay }}</div>
</div>
</router-link>
</template>
<script>
import Uptime from "./Uptime.vue";
export default {
@@ -51,6 +53,16 @@ export default {
};
},
computed: {
endpointDisplay() {
return this.$root.endpointDisplayFunction(this.stack.endpoint);
},
url() {
if (this.stack.endpoint) {
return `/compose/${this.stack.name}/${this.stack.endpoint}`;
} else {
return `/compose/${this.stack.name}`;
}
},
depthMargin() {
return {
marginLeft: `${31 * this.depth}px`,
@@ -117,16 +129,31 @@ export default {
padding-right: 2px !important;
}
// .stack-item {
// width: 100%;
// }
.tags {
margin-top: 4px;
padding-left: 67px;
.item {
text-decoration: none;
display: flex;
flex-wrap: wrap;
gap: 0;
align-items: center;
min-height: 52px;
border-radius: 10px;
transition: all ease-in-out 0.15s;
width: 100%;
padding: 5px 8px;
&.disabled {
opacity: 0.3;
}
&:hover {
background-color: $highlight-white;
}
&.active {
background-color: #cdf8f4;
}
.title {
margin-top: -4px;
}
.endpoint {
font-size: 12px;
color: $dark-font-color3;
}
}
.collapsed {

View File

@@ -7,8 +7,7 @@
<script>
import { Terminal } from "@xterm/xterm";
import { FitAddon } from "@xterm/addon-fit";
import { WebLinksAddon } from "xterm-addon-web-links";
import { TERMINAL_COLS, TERMINAL_ROWS } from "../../../backend/util-common";
import { TERMINAL_COLS, TERMINAL_ROWS } from "../../../common/util-common";
export default {
/**
@@ -24,6 +23,11 @@ export default {
require: true,
},
endpoint: {
type: String,
require: true,
},
// Require if mode is interactive
stackName: {
type: String,
@@ -110,14 +114,14 @@ export default {
// Create a new Terminal
if (this.mode === "mainTerminal") {
this.$root.getSocket().emit("mainTerminal", this.name, (res) => {
this.$root.emitAgent(this.endpoint, "mainTerminal", this.name, (res) => {
if (!res.ok) {
this.$root.toastRes(res);
}
});
} else if (this.mode === "interactive") {
console.debug("Create Interactive terminal:", this.name);
this.$root.getSocket().emit("interactiveTerminal", this.stackName, this.serviceName, this.shell, (res) => {
this.$root.emitAgent(this.endpoint, "interactiveTerminal", this.stackName, this.serviceName, this.shell, (res) => {
if (!res.ok) {
this.$root.toastRes(res);
}
@@ -134,15 +138,15 @@ export default {
},
methods: {
bind(name) {
bind(endpoint, name) {
// Workaround: normally this.name should be set, but it is not sometimes, so we use the parameter, but eventually this.name and name must be the same name
if (name) {
this.$root.unbindTerminal(name);
this.$root.bindTerminal(name, this.terminal);
this.$root.bindTerminal(endpoint, name, this.terminal);
console.debug("Terminal bound via parameter: " + name);
} else if (this.name) {
this.$root.unbindTerminal(this.name);
this.$root.bindTerminal(this.name, this.terminal);
this.$root.bindTerminal(this.endpoint, this.name, this.terminal);
console.debug("Terminal bound: " + this.name);
} else {
console.debug("Terminal name not set");
@@ -173,7 +177,7 @@ export default {
// Remove the input from the terminal
this.removeInput();
this.$root.getSocket().emit("terminalInput", this.name, buffer + e.key, (err) => {
this.$root.emitAgent(this.endpoint, "terminalInput", this.name, buffer + e.key, (err) => {
this.$root.toastError(err.msg);
});
@@ -192,7 +196,7 @@ export default {
// TODO
} else if (e.key === "\u0003") { // Ctrl + C
console.debug("Ctrl + C");
this.$root.getSocket().emit("terminalInput", this.name, e.key);
this.$root.emitAgent(this.endpoint, "terminalInput", this.name, e.key);
this.removeInput();
} else {
this.cursorPosition++;
@@ -205,7 +209,7 @@ export default {
interactiveTerminalConfig() {
this.terminal.onKey(e => {
this.$root.getSocket().emit("terminalInput", this.name, e.key, (res) => {
this.$root.emitAgent(this.endpoint, "terminalInput", this.name, e.key, (res) => {
if (!res.ok) {
this.$root.toastRes(res);
}
@@ -234,7 +238,7 @@ export default {
this.terminalFitAddOn.fit();
let rows = this.terminal.rows;
let cols = this.terminal.cols;
this.$root.getSocket().emit("terminalResize", this.name, rows, cols);
this.$root.emitAgent(this.endpoint, "terminalResize", this.name, rows, cols);
}
}
};

View File

@@ -3,7 +3,7 @@
</template>
<script>
import { statusColor, statusNameShort } from "../../../backend/util-common";
import { statusColor, statusNameShort } from "../../../common/util-common";
export default {
props: {