Просмотр исходного кода

Merge pull request #1541 from weseek/reactify-admin/add-grobal-notification-component

Reactify admin/add grobal notification component
Yuki Takei 6 лет назад
Родитель
Сommit
010eb5a841

+ 3 - 0
src/client/js/app.jsx

@@ -36,6 +36,7 @@ import TableOfContents from './components/TableOfContents';
 
 import UserGroupDetailPage from './components/Admin/UserGroupDetail/UserGroupDetailPage';
 import NotificationSetting from './components/Admin/Notification/NotificationSetting';
+import ManageGlobalNotification from './components/Admin/Notification/ManageGlobalNotification';
 import MarkdownSetting from './components/Admin/MarkdownSetting/MarkDownSetting';
 import UserManagement from './components/Admin/UserManagement';
 import AppSettingsPage from './components/Admin/App/AppSettingsPage';
@@ -169,6 +170,7 @@ const adminContainers = {
   'admin-user-page': adminUsersContainer,
   'admin-external-account-setting': adminExternalAccountsContainer,
   'admin-notification-setting': adminNotificationContainer,
+  'admin-global-notification-setting': adminNotificationContainer,
   'admin-markdown-setting': adminMarkDownContainer,
   'admin-export-page': websocketContainer,
 };
@@ -197,6 +199,7 @@ const adminComponentMappings = {
   'admin-user-page': <UserManagement />,
   'admin-external-account-setting': <ManageExternalAccount />,
   'admin-notification-setting': <NotificationSetting />,
+  'admin-global-notification-setting': <ManageGlobalNotification />,
   'admin-markdown-setting': <MarkdownSetting />,
   'admin-export-page': <ExportArchiveDataPage crowi={appContainer} />,
 };

+ 262 - 0
src/client/js/components/Admin/Notification/ManageGlobalNotification.jsx

@@ -0,0 +1,262 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+import { withTranslation } from 'react-i18next';
+
+import loggerFactory from '@alias/logger';
+
+import { toastError } from '../../../util/apiNotification';
+
+import TriggerEventCheckBox from './TriggerEventCheckBox';
+import AdminUpdateButtonRow from '../Common/AdminUpdateButtonRow';
+
+const logger = loggerFactory('growi:manageGlobalNotification');
+
+class ManageGlobalNotification extends React.Component {
+
+  constructor() {
+    super();
+
+    this.state = {
+      retrieveError: null,
+      triggerPath: '',
+      notifyToType: 'mail',
+      emailToSend: '',
+      slackChannelToSend: '',
+      triggerEvents: new Set([]),
+    };
+
+    this.submitHandler = this.submitHandler.bind(this);
+  }
+
+  componentDidMount() {
+    this.retrieveTriggerEvent();
+  }
+
+  async retrieveTriggerEvent() {
+    try {
+      // TODO GW-913 create apiV3
+    }
+    catch (err) {
+      toastError(err);
+      logger.error(err);
+      this.setState({ retrieveError: err });
+    }
+  }
+
+  onChangeTriggerPath(inputValue) {
+    this.setState({ triggerPath: inputValue });
+  }
+
+  onChangeNotifyToType(notifyToType) {
+    this.setState({ notifyToType });
+  }
+
+  onChangeEmailToSend(inputValue) {
+    this.setState({ emailToSend: inputValue });
+  }
+
+  onChangeSlackChannelToSend(inputValue) {
+    this.setState({ slackChannelToSend: inputValue });
+  }
+
+  onChangeTriggerEvents(triggerEvent) {
+    const { triggerEvents } = this.state;
+
+    if (triggerEvents.has(triggerEvent)) {
+      triggerEvents.delete(triggerEvent);
+      this.setState({ triggerEvents });
+    }
+    else {
+      triggerEvents.add(triggerEvent);
+      this.setState({ triggerEvents });
+    }
+  }
+
+  async submitHandler() {
+
+    try {
+      // TODO GW-778 create apiV3 update notification
+    }
+    catch (err) {
+      toastError(err);
+      logger.error(err);
+    }
+  }
+
+
+  render() {
+    const { t } = this.props;
+    return (
+      <React.Fragment>
+
+        <a href="/admin/notification#global-notification" className="btn btn-default">
+          <i className="icon-fw ti-arrow-left" aria-hidden="true"></i>
+          {t('notification_setting.back_to_list')}
+        </a>
+
+        <div className="row">
+          <div className="m-t-20 form-box col-md-12">
+            <h2 className="border-bottom mb-5">{t('notification_setting.notification_detail')}</h2>
+          </div>
+
+          <div className="col-sm-4">
+            <div className="form-group">
+              <h3 htmlFor="triggerPath">{t('notification_setting.trigger_path')}
+                {/* eslint-disable-next-line react/no-danger */}
+                <small dangerouslySetInnerHTML={{ __html: t('notification_setting.trigger_path_help', '<code>*</code>') }} />
+                <input
+                  className="form-control"
+                  type="text"
+                  name="triggerPath"
+                  value={this.state.triggerPath}
+                  onChange={(e) => { this.onChangeTriggerPath(e.target.value) }}
+                  required
+                />
+              </h3>
+            </div>
+
+            <div className="form-group form-inline">
+              <h3>{t('notification_setting.notify_to')}</h3>
+              <div className="radio radio-primary">
+                <input
+                  type="radio"
+                  id="mail"
+                  name="notifyToType"
+                  value="mail"
+                  checked={this.state.notifyToType === 'mail'}
+                  onChange={() => { this.onChangeNotifyToType('mail') }}
+                />
+                <label htmlFor="mail">
+                  <p className="font-weight-bold">Email</p>
+                </label>
+              </div>
+              <div className="radio radio-primary">
+                <input
+                  type="radio"
+                  id="slack"
+                  name="notifyToType"
+                  value="slack"
+                  checked={this.state.notifyToType === 'slack'}
+                  onChange={() => { this.onChangeNotifyToType('slack') }}
+                />
+                <label htmlFor="slack">
+                  <p className="font-weight-bold">Slack</p>
+                </label>
+              </div>
+            </div>
+
+            {this.state.notifyToType === 'mail'
+              ? (
+                <div className="form-group notify-to-option" id="mail-input">
+                  <input
+                    className="form-control"
+                    type="text"
+                    name="toEmail"
+                    placeholder="Email"
+                    value={this.state.emailToSend}
+                    onChange={(e) => { this.onChangeEmailToSend(e.target.value) }}
+                  />
+                  <p className="help">
+                    <b>Hint: </b>
+                    <a href="https://ifttt.com/create" target="blank">{t('notification_setting.email.ifttt_link')}
+                      <i className="icon-share-alt" />
+                    </a>
+                  </p>
+                </div>
+              )
+              : (
+                <div className="form-group notify-to-option" id="slack-input">
+                  <input
+                    className="form-control"
+                    type="text"
+                    name="notificationGlobal[slackChannels]"
+                    placeholder="Slack Channel"
+                    value={this.state.slackChannelToSend}
+                    onChange={(e) => { this.onChangeSlackChannelToSend(e.target.value) }}
+                  />
+                </div>
+              )}
+
+          </div>
+
+
+          <div className="col-sm-offset-1 col-sm-5">
+            <div className="form-group">
+              <h3>{t('notification_setting.trigger_events')}</h3>
+              <TriggerEventCheckBox
+                event="pageCreate"
+                checked={this.state.triggerEvents.has('pageCreate')}
+                onChange={() => this.onChangeTriggerEvents('pageCreate')}
+              >
+                <span className="label label-success">
+                  <i className="icon-doc"></i> CREATE
+                </span>
+              </TriggerEventCheckBox>
+              <TriggerEventCheckBox
+                event="pageEdit"
+                checked={this.state.triggerEvents.has('pageEdit')}
+                onChange={() => this.onChangeTriggerEvents('pageEdit')}
+              >
+                <span className="label label-warning">
+                  <i className="icon-pencil"></i>EDIT
+                </span>
+              </TriggerEventCheckBox>
+              <TriggerEventCheckBox
+                event="pageMove"
+                checked={this.state.triggerEvents.has('pageMove')}
+                onChange={() => this.onChangeTriggerEvents('pageMove')}
+              >
+                <span className="label label-warning">
+                  <i className="icon-action-redo"></i>MOVE
+                </span>
+              </TriggerEventCheckBox>
+              <TriggerEventCheckBox
+                event="pageDelete"
+                checked={this.state.triggerEvents.has('pageDelete')}
+                onChange={() => this.onChangeTriggerEvents('pageDelete')}
+              >
+                <span className="label label-danger">
+                  <i className="icon-fire"></i>DELETE
+                </span>
+              </TriggerEventCheckBox>
+              <TriggerEventCheckBox
+                event="pageLike"
+                checked={this.state.triggerEvents.has('pageLike')}
+                onChange={() => this.onChangeTriggerEvents('pageLike')}
+              >
+                <span className="label label-info">
+                  <i className="icon-like"></i>LIKE
+                </span>
+              </TriggerEventCheckBox>
+              <TriggerEventCheckBox
+                event="comment"
+                checked={this.state.triggerEvents.has('comment')}
+                onChange={() => this.onChangeTriggerEvents('comment')}
+              >
+                <span className="label label-default">
+                  <i className="icon-bubble"></i>POST
+                </span>
+              </TriggerEventCheckBox>
+
+            </div>
+          </div>
+
+          <AdminUpdateButtonRow
+            onClick={this.submitHandler}
+            disabled={this.state.retrieveError != null}
+          />
+
+        </div>
+
+      </React.Fragment>
+
+    );
+  }
+
+}
+
+ManageGlobalNotification.propTypes = {
+  t: PropTypes.func.isRequired, // i18next
+};
+
+export default withTranslation()(ManageGlobalNotification);

+ 36 - 0
src/client/js/components/Admin/Notification/TriggerEventCheckBox.jsx

@@ -0,0 +1,36 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+import { withTranslation } from 'react-i18next';
+
+const TriggerEventCheckBox = (props) => {
+  const { t } = props;
+
+  return (
+    <div className="checkbox checkbox-inverse">
+      <input
+        type="checkbox"
+        id={`trigger-event-${props.event}`}
+        value={props.event}
+        checked={props.checked}
+        onChange={props.onChange}
+      />
+      <label htmlFor={`trigger-event-${props.event}`}>
+        {props.children}{' '}
+        {t(`notification_setting.event_${props.event}`)}
+      </label>
+    </div>
+  );
+};
+
+
+TriggerEventCheckBox.propTypes = {
+  t: PropTypes.func.isRequired, // i18next
+
+  checked: PropTypes.bool.isRequired,
+  onChange: PropTypes.func.isRequired,
+  event: PropTypes.string.isRequired,
+  children: PropTypes.object.isRequired,
+};
+
+
+export default withTranslation()(TriggerEventCheckBox);

+ 64 - 47
src/server/views/admin/global-notification-detail.html

@@ -31,16 +31,16 @@
       {% include './widget/menu.html' with {current: 'notification'} %}
     </div>
 
-    <div class="col-md-9">
-      <a href="/admin/notification#global-notification" class="btn btn-default">
+    <div class="col-md-9" id="admin-global-notification-setting" />
+    <!-- <a href="/admin/notification#global-notification" class="btn btn-default">
         <i class="icon-fw ti-arrow-left" aria-hidden="true"></i>
         {{ t('notification_setting.back_to_list') }}
       </a>
 
       {% if setting %}
-        {% set actionPath = '/admin/global-notification/' + setting.id + '/update' %}
+      {% set actionPath = '/admin/global-notification/' + setting.id + '/update' %}
       {% else %}
-        {% set actionPath = '/admin/global-notification/new' %}
+      {% set actionPath = '/admin/global-notification/new' %}
       {% endif %}
 
       <div class="row">
@@ -50,20 +50,24 @@
           <form action="{{ actionPath }}" method="post" class="form-horizontal" role="form">
             <fieldset class="col-sm-4">
               <div class="form-group">
-                <h3 for="triggerPath">{{ t('notification_setting.trigger_path') }} <small>{{ t('notification_setting.trigger_path_help', '<code>*</code>') }}</small></h3>
-                <input class="form-control" type="text" name="notificationGlobal[triggerPath]" value="{{ setting.triggerPath || '' }}" required>
+                <h3 for="triggerPath">{{ t('notification_setting.trigger_path') }}
+                  <small>{{ t('notification_setting.trigger_path_help', '<code>*</code>') }}</small></h3>
+                <input class="form-control" type="text" name="notificationGlobal[triggerPath]"
+                  value="{{ setting.triggerPath || '' }}" required>
               </div>
 
               <div class="form-group form-inline">
                 <h3>{{ t('notification_setting.notify_to') }}</h3>
                 <div class="radio radio-primary">
-                  <input type="radio" id="mail" name="notificationGlobal[notifyToType]" value="mail" {% if setting.__t == 'mail' %}checked{% endif %}>
+                  <input type="radio" id="mail" name="notificationGlobal[notifyToType]" value="mail"
+                    {% if setting.__t == 'mail' %}checked{% endif %}>
                   <label for="mail">
                     <p class="font-weight-bold">Email</p>
                   </label>
                 </div>
                 <div class="radio radio-primary">
-                  <input type="radio" id="slack" name="notificationGlobal[notifyToType]" value="slack" {% if setting.__t == 'slack' %}checked{% endif %}>
+                  <input type="radio" id="slack" name="notificationGlobal[notifyToType]" value="slack"
+                    {% if setting.__t == 'slack' %}checked{% endif %}>
                   <label for="slack">
                     <p class="font-weight-bold">Slack</p>
                   </label>
@@ -71,15 +75,19 @@
               </div>
 
               <div class="form-group notify-to-option {% if setting.__t != 'mail' %}d-none{% endif %}" id="mail-input">
-                <input class="form-control" type="text" name="notificationGlobal[toEmail]" placeholder="Email" value="{{ setting.toEmail || '' }}">
+                <input class="form-control" type="text" name="notificationGlobal[toEmail]" placeholder="Email"
+                  value="{{ setting.toEmail || '' }}">
                 <p class="help">
                   <b>Hint: </b>
-                  <a href="https://ifttt.com/create" target="_blank">{{ t('notification_setting.email.ifttt_link') }} <i class="icon-share-alt"></i></a>
+                  <a href="https://ifttt.com/create" target="_blank">{{ t('notification_setting.email.ifttt_link') }} <i
+                      class="icon-share-alt"></i></a>
                 </p>
               </div>
 
-              <div class="form-group notify-to-option {% if setting.__t != 'slack' %}d-none{% endif %}" id="slack-input">
-                <input class="form-control" type="text" name="notificationGlobal[slackChannels]" placeholder="Slack Channel" value="{{ setting.slackChannels || '' }}">
+              <div class="form-group notify-to-option {% if setting.__t != 'slack' %}d-none{% endif %}"
+                id="slack-input">
+                <input class="form-control" type="text" name="notificationGlobal[slackChannels]"
+                  placeholder="Slack Channel" value="{{ setting.slackChannels || '' }}">
               </div>
             </fieldset>
 
@@ -87,45 +95,57 @@
               <div class="form-group">
                 <h3>{{ t('notification_setting.trigger_events') }}</h3>
                 <div class="checkbox checkbox-inverse">
-                  <input type="checkbox" id="trigger-event-pageCreate" name="notificationGlobal[triggerEvent:pageCreate]" value="pageCreate"
+                  <input type="checkbox" id="trigger-event-pageCreate"
+                    name="notificationGlobal[triggerEvent:pageCreate]" value="pageCreate"
                     {% if setting && (setting.triggerEvents.indexOf('pageCreate') != -1) %}checked{% endif %} />
                   <label for="trigger-event-pageCreate">
-                    <span class="label label-success"><i class="icon-doc"></i> CREATE</span> - {{ t('notification_setting.event_pageCreate') }}
+                    <span class="label label-success"><i class="icon-doc"></i> CREATE</span> -
+                    {{ t('notification_setting.event_pageCreate') }}
                   </label>
                 </div>
                 <div class="checkbox checkbox-inverse">
-                  <input type="checkbox" id="trigger-event-pageEdit" name="notificationGlobal[triggerEvent:pageEdit]" value="pageEdit"
+                  <input type="checkbox" id="trigger-event-pageEdit" name="notificationGlobal[triggerEvent:pageEdit]"
+                    value="pageEdit"
                     {% if setting && (setting.triggerEvents.indexOf('pageEdit') != -1) %}checked{% endif %} />
                   <label for="trigger-event-pageEdit">
-                    <span class="label label-warning"><i class="icon-pencil"></i> EDIT</span> - {{ t('notification_setting.event_pageEdit') }}
+                    <span class="label label-warning"><i class="icon-pencil"></i> EDIT</span> -
+                    {{ t('notification_setting.event_pageEdit') }}
                   </label>
                 </div>
                 <div class="checkbox checkbox-inverse">
-                  <input type="checkbox" id="trigger-event-pageMove" name="notificationGlobal[triggerEvent:pageMove]" value="pageMove"
+                  <input type="checkbox" id="trigger-event-pageMove" name="notificationGlobal[triggerEvent:pageMove]"
+                    value="pageMove"
                     {% if setting && (setting.triggerEvents.indexOf('pageMove') != -1) %}checked{% endif %} />
                   <label for="trigger-event-pageMove">
-                    <span class="label label-warning"><i class="icon-action-redo"></i> MOVE</span> - {{ t('notification_setting.event_pageMove') }}
+                    <span class="label label-warning"><i class="icon-action-redo"></i> MOVE</span> -
+                    {{ t('notification_setting.event_pageMove') }}
                   </label>
                 </div>
                 <div class="checkbox checkbox-inverse">
-                  <input type="checkbox" id="trigger-event-pageDelete" name="notificationGlobal[triggerEvent:pageDelete]" value="pageDelete"
+                  <input type="checkbox" id="trigger-event-pageDelete"
+                    name="notificationGlobal[triggerEvent:pageDelete]" value="pageDelete"
                     {% if setting && (setting.triggerEvents.indexOf('pageDelete') != -1) %}checked{% endif %} />
                   <label for="trigger-event-pageDelete">
-                    <span class="label label-danger"><i class="icon-fire"></i> DELETE</span> - {{ t('notification_setting.event_pageDelete') }}
+                    <span class="label label-danger"><i class="icon-fire"></i> DELETE</span> -
+                    {{ t('notification_setting.event_pageDelete') }}
                   </label>
                 </div>
                 <div class="checkbox checkbox-inverse">
-                    <input type="checkbox" id="trigger-event-pageLike" name="notificationGlobal[triggerEvent:pageLike]" value="pageLike"
-                      {% if setting && (setting.triggerEvents.indexOf('pageLike') != -1) %}checked{% endif %} />
-                    <label for="trigger-event-pageLike">
-                      <span class="label label-info"><i class="icon-like"></i> LIKE</span> - {{ t('notification_setting.event_pageLike') }}
-                    </label>
-                  </div>
+                  <input type="checkbox" id="trigger-event-pageLike" name="notificationGlobal[triggerEvent:pageLike]"
+                    value="pageLike"
+                    {% if setting && (setting.triggerEvents.indexOf('pageLike') != -1) %}checked{% endif %} />
+                  <label for="trigger-event-pageLike">
+                    <span class="label label-info"><i class="icon-like"></i> LIKE</span> -
+                    {{ t('notification_setting.event_pageLike') }}
+                  </label>
+                </div>
                 <div class="checkbox checkbox-inverse">
-                  <input type="checkbox" id="trigger-event-comment" name="notificationGlobal[triggerEvent:comment]" value="comment"
+                  <input type="checkbox" id="trigger-event-comment" name="notificationGlobal[triggerEvent:comment]"
+                    value="comment"
                     {% if setting && (setting.triggerEvents.indexOf('comment') != -1) %}checked{% endif %} />
                   <label for="trigger-event-comment">
-                    <span class="label label-default"><i class="icon-fw icon-bubble"></i> POST</span> - {{ t('notification_setting.event_comment') }}
+                    <span class="label label-default"><i class="icon-fw icon-bubble"></i> POST</span> -
+                    {{ t('notification_setting.event_comment') }}
                   </label>
                 </div>
               </div>
@@ -136,34 +156,31 @@
               <input type="hidden" name="_csrf" value="{{ csrf() }}">
               <button type="submit" class="btn btn-primary">
                 {% if setting %}
-                  {{ t('Update') }}
+                {{ t('Update') }}
                 {% else %}
-                  {{ t('Create') }}
+                {{ t('Create') }}
                 {% endif %}
               </button>
             </div>
           </form>
         </div>
-      </div>
+      </div> -->
 
-    </div>
   </div>
-</div>
-
-<script>
-  $('input[name="notificationGlobal[notifyToType]"]').change(function() {
-    var val = $(this).val();
-    $('.notify-to-option').addClass('d-none');
-    $('#' + val + '-input').removeClass('d-none');
-  });
 
-  $('button#global-notificatin-delete').submit(function() {
-    alert(123)
-  });
-</script>
-{% endblock content_main %}
+  <script>
+    $('input[name="notificationGlobal[notifyToType]"]').change(function () {
+      var val = $(this).val();
+      $('.notify-to-option').addClass('d-none');
+      $('#' + val + '-input').removeClass('d-none');
+    });
 
-{% block content_footer %}
-{% endblock content_footer %}
+    $('button#global-notificatin-delete').submit(function () {
+      alert(123)
+    });
 
+  </script>
+  {% endblock content_main %}
 
+  {% block content_footer %}
+  {% endblock content_footer %}