1import React, { PureComponent } from 'react';
2import { MapDispatchToProps, MapStateToProps } from 'react-redux';
3import { NavModel } from '@grafana/data';
4import { config } from '@grafana/runtime';
5import { Form, Spinner } from '@grafana/ui';
6import Page from 'app/core/components/Page/Page';
7import { connectWithCleanUp } from 'app/core/components/connectWithCleanUp';
8import { NotificationChannelForm } from './components/NotificationChannelForm';
9import { loadNotificationChannel, testNotificationChannel, updateNotificationChannel } from './state/actions';
10import { getNavModel } from 'app/core/selectors/navModel';
11import { mapChannelsToSelectableValue, transformSubmitData, transformTestData } from './utils/notificationChannels';
12import { NotificationChannelType, NotificationChannelDTO, StoreState } from 'app/types';
13import { resetSecureField } from './state/reducers';
14import { GrafanaRouteComponentProps } from 'app/core/navigation/types';
15
16interface OwnProps extends GrafanaRouteComponentProps<{ id: string }> {}
17
18interface ConnectedProps {
19  navModel: NavModel;
20  notificationChannel: any;
21  notificationChannelTypes: NotificationChannelType[];
22}
23
24interface DispatchProps {
25  loadNotificationChannel: typeof loadNotificationChannel;
26  testNotificationChannel: typeof testNotificationChannel;
27  updateNotificationChannel: typeof updateNotificationChannel;
28  resetSecureField: typeof resetSecureField;
29}
30
31type Props = OwnProps & ConnectedProps & DispatchProps;
32
33export class EditNotificationChannelPage extends PureComponent<Props> {
34  componentDidMount() {
35    this.props.loadNotificationChannel(parseInt(this.props.match.params.id, 10));
36  }
37
38  onSubmit = (formData: NotificationChannelDTO) => {
39    const { notificationChannel } = this.props;
40
41    this.props.updateNotificationChannel({
42      /*
43       Some settings which lives in a collapsed section will not be registered since
44       the section will not be rendered if a user doesn't expand it. Therefore we need to
45       merge the initialData with any changes from the form.
46      */
47      ...transformSubmitData({
48        ...notificationChannel,
49        ...formData,
50        settings: { ...notificationChannel.settings, ...formData.settings },
51      }),
52      id: notificationChannel.id,
53    });
54  };
55
56  onTestChannel = (formData: NotificationChannelDTO) => {
57    const { notificationChannel } = this.props;
58    /*
59      Same as submit
60     */
61    this.props.testNotificationChannel(
62      transformTestData({
63        ...notificationChannel,
64        ...formData,
65        settings: { ...notificationChannel.settings, ...formData.settings },
66      })
67    );
68  };
69
70  render() {
71    const { navModel, notificationChannel, notificationChannelTypes } = this.props;
72
73    return (
74      <Page navModel={navModel}>
75        <Page.Contents>
76          <h2 className="page-sub-heading">Edit notification channel</h2>
77          {notificationChannel && notificationChannel.id > 0 ? (
78            <Form
79              maxWidth={600}
80              onSubmit={this.onSubmit}
81              defaultValues={{
82                ...notificationChannel,
83                type: notificationChannelTypes.find((n) => n.value === notificationChannel.type),
84              }}
85            >
86              {({ control, errors, getValues, register, watch }) => {
87                const selectedChannel = notificationChannelTypes.find((c) => c.value === getValues().type.value);
88
89                return (
90                  <NotificationChannelForm
91                    selectableChannels={mapChannelsToSelectableValue(notificationChannelTypes, true)}
92                    selectedChannel={selectedChannel}
93                    imageRendererAvailable={config.rendererAvailable}
94                    onTestChannel={this.onTestChannel}
95                    register={register}
96                    watch={watch}
97                    errors={errors}
98                    getValues={getValues}
99                    control={control}
100                    resetSecureField={this.props.resetSecureField}
101                    secureFields={notificationChannel.secureFields}
102                  />
103                );
104              }}
105            </Form>
106          ) : (
107            <div>
108              Loading notification channel
109              <Spinner />
110            </div>
111          )}
112        </Page.Contents>
113      </Page>
114    );
115  }
116}
117
118const mapStateToProps: MapStateToProps<ConnectedProps, OwnProps, StoreState> = (state) => {
119  return {
120    navModel: getNavModel(state.navIndex, 'channels'),
121    notificationChannel: state.notificationChannel.notificationChannel,
122    notificationChannelTypes: state.notificationChannel.notificationChannelTypes,
123  };
124};
125
126const mapDispatchToProps: MapDispatchToProps<DispatchProps, OwnProps> = {
127  loadNotificationChannel,
128  testNotificationChannel,
129  updateNotificationChannel,
130  resetSecureField,
131};
132
133export default connectWithCleanUp(
134  mapStateToProps,
135  mapDispatchToProps,
136  (state) => state.notificationChannel
137)(EditNotificationChannelPage);
138