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

Merge branch 'master' into feat/page-bulk-export

Futa Arai 1 год назад
Родитель
Сommit
7c5bea92a6
31 измененных файлов с 972 добавлено и 581 удалено
  1. 1 1
      .devcontainer/devcontainer.json
  2. 2 0
      .npmrc
  3. 1 1
      apps/app/.env.production
  4. 1 1
      apps/app/docker/Dockerfile
  5. 9 6
      apps/app/public/static/locales/en_US/translation.json
  6. 9 6
      apps/app/public/static/locales/fr_FR/translation.json
  7. 9 6
      apps/app/public/static/locales/ja_JP/translation.json
  8. 9 5
      apps/app/public/static/locales/zh_CN/translation.json
  9. 9 5
      apps/app/src/client/components/PageEditor/EditorNavbar/EditorNavbar.tsx
  10. 38 32
      apps/app/src/client/components/PageEditor/PageEditor.tsx
  11. 6 66
      apps/app/src/client/components/ShortcutsModal.module.scss
  12. 213 121
      apps/app/src/client/components/ShortcutsModal.tsx
  13. 41 0
      apps/app/src/client/components/Sidebar/AppTitle/AppTitle.module.scss
  14. 27 11
      apps/app/src/client/components/Sidebar/AppTitle/AppTitle.tsx
  15. 20 5
      apps/app/src/client/components/Sidebar/Sidebar.tsx
  16. 5 1
      apps/app/src/client/components/SystemVersion.module.scss
  17. 12 0
      apps/app/src/pages/login/index.page.tsx
  18. 1 1
      apps/app/src/server/routes/apiv3/import.js
  19. 72 19
      apps/app/src/server/routes/apiv3/revisions.js
  20. 91 1
      apps/app/src/server/routes/apiv3/search.js
  21. 96 4
      apps/app/src/server/routes/apiv3/share-links.js
  22. 0 12
      apps/app/src/styles/style-app.scss
  23. 1 1
      apps/slackbot-proxy/docker/Dockerfile
  24. 1 1
      bin/data-migrations/src/migrations/v60x/csv.js
  25. 1 1
      bin/data-migrations/src/migrations/v60x/tsv.js
  26. 2 3
      package.json
  27. 25 0
      packages/core-styles/scss/helpers/_modifier-keys.scss
  28. 12 14
      packages/editor/package.json
  29. 7 0
      packages/editor/src/client/components-internal/CodeMirrorEditor/CodeMirrorEditor.tsx
  30. 3 2
      packages/remark-attachment-refs/src/server/routes/refs.ts
  31. 248 255
      pnpm-lock.yaml

+ 1 - 1
.devcontainer/devcontainer.json

@@ -8,7 +8,7 @@
 
   "features": {
     "ghcr.io/devcontainers/features/node:1": {
-      "version": "20.18.0"
+      "version": "20.18.3"
     }
   },
 

+ 2 - 0
.npmrc

@@ -0,0 +1,2 @@
+# see: https://pnpm.io/next/npmrc#force-legacy-deploy
+force-legacy-deploy=true

+ 1 - 1
apps/app/.env.production

@@ -7,4 +7,4 @@ MIGRATIONS_DIR=dist/migrations/
 
 # OpenTelemetry Configuration
 OTEL_TRACES_SAMPLER_ARG=0.1
-
+OTEL_EXPORTER_OTLP_ENDPOINT="https://telemetry.growi.org"

+ 1 - 1
apps/app/docker/Dockerfile

@@ -14,7 +14,7 @@ WORKDIR ${optDir}
 RUN apt-get update && apt-get install -y ca-certificates wget curl --no-install-recommends
 
 # install pnpm
-RUN wget -qO- https://get.pnpm.io/install.sh | ENV="$HOME/.shrc" SHELL="$(which sh)" sh -
+RUN wget -qO- https://get.pnpm.io/install.sh | ENV="$HOME/.shrc" SHELL="$(which sh)" PNPM_VERSION="10.4.1" sh -
 ENV PNPM_HOME="/root/.local/share/pnpm"
 ENV PATH="$PNPM_HOME:$PATH"
 

+ 9 - 6
apps/app/public/static/locales/en_US/translation.json

@@ -454,7 +454,7 @@
   "modal_shortcuts": {
     "global": {
       "title": "Global shortcuts",
-      "Open/Close shortcut help": "Open/Close<br>shortcut help",
+      "Open/Close shortcut help": "Open/Close Shortcut Help",
       "Edit Page": "Edit Page",
       "Create Page": "Create Page",
       "Search": "Search",
@@ -468,11 +468,14 @@
       "Indent": "Indent",
       "Outdent": "Outdent",
       "Save Page": "Save Page",
-      "Delete Line": "Delete Line"
-    },
-    "commentform": {
-      "title": "Comment Form shortcuts",
-      "Post": "Post"
+      "Only Editor": "(Editor Only)",
+      "Delete Line": "Delete Line",
+      "Search in Editor": "Search in Editor",
+      "Move Line": "Move Line",
+      "Copy Line": "Copy Line",
+      "Toggle Line": "Toggle Line Comment",
+      "Insert Line": "Insert Line",
+      "Post Comment": "(Post Comment)"
     }
   },
   "modal_resolve_conflict": {

+ 9 - 6
apps/app/public/static/locales/fr_FR/translation.json

@@ -456,18 +456,21 @@
       "Show Contributors": "Voir contributeurs",
       "MirrorMode": "Mode mirroir",
       "Konami Code": "Code Konami",
-      "konami_code_url": "https://en.wikipedia.org/wiki/Konami_Code"
+      "konami_code_url": "https://fr.wikipedia.org/wiki/Code_Konami"
     },
     "editor": {
       "title": "Raccourcis d'édition",
       "Indent": "Indentation",
       "Outdent": "Retrait",
       "Save Page": "Sauvegarder la page",
-      "Delete Line": "Supprimer la ligne"
-    },
-    "commentform": {
-      "title": "Raccourcis de commentaires",
-      "Post": "Poster"
+      "Only Editor": "(Éditeur uniquement)",
+      "Delete Line": "Supprimer la ligne",
+      "Search in Editor": "Rechercher dans l'éditeur",
+      "Move Line": "Déplacer la ligne",
+      "Copy Line": "Copier la ligne",
+      "Toggle Line": "Commenter/Décommenter la ligne",
+      "Insert Line": "Insérer une ligne",
+      "Post Comment": "(Publier le commentaire)"
     }
   },
   "modal_resolve_conflict": {

+ 9 - 6
apps/app/public/static/locales/ja_JP/translation.json

@@ -487,7 +487,7 @@
   "modal_shortcuts": {
     "global": {
       "title": "グローバルショートカット",
-      "Open/Close shortcut help": "ショートカットヘルプ<br>表示/非表示",
+      "Open/Close shortcut help": "ショートカットヘルプ<br>表示/非表示",
       "Edit Page": "ページ編集",
       "Create Page": "ページ作成",
       "Search": "検索",
@@ -501,11 +501,14 @@
       "Indent": "インデント",
       "Outdent": "左インデント",
       "Save Page": "保存",
-      "Delete Line": "行削除"
-    },
-    "commentform": {
-      "title": "コメントフォームショートカット",
-      "Post": "投稿"
+      "Only Editor": "(エディターのみ)",
+      "Delete Line": "行削除",
+      "Search in Editor": "エディター内検索",
+      "Move Line": "行の移動",
+      "Copy Line": "行のコピー",
+      "Toggle Line": "行の非表示化",
+      "Insert Line": "行を挿入",
+      "Post Comment": "(コメント投稿)"
     }
   },
   "modal_resolve_conflict": {

+ 9 - 5
apps/app/public/static/locales/zh_CN/translation.json

@@ -449,6 +449,7 @@
       "Create Page": "创建页面",
       "Search": "搜索",
       "Show Contributors": "显示参与者",
+      "MirrorMode": "镜像模式",
       "Konami Code": "Konami Code",
       "konami_code_url": "https://en.wikipedia.org/wiki/Konami_Code"
     },
@@ -457,11 +458,14 @@
       "Indent": "缩进",
       "Outdent": "回退缩进",
       "Save Page": "保存页面",
-      "Delete Line": "删除行"
-    },
-    "commentform": {
-      "title": "注释窗体快捷方式",
-      "Post": "提交"
+      "Only Editor": "(仅编辑器)",
+      "Delete Line": "删除行",
+      "Search in Editor": "编辑器内搜索",
+      "Move Line": "移动行",
+      "Copy Line": "复制行",
+      "Toggle Line": "注释/取消注释行",
+      "Insert Line": "插入行",
+      "Post Comment": "(发表评论)"
     }
   },
   "modal_resolve_conflict": {

+ 9 - 5
apps/app/src/client/components/PageEditor/EditorNavbar/EditorNavbar.tsx

@@ -8,16 +8,20 @@ import styles from './EditorNavbar.module.scss';
 
 const moduleClass = styles['editor-navbar'] ?? '';
 
-export const EditorNavbar = (): JSX.Element => {
+const EditingUsers = (): JSX.Element => {
   const { data: editingUsers } = useEditingUsers();
+  return (
+    <EditingUserList
+      userList={editingUsers?.userList ?? []}
+    />
+  );
+};
 
+export const EditorNavbar = (): JSX.Element => {
   return (
     <div className={`${moduleClass} d-flex flex-column flex-sm-row justify-content-between ps-3 ps-md-5 ps-xl-4 pe-4 py-1 align-items-sm-end`}>
       <div className="order-2 order-sm-1"><PageHeader /></div>
-      <div className="order-1 order-sm-2"><EditingUserList
-        userList={editingUsers?.userList ?? []}
-      />
-      </div>
+      <div className="order-1 order-sm-2"><EditingUsers /></div>
     </div>
   );
 };

+ 38 - 32
apps/app/src/client/components/PageEditor/PageEditor.tsx

@@ -81,7 +81,7 @@ type Props = {
   visibility?: boolean,
 }
 
-export const PageEditor = React.memo((props: Props): JSX.Element => {
+export const PageEditorSubstance = (props: Props): JSX.Element => {
 
   const { t } = useTranslation();
 
@@ -361,42 +361,48 @@ export const PageEditor = React.memo((props: Props): JSX.Element => {
     return <></>;
   }
 
+  return (
+    <div className={`flex-expand-horiz ${props.visibility ? '' : 'd-none'}`}>
+      <div className="page-editor-editor-container flex-expand-vert border-end">
+        <CodeMirrorEditorMain
+          isEditorMode={editorMode === EditorMode.Editor}
+          onSave={saveWithShortcut}
+          onUpload={uploadHandler}
+          acceptedUploadFileType={acceptedUploadFileType}
+          onScroll={scrollEditorHandlerThrottle}
+          indentSize={currentIndentSize ?? defaultIndentSize}
+          user={user ?? undefined}
+          pageId={pageId ?? undefined}
+          initialValue={initialValue}
+          editorSettings={editorSettings}
+          onEditorsUpdated={onEditorsUpdated}
+          cmProps={cmProps}
+        />
+      </div>
+      <div
+        ref={previewRef}
+        onScroll={scrollPreviewHandlerThrottle}
+        className="page-editor-preview-container flex-expand-vert overflow-y-auto d-none d-lg-flex"
+      >
+        <Preview
+          rendererOptions={rendererOptions}
+          markdown={markdownToPreview}
+          pagePath={currentPagePath}
+          expandContentWidth={shouldExpandContent}
+          style={pastEndStyle}
+        />
+      </div>
+    </div>
+  );
+};
+
+export const PageEditor = React.memo((props: Props): JSX.Element => {
   return (
     <div data-testid="page-editor" id="page-editor" className={`flex-expand-vert ${props.visibility ? '' : 'd-none'}`}>
 
       <EditorNavbar />
 
-      <div className={`flex-expand-horiz ${props.visibility ? '' : 'd-none'}`}>
-        <div className="page-editor-editor-container flex-expand-vert border-end">
-          <CodeMirrorEditorMain
-            isEditorMode={editorMode === EditorMode.Editor}
-            onSave={saveWithShortcut}
-            onUpload={uploadHandler}
-            acceptedUploadFileType={acceptedUploadFileType}
-            onScroll={scrollEditorHandlerThrottle}
-            indentSize={currentIndentSize ?? defaultIndentSize}
-            user={user ?? undefined}
-            pageId={pageId ?? undefined}
-            initialValue={initialValue}
-            editorSettings={editorSettings}
-            onEditorsUpdated={onEditorsUpdated}
-            cmProps={cmProps}
-          />
-        </div>
-        <div
-          ref={previewRef}
-          onScroll={scrollPreviewHandlerThrottle}
-          className="page-editor-preview-container flex-expand-vert overflow-y-auto d-none d-lg-flex"
-        >
-          <Preview
-            rendererOptions={rendererOptions}
-            markdown={markdownToPreview}
-            pagePath={currentPagePath}
-            expandContentWidth={shouldExpandContent}
-            style={pastEndStyle}
-          />
-        </div>
-      </div>
+      <PageEditorSubstance visibility={props.visibility} />
 
       <EditorNavbarBottom />
 

+ 6 - 66
apps/app/src/client/components/ShortcutsModal.module.scss

@@ -1,77 +1,17 @@
 @use '@growi/core-styles/scss/bootstrap/init' as bs;
+@use '@growi/core-styles/scss/helpers/modifier-keys';
 
 .shortcuts-modal :global {
-  h3 {
-    margin-bottom: 1em;
-  }
-
-  table {
-    th {
-      vertical-align: middle;
-    }
-    td {
-      min-width: 170px;
-    }
-  }
-
-  @include bs.media-breakpoint-up(sm) {
-    table {
-      table-layout: fixed;
-      th {
-        width: 170px;
-      }
-    }
-  }
 
-  // see http://coliss.com/articles/build-websites/operation/css/css-apple-keyboard-style-by-nrjmadan.html
   .key {
     /* Box Properties */
-    display: inline-block;
-    width: 36px;
-    height: 36px;
-    margin: 0 4px;
+    padding: 0 4px;
 
     /* Text Properties */
-    font: 18px/36px Helvetica, serif;
-    color: bs.$secondary;
-    text-align: center;
-    text-transform: uppercase;
-    background: white;
-    border-radius: 4px;
-    box-shadow: 0 1px 3px 1px rgba(0, 0, 0, 50%);
-
-    /* SVG Properties */
-    polygon {
-      fill: bs.$secondary;
-    }
-
-    &.key-longer {
-      width: 64px;
-    }
-    &.key-long {
-      width: 72px;
-    }
-    &.key-small {
-      width: 24px;
-      height: 24px;
-      margin: 4px 2px;
-      font-size: 18px;
-      line-height: 22px;
-    }
+    background: var(--bs-tertiary-bg);
+    border: var(--bs-border-width) solid var(--bs-border-color);
+    border-radius: var(--bs-border-radius-sm);
   }
 
-  .dl-horizontal {
-    dt {
-      display: flex;
-      align-items: center;
-      justify-content: flex-end;
-
-      // width: 180px;
-      height: 41px;
-    }
-
-    // dd {
-    //   margin-left: 190px;
-    // }
-  }
+  @include modifier-keys.modifier-key;
 }

+ 213 - 121
apps/app/src/client/components/ShortcutsModal.tsx

@@ -21,139 +21,231 @@ const ShortcutsModal = (): JSX.Element => {
     // add classes to cmd-key by OS
     const platform = window.navigator.platform.toLowerCase();
     const isMac = (platform.indexOf('mac') > -1);
-    const additionalClassByOs = isMac ? 'mac' : 'key-longer win';
+    const additionalClassByOs = isMac ? 'mac' : 'win';
 
     return (
       <div className="container">
         <div className="row">
           <div className="col-lg-6">
-            <h3>
+            <h6>
               <strong>{t('modal_shortcuts.global.title')}</strong>
-            </h3>
+            </h6>
 
-            <table className="table">
-              <tbody>
-                <tr>
-                  <th>
-                    {/* eslint-disable-next-line react/no-danger */}
-                    <span dangerouslySetInnerHTML={{ __html: t('modal_shortcuts.global.Open/Close shortcut help') }} />:
-                  </th>
-                  <td>
-                    <span className={`key cmd-key ${additionalClassByOs}`}></span> + <span className="key">/</span>
-                  </td>
-                </tr>
-                <tr>
-                  <th>{t('modal_shortcuts.global.Create Page')}:</th>
-                  <td>
-                    <span className="key">C</span>
-                  </td>
-                </tr>
-                <tr>
-                  <th>{t('modal_shortcuts.global.Edit Page')}:</th>
-                  <td>
-                    <span className="key">E</span>
-                  </td>
-                </tr>
-                <tr>
-                  <th>{t('modal_shortcuts.global.Search')}:</th>
-                  <td><span className="key">/</span></td>
-                </tr>
-                <tr>
-                  <th>
-                    {/* eslint-disable-next-line react/no-danger */}
-                    <span dangerouslySetInnerHTML={{ __html: t('modal_shortcuts.global.Show Contributors') }} />:
-                  </th>
-                  <td className="text-nowrap">
-                    <a href="{ t('modal_shortcuts.global.konami_code_url') }" target="_blank">
+            <ul className="list-unstyled m-0">
+              {/* Open/Close shortcut help */}
+              <li className="d-flex align-items-center p-3 border-bottom">
+                <div className="flex-grow-1">
+                  <span
+                    className="text-nowrap"
+                    // eslint-disable-next-line react/no-danger
+                    dangerouslySetInnerHTML={{ __html: t('modal_shortcuts.global.Open/Close shortcut help') }}
+                  />
+                </div>
+                <div className="d-flex align-items-center">
+                  <span className={`key cmd-key ${additionalClassByOs}`}></span>
+                  <span className="text-secondary mx-2">+</span>
+                  <span className="key">/</span>
+                </div>
+              </li>
+              {/* Create Page */}
+              <li className="d-flex align-items-center p-3 border-bottom">
+                <div className="flex-grow-1">{t('modal_shortcuts.global.Create Page')}</div>
+                <div>
+                  <span className="key">C</span>
+                </div>
+              </li>
+              {/* Edit Page */}
+              <li className="d-flex align-items-center p-3 border-bottom">
+                <div className="flex-grow-1">{t('modal_shortcuts.global.Edit Page')}</div>
+                <div>
+                  <span className="key">E</span>
+                </div>
+              </li>
+              {/* Search */}
+              <li className="d-flex align-items-center p-3 border-bottom">
+                <div className="flex-grow-1">{t('modal_shortcuts.global.Search')}</div>
+                <div>
+                  <span className="key">/</span>
+                </div>
+              </li>
+              {/* Show Contributors */}
+              <li className="d-flex align-items-center p-3 border-bottom">
+                <div className="flex-grow-1">
+                  <span
+                    className="text-nowrap"
+                    // eslint-disable-next-line react/no-danger
+                    dangerouslySetInnerHTML={{ __html: t('modal_shortcuts.global.Show Contributors') }}
+                  />
+                </div>
+                <div className="text-start">
+                  <a href={t('modal_shortcuts.global.konami_code_url')} target="_blank" rel="noreferrer">
+                    <span className="text-secondary small">
                       {t('modal_shortcuts.global.Konami Code')}
-                    </a>
-                    <br />
-                    <span className="key key-small">&uarr;</span>&nbsp;<span className="key key-small">&uarr;</span>
-                    <span className="key key-small">&darr;</span>&nbsp;<span className="key key-small">&darr;</span>
-                    <br />
-                    <span className="key key-small">&larr;</span>&nbsp;<span className="key key-small">&rarr;</span>
-                    <span className="key key-small">&larr;</span>&nbsp;<span className="key key-small">&rarr;</span>
-                    <br />
-                    <span className="key key-small">B</span>&nbsp;<span className="key key-small">A</span>
-                  </td>
-                </tr>
-                <tr>
-                  <th>{t('modal_shortcuts.global.MirrorMode')}:</th>
-                  <td className="text-nowrap">
-                    <a href="{ t('modal_shortcuts.global.konami_code_url') }" target="_blank">
+                    </span>
+                  </a>
+                  <div className="d-flex gap-2 flex-column align-items-start mt-1">
+                    <div className="d-flex gap-1">
+                      <span className="key material-symbols-outlined fs-5 px-0">arrow_upward</span>
+                      <span className="key material-symbols-outlined fs-5 px-0">arrow_upward</span>
+                      <span className="key material-symbols-outlined fs-5 px-0">arrow_downward</span>
+                      <span className="key material-symbols-outlined fs-5 px-0">arrow_downward</span>
+                    </div>
+                    <div className="d-flex gap-1">
+                      <span className="key material-symbols-outlined fs-5 px-0">arrow_back</span>
+                      <span className="key material-symbols-outlined fs-5 px-0">arrow_forward</span>
+                      <span className="key material-symbols-outlined fs-5 px-0">arrow_back</span>
+                      <span className="key material-symbols-outlined fs-5 px-0">arrow_forward</span>
+                    </div>
+                    <div className="d-flex gap-1">
+                      <span className="key">B</span>
+                      <span className="key">A</span>
+                    </div>
+                  </div>
+                </div>
+              </li>
+              {/* Mirror Mode */}
+              <li className="d-flex align-items-center p-3">
+                <div className="flex-grow-1">{t('modal_shortcuts.global.MirrorMode')}</div>
+                <div className="text-start">
+                  <a href={t('modal_shortcuts.global.konami_code_url')} target="_blank" rel="noreferrer">
+                    <span className="text-secondary small">
                       {t('modal_shortcuts.global.Konami Code')}
-                    </a>
-                    <br />
-                    <span className="key key-small">X</span>&nbsp;<span className="key key-small">X</span>
-                    <span className="key key-small">B</span>&nbsp;<span className="key key-small">B</span>
-                    <br />
-                    <span className="key key-small">A</span>&nbsp;<span className="key key-small">Y</span>
-                    <span className="key key-small">A</span>&nbsp;<span className="key key-small">Y</span>
-                    <br />
-                    <span className="key key-small">&darr;</span>&nbsp;<span className="key key-small">&larr;</span>
-                  </td>
-                </tr>
-              </tbody>
-            </table>
+                    </span>
+                  </a>
+                  <div className="d-flex gap-2 flex-column align-items-start mt-1">
+                    <div className="d-flex gap-1">
+                      <span className="key">X</span>
+                      <span className="key">X</span>
+                      <span className="key">B</span>
+                      <span className="key">B</span>
+                    </div>
+                    <div className="d-flex gap-1">
+                      <span className="key">A</span>
+                      <span className="key">Y</span>
+                      <span className="key">A</span>
+                      <span className="key">Y</span>
+                    </div>
+                    <div className="d-flex gap-1">
+                      <span className="key material-symbols-outlined fs-5 px-0">arrow_downward</span>
+                      <span className="key material-symbols-outlined fs-5 px-0">arrow_back</span>
+                    </div>
+                  </div>
+                </div>
+              </li>
+            </ul>
           </div>
 
           <div className="col-lg-6">
-            <h3>
+            <h6>
               <strong>{t('modal_shortcuts.editor.title')}</strong>
-            </h3>
-            <table className="table">
-              <tbody>
-                <tr>
-                  <th>{t('modal_shortcuts.editor.Indent')}:</th>
-                  <td>
-                    <span className="key key-longer">Tab</span>
-                  </td>
-                </tr>
-                <tr>
-                  <th>{t('modal_shortcuts.editor.Outdent')}:</th>
-                  <td className="text-nowrap">
-                    <span className="key key-long">Shift</span> + <span className="key key-longer">Tab</span>
-                  </td>
-                </tr>
-                <tr>
-                  <th>{t('modal_shortcuts.editor.Save Page')}:</th>
-                  <td>
-                    <span className={`key cmd-key ${additionalClassByOs}`}></span> + <span className="key">S</span>
-                  </td>
-                </tr>
-                <tr>
-                  <th>{t('modal_shortcuts.editor.Delete Line')}:</th>
-                  <td>
-                    <span className={`key cmd-key ${additionalClassByOs}`}></span> + <span className="key">D</span>
-                  </td>
-                </tr>
-              </tbody>
-            </table>
-
-            <h3>
-              <strong>{t('modal_shortcuts.commentform.title')}</strong>
-            </h3>
-
-            <table className="table">
-              <tbody>
-                <tr>
-                  <th>{t('modal_shortcuts.commentform.Post')}:</th>
-                  <td className="text-nowrap">
-                    <span className={`key cmd-key ${additionalClassByOs}`}></span> +
-                    <span className="key key-longer">
-                      <span className="material-symbols-outlined">keyboard_return</span>
-                    </span>
-                  </td>
-                </tr>
-                <tr>
-                  <th>{t('modal_shortcuts.editor.Delete Line')}:</th>
-                  <td>
-                    <span className={`key cmd-key ${additionalClassByOs}`}></span> + <span className="key">D</span>
-                  </td>
-                </tr>
-              </tbody>
-            </table>
+            </h6>
+            <ul className="list-unstyled m-0">
+              {/* Search in Editor */}
+              <li className="d-flex align-items-center p-3 border-bottom">
+                <div className="flex-grow-1">{t('modal_shortcuts.editor.Search in Editor')}</div>
+                <div className="text-nowrap">
+                  <span className={`key cmd-key ${additionalClassByOs}`}></span>
+                  <span className="text-secondary mx-2">+</span>
+                  <span className="key">F</span>
+                </div>
+              </li>
+              {/* Save Page */}
+              <li className="d-flex align-items-center p-3 border-bottom">
+                <div className="flex-grow-1">
+                  {t('modal_shortcuts.editor.Save Page')}
+                  <span className="small text-secondary ms-1">{t('modal_shortcuts.editor.Only Editor')}</span>
+                </div>
+                <div className="text-nowrap">
+                  <span className={`key cmd-key ${additionalClassByOs}`}></span>
+                  <span className="text-secondary mx-2">+</span>
+                  <span className="key">S</span>
+                </div>
+              </li>
+              {/* Indent */}
+              <li className="d-flex align-items-center p-3 border-bottom">
+                <div className="flex-grow-1">{t('modal_shortcuts.editor.Indent')}</div>
+                <div>
+                  <span className="key">Tab</span>
+                </div>
+              </li>
+              {/* Outdent */}
+              <li className="d-flex align-items-center p-3 border-bottom">
+                <div className="flex-grow-1">{t('modal_shortcuts.editor.Outdent')}</div>
+                <div className="text-nowrap gap-1">
+                  <span className="key">Shift</span>
+                  <span className="text-secondary mx-2">+</span>
+                  <span className="key">Tab</span>
+                </div>
+              </li>
+              {/* Delete Line */}
+              <li className="d-flex align-items-center p-3 border-bottom">
+                <div className="flex-grow-1">{t('modal_shortcuts.editor.Delete Line')}</div>
+                <div className="text-nowrap">
+                  <span className={`key cmd-key ${additionalClassByOs}`}></span>
+                  <span className="text-secondary mx-2">+</span>
+                  <span className="key">Shift</span>
+                  <span className="text-secondary mx-2">+</span>
+                  <span className="key">K</span>
+                </div>
+              </li>
+              {/* Insert Line */}
+              <li className="d-flex align-items-center p-3 border-bottom">
+                <div className="flex-grow-1">
+                  <span
+                  // eslint-disable-next-line react/no-danger
+                    dangerouslySetInnerHTML={{ __html: t('modal_shortcuts.editor.Insert Line') }}
+                  />
+                  <br />
+                  <span className="small text-secondary ms-1">{t('modal_shortcuts.editor.Post Comment')}</span>
+                </div>
+                <div className="text-nowrap">
+                  <span className={`key cmd-key ${additionalClassByOs}`}></span>
+                  <span className="text-secondary mx-2">+</span>
+                  <span className="key">Enter</span>
+                </div>
+              </li>
+              {/* Move Line */}
+              <li className="d-flex align-items-center p-3 border-bottom">
+                <div className="flex-grow-1">{t('modal_shortcuts.editor.Move Line')}</div>
+                <div className="text-nowrap">
+                  <span className={`key alt-key ${additionalClassByOs}`}></span>
+                  <span className="text-secondary mx-2">+</span>
+                  <span className="key material-symbols-outlined fs-5 px-0">arrow_downward</span>
+                  <span className="text-secondary mx-2">or</span>
+                  <span className="key material-symbols-outlined fs-5 px-0">arrow_upward</span>
+                </div>
+              </li>
+              {/* Copy Line */}
+              <li className="d-flex align-items-center p-3 border-bottom">
+                <div className="flex-grow-1">{t('modal_shortcuts.editor.Copy Line')}</div>
+                <div className="text-nowrap">
+                  <div className="text-start">
+                    <div>
+                      <span className={`key alt-key ${additionalClassByOs}`}></span>
+                      <span className="text-secondary mx-2">+</span>
+                      <span className="key">Shift</span>
+                      <span className="text-secondary ms-2">+</span>
+                    </div>
+                    <div className="mt-1">
+                      <span className="key material-symbols-outlined fs-5 px-0">arrow_downward</span>
+                      <span className="text-secondary mx-2">or</span>
+                      <span className="key material-symbols-outlined fs-5 px-0">arrow_upward</span>
+                    </div>
+                  </div>
+                </div>
+              </li>
+              {/* Toggle Line */}
+              <li className="d-flex align-items-center p-3">
+                <div className="flex-grow-1">{t('modal_shortcuts.editor.Toggle Line')}</div>
+                <div className="text-nowrap">
+                  <span className={`key cmd-key ${additionalClassByOs}`}></span>
+                  <span className="text-secondary mx-2">+</span>
+                  <span className="key">/</span>
+                </div>
+              </li>
+            </ul>
           </div>
+          {/* TODO: Add docs link button https://redmine.weseek.co.jp/issues/161862 */}
         </div>
       </div>
     );
@@ -163,10 +255,10 @@ const ShortcutsModal = (): JSX.Element => {
     <>
       { status != null && (
         <Modal id="shortcuts-modal" size="lg" isOpen={status.isOpened} toggle={close} className={`shortcuts-modal ${styles['shortcuts-modal']}`}>
-          <ModalHeader tag="h4" toggle={close}>
+          <ModalHeader tag="h4" toggle={close} className="px-4">
             {t('Shortcuts')}
           </ModalHeader>
-          <ModalBody>
+          <ModalBody className="p-md-4">
             {bodyContent()}
           </ModalBody>
         </Modal>

+ 41 - 0
apps/app/src/client/components/Sidebar/AppTitle/AppTitle.module.scss

@@ -2,6 +2,7 @@
 @use '@growi/core-styles/scss/variables/growi-official-colors';
 @use '~/styles/variables' as var;
 @use '../button-styles';
+@use '~/styles/mixins';
 
 // GROWI Logo
 .grw-app-title :global {
@@ -25,6 +26,22 @@
   }
 }
 
+// == GROWI Logo when Editor mode
+@include mixins.at-editing() {
+  @include bs.media-breakpoint-up(xl) {
+    .grw-app-title :global {
+      .grw-logo {
+          opacity: 0.5;
+          transition: opacity 0.8s ease;
+
+          &:hover {
+            opacity: 1;
+          }
+      }
+    }
+  }
+}
+
 
 // == Location
 .on-subnavigation {
@@ -64,6 +81,30 @@
   width: calc(100% - $toggle-collapse-button-width);
 }
 
+// ==Sidebar Head when Editor mode
+@include bs.color-mode(light) {
+  .on-editor-sidebar-head {
+    background-color: var(
+      --on-editor-sidebar-head-bg,
+      var(
+        --grw-sidebar-nav-bg,
+        var(--grw-highlight-100)
+      )
+    );
+  }
+}
+
+@include bs.color-mode(dark) {
+  .on-editor-sidebar-head {
+    background-color: var(
+      --on-editor-sidebar-head-bg,
+      var(
+        --grw-sidebar-nav-bg,
+        var(--grw-highlight-800)
+      )
+    );
+  }
+}
 
 // == Interaction
 @keyframes bounce-to-right {

+ 27 - 11
apps/app/src/client/components/Sidebar/AppTitle/AppTitle.tsx

@@ -12,28 +12,29 @@ import styles from './AppTitle.module.scss';
 
 type Props = {
   className?: string,
+  hideAppTitle?: boolean;
 }
 
-const AppTitleSubstance = memo((props: Props): JSX.Element => {
-
-  const { className } = props;
+const AppTitleSubstance = memo(({ className = '', hideAppTitle = false }: Props): JSX.Element => {
 
   const { data: isDefaultLogo } = useIsDefaultLogo();
   const { data: appTitle } = useAppTitle();
   const { data: confidential } = useConfidential();
 
   return (
-    <div className={`${styles['grw-app-title']} ${className} d-flex d-edit-none`}>
+    <div className={`${styles['grw-app-title']} ${className} d-flex`}>
       {/* Brand Logo  */}
       <Link href="/" className="grw-logo d-block">
         <SidebarBrandLogo isDefaultLogo={isDefaultLogo} />
       </Link>
       <div className="flex-grow-1 d-flex align-items-center justify-content-between gap-3 overflow-hidden">
-        <div id="grw-site-name" className="grw-site-name text-truncate">
-          <Link href="/" className="fs-4">
-            {appTitle}
-          </Link>
-        </div>
+        {!hideAppTitle && (
+          <div id="grw-site-name" className="grw-site-name text-truncate">
+            <Link href="/" className="fs-4">
+              {appTitle}
+            </Link>
+          </div>
+        )}
       </div>
       {!(confidential == null || confidential === '')
       && (
@@ -56,6 +57,21 @@ export const AppTitleOnSubnavigation = memo((): JSX.Element => {
   return <AppTitleSubstance className={`position-absolute ${styles['on-subnavigation']}`} />;
 });
 
-export const AppTitleOnSidebarHead = memo((): JSX.Element => {
-  return <AppTitleSubstance className={`position-absolute z-1 ${styles['on-sidebar-head']}`} />;
+export const AppTitleOnSidebarHead = memo(({ hideAppTitle }: Props): JSX.Element => {
+  return (
+    <AppTitleSubstance
+      className={`position-absolute z-1 ${styles['on-sidebar-head']}`}
+      hideAppTitle={hideAppTitle}
+    />
+  );
+});
+
+export const AppTitleOnEditorSidebarHead = memo((): JSX.Element => {
+  return (
+    <div className={`${styles['on-editor-sidebar-head']}`}>
+      <AppTitleSubstance
+        className={`${styles['on-sidebar-head']}`}
+      />
+    </div>
+  );
 });

+ 20 - 5
apps/app/src/client/components/Sidebar/Sidebar.tsx

@@ -11,6 +11,7 @@ import { useIsomorphicLayoutEffect } from 'usehooks-ts';
 
 import { SidebarMode } from '~/interfaces/ui';
 import { useIsSearchPage } from '~/stores-universal/context';
+import { EditorMode, useEditorMode } from '~/stores-universal/ui';
 import {
   useDrawerOpened,
   useCollapsedContentsOpened,
@@ -18,11 +19,13 @@ import {
   usePreferCollapsedMode,
   useSidebarMode,
   useSidebarScrollerRef,
+  useIsDeviceLargerThanMd,
+  useIsDeviceLargerThanXl,
 } from '~/stores/ui';
 
 import { DrawerToggler } from '../Common/DrawerToggler';
 
-import { AppTitleOnSidebarHead, AppTitleOnSubnavigation } from './AppTitle/AppTitle';
+import { AppTitleOnSidebarHead, AppTitleOnEditorSidebarHead, AppTitleOnSubnavigation } from './AppTitle/AppTitle';
 import { ResizableAreaFallback } from './ResizableArea/ResizableAreaFallback';
 import type { ResizableAreaProps } from './ResizableArea/props';
 import { SidebarHead } from './SidebarHead';
@@ -230,6 +233,14 @@ export const Sidebar = (): JSX.Element => {
   } = useSidebarMode();
 
   const { data: isSearchPage } = useIsSearchPage();
+  const { data: editorMode } = useEditorMode();
+  const { data: isMdSize } = useIsDeviceLargerThanMd();
+  const { data: isXlSize } = useIsDeviceLargerThanXl();
+
+  const isEditorMode = editorMode === EditorMode.Editor;
+  const shouldHideSiteName = isEditorMode && isXlSize;
+  const shouldHideSubnavAppTitle = isEditorMode && isMdSize && (isDrawerMode() || isCollapsedMode());
+  const shouldShowEditorSidebarHead = isEditorMode && isXlSize;
 
   // css styles
   const grwSidebarClass = styles['grw-sidebar'];
@@ -253,12 +264,16 @@ export const Sidebar = (): JSX.Element => {
         <DrawerToggler className="position-fixed d-none d-md-block">
           <span className="material-symbols-outlined">reorder</span>
         </DrawerToggler>
-      ) }
-      { sidebarMode != null && !isDockMode() && !isSearchPage && <AppTitleOnSubnavigation /> }
+      )}
+      { sidebarMode != null && !isDockMode() && !isSearchPage && !shouldHideSubnavAppTitle && (
+        <AppTitleOnSubnavigation />
+      )}
       <DrawableContainer className={`${grwSidebarClass} ${modeClass} border-end flex-expand-vh-100`} divProps={{ 'data-testid': 'grw-sidebar' }}>
         <ResizableContainer>
-          { sidebarMode != null && !isCollapsedMode() && <AppTitleOnSidebarHead /> }
-          <SidebarHead />
+          { sidebarMode != null && !isCollapsedMode() && (
+            <AppTitleOnSidebarHead hideAppTitle={shouldHideSiteName} />
+          )}
+          {shouldShowEditorSidebarHead ? <AppTitleOnEditorSidebarHead /> : <SidebarHead />}
           <CollapsibleContainer Nav={SidebarNav} className="border-top">
             <SidebarContents />
           </CollapsibleContainer>

+ 5 - 1
apps/app/src/client/components/SystemVersion.module.scss

@@ -1,6 +1,10 @@
-.system-version {
+@use '@growi/core-styles/scss/helpers/modifier-keys';
+
+.system-version :global {
   position: fixed;
   right: 0.5em;
   bottom: 0;
   opacity: 0.6;
+
+  @include modifier-keys.modifier-key;
 }

+ 12 - 0
apps/app/src/pages/login/index.page.tsx

@@ -1,5 +1,6 @@
 import React from 'react';
 
+import { pagePathUtils } from '@growi/core/dist/utils';
 import type {
   NextPage, GetServerSideProps, GetServerSidePropsContext,
 } from 'next';
@@ -24,6 +25,8 @@ import {
 import styles from './index.module.scss';
 
 
+const { isPermalink, isUserPage, isUsersTopPage } = pagePathUtils;
+
 const LoginForm = dynamic(() => import('~/client/components/LoginForm').then(mod => mod.LoginForm), { ssr: false });
 
 
@@ -127,6 +130,15 @@ async function injectServerConfigurations(context: GetServerSidePropsContext, pr
 export const getServerSideProps: GetServerSideProps = async(context: GetServerSidePropsContext) => {
   const result = await getServerSideCommonProps(context);
 
+
+  // redirect to the page the user was on before moving to the Login Page
+  if (context.req.headers.referer != null) {
+    const urlBeforeLogin = new URL(context.req.headers.referer);
+    if (isPermalink(urlBeforeLogin.pathname) || isUserPage(urlBeforeLogin.pathname) || isUsersTopPage(urlBeforeLogin.pathname)) {
+      (context.req as CrowiRequest).session.redirectTo = urlBeforeLogin.href;
+    }
+  }
+
   // check for presence
   // see: https://github.com/vercel/next.js/issues/19271#issuecomment-730006862
   if (!('props' in result)) {

+ 1 - 1
apps/app/src/server/routes/apiv3/import.js

@@ -319,7 +319,7 @@ export default function route(crowi) {
    *                      type: object
    *                      description: the property of each extracted file
    */
-  router.post('/upload', uploads.single('file'), accessTokenParser, loginRequired, adminRequired, addActivity, async(req, res) => {
+  router.post('/upload', accessTokenParser, loginRequired, adminRequired, uploads.single('file'), addActivity, async(req, res) => {
     const { file } = req;
     const zipFile = importService.getFile(file.filename);
     let data = null;

+ 72 - 19
apps/app/src/server/routes/apiv3/revisions.js

@@ -18,6 +18,41 @@ const router = express.Router();
 
 const MIGRATION_FILE_NAME = '20211227060705-revision-path-to-page-id-schema-migration--fixed-7549';
 
+/**
+ * @swagger
+ * components:
+ *   schemas:
+ *     Revision:
+ *       type: object
+ *       properties:
+ *         _id:
+ *           type: string
+ *           description: The revision ID
+ *         format:
+ *           type: string
+ *           description: The format of the revision
+ *         pageId:
+ *           type: string
+ *           description: The ID of the page the revision belongs to
+ *         body:
+ *           type: string
+ *           description: The content of the revision
+ *         author:
+ *           $ref: '#/components/schemas/User'
+ *         origin:
+ *           type: string
+ *           description: The origin of the revision
+ *         hasDiffToPrev:
+ *           type: boolean
+ *           description: Whether the revision has differences to the previous one
+ *         createdAt:
+ *           type: string
+ *           format: date-time
+ *           description: The creation time of the revision
+ *         __v:
+ *           type: integer
+ *           description: The version key of the revision
+ */
 /** @param {import('~/server/crowi').default} crowi Crowi instance */
 module.exports = (crowi) => {
   const certifySharedPage = require('../../middlewares/certify-shared-page')(crowi);
@@ -41,6 +76,23 @@ module.exports = (crowi) => {
     ],
   };
 
+  let cachedAppliedAt = null;
+
+  const getAppliedAtOfTheMigrationFile = async() => {
+
+    if (cachedAppliedAt != null) {
+      return cachedAppliedAt;
+    }
+
+    const migrationCollection = connection.collection('migrations');
+    const migration = await migrationCollection.findOne({ fileName: { $regex: `^${MIGRATION_FILE_NAME}` } });
+    const appliedAt = migration.appliedAt;
+
+    cachedAppliedAt = appliedAt;
+
+    return appliedAt;
+  };
+
   /**
    * @swagger
    *
@@ -67,25 +119,21 @@ module.exports = (crowi) => {
    *        responses:
    *          200:
    *            description: Return revisions belong to page
-   *
+   *            content:
+   *              application/json:
+   *               schema:
+   *                properties:
+   *                  revisions:
+   *                    type: array
+   *                    items:
+   *                      $ref: '#/components/schemas/Revision'
+   *                  totalCount:
+   *                    type: number
+   *                    description: total count of revisions
+   *                  offset:
+   *                    type: number
+   *                    description: offset of the revisions
    */
-  let cachedAppliedAt = null;
-
-  const getAppliedAtOfTheMigrationFile = async() => {
-
-    if (cachedAppliedAt != null) {
-      return cachedAppliedAt;
-    }
-
-    const migrationCollection = connection.collection('migrations');
-    const migration = await migrationCollection.findOne({ fileName: { $regex: `^${MIGRATION_FILE_NAME}` } });
-    const appliedAt = migration.appliedAt;
-
-    cachedAppliedAt = appliedAt;
-
-    return appliedAt;
-  };
-
   router.get('/list', certifySharedPage, accessTokenParser, loginRequired, validator.retrieveRevisions, apiV3FormValidator, async(req, res) => {
     const pageId = req.query.pageId;
     const limit = req.query.limit || await crowi.configManager.getConfig('customize:showPageLimitationS') || 10;
@@ -178,7 +226,12 @@ module.exports = (crowi) => {
    *        responses:
    *          200:
    *            description: Return revision
-   *
+   *            content:
+   *              application/json:
+   *                schema:
+   *                  properties:
+   *                    revision:
+   *                      $ref: '#/components/schemas/Revision'
    */
   router.get('/:id', certifySharedPage, accessTokenParser, loginRequired, validator.retrieveRevisionById, apiV3FormValidator, async(req, res) => {
     const revisionId = req.params.id;

+ 91 - 1
apps/app/src/server/routes/apiv3/search.js

@@ -17,6 +17,87 @@ const router = express.Router();
 
 const noCache = require('nocache');
 
+/**
+ * @swagger
+ *
+ * components:
+ *   schemas:
+ *     Indices:
+ *       type: object
+ *       properties:
+ *         growi:
+ *           type: object
+ *           properties:
+ *             uuid:
+ *               type: string
+ *             health:
+ *               type: string
+ *             status:
+ *               type: string
+ *             primaries:
+ *               type: object
+ *               $ref: '#/components/schemas/SearchIndex'
+ *             total:
+ *               type: object
+ *               $ref: '#/components/schemas/SearchIndex'
+ *         aliases:
+ *           type: object
+ *           properties:
+ *             growi:
+ *               type: object
+ *               properties:
+ *                 aliases:
+ *                   type: object
+ *                   properties:
+ *                     growi-alias:
+ *                       type: object
+ *         isNormalized:
+ *           type: boolean
+ *     SearchIndex:
+ *       type: object
+ *       properties:
+ *         docs:
+ *           type: object
+ *           properties:
+ *             count:
+ *               type: integer
+ *             deleted:
+ *               type: integer
+ *         store:
+ *           type: object
+ *           properties:
+ *             size_in_bytes:
+ *               type: integer
+ *             total_data_set_size_in_bytes:
+ *               type: integer
+ *             reserved_in_bytes:
+ *               type: integer
+ *         indexing:
+ *           type: object
+ *           properties:
+ *             index_total:
+ *               type: integer
+ *             index_time_in_millis:
+ *               type: integer
+ *             index_current:
+ *               type: integer
+ *             index_failed:
+ *               type: integer
+ *             delete_total:
+ *               type: integer
+ *             delete_time_in_millis:
+ *               type: integer
+ *             delete_current:
+ *               type: integer
+ *             noop_update_total:
+ *               type: integer
+ *             is_throttled:
+ *               type: boolean
+ *             throttle_time_in_millis:
+ *               type: integer
+ *             write_load:
+ *               type: number
+ */
 /** @param {import('~/server/crowi').default} crowi Crowi instance */
 module.exports = (crowi) => {
   const loginRequired = require('../../middlewares/login-required')(crowi);
@@ -42,6 +123,8 @@ module.exports = (crowi) => {
    *                properties:
    *                  info:
    *                    type: object
+   *                    description: Status of indices
+   *                    $ref: '#/components/schemas/Indices'
    */
   router.get('/indices', noCache(), accessTokenParser, loginRequired, adminRequired, async(req, res) => {
     const { searchService } = crowi;
@@ -63,7 +146,7 @@ module.exports = (crowi) => {
    * @swagger
    *
    *  /search/connection:
-   *    get:
+   *    post:
    *      tags: [FullTextSearch Management]
    *      summary: /search/connection
    *      description: Reconnect to Elasticsearch
@@ -117,6 +200,13 @@ module.exports = (crowi) => {
    *      responses:
    *        200:
    *          description: Return 200
+   *          content:
+   *            application/json:
+   *              schema:
+   *                properties:
+   *                  message:
+   *                    type: string
+   *                    description: Operation is successfully processed, or requested
    */
   router.put('/indices', accessTokenParser, loginRequired, adminRequired, addActivity, validatorForPutIndices, apiV3FormValidator, async(req, res) => {
     const operation = req.body.operation;

+ 96 - 4
apps/app/src/server/routes/apiv3/share-links.js

@@ -20,6 +20,65 @@ const validator = {};
 
 const today = new Date();
 
+/**
+ * @swagger
+ *
+ * components:
+ *   schemas:
+ *     ShareLink:
+ *       type: object
+ *       properties:
+ *         _id:
+ *           type: string
+ *           description: The unique identifier of the share link
+ *         relatedPage:
+ *           type: object
+ *           properties:
+ *             _id:
+ *               type: string
+ *               description: The unique identifier of the related page
+ *             path:
+ *               type: string
+ *               description: The path of the related page
+ *         expiredAt:
+ *           type: string
+ *           format: date-time
+ *           description: The expiration date of the share link
+ *         description:
+ *           type: string
+ *           description: The description of the share link
+ *         createdAt:
+ *           type: string
+ *           format: date-time
+ *           description: The creation date of the share link
+ *         __v:
+ *           type: integer
+ *           description: The version key
+ *     ShareLinkSimple:
+ *       type: object
+ *       properties:
+ *         relatedPage:
+ *           type: string
+ *           description: The unique identifier of the related page
+ *         expiredAt:
+ *           type: string
+ *           format: date-time
+ *           description: The expiration date of the share link
+ *         description:
+ *           type: string
+ *           description: The description of the share link
+ *         createdAt:
+ *           type: string
+ *           format: date-time
+ *           description: The creation date of the share link
+ *         __v:
+ *           type: integer
+ *           description: The version key
+ *         _id:
+ *           type: string
+ *           description: The unique identifier of the share link
+ */
+
 /** @param {import('~/server/crowi').default} crowi Crowi instance */
 module.exports = (crowi) => {
   const loginRequired = require('../../middlewares/login-required')(crowi);
@@ -54,7 +113,9 @@ module.exports = (crowi) => {
    *  paths:
    *    /share-links/:
    *      get:
-   *        tags: [ShareLink]
+   *        tags: [ShareLinks]
+   *        security:
+   *          - cookieAuth: []
    *        description: get share links
    *        parameters:
    *          - name: relatedPage
@@ -66,6 +127,14 @@ module.exports = (crowi) => {
    *        responses:
    *          200:
    *            description: Succeeded to get share links
+   *            content:
+   *              application/json:
+   *                schema:
+   *                  properties:
+   *                    shareLinksResult:
+   *                      type: array
+   *                      items:
+   *                        $ref: '#/components/schemas/ShareLink'
    */
   router.get('/', loginRequired, linkSharingRequired, validator.getShareLinks, apiV3FormValidator, async(req, res) => {
     const { relatedPage } = req.query;
@@ -104,7 +173,9 @@ module.exports = (crowi) => {
    *  paths:
    *    /share-links/:
    *      post:
-   *        tags: [ShareLink]
+   *        tags: [ShareLinks]
+   *        security:
+   *          - cookieAuth: []
    *        description: Create new share link
    *        parameters:
    *          - name: relatedPage
@@ -126,8 +197,11 @@ module.exports = (crowi) => {
    *        responses:
    *          200:
    *            description: Succeeded to create one share link
+   *            content:
+   *              application/json:
+   *                schema:
+   *                 $ref: '#/components/schemas/ShareLinkSimple'
    */
-
   router.post('/', loginRequired, excludeReadOnlyUser, linkSharingRequired, addActivity, validator.shareLinkStatus, apiV3FormValidator, async(req, res) => {
     const { relatedPage, expiredAt, description } = req.body;
 
@@ -165,7 +239,9 @@ module.exports = (crowi) => {
   *    /share-links/:
   *      delete:
   *        tags: [ShareLinks]
-  *        summary: /share-links/
+  *        security:
+  *          - cookieAuth: []
+  *        summary: delete all share links related one page
   *        description: delete all share links related one page
   *        parameters:
   *          - name: relatedPage
@@ -177,6 +253,10 @@ module.exports = (crowi) => {
   *        responses:
   *          200:
   *            description: Succeeded to delete o all share links related one page
+  *            content:
+  *              application/json:
+  *                schema:
+  *                 $ref: '#/components/schemas/ShareLinkSimple'
   */
   router.delete('/', loginRequired, excludeReadOnlyUser, addActivity, validator.deleteShareLinks, apiV3FormValidator, async(req, res) => {
     const { relatedPage } = req.query;
@@ -208,10 +288,20 @@ module.exports = (crowi) => {
   *    /share-links/all:
   *      delete:
   *        tags: [ShareLink Management]
+  *        security:
+  *         - cookieAuth: []
+  *        summary: delete all share links
   *        description: delete all share links
   *        responses:
   *          200:
   *            description: Succeeded to remove all share links
+  *            content:
+  *              application/json:
+  *                schema:
+  *                  properties:
+  *                    deletedCount:
+  *                      type: integer
+  *                      description: The number of share links deleted
   */
   router.delete('/all', loginRequired, adminRequired, addActivity, async(req, res) => {
 
@@ -240,6 +330,8 @@ module.exports = (crowi) => {
   *    /share-links/{id}:
   *      delete:
   *        tags: [ShareLinks]
+  *        security:
+  *          - cookieAuth: []
   *        description: delete one share link related one page
   *        parameters:
   *          - name: id

+ 0 - 12
apps/app/src/styles/style-app.scss

@@ -82,18 +82,6 @@
   }
 }
 
-.cmd-key.mac {
-  &::after {
-    content: '⌘';
-  }
-}
-
-.cmd-key.win {
-  &::after {
-    content: 'Ctrl';
-  }
-}
-
 .grw-page-control-dropdown-item {
   display: flex !important;
   align-items: center;

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

@@ -11,7 +11,7 @@ WORKDIR ${optDir}
 
 # install pnpm
 RUN apt-get update && apt-get install -y ca-certificates wget --no-install-recommends \
-  && wget -qO- https://get.pnpm.io/install.sh | ENV="$HOME/.shrc" SHELL="$(which sh)" sh -
+  && wget -qO- https://get.pnpm.io/install.sh | ENV="$HOME/.shrc" SHELL="$(which sh)" PNPM_VERSION="10.4.1" sh -
 ENV PNPM_HOME="/root/.local/share/pnpm"
 ENV PATH="$PNPM_HOME:$PATH"
 

+ 1 - 1
bin/data-migrations/src/migrations/v60x/csv.js

@@ -7,7 +7,7 @@ module.exports = [
    * @type {MigrationModule}
    */
   (body) => {
-    const oldCsvTableRegExp = /::: csv(-h)?\n([\s\S]*?)\n:::/g; // CSV old format
+    const oldCsvTableRegExp = /:::\s?csv(-h)?\n([\s\S]*?)\n:::/g; // CSV old format
     return body.replace(oldCsvTableRegExp, '``` csv$1\n$2\n```');
   },
 ];

+ 1 - 1
bin/data-migrations/src/migrations/v60x/tsv.js

@@ -7,7 +7,7 @@ module.exports = [
    * @type {MigrationModule}
    */
   (body) => {
-    const oldTsvTableRegExp = /::: tsv(-h)?\n([\s\S]*?)\n:::/g; // TSV old format
+    const oldTsvTableRegExp = /:::\s?tsv(-h)?\n([\s\S]*?)\n:::/g; // TSV old format
     return body.replace(oldTsvTableRegExp, '``` tsv$1\n$2\n```');
   },
 ];

+ 2 - 3
package.json

@@ -20,7 +20,7 @@
   "bugs": {
     "url": "https://github.com/weseek/growi/issues"
   },
-  "packageManager": "pnpm@9.4.0",
+  "packageManager": "pnpm@10.4.1",
   "scripts": {
     "bootstrap": "pnpm install",
     "start": "pnpm run app:server",
@@ -114,7 +114,6 @@
     }
   },
   "engines": {
-    "node": "^18 || ^20",
-    "pnpm": ">=9.4 <10"
+    "node": "^18 || ^20"
   }
 }

+ 25 - 0
packages/core-styles/scss/helpers/_modifier-keys.scss

@@ -0,0 +1,25 @@
+@mixin modifier-key {
+  .cmd-key.mac {
+    &::after {
+      content: '⌘';
+    }
+  }
+
+  .cmd-key.win {
+    &::after {
+      content: 'Ctrl';
+    }
+  }
+
+  .alt-key.mac {
+    &::after {
+      content: '⌥';
+    }
+  }
+
+  .alt-key.win {
+    &::after {
+      content: 'Alt';
+    }
+  }
+}

+ 12 - 14
packages/editor/package.json

@@ -24,19 +24,17 @@
     "react-dom": "^18.2.0"
   },
   "// comments for devDependencies": {
-    "string-width": "5.0.0 or above exports only ESM.",
-    "@codemirror/*": "Fix version of @codemirror/state < 6.4.0 due to fix the issue of https://github.com/weseek/growi/pull/9267 and https://github.com/weseek/growi/pull/9043",
-    "@codemirror/merge": "Fixed version at 6.0.0 due to errors caused by dependent packages"
+    "string-width": "5.0.0 or above exports only ESM."
   },
   "devDependencies": {
-    "@codemirror/autocomplete": "^6.18.1",
-    "@codemirror/commands": "~6.2.5",
-    "@codemirror/lang-markdown": "~6.2.5",
-    "@codemirror/language": "~6.9.3",
+    "@codemirror/autocomplete": "^6.18.4",
+    "@codemirror/commands": "^6.8.0",
+    "@codemirror/lang-markdown": "^6.3.2",
+    "@codemirror/language": "^6.10.8",
     "@codemirror/language-data": "^6.5.1",
-    "@codemirror/merge": "6.0.0",
-    "@codemirror/state": "~6.3.0",
-    "@codemirror/view": "~6.22.3",
+    "@codemirror/merge": "^6.8.0",
+    "@codemirror/state": "^6.5.2",
+    "@codemirror/view": "^6.36.2",
     "@emoji-mart/data": "^1.2.1",
     "@emoji-mart/react": "^1.1.1",
     "@growi/core": "workspace:^",
@@ -48,10 +46,10 @@
     "@replit/codemirror-vscode-keymap": "^6.0.2",
     "@types/react": "^18.2.14",
     "@types/react-dom": "^18.2.6",
-    "@uiw/codemirror-theme-eclipse": "^4.23.5",
-    "@uiw/codemirror-theme-kimbie": "^4.23.5",
-    "@uiw/codemirror-themes": "^4.23.5",
-    "@uiw/react-codemirror": "^4.23.5",
+    "@uiw/codemirror-theme-eclipse": "^4.23.8",
+    "@uiw/codemirror-theme-kimbie": "^4.23.8",
+    "@uiw/codemirror-themes": "^4.23.8",
+    "@uiw/react-codemirror": "^4.23.8",
     "bootstrap": "=5.3.2",
     "cm6-theme-basic-light": "^0.2.0",
     "cm6-theme-material-dark": "^0.2.0",

+ 7 - 0
packages/editor/src/client/components-internal/CodeMirrorEditor/CodeMirrorEditor.tsx

@@ -23,6 +23,13 @@ import { Toolbar } from './Toolbar';
 
 import style from './CodeMirrorEditor.module.scss';
 
+
+// Fix IME cursor position issue by EditContext
+// ref: https://github.com/weseek/growi/pull/9267
+// ref: https://discuss.codemirror.net/t/issue-with-google-japanese-ime-cursor-position-in-v6/8810/3
+(EditorView as unknown as { EDIT_CONTEXT: boolean }).EDIT_CONTEXT = false;
+
+
 const CodeMirrorEditorContainer = forwardRef<HTMLDivElement, DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>>(
   (props, ref) => {
     const { className = '', ...rest } = props;

+ 3 - 2
packages/remark-attachment-refs/src/server/routes/refs.ts

@@ -86,6 +86,7 @@ export const routesFactory = (crowi): any => {
   router.get('/ref', accessTokenParser, loginRequired, async(req: RequestWithUser, res) => {
     const user = req.user;
     const { pagePath, fileNameOrId } = req.query;
+    const filterXSS = new FilterXSS();
 
     if (pagePath == null) {
       res.status(400).send('the param \'pagePath\' must be set.');
@@ -96,7 +97,7 @@ export const routesFactory = (crowi): any => {
 
     // not found
     if (page == null) {
-      res.status(404).send(`pagePath: '${pagePath}' is not found or forbidden.`);
+      res.status(404).send(filterXSS.process(`pagePath: '${pagePath}' is not found or forbidden.`));
       return;
     }
 
@@ -117,7 +118,7 @@ export const routesFactory = (crowi): any => {
 
     // not found
     if (attachment == null) {
-      res.status(404).send(`attachment '${fileNameOrId}' is not found.`);
+      res.status(404).send(filterXSS.process(`attachment '${fileNameOrId}' is not found.`));
       return;
     }
 

+ 248 - 255
pnpm-lock.yaml

@@ -59,7 +59,7 @@ importers:
         version: 4.3.1(vite@5.4.14(@types/node@20.14.0)(sass@1.77.6)(terser@5.37.0))
       '@vitest/coverage-v8':
         specifier: ^2.1.1
-        version: 2.1.1(vitest@2.1.1(@types/node@20.14.0)(@vitest/ui@2.1.1)(happy-dom@15.7.4)(sass@1.77.6)(terser@5.37.0))
+        version: 2.1.1(vitest@2.1.1)
       '@vitest/ui':
         specifier: ^2.1.1
         version: 2.1.1(vitest@2.1.1)
@@ -77,7 +77,7 @@ importers:
         version: 12.1.6(eslint@8.41.0)(next@14.2.22(@babel/core@7.24.6)(@opentelemetry/api@1.9.0)(@playwright/test@1.49.1)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(sass@1.77.6))(typescript@5.0.4)
       eslint-config-weseek:
         specifier: ^2.1.1
-        version: 2.1.1(@babel/core@7.24.6)(@babel/eslint-parser@7.24.7(@babel/core@7.24.6)(eslint@8.41.0))(@typescript-eslint/eslint-plugin@5.59.7(@typescript-eslint/parser@5.59.7(eslint@8.41.0)(typescript@5.0.4))(eslint@8.41.0)(typescript@5.0.4))(@typescript-eslint/parser@5.59.7(eslint@8.41.0)(typescript@5.0.4))(eslint-import-resolver-typescript@3.2.5(eslint-plugin-import@2.26.0)(eslint@8.41.0))(eslint-plugin-import@2.26.0(@typescript-eslint/parser@5.59.7(eslint@8.41.0)(typescript@5.0.4))(eslint-import-resolver-typescript@3.2.5)(eslint@8.41.0))(eslint-plugin-jsx-a11y@6.5.1(eslint@8.41.0))(eslint-plugin-react-hooks@4.6.0(eslint@8.41.0))(eslint-plugin-react@7.30.1(eslint@8.41.0))(eslint-plugin-vue@7.20.0(eslint@8.41.0))(eslint@8.41.0)
+        version: 2.1.1(@babel/core@7.24.6)(@babel/eslint-parser@7.24.7(@babel/core@7.24.6)(eslint@8.41.0))(@typescript-eslint/eslint-plugin@5.59.7(@typescript-eslint/parser@5.59.7(eslint@8.41.0)(typescript@5.0.4))(eslint@8.41.0)(typescript@5.0.4))(@typescript-eslint/parser@5.59.7(eslint@8.41.0)(typescript@5.0.4))(eslint-import-resolver-typescript@3.2.5)(eslint-plugin-import@2.26.0)(eslint-plugin-jsx-a11y@6.5.1(eslint@8.41.0))(eslint-plugin-react-hooks@4.6.0(eslint@8.41.0))(eslint-plugin-react@7.30.1(eslint@8.41.0))(eslint-plugin-vue@7.20.0(eslint@8.41.0))(eslint@8.41.0)
       eslint-import-resolver-typescript:
         specifier: ^3.2.5
         version: 3.2.5(eslint-plugin-import@2.26.0)(eslint@8.41.0)
@@ -185,7 +185,7 @@ importers:
         version: 2.1.1(@types/node@20.14.0)(@vitest/ui@2.1.1)(happy-dom@15.7.4)(sass@1.77.6)(terser@5.37.0)
       vitest-mock-extended:
         specifier: ^2.0.2
-        version: 2.0.2(typescript@5.0.4)(vitest@2.1.1(@types/node@20.14.0)(@vitest/ui@2.1.1)(happy-dom@15.7.4)(sass@1.77.6)(terser@5.37.0))
+        version: 2.0.2(typescript@5.0.4)(vitest@2.1.1)
       vue-tsc:
         specifier: ^2.1.10
         version: 2.1.10(typescript@5.0.4)
@@ -867,7 +867,7 @@ importers:
         version: 3.1.0
       eslint-plugin-jest:
         specifier: ^26.5.3
-        version: 26.9.0(@typescript-eslint/eslint-plugin@5.59.7(@typescript-eslint/parser@5.59.7(eslint@8.41.0)(typescript@5.0.4))(eslint@8.41.0)(typescript@5.4.2))(eslint@8.41.0)(jest@29.7.0(@types/node@20.14.0)(ts-node@10.9.2(@swc/core@1.5.25(@swc/helpers@0.5.11))(@types/node@20.14.0)(typescript@5.4.2)))(typescript@5.4.2)
+        version: 26.9.0(@typescript-eslint/eslint-plugin@5.59.7(@typescript-eslint/parser@5.59.7(eslint@8.41.0)(typescript@5.4.2))(eslint@8.41.0)(typescript@5.4.2))(eslint@8.41.0)(jest@29.7.0(@types/node@20.14.0)(ts-node@10.9.2(@swc/core@1.5.25(@swc/helpers@0.5.11))(@types/node@20.14.0)(typescript@5.4.2)))(typescript@5.4.2)
       fslightbox-react:
         specifier: ^1.7.6
         version: 1.7.6(prop-types@15.8.1)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
@@ -1134,29 +1134,29 @@ importers:
         version: 18.2.0(react@18.2.0)
     devDependencies:
       '@codemirror/autocomplete':
-        specifier: ^6.18.1
-        version: 6.18.1(@codemirror/language@6.9.3)(@codemirror/state@6.3.3)(@codemirror/view@6.22.3)(@lezer/common@1.2.2)
+        specifier: ^6.18.4
+        version: 6.18.4
       '@codemirror/commands':
-        specifier: ~6.2.5
-        version: 6.2.5
+        specifier: ^6.8.0
+        version: 6.8.0
       '@codemirror/lang-markdown':
-        specifier: ~6.2.5
-        version: 6.2.5
+        specifier: ^6.3.2
+        version: 6.3.2
       '@codemirror/language':
-        specifier: ~6.9.3
-        version: 6.9.3
+        specifier: ^6.10.8
+        version: 6.10.8
       '@codemirror/language-data':
         specifier: ^6.5.1
-        version: 6.5.1(@codemirror/state@6.3.3)(@codemirror/view@6.22.3)(@lezer/common@1.2.2)
+        version: 6.5.1
       '@codemirror/merge':
-        specifier: 6.0.0
-        version: 6.0.0
+        specifier: ^6.8.0
+        version: 6.8.0
       '@codemirror/state':
-        specifier: ~6.3.0
-        version: 6.3.3
+        specifier: ^6.5.2
+        version: 6.5.2
       '@codemirror/view':
-        specifier: ~6.22.3
-        version: 6.22.3
+        specifier: ^6.36.2
+        version: 6.36.2
       '@emoji-mart/data':
         specifier: ^1.2.1
         version: 1.2.1
@@ -1177,13 +1177,13 @@ importers:
         version: 2.11.8
       '@replit/codemirror-emacs':
         specifier: ^6.1.0
-        version: 6.1.0(@codemirror/autocomplete@6.18.1(@codemirror/language@6.9.3)(@codemirror/state@6.3.3)(@codemirror/view@6.22.3)(@lezer/common@1.2.2))(@codemirror/commands@6.2.5)(@codemirror/search@6.5.6)(@codemirror/state@6.3.3)(@codemirror/view@6.22.3)
+        version: 6.1.0(@codemirror/autocomplete@6.18.4)(@codemirror/commands@6.8.0)(@codemirror/search@6.5.6)(@codemirror/state@6.5.2)(@codemirror/view@6.36.2)
       '@replit/codemirror-vim':
         specifier: ^6.2.1
-        version: 6.2.1(@codemirror/commands@6.2.5)(@codemirror/language@6.9.3)(@codemirror/search@6.5.6)(@codemirror/state@6.3.3)(@codemirror/view@6.22.3)
+        version: 6.2.1(@codemirror/commands@6.8.0)(@codemirror/language@6.10.8)(@codemirror/search@6.5.6)(@codemirror/state@6.5.2)(@codemirror/view@6.36.2)
       '@replit/codemirror-vscode-keymap':
         specifier: ^6.0.2
-        version: 6.0.2(@codemirror/autocomplete@6.18.1(@codemirror/language@6.9.3)(@codemirror/state@6.3.3)(@codemirror/view@6.22.3)(@lezer/common@1.2.2))(@codemirror/commands@6.2.5)(@codemirror/language@6.9.3)(@codemirror/lint@6.8.1)(@codemirror/search@6.5.6)(@codemirror/state@6.3.3)(@codemirror/view@6.22.3)
+        version: 6.0.2(@codemirror/autocomplete@6.18.4)(@codemirror/commands@6.8.0)(@codemirror/language@6.10.8)(@codemirror/lint@6.8.1)(@codemirror/search@6.5.6)(@codemirror/state@6.5.2)(@codemirror/view@6.36.2)
       '@types/react':
         specifier: ^18.2.14
         version: 18.3.3
@@ -1191,32 +1191,32 @@ importers:
         specifier: ^18.2.6
         version: 18.3.0
       '@uiw/codemirror-theme-eclipse':
-        specifier: ^4.23.5
-        version: 4.23.5(@codemirror/language@6.9.3)(@codemirror/state@6.3.3)(@codemirror/view@6.22.3)
+        specifier: ^4.23.8
+        version: 4.23.8(@codemirror/language@6.10.8)(@codemirror/state@6.5.2)(@codemirror/view@6.36.2)
       '@uiw/codemirror-theme-kimbie':
-        specifier: ^4.23.5
-        version: 4.23.5(@codemirror/language@6.9.3)(@codemirror/state@6.3.3)(@codemirror/view@6.22.3)
+        specifier: ^4.23.8
+        version: 4.23.8(@codemirror/language@6.10.8)(@codemirror/state@6.5.2)(@codemirror/view@6.36.2)
       '@uiw/codemirror-themes':
-        specifier: ^4.23.5
-        version: 4.23.5(@codemirror/language@6.9.3)(@codemirror/state@6.3.3)(@codemirror/view@6.22.3)
+        specifier: ^4.23.8
+        version: 4.23.8(@codemirror/language@6.10.8)(@codemirror/state@6.5.2)(@codemirror/view@6.36.2)
       '@uiw/react-codemirror':
-        specifier: ^4.23.5
-        version: 4.23.5(@babel/runtime@7.25.4)(@codemirror/autocomplete@6.18.1(@codemirror/language@6.9.3)(@codemirror/state@6.3.3)(@codemirror/view@6.22.3)(@lezer/common@1.2.2))(@codemirror/language@6.9.3)(@codemirror/lint@6.8.1)(@codemirror/search@6.5.6)(@codemirror/state@6.3.3)(@codemirror/theme-one-dark@6.1.2)(@codemirror/view@6.22.3)(codemirror@6.0.1(@lezer/common@1.2.2))(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
+        specifier: ^4.23.8
+        version: 4.23.8(@babel/runtime@7.25.4)(@codemirror/autocomplete@6.18.4)(@codemirror/language@6.10.8)(@codemirror/lint@6.8.1)(@codemirror/search@6.5.6)(@codemirror/state@6.5.2)(@codemirror/theme-one-dark@6.1.2)(@codemirror/view@6.36.2)(codemirror@6.0.1)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
       bootstrap:
         specifier: '=5.3.2'
         version: 5.3.2(@popperjs/core@2.11.8)
       cm6-theme-basic-light:
         specifier: ^0.2.0
-        version: 0.2.0(@codemirror/language@6.9.3)(@codemirror/state@6.3.3)(@codemirror/view@6.22.3)(@lezer/highlight@1.2.1)
+        version: 0.2.0(@codemirror/language@6.10.8)(@codemirror/state@6.5.2)(@codemirror/view@6.36.2)(@lezer/highlight@1.2.1)
       cm6-theme-material-dark:
         specifier: ^0.2.0
-        version: 0.2.0(@codemirror/language@6.9.3)(@codemirror/state@6.3.3)(@codemirror/view@6.22.3)(@lezer/highlight@1.2.1)
+        version: 0.2.0(@codemirror/language@6.10.8)(@codemirror/state@6.5.2)(@codemirror/view@6.36.2)(@lezer/highlight@1.2.1)
       cm6-theme-nord:
         specifier: ^0.2.0
-        version: 0.2.0(@codemirror/language@6.9.3)(@codemirror/state@6.3.3)(@codemirror/view@6.22.3)(@lezer/highlight@1.2.1)
+        version: 0.2.0(@codemirror/language@6.10.8)(@codemirror/state@6.5.2)(@codemirror/view@6.36.2)(@lezer/highlight@1.2.1)
       codemirror:
         specifier: ^6.0.1
-        version: 6.0.1(@lezer/common@1.2.2)
+        version: 6.0.1
       csv-to-markdown-table:
         specifier: ^1.4.1
         version: 1.4.1
@@ -1255,7 +1255,7 @@ importers:
         version: 6.2.0
       y-codemirror.next:
         specifier: ^0.3.5
-        version: 0.3.5(@codemirror/state@6.3.3)(@codemirror/view@6.22.3)(yjs@13.6.19)
+        version: 0.3.5(@codemirror/state@6.5.2)(@codemirror/view@6.36.2)(yjs@13.6.19)
       y-socket.io:
         specifier: ^1.1.3
         version: 1.1.3(yjs@13.6.19)
@@ -2381,16 +2381,11 @@ packages:
   '@chevrotain/utils@11.0.3':
     resolution: {integrity: sha512-YslZMgtJUyuMbZ+aKvfF3x1f5liK4mWNxghFRv7jqRR9C3R3fAOGTTKvxXDa2Y1s9zSbcpuO0cAxDYsc9SrXoQ==}
 
-  '@codemirror/autocomplete@6.18.1':
-    resolution: {integrity: sha512-iWHdj/B1ethnHRTwZj+C1obmmuCzquH29EbcKr0qIjA9NfDeBDJ7vs+WOHsFeLeflE4o+dHfYndJloMKHUkWUA==}
-    peerDependencies:
-      '@codemirror/language': ^6.0.0
-      '@codemirror/state': ^6.0.0
-      '@codemirror/view': ^6.0.0
-      '@lezer/common': ^1.0.0
+  '@codemirror/autocomplete@6.18.4':
+    resolution: {integrity: sha512-sFAphGQIqyQZfP2ZBsSHV7xQvo9Py0rV0dW7W3IMRdS+zDuNb2l3no78CvUaWKGfzFjI4FTrLdUSj86IGb2hRA==}
 
-  '@codemirror/commands@6.2.5':
-    resolution: {integrity: sha512-dSi7ow2P2YgPBZflR9AJoaTHvqmeGIgkhignYMd5zK5y6DANTvxKxp6eMEpIDUJkRAaOY/TFZ4jP1ADIO/GLVA==}
+  '@codemirror/commands@6.8.0':
+    resolution: {integrity: sha512-q8VPEFaEP4ikSlt6ZxjB3zW72+7osfAYW9i8Zu943uqbKuz6utc1+F170hyLUCUltXORjQXRyYQNfkckzA/bPQ==}
 
   '@codemirror/lang-angular@0.1.2':
     resolution: {integrity: sha512-Nq7lmx9SU+JyoaRcs6SaJs7uAmW2W06HpgJVQYeZptVGNWDzDvzhjwVb/ZuG1rwTlOocY4Y9GwNOBuKCeJbKtw==}
@@ -2422,8 +2417,8 @@ packages:
   '@codemirror/lang-liquid@6.2.1':
     resolution: {integrity: sha512-J1Mratcm6JLNEiX+U2OlCDTysGuwbHD76XwuL5o5bo9soJtSbz2g6RU3vGHFyS5DC8rgVmFSzi7i6oBftm7tnA==}
 
-  '@codemirror/lang-markdown@6.2.5':
-    resolution: {integrity: sha512-Hgke565YcO4fd9pe2uLYxnMufHO5rQwRr+AAhFq8ABuhkrjyX8R5p5s+hZUTdV60O0dMRjxKhBLxz8pu/MkUVA==}
+  '@codemirror/lang-markdown@6.3.2':
+    resolution: {integrity: sha512-c/5MYinGbFxYl4itE9q/rgN/sMTjOr8XL5OWnC+EaRMLfCbVUmmubTJfdgpfcSS2SCaT7b+Q+xi3l6CgoE+BsA==}
 
   '@codemirror/lang-php@6.0.1':
     resolution: {integrity: sha512-ublojMdw/PNWa7qdN5TMsjmqkNuTBD3k6ndZ4Z0S25SBAiweFGyY68AS3xNcIOlb6DDFDvKlinLQ40vSLqf8xA==}
@@ -2455,8 +2450,8 @@ packages:
   '@codemirror/language-data@6.5.1':
     resolution: {integrity: sha512-0sWxeUSNlBr6OmkqybUTImADFUP0M3P0IiSde4nc24bz/6jIYzqYSgkOSLS+CBIoW1vU8Q9KUWXscBXeoMVC9w==}
 
-  '@codemirror/language@6.9.3':
-    resolution: {integrity: sha512-qq48pYzoi6ldYWV/52+Z9Ou6QouVI+8YwvxFbUypI33NbjG2UeRHKENRyhwljTTiOqjQ33FjyZj6EREQ9apAOQ==}
+  '@codemirror/language@6.10.8':
+    resolution: {integrity: sha512-wcP8XPPhDH2vTqf181U8MbZnW+tDyPYy0UzVOa+oHORjyT+mhhom9vBd7dApJwoDz9Nb/a8kHjJIsuA/t8vNFw==}
 
   '@codemirror/legacy-modes@6.4.1':
     resolution: {integrity: sha512-vdg3XY7OAs5uLDx2Iw+cGfnwtd7kM+Et/eMsqAGTfT/JKiVBQZXosTzjEbWAi/FrY6DcQIz8mQjBozFHZEUWQA==}
@@ -2464,20 +2459,20 @@ packages:
   '@codemirror/lint@6.8.1':
     resolution: {integrity: sha512-IZ0Y7S4/bpaunwggW2jYqwLuHj0QtESf5xcROewY6+lDNwZ/NzvR4t+vpYgg9m7V8UXLPYqG+lu3DF470E5Oxg==}
 
-  '@codemirror/merge@6.0.0':
-    resolution: {integrity: sha512-dxdUIQRxgC+xqzBtfY5zjgDIR38Xp6iycb8Lp1Q2gzEkX9y/UrqOAOlpqU3kfDBa0wGHrjlSYzpcQ/lXWG/59w==}
+  '@codemirror/merge@6.8.0':
+    resolution: {integrity: sha512-EcCD4OJlGz6lJaqZOFM/RE6fqM4XSQlWNWVxm2CJS1snbrbkgYLTvj8c++pFUWpJOUiNgcxvYMYkMisnC0aR6g==}
 
   '@codemirror/search@6.5.6':
     resolution: {integrity: sha512-rpMgcsh7o0GuCDUXKPvww+muLA1pDJaFrpq/CCHtpQJYz8xopu4D1hPcKRoDD0YlF8gZaqTNIRa4VRBWyhyy7Q==}
 
-  '@codemirror/state@6.3.3':
-    resolution: {integrity: sha512-0wufKcTw2dEwEaADajjHf6hBy1sh3M6V0e+q4JKIhLuiMSe5td5HOWpUdvKth1fT1M9VYOboajoBHpkCd7PG7A==}
+  '@codemirror/state@6.5.2':
+    resolution: {integrity: sha512-FVqsPqtPWKVVL3dPSxy8wEF/ymIEuVzF1PK3VbUgrxXpJUSHQWWZz4JMToquRxnkw+36LTamCZG2iua2Ptq0fA==}
 
   '@codemirror/theme-one-dark@6.1.2':
     resolution: {integrity: sha512-F+sH0X16j/qFLMAfbciKTxVOwkdAS336b7AXTKOZhy8BR3eH/RelsnLgLFINrpST63mmN2OuwUt0W2ndUgYwUA==}
 
-  '@codemirror/view@6.22.3':
-    resolution: {integrity: sha512-rqnq+Zospwoi3x1vZ8BGV1MlRsaGljX+6qiGYmIpJ++M+LCC+wjfDaPklhwpWSgv7pr/qx29KiAKQBH5+DOn4w==}
+  '@codemirror/view@6.36.2':
+    resolution: {integrity: sha512-DZ6ONbs8qdJK0fdN7AB82CgI6tYXf4HWk1wSVa0+9bhVznCuuvhQtX8bFBoy3dv8rZSQqUd8GvhVAcielcidrA==}
 
   '@colors/colors@1.5.0':
     resolution: {integrity: sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==}
@@ -3004,6 +2999,9 @@ packages:
   '@manypkg/get-packages@1.1.3':
     resolution: {integrity: sha512-fo+QhuU3qE/2TQMQmbVMqaQ6EWbMhi4ABWP+O4AM1NqPBuy0OrApV5LO6BrrgnhtAHS2NH6RrVk9OL181tTi8A==}
 
+  '@marijn/find-cluster-break@1.0.2':
+    resolution: {integrity: sha512-l0h88YhZFyKdXIFNfSWpyjStDjGHwZ/U7iobcK1cQQD8sejsONdQtTVU+1wVN1PBw40PiiHB1vA5S7VTfQiP9g==}
+
   '@marp-team/marp-core@3.9.1':
     resolution: {integrity: sha512-/GOecdgt0HmvFnC/C2flxPfUVgLMNE8lP8UAvjlFfWyeB9hyNBP5k1N2Wnx0mXPU8UHpDzYdySDxIR+ki2p8Fw==}
     engines: {node: ^12.20 || ^14.13.1 || >=16}
@@ -4818,8 +4816,8 @@ packages:
     resolution: {integrity: sha512-tyN+X2jvMslUszIiYbF0ZleP+RqQsFVpGrKI6e0Eet1w8WmhsAtmzaqm8oM8WJQ1ysLwhnsK/4hYHJjOgJVfQQ==}
     engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
 
-  '@uiw/codemirror-extensions-basic-setup@4.23.5':
-    resolution: {integrity: sha512-eTMfT8TejVN/D5vvuz9Lab+MIoRYdtqa2ftZZmU3JpcDIXf9KaExPo+G2Rl9HqySzaasgGXOOG164MAnj3MSIw==}
+  '@uiw/codemirror-extensions-basic-setup@4.23.8':
+    resolution: {integrity: sha512-XJR/8AEVcE7ufy1BhW2nCN9qSVDYEdCtYLfvhaMwl6Q3qcaYYCGE2K5QbFCy7LsdP/3uZKvc1OskuqatoOPdhQ==}
     peerDependencies:
       '@codemirror/autocomplete': '>=6.0.0'
       '@codemirror/commands': '>=6.0.0'
@@ -4829,21 +4827,21 @@ packages:
       '@codemirror/state': '>=6.0.0'
       '@codemirror/view': '>=6.0.0'
 
-  '@uiw/codemirror-theme-eclipse@4.23.5':
-    resolution: {integrity: sha512-WsfcdDjQQCpd42KUJcp/2r5UjTvXetR5V6Zp12ZJliL1gpjtHdZ6ZJxSwQhga6pfEBn2ITz5u5lZgBv/zXgtqg==}
+  '@uiw/codemirror-theme-eclipse@4.23.8':
+    resolution: {integrity: sha512-tSjqC7x/cjrXLgePw43J/7RDdJT6argHnMNN2EzhTkRaXiVO+V0sf5aPuptr0SbKgqNGfcF3SY12au+bH6eoWQ==}
 
-  '@uiw/codemirror-theme-kimbie@4.23.5':
-    resolution: {integrity: sha512-vC3kr0Lr5AhN2J4KhMYHObRovl3aTBrDMC44JSLzgwU+EBceNPEMrFKfY0pnDgyCXof95R8k4+cfH0WjfQFvtA==}
+  '@uiw/codemirror-theme-kimbie@4.23.8':
+    resolution: {integrity: sha512-Z0FTYrcsFylo709qUcuDbB6zB+ERreKi2BfxuxDX4aBiVSjMmjTB1ecPUfllWvrM+qUvAFaTdH+F9e9h3fzNyg==}
 
-  '@uiw/codemirror-themes@4.23.5':
-    resolution: {integrity: sha512-yWUTpaVroxIxjKASQAmKaYy+ZYtF+YB6d8sVmSRK2TVD13M+EWvVT2jBGFLqR1UVg7G0W/McAy8xdeTg+a3slg==}
+  '@uiw/codemirror-themes@4.23.8':
+    resolution: {integrity: sha512-PZmJBZxWMuZ48p/2D5aRPl8zTlBq1d/+NeRqyyH6P6k6yWDF6h71m0Dt+fjslgPE7KmWXux2hbejXXXoRLZO9Q==}
     peerDependencies:
       '@codemirror/language': '>=6.0.0'
       '@codemirror/state': '>=6.0.0'
       '@codemirror/view': '>=6.0.0'
 
-  '@uiw/react-codemirror@4.23.5':
-    resolution: {integrity: sha512-2zzGpx61L4mq9zDG/hfsO4wAH209TBE8VVsoj/qrccRe6KfcneCwKgRxtQjxBCCnO0Q5S+IP+uwCx5bXRzgQFQ==}
+  '@uiw/react-codemirror@4.23.8':
+    resolution: {integrity: sha512-/NA5Pj4MmXkLSlmlUm4yfEmRLntrNq5TkQKBSINn7TukXQ4fc+C6Bk0U60Qa4rkvCSgwzZdQ2exyP0t0+2GtqA==}
     peerDependencies:
       '@babel/runtime': '>=7.11.0'
       '@codemirror/state': '>=6.0.0'
@@ -14458,229 +14456,206 @@ snapshots:
 
   '@chevrotain/utils@11.0.3': {}
 
-  '@codemirror/autocomplete@6.18.1(@codemirror/language@6.9.3)(@codemirror/state@6.3.3)(@codemirror/view@6.22.3)(@lezer/common@1.2.2)':
+  '@codemirror/autocomplete@6.18.4':
     dependencies:
-      '@codemirror/language': 6.9.3
-      '@codemirror/state': 6.3.3
-      '@codemirror/view': 6.22.3
+      '@codemirror/language': 6.10.8
+      '@codemirror/state': 6.5.2
+      '@codemirror/view': 6.36.2
       '@lezer/common': 1.2.2
 
-  '@codemirror/commands@6.2.5':
+  '@codemirror/commands@6.8.0':
     dependencies:
-      '@codemirror/language': 6.9.3
-      '@codemirror/state': 6.3.3
-      '@codemirror/view': 6.22.3
+      '@codemirror/language': 6.10.8
+      '@codemirror/state': 6.5.2
+      '@codemirror/view': 6.36.2
       '@lezer/common': 1.2.2
 
   '@codemirror/lang-angular@0.1.2':
     dependencies:
       '@codemirror/lang-html': 6.4.5
       '@codemirror/lang-javascript': 6.1.9
-      '@codemirror/language': 6.9.3
+      '@codemirror/language': 6.10.8
       '@lezer/common': 1.2.2
       '@lezer/highlight': 1.2.1
       '@lezer/lr': 1.4.2
 
   '@codemirror/lang-cpp@6.0.2':
     dependencies:
-      '@codemirror/language': 6.9.3
+      '@codemirror/language': 6.10.8
       '@lezer/cpp': 1.1.1
 
-  '@codemirror/lang-css@6.2.0(@codemirror/view@6.22.3)':
+  '@codemirror/lang-css@6.2.0':
     dependencies:
-      '@codemirror/autocomplete': 6.18.1(@codemirror/language@6.9.3)(@codemirror/state@6.3.3)(@codemirror/view@6.22.3)(@lezer/common@1.2.2)
-      '@codemirror/language': 6.9.3
-      '@codemirror/state': 6.3.3
+      '@codemirror/autocomplete': 6.18.4
+      '@codemirror/language': 6.10.8
+      '@codemirror/state': 6.5.2
       '@lezer/common': 1.2.2
       '@lezer/css': 1.1.3
-    transitivePeerDependencies:
-      - '@codemirror/view'
 
-  '@codemirror/lang-go@6.0.1(@codemirror/view@6.22.3)':
+  '@codemirror/lang-go@6.0.1':
     dependencies:
-      '@codemirror/autocomplete': 6.18.1(@codemirror/language@6.9.3)(@codemirror/state@6.3.3)(@codemirror/view@6.22.3)(@lezer/common@1.2.2)
-      '@codemirror/language': 6.9.3
-      '@codemirror/state': 6.3.3
+      '@codemirror/autocomplete': 6.18.4
+      '@codemirror/language': 6.10.8
+      '@codemirror/state': 6.5.2
       '@lezer/common': 1.2.2
       '@lezer/go': 1.0.0
-    transitivePeerDependencies:
-      - '@codemirror/view'
 
   '@codemirror/lang-html@6.4.5':
     dependencies:
-      '@codemirror/autocomplete': 6.18.1(@codemirror/language@6.9.3)(@codemirror/state@6.3.3)(@codemirror/view@6.22.3)(@lezer/common@1.2.2)
-      '@codemirror/lang-css': 6.2.0(@codemirror/view@6.22.3)
+      '@codemirror/autocomplete': 6.18.4
+      '@codemirror/lang-css': 6.2.0
       '@codemirror/lang-javascript': 6.1.9
-      '@codemirror/language': 6.9.3
-      '@codemirror/state': 6.3.3
-      '@codemirror/view': 6.22.3
+      '@codemirror/language': 6.10.8
+      '@codemirror/state': 6.5.2
+      '@codemirror/view': 6.36.2
       '@lezer/common': 1.2.2
       '@lezer/css': 1.1.3
       '@lezer/html': 1.3.6
 
   '@codemirror/lang-java@6.0.1':
     dependencies:
-      '@codemirror/language': 6.9.3
+      '@codemirror/language': 6.10.8
       '@lezer/java': 1.0.4
 
   '@codemirror/lang-javascript@6.1.9':
     dependencies:
-      '@codemirror/autocomplete': 6.18.1(@codemirror/language@6.9.3)(@codemirror/state@6.3.3)(@codemirror/view@6.22.3)(@lezer/common@1.2.2)
-      '@codemirror/language': 6.9.3
+      '@codemirror/autocomplete': 6.18.4
+      '@codemirror/language': 6.10.8
       '@codemirror/lint': 6.8.1
-      '@codemirror/state': 6.3.3
-      '@codemirror/view': 6.22.3
+      '@codemirror/state': 6.5.2
+      '@codemirror/view': 6.36.2
       '@lezer/common': 1.2.2
       '@lezer/javascript': 1.4.5
 
   '@codemirror/lang-json@6.0.1':
     dependencies:
-      '@codemirror/language': 6.9.3
+      '@codemirror/language': 6.10.8
       '@lezer/json': 1.0.1
 
-  '@codemirror/lang-less@6.0.1(@codemirror/view@6.22.3)':
+  '@codemirror/lang-less@6.0.1':
     dependencies:
-      '@codemirror/lang-css': 6.2.0(@codemirror/view@6.22.3)
-      '@codemirror/language': 6.9.3
+      '@codemirror/lang-css': 6.2.0
+      '@codemirror/language': 6.10.8
       '@lezer/highlight': 1.2.1
       '@lezer/lr': 1.4.2
-    transitivePeerDependencies:
-      - '@codemirror/view'
 
   '@codemirror/lang-liquid@6.2.1':
     dependencies:
-      '@codemirror/autocomplete': 6.18.1(@codemirror/language@6.9.3)(@codemirror/state@6.3.3)(@codemirror/view@6.22.3)(@lezer/common@1.2.2)
+      '@codemirror/autocomplete': 6.18.4
       '@codemirror/lang-html': 6.4.5
-      '@codemirror/language': 6.9.3
-      '@codemirror/state': 6.3.3
-      '@codemirror/view': 6.22.3
+      '@codemirror/language': 6.10.8
+      '@codemirror/state': 6.5.2
+      '@codemirror/view': 6.36.2
       '@lezer/common': 1.2.2
       '@lezer/highlight': 1.2.1
       '@lezer/lr': 1.4.2
 
-  '@codemirror/lang-markdown@6.2.5':
+  '@codemirror/lang-markdown@6.3.2':
     dependencies:
-      '@codemirror/autocomplete': 6.18.1(@codemirror/language@6.9.3)(@codemirror/state@6.3.3)(@codemirror/view@6.22.3)(@lezer/common@1.2.2)
+      '@codemirror/autocomplete': 6.18.4
       '@codemirror/lang-html': 6.4.5
-      '@codemirror/language': 6.9.3
-      '@codemirror/state': 6.3.3
-      '@codemirror/view': 6.22.3
+      '@codemirror/language': 6.10.8
+      '@codemirror/state': 6.5.2
+      '@codemirror/view': 6.36.2
       '@lezer/common': 1.2.2
       '@lezer/markdown': 1.0.5
 
   '@codemirror/lang-php@6.0.1':
     dependencies:
       '@codemirror/lang-html': 6.4.5
-      '@codemirror/language': 6.9.3
-      '@codemirror/state': 6.3.3
+      '@codemirror/language': 6.10.8
+      '@codemirror/state': 6.5.2
       '@lezer/common': 1.2.2
       '@lezer/php': 1.0.1
 
-  '@codemirror/lang-python@6.1.3(@codemirror/state@6.3.3)(@codemirror/view@6.22.3)(@lezer/common@1.2.2)':
+  '@codemirror/lang-python@6.1.3':
     dependencies:
-      '@codemirror/autocomplete': 6.18.1(@codemirror/language@6.9.3)(@codemirror/state@6.3.3)(@codemirror/view@6.22.3)(@lezer/common@1.2.2)
-      '@codemirror/language': 6.9.3
+      '@codemirror/autocomplete': 6.18.4
+      '@codemirror/language': 6.10.8
       '@lezer/python': 1.1.8
-    transitivePeerDependencies:
-      - '@codemirror/state'
-      - '@codemirror/view'
-      - '@lezer/common'
 
   '@codemirror/lang-rust@6.0.1':
     dependencies:
-      '@codemirror/language': 6.9.3
+      '@codemirror/language': 6.10.8
       '@lezer/rust': 1.0.1
 
-  '@codemirror/lang-sass@6.0.2(@codemirror/view@6.22.3)':
+  '@codemirror/lang-sass@6.0.2':
     dependencies:
-      '@codemirror/lang-css': 6.2.0(@codemirror/view@6.22.3)
-      '@codemirror/language': 6.9.3
-      '@codemirror/state': 6.3.3
+      '@codemirror/lang-css': 6.2.0
+      '@codemirror/language': 6.10.8
+      '@codemirror/state': 6.5.2
       '@lezer/common': 1.2.2
       '@lezer/sass': 1.0.3
-    transitivePeerDependencies:
-      - '@codemirror/view'
 
-  '@codemirror/lang-sql@6.5.2(@codemirror/view@6.22.3)(@lezer/common@1.2.2)':
+  '@codemirror/lang-sql@6.5.2':
     dependencies:
-      '@codemirror/autocomplete': 6.18.1(@codemirror/language@6.9.3)(@codemirror/state@6.3.3)(@codemirror/view@6.22.3)(@lezer/common@1.2.2)
-      '@codemirror/language': 6.9.3
-      '@codemirror/state': 6.3.3
+      '@codemirror/autocomplete': 6.18.4
+      '@codemirror/language': 6.10.8
+      '@codemirror/state': 6.5.2
       '@lezer/highlight': 1.2.1
       '@lezer/lr': 1.4.2
-    transitivePeerDependencies:
-      - '@codemirror/view'
-      - '@lezer/common'
 
   '@codemirror/lang-vue@0.1.2':
     dependencies:
       '@codemirror/lang-html': 6.4.5
       '@codemirror/lang-javascript': 6.1.9
-      '@codemirror/language': 6.9.3
+      '@codemirror/language': 6.10.8
       '@lezer/common': 1.2.2
       '@lezer/highlight': 1.2.1
       '@lezer/lr': 1.4.2
 
   '@codemirror/lang-wast@6.0.1':
     dependencies:
-      '@codemirror/language': 6.9.3
+      '@codemirror/language': 6.10.8
       '@lezer/highlight': 1.2.1
       '@lezer/lr': 1.4.2
 
-  '@codemirror/lang-xml@6.0.2(@codemirror/view@6.22.3)':
+  '@codemirror/lang-xml@6.0.2':
     dependencies:
-      '@codemirror/autocomplete': 6.18.1(@codemirror/language@6.9.3)(@codemirror/state@6.3.3)(@codemirror/view@6.22.3)(@lezer/common@1.2.2)
-      '@codemirror/language': 6.9.3
-      '@codemirror/state': 6.3.3
+      '@codemirror/autocomplete': 6.18.4
+      '@codemirror/language': 6.10.8
+      '@codemirror/state': 6.5.2
       '@lezer/common': 1.2.2
       '@lezer/xml': 1.0.2
-    transitivePeerDependencies:
-      - '@codemirror/view'
 
-  '@codemirror/lang-yaml@6.1.1(@codemirror/view@6.22.3)':
+  '@codemirror/lang-yaml@6.1.1':
     dependencies:
-      '@codemirror/autocomplete': 6.18.1(@codemirror/language@6.9.3)(@codemirror/state@6.3.3)(@codemirror/view@6.22.3)(@lezer/common@1.2.2)
-      '@codemirror/language': 6.9.3
-      '@codemirror/state': 6.3.3
+      '@codemirror/autocomplete': 6.18.4
+      '@codemirror/language': 6.10.8
+      '@codemirror/state': 6.5.2
       '@lezer/common': 1.2.2
       '@lezer/highlight': 1.2.1
       '@lezer/yaml': 1.0.3
-    transitivePeerDependencies:
-      - '@codemirror/view'
 
-  '@codemirror/language-data@6.5.1(@codemirror/state@6.3.3)(@codemirror/view@6.22.3)(@lezer/common@1.2.2)':
+  '@codemirror/language-data@6.5.1':
     dependencies:
       '@codemirror/lang-angular': 0.1.2
       '@codemirror/lang-cpp': 6.0.2
-      '@codemirror/lang-css': 6.2.0(@codemirror/view@6.22.3)
-      '@codemirror/lang-go': 6.0.1(@codemirror/view@6.22.3)
+      '@codemirror/lang-css': 6.2.0
+      '@codemirror/lang-go': 6.0.1
       '@codemirror/lang-html': 6.4.5
       '@codemirror/lang-java': 6.0.1
       '@codemirror/lang-javascript': 6.1.9
       '@codemirror/lang-json': 6.0.1
-      '@codemirror/lang-less': 6.0.1(@codemirror/view@6.22.3)
+      '@codemirror/lang-less': 6.0.1
       '@codemirror/lang-liquid': 6.2.1
-      '@codemirror/lang-markdown': 6.2.5
+      '@codemirror/lang-markdown': 6.3.2
       '@codemirror/lang-php': 6.0.1
-      '@codemirror/lang-python': 6.1.3(@codemirror/state@6.3.3)(@codemirror/view@6.22.3)(@lezer/common@1.2.2)
+      '@codemirror/lang-python': 6.1.3
       '@codemirror/lang-rust': 6.0.1
-      '@codemirror/lang-sass': 6.0.2(@codemirror/view@6.22.3)
-      '@codemirror/lang-sql': 6.5.2(@codemirror/view@6.22.3)(@lezer/common@1.2.2)
+      '@codemirror/lang-sass': 6.0.2
+      '@codemirror/lang-sql': 6.5.2
       '@codemirror/lang-vue': 0.1.2
       '@codemirror/lang-wast': 6.0.1
-      '@codemirror/lang-xml': 6.0.2(@codemirror/view@6.22.3)
-      '@codemirror/lang-yaml': 6.1.1(@codemirror/view@6.22.3)
-      '@codemirror/language': 6.9.3
+      '@codemirror/lang-xml': 6.0.2
+      '@codemirror/lang-yaml': 6.1.1
+      '@codemirror/language': 6.10.8
       '@codemirror/legacy-modes': 6.4.1
-    transitivePeerDependencies:
-      - '@codemirror/state'
-      - '@codemirror/view'
-      - '@lezer/common'
 
-  '@codemirror/language@6.9.3':
+  '@codemirror/language@6.10.8':
     dependencies:
-      '@codemirror/state': 6.3.3
-      '@codemirror/view': 6.22.3
+      '@codemirror/state': 6.5.2
+      '@codemirror/view': 6.36.2
       '@lezer/common': 1.2.2
       '@lezer/highlight': 1.2.1
       '@lezer/lr': 1.4.2
@@ -14688,37 +14663,42 @@ snapshots:
 
   '@codemirror/legacy-modes@6.4.1':
     dependencies:
-      '@codemirror/language': 6.9.3
+      '@codemirror/language': 6.10.8
 
   '@codemirror/lint@6.8.1':
     dependencies:
-      '@codemirror/state': 6.3.3
-      '@codemirror/view': 6.22.3
+      '@codemirror/state': 6.5.2
+      '@codemirror/view': 6.36.2
       crelt: 1.0.6
 
-  '@codemirror/merge@6.0.0':
+  '@codemirror/merge@6.8.0':
     dependencies:
-      '@codemirror/state': 6.3.3
-      '@codemirror/view': 6.22.3
+      '@codemirror/language': 6.10.8
+      '@codemirror/state': 6.5.2
+      '@codemirror/view': 6.36.2
+      '@lezer/highlight': 1.2.1
+      style-mod: 4.1.2
 
   '@codemirror/search@6.5.6':
     dependencies:
-      '@codemirror/state': 6.3.3
-      '@codemirror/view': 6.22.3
+      '@codemirror/state': 6.5.2
+      '@codemirror/view': 6.36.2
       crelt: 1.0.6
 
-  '@codemirror/state@6.3.3': {}
+  '@codemirror/state@6.5.2':
+    dependencies:
+      '@marijn/find-cluster-break': 1.0.2
 
   '@codemirror/theme-one-dark@6.1.2':
     dependencies:
-      '@codemirror/language': 6.9.3
-      '@codemirror/state': 6.3.3
-      '@codemirror/view': 6.22.3
+      '@codemirror/language': 6.10.8
+      '@codemirror/state': 6.5.2
+      '@codemirror/view': 6.36.2
       '@lezer/highlight': 1.2.1
 
-  '@codemirror/view@6.22.3':
+  '@codemirror/view@6.36.2':
     dependencies:
-      '@codemirror/state': 6.3.3
+      '@codemirror/state': 6.5.2
       style-mod: 4.1.2
       w3c-keyname: 2.2.8
 
@@ -15408,6 +15388,8 @@ snapshots:
       globby: 11.1.0
       read-yaml-file: 1.1.0
 
+  '@marijn/find-cluster-break@1.0.2': {}
+
   '@marp-team/marp-core@3.9.1':
     dependencies:
       '@marp-team/marpit': 2.6.1
@@ -16329,31 +16311,31 @@ snapshots:
 
   '@react-dnd/shallowequal@2.0.0': {}
 
-  '@replit/codemirror-emacs@6.1.0(@codemirror/autocomplete@6.18.1(@codemirror/language@6.9.3)(@codemirror/state@6.3.3)(@codemirror/view@6.22.3)(@lezer/common@1.2.2))(@codemirror/commands@6.2.5)(@codemirror/search@6.5.6)(@codemirror/state@6.3.3)(@codemirror/view@6.22.3)':
+  '@replit/codemirror-emacs@6.1.0(@codemirror/autocomplete@6.18.4)(@codemirror/commands@6.8.0)(@codemirror/search@6.5.6)(@codemirror/state@6.5.2)(@codemirror/view@6.36.2)':
     dependencies:
-      '@codemirror/autocomplete': 6.18.1(@codemirror/language@6.9.3)(@codemirror/state@6.3.3)(@codemirror/view@6.22.3)(@lezer/common@1.2.2)
-      '@codemirror/commands': 6.2.5
+      '@codemirror/autocomplete': 6.18.4
+      '@codemirror/commands': 6.8.0
       '@codemirror/search': 6.5.6
-      '@codemirror/state': 6.3.3
-      '@codemirror/view': 6.22.3
+      '@codemirror/state': 6.5.2
+      '@codemirror/view': 6.36.2
 
-  '@replit/codemirror-vim@6.2.1(@codemirror/commands@6.2.5)(@codemirror/language@6.9.3)(@codemirror/search@6.5.6)(@codemirror/state@6.3.3)(@codemirror/view@6.22.3)':
+  '@replit/codemirror-vim@6.2.1(@codemirror/commands@6.8.0)(@codemirror/language@6.10.8)(@codemirror/search@6.5.6)(@codemirror/state@6.5.2)(@codemirror/view@6.36.2)':
     dependencies:
-      '@codemirror/commands': 6.2.5
-      '@codemirror/language': 6.9.3
+      '@codemirror/commands': 6.8.0
+      '@codemirror/language': 6.10.8
       '@codemirror/search': 6.5.6
-      '@codemirror/state': 6.3.3
-      '@codemirror/view': 6.22.3
+      '@codemirror/state': 6.5.2
+      '@codemirror/view': 6.36.2
 
-  '@replit/codemirror-vscode-keymap@6.0.2(@codemirror/autocomplete@6.18.1(@codemirror/language@6.9.3)(@codemirror/state@6.3.3)(@codemirror/view@6.22.3)(@lezer/common@1.2.2))(@codemirror/commands@6.2.5)(@codemirror/language@6.9.3)(@codemirror/lint@6.8.1)(@codemirror/search@6.5.6)(@codemirror/state@6.3.3)(@codemirror/view@6.22.3)':
+  '@replit/codemirror-vscode-keymap@6.0.2(@codemirror/autocomplete@6.18.4)(@codemirror/commands@6.8.0)(@codemirror/language@6.10.8)(@codemirror/lint@6.8.1)(@codemirror/search@6.5.6)(@codemirror/state@6.5.2)(@codemirror/view@6.36.2)':
     dependencies:
-      '@codemirror/autocomplete': 6.18.1(@codemirror/language@6.9.3)(@codemirror/state@6.3.3)(@codemirror/view@6.22.3)(@lezer/common@1.2.2)
-      '@codemirror/commands': 6.2.5
-      '@codemirror/language': 6.9.3
+      '@codemirror/autocomplete': 6.18.4
+      '@codemirror/commands': 6.8.0
+      '@codemirror/language': 6.10.8
       '@codemirror/lint': 6.8.1
       '@codemirror/search': 6.5.6
-      '@codemirror/state': 6.3.3
-      '@codemirror/view': 6.22.3
+      '@codemirror/state': 6.5.2
+      '@codemirror/view': 6.36.2
 
   '@restart/hooks@0.4.16(react@18.2.0)':
     dependencies:
@@ -17778,10 +17760,10 @@ snapshots:
     transitivePeerDependencies:
       - supports-color
 
-  '@typescript-eslint/eslint-plugin@5.59.7(@typescript-eslint/parser@5.59.7(eslint@8.41.0)(typescript@5.0.4))(eslint@8.41.0)(typescript@5.4.2)':
+  '@typescript-eslint/eslint-plugin@5.59.7(@typescript-eslint/parser@5.59.7(eslint@8.41.0)(typescript@5.4.2))(eslint@8.41.0)(typescript@5.4.2)':
     dependencies:
       '@eslint-community/regexpp': 4.5.1
-      '@typescript-eslint/parser': 5.59.7(eslint@8.41.0)(typescript@5.0.4)
+      '@typescript-eslint/parser': 5.59.7(eslint@8.41.0)(typescript@5.4.2)
       '@typescript-eslint/scope-manager': 5.59.7
       '@typescript-eslint/type-utils': 5.59.7(eslint@8.41.0)(typescript@5.4.2)
       '@typescript-eslint/utils': 5.59.7(eslint@8.41.0)(typescript@5.4.2)
@@ -17810,6 +17792,19 @@ snapshots:
     transitivePeerDependencies:
       - supports-color
 
+  '@typescript-eslint/parser@5.59.7(eslint@8.41.0)(typescript@5.4.2)':
+    dependencies:
+      '@typescript-eslint/scope-manager': 5.59.7
+      '@typescript-eslint/types': 5.59.7
+      '@typescript-eslint/typescript-estree': 5.59.7(typescript@5.4.2)
+      debug: 4.4.0(supports-color@5.5.0)
+      eslint: 8.41.0
+    optionalDependencies:
+      typescript: 5.4.2
+    transitivePeerDependencies:
+      - supports-color
+    optional: true
+
   '@typescript-eslint/scope-manager@5.59.7':
     dependencies:
       '@typescript-eslint/types': 5.59.7
@@ -17905,47 +17900,47 @@ snapshots:
       '@typescript-eslint/types': 5.59.7
       eslint-visitor-keys: 3.4.3
 
-  '@uiw/codemirror-extensions-basic-setup@4.23.5(@codemirror/autocomplete@6.18.1(@codemirror/language@6.9.3)(@codemirror/state@6.3.3)(@codemirror/view@6.22.3)(@lezer/common@1.2.2))(@codemirror/commands@6.2.5)(@codemirror/language@6.9.3)(@codemirror/lint@6.8.1)(@codemirror/search@6.5.6)(@codemirror/state@6.3.3)(@codemirror/view@6.22.3)':
+  '@uiw/codemirror-extensions-basic-setup@4.23.8(@codemirror/autocomplete@6.18.4)(@codemirror/commands@6.8.0)(@codemirror/language@6.10.8)(@codemirror/lint@6.8.1)(@codemirror/search@6.5.6)(@codemirror/state@6.5.2)(@codemirror/view@6.36.2)':
     dependencies:
-      '@codemirror/autocomplete': 6.18.1(@codemirror/language@6.9.3)(@codemirror/state@6.3.3)(@codemirror/view@6.22.3)(@lezer/common@1.2.2)
-      '@codemirror/commands': 6.2.5
-      '@codemirror/language': 6.9.3
+      '@codemirror/autocomplete': 6.18.4
+      '@codemirror/commands': 6.8.0
+      '@codemirror/language': 6.10.8
       '@codemirror/lint': 6.8.1
       '@codemirror/search': 6.5.6
-      '@codemirror/state': 6.3.3
-      '@codemirror/view': 6.22.3
+      '@codemirror/state': 6.5.2
+      '@codemirror/view': 6.36.2
 
-  '@uiw/codemirror-theme-eclipse@4.23.5(@codemirror/language@6.9.3)(@codemirror/state@6.3.3)(@codemirror/view@6.22.3)':
+  '@uiw/codemirror-theme-eclipse@4.23.8(@codemirror/language@6.10.8)(@codemirror/state@6.5.2)(@codemirror/view@6.36.2)':
     dependencies:
-      '@uiw/codemirror-themes': 4.23.5(@codemirror/language@6.9.3)(@codemirror/state@6.3.3)(@codemirror/view@6.22.3)
+      '@uiw/codemirror-themes': 4.23.8(@codemirror/language@6.10.8)(@codemirror/state@6.5.2)(@codemirror/view@6.36.2)
     transitivePeerDependencies:
       - '@codemirror/language'
       - '@codemirror/state'
       - '@codemirror/view'
 
-  '@uiw/codemirror-theme-kimbie@4.23.5(@codemirror/language@6.9.3)(@codemirror/state@6.3.3)(@codemirror/view@6.22.3)':
+  '@uiw/codemirror-theme-kimbie@4.23.8(@codemirror/language@6.10.8)(@codemirror/state@6.5.2)(@codemirror/view@6.36.2)':
     dependencies:
-      '@uiw/codemirror-themes': 4.23.5(@codemirror/language@6.9.3)(@codemirror/state@6.3.3)(@codemirror/view@6.22.3)
+      '@uiw/codemirror-themes': 4.23.8(@codemirror/language@6.10.8)(@codemirror/state@6.5.2)(@codemirror/view@6.36.2)
     transitivePeerDependencies:
       - '@codemirror/language'
       - '@codemirror/state'
       - '@codemirror/view'
 
-  '@uiw/codemirror-themes@4.23.5(@codemirror/language@6.9.3)(@codemirror/state@6.3.3)(@codemirror/view@6.22.3)':
+  '@uiw/codemirror-themes@4.23.8(@codemirror/language@6.10.8)(@codemirror/state@6.5.2)(@codemirror/view@6.36.2)':
     dependencies:
-      '@codemirror/language': 6.9.3
-      '@codemirror/state': 6.3.3
-      '@codemirror/view': 6.22.3
+      '@codemirror/language': 6.10.8
+      '@codemirror/state': 6.5.2
+      '@codemirror/view': 6.36.2
 
-  '@uiw/react-codemirror@4.23.5(@babel/runtime@7.25.4)(@codemirror/autocomplete@6.18.1(@codemirror/language@6.9.3)(@codemirror/state@6.3.3)(@codemirror/view@6.22.3)(@lezer/common@1.2.2))(@codemirror/language@6.9.3)(@codemirror/lint@6.8.1)(@codemirror/search@6.5.6)(@codemirror/state@6.3.3)(@codemirror/theme-one-dark@6.1.2)(@codemirror/view@6.22.3)(codemirror@6.0.1(@lezer/common@1.2.2))(react-dom@18.2.0(react@18.2.0))(react@18.2.0)':
+  '@uiw/react-codemirror@4.23.8(@babel/runtime@7.25.4)(@codemirror/autocomplete@6.18.4)(@codemirror/language@6.10.8)(@codemirror/lint@6.8.1)(@codemirror/search@6.5.6)(@codemirror/state@6.5.2)(@codemirror/theme-one-dark@6.1.2)(@codemirror/view@6.36.2)(codemirror@6.0.1)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)':
     dependencies:
       '@babel/runtime': 7.25.4
-      '@codemirror/commands': 6.2.5
-      '@codemirror/state': 6.3.3
+      '@codemirror/commands': 6.8.0
+      '@codemirror/state': 6.5.2
       '@codemirror/theme-one-dark': 6.1.2
-      '@codemirror/view': 6.22.3
-      '@uiw/codemirror-extensions-basic-setup': 4.23.5(@codemirror/autocomplete@6.18.1(@codemirror/language@6.9.3)(@codemirror/state@6.3.3)(@codemirror/view@6.22.3)(@lezer/common@1.2.2))(@codemirror/commands@6.2.5)(@codemirror/language@6.9.3)(@codemirror/lint@6.8.1)(@codemirror/search@6.5.6)(@codemirror/state@6.3.3)(@codemirror/view@6.22.3)
-      codemirror: 6.0.1(@lezer/common@1.2.2)
+      '@codemirror/view': 6.36.2
+      '@uiw/codemirror-extensions-basic-setup': 4.23.8(@codemirror/autocomplete@6.18.4)(@codemirror/commands@6.8.0)(@codemirror/language@6.10.8)(@codemirror/lint@6.8.1)(@codemirror/search@6.5.6)(@codemirror/state@6.5.2)(@codemirror/view@6.36.2)
+      codemirror: 6.0.1
       react: 18.2.0
       react-dom: 18.2.0(react@18.2.0)
     transitivePeerDependencies:
@@ -17969,7 +17964,7 @@ snapshots:
     transitivePeerDependencies:
       - supports-color
 
-  '@vitest/coverage-v8@2.1.1(vitest@2.1.1(@types/node@20.14.0)(@vitest/ui@2.1.1)(happy-dom@15.7.4)(sass@1.77.6)(terser@5.37.0))':
+  '@vitest/coverage-v8@2.1.1(vitest@2.1.1)':
     dependencies:
       '@ampproject/remapping': 2.3.0
       '@bcoe/v8-coverage': 0.2.3
@@ -19177,40 +19172,38 @@ snapshots:
 
   clsx@1.2.1: {}
 
-  cm6-theme-basic-light@0.2.0(@codemirror/language@6.9.3)(@codemirror/state@6.3.3)(@codemirror/view@6.22.3)(@lezer/highlight@1.2.1):
+  cm6-theme-basic-light@0.2.0(@codemirror/language@6.10.8)(@codemirror/state@6.5.2)(@codemirror/view@6.36.2)(@lezer/highlight@1.2.1):
     dependencies:
-      '@codemirror/language': 6.9.3
-      '@codemirror/state': 6.3.3
-      '@codemirror/view': 6.22.3
+      '@codemirror/language': 6.10.8
+      '@codemirror/state': 6.5.2
+      '@codemirror/view': 6.36.2
       '@lezer/highlight': 1.2.1
 
-  cm6-theme-material-dark@0.2.0(@codemirror/language@6.9.3)(@codemirror/state@6.3.3)(@codemirror/view@6.22.3)(@lezer/highlight@1.2.1):
+  cm6-theme-material-dark@0.2.0(@codemirror/language@6.10.8)(@codemirror/state@6.5.2)(@codemirror/view@6.36.2)(@lezer/highlight@1.2.1):
     dependencies:
-      '@codemirror/language': 6.9.3
-      '@codemirror/state': 6.3.3
-      '@codemirror/view': 6.22.3
+      '@codemirror/language': 6.10.8
+      '@codemirror/state': 6.5.2
+      '@codemirror/view': 6.36.2
       '@lezer/highlight': 1.2.1
 
-  cm6-theme-nord@0.2.0(@codemirror/language@6.9.3)(@codemirror/state@6.3.3)(@codemirror/view@6.22.3)(@lezer/highlight@1.2.1):
+  cm6-theme-nord@0.2.0(@codemirror/language@6.10.8)(@codemirror/state@6.5.2)(@codemirror/view@6.36.2)(@lezer/highlight@1.2.1):
     dependencies:
-      '@codemirror/language': 6.9.3
-      '@codemirror/state': 6.3.3
-      '@codemirror/view': 6.22.3
+      '@codemirror/language': 6.10.8
+      '@codemirror/state': 6.5.2
+      '@codemirror/view': 6.36.2
       '@lezer/highlight': 1.2.1
 
   co@4.6.0: {}
 
-  codemirror@6.0.1(@lezer/common@1.2.2):
+  codemirror@6.0.1:
     dependencies:
-      '@codemirror/autocomplete': 6.18.1(@codemirror/language@6.9.3)(@codemirror/state@6.3.3)(@codemirror/view@6.22.3)(@lezer/common@1.2.2)
-      '@codemirror/commands': 6.2.5
-      '@codemirror/language': 6.9.3
+      '@codemirror/autocomplete': 6.18.4
+      '@codemirror/commands': 6.8.0
+      '@codemirror/language': 6.10.8
       '@codemirror/lint': 6.8.1
       '@codemirror/search': 6.5.6
-      '@codemirror/state': 6.3.3
-      '@codemirror/view': 6.22.3
-    transitivePeerDependencies:
-      - '@lezer/common'
+      '@codemirror/state': 6.5.2
+      '@codemirror/view': 6.36.2
 
   collect-v8-coverage@1.0.2: {}
 
@@ -20296,7 +20289,7 @@ snapshots:
 
   escape-string-regexp@5.0.0: {}
 
-  eslint-config-airbnb-base@13.1.0(eslint-plugin-import@2.26.0(@typescript-eslint/parser@5.59.7(eslint@8.41.0)(typescript@5.0.4))(eslint-import-resolver-typescript@3.2.5)(eslint@8.41.0))(eslint@8.41.0):
+  eslint-config-airbnb-base@13.1.0(eslint-plugin-import@2.26.0)(eslint@8.41.0):
     dependencies:
       eslint: 8.41.0
       eslint-plugin-import: 2.26.0(@typescript-eslint/parser@5.59.7(eslint@8.41.0)(typescript@5.0.4))(eslint-import-resolver-typescript@3.2.5)(eslint@8.41.0)
@@ -20304,10 +20297,10 @@ snapshots:
       object.assign: 4.1.5
       object.entries: 1.1.5
 
-  eslint-config-airbnb@17.1.0(eslint-plugin-import@2.26.0(@typescript-eslint/parser@5.59.7(eslint@8.41.0)(typescript@5.0.4))(eslint-import-resolver-typescript@3.2.5)(eslint@8.41.0))(eslint-plugin-jsx-a11y@6.5.1(eslint@8.41.0))(eslint-plugin-react@7.30.1(eslint@8.41.0))(eslint@8.41.0):
+  eslint-config-airbnb@17.1.0(eslint-plugin-import@2.26.0)(eslint-plugin-jsx-a11y@6.5.1(eslint@8.41.0))(eslint-plugin-react@7.30.1(eslint@8.41.0))(eslint@8.41.0):
     dependencies:
       eslint: 8.41.0
-      eslint-config-airbnb-base: 13.1.0(eslint-plugin-import@2.26.0(@typescript-eslint/parser@5.59.7(eslint@8.41.0)(typescript@5.0.4))(eslint-import-resolver-typescript@3.2.5)(eslint@8.41.0))(eslint@8.41.0)
+      eslint-config-airbnb-base: 13.1.0(eslint-plugin-import@2.26.0)(eslint@8.41.0)
       eslint-plugin-import: 2.26.0(@typescript-eslint/parser@5.59.7(eslint@8.41.0)(typescript@5.0.4))(eslint-import-resolver-typescript@3.2.5)(eslint@8.41.0)
       eslint-plugin-jsx-a11y: 6.5.1(eslint@8.41.0)
       eslint-plugin-react: 7.30.1(eslint@8.41.0)
@@ -20333,14 +20326,14 @@ snapshots:
       - eslint-import-resolver-webpack
       - supports-color
 
-  eslint-config-weseek@2.1.1(@babel/core@7.24.6)(@babel/eslint-parser@7.24.7(@babel/core@7.24.6)(eslint@8.41.0))(@typescript-eslint/eslint-plugin@5.59.7(@typescript-eslint/parser@5.59.7(eslint@8.41.0)(typescript@5.0.4))(eslint@8.41.0)(typescript@5.0.4))(@typescript-eslint/parser@5.59.7(eslint@8.41.0)(typescript@5.0.4))(eslint-import-resolver-typescript@3.2.5(eslint-plugin-import@2.26.0)(eslint@8.41.0))(eslint-plugin-import@2.26.0(@typescript-eslint/parser@5.59.7(eslint@8.41.0)(typescript@5.0.4))(eslint-import-resolver-typescript@3.2.5)(eslint@8.41.0))(eslint-plugin-jsx-a11y@6.5.1(eslint@8.41.0))(eslint-plugin-react-hooks@4.6.0(eslint@8.41.0))(eslint-plugin-react@7.30.1(eslint@8.41.0))(eslint-plugin-vue@7.20.0(eslint@8.41.0))(eslint@8.41.0):
+  eslint-config-weseek@2.1.1(@babel/core@7.24.6)(@babel/eslint-parser@7.24.7(@babel/core@7.24.6)(eslint@8.41.0))(@typescript-eslint/eslint-plugin@5.59.7(@typescript-eslint/parser@5.59.7(eslint@8.41.0)(typescript@5.0.4))(eslint@8.41.0)(typescript@5.0.4))(@typescript-eslint/parser@5.59.7(eslint@8.41.0)(typescript@5.0.4))(eslint-import-resolver-typescript@3.2.5)(eslint-plugin-import@2.26.0)(eslint-plugin-jsx-a11y@6.5.1(eslint@8.41.0))(eslint-plugin-react-hooks@4.6.0(eslint@8.41.0))(eslint-plugin-react@7.30.1(eslint@8.41.0))(eslint-plugin-vue@7.20.0(eslint@8.41.0))(eslint@8.41.0):
     dependencies:
       '@babel/core': 7.24.6
       '@babel/eslint-parser': 7.24.7(@babel/core@7.24.6)(eslint@8.41.0)
       '@typescript-eslint/eslint-plugin': 5.59.7(@typescript-eslint/parser@5.59.7(eslint@8.41.0)(typescript@5.0.4))(eslint@8.41.0)(typescript@5.0.4)
       '@typescript-eslint/parser': 5.59.7(eslint@8.41.0)(typescript@5.0.4)
       eslint: 8.41.0
-      eslint-config-airbnb: 17.1.0(eslint-plugin-import@2.26.0(@typescript-eslint/parser@5.59.7(eslint@8.41.0)(typescript@5.0.4))(eslint-import-resolver-typescript@3.2.5)(eslint@8.41.0))(eslint-plugin-jsx-a11y@6.5.1(eslint@8.41.0))(eslint-plugin-react@7.30.1(eslint@8.41.0))(eslint@8.41.0)
+      eslint-config-airbnb: 17.1.0(eslint-plugin-import@2.26.0)(eslint-plugin-jsx-a11y@6.5.1(eslint@8.41.0))(eslint-plugin-react@7.30.1(eslint@8.41.0))(eslint@8.41.0)
       eslint-import-resolver-typescript: 3.2.5(eslint-plugin-import@2.26.0)(eslint@8.41.0)
       eslint-plugin-import: 2.26.0(@typescript-eslint/parser@5.59.7(eslint@8.41.0)(typescript@5.0.4))(eslint-import-resolver-typescript@3.2.5)(eslint@8.41.0)
       eslint-plugin-react: 7.30.1(eslint@8.41.0)
@@ -20360,7 +20353,7 @@ snapshots:
     dependencies:
       debug: 4.4.0(supports-color@5.5.0)
       eslint: 8.41.0
-      eslint-plugin-import: 2.26.0(@typescript-eslint/parser@5.59.7(eslint@8.41.0)(typescript@5.0.4))(eslint-import-resolver-typescript@2.7.1)(eslint@8.41.0)
+      eslint-plugin-import: 2.26.0(@typescript-eslint/parser@5.59.7(eslint@8.41.0)(typescript@5.0.4))(eslint-import-resolver-typescript@3.2.5)(eslint@8.41.0)
       glob: 7.2.3
       is-glob: 4.0.3
       resolve: 1.22.8
@@ -20382,7 +20375,7 @@ snapshots:
     transitivePeerDependencies:
       - supports-color
 
-  eslint-module-utils@2.7.3(@typescript-eslint/parser@5.59.7(eslint@8.41.0)(typescript@5.0.4))(eslint-import-resolver-node@0.3.6)(eslint-import-resolver-typescript@2.7.1(eslint-plugin-import@2.26.0)(eslint@8.41.0)):
+  eslint-module-utils@2.7.3(@typescript-eslint/parser@5.59.7(eslint@8.41.0)(typescript@5.0.4))(eslint-import-resolver-node@0.3.6)(eslint-import-resolver-typescript@2.7.1):
     dependencies:
       debug: 3.2.7
       find-up: 2.1.0
@@ -20393,7 +20386,7 @@ snapshots:
     transitivePeerDependencies:
       - supports-color
 
-  eslint-module-utils@2.7.3(@typescript-eslint/parser@5.59.7(eslint@8.41.0)(typescript@5.0.4))(eslint-import-resolver-node@0.3.6)(eslint-import-resolver-typescript@3.2.5(eslint-plugin-import@2.26.0)(eslint@8.41.0)):
+  eslint-module-utils@2.7.3(@typescript-eslint/parser@5.59.7(eslint@8.41.0)(typescript@5.0.4))(eslint-import-resolver-node@0.3.6)(eslint-import-resolver-typescript@3.2.5):
     dependencies:
       debug: 3.2.7
       find-up: 2.1.0
@@ -20412,7 +20405,7 @@ snapshots:
       doctrine: 2.1.0
       eslint: 8.41.0
       eslint-import-resolver-node: 0.3.6
-      eslint-module-utils: 2.7.3(@typescript-eslint/parser@5.59.7(eslint@8.41.0)(typescript@5.0.4))(eslint-import-resolver-node@0.3.6)(eslint-import-resolver-typescript@2.7.1(eslint-plugin-import@2.26.0)(eslint@8.41.0))
+      eslint-module-utils: 2.7.3(@typescript-eslint/parser@5.59.7(eslint@8.41.0)(typescript@5.0.4))(eslint-import-resolver-node@0.3.6)(eslint-import-resolver-typescript@2.7.1)
       has: 1.0.3
       is-core-module: 2.15.1
       is-glob: 4.0.3
@@ -20435,7 +20428,7 @@ snapshots:
       doctrine: 2.1.0
       eslint: 8.41.0
       eslint-import-resolver-node: 0.3.6
-      eslint-module-utils: 2.7.3(@typescript-eslint/parser@5.59.7(eslint@8.41.0)(typescript@5.0.4))(eslint-import-resolver-node@0.3.6)(eslint-import-resolver-typescript@3.2.5(eslint-plugin-import@2.26.0)(eslint@8.41.0))
+      eslint-module-utils: 2.7.3(@typescript-eslint/parser@5.59.7(eslint@8.41.0)(typescript@5.0.4))(eslint-import-resolver-node@0.3.6)(eslint-import-resolver-typescript@3.2.5)
       has: 1.0.3
       is-core-module: 2.15.1
       is-glob: 4.0.3
@@ -20461,12 +20454,12 @@ snapshots:
       - typescript
     optional: true
 
-  eslint-plugin-jest@26.9.0(@typescript-eslint/eslint-plugin@5.59.7(@typescript-eslint/parser@5.59.7(eslint@8.41.0)(typescript@5.0.4))(eslint@8.41.0)(typescript@5.4.2))(eslint@8.41.0)(jest@29.7.0(@types/node@20.14.0)(ts-node@10.9.2(@swc/core@1.5.25(@swc/helpers@0.5.11))(@types/node@20.14.0)(typescript@5.4.2)))(typescript@5.4.2):
+  eslint-plugin-jest@26.9.0(@typescript-eslint/eslint-plugin@5.59.7(@typescript-eslint/parser@5.59.7(eslint@8.41.0)(typescript@5.4.2))(eslint@8.41.0)(typescript@5.4.2))(eslint@8.41.0)(jest@29.7.0(@types/node@20.14.0)(ts-node@10.9.2(@swc/core@1.5.25(@swc/helpers@0.5.11))(@types/node@20.14.0)(typescript@5.4.2)))(typescript@5.4.2):
     dependencies:
       '@typescript-eslint/utils': 5.59.7(eslint@8.41.0)(typescript@5.4.2)
       eslint: 8.41.0
     optionalDependencies:
-      '@typescript-eslint/eslint-plugin': 5.59.7(@typescript-eslint/parser@5.59.7(eslint@8.41.0)(typescript@5.0.4))(eslint@8.41.0)(typescript@5.4.2)
+      '@typescript-eslint/eslint-plugin': 5.59.7(@typescript-eslint/parser@5.59.7(eslint@8.41.0)(typescript@5.4.2))(eslint@8.41.0)(typescript@5.4.2)
       jest: 29.7.0(@types/node@20.14.0)(ts-node@10.9.2(@swc/core@1.5.25(@swc/helpers@0.5.11))(@types/node@20.14.0)(typescript@5.4.2))
     transitivePeerDependencies:
       - supports-color
@@ -27110,7 +27103,7 @@ snapshots:
       sass: 1.77.6
       terser: 5.37.0
 
-  vitest-mock-extended@2.0.2(typescript@5.0.4)(vitest@2.1.1(@types/node@20.14.0)(@vitest/ui@2.1.1)(happy-dom@15.7.4)(sass@1.77.6)(terser@5.37.0)):
+  vitest-mock-extended@2.0.2(typescript@5.0.4)(vitest@2.1.1):
     dependencies:
       ts-essentials: 10.0.2(typescript@5.0.4)
       typescript: 5.0.4
@@ -27432,10 +27425,10 @@ snapshots:
 
   xtend@4.0.2: {}
 
-  y-codemirror.next@0.3.5(@codemirror/state@6.3.3)(@codemirror/view@6.22.3)(yjs@13.6.19):
+  y-codemirror.next@0.3.5(@codemirror/state@6.5.2)(@codemirror/view@6.36.2)(yjs@13.6.19):
     dependencies:
-      '@codemirror/state': 6.3.3
-      '@codemirror/view': 6.22.3
+      '@codemirror/state': 6.5.2
+      '@codemirror/view': 6.36.2
       lib0: 0.2.94
       yjs: 13.6.19