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

Merge pull request #6273 from weseek/fix/lint-error

fix: Lint errors and tsc errors
Yuki Takei 3 лет назад
Родитель
Сommit
7f01c3b235
62 измененных файлов с 403 добавлено и 369 удалено
  1. 1 2
      packages/app/src/client/services/page-operation.ts
  2. 1 1
      packages/app/src/components/Admin/UserGroup/UserGroupModal.tsx
  3. 1 1
      packages/app/src/components/InAppNotification/InAppNotificationElm.tsx
  4. 2 1
      packages/app/src/components/InAppNotification/InAppNotificationList.tsx
  5. 1 1
      packages/app/src/components/InAppNotification/PageNotification/PageModelNotification.tsx
  6. 2 2
      packages/app/src/components/Navbar/GlobalSearch.tsx
  7. 1 2
      packages/app/src/components/Navbar/GrowiContextualSubNavigation.tsx
  8. 3 2
      packages/app/src/components/Navbar/GrowiNavbar.tsx
  9. 1 2
      packages/app/src/components/Page/DisplaySwitcher.tsx
  10. 1 1
      packages/app/src/components/Page/RevisionRenderer.tsx
  11. 1 1
      packages/app/src/components/PageAlert/TrashPageAlert.tsx
  12. 24 22
      packages/app/src/components/PageComment/CommentEditor.tsx
  13. 2 1
      packages/app/src/components/PageContentFooter.tsx
  14. 1 2
      packages/app/src/components/PageDeleteModal.tsx
  15. 15 12
      packages/app/src/components/PageEditor/Preview.tsx
  16. 1 2
      packages/app/src/components/SavePageControls/GrantSelector.tsx
  17. 1 2
      packages/app/src/components/Sidebar/PageTree/Item.tsx
  18. 1 1
      packages/app/src/components/Sidebar/PageTree/ItemsTree.tsx
  19. 1 4
      packages/app/src/components/Sidebar/RecentChanges.tsx
  20. 1 2
      packages/app/src/components/SubscribeButton.tsx
  21. 2 2
      packages/app/src/interfaces/activity.ts
  22. 1 11
      packages/app/src/interfaces/attachment.ts
  23. 2 2
      packages/app/src/interfaces/comment.ts
  24. 0 19
      packages/app/src/interfaces/common.ts
  25. 2 1
      packages/app/src/interfaces/external-account.ts
  26. 1 6
      packages/app/src/interfaces/global.ts
  27. 1 1
      packages/app/src/interfaces/page-grant.ts
  28. 10 116
      packages/app/src/interfaces/page.ts
  29. 3 25
      packages/app/src/interfaces/revision.ts
  30. 1 6
      packages/app/src/interfaces/subscription.ts
  31. 3 6
      packages/app/src/interfaces/tag.ts
  32. 1 1
      packages/app/src/interfaces/ui.ts
  33. 2 2
      packages/app/src/interfaces/user-ui-settings.ts
  34. 3 37
      packages/app/src/interfaces/user.ts
  35. 1 3
      packages/app/src/next-i18next.config.ts
  36. 10 9
      packages/app/src/pages/[[...path]].page.tsx
  37. 1 2
      packages/app/src/pages/commons.ts
  38. 6 5
      packages/app/src/server/models/password-reset-order.ts
  39. 1 2
      packages/app/src/server/models/subscription.ts
  40. 1 1
      packages/app/src/server/models/user-registration-order.ts
  41. 1 2
      packages/app/src/server/routes/apiv3/page.js
  42. 1 2
      packages/app/src/server/service/in-app-notification.ts
  43. 1 2
      packages/app/src/server/service/installer.ts
  44. 3 3
      packages/app/src/server/service/page.ts
  45. 1 1
      packages/app/src/stores/comment.tsx
  46. 2 2
      packages/app/src/stores/context.tsx
  47. 1 1
      packages/app/src/stores/editor.tsx
  48. 1 2
      packages/app/src/stores/page-listing.tsx
  49. 7 7
      packages/app/src/stores/page.tsx
  50. 3 2
      packages/app/src/stores/ui.tsx
  51. 0 22
      packages/core/src/index.js
  52. 29 0
      packages/core/src/index.ts
  53. 11 0
      packages/core/src/interfaces/attachment.ts
  54. 21 0
      packages/core/src/interfaces/common.ts
  55. 0 0
      packages/core/src/interfaces/has-object-id.ts
  56. 0 0
      packages/core/src/interfaces/lang.ts
  57. 131 0
      packages/core/src/interfaces/page.ts
  58. 28 0
      packages/core/src/interfaces/revision.ts
  59. 6 0
      packages/core/src/interfaces/subscription.ts
  60. 4 0
      packages/core/src/interfaces/tag.ts
  61. 37 0
      packages/core/src/interfaces/user.ts
  62. 1 2
      packages/ui/src/components/PagePath/PageListMeta.tsx

+ 1 - 2
packages/app/src/client/services/page-operation.ts

@@ -1,7 +1,6 @@
+import { SubscriptionStatusType } from '@growi/core';
 import urljoin from 'url-join';
 
-import { SubscriptionStatusType } from '~/interfaces/subscription';
-
 import { toastError } from '../util/apiNotification';
 import { apiv3Post, apiv3Put } from '../util/apiv3-client';
 

+ 1 - 1
packages/app/src/components/Admin/UserGroup/UserGroupModal.tsx

@@ -2,13 +2,13 @@ import React, {
   FC, useState, useEffect, useCallback,
 } from 'react';
 
+import { Ref } from '@growi/core';
 import { TFunctionResult } from 'i18next';
 import { useTranslation } from 'next-i18next';
 import {
   Modal, ModalHeader, ModalBody, ModalFooter,
 } from 'reactstrap';
 
-import { Ref } from '~/interfaces/common';
 import { IUserGroup, IUserGroupHasId } from '~/interfaces/user';
 
 type Props = {

+ 1 - 1
packages/app/src/components/InAppNotification/InAppNotificationElm.tsx

@@ -2,12 +2,12 @@ import React, {
   FC, useRef,
 } from 'react';
 
+import { HasObjectId } from '@growi/core';
 import { UserPicture } from '@growi/ui';
 import { DropdownItem } from 'reactstrap';
 
 import { IInAppNotificationOpenable } from '~/client/interfaces/in-app-notification-openable';
 import { apiv3Post } from '~/client/util/apiv3-client';
-import { HasObjectId } from '~/interfaces/has-object-id';
 import { IInAppNotification, InAppNotificationStatuses } from '~/interfaces/in-app-notification';
 
 // Change the display for each targetmodel

+ 2 - 1
packages/app/src/components/InAppNotification/InAppNotificationList.tsx

@@ -1,7 +1,8 @@
 import React, { FC } from 'react';
 
+import { HasObjectId } from '@growi/core';
+
 import { IInAppNotification, PaginateResult } from '~/interfaces/in-app-notification';
-import { HasObjectId } from '~/interfaces/has-object-id';
 
 import InAppNotificationElm from './InAppNotificationElm';
 

+ 1 - 1
packages/app/src/components/InAppNotification/PageNotification/PageModelNotification.tsx

@@ -2,10 +2,10 @@ import React, {
   forwardRef, ForwardRefRenderFunction, useImperativeHandle,
 } from 'react';
 
+import { HasObjectId } from '@growi/core';
 import { PagePathLabel } from '@growi/ui';
 
 import { IInAppNotificationOpenable } from '~/client/interfaces/in-app-notification-openable';
-import { HasObjectId } from '~/interfaces/has-object-id';
 import { IInAppNotification } from '~/interfaces/in-app-notification';
 
 import { parseSnapshot } from '../../../models/serializers/in-app-notification-snapshot/page';

+ 2 - 2
packages/app/src/components/Navbar/GlobalSearch.tsx

@@ -18,11 +18,11 @@ import SearchForm from '../SearchForm';
 import styles from './GlobalSearch.module.scss';
 
 
-type Props = {
+export type GlobalSearchProps = {
   dropup?: boolean,
 }
 
-export const GlobalSearch = (props: Props): JSX.Element => {
+export const GlobalSearch = (props: GlobalSearchProps): JSX.Element => {
   const { t } = useTranslation();
 
   const { dropup } = props;

+ 1 - 2
packages/app/src/components/Navbar/GrowiContextualSubNavigation.tsx

@@ -1,13 +1,12 @@
 import React, { useState, useEffect, useCallback } from 'react';
 
+import { isPopulated } from '@growi/core';
 import { useTranslation } from 'next-i18next';
-import PropTypes from 'prop-types';
 import { DropdownItem } from 'reactstrap';
 
 import { exportAsMarkdown } from '~/client/services/page-operation';
 import { toastSuccess, toastError } from '~/client/util/apiNotification';
 import { apiPost } from '~/client/util/apiv1-client';
-import { isPopulated } from '~/interfaces/common';
 import {
   IPageToRenameWithMeta, IPageWithMeta, IPageInfoForEntity,
 } from '~/interfaces/page';

+ 3 - 2
packages/app/src/components/Navbar/GrowiNavbar.tsx

@@ -9,18 +9,19 @@ import Link from 'next/link';
 import { useRipple } from 'react-use-ripple';
 import { UncontrolledTooltip } from 'reactstrap';
 
-import { HasChildren } from '~/interfaces/common';
 import {
   useIsSearchPage, useCurrentPagePath, useIsGuestUser, useIsSearchServiceConfigured, useAppTitle, useConfidential,
 } from '~/stores/context';
 import { usePageCreateModal } from '~/stores/modal';
 import { useIsDeviceSmallerThanMd } from '~/stores/ui';
 
+import { HasChildren } from '../../interfaces/common';
 import GrowiLogo from '../Icons/GrowiLogo';
 
 import PersonalDropdown from './PersonalDropdown';
 
 import styles from './GrowiNavbar.module.scss';
+import { GlobalSearchProps } from './GlobalSearch';
 
 
 const ShowSkeltonInSSR = memo(({ children }: HasChildren): JSX.Element => {
@@ -130,7 +131,7 @@ Confidential.displayName = 'Confidential';
 
 export const GrowiNavbar = (): JSX.Element => {
 
-  const GlobalSearch = dynamic(() => import('./GlobalSearch').then(mod => mod.GlobalSearch), { ssr: false });
+  const GlobalSearch = dynamic<GlobalSearchProps>(() => import('./GlobalSearch').then(mod => mod.GlobalSearch), { ssr: false });
 
   const { data: appTitle } = useAppTitle();
   const { data: confidential } = useConfidential();

+ 1 - 2
packages/app/src/components/Page/DisplaySwitcher.tsx

@@ -1,4 +1,4 @@
-import React, { useMemo } from 'react';
+import React from 'react';
 
 import { pagePathUtils } from '@growi/core';
 import { useTranslation } from 'next-i18next';
@@ -6,7 +6,6 @@ import dynamic from 'next/dynamic';
 import { TabContent, TabPane } from 'reactstrap';
 
 import { smoothScrollIntoView } from '~/client/util/smooth-scroll';
-import { isPopulated } from '~/interfaces/common';
 import {
   useCurrentPagePath, useIsSharedUser, useIsEditable, useIsUserPage, usePageUser, useShareLinkId, useIsNotFound, useIsNotCreatable,
 } from '~/stores/context';

+ 1 - 1
packages/app/src/components/Page/RevisionRenderer.tsx

@@ -47,7 +47,7 @@ const logger = loggerFactory('components:Page:RevisionRenderer');
 
 //   // for non-chrome browsers compatibility
 //   try {
-//     // eslint-disable-next-line regex/invalid
+// eslint-disable-next-line regex/invalid, max-len
 //     keywordRegexp2 = new RegExp(`(?<!<)${normalizedKeywords}(?!(.*?("|>)))`, 'ig'); // inferior (this doesn't work well when html tags exist a lot) https://regex101.com/r/Dfi61F/1
 //   }
 //   catch (err) {

+ 1 - 1
packages/app/src/components/PageAlert/TrashPageAlert.tsx

@@ -36,7 +36,7 @@ export const TrashPageAlert = (): JSX.Element => {
 
   const lastUpdateUserName = pageData?.lastUpdateUser.name;
   const deletedAt = pageData?.deletedAt ? format(new Date(pageData?.deletedAt), 'yyyy/MM/dd HH:mm') : '';
-  const revisionId = pageData?.revision._id;
+  const revisionId = pageData?.revision?._id;
 
   if (!isTrashPage) {
     return <></>;

+ 24 - 22
packages/app/src/components/PageComment/CommentEditor.tsx

@@ -100,28 +100,30 @@ const CommentEditor = (props: PropsType): JSX.Element => {
       parsedHTML: '',
     };
 
-    const interceptorManager: IInterceptorManager = (window as CustomWindow).interceptorManager;
-    interceptorManager.process('preRenderCommnetPreview', context)
-      .then(() => { return interceptorManager.process('prePreProcess', context) })
-      .then(() => {
-        context.markdown = rendererOptions.preProcess(context.markdown, context);
-      })
-      .then(() => { return interceptorManager.process('postPreProcess', context) })
-      .then(() => {
-        const parsedHTML = rendererOptions.process(context.markdown, context);
-        context.parsedHTML = parsedHTML;
-      })
-      .then(() => { return interceptorManager.process('prePostProcess', context) })
-      .then(() => {
-        context.parsedHTML = rendererOptions.postProcess(context.parsedHTML, context);
-      })
-      .then(() => { return interceptorManager.process('postPostProcess', context) })
-      .then(() => { return interceptorManager.process('preRenderCommentPreviewHtml', context) })
-      .then(() => {
-        setHtml(context.parsedHTML);
-      })
-      // process interceptors for post rendering
-      .then(() => { return interceptorManager.process('postRenderCommentPreviewHtml', context) });
+    // TODO: use ReactMarkdown
+
+    // const interceptorManager: IInterceptorManager = (window as CustomWindow).interceptorManager;
+    // interceptorManager.process('preRenderCommnetPreview', context)
+    //   .then(() => { return interceptorManager.process('prePreProcess', context) })
+    //   .then(() => {
+    //     context.markdown = rendererOptions.preProcess(context.markdown, context);
+    //   })
+    //   .then(() => { return interceptorManager.process('postPreProcess', context) })
+    //   .then(() => {
+    //     const parsedHTML = rendererOptions.process(context.markdown, context);
+    //     context.parsedHTML = parsedHTML;
+    //   })
+    //   .then(() => { return interceptorManager.process('prePostProcess', context) })
+    //   .then(() => {
+    //     context.parsedHTML = rendererOptions.postProcess(context.parsedHTML, context);
+    //   })
+    //   .then(() => { return interceptorManager.process('postPostProcess', context) })
+    //   .then(() => { return interceptorManager.process('preRenderCommentPreviewHtml', context) })
+    //   .then(() => {
+    //     setHtml(context.parsedHTML);
+    //   })
+    //   // process interceptors for post rendering
+    //   .then(() => { return interceptorManager.process('postRenderCommentPreviewHtml', context) });
   }, [rendererOptions]);
 
   const handleSelect = useCallback((activeTab: string) => {

+ 2 - 1
packages/app/src/components/PageContentFooter.tsx

@@ -1,6 +1,7 @@
 import React, { FC, memo } from 'react';
 
-import { Ref } from '../interfaces/common';
+import { Ref } from '@growi/core';
+
 import { IUser } from '../interfaces/user';
 
 import AuthorInfo from './Navbar/AuthorInfo';

+ 1 - 2
packages/app/src/components/PageDeleteModal.tsx

@@ -2,7 +2,7 @@ import React, {
   useState, FC, useMemo, useEffect,
 } from 'react';
 
-import { pagePathUtils } from '@growi/core';
+import { HasObjectId, pagePathUtils } from '@growi/core';
 import { useTranslation } from 'next-i18next';
 import {
   Modal, ModalHeader, ModalBody, ModalFooter,
@@ -10,7 +10,6 @@ import {
 
 import { apiPost } from '~/client/util/apiv1-client';
 import { apiv3Post } from '~/client/util/apiv3-client';
-import { HasObjectId } from '~/interfaces/has-object-id';
 import {
   IDeleteSinglePageApiv1Result, IDeleteManyPageApiv3Result, IPageToDeleteWithMeta, IDataWithMeta, isIPageInfoForEntity, IPageInfoForEntity,
 } from '~/interfaces/page';

+ 15 - 12
packages/app/src/components/PageEditor/Preview.tsx

@@ -47,19 +47,22 @@ const Preview = React.forwardRef((props: UnstatedProps, ref: RefObject<HTMLDivEl
   }, [markdown, pagePath, editorSettings?.renderDrawioInRealtime]);
 
   const renderPreview = useCallback(async() => {
-    if (interceptorManager != null) {
-      await interceptorManager.process('preRenderPreview', context);
-      await interceptorManager.process('prePreProcess', context);
-      context.markdown = rendererOptions.preProcess(context.markdown, context);
-      await interceptorManager.process('postPreProcess', context);
-      context.parsedHTML = rendererOptions.process(context.markdown, context);
-      await interceptorManager.process('prePostProcess', context);
-      context.parsedHTML = rendererOptions.postProcess(context.parsedHTML, context);
-      await interceptorManager.process('postPostProcess', context);
-      await interceptorManager.process('preRenderPreviewHtml', context);
-    }
 
-    setHtml(context.parsedHTML ?? '');
+    // TODO: use ReactMarkdown
+
+    // if (interceptorManager != null) {
+    //   await interceptorManager.process('preRenderPreview', context);
+    //   await interceptorManager.process('prePreProcess', context);
+    //   context.markdown = rendererOptions.preProcess(context.markdown, context);
+    //   await interceptorManager.process('postPreProcess', context);
+    //   context.parsedHTML = rendererOptions.process(context.markdown, context);
+    //   await interceptorManager.process('prePostProcess', context);
+    //   context.parsedHTML = rendererOptions.postProcess(context.parsedHTML, context);
+    //   await interceptorManager.process('postPostProcess', context);
+    //   await interceptorManager.process('preRenderPreviewHtml', context);
+    // }
+
+    // setHtml(context.parsedHTML ?? '');
   }, [context, rendererOptions]);
 
   useEffect(() => {

+ 1 - 2
packages/app/src/components/SavePageControls/GrantSelector.tsx

@@ -1,5 +1,6 @@
 import React, { useCallback, useState } from 'react';
 
+import { isPopulated } from '@growi/core';
 import { useTranslation } from 'next-i18next';
 import {
   UncontrolledDropdown,
@@ -8,8 +9,6 @@ import {
   Modal, ModalHeader, ModalBody,
 } from 'reactstrap';
 
-
-import { isPopulated } from '~/interfaces/common';
 import { IUserGroupHasId } from '~/interfaces/user';
 import { useCurrentUser } from '~/stores/context';
 import { useSWRxMyUserGroupRelations } from '~/stores/user-group';

+ 1 - 2
packages/app/src/components/Sidebar/PageTree/Item.tsx

@@ -4,7 +4,7 @@ import React, {
 
 import nodePath from 'path';
 
-import { pathUtils, pagePathUtils } from '@growi/core';
+import { pathUtils, pagePathUtils, Nullable } from '@growi/core';
 import { useTranslation } from 'next-i18next';
 import Link from 'next/link';
 import { useDrag, useDrop } from 'react-dnd';
@@ -14,7 +14,6 @@ import { bookmark, unbookmark, resumeRenameOperation } from '~/client/services/p
 import { toastWarning, toastError, toastSuccess } from '~/client/util/apiNotification';
 import { apiv3Put, apiv3Post } from '~/client/util/apiv3-client';
 import TriangleIcon from '~/components/Icons/TriangleIcon';
-import { Nullable } from '~/interfaces/common';
 import {
   IPageHasId, IPageInfoAll, IPageToDeleteWithMeta,
 } from '~/interfaces/page';

+ 1 - 1
packages/app/src/components/Sidebar/PageTree/ItemsTree.tsx

@@ -2,11 +2,11 @@ import React, {
   useEffect, useRef, useState, useMemo, useCallback,
 } from 'react';
 
+import { Nullable } from '@growi/core';
 import { useTranslation } from 'next-i18next';
 import { debounce } from 'throttle-debounce';
 
 import { toastError, toastSuccess } from '~/client/util/apiNotification';
-import { Nullable } from '~/interfaces/common';
 import { IPageHasId, IPageToDeleteWithMeta } from '~/interfaces/page';
 import { AncestorsChildrenResult, RootPageResult, TargetAndAncestors } from '~/interfaces/page-listing-results';
 import { OnDuplicatedFunction, OnDeletedFunction } from '~/interfaces/ui';

+ 1 - 4
packages/app/src/components/Sidebar/RecentChanges.tsx

@@ -2,15 +2,12 @@ import React, {
   memo, useCallback, useEffect, useState,
 } from 'react';
 
-import { DevidedPagePath } from '@growi/core';
+import { DevidedPagePath, isPopulated } from '@growi/core';
 import { UserPicture, FootstampIcon } from '@growi/ui';
 import { useTranslation } from 'next-i18next';
 import Link from 'next/link';
-import PropTypes from 'prop-types';
-
 
 import PagePathHierarchicalLink from '~/components/PagePathHierarchicalLink';
-import { isPopulated } from '~/interfaces/common';
 import { IPageHasId } from '~/interfaces/page';
 import LinkedPagePath from '~/models/linked-page-path';
 import { useSWRInifinitexRecentlyUpdated } from '~/stores/page-listing';

+ 1 - 2
packages/app/src/components/SubscribeButton.tsx

@@ -1,10 +1,9 @@
 import React, { FC, useCallback } from 'react';
 
+import { SubscriptionStatusType } from '@growi/core';
 import { useTranslation } from 'next-i18next';
 import { UncontrolledTooltip } from 'reactstrap';
 
-import { SubscriptionStatusType } from '~/interfaces/subscription';
-
 import styles from './SubscribeButton.module.scss';
 
 

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

@@ -1,5 +1,5 @@
-import { Ref } from './common';
-import { HasObjectId } from './has-object-id';
+import { Ref, HasObjectId } from '@growi/core';
+
 import { IUser } from './user';
 
 // Model

+ 1 - 11
packages/app/src/interfaces/attachment.ts

@@ -1,11 +1 @@
-import { Ref } from './common';
-import { IPage } from './page';
-import { IUser } from './user';
-
-export type IAttachment = {
-  page?: Ref<IPage>,
-  creator?: Ref<IUser>,
-
-  // virtual property
-  filePathProxied: string,
-};
+export type { IAttachment } from '@growi/core';

+ 2 - 2
packages/app/src/interfaces/comment.ts

@@ -1,5 +1,5 @@
-import { Nullable, Ref } from './common';
-import { HasObjectId } from './has-object-id';
+import { Nullable, Ref, HasObjectId } from '@growi/core';
+
 import { IPage } from './page';
 import { IRevision } from './revision';
 import { IUser } from './user';

+ 0 - 19
packages/app/src/interfaces/common.ts

@@ -4,25 +4,6 @@
 
 import { ReactNode } from 'react';
 
-import { HasObjectId } from './has-object-id';
-
-
-// Foreign key field
-export type Ref<T> = string | T & HasObjectId;
-
-export type Nullable<T> = T | null | undefined;
-
-export const isPopulated = <T>(ref: Ref<T>): ref is T & HasObjectId => {
-  return !(typeof ref === 'string');
-};
-
-export const getIdForRef = <T>(ref: Ref<T>): string => {
-  return isPopulated(ref)
-    ? ref._id
-    : ref;
-};
-
-
 export type HasChildren<T = ReactNode> = {
   children?: T
 }

+ 2 - 1
packages/app/src/interfaces/external-account.ts

@@ -1,4 +1,5 @@
-import { Ref } from '~/interfaces/common';
+import { Ref } from '@growi/core';
+
 import { IUser } from '~/interfaces/user';
 
 

+ 1 - 6
packages/app/src/interfaces/global.ts

@@ -1,13 +1,8 @@
 import EventEmitter from 'events';
 
-import GrowiRenderer from '~/services/renderer/growi-renderer';
-import Xss from '~/services/xss';
-
 import { IGraphViewer } from './graph-viewer';
 
 export type CustomWindow = Window
                          & typeof globalThis
                          & { globalEmitter: EventEmitter }
-                         & { GraphViewer: IGraphViewer }
-                         & { growiRenderer: GrowiRenderer }
-                         & { previewRenderer: GrowiRenderer }; // TODO: Remove this code when reveal.js is omitted. see: https://github.com/weseek/growi/pull/6223
+                         & { GraphViewer: IGraphViewer };

+ 1 - 1
packages/app/src/interfaces/page-grant.ts

@@ -5,7 +5,7 @@ export type IDataApplicableGroup = {
 }
 
 export type IDataApplicableGrant = null | IDataApplicableGroup;
-export type IRecordApplicableGrant = Record<PageGrant, IDataApplicableGrant>
+export type IRecordApplicableGrant = Partial<Record<PageGrant, IDataApplicableGrant>>
 export type IResApplicableGrant = {
   data?: IRecordApplicableGrant
 }

+ 10 - 116
packages/app/src/interfaces/page.ts

@@ -1,125 +1,19 @@
-import { Ref, Nullable } from './common';
-import { HasObjectId } from './has-object-id';
-import { IPageOperationProcessData } from './page-operation';
-import { IRevision, HasRevisionShortbody } from './revision';
-import { SubscriptionStatusType } from './subscription';
-import { ITag } from './tag';
-import { IUser } from './user';
-
+import { IPageHasId, Nullable } from '@growi/core';
 
-export interface IPage {
-  path: string,
-  status: string,
-  revision: Ref<IRevision>,
-  tags: Ref<ITag>[],
-  creator: any,
-  createdAt: Date,
-  updatedAt: Date,
-  seenUsers: Ref<IUser>[],
-  parent: Ref<IPage> | null,
-  descendantCount: number,
-  isEmpty: boolean,
-  grant: PageGrant,
-  grantedUsers: Ref<IUser>[],
-  grantedGroup: Ref<any>,
-  lastUpdateUser: Ref<IUser>,
-  liker: Ref<IUser>[],
-  commentCount: number
-  slackChannels: string,
-  pageIdOnHackmd: string,
-  revisionHackmdSynced: Ref<IRevision>,
-  hasDraftOnHackmd: boolean,
-  deleteUser: Ref<IUser>,
-  deletedAt: Date,
-  latestRevision?: Ref<IRevision>,
-}
+import { IPageOperationProcessData } from './page-operation';
 
-export const PageGrant = {
-  GRANT_PUBLIC: 1,
-  GRANT_RESTRICTED: 2,
-  GRANT_SPECIFIED: 3, // DEPRECATED
-  GRANT_OWNER: 4,
-  GRANT_USER_GROUP: 5,
-};
-export type PageGrant = typeof PageGrant[keyof typeof PageGrant];
+export { PageGrant } from '@growi/core';
+export type {
+  IPage, IPageHasId, IPageInfo, IPageInfoForEntity, IPageInfoForOperation, IPageInfoForListing, IPageInfoAll,
+  IDataWithMeta, IPageWithMeta, IPageToDeleteWithMeta, IPageToRenameWithMeta,
+} from '@growi/core';
 
-export type IPageHasId = IPage & HasObjectId;
+export {
+  isIPageInfoForEntity, isIPageInfoForOperation, isIPageInfoForListing,
+} from '@growi/core';
 
 export type IPageForItem = Partial<IPageHasId & {isTarget?: boolean, processData?: IPageOperationProcessData}>;
 
-export type IPageInfo = {
-  isV5Compatible: boolean,
-  isEmpty: boolean,
-  isMovable: boolean,
-  isDeletable: boolean,
-  isAbleToDeleteCompletely: boolean,
-  isRevertible: boolean,
-  contentAge?: number,
-}
-
-export type IPageInfoForEntity = IPageInfo & {
-  bookmarkCount?: number,
-  sumOfLikers?: number,
-  likerIds?: string[],
-  sumOfSeenUsers?: number,
-  seenUserIds?: string[],
-}
-
-export type IPageInfoForOperation = IPageInfoForEntity & {
-  isBookmarked?: boolean,
-  isLiked?: boolean,
-  subscriptionStatus?: SubscriptionStatusType,
-}
-
-export type IPageInfoForListing = IPageInfoForEntity & HasRevisionShortbody;
-
-export type IPageInfoAll = IPageInfo | IPageInfoForEntity | IPageInfoForOperation | IPageInfoForListing;
-
-// eslint-disable-next-line @typescript-eslint/no-explicit-any
-export const isIPageInfoForEntity = (pageInfo: any | undefined): pageInfo is IPageInfoForEntity => {
-  return pageInfo != null;
-};
-
-// eslint-disable-next-line @typescript-eslint/no-explicit-any
-export const isIPageInfoForOperation = (pageInfo: any | undefined): pageInfo is IPageInfoForOperation => {
-  return pageInfo != null
-    && isIPageInfoForEntity(pageInfo)
-    && ('isBookmarked' in pageInfo || 'isLiked' in pageInfo || 'subscriptionStatus' in pageInfo);
-};
-
-// eslint-disable-next-line @typescript-eslint/no-explicit-any
-export const isIPageInfoForListing = (pageInfo: any | undefined): pageInfo is IPageInfoForListing => {
-  return pageInfo != null
-    && isIPageInfoForEntity(pageInfo)
-    && 'revisionShortBody' in pageInfo;
-};
-
-// export type IPageInfoTypeResolver<T extends IPageInfo> =
-//   T extends HasRevisionShortbody ? IPageInfoForListing :
-//   T extends { isBookmarked?: boolean } | { isLiked?: boolean } | { subscriptionStatus?: SubscriptionStatusType } ? IPageInfoForOperation :
-//   T extends { bookmarkCount: number } ? IPageInfoForEntity :
-//   T extends { isEmpty: number } ? IPageInfo :
-//   T;
-
-/**
- * Union Distribution
- * @param pageInfo
- * @returns
- */
-// export const resolvePageInfo = <T extends IPageInfo>(pageInfo: T | undefined): IPageInfoTypeResolver<T> => {
-//   return <IPageInfoTypeResolver<T>>pageInfo;
-// };
-
-export type IDataWithMeta<D = unknown, M = unknown> = {
-  data: D,
-  meta?: M,
-}
-
-export type IPageWithMeta<M = IPageInfoAll> = IDataWithMeta<IPageHasId, M>;
-
-export type IPageToDeleteWithMeta<T = IPageInfoForEntity | unknown> = IDataWithMeta<HasObjectId & (IPage | { path: string, revision: string | null}), T>;
-export type IPageToRenameWithMeta<T = IPageInfoForEntity | unknown> = IPageToDeleteWithMeta<T>;
-
 export type IPageGrantData = {
   grant: number,
   grantedGroup?: {

+ 3 - 25
packages/app/src/interfaces/revision.ts

@@ -1,25 +1,3 @@
-import { IUser } from './user';
-
-export type IRevision = {
-  body: string,
-  author: IUser,
-  hasDiffToPrev: boolean;
-  createdAt: Date,
-  updatedAt: Date,
-}
-
-export type IRevisionsForPagination = {
-  revisions: IRevision[], // revisions in one pagination
-  totalCounts: number // total counts
-}
-
-export type IRevisionOnConflict = {
-  revisionId: string,
-  revisionBody: string,
-  createdAt: Date,
-  user: IUser
-}
-
-export type HasRevisionShortbody = {
-  revisionShortBody?: string,
-}
+export type {
+  IRevision, IRevisionsForPagination, IRevisionOnConflict, HasRevisionShortbody,
+} from '@growi/core';

+ 1 - 6
packages/app/src/interfaces/subscription.ts

@@ -1,6 +1 @@
-export const SubscriptionStatusType = {
-  SUBSCRIBE: 'SUBSCRIBE',
-  UNSUBSCRIBE: 'UNSUBSCRIBE',
-} as const;
-export const AllSubscriptionStatusType = Object.values(SubscriptionStatusType);
-export type SubscriptionStatusType = typeof SubscriptionStatusType[keyof typeof SubscriptionStatusType];
+export { SubscriptionStatusType, AllSubscriptionStatusType } from '@growi/core';

+ 3 - 6
packages/app/src/interfaces/tag.ts

@@ -1,20 +1,17 @@
+import { ITag } from '@growi/core';
+
 import { IPageHasId } from './page';
 
-export type ITag<ID = string> = {
-  _id: ID
-  name: string,
-}
+export type { ITag } from '@growi/core';
 
 export type IDataTagCount = ITag & {count: number}
 
-
 export type IPageTagsInfo = {
   tags : string[],
 }
 
 export type IListTagNamesByPage = string[];
 
-
 export type IResTagsUpdateApiv1 = {
   ok: boolean,
   savedPage: IPageHasId,

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

@@ -1,4 +1,4 @@
-import { Nullable } from './common';
+import { Nullable } from '@growi/core';
 
 export const SidebarContentsType = {
   CUSTOM: 'custom',

+ 2 - 2
packages/app/src/interfaces/user-ui-settings.ts

@@ -1,7 +1,7 @@
-import { IUser } from './user';
+import { Ref } from '@growi/core';
 
 import { SidebarContentsType } from './ui';
-import { Ref } from './common';
+import { IUser } from './user';
 
 export interface IUserUISettings {
   user: Ref<IUser> | null;

+ 3 - 37
packages/app/src/interfaces/user.ts

@@ -1,37 +1,3 @@
-import { IAttachment } from './attachment';
-import { Ref } from './common';
-import { HasObjectId } from './has-object-id';
-import { Lang } from './lang';
-
-export type IUser = {
-  name: string,
-  username: string,
-  email: string,
-  password: string,
-  image?: string, // for backward conpatibility
-  imageAttachment?: Ref<IAttachment>,
-  imageUrlCached: string,
-  isGravatarEnabled: boolean,
-  admin: boolean,
-  apiToken?: string,
-  isEmailPublished: boolean,
-  lang: Lang,
-  slackMemberId?: string,
-}
-
-export type IUserGroupRelation = {
-  relatedGroup: Ref<IUserGroup>,
-  relatedUser: Ref<IUser>,
-  createdAt: Date,
-}
-
-export type IUserGroup = {
-  name: string;
-  createdAt: Date;
-  description: string;
-  parent: Ref<IUserGroupHasId> | null;
-}
-
-export type IUserHasId = IUser & HasObjectId;
-export type IUserGroupHasId = IUserGroup & HasObjectId;
-export type IUserGroupRelationHasId = IUserGroupRelation & HasObjectId;
+export type {
+  IUser, IUserGroupRelation, IUserGroup, IUserHasId, IUserGroupHasId, IUserGroupRelationHasId,
+} from '@growi/core';

+ 1 - 3
packages/app/src/next-i18next.config.ts

@@ -1,12 +1,10 @@
 import path from 'path';
 
-import { isServer } from '@growi/core';
+import { isServer, AllLang, Lang } from '@growi/core';
 import I18nextChainedBackend from 'i18next-chained-backend';
 import I18NextHttpBackend from 'i18next-http-backend';
 import I18NextLocalStorageBackend from 'i18next-localstorage-backend';
 
-import { AllLang, Lang } from './interfaces/lang';
-
 const isDev = process.env.NODE_ENV === 'development';
 
 export const i18n = {

+ 10 - 9
packages/app/src/pages/[[...path]].page.tsx

@@ -2,7 +2,9 @@ import React, { useEffect } from 'react';
 
 import EventEmitter from 'events';
 
-import { isClient, pagePathUtils, pathUtils } from '@growi/core';
+import {
+  IDataWithMeta, IPageInfoForEntity, IPagePopulatedToShowRevision, isClient, pagePathUtils, pathUtils,
+} from '@growi/core';
 import ExtensibleCustomError from 'extensible-custom-error';
 import {
   NextPage, GetServerSideProps, GetServerSidePropsContext,
@@ -21,7 +23,6 @@ import { CrowiRequest } from '~/interfaces/crowi-request';
 // import { useRendererSettings } from '~/stores/renderer';
 // import { EditorMode, useEditorMode, useIsMobile } from '~/stores/ui';
 import { CustomWindow } from '~/interfaces/global';
-import { IPageWithMeta } from '~/interfaces/page';
 import { RendererConfig } from '~/interfaces/services/renderer';
 import { ISidebarConfig } from '~/interfaces/sidebar-config';
 import { PageModel, PageDocument } from '~/server/models/page';
@@ -77,6 +78,7 @@ const IdenticalPathPage = (): JSX.Element => {
   return <IdenticalPathPage />;
 };
 
+type IPageToShowRevisionWithMeta = IDataWithMeta<IPagePopulatedToShowRevision, IPageInfoForEntity>;
 
 type Props = CommonProps & {
   currentUser: string,
@@ -164,10 +166,9 @@ const GrowiPage: NextPage<Props> = (props: Props) => {
   // useIsTrashPage(_isTrashPage(props.currentPagePath));
   // useShared();
   // useShareLinkId(props.shareLinkId);
-  useIsSharedUser(props.currentUser == null); // '/shared' is not routed this page
+  useIsSharedUser(false); // this page cann't be routed for '/share'
   useIsIdenticalPath(false); // TODO: need to initialize from props
   // useIsAbleToDeleteCompletely(props.isAbleToDeleteCompletely);
-  useIsSharedUser(false); // this page cann't be routed for '/share'
   useIsEnabledStaleNotification(props.isEnabledStaleNotification);
   useIsBlinkedHeaderAtBoot(false);
 
@@ -193,9 +194,9 @@ const GrowiPage: NextPage<Props> = (props: Props) => {
 
   // const { data: editorMode } = useEditorMode();
 
-  let pageWithMeta: IPageWithMeta | undefined;
+  let pageWithMeta: IPageToShowRevisionWithMeta | undefined;
   if (props.pageWithMetaStr != null) {
-    pageWithMeta = JSON.parse(props.pageWithMetaStr) as IPageWithMeta;
+    pageWithMeta = JSON.parse(props.pageWithMetaStr) as IPageToShowRevisionWithMeta;
   }
   useCurrentPageId(pageWithMeta?.data._id);
   useSWRxCurrentPage(undefined, pageWithMeta?.data); // store initial data
@@ -312,7 +313,7 @@ class MultiplePagesHitsError extends ExtensibleCustomError {
 
 }
 
-async function getPageData(context: GetServerSidePropsContext, props: Props): Promise<IPageWithMeta|null> {
+async function getPageData(context: GetServerSidePropsContext, props: Props): Promise<IPageToShowRevisionWithMeta|null> {
   const req: CrowiRequest = context.req as CrowiRequest;
   const { crowi } = req;
   const { revisionId } = req.query;
@@ -335,7 +336,7 @@ async function getPageData(context: GetServerSidePropsContext, props: Props): Pr
     }
   }
 
-  const result: IPageWithMeta = await pageService.findPageAndMetaDataByViewer(pageId, currentPathname, user, true); // includeEmpty = true, isSharedPage = false
+  const result: IPageToShowRevisionWithMeta = await pageService.findPageAndMetaDataByViewer(pageId, currentPathname, user, true); // includeEmpty = true, isSharedPage = false
   const page = result?.data as unknown as PageDocument;
 
   // populate & check if the revision is latest
@@ -348,7 +349,7 @@ async function getPageData(context: GetServerSidePropsContext, props: Props): Pr
   return result;
 }
 
-async function injectRoutingInformation(context: GetServerSidePropsContext, props: Props, pageWithMeta: IPageWithMeta|null): Promise<void> {
+async function injectRoutingInformation(context: GetServerSidePropsContext, props: Props, pageWithMeta: IPageToShowRevisionWithMeta|null): Promise<void> {
   const req: CrowiRequest = context.req as CrowiRequest;
   const { crowi } = req;
   const Page = crowi.model('Page') as PageModel;

+ 1 - 2
packages/app/src/pages/commons.ts

@@ -1,9 +1,8 @@
-import { DevidedPagePath } from '@growi/core';
+import { DevidedPagePath, Lang } from '@growi/core';
 import { GetServerSideProps, GetServerSidePropsContext } from 'next';
 import { SSRConfig, UserConfig } from 'next-i18next';
 
 import { CrowiRequest } from '~/interfaces/crowi-request';
-import { Lang } from '~/interfaces/lang';
 
 import * as nextI18NextConfig from '../next-i18next.config';
 

+ 6 - 5
packages/app/src/server/models/password-reset-order.ts

@@ -1,11 +1,12 @@
+import crypto from 'crypto';
+
+import { getOrCreateModel } from '@growi/core';
+import { addMinutes } from 'date-fns';
 import mongoose, {
   Schema, Model, Document,
 } from 'mongoose';
-
-import { addMinutes } from 'date-fns';
 import uniqueValidator from 'mongoose-unique-validator';
-import crypto from 'crypto';
-import { getOrCreateModel } from '@growi/core';
+
 
 const ObjectId = mongoose.Schema.Types.ObjectId;
 
@@ -20,7 +21,7 @@ export interface IPasswordResetOrder {
 }
 
 export interface PasswordResetOrderDocument extends IPasswordResetOrder, Document {
-  isExpired(): Promise<boolean>
+  isExpired(): boolean
   revokeOneTimeToken(): Promise<void>
 }
 

+ 1 - 2
packages/app/src/server/models/subscription.ts

@@ -1,10 +1,9 @@
-import { getOrCreateModel } from '@growi/core';
+import { getOrCreateModel, SubscriptionStatusType, AllSubscriptionStatusType } from '@growi/core';
 import {
   Types, Document, Model, Schema,
 } from 'mongoose';
 
 import { AllSupportedTargetModels } from '~/interfaces/activity';
-import { SubscriptionStatusType, AllSubscriptionStatusType } from '~/interfaces/subscription';
 
 
 export interface ISubscription {

+ 1 - 1
packages/app/src/server/models/user-registration-order.ts

@@ -17,7 +17,7 @@ export interface IUserRegistrationOrder {
 }
 
 export interface UserRegistrationOrderDocument extends IUserRegistrationOrder, Document {
-  isExpired(): Promise<boolean>
+  isExpired(): boolean
   revokeOneTimeToken(): Promise<void>
 }
 

+ 1 - 2
packages/app/src/server/routes/apiv3/page.js

@@ -1,7 +1,6 @@
-import { pagePathUtils } from '@growi/core';
+import { pagePathUtils, AllSubscriptionStatusType, SubscriptionStatusType } from '@growi/core';
 
 import { SupportedAction, SupportedTargetModel } from '~/interfaces/activity';
-import { AllSubscriptionStatusType, SubscriptionStatusType } from '~/interfaces/subscription';
 import { generateAddActivityMiddleware } from '~/server/middlewares/add-activity';
 import Subscription from '~/server/models/subscription';
 import UserGroup from '~/server/models/user-group';

+ 1 - 2
packages/app/src/server/service/in-app-notification.ts

@@ -1,11 +1,10 @@
+import { HasObjectId, SubscriptionStatusType } from '@growi/core';
 import { subDays } from 'date-fns';
 import { Types } from 'mongoose';
 
 import { AllEssentialActions, SupportedAction } from '~/interfaces/activity';
-import { HasObjectId } from '~/interfaces/has-object-id';
 import { InAppNotificationStatuses, PaginateResult } from '~/interfaces/in-app-notification';
 import { IPage } from '~/interfaces/page';
-import { SubscriptionStatusType } from '~/interfaces/subscription';
 import { IUser } from '~/interfaces/user';
 import { stringifySnapshot } from '~/models/serializers/in-app-notification-snapshot/page';
 import { ActivityDocument } from '~/server/models/activity';

+ 1 - 2
packages/app/src/server/service/installer.ts

@@ -1,11 +1,10 @@
 import path from 'path';
 
+import { Lang } from '@growi/core';
 import ExtensibleCustomError from 'extensible-custom-error';
 import fs from 'graceful-fs';
 import mongoose from 'mongoose';
 
-
-import { Lang } from '~/interfaces/lang';
 import { IPage } from '~/interfaces/page';
 import { IUser } from '~/interfaces/user';
 import loggerFactory from '~/utils/logger';

+ 3 - 3
packages/app/src/server/service/page.ts

@@ -1,14 +1,14 @@
 import pathlib from 'path';
 import { Readable, Writable } from 'stream';
 
-import { pagePathUtils, pathUtils } from '@growi/core';
+import {
+  pagePathUtils, pathUtils, Ref, HasObjectId,
+} from '@growi/core';
 import escapeStringRegexp from 'escape-string-regexp';
 import mongoose, { ObjectId, QueryCursor } from 'mongoose';
 import streamToPromise from 'stream-to-promise';
 
-import { Ref } from '~/interfaces/common';
 import { V5ConversionErrCode } from '~/interfaces/errors/v5-conversion-error';
-import { HasObjectId } from '~/interfaces/has-object-id';
 import {
   IPage, IPageInfo, IPageInfoForEntity, IPageWithMeta,
 } from '~/interfaces/page';

+ 1 - 1
packages/app/src/stores/comment.tsx

@@ -1,9 +1,9 @@
+import { Nullable } from '@growi/core';
 import useSWR, { SWRResponse } from 'swr';
 
 import { apiGet, apiPost } from '~/client/util/apiv1-client';
 
 import { ICommentHasIdList, ICommentPostArgs } from '../interfaces/comment';
-import { Nullable } from '../interfaces/common';
 
 type IResponseComment = {
   comments: ICommentHasIdList,

+ 2 - 2
packages/app/src/stores/context.tsx

@@ -106,8 +106,8 @@ export const useTemplateTagData = (initialData?: Nullable<string>): SWRResponse<
   return useStaticSWR<Nullable<string>, Error>('templateTagData', initialData);
 };
 
-export const useIsSharedUser = (initialData?: Nullable<boolean>): SWRResponse<Nullable<boolean>, Error> => {
-  return useStaticSWR<Nullable<boolean>, Error>('isSharedUser', initialData);
+export const useIsSharedUser = (initialData?: boolean): SWRResponse<boolean, Error> => {
+  return useStaticSWR<boolean, Error>('isSharedUser', initialData);
 };
 
 export const useShareLinksNumber = (initialData?: Nullable<any>): SWRResponse<Nullable<any>, Error> => {

+ 1 - 1
packages/app/src/stores/editor.tsx

@@ -1,9 +1,9 @@
+import { Nullable } from '@growi/core';
 import useSWR, { SWRResponse } from 'swr';
 import useSWRImmutable from 'swr/immutable';
 
 import { apiGet } from '~/client/util/apiv1-client';
 import { apiv3Get, apiv3Put } from '~/client/util/apiv3-client';
-import { Nullable } from '~/interfaces/common';
 import { IEditorSettings } from '~/interfaces/editor-settings';
 import { SlackChannels } from '~/interfaces/user-trigger-notification';
 

+ 1 - 2
packages/app/src/stores/page-listing.tsx

@@ -1,9 +1,8 @@
+import { Nullable, HasObjectId } from '@growi/core';
 import useSWR, { SWRResponse } from 'swr';
 import useSWRImmutable from 'swr/immutable';
 import useSWRInfinite, { SWRInfiniteResponse } from 'swr/infinite';
 
-import { Nullable } from '~/interfaces/common';
-import { HasObjectId } from '~/interfaces/has-object-id';
 import {
   IDataWithMeta, IPageHasId, IPageInfoForListing, IPageInfoForOperation,
 } from '~/interfaces/page';

+ 7 - 7
packages/app/src/stores/page.tsx

@@ -1,34 +1,34 @@
+import { IPagePopulatedToShowRevision, Nullable } from '@growi/core';
 import useSWR, { SWRResponse } from 'swr';
 import useSWRImmutable from 'swr/immutable';
 
 import { apiv3Get } from '~/client/util/apiv3-client';
 import {
-  IPageInfo, IPageHasId, IPageInfoForOperation, IPageInfoAll,
+  IPageInfo, IPageInfoForOperation, IPageInfoAll,
 } from '~/interfaces/page';
 import { IRecordApplicableGrant, IResIsGrantNormalized } from '~/interfaces/page-grant';
 import { IRevisionsForPagination } from '~/interfaces/revision';
 
 import { apiGet } from '../client/util/apiv1-client';
-import { Nullable } from '../interfaces/common';
 import { IPageTagsInfo } from '../interfaces/tag';
 
 import { useCurrentPageId } from './context';
 
-export const useSWRxPage = (pageId?: string|null, shareLinkId?: string): SWRResponse<IPageHasId, Error> => {
-  return useSWR<IPageHasId, Error>(
+export const useSWRxPage = (pageId?: string|null, shareLinkId?: string): SWRResponse<IPagePopulatedToShowRevision, Error> => {
+  return useSWR<IPagePopulatedToShowRevision, Error>(
     pageId != null ? ['/page', pageId, shareLinkId] : null,
     (endpoint, pageId, shareLinkId) => apiv3Get(endpoint, { pageId, shareLinkId }).then(result => result.data.page),
   );
 };
 
-export const useSWRxPageByPath = (path?: string): SWRResponse<IPageHasId, Error> => {
-  return useSWR<IPageHasId, Error>(
+export const useSWRxPageByPath = (path?: string): SWRResponse<IPagePopulatedToShowRevision, Error> => {
+  return useSWR<IPagePopulatedToShowRevision, Error>(
     path != null ? ['/page', path] : null,
     (endpoint, path) => apiv3Get(endpoint, { path }).then(result => result.data.page),
   );
 };
 
-export const useSWRxCurrentPage = (shareLinkId?: string, initialData?: IPageHasId): SWRResponse<IPageHasId, Error> => {
+export const useSWRxCurrentPage = (shareLinkId?: string, initialData?: IPagePopulatedToShowRevision): SWRResponse<IPagePopulatedToShowRevision, Error> => {
   const { data: currentPageId } = useCurrentPageId();
 
   const swrResult = useSWRxPage(currentPageId, shareLinkId);

+ 3 - 2
packages/app/src/stores/ui.tsx

@@ -1,6 +1,8 @@
 import { RefObject } from 'react';
 
-import { isClient, isServer, pagePathUtils } from '@growi/core';
+import {
+  isClient, isServer, pagePathUtils, Nullable,
+} from '@growi/core';
 import { Breakpoint, addBreakpointListener } from '@growi/ui';
 import SimpleBar from 'simplebar-react';
 import {
@@ -11,7 +13,6 @@ import useSWRImmutable from 'swr/immutable';
 import { IFocusable } from '~/client/interfaces/focusable';
 import { useUserUISettings } from '~/client/services/user-ui-settings';
 import { apiv3Get, apiv3Put } from '~/client/util/apiv3-client';
-import { Nullable } from '~/interfaces/common';
 import { ISidebarConfig } from '~/interfaces/sidebar-config';
 import { SidebarContentsType } from '~/interfaces/ui';
 import { UpdateDescCountData } from '~/interfaces/websocket';

+ 0 - 22
packages/core/src/index.js

@@ -1,22 +0,0 @@
-import * as _customTagUtils from './plugin/util/custom-tag-utils';
-import * as _envUtils from './utils/env-utils';
-import * as _pagePathUtils from './utils/page-path-utils';
-import * as _pageUtils from './utils/page-utils';
-import * as _pathUtils from './utils/path-utils';
-import * as _templateChecker from './utils/template-checker';
-
-// export utils
-export const pathUtils = _pathUtils;
-export const envUtils = _envUtils;
-export const pagePathUtils = _pagePathUtils;
-export const pageUtils = _pageUtils;
-export const templateChecker = _templateChecker;
-export const customTagUtils = _customTagUtils;
-
-export * from './plugin/interfaces/plugin-definition-v4';
-export * from './plugin/service/tag-cache-manager';
-export * from './models/devided-page-path';
-export * from './service/localstorage-manager';
-export * from './utils/basic-interceptor';
-export * from './utils/browser-utils';
-export * from './utils/mongoose-utils';

+ 29 - 0
packages/core/src/index.ts

@@ -0,0 +1,29 @@
+import * as _customTagUtils from './plugin/util/custom-tag-utils';
+import * as _envUtils from './utils/env-utils';
+
+// export utils by *.js
+export const envUtils = _envUtils;
+export const customTagUtils = _customTagUtils;
+
+// export utils
+export * as templateChecker from './utils/template-checker';
+export * as pagePathUtils from './utils/page-path-utils';
+export * as pathUtils from './utils/path-utils';
+export * as pageUtils from './utils/page-utils';
+
+export * from './interfaces/attachment';
+export * from './interfaces/common';
+export * from './interfaces/has-object-id';
+export * from './interfaces/lang';
+export * from './interfaces/page';
+export * from './interfaces/revision';
+export * from './interfaces/subscription';
+export * from './interfaces/tag';
+export * from './interfaces/user';
+export * from './plugin/interfaces/plugin-definition-v4';
+export * from './plugin/service/tag-cache-manager';
+export * from './models/devided-page-path';
+export * from './service/localstorage-manager';
+export * from './utils/basic-interceptor';
+export * from './utils/browser-utils';
+export * from './utils/mongoose-utils';

+ 11 - 0
packages/core/src/interfaces/attachment.ts

@@ -0,0 +1,11 @@
+import { Ref } from './common';
+import { IPage } from './page';
+import { IUser } from './user';
+
+export type IAttachment = {
+  page?: Ref<IPage>,
+  creator?: Ref<IUser>,
+
+  // virtual property
+  filePathProxied: string,
+};

+ 21 - 0
packages/core/src/interfaces/common.ts

@@ -0,0 +1,21 @@
+/*
+ * Common types and interfaces
+ */
+
+import { HasObjectId } from './has-object-id';
+
+
+// Foreign key field
+export type Ref<T> = string | T & HasObjectId;
+
+export type Nullable<T> = T | null | undefined;
+
+export const isPopulated = <T>(ref: Ref<T>): ref is T & HasObjectId => {
+  return !(typeof ref === 'string');
+};
+
+export const getIdForRef = <T>(ref: Ref<T>): string => {
+  return isPopulated(ref)
+    ? ref._id
+    : ref;
+};

+ 0 - 0
packages/app/src/interfaces/has-object-id.ts → packages/core/src/interfaces/has-object-id.ts


+ 0 - 0
packages/app/src/interfaces/lang.ts → packages/core/src/interfaces/lang.ts


+ 131 - 0
packages/core/src/interfaces/page.ts

@@ -0,0 +1,131 @@
+import { Ref } from './common';
+import { HasObjectId } from './has-object-id';
+import { IRevision, HasRevisionShortbody, IRevisionHasId } from './revision';
+import { SubscriptionStatusType } from './subscription';
+import { ITag } from './tag';
+import { IUser, IUserGroupHasId, IUserHasId } from './user';
+
+
+export type IPage = {
+  path: string,
+  status: string,
+  revision: Ref<IRevision>,
+  tags: Ref<ITag>[],
+  creator: any,
+  createdAt: Date,
+  updatedAt: Date,
+  seenUsers: Ref<IUser>[],
+  parent: Ref<IPage> | null,
+  descendantCount: number,
+  isEmpty: boolean,
+  grant: PageGrant,
+  grantedUsers: Ref<IUser>[],
+  grantedGroup: Ref<any>,
+  lastUpdateUser: Ref<IUser>,
+  liker: Ref<IUser>[],
+  commentCount: number
+  slackChannels: string,
+  pageIdOnHackmd: string,
+  revisionHackmdSynced: Ref<IRevision>,
+  hasDraftOnHackmd: boolean,
+  deleteUser: Ref<IUser>,
+  deletedAt: Date,
+  latestRevision?: Ref<IRevision>,
+}
+
+export type IPagePopulatedToList = Omit<IPageHasId, 'lastUpdateUser'> & {
+  lastUpdateUser: IUserHasId,
+}
+
+export type IPagePopulatedToShowRevision = Omit<IPageHasId, 'lastUpdateUser'|'creator'|'deleteUser'|'grantedGroup'|'revision'|'author'> & {
+  lastUpdateUser: IUserHasId,
+  creator: IUserHasId,
+  deleteUser: IUserHasId,
+  grantedGroup: IUserGroupHasId,
+  revision: IRevisionHasId,
+  author: IUserHasId,
+}
+
+export const PageGrant = {
+  GRANT_PUBLIC: 1,
+  GRANT_RESTRICTED: 2,
+  GRANT_SPECIFIED: 3, // DEPRECATED
+  GRANT_OWNER: 4,
+  GRANT_USER_GROUP: 5,
+} as const;
+export type PageGrant = typeof PageGrant[keyof typeof PageGrant];
+
+export type IPageHasId = IPage & HasObjectId;
+
+export type IPageInfo = {
+  isV5Compatible: boolean,
+  isEmpty: boolean,
+  isMovable: boolean,
+  isDeletable: boolean,
+  isAbleToDeleteCompletely: boolean,
+  isRevertible: boolean,
+  contentAge?: number,
+}
+
+export type IPageInfoForEntity = IPageInfo & {
+  bookmarkCount?: number,
+  sumOfLikers?: number,
+  likerIds?: string[],
+  sumOfSeenUsers?: number,
+  seenUserIds?: string[],
+}
+
+export type IPageInfoForOperation = IPageInfoForEntity & {
+  isBookmarked?: boolean,
+  isLiked?: boolean,
+  subscriptionStatus?: SubscriptionStatusType,
+}
+
+export type IPageInfoForListing = IPageInfoForEntity & HasRevisionShortbody;
+
+export type IPageInfoAll = IPageInfo | IPageInfoForEntity | IPageInfoForOperation | IPageInfoForListing;
+
+// eslint-disable-next-line @typescript-eslint/no-explicit-any
+export const isIPageInfoForEntity = (pageInfo: any | undefined): pageInfo is IPageInfoForEntity => {
+  return pageInfo != null;
+};
+
+// eslint-disable-next-line @typescript-eslint/no-explicit-any
+export const isIPageInfoForOperation = (pageInfo: any | undefined): pageInfo is IPageInfoForOperation => {
+  return pageInfo != null
+    && isIPageInfoForEntity(pageInfo)
+    && ('isBookmarked' in pageInfo || 'isLiked' in pageInfo || 'subscriptionStatus' in pageInfo);
+};
+
+// eslint-disable-next-line @typescript-eslint/no-explicit-any
+export const isIPageInfoForListing = (pageInfo: any | undefined): pageInfo is IPageInfoForListing => {
+  return pageInfo != null
+    && isIPageInfoForEntity(pageInfo)
+    && 'revisionShortBody' in pageInfo;
+};
+
+// export type IPageInfoTypeResolver<T extends IPageInfo> =
+//   T extends HasRevisionShortbody ? IPageInfoForListing :
+//   T extends { isBookmarked?: boolean } | { isLiked?: boolean } | { subscriptionStatus?: SubscriptionStatusType } ? IPageInfoForOperation :
+//   T extends { bookmarkCount: number } ? IPageInfoForEntity :
+//   T extends { isEmpty: number } ? IPageInfo :
+//   T;
+
+/**
+ * Union Distribution
+ * @param pageInfo
+ * @returns
+ */
+// export const resolvePageInfo = <T extends IPageInfo>(pageInfo: T | undefined): IPageInfoTypeResolver<T> => {
+//   return <IPageInfoTypeResolver<T>>pageInfo;
+// };
+
+export type IDataWithMeta<D = unknown, M = unknown> = {
+  data: D,
+  meta?: M,
+}
+
+export type IPageWithMeta<M = IPageInfoAll> = IDataWithMeta<IPageHasId, M>;
+
+export type IPageToDeleteWithMeta<T = IPageInfoForEntity | unknown> = IDataWithMeta<HasObjectId & (IPage | { path: string, revision: string | null}), T>;
+export type IPageToRenameWithMeta<T = IPageInfoForEntity | unknown> = IPageToDeleteWithMeta<T>;

+ 28 - 0
packages/core/src/interfaces/revision.ts

@@ -0,0 +1,28 @@
+import { HasObjectId } from './has-object-id';
+import { IUser } from './user';
+
+export type IRevision = {
+  body: string,
+  author: IUser,
+  hasDiffToPrev: boolean;
+  createdAt: Date,
+  updatedAt: Date,
+}
+
+export type IRevisionHasId = IRevision & HasObjectId;
+
+export type IRevisionsForPagination = {
+  revisions: IRevision[], // revisions in one pagination
+  totalCounts: number // total counts
+}
+
+export type IRevisionOnConflict = {
+  revisionId: string,
+  revisionBody: string,
+  createdAt: Date,
+  user: IUser
+}
+
+export type HasRevisionShortbody = {
+  revisionShortBody?: string,
+}

+ 6 - 0
packages/core/src/interfaces/subscription.ts

@@ -0,0 +1,6 @@
+export const SubscriptionStatusType = {
+  SUBSCRIBE: 'SUBSCRIBE',
+  UNSUBSCRIBE: 'UNSUBSCRIBE',
+} as const;
+export const AllSubscriptionStatusType = Object.values(SubscriptionStatusType);
+export type SubscriptionStatusType = typeof SubscriptionStatusType[keyof typeof SubscriptionStatusType];

+ 4 - 0
packages/core/src/interfaces/tag.ts

@@ -0,0 +1,4 @@
+export type ITag<ID = string> = {
+  _id: ID
+  name: string,
+}

+ 37 - 0
packages/core/src/interfaces/user.ts

@@ -0,0 +1,37 @@
+import { IAttachment } from './attachment';
+import { Ref } from './common';
+import { HasObjectId } from './has-object-id';
+import { Lang } from './lang';
+
+export type IUser = {
+  name: string,
+  username: string,
+  email: string,
+  password: string,
+  image?: string, // for backward conpatibility
+  imageAttachment?: Ref<IAttachment>,
+  imageUrlCached: string,
+  isGravatarEnabled: boolean,
+  admin: boolean,
+  apiToken?: string,
+  isEmailPublished: boolean,
+  lang: Lang,
+  slackMemberId?: string,
+}
+
+export type IUserGroupRelation = {
+  relatedGroup: Ref<IUserGroup>,
+  relatedUser: Ref<IUser>,
+  createdAt: Date,
+}
+
+export type IUserGroup = {
+  name: string;
+  createdAt: Date;
+  description: string;
+  parent: Ref<IUserGroupHasId> | null;
+}
+
+export type IUserHasId = IUser & HasObjectId;
+export type IUserGroupHasId = IUserGroup & HasObjectId;
+export type IUserGroupRelationHasId = IUserGroupRelation & HasObjectId;

+ 1 - 2
packages/ui/src/components/PagePath/PageListMeta.tsx

@@ -2,8 +2,7 @@ import React, { FC } from 'react';
 
 import assert from 'assert';
 
-import { IPageHasId } from '@growi/app/src/interfaces/page';
-import { templateChecker, pagePathUtils } from '@growi/core';
+import { templateChecker, pagePathUtils, IPageHasId } from '@growi/core';
 
 import { FootstampIcon } from '../SearchPage/FootstampIcon';