From b0b764f073cb8f95eba5e90b491dd583234eab8f Mon Sep 17 00:00:00 2001 From: maksis Date: Tue, 31 Dec 2024 19:14:52 +0200 Subject: [PATCH] Fix various SonarLint warnings --- src/components/CountLabel.tsx | 6 +- src/components/ExternalLink.tsx | 18 +++- src/components/InstallPrompt.tsx | 4 +- .../builder/slidingMenuBuilder.tsx | 14 ++-- .../decorators/UserMenuDecorator.tsx | 2 +- .../effects/useActionMenuItems.tsx | 4 +- .../autosuggest/base/SuggestField.tsx | 9 +- src/components/browserbar/Section.tsx | 5 +- src/components/browserbar/style.css | 2 +- .../__tests__/DownloadDialog.test.tsx | 10 +-- .../download/layout/DownloadView.tsx | 4 +- .../download/layout/sections/PathListItem.tsx | 14 +++- src/components/file-preview/AudioFile.tsx | 4 +- src/components/file-preview/VideoFile.tsx | 4 +- .../filebrowser/FileBrowserDialog.tsx | 2 +- .../filebrowser/sections/FileItemList.tsx | 25 +++--- src/components/format/FormattedFile.tsx | 5 +- src/components/main/AuthenticatedApp.tsx | 4 +- src/components/main/MeasuredBackground.tsx | 4 +- src/components/semantic/Accordion.tsx | 2 +- src/components/semantic/ActionInput.tsx | 2 +- src/components/semantic/Button.tsx | 2 +- src/components/semantic/Checkbox.tsx | 2 +- src/components/semantic/ConfirmDialog.tsx | 4 +- src/components/semantic/Dropdown.tsx | 26 +++--- src/components/semantic/InputDialog.tsx | 2 +- src/components/semantic/LinkButton.tsx | 35 ++++++++ src/components/semantic/Modal.tsx | 4 +- src/components/semantic/Popup.tsx | 6 +- src/components/semantic/SectionedDropdown.tsx | 4 +- src/components/semantic/TableDropdown.tsx | 2 +- src/components/semantic/effects/useModal.ts | 4 +- src/components/table/Cell.tsx | 32 ++----- src/components/table/TableContainer.tsx | 4 +- src/components/table/TextFilter.tsx | 6 +- src/components/table/VirtualTable.tsx | 4 - src/components/table/style.css | 15 +--- .../text/highlights/HighlightUrlLink.tsx | 17 ++-- .../__tests__/FavoriteHubDialog.test.tsx | 10 +-- .../components/FavoriteHubDialog.tsx | 4 +- src/routes/Home/components/Home.tsx | 2 +- src/routes/Home/components/WidgetLayout.tsx | 6 +- src/routes/Login/components/Login.tsx | 4 +- ...oginStateEffect.ts => LoginStateEffect.ts} | 7 +- .../Queue/components/BundleFileDialog.tsx | 6 +- .../Queue/components/BundleSourceDialog.tsx | 6 +- .../Queue/components/BundleSourceTable.tsx | 23 ++--- src/routes/Queue/components/Queue.tsx | 2 +- src/routes/Search/components/ResultTable.tsx | 6 +- src/routes/Search/components/Search.tsx | 10 +-- src/routes/Search/components/SearchInput.tsx | 4 +- .../options-panel/FileTypeField.tsx | 2 +- .../options-panel/HubSelectField.tsx | 2 +- .../options-panel/SearchOptionsForm.tsx | 2 +- .../components/options-panel/SizeField.tsx | 4 +- .../components/result-dialog/ResultDialog.tsx | 6 +- .../result-dialog/UserResultTable.tsx | 9 +- src/routes/Settings/components/MenuItems.tsx | 57 +------------ .../Settings/components/SettingSection.tsx | 24 +++--- .../components/SettingsSideMenuLayout.tsx | 2 +- .../components/FavoriteDirectoryDialog.tsx | 2 +- .../Downloads/components/SearchTypeDialog.tsx | 2 +- .../components/extension/Extension.tsx | 20 ++--- .../routes/System/components/LogSection.tsx | 5 +- .../routes/System/components/WebUsersPage.tsx | 2 +- .../__tests__/ShareDirectoryDialog.test.tsx | 6 +- .../Share/components/ShareDirectoryDialog.tsx | 5 +- .../Sidebar/components/RecentLayout.tsx | 1 - .../Sidebar/components/SessionLayout.tsx | 23 ++--- src/routes/Sidebar/components/Sidebar.tsx | 10 +-- .../Sidebar/components/TopMenuLayout.tsx | 4 +- .../components/chat/MessageComposer.tsx | 6 +- .../chat/effects/useChatFileUploader.ts | 6 +- .../chat/effects/useMessageComposer.ts | 5 +- .../components/effects/useSessionHelpers.ts | 1 - .../Filelists/components/FilelistFooter.tsx | 4 +- .../components/FilelistItemTable.tsx | 6 -- .../Filelists/components/FilelistNew.tsx | 9 +- .../FilelistItemInfoDialog.tsx | 6 +- .../routes/Files/components/FileFooter.tsx | 4 +- .../routes/Hubs/components/HubFooter.tsx | 4 +- .../Sidebar/routes/Hubs/components/HubNew.tsx | 8 +- .../routes/Messages/components/MessageNew.tsx | 8 +- src/routes/Transfers/components/Transfers.tsx | 2 +- src/stores/LocalSettingStore.ts | 2 +- src/stores/LoginStore.ts | 2 +- src/style.css | 43 ++++++---- src/tests/test-form-helpers.tsx | 9 +- src/utils/ActionUtils.ts | 7 +- src/utils/BrowserUtils.ts | 4 +- src/utils/FormUtils.ts | 8 +- src/utils/Formatter.ts | 4 +- src/utils/MenuUtils.ts | 2 - src/utils/TranslationUtils.ts | 2 +- src/utils/semantic.js | 1 - .../components/ExtensionInfoEntry.tsx | 2 - .../Extensions/components/Extensions.tsx | 4 +- src/widgets/RSS/actions/RSSActions.ts | 4 +- .../Transfers/components/Transfers.tsx | 15 ++-- webpack/bundle-loader.js | 83 ------------------- 100 files changed, 351 insertions(+), 501 deletions(-) create mode 100644 src/components/semantic/LinkButton.tsx rename src/routes/Login/effects/{UseLoginStateEffect.ts => LoginStateEffect.ts} (90%) delete mode 100644 webpack/bundle-loader.js diff --git a/src/components/CountLabel.tsx b/src/components/CountLabel.tsx index f450189e5..a1c93cdb3 100644 --- a/src/components/CountLabel.tsx +++ b/src/components/CountLabel.tsx @@ -15,11 +15,11 @@ export interface CountLabelProps { size?: string; circular?: boolean; className?: string; - onClick?: (evt: React.SyntheticEvent) => void; + // onClick?: (evt: React.SyntheticEvent) => void; } const CountLabel = React.forwardRef(function CountLabel( - { urgencies, empty = false, size, className, circular = false, onClick }, + { urgencies, empty = false, size, className, circular = false }, ref, ) { // We must always have valid urgencies when the component is rendered (checked by AnimatedCountLabel) @@ -42,7 +42,7 @@ const CountLabel = React.forwardRef(function Co ); return ( -
+
{empty ? null : urgencies[max]}
); diff --git a/src/components/ExternalLink.tsx b/src/components/ExternalLink.tsx index 681ffaa28..fb73a63cd 100644 --- a/src/components/ExternalLink.tsx +++ b/src/components/ExternalLink.tsx @@ -3,10 +3,22 @@ import * as React from 'react'; type ExternalLinkProps = React.PropsWithChildren<{ url: string; className?: string; -}>; +}> & + React.AnchorHTMLAttributes; -const ExternalLink: React.FC = ({ url, children, className = '' }) => ( - +const ExternalLink: React.FC = ({ + url, + children, + className = '', + ...other +}) => ( + {children} ); diff --git a/src/components/InstallPrompt.tsx b/src/components/InstallPrompt.tsx index 1549b0f4c..5c4eca4f0 100644 --- a/src/components/InstallPrompt.tsx +++ b/src/components/InstallPrompt.tsx @@ -1,8 +1,6 @@ import { useContext } from 'react'; import * as React from 'react'; -//import ExternalLink from 'components/ExternalLink'; -//import LinkConstants from 'constants/LinkConstants'; import Message from 'components/semantic/Message'; import Button from 'components/semantic/Button'; @@ -47,7 +45,7 @@ const InstallPrompt: React.FC = ({ alwaysShow }) => { diff --git a/src/components/semantic/Checkbox.tsx b/src/components/semantic/Checkbox.tsx index a57400fd1..60cd8bf77 100644 --- a/src/components/semantic/Checkbox.tsx +++ b/src/components/semantic/Checkbox.tsx @@ -23,7 +23,7 @@ export interface CheckboxProps { className?: string; style?: React.CSSProperties; settings?: SemanticUI.CheckboxSettings; - beforeUnchecked?: () => void; + beforeUnchecked?: () => void | false; id?: string; name?: string; diff --git a/src/components/semantic/ConfirmDialog.tsx b/src/components/semantic/ConfirmDialog.tsx index b0d7f4473..16c324b73 100644 --- a/src/components/semantic/ConfirmDialog.tsx +++ b/src/components/semantic/ConfirmDialog.tsx @@ -53,7 +53,7 @@ const ConfirmDialog: React.FC = (props) => { // We can't use the basic (fully dimmed) style inside other modals const basic = !closeContext; return ReactDOM.createPortal( -
+
{title}
@@ -83,7 +83,7 @@ const ConfirmDialog: React.FC = (props) => { />
-
, + , document.getElementById(MODAL_NODE_ID)!, ); }; diff --git a/src/components/semantic/Dropdown.tsx b/src/components/semantic/Dropdown.tsx index 8c76f5e9d..4d71cf201 100644 --- a/src/components/semantic/Dropdown.tsx +++ b/src/components/semantic/Dropdown.tsx @@ -46,7 +46,7 @@ interface State { const ANIMATION_DURATION = 200; class Dropdown extends React.PureComponent { - static defaultProps: Pick = { + static readonly defaultProps: Pick = { direction: 'auto', leftIcon: false, }; @@ -103,12 +103,21 @@ class Dropdown extends React.PureComponent { $(this.c).dropdown(settings); }; + getIcon = () => { + const { triggerIcon, selection } = this.props; + + if (triggerIcon !== undefined) { + return triggerIcon; + } + + return selection ? 'dropdown' : IconConstants.EXPAND; + }; + render() { const { leftIcon, caption, button, - triggerIcon, captionIcon, dropDownElementProps, selection, @@ -128,18 +137,7 @@ class Dropdown extends React.PureComponent { { 'selection fluid': selection }, ); - const icon = ( - - ); + const icon = ; return (
{ onApproved = () => { if (!this.c.reportValidity()) { - return Promise.reject(); + return Promise.reject(Error('Invalid input')); } return this.props.onApproved(this.state.value); diff --git a/src/components/semantic/LinkButton.tsx b/src/components/semantic/LinkButton.tsx new file mode 100644 index 000000000..7160d4699 --- /dev/null +++ b/src/components/semantic/LinkButton.tsx @@ -0,0 +1,35 @@ +import * as React from 'react'; + +import classNames from 'classnames'; + +import 'fomantic-ui-css/components/button.min.css'; + +export interface LinkButtonProps extends React.ButtonHTMLAttributes { + // Disable button (the button will be disabled automatically when 'loading' is true) + disabled?: boolean; + + caption: React.ReactNode; +} + +const LinkButton: React.FC = ({ + className, + caption, + disabled, + color = 'blue', + ...other +}) => { + const buttonStyle = classNames( + 'ui button basic link', + { disabled: !!disabled }, + color, + className, + ); + + return ( + + ); +}; + +export default LinkButton; diff --git a/src/components/semantic/Modal.tsx b/src/components/semantic/Modal.tsx index 076d04afc..1447febf7 100644 --- a/src/components/semantic/Modal.tsx +++ b/src/components/semantic/Modal.tsx @@ -70,7 +70,7 @@ const Modal = React.forwardRef(function Modal(props, ha const mainClass = classNames('ui modal', { full: fullHeight }, className); return ReactDOM.createPortal( - , + , document.getElementById(MODAL_NODE_ID)!, ); }); diff --git a/src/components/semantic/Popup.tsx b/src/components/semantic/Popup.tsx index 2b9c33c5d..35b23b9c1 100644 --- a/src/components/semantic/Popup.tsx +++ b/src/components/semantic/Popup.tsx @@ -37,9 +37,7 @@ interface PopupContentProps extends Pick { const PopupContent: React.FC = (props) => { const content = useMemo(() => { const { children } = props; - return typeof children === 'function' - ? children(props.hide) - : (children as ChildType); + return typeof children === 'function' ? children(props.hide) : children; }, [props.contentUpdateTrigger]); useEffect(() => { @@ -56,7 +54,7 @@ interface State { visible: boolean; } class Popup extends React.PureComponent { - static defaultProps: Pick = { + static readonly defaultProps: Pick = { position: 'bottom left', triggerClassName: '', }; diff --git a/src/components/semantic/SectionedDropdown.tsx b/src/components/semantic/SectionedDropdown.tsx index 6a4e468ec..10061a255 100644 --- a/src/components/semantic/SectionedDropdown.tsx +++ b/src/components/semantic/SectionedDropdown.tsx @@ -15,9 +15,9 @@ const SectionedDropdown: React.FC = ({ children, ...othe {React.Children.map(validChildren, (child, index) => { return ( - + ).key ?? index}> {child} - {validChildren.length && index !== validChildren.length - 1 && ( + {!!validChildren.length && index !== validChildren.length - 1 && (
)} diff --git a/src/components/semantic/TableDropdown.tsx b/src/components/semantic/TableDropdown.tsx index 350aabfad..f6fe6396f 100644 --- a/src/components/semantic/TableDropdown.tsx +++ b/src/components/semantic/TableDropdown.tsx @@ -27,7 +27,7 @@ export interface TableDropdownProps { } class TableDropdown extends React.Component { - static defaultProps: Pick< + static readonly defaultProps: Pick< TableDropdownProps, 'linkCaption' | 'triggerIcon' | 'position' > = { diff --git a/src/components/semantic/effects/useModal.ts b/src/components/semantic/effects/useModal.ts index dda02b154..fd16b8497 100644 --- a/src/components/semantic/effects/useModal.ts +++ b/src/components/semantic/effects/useModal.ts @@ -13,7 +13,7 @@ export type CommonModalProps = { type ModalSettings = Partial; export const useModal = (props: CommonModalProps, customSettings: ModalSettings) => { - const ref = React.useRef(null); + const ref = React.useRef(null); // Set to true when the modal is being closed cleanly (backdrop click/action buttons) // We need to clean the DOM for non-clean closures @@ -51,7 +51,7 @@ export const useModal = (props: CommonModalProps, customSettings: ModalSettings) return false; } - return; + return void 0; }; React.useLayoutEffect(() => { diff --git a/src/components/table/Cell.tsx b/src/components/table/Cell.tsx index 35842180b..19ea6e6d9 100644 --- a/src/components/table/Cell.tsx +++ b/src/components/table/Cell.tsx @@ -21,16 +21,13 @@ import * as API from 'types/api'; import { ActionHandlerDecorator } from 'decorators/ActionHandlerDecorator'; import { useSession } from 'context/SessionContext'; import { formatDecimal } from 'utils/ValueFormat'; +import LinkButton from 'components/semantic/LinkButton'; const getCellContent = (cellData: any) => { if (typeof cellData === 'object') { return Array.isArray(cellData) ? cellData.length : cellData.str; } - //if (typeof cellData === 'boolean') { - // return cellData ? 'Yes' : 'No'; - //} - if (cellData === 0) { return null; } @@ -52,7 +49,7 @@ interface HeaderCellProps extends CellProps { export const HeaderCell = ({ onClick, label, columnKey, ...props }: HeaderCellProps) => ( - {label} + ); @@ -83,6 +80,7 @@ export const FileActionCell = < typeInfo={rowDataGetter!().type} caption={cellData} className="icon-caption" + linkColor="black" /> } itemData={rowDataGetter!} @@ -145,7 +143,7 @@ export const ActionLinkCell = < return ( > {({ onClickAction }) => ( - onClickAction({ @@ -155,27 +153,14 @@ export const ActionLinkCell = < entity: entity as EntityT, }) } - > - {getCellContent(cellData)} - + caption={getCellContent(cellData)} + color="black" + /> )} ); - - /*return ( - - );*/ }; -//export const ActionLinkCell = ActionHandlerDecorator(ActionLinkCellPlain); - export interface NumberCellProps extends RowWrapperCellChildProps { cellData?: number; } @@ -267,10 +252,11 @@ export const FileDownloadCell = < onClick={clickHandlerGetter ? clickHandlerGetter(cellData, rowDataGetter!) : null} caption={cellData} className="icon-caption" + linkColor="black" /> } user={userGetter(rowDataGetter!())} - linkCaption={!!clickHandlerGetter ? false : true} + linkCaption={!clickHandlerGetter} itemInfoGetter={rowDataGetter!} downloadHandler={downloadHandler} {...props} diff --git a/src/components/table/TableContainer.tsx b/src/components/table/TableContainer.tsx index a05db028e..72d43dc15 100644 --- a/src/components/table/TableContainer.tsx +++ b/src/components/table/TableContainer.tsx @@ -3,7 +3,7 @@ import * as React from 'react'; import { Table, ColumnProps } from 'fixed-data-table-2'; import TableActions from 'actions/TableActions'; -import { useMobileLayout } from 'utils/BrowserUtils'; +import { usingMobileLayout } from 'utils/BrowserUtils'; import Measure, { ContentRect } from 'react-measure'; import RowWrapperCell from 'components/table/RowWrapperCell'; @@ -207,7 +207,7 @@ class TableContainer extends React.Component { const { cell, columnKey, renderCondition } = column.props; const { store, rowClassNameGetter, moduleId, t } = this.props; - const mobileView = useMobileLayout(); + const mobileView = usingMobileLayout(); if (!mobileView) { // Get column width if (!!columnKey && !!this.state.columnWidths[columnKey]) { diff --git a/src/components/table/TextFilter.tsx b/src/components/table/TextFilter.tsx index 64eaf9d15..4df2555e3 100644 --- a/src/components/table/TextFilter.tsx +++ b/src/components/table/TextFilter.tsx @@ -11,7 +11,7 @@ import TableFilterDecorator, { import * as API from 'types/api'; import * as UI from 'types/ui'; -import { useMobileLayout } from 'utils/BrowserUtils'; +import { usingMobileLayout } from 'utils/BrowserUtils'; import { translate } from 'utils/TranslationUtils'; import { Translation } from 'react-i18next'; @@ -57,7 +57,7 @@ class TextFilter extends React.PureComponent< timer: number | undefined; input: HTMLInputElement; - static defaultProps: Pick = { + static readonly defaultProps: Pick = { autoFocus: true, }; @@ -118,7 +118,7 @@ class TextFilter extends React.PureComponent< onChange={this.onTextChanged} value={value} type="text" - autoFocus={!useMobileLayout() && autoFocus} + autoFocus={!usingMobileLayout() && autoFocus} /> { ); componentDidMount() { - //this._dataLoader = new RowDataLoader(this.props.store, () => this.forceUpdate() ); - - //this.unsubscribe = this.props.store.listen(this._dataLoader.onItemsUpdated.bind(this._dataLoader)); - this.start(this.props.entityId); } diff --git a/src/components/table/style.css b/src/components/table/style.css index 787233e5c..dd1119353 100644 --- a/src/components/table/style.css +++ b/src/components/table/style.css @@ -27,11 +27,6 @@ outline: inherit; } -.virtual-table .public_fixedDataTable_header a, -.public_fixedDataTableCell_main a { - color: black; -} - /* Common cell content styles */ .virtual-table .cell-wrapper { @@ -96,6 +91,10 @@ /* Table dropdowns */ .table-container-wrapper .dropdown > .popup.trigger { max-width: 100%; + + line-height: 21px; + display: flex; + align-items: flex-start; } .table-container-wrapper .dropdown > .popup.trigger .caption { @@ -106,12 +105,6 @@ overflow: hidden; } -.table-container-wrapper .dropdown > .popup.trigger { - line-height: 21px; - display: flex; - align-items: flex-start; -} - .table-container-wrapper .dropdown > .popup.trigger:hover, .public_fixedDataTableCell_main a:hover { cursor: pointer; diff --git a/src/components/text/highlights/HighlightUrlLink.tsx b/src/components/text/highlights/HighlightUrlLink.tsx index a80f73d92..1e764f9ba 100644 --- a/src/components/text/highlights/HighlightUrlLink.tsx +++ b/src/components/text/highlights/HighlightUrlLink.tsx @@ -7,6 +7,7 @@ import HubSessionStore from 'stores/HubSessionStore'; import { useNavigate, useLocation, NavigateFunction, Location } from 'react-router'; import { AuthenticatedSession, useSession } from 'context/SessionContext'; +import ExternalLink from 'components/ExternalLink'; const onClickLink = ( evt: React.MouseEvent, @@ -16,9 +17,9 @@ const onClickLink = ( ) => { const uri: string = (evt.target as any).href; if ( - uri.indexOf('adc://') === 0 || - uri.indexOf('adcs://') === 0 || - uri.indexOf('dchub://') === 0 + uri.startsWith('adc://') || + uri.startsWith('adcs://') || + uri.startsWith('dchub://') ) { evt.preventDefault(); @@ -44,15 +45,11 @@ export const HighlightUrlLink: React.FC = ({ text, ...oth const location = useLocation(); const navigate = useNavigate(); return ( - onClickLink(evt, location, navigate, session)} - {...other} + url={text} > {text} - + ); }; diff --git a/src/routes/FavoriteHubs/__tests__/FavoriteHubDialog.test.tsx b/src/routes/FavoriteHubs/__tests__/FavoriteHubDialog.test.tsx index ae50da3e7..bc89dea46 100644 --- a/src/routes/FavoriteHubs/__tests__/FavoriteHubDialog.test.tsx +++ b/src/routes/FavoriteHubs/__tests__/FavoriteHubDialog.test.tsx @@ -98,7 +98,7 @@ describe('FavoriteHubDialog', () => { }, ]; - const renderData = await renderRoutes(routes, { + const renderData = renderRoutes(routes, { socket, routerProps: { initialEntries: ['/home'] }, }); @@ -137,11 +137,11 @@ describe('FavoriteHubDialog', () => { expect(onUpdated).toHaveBeenCalledTimes(1); expect(onUpdated.mock.calls[0]).toMatchSnapshot(); - }, 100000); + }); test('should create new', async () => { const userEvent = setupUserEvent(); - const { getByText, getByLabelText, modalController, onCreated, onUpdated } = + const { getByText, getByLabelText, modalController, onCreated } = await renderDialog(null); await modalController.openDialog(); @@ -162,7 +162,5 @@ describe('FavoriteHubDialog', () => { expect(onCreated).toHaveBeenCalledTimes(1); expect(onCreated.mock.calls[0]).toMatchSnapshot(); - - // stop(); - }, 100000); + }); }); diff --git a/src/routes/FavoriteHubs/components/FavoriteHubDialog.tsx b/src/routes/FavoriteHubs/components/FavoriteHubDialog.tsx index 6137b471a..911719880 100644 --- a/src/routes/FavoriteHubs/components/FavoriteHubDialog.tsx +++ b/src/routes/FavoriteHubs/components/FavoriteHubDialog.tsx @@ -206,7 +206,7 @@ const toFavoriteHub = ( }; const isAdcHub = (hubUrl?: string) => - !!hubUrl && (hubUrl.indexOf('adc://') === 0 || hubUrl.indexOf('adcs://') === 0); + !!hubUrl && (hubUrl.startsWith('adc://') || hubUrl.startsWith('adcs://')); // Get selection values for the profiles field const getFieldProfiles = ( @@ -286,7 +286,7 @@ const FavoriteHubDialog: React.FC = ({ } return socket.patch( - `${FavoriteHubConstants.HUBS_URL}/${hubEntry!.id}`, + `${FavoriteHubConstants.HUBS_URL}/${hubEntry.id}`, updatedEntryFields, ); }; diff --git a/src/routes/Home/components/Home.tsx b/src/routes/Home/components/Home.tsx index ef7773d1a..9fd6f5c36 100644 --- a/src/routes/Home/components/Home.tsx +++ b/src/routes/Home/components/Home.tsx @@ -8,7 +8,7 @@ import WidgetLayout from 'routes/Home/components/WidgetLayout'; import '../style.css'; class Home extends Component { - static displayName = 'Home'; + static readonly displayName = 'Home'; render() { return ( diff --git a/src/routes/Home/components/WidgetLayout.tsx b/src/routes/Home/components/WidgetLayout.tsx index a38eac727..baaf63eca 100644 --- a/src/routes/Home/components/WidgetLayout.tsx +++ b/src/routes/Home/components/WidgetLayout.tsx @@ -25,17 +25,17 @@ const mapWidget = ( layoutItem: Layout, rootWidgetT: UI.ModuleTranslator, ): React.ReactNode => { - const widgetInfo = WidgetStore.getWidgetInfoById(layoutItem.i!); + const widgetInfo = WidgetStore.getWidgetInfoById(layoutItem.i); invariant(widgetInfo, 'Widget info missing'); if (!widgetInfo) { return null; } - const settings = WidgetStore.getWidgetSettings(layoutItem.i!, widgetInfo); + const settings = WidgetStore.getWidgetSettings(layoutItem.i, widgetInfo); return ( = () => { const usernameRef = useRef(null); const passwordRef = useRef(null); - const [loading, setLoading] = useSessionState(); + const { loading, setLoading } = useSessionState(); if (!!refreshToken) { return ( { - const loadingState = useState(false); - const setLoading = loadingState[1]; + const [loading, setLoading] = useState(false); const { i18n } = useTranslation(); const location = useLocation(); const navigate = useNavigate(); @@ -29,7 +28,7 @@ const useSessionState = () => { // Redirect to the main app const state = location.state as LoginLocationState; - const nextPath = state && state.nextPath ? state.nextPath : '/'; + const nextPath = state?.nextPath ?? '/'; navigate(nextPath, { replace: true }); } else if (!!loginInfo.lastError && !LoginStore.refreshToken) { // Keep the loading state as true as long as there is socket actions happening @@ -53,7 +52,7 @@ const useSessionState = () => { } }, []); - return loadingState; + return { loading, setLoading }; }; export { useSessionState }; diff --git a/src/routes/Queue/components/BundleFileDialog.tsx b/src/routes/Queue/components/BundleFileDialog.tsx index af0d934ad..e3a28ee21 100644 --- a/src/routes/Queue/components/BundleFileDialog.tsx +++ b/src/routes/Queue/components/BundleFileDialog.tsx @@ -20,14 +20,10 @@ interface DataProps extends DataProviderDecoratorChildProps { bundle: API.QueueBundle; } -/*interface RouteProps { - bundleId: string; -}*/ - type Props = BundleFileDialogProps & DataProps & ModalRouteDecoratorChildProps; class BundleFileDialog extends Component { - static displayName = 'BundleFileDialog'; + static readonly displayName = 'BundleFileDialog'; render() { const { bundle } = this.props; diff --git a/src/routes/Queue/components/BundleSourceDialog.tsx b/src/routes/Queue/components/BundleSourceDialog.tsx index d7e8c15fe..e22756e3b 100644 --- a/src/routes/Queue/components/BundleSourceDialog.tsx +++ b/src/routes/Queue/components/BundleSourceDialog.tsx @@ -24,14 +24,10 @@ interface DataProps extends DataProviderDecoratorChildProps { bundle: API.QueueBundle; } -/*interface RouteProps { - bundleId: string; -}*/ - type Props = BundleSourceDialogProps & ModalRouteDecoratorChildProps; class SourceDialog extends Component { - static displayName = 'SourceDialog'; + static readonly displayName = 'SourceDialog'; render() { const { bundle, queueT } = this.props; diff --git a/src/routes/Queue/components/BundleSourceTable.tsx b/src/routes/Queue/components/BundleSourceTable.tsx index e246dee03..a70dacd27 100644 --- a/src/routes/Queue/components/BundleSourceTable.tsx +++ b/src/routes/Queue/components/BundleSourceTable.tsx @@ -80,14 +80,17 @@ const BundleSourceTable: React.FC< - {sources.sort(userSort).map((source) => ( - - ))} + {sources + .slice() + .sort(userSort) + .map((source) => ( + + ))}
@@ -99,7 +102,7 @@ export default DataProviderDecorator - socket.get(`${QueueConstants.BUNDLES_URL}/${bundle!.id}/sources`), + socket.get(`${QueueConstants.BUNDLES_URL}/${bundle.id}/sources`), }, onSocketConnected: (addSocketListener, { refetchData, props }) => { addSocketListener( @@ -107,7 +110,7 @@ export default DataProviderDecorator { // Avoid flickering when there are many bundles running - if (data.id === props.bundle!.id) { + if (data.id === props.bundle.id) { refetchData(); } }, diff --git a/src/routes/Queue/components/Queue.tsx b/src/routes/Queue/components/Queue.tsx index 1dfa20a6e..c72acc0cf 100644 --- a/src/routes/Queue/components/Queue.tsx +++ b/src/routes/Queue/components/Queue.tsx @@ -53,7 +53,7 @@ const PriorityCell: React.FC< ); class Queue extends React.Component { - static displayName = 'Queue'; + static readonly displayName = 'Queue'; isActive = (cellData: any, rowData: API.QueueBundle) => { return !rowData.status.downloaded; diff --git a/src/routes/Search/components/ResultTable.tsx b/src/routes/Search/components/ResultTable.tsx index 5ea8a1ea8..de4088754 100644 --- a/src/routes/Search/components/ResultTable.tsx +++ b/src/routes/Search/components/ResultTable.tsx @@ -69,8 +69,8 @@ const UserCell: React.FC< ); const resultUserGetter = (rowData: API.GroupedSearchResult) => { - if (!rowData || !rowData.users) { - return rowData.users.user; + if (!rowData?.users) { + return rowData?.users?.user; } return rowData.users.user; @@ -106,7 +106,7 @@ export interface ResultTableProps { } class ResultTable extends React.Component { - static displayName = 'ResultTable'; + static readonly displayName = 'ResultTable'; rowClassNameGetter = (rowData: API.GroupedSearchResult) => { return dupeToStringType(rowData.dupe); diff --git a/src/routes/Search/components/Search.tsx b/src/routes/Search/components/Search.tsx index 4eaa09516..3af2b0ab4 100644 --- a/src/routes/Search/components/Search.tsx +++ b/src/routes/Search/components/Search.tsx @@ -29,10 +29,6 @@ import '../style.css'; const RESULT_WAIT_PERIOD = 4000; -/*interface SearchLocationState { - searchString?: string; -}*/ - interface SearchProps {} interface SearchDataProps extends DataProviderDecoratorChildProps, WithTranslation { @@ -47,7 +43,7 @@ const loadHubOptions = () => { }; const saveHubOptions = (hubs: string[] | null) => { - if (!hubs || !hubs.length) { + if (!hubs?.length) { removeSessionProperty(SEARCH_HUBS_KEY); } else { saveSessionProperty(SEARCH_HUBS_KEY, hubs); @@ -106,7 +102,7 @@ const Search: React.FC = ({ instance, t }) => { const checkLocationState = () => { const { state } = location; - if (state && state.searchString /* && state.searchString !== searchString*/) { + if (state?.searchString /* && state.searchString !== searchString*/) { search(state.searchString); // Avoid searching for it again @@ -125,7 +121,7 @@ const Search: React.FC = ({ instance, t }) => { useEffect(() => { checkLocationState(); - }, [location.state && location.state.searchString]); + }, [location.state?.searchString]); useEffect(() => { if (!running) { diff --git a/src/routes/Search/components/SearchInput.tsx b/src/routes/Search/components/SearchInput.tsx index 25d1b0c06..e0773ef8e 100644 --- a/src/routes/Search/components/SearchInput.tsx +++ b/src/routes/Search/components/SearchInput.tsx @@ -8,7 +8,7 @@ import Button from 'components/semantic/Button'; import * as UI from 'types/ui'; import IconConstants from 'constants/IconConstants'; -import { useMobileLayout } from 'utils/BrowserUtils'; +import { usingMobileLayout } from 'utils/BrowserUtils'; import { SearchOptionsButton, SearchOptions } from './options-panel'; interface SearchInputProps { @@ -28,7 +28,7 @@ const SearchInput: React.FC = ({ }) => { const [options, setOptions] = useState(defaultOptions); - const mobile = useMobileLayout(); + const mobile = usingMobileLayout(); return (
diff --git a/src/routes/Search/components/options-panel/FileTypeField.tsx b/src/routes/Search/components/options-panel/FileTypeField.tsx index 64f62054f..5c9c9811a 100644 --- a/src/routes/Search/components/options-panel/FileTypeField.tsx +++ b/src/routes/Search/components/options-panel/FileTypeField.tsx @@ -45,7 +45,7 @@ const typeToMenuItem = ( selectedItem: UI.SearchTypeItem, ) => ( onChange(type.id)} icon={} active={selectedItem.id === type.id} diff --git a/src/routes/Search/components/options-panel/HubSelectField.tsx b/src/routes/Search/components/options-panel/HubSelectField.tsx index 191824c11..f28dddbcd 100644 --- a/src/routes/Search/components/options-panel/HubSelectField.tsx +++ b/src/routes/Search/components/options-panel/HubSelectField.tsx @@ -32,7 +32,7 @@ const HubSelectField: React.FC = ({ hubs, value, onChange }) => { return false; } - return; + return void 0; }; return ( diff --git a/src/routes/Search/components/options-panel/SearchOptionsForm.tsx b/src/routes/Search/components/options-panel/SearchOptionsForm.tsx index 04242979e..3f4cfed3c 100644 --- a/src/routes/Search/components/options-panel/SearchOptionsForm.tsx +++ b/src/routes/Search/components/options-panel/SearchOptionsForm.tsx @@ -81,7 +81,7 @@ const removeEmptyProperties = (formValue: Entry) => { }; class SearchOptionsForm extends PureComponent { - static displayName = 'SearchOptionForm'; + static readonly displayName = 'SearchOptionForm'; constructor(props: SearchOptionsFormProps) { super(props); diff --git a/src/routes/Search/components/options-panel/SizeField.tsx b/src/routes/Search/components/options-panel/SizeField.tsx index 89e73fdf6..b9eca2cdc 100644 --- a/src/routes/Search/components/options-panel/SizeField.tsx +++ b/src/routes/Search/components/options-panel/SizeField.tsx @@ -33,7 +33,7 @@ const SizeField: React.FC = ({ inputProps, moduleT, onChange, value }) => const [unitIndex, setUnitIndex] = useState(initialData.unitIndex); const valueToBytes = () => { - let ret = displayValue || 0; + let ret = displayValue ?? 0; if (!!unitIndex) { for (let i = 1; i <= unitIndex; i++) { ret *= 1024; @@ -68,7 +68,7 @@ const SizeField: React.FC = ({ inputProps, moduleT, onChange, value }) => type="number" {...inputProps} min={0} - value={displayValue || ''} + value={displayValue ?? ''} onChange={(evt) => { const newValue = !!evt.target.value ? parseInt(evt.target.value) : null; if (!!newValue) { diff --git a/src/routes/Search/components/result-dialog/ResultDialog.tsx b/src/routes/Search/components/result-dialog/ResultDialog.tsx index dec6114a0..4a85f1306 100644 --- a/src/routes/Search/components/result-dialog/ResultDialog.tsx +++ b/src/routes/Search/components/result-dialog/ResultDialog.tsx @@ -29,14 +29,10 @@ interface DataProps extends DataProviderDecoratorChildProps { parentResult: API.GroupedSearchResult; } -/*interface RouteProps { - resultId: string; -}*/ - type Props = ResultDialogProps & ModalRouteDecoratorChildProps; class ResultDialog extends Component { - static displayName = 'ResultDialog'; + static readonly displayName = 'ResultDialog'; itemDataGetter: UI.DownloadItemDataGetter = ( itemId, diff --git a/src/routes/Search/components/result-dialog/UserResultTable.tsx b/src/routes/Search/components/result-dialog/UserResultTable.tsx index e47b20f50..d069fa3f4 100644 --- a/src/routes/Search/components/result-dialog/UserResultTable.tsx +++ b/src/routes/Search/components/result-dialog/UserResultTable.tsx @@ -88,9 +88,12 @@ const UserResultTable: React.FC - {results.sort(resultSort).map((result) => ( - - ))} + {results + .slice() + .sort(resultSort) + .map((result) => ( + + ))}
diff --git a/src/routes/Settings/components/MenuItems.tsx b/src/routes/Settings/components/MenuItems.tsx index 23e215e10..c8f906e97 100644 --- a/src/routes/Settings/components/MenuItems.tsx +++ b/src/routes/Settings/components/MenuItems.tsx @@ -26,10 +26,6 @@ const menuItemToLinkComponent = ( settingsT: UI.ModuleTranslator, { hasAccess }: AuthenticatedSession, ) => { - /*if (menuItemInfo.debugOnly && process.env.NODE_ENV === 'production') { - return null; - }*/ - if (menuItemInfo.access && !hasAccess(menuItemInfo.access)) { return null; } @@ -53,8 +49,8 @@ export const rootMenuItemToLinkComponent = ( ) => { // Browsing is smoother when the child page is loaded directly // Don't use the child URL for currently active parent so that the route is detected as active correctly - let url = sectionToUrl(rootMenuItem, undefined); - if (rootMenuItem.menuItems && location.pathname.indexOf(url) !== 0) { + let url = sectionToUrl(rootMenuItem); + if (rootMenuItem.menuItems && !location.pathname.startsWith(url)) { url = sectionToUrl(rootMenuItem.menuItems[0], rootMenuItem); } @@ -71,55 +67,6 @@ export const childMenuItemToLinkComponent = ( return menuItemToLinkComponent(url, childMenuItem, settingsT, session); }; -/*export const menuItemsToRouteComponentArray = ( - currentMenuItem: SectionType, - menuItems: SectionType[] | undefined, - settingsT: UI.ModuleTranslator, - moduleT: UI.ModuleTranslator | undefined, - parent: SectionType | undefined -) => { - if (!menuItems) { - return null; - } - - return menuItems.map((item) => ( - - } - /> - )); -};*/ - -/*export const isItemActive = ( - item: ChildSectionType, - parent: RootSectionType | undefined, - location: Location -) => { - return location.pathname.indexOf(sectionToUrl(item, parent)) === 0; -}; - -export const findMenuItem = ( - menuItems: ChildSectionType[], - parent: RootSectionType | undefined, - location: Location -) => { - if (!menuItems) { - return null; - } - - return menuItems.find((item) => isItemActive(item, parent, location)); -};*/ - export const findMainSection = ( mainSection: string | undefined, rootMenuItems: RootSectionType[], diff --git a/src/routes/Settings/components/SettingSection.tsx b/src/routes/Settings/components/SettingSection.tsx index 20f47d53c..cf0b1ed72 100644 --- a/src/routes/Settings/components/SettingSection.tsx +++ b/src/routes/Settings/components/SettingSection.tsx @@ -1,7 +1,7 @@ import * as React from 'react'; import classNames from 'classnames'; -import { useMobileLayout } from 'utils/BrowserUtils'; +import { usingMobileLayout } from 'utils/BrowserUtils'; import SettingsSideMenuLayout from './SettingsSideMenuLayout'; import SettingsTopMenuLayout from './SettingsTopMenuLayout'; @@ -61,7 +61,7 @@ const SettingSection: React.FC = (props) => { }); const SectionLayoutComponent = - useMobileLayout() || window.innerWidth < 1000 + usingMobileLayout() || window.innerWidth < 1000 ? SettingsTopMenuLayout : SettingsSideMenuLayout; @@ -85,20 +85,22 @@ const SettingSection: React.FC = (props) => { ), }; + const getSaveButton = (className: string) => { + if (selectedChildMenuItem.noSave) { + return null; + } + + return ( + + ); + }; + return ( - !selectedChildMenuItem.noSave && ( - - ) - } + getSaveButton={getSaveButton} message={getMessage(selectedChildMenuItem, settingsT)} contentClassname={contentClassname} menu={menu} diff --git a/src/routes/Settings/components/SettingsSideMenuLayout.tsx b/src/routes/Settings/components/SettingsSideMenuLayout.tsx index 4b7a46205..8f82528e6 100644 --- a/src/routes/Settings/components/SettingsSideMenuLayout.tsx +++ b/src/routes/Settings/components/SettingsSideMenuLayout.tsx @@ -56,7 +56,7 @@ const Content: React.FC = ({
} + icon={} rightComponent={getSaveButton()} />
diff --git a/src/routes/Settings/routes/Downloads/components/FavoriteDirectoryDialog.tsx b/src/routes/Settings/routes/Downloads/components/FavoriteDirectoryDialog.tsx index 629050488..38d5ecc0f 100644 --- a/src/routes/Settings/routes/Downloads/components/FavoriteDirectoryDialog.tsx +++ b/src/routes/Settings/routes/Downloads/components/FavoriteDirectoryDialog.tsx @@ -87,7 +87,7 @@ const FavoriteDirectoryDialog: React.FC = ({ } return socket.patch( - `${FavoriteDirectoryConstants.DIRECTORIES_URL}/${directoryEntry!.id}`, + `${FavoriteDirectoryConstants.DIRECTORIES_URL}/${directoryEntry.id}`, changedFields, ); }; diff --git a/src/routes/Settings/routes/Downloads/components/SearchTypeDialog.tsx b/src/routes/Settings/routes/Downloads/components/SearchTypeDialog.tsx index 8b27102ba..3992a1f0c 100644 --- a/src/routes/Settings/routes/Downloads/components/SearchTypeDialog.tsx +++ b/src/routes/Settings/routes/Downloads/components/SearchTypeDialog.tsx @@ -66,7 +66,7 @@ const SearchTypeDialog: React.FC = ({ } return socket.patch( - `${SearchConstants.SEARCH_TYPES_URL}/${searchTypeEntry!.id}`, + `${SearchConstants.SEARCH_TYPES_URL}/${searchTypeEntry.id}`, changedFields, ); }; diff --git a/src/routes/Settings/routes/Extensions/components/extension/Extension.tsx b/src/routes/Settings/routes/Extensions/components/extension/Extension.tsx index 101b7ea17..648ac9f95 100644 --- a/src/routes/Settings/routes/Extensions/components/extension/Extension.tsx +++ b/src/routes/Settings/routes/Extensions/components/extension/Extension.tsx @@ -19,6 +19,7 @@ import { } from 'decorators/SocketSubscriptionDecorator'; import { errorResponseToString } from 'utils/TypeConvert'; import { DataFetchError } from 'decorators/DataProviderDecorator'; +import classNames from 'classnames'; interface VersionProps { title: string; @@ -58,15 +59,7 @@ const formatAuthor = ( npmPackage?: UI.NpmPackage, installedPackage?: API.Extension, ) => { - let author: string | undefined; - if (installedPackage && installedPackage.author) { - author = installedPackage.author; - } - - if (npmPackage) { - author = npmPackage.publisher.username; - } - + const author = npmPackage ? npmPackage.publisher.username : installedPackage?.author; if (!author) { return null; } @@ -179,9 +172,9 @@ class Extension extends React.PureComponent<
- +
{formatAuthor(moduleT, npmPackage, installedPackage)}
@@ -199,7 +192,10 @@ class Extension extends React.PureComponent< />
{!npmPackage && formatNote(moduleT, installedPackage, npmError)}
{ enabled: false, }; - convertKey = (suffix?: string) => { - return `log_${this.props.section}${suffix ? `_${suffix}` : ''}`; + convertKey = (optionalSuffix?: string) => { + const suffix = optionalSuffix ? `_${optionalSuffix}` : ''; + return `log_${this.props.section}${suffix}`; }; onSettingsReceived = (settings: API.SettingValueMap) => { diff --git a/src/routes/Settings/routes/System/components/WebUsersPage.tsx b/src/routes/Settings/routes/System/components/WebUsersPage.tsx index d82d8061c..d76bb9401 100644 --- a/src/routes/Settings/routes/System/components/WebUsersPage.tsx +++ b/src/routes/Settings/routes/System/components/WebUsersPage.tsx @@ -57,7 +57,7 @@ interface WebUsersPageDataProps extends DataProviderDecoratorChildProps { } class WebUsersPage extends React.Component { - static displayName = 'WebUsersPage'; + static readonly displayName = 'WebUsersPage'; render() { const { users, moduleT } = this.props; diff --git a/src/routes/Share/__tests__/ShareDirectoryDialog.test.tsx b/src/routes/Share/__tests__/ShareDirectoryDialog.test.tsx index 8ac018946..814a51ff2 100644 --- a/src/routes/Share/__tests__/ShareDirectoryDialog.test.tsx +++ b/src/routes/Share/__tests__/ShareDirectoryDialog.test.tsx @@ -127,7 +127,7 @@ describe('ShareDirectoryDialog', () => { }, ]; - const renderData = await renderRoutes(routes, { + const renderData = renderRoutes(routes, { socket, routerProps: { initialEntries: ['/home'] }, }); @@ -214,7 +214,7 @@ describe('ShareDirectoryDialog', () => { // Set the initial browse dialog path const path = '/home/airdcpp/Downloads/'; - saveLocalProperty(getBrowseStorageKey(FilesystemConstants.LOCATION_DOWNLOAD)!, path); + saveLocalProperty(getBrowseStorageKey(FilesystemConstants.LOCATION_DOWNLOAD), path); // Open dialog and select the initial path expect(fireEvent.click(getByText('Browse'))).toBeTruthy(); @@ -253,7 +253,5 @@ describe('ShareDirectoryDialog', () => { expect(onCreated).toHaveBeenCalledTimes(1); expect(onCreated.mock.calls[0]).toMatchSnapshot(); - - // stop(); }, 100000); }); diff --git a/src/routes/Share/components/ShareDirectoryDialog.tsx b/src/routes/Share/components/ShareDirectoryDialog.tsx index 3e357271a..94fc9ea04 100644 --- a/src/routes/Share/components/ShareDirectoryDialog.tsx +++ b/src/routes/Share/components/ShareDirectoryDialog.tsx @@ -124,10 +124,7 @@ const ShareDirectoryDialog: React.FC = ({ return socket.post(ShareRootConstants.ROOTS_URL, changedFields); } - return socket.patch( - `${ShareRootConstants.ROOTS_URL}/${rootEntry!.id}`, - changedFields, - ); + return socket.patch(`${ShareRootConstants.ROOTS_URL}/${rootEntry.id}`, changedFields); }; const onFieldSetting: FormFieldSettingHandler = ( diff --git a/src/routes/Sidebar/components/RecentLayout.tsx b/src/routes/Sidebar/components/RecentLayout.tsx index 0ce0e4e3e..425a1fb24 100644 --- a/src/routes/Sidebar/components/RecentLayout.tsx +++ b/src/routes/Sidebar/components/RecentLayout.tsx @@ -3,7 +3,6 @@ import * as React from 'react'; import DataProviderDecorator, { DataProviderDecoratorChildProps, } from 'decorators/DataProviderDecorator'; -//import RedrawDecorator from 'decorators/RedrawDecorator'; import { useFormatter } from 'context/FormatterContext'; import LayoutHeader from 'components/semantic/LayoutHeader'; diff --git a/src/routes/Sidebar/components/SessionLayout.tsx b/src/routes/Sidebar/components/SessionLayout.tsx index de1c40a88..d2ab0b327 100644 --- a/src/routes/Sidebar/components/SessionLayout.tsx +++ b/src/routes/Sidebar/components/SessionLayout.tsx @@ -7,7 +7,7 @@ import SideMenuLayout from './SideMenuLayout'; import Message from 'components/semantic/Message'; -import { useMobileLayout } from 'utils/BrowserUtils'; +import { usingMobileLayout } from 'utils/BrowserUtils'; import * as API from 'types/api'; import * as UI from 'types/ui'; @@ -127,6 +127,17 @@ const SessionLayout = < const { disableSideMenu, items, unreadInfoStore, sessionT, uiActions } = props; + const useTopMenu = disableSideMenu || usingMobileLayout(layoutWidth); + + const { + getItemHeaderTitle, + getItemHeaderDescription, + getItemHeaderIcon, + getNewButton, + getSessionMenuItems, + getSessionActionMenuItems, + } = useComponents({ ...props, activeItem, hasEditAccess, isNewLayout }); + if (!hasEditAccess && items.length === 0) { // Nothing to show return ( @@ -140,17 +151,7 @@ const SessionLayout = < ); } - const useTopMenu = disableSideMenu || useMobileLayout(layoutWidth); - const MenuLayout = useTopMenu ? TopMenuLayout : SideMenuLayout; - const { - getItemHeaderTitle, - getItemHeaderDescription, - getItemHeaderIcon, - getNewButton, - getSessionMenuItems, - getSessionActionMenuItems, - } = useComponents({ ...props, activeItem, hasEditAccess, isNewLayout }); return ( = (props) => { setVisibility(Visibility.VISIBLE); }; - if (resizable.current && resizable.current.resizable) { + if (resizable.current?.resizable) { $(resizable.current.resizable).sidebar({ context: '.sidebar-context', transition: 'overlay', mobileTransition: 'overlay', - closable: !useMobileLayout(), + closable: !usingMobileLayout(), onVisible: onVisible, onShow: onShow, onHidden: onHidden, @@ -91,7 +91,7 @@ const Sidebar: React.FC = (props) => { }, []); useEffect(() => { - if (resizable.current && resizable.current.resizable) { + if (resizable.current?.resizable) { const shouldShow = showSidebar(props); if (shouldShow && visibility === Visibility.HIDDEN) { $(resizable.current.resizable).sidebar('show'); @@ -148,7 +148,7 @@ const Sidebar: React.FC = (props) => { top: false, right: false, bottom: false, - left: !useMobileLayout(), + left: !usingMobileLayout(), topRight: false, bottomRight: false, bottomLeft: false, diff --git a/src/routes/Sidebar/components/TopMenuLayout.tsx b/src/routes/Sidebar/components/TopMenuLayout.tsx index 5cd8dab68..4a9acad96 100644 --- a/src/routes/Sidebar/components/TopMenuLayout.tsx +++ b/src/routes/Sidebar/components/TopMenuLayout.tsx @@ -1,5 +1,5 @@ import * as React from 'react'; -import { useMobileLayout } from 'utils/BrowserUtils'; +import { usingMobileLayout } from 'utils/BrowserUtils'; import ActionButton from 'components/ActionButton'; import SectionedDropdown from 'components/semantic/SectionedDropdown'; @@ -58,7 +58,7 @@ const CloseButton = < actions, activeItem, }: CloseButtonProps) => { - if (!activeItem || useMobileLayout()) { + if (!activeItem || usingMobileLayout()) { return null; } diff --git a/src/routes/Sidebar/components/chat/MessageComposer.tsx b/src/routes/Sidebar/components/chat/MessageComposer.tsx index fe99abfe1..242207049 100644 --- a/src/routes/Sidebar/components/chat/MessageComposer.tsx +++ b/src/routes/Sidebar/components/chat/MessageComposer.tsx @@ -4,7 +4,7 @@ import classNames from 'classnames'; import { MentionsInput, Mention, DataFunc } from 'react-mentions'; import Dropzone, { DropzoneRef } from 'react-dropzone'; -import { useMobileLayout } from 'utils/BrowserUtils'; +import { usingMobileLayout } from 'utils/BrowserUtils'; import UserConstants from 'constants/UserConstants'; @@ -102,11 +102,11 @@ export const MessageComposer: React.FC = (props) => { }) .then((users: API.HubUser[]) => callback(users.map(userToMention))) .catch((error: ErrorResponse) => - console.log(`Failed to fetch suggestions: ${error}`), + console.log(`Failed to fetch suggestions: ${error.message}`), ); }; - const mobile = useMobileLayout(); + const mobile = usingMobileLayout(); const className = classNames('ui form composer', { small: mobile }, { large: !mobile }); const hasFileUploadAccess = diff --git a/src/routes/Sidebar/components/chat/effects/useChatFileUploader.ts b/src/routes/Sidebar/components/chat/effects/useChatFileUploader.ts index a98632cb8..b65d0a7ed 100644 --- a/src/routes/Sidebar/components/chat/effects/useChatFileUploader.ts +++ b/src/routes/Sidebar/components/chat/effects/useChatFileUploader.ts @@ -71,11 +71,7 @@ export const useFileUploader = ({ }; const onPaste = (evt: React.ClipboardEvent) => { - if ( - evt.clipboardData && - evt.clipboardData.files && - (evt.clipboardData as any).files.length - ) { + if (evt.clipboardData?.files.length) { const files: File[] = []; { diff --git a/src/routes/Sidebar/components/chat/effects/useMessageComposer.ts b/src/routes/Sidebar/components/chat/effects/useMessageComposer.ts index 3687a17b7..36c383ae4 100644 --- a/src/routes/Sidebar/components/chat/effects/useMessageComposer.ts +++ b/src/routes/Sidebar/components/chat/effects/useMessageComposer.ts @@ -1,7 +1,7 @@ import React, { useEffect } from 'react'; import { OnChangeHandlerFunc } from 'react-mentions'; -import { useLocation } from 'react-router'; +import { useLocation, Location, useNavigate } from 'react-router'; import * as UI from 'types/ui'; import { @@ -11,7 +11,6 @@ import { } from 'utils/BrowserUtils'; import ChatCommandHandler from '../ChatCommandHandler'; -import { Location, useNavigate } from 'react-router'; import { useSocket } from 'context/SocketContext'; import { useSession } from 'context/SessionContext'; @@ -102,7 +101,7 @@ export const useMessageComposer = ({ chatController, t }: MessageComposerProps) const textTrimmed = inputText.replace(/\s+$/, ''); if (textTrimmed) { - if (textTrimmed[0] === '/') { + if (textTrimmed.startsWith('/')) { handleCommand(textTrimmed); } diff --git a/src/routes/Sidebar/components/effects/useSessionHelpers.ts b/src/routes/Sidebar/components/effects/useSessionHelpers.ts index 21384b5f0..54d020a01 100644 --- a/src/routes/Sidebar/components/effects/useSessionHelpers.ts +++ b/src/routes/Sidebar/components/effects/useSessionHelpers.ts @@ -28,7 +28,6 @@ export const useSessionRouteHelpers = ({ baseUrl }: SessionRouteHelperProps) => const newUrl = `/${baseUrl}/new`; const replaceNew = () => { - // const { navigate } = props; navigate(newUrl, { replace: true }); }; diff --git a/src/routes/Sidebar/routes/Filelists/components/FilelistFooter.tsx b/src/routes/Sidebar/routes/Filelists/components/FilelistFooter.tsx index 72716626e..24f661ecb 100644 --- a/src/routes/Sidebar/routes/Filelists/components/FilelistFooter.tsx +++ b/src/routes/Sidebar/routes/Filelists/components/FilelistFooter.tsx @@ -2,7 +2,7 @@ import * as React from 'react'; import { useFormatter } from 'context/FormatterContext'; import { FooterItem, SessionFooter } from 'routes/Sidebar/components/SessionFooter'; -import { useMobileLayout } from 'utils/BrowserUtils'; +import { usingMobileLayout } from 'utils/BrowserUtils'; import * as API from 'types/api'; import * as UI from 'types/ui'; @@ -14,7 +14,7 @@ interface FilelistFooterProps { const FilelistFooter: React.FC = ({ session, sessionT }) => { const { formatSize } = useFormatter(); - if (useMobileLayout()) { + if (usingMobileLayout()) { return null; } diff --git a/src/routes/Sidebar/routes/Filelists/components/FilelistItemTable.tsx b/src/routes/Sidebar/routes/Filelists/components/FilelistItemTable.tsx index 8eaf678db..287a7ade6 100644 --- a/src/routes/Sidebar/routes/Filelists/components/FilelistItemTable.tsx +++ b/src/routes/Sidebar/routes/Filelists/components/FilelistItemTable.tsx @@ -1,4 +1,3 @@ -//import { useMemo } from 'react'; import * as React from 'react'; import { dupeToStringType } from 'utils/TypeConvert'; @@ -91,7 +90,6 @@ class FilelistItemTable extends React.Component { const { files, directories } = location!.type as API.DirectoryType; if (files !== 0 || directories !== 0) { return ; - //return null; } // The directory was changed but the download state hasn't changed yet @@ -116,10 +114,6 @@ class FilelistItemTable extends React.Component { return undefined; }; - userGetter = () => { - return this.props.session.user; - }; - render() { const { session } = this.props; return ( diff --git a/src/routes/Sidebar/routes/Filelists/components/FilelistNew.tsx b/src/routes/Sidebar/routes/Filelists/components/FilelistNew.tsx index b7b7fbbac..4b8d2c66e 100644 --- a/src/routes/Sidebar/routes/Filelists/components/FilelistNew.tsx +++ b/src/routes/Sidebar/routes/Filelists/components/FilelistNew.tsx @@ -11,6 +11,7 @@ import * as API from 'types/api'; import IconConstants from 'constants/IconConstants'; import { UserSelectField } from 'components/select'; import { NewSessionLayoutProps } from 'routes/Sidebar/components/types'; +import LinkButton from 'components/semantic/LinkButton'; const FilelistNew: React.FC = (props) => { const handleSubmit = (user: API.HintedUser) => { @@ -35,11 +36,9 @@ const FilelistNew: React.FC = (props) => { }; const recentUserRender = (entry: API.HistoryItem) => { - return ( - handleSubmit(entry.user!)}> - {entry.user!.nicks + (entry.description ? ` (${entry.description})` : '')} - - ); + const caption = + entry.user!.nicks + (entry.description ? ` (${entry.description})` : ''); + return handleSubmit(entry.user!)} caption={caption} />; }; const hasSession = (entry: API.HistoryItem) => { diff --git a/src/routes/Sidebar/routes/Filelists/components/item-info-dialog/FilelistItemInfoDialog.tsx b/src/routes/Sidebar/routes/Filelists/components/item-info-dialog/FilelistItemInfoDialog.tsx index 6f8852140..c9ce6a559 100644 --- a/src/routes/Sidebar/routes/Filelists/components/item-info-dialog/FilelistItemInfoDialog.tsx +++ b/src/routes/Sidebar/routes/Filelists/components/item-info-dialog/FilelistItemInfoDialog.tsx @@ -27,10 +27,6 @@ interface DataProps extends DataProviderDecoratorChildProps { fileItem: API.FilelistItem; } -/*interface RouteProps { - itemId: string; -}*/ - type Props = FilelistItemInfoDialogProps & ModalRouteDecoratorChildProps; export const FilelistItemGetter = (session: API.FilelistSession) => { @@ -42,7 +38,7 @@ export const FilelistItemGetter = (session: API.FilelistSession) => { }; class FilelistItemInfoDialog extends Component { - static displayName = 'FilelistItemInfoDialog'; + static readonly displayName = 'FilelistItemInfoDialog'; render() { const { fileItem, session } = this.props; diff --git a/src/routes/Sidebar/routes/Files/components/FileFooter.tsx b/src/routes/Sidebar/routes/Files/components/FileFooter.tsx index 39131010e..feeef559c 100644 --- a/src/routes/Sidebar/routes/Files/components/FileFooter.tsx +++ b/src/routes/Sidebar/routes/Files/components/FileFooter.tsx @@ -3,7 +3,7 @@ import * as React from 'react'; import RedrawDecorator from 'decorators/RedrawDecorator'; import { useFormatter } from 'context/FormatterContext'; import { FooterItem, SessionFooter } from 'routes/Sidebar/components/SessionFooter'; -import { useMobileLayout } from 'utils/BrowserUtils'; +import { usingMobileLayout } from 'utils/BrowserUtils'; import * as API from 'types/api'; import * as UI from 'types/ui'; @@ -15,7 +15,7 @@ interface FileFooterProps { const FileFooter: React.FC = ({ item, sessionT }) => { const { formatRelativeTime } = useFormatter(); - if (useMobileLayout()) { + if (usingMobileLayout()) { return null; } diff --git a/src/routes/Sidebar/routes/Hubs/components/HubFooter.tsx b/src/routes/Sidebar/routes/Hubs/components/HubFooter.tsx index 0e4a96114..00997c34c 100644 --- a/src/routes/Sidebar/routes/Hubs/components/HubFooter.tsx +++ b/src/routes/Sidebar/routes/Hubs/components/HubFooter.tsx @@ -17,7 +17,7 @@ import { SocketSubscriptionDecorator, SocketSubscriptionDecoratorChildProps, } from 'decorators/SocketSubscriptionDecorator'; -import { useMobileLayout } from 'utils/BrowserUtils'; +import { usingMobileLayout } from 'utils/BrowserUtils'; import { useLayoutWidth } from 'context/LayoutWidthContext'; import { ActionMenu } from 'components/action-menu'; import { HubSettingActionMenu } from 'actions/ui/hub/HubSettingActions'; @@ -82,7 +82,7 @@ const HubFooter: React.FC = (props) => { } /> - {!useMobileLayout(layoutWidth) && ( + {!usingMobileLayout(layoutWidth) && ( { handleConnect = (hubUrl: string) => { @@ -33,7 +34,12 @@ class HubNew extends Component { }; recentHubRender = (entry: API.HistoryItem) => { - return this.handleConnect(entry.hub_url)}>{entry.name}; + return ( + this.handleConnect(entry.hub_url)} + caption={entry.name} + /> + ); }; render() { diff --git a/src/routes/Sidebar/routes/Messages/components/MessageNew.tsx b/src/routes/Sidebar/routes/Messages/components/MessageNew.tsx index 3d6cff387..ec5682d09 100644 --- a/src/routes/Sidebar/routes/Messages/components/MessageNew.tsx +++ b/src/routes/Sidebar/routes/Messages/components/MessageNew.tsx @@ -10,6 +10,7 @@ import * as API from 'types/api'; import IconConstants from 'constants/IconConstants'; import { UserSelectField } from 'components/select'; import { NewSessionLayoutProps } from 'routes/Sidebar/components/types'; +import LinkButton from 'components/semantic/LinkButton'; const hasSession = (entry: API.HistoryItem) => { return PrivateChatSessionStore.getSession(entry.user!.cid); @@ -26,7 +27,12 @@ const MessageNew: React.FC = (props) => { }; const recentUserRender = (entry: API.HistoryItem) => { - return handleSubmit(entry.user!)}>{entry.user!.nicks}; + return ( + handleSubmit(entry.user!)} + caption={entry.user!.nicks} + /> + ); }; const { sessionT } = props; diff --git a/src/routes/Transfers/components/Transfers.tsx b/src/routes/Transfers/components/Transfers.tsx index b13e1a2a8..f959eda5e 100644 --- a/src/routes/Transfers/components/Transfers.tsx +++ b/src/routes/Transfers/components/Transfers.tsx @@ -35,7 +35,7 @@ const FlagsCell: React.FC> = ({ interface TransfersProps extends WithTranslation {} class Transfers extends React.Component { - static displayName = 'Transfers'; + static readonly displayName = 'Transfers'; isPositive = (cellData: number) => { return cellData > 0; diff --git a/src/stores/LocalSettingStore.ts b/src/stores/LocalSettingStore.ts index 192c16449..4eaca6459 100644 --- a/src/stores/LocalSettingStore.ts +++ b/src/stores/LocalSettingStore.ts @@ -112,7 +112,7 @@ const Store = { return this.settings[key]; } - return this.getDefinition(key)!.default_value; + return this.getDefinition(key).default_value; }, getValues() { diff --git a/src/stores/LoginStore.ts b/src/stores/LoginStore.ts index bfe65d766..9f57c6513 100644 --- a/src/stores/LoginStore.ts +++ b/src/stores/LoginStore.ts @@ -122,7 +122,7 @@ const LoginStore = { this._lastError = { id: 'sessionLost', message: 'Session lost', - }; // translate('Session lost', i18n.t.bind(i18n), UI.Modules.LOGIN); + }; } else { this._lastError = errorToString(error); } diff --git a/src/style.css b/src/style.css index c21302f80..30fd5bd2c 100644 --- a/src/style.css +++ b/src/style.css @@ -29,6 +29,15 @@ section#container-main, height: 100dvh; } +.ui.button.basic.link { + box-shadow: 0 0 !important; + padding: unset; +} + +.ui.button.basic.link:hover { + text-decoration:underline; +} + .ui.checkbox.floating { width: 100%; margin: 10px 0px; @@ -50,6 +59,7 @@ section#container-main, .ui.dropdown { font-size: inherit; + max-width: 100%; } .ui.dropdown .menu > .item:not(.submenu) { @@ -88,10 +98,25 @@ section#container-main, align-self: center; } +.ui.dropdown .menu { + z-index: 1000; +} + .ui.dropdown .menu .header { display: flex; } +.ui.dropdown:not(.button) > .caption { + user-select: auto !important; + overflow: hidden; + max-width: 100%; +} + +td .ui.dropdown > .caption > .icon-caption { + display: contents; +} + + .divided.list .item .description { font-size: 90%; } @@ -261,24 +286,6 @@ th { overflow: hidden; } -.ui.dropdown .menu { - z-index: 1000; -} - -.ui.dropdown:not(.button) > .caption { - user-select: auto !important; - overflow: hidden; - max-width: 100%; -} - -.ui.dropdown { - max-width: 100%; -} - -td .ui.dropdown > .caption > .icon-caption { - display: contents; -} - .notifications-tl h4.notification-title { overflow: hidden; } diff --git a/src/tests/test-form-helpers.tsx b/src/tests/test-form-helpers.tsx index 9b0efff79..28e4728c0 100644 --- a/src/tests/test-form-helpers.tsx +++ b/src/tests/test-form-helpers.tsx @@ -1,5 +1,5 @@ import { fireEvent, getByText, RenderResult, waitFor } from '@testing-library/react'; -import userEventOriginal, { userEvent, UserEvent } from '@testing-library/user-event'; +import userEventOriginal, { UserEvent } from '@testing-library/user-event'; import selectEvent from './react-select-event'; type FieldValueMap = { @@ -20,12 +20,7 @@ export const expectFieldsDisabled = ( ) => { for (const label of labels) { const element = getByLabelText(label) as HTMLInputElement; - /*if (label.indexOf('file') !== -1) { - // File field, no browse button - expect(element.querySelector('input')).not.toBeTruthy(); - } else*/ { - expect(element.hasAttribute('disabled')).toBe(true); - } + expect(element.hasAttribute('disabled')).toBe(true); } }; diff --git a/src/utils/ActionUtils.ts b/src/utils/ActionUtils.ts index 550c2db5e..855f007af 100644 --- a/src/utils/ActionUtils.ts +++ b/src/utils/ActionUtils.ts @@ -23,11 +23,6 @@ export const actionAccess = ( action: Pick, 'access'>, { hasAccess }: AuthenticatedSession, ) => { - //invariant( - // !action.hasOwnProperty('access') || action.access, - // `Invalid access supplied for an action ${action.displayName}` - //); - return !action.access || hasAccess(action.access); }; @@ -47,7 +42,7 @@ export const toActionI18nKey = ( moduleId: string | string[], ) => { invariant(!!action.displayName, 'Invalid action'); - return textToI18nKey(action.displayName!, [ + return textToI18nKey(action.displayName, [ ...toArray(moduleId), UI.SubNamespaces.ACTIONS, ]); diff --git a/src/utils/BrowserUtils.ts b/src/utils/BrowserUtils.ts index 40ffb0a0f..6b589ea55 100644 --- a/src/utils/BrowserUtils.ts +++ b/src/utils/BrowserUtils.ts @@ -70,8 +70,8 @@ export const hasTouchSupport = () => { export const hasCopySupport = () => !!(navigator as any).clipboard; -export const useMobileLayout = (width?: number | null) => { - return (width || window.innerWidth) < 700 || window.innerHeight < 500; +export const usingMobileLayout = (width?: number | null) => { + return (width ?? window.innerWidth) < 700 || window.innerHeight < 500; }; export const pushUnique = ( diff --git a/src/utils/FormUtils.ts b/src/utils/FormUtils.ts index ad63d7367..d05ad488a 100644 --- a/src/utils/FormUtils.ts +++ b/src/utils/FormUtils.ts @@ -68,7 +68,7 @@ const typeToComponent = ( default: } - throw `Field type ${type} is not supported`; + throw Error(`Field type ${type} is not supported`); }; const parseDefinitions = (definitions: UI.FormFieldDefinition[]): tcomb.Type => { @@ -154,7 +154,7 @@ const normalizeSettingValueMap = ( return normalizeSettingValueMap(arrayItem, definitions!); } - throw `Invalid value for a list struct ${arrayItem}`; + throw Error(`Invalid value for a list struct ${arrayItem}`); }); } else if (item_type === API.SettingTypeEnum.HINTED_USER) { reducedValue[key] = fieldValue; @@ -169,7 +169,7 @@ const normalizeSettingValueMap = ( ) { reducedValue[key] = normalizeSettingValueMap(fieldValue, definitions!); } else { - throw `Invalid value for a struct ${key}`; + throw Error(`Invalid value for a struct ${key}`); } } else if (type === API.SettingTypeEnum.HINTED_USER) { reducedValue[key] = fieldValue as UI.FormValueBase; @@ -178,7 +178,7 @@ const normalizeSettingValueMap = ( } } else if (!value) { // Initialize empty value but don't merge missing fields into an existing value (we might be merging) - reducedValue[key] = default_value ? default_value : null; + reducedValue[key] = default_value || null; } return reducedValue; diff --git a/src/utils/Formatter.ts b/src/utils/Formatter.ts index b44792694..056319297 100644 --- a/src/utils/Formatter.ts +++ b/src/utils/Formatter.ts @@ -189,9 +189,7 @@ const formatSpeed = ( }; const formatBoolean = (value: boolean, t: UI.TranslateF) => { - return value - ? translate('Yes', t, UI.Modules.COMMON) - : translate('No', t, UI.Modules.COMMON); + return translate(value ? 'Yes' : 'No', t, UI.Modules.COMMON); }; export const createFormatter = (i18n: i18n) => { diff --git a/src/utils/MenuUtils.ts b/src/utils/MenuUtils.ts index ea2b250d8..f8facc896 100644 --- a/src/utils/MenuUtils.ts +++ b/src/utils/MenuUtils.ts @@ -1,5 +1,3 @@ -// import invariant from 'invariant'; - import { actionFilter, actionAccess } from 'utils/ActionUtils'; import * as UI from 'types/ui'; diff --git a/src/utils/TranslationUtils.ts b/src/utils/TranslationUtils.ts index f051c7586..19d582f8c 100644 --- a/src/utils/TranslationUtils.ts +++ b/src/utils/TranslationUtils.ts @@ -26,7 +26,7 @@ export const toI18nKey = ( invariant(!key.includes(' '), 'Invalid i18key'); if ( UI.SubNamespaces[key.toUpperCase() as keyof typeof UI.SubNamespaces] || - (reservedSubNamespaces && reservedSubNamespaces.includes(key)) + reservedSubNamespaces?.includes(key) ) { key += 'Caption'; } diff --git a/src/utils/semantic.js b/src/utils/semantic.js index beaf180d0..fc324fcc6 100644 --- a/src/utils/semantic.js +++ b/src/utils/semantic.js @@ -10,7 +10,6 @@ import 'fomantic-ui-css/components/label.min.css'; import 'fomantic-ui-css/components/list.min.css'; import 'fomantic-ui-css/components/menu.min.css'; import 'fomantic-ui-css/components/message.min.css'; -import 'fomantic-ui-css/components/menu.min.css'; import 'fomantic-ui-css/components/progress.min.css'; import 'fomantic-ui-css/components/reset.min.css'; import 'fomantic-ui-css/components/segment.min.css'; diff --git a/src/widgets/Extensions/components/ExtensionInfoEntry.tsx b/src/widgets/Extensions/components/ExtensionInfoEntry.tsx index 9a710b003..b16994282 100644 --- a/src/widgets/Extensions/components/ExtensionInfoEntry.tsx +++ b/src/widgets/Extensions/components/ExtensionInfoEntry.tsx @@ -8,7 +8,6 @@ import { compareVersions } from 'compare-versions'; import * as API from 'types/api'; import * as UI from 'types/ui'; -import { DataFetchError } from 'decorators/DataProviderDecorator'; import { Link } from 'react-router'; interface VersionProps { @@ -34,7 +33,6 @@ const Version: React.FC = ({ packageInfo, moduleT }) => { export interface ExtensionProps { installedPackage?: API.Extension; npmPackage: UI.NpmPackage; - npmError?: DataFetchError | null; moduleT: UI.ModuleTranslator; } diff --git a/src/widgets/Extensions/components/Extensions.tsx b/src/widgets/Extensions/components/Extensions.tsx index 7996cb5cd..c53e7d720 100644 --- a/src/widgets/Extensions/components/Extensions.tsx +++ b/src/widgets/Extensions/components/Extensions.tsx @@ -59,6 +59,7 @@ const NpmPackageLayout: React.FC 0 && (
{packageCatalog + .slice() .sort(packageDateSort) .map((data) => getItem(data.package, widgetT, installedPackages))}
@@ -71,8 +72,7 @@ export default DataProviderDecorator - fetchCorsSafeData(ExtensionConstants.NPM_PACKAGES_URL, true), + packageCatalog: () => fetchCorsSafeData(ExtensionConstants.NPM_PACKAGES_URL, true), }, dataConverters: { packageCatalog: ({ objects }) => objects, diff --git a/src/widgets/RSS/actions/RSSActions.ts b/src/widgets/RSS/actions/RSSActions.ts index e7615fd6f..eaf4768c2 100644 --- a/src/widgets/RSS/actions/RSSActions.ts +++ b/src/widgets/RSS/actions/RSSActions.ts @@ -43,10 +43,10 @@ const handleOpenLink: Handler = ({ itemData }) => { if (typeof entry.link === 'string') { link = entry.link; - } else if (entry.link && entry.link.attr.href && entry.link.attr.href.length > 2) { + } else if (entry?.link?.attr.href && entry.link.attr.href.length > 2) { link = entry.link.attr.href; - if (link[0] === '/' && link[1] !== '/') { + if (link.startsWith('//')) { // Relative paths, add the base URL (at least Github seems to use these) const urlLocation = getLocation(feedUrl); if (urlLocation) { diff --git a/src/widgets/Transfers/components/Transfers.tsx b/src/widgets/Transfers/components/Transfers.tsx index 5a0db50a9..b728bbba2 100644 --- a/src/widgets/Transfers/components/Transfers.tsx +++ b/src/widgets/Transfers/components/Transfers.tsx @@ -98,13 +98,12 @@ class Transfers extends PureComponent< this.idleInterval = window.setInterval(this.checkIdle, IDLE_APPEND_INTERVAL_MS); }; - onStatsReceived = (stats: API.TransferStats) => { - this.setState({ - points: addSpeed(this.state.points, stats.speed_down, stats.speed_up), - maxDownload: Math.max(stats.speed_down, this.state.maxDownload), - maxUpload: Math.max(stats.speed_up, this.state.maxUpload), - stats, - }); + onStatsReceived = (newStats: API.TransferStats) => { + this.setState((prevState) => ({ + points: addSpeed(prevState.points, newStats.speed_down, newStats.speed_up), + maxDownload: Math.max(newStats.speed_down, prevState.maxDownload), + maxUpload: Math.max(newStats.speed_up, prevState.maxUpload), + })); }; onStatsUpdated = (newStats: Partial) => { @@ -117,7 +116,7 @@ class Transfers extends PureComponent< // // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/now if (!hasEllapsedSinceLastUpdate(points, 100)) { - //console.log(`Transfer widget: burst update ignored`); + console.debug(`Transfer widget: burst update ignored`); return; } diff --git a/webpack/bundle-loader.js b/webpack/bundle-loader.js deleted file mode 100644 index b87836041..000000000 --- a/webpack/bundle-loader.js +++ /dev/null @@ -1,83 +0,0 @@ -/* - MIT License http://www.opensource.org/licenses/mit-license.php - Author Tobias Koppers @sokra - Modified version, originally created by Richard Scarrott @richardscarrott - */ - -var loaderUtils = require("loader-utils"); -var LoaderDependency = require("webpack/lib/dependencies/LoaderDependency"); - -module.exports = function() {}; -module.exports.pitch = function(remainingRequest) { - this.cacheable && this.cacheable(); - var query = loaderUtils.getOptions(this) || {}; - if(query.name) { - var options = { - context: query.context || this.rootContext || this.options && this.options.context, - regExp: query.regExp - }; - var chunkName = loaderUtils.interpolateName(this, query.name, options); - var chunkNameParam = ", " + JSON.stringify(chunkName); - } else { - var chunkNameParam = ''; - } - var result; - if(query.lazy) { - result = [ - "module.exports = function(successCallback, errorCallback) {\n", - " require.ensure([], function() {\n", - " successCallback(require(", loaderUtils.stringifyRequest(this, "!!" + remainingRequest), "));\n", - " }, function() {\n", - " if (errorCallback) errorCallback.apply(this, arguments);\n", - " }" + chunkNameParam + ");\n", - "};"]; - } else { - result = [ - "var cbs,\n", - " data,\n", - " error = false;\n", - "module.exports = function(successCallback, errorCallback) {\n", - " errorCallback = errorCallback || function() {};\n", - " if (data) {\n", - " successCallback(data);\n", - " } else {\n", - " if (error) {\n", - " // Try again.\n", - " requireBundle();\n", - " }\n", - " cbs.push({\n", - " success: successCallback,\n", - " error: errorCallback\n", - " });\n", - " }\n", - "};\n", - "function requireBundle() {\n", - " cbs = [];\n", - " require.ensure([], function() {\n", - " data = require(", loaderUtils.stringifyRequest(this, "!!" + remainingRequest), ");\n", - " for(var i = 0, l = cbs.length; i < l; i++) {\n", - " cbs[i].success(data);\n", - " }\n", - " error = false;\n", - " cbs = null;\n", - " }, function() {\n", - " for(var i = 0, l = cbs.length; i < l; i++) {\n", - " cbs[i].error.apply(this, arguments);\n", - " }\n", - " error = true;\n", - " cbs = null;\n", - " }" + chunkNameParam + ");\n", - "}\n", - "requireBundle();" - ]; - } - - if (this._module.type !== "javascript/auto") { - var nmf = this._compilation.dependencyFactories.get(LoaderDependency); - this._module.type = "javascript/auto"; - this._module.generator = nmf.getGenerator("javascript/auto"); - this._module.parser = nmf.getParser("javascript/auto"); - } - - return result.join(""); -}; \ No newline at end of file