Преглед изворни кода

Merge branch 'master' into feat/growi-bot

itizawa пре 5 година
родитељ
комит
9b86b55288

+ 3 - 3
resource/locales/en_US/translation.json

@@ -165,6 +165,7 @@
   },
   "not_found_page": {
     "Create Page": "Create Page",
+    "page_not_exist": "This page does not exist.",
     "page_not_exist_alert": "This page does not exist. Please create a new page."
   },
   "custom_navigation": {
@@ -330,10 +331,9 @@
     "revision": "version",
     "comparing_source": "Source",
     "comparing_target": "Target",
-    "comparing_revisions": "Comparing versions",
+    "comparing_revisions": "Comparing the difference",
     "compare_latest":"Compare latest revision",
-    "compare_previous":"Compare previous revision",
-    "comparing_with_latest": "Always compare with the latest version"
+    "compare_previous":"Compare previous revision"
   },
   "modal_rename": {
     "label": {

+ 3 - 3
resource/locales/ja_JP/translation.json

@@ -168,6 +168,7 @@
   },
   "not_found_page": {
     "Create Page": "ページを作成する",
+    "page_not_exist": "このページは存在しません。",
     "page_not_exist_alert": "このページは存在しません。新たに作成する必要があります。"
   },
   "custom_navigation": {
@@ -332,10 +333,9 @@
     "revision": "バージョン",
     "comparing_source": "ソース",
     "comparing_target": "ターゲット",
-    "comparing_revisions": "比較",
+    "comparing_revisions": "差分を比較する",
     "compare_latest":"最新と比較",
-    "compare_previous":"1つ前のバージョンと比較",
-    "comparing_with_latest": "常に最新バージョンと比較する"
+    "compare_previous":"1つ前のバージョンと比較"
   },
   "modal_rename": {
     "label": {

+ 3 - 3
resource/locales/zh_CN/translation.json

@@ -166,6 +166,7 @@
   },
   "not_found_page": {
     "Create Page": "创建页面",
+    "page_not_exist": "该页面不存在",
     "page_not_exist_alert": "该页面不存在,请创建一个新页面"
   },
   "custom_navigation": {
@@ -311,10 +312,9 @@
     "revision": "版本",
     "comparing_source": "源头",
     "comparing_target": "目标",
-    "comparing_revisions": "比较版本",
+    "comparing_revisions": "比较两者的区别",
     "compare_latest":"比較最新版本",
-    "compare_previous":"比較以前的版本",
-    "comparing_with_latest": "一定要与最新版本进行比较"
+    "compare_previous":"比較以前的版本"
   },
 	"modal_rename": {
 		"label": {

+ 2 - 2
src/client/js/components/Page/DisplaySwitcher.jsx

@@ -19,7 +19,7 @@ const DisplaySwitcher = (props) => {
     navigationContainer, pageContainer,
   } = props;
   const { editorMode } = navigationContainer.state;
-  const { pageUser } = pageContainer.state;
+  const { isPageExist, pageUser } = pageContainer.state;
 
   return (
     <>
@@ -30,7 +30,7 @@ const DisplaySwitcher = (props) => {
             <div className="grw-side-contents-container">
               <div className="grw-side-contents-sticky-container">
                 <div className="border-bottom pb-1">
-                  <PageAccessories />
+                  <PageAccessories isNotFoundPage={!isPageExist} />
                 </div>
 
                 <div className="d-none d-lg-block">

+ 5 - 1
src/client/js/components/PageAccessories.jsx

@@ -9,7 +9,7 @@ import AppContainer from '../services/AppContainer';
 import PageAccessoriesContainer from '../services/PageAccessoriesContainer';
 
 const PageAccessories = (props) => {
-  const { appContainer, pageAccessoriesContainer } = props;
+  const { appContainer, pageAccessoriesContainer, isNotFoundPage } = props;
   const { isGuestUser, isSharedUser } = appContainer;
 
   return (
@@ -17,10 +17,12 @@ const PageAccessories = (props) => {
       <PageAccessoriesModalControl
         isGuestUser={isGuestUser}
         isSharedUser={isSharedUser}
+        isNotFoundPage={isNotFoundPage}
       />
       <PageAccessoriesModal
         isGuestUser={isGuestUser}
         isSharedUser={isSharedUser}
+        isNotFoundPage={isNotFoundPage}
         isOpen={pageAccessoriesContainer.state.isPageAccessoriesModalShown}
         onClose={pageAccessoriesContainer.closePageAccessoriesModal}
       />
@@ -35,6 +37,8 @@ const PageAccessoriesWrapper = withUnstatedContainers(PageAccessories, [AppConta
 PageAccessories.propTypes = {
   appContainer: PropTypes.instanceOf(AppContainer).isRequired,
   pageAccessoriesContainer: PropTypes.instanceOf(PageAccessoriesContainer).isRequired,
+
+  isNotFoundPage: PropTypes.bool.isRequired,
 };
 
 export default PageAccessoriesWrapper;

+ 6 - 4
src/client/js/components/PageAccessoriesModal.jsx

@@ -24,7 +24,7 @@ import ExpandOrContractButton from './ExpandOrContractButton';
 
 const PageAccessoriesModal = (props) => {
   const {
-    t, pageAccessoriesContainer, onClose, isGuestUser, isSharedUser,
+    t, pageAccessoriesContainer, onClose, isGuestUser, isSharedUser, isNotFoundPage,
   } = props;
   const { switchActiveTab } = pageAccessoriesContainer;
   const { activeTab, activeComponents } = pageAccessoriesContainer.state;
@@ -48,21 +48,22 @@ const PageAccessoriesModal = (props) => {
         Icon: HistoryIcon,
         i18n: t('History'),
         index: 2,
-        isLinkEnabled: v => !isGuestUser && !isSharedUser,
+        isLinkEnabled: v => !isGuestUser && !isSharedUser && !isNotFoundPage,
       },
       attachment: {
         Icon: AttachmentIcon,
         i18n: t('attachment_data'),
         index: 3,
+        isLinkEnabled: v => !isNotFoundPage,
       },
       shareLink: {
         Icon: ShareLinkIcon,
         i18n: t('share_links.share_link_management'),
         index: 4,
-        isLinkEnabled: v => !isGuestUser && !isSharedUser,
+        isLinkEnabled: v => !isGuestUser && !isSharedUser && !isNotFoundPage,
       },
     };
-  }, [t, isGuestUser, isSharedUser]);
+  }, [t, isGuestUser, isSharedUser, isNotFoundPage]);
 
   const closeModalHandler = useCallback(() => {
     if (onClose == null) {
@@ -149,6 +150,7 @@ PageAccessoriesModal.propTypes = {
   pageAccessoriesContainer: PropTypes.instanceOf(PageAccessoriesContainer).isRequired,
   isGuestUser: PropTypes.bool.isRequired,
   isSharedUser: PropTypes.bool.isRequired,
+  isNotFoundPage: PropTypes.bool.isRequired,
   isOpen: PropTypes.bool.isRequired,
   onClose: PropTypes.func,
 };

+ 16 - 6
src/client/js/components/PageAccessoriesModalControl.jsx

@@ -17,7 +17,7 @@ import { withUnstatedContainers } from './UnstatedUtils';
 
 const PageAccessoriesModalControl = (props) => {
   const {
-    t, pageAccessoriesContainer, isGuestUser, isSharedUser,
+    t, pageAccessoriesContainer, isGuestUser, isSharedUser, isNotFoundPage,
   } = props;
 
   const accessoriesBtnList = useMemo(() => {
@@ -37,27 +37,36 @@ const PageAccessoriesModalControl = (props) => {
       {
         name: 'pageHistory',
         Icon: <HistoryIcon />,
-        disabled: isGuestUser || isSharedUser,
+        disabled: isGuestUser || isSharedUser || isNotFoundPage,
         i18n: t('History'),
       },
       {
         name: 'attachment',
         Icon: <AttachmentIcon />,
-        disabled: false,
+        disabled: isNotFoundPage,
         i18n: t('attachment_data'),
       },
       {
         name: 'shareLink',
         Icon: <ShareLinkIcon />,
-        disabled: isGuestUser || isSharedUser,
+        disabled: isGuestUser || isSharedUser || isNotFoundPage,
         i18n: t('share_links.share_link_management'),
       },
     ];
-  }, [t, isGuestUser, isSharedUser]);
+  }, [t, isGuestUser, isSharedUser, isNotFoundPage]);
 
   return (
     <div className="grw-page-accessories-control d-flex flex-nowrap align-items-center justify-content-end justify-content-lg-between">
       {accessoriesBtnList.map((accessory) => {
+
+        let tooltipMessage;
+        if (accessory.disabled) {
+          tooltipMessage = isNotFoundPage ? t('not_found_page.page_not_exist') : t('Not available for guest');
+        }
+        else {
+          tooltipMessage = accessory.i18n;
+        }
+
         return (
           <Fragment key={accessory.name}>
             <div id={`shareLink-btn-wrapper-for-tooltip-for-${accessory.name}`}>
@@ -70,7 +79,7 @@ const PageAccessoriesModalControl = (props) => {
               </button>
             </div>
             <UncontrolledTooltip placement="top" target={`shareLink-btn-wrapper-for-tooltip-for-${accessory.name}`} fade={false}>
-              {accessory.disabled ? t('Not available for guest') : accessory.i18n}
+              {tooltipMessage}
             </UncontrolledTooltip>
           </Fragment>
         );
@@ -94,6 +103,7 @@ PageAccessoriesModalControl.propTypes = {
 
   isGuestUser: PropTypes.bool.isRequired,
   isSharedUser: PropTypes.bool.isRequired,
+  isNotFoundPage: PropTypes.bool.isRequired,
 };
 
 export default withTranslation()(PageAccessoriesModalControlWrapper);

+ 32 - 3
src/client/js/components/PageHistory/RevisionDiff.jsx

@@ -1,12 +1,16 @@
+/* eslint-disable react/no-danger */
 import React from 'react';
 import PropTypes from 'prop-types';
 
 import { createPatch } from 'diff';
 import { html } from 'diff2html';
+import { withTranslation } from 'react-i18next';
+import UserDate from '../User/UserDate';
 
-export default class RevisionDiff extends React.Component {
+class RevisionDiff extends React.Component {
 
   render() {
+    const { t } = this.props;
     const currentRevision = this.props.currentRevision;
     const previousRevision = this.props.previousRevision;
     const revisionDiffOpened = this.props.revisionDiffOpened;
@@ -38,14 +42,39 @@ export default class RevisionDiff extends React.Component {
     }
 
     const diffView = { __html: diffViewHTML };
-    // eslint-disable-next-line react/no-danger
-    return <div className="revision-history-diff" dangerouslySetInnerHTML={diffView} />;
+    return (
+      <>
+        <div className="comparison-header">
+          <div className="container pt-1 pr-0">
+            <div className="row">
+              <div className="col comparison-source-wrapper pt-1 px-0">
+                <span className="comparison-source pr-3">{t('page_history.comparing_source')}</span><UserDate dateTime={previousRevision.createdAt} />
+                <a href={`?revision=${previousRevision._id}`} className="ml-3">
+                  <i className="icon-login"></i>
+                </a>
+
+              </div>
+              <div className="col comparison-target-wrapper pt-1">
+                <span className="comparison-target pr-3">{t('page_history.comparing_target')}</span><UserDate dateTime={currentRevision.createdAt} />
+                <a href={`?revision=${currentRevision._id}`} className="ml-3">
+                  <i className="icon-login"></i>
+                </a>
+              </div>
+            </div>
+          </div>
+        </div>
+        <div className="revision-history-diff" dangerouslySetInnerHTML={diffView} />
+      </>
+    );
   }
 
 }
 
 RevisionDiff.propTypes = {
+  t: PropTypes.func.isRequired,
   currentRevision: PropTypes.object.isRequired,
   previousRevision: PropTypes.object.isRequired,
   revisionDiffOpened: PropTypes.bool.isRequired,
 };
+
+export default withTranslation()(RevisionDiff);

+ 1 - 16
src/client/js/components/RevisionComparer/RevisionComparer.jsx

@@ -55,20 +55,7 @@ const RevisionComparer = (props) => {
   return (
     <div className="revision-compare">
       <div className="d-flex">
-        <h3 className="align-self-center mb-0">{ t('page_history.comparing_revisions') }</h3>
-        <div className="align-self-center ml-3">
-          <div className="custom-control custom-switch">
-            <input
-              type="checkbox"
-              className="custom-control-input"
-              id="comparingWithLatest"
-              onChange={() => revisionComparerContainer.toggleCompareWithLatest()}
-            />
-            <label className="custom-control-label" htmlFor="comparingWithLatest">
-              { t('page_history.comparing_with_latest') }
-            </label>
-          </div>
-        </div>
+        <h4 className="align-self-center">{ t('page_history.comparing_revisions') }</h4>
         <Dropdown
           className="grw-copy-dropdown align-self-center ml-auto"
           isOpen={dropdownOpen}
@@ -92,8 +79,6 @@ const RevisionComparer = (props) => {
         </Dropdown>
       </div>
 
-      <hr />
-
       <div className="revision-compare-outer">
         { showDiff && (
           <RevisionDiff

+ 0 - 16
src/client/js/services/RevisionComparerContainer.js

@@ -27,7 +27,6 @@ export default class RevisionComparerContainer extends Container {
     };
 
     this.initRevisions = this.initRevisions.bind(this);
-    this.toggleCompareWithLatest = this.toggleCompareWithLatest.bind(this);
   }
 
   /**
@@ -110,19 +109,4 @@ export default class RevisionComparerContainer extends Container {
     return null;
   }
 
-  /**
-   * toggle state "compareWithLatest", and if true, set "targetRevision" to the latest revision
-   */
-  toggleCompareWithLatest() {
-    const { compareWithLatest } = this.state;
-    const newCompareWithLatest = !compareWithLatest;
-
-    this.setState(
-      Object.assign(
-        { compareWithLatest: newCompareWithLatest },
-        (newCompareWithLatest === true ? { targetRevision: this.state.latestRevision } : {}),
-      ),
-    );
-  }
-
 }

+ 26 - 1
src/client/styles/scss/_page-history.scss

@@ -1,3 +1,6 @@
+// @import '../scss/variables';
+// @import '../scss/override-bootstrap-variables';
+
 .revision-history-table {
   tbody {
     max-height: 250px;
@@ -19,15 +22,37 @@
 }
 
 .revision-history-diff {
-  padding-left: 40px;
   color: $gray-900;
   table-layout: fixed;
 }
 
+.comparison-header {
+  height: 34px;
+  background-color: #ffffff;
+  border: 1px solid $gray-300;
+  .comparison-source-wrapper {
+    height: 26px;
+    margin-right: 1px;
+    border-right: 1px solid $gray-300;
+    .comparison-source {
+      color: $gray-500;
+    }
+  }
+  .comparison-target-wrapper {
+    height: 26px;
+    .comparison-target {
+      color: $gray-500;
+    }
+  }
+}
+
 .revision-compare {
   .revision-compare-outer {
     min-height: 100px;
     max-height: 250px;
     overflow: auto;
   }
+  .d2h-file-header {
+    display: none;
+  }
 }