Răsfoiți Sursa

move some interfaces under @growi/core

Yuki Takei 3 ani în urmă
părinte
comite
c506979092
53 a modificat fișierele cu 316 adăugiri și 307 ștergeri
  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. 1 2
      packages/app/src/components/Navbar/GrowiContextualSubNavigation.tsx
  7. 1 1
      packages/app/src/components/Navbar/GrowiNavbar.tsx
  8. 1 2
      packages/app/src/components/Page/DisplaySwitcher.tsx
  9. 1 1
      packages/app/src/components/Page/RevisionRenderer.tsx
  10. 2 1
      packages/app/src/components/PageContentFooter.tsx
  11. 1 2
      packages/app/src/components/PageDeleteModal.tsx
  12. 1 2
      packages/app/src/components/SavePageControls/GrantSelector.tsx
  13. 1 2
      packages/app/src/components/Sidebar/PageTree/Item.tsx
  14. 1 1
      packages/app/src/components/Sidebar/PageTree/ItemsTree.tsx
  15. 1 4
      packages/app/src/components/Sidebar/RecentChanges.tsx
  16. 1 2
      packages/app/src/components/SubscribeButton.tsx
  17. 2 2
      packages/app/src/interfaces/activity.ts
  18. 1 11
      packages/app/src/interfaces/attachment.ts
  19. 2 2
      packages/app/src/interfaces/comment.ts
  20. 0 19
      packages/app/src/interfaces/common.ts
  21. 2 1
      packages/app/src/interfaces/external-account.ts
  22. 1 6
      packages/app/src/interfaces/global.ts
  23. 9 116
      packages/app/src/interfaces/page.ts
  24. 3 25
      packages/app/src/interfaces/revision.ts
  25. 1 6
      packages/app/src/interfaces/subscription.ts
  26. 3 6
      packages/app/src/interfaces/tag.ts
  27. 1 1
      packages/app/src/interfaces/ui.ts
  28. 2 2
      packages/app/src/interfaces/user-ui-settings.ts
  29. 3 37
      packages/app/src/interfaces/user.ts
  30. 1 3
      packages/app/src/next-i18next.config.ts
  31. 1 2
      packages/app/src/pages/commons.ts
  32. 1 2
      packages/app/src/server/models/subscription.ts
  33. 1 2
      packages/app/src/server/routes/apiv3/page.js
  34. 1 2
      packages/app/src/server/service/in-app-notification.ts
  35. 1 2
      packages/app/src/server/service/installer.ts
  36. 3 3
      packages/app/src/server/service/page.ts
  37. 1 1
      packages/app/src/stores/comment.tsx
  38. 1 1
      packages/app/src/stores/editor.tsx
  39. 1 2
      packages/app/src/stores/page-listing.tsx
  40. 1 1
      packages/app/src/stores/page.tsx
  41. 3 2
      packages/app/src/stores/ui.tsx
  42. 0 22
      packages/core/src/index.js
  43. 29 0
      packages/core/src/index.ts
  44. 11 0
      packages/core/src/interfaces/attachment.ts
  45. 21 0
      packages/core/src/interfaces/common.ts
  46. 0 0
      packages/core/src/interfaces/has-object-id.ts
  47. 0 0
      packages/core/src/interfaces/lang.ts
  48. 118 0
      packages/core/src/interfaces/page.ts
  49. 25 0
      packages/core/src/interfaces/revision.ts
  50. 6 0
      packages/core/src/interfaces/subscription.ts
  51. 4 0
      packages/core/src/interfaces/tag.ts
  52. 37 0
      packages/core/src/interfaces/user.ts
  53. 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';

+ 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';

+ 1 - 1
packages/app/src/components/Navbar/GrowiNavbar.tsx

@@ -9,13 +9,13 @@ 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';

+ 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) {

+ 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';

+ 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 };

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

@@ -1,125 +1,18 @@
-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 type {
+  IPage, IPageHasId, PageGrant, 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 = {

+ 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';
 

+ 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 - 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,

+ 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';

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

@@ -1,3 +1,4 @@
+import { Nullable } from '@growi/core';
 import useSWR, { SWRResponse } from 'swr';
 import useSWRImmutable from 'swr/immutable';
 
@@ -9,7 +10,6 @@ import { IRecordApplicableGrant, IResIsGrantNormalized } from '~/interfaces/page
 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';

+ 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


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

@@ -0,0 +1,118 @@
+import { Ref } from './common';
+import { HasObjectId } from './has-object-id';
+import { IRevision, HasRevisionShortbody } from './revision';
+import { SubscriptionStatusType } from './subscription';
+import { ITag } from './tag';
+import { IUser } from './user';
+
+
+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>,
+}
+
+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 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>;

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

@@ -0,0 +1,25 @@
+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,
+}

+ 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';