diff --git a/scm-ui-components/packages/ui-types/src/Plugin.js b/scm-ui-components/packages/ui-types/src/Plugin.js index 0f9694b5fb..c7612a8bf8 100644 --- a/scm-ui-components/packages/ui-types/src/Plugin.js +++ b/scm-ui-components/packages/ui-types/src/Plugin.js @@ -11,6 +11,7 @@ export type Plugin = { category: string, avatarUrl: string, pending: boolean, + markedForUninstall?: boolean, dependencies: string[], _links: Links }; @@ -31,5 +32,6 @@ export type PendingPlugins = { _embedded: { new: [], update: [], + uninstall: [] } } diff --git a/scm-ui/public/locales/de/admin.json b/scm-ui/public/locales/de/admin.json index d2cd2c6640..69b1ed26de 100644 --- a/scm-ui/public/locales/de/admin.json +++ b/scm-ui/public/locales/de/admin.json @@ -34,15 +34,19 @@ "modal": { "title": { "install": "{{name}} Plugin installieren", - "update": "{{name}} Plugin aktualisieren" + "update": "{{name}} Plugin aktualisieren", + "uninstall": "{{name}} Plugin deinstallieren" }, "restart": "Neustarten um Plugin zu aktivieren", "install": "Installieren", "update": "Aktualisieren", + "uninstall": "Deinstallieren", "installQueue": "Werden installiert:", "updateQueue": "Werden aktualisiert:", + "uninstallQueue": "Werden deinstalliert:", "installAndRestart": "Installieren und Neustarten", "updateAndRestart": "Aktualisieren und Neustarten", + "uninstallAndRestart": "Deinstallieren and Neustarten", "executeAndRestart": "Ausführen und Neustarten", "abort": "Abbrechen", "author": "Autor", diff --git a/scm-ui/public/locales/en/admin.json b/scm-ui/public/locales/en/admin.json index 63f6089b09..47edd1f2d7 100644 --- a/scm-ui/public/locales/en/admin.json +++ b/scm-ui/public/locales/en/admin.json @@ -34,15 +34,19 @@ "modal": { "title": { "install": "Install {{name}} Plugin", - "update": "Update {{name}} Plugin" + "update": "Update {{name}} Plugin", + "uninstall": "Uninstall {{name}} Plugin" }, "restart": "Restart to activate", "install": "Install", "update": "Update", + "uninstall": "Uninstall", "installQueue": "Will be installed:", "updateQueue": "Will be updated:", + "uninstallQueue": "Will be uninstalled:", "installAndRestart": "Install and Restart", "updateAndRestart": "Update and Restart", + "uninstallAndRestart": "Uninstall and Restart", "executeAndRestart": "Execute and Restart", "abort": "Abort", "author": "Author", diff --git a/scm-ui/src/admin/plugins/components/ExecutePendingModal.js b/scm-ui/src/admin/plugins/components/ExecutePendingModal.js index 673ddd18cb..b559413d2b 100644 --- a/scm-ui/src/admin/plugins/components/ExecutePendingModal.js +++ b/scm-ui/src/admin/plugins/components/ExecutePendingModal.js @@ -86,11 +86,9 @@ class ExecutePendingModal extends React.Component { <> {t("plugins.modal.installQueue")} )} @@ -107,11 +105,28 @@ class ExecutePendingModal extends React.Component { <> {t("plugins.modal.updateQueue")} + + )} + + ); + }; + + renderUninstallQueue = () => { + const { pendingPlugins, t } = this.props; + return ( + <> + {pendingPlugins._embedded && + pendingPlugins._embedded.uninstall.length > 0 && ( + <> + {t("plugins.modal.uninstallQueue")} + )} @@ -128,6 +143,7 @@ class ExecutePendingModal extends React.Component {

{t("plugins.modal.executePending")}

{this.renderInstallQueue()} {this.renderUpdateQueue()} + {this.renderUninstallQueue()}
{this.renderNotifications()}
diff --git a/scm-ui/src/admin/plugins/components/PluginEntry.js b/scm-ui/src/admin/plugins/components/PluginEntry.js index 0d17af0475..7785c04a35 100644 --- a/scm-ui/src/admin/plugins/components/PluginEntry.js +++ b/scm-ui/src/admin/plugins/components/PluginEntry.js @@ -7,10 +7,10 @@ import PluginAvatar from "./PluginAvatar"; import classNames from "classnames"; import PluginModal from "./PluginModal"; - const PluginAction = { INSTALL: "install", - UPDATE: "update" + UPDATE: "update", + UNINSTALL: "uninstall" }; type Props = { @@ -22,7 +22,9 @@ type Props = { }; type State = { - showModal: boolean + showInstallModal: boolean, + showUpdateModal: boolean, + showUninstallModal: boolean }; const styles = { @@ -45,6 +47,12 @@ const styles = { "& .level": { paddingBottom: "0.5rem" } + }, + actionbar: { + display: "flex", + "& span + span": { + marginLeft: "0.5rem" + } } }; @@ -53,7 +61,9 @@ class PluginEntry extends React.Component { super(props); this.state = { - showModal: false + showInstallModal: false, + showUpdateModal: false, + showUninstallModal: false }; } @@ -61,10 +71,9 @@ class PluginEntry extends React.Component { return ; }; - toggleModal = () => { - this.setState(prevState => ({ - showModal: !prevState.showModal - })); + toggleModal = (showModal: string) => { + const oldValue = this.state[showModal]; + this.setState({ [showModal]: !oldValue }); }; createFooterRight = (plugin: Plugin) => { @@ -81,72 +90,100 @@ class PluginEntry extends React.Component { return plugin._links && plugin._links.update && plugin._links.update.href; }; + isUninstallable = () => { + const { plugin } = this.props; + return ( + plugin._links && plugin._links.uninstall && plugin._links.uninstall.href + ); + }; + createActionbar = () => { const { classes } = this.props; - if (this.isInstallable()) { - return ( - - - - ); - } else if (this.isUpdatable()) { - return ( - - - - ); - } + return ( +
+ {this.isInstallable() && ( + this.toggleModal("showInstallModal")} + > + + + )} + {this.isUninstallable() && ( + this.toggleModal("showUninstallModal")} + > + + + )} + {this.isUpdatable() && ( + this.toggleModal("showUpdateModal")} + > + + + )} +
+ ); }; renderModal = () => { const { plugin, refresh } = this.props; - if (this.isInstallable()) { + if (this.state.showInstallModal && this.isInstallable()) { return ( this.toggleModal("showInstallModal")} /> ); - } else if (this.isUpdatable()) { + } else if (this.state.showUpdateModal && this.isUpdatable()) { return ( this.toggleModal("showUpdateModal")} /> ); + } else if (this.state.showUninstallModal && this.isUninstallable()) { + return ( + this.toggleModal("showUninstallModal")} + /> + ); + } else { + return null; } }; createPendingSpinner = () => { const { plugin, classes } = this.props; - if (plugin.pending) { - return ( - - - - ); - } - return null; + return ( + + + + ); }; render() { const { plugin, classes } = this.props; - const { showModal } = this.state; const avatar = this.createAvatar(plugin); const actionbar = this.createActionbar(); const footerRight = this.createFooterRight(plugin); - const modal = showModal ? this.renderModal() : null; + const modal = this.renderModal(); return ( <> @@ -157,7 +194,9 @@ class PluginEntry extends React.Component { title={plugin.displayName ? plugin.displayName : plugin.name} description={plugin.description} contentRight={ - plugin.pending ? this.createPendingSpinner() : actionbar + plugin.pending || plugin.markedForUninstall + ? this.createPendingSpinner() + : actionbar } footerRight={footerRight} /> diff --git a/scm-ui/src/admin/plugins/components/PluginModal.js b/scm-ui/src/admin/plugins/components/PluginModal.js index 024a9cf32e..0d48fc8ea0 100644 --- a/scm-ui/src/admin/plugins/components/PluginModal.js +++ b/scm-ui/src/admin/plugins/components/PluginModal.js @@ -103,6 +103,8 @@ class PluginModal extends React.Component { pluginActionLink = plugin._links.install.href; } else if (pluginAction === "update") { pluginActionLink = plugin._links.update.href; + } else if (pluginAction === "uninstall") { + pluginActionLink = plugin._links.uninstall.href; } return pluginActionLink + "?restart=" + restart.toString(); }; @@ -256,49 +258,48 @@ class PluginModal extends React.Component { )} - {pluginAction === "update" && ( - <> -
-
- {t("plugins.modal.currentVersion")}: -
-
- {plugin.version} -
+ {(pluginAction === "update" || pluginAction === "uninstall") && ( +
+
+ {t("plugins.modal.currentVersion")}:
-
-
- {t("plugins.modal.newVersion")}: -
-
- {plugin.newVersion} -
+
+ {plugin.version}
- +
+ )} + {pluginAction === "update" && ( +
+
+ {t("plugins.modal.newVersion")}: +
+
+ {plugin.newVersion} +
+
)} - {this.renderDependencies()}