client/app/pages/alert/Alert.jsx (244 lines of code) (raw):
import { head, includes, trim, template, values } from "lodash";
import React from "react";
import PropTypes from "prop-types";
import LoadingState from "@/components/items-list/components/LoadingState";
import routeWithUserSession from "@/components/ApplicationArea/routeWithUserSession";
import navigateTo from "@/components/ApplicationArea/navigateTo";
import { currentUser } from "@/services/auth";
import notification from "@/services/notification";
import AlertService from "@/services/alert";
import { Query as QueryService } from "@/services/query";
import routes from "@/services/routes";
import MenuButton from "./components/MenuButton";
import AlertView from "./AlertView";
import AlertEdit from "./AlertEdit";
import AlertNew from "./AlertNew";
const MODES = {
NEW: 0,
VIEW: 1,
EDIT: 2,
};
const defaultNameBuilder = template("<%= query.name %>: <%= options.column %> <%= options.op %> <%= options.value %>");
export function getDefaultName(alert) {
if (!alert.query) {
return "New Alert";
}
return defaultNameBuilder(alert);
}
class Alert extends React.Component {
static propTypes = {
mode: PropTypes.oneOf(values(MODES)),
alertId: PropTypes.string,
onError: PropTypes.func,
};
static defaultProps = {
mode: null,
alertId: null,
onError: () => {},
};
_isMounted = false;
state = {
alert: null,
queryResult: null,
pendingRearm: null,
canEdit: false,
mode: null,
};
componentDidMount() {
this._isMounted = true;
const { mode } = this.props;
this.setState({ mode });
if (mode === MODES.NEW) {
this.setState({
alert: {
options: {
op: ">",
value: 1,
muted: false,
},
},
pendingRearm: 0,
canEdit: true,
});
} else {
const { alertId } = this.props;
AlertService.get({ id: alertId })
.then(alert => {
if (this._isMounted) {
const canEdit = currentUser.canEdit(alert);
// force view mode if can't edit
if (!canEdit) {
this.setState({ mode: MODES.VIEW });
notification.warn(
"You cannot edit this alert",
"You do not have sufficient permissions to edit this alert, and have been redirected to the view-only page.",
{ duration: 0 }
);
}
this.setState({ alert, canEdit, pendingRearm: alert.rearm });
this.onQuerySelected(alert.query);
}
})
.catch(error => {
if (this._isMounted) {
this.props.onError(error);
}
});
}
}
componentWillUnmount() {
this._isMounted = false;
}
save = () => {
const { alert, pendingRearm } = this.state;
alert.name = trim(alert.name) || getDefaultName(alert);
alert.rearm = pendingRearm || null;
return AlertService.save(alert)
.then(alert => {
notification.success("Saved.");
navigateTo(`alerts/${alert.id}`, true);
this.setState({ alert, mode: MODES.VIEW });
})
.catch(() => {
notification.error("Failed saving alert.");
});
};
onQuerySelected = query => {
this.setState(({ alert }) => ({
alert: Object.assign(alert, { query }),
queryResult: null,
}));
if (query) {
// get cached result for column names and values
new QueryService(query).getQueryResultPromise().then(queryResult => {
if (this._isMounted) {
this.setState({ queryResult });
let { column } = this.state.alert.options;
const columns = queryResult.getColumnNames();
// default to first column name if none chosen, or irrelevant in current query
if (!column || !includes(columns, column)) {
column = head(queryResult.getColumnNames());
}
this.setAlertOptions({ column });
}
});
}
};
onNameChange = name => {
const { alert } = this.state;
this.setState({
alert: Object.assign(alert, { name }),
});
};
onRearmChange = pendingRearm => {
this.setState({ pendingRearm });
};
setAlertOptions = obj => {
const { alert } = this.state;
const options = { ...alert.options, ...obj };
this.setState({
alert: Object.assign(alert, { options }),
});
};
delete = () => {
const { alert } = this.state;
return AlertService.delete(alert)
.then(() => {
notification.success("Alert deleted successfully.");
navigateTo("alerts");
})
.catch(() => {
notification.error("Failed deleting alert.");
});
};
mute = () => {
const { alert } = this.state;
return AlertService.mute(alert)
.then(() => {
this.setAlertOptions({ muted: true });
notification.warn("Notifications have been muted.");
})
.catch(() => {
notification.error("Failed muting notifications.");
});
};
unmute = () => {
const { alert } = this.state;
return AlertService.unmute(alert)
.then(() => {
this.setAlertOptions({ muted: false });
notification.success("Notifications have been restored.");
})
.catch(() => {
notification.error("Failed restoring notifications.");
});
};
edit = () => {
const { id } = this.state.alert;
navigateTo(`alerts/${id}/edit`, true);
this.setState({ mode: MODES.EDIT });
};
cancel = () => {
const { id } = this.state.alert;
navigateTo(`alerts/${id}`, true);
this.setState({ mode: MODES.VIEW });
};
render() {
const { alert } = this.state;
if (!alert) {
return <LoadingState className="m-t-30" />;
}
const muted = !!alert.options.muted;
const { queryResult, mode, canEdit, pendingRearm } = this.state;
const menuButton = (
<MenuButton doDelete={this.delete} muted={muted} mute={this.mute} unmute={this.unmute} canEdit={canEdit} />
);
const commonProps = {
alert,
queryResult,
pendingRearm,
save: this.save,
menuButton,
onQuerySelected: this.onQuerySelected,
onRearmChange: this.onRearmChange,
onNameChange: this.onNameChange,
onCriteriaChange: this.setAlertOptions,
onNotificationTemplateChange: this.setAlertOptions,
};
return (
<div className="alert-page">
<div className="container">
{mode === MODES.NEW && <AlertNew {...commonProps} />}
{mode === MODES.VIEW && (
<AlertView canEdit={canEdit} onEdit={this.edit} muted={muted} unmute={this.unmute} {...commonProps} />
)}
{mode === MODES.EDIT && <AlertEdit cancel={this.cancel} {...commonProps} />}
</div>
</div>
);
}
}
routes.register(
"Alerts.New",
routeWithUserSession({
path: "/alerts/new",
title: "New Alert",
render: pageProps => <Alert {...pageProps} mode={MODES.NEW} />,
})
);
routes.register(
"Alerts.View",
routeWithUserSession({
path: "/alerts/:alertId",
title: "Alert",
render: pageProps => <Alert {...pageProps} mode={MODES.VIEW} />,
})
);
routes.register(
"Alerts.Edit",
routeWithUserSession({
path: "/alerts/:alertId/edit",
title: "Alert",
render: pageProps => <Alert {...pageProps} mode={MODES.EDIT} />,
})
);