mizozobu пре 7 година
родитељ
комит
d00c98a55a

+ 12 - 0
src/client/js/app.js

@@ -44,6 +44,7 @@ import CustomCssEditor from './components/Admin/CustomCssEditor';
 import CustomScriptEditor from './components/Admin/CustomScriptEditor';
 import CustomHeaderEditor from './components/Admin/CustomHeaderEditor';
 import AdminRebuildSearch from './components/Admin/AdminRebuildSearch';
+import GroupDeleteControl from './components/GroupDeleteControl/GroupDeleteControl';
 
 
 const logger = loggerFactory('growi:app');
@@ -571,6 +572,17 @@ if (adminRebuildSearchElem != null) {
     adminRebuildSearchElem,
   );
 }
+const adminGrantSelectorElem = document.getElementById('admin-delete-user-group-modal');
+if (adminGrantSelectorElem != null) {
+  ReactDOM.render(
+    <I18nextProvider i18n={i18n}>
+      <GroupDeleteControl
+        crowi={crowi}
+      />
+    </I18nextProvider>,
+    adminGrantSelectorElem,
+  );
+}
 
 // notification from websocket
 function updatePageStatusAlert(page, user) {

+ 190 - 0
src/client/js/components/GroupDeleteControl/GroupDeleteControl.jsx

@@ -0,0 +1,190 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+import { withTranslation } from 'react-i18next';
+
+import FormGroup from 'react-bootstrap/es/FormGroup';
+import FormControl from 'react-bootstrap/es/FormControl';
+
+/**
+ * Delete User Group Select component
+ *
+ * @export
+ * @class GrantSelector
+ * @extends {React.Component}
+ */
+class GroupDeleteControl extends React.Component {
+
+  constructor(props) {
+    super(props);
+
+    this.actionForPages = {
+      public: 'public',
+      delete: 'delete',
+      transfer: 'transfer',
+    };
+
+    this.availableOptions = [
+      {
+        id: 1, actionForPages: this.actionForPages.public, iconClass: 'icon-people', styleClass: '', label: 'Publish all private pages',
+      },
+      {
+        id: 2, actionForPages: this.actionForPages.delete, iconClass: 'icon-trash', styleClass: 'text-danger', label: 'Delete all private pages',
+      },
+      {
+        id: 3, actionForPages: this.actionForPages.transfer, iconClass: 'icon-options', styleClass: '', label: 'Transfer ownership to another group',
+      },
+    ];
+
+    this.state = {
+      deleteGroupId: '',
+      deleteGroupName: '',
+      groups: [],
+      actionForPages: this.actionForPages.public,
+      selectedGroupId: '',
+    };
+
+    // retrieve xss library from window
+    this.xss = window.xss;
+
+    this.getGroupName = this.getGroupName.bind(this);
+    this.changeActionHandler = this.changeActionHandler.bind(this);
+    this.changeGroupHandler = this.changeGroupHandler.bind(this);
+    this.renderPageActionSelector = this.renderPageActionSelector.bind(this);
+    this.renderGroupSelector = this.renderGroupSelector.bind(this);
+    this.disableSubmit = this.disableSubmit.bind(this);
+  }
+
+  componentDidMount() {
+    this.retrieveUserGroupRelations();
+
+    $('#admin-delete-user-group-modal').on('show.bs.modal', (button) => {
+      const data = $(button.relatedTarget);
+      const deleteGroupId = data.data('user-group-id');
+      const deleteGroupName = data.data('user-group-name');
+
+      this.setState({ deleteGroupId, deleteGroupName });
+    });
+  }
+
+  getGroupName(group) {
+    return this.xss.process(group.name);
+  }
+
+  async retrieveUserGroupRelations() {
+    const res = await this.props.crowi.apiGet('/me/user-group-relations'); // FIXME
+    this.setState({
+      groups: res.userGroupRelations.map((relation) => {
+        return relation.relatedGroup;
+      }),
+    });
+  }
+
+  changeActionHandler(e) {
+    const actionForPages = e.target.value;
+    this.setState({ actionForPages });
+  }
+
+  changeGroupHandler(e) {
+    const selectedGroupId = e.target.value;
+    this.setState({ selectedGroupId });
+  }
+
+  renderPageActionSelector() {
+    const { t } = this.props;
+
+    const optoins = this.availableOptions.map((opt) => {
+      const dataContent = `<i class="icon icon-fw ${opt.iconClass} ${opt.styleClass}"></i> <span class="${opt.styleClass}">${t(opt.label)}</span>`;
+      return <option key={opt.id} value={opt.actionForPages} data-content={dataContent}>{t(opt.label)}</option>;
+    });
+
+    const bsClassName = 'form-control-dummy'; // set form-control* to shrink width
+    return (
+      <FormGroup className="grant-selector m-b-0">
+        <FormControl
+          name="actionForPages"
+          componentClass="select"
+          placeholder="select"
+          defaultValue={this.actionForPages.public}
+          bsClass={bsClassName}
+          className="btn-group-sm selectpicker"
+          onChange={this.changeActionHandler}
+        >
+          {optoins}
+        </FormControl>
+      </FormGroup>
+    );
+  }
+
+  renderGroupSelector() {
+    const options = this.state.groups.map((group) => {
+      const dataContent = `<i class="icon icon-fw icon-organization"></i> ${this.getGroupName(group)}`;
+      return <option key={group._id} value={group._id} data-content={dataContent}>{this.getGroupName(group)}</option>;
+    });
+
+    return (
+      <select
+        name="selectedGroupId"
+        className={this.state.actionForPages === this.actionForPages.transfer ? '' : 'd-none'}
+        value={this.state.selectedGroupId}
+        onChange={this.changeGroupHandler}
+      >
+        <option value="" disabled>{this.state.groups.length === 0 ? 'No groups to select' : 'Choose a group'}</option>
+        {options}
+      </select>
+    );
+  }
+
+  disableSubmit() {
+    if (this.state.actionForPages === this.actionForPages.transfer) {
+      return this.state.selectedGroupId === '';
+    }
+
+    return false;
+  }
+
+  render() {
+    return (
+      <div className="modal-dialog">
+        <div className="modal-content">
+          <div className="modal-header bg-danger">
+            <button type="button" className="close" data-dismiss="modal" aria-hidden="true">&times;</button>
+            <div className="modal-title">
+              <i className="icon icon-fire"></i> グループの削除
+            </div>
+          </div>
+
+          <div className="modal-body">
+            <dl>
+              <dt>グループ名</dt>
+              <dd>{this.state.deleteGroupName}</dd>
+            </dl>
+            <span className="text-danger">
+              グループ及び限定公開のページの削除を行うと元に戻すことはできませんのでご注意ください。
+            </span>
+          </div>
+          <div className="modal-footer">
+            <form action="/admin/user-group.remove" method="post" id="admin-user-groups-delete" className="d-flex justify-content-between">
+              <div className="d-flex">
+                {this.renderPageActionSelector()}
+                {this.renderGroupSelector()}
+              </div>
+              <input type="hidden" id="deleteGroupId" name="deleteGroupId" value={this.state.deleteGroupId} onChange={() => {}} />
+              <input type="hidden" name="_csrf" defaultValue={this.props.crowi.csrfToken} />
+              <button type="submit" value="" className="btn btn-sm btn-danger" disabled={this.disableSubmit()}>
+                <i className="icon icon-fire"></i> 削除
+              </button>
+            </form>
+          </div>
+        </div>
+      </div>
+    );
+  }
+
+}
+
+GroupDeleteControl.propTypes = {
+  t: PropTypes.func.isRequired, // i18next
+  crowi: PropTypes.object.isRequired,
+};
+
+export default withTranslation()(GroupDeleteControl);

+ 0 - 9
src/client/js/legacy/crowi-admin.js

@@ -61,15 +61,6 @@ $(() => {
     return false;
   });
 
-  $('#admin-delete-user-group-modal').on('show.bs.modal', (button) => {
-    const data = $(button.relatedTarget);
-    const userGroupId = data.data('user-group-id');
-    const userGroupName = data.data('user-group-name');
-
-    $('#admin-delete-user-group-name').text(userGroupName);
-    $('#admin-user-groups-delete input[name=user_group_id]').val(userGroupId);
-  });
-
   $('form#user-group-relation-create').on('submit', function(e) {
     $.post('/admin/user-group-relation/create', $(this).serialize(), (res) => {
       $('#admin-add-user-group-relation-modal').modal('hide');

+ 1 - 34
src/server/views/admin/user-groups.html

@@ -74,40 +74,7 @@
       </div><!-- /.modal -->
       {% endif %}
 
-      <div class="modal fade" id="admin-delete-user-group-modal">
-        <div class="modal-dialog">
-          <div class="modal-content">
-            <div class="modal-header bg-danger">
-              <button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
-              <div class="modal-title">
-                <i class="icon icon-fire"></i> グループの削除
-              </div>
-            </div>
-
-            <div class="modal-body">
-              <dl>
-                <dt>グループ名</dt>
-                <dd><span id="admin-delete-user-group-name"></span></dd>
-              </dl>
-              <span class="text-danger">
-                グループの削除を行うと元に戻すことはできませんのでご注意ください。
-              </span>
-            </div>
-            <div class="modal-footer">
-              <form action="/admin/user-group.remove" method="post" id="admin-user-groups-delete" class="text-right">
-                <input type="hidden" name="user_group_id" value="">
-                <input type="hidden" name="_csrf" value="{{ csrf() }}">
-                <button type="submit" value="" class="btn btn-sm btn-danger">
-                  <i class="icon icon-fire"></i> 削除
-                </button>
-              </form>
-            </div>
-
-          </div>
-          <!-- /.modal-content -->
-        </div>
-        <!-- /.modal-dialog -->
-      </div>
+      <div class="modal fade" id="admin-delete-user-group-modal"></div>
 
       <h2>グループ一覧</h2>