feat: Implement stateful admin update with post-restart context, database migrations, and dedicated view components.
This commit is contained in:
100
src/modules/admin/update.view.ts
Normal file
100
src/modules/admin/update.view.ts
Normal file
@@ -0,0 +1,100 @@
|
||||
import { ActionRowBuilder, ButtonBuilder, ButtonStyle } from "discord.js";
|
||||
import { createInfoEmbed, createSuccessEmbed, createWarningEmbed, createErrorEmbed } from "@lib/embeds";
|
||||
|
||||
// Constants for UI
|
||||
const LOG_TRUNCATE_LENGTH = 1000;
|
||||
const OUTPUT_TRUNCATE_LENGTH = 500;
|
||||
|
||||
function truncate(text: string, maxLength: number): string {
|
||||
return text.length > maxLength ? `${text.substring(0, maxLength)}\n...and more` : text;
|
||||
}
|
||||
|
||||
export function getCheckingEmbed() {
|
||||
return createInfoEmbed("Checking for updates...", "System Update");
|
||||
}
|
||||
|
||||
export function getNoUpdatesEmbed() {
|
||||
return createSuccessEmbed("The bot is already up to date.", "No Updates Found");
|
||||
}
|
||||
|
||||
export function getUpdatesAvailableMessage(branch: string, log: string, force: boolean) {
|
||||
const embed = createInfoEmbed(
|
||||
`**Branch:** \`${branch}\`\n\n**Pending Changes:**\n\`\`\`\n${truncate(log, LOG_TRUNCATE_LENGTH)}\n\`\`\`\n**Do you want to proceed?**`,
|
||||
"Updates Available"
|
||||
);
|
||||
|
||||
const confirmButton = new ButtonBuilder()
|
||||
.setCustomId("confirm_update")
|
||||
.setLabel(force ? "Force Update & Restart" : "Update & Restart")
|
||||
.setStyle(force ? ButtonStyle.Danger : ButtonStyle.Success);
|
||||
|
||||
const cancelButton = new ButtonBuilder()
|
||||
.setCustomId("cancel_update")
|
||||
.setLabel("Cancel")
|
||||
.setStyle(ButtonStyle.Secondary);
|
||||
|
||||
const row = new ActionRowBuilder<ButtonBuilder>()
|
||||
.addComponents(confirmButton, cancelButton);
|
||||
|
||||
return { embeds: [embed], components: [row] };
|
||||
}
|
||||
|
||||
export function getPreparingEmbed() {
|
||||
return createInfoEmbed("⏳ Preparing update...", "Update In Progress");
|
||||
}
|
||||
|
||||
export function getUpdatingEmbed(needsDependencyInstall: boolean) {
|
||||
const message = `Downloading and applying updates...${needsDependencyInstall ? `\nExpect a slightly longer startup for dependency installation.` : ""}\nThe system will restart automatically.`;
|
||||
return createWarningEmbed(message, "Updating & Restarting");
|
||||
}
|
||||
|
||||
export function getCancelledEmbed() {
|
||||
return createInfoEmbed("Update cancelled.", "Cancelled");
|
||||
}
|
||||
|
||||
export function getTimeoutEmbed() {
|
||||
return createWarningEmbed("Update confirmation timed out.", "Timed Out");
|
||||
}
|
||||
|
||||
export function getErrorEmbed(error: unknown) {
|
||||
const message = error instanceof Error ? error.message : String(error);
|
||||
return createErrorEmbed(`Failed to update:\n\`\`\`\n${message}\n\`\`\``, "Update Failed");
|
||||
}
|
||||
|
||||
export interface PostRestartResult {
|
||||
installSuccess: boolean;
|
||||
installOutput: string;
|
||||
migrationSuccess: boolean;
|
||||
migrationOutput: string;
|
||||
ranInstall: boolean;
|
||||
ranMigrations: boolean;
|
||||
}
|
||||
|
||||
export function getPostRestartEmbed(result: PostRestartResult) {
|
||||
const parts: string[] = ["System updated successfully."];
|
||||
|
||||
if (result.ranInstall) {
|
||||
parts.push(`**Dependencies:** ${result.installSuccess ? "✅ Installed" : "❌ Failed"}`);
|
||||
}
|
||||
|
||||
if (result.ranMigrations) {
|
||||
parts.push(`**Migrations:** ${result.migrationSuccess ? "✅ Applied" : "❌ Failed"}`);
|
||||
}
|
||||
|
||||
if (result.installOutput) {
|
||||
parts.push(`\n**Install Output:**\n\`\`\`\n${truncate(result.installOutput, OUTPUT_TRUNCATE_LENGTH)}\n\`\`\``);
|
||||
}
|
||||
|
||||
if (result.migrationOutput) {
|
||||
parts.push(`\n**Migration Output:**\n\`\`\`\n${truncate(result.migrationOutput, OUTPUT_TRUNCATE_LENGTH)}\n\`\`\``);
|
||||
}
|
||||
|
||||
const isSuccess = result.installSuccess && result.migrationSuccess;
|
||||
const title = isSuccess ? "Update Complete" : "Update Completed with Errors";
|
||||
|
||||
return createSuccessEmbed(parts.join("\n"), title);
|
||||
}
|
||||
|
||||
export function getInstallingDependenciesEmbed() {
|
||||
return createSuccessEmbed("Installing dependencies...", "Post-Update Action");
|
||||
}
|
||||
Reference in New Issue
Block a user