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

Merge branch 'dev/7.0.x' into imprv/126527-131252-file-paste

reiji-h 2 лет назад
Родитель
Сommit
64c8286162
37 измененных файлов с 222 добавлено и 665 удалено
  1. 1 0
      .devcontainer/Dockerfile
  2. 1 1
      .devcontainer/devcontainer.json
  3. 1 1
      .github/workflows/auto-labeling.yml
  4. 5 2
      .github/workflows/ci-app.yml
  5. 3 0
      .github/workflows/ci-slackbot-proxy.yml
  6. 1 0
      .github/workflows/release-slackbot-proxy.yml
  7. 4 8
      .github/workflows/release.yml
  8. 1 1
      .github/workflows/reusable-app-build-image.yml
  9. 5 3
      .github/workflows/reusable-app-prod.yml
  10. 1 0
      .github/workflows/reusable-app-reg-suit.yml
  11. 25 1
      CHANGELOG.md
  12. 2 2
      README.md
  13. 2 2
      README_JP.md
  14. 1 1
      apps/app/bin/github-actions/update-readme.sh
  15. 1 0
      apps/app/docker/Dockerfile
  16. 3 3
      apps/app/docker/README.md
  17. 1 0
      apps/app/package.json
  18. 2 2
      apps/app/public/static/locales/en_US/admin.json
  19. 2 2
      apps/app/public/static/locales/ja_JP/admin.json
  20. 2 2
      apps/app/public/static/locales/zh_CN/admin.json
  21. 2 2
      apps/app/src/components/Admin/Customize/CustomizePresentationSetting.tsx
  22. 32 55
      apps/app/src/components/Navbar/GrowiContextualSubNavigation.tsx
  23. 0 4
      apps/app/src/components/Navbar/GrowiSubNavigation.module.scss
  24. 2 22
      apps/app/src/components/Navbar/GrowiSubNavigation.tsx
  25. 0 0
      apps/app/src/components/PageSideContents/PageSideContents.module.scss
  26. 71 7
      apps/app/src/components/PageSideContents/PageSideContents.tsx
  27. 1 0
      apps/app/src/components/PageSideContents/index.ts
  28. 3 4
      apps/app/src/components/PageTags/PageTags.tsx
  29. 0 0
      apps/app/src/components/PageTags/RenderTagLabels.tsx
  30. 1 1
      apps/app/src/components/PageTags/TagEditModal.tsx
  31. 0 0
      apps/app/src/components/PageTags/TagLabels.module.scss
  32. 1 3
      apps/app/src/components/PageTags/TagsInput.tsx
  33. 2 0
      apps/app/src/components/PageTags/index.ts
  34. 0 4
      apps/app/src/styles/_editor.scss
  35. 1 0
      apps/slackbot-proxy/docker/Dockerfile
  36. 2 3
      package.json
  37. 40 529
      yarn.lock

+ 1 - 0
.devcontainer/Dockerfile

@@ -51,6 +51,7 @@ RUN apt-get update \
 ENV DEBIAN_FRONTEND=dialog
 
 RUN yarn global add turbo
+RUN yarn global add node-gyp
 
 # Uncomment to default to non-root user
 # USER $USER_UID

+ 1 - 1
.devcontainer/devcontainer.json

@@ -34,7 +34,7 @@
   // "shutdownAction": "none",
 
   // Use 'postCreateCommand' to run commands after the container is created.
-  "postCreateCommand": "yarn global add turbo && yarn install",
+  "postCreateCommand": "yarn global add turbo node-gyp && yarn install",
 
   // Uncomment to connect as a non-root user. See https://aka.ms/vscode-remote/containers/non-root.
   "remoteUser": "node"

+ 1 - 1
.github/workflows/auto-labeling.yml

@@ -37,7 +37,7 @@ jobs:
         !startsWith( github.head_ref, 'dependabot/' ))
 
     steps:
-      - uses: amannn/action-semantic-pull-request@v5.0.2
+      - uses: amannn/action-semantic-pull-request@v5
         with:
           types: |
             feat

+ 5 - 2
.github/workflows/ci-app.yml

@@ -61,6 +61,7 @@ jobs:
       - name: Install dependencies
         run: |
           yarn global add turbo
+          yarn global add node-gyp
           yarn --frozen-lockfile
 
       - name: Lint
@@ -95,7 +96,7 @@ jobs:
 
     services:
       mongodb:
-        image: mongo:4.4
+        image: mongo:6.0
         ports:
           - 27017/tcp
 
@@ -132,6 +133,7 @@ jobs:
       - name: Install dependencies
         run: |
           yarn global add turbo
+          yarn global add node-gyp
           yarn --frozen-lockfile
 
       - name: Test
@@ -176,7 +178,7 @@ jobs:
 
     services:
       mongodb:
-        image: mongo:4.4
+        image: mongo:6.0
         ports:
           - 27017/tcp
 
@@ -214,6 +216,7 @@ jobs:
       - name: Install dependencies
         run: |
           yarn global add turbo
+          yarn global add node-gyp
           yarn --frozen-lockfile
 
       - name: turbo run dev:ci

+ 3 - 0
.github/workflows/ci-slackbot-proxy.yml

@@ -63,6 +63,7 @@ jobs:
     - name: Install dependencies
       run: |
         yarn global add turbo
+        yarn global add node-gyp
         yarn --frozen-lockfile
 
     - name: Lint
@@ -137,6 +138,7 @@ jobs:
     - name: Install dependencies
       run: |
         yarn global add turbo
+        yarn global add node-gyp
         yarn --frozen-lockfile
 
     - name: yarn dev:ci
@@ -220,6 +222,7 @@ jobs:
 
     - name: Install dependencies
       run: |
+        yarn global add node-gyp
         yarn --frozen-lockfile
 
     - name: Restore dist

+ 1 - 0
.github/workflows/release-slackbot-proxy.yml

@@ -109,6 +109,7 @@ jobs:
     - name: Install dependencies
       run: |
         yarn global add turbo
+        yarn global add node-gyp
         yarn --frozen-lockfile
 
     - name: Bump versions for next RC

+ 4 - 8
.github/workflows/release.yml

@@ -31,6 +31,7 @@ jobs:
     - name: Install dependencies
       run: |
         yarn global add turbo
+        yarn global add node-gyp
         yarn --frozen-lockfile
 
     - name: Bump versions
@@ -153,7 +154,7 @@ jobs:
 
 
   post-publish:
-    needs: [publish-image, publish-image-ghcr]
+    needs: [create-github-release, publish-image, publish-image-ghcr]
     runs-on: ubuntu-latest
 
     steps:
@@ -176,15 +177,9 @@ jobs:
         url: ${{ secrets.SLACK_WEBHOOK_URL }}
         created_tag: 'v${{ needs.create-github-release.outputs.RELEASED_VERSION }}'
 
-    - name: Check whether workspace is clean
-      run: |
-        STATUS=`git status --porcelain`
-        if [ -z "$STATUS" ]; then exit 0; else exit 1; fi
-
-
 
   create-pr-for-next-rc:
-    needs: [publish-image, publish-image-ghcr]
+    needs: [create-github-release, publish-image, publish-image-ghcr]
     runs-on: ubuntu-latest
 
     steps:
@@ -201,6 +196,7 @@ jobs:
     - name: Install dependencies
       run: |
         yarn global add turbo
+        yarn global add node-gyp
         yarn --frozen-lockfile
 
     - name: Bump versions for next RC

+ 1 - 1
.github/workflows/reusable-app-build-image.yml

@@ -36,7 +36,7 @@ jobs:
     - uses: actions/checkout@v3
 
     - name: Configure AWS Credentials
-      uses: aws-actions/configure-aws-credentials@v2
+      uses: aws-actions/configure-aws-credentials@v4
       with:
         aws-region: ap-northeast-1
         role-to-assume: ${{ secrets.AWS_ROLE_TO_ASSUME_FOR_OIDC }}

+ 5 - 3
.github/workflows/reusable-app-prod.yml

@@ -56,6 +56,7 @@ jobs:
 
     - name: Install dependencies
       run: |
+        yarn global add node-gyp
         yarn --frozen-lockfile
 
     - name: Restore dist
@@ -126,7 +127,7 @@ jobs:
 
     services:
       mongodb:
-        image: mongo:4.4
+        image: mongo:6.0
         ports:
         - 27017/tcp
       elasticsearch:
@@ -214,7 +215,7 @@ jobs:
 
     services:
       mongodb:
-        image: mongo:4.4
+        image: mongo:6.0
         ports:
         - 27017/tcp
       elasticsearch:
@@ -267,6 +268,7 @@ jobs:
 
     - name: Install dependencies
       run: |
+        yarn global add node-gyp
         yarn --frozen-lockfile
         yarn cypress install
 
@@ -303,7 +305,7 @@ jobs:
         cat config/ci/.env.local.for-auto-install-with-allowing-guest >> .env.production.local
 
     - name: Cypress Run
-      uses: cypress-io/github-action@v5
+      uses: cypress-io/github-action@v6
       with:
         browser: chromium
         working-directory: ./apps/app

+ 1 - 0
.github/workflows/reusable-app-reg-suit.yml

@@ -82,6 +82,7 @@ jobs:
 
     - name: Install dependencies
       run: |
+        yarn global add node-gyp
         yarn --frozen-lockfile
 
     - name: Download screenshots taken by cypress

+ 25 - 1
CHANGELOG.md

@@ -1,9 +1,33 @@
 # Changelog
 
-## [Unreleased](https://github.com/weseek/growi/compare/v6.2.0...HEAD)
+## [Unreleased](https://github.com/weseek/growi/compare/v6.2.1...HEAD)
 
 *Please do not manually update this file. We've automated the process.*
 
+## [v6.2.1](https://github.com/weseek/growi/compare/v6.2.0...v6.2.1) - 2023-10-03
+
+### BREAKING CHANGES
+
+- support: Omit promster (#8105) @yuki-takei
+
+### 🚀 Improvement
+
+- imprv: Download a markdown file using the page name as the file name (#8061) @soumaeda
+- imprv: Admin customize presentation form (#8083) @meiri-k
+- imprv: i18n for marp settings (#8110) @moekumasaka
+- imprv: i18n "Create /Sidebar page" label (#8085) @yuki-takei
+
+### 🐛 Bug Fixes
+
+- fix: Marp is enabled incorrectly problem (#8100) @reiji-h
+- fix: Do not work img tag if use style property 62x (#8092) @jam411
+
+### 🧰 Maintenance
+
+- support: Internationalization USER_REGISTRATION_APPROVAL_REQUEST label for v62x (#8130) @jam411
+- ci(deps): bump get-func-name from 2.0.0 to 2.0.2 (#8119) @dependabot
+- support: Omit promster (#8105) @yuki-takei
+
 ## [v6.2.0](https://github.com/weseek/growi/compare/v6.1.12...v6.2.0) - 2023-09-14
 
 ### 💎 Features

+ 2 - 2
README.md

@@ -83,12 +83,12 @@ See [GROWI Docs: Environment Variables](https://docs.growi.org/en/admin-guide/ad
 - npm 6.x
 - yarn
 - [Turborepo](https://turbo.build/repo)
-- MongoDB 4.x
+- MongoDB 4.4 or above
 
 ### Optional Dependencies
 
 - Redis 3.x
-- ElasticSearch 6.x or 7.x (needed when using Full-text search)
+- ElasticSearch 7.x or 8.x (needed when using Full-text search)
   - **CAUTION: Following plugins are required**
     - [Japanese (kuromoji) Analysis plugin](https://www.elastic.co/guide/en/elasticsearch/plugins/current/analysis-kuromoji.html)
     - [ICU Analysis Plugin](https://www.elastic.co/guide/en/elasticsearch/plugins/current/analysis-icu.html)

+ 2 - 2
README_JP.md

@@ -82,12 +82,12 @@ Crowi からの移行は **[こちら](https://docs.growi.org/en/admin-guide/mig
 - npm 6.x
 - yarn
 - [Turborepo](https://turbo.build/repo)
-- MongoDB 4.x
+- MongoDB 4.4 以上
 
 ### オプションの依存関係
 
 - Redis 3.x
-- ElasticSearch 6.x or 7.x (needed when using Full-text search)
+- ElasticSearch 7.x or 8.x (needed when using Full-text search)
   - **注意: 次のプラグインが必要です**
     - [Japanese (kuromoji) Analysis plugin](https://www.elastic.co/guide/en/elasticsearch/plugins/current/analysis-kuromoji.html)
     - [ICU Analysis Plugin](https://www.elastic.co/guide/en/elasticsearch/plugins/current/analysis-icu.html)

+ 1 - 1
apps/app/bin/github-actions/update-readme.sh

@@ -2,4 +2,4 @@
 
 cd docker
 
-sed -i -e "s/^\([*] \[\`\)[^\`]\+\(\`, \`7\.0\`, .\+\]\)\(.\+\/blob\/v\).\+\(\/packages\/app\/docker\/Dockerfile.\+\)$/\1${RELEASED_VERSION}\2\3${RELEASED_VERSION}\4/" README.md
+sed -i -e "s/^\([*] \[\`\)[^\`]\+\(\`, \`7\.0\`, .\+\]\)\(.\+\/blob\/v\).\+\(\/apps\/app\/docker\/Dockerfile.\+\)$/\1${RELEASED_VERSION}\2\3${RELEASED_VERSION}\4/" README.md

+ 1 - 0
apps/app/docker/Dockerfile

@@ -34,6 +34,7 @@ COPY --from=base ${optDir}/out/yarn.lock ./yarn.lock
 
 # setup (with network-timeout = 1 hour)
 RUN yarn config set network-timeout 3600000
+RUN yarn global add node-gyp
 RUN yarn --frozen-lockfile
 
 # make artifacts

+ 3 - 3
apps/app/docker/README.md

@@ -11,8 +11,8 @@ Supported tags and respective Dockerfile links
 ------------------------------------------------
 
 * [`7.0.0`, `7.0`, `7`, `latest` (Dockerfile)](https://github.com/weseek/growi/blob/v7.0.0/apps/app/docker/Dockerfile)
-* [`6.2.0`, `6.2`, `6` (Dockerfile)](https://github.com/weseek/growi/blob/v6.2.0/apps/app/docker/Dockerfile)
-* [`6.1.0`, `6.1` (Dockerfile)](https://github.com/weseek/growi/blob/v6.1.8/apps/app/docker/Dockerfile)
+* [`6.2.1`, `6.2`, `6`, `latest` (Dockerfile)](https://github.com/weseek/growi/blob/v6.2.1/apps/app/docker/Dockerfile)
+* [`6.1.15`, `6.1` (Dockerfile)](https://github.com/weseek/growi/blob/v6.1.15/apps/app/docker/Dockerfile)
 
 
 What is GROWI?
@@ -30,7 +30,7 @@ Requirements
 
 ### Optional Dependencies
 
-* ElasticSearch (>= 6.6)
+* ElasticSearch (>= 7.17)
     * Japanese (kuromoji) Analysis plugin
     * ICU Analysis Plugin
 

+ 1 - 0
apps/app/package.json

@@ -242,6 +242,7 @@
     "null-loader": "^4.0.1",
     "plantuml-encoder": "^1.2.5",
     "prettier": "^1.19.1",
+    "pretty-bytes": "^6.1.1",
     "react-codemirror2": "^6.0.0",
     "react-copy-to-clipboard": "^5.0.1",
     "react-dropzone": "^11.2.4",

+ 2 - 2
apps/app/public/static/locales/en_US/admin.json

@@ -488,8 +488,8 @@
       "enable_marp_desc": "Marp can be used in presentation preview. This option may make you vulnerable to XSS.",
       "marp_official_site": "The Marp Official Site",
       "marp_official_site_link": "https://marp.app",
-      "marp_in_growi" : "GROWI Docs - Create slide using Marp",
-      "marp_in_growi_link": "https://docs.growi.org/en/guide/features/marp.html"
+      "presentation_docs" : "GROWI Docs - Create slides for a presentation",
+      "presentation_docs_link": "https://docs.growi.org/en/guide/features/presentation.html"
     },
     "custom_title": "Custom title",
     "custom_title_detail": "You can customize <code>&lt;title&gt;</code> tag. Following placeholders will be automatically replaced:",

+ 2 - 2
apps/app/public/static/locales/ja_JP/admin.json

@@ -497,8 +497,8 @@
       "enable_marp_desc": "プレゼンテーション表示に Marp を利用できるようになります。ただし、XSS に対して脆弱になる恐れがあります。",
       "marp_official_site": "参考:Marp 公式サイト",
       "marp_official_site_link": "https://marp.app",
-      "marp_in_growi" : "参考:GROWI Docs - Marp でスライドを作成する",
-      "marp_in_growi_link": "https://docs.growi.org/ja/guide/features/marp.html"
+      "presentation_docs" : "参考:GROWI Docs - プレゼンテーション機能を使う",
+      "presentation_docs_link": "https://docs.growi.org/ja/guide/features/presentation.html"
     },
     "custom_title": "カスタム Title",
     "custom_title_detail": "<code>&lt;title&gt;</code>タグのコンテンツをカスタマイズできます。以下のプレースホルダーは自動的に置換されます:",

+ 2 - 2
apps/app/public/static/locales/zh_CN/admin.json

@@ -496,8 +496,8 @@
       "enable_marp_desc": "Marp 可在演示视图中使用。该选项可能会使您受到 XSS 的攻击。",
       "marp_official_site": "参考资料:Marp 官方网站",
       "marp_official_site_link": "https://marp.app",
-      "marp_in_growi" : "参考资料:GROWI Docs - Create slide using Marp",
-      "marp_in_growi_link": "https://docs.growi.org/en/guide/features/marp.html"
+      "presentation_docs" : "参考资料:GROWI Docs - Create slides for a presentation",
+      "presentation_docs_link": "https://docs.growi.org/en/guide/features/presentation.html"
     },
     "custom_title": "自定义标题",
     "custom_title_detail": "您可以自定义<code>&lt;title&gt;</code>标记。<br><code>&123;&123;sitename&&125;&125;</code>将自动替换为应用程序名称,并且<code>&123;&123;page&&125;&125;</code>将替换为页面名称/路径。",

+ 2 - 2
apps/app/src/components/Admin/Customize/CustomizePresentationSetting.tsx

@@ -51,10 +51,10 @@ const CustomizePresentationSetting = (props: Props): JSX.Element => {
               </a>
               <br></br>
               <a
-                href={`${t('admin:customize_settings.presentation_options.marp_in_gorwi_link')}`}
+                href={`${t('admin:customize_settings.presentation_options.presentation_docs_link')}`}
                 target="_blank"
                 rel="noopener noreferrer"
-              >{`${t('admin:customize_settings.presenattion_options.marp_in_growi')}`}
+              >{`${t('admin:customize_settings.presentation_options.presentation_docs')}`}
               </a>
             </p>
           </CustomizePresentationOption>

+ 32 - 55
apps/app/src/components/Navbar/GrowiContextualSubNavigation.tsx

@@ -1,4 +1,4 @@
-import React, { useState, useEffect, useCallback } from 'react';
+import React, { useState, useCallback } from 'react';
 
 import { isPopulated } from '@growi/core';
 import type {
@@ -11,25 +11,22 @@ import dynamic from 'next/dynamic';
 import { useRouter } from 'next/router';
 import { DropdownItem } from 'reactstrap';
 
-import { exportAsMarkdown, updateContentWidth, useUpdateStateAfterSave } from '~/client/services/page-operation';
-import { apiPost } from '~/client/util/apiv1-client';
-import { toastSuccess, toastError } from '~/client/util/toastr';
+import { exportAsMarkdown, updateContentWidth } from '~/client/services/page-operation';
 import { OnDuplicatedFunction, OnRenamedFunction, OnDeletedFunction } from '~/interfaces/ui';
 import {
   useCurrentPathname,
   useCurrentUser, useIsGuestUser, useIsReadOnlyUser, useIsSharedUser, useShareLinkId, useIsContainerFluid, useIsIdenticalPath,
 } from '~/stores/context';
-import { usePageTagsForEditors } from '~/stores/editor';
 import {
   usePageAccessoriesModal, PageAccessoriesModalContents, IPageForPageDuplicateModal,
   usePageDuplicateModal, usePageRenameModal, usePageDeleteModal, usePagePresentationModal,
 } from '~/stores/modal';
 import {
-  useSWRMUTxCurrentPage, useSWRxTagsInfo, useCurrentPageId, useIsNotFound, useTemplateTagData, useSWRxPageInfo,
+  useSWRMUTxCurrentPage, useCurrentPageId, useIsNotFound, useSWRxPageInfo,
 } from '~/stores/page';
 import { mutatePageTree } from '~/stores/page-listing';
 import {
-  EditorMode, useDrawerMode, useEditorMode, useIsAbleToShowPageManagement, useIsAbleToShowTagLabel,
+  EditorMode, useDrawerMode, useEditorMode, useIsAbleToShowPageManagement,
   useIsAbleToChangeEditorMode, useIsAbleToShowPageAuthors,
 } from '~/stores/ui';
 
@@ -217,38 +214,39 @@ const GrowiContextualSubNavigation = (props: GrowiContextualSubNavigationProps):
   const { data: isContainerFluid } = useIsContainerFluid();
 
   const { data: isAbleToShowPageManagement } = useIsAbleToShowPageManagement();
-  const { data: isAbleToShowTagLabel } = useIsAbleToShowTagLabel();
   const { data: isAbleToChangeEditorMode } = useIsAbleToChangeEditorMode();
   const { data: isAbleToShowPageAuthors } = useIsAbleToShowPageAuthors();
 
-  const { mutate: mutateSWRTagsInfo, data: tagsInfoData } = useSWRxTagsInfo(currentPage?._id);
-
+  // TODO: implement tags for editor
+  // refs: https://redmine.weseek.co.jp/issues/132125
   // eslint-disable-next-line max-len
-  const { data: tagsForEditors, mutate: mutatePageTagsForEditors, sync: syncPageTagsForEditors } = usePageTagsForEditors(!isSharedPage ? currentPage?._id : undefined);
+  // const { data: tagsForEditors, mutate: mutatePageTagsForEditors, sync: syncPageTagsForEditors } = usePageTagsForEditors(!isSharedPage ? currentPage?._id : undefined);
+  // const { data: templateTagData } = useTemplateTagData();
 
   const { open: openDuplicateModal } = usePageDuplicateModal();
   const { open: openRenameModal } = usePageRenameModal();
   const { open: openDeleteModal } = usePageDeleteModal();
-  const { data: templateTagData } = useTemplateTagData();
   const { mutate: mutatePageInfo } = useSWRxPageInfo(pageId);
 
-  const updateStateAfterSave = useUpdateStateAfterSave(pageId);
-
   const path = currentPage?.path ?? currentPathname;
 
-  useEffect(() => {
-    // Run only when tagsInfoData has been updated
-    if (templateTagData == null) {
-      syncPageTagsForEditors();
-    }
-    // eslint-disable-next-line react-hooks/exhaustive-deps
-  }, [tagsInfoData?.tags]);
-
-  useEffect(() => {
-    if (pageId === null && templateTagData != null) {
-      mutatePageTagsForEditors(templateTagData);
-    }
-  }, [pageId, mutatePageTagsForEditors, templateTagData, mutateSWRTagsInfo]);
+  // TODO: implement tags for editor
+  // refs: https://redmine.weseek.co.jp/issues/132125
+  // useEffect(() => {
+  //   // Run only when tagsInfoData has been updated
+  //   if (templateTagData == null) {
+  //     syncPageTagsForEditors();
+  //   }
+  //   // eslint-disable-next-line react-hooks/exhaustive-deps
+  // }, [tagsInfoData?.tags]);
+
+  // TODO: implement tags for editor
+  // refs: https://redmine.weseek.co.jp/issues/132125
+  // useEffect(() => {
+  //   if (pageId === null && templateTagData != null) {
+  //     mutatePageTagsForEditors(templateTagData);
+  //   }
+  // }, [pageId, mutatePageTagsForEditors, templateTagData, mutateSWRTagsInfo]);
 
   const [isPageTemplateModalShown, setIsPageTempleteModalShown] = useState(false);
 
@@ -257,30 +255,13 @@ const GrowiContextualSubNavigation = (props: GrowiContextualSubNavigationProps):
   const isViewMode = editorMode === EditorMode.View;
 
 
-  const tagsUpdatedHandlerForViewMode = useCallback(async(newTags: string[]) => {
-    if (currentPage == null) {
-      return;
-    }
-
-    const { _id: pageId, revision: revisionId } = currentPage;
-    try {
-      await apiPost('/tags.update', { pageId, revisionId, tags: newTags });
-
-      updateStateAfterSave?.();
-
-      toastSuccess('updated tags successfully');
-    }
-    catch (err) {
-      toastError(err);
-    }
-
-  }, [currentPage, updateStateAfterSave]);
-
-  const tagsUpdatedHandlerForEditMode = useCallback((newTags: string[]): void => {
-    // It will not be reflected in the DB until the page is refreshed
-    mutatePageTagsForEditors(newTags);
-    return;
-  }, [mutatePageTagsForEditors]);
+  // TODO: implement tags for editor
+  // refs: https://redmine.weseek.co.jp/issues/132125
+  // const tagsUpdatedHandlerForEditMode = useCallback((newTags: string[]): void => {
+  //   // It will not be reflected in the DB until the page is refreshed
+  //   mutatePageTagsForEditors(newTags);
+  //   return;
+  // }, [mutatePageTagsForEditors]);
 
   const duplicateItemClickedHandler = useCallback(async(page: IPageForPageDuplicateModal) => {
     const duplicatedHandler: OnDuplicatedFunction = (fromPath, toPath) => {
@@ -440,12 +421,8 @@ const GrowiContextualSubNavigation = (props: GrowiContextualSubNavigationProps):
       pagePath={pagePath}
       pageId={currentPage?._id}
       showDrawerToggler={isDrawerMode}
-      showTagLabel={isAbleToShowTagLabel}
-      isTagLabelsDisabled={!!isGuestUser || !!isReadOnlyUser}
       isDrawerMode={isDrawerMode}
       isCompactMode={isCompactMode}
-      tags={isViewMode ? tagsInfoData?.tags : tagsForEditors}
-      tagsUpdatedHandler={isViewMode ? tagsUpdatedHandlerForViewMode : tagsUpdatedHandlerForEditMode}
       rightComponent={RightComponent}
       additionalClasses={['container-fluid']}
     />

+ 0 - 4
apps/app/src/components/Navbar/GrowiSubNavigation.module.scss

@@ -33,10 +33,6 @@
       line-height: 1.4em;
     }
 
-    .grw-taglabels-container {
-      margin-bottom: 0.5rem;
-    }
-
     .grw-page-path-nav {
       .separator {
         margin-right: 0.2em;

+ 2 - 22
apps/app/src/components/Navbar/GrowiSubNavigation.tsx

@@ -1,12 +1,9 @@
 import React from 'react';
 
-import dynamic from 'next/dynamic';
-
 import {
   EditorMode, useEditorMode,
 } from '~/stores/ui';
 
-import { TagLabelsSkeleton } from '../Page/TagLabels';
 import PagePathNav from '../PagePathNav';
 
 import DrawerToggler from './DrawerToggler';
@@ -15,23 +12,15 @@ import DrawerToggler from './DrawerToggler';
 import styles from './GrowiSubNavigation.module.scss';
 
 
-const TagLabels = dynamic(() => import('../Page/TagLabels').then(mod => mod.TagLabels), {
-  ssr: false,
-  loading: TagLabelsSkeleton,
-});
-
-
 export type GrowiSubNavigationProps = {
   pagePath?: string,
   pageId?: string,
   isNotFound?: boolean,
   showDrawerToggler?: boolean,
-  showTagLabel?: boolean,
   isTagLabelsDisabled?: boolean,
   isDrawerMode?: boolean,
   isCompactMode?: boolean,
   tags?: string[],
-  tagsUpdatedHandler?: (newTags: string[]) => Promise<void> | void,
   rightComponent?: React.FunctionComponent,
   additionalClasses?: string[],
 }
@@ -42,9 +31,8 @@ export const GrowiSubNavigation = (props: GrowiSubNavigationProps): JSX.Element
 
   const {
     pageId, pagePath,
-    showDrawerToggler, showTagLabel,
-    isTagLabelsDisabled, isDrawerMode, isCompactMode,
-    tags, tagsUpdatedHandler,
+    showDrawerToggler,
+    isDrawerMode, isCompactMode,
     rightComponent: RightComponent,
     additionalClasses = [],
   } = props;
@@ -67,14 +55,6 @@ export const GrowiSubNavigation = (props: GrowiSubNavigationProps): JSX.Element
           </div>
         ) }
         <div className="grw-path-nav-container">
-          { (showTagLabel && !isCompactMode) && (
-            <div className="grw-taglabels-container">
-              { tags != null
-                ? <TagLabels tags={tags} isTagLabelsDisabled={isTagLabelsDisabled ?? false} tagsUpdateInvoked={tagsUpdatedHandler} />
-                : <TagLabelsSkeleton />
-              }
-            </div>
-          ) }
           { pagePath != null && (
             <PagePathNav pageId={pageId} pagePath={pagePath} isSingleLineMode={isEditorMode} isCompactMode={isCompactMode} />
           ) }

+ 0 - 0
apps/app/src/components/PageSideContents.module.scss → apps/app/src/components/PageSideContents/PageSideContents.module.scss


+ 71 - 7
apps/app/src/components/PageSideContents.tsx → apps/app/src/components/PageSideContents/PageSideContents.tsx

@@ -1,17 +1,24 @@
-import React from 'react';
+import React, { useCallback } from 'react';
 
-import type { IPageHasId, IPageInfoForOperation } from '@growi/core';
+import { getIdForRef, type IPageHasId, type IPageInfoForOperation } from '@growi/core';
 import { pagePathUtils } from '@growi/core/dist/utils';
 import { useTranslation } from 'next-i18next';
+import dynamic from 'next/dynamic';
 import { Link } from 'react-scroll';
 
+import { useUpdateStateAfterSave } from '~/client/services/page-operation';
+import { apiPost } from '~/client/util/apiv1-client';
+import { toastSuccess, toastError } from '~/client/util/toastr';
+import { useIsGuestUser, useIsReadOnlyUser } from '~/stores/context';
 import { useDescendantsPageListModal } from '~/stores/modal';
-import { useSWRxPageInfo } from '~/stores/page';
+import { useSWRxPageInfo, useSWRxTagsInfo } from '~/stores/page';
+import { useIsAbleToShowTagLabel } from '~/stores/ui';
 
-import CountBadge from './Common/CountBadge';
-import { ContentLinkButtons } from './ContentLinkButtons';
-import PageListIcon from './Icons/PageListIcon';
-import TableOfContents from './TableOfContents';
+import CountBadge from '../Common/CountBadge';
+import { ContentLinkButtons } from '../ContentLinkButtons';
+import PageListIcon from '../Icons/PageListIcon';
+import { PageTagsSkeleton } from '../PageTags';
+import TableOfContents from '../TableOfContents';
 
 import styles from './PageSideContents.module.scss';
 
@@ -19,6 +26,59 @@ import styles from './PageSideContents.module.scss';
 const { isTopPage, isUsersHomepage, isTrashPage } = pagePathUtils;
 
 
+const PageTags = dynamic(() => import('../PageTags').then(mod => mod.PageTags), {
+  ssr: false,
+  loading: PageTagsSkeleton,
+});
+
+
+type TagsProps = {
+  pageId: string,
+  revisionId: string,
+}
+
+const Tags = (props: TagsProps): JSX.Element => {
+  const { pageId, revisionId } = props;
+
+  const { data: tagsInfoData } = useSWRxTagsInfo(pageId);
+
+  const { data: showTagLabel } = useIsAbleToShowTagLabel();
+  const { data: isGuestUser } = useIsGuestUser();
+  const { data: isReadOnlyUser } = useIsReadOnlyUser();
+
+  const updateStateAfterSave = useUpdateStateAfterSave(pageId);
+
+  const tagsUpdatedHandler = useCallback(async(newTags: string[]) => {
+    try {
+      await apiPost('/tags.update', { pageId, revisionId, tags: newTags });
+
+      updateStateAfterSave?.();
+
+      toastSuccess('updated tags successfully');
+    }
+    catch (err) {
+      toastError(err);
+    }
+
+  }, [pageId, revisionId, updateStateAfterSave]);
+
+  if (!showTagLabel) {
+    return <></>;
+  }
+
+  const isTagLabelsDisabled = !!isGuestUser || !!isReadOnlyUser;
+
+  return (
+    <div className="grw-taglabels-container">
+      { tagsInfoData?.tags != null
+        ? <PageTags tags={tagsInfoData.tags} isTagLabelsDisabled={isTagLabelsDisabled ?? false} tagsUpdateInvoked={tagsUpdatedHandler} />
+        : <PageTagsSkeleton />
+      }
+    </div>
+  );
+};
+
+
 export type PageSideContentsProps = {
   page: IPageHasId,
   isSharedUser?: boolean,
@@ -38,8 +98,12 @@ export const PageSideContents = (props: PageSideContentsProps): JSX.Element => {
   const isUsersHomepagePath = isUsersHomepage(pagePath);
   const isTrash = isTrashPage(pagePath);
 
+
   return (
     <>
+      {/* Tags */}
+      <Tags pageId={page._id} revisionId={getIdForRef(page.revision)} />
+
       {/* Page list */}
       <div className={`grw-page-accessories-control ${styles['grw-page-accessories-control']}`}>
         {!isSharedUser && (

+ 1 - 0
apps/app/src/components/PageSideContents/index.ts

@@ -0,0 +1 @@
+export * from './PageSideContents';

+ 3 - 4
apps/app/src/components/Page/TagLabels.tsx → apps/app/src/components/PageTags/PageTags.tsx

@@ -13,11 +13,11 @@ type Props = {
   tagsUpdateInvoked?: (tags: string[]) => Promise<void> | void,
 }
 
-export const TagLabelsSkeleton = (): JSX.Element => {
+export const PageTagsSkeleton = (): JSX.Element => {
   return <Skeleton additionalClass={`${styles['grw-tag-labels-skeleton']} py-1`} />;
 };
 
-export const TagLabels:FC<Props> = (props: Props) => {
+export const PageTags:FC<Props> = (props: Props) => {
   const { tags, isTagLabelsDisabled, tagsUpdateInvoked } = props;
 
   const [isTagEditModalShown, setIsTagEditModalShown] = useState(false);
@@ -31,13 +31,12 @@ export const TagLabels:FC<Props> = (props: Props) => {
   };
 
   if (tags == null) {
-    return <TagLabelsSkeleton />;
+    return <PageTagsSkeleton />;
   }
 
   return (
     <>
       <div className={`${styles['grw-tag-labels']} grw-tag-labels d-flex align-items-center`} data-testid="grw-tag-labels">
-        <i className="tag-icon icon-tag me-2" />
         <RenderTagLabels
           tags={tags}
           openEditorModal={openEditorModal}

+ 0 - 0
apps/app/src/components/Page/RenderTagLabels.tsx → apps/app/src/components/PageTags/RenderTagLabels.tsx


+ 1 - 1
apps/app/src/components/Page/TagEditModal.tsx → apps/app/src/components/PageTags/TagEditModal.tsx

@@ -5,7 +5,7 @@ import {
   Modal, ModalHeader, ModalBody, ModalFooter,
 } from 'reactstrap';
 
-import TagsInput from './TagsInput';
+import { TagsInput } from './TagsInput';
 
 type Props = {
   tags: string[],

+ 0 - 0
apps/app/src/components/Page/TagLabels.module.scss → apps/app/src/components/PageTags/TagLabels.module.scss


+ 1 - 3
apps/app/src/components/Page/TagsInput.tsx → apps/app/src/components/PageTags/TagsInput.tsx

@@ -20,7 +20,7 @@ type Props = {
   onTagsUpdated: (tags: string[]) => void,
 }
 
-const TagsInput: FC<Props> = (props: Props) => {
+export const TagsInput: FC<Props> = (props: Props) => {
   const { t } = useTranslation();
   const tagsInputRef = useRef<TypeaheadInstance>(null);
 
@@ -79,5 +79,3 @@ const TagsInput: FC<Props> = (props: Props) => {
     </div>
   );
 };
-
-export default TagsInput;

+ 2 - 0
apps/app/src/components/PageTags/index.ts

@@ -0,0 +1,2 @@
+export * from './PageTags';
+export * from './TagsInput';

+ 0 - 4
apps/app/src/styles/_editor.scss

@@ -96,10 +96,6 @@
       height: 38px;
       font-size: 18px;
     }
-
-    .grw-taglabels-container {
-      margin-bottom: 0;
-    }
   }
 
   // ellipsis .grw-page-path-hierarchical-link

+ 1 - 0
apps/slackbot-proxy/docker/Dockerfile

@@ -29,6 +29,7 @@ COPY --from=base ${optDir}/out/yarn.lock ./yarn.lock
 
 # setup (with network-timeout = 1 hour)
 RUN yarn config set network-timeout 3600000
+RUN yarn global add node-gyp
 RUN yarn --frozen-lockfile
 
 # make artifacts

+ 2 - 3
package.json

@@ -51,7 +51,6 @@
     "@swc-node/register": "^1.6.2",
     "@swc/core": "^1.3.36",
     "@swc/helpers": "^0.4.14",
-    "@testing-library/cypress": "^9.0.0",
     "@types/css-modules": "^1.0.2",
     "@types/eslint": "^8.37.0",
     "@types/estree": "^1.0.1",
@@ -62,8 +61,8 @@
     "@vitejs/plugin-react": "^4.0.3",
     "@vitest/coverage-c8": "^0.31.1",
     "@vitest/ui": "^0.31.1",
-    "cypress": "^12.17.2",
-    "cypress-wait-until": "^1.7.2",
+    "cypress": "^13.3.0",
+    "cypress-wait-until": "^2.0.1",
     "eslint": "^8.41.0",
     "eslint-config-next": "^12.1.6",
     "eslint-config-weseek": "^2.1.1",

Разница между файлами не показана из-за своего большого размера
+ 40 - 529
yarn.lock


Некоторые файлы не были показаны из-за большого количества измененных файлов