discourse/app/assets/javascripts/admin/addon/routes/admin-backups.js
Martin Brennan 1446596089
UX: Apply admin interface guidelines to Backups page (#28051)
This commit converts the Backups page in the admin interface
to follow our new admin interface guidelines.

As part of this work, I've also made `AdminPageHeader` and `AdminPageSubheader`
components that can be reused on any admin page for consistency, that handle
the title and action buttons and also breadcrumbs.

Also renamed `AdminPluginFilteredSiteSettings` to `AdminFilteredSiteSettings` since
it can be used generally to show a subset of filtered site settings, not only
settings for a plugin. Not sure if it's ideal to have to define a new route for this
for every config area, but not sure how else to do it right now.
2024-08-20 09:59:43 +10:00

182 lines
4.9 KiB
JavaScript

import EmberObject, { action } from "@ember/object";
import { service } from "@ember/service";
import { ajax } from "discourse/lib/ajax";
import { extractError } from "discourse/lib/ajax-error";
import PreloadStore from "discourse/lib/preload-store";
import DiscourseRoute from "discourse/routes/discourse";
import getURL from "discourse-common/lib/get-url";
import { bind } from "discourse-common/utils/decorators";
import I18n from "discourse-i18n";
import StartBackupModal from "admin/components/modal/start-backup";
import Backup from "admin/models/backup";
import BackupStatus from "admin/models/backup-status";
const LOG_CHANNEL = "/admin/backups/logs";
export default class AdminBackupsRoute extends DiscourseRoute {
@service currentUser;
@service dialog;
@service router;
@service messageBus;
@service modal;
titleToken() {
return I18n.t("admin.backups.title");
}
activate() {
this.messageBus.subscribe(LOG_CHANNEL, this.onMessage);
}
deactivate() {
this.messageBus.unsubscribe(LOG_CHANNEL, this.onMessage);
}
async model() {
const status = await PreloadStore.getAndRemove("operations_status", () =>
ajax("/admin/backups/status.json")
);
return BackupStatus.create({
isOperationRunning: status.is_operation_running,
canRollback: status.can_rollback,
allowRestore: status.allow_restore,
});
}
@bind
onMessage(log) {
if (log.message === "[STARTED]") {
this.currentUser.set("hideReadOnlyAlert", true);
this.controllerFor("adminBackups").set("model.isOperationRunning", true);
this.controllerFor("adminBackupsLogs").get("logs").clear();
} else if (log.message === "[FAILED]") {
this.controllerFor("adminBackups").set("model.isOperationRunning", false);
this.dialog.alert(
I18n.t("admin.backups.operations.failed", {
operation: log.operation,
})
);
} else if (log.message === "[SUCCESS]") {
this.currentUser.set("hideReadOnlyAlert", false);
this.controllerFor("adminBackups").set("model.isOperationRunning", false);
if (log.operation === "restore") {
// redirect to homepage when the restore is done (session might be lost)
window.location = getURL("/");
}
} else {
this.controllerFor("adminBackupsLogs")
.get("logs")
.pushObject(EmberObject.create(log));
}
}
@action
showStartBackupModal() {
this.modal.show(StartBackupModal, {
model: { startBackup: this.startBackup },
});
}
@action
startBackup(withUploads) {
this.router.transitionTo("admin.backups.logs");
Backup.start(withUploads).then((result) => {
if (!result.success) {
this.dialog.alert(result.message);
}
});
}
@action
destroyBackup(backup) {
return this.dialog.yesNoConfirm({
message: I18n.t("admin.backups.operations.destroy.confirm"),
didConfirm: () => {
backup
.destroy()
.then(() =>
this.controllerFor("adminBackupsIndex")
.get("model")
.removeObject(backup)
);
},
});
}
@action
startRestore(backup) {
this.dialog.yesNoConfirm({
message: I18n.t("admin.backups.operations.restore.confirm"),
didConfirm: () => {
this.router.transitionTo("admin.backups.logs");
backup.restore();
},
});
}
@action
cancelOperation() {
this.dialog.yesNoConfirm({
message: I18n.t("admin.backups.operations.cancel.confirm"),
didConfirm: () => {
Backup.cancel().then(() => {
this.controllerFor("adminBackups").set(
"model.isOperationRunning",
false
);
});
},
});
}
@action
rollback() {
return this.dialog.yesNoConfirm({
message: I18n.t("admin.backups.operations.rollback.confirm"),
didConfirm: () => {
Backup.rollback().then((result) => {
if (!result.success) {
this.dialog.alert(result.message);
} else {
// redirect to homepage (session might be lost)
window.location = getURL("/");
}
});
},
});
}
@action
uploadSuccess(filename) {
this.dialog.alert(I18n.t("admin.backups.upload.success", { filename }));
}
@action
uploadError(filename, message) {
this.dialog.alert(
I18n.t("admin.backups.upload.error", { filename, message })
);
}
@action
remoteUploadSuccess() {
Backup.find()
.then((backups) => backups.map((backup) => Backup.create(backup)))
.then((backups) => {
this.controllerFor("adminBackupsIndex").set(
"model",
backups.map((backup) => Backup.create(backup))
);
})
.catch((error) => {
this.dialog.alert(
I18n.t("admin.backups.backup_storage_error", {
error_message: extractError(error),
})
);
return [];
});
}
}