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

Merge branch 'master' into fix/gw7894-fix-image-not-showing-and-exceed-crop-modal-area

Mudana-Grune 3 лет назад
Родитель
Сommit
5bde865dc5

+ 16 - 1
CHANGELOG.md

@@ -1,9 +1,24 @@
 # Changelog
 
-## [Unreleased](https://github.com/weseek/growi/compare/v5.1.4...HEAD)
+## [Unreleased](https://github.com/weseek/growi/compare/v5.1.5...HEAD)
 
 *Please do not manually update this file. We've automated the process.*
 
+## [v5.1.5](https://github.com/weseek/growi/compare/v5.1.4...v5.1.5) - 2022-10-04
+
+### 💎 Features
+
+- feat: Add option to not use crop modal on brand logo upload (#6677) @Yohei-Shiina
+
+### 🚀 Improvement
+
+- imprv: Emoji picker performance for v5.x (#6689) @hakumizuki
+
+### 🐛 Bug Fixes
+
+- fix(auditlog): Attachment download is displayed even if the filter is unchecked (#6688) @miya
+- fix: firstName and lastName japanese translations in SAML  (#6631) @kaoritokashiki
+
 ## [v5.1.4](https://github.com/weseek/growi/compare/v5.1.3...v5.1.4) - 2022-09-12
 
 ### 💎 Features

+ 1 - 1
lerna.json

@@ -1,7 +1,7 @@
 {
   "npmClient": "yarn",
   "useWorkspaces": true,
-  "version": "5.1.5-RC.0",
+  "version": "5.1.6-RC.0",
   "packages": [
     "packages/*"
   ]

+ 1 - 1
package.json

@@ -1,6 +1,6 @@
 {
   "name": "growi",
-  "version": "5.1.5-RC.0",
+  "version": "5.1.6-RC.0",
   "description": "Team collaboration software using markdown",
   "tags": [
     "wiki",

+ 2 - 2
packages/app/docker/README.md

@@ -10,8 +10,8 @@ GROWI Official docker image
 Supported tags and respective Dockerfile links
 ------------------------------------------------
 
-* [`5.1.4`, `5.1`, `5`, `latest` (Dockerfile)](https://github.com/weseek/growi/blob/v5.1.4/packages/app/docker/Dockerfile)
-* [`5.1.4-nocdn`, `5.1-nocdn`, `5-nocdn`, `latest-nocdn` (Dockerfile)](https://github.com/weseek/growi/blob/v5.1.4/packages/app/docker/Dockerfile)
+* [`5.1.5`, `5.1`, `5`, `latest` (Dockerfile)](https://github.com/weseek/growi/blob/v5.1.5/packages/app/docker/Dockerfile)
+* [`5.1.5-nocdn`, `5.1-nocdn`, `5-nocdn`, `latest-nocdn` (Dockerfile)](https://github.com/weseek/growi/blob/v5.1.5/packages/app/docker/Dockerfile)
 * [`5.0.11`, `5.0` (Dockerfile)](https://github.com/weseek/growi/blob/v5.0.11/packages/app/docker/Dockerfile)
 * [`5.0.11-nocdn`, `5.0-nocdn` (Dockerfile)](https://github.com/weseek/growi/blob/v5.0.11/packages/app/docker/Dockerfile)
 * [`4.5.23`, `4.5`, `4`, `latest` (Dockerfile)](https://github.com/weseek/growi/blob/v4.5.23/packages/app/docker/Dockerfile)

+ 8 - 8
packages/app/package.json

@@ -1,6 +1,6 @@
 {
   "name": "@growi/app",
-  "version": "5.1.5-RC.0",
+  "version": "5.1.6-RC.0",
   "license": "MIT",
   "scripts": {
     "//// for production": "",
@@ -64,12 +64,12 @@
     "@elastic/elasticsearch7": "npm:@elastic/elasticsearch@^7.17.0",
     "@godaddy/terminus": "^4.9.0",
     "@google-cloud/storage": "^5.8.5",
-    "@growi/codemirror-textlint": "^5.1.5-RC.0",
-    "@growi/core": "^5.1.5-RC.0",
-    "@growi/plugin-attachment-refs": "^5.1.5-RC.0",
-    "@growi/plugin-lsx": "^5.1.5-RC.0",
-    "@growi/plugin-pukiwiki-like-linker": "^5.1.5-RC.0",
-    "@growi/slack": "^5.1.5-RC.0",
+    "@growi/codemirror-textlint": "^5.1.6-RC.0",
+    "@growi/core": "^5.1.6-RC.0",
+    "@growi/plugin-attachment-refs": "^5.1.6-RC.0",
+    "@growi/plugin-lsx": "^5.1.6-RC.0",
+    "@growi/plugin-pukiwiki-like-linker": "^5.1.6-RC.0",
+    "@growi/slack": "^5.1.6-RC.0",
     "@promster/express": "^7.0.2",
     "@promster/server": "^7.0.4",
     "@slack/events-api": "^3.0.0",
@@ -172,7 +172,7 @@
   },
   "devDependencies": {
     "@alienfast/i18next-loader": "^1.1.4",
-    "@growi/ui": "^5.1.5-RC.0",
+    "@growi/ui": "^5.1.6-RC.0",
     "@handsontable/react": "=2.1.0",
     "@types/compression": "^1.7.0",
     "@types/express": "^4.17.11",

+ 5 - 1
packages/app/public/static/locales/en_US/admin/admin.json

@@ -598,6 +598,10 @@
     "PAGE_DELETE_COMPLETELY": "Delete completely page",
     "PAGE_REVERT": "Revert page",
     "PAGE_EMPTY_TRASH": "Empty trash",
+    "PAGE_RECURSIVELY_RENAME": "Recursive page rename",
+    "PAGE_RECURSIVELY_DELETE": "Recursive page delete",
+    "PAGE_RECURSIVELY_DELETE_COMPLETELY": "Recursive page delete completely",
+    "PAGE_RECURSIVELY_REVERT": "Recursive page revert",
     "PAGE_SUBSCRIBE": "Subscribe page",
     "PAGE_UNSUBSCRIBE": "Unsubscribe page",
     "PAGE_EXPORT": "Export page",
@@ -615,7 +619,7 @@
     "SHARE_LINK_NOT_FOUND": "Page view (Not found share link)",
     "ATTACHMENT_ADD": "Add Attachment",
     "ATTACHMENT_REMOVE": "Delete Attachment",
-    "ACTION_ATTACHMENT_DOWNLOAD": "Download Attachment",
+    "ATTACHMENT_DOWNLOAD": "Download Attachment",
     "SEARCH_PAGE": "Page Search",
     "SEARCH_PAGE_VIEW": "Page view(Search results page)",
     "ADMIN_APP_SETTING_UPDATE": "Update App Settings",

+ 5 - 1
packages/app/public/static/locales/ja_JP/admin/admin.json

@@ -597,6 +597,10 @@
     "PAGE_DELETE_COMPLETELY": "ページの完全削除",
     "PAGE_REVERT": "ページを元に戻す",
     "PAGE_EMPTY_TRASH": "ゴミ箱を空にする",
+    "PAGE_RECURSIVELY_RENAME": "再帰的なページのリネーム",
+    "PAGE_RECURSIVELY_DELETE": "再帰的なページの削除",
+    "PAGE_RECURSIVELY_DELETE_COMPLETELY": "再起的なページの完全削除",
+    "PAGE_RECURSIVELY_REVERT": "再起的なページの復元",
     "PAGE_SUBSCRIBE": "ページをサブスクライブ",
     "PAGE_UNSUBSCRIBE": "ページをアンサブスクライブ",
     "PAGE_EXPORT": "マークダウン形式でページをエクスポート",
@@ -614,7 +618,7 @@
     "SHARE_LINK_NOT_FOUND": "ページ閲覧(存在しない共有リンク)",
     "ATTACHMENT_ADD": "添付データの追加",
     "ATTACHMENT_REMOVE": "添付データの削除",
-    "ACTION_ATTACHMENT_DOWNLOAD": "添付データのダウンロード",
+    "ATTACHMENT_DOWNLOAD": "添付データのダウンロード",
     "SEARCH_PAGE": "ページの検索",
     "SEARCH_PAGE_VIEW": "ページ閲覧(検索結果ページ)",
     "ADMIN_APP_SETTING_UPDATE": "アプリ設定の更新",

+ 5 - 1
packages/app/public/static/locales/zh_CN/admin/admin.json

@@ -608,6 +608,10 @@
     "PAGE_DELETE_COMPLETELY": "彻底删除页面",
     "PAGE_REVERT": "还原页面",
     "PAGE_EMPTY_TRASH": "清空垃圾箱",
+    "PAGE_RECURSIVELY_RENAME": "递归页面重命名",
+    "PAGE_RECURSIVELY_DELETE": "递归页面删除",
+    "PAGE_RECURSIVELY_DELETE_COMPLETELY": "递归页面完全删除",
+    "PAGE_RECURSIVELY_REVERT": "递归页面还原",
     "PAGE_SUBSCRIBE": "订阅页面",
     "PAGE_UNSUBSCRIBE": "退订页面",
     "PAGE_EXPORT": "导出页面",
@@ -625,7 +629,7 @@
     "SHARE_LINK_NOT_FOUND": "页面浏览量(未找到分享链接)",
     "ATTACHMENT_ADD": "添加附件",
     "ATTACHMENT_REMOVE": "删除附件",
-    "ACTION_ATTACHMENT_DOWNLOAD": "下载附件",
+    "ATTACHMENT_DOWNLOAD": "下载附件",
     "SEARCH_PAGE": "页面搜索",
     "SEARCH_PAGE_VIEW": "页面浏览量(搜索结果页面)",
     "ADMIN_APP_SETTING_UPDATE": "更新应用设置",

+ 101 - 29
packages/app/src/components/PageEditor/CodeMirrorEditor.jsx

@@ -7,6 +7,7 @@ import * as loadCssSync from 'load-css-file';
 import PropTypes from 'prop-types';
 import { Button } from 'reactstrap';
 import * as loadScript from 'simple-load-script';
+import { throttle, debounce } from 'throttle-debounce';
 import urljoin from 'url-join';
 
 import InterceptorManager from '~/services/interceptor-manager';
@@ -115,7 +116,9 @@ class CodeMirrorEditor extends AbstractEditor {
       isCheatsheetModalShown: false,
       additionalClassSet: new Set(),
       isEmojiPickerShown: false,
-      emojiSearchText: null,
+      emojiSearchText: '',
+      startPosWithEmojiPickerModeTurnedOn: null,
+      isEmojiPickerMode: false,
     };
 
     this.gridEditModal = React.createRef();
@@ -140,7 +143,16 @@ class CodeMirrorEditor extends AbstractEditor {
     this.pasteHandler = this.pasteHandler.bind(this);
     this.cursorHandler = this.cursorHandler.bind(this);
     this.changeHandler = this.changeHandler.bind(this);
-    this.keyUpHandler = this.keyUpHandler.bind(this);
+    this.turnOnEmojiPickerMode = this.turnOnEmojiPickerMode.bind(this);
+    this.turnOffEmojiPickerMode = this.turnOffEmojiPickerMode.bind(this);
+    this.windowClickHandler = this.windowClickHandler.bind(this);
+    this.keyDownHandler = this.keyDownHandler.bind(this);
+    this.keyDownHandlerForEmojiPicker = this.keyDownHandlerForEmojiPicker.bind(this);
+    this.keyDownHandlerForEmojiPickerThrottled = throttle(400, this.keyDownHandlerForEmojiPicker);
+    this.showEmojiPicker = this.showEmojiPicker.bind(this);
+    this.keyPressHandlerForEmojiPicker = this.keyPressHandlerForEmojiPicker.bind(this);
+    this.keyPressHandlerForEmojiPickerThrottled = debounce(50, throttle(200, this.keyPressHandlerForEmojiPicker));
+    this.keyPressHandler = this.keyPressHandler.bind(this);
 
     this.updateCheatsheetStates = this.updateCheatsheetStates.bind(this);
 
@@ -155,7 +167,6 @@ class CodeMirrorEditor extends AbstractEditor {
 
     this.foldDrawioSection = this.foldDrawioSection.bind(this);
     this.onSaveForDrawio = this.onSaveForDrawio.bind(this);
-    this.checkWhetherEmojiPickerShouldBeShown = this.checkWhetherEmojiPickerShouldBeShown.bind(this);
 
   }
 
@@ -186,6 +197,13 @@ class CodeMirrorEditor extends AbstractEditor {
     }
     this.emojiPickerHelper = new EmojiPickerHelper(this.getCodeMirror());
 
+    // HACKME: Find a better way to handle onClick for Editor
+    document.addEventListener('click', this.windowClickHandler);
+  }
+
+  componentWillUnmount() {
+    // HACKME: Find a better way to handle onClick for Editor
+    document.removeEventListener('click', this.windowClickHandler);
   }
 
   componentWillReceiveProps(nextProps) {
@@ -586,10 +604,82 @@ class CodeMirrorEditor extends AbstractEditor {
 
   }
 
-  keyUpHandler(editor, event) {
-    if (event.key !== 'Backspace') {
-      this.checkWhetherEmojiPickerShouldBeShown();
+  turnOnEmojiPickerMode(pos) {
+    this.setState({
+      isEmojiPickerMode: true,
+      startPosWithEmojiPickerModeTurnedOn: pos,
+    });
+  }
+
+  turnOffEmojiPickerMode() {
+    this.setState({
+      isEmojiPickerMode: false,
+    });
+  }
+
+  showEmojiPicker(initialSearchingText) {
+    // show emoji picker with a stored word
+    this.setState({
+      isEmojiPickerShown: true,
+      emojiSearchText: initialSearchingText ?? '',
+    });
+
+    const resetStartPos = initialSearchingText == null;
+    if (resetStartPos) {
+      this.setState({ startPosWithEmojiPickerModeTurnedOn: null });
     }
+
+    this.turnOffEmojiPickerMode();
+  }
+
+  keyPressHandlerForEmojiPicker(editor, event) {
+    const char = event.key;
+    const isEmojiPickerMode = this.state.isEmojiPickerMode;
+
+    // evaluate whether emoji picker mode to be turned on
+    if (!isEmojiPickerMode) {
+      const startPos = this.emojiPickerHelper.shouldModeTurnOn(char);
+      if (startPos == null) {
+        return;
+      }
+
+      this.turnOnEmojiPickerMode(startPos);
+      return;
+    }
+
+    // evaluate whether EmojiPicker to be opened
+    const startPos = this.state.startPosWithEmojiPickerModeTurnedOn;
+    if (this.emojiPickerHelper.shouldOpen(startPos)) {
+      const initialSearchingText = this.emojiPickerHelper.getInitialSearchingText(startPos);
+      this.showEmojiPicker(initialSearchingText);
+      return;
+    }
+
+    this.turnOffEmojiPickerMode();
+  }
+
+  keyPressHandler(editor, event) {
+    this.keyPressHandlerForEmojiPickerThrottled(editor, event);
+  }
+
+  keyDownHandlerForEmojiPicker(editor, event) {
+    const key = event.key;
+
+    if (!this.state.isEmojiPickerMode) {
+      return;
+    }
+
+    if (['ArrowRight', 'ArrowLeft', 'ArrowUp', 'ArrowDown', 'BackSpace'].includes(key)) {
+      this.turnOffEmojiPickerMode();
+    }
+  }
+
+  keyDownHandler(editor, event) {
+    this.keyDownHandlerForEmojiPickerThrottled(editor, event);
+  }
+
+  windowClickHandler() {
+    this.turnOffEmojiPickerMode();
   }
 
   /**
@@ -613,26 +703,6 @@ class CodeMirrorEditor extends AbstractEditor {
 
   }
 
-  /**
-   * Show emoji picker component when emoji pattern (`:` + searchWord ) found
-   * eg `:a`, `:ap`
-   */
-  checkWhetherEmojiPickerShouldBeShown() {
-    const searchWord = this.emojiPickerHelper.getEmoji();
-
-    if (searchWord == null) {
-      this.setState({ isEmojiPickerShown: false });
-      this.setState({ emojiSearchText: null });
-    }
-    else {
-      this.setState({ emojiSearchText: searchWord });
-      // Show emoji picker after user stop typing
-      setTimeout(() => {
-        this.setState({ isEmojiPickerShown: true });
-      }, 700);
-    }
-  }
-
   /**
    * update states which related to cheatsheet
    * @param {boolean} isGfmModeTmp (use state.isGfmMode if null is set)
@@ -712,7 +782,8 @@ class CodeMirrorEditor extends AbstractEditor {
         <div className="text-left">
           <div className="mb-2 d-none d-md-block">
             <EmojiPicker
-              onClose={() => this.setState({ isEmojiPickerShown: false, emojiSearchText: null })}
+              onClose={() => this.setState({ isEmojiPickerShown: false })}
+              onSelected={emoji => this.emojiPickerHelper.addEmoji(emoji, this.state.startPosWithEmojiPickerModeTurnedOn)}
               emojiSearchText={emojiSearchText}
               emojiPickerHelper={this.emojiPickerHelper}
               isOpen={this.state.isEmojiPickerShown}
@@ -966,7 +1037,7 @@ class CodeMirrorEditor extends AbstractEditor {
         color={null}
         bssize="small"
         title="Emoji"
-        onClick={() => this.setState({ isEmojiPickerShown: true })}
+        onClick={() => this.showEmojiPicker()}
       >
         <EditorIcon icon="Emoji" />
       </Button>,
@@ -1045,7 +1116,8 @@ class CodeMirrorEditor extends AbstractEditor {
               this.props.onDragEnter(event);
             }
           }}
-          onKeyUp={this.keyUpHandler}
+          onKeyPress={this.keyPressHandler}
+          onKeyDown={this.keyDownHandler}
         />
 
         { this.renderLoadingKeymapOverlay() }

+ 9 - 13
packages/app/src/components/PageEditor/EmojiPicker.tsx

@@ -1,4 +1,4 @@
-import React, { FC } from 'react';
+import React, { FC, useCallback } from 'react';
 
 import { Picker } from 'emoji-mart';
 import { Modal } from 'reactstrap';
@@ -9,6 +9,7 @@ import EmojiPickerHelper, { getEmojiTranslation } from './EmojiPickerHelper';
 
 type Props = {
   onClose: () => void,
+  onSelected: (emoji: string) => void,
   emojiSearchText: string,
   emojiPickerHelper: EmojiPickerHelper,
   isOpen: boolean
@@ -17,28 +18,23 @@ type Props = {
 const EmojiPicker: FC<Props> = (props: Props) => {
 
   const {
-    onClose, emojiSearchText, emojiPickerHelper, isOpen,
+    onClose, onSelected, emojiSearchText, emojiPickerHelper, isOpen,
   } = props;
 
   // Set search emoji input and trigger search
-  const searchEmoji = () => {
+  const searchEmoji = useCallback(() => {
     const input = window.document.querySelector('[id^="emoji-mart-search"]') as HTMLInputElement;
     const valueSetter = Object.getOwnPropertyDescriptor(window.HTMLInputElement.prototype, 'value')?.set;
     valueSetter?.call(input, emojiSearchText);
     const event = new Event('input', { bubbles: true });
     input.dispatchEvent(event);
     input.focus();
-  };
-
-  const selectEmoji = (emoji) => {
-    if (emojiSearchText !== null) {
-      emojiPickerHelper.addEmojiOnSearch(emoji);
-    }
-    else {
-      emojiPickerHelper.addEmoji(emoji);
-    }
+  }, [emojiSearchText]);
+
+  const selectEmoji = useCallback((emoji) => {
+    onSelected(emoji);
     onClose();
-  };
+  }, [onClose, onSelected]);
 
 
   const translation = getEmojiTranslation();

+ 51 - 62
packages/app/src/components/PageEditor/EmojiPickerHelper.ts

@@ -1,89 +1,78 @@
 import { CSSProperties } from 'react';
 
+import { Position } from 'codemirror';
 import i18n from 'i18next';
 
-// https://regex101.com/r/Gqhor8/1
-const EMOJI_PATTERN = new RegExp(/\B:[^:\s]+/);
+// https://regex101.com/r/x5LbOZ/1
+const EMOJI_PATTERN = new RegExp(/^:[a-z0-9-+_]+$/);
 
 export default class EmojiPickerHelper {
 
-editor;
+  editor;
 
-pattern: RegExp;
+  pattern: string;
 
-constructor(editor) {
-  this.editor = editor;
-  this.pattern = EMOJI_PATTERN;
-}
+  constructor(editor) {
+    this.editor = editor;
+  }
 
-setStyle = ():CSSProperties => {
-  const offset = 20;
-  const emojiPickerHeight = 420;
-  const cursorPos = this.editor.cursorCoords(true);
-  const editorPos = this.editor.getWrapperElement().getBoundingClientRect();
-  // Emoji Picker bottom position exceed editor's bottom position
-  if (cursorPos.bottom + emojiPickerHeight > editorPos.bottom) {
+  setStyle = (): CSSProperties => {
+    const offset = 20;
+    const emojiPickerHeight = 420;
+    const cursorPos = this.editor.cursorCoords(true);
+    const editorPos = this.editor.getWrapperElement().getBoundingClientRect();
+    // Emoji Picker bottom position exceed editor's bottom position
+    if (cursorPos.bottom + emojiPickerHeight > editorPos.bottom) {
+      return {
+        top: editorPos.bottom - emojiPickerHeight,
+        left: cursorPos.left + offset,
+        position: 'fixed',
+      };
+    }
     return {
-      top: editorPos.bottom - emojiPickerHeight,
+      top: cursorPos.top + offset,
       left: cursorPos.left + offset,
       position: 'fixed',
     };
-  }
-  return {
-    top: cursorPos.top + offset,
-    left: cursorPos.left + offset,
-    position: 'fixed',
   };
-}
 
-getSearchCursor =() => {
-  const currentPos = this.editor.getCursor();
-  const sc = this.editor.getSearchCursor(this.pattern, currentPos, { multiline: false });
-  return sc;
-}
+  shouldModeTurnOn = (char: string): Position | null | undefined => {
+    if (char !== ':') {
+      return null;
+    }
 
-// Add emoji when triggered by search
-addEmojiOnSearch = (emoji) => {
-  const currentPos = this.editor.getCursor();
-  const sc = this.getSearchCursor();
-  if (sc.findPrevious()) {
-    sc.replace(`${emoji.colons} `, this.editor.getTokenAt(currentPos).string);
-    this.editor.focus();
-    this.editor.refresh();
+    const currentPos = this.editor.getCursor();
+    const sc = this.editor.getSearchCursor(':', currentPos, { multiline: false });
+    if (sc.findPrevious()) {
+      return sc.pos.from;
+    }
   }
-}
 
+  shouldOpen = (startPos: Position): boolean => {
+    const currentPos = this.editor.getCursor();
+    const rangeStr = this.editor.getRange(startPos, currentPos);
 
-// Add emoji when triggered by click emoji icon on top of editor
-addEmoji = (emoji) => {
-  const currentPos = this.editor.getCursor();
-  const doc = this.editor.getDoc();
-  doc.replaceRange(`${emoji.colons} `, currentPos);
-  this.editor.focus();
-  this.editor.refresh();
-}
+    return EMOJI_PATTERN.test(rangeStr);
+  }
 
-getEmoji = () => {
-  const sc = this.getSearchCursor();
-  const currentPos = this.editor.getCursor();
+  getInitialSearchingText = (startPos: Position): void => {
+    const currentPos = this.editor.getCursor();
+    const rangeStr = this.editor.getRange(startPos, currentPos);
 
-  if (sc.findPrevious()) {
-    const isInputtingEmoji = (currentPos.line === sc.to().line && currentPos.ch === sc.to().ch);
-    // current search cursor position
-    if (!isInputtingEmoji) {
-      return;
-    }
-    const pos = {
-      line: sc.to().line,
-      ch: sc.to().ch,
-    };
-    const currentSearchText = sc.matches(true, pos).match[0];
-    const searchWord = currentSearchText.replace(':', '');
-    return searchWord;
+    return rangeStr.slice(1); // return without the heading ':'
   }
 
-  return;
-}
+  addEmoji = (emoji: { colons: string }, startPosToReplace: Position|null): void => {
+    const currentPos = this.editor.getCursor();
+
+    const from = startPosToReplace ?? currentPos;
+    const to = currentPos;
+
+    const doc = this.editor.getDoc();
+    doc.replaceRange(`${emoji.colons} `, from, to);
+    this.editor.focus();
+    this.editor.refresh();
+  };
 
 }
 

+ 1 - 1
packages/app/src/interfaces/activity.ts

@@ -67,7 +67,7 @@ const ACTION_SHARE_LINK_EXPIRED_PAGE_VIEW = 'SHARE_LINK_EXPIRED_PAGE_VIEW';
 const ACTION_SHARE_LINK_NOT_FOUND = 'SHARE_LINK_NOT_FOUND';
 const ACTION_ATTACHMENT_ADD = 'ATTACHMENT_ADD';
 const ACTION_ATTACHMENT_REMOVE = 'ATTACHMENT_REMOVE';
-const ACTION_ATTACHMENT_DOWNLOAD = 'ACTION_ATTACHMENT_DOWNLOAD';
+const ACTION_ATTACHMENT_DOWNLOAD = 'ATTACHMENT_DOWNLOAD';
 const ACTION_SEARCH_PAGE = 'SEARCH_PAGE';
 const ACTION_SEARCH_PAGE_VIEW = 'SEARCH_PAGE_VIEW';
 const ACTION_ADMIN_APP_SETTINGS_UPDATE = 'ADMIN_APP_SETTING_UPDATE';

+ 1 - 1
packages/app/test/cypress/integration/21-basic-features-for-guest/access-to-page.spec.ts

@@ -36,7 +36,7 @@ context('Access to page by guest', () => {
     cy.collapseSidebar(true, true);
 
     // eslint-disable-next-line cypress/no-unnecessary-waiting
-    cy.wait(500);
+    cy.wait(1000);
 
     cy.screenshot(`${ssPrefix}-sandbox-edit-page`);
   })

+ 1 - 0
packages/app/test/cypress/integration/50-sidebar/access-to-side-bar.spec.ts

@@ -176,6 +176,7 @@ context('Access to sidebar', () => {
 
   it('Successfully access to trash page', () => {
     cy.visit('/');
+    cy.collapseSidebar(true);
     cy.get('.grw-sidebar-nav-secondary-container').within(() => {
       cy.get('a[href*="/trash"]').click();
     });

+ 7 - 2
packages/app/test/cypress/integration/50-sidebar/switching-sidebar-mode.spec.ts

@@ -21,13 +21,18 @@ context('Switch sidebar mode', () => {
 
   it('Switching sidebar mode', () => {
     cy.visit('/');
+    cy.collapseSidebar(true, true)
     cy.get('.grw-personal-dropdown').first().click();
 
     cy.get('[for="swSidebarMode"]').click({force: true});
-    cy.screenshot(`${ssPrefix}-switch-sidebar-mode`, { capture: 'viewport' });
+    cy.screenshot(`${ssPrefix}-switch-sidebar-mode`, {
+      blackout: ['#revision-toc', '[data-hide-in-vrt=true]'],
+    })
 
     cy.get('[for="swSidebarMode"]').click({force: true});
-    cy.screenshot(`${ssPrefix}-switch-sidebar-mode-back`, { capture: 'viewport' });
+    cy.screenshot(`${ssPrefix}-switch-sidebar-mode-back`, {
+      blackout: ['#revision-toc', '[data-hide-in-vrt=true]'],
+    })
   });
 
 });

+ 1 - 1
packages/codemirror-textlint/package.json

@@ -1,6 +1,6 @@
 {
   "name": "@growi/codemirror-textlint",
-  "version": "5.1.5-RC.0",
+  "version": "5.1.6-RC.0",
   "license": "MIT",
   "main": "dist/index.js",
   "scripts": {

+ 1 - 1
packages/core/package.json

@@ -1,6 +1,6 @@
 {
   "name": "@growi/core",
-  "version": "5.1.5-RC.0",
+  "version": "5.1.6-RC.0",
   "description": "GROWI Core Libraries",
   "license": "MIT",
   "keywords": [

+ 1 - 1
packages/plugin-attachment-refs/package.json

@@ -1,6 +1,6 @@
 {
   "name": "@growi/plugin-attachment-refs",
-  "version": "5.1.5-RC.0",
+  "version": "5.1.6-RC.0",
   "description": "GROWI Plugin to add ref/refimg/refs/refsimg tags",
   "license": "MIT",
   "keywords": [

+ 1 - 1
packages/plugin-lsx/package.json

@@ -1,6 +1,6 @@
 {
   "name": "@growi/plugin-lsx",
-  "version": "5.1.5-RC.0",
+  "version": "5.1.6-RC.0",
   "description": "GROWI plugin to list pages",
   "license": "MIT",
   "keywords": [

+ 1 - 1
packages/plugin-pukiwiki-like-linker/package.json

@@ -1,6 +1,6 @@
 {
   "name": "@growi/plugin-pukiwiki-like-linker",
-  "version": "5.1.5-RC.0",
+  "version": "5.1.6-RC.0",
   "description": "GROWI plugin to add PukiwikiLikeLinker",
   "license": "MIT",
   "keywords": [

+ 1 - 1
packages/slack/package.json

@@ -1,6 +1,6 @@
 {
   "name": "@growi/slack",
-  "version": "5.1.5-RC.0",
+  "version": "5.1.6-RC.0",
   "license": "MIT",
   "main": "dist/index.js",
   "typings": "dist/index.d.ts",

+ 2 - 2
packages/slackbot-proxy/package.json

@@ -1,6 +1,6 @@
 {
   "name": "@growi/slackbot-proxy",
-  "version": "5.1.5-slackbot-proxy.0",
+  "version": "5.1.6-slackbot-proxy.0",
   "license": "MIT",
   "scripts": {
     "build": "yarn tsc && tsc-alias -p tsconfig.build.json",
@@ -25,7 +25,7 @@
   },
   "dependencies": {
     "@godaddy/terminus": "^4.9.0",
-    "@growi/slack": "^5.1.5-RC.0",
+    "@growi/slack": "^5.1.6-RC.0",
     "@slack/oauth": "^2.0.1",
     "@slack/web-api": "^6.2.4",
     "@tsed/common": "^6.43.0",

+ 1 - 1
packages/ui/package.json

@@ -1,6 +1,6 @@
 {
   "name": "@growi/ui",
-  "version": "5.1.5-RC.0",
+  "version": "5.1.6-RC.0",
   "description": "GROWI UI Libraries",
   "license": "MIT",
   "keywords": [