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

Merge branch 'master' into fix/144018-codemirror-not-clear-color

satof3 1 год назад
Родитель
Сommit
dca7d42a5b
32 измененных файлов с 584 добавлено и 363 удалено
  1. 2 1
      .devcontainer/devcontainer.json
  2. 1 0
      .github/dependabot.yml
  3. 3 3
      .github/workflows/ci-app.yml
  4. 3 3
      .github/workflows/ci-slackbot-proxy.yml
  5. 6 3
      .mergify.yml
  6. 2 13
      .vscode/launch.json
  7. 2 1
      apps/app/src/components/Admin/AuditLog/ActivityTable.tsx
  8. 1 1
      apps/app/src/components/Bookmarks/BookmarkFolderItem.tsx
  9. 1 1
      apps/app/src/components/Bookmarks/BookmarkItem.tsx
  10. 27 6
      apps/app/src/components/Common/CopyDropdown/CopyDropdown.jsx
  11. 5 0
      apps/app/src/components/Common/CopyDropdown/CopyDropdown.module.scss
  12. 4 4
      apps/app/src/components/ContentLinkButtons.tsx
  13. 0 1
      apps/app/src/components/PageSideContents/PageAccessoriesControl.module.scss
  14. 3 3
      apps/app/src/components/PageSideContents/PageAccessoriesControl.tsx
  15. 19 0
      apps/app/src/components/ReactMarkdownComponents/CodeBlock.module.scss
  16. 6 5
      apps/app/src/components/ReactMarkdownComponents/CodeBlock.tsx
  17. 1 0
      apps/app/src/components/Sidebar/Sidebar.module.scss
  18. 4 5
      apps/app/src/components/TagList.tsx
  19. 1 1
      apps/app/src/components/TreeItem/SimpleItem.tsx
  20. 12 4
      apps/app/src/features/growi-plugin/server/services/growi-plugin/growi-plugin.ts
  21. 1 1
      apps/app/src/server/.node-dev.json
  22. 2 3
      apps/app/src/server/crowi/express-init.js
  23. 4 2
      apps/app/src/server/routes/apiv3/page/check-page-existence.ts
  24. 2 2
      apps/app/src/server/service/config-manager.spec.ts
  25. 5 3
      apps/app/src/server/service/customize.ts
  26. 3 2
      apps/slackbot-proxy/package.json
  27. 5 5
      package.json
  28. 6 4
      packages/pluginkit/vitest.config.ts
  29. 2 1
      packages/preset-themes/src/index.ts
  30. 4 4
      packages/ui/src/components/UserPicture.tsx
  31. 4 0
      vitest.workspace.ts
  32. 443 281
      yarn.lock

+ 2 - 1
.devcontainer/devcontainer.json

@@ -25,7 +25,8 @@
     "editorconfig.editorconfig",
     "esbenp.prettier-vscode",
     "shinnn.stylelint",
-    "stylelint.vscode-stylelint"
+    "stylelint.vscode-stylelint",
+    "vitest.explorer"
   ],
 
   // Uncomment the next line if you want start specific services in your Docker Compose config.

+ 1 - 0
.github/dependabot.yml

@@ -26,4 +26,5 @@ updates:
       - dependency-name: string-width
       - dependency-name: "@handsontable/react"
       - dependency-name: handsontable
+      - dependency-name: typeorm
 

+ 3 - 3
.github/workflows/ci-app.yml

@@ -22,7 +22,7 @@ concurrency:
 
 
 jobs:
-  lint:
+  ci-app-lint:
     runs-on: ubuntu-latest
 
     strategy:
@@ -87,7 +87,7 @@ jobs:
           key: dist-app-7.x-ci-${{ runner.OS }}-node${{ matrix.node-version }}-${{ hashFiles('node_modules/.cache/turbo/*-meta.json') }}
 
 
-  test:
+  ci-app-test:
     runs-on: ubuntu-latest
 
     strategy:
@@ -169,7 +169,7 @@ jobs:
           key: dist-app-7.x-ci-${{ runner.OS }}-node${{ matrix.node-version }}-${{ hashFiles('node_modules/.cache/turbo/*-meta.json') }}
 
 
-  launch-dev:
+  ci-app-launch-dev:
     runs-on: ubuntu-latest
 
     strategy:

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

@@ -24,7 +24,7 @@ concurrency:
 
 jobs:
 
-  lint:
+  ci-slackbot-proxy-lint:
     runs-on: ubuntu-latest
 
     strategy:
@@ -89,7 +89,7 @@ jobs:
         key: dist-slackbot-proxy-ci-${{ runner.OS }}-node${{ matrix.node-version }}-${{ hashFiles('node_modules/.cache/turbo/*-meta.json') }}
 
 
-  launch-dev:
+  ci-slackbot-proxy-launch-dev:
     runs-on: ubuntu-latest
 
     strategy:
@@ -174,7 +174,7 @@ jobs:
         key: dist-slackbot-proxy-ci-${{ runner.OS }}-node${{ matrix.node-version }}-${{ hashFiles('node_modules/.cache/turbo/*-meta.json') }}
 
 
-  launch-prod:
+  ci-slackbot-proxy-launch-prod:
     runs-on: ubuntu-latest
 
     strategy:

+ 6 - 3
.mergify.yml

@@ -3,9 +3,12 @@ pull_request_rules:
     conditions:
       - author = dependabot[bot]
       - '#approved-reviews-by >= 1'
-      - check-success = "lint (20.x)"
-      - check-success = "test (20.x)"
-      - check-success = "launch-dev (20.x)"
+      - check-success = "ci-slackbot-proxy-lint (20.x)"
+      - check-success = "ci-slackbot-proxy-launch-dev (20.x)"
+      - check-success = "ci-slackbot-proxy-launch-prod (20.x)"
+      - check-success = "ci-app-lint (20.x)"
+      - check-success = "ci-app-test (20.x)"
+      - check-success = "ci-app-launch-dev (20.x)"
       - check-success = "test-prod-node18 / launch-prod"
       - check-success = "test-prod-node20 / launch-prod"
     actions:

+ 2 - 13
.vscode/launch.json

@@ -18,17 +18,6 @@
       },
       {
         "type": "node",
-        "request": "launch",
-        "name": "Debug: Current File with Vitest",
-        "autoAttachChildProcesses": true,
-        "skipFiles": ["<node_internals>/**", "**/node_modules/**"],
-        "program": "${workspaceRoot}/node_modules/vitest/vitest.mjs",
-        "args": ["run", "${relativeFile}"],
-        "smartStep": true,
-        "console": "integratedTerminal"
-      },
-      {
-        "type": "pwa-node",
         "request": "attach",
         "name": "Debug: Attach Debugger to Server",
         "port": 9229,
@@ -38,7 +27,7 @@
         }
       },
       {
-        "type": "pwa-node",
+        "type": "node",
         "request": "launch",
         "name": "Debug: Server",
         "cwd": "${workspaceFolder}/apps/app",
@@ -57,7 +46,7 @@
         }
       },
       {
-        "type": "pwa-chrome",
+        "type": "chrome",
         "request": "launch",
         "name": "Debug: Chrome",
         "sourceMaps": true,

+ 2 - 1
apps/app/src/components/Admin/AuditLog/ActivityTable.tsx

@@ -1,6 +1,7 @@
 import type { FC } from 'react';
 import React, { useState, useCallback } from 'react';
 
+import { isPopulated } from '@growi/core';
 import { pagePathUtils } from '@growi/core/dist/utils';
 import { UserPicture } from '@growi/ui/dist/components';
 import { format } from 'date-fns/format';
@@ -51,7 +52,7 @@ export const ActivityTable : FC<Props> = (props: Props) => {
                       <UserPicture user={activity.user} />
                       <a
                         className="ms-2"
-                        href={pagePathUtils.userHomepagePath(activity.user)}
+                        href={isPopulated(activity.user) ? pagePathUtils.userHomepagePath(activity.user) : undefined}
                       >
                         {activity.snapshot?.username}
                       </a>

+ 1 - 1
apps/app/src/components/Bookmarks/BookmarkFolderItem.tsx

@@ -225,7 +225,7 @@ export const BookmarkFolderItem: FC<BookmarkFolderItemProps> = (props: BookmarkF
         isDropable={isDropable}
       >
         <li
-          className="list-group-item list-group-item-action border-0 py-2 d-flex align-items-center rounded"
+          className="list-group-item list-group-item-action border-0 py-2 d-flex align-items-center rounded-1"
           onClick={loadChildFolder}
           style={{ paddingLeft }}
         >

+ 1 - 1
apps/app/src/components/Bookmarks/BookmarkItem.tsx

@@ -148,7 +148,7 @@ export const BookmarkItem = (props: Props): JSX.Element => {
       useDragMode={isOperable}
     >
       <li
-        className="grw-bookmark-item-list list-group-item list-group-item-action border-0 py-0 pe-1 me-auto d-flex align-items-center rounded"
+        className="grw-bookmark-item-list list-group-item list-group-item-action border-0 py-0 pe-1 me-auto d-flex align-items-center rounded-1"
         key={bookmarkedPage._id}
         id={bookmarkItemId}
         style={{ paddingLeft }}

+ 27 - 6
apps/app/src/components/Common/CopyDropdown/CopyDropdown.jsx

@@ -16,10 +16,12 @@ import styles from './CopyDropdown.module.scss';
 const { encodeSpaces } = pagePathUtils;
 
 /* eslint-disable react/prop-types */
-const DropdownItemContents = ({ title, contents }) => (
+const DropdownItemContents = ({
+  title, contents, className, style,
+}) => (
   <>
     <div className="h6 mt-1 mb-2"><strong>{title}</strong></div>
-    <div className="card custom-card mb-1 p-2">{contents}</div>
+    <div className={`card custom-card mb-1 p-2 ${className}`} style={style}>{contents}</div>
   </>
 );
 /* eslint-enable react/prop-types */
@@ -110,7 +112,12 @@ export const CopyDropdown = (props) => {
 
   return (
     <>
-      <Dropdown className={`${styles['grw-copy-dropdown']} grw-copy-dropdown d-print-none`} isOpen={dropdownOpen} size="sm" toggle={toggleDropdown}>
+      <Dropdown
+        className={`${styles['grw-copy-dropdown']} grw-copy-dropdown d-print-none`}
+        isOpen={dropdownOpen}
+        size="sm"
+        toggle={toggleDropdown}
+      >
         <DropdownToggle
           caret={isShareLinkMode}
           className={`btn-copy ${dropdownToggleClassName}`}
@@ -144,7 +151,11 @@ export const CopyDropdown = (props) => {
           {/* Page path */}
           <CopyToClipboard text={pagePathWithParams} onCopy={showToolTip}>
             <DropdownItem className="px-3">
-              <DropdownItemContents title={t('copy_to_clipboard.Page path')} contents={pagePathWithParams} />
+              <DropdownItemContents
+                title={t('copy_to_clipboard.Page path')}
+                contents={pagePathWithParams}
+                className="text-truncate d-block"
+              />
             </DropdownItem>
           </CopyToClipboard>
 
@@ -153,7 +164,11 @@ export const CopyDropdown = (props) => {
           {/* Page path URL */}
           <CopyToClipboard text={pagePathUrl} onCopy={showToolTip}>
             <DropdownItem className="px-3">
-              <DropdownItemContents title={t('copy_to_clipboard.Page URL')} contents={pagePathUrl} />
+              <DropdownItemContents
+                title={t('copy_to_clipboard.Page URL')}
+                contents={pagePathUrl}
+                className="text-truncate d-block"
+              />
             </DropdownItem>
           </CopyToClipboard>
           <DropdownItem divider className="my-0"></DropdownItem>
@@ -162,7 +177,11 @@ export const CopyDropdown = (props) => {
           { pageId && (
             <CopyToClipboard text={permalink} onCopy={showToolTip}>
               <DropdownItem className="px-3">
-                <DropdownItemContents title={t('copy_to_clipboard.Permanent link')} contents={permalink} />
+                <DropdownItemContents
+                  title={t('copy_to_clipboard.Permanent link')}
+                  contents={permalink}
+                  className="text-truncate d-block"
+                />
               </DropdownItem>
             </CopyToClipboard>
           )}
@@ -176,6 +195,8 @@ export const CopyDropdown = (props) => {
                 <DropdownItemContents
                   title={t('copy_to_clipboard.Page path and permanent link')}
                   contents={<>{pagePathWithParams}<br />{permalink}</>}
+                  className="text-truncate"
+                  style={{ direction: 'rtl' }}
                 />
               </DropdownItem>
             </CopyToClipboard>

+ 5 - 0
apps/app/src/components/Common/CopyDropdown/CopyDropdown.module.scss

@@ -9,6 +9,11 @@
 
   .dropdown-menu {
     min-width: 310px;
+    max-width: 375px;
+
+    @include bs.media-breakpoint-up(md) {
+      max-width: 600px;
+    }
 
     .dropdown-header {
       margin-bottom: 0.5em;

+ 4 - 4
apps/app/src/components/ContentLinkButtons.tsx

@@ -10,9 +10,9 @@ const BookMarkLinkButton = React.memo(() => {
     <ScrollLink to="bookmarks-list" offset={-120}>
       <button
         type="button"
-        className="btn btn-sm btn-outline-neutral-secondary rounded-pill d-flex align-items-center w-100"
+        className="btn btn-sm btn-outline-neutral-secondary rounded-pill d-flex align-items-center w-100 px-3"
       >
-        <span className="material-symbols-outlined p-0">bookmark</span>
+        <span className="material-symbols-outlined p-0 me-2">bookmark</span>
         <span>{t('user_home_page.bookmarks')}</span>
       </button>
     </ScrollLink>
@@ -27,9 +27,9 @@ const RecentlyCreatedLinkButton = React.memo(() => {
     <ScrollLink to="recently-created-list" offset={-120}>
       <button
         type="button"
-        className="btn btn-sm btn-outline-neutral-secondary rounded-pill d-flex align-items-center w-100"
+        className="btn btn-sm btn-outline-neutral-secondary rounded-pill d-flex align-items-center w-100 px-3"
       >
-        <span className="growi-custom-icons mx-1">recently_created</span>
+        <span className="growi-custom-icons mx-2 ">recently_created</span>
         <span>{t('user_home_page.recently_created')}</span>
       </button>
     </ScrollLink>

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

@@ -31,6 +31,5 @@
 @include bs.media-breakpoint-up(lg) {
   .btn-page-accessories :global {
     flex-grow: 1;
-    padding: 1px 5px 1px 10px;
   }
 }

+ 3 - 3
apps/app/src/components/PageSideContents/PageAccessoriesControl.tsx

@@ -27,11 +27,11 @@ export const PageAccessoriesControl = memo((props: Props): JSX.Element => {
   return (
     <button
       type="button"
-      className={`btn btn-outline-neutral-secondary ${moduleClass} ${className} rounded-pill`}
+      className={`btn btn-outline-neutral-secondary ${moduleClass} ${className} rounded-pill py-1 px-lg-3`}
       onClick={onClick}
     >
-      <span className="grw-icon d-flex">{icon}</span>
-      <span className="grw-labels ms-1 d-none d-lg-flex">
+      <span className="grw-icon d-flex me-lg-2">{icon}</span>
+      <span className="grw-labels d-none d-lg-flex">
         {label}
         {/* Do not display CountBadge if '/trash/*': https://github.com/weseek/growi/pull/7600 */}
         { count != null

+ 19 - 0
apps/app/src/components/ReactMarkdownComponents/CodeBlock.module.scss

@@ -1,6 +1,25 @@
 @use '~/styles/variables' as var;
 @use '@growi/core/scss/bootstrap/init' as bs;
 
+
+.code-highlighted {
+  // for word wrapping
+  // ref: https://qiita.com/spaceonly/items/9aa8599a082cb72740b7
+  %breaker {
+    word-break: break-all !important;
+    word-wrap: break-word !important;
+    overflow-wrap: break-word !important;
+    white-space: break-spaces !important;
+    line-break: anywhere !important;
+  };
+
+  @extend %breaker;
+
+  code {
+    @extend %breaker;
+  }
+}
+
 .code-highlighted-title {
   position: absolute;
   top: 0;

+ 6 - 5
apps/app/src/components/ReactMarkdownComponents/CodeBlock.tsx

@@ -1,11 +1,12 @@
-import { ReactNode } from 'react';
+import type { ReactNode } from 'react';
 
-import type { CodeComponent } from 'react-markdown/lib/ast-to-react';
+import type { CodeComponent, CodeProps } from 'react-markdown/lib/ast-to-react';
 import { PrismAsyncLight } from 'react-syntax-highlighter';
 import { oneDark } from 'react-syntax-highlighter/dist/cjs/styles/prism';
 
 import styles from './CodeBlock.module.scss';
 
+const codeHighlightedClass = styles['code-highlighted'];
 
 // remove font-family
 Object.entries<object>(oneDark).forEach(([key, value]) => {
@@ -49,7 +50,7 @@ function CodeBlockSubstance({ lang, children }: { lang: string, children: ReactN
   const isSimpleString = Array.isArray(children) && children.length === 1 && typeof children[0] === 'string';
   if (!isSimpleString) {
     return (
-      <div className="code-highlighted" style={oneDark['pre[class*="language-"]']}>
+      <div className={codeHighlightedClass} style={oneDark['pre[class*="language-"]']}>
         <code className={`language-${lang}`} style={oneDark['code[class*="language-"]']}>
           {children}
         </code>
@@ -59,7 +60,7 @@ function CodeBlockSubstance({ lang, children }: { lang: string, children: ReactN
 
   return (
     <PrismAsyncLight
-      className="code-highlighted"
+      className={codeHighlightedClass}
       PreTag="div"
       style={oneDark}
       language={lang}
@@ -69,7 +70,7 @@ function CodeBlockSubstance({ lang, children }: { lang: string, children: ReactN
   );
 }
 
-export const CodeBlock: CodeComponent = ({ inline, className, children }) => {
+export const CodeBlock: CodeComponent = ({ inline, className, children }: CodeProps) => {
 
   if (inline) {
     return <code className={`code-inline ${className ?? ''}`}>{children}</code>;

+ 1 - 0
apps/app/src/components/Sidebar/Sidebar.module.scss

@@ -44,6 +44,7 @@
         left: var.$grw-sidebar-nav-width;
         min-height: 50vh;
         max-height: calc(100vh - var.$grw-sidebar-nav-width * 2);
+        border-radius: 0 4px 4px 0 ;
       }
     }
   }

+ 4 - 5
apps/app/src/components/TagList.tsx

@@ -1,11 +1,10 @@
-import React, {
-  FC, useCallback,
-} from 'react';
+import type { FC } from 'react';
+import React, { useCallback } from 'react';
 
 import { useTranslation } from 'next-i18next';
 
 import { useKeywordManager } from '~/client/services/search-operation';
-import { IDataTagCount } from '~/interfaces/tag';
+import type { IDataTagCount } from '~/interfaces/tag';
 
 import PaginationWrapper from './PaginationWrapper';
 
@@ -42,7 +41,7 @@ const TagList: FC<TagListProps> = (props:(TagListProps & typeof defaultProps)) =
         <button
           key={tag._id}
           type="button"
-          className="list-group-item list-group-item-action d-flex justify-content-between"
+          className="list-group-item list-group-item-action d-flex justify-content-between rounded-1"
           onClick={() => pushState(`tag:${tag.name}`)}
         >
           <div className="text-truncate grw-tag badge">{tag.name}</div>

+ 1 - 1
apps/app/src/components/TreeItem/SimpleItem.tsx

@@ -201,7 +201,7 @@ export const SimpleItem: FC<SimpleItemProps> = (props) => {
       <li
         ref={itemRef}
         role="button"
-        className={`list-group-item border-0 py-0 pr-3 d-flex align-items-center text-muted ${page.isTarget ? 'active' : 'list-group-item-action'}`}
+        className={`list-group-item border-0 py-0 pr-3 d-flex align-items-center text-muted rounded-1 ${page.isTarget ? 'active' : 'list-group-item-action'}`}
         id={page.isTarget ? 'grw-pagetree-current-page-item' : `grw-pagetree-list-${page._id}`}
         onClick={itemClickHandler}
       >

+ 12 - 4
apps/app/src/features/growi-plugin/server/services/growi-plugin/growi-plugin.ts

@@ -7,7 +7,7 @@ import type { GrowiPluginPackageData } from '@growi/pluginkit';
 import { importPackageJson, validateGrowiDirective } from '@growi/pluginkit/dist/v4/server/index.cjs';
 // eslint-disable-next-line no-restricted-imports
 import axios from 'axios';
-import mongoose from 'mongoose';
+import type mongoose from 'mongoose';
 import streamToPromise from 'stream-to-promise';
 import unzipStream from 'unzip-stream';
 
@@ -28,13 +28,21 @@ const logger = loggerFactory('growi:plugins:plugin-utils');
 export type GrowiPluginResourceEntries = [installedPath: string, href: string][];
 
 function retrievePluginManifest(growiPlugin: IGrowiPlugin): ViteManifest | undefined {
-  const manifestPath = path.join(PLUGIN_STORING_PATH, growiPlugin.installedPath, 'dist/manifest.json');
+  // ref: https://vitejs.dev/guide/migration.html#manifest-files-are-now-generated-in-vite-directory-by-default
+  const manifestPathByVite4 = path.join(PLUGIN_STORING_PATH, growiPlugin.installedPath, 'dist/manifest.json');
+  const manifestPath = path.join(PLUGIN_STORING_PATH, growiPlugin.installedPath, 'dist/.vite/manifest.json');
 
-  if (!fs.existsSync(manifestPath)) {
+  const isManifestByVite4Exists = fs.existsSync(manifestPathByVite4);
+  const isManifestExists = fs.existsSync(manifestPath);
+
+  if (!isManifestByVite4Exists && !isManifestExists) {
     return;
   }
 
-  const manifestStr: string = readFileSync(manifestPath, 'utf-8');
+  const manifestStr: string = readFileSync(
+    isManifestExists ? manifestPath : manifestPathByVite4,
+    'utf-8',
+  );
   return JSON.parse(manifestStr);
 }
 

+ 1 - 1
apps/app/src/server/.node-dev.json

@@ -5,6 +5,6 @@
     "public/static",
 
     "// ignore watching preset theme updates",
-    "packages/preset-themes/dist/themes/manifest.json"
+    "packages/preset-themes/dist/themes/.vite/manifest.json"
   ]
 }

+ 2 - 3
apps/app/src/server/crowi/express-init.js

@@ -1,4 +1,4 @@
-import { manifestPath as presetThemesManifestPath } from '@growi/preset-themes';
+import { themesRootPath as presetThemesRootPath } from '@growi/preset-themes';
 import csrf from 'csurf';
 import qs from 'qs';
 
@@ -12,7 +12,6 @@ const logger = loggerFactory('growi:crowi:express-init');
 
 module.exports = function(crowi, app) {
   const debug = require('debug')('growi:crowi:express-init');
-  const path = require('path');
   const express = require('express');
   const compression = require('compression');
   const helmet = require('helmet');
@@ -86,7 +85,7 @@ module.exports = function(crowi, app) {
   const staticOption = (crowi.node_env === 'production') ? { maxAge: '30d' } : {};
   app.use(express.static(crowi.publicDir, staticOption));
   app.use('/static/preset-themes', express.static(
-    resolveFromRoot(`../../node_modules/@growi/preset-themes/${path.dirname(presetThemesManifestPath)}`),
+    resolveFromRoot(`../../node_modules/@growi/preset-themes/${presetThemesRootPath}`),
   ));
   app.use(PLUGIN_EXPRESS_STATIC_DIR, express.static(PLUGIN_STORING_PATH));
 

+ 4 - 2
apps/app/src/server/routes/apiv3/page/check-page-existence.ts

@@ -1,5 +1,6 @@
 import type { IPage, IUserHasId } from '@growi/core';
 import { ErrorV3 } from '@growi/core/dist/models';
+import { normalizePath } from '@growi/core/dist/utils/path-utils';
 import type { Request, RequestHandler } from 'express';
 import type { ValidationChain } from 'express-validator';
 import { query } from 'express-validator';
@@ -44,10 +45,11 @@ export const checkPageExistenceHandlersFactory: CreatePageHandlersFactory = (cro
       const { path } = req.query;
 
       if (path == null || Array.isArray(path)) {
-        return res.apiv3Err(new ErrorV3('The param "path" must be an page id'));
+        return res.apiv3Err(new ErrorV3('The param "path" must be a string'));
       }
 
-      const count = await Page.countByPathAndViewer(path.toString(), req.user);
+      const normalizedPath = normalizePath(path.toString());
+      const count = await Page.countByPathAndViewer(normalizedPath, req.user);
       res.apiv3({ isExist: count > 0 });
     },
   ];

+ 2 - 2
apps/app/src/server/service/config-manager.spec.ts

@@ -17,7 +17,7 @@ describe('ConfigManager test', () => {
 
   describe('updateConfigsInTheSameNamespace()', () => {
 
-    test.concurrent('invoke publishUpdateMessage()', async() => {
+    test('invoke publishUpdateMessage()', async() => {
       // setup
       ConfigModel.bulkWrite = vi.fn();
       configManager.loadConfigs = vi.fn();
@@ -33,7 +33,7 @@ describe('ConfigManager test', () => {
       expect(configManager.publishUpdateMessage).toHaveBeenCalledTimes(1);
     });
 
-    test.concurrent('does not invoke publishUpdateMessage()', async() => {
+    test('does not invoke publishUpdateMessage()', async() => {
       // setup
       ConfigModel.bulkWrite = vi.fn();
       configManager.loadConfigs = vi.fn();

+ 5 - 3
apps/app/src/server/service/customize.ts

@@ -1,7 +1,9 @@
-import { ColorScheme } from '@growi/core';
+import path from 'path';
+
+import type { ColorScheme } from '@growi/core';
 import { DevidedPagePath } from '@growi/core/dist/models';
 import { getForcedColorScheme } from '@growi/core/dist/utils';
-import { DefaultThemeMetadata, PresetThemesMetadatas } from '@growi/preset-themes';
+import { DefaultThemeMetadata, PresetThemesMetadatas, manifestPath } from '@growi/preset-themes';
 import uglifycss from 'uglifycss';
 
 import { growiPluginService } from '~/features/growi-plugin/server/services';
@@ -162,7 +164,7 @@ class CustomizeService implements S2sMessageHandlable {
     // retrieve preset theme
     else {
       // import preset-themes manifest
-      const presetThemesManifest = await import('@growi/preset-themes/dist/themes/manifest.json').then(imported => imported.default);
+      const presetThemesManifest = await import(path.join('@growi/preset-themes', manifestPath)).then(imported => imported.default);
 
       const themeMetadata = PresetThemesMetadatas.find(p => p.name === theme);
       this.forcedColorScheme = getForcedColorScheme(themeMetadata?.schemeType);

+ 3 - 2
apps/slackbot-proxy/package.json

@@ -24,7 +24,8 @@
     "version": "yarn version --no-git-tag-version --preid=slackbot-proxy"
   },
   "// comments for dependencies": {
-    "read-pkg-up": "v8 doesn't support CommonJS anymore. https://github.com/sindresorhus/read-pkg-up/issues/17"
+    "read-pkg-up": "v8 doesn't support CommonJS anymore. https://github.com/sindresorhus/read-pkg-up/issues/17",
+    "typeorm": "Upgrading to v0.3.x requires significant changes. https://github.com/tsedio/tsed/blob/production/docs/tutorials/typeorm.md"
   },
   "dependencies": {
     "@godaddy/terminus": "^4.9.0",
@@ -49,7 +50,7 @@
     "method-override": "^3.0.0",
     "mysql2": "^2.2.5",
     "read-pkg-up": "^7.0.1",
-    "typeorm": "^0.3.20",
+    "typeorm": "=0.2.45",
     "universal-bunyan": "^0.9.2"
   },
   "devDependencies": {

+ 5 - 5
package.json

@@ -89,11 +89,11 @@
     "ts-node-dev": "^2.0.0",
     "tsconfig-paths": "^3.9.0",
     "typescript": "~5.0.0",
-    "vite": "^4.5.3",
-    "vite-plugin-dts": "^2.3.0",
-    "vite-tsconfig-paths": "^4.2.0",
-    "vitest": "^0.34.6",
-    "vitest-mock-extended": "^1.1.3"
+    "vite": "^5.2.9",
+    "vite-plugin-dts": "^3.8.3",
+    "vite-tsconfig-paths": "^4.3.2",
+    "vitest": "^1.5.0",
+    "vitest-mock-extended": "^1.3.1"
   },
   "engines": {
     "node": "^18 || ^20",

+ 6 - 4
packages/pluginkit/vitest.config.ts

@@ -10,10 +10,12 @@ export default defineConfig({
     clearMocks: true,
     globals: true,
     coverage: {
-      lines: 100,
-      functions: 100,
-      branches: 100,
-      statements: 100,
+      thresholds: {
+        lines: 100,
+        functions: 100,
+        branches: 100,
+        statements: 100,
+      },
     },
   },
 });

+ 2 - 1
packages/preset-themes/src/index.ts

@@ -1,3 +1,4 @@
 export * from './consts/preset-themes';
 
-export const manifestPath = 'dist/themes/manifest.json';
+export const themesRootPath = 'dist/themes';
+export const manifestPath = `${themesRootPath}/.vite/manifest.json`;

+ 4 - 4
packages/ui/src/components/UserPicture.tsx

@@ -15,7 +15,7 @@ const DEFAULT_IMAGE = '/images/icons/user.svg';
 
 
 type UserPictureRootProps = {
-  user: Partial<IUser>,
+  user: IUser,
   className?: string,
   children?: ReactNode,
 }
@@ -28,11 +28,11 @@ const UserPictureRootWithLink = forwardRef<HTMLSpanElement, UserPictureRootProps
   const router = useRouter();
 
   const { user } = props;
-  const href = pagePathUtils.userHomepagePath(user);
 
   const clickHandler = useCallback(() => {
+    const href = pagePathUtils.userHomepagePath(user);
     router.push(href);
-  }, [href, router]);
+  }, [router, user]);
 
   // Using <span> tag here instead of <a> tag because UserPicture is used in SearchResultList which is essentially a anchor tag.
   // Nested anchor tags causes a warning.
@@ -64,7 +64,7 @@ const withTooltip = (UserPictureSpanElm: React.ForwardRefExoticComponent<UserPic
 /**
  * type guard to determine whether the specified object is IUser
  */
-const isUserObj = (obj: Partial<IUser> | Ref<IUser>): obj is Partial<IUser> => {
+const isUserObj = (obj: Partial<IUser> | Ref<IUser>): obj is IUser => {
   return typeof obj !== 'string' && 'username' in obj;
 };
 

+ 4 - 0
vitest.workspace.ts

@@ -0,0 +1,4 @@
+export default [
+  'apps/*/vitest.config.ts',
+  'packages/*/vitest.config.ts',
+];

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


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