Jelajahi Sumber

added support for specifying RevisionId as initial value.

Ryu Sato 5 tahun lalu
induk
melakukan
fea6d7de68

+ 29 - 34
src/client/js/components/RevisionCompare.jsx

@@ -10,44 +10,39 @@ import RevisionDiff from './PageHistory/RevisionDiff';
 import RevisionIdForm from './RevisionCompare/RevisionIdForm';
 
 class PageCompare extends React.Component {
-  componentWillMount() {
+  async componentWillMount() {
     const { revisionCompareContainer } = this.props;
-    const { pageContainer } = revisionCompareContainer;
-    const { compareRevisionIds } = pageContainer.state;
-    const [fromRevisionId, toRevisionId] = compareRevisionIds;
-
-    revisionCompareContainer.fetchPageRevisionBody(fromRevisionId, toRevisionId);
-    revisionCompareContainer.fetchPageRevisions();
+    await revisionCompareContainer.readyRevisions();
   }
 
-  /**
-   * render a row (Revision component and RevisionDiff component)
-   * @param {Revision} revisionSelected
-   * @param {Array} revisionList
-   */
-  renderRevisionSelector(label) {
-    if (["FromRev", "ToRev"].indexOf(label) === -1) {
-      return <div></div>
-    }
+  // /**
+  //  * render a row (Revision component and RevisionDiff component)
+  //  * @param {Revision} revisionSelected
+  //  * @param {Array} revisionList
+  //  */
+  // renderRevisionSelector(label) {
+  //   if (["FromRev", "ToRev"].indexOf(label) === -1) {
+  //     return <div></div>
+  //   }
 
-    const { revisionCompareContainer } = this.props;
-    const selectedRev = (label === "FromRev" ? revisionCompareContainer.state.fromRevision : revisionCompareContainer.state.toRevision);
-    const changeHandler = (label === "FromRev" ? revisionCompareContainer.handleFromRevisionChange : revisionCompareContainer.handleToRevisionChange);
-    return (
-      <div class="input-group mb-3 col-sm">
-        <div class="input-group-prepend">
-          <label class="input-group-text" for="inputGroupSelect01">{ label }</label>
-        </div>
-        <select class="custom-select" id="inputGroupSelect01" value={selectedRev ? selectedRev._id : ""} onChange={e => changeHandler(e.target.value)}>
-          {
-            revisionCompareContainer.state.recentRevisions.map(rev => (
-              <option key={rev._id} value={rev._id}>{ rev._id }</option>
-            ))
-          }
-        </select>
-      </div>
-    );
-  }
+  //   const { revisionCompareContainer } = this.props;
+  //   const selectedRev = (label === "FromRev" ? revisionCompareContainer.state.fromRevision : revisionCompareContainer.state.toRevision);
+  //   const changeHandler = (label === "FromRev" ? revisionCompareContainer.handleFromRevisionChange : revisionCompareContainer.handleToRevisionChange);
+  //   return (
+  //     <div class="input-group mb-3 col-sm">
+  //       <div class="input-group-prepend">
+  //         <label class="input-group-text" for="inputGroupSelect01">{ label }</label>
+  //       </div>
+  //       <select class="custom-select" id="inputGroupSelect01" value={selectedRev ? selectedRev._id : ""} onChange={e => changeHandler(e.target.value)}>
+  //         {
+  //           revisionCompareContainer.state.recentRevisions.map(rev => (
+  //             <option key={rev._id} value={rev._id}>{ rev._id }</option>
+  //           ))
+  //         }
+  //       </select>
+  //     </div>
+  //   );
+  // }
 
   render() {
     const { t, revisionCompareContainer } = this.props;

+ 22 - 14
src/client/js/components/RevisionCompare/RevisionIdForm.jsx

@@ -15,42 +15,50 @@ class RevisionIdForm extends React.Component {
     };
 
     this.loadFilteredRevisionOptions = this.loadFilteredRevisionOptions.bind(this);
-    this.handleInputChange = this.handleInputChange.bind(this);
   }
 
-  loadFilteredRevisionOptions(inputText, callback) {
+  revisionOptions() {
     const { revisionCompareContainer } = this.props;
-    const revisionOptions = revisionCompareContainer.state.recentRevisions.map(rev => {
+    return revisionCompareContainer.state.recentRevisions.map(rev => {
       return { label: rev._id, value: rev._id };
     });
-    const filteredRevisionOptions = revisionOptions.filter(rev =>
-      rev.label.toLowerCase().includes(inputText.toLowerCase())
-    );
+  }
+
+  async loadFilteredRevisionOptions(inputText, callback) {
+    console.log(`loadFilteredRevisionOptions is called`);
+    const { revisionCompareContainer } = this.props;
+
+    // If the RevisionId user entered exists, it is added to the list.
+    await revisionCompareContainer.fetchPageRevisionIfExists(inputText);
 
-    return callback(filteredRevisionOptions);
+    // Filter the RevisionId that matches the text user entered.
+    const revisionOptions = this.revisionOptions();
+    const filteredRevisionOptions = revisionOptions.filter(rev => rev.label.toLowerCase().includes(inputText.toLowerCase()));
+    callback(filteredRevisionOptions);
   }
 
   /**
    * render a row (Revision component and RevisionDiff component)
    * @param {label} label text of inputbox
    */
-  renderRevisionSelector(label) {
+  renderRevisionSelector(label, inputText) {
     if (["FromRev", "ToRev"].indexOf(label) === -1) {
       return <div></div>
     }
+    const forFromRev = (label === "FromRev");
 
     const { revisionCompareContainer } = this.props;
-    const changeHandler = (label === "FromRev" ? revisionCompareContainer.handleFromRevisionChange : revisionCompareContainer.handleToRevisionChange);
+    const changeHandler = (forFromRev ? revisionCompareContainer.handleFromRevisionChange : revisionCompareContainer.handleToRevisionChange);
+    const rev = (forFromRev ? revisionCompareContainer.state.fromRevision?._id : revisionCompareContainer.state.toRevision?._id );
     return (
-      <div class="input-group mb-3 col-sm">
-        <div class="input-group-prepend">
-          <label class="input-group-text" for="inputGroupSelect01">{ label }</label>
-        </div>
+      <div class="mb-3 col-sm">
         <AsyncSelect
           cacheOptions
           loadOptions={this.loadFilteredRevisionOptions}
-          defaultOptions
+          defaultOptions={this.revisionOptions()}
           onChange={(selectedOption) => changeHandler(selectedOption.value)}
+          placeholder={label}
+          options={[rev]}
         />
       </div>
     );

+ 91 - 24
src/client/js/services/RevisionCompareContainer.js

@@ -26,7 +26,13 @@ export default class RevisionCompareContainer extends Container {
       recentRevisions: [],
     }
 
+    this.readyRevisions = this.readyRevisions.bind(this);
     this.fetchPageRevisionBody = this.fetchPageRevisionBody.bind(this);
+    // this.fetchPageRevisionBodyForFrom = this.fetchPageRevisionBodyForFrom.bind(this);
+    // this.fetchPageRevisionBodyForTo = this.fetchPageRevisionBodyForTo.bind(this);
+    this.fetchPageRevisions = this.fetchPageRevisions.bind(this);
+    // this.appendRevisionToRecentRevisions = this.appendRevisionToRecentRevisions.bind(this);
+    this.fetchPageRevisionIfExists = this.fetchPageRevisionIfExists.bind(this);
     this.handleFromRevisionChange = this.handleFromRevisionChange.bind(this);
     this.handleToRevisionChange = this.handleToRevisionChange.bind(this);
   }
@@ -38,25 +44,31 @@ export default class RevisionCompareContainer extends Container {
     return 'RevisionCompareContainer';
   }
 
+  async readyRevisions() {
+    const [fromRevisionIdParam, toRevisionIdParam] = this.pageContainer.state.compareRevisionIds || [];
+
+    await this.fetchPageRevisions();
+    await this.fetchPageRevisionIfExists(fromRevisionIdParam);
+    await this.fetchPageRevisionIfExists(toRevisionIdParam);
+
+    const fromRevision = this.state.recentRevisions.find(rev => rev._id === fromRevisionIdParam);
+    const toRevision = this.state.recentRevisions.find(rev => rev._id === toRevisionIdParam);
+    this.setState({ fromRevision, toRevision });
+  }
+
   /**
    * fetch page revision body by revision_id in argument
-   * @param {string} fromRevisionId
-   * @param {string} toRevisionId
+   * @param {string} revisionId
    */
-  async fetchPageRevisionBody(fromRevisionId, toRevisionId) {
+  async fetchPageRevisionBody(revisionId) {
     const { pageId, shareLinkId } = this.pageContainer.state;
     try {
-      const revsAll = [
-        { id: fromRevisionId, key: "fromRevision" },
-        { id: toRevisionId,   key: "toRevision" },
-      ];
-      const revs = revsAll.filter(it => it && it.id);
-      for(let it of revs) {
-        const res = await this.appContainer.apiv3Get(`/revisions/${it.id}`, { pageId, shareLinkId });
-        const state = {}
-        state[it.key] = res.data.revision;
-        this.setState(state);
+      const res = await this.appContainer.apiv3Get(`/revisions/${revisionId}`, { pageId, shareLinkId });
+      if (!res || !res.data || !res.data.revision) {
+        console.log(`cannot get revision: ${res}`);
+        return null;
       }
+      return res.data.revision;
     }
     catch (err) {
       toastError(err);
@@ -65,14 +77,33 @@ export default class RevisionCompareContainer extends Container {
     }
   }
 
+  // async fetchPageRevisionBodyForFrom(revisionId) {
+  //   console.log("fetchPageRevisionBodyForFrom is called");
+  //   const fromRevision = await this.fetchPageRevisionBody(revisionId);
+  //   if (fromRevision) {
+  //     this.setState({ fromRevision });
+  //     this.appendRevisionToRecentRevisions(fromRevision);
+  //   }
+  // }
+
+  // async fetchPageRevisionBodyForTo(revisionId) {
+  //   console.log("fetchPageRevisionBodyForTo is called");
+  //   const toRevision = await this.fetchPageRevisionBody(revisionId);
+  //   if (toRevision) {
+  //     this.setState({ toRevision });
+  //     this.appendRevisionToRecentRevisions(toRevision);
+  //   }
+  // }
+
   async fetchPageRevisions() {
     const { pageId, shareLinkId } = this.pageContainer.state;
     const page = 1; // The pagination start number is fixed to 1.
     const res = await this.appContainer.apiv3Get('/revisions/list', {
-      pageId, shareLinkId, page, limit: 100,
+      pageId, shareLinkId, page, limit: 2,
     });
     const recentRevisions = res.data.docs;
 
+    // [TODO] delete if no need
     res.data.docs.forEach((revision, i) => {
       const user = revision.author;
       if (user) {
@@ -83,18 +114,54 @@ export default class RevisionCompareContainer extends Container {
     this.setState({ recentRevisions });
   }
 
-  handleFromRevisionChange(revisionId) {
-    this.setState({
-      fromRevision: revisionId
-    })
-    this.fetchPageRevisionBody(revisionId, this.state.toRevision._id);
+  // appendRevisionToRecentRevisions(revision) {
+  //   const newRecentRevisions = this.state.recentRevisions;
+  //   newRecentRevisions.push(revision);
+  //   newRecentRevisions.sort((a, b) => {
+  //     if (a._id < b._id) { return -1; }
+  //     if (a._id > b._id) { return 1; }
+  //     return 0;
+  //   });
+  //   this.setState({ recentRevisions: newRecentRevisions });
+  // }
+
+  async fetchPageRevisionIfExists(revisionId) {
+    try {
+      const revision = await this.fetchPageRevisionBody(revisionId);
+      if (!revision || this.state.recentRevisions.map(rev => rev._id).includes(revision._id)) {
+        return null;
+      }
+
+      const newRecentRevisions = this.state.recentRevisions;
+      newRecentRevisions.push(revision);
+      newRecentRevisions.sort((a, b) => {
+        if (a._id < b._id) { return -1; }
+        if (a._id > b._id) { return 1; }
+        return 0;
+      });
+      this.setState({ recentRevisions: newRecentRevisions });
+      return revision;
+    }
+    catch (err) {
+      // If the RevisionId being entered is not correct, no special action will be taken.
+      // [TODO] ignore default error handling of apiv3ErrorHandler
+      if (err.length === 1 && err[0].code === 'validation_failed') {
+        return;
+      }
+      toastError(err);
+      this.setState({ errorMessage: err.message });
+      logger.error(err);
+    }
+  }
+
+  async handleFromRevisionChange(revisionId) {
+    const fromRevision = await this.fetchPageRevisionBody(revisionId);
+    this.setState({ fromRevision })
   }
 
-  handleToRevisionChange(revisionId) {
-    this.setState({
-      toRevision: revisionId
-    })
-    this.fetchPageRevisionBody(this.state.fromRevision._id, revisionId);
+  async handleToRevisionChange(revisionId) {
+    const toRevision = await this.fetchPageRevisionBody(revisionId);
+    this.setState({ toRevision })
   }
 
 }