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

Merge pull request #2210 from weseek/support/reactify-empty-trash

Support/reactify trash alert
Yuki Takei 5 лет назад
Родитель
Сommit
620be6bc8d

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

@@ -22,6 +22,7 @@ import PageComments from './components/PageComments';
 import PageTimeline from './components/PageTimeline';
 import CommentEditorLazyRenderer from './components/PageComment/CommentEditorLazyRenderer';
 import PageManagement from './components/Page/PageManagement';
+import TrashPageAlert from './components/Page/TrashPageAlert';
 import PageAttachment from './components/PageAttachment';
 import PageStatusAlert from './components/PageStatusAlert';
 import PagePathAutoComplete from './components/PagePathAutoComplete';
@@ -77,6 +78,8 @@ Object.assign(componentMappings, {
   'page-status-alert': <PageStatusAlert />,
   'save-page-controls': <SavePageControls />,
 
+  'trash-page-alert': <TrashPageAlert />,
+
   'page-timeline': <PageTimeline />,
 
   'personal-setting': <PersonalSettings crowi={personalContainer} />,

+ 77 - 0
src/client/js/components/Page/TrashPageAlert.jsx

@@ -0,0 +1,77 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+
+import { withTranslation } from 'react-i18next';
+
+import { createSubscribedElement } from '../UnstatedUtils';
+import AppContainer from '../../services/AppContainer';
+import PageContainer from '../../services/PageContainer';
+import UserPicture from '../User/UserPicture';
+
+
+const TrashPageAlert = (props) => {
+  const { t, appContainer, pageContainer } = props;
+  const {
+    path, isDeleted, revisionAuthor, updatedAt, hasChildren, isAbleToDeleteCompletely,
+  } = pageContainer.state;
+  const { currentUser } = appContainer;
+
+  function renderEmptyButton() {
+    return (
+      <button href="#" type="button" className="btn btn-danger rounded-pill btn-sm ml-auto" data-target="#emptyTrash" data-toggle="modal">
+        <i className="icon-trash" aria-hidden="true"></i>{ t('modal_empty.empty_the_trash') }
+      </button>
+    );
+  }
+
+  function renderTrashPageManagementButtons() {
+    return (
+      <>
+        <button
+          type="button"
+          className="btn btn-outline-secondary rounded-pill btn-sm ml-auto mr-2"
+          data-target="#putBackPage"
+          data-toggle="modal"
+        >
+          <i className="icon-action-undo" aria-hidden="true"></i> { t('Put Back') }
+        </button>
+        <button
+          type="button"
+          className="btn btn-danger rounded-pill btn-sm mr-2"
+          disabled={!isAbleToDeleteCompletely}
+          data-target="#deletePage"
+          data-toggle="modal"
+        >
+          <i className="icon-fire" aria-hidden="true"></i> { t('Delete Completely') }
+        </button>
+      </>
+    );
+  }
+
+  return (
+    <div className="alert alert-warning py-3 px-4 d-flex align-items-center">
+      <div>
+      This page is in the trash <i className="icon-trash" aria-hidden="true"></i>.
+        {isDeleted && <span><br /><UserPicture user={revisionAuthor} /> Deleted by {revisionAuthor.name} at {updatedAt}</span>}
+      </div>
+      {(currentUser.admin && path === '/trash' && hasChildren) && renderEmptyButton()}
+      {(isDeleted && currentUser != null) && renderTrashPageManagementButtons()}
+    </div>
+  );
+};
+
+/**
+ * Wrapper component for using unstated
+ */
+const TrashPageAlertWrapper = (props) => {
+  return createSubscribedElement(TrashPageAlert, props, [AppContainer, PageContainer]);
+};
+
+
+TrashPageAlert.propTypes = {
+  t: PropTypes.func.isRequired, // i18next
+  appContainer: PropTypes.instanceOf(AppContainer).isRequired,
+  pageContainer: PropTypes.instanceOf(PageContainer).isRequired,
+};
+
+export default withTranslation()(TrashPageAlertWrapper);

+ 3 - 2
src/client/js/services/PageContainer.js

@@ -32,7 +32,6 @@ export default class PageContainer extends Container {
 
     const revisionId = mainContent.getAttribute('data-page-revision-id');
     const path = decodeURI(mainContent.getAttribute('data-path'));
-
     this.state = {
       // local page data
       markdown: null, // will be initialized after initStateMarkdown()
@@ -48,8 +47,10 @@ export default class PageContainer extends Container {
       createdAt: mainContent.getAttribute('data-page-created-at'),
       creator: JSON.parse(mainContent.getAttribute('data-page-creator')),
       updatedAt: mainContent.getAttribute('data-page-updated-at'),
-
+      isDeleted:  JSON.parse(mainContent.getAttribute('data-page-is-deleted')),
+      isAbleToDeleteCompletely:  JSON.parse(mainContent.getAttribute('data-page-is-able-to-delete-completely')),
       tags: [],
+      hasChildren: JSON.parse(mainContent.getAttribute('data-page-has-children')),
       templateTagData: mainContent.getAttribute('data-template-tags') || null,
 
       // latest(on remote) information

+ 1 - 19
src/server/views/widget/page_alerts.html

@@ -82,25 +82,7 @@
     {% endif %}
 
     {% if isTrashPage() %}
-    <div class="alert alert-warning py-3 px-4 d-flex align-items-center justify-content-between">
-      <div>
-        This page is in the trash <i class="icon-trash" aria-hidden="true"></i>.
-        {% if page.isDeleted() %}
-        <br>Deleted by <img src="{{ page.lastUpdateUser|picture }}" class="picture picture-sm rounded-circle"> {{ page.lastUpdateUser.name }} at {{ page.updatedAt|datetz('Y-m-d H:i:s') }}
-        {% endif %}
-      </div>
-      {% if user and user.admin and req.path == '/trash' and pages.length > 0 %}
-      <div>
-        <button href="#" class="btn btn-danger rounded-pill btn-sm" data-target="#emptyTrash" data-toggle="modal"><i class="icon-trash" aria-hidden="true"></i>{{ t('modal_empty.empty_the_trash') }}</button>
-      </div>
-      {% endif %}
-      {% if page.isDeleted() and user %}
-      <div>
-        <button href="#" class="btn btn-outline-secondary rounded-pill btn-sm mr-2" data-target="#putBackPage" data-toggle="modal"><i class="icon-action-undo" aria-hidden="true"></i> {{ t('Put Back') }}</button>
-        <button href="#" class="btn btn-danger rounded-pill btn-sm mr-2" {% if !user.canDeleteCompletely(page.creator._id) %} disabled="disabled" {% endif %} data-target="#deletePage" data-toggle="modal"><i class="icon-fire" aria-hidden="true"></i> {{ t('Delete Completely') }}</button>
-      </div>
-      {% endif %}
-    </div>
+      <div id="trash-page-alert"></div>
     {% endif %}
   </div>
 </div>

+ 5 - 0
src/server/views/widget/page_content.html

@@ -11,16 +11,21 @@
   data-page-has-draft-on-hackmd="{% if hasDraftOnHackmd %}{{ hasDraftOnHackmd.toString() }}{% endif %}"
   data-page-is-liked="{% if page.isLiked(user) %}true{% else %}false{% endif %}"
   data-page-is-seen="{% if page and page.isSeenUser(user) %}1{% else %}0{% endif %}"
+  data-page-is-deleted="{% if page.isDeleted() %}true{% else %}false{% endif %}"
+  data-page-is-able-to-delete-completely="{% if user.canDeleteCompletely(page.creator._id) %}true{% else %}false{% endif %}"
   data-slack-channels="{{ slack|default('') }}"
   data-page-created-at="{% if page %}{{ page.createdAt|datetz('Y/m/d H:i:s') }}{% endif %}"
   data-page-creator="{% if page %}{{ page.creator|json }}{% endif %}"
   data-page-updated-at="{% if page %}{{ page.updatedAt|datetz('Y/m/d H:i:s') }}{% endif %}"
+  data-page-has-children="{% if pages.length > 0 %}true{% else %}false{% endif %}"
   >
 {% else %}
 <div id="content-main" class="content-main"
   data-path="{{ encodeURI(path) }}"
   data-current-user="{% if user %}{{ user._id.toString() }}{% endif %}"
   data-slack-channels="{{ slack|default('') }}"
+  data-page-is-deleted="{% if page.isDeleted() %}true{% else %}false{% endif %}"
+  data-page-has-children="{% if pages.length > 0 %}true{% else %}false{% endif %}"
   >
 {% endif %}