mirror of
https://github.com/scm-manager/scm-manager.git
synced 2025-11-13 08:55:44 +01:00
create abstract pluginModal dialog for all plugin actions to avoid duplicate code
This commit is contained in:
@@ -5,8 +5,13 @@ import type { Plugin } from "@scm-manager/ui-types";
|
|||||||
import { CardColumn } from "@scm-manager/ui-components";
|
import { CardColumn } from "@scm-manager/ui-components";
|
||||||
import PluginAvatar from "./PluginAvatar";
|
import PluginAvatar from "./PluginAvatar";
|
||||||
import classNames from "classnames";
|
import classNames from "classnames";
|
||||||
import InstallPluginModal from "./InstallPluginModal";
|
import PluginModal from "./PluginModal";
|
||||||
import UpdatePluginModal from "./UpdatePluginModal";
|
|
||||||
|
|
||||||
|
const PluginAction = {
|
||||||
|
INSTALL: "install",
|
||||||
|
UPDATE: "update"
|
||||||
|
};
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
plugin: Plugin,
|
plugin: Plugin,
|
||||||
@@ -103,16 +108,18 @@ class PluginEntry extends React.Component<Props, State> {
|
|||||||
const { plugin, refresh } = this.props;
|
const { plugin, refresh } = this.props;
|
||||||
if (this.isInstallable()) {
|
if (this.isInstallable()) {
|
||||||
return (
|
return (
|
||||||
<InstallPluginModal
|
<PluginModal
|
||||||
plugin={plugin}
|
plugin={plugin}
|
||||||
|
pluginAction={PluginAction.INSTALL}
|
||||||
refresh={refresh}
|
refresh={refresh}
|
||||||
onClose={this.toggleModal}
|
onClose={this.toggleModal}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
} else if (this.isUpdatable()) {
|
} else if (this.isUpdatable()) {
|
||||||
return (
|
return (
|
||||||
<UpdatePluginModal
|
<PluginModal
|
||||||
plugin={plugin}
|
plugin={plugin}
|
||||||
|
pluginAction={PluginAction.UPDATE}
|
||||||
refresh={refresh}
|
refresh={refresh}
|
||||||
onClose={this.toggleModal}
|
onClose={this.toggleModal}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ import SuccessNotification from "./SuccessNotification";
|
|||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
plugin: Plugin,
|
plugin: Plugin,
|
||||||
|
pluginAction: string,
|
||||||
refresh: () => void,
|
refresh: () => void,
|
||||||
onClose: () => void,
|
onClose: () => void,
|
||||||
|
|
||||||
@@ -37,15 +38,20 @@ type State = {
|
|||||||
const styles = {
|
const styles = {
|
||||||
userLabelAlignment: {
|
userLabelAlignment: {
|
||||||
textAlign: "left",
|
textAlign: "left",
|
||||||
marginRight: 0,
|
marginRight: 0
|
||||||
|
},
|
||||||
|
userLabelMarginSmall: {
|
||||||
minWidth: "5.5em"
|
minWidth: "5.5em"
|
||||||
},
|
},
|
||||||
|
userLabelMarginLarge: {
|
||||||
|
minWidth: "9em"
|
||||||
|
},
|
||||||
userFieldFlex: {
|
userFieldFlex: {
|
||||||
flexGrow: 4
|
flexGrow: 4
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class InstallPluginModal extends React.Component<Props, State> {
|
class PluginModal extends React.Component<Props, State> {
|
||||||
constructor(props: Props) {
|
constructor(props: Props) {
|
||||||
super(props);
|
super(props);
|
||||||
this.state = {
|
this.state = {
|
||||||
@@ -55,7 +61,7 @@ class InstallPluginModal extends React.Component<Props, State> {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
onInstallSuccess = () => {
|
onSuccess = () => {
|
||||||
const { restart } = this.state;
|
const { restart } = this.state;
|
||||||
const { refresh, onClose } = this.props;
|
const { refresh, onClose } = this.props;
|
||||||
|
|
||||||
@@ -87,16 +93,28 @@ class InstallPluginModal extends React.Component<Props, State> {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
install = (e: Event) => {
|
createPluginActionLink = () => {
|
||||||
|
const { plugin, pluginAction } = this.props;
|
||||||
const { restart } = this.state;
|
const { restart } = this.state;
|
||||||
const { plugin } = this.props;
|
|
||||||
|
let pluginActionLink = "";
|
||||||
|
|
||||||
|
if (pluginAction === "install") {
|
||||||
|
pluginActionLink = plugin._links.install.href;
|
||||||
|
} else if (pluginAction === "update") {
|
||||||
|
pluginActionLink = plugin._links.update.href;
|
||||||
|
}
|
||||||
|
return pluginActionLink + "?restart=" + restart.toString();
|
||||||
|
};
|
||||||
|
|
||||||
|
handlePluginAction = (e: Event) => {
|
||||||
this.setState({
|
this.setState({
|
||||||
loading: true
|
loading: true
|
||||||
});
|
});
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
apiClient
|
apiClient
|
||||||
.post(plugin._links.install.href + "?restart=" + restart.toString())
|
.post(this.createPluginActionLink())
|
||||||
.then(this.onInstallSuccess)
|
.then(this.onSuccess)
|
||||||
.catch(error => {
|
.catch(error => {
|
||||||
this.setState({
|
this.setState({
|
||||||
loading: false,
|
loading: false,
|
||||||
@@ -106,21 +124,21 @@ class InstallPluginModal extends React.Component<Props, State> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
footer = () => {
|
footer = () => {
|
||||||
const { onClose, t } = this.props;
|
const { pluginAction, onClose, t } = this.props;
|
||||||
const { loading, error, restart, success } = this.state;
|
const { loading, error, restart, success } = this.state;
|
||||||
|
|
||||||
let color = "primary";
|
let color = "primary";
|
||||||
let label = "plugins.modal.install";
|
let label = `plugins.modal.${pluginAction}`;
|
||||||
if (restart) {
|
if (restart) {
|
||||||
color = "warning";
|
color = "warning";
|
||||||
label = "plugins.modal.installAndRestart";
|
label = `plugins.modal.${pluginAction}AndRestart`;
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<ButtonGroup>
|
<ButtonGroup>
|
||||||
<Button
|
<Button
|
||||||
label={t(label)}
|
label={t(label)}
|
||||||
color={color}
|
color={color}
|
||||||
action={this.install}
|
action={this.handlePluginAction}
|
||||||
loading={loading}
|
loading={loading}
|
||||||
disabled={!!error || success}
|
disabled={!!error || success}
|
||||||
/>
|
/>
|
||||||
@@ -185,7 +203,7 @@ class InstallPluginModal extends React.Component<Props, State> {
|
|||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { restart } = this.state;
|
const { restart } = this.state;
|
||||||
const { plugin, onClose, classes, t } = this.props;
|
const { plugin, pluginAction, onClose, classes, t } = this.props;
|
||||||
|
|
||||||
const body = (
|
const body = (
|
||||||
<>
|
<>
|
||||||
@@ -200,6 +218,9 @@ class InstallPluginModal extends React.Component<Props, State> {
|
|||||||
<div
|
<div
|
||||||
className={classNames(
|
className={classNames(
|
||||||
classes.userLabelAlignment,
|
classes.userLabelAlignment,
|
||||||
|
pluginAction === "install"
|
||||||
|
? classes.userLabelMarginSmall
|
||||||
|
: classes.userLabelMarginLarge,
|
||||||
"field-label is-inline-flex"
|
"field-label is-inline-flex"
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
@@ -214,10 +235,12 @@ class InstallPluginModal extends React.Component<Props, State> {
|
|||||||
{plugin.author}
|
{plugin.author}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
{pluginAction === "install" && (
|
||||||
<div className="field is-horizontal">
|
<div className="field is-horizontal">
|
||||||
<div
|
<div
|
||||||
className={classNames(
|
className={classNames(
|
||||||
classes.userLabelAlignment,
|
classes.userLabelAlignment,
|
||||||
|
classes.userLabelMarginSmall,
|
||||||
"field-label is-inline-flex"
|
"field-label is-inline-flex"
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
@@ -232,6 +255,49 @@ class InstallPluginModal extends React.Component<Props, State> {
|
|||||||
{plugin.version}
|
{plugin.version}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
)}
|
||||||
|
{pluginAction === "update" && (
|
||||||
|
<>
|
||||||
|
<div className="field is-horizontal">
|
||||||
|
<div
|
||||||
|
className={classNames(
|
||||||
|
classes.userLabelAlignment,
|
||||||
|
classes.userLabelMarginLarge,
|
||||||
|
"field-label is-inline-flex"
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
{t("plugins.modal.currentVersion")}:
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
className={classNames(
|
||||||
|
classes.userFieldFlex,
|
||||||
|
"field-body is-inline-flex"
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
{plugin.version}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="field is-horizontal">
|
||||||
|
<div
|
||||||
|
className={classNames(
|
||||||
|
classes.userLabelAlignment,
|
||||||
|
classes.userLabelMarginLarge,
|
||||||
|
"field-label is-inline-flex"
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
{t("plugins.modal.newVersion")}:
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
className={classNames(
|
||||||
|
classes.userFieldFlex,
|
||||||
|
"field-body is-inline-flex"
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
{plugin.newVersion}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
|
||||||
{this.renderDependencies()}
|
{this.renderDependencies()}
|
||||||
</div>
|
</div>
|
||||||
@@ -252,7 +318,7 @@ class InstallPluginModal extends React.Component<Props, State> {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Modal
|
<Modal
|
||||||
title={t("plugins.modal.title.install", {
|
title={t(`plugins.modal.title.${pluginAction}`, {
|
||||||
name: plugin.displayName ? plugin.displayName : plugin.name
|
name: plugin.displayName ? plugin.displayName : plugin.name
|
||||||
})}
|
})}
|
||||||
closeFunction={() => onClose()}
|
closeFunction={() => onClose()}
|
||||||
@@ -267,4 +333,4 @@ class InstallPluginModal extends React.Component<Props, State> {
|
|||||||
export default compose(
|
export default compose(
|
||||||
injectSheet(styles),
|
injectSheet(styles),
|
||||||
translate("admin")
|
translate("admin")
|
||||||
)(InstallPluginModal);
|
)(PluginModal);
|
||||||
@@ -1,288 +0,0 @@
|
|||||||
//@flow
|
|
||||||
import React from "react";
|
|
||||||
import { compose } from "redux";
|
|
||||||
import { translate } from "react-i18next";
|
|
||||||
import injectSheet from "react-jss";
|
|
||||||
import type { Plugin } from "@scm-manager/ui-types";
|
|
||||||
import {
|
|
||||||
apiClient,
|
|
||||||
Button,
|
|
||||||
ButtonGroup,
|
|
||||||
Checkbox,
|
|
||||||
ErrorNotification,
|
|
||||||
Modal,
|
|
||||||
Notification
|
|
||||||
} from "@scm-manager/ui-components";
|
|
||||||
import classNames from "classnames";
|
|
||||||
import waitForRestart from "./waitForRestart";
|
|
||||||
import SuccessNotification from "./SuccessNotification";
|
|
||||||
|
|
||||||
type Props = {
|
|
||||||
plugin: Plugin,
|
|
||||||
refresh: () => void,
|
|
||||||
onClose: () => void,
|
|
||||||
|
|
||||||
// context props
|
|
||||||
classes: any,
|
|
||||||
t: (key: string, params?: Object) => string
|
|
||||||
};
|
|
||||||
|
|
||||||
type State = {
|
|
||||||
success: boolean,
|
|
||||||
restart: boolean,
|
|
||||||
loading: boolean,
|
|
||||||
error?: Error
|
|
||||||
};
|
|
||||||
|
|
||||||
const styles = {
|
|
||||||
userLabelAlignment: {
|
|
||||||
textAlign: "left",
|
|
||||||
marginRight: 0,
|
|
||||||
minWidth: "9em"
|
|
||||||
},
|
|
||||||
userFieldFlex: {
|
|
||||||
flexGrow: 4
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
class UpdatePluginModal extends React.Component<Props, State> {
|
|
||||||
constructor(props: Props) {
|
|
||||||
super(props);
|
|
||||||
this.state = {
|
|
||||||
loading: false,
|
|
||||||
restart: false,
|
|
||||||
success: false
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
onUpdateSuccess = () => {
|
|
||||||
const { restart } = this.state;
|
|
||||||
const { refresh, onClose } = this.props;
|
|
||||||
|
|
||||||
const newState = {
|
|
||||||
loading: false,
|
|
||||||
error: undefined
|
|
||||||
};
|
|
||||||
|
|
||||||
if (restart) {
|
|
||||||
waitForRestart()
|
|
||||||
.then(() => {
|
|
||||||
this.setState({
|
|
||||||
...newState,
|
|
||||||
success: true
|
|
||||||
});
|
|
||||||
})
|
|
||||||
.catch(error => {
|
|
||||||
this.setState({
|
|
||||||
loading: false,
|
|
||||||
success: false,
|
|
||||||
error
|
|
||||||
});
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
this.setState(newState, () => {
|
|
||||||
refresh();
|
|
||||||
onClose();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
update = (e: Event) => {
|
|
||||||
const { restart } = this.state;
|
|
||||||
const { plugin } = this.props;
|
|
||||||
this.setState({
|
|
||||||
loading: true
|
|
||||||
});
|
|
||||||
e.preventDefault();
|
|
||||||
apiClient
|
|
||||||
.post(plugin._links.update.href + "?restart=" + restart.toString())
|
|
||||||
.then(this.onUpdateSuccess)
|
|
||||||
.catch(error => {
|
|
||||||
this.setState({
|
|
||||||
loading: false,
|
|
||||||
error: error
|
|
||||||
});
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
footer = () => {
|
|
||||||
const { onClose, t } = this.props;
|
|
||||||
const { loading, error, restart, success } = this.state;
|
|
||||||
|
|
||||||
let color = "primary";
|
|
||||||
let label = "plugins.modal.update";
|
|
||||||
if (restart) {
|
|
||||||
color = "warning";
|
|
||||||
label = "plugins.modal.updateAndRestart";
|
|
||||||
}
|
|
||||||
return (
|
|
||||||
<ButtonGroup>
|
|
||||||
<Button
|
|
||||||
label={t(label)}
|
|
||||||
color={color}
|
|
||||||
action={this.update}
|
|
||||||
loading={loading}
|
|
||||||
disabled={!!error || success}
|
|
||||||
/>
|
|
||||||
<Button label={t("plugins.modal.abort")} action={onClose} />
|
|
||||||
</ButtonGroup>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
renderDependencies() {
|
|
||||||
const { plugin, classes, t } = this.props;
|
|
||||||
|
|
||||||
let dependencies = null;
|
|
||||||
if (plugin.dependencies && plugin.dependencies.length > 0) {
|
|
||||||
dependencies = (
|
|
||||||
<div className="media">
|
|
||||||
<Notification type="warning">
|
|
||||||
<strong>{t("plugins.modal.dependencyNotification")}</strong>
|
|
||||||
<ul className={classes.listSpacing}>
|
|
||||||
{plugin.dependencies.map((dependency, index) => {
|
|
||||||
return <li key={index}>{dependency}</li>;
|
|
||||||
})}
|
|
||||||
</ul>
|
|
||||||
</Notification>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return dependencies;
|
|
||||||
}
|
|
||||||
|
|
||||||
renderNotifications = () => {
|
|
||||||
const { t } = this.props;
|
|
||||||
const { restart, error, success } = this.state;
|
|
||||||
if (error) {
|
|
||||||
return (
|
|
||||||
<div className="media">
|
|
||||||
<ErrorNotification error={error} />
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
} else if (success) {
|
|
||||||
return (
|
|
||||||
<div className="media">
|
|
||||||
<SuccessNotification />
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
} else if (restart) {
|
|
||||||
return (
|
|
||||||
<div className="media">
|
|
||||||
<Notification type="warning">
|
|
||||||
{t("plugins.modal.restartNotification")}
|
|
||||||
</Notification>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
};
|
|
||||||
|
|
||||||
handleRestartChange = (value: boolean) => {
|
|
||||||
this.setState({
|
|
||||||
restart: value
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const { restart } = this.state;
|
|
||||||
const { plugin, onClose, classes, t } = this.props;
|
|
||||||
|
|
||||||
const body = (
|
|
||||||
<>
|
|
||||||
<div className="media">
|
|
||||||
<div className="media-content">
|
|
||||||
<p>{plugin.description}</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="media">
|
|
||||||
<div className="media-content">
|
|
||||||
<div className="field is-horizontal">
|
|
||||||
<div
|
|
||||||
className={classNames(
|
|
||||||
classes.userLabelAlignment,
|
|
||||||
"field-label is-inline-flex"
|
|
||||||
)}
|
|
||||||
>
|
|
||||||
{t("plugins.modal.author")}:
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
className={classNames(
|
|
||||||
classes.userFieldFlex,
|
|
||||||
"field-body is-inline-flex"
|
|
||||||
)}
|
|
||||||
>
|
|
||||||
{plugin.author}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="field is-horizontal">
|
|
||||||
<div
|
|
||||||
className={classNames(
|
|
||||||
classes.userLabelAlignment,
|
|
||||||
"field-label is-inline-flex"
|
|
||||||
)}
|
|
||||||
>
|
|
||||||
{t("plugins.modal.currentVersion")}:
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
className={classNames(
|
|
||||||
classes.userFieldFlex,
|
|
||||||
"field-body is-inline-flex"
|
|
||||||
)}
|
|
||||||
>
|
|
||||||
{plugin.version}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="field is-horizontal">
|
|
||||||
<div
|
|
||||||
className={classNames(
|
|
||||||
classes.userLabelAlignment,
|
|
||||||
"field-label is-inline-flex"
|
|
||||||
)}
|
|
||||||
>
|
|
||||||
{t("plugins.modal.newVersion")}:
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
className={classNames(
|
|
||||||
classes.userFieldFlex,
|
|
||||||
"field-body is-inline-flex"
|
|
||||||
)}
|
|
||||||
>
|
|
||||||
{plugin.newVersion}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{this.renderDependencies()}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="media">
|
|
||||||
<div className="media-content">
|
|
||||||
<Checkbox
|
|
||||||
checked={restart}
|
|
||||||
label={t("plugins.modal.restart")}
|
|
||||||
onChange={this.handleRestartChange}
|
|
||||||
disabled={false}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{this.renderNotifications()}
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Modal
|
|
||||||
title={t("plugins.modal.title.update", {
|
|
||||||
name: plugin.displayName ? plugin.displayName : plugin.name
|
|
||||||
})}
|
|
||||||
closeFunction={() => onClose()}
|
|
||||||
body={body}
|
|
||||||
footer={this.footer()}
|
|
||||||
active={true}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default compose(
|
|
||||||
injectSheet(styles),
|
|
||||||
translate("admin")
|
|
||||||
)(UpdatePluginModal);
|
|
||||||
Reference in New Issue
Block a user