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

Merge branch 'master' into fix/gw7931-fix-dnd-behavior

Ryoji Shimizu 3 лет назад
Родитель
Сommit
520a5e0e0c

+ 5 - 4
packages/app/src/components/PageComment/CommentEditor.tsx

@@ -230,6 +230,7 @@ export const CommentEditor = (props: CommentEditorProps): JSX.Element => {
             type="button"
             className="btn btn-lg btn-link"
             onClick={() => setIsReadyToUse(true)}
+            data-testid="open-comment-editor-button"
           >
             <i className="icon-bubble"></i> Add Comment
           </button>
@@ -300,9 +301,9 @@ export const CommentEditor = (props: CommentEditorProps): JSX.Element => {
         <div className="comment-submit">
           <div className="d-flex">
             <span className="flex-grow-1" />
-            <span className="d-none d-sm-inline">{ errorMessage && errorMessage }</span>
+            <span className="d-none d-sm-inline">{errorMessage && errorMessage}</span>
 
-            { isSlackConfigured && isSlackEnabled != null
+            {isSlackConfigured && isSlackEnabled != null
               && (
                 <div className="form-inline align-self-center mr-md-2">
                   <SlackNotification
@@ -321,7 +322,7 @@ export const CommentEditor = (props: CommentEditorProps): JSX.Element => {
           </div>
           <div className="d-block d-sm-none mt-2">
             <div className="d-flex justify-content-end">
-              { error && errorMessage }
+              {error && errorMessage}
               <span className="mr-2">{cancelButton}</span><span>{submitButton}</span>
             </div>
           </div>
@@ -337,7 +338,7 @@ export const CommentEditor = (props: CommentEditorProps): JSX.Element => {
           <UserPicture user={currentUser} noLink noTooltip />
         </div>
         <div className="comment-form-main">
-          { isReadyToUse
+          {isReadyToUse
             ? renderReady()
             : renderBeforeReady()
           }

+ 1 - 0
packages/app/src/components/PageEditor/CodeMirrorEditor.jsx

@@ -40,6 +40,7 @@ import styles from './CodeMirrorEditor.module.scss';
 window.JSHINT = JSHINT;
 window.kuromojin = { dicPath: '/static/dict' };
 
+require('codemirror/addon/hint/show-hint.css'); // Import from CodeMirrorEditor.module.scss not working
 require('codemirror/addon/display/placeholder');
 require('codemirror/addon/edit/matchbrackets');
 require('codemirror/addon/edit/matchtags');

+ 0 - 1
packages/app/src/components/PageEditor/CodeMirrorEditor.module.scss

@@ -4,7 +4,6 @@
   @import '~codemirror/lib/codemirror';
 
   // addons
-  @import '~codemirror/addon/hint/show-hint';
   @import '~codemirror/addon/fold/foldgutter';
   @import '~codemirror/addon/lint/lint';
 

+ 15 - 12
packages/app/src/components/PageEditor/CommentMentionHelper.ts

@@ -1,20 +1,22 @@
-import i18n from 'i18next';
+import { Editor } from 'codemirror';
+import { i18n } from 'next-i18next';
 import { debounce } from 'throttle-debounce';
 
 import { apiv3Get } from '~/client/util/apiv3-client';
 
+type UsersListForHints = {
+  text: string
+  displayText: string
+}
 export default class CommentMentionHelper {
 
-  editor;
-
-  pattern: RegExp;
-
+  editor: Editor;
 
-  constructor(editor) {
+  constructor(editor: Editor) {
     this.editor = editor;
   }
 
-  getUsernamHint = () => {
+  getUsenameHint = (): void => {
     // Get word that contains `@` character at the begining
     const currentPos = this.editor.getCursor();
     const wordStart = this.editor.findWordAt(currentPos).anchor.ch - 1;
@@ -32,14 +34,15 @@ export default class CommentMentionHelper {
     }
 
     // Get username after `@` character and search username
-    const mention = searchMention.substr(1);
+    const mention = searchMention.slice(1);
     this.editor.showHint({
       completeSingle: false,
       hint: async() => {
         if (mention.length > 0) {
           const users = await this.getUsersList(mention);
           return {
-            list: users.length > 0 ? users : [{ text: '', displayText: i18n.t('page_comment.no_user_found') }],
+            // Returns default value if i18n is null because it cannot do early return.
+            list: users.length > 0 ? users : [{ text: '', displayText: i18n != null ? i18n.t('page_comment.no_user_found') : 'No user found' }],
             from: searchFrom,
             to: searchTo,
           };
@@ -48,15 +51,15 @@ export default class CommentMentionHelper {
     });
   };
 
-  getUsersList = async(q: string) => {
+  getUsersList = async(q: string): Promise<UsersListForHints[]> => {
     const limit = 20;
     const { data } = await apiv3Get('/users/usernames', { q, limit });
-    return data.activeUser.usernames.map(username => ({
+    return data.activeUser.usernames.map((username: string) => ({
       text: `@${username} `,
       displayText: username,
     }));
   };
 
-  showUsernameHint = debounce(800, () => this.getUsernamHint());
+  showUsernameHint = debounce(800, () => this.getUsenameHint());
 
 }

+ 6 - 5
packages/app/src/components/PageSideContents.tsx

@@ -37,7 +37,7 @@ export const PageSideContents = (props: PageSideContentsProps): JSX.Element => {
     <>
       {/* Page list */}
       <div className={`grw-page-accessories-control ${styles['grw-page-accessories-control']}`}>
-        { !isSharedUser && (
+        {!isSharedUser && (
           <button
             type="button"
             className="btn btn-block btn-outline-secondary grw-btn-page-accessories rounded-pill d-flex justify-content-between align-items-center"
@@ -50,16 +50,17 @@ export const PageSideContents = (props: PageSideContentsProps): JSX.Element => {
             {t('page_list')}
             <CountBadge count={page?.descendantCount} offset={1} />
           </button>
-        ) }
+        )}
       </div>
 
       {/* Comments */}
-      { !isTopPagePath && (
+      {!isTopPagePath && (
         <div className={`mt-2 grw-page-accessories-control ${styles['grw-page-accessories-control']}`}>
           <Link to={'page-comments'} offset={-120}>
             <button
               type="button"
               className="btn btn-block btn-outline-secondary grw-btn-page-accessories rounded-pill d-flex justify-content-between align-items-center"
+              data-testid="page-comment-button"
             >
               <i className="icon-fw icon-bubbles grw-page-accessories-control-icon"></i>
               <span>Comments</span>
@@ -67,11 +68,11 @@ export const PageSideContents = (props: PageSideContentsProps): JSX.Element => {
             </button>
           </Link>
         </div>
-      ) }
+      )}
 
       <div className="d-none d-lg-block">
         <TableOfContents />
-        { isUsersHomePagePath && <ContentLinkButtons author={page?.creator} /> }
+        {isUsersHomePagePath && <ContentLinkButtons author={page?.creator} />}
       </div>
     </>
   );

+ 61 - 0
packages/app/test/cypress/integration/20-basic-features/20-basic-features--username-mention.spec.ts

@@ -0,0 +1,61 @@
+context('Mention username in comment', () => {
+  const ssPrefix = 'mention-username-';
+
+  beforeEach(() => {
+    // login
+    cy.fixture("user-admin.json").then(user => {
+      cy.login(user.username, user.password);
+    });
+
+    // Visit /Sandbox
+    cy.visit('/Sandbox');
+    cy.waitUntilSkeletonDisappear();
+
+    cy.collapseSidebar(true, true);
+
+    // Go to comment page
+    cy.getByTestid('page-comment-button').click();
+
+    // Open comment editor
+    cy.waitUntil(() => {
+      // do
+      cy.getByTestid('open-comment-editor-button').click();
+      // wait until
+      return cy.get('.comment-write').then($elem => $elem.is(':visible'));
+    });
+
+  });
+
+  it('Successfully mention username in comment', () => {
+    const username = '@adm';
+
+    cy.waitUntil(() => {
+      // do
+      cy.get('.CodeMirror').type(username);
+      // wait until
+      return cy.get('.CodeMirror-hints').then($elem => $elem.is(':visible'));
+    });
+
+    cy.get('#comments-container').within(() => { cy.screenshot(`${ssPrefix}1-username-found`) });
+    // Click on mentioned username
+    cy.get('.CodeMirror-hints > li').first().click();
+    cy.get('#comments-container').within(() => { cy.screenshot(`${ssPrefix}2-username-mentioned`) });
+  });
+
+  it('Username not found when mention username in comment', () => {
+    const username = '@user';
+
+    cy.waitUntil(() => {
+      // do
+      cy.get('.CodeMirror').type(username);
+      // wait until
+      return cy.get('.CodeMirror-hints').then($elem => $elem.is(':visible'));
+    });
+
+    cy.get('#comments-container').within(() => { cy.screenshot(`${ssPrefix}3-username-not-found`) });
+    // Click on username not found hint
+    cy.get('.CodeMirror-hints > li').first().click();
+    cy.get('#comments-container').within(() => { cy.screenshot(`${ssPrefix}4-no-username-mentioned`) });
+  });
+
+});