From 8393ccc7f8decebc38ddcb9f2e94851b947e0598 Mon Sep 17 00:00:00 2001
From: Henry Heino <46334387+personalizedrefrigerator@users.noreply.github.com>
Date: Mon, 15 Apr 2024 10:15:18 -0700
Subject: [PATCH] Chore: Desktop: Use stronger types in `Sidebar.tsx` (#10305)
---
packages/app-desktop/gui/Sidebar/Sidebar.tsx | 119 ++++++++++++-------
packages/lib/reducer.ts | 6 +-
packages/lib/services/commands/MenuUtils.ts | 4 +-
3 files changed, 82 insertions(+), 47 deletions(-)
diff --git a/packages/app-desktop/gui/Sidebar/Sidebar.tsx b/packages/app-desktop/gui/Sidebar/Sidebar.tsx
index 9a7255f73..0bbefc01a 100644
--- a/packages/app-desktop/gui/Sidebar/Sidebar.tsx
+++ b/packages/app-desktop/gui/Sidebar/Sidebar.tsx
@@ -1,5 +1,5 @@
import * as React from 'react';
-import { useEffect, useRef, useCallback, useMemo } from 'react';
+import { useEffect, useRef, useCallback, useMemo, DragEventHandler, MouseEventHandler, RefObject } from 'react';
import { StyledRoot, StyledAddButton, StyledShareIcon, StyledHeader, StyledHeaderIcon, StyledAllNotesIcon, StyledHeaderLabel, StyledListItem, StyledListItemAnchor, StyledExpandLink, StyledNoteCount, StyledSyncReportText, StyledSyncReport, StyledSynchronizeButton, StyledSpanFix } from './styles';
import { ButtonLevel } from '../Button/Button';
import CommandService from '@joplin/lib/services/CommandService';
@@ -19,40 +19,38 @@ import Tag from '@joplin/lib/models/Tag';
import Logger from '@joplin/utils/Logger';
import { FolderEntity, FolderIcon, FolderIconType, TagEntity } from '@joplin/lib/services/database/types';
import stateToWhenClauseContext from '../../services/commands/stateToWhenClauseContext';
-import { store } from '@joplin/lib/reducer';
+import { StateDecryptionWorker, StateResourceFetcher, store } from '@joplin/lib/reducer';
import PerFolderSortOrderService from '../../services/sortOrder/PerFolderSortOrderService';
import { getFolderCallbackUrl, getTagCallbackUrl } from '@joplin/lib/callbackUrlUtils';
import FolderIconBox from '../FolderIconBox';
import onFolderDrop from '@joplin/lib/models/utils/onFolderDrop';
import { RuntimeProps } from './commands/focusElementSideBar';
-const { connect } = require('react-redux');
+import { connect } from 'react-redux';
import { renderFolders, renderTags } from '@joplin/lib/components/shared/side-menu-shared';
import { getTrashFolderIcon, getTrashFolderId } from '@joplin/lib/services/trash';
import { focus } from '@joplin/lib/utils/focusHandler';
import { ThemeStyle, themeStyle } from '@joplin/lib/theme';
-const bridge = require('@electron/remote').require('./bridge').default;
+import { Dispatch } from 'redux';
+import bridge from '../../services/bridge';
const Menu = bridge().Menu;
const MenuItem = bridge().MenuItem;
-const { substrWithEllipsis } = require('@joplin/lib/string-utils');
+import { substrWithEllipsis } from '@joplin/lib/string-utils';
const { ALL_NOTES_FILTER_ID } = require('@joplin/lib/reserved-ids');
-const { clipboard } = require('electron');
+import { clipboard } from 'electron';
const logger = Logger.create('Sidebar');
interface Props {
themeId: number;
- // eslint-disable-next-line @typescript-eslint/ban-types -- Old code before rule was applied
- dispatch: Function;
+ dispatch: Dispatch;
folders: FolderEntity[];
collapsedFolderIds: string[];
notesParentType: string;
selectedFolderId: string;
selectedTagId: string;
selectedSmartFilterId: string;
- // eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
- decryptionWorker: any;
- // eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
- resourceFetcher: any;
+ decryptionWorker: StateDecryptionWorker;
+ resourceFetcher: StateResourceFetcher;
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
syncReport: any;
tags: TagEntity[];
@@ -66,17 +64,30 @@ const commands = [
require('./commands/focusElementSideBar'),
];
-// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
-function ExpandIcon(props: any) {
+interface ExpandIconProps {
+ themeId: number;
+ isExpanded: boolean;
+ isVisible: boolean;
+}
+
+function ExpandIcon(props: ExpandIconProps) {
const theme = themeStyle(props.themeId);
- // eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
- const style: any = { width: 16, maxWidth: 16, opacity: 0.5, fontSize: Math.round(theme.toolbarIconSize * 0.8), display: 'flex', justifyContent: 'center' };
+ const style: React.CSSProperties = {
+ width: 16, maxWidth: 16, opacity: 0.5, fontSize: Math.round(theme.toolbarIconSize * 0.8), display: 'flex', justifyContent: 'center',
+ };
if (!props.isVisible) style.visibility = 'hidden';
return ;
}
-// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
-function ExpandLink(props: any) {
+interface ExpandLinkProps {
+ themeId: number;
+ folderId: string;
+ hasChildren: boolean;
+ isExpanded: boolean;
+ onClick: MouseEventHandler;
+}
+
+function ExpandLink(props: ExpandLinkProps) {
return props.hasChildren ? (
@@ -100,8 +111,33 @@ const renderFolderIcon = (folderIcon: FolderIcon) => {
return
;
};
-// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
-function FolderItem(props: any) {
+type ItemDragListener = DragEventHandler;
+type ItemContextMenuListener = MouseEventHandler;
+type ItemClickListener = MouseEventHandler;
+
+interface FolderItemProps {
+ themeId: number;
+ hasChildren: boolean;
+ showFolderIcon: boolean;
+ isExpanded: boolean;
+ parentId: string;
+ depth: number;
+ selected: boolean;
+ folderId: string;
+ folderTitle: string;
+ folderIcon: FolderIcon;
+ anchorRef: RefObject;
+ noteCount: number;
+ onFolderDragStart_: ItemDragListener;
+ onFolderDragOver_: ItemDragListener;
+ onFolderDrop_: ItemDragListener;
+ itemContextMenu: ItemContextMenuListener;
+ folderItem_click: (folderId: string)=> void;
+ onFolderToggleClick_: ItemClickListener;
+ shareId: string;
+}
+
+function FolderItem(props: FolderItemProps) {
const { hasChildren, showFolderIcon, isExpanded, parentId, depth, selected, folderId, folderTitle, folderIcon, anchorRef, noteCount, onFolderDragStart_, onFolderDragOver_, onFolderDrop_, itemContextMenu, folderItem_click, onFolderToggleClick_, shareId } = props;
const noteCountComp = noteCount ? {noteCount} : null;
@@ -147,11 +183,9 @@ const menuUtils = new MenuUtils(CommandService.instance());
const SidebarComponent = (props: Props) => {
- // eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
- const folderItemsOrder_ = useRef();
+ const folderItemsOrder_ = useRef();
folderItemsOrder_.current = [];
- // eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
- const tagItemsOrder_ = useRef();
+ const tagItemsOrder_ = useRef();
tagItemsOrder_.current = [];
const rootRef = useRef(null);
@@ -214,8 +248,7 @@ const SidebarComponent = (props: Props) => {
getFirstAnchorItemRef,
]);
- // eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
- const onFolderDragStart_ = useCallback((event: any) => {
+ const onFolderDragStart_: ItemDragListener = useCallback(event => {
const folderId = event.currentTarget.getAttribute('data-folder-id');
if (!folderId) return;
@@ -224,14 +257,12 @@ const SidebarComponent = (props: Props) => {
event.dataTransfer.setData('text/x-jop-folder-ids', JSON.stringify([folderId]));
}, []);
- // eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
- const onFolderDragOver_ = useCallback((event: any) => {
+ const onFolderDragOver_: ItemDragListener = useCallback(event => {
if (event.dataTransfer.types.indexOf('text/x-jop-note-ids') >= 0) event.preventDefault();
if (event.dataTransfer.types.indexOf('text/x-jop-folder-ids') >= 0) event.preventDefault();
}, []);
- // eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
- const onFolderDrop_ = useCallback(async (event: any) => {
+ const onFolderDrop_: ItemDragListener = useCallback(async event => {
const folderId = event.currentTarget.getAttribute('data-folder-id');
const dt = event.dataTransfer;
if (!dt) return;
@@ -257,8 +288,7 @@ const SidebarComponent = (props: Props) => {
}
}, []);
- // eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
- const onTagDrop_ = useCallback(async (event: any) => {
+ const onTagDrop_: ItemDragListener = useCallback(async event => {
const tagId = event.currentTarget.getAttribute('data-tag-id');
const dt = event.dataTransfer;
if (!dt) return;
@@ -273,8 +303,7 @@ const SidebarComponent = (props: Props) => {
}
}, []);
- // eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
- const onFolderToggleClick_ = useCallback((event: any) => {
+ const onFolderToggleClick_: ItemClickListener = useCallback(event => {
const folderId = event.currentTarget.getAttribute('data-folder-id');
props.dispatch({
@@ -293,8 +322,7 @@ const SidebarComponent = (props: Props) => {
menu.popup({ window: bridge().window() });
}, []);
- // eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
- const itemContextMenu = useCallback(async (event: any) => {
+ const itemContextMenu: ItemContextMenuListener = useCallback(async event => {
const itemId = event.currentTarget.getAttribute('data-id');
if (itemId === Folder.conflictFolderId()) return;
@@ -472,8 +500,7 @@ const SidebarComponent = (props: Props) => {
});
}, [props.dispatch]);
- // eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
- const tagItem_click = useCallback((tag: any) => {
+ const tagItem_click = useCallback((tag: TagEntity|undefined) => {
props.dispatch({
type: 'TAG_SELECT',
id: tag ? tag.id : null,
@@ -625,8 +652,15 @@ const SidebarComponent = (props: Props) => {
);
};
- // eslint-disable-next-line @typescript-eslint/ban-types, @typescript-eslint/no-explicit-any -- Old code before rule was applied, Old code before rule was applied
- const renderHeader = (key: string, label: string, iconName: string, contextMenuHandler: Function = null, onPlusButtonClick: Function = null, extraProps: any = {}) => {
+ const renderHeader = (
+ key: string,
+ label: string,
+ iconName: string,
+ contextMenuHandler: ItemContextMenuListener|null = null,
+ onPlusButtonClick: ItemClickListener|null = null,
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
+ extraProps: any = {},
+ ) => {
const headerClick = extraProps.onClick || null;
delete extraProps.onClick;
const ref = anchorItemRef('headers', key);
@@ -637,8 +671,7 @@ const SidebarComponent = (props: Props) => {
ref={ref}
{...extraProps}
onContextMenu={contextMenuHandler}
- // eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
- onClick={(event: any) => {
+ onClick={(event: MouseEvent) => {
// if a custom click event is attached, trigger that.
if (headerClick) {
headerClick(key, event);
@@ -655,7 +688,7 @@ const SidebarComponent = (props: Props) => {
};
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
- const onKeyDown = useCallback((event: any) => {
+ const onKeyDown = useCallback((event: KeyboardEvent) => {
const keyCode = event.keyCode;
const selectedItem = getSelectedItem();
diff --git a/packages/lib/reducer.ts b/packages/lib/reducer.ts
index 738f92339..cd7f632c0 100644
--- a/packages/lib/reducer.ts
+++ b/packages/lib/reducer.ts
@@ -45,7 +45,7 @@ interface StateClipperServer {
port: number;
}
-interface StateDecryptionWorker {
+export interface StateDecryptionWorker {
state: string;
itemIndex: number;
itemCount: number;
@@ -55,8 +55,9 @@ interface StateDecryptionWorker {
skippedItemCount: number;
}
-interface StateResourceFetcher {
+export interface StateResourceFetcher {
toFetchCount: number;
+ fetchingCount: number;
}
export interface StateLastDeletion {
@@ -187,6 +188,7 @@ export const defaultState: State = {
selectedNoteTags: [],
resourceFetcher: {
toFetchCount: 0,
+ fetchingCount: 0,
},
backwardHistoryNotes: [],
forwardHistoryNotes: [],
diff --git a/packages/lib/services/commands/MenuUtils.ts b/packages/lib/services/commands/MenuUtils.ts
index aa90ba777..88e394638 100644
--- a/packages/lib/services/commands/MenuUtils.ts
+++ b/packages/lib/services/commands/MenuUtils.ts
@@ -10,10 +10,10 @@ export interface MenuItem {
id?: string;
label?: string;
// eslint-disable-next-line @typescript-eslint/ban-types -- Old code before rule was applied
- click?: Function;
+ click?: ()=> void;
// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Old code before rule was applied
role?: any;
- type?: string;
+ type?: 'normal'|'separator'|'submenu';
accelerator?: string;
checked?: boolean;
enabled?: boolean;