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

Merge remote-tracking branch 'origin/master' into support/omit-textlint

Yuki Takei 3 лет назад
Родитель
Сommit
6a76be126b

+ 0 - 2
apps/app/src/components/Admin/Notification/NotificationSetting.jsx

@@ -126,12 +126,10 @@ function NotificationSetting(props) {
       user_trigger_notification: {
       user_trigger_notification: {
         Icon: () => <i className="icon-settings" />,
         Icon: () => <i className="icon-settings" />,
         i18n: 'User trigger notification',
         i18n: 'User trigger notification',
-        index: 0,
       },
       },
       global_notification: {
       global_notification: {
         Icon: () => <i className="icon-settings" />,
         Icon: () => <i className="icon-settings" />,
         i18n: 'Global notification',
         i18n: 'Global notification',
-        index: 1,
       },
       },
     };
     };
   }, []);
   }, []);

+ 0 - 7
apps/app/src/components/Admin/Security/SecurityManagementContents.jsx

@@ -32,37 +32,30 @@ const SecurityManagementContents = () => {
       passport_local: {
       passport_local: {
         Icon: () => <i className="fa fa-users" />,
         Icon: () => <i className="fa fa-users" />,
         i18n: 'ID/Pass',
         i18n: 'ID/Pass',
-        index: 0,
       },
       },
       passport_ldap: {
       passport_ldap: {
         Icon: () => <i className="fa fa-sitemap" />,
         Icon: () => <i className="fa fa-sitemap" />,
         i18n: 'LDAP',
         i18n: 'LDAP',
-        index: 1,
       },
       },
       passport_saml: {
       passport_saml: {
         Icon: () => <i className="fa fa-key" />,
         Icon: () => <i className="fa fa-key" />,
         i18n: 'SAML',
         i18n: 'SAML',
-        index: 2,
       },
       },
       passport_oidc: {
       passport_oidc: {
         Icon: () => <i className="fa fa-key" />,
         Icon: () => <i className="fa fa-key" />,
         i18n: 'OIDC',
         i18n: 'OIDC',
-        index: 3,
       },
       },
       passport_google: {
       passport_google: {
         Icon: () => <i className="fa fa-google" />,
         Icon: () => <i className="fa fa-google" />,
         i18n: 'Google',
         i18n: 'Google',
-        index: 4,
       },
       },
       passport_github: {
       passport_github: {
         Icon: () => <i className="fa fa-github" />,
         Icon: () => <i className="fa fa-github" />,
         i18n: 'GitHub',
         i18n: 'GitHub',
-        index: 5,
       },
       },
       // passport_facebook: {
       // passport_facebook: {
       //   Icon: () => <i className="fa fa-facebook" />,
       //   Icon: () => <i className="fa fa-facebook" />,
       //   i18n: '(TBD) Facebook',
       //   i18n: '(TBD) Facebook',
-      //   index: 7,
       // },
       // },
     };
     };
   }, []);
   }, []);

+ 62 - 64
apps/app/src/components/CustomNavigation/CustomNav.jsx → apps/app/src/components/CustomNavigation/CustomNav.tsx

@@ -2,16 +2,20 @@ import React, {
   useEffect, useState, useRef, useMemo, useCallback,
   useEffect, useState, useRef, useMemo, useCallback,
 } from 'react';
 } from 'react';
 
 
-import PropTypes from 'prop-types';
+import { Breakpoint } from '@growi/ui/dist/interfaces/breakpoints';
 import {
 import {
   Nav, NavItem, NavLink,
   Nav, NavItem, NavLink,
 } from 'reactstrap';
 } from 'reactstrap';
 
 
+import { ICustomNavTabMappings } from '~/interfaces/ui';
+
 import styles from './CustomNav.module.scss';
 import styles from './CustomNav.module.scss';
 
 
 
 
-function getBreakpointOneLevelLarger(breakpoint) {
+function getBreakpointOneLevelLarger(breakpoint: Breakpoint): Omit<Breakpoint, 'xs' | 'sm'> {
   switch (breakpoint) {
   switch (breakpoint) {
+    case 'xs':
+      return 'sm';
     case 'sm':
     case 'sm':
       return 'md';
       return 'md';
     case 'md':
     case 'md':
@@ -25,12 +29,18 @@ function getBreakpointOneLevelLarger(breakpoint) {
 }
 }
 
 
 
 
-export const CustomNavDropdown = (props) => {
+type CustomNavDropdownProps = {
+  navTabMapping: ICustomNavTabMappings,
+  activeTab: string,
+  onNavSelected?: (selectedTabKey: string) => void,
+};
+
+export const CustomNavDropdown = (props: CustomNavDropdownProps): JSX.Element => {
   const {
   const {
     activeTab, navTabMapping, onNavSelected,
     activeTab, navTabMapping, onNavSelected,
   } = props;
   } = props;
 
 
-  const activeObj = navTabMapping[activeTab];
+  const { Icon, i18n } = navTabMapping[activeTab];
 
 
   const menuItemClickHandler = useCallback((key) => {
   const menuItemClickHandler = useCallback((key) => {
     if (onNavSelected != null) {
     if (onNavSelected != null) {
@@ -48,16 +58,15 @@ export const CustomNavDropdown = (props) => {
         aria-expanded="false"
         aria-expanded="false"
       >
       >
         <span className="float-left">
         <span className="float-left">
-          { activeObj != null && (
-            <><activeObj.Icon /> {activeObj.i18n}</>
-          ) }
+          { Icon != null && <Icon /> } {i18n}
         </span>
         </span>
       </button>
       </button>
       <div className="dropdown-menu dropdown-menu-right">
       <div className="dropdown-menu dropdown-menu-right">
         {Object.entries(navTabMapping).map(([key, value]) => {
         {Object.entries(navTabMapping).map(([key, value]) => {
 
 
           const isActive = activeTab === key;
           const isActive = activeTab === key;
-          const isLinkEnabled = value.isLinkEnabled != null ? value.isLinkEnabled(value) : true;
+          const _isLinkEnabled = value.isLinkEnabled ?? true;
+          const isLinkEnabled = typeof _isLinkEnabled === 'boolean' ? _isLinkEnabled : _isLinkEnabled(value);
           const { Icon, i18n } = value;
           const { Icon, i18n } = value;
 
 
           return (
           return (
@@ -68,7 +77,7 @@ export const CustomNavDropdown = (props) => {
               disabled={!isLinkEnabled}
               disabled={!isLinkEnabled}
               onClick={() => menuItemClickHandler(key)}
               onClick={() => menuItemClickHandler(key)}
             >
             >
-              <Icon /> {i18n}
+              { Icon != null && <Icon /> } {i18n}
             </button>
             </button>
           );
           );
         })}
         })}
@@ -77,23 +86,29 @@ export const CustomNavDropdown = (props) => {
   );
   );
 };
 };
 
 
-CustomNavDropdown.propTypes = {
-  navTabMapping: PropTypes.object.isRequired,
-  activeTab: PropTypes.string,
-  onNavSelected: PropTypes.func,
-};
 
 
+type CustomNavTabProps = {
+  activeTab: string,
+  navTabMapping: ICustomNavTabMappings,
+  onNavSelected?: (selectedTabKey: string) => void,
+  hideBorderBottom?: boolean,
+  breakpointToHideInactiveTabsDown?: Breakpoint,
+  navRightElement?: JSX.Element,
+};
 
 
-export const CustomNavTab = (props) => {
-  const navContainer = useRef();
+export const CustomNavTab = (props: CustomNavTabProps): JSX.Element => {
   const [sliderWidth, setSliderWidth] = useState(0);
   const [sliderWidth, setSliderWidth] = useState(0);
   const [sliderMarginLeft, setSliderMarginLeft] = useState(0);
   const [sliderMarginLeft, setSliderMarginLeft] = useState(0);
 
 
   const {
   const {
-    activeTab, navTabMapping, onNavSelected, hideBorderBottom, breakpointToHideInactiveTabsDown, navRightElement,
+    activeTab, navTabMapping, onNavSelected,
+    hideBorderBottom,
+    breakpointToHideInactiveTabsDown, navRightElement,
   } = props;
   } = props;
 
 
-  const navTabRefs = useMemo(() => {
+  const navContainerRef = useRef<HTMLDivElement>(null);
+
+  const navTabRefs: { [key: string]: HTMLAnchorElement } = useMemo(() => {
     const obj = {};
     const obj = {};
     Object.keys(navTabMapping).forEach((key) => {
     Object.keys(navTabMapping).forEach((key) => {
       obj[key] = React.createRef();
       obj[key] = React.createRef();
@@ -107,9 +122,9 @@ export const CustomNavTab = (props) => {
     }
     }
   }, [onNavSelected]);
   }, [onNavSelected]);
 
 
-  function registerNavLink(key, elm) {
-    if (elm != null) {
-      navTabRefs[key] = elm;
+  function registerNavLink(key: string, anchorElem: HTMLAnchorElement | null) {
+    if (anchorElem != null) {
+      navTabRefs[key] = anchorElem;
     }
     }
   }
   }
 
 
@@ -123,27 +138,28 @@ export const CustomNavTab = (props) => {
       return;
       return;
     }
     }
 
 
-    if (navContainer == null) {
+    if (navContainerRef.current == null) {
       return;
       return;
     }
     }
 
 
-    let tempML = 0;
+    const navContainer = navContainerRef.current;
 
 
-    const styles = Object.entries(navTabRefs).map((el) => {
-      const width = getPercentage(el[1].offsetWidth, navContainer.current.offsetWidth);
-      const marginLeft = tempML;
-      tempML += width;
-      return { width, marginLeft };
-    });
-    const { width, marginLeft } = styles[navTabMapping[activeTab].index];
+    let marginLeft = 0;
+    for (const [key, anchorElem] of Object.entries(navTabRefs)) {
+      const width = getPercentage(anchorElem.offsetWidth, navContainer.offsetWidth);
 
 
-    setSliderWidth(width);
-    setSliderMarginLeft(marginLeft);
+      if (key === activeTab) {
+        setSliderWidth(width);
+        setSliderMarginLeft(marginLeft);
+        break;
+      }
 
 
+      marginLeft += width;
+    }
   }, [activeTab, navTabRefs, navTabMapping]);
   }, [activeTab, navTabRefs, navTabMapping]);
 
 
   // determine inactive classes to hide NavItem
   // determine inactive classes to hide NavItem
-  const inactiveClassnames = [];
+  const inactiveClassnames: string[] = [];
   if (breakpointToHideInactiveTabsDown != null) {
   if (breakpointToHideInactiveTabsDown != null) {
     const breakpointOneLevelLarger = getBreakpointOneLevelLarger(breakpointToHideInactiveTabsDown);
     const breakpointOneLevelLarger = getBreakpointOneLevelLarger(breakpointToHideInactiveTabsDown);
     inactiveClassnames.push('d-none');
     inactiveClassnames.push('d-none');
@@ -152,12 +168,13 @@ export const CustomNavTab = (props) => {
 
 
   return (
   return (
     <div className={`grw-custom-nav-tab ${styles['grw-custom-nav-tab']}`}>
     <div className={`grw-custom-nav-tab ${styles['grw-custom-nav-tab']}`}>
-      <div ref={navContainer} className="d-flex justify-content-between">
+      <div ref={navContainerRef} className="d-flex justify-content-between">
         <Nav className="nav-title">
         <Nav className="nav-title">
           {Object.entries(navTabMapping).map(([key, value]) => {
           {Object.entries(navTabMapping).map(([key, value]) => {
 
 
             const isActive = activeTab === key;
             const isActive = activeTab === key;
-            const isLinkEnabled = value.isLinkEnabled != null ? value.isLinkEnabled(value) : true;
+            const _isLinkEnabled = value.isLinkEnabled ?? true;
+            const isLinkEnabled = typeof _isLinkEnabled === 'boolean' ? _isLinkEnabled : _isLinkEnabled(value);
             const { Icon, i18n } = value;
             const { Icon, i18n } = value;
 
 
             return (
             return (
@@ -166,7 +183,7 @@ export const CustomNavTab = (props) => {
                 className={`p-0 ${isActive ? 'active' : inactiveClassnames.join(' ')}`}
                 className={`p-0 ${isActive ? 'active' : inactiveClassnames.join(' ')}`}
               >
               >
                 <NavLink type="button" key={key} innerRef={elm => registerNavLink(key, elm)} disabled={!isLinkEnabled} onClick={() => navLinkClickHandler(key)}>
                 <NavLink type="button" key={key} innerRef={elm => registerNavLink(key, elm)} disabled={!isLinkEnabled} onClick={() => navLinkClickHandler(key)}>
-                  <Icon /> {i18n}
+                  { Icon != null && <Icon /> } {i18n}
                 </NavLink>
                 </NavLink>
               </NavItem>
               </NavItem>
             );
             );
@@ -181,27 +198,23 @@ export const CustomNavTab = (props) => {
 
 
 };
 };
 
 
-CustomNavTab.propTypes = {
-  activeTab: PropTypes.string.isRequired,
-  navTabMapping: PropTypes.object.isRequired,
-  onNavSelected: PropTypes.func,
-  hideBorderBottom: PropTypes.bool,
-  breakpointToHideInactiveTabsDown: PropTypes.oneOf(['xs', 'sm', 'md', 'lg', 'xl']),
-  navRightElement: PropTypes.node,
-};
 
 
-CustomNavTab.defaultProps = {
-  hideBorderBottom: false,
+type CustomNavProps = {
+  activeTab: string,
+  navTabMapping: ICustomNavTabMappings,
+  onNavSelected?: (selectedTabKey: string) => void,
+  hideBorderBottom?: boolean,
+  breakpointToHideInactiveTabsDown?: Breakpoint,
+  breakpointToSwitchDropdownDown?: Breakpoint,
 };
 };
 
 
-
-const CustomNav = (props) => {
+const CustomNav = (props: CustomNavProps): JSX.Element => {
 
 
   const tabClassnames = ['d-none'];
   const tabClassnames = ['d-none'];
   const dropdownClassnames = ['d-block'];
   const dropdownClassnames = ['d-block'];
 
 
   // determine classes to show/hide
   // determine classes to show/hide
-  const breakpointOneLevelLarger = getBreakpointOneLevelLarger(props.breakpointToSwitchDropdownDown);
+  const breakpointOneLevelLarger = getBreakpointOneLevelLarger(props.breakpointToSwitchDropdownDown ?? 'sm');
   tabClassnames.push(`d-${breakpointOneLevelLarger}-block`);
   tabClassnames.push(`d-${breakpointOneLevelLarger}-block`);
   dropdownClassnames.push(`d-${breakpointOneLevelLarger}-none`);
   dropdownClassnames.push(`d-${breakpointOneLevelLarger}-none`);
 
 
@@ -218,19 +231,4 @@ const CustomNav = (props) => {
 
 
 };
 };
 
 
-CustomNav.propTypes = {
-  activeTab: PropTypes.string.isRequired,
-  navTabMapping: PropTypes.object.isRequired,
-  onNavSelected: PropTypes.func,
-  hideBorderBottom: PropTypes.bool,
-  breakpointToHideInactiveTabsDown: PropTypes.oneOf(['xs', 'sm', 'md', 'lg', 'xl']),
-  breakpointToSwitchDropdownDown: PropTypes.oneOf(['xs', 'sm', 'md', 'lg', 'xl']),
-};
-
-CustomNav.defaultProps = {
-  hideBorderBottom: false,
-  breakpointToSwitchDropdownDown: 'sm',
-};
-
-
 export default CustomNav;
 export default CustomNav;

+ 2 - 1
apps/app/src/components/CustomNavigation/CustomTabContent.tsx

@@ -24,11 +24,12 @@ const CustomTabContent = (props: Props): JSX.Element => {
       {Object.entries(navTabMapping).map(([key, value]) => {
       {Object.entries(navTabMapping).map(([key, value]) => {
 
 
         const { Content } = value;
         const { Content } = value;
+        const content = Content != null ? <Content /> : <></>;
 
 
         return (
         return (
           <TabPane key={key} tabId={key}>
           <TabPane key={key} tabId={key}>
             <LazyRenderer shouldRender={key === activeTab}>
             <LazyRenderer shouldRender={key === activeTab}>
-              <Content />
+              {content}
             </LazyRenderer>
             </LazyRenderer>
           </TabPane>
           </TabPane>
         );
         );

+ 0 - 2
apps/app/src/components/DescendantsPageListModal.tsx

@@ -54,7 +54,6 @@ export const DescendantsPageListModal = (): JSX.Element => {
           return <DescendantsPageList path={status.path} />;
           return <DescendantsPageList path={status.path} />;
         },
         },
         i18n: t('page_list'),
         i18n: t('page_list'),
-        index: 0,
         isLinkEnabled: () => !isSharedUser,
         isLinkEnabled: () => !isSharedUser,
       },
       },
       timeline: {
       timeline: {
@@ -66,7 +65,6 @@ export const DescendantsPageListModal = (): JSX.Element => {
           return <PageTimeline />;
           return <PageTimeline />;
         },
         },
         i18n: t('Timeline View'),
         i18n: t('Timeline View'),
-        index: 1,
         isLinkEnabled: () => !isSharedUser,
         isLinkEnabled: () => !isSharedUser,
       },
       },
     };
     };

+ 0 - 2
apps/app/src/components/InAppNotification/InAppNotificationPage.tsx

@@ -127,13 +127,11 @@ export const InAppNotificationPage: FC = () => {
       Icon: () => <></>,
       Icon: () => <></>,
       Content: () => InAppNotificationCategoryByStatus(),
       Content: () => InAppNotificationCategoryByStatus(),
       i18n: t('in_app_notification.all'),
       i18n: t('in_app_notification.all'),
-      index: 0,
     },
     },
     external_accounts: {
     external_accounts: {
       Icon: () => <></>,
       Icon: () => <></>,
       Content: () => InAppNotificationCategoryByStatus(InAppNotificationStatuses.STATUS_UNOPENED),
       Content: () => InAppNotificationCategoryByStatus(InAppNotificationStatuses.STATUS_UNOPENED),
       i18n: t('in_app_notification.unopend'),
       i18n: t('in_app_notification.unopend'),
-      index: 1,
     },
     },
   };
   };
 
 

+ 0 - 6
apps/app/src/components/Me/PersonalSettings.jsx

@@ -22,37 +22,31 @@ const PersonalSettings = () => {
         Icon: () => <i className="icon-fw icon-user"></i>,
         Icon: () => <i className="icon-fw icon-user"></i>,
         Content: UserSettings,
         Content: UserSettings,
         i18n: t('User Information'),
         i18n: t('User Information'),
-        index: 0,
       },
       },
       external_accounts: {
       external_accounts: {
         Icon: () => <i className="icon-fw icon-share-alt"></i>,
         Icon: () => <i className="icon-fw icon-share-alt"></i>,
         Content: ExternalAccountLinkedMe,
         Content: ExternalAccountLinkedMe,
         i18n: t('admin:user_management.external_accounts'),
         i18n: t('admin:user_management.external_accounts'),
-        index: 1,
       },
       },
       password_settings: {
       password_settings: {
         Icon: () => <i className="icon-fw icon-lock"></i>,
         Icon: () => <i className="icon-fw icon-lock"></i>,
         Content: PasswordSettings,
         Content: PasswordSettings,
         i18n: t('Password Settings'),
         i18n: t('Password Settings'),
-        index: 2,
       },
       },
       api_settings: {
       api_settings: {
         Icon: () => <i className="icon-fw icon-paper-plane"></i>,
         Icon: () => <i className="icon-fw icon-paper-plane"></i>,
         Content: ApiSettings,
         Content: ApiSettings,
         i18n: t('API Settings'),
         i18n: t('API Settings'),
-        index: 3,
       },
       },
       // editor_settings: {
       // editor_settings: {
       //   Icon: () => <i className="icon-fw icon-pencil"></i>,
       //   Icon: () => <i className="icon-fw icon-pencil"></i>,
       //   Content: EditorSettings,
       //   Content: EditorSettings,
       //   i18n: t('editor_settings.editor_settings'),
       //   i18n: t('editor_settings.editor_settings'),
-      //   index: 4,
       // },
       // },
       in_app_notification_settings: {
       in_app_notification_settings: {
         Icon: () => <i className="icon-fw icon-bell"></i>,
         Icon: () => <i className="icon-fw icon-bell"></i>,
         Content: InAppNotificationSettings,
         Content: InAppNotificationSettings,
         i18n: t('in_app_notification_settings.in_app_notification_settings'),
         i18n: t('in_app_notification_settings.in_app_notification_settings'),
-        index: 5,
       },
       },
     };
     };
   }, [t]);
   }, [t]);

+ 0 - 2
apps/app/src/components/NotFoundPage.tsx

@@ -24,13 +24,11 @@ const NotFoundPage = (props: NotFoundPageProps): JSX.Element => {
         Icon: PageListIcon,
         Icon: PageListIcon,
         Content: () => <DescendantsPageList path={path} />,
         Content: () => <DescendantsPageList path={path} />,
         i18n: t('page_list'),
         i18n: t('page_list'),
-        index: 0,
       },
       },
       timeLine: {
       timeLine: {
         Icon: TimeLineIcon,
         Icon: TimeLineIcon,
         Content: PageTimeline,
         Content: PageTimeline,
         i18n: t('Timeline View'),
         i18n: t('Timeline View'),
-        index: 1,
       },
       },
     };
     };
   }, [path, t]);
   }, [path, t]);

+ 1 - 4
apps/app/src/components/PageAccessoriesModal.tsx

@@ -78,7 +78,6 @@ const PageAccessoriesModal = (): JSX.Element => {
           return <PageHistory onClose={close} sourceRevisionId={sourceRevisionId} targetRevisionId={targetRevisionId}/>;
           return <PageHistory onClose={close} sourceRevisionId={sourceRevisionId} targetRevisionId={targetRevisionId}/>;
         },
         },
         i18n: t('History'),
         i18n: t('History'),
-        index: 0,
         isLinkEnabled: () => !isGuestUser && !isSharedUser,
         isLinkEnabled: () => !isGuestUser && !isSharedUser,
       },
       },
       [PageAccessoriesModalContents.Attachment]: {
       [PageAccessoriesModalContents.Attachment]: {
@@ -87,7 +86,6 @@ const PageAccessoriesModal = (): JSX.Element => {
           return <PageAttachment />;
           return <PageAttachment />;
         },
         },
         i18n: t('attachment_data'),
         i18n: t('attachment_data'),
-        index: 1,
       },
       },
       [PageAccessoriesModalContents.ShareLink]: {
       [PageAccessoriesModalContents.ShareLink]: {
         Icon: ShareLinkIcon,
         Icon: ShareLinkIcon,
@@ -95,7 +93,6 @@ const PageAccessoriesModal = (): JSX.Element => {
           return <ShareLink />;
           return <ShareLink />;
         },
         },
         i18n: t('share_links.share_link_management'),
         i18n: t('share_links.share_link_management'),
-        index: 2,
         isLinkEnabled: () => !isGuestUser && !isSharedUser && !isLinkSharingDisabled,
         isLinkEnabled: () => !isGuestUser && !isSharedUser && !isLinkSharingDisabled,
       },
       },
     };
     };
@@ -133,7 +130,7 @@ const PageAccessoriesModal = (): JSX.Element => {
           activeTab={activeTab}
           activeTab={activeTab}
           navTabMapping={navTabMapping}
           navTabMapping={navTabMapping}
           breakpointToHideInactiveTabsDown="md"
           breakpointToHideInactiveTabsDown="md"
-          onNavSelected={(v) => {
+          onNavSelected={(v: PageAccessoriesModalContents) => {
             setActiveTab(v);
             setActiveTab(v);
           }}
           }}
           hideBorderBottom
           hideBorderBottom

+ 0 - 2
apps/app/src/components/PageComment/CommentEditor.tsx

@@ -36,12 +36,10 @@ const navTabMapping = {
   comment_editor: {
   comment_editor: {
     Icon: () => <i className="icon-settings" />,
     Icon: () => <i className="icon-settings" />,
     i18n: 'Write',
     i18n: 'Write',
-    index: 0,
   },
   },
   comment_preview: {
   comment_preview: {
     Icon: () => <i className="icon-settings" />,
     Icon: () => <i className="icon-settings" />,
     i18n: 'Preview',
     i18n: 'Preview',
-    index: 1,
   },
   },
 };
 };
 
 

+ 0 - 1
apps/app/src/components/TrashPageList.tsx

@@ -87,7 +87,6 @@ export const TrashPageList = (): JSX.Element => {
         Icon: PageListIcon,
         Icon: PageListIcon,
         Content: DescendantsPageListForTrash,
         Content: DescendantsPageListForTrash,
         i18n: t('page_list'),
         i18n: t('page_list'),
-        index: 0,
       },
       },
     };
     };
   }, [t]);
   }, [t]);

+ 1 - 2
apps/app/src/interfaces/ui.ts

@@ -11,10 +11,9 @@ export type SidebarContentsType = typeof SidebarContentsType[keyof typeof Sideba
 
 
 
 
 export type ICustomTabContent = {
 export type ICustomTabContent = {
-  Content: () => JSX.Element,
+  Content?: () => JSX.Element,
   i18n?: string,
   i18n?: string,
   Icon?: () => JSX.Element,
   Icon?: () => JSX.Element,
-  index?: number,
   isLinkEnabled?: boolean | ((content: ICustomTabContent) => boolean),
   isLinkEnabled?: boolean | ((content: ICustomTabContent) => boolean),
 };
 };
 
 

+ 0 - 2
apps/app/src/pages/installer.page.tsx

@@ -46,13 +46,11 @@ const InstallerPage: NextPage<Props> = (props: Props) => {
         Icon: () => <i className="icon-fw icon-user"></i>,
         Icon: () => <i className="icon-fw icon-user"></i>,
         Content: InstallerForm,
         Content: InstallerForm,
         i18n: t('installer.tab'),
         i18n: t('installer.tab'),
-        index: 0,
       },
       },
       external_accounts: {
       external_accounts: {
         Icon: () => <i className="icon-fw icon-share-alt"></i>,
         Icon: () => <i className="icon-fw icon-share-alt"></i>,
         Content: DataTransferForm,
         Content: DataTransferForm,
         i18n: tCommons('g2g_data_transfer.tab'),
         i18n: tCommons('g2g_data_transfer.tab'),
-        index: 1,
       },
       },
     };
     };
   }, [t, tCommons]);
   }, [t, tCommons]);

+ 3 - 0
apps/app/src/server/service/page.ts

@@ -1468,6 +1468,9 @@ class PageService {
 
 
           throw err;
           throw err;
         }
         }
+        finally {
+          this.pageEvent.emit('syncDescendantsUpdate', deletedPage, user);
+        }
       })();
       })();
     }
     }
     else {
     else {

+ 2 - 4
packages/remark-lsx/src/server/routes/lsx.ts

@@ -176,9 +176,10 @@ class Lsx {
 
 
 }
 }
 
 
-// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
+// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any
 export const routesFactory = (crowi): any => {
 export const routesFactory = (crowi): any => {
   const Page = crowi.model('Page');
   const Page = crowi.model('Page');
+  // eslint-disable-next-line @typescript-eslint/no-explicit-any
   const actions: any = {};
   const actions: any = {};
 
 
   /**
   /**
@@ -194,9 +195,6 @@ export const routesFactory = (crowi): any => {
     const builder = new Page.PageQueryBuilder(baseQuery);
     const builder = new Page.PageQueryBuilder(baseQuery);
     builder.addConditionToListOnlyDescendants(pagePath);
     builder.addConditionToListOnlyDescendants(pagePath);
 
 
-    builder
-      .addConditionToExcludeTrashed();
-
     return Page.addConditionToFilteringByViewerForList(builder, user);
     return Page.addConditionToFilteringByViewerForList(builder, user);
   }
   }
 
 

+ 1 - 1
packages/remark-lsx/src/services/renderer/lsx.ts

@@ -18,7 +18,7 @@ type DirectiveAttributes = Record<string, string>
 
 
 export const remarkPlugin: Plugin = function() {
 export const remarkPlugin: Plugin = function() {
   return (tree) => {
   return (tree) => {
-    visit(tree, (node, index) => {
+    visit(tree, (node) => {
       if (node.type === remarkGrowiDirectivePluginType.Text || node.type === remarkGrowiDirectivePluginType.Leaf) {
       if (node.type === remarkGrowiDirectivePluginType.Text || node.type === remarkGrowiDirectivePluginType.Leaf) {
         if (typeof node.name !== 'string') {
         if (typeof node.name !== 'string') {
           return;
           return;