This commit is contained in:
Julian Lohrber 2024-12-28 15:17:44 +01:00 committed by GitHub
commit a5bf872a42
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 102 additions and 11 deletions

View file

@ -76,12 +76,14 @@ export class AgentManager {
* @param url * @param url
* @param username * @param username
* @param password * @param password
* @param name
*/ */
async add(url : string, username : string, password : string) : Promise<Agent> { async add(url: string, username: string, password: string, name: string): Promise<Agent> {
let bean = R.dispense("agent") as Agent; let bean = R.dispense("agent") as Agent;
bean.url = url; bean.url = url;
bean.username = username; bean.username = username;
bean.password = password; bean.password = password;
bean.name = name;
await R.store(bean); await R.store(bean);
return bean; return bean;
} }
@ -106,6 +108,23 @@ export class AgentManager {
} }
} }
/**
*
* @param url
* @param updatedName
*/
async update(url: string, updatedName: string) {
const agent = await R.findOne("agent", " url = ? ", [
url,
]);
if (agent) {
agent.name = updatedName;
await R.store(agent);
} else {
throw new Error("Agent not found");
}
}
connect(url : string, username : string, password : string) { connect(url : string, username : string, password : string) {
let obj = new URL(url); let obj = new URL(url);
let endpoint = obj.host; let endpoint = obj.host;
@ -278,6 +297,8 @@ export class AgentManager {
url: "", url: "",
username: "", username: "",
endpoint: "", endpoint: "",
name: "",
updatedName: "",
}; };
for (let endpoint in list) { for (let endpoint in list) {

View file

@ -7,6 +7,7 @@ export async function up(knex: Knex): Promise<void> {
table.string("url", 255).notNullable().unique(); table.string("url", 255).notNullable().unique();
table.string("username", 255).notNullable(); table.string("username", 255).notNullable();
table.string("password", 255).notNullable(); table.string("password", 255).notNullable();
table.string("name", 255);
table.boolean("active").notNullable().defaultTo(true); table.boolean("active").notNullable().defaultTo(true);
}); });
} }

View file

@ -23,6 +23,7 @@ export class Agent extends BeanModel {
url: this.url, url: this.url,
username: this.username, username: this.username,
endpoint: this.endpoint, endpoint: this.endpoint,
name: this.name,
}; };
} }

View file

@ -20,7 +20,7 @@ export class ManageAgentSocketHandler extends SocketHandler {
let data = requestData as LooseObject; let data = requestData as LooseObject;
let manager = socket.instanceManager; let manager = socket.instanceManager;
await manager.test(data.url, data.username, data.password); await manager.test(data.url, data.username, data.password);
await manager.add(data.url, data.username, data.password); await manager.add(data.url, data.username, data.password, data.name);
// connect to the agent // connect to the agent
manager.connect(data.url, data.username, data.password); manager.connect(data.url, data.username, data.password);
@ -66,5 +66,27 @@ export class ManageAgentSocketHandler extends SocketHandler {
callbackError(e, callback); callbackError(e, callback);
} }
}); });
// updateAgent
socket.on("updateAgent", async (name : string, updatedName : string, callback : unknown) => {
try {
log.debug("manage-agent-socket-handler", "updateAgent");
checkLogin(socket);
let manager = socket.instanceManager;
await manager.update(name, updatedName);
server.disconnectAllSocketClients(undefined, socket.id);
manager.sendAgentList();
callbackResult({
ok: true,
msg: "agentUpdatedSuccessfully",
msgi18n: true,
}, callback);
} catch (e) {
callbackError(e, callback);
}
});
} }
} }

View file

@ -11,8 +11,11 @@ declare module 'vue' {
Appearance: typeof import('./src/components/settings/Appearance.vue')['default'] Appearance: typeof import('./src/components/settings/Appearance.vue')['default']
ArrayInput: typeof import('./src/components/ArrayInput.vue')['default'] ArrayInput: typeof import('./src/components/ArrayInput.vue')['default']
ArraySelect: typeof import('./src/components/ArraySelect.vue')['default'] ArraySelect: typeof import('./src/components/ArraySelect.vue')['default']
BButton: typeof import('bootstrap-vue-next')['BButton']
BDropdown: typeof import('bootstrap-vue-next')['BDropdown'] BDropdown: typeof import('bootstrap-vue-next')['BDropdown']
BDropdownItem: typeof import('bootstrap-vue-next')['BDropdownItem'] BDropdownItem: typeof import('bootstrap-vue-next')['BDropdownItem']
BFormGroup: typeof import('bootstrap-vue-next')['BFormGroup']
BFormInput: typeof import('bootstrap-vue-next')['BFormInput']
BModal: typeof import('bootstrap-vue-next')['BModal'] BModal: typeof import('bootstrap-vue-next')['BModal']
Confirm: typeof import('./src/components/Confirm.vue')['default'] Confirm: typeof import('./src/components/Confirm.vue')['default']
Container: typeof import('./src/components/Container.vue')['default'] Container: typeof import('./src/components/Container.vue')['default']
@ -29,4 +32,7 @@ declare module 'vue' {
TwoFADialog: typeof import('./src/components/TwoFADialog.vue')['default'] TwoFADialog: typeof import('./src/components/TwoFADialog.vue')['default']
Uptime: typeof import('./src/components/Uptime.vue')['default'] Uptime: typeof import('./src/components/Uptime.vue')['default']
} }
export interface ComponentCustomProperties {
vBModal: typeof import('bootstrap-vue-next')['vBModal']
}
} }

View file

@ -114,6 +114,8 @@
"removeAgent": "Remove Agent", "removeAgent": "Remove Agent",
"removeAgentMsg": "Are you sure you want to remove this agent?", "removeAgentMsg": "Are you sure you want to remove this agent?",
"LongSyntaxNotSupported": "Long syntax is not supported here. Please use the YAML editor.", "LongSyntaxNotSupported": "Long syntax is not supported here. Please use the YAML editor.",
"name": "Dockge Agent Display name",
"updatedName": "New Dockge Agent Display name",
"Saved": "Saved", "Saved": "Saved",
"Deployed": "Deployed", "Deployed": "Deployed",
"Deleted": "Deleted", "Deleted": "Deleted",

View file

@ -131,10 +131,15 @@ export default defineComponent({
methods: { methods: {
endpointDisplayFunction(endpoint : string) { endpointDisplayFunction(endpoint : string) {
if (endpoint) { for (const [k, v] of Object.entries(this.$data.agentList)) {
return endpoint; if (endpoint) {
} else { if (endpoint === v["endpoint"] && v["name"] !== "") {
return this.$t("currentEndpoint"); return v["name"];
}
if (endpoint === v["endpoint"] && v["name"] === "" ) {
return endpoint;
}
}
} }
}, },

View file

@ -99,7 +99,7 @@
<label for="name" class="form-label">{{ $t("dockgeAgent") }}</label> <label for="name" class="form-label">{{ $t("dockgeAgent") }}</label>
<select v-model="stack.endpoint" class="form-select"> <select v-model="stack.endpoint" class="form-select">
<option v-for="(agent, endpoint) in $root.agentList" :key="endpoint" :value="endpoint" :disabled="$root.agentStatusList[endpoint] != 'online'"> <option v-for="(agent, endpoint) in $root.agentList" :key="endpoint" :value="endpoint" :disabled="$root.agentStatusList[endpoint] != 'online'">
({{ $root.agentStatusList[endpoint] }}) {{ (endpoint) ? endpoint : $t("currentEndpoint") }} ({{ $root.agentStatusList[endpoint] }}) {{ (agent.name !== '') ? agent.name : agent.url || $t("Controller") }}
</option> </option>
</select> </select>
</div> </div>

View file

@ -49,13 +49,25 @@
</template> </template>
<!-- Agent Display Name --> <!-- Agent Display Name -->
<span v-if="endpoint === ''">{{ $t("currentEndpoint") }}</span> <template v-if="$root.agentStatusList[endpoint]">
<a v-else :href="agent.url" target="_blank">{{ endpoint }}</a> <span v-if="endpoint === '' && agent.name === ''" class="badge bg-secondary me-2">Controller</span>
<span v-else-if="agent.name === ''" :href="agent.url" class="me-2">{{ endpoint }}</span>
<span v-else :href="agent.url" class="me-2">{{ agent.name }}</span>
</template>
<!-- Edit Name -->
<font-awesome-icon icon="pen-to-square" @click="showEditAgentNameDialog[agent.name] = !showEditAgentNameDialog[agent.Name]" />
<!-- Edit Dialog -->
<BModal v-model="showEditAgentNameDialog[agent.name]" :no-close-on-backdrop="true" :close-on-esc="true" :okTitle="$t('Update Name')" okVariant="info" @ok="updateName(agent.url, agent.updatedName)">
<label for="Update Name" class="form-label">Current value: {{ $t(agent.name) }}</label>
<input id="updatedName" v-model="agent.updatedName" type="text" class="form-control" optional>
</BModal>
<!-- Remove Button --> <!-- Remove Button -->
<font-awesome-icon v-if="endpoint !== ''" class="ms-2 remove-agent" icon="trash" @click="showRemoveAgentDialog[agent.url] = !showRemoveAgentDialog[agent.url]" /> <font-awesome-icon v-if="endpoint !== ''" class="ms-2 remove-agent" icon="trash" @click="showRemoveAgentDialog[agent.url] = !showRemoveAgentDialog[agent.url]" />
<!-- Remoe Agent Dialog --> <!-- Remove Agent Dialog -->
<BModal v-model="showRemoveAgentDialog[agent.url]" :okTitle="$t('removeAgent')" okVariant="danger" @ok="removeAgent(agent.url)"> <BModal v-model="showRemoveAgentDialog[agent.url]" :okTitle="$t('removeAgent')" okVariant="danger" @ok="removeAgent(agent.url)">
<p>{{ agent.url }}</p> <p>{{ agent.url }}</p>
{{ $t("removeAgentMsg") }} {{ $t("removeAgentMsg") }}
@ -81,6 +93,11 @@
<input id="password" v-model="agent.password" type="password" class="form-control" required autocomplete="new-password"> <input id="password" v-model="agent.password" type="password" class="form-control" required autocomplete="new-password">
</div> </div>
<div class="mb-3">
<label for="name" class="form-label">{{ $t("Friendly Name") }}</label>
<input id="name" v-model="agent.name" type="text" class="form-control" optional>
</div>
<button type="submit" class="btn btn-primary" :disabled="connectingAgent"> <button type="submit" class="btn btn-primary" :disabled="connectingAgent">
<template v-if="connectingAgent">{{ $t("connecting") }}</template> <template v-if="connectingAgent">{{ $t("connecting") }}</template>
<template v-else>{{ $t("connect") }}</template> <template v-else>{{ $t("connect") }}</template>
@ -121,11 +138,14 @@ export default {
dockerRunCommand: "", dockerRunCommand: "",
showAgentForm: false, showAgentForm: false,
showRemoveAgentDialog: {}, showRemoveAgentDialog: {},
showEditAgentNameDialog: {},
connectingAgent: false, connectingAgent: false,
agent: { agent: {
url: "http://", url: "http://",
username: "", username: "",
password: "", password: "",
name: "",
updatedName: "",
} }
}; };
}, },
@ -199,6 +219,19 @@ export default {
}); });
}, },
updateName(url, updatedName) {
this.$root.getSocket().emit("updateAgent", url, updatedName, (res) => {
this.$root.toastRes(res);
if (res.ok) {
this.showAgentForm = false;
this.agent = {
updatedName: "",
};
}
});
},
getStatusNum(statusName) { getStatusNum(statusName) {
let num = 0; let num = 0;
@ -286,7 +319,7 @@ export default {
} }
}, },
}, }
}; };
</script> </script>