_search.page.tsx 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191
  1. import {
  2. NextPage, GetServerSideProps, GetServerSidePropsContext,
  3. } from 'next';
  4. import { serverSideTranslations } from 'next-i18next/serverSideTranslations';
  5. import dynamic from 'next/dynamic';
  6. import Head from 'next/head';
  7. import type { CrowiRequest } from '~/interfaces/crowi-request';
  8. import type { RendererConfig } from '~/interfaces/services/renderer';
  9. import type { ISidebarConfig } from '~/interfaces/sidebar-config';
  10. import type { IUser, IUserHasId } from '~/interfaces/user';
  11. import type { IUserUISettings } from '~/interfaces/user-ui-settings';
  12. import type { UserUISettingsModel } from '~/server/models/user-ui-settings';
  13. import {
  14. useCsrfToken, useCurrentUser, useIsSearchPage, useIsSearchScopeChildrenAsDefault,
  15. useIsSearchServiceConfigured, useIsSearchServiceReachable, useRendererConfig, useShowPageLimitationL,
  16. } from '~/stores/context';
  17. import {
  18. usePreferDrawerModeByUser, usePreferDrawerModeOnEditByUser, useSidebarCollapsed,
  19. useCurrentSidebarContents, useCurrentProductNavWidth,
  20. } from '~/stores/ui';
  21. import { SearchPage } from '../components/SearchPage';
  22. import {
  23. CommonProps, getNextI18NextConfig, getServerSideCommonProps, useCustomTitle,
  24. } from './utils/commons';
  25. const SearchResultLayout = dynamic(() => import('~/components/Layout/SearchResultLayout'), { ssr: false });
  26. type Props = CommonProps & {
  27. currentUser: IUser,
  28. isSearchServiceConfigured: boolean,
  29. isSearchServiceReachable: boolean,
  30. isSearchScopeChildrenAsDefault: boolean,
  31. // UI
  32. userUISettings?: IUserUISettings
  33. // Sidebar
  34. sidebarConfig: ISidebarConfig,
  35. // Render config
  36. rendererConfig: RendererConfig,
  37. // search limit
  38. showPageLimitationL: number
  39. };
  40. const SearchResultPage: NextPage<Props> = (props: Props) => {
  41. const { userUISettings } = props;
  42. // commons
  43. useCsrfToken(props.csrfToken);
  44. useCurrentUser(props.currentUser ?? null);
  45. // Search
  46. useIsSearchPage(true);
  47. useIsSearchServiceConfigured(props.isSearchServiceConfigured);
  48. useIsSearchServiceReachable(props.isSearchServiceReachable);
  49. useIsSearchScopeChildrenAsDefault(props.isSearchScopeChildrenAsDefault);
  50. // UserUISettings
  51. usePreferDrawerModeByUser(userUISettings?.preferDrawerModeByUser ?? props.sidebarConfig.isSidebarDrawerMode);
  52. usePreferDrawerModeOnEditByUser(userUISettings?.preferDrawerModeOnEditByUser);
  53. useSidebarCollapsed(userUISettings?.isSidebarCollapsed ?? props.sidebarConfig.isSidebarClosedAtDockMode);
  54. useCurrentSidebarContents(userUISettings?.currentSidebarContents);
  55. useCurrentProductNavWidth(userUISettings?.currentProductNavWidth);
  56. // render config
  57. useRendererConfig(props.rendererConfig);
  58. useShowPageLimitationL(props.showPageLimitationL);
  59. const PutbackPageModal = (): JSX.Element => {
  60. const PutbackPageModal = dynamic(() => import('../components/PutbackPageModal'), { ssr: false });
  61. return <PutbackPageModal />;
  62. };
  63. const classNames: string[] = [];
  64. // if (props.isContainerFluid) {
  65. // classNames.push('growi-layout-fluid');
  66. // }
  67. return (
  68. <>
  69. <Head>
  70. {/*
  71. {renderScriptTagByName('drawio-viewer')}
  72. {renderScriptTagByName('highlight-addons')}
  73. */}
  74. </Head>
  75. <SearchResultLayout title={useCustomTitle(props, 'GROWI')} className={classNames.join(' ')}>
  76. <div id="search-page">
  77. <SearchPage />
  78. </div>
  79. </SearchResultLayout>
  80. <PutbackPageModal />
  81. </>
  82. );
  83. };
  84. async function injectUserUISettings(context: GetServerSidePropsContext, props: Props): Promise<void> {
  85. const { model: mongooseModel } = await import('mongoose');
  86. const req = context.req as CrowiRequest<IUserHasId & any>;
  87. const { user } = req;
  88. const UserUISettings = mongooseModel('UserUISettings') as UserUISettingsModel;
  89. const userUISettings = user == null ? null : await UserUISettings.findOne({ user: user._id }).exec();
  90. if (userUISettings != null) {
  91. props.userUISettings = userUISettings.toObject();
  92. }
  93. }
  94. function injectServerConfigurations(context: GetServerSidePropsContext, props: Props): void {
  95. const req: CrowiRequest = context.req as CrowiRequest;
  96. const { crowi } = req;
  97. const { configManager, searchService } = crowi;
  98. props.isSearchServiceConfigured = searchService.isConfigured;
  99. props.isSearchServiceReachable = searchService.isReachable;
  100. props.isSearchScopeChildrenAsDefault = configManager.getConfig('crowi', 'customize:isSearchScopeChildrenAsDefault');
  101. props.sidebarConfig = {
  102. isSidebarDrawerMode: configManager.getConfig('crowi', 'customize:isSidebarDrawerMode'),
  103. isSidebarClosedAtDockMode: configManager.getConfig('crowi', 'customize:isSidebarClosedAtDockMode'),
  104. };
  105. props.rendererConfig = {
  106. isEnabledLinebreaks: configManager.getConfig('markdown', 'markdown:isEnabledLinebreaks'),
  107. isEnabledLinebreaksInComments: configManager.getConfig('markdown', 'markdown:isEnabledLinebreaksInComments'),
  108. adminPreferredIndentSize: configManager.getConfig('markdown', 'markdown:adminPreferredIndentSize'),
  109. isIndentSizeForced: configManager.getConfig('markdown', 'markdown:isIndentSizeForced'),
  110. plantumlUri: process.env.PLANTUML_URI ?? null,
  111. blockdiagUri: process.env.BLOCKDIAG_URI ?? null,
  112. // XSS Options
  113. isEnabledXssPrevention: configManager.getConfig('markdown', 'markdown:xss:isEnabledPrevention'),
  114. attrWhiteList: crowi.xssService.getAttrWhiteList(),
  115. tagWhiteList: crowi.xssService.getTagWhiteList(),
  116. highlightJsStyleBorder: crowi.configManager.getConfig('crowi', 'customize:highlightJsStyleBorder'),
  117. };
  118. props.showPageLimitationL = configManager.getConfig('crowi', 'customize:showPageLimitationL');
  119. }
  120. /**
  121. * for Server Side Translations
  122. * @param context
  123. * @param props
  124. * @param namespacesRequired
  125. */
  126. async function injectNextI18NextConfigurations(context: GetServerSidePropsContext, props: Props, namespacesRequired?: string[] | undefined): Promise<void> {
  127. const nextI18NextConfig = await getNextI18NextConfig(serverSideTranslations, context, namespacesRequired);
  128. props._nextI18Next = nextI18NextConfig._nextI18Next;
  129. }
  130. export const getServerSideProps: GetServerSideProps = async(context: GetServerSidePropsContext) => {
  131. const req = context.req as CrowiRequest<IUserHasId & any>;
  132. const { user } = req;
  133. const result = await getServerSideCommonProps(context);
  134. // check for presence
  135. // see: https://github.com/vercel/next.js/issues/19271#issuecomment-730006862
  136. if (!('props' in result)) {
  137. throw new Error('invalid getSSP result');
  138. }
  139. const props: Props = result.props as Props;
  140. if (user != null) {
  141. props.currentUser = user.toObject();
  142. }
  143. await injectUserUISettings(context, props);
  144. injectServerConfigurations(context, props);
  145. await injectNextI18NextConfigurations(context, props, ['translation']);
  146. return {
  147. props,
  148. };
  149. };
  150. export default SearchResultPage;