context.tsx 12 KB

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