From 9163b3d2e2274eef0994d790307f1e7d62fb9b66 Mon Sep 17 00:00:00 2001 From: Jarek Radosz Date: Sun, 22 Jan 2023 20:19:31 +0100 Subject: [PATCH] DEV: Modernize upgrade-show and repo model fixup upgrade-show controller --- .../discourse/controllers/upgrade-index.js | 2 +- .../discourse/controllers/upgrade-show.js | 179 ++++++------ .../discourse/helpers/new-commits.js | 7 +- assets/javascripts/discourse/models/repo.js | 256 +++++++++--------- .../discourse/routes/upgrade-index.js | 9 +- .../discourse/routes/upgrade-show.js | 10 +- .../discourse/templates/upgrade-show.hbs | 32 +-- .../components/repo-status-test.js | 6 +- 8 files changed, 256 insertions(+), 245 deletions(-) diff --git a/assets/javascripts/discourse/controllers/upgrade-index.js b/assets/javascripts/discourse/controllers/upgrade-index.js index dae2ae3..d3ec21f 100644 --- a/assets/javascripts/discourse/controllers/upgrade-index.js +++ b/assets/javascripts/discourse/controllers/upgrade-index.js @@ -17,7 +17,7 @@ export default Controller.extend({ ), allUpToDate: computed("model.@each.upToDate", function () { - return this.get("model").every((repo) => repo.get("upToDate")); + return this.get("model").every((repo) => repo.upToDate); }), actions: { diff --git a/assets/javascripts/discourse/controllers/upgrade-show.js b/assets/javascripts/discourse/controllers/upgrade-show.js index 2530e2a..f6db71b 100644 --- a/assets/javascripts/discourse/controllers/upgrade-show.js +++ b/assets/javascripts/discourse/controllers/upgrade-show.js @@ -1,66 +1,72 @@ import Repo from "discourse/plugins/docker_manager/discourse/models/repo"; import Controller from "@ember/controller"; -import { equal } from "@ember/object/computed"; -import { computed } from "@ember/object"; import { inject as service } from "@ember/service"; +import { tracked } from "@glimmer/tracking"; +import { equal } from "@ember/object/computed"; +import { action } from "@ember/object"; -export default Controller.extend({ - dialog: service(), +export default class UpgradeShow extends Controller { + @service messageBus; + @service dialog; - output: null, + @tracked output = ""; + @tracked status = null; + @tracked percent = 0; - init() { - this._super(); - this.reset(); - }, + @equal("status", "complete") complete; + @equal("status", "failed") failed; - complete: equal("status", "complete"), - failed: equal("status", "failed"), + get multiUpgrade() { + return this.model.length !== 1; + } - multiUpgrade: computed("model.length", function () { - return this.get("model.length") !== 1; - }), + get title() { + return this.multiUpgrade ? "All" : this.model[0].name; + } - title: computed("model.@each.name", function () { - return this.get("multiUpgrade") ? "All" : this.get("model")[0].get("name"); - }), + get isUpToDate() { + return this.model.every((repo) => repo.upToDate); + } - isUpToDate: computed("model.@each.upToDate", function () { - return this.get("model").every((repo) => repo.get("upToDate")); - }), + get upgrading() { + return this.model.some((repo) => repo.upgrading); + } - upgrading: computed("model.@each.upgrading", function () { - return this.get("model").some((repo) => repo.get("upgrading")); - }), + get repos() { + return this.isMultiple ? this.model : [this.model]; + } - repos() { - const model = this.get("model"); - return this.get("isMultiple") ? model : [model]; - }, + get upgradeButtonText() { + if (this.upgrading) { + return "Upgrading..."; + } else { + return "Start Upgrading"; + } + } updateAttribute(key, value, valueIsKey = false) { - this.get("model").forEach((repo) => { - value = valueIsKey ? repo.get(value) : value; - repo.set(key, value); + this.model.forEach((repo) => { + value = valueIsKey ? repo[value] : value; + repo[key] = value; }); - }, + } messageReceived(msg) { switch (msg.type) { case "log": - this.set("output", this.get("output") + msg.value + "\n"); + this.output = this.output + msg.value + "\n"; break; case "percent": - this.set("percent", msg.value); + this.percent = msg.value; break; case "status": - this.set("status", msg.value); + this.status = msg.value; if (msg.value === "complete") { - this.get("model") - .filter((repo) => repo.get("upgrading")) + this.model + .filter((repo) => repo.upgrading) .forEach((repo) => { - repo.set("version", repo.get("latest.version")); + repo.version = repo.latest?.version; }); } @@ -70,73 +76,68 @@ export default Controller.extend({ break; } - }, - - upgradeButtonText: computed("upgrading", function () { - if (this.get("upgrading")) { - return "Upgrading..."; - } else { - return "Start Upgrading"; - } - }), + } startBus() { this.messageBus.subscribe("/docker/upgrade", (msg) => { this.messageReceived(msg); }); - }, + } stopBus() { this.messageBus.unsubscribe("/docker/upgrade"); - }, + } reset() { - this.setProperties({ output: "", status: null, percent: 0 }); - }, + this.output = ""; + this.status = null; + this.percent = 0; + } - actions: { - start() { - this.reset(); + @action + start() { + this.reset(); - if (this.get("multiUpgrade")) { - this.get("model") - .filter((repo) => !repo.get("upToDate")) - .forEach((repo) => repo.set("upgrading", true)); - return Repo.upgradeAll(); - } + if (this.multiUpgrade) { + this.model + .filter((repo) => !repo.upToDate) + .forEach((repo) => (repo.upgrading = true)); - const repo = this.get("model")[0]; - if (repo.get("upgrading")) { - return; - } - repo.startUpgrade(); - }, + return Repo.upgradeAll(); + } - resetUpgrade() { - const message = ` - WARNING: You should only reset upgrades that have failed and are not running. + const repo = this.model[0]; + if (repo.upgrading) { + return; + } - This will NOT cancel currently running builds and should only be used as a last resort. - `; + repo.startUpgrade(); + } - this.dialog.confirm({ - message, - didConfirm: () => { - if (this.get("multiUpgrade")) { - return Repo.resetAll( - this.get("model").filter((repo) => !repo.get("upToDate")) - ).finally(() => { - this.reset(); - this.updateAttribute("upgrading", false); - }); - } + @action + resetUpgrade() { + const message = ` + WARNING: You should only reset upgrades that have failed and are not running. + This will NOT cancel currently running builds and should only be used as a last resort. + `; - const repo = this.get("model")[0]; - repo.resetUpgrade().then(() => { + this.dialog.confirm({ + message, + didConfirm: async () => { + if (this.multiUpgrade) { + try { + await Repo.resetAll(this.model.filter((repo) => !repo.upToDate)); + } finally { this.reset(); - }); - }, - }); - }, - }, -}); + this.updateAttribute("upgrading", false); + return; + } + } + + const repo = this.model[0]; + await repo.resetUpgrade(); + this.reset(); + }, + }); + } +} diff --git a/assets/javascripts/discourse/helpers/new-commits.js b/assets/javascripts/discourse/helpers/new-commits.js index 37fb5d6..034081c 100644 --- a/assets/javascripts/discourse/helpers/new-commits.js +++ b/assets/javascripts/discourse/helpers/new-commits.js @@ -1,10 +1,13 @@ import { helper as buildHelper } from "@ember/component/helper"; -import { isNone } from "@ember/utils"; import { htmlSafe } from "@ember/template"; export default buildHelper(function (params) { const [commitsBehind, oldSha, newSha, url] = params; + if (!commitsBehind) { + return ""; + } + if (parseInt(commitsBehind, 10) === 0) { return ""; } @@ -13,7 +16,7 @@ export default buildHelper(function (params) { commitsBehind === 1 ? "" : "s" }`; - if (isNone(url)) { + if (!url) { return description; } diff --git a/assets/javascripts/discourse/models/repo.js b/assets/javascripts/discourse/models/repo.js index e458851..b6eefdc 100644 --- a/assets/javascripts/discourse/models/repo.js +++ b/assets/javascripts/discourse/models/repo.js @@ -1,162 +1,176 @@ -import { default as EmberObject, computed } from "@ember/object"; -import { or } from "@ember/object/computed"; -import { isNone } from "@ember/utils"; -import { Promise } from "rsvp"; import { ajax } from "discourse/lib/ajax"; +import { tracked } from "@glimmer/tracking"; +import { TrackedObject } from "@ember-compat/tracked-built-ins"; let loaded = []; function concatVersions(repos) { - return repos.map((repo) => repo.get("version")).join(", "); + return repos.map((repo) => repo.version).join(", "); } -const Repo = EmberObject.extend({ - unloaded: true, - checking: false, +export default class Repo { + @tracked unloaded = true; + @tracked checking = false; + @tracked lastCheckedAt = null; + @tracked latest = new TrackedObject({}); - checkingStatus: or("unloaded", "checking"), - upToDate: computed("upgrading", "version", "latest.version", function () { - return ( - !this.get("upgrading") && - (this.get("version") === this.get("latest.version")) - ); - }), + // model attributes + @tracked name = null; + @tracked path = null; + @tracked branch = null; + @tracked official = false; + @tracked fork = false; + @tracked id = null; + @tracked version = null; + @tracked pretty_version = null; + @tracked url = null; + @tracked upgrading = false; - prettyVersion: computed("version", "pretty_version", function () { - return this.get("pretty_version") || this.get("version")?.substring(0, 8); - }), + constructor(attributes) { + for (const [key, value] of Object.entries(attributes)) { + this[key] = value; + } + } - prettyLatestVersion: computed("latest.{version,pretty_version}", function () { - return ( - this.get("latest.pretty_version") || - this.get("latest.version")?.substring(0, 8) - ); - }), + get checkingStatus() { + return this.unloaded || this.checking; + } + + get upToDate() { + return !this.upgrading && this.version === this.latest?.version; + } + + get prettyVersion() { + return this.pretty_version || this.version?.substring(0, 8); + } + + get prettyLatestVersion() { + return this.latest?.pretty_version || this.latest?.version?.substring(0, 8); + } get shouldCheck() { - if (isNone(this.get("version"))) { + if (this.version === null) { return false; } - if (this.get("checking")) { + + if (this.checking) { return false; } // Only check once every minute - const lastCheckedAt = this.get("lastCheckedAt"); - if (lastCheckedAt) { - const ago = new Date().getTime() - lastCheckedAt; + if (this.lastCheckedAt) { + const ago = new Date().getTime() - this.lastCheckedAt; return ago > 60 * 1000; } - return true; - }, - repoAjax(url, args) { - args = args || {}; - args.data = this.getProperties("path", "version", "branch"); + return true; + } + + repoAjax(url, args = {}) { + args.data = { + path: this.path, + version: this.version, + branch: this.branch, + }; return ajax(url, args); - }, + } - findLatest() { - return new Promise((resolve) => { - if (!this.get("shouldCheck")) { - this.set("unloaded", false); - return resolve(); - } + async findLatest() { + if (!this.shouldCheck) { + this.unloaded = false; + return; + } - this.set("checking", true); - this.repoAjax("/admin/docker/latest").then((result) => { - this.setProperties({ - unloaded: false, - checking: false, - lastCheckedAt: new Date().getTime(), - latest: EmberObject.create(result.latest), - }); - resolve(); - }); - }); - }, + this.checking = true; - findProgress() { - return this.repoAjax("/admin/docker/progress").then( - (result) => result.progress - ); - }, + const result = await this.repoAjax("/admin/docker/latest"); - resetUpgrade() { - return this.repoAjax("/admin/docker/upgrade", { + this.unloaded = false; + this.checking = false; + this.lastCheckedAt = new Date().getTime(); + + for (const [key, value] of Object.entries(result.latest)) { + this.latest[key] = value; + } + } + + async findProgress() { + const result = await this.repoAjax("/admin/docker/progress"); + return result.progress; + } + + async resetUpgrade() { + await this.repoAjax("/admin/docker/upgrade", { dataType: "text", type: "DELETE", - }).then(() => { - this.set("upgrading", false); }); - }, - startUpgrade() { - this.set("upgrading", true); + this.upgrading = false; + } - return this.repoAjax("/admin/docker/upgrade", { - dataType: "text", - type: "POST", - }).catch(() => { - this.set("upgrading", false); - }); - }, -}); + async startUpgrade() { + this.upgrading = true; -Repo.reopenClass({ - findAll() { - return new Promise((resolve) => { - if (loaded.length) { - return resolve(loaded); - } - - ajax("/admin/docker/repos").then((result) => { - loaded = result.repos.map((r) => Repo.create(r)); - resolve(loaded); + try { + await this.repoAjax("/admin/docker/upgrade", { + dataType: "text", + type: "POST", }); - }); - }, + } catch (e) { + this.upgrading = false; + } + } +} - findUpgrading() { - return this.findAll().then((result) => result.findBy("upgrading", true)); - }, +Repo.findAll = async function () { + if (loaded.length) { + return loaded; + } - find(id) { - return this.findAll().then((result) => result.findBy("id", id)); - }, + const result = await ajax("/admin/docker/repos"); + loaded = result.repos.map((r) => new Repo(r)); + return loaded; +}; - upgradeAll() { - return ajax("/admin/docker/upgrade", { - dataType: "text", - type: "POST", - data: { path: "all" }, - }); - }, +Repo.findUpgrading = async function () { + const result = await Repo.findAll(); + return result.findBy("upgrading", true); +}; - resetAll(repos) { - return ajax("/admin/docker/upgrade", { - dataType: "text", - type: "DELETE", - data: { path: "all", version: concatVersions(repos) }, - }); - }, +Repo.find = async function (id) { + const result = await Repo.findAll(); + return result.findBy("id", id); +}; - findLatestAll() { - return ajax("/admin/docker/latest", { - dataType: "text", - type: "GET", - data: { path: "all" }, - }); - }, +Repo.upgradeAll = function () { + return ajax("/admin/docker/upgrade", { + dataType: "text", + type: "POST", + data: { path: "all" }, + }); +}; - findAllProgress(repos) { - return ajax("/admin/docker/progress", { - dataType: "text", - type: "GET", - data: { path: "all", version: concatVersions(repos) }, - }); - }, -}); +Repo.resetAll = function (repos) { + return ajax("/admin/docker/upgrade", { + dataType: "text", + type: "DELETE", + data: { path: "all", version: concatVersions(repos) }, + }); +}; -export default Repo; +Repo.findLatestAll = function () { + return ajax("/admin/docker/latest", { + dataType: "text", + type: "GET", + data: { path: "all" }, + }); +}; + +Repo.findAllProgress = function (repos) { + return ajax("/admin/docker/progress", { + dataType: "text", + type: "GET", + data: { path: "all", version: concatVersions(repos) }, + }); +}; diff --git a/assets/javascripts/discourse/routes/upgrade-index.js b/assets/javascripts/discourse/routes/upgrade-index.js index 93ff75c..3939857 100644 --- a/assets/javascripts/discourse/routes/upgrade-index.js +++ b/assets/javascripts/discourse/routes/upgrade-index.js @@ -22,20 +22,17 @@ export default Route.extend({ controller.setProperties({ model, upgrading: null }); model.forEach((repo) => { - if (repo.get("upgrading")) { + if (repo.upgrading) { controller.set("upgrading", repo); } // Special case: Upgrade docker manager first - if (repo.get("id") === "docker_manager") { + if (repo.id === "docker_manager") { controller.set("managerRepo", repo); } // Special case: If the branch is "main" warn user - if ( - repo.get("id") === "discourse" && - repo.get("branch") === "origin/main" - ) { + if (repo.id === "discourse" && repo.branch === "origin/main") { upgradeController.appendBannerHtml(` WARNING: Your Discourse is tracking the 'main' branch which may be unstable, diff --git a/assets/javascripts/discourse/routes/upgrade-show.js b/assets/javascripts/discourse/routes/upgrade-show.js index fdde47f..af89602 100644 --- a/assets/javascripts/discourse/routes/upgrade-show.js +++ b/assets/javascripts/discourse/routes/upgrade-show.js @@ -1,6 +1,5 @@ import Repo from "discourse/plugins/docker_manager/discourse/models/repo"; import Route from "@ember/routing/route"; -import EmberObject from "@ember/object"; import { Promise } from "rsvp"; export default Route.extend({ @@ -15,16 +14,19 @@ export default Route.extend({ if (Array.isArray(model)) { return Repo.findLatestAll().then((response) => { JSON.parse(response).repos.forEach((_repo) => { - const repo = model.find((repo) => repo.get("path") === _repo.path); + const repo = model.find((repo) => repo.path === _repo.path); if (!repo) { return; } delete _repo.path; - repo.set("latest", EmberObject.create(_repo)); + + for (const [key, value] of Object.entries(_repo)) { + repo.latest[key] = value; + } }); return Repo.findAllProgress( - model.filter((repo) => !repo.get("upToDate")) + model.filter((repo) => !repo.upToDate) ).then((progress) => { this.set("progress", JSON.parse(progress).progress); }); diff --git a/assets/javascripts/discourse/templates/upgrade-show.hbs b/assets/javascripts/discourse/templates/upgrade-show.hbs index 164df9a..5e988bb 100644 --- a/assets/javascripts/discourse/templates/upgrade-show.hbs +++ b/assets/javascripts/discourse/templates/upgrade-show.hbs @@ -1,33 +1,29 @@ -

Upgrade {{title}}

+

Upgrade {{this.title}}

-{{#if complete}} +{{#if this.complete}}

Upgrade completed successfully!

-{{/if}} - -{{#if failed}} +{{else if this.failed}}

Sorry, there was an error upgrading Discourse. Please check the logs below.

{{/if}} -{{#if isUpToDate}} - {{#unless multiUpgrade}} -

{{title}} is at the newest version.

+{{#if this.isUpToDate}} + {{#unless this.multiUpgrade}} +

{{this.title}} is at the newest version.

{{else}}

Everything is up-to-date.

{{/unless}} {{else}} -
- + - {{#if upgrading}} - - {{/if}} -
+ {{#if this.upgrading}} + + {{/if}} {{/if}} diff --git a/test/javascripts/integration/components/repo-status-test.js b/test/javascripts/integration/components/repo-status-test.js index b54ea82..ebe4504 100644 --- a/test/javascripts/integration/components/repo-status-test.js +++ b/test/javascripts/integration/components/repo-status-test.js @@ -4,8 +4,7 @@ import { find, render } from "@ember/test-helpers"; import hbs from "htmlbars-inline-precompile"; import Repo from "discourse/plugins/docker_manager/discourse/models/repo"; -const repoObject = Repo.create({ - unloaded: false, +const repoObject = new Repo({ branch: "origin/main", id: "discourse", name: "discourse", @@ -23,8 +22,7 @@ const repoObject = Repo.create({ }, }); -const managerRepo = Repo.create({ - unloaded: false, +const managerRepo = new Repo({ branch: "origin/main", id: "docker_manager", name: "docker_manager",