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

Merge pull request #2739 from weseek/feat/GW-3609-add-button-for-shre-link

Feat/gw 3609 add button for shre link
Yuki Takei 5 лет назад
Родитель
Сommit
78e0ee94f2

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

@@ -19,7 +19,6 @@ import PageComments from './components/PageComments';
 import PageTimeline from './components/PageTimeline';
 import CommentEditorLazyRenderer from './components/PageComment/CommentEditorLazyRenderer';
 import PageManagement from './components/Page/PageManagement';
-import PageShareManagement from './components/Page/PageShareManagement';
 import TrashPageAlert from './components/Page/TrashPageAlert';
 import PageAttachment from './components/PageAttachment';
 import PageStatusAlert from './components/PageStatusAlert';
@@ -90,7 +89,6 @@ if (pageContainer.state.pageId != null) {
     'page-comment-write': <CommentEditorLazyRenderer />,
     'page-attachment': <PageAttachment />,
     'page-management': <PageManagement />,
-    'page-share-management': <PageShareManagement />,
 
     'revision-toc': <TableOfContents />,
     'seen-user-list': <SeenUserList />,

+ 1 - 1
src/client/js/components/Admin/Security/ShareLinkSetting.jsx

@@ -11,7 +11,7 @@ import AppContainer from '../../../services/AppContainer';
 import AdminGeneralSecurityContainer from '../../../services/AdminGeneralSecurityContainer';
 
 import DeleteAllShareLinksModal from './DeleteAllShareLinksModal';
-import ShareLinkList from '../../ShareLinkList';
+import ShareLinkList from '../../ShareLink/ShareLinkList';
 
 class ShareLinkSetting extends React.Component {
 

+ 35 - 0
src/client/js/components/Icons/ShareLinkIcon.jsx

@@ -0,0 +1,35 @@
+import React from 'react';
+
+const ShareLink = () => (
+  <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20">
+    <g transform="translate(-142 -502)">
+      <rect width="20" height="20" transform="translate(142 502)" fill="none" />
+      <g transform="translate(16 286.938)">
+        <path
+          d="M-1.813-3.563a2.711,2.711,0,0,0-1.274.308,2.8,2.8,0,0,0-.976.835L-11.48-6.2a2.676,2.676,
+          0,0,0,.105-.738,2.555,2.555,0,0,0-.044-.466,3.34,3.34,0,0,0-.114-.448l7.453-3.621a2.71,2.71,
+          0,0,0,.984.853,2.764,2.764,0,0,0,1.283.308,2.708,2.708,0,0,0,1.986-.826A2.708,2.708,0,0,
+          0,1-13.125a2.751,2.751,0,0,0-.378-1.406A2.793,2.793,0,0,0-.406-15.56a2.751,2.751,0,0,
+          0-1.406-.378,2.751,2.751,0,0,0-1.406.378,2.793,2.793,0,0,0-1.028,1.028,2.751,2.751,0,0,0-.378,
+          1.406v.105a.64.64,0,0,0,.009.105.641.641,0,0,1,.009.105A.641.641,0,0,0-4.6-12.7a.694.694,0,0,0,
+          .026.105.332.332,0,0,1,.018.105l-7.559,3.674a2.735,2.735,0,0,0-.923-.686,2.727,2.727,0,0,
+          0-1.151-.246,2.708,2.708,0,0,0-1.986.826A2.708,2.708,0,0,0-17-6.937a2.708,2.708,0,0,0,
+          .826,1.986,2.708,2.708,0,0,0,1.986.826A2.666,2.666,0,0,0-11.99-5.2l7.453,3.8a1.388,1.388,0,0,
+          0-.053.211q-.018.105-.026.22t-.009.22A2.751,2.751,0,0,0-4.247.656,2.792,2.792,0,0,0-3.219,
+          1.685a2.751,2.751,0,0,0,1.406.378A2.708,2.708,0,0,0,.174,1.236,2.708,2.708,0,0,0,1-.75,2.708,
+          2.708,0,0,0,.174-2.736,2.708,2.708,0,0,0-1.813-3.563Zm-1.2-10.758a1.627,1.627,0,0,1,1.2-.492,
+          1.627,1.627,0,0,1,1.2.492,1.627,1.627,0,0,1,.492,1.2,1.627,1.627,0,0,1-.492,1.2,1.627,1.627,
+          0,0,1-1.2.492,1.627,1.627,0,0,1-1.2-.492,1.627,1.627,0,0,1-.492-1.2A1.627,1.627,0,0,
+          1-3.008-14.32Zm-9.984,8.578a1.627,1.627,0,0,1-1.2.492,1.627,1.627,0,0,1-1.2-.492,1.627,
+          1.627,0,0,1-.492-1.2,1.627,1.627,0,0,1,.492-1.2,1.627,1.627,0,0,1,1.2-.492,1.627,1.627,
+          0,0,1,1.2.492,1.627,1.627,0,0,1,.492,1.2A1.627,1.627,0,0,1-12.992-5.742ZM-.617.445a1.627,
+          1.627,0,0,1-1.2.492,1.627,1.627,0,0,1-1.2-.492A1.627,1.627,0,0,1-3.5-.75a1.627,1.627,0,0,
+          1,.492-1.2,1.627,1.627,0,0,1,1.2-.492,1.627,1.627,0,0,1,1.2.492A1.627,1.627,0,0,1-.125-.75,1.627,1.627,0,0,1-.617.445Z"
+          transform="translate(144 232)"
+        />
+      </g>
+    </g>
+  </svg>
+);
+
+export default ShareLink;

+ 38 - 0
src/client/js/components/Page/PageManagement.jsx

@@ -2,6 +2,7 @@ import React, { useState } from 'react';
 import PropTypes from 'prop-types';
 import { UncontrolledTooltip } from 'reactstrap';
 import { withTranslation } from 'react-i18next';
+import urljoin from 'url-join';
 
 import { isTopPage } from '@commons/util/path-utils';
 import { withUnstatedContainers } from '../UnstatedUtils';
@@ -58,6 +59,36 @@ const PageManagement = (props) => {
   }
 
 
+  // TODO GW-2746 bulk export pages
+  // async function getArchivePageData() {
+  //   try {
+  //     const res = await appContainer.apiv3Get('page/count-children-pages', { pageId });
+  //     setTotalPages(res.data.dummy);
+  //   }
+  //   catch (err) {
+  //     setErrorMessage(t('export_bulk.failed_to_count_pages'));
+  //   }
+  // }
+
+  async function exportPageHandler(format) {
+    const { pageId, revisionId } = pageContainer.state;
+    const url = new URL(urljoin(window.location.origin, '_api/v3/page/export', pageId));
+    url.searchParams.append('format', format);
+    url.searchParams.append('revisionId', revisionId);
+    window.location.href = url.href;
+  }
+
+  // TODO GW-2746 create api to bulk export pages
+  // function openArchiveModalHandler() {
+  //   setIsArchiveCreateModalShown(true);
+  //   getArchivePageData();
+  // }
+
+  // TODO GW-2746 create api to bulk export pages
+  // function closeArchiveCreateModalHandler() {
+  //   setIsArchiveCreateModalShown(false);
+  // }
+
   function renderDropdownItemForNotTopPage() {
     return (
       <>
@@ -67,6 +98,13 @@ const PageManagement = (props) => {
         <button className="dropdown-item" type="button" onClick={openPageDuplicateModalHandler}>
           <i className="icon-fw icon-docs"></i> { t('Duplicate') }
         </button>
+        <button type="button" className="dropdown-item" onClick={() => { exportPageHandler('md') }}>
+          <i className="icon-fw icon-cloud-download"></i>{t('export_bulk.export_page_markdown')}
+        </button>
+        {/* TODO GW-2746 create api to bulk export pages */}
+        {/* <button className="dropdown-item" type="button" onClick={openArchiveModalHandler}>
+          <i className="icon-fw"></i>{t('Create Archive Page')}
+        </button> */}
         <div className="dropdown-divider"></div>
       </>
     );

+ 0 - 159
src/client/js/components/Page/PageShareManagement.jsx

@@ -1,159 +0,0 @@
-import React, { useState } from 'react';
-import PropTypes from 'prop-types';
-import { UncontrolledTooltip } from 'reactstrap';
-import { withTranslation } from 'react-i18next';
-import urljoin from 'url-join';
-import { withUnstatedContainers } from '../UnstatedUtils';
-
-import AppContainer from '../../services/AppContainer';
-import PageContainer from '../../services/PageContainer';
-import OutsideShareLinkModal from '../OutsideShareLinkModal';
-
-// TODO GW-2746 bulk export pages
-// import ArchiveCreateModal from '../ArchiveCreateModal';
-
-const PageShareManagement = (props) => {
-  const { t, appContainer, pageContainer } = props;
-
-  // TODO GW-2746 bulk export pages
-  // eslint-disable-next-line no-unused-vars
-  const { path, pageId } = pageContainer.state;
-  const { currentUser } = appContainer;
-
-  const [isOutsideShareLinkModalShown, setIsOutsideShareLinkModalShown] = useState(false);
-
-  // TODO GW-2746 bulk export pages
-  // const [isArchiveCreateModalShown, setIsArchiveCreateModalShown] = useState(false);
-  // const [totalPages, setTotalPages] = useState(null);
-  // const [errorMessage, setErrorMessage] = useState(null);
-
-  function openOutsideShareLinkModalHandler() {
-    setIsOutsideShareLinkModalShown(true);
-  }
-
-  function closeOutsideShareLinkModalHandler() {
-    setIsOutsideShareLinkModalShown(false);
-  }
-
-  // TODO GW-2746 bulk export pages
-  // async function getArchivePageData() {
-  //   try {
-  //     const res = await appContainer.apiv3Get('page/count-children-pages', { pageId });
-  //     setTotalPages(res.data.dummy);
-  //   }
-  //   catch (err) {
-  //     setErrorMessage(t('export_bulk.failed_to_count_pages'));
-  //   }
-  // }
-
-  async function exportPageHandler(format) {
-    const { pageId, revisionId } = pageContainer.state;
-    const url = new URL(urljoin(window.location.origin, '_api/v3/page/export', pageId));
-    url.searchParams.append('format', format);
-    url.searchParams.append('revisionId', revisionId);
-    window.location.href = url.href;
-  }
-
-  // TODO GW-2746 create api to bulk export pages
-  // function openArchiveModalHandler() {
-  //   setIsArchiveCreateModalShown(true);
-  //   getArchivePageData();
-  // }
-
-  // TODO GW-2746 create api to bulk export pages
-  // function closeArchiveCreateModalHandler() {
-  //   setIsArchiveCreateModalShown(false);
-  // }
-
-
-  function renderModals() {
-    if (currentUser == null) {
-      return null;
-    }
-
-    return (
-      <>
-        <OutsideShareLinkModal
-          isOpen={isOutsideShareLinkModalShown}
-          onClose={closeOutsideShareLinkModalHandler}
-        />
-
-        {/* TODO GW-2746 bulk export pages */}
-        {/* <ArchiveCreateModal
-          isOpen={isArchiveCreateModalShown}
-          onClose={closeArchiveCreateModalHandler}
-          path={path}
-          errorMessage={errorMessage}
-          totalPages={totalPages}
-        /> */}
-      </>
-    );
-  }
-
-
-  function renderCurrentUser() {
-    return (
-      <>
-        <button
-          type="button"
-          className="btn-link nav-link bg-transparent dropdown-toggle dropdown-toggle-no-caret"
-          data-toggle="dropdown"
-        >
-          <i className="icon-share"></i>
-        </button>
-      </>
-    );
-  }
-
-  function renderGuestUser() {
-    return (
-      <>
-        <button
-          type="button"
-          className="btn nav-link bg-transparent dropdown-toggle dropdown-toggle-no-caret disabled"
-          id="auth-guest-tltips"
-        >
-          <i className="icon-share"></i>
-        </button>
-        <UncontrolledTooltip placement="top" target="auth-guest-tltips">
-          {t('Not available for guest')}
-        </UncontrolledTooltip>
-      </>
-    );
-  }
-
-  return (
-    <>
-      {currentUser == null ? renderGuestUser() : renderCurrentUser()}
-      <div className="dropdown-menu dropdown-menu-right">
-        <button className="dropdown-item" type="button" onClick={openOutsideShareLinkModalHandler}>
-          <i className="icon-fw icon-link"></i>{t('share_links.Shere this page link to public')}
-          <span className="ml-2 badge badge-info badge-pill">{pageContainer.state.shareLinksNumber}</span>
-        </button>
-        <button type="button" className="dropdown-item" onClick={() => { exportPageHandler('md') }}>
-          <span>{t('export_bulk.export_page_markdown')}</span>
-        </button>
-        {/* TODO GW-2746 create api to bulk export pages */}
-        {/* <button className="dropdown-item" type="button" onClick={openArchiveModalHandler}>
-          <i className="icon-fw"></i>{t('Create Archive Page')}
-        </button> */}
-      </div>
-      {renderModals()}
-    </>
-  );
-
-};
-
-/**
- * Wrapper component for using unstated
- */
-const PageShareManagementWrapper = withUnstatedContainers(PageShareManagement, [AppContainer, PageContainer]);
-
-
-PageShareManagement.propTypes = {
-  t: PropTypes.func.isRequired, // i18next
-  appContainer: PropTypes.instanceOf(AppContainer).isRequired,
-  pageContainer: PropTypes.instanceOf(PageContainer).isRequired,
-};
-
-export default withTranslation()(PageShareManagementWrapper);

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

@@ -11,6 +11,7 @@ import PageListIcon from './Icons/PageListIcon';
 import TimeLineIcon from './Icons/TimeLineIcon';
 import RecentChangesIcon from './Icons/RecentChangesIcon';
 import AttachmentIcon from './Icons/AttachmentIcon';
+import ShareLinkIcon from './Icons/ShareLinkIcon';
 
 import { withUnstatedContainers } from './UnstatedUtils';
 import PageAccessoriesContainer from '../services/PageAccessoriesContainer';
@@ -18,6 +19,7 @@ import PageAttachment from './PageAttachment';
 import PageTimeline from './PageTimeline';
 import PageList from './PageList';
 import PageHistory from './PageHistory';
+import ShareLink from './ShareLink/ShareLink';
 
 const PageAccessoriesModal = (props) => {
   const { t, pageAccessoriesContainer } = props;
@@ -33,7 +35,7 @@ const PageAccessoriesModal = (props) => {
 
   return (
     <React.Fragment>
-      <Modal size="lg" isOpen={props.isOpen} toggle={closeModalHandler} className="grw-page-accessories-modal">
+      <Modal size="xl" isOpen={props.isOpen} toggle={closeModalHandler} className="grw-page-accessories-modal">
         <ModalBody>
           <Nav className="nav-title border-bottom">
             <NavItem type="button" className={`nav-link ${activeTab === 'pagelist' && 'active active-border'}`}>
@@ -76,6 +78,16 @@ const PageAccessoriesModal = (props) => {
                 {t('attachment_data')}
               </NavLink>
             </NavItem>
+            <NavItem type="button" className={`nav-link ${activeTab === 'share-link' && 'active active-border'}`}>
+              <NavLink
+                onClick={() => {
+                  switchActiveTab('share-link');
+                }}
+              >
+                <ShareLinkIcon />
+                {t('share_links.share_link_management')}
+              </NavLink>
+            </NavItem>
           </Nav>
           <TabContent activeTab={activeTab}>
 
@@ -93,6 +105,9 @@ const PageAccessoriesModal = (props) => {
             <TabPane tabId="attachment" className="p-4">
               {pageAccessoriesContainer.state.activeComponents.has('attachment') && <PageAttachment />}
             </TabPane>
+            <TabPane tabId="share-link" className="p-4">
+              {pageAccessoriesContainer.state.activeComponents.has('share-link') && <ShareLink />}
+            </TabPane>
           </TabContent>
         </ModalBody>
       </Modal>

+ 29 - 40
src/client/js/components/OutsideShareLinkModal.jsx → src/client/js/components/ShareLink/ShareLink.jsx

@@ -1,23 +1,18 @@
 import React from 'react';
 import PropTypes from 'prop-types';
 
-import {
-  Modal, ModalHeader, ModalBody,
-} from 'reactstrap';
-
 import { withTranslation } from 'react-i18next';
+import { withUnstatedContainers } from '../UnstatedUtils';
 
-import { withUnstatedContainers } from './UnstatedUtils';
-
-import AppContainer from '../services/AppContainer';
-import PageContainer from '../services/PageContainer';
+import AppContainer from '../../services/AppContainer';
+import PageContainer from '../../services/PageContainer';
 
 import ShareLinkList from './ShareLinkList';
 import ShareLinkForm from './ShareLinkForm';
 
-import { toastSuccess, toastError } from '../util/apiNotification';
+import { toastSuccess, toastError } from '../../util/apiNotification';
 
-class OutsideShareLinkModal extends React.Component {
+class ShareLink extends React.Component {
 
   constructor() {
     super();
@@ -90,33 +85,27 @@ class OutsideShareLinkModal extends React.Component {
     const { t } = this.props;
 
     return (
-      <Modal size="xl" isOpen={this.props.isOpen} toggle={this.props.onClose}>
-        <ModalHeader tag="h4" toggle={this.props.onClose} className="bg-primary text-light">{t('share_links.Shere this page link to public')}
-        </ModalHeader>
-        <ModalBody>
-          <div className="container">
-            <h3 className="grw-modal-head  d-flex  pb-2">
-              { t('share_links.share_link_list') }
-              <button className="btn btn-danger ml-auto " type="button" onClick={this.deleteAllLinksButtonHandler}>{t('delete_all')}</button>
-            </h3>
-
-            <div>
-              <ShareLinkList
-                shareLinks={this.state.shareLinks}
-                onClickDeleteButton={this.deleteLinkById}
-              />
-              <button
-                className="btn btn-outline-secondary d-block mx-auto px-5 mb-3"
-                type="button"
-                onClick={this.toggleShareLinkFormHandler}
-              >
-                {this.state.isOpenShareLinkForm ? t('Close') : t('New')}
-              </button>
-              {this.state.isOpenShareLinkForm && <ShareLinkForm onCloseForm={this.toggleShareLinkFormHandler} />}
-            </div>
-          </div>
-        </ModalBody>
-      </Modal>
+      <div className="container">
+        <h3 className="grw-modal-head  d-flex  pb-2">
+          { t('share_links.share_link_list') }
+          <button className="btn btn-danger ml-auto " type="button" onClick={this.deleteAllLinksButtonHandler}>{t('delete_all')}</button>
+        </h3>
+
+        <div>
+          <ShareLinkList
+            shareLinks={this.state.shareLinks}
+            onClickDeleteButton={this.deleteLinkById}
+          />
+          <button
+            className="btn btn-outline-secondary d-block mx-auto px-5 mb-3"
+            type="button"
+            onClick={this.toggleShareLinkFormHandler}
+          >
+            {this.state.isOpenShareLinkForm ? t('Close') : t('New')}
+          </button>
+          {this.state.isOpenShareLinkForm && <ShareLinkForm onCloseForm={this.toggleShareLinkFormHandler} />}
+        </div>
+      </div>
     );
   }
 
@@ -125,9 +114,9 @@ class OutsideShareLinkModal extends React.Component {
 /**
  * Wrapper component for using unstated
  */
-const ModalControlWrapper = withUnstatedContainers(OutsideShareLinkModal, [AppContainer, PageContainer]);
+const ShareLinkWrapper = withUnstatedContainers(ShareLink, [AppContainer, PageContainer]);
 
-OutsideShareLinkModal.propTypes = {
+ShareLink.propTypes = {
   t: PropTypes.func.isRequired, //  i18next
   appContainer: PropTypes.instanceOf(AppContainer).isRequired,
   pageContainer: PropTypes.instanceOf(PageContainer).isRequired,
@@ -136,4 +125,4 @@ OutsideShareLinkModal.propTypes = {
   onClose: PropTypes.func.isRequired,
 };
 
-export default withTranslation()(ModalControlWrapper);
+export default withTranslation()(ShareLinkWrapper);

+ 4 - 4
src/client/js/components/ShareLinkForm.jsx → src/client/js/components/ShareLink/ShareLinkForm.jsx

@@ -6,12 +6,12 @@ import dateFnsFormat from 'date-fns/format';
 import parse from 'date-fns/parse';
 
 import { isInteger } from 'core-js/fn/number';
-import { withUnstatedContainers } from './UnstatedUtils';
+import { withUnstatedContainers } from '../UnstatedUtils';
 
-import { toastSuccess, toastError } from '../util/apiNotification';
+import { toastSuccess, toastError } from '../../util/apiNotification';
 
-import AppContainer from '../services/AppContainer';
-import PageContainer from '../services/PageContainer';
+import AppContainer from '../../services/AppContainer';
+import PageContainer from '../../services/PageContainer';
 
 class ShareLinkForm extends React.Component {
 

+ 3 - 3
src/client/js/components/ShareLinkList.jsx → src/client/js/components/ShareLink/ShareLinkList.jsx

@@ -5,10 +5,10 @@ import PropTypes from 'prop-types';
 import { withTranslation } from 'react-i18next';
 import dateFnsFormat from 'date-fns/format';
 
-import { withUnstatedContainers } from './UnstatedUtils';
+import { withUnstatedContainers } from '../UnstatedUtils';
 
-import AppContainer from '../services/AppContainer';
-import CopyDropdown from './Page/CopyDropdown';
+import AppContainer from '../../services/AppContainer';
+import CopyDropdown from '../Page/CopyDropdown';
 
 const ShareLinkList = (props) => {
 

+ 9 - 0
src/client/js/components/TopOfTableContents.jsx

@@ -9,6 +9,7 @@ import PageListIcon from './Icons/PageListIcon';
 import TimeLineIcon from './Icons/TimeLineIcon';
 import RecentChangesIcon from './Icons/RecentChangesIcon';
 import AttachmentIcon from './Icons/AttachmentIcon';
+import ShareLinkIcon from './Icons/ShareLinkIcon';
 
 import PageAccessoriesModal from './PageAccessoriesModal';
 
@@ -63,6 +64,14 @@ const TopOfTableContents = (props) => {
           <AttachmentIcon />
         </button>
 
+        <button
+          type="button"
+          className="btn btn-link grw-btn-top-of-table"
+          onClick={() => pageAccessoriesContainer.openPageAccessoriesModal('share-link')}
+        >
+          <ShareLinkIcon />
+        </button>
+
         <div
           id="seen-user-list"
           data-user-ids-str="{{ page.seenUsers|slice(-15)|default([])|reverse|join(',') }}"

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

@@ -63,11 +63,6 @@
     </a>
   </li>
 
-  <!-- Outside-share-link -->
-  {% if !isTrashPage() %}
-    <li id="page-share-management" class="nav-item dropdown d-edit-none"></li>
-  {% endif %}
-
   <!-- icon-options-vertical -->
   {% if !isTrashPage() %}
     <li id="page-management" class="nav-item dropdown d-edit-none"></li>