context.tsx 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332
  1. import type EventEmitter from 'events';
  2. import { AcceptedUploadFileType } from '@growi/core';
  3. import type { ColorScheme, IUserHasId } from '@growi/core';
  4. import { useSWRStatic } from '@growi/core/dist/swr';
  5. import type { SWRResponse } from 'swr';
  6. import useSWR from 'swr';
  7. import useSWRImmutable from 'swr/immutable';
  8. import type { SupportedActionType } from '~/interfaces/activity';
  9. import type { RendererConfig } from '~/interfaces/services/renderer';
  10. import { useContextSWR } from './use-context-swr';
  11. declare global {
  12. // eslint-disable-next-line vars-on-top, no-var
  13. var globalEmitter: EventEmitter;
  14. }
  15. type Nullable<T> = T | null;
  16. export const useCsrfToken = (initialData?: string): SWRResponse<string, Error> => {
  17. return useContextSWR<string, Error>('csrfToken', initialData);
  18. };
  19. export const useAppTitle = (initialData?: string): SWRResponse<string, Error> => {
  20. return useContextSWR('appTitle', initialData);
  21. };
  22. export const useSiteUrl = (initialData?: string): SWRResponse<string, Error> => {
  23. return useContextSWR<string, Error>('siteUrl', initialData);
  24. };
  25. export const useConfidential = (initialData?: string): SWRResponse<string, Error> => {
  26. return useContextSWR('confidential', initialData);
  27. };
  28. export const useCurrentUser = (initialData?: Nullable<IUserHasId>): SWRResponse<Nullable<IUserHasId>, Error> => {
  29. return useContextSWR('currentUser', initialData);
  30. };
  31. export const useCurrentPathname = (initialData?: string): SWRResponse<string, Error> => {
  32. return useContextSWR('currentPathname', initialData);
  33. };
  34. export const useIsIdenticalPath = (initialData?: boolean): SWRResponse<boolean, Error> => {
  35. return useContextSWR<boolean, Error>('isIdenticalPath', initialData, { fallbackData: false });
  36. };
  37. export const useIsForbidden = (initialData?: boolean): SWRResponse<boolean, Error> => {
  38. return useContextSWR<boolean, Error>('isForbidden', initialData, { fallbackData: false });
  39. };
  40. export const useIsNotCreatable = (initialData?: boolean): SWRResponse<boolean, Error> => {
  41. return useContextSWR<boolean, Error>('isNotCreatable', initialData, { fallbackData: false });
  42. };
  43. export const useIsSharedUser = (initialData?: boolean): SWRResponse<boolean, Error> => {
  44. return useContextSWR<boolean, Error>('isSharedUser', initialData);
  45. };
  46. export const useShareLinkId = (initialData?: string): SWRResponse<string, Error> => {
  47. return useContextSWR('shareLinkId', initialData);
  48. };
  49. export const useDisableLinkSharing = (initialData?: Nullable<boolean>): SWRResponse<Nullable<boolean>, Error> => {
  50. return useContextSWR<Nullable<boolean>, Error>('disableLinkSharing', initialData);
  51. };
  52. export const useRegistrationWhitelist = (initialData?: Nullable<string[]>): SWRResponse<Nullable<string[]>, Error> => {
  53. return useContextSWR<Nullable<string[]>, Error>('registrationWhitelist', initialData);
  54. };
  55. export const useIsSearchPage = (initialData?: Nullable<boolean>) : SWRResponse<Nullable<boolean>, Error> => {
  56. return useContextSWR<Nullable<any>, Error>('isSearchPage', initialData);
  57. };
  58. export const useIsAclEnabled = (initialData?: boolean) : SWRResponse<boolean, Error> => {
  59. return useContextSWR<boolean, Error>('isAclEnabled', initialData);
  60. };
  61. export const useIsSearchServiceConfigured = (initialData?: boolean) : SWRResponse<boolean, Error> => {
  62. return useContextSWR<boolean, Error>('isSearchServiceConfigured', initialData);
  63. };
  64. export const useIsSearchServiceReachable = (initialData?: boolean) : SWRResponse<boolean, Error> => {
  65. return useContextSWR<boolean, Error>('isSearchServiceReachable', initialData);
  66. };
  67. export const useElasticsearchMaxBodyLengthToIndex = (initialData?: number) : SWRResponse<number, Error> => {
  68. return useContextSWR('elasticsearchMaxBodyLengthToIndex', initialData);
  69. };
  70. export const useIsMailerSetup = (initialData?: boolean): SWRResponse<boolean, any> => {
  71. return useContextSWR('isMailerSetup', initialData);
  72. };
  73. export const useIsSearchScopeChildrenAsDefault = (initialData?: boolean) : SWRResponse<boolean, Error> => {
  74. return useContextSWR<boolean, Error>('isSearchScopeChildrenAsDefault', initialData, { fallbackData: false });
  75. };
  76. export const useShowPageSideAuthors = (initialData?: boolean): SWRResponse<boolean, Error> => {
  77. return useContextSWR('showPageSideAuthors', initialData, { fallbackData: false });
  78. };
  79. export const useIsEnabledMarp = (initialData?: boolean) : SWRResponse<boolean, Error> => {
  80. return useContextSWR<boolean, Error>('isEnabledMarp', initialData, { fallbackData: false });
  81. };
  82. export const useIsSlackConfigured = (initialData?: boolean) : SWRResponse<boolean, Error> => {
  83. return useContextSWR<boolean, Error>('isSlackConfigured', initialData);
  84. };
  85. export const useIsEnabledAttachTitleHeader = (initialData?: boolean) : SWRResponse<boolean, Error> => {
  86. return useContextSWR<boolean, Error>('isEnabledAttachTitleHeader', initialData);
  87. };
  88. export const useIsIndentSizeForced = (initialData?: boolean) : SWRResponse<boolean, Error> => {
  89. return useContextSWR<boolean, Error>('isIndentSizeForced', initialData, { fallbackData: false });
  90. };
  91. export const useDefaultIndentSize = (initialData?: number) : SWRResponse<number, Error> => {
  92. return useContextSWR<number, Error>('defaultIndentSize', initialData, { fallbackData: 4 });
  93. };
  94. export const useAuditLogEnabled = (initialData?: boolean): SWRResponse<boolean, Error> => {
  95. return useContextSWR<boolean, Error>('auditLogEnabled', initialData, { fallbackData: false });
  96. };
  97. export const useActivityExpirationSeconds = (initialData?: number) : SWRResponse<number, Error> => {
  98. return useContextSWR<number, Error>('activityExpirationSeconds', initialData);
  99. };
  100. export const useAuditLogAvailableActions = (initialData?: Array<SupportedActionType>) : SWRResponse<Array<SupportedActionType>, Error> => {
  101. return useContextSWR<Array<SupportedActionType>, Error>('auditLogAvailableActions', initialData);
  102. };
  103. export const useGrowiVersion = (initialData?: string): SWRResponse<string, any> => {
  104. return useContextSWR('growiVersion', initialData);
  105. };
  106. export const useIsEnabledStaleNotification = (initialData?: boolean): SWRResponse<boolean, any> => {
  107. return useContextSWR('isEnabledStaleNotification', initialData);
  108. };
  109. export const useRendererConfig = (initialData?: RendererConfig): SWRResponse<RendererConfig, any> => {
  110. return useContextSWR('growiRendererConfig', initialData);
  111. };
  112. export const useIsAllReplyShown = (initialData?: boolean): SWRResponse<boolean, Error> => {
  113. return useContextSWR('isAllReplyShown', initialData);
  114. };
  115. export const useIsBlinkedHeaderAtBoot = (initialData?: boolean): SWRResponse<boolean, Error> => {
  116. return useContextSWR('isBlinkedAtBoot', initialData, { fallbackData: false });
  117. };
  118. export const useIsUploadEnabled = (initialData?: boolean): SWRResponse<boolean, Error> => {
  119. return useContextSWR('isUploadEnabled', initialData);
  120. };
  121. export const useIsUploadAllFileAllowed = (initialData?: boolean): SWRResponse<boolean, Error> => {
  122. return useContextSWR('isUploadAllFileAllowed', initialData);
  123. };
  124. export const useIsBulkExportPagesEnabled = (initialData?: boolean): SWRResponse<boolean, Error> => {
  125. return useContextSWR('isBulkExportPagesEnabled', initialData);
  126. };
  127. export const useIsPdfBulkExportEnabled = (initialData?: boolean): SWRResponse<boolean, Error> => {
  128. return useContextSWR('isPdfBulkExportEnabled', initialData);
  129. };
  130. export const useShowPageLimitationL = (initialData?: number): SWRResponse<number, Error> => {
  131. return useContextSWR('showPageLimitationL', initialData);
  132. };
  133. export const useShowPageLimitationXL = (initialData?: number): SWRResponse<number, Error> => {
  134. return useContextSWR('showPageLimitationXL', initialData);
  135. };
  136. export const useCustomizeTitle = (initialData?: string): SWRResponse<string, Error> => {
  137. return useContextSWR('CustomizeTitle', initialData);
  138. };
  139. export const useIsDefaultLogo = (initialData?: boolean): SWRResponse<boolean, Error> => {
  140. return useContextSWR('isDefaultLogo', initialData);
  141. };
  142. export const useIsCustomizedLogoUploaded = (initialData?: boolean): SWRResponse<boolean, Error> => {
  143. return useSWRStatic('isCustomizedLogoUploaded', initialData);
  144. };
  145. export const useForcedColorScheme = (initialData?: ColorScheme): SWRResponse<ColorScheme, Error> => {
  146. return useContextSWR('forcedColorScheme', initialData);
  147. };
  148. export const useGrowiCloudUri = (initialData?: string): SWRResponse<string, Error> => {
  149. return useContextSWR('growiCloudUri', initialData);
  150. };
  151. export const useGrowiAppIdForGrowiCloud = (initialData?: number): SWRResponse<number, Error> => {
  152. return useContextSWR('growiAppIdForGrowiCloud', initialData);
  153. };
  154. export const useIsContainerFluid = (initialData?: boolean): SWRResponse<boolean, Error> => {
  155. return useContextSWR('isContainerFluid', initialData);
  156. };
  157. export const useIsLocalAccountRegistrationEnabled = (initialData?: boolean): SWRResponse<boolean, Error> => {
  158. return useContextSWR('isLocalAccountRegistrationEnabled', initialData);
  159. };
  160. export const useIsRomUserAllowedToComment = (initialData?: boolean): SWRResponse<boolean, Error> => {
  161. return useContextSWR('isRomUserAllowedToComment', initialData);
  162. };
  163. export const useIsAiEnabled = (initialData?: boolean): SWRResponse<boolean, Error> => {
  164. return useContextSWR('isAiEnabled', initialData);
  165. };
  166. export const useLimitLearnablePageCountPerAssistant = (initialData?: number): SWRResponse<number, Error> => {
  167. return useContextSWR('limitLearnablePageCountPerAssistant', initialData);
  168. };
  169. export const useIsUsersHomepageDeletionEnabled = (initialData?: boolean): SWRResponse<boolean, false> => {
  170. return useContextSWR('isUsersHomepageDeletionEnabled', initialData);
  171. export const useIsEnableUnifiedMergeView = (initialData?: boolean): SWRResponse<boolean, Error> => {
  172. return useSWRStatic<boolean, Error>('isEnableUnifiedMergeView', initialData, { fallbackData: false });
  173. };
  174. /** **********************************************************
  175. * Computed contexts
  176. *********************************************************** */
  177. export const useIsGuestUser = (): SWRResponse<boolean, Error> => {
  178. const { data: currentUser, isLoading } = useCurrentUser();
  179. return useSWRImmutable(
  180. isLoading ? null : ['isGuestUser', currentUser?._id],
  181. ([, currentUserId]) => currentUserId == null,
  182. { fallbackData: currentUser?._id == null },
  183. );
  184. };
  185. export const useIsReadOnlyUser = (): SWRResponse<boolean, Error> => {
  186. const { data: currentUser, isLoading: isCurrentUserLoading } = useCurrentUser();
  187. const { data: isGuestUser, isLoading: isGuestUserLoding } = useIsGuestUser();
  188. const isLoading = isCurrentUserLoading || isGuestUserLoding;
  189. const isReadOnlyUser = !isGuestUser && !!currentUser?.readOnly;
  190. return useSWRImmutable(
  191. isLoading ? null : ['isReadOnlyUser', isReadOnlyUser, currentUser?._id],
  192. () => isReadOnlyUser,
  193. { fallbackData: isReadOnlyUser },
  194. );
  195. };
  196. export const useIsAdmin = (): SWRResponse<boolean, Error> => {
  197. const { data: currentUser, isLoading } = useCurrentUser();
  198. return useSWR(
  199. isLoading ? null : ['isAdminUser', currentUser?._id, currentUser?.admin],
  200. ([, , isAdmin]) => isAdmin ?? false,
  201. {
  202. fallbackData: currentUser?.admin ?? false,
  203. keepPreviousData: true,
  204. // disable all revalidation but revalidateIfStale
  205. revalidateOnMount: false,
  206. revalidateOnFocus: false,
  207. revalidateOnReconnect: false,
  208. },
  209. );
  210. };
  211. export const useIsEditable = (): SWRResponse<boolean, Error> => {
  212. const { data: isGuestUser } = useIsGuestUser();
  213. const { data: isReadOnlyUser } = useIsReadOnlyUser();
  214. const { data: isForbidden } = useIsForbidden();
  215. const { data: isNotCreatable } = useIsNotCreatable();
  216. const { data: isIdenticalPath } = useIsIdenticalPath();
  217. return useSWRImmutable(
  218. ['isEditable', isGuestUser, isReadOnlyUser, isForbidden, isNotCreatable, isIdenticalPath],
  219. ([, isGuestUser, isReadOnlyUser, isForbidden, isNotCreatable, isIdenticalPath]) => {
  220. return (!isForbidden && !isIdenticalPath && !isNotCreatable && !isGuestUser && !isReadOnlyUser);
  221. },
  222. );
  223. };
  224. export const useAcceptedUploadFileType = (): SWRResponse<AcceptedUploadFileType, Error> => {
  225. const { data: isUploadEnabled } = useIsUploadEnabled();
  226. const { data: isUploadAllFileAllowed } = useIsUploadAllFileAllowed();
  227. return useSWRImmutable(
  228. ['acceptedUploadFileType', isUploadEnabled, isUploadAllFileAllowed],
  229. ([, isUploadEnabled, isUploadAllFileAllowed]) => {
  230. if (!isUploadEnabled) {
  231. return AcceptedUploadFileType.NONE;
  232. }
  233. if (isUploadAllFileAllowed) {
  234. return AcceptedUploadFileType.ALL;
  235. }
  236. return AcceptedUploadFileType.IMAGE;
  237. },
  238. );
  239. };
  240. // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
  241. export const useGrowiDocumentationUrl = () => {
  242. const { data: growiCloudUri } = useGrowiCloudUri();
  243. return useSWR(
  244. ['documentationUrl', growiCloudUri],
  245. ([, growiCloudUri]) => {
  246. const url = growiCloudUri != null
  247. ? new URL('/help', growiCloudUri)
  248. : new URL('https://docs.growi.org');
  249. return url.toString();
  250. },
  251. {
  252. fallbackData: 'https://docs.growi.org',
  253. revalidateOnFocus: false,
  254. revalidateOnReconnect: false,
  255. },
  256. );
  257. };