diff --git a/webui/package.json b/webui/package.json index a1ff251a7..23c7f18a8 100644 --- a/webui/package.json +++ b/webui/package.json @@ -1,6 +1,6 @@ { "name": "openvsx-webui", - "version": "0.11.7", + "version": "0.11.8", "description": "User interface for Eclipse Open VSX", "keywords": [ "react", diff --git a/webui/src/main.tsx b/webui/src/main.tsx index 2eec65bdd..34419329d 100644 --- a/webui/src/main.tsx +++ b/webui/src/main.tsx @@ -8,7 +8,7 @@ * SPDX-License-Identifier: EPL-2.0 ********************************************************************************/ -import React, { FunctionComponent, ReactNode, useEffect, useState } from 'react'; +import React, { FunctionComponent, ReactNode, useEffect, useState, useRef } from 'react'; import { CssBaseline } from '@mui/material'; import { Route, Routes } from 'react-router-dom'; import { AdminDashboard, AdminDashboardRoutes } from './pages/admin-dashboard/admin-dashboard'; @@ -28,25 +28,25 @@ export const Main: FunctionComponent = props => { const [userLoading, setUserLoading] = useState(true); const [error, setError] = useState<{message: string, code?: number | string}>(); const [isErrorDialogOpen, setIsErrorDialogOpen] = useState(false); - const abortController = new AbortController(); + const abortController = useRef(new AbortController()); useEffect(() => { // If there was an authentication error, get the message from the server and show it const searchParams = new URLSearchParams(window.location.search); if (searchParams.has('auth-error')) { - props.service.getUserAuthError(abortController).then(onError); + props.service.getUserAuthError(abortController.current).then(onError); } // Get data of the currently logged in user updateUser(); - return () => abortController.abort(); + return () => abortController.current.abort(); }, []); const updateUser = async () => { try { setUserLoading(true); - const user = await props.service.getUser(abortController); + const user = await props.service.getUser(abortController.current); if (isError(user)) { // An error result with HTTP OK status indicates that the user is not logged in. setUser(undefined); diff --git a/webui/src/pages/admin-dashboard/extension-admin.tsx b/webui/src/pages/admin-dashboard/extension-admin.tsx index eb35257a6..79f766215 100644 --- a/webui/src/pages/admin-dashboard/extension-admin.tsx +++ b/webui/src/pages/admin-dashboard/extension-admin.tsx @@ -8,7 +8,7 @@ * SPDX-License-Identifier: EPL-2.0 ********************************************************************************/ -import React, { FunctionComponent, useState, useContext, useEffect } from 'react'; +import React, { FunctionComponent, useState, useContext, useEffect, useRef } from 'react'; import { SearchListContainer } from './search-list-container'; import { ExtensionListSearchfield } from '../extension-list/extension-list-searchfield'; import { Button, Typography } from '@mui/material'; @@ -18,10 +18,10 @@ import { ExtensionVersionContainer } from './extension-version-container'; import { StyledInput } from './namespace-input'; export const ExtensionAdmin: FunctionComponent = props => { - const abortController = new AbortController(); + const abortController = useRef(new AbortController()); useEffect(() => { return () => { - abortController.abort(); + abortController.current.abort(); }; }, []); @@ -59,7 +59,7 @@ export const ExtensionAdmin: FunctionComponent = props => { setExtensionFieldError(false); try { setLoading(true); - const extensionDetail = await service.admin.getExtension(abortController, namespaceValue, extensionValue); + const extensionDetail = await service.admin.getExtension(abortController.current, namespaceValue, extensionValue); if (isError(extensionDetail)) { throw extensionDetail; } diff --git a/webui/src/pages/admin-dashboard/extension-remove-dialog.tsx b/webui/src/pages/admin-dashboard/extension-remove-dialog.tsx index 0c5e13695..2c6394725 100644 --- a/webui/src/pages/admin-dashboard/extension-remove-dialog.tsx +++ b/webui/src/pages/admin-dashboard/extension-remove-dialog.tsx @@ -8,7 +8,7 @@ * SPDX-License-Identifier: EPL-2.0 ********************************************************************************/ -import React, { FunctionComponent, useState, useContext, useEffect } from 'react'; +import React, { FunctionComponent, useState, useContext, useEffect, useRef } from 'react'; import { Button, Dialog, DialogTitle, DialogContent, DialogContentText, DialogActions, Typography } from '@mui/material'; import { ButtonWithProgress } from '../../components/button-with-progress'; import { Extension, TargetPlatformVersion } from '../../extension-registry-types'; @@ -18,10 +18,10 @@ import { getTargetPlatformDisplayName } from '../../utils'; export const ExtensionRemoveDialog: FunctionComponent = props => { const { service, handleError } = useContext(MainContext); - const abortController = new AbortController(); + const abortController = useRef(new AbortController()); useEffect(() => { return () => { - abortController.abort(); + abortController.current.abort(); }; }, []); @@ -49,7 +49,7 @@ export const ExtensionRemoveDialog: FunctionComponent(new AbortController()); const getTargetPlatformVersions = () => { const versionMap: TargetPlatformVersion[] = []; @@ -36,10 +37,9 @@ export const ExtensionVersionContainer: FunctionComponent { return () => { - abortController.abort(); + abortController.current.abort(); }; }, []); @@ -50,7 +50,7 @@ export const ExtensionVersionContainer: FunctionComponent { const [currentNamespace, setCurrentNamespace] = useState(); const [notFound, setNotFound] = useState(''); - const abortController = new AbortController(); + const abortController = useRef(new AbortController()); useEffect(() => { return () => { - abortController.abort(); + abortController.current.abort(); }; }, []); @@ -39,7 +39,7 @@ export const NamespaceAdmin: FunctionComponent = props => { } try { setLoading(true); - const namespace = await service.admin.getNamespace(abortController, namespaceName); + const namespace = await service.admin.getNamespace(abortController.current, namespaceName); if (isError(namespace)) { throw namespace; } @@ -66,7 +66,7 @@ export const NamespaceAdmin: FunctionComponent = props => { const onCreate = async () => { try { setCreating(true); - await service.admin.createNamespace(abortController, { + await service.admin.createNamespace(abortController.current, { name: inputValue }); await fetchNamespace(inputValue); diff --git a/webui/src/pages/admin-dashboard/namespace-change-dialog.tsx b/webui/src/pages/admin-dashboard/namespace-change-dialog.tsx index 39e7de3be..a62a12521 100644 --- a/webui/src/pages/admin-dashboard/namespace-change-dialog.tsx +++ b/webui/src/pages/admin-dashboard/namespace-change-dialog.tsx @@ -8,7 +8,7 @@ * SPDX-License-Identifier: EPL-2.0 ********************************************************************************/ - import React, { ChangeEvent, FunctionComponent, useState, useContext, useEffect } from 'react'; + import React, { ChangeEvent, FunctionComponent, useState, useContext, useEffect, useRef } from 'react'; import { Button, Checkbox, Dialog, DialogActions, DialogContent, DialogContentText, DialogTitle, FormControlLabel, TextField } from '@mui/material'; @@ -34,10 +34,10 @@ const [infoDialogIsOpen, setInfoDialogIsOpen] = useState(false); const [infoDialogMessage, setInfoDialogMessage] = useState(''); - const abortController = new AbortController(); + const abortController = useRef(new AbortController()); useEffect(() => { return () => { - abortController.abort(); + abortController.current.abort(); }; }, []); @@ -70,7 +70,7 @@ setWorking(true); props.setLoadingState(true); const oldNamespace = props.namespace.name; - const result = await service.admin.changeNamespace(abortController, { oldNamespace, newNamespace, removeOldNamespace, mergeIfNewNamespaceAlreadyExists }); + const result = await service.admin.changeNamespace(abortController.current, { oldNamespace, newNamespace, removeOldNamespace, mergeIfNewNamespaceAlreadyExists }); if (isError(result)) { throw result; } diff --git a/webui/src/pages/admin-dashboard/publisher-admin.tsx b/webui/src/pages/admin-dashboard/publisher-admin.tsx index 19262834b..bbabbb66b 100644 --- a/webui/src/pages/admin-dashboard/publisher-admin.tsx +++ b/webui/src/pages/admin-dashboard/publisher-admin.tsx @@ -8,7 +8,7 @@ * SPDX-License-Identifier: EPL-2.0 ********************************************************************************/ -import React, { FunctionComponent, useState, useContext, createContext, useEffect } from 'react'; +import React, { FunctionComponent, useState, useContext, createContext, useEffect, useRef } from 'react'; import { Typography, Box } from '@mui/material'; import { PublisherInfo } from '../../extension-registry-types'; import { MainContext } from '../../context'; @@ -20,10 +20,10 @@ export const UpdateContext = createContext({ handleUpdate: () => { } }); export const PublisherAdmin: FunctionComponent = props => { const { pageSettings, service, user, handleError } = useContext(MainContext); - const abortController = new AbortController(); + const abortController = useRef(new AbortController()); useEffect(() => { return () => { - abortController.abort(); + abortController.current.abort(); }; }, []); @@ -40,7 +40,7 @@ export const PublisherAdmin: FunctionComponent = props => { try { setLoading(true); if (publisherName !== '') { - const publisher = await service.admin.getPublisherInfo(abortController, 'github', publisherName); + const publisher = await service.admin.getPublisherInfo(abortController.current, 'github', publisherName); setNotFound(''); setPublisher(publisher); } else { diff --git a/webui/src/pages/admin-dashboard/publisher-revoke-dialog.tsx b/webui/src/pages/admin-dashboard/publisher-revoke-dialog.tsx index 84d42c4f5..ffb613aa4 100644 --- a/webui/src/pages/admin-dashboard/publisher-revoke-dialog.tsx +++ b/webui/src/pages/admin-dashboard/publisher-revoke-dialog.tsx @@ -8,7 +8,7 @@ * SPDX-License-Identifier: EPL-2.0 ********************************************************************************/ -import React, { FunctionComponent, useState, useContext, useEffect } from 'react'; +import React, { FunctionComponent, useState, useContext, useEffect, useRef } from 'react'; import { Button, Dialog, DialogTitle, DialogContent, DialogContentText, DialogActions, Typography, Link } from '@mui/material'; @@ -24,10 +24,10 @@ export const PublisherRevokeDialog: FunctionComponent(new AbortController()); useEffect(() => { return () => { - abortController.abort(); + abortController.current.abort(); }; }, []); @@ -45,7 +45,7 @@ export const PublisherRevokeDialog: FunctionComponent(); const [loading, setLoading] = useState(true); const context = useContext(MainContext); - const abortController = new AbortController(); + const abortController = useRef(new AbortController()); useEffect(() => { updateChanges(); - return () => abortController.abort(); + return () => abortController.current.abort(); }, []); useEffect(() => { @@ -34,7 +34,7 @@ export const ExtensionDetailChanges: FunctionComponent => { if (props.extension.files.changelog) { try { - const changelog = await context.service.getExtensionChangelog(abortController, props.extension); + const changelog = await context.service.getExtensionChangelog(abortController.current, props.extension); setChangelog(changelog); } catch (err) { context.handleError(err); diff --git a/webui/src/pages/extension-detail/extension-detail-overview.tsx b/webui/src/pages/extension-detail/extension-detail-overview.tsx index 90c840674..48a53b841 100644 --- a/webui/src/pages/extension-detail/extension-detail-overview.tsx +++ b/webui/src/pages/extension-detail/extension-detail-overview.tsx @@ -8,7 +8,7 @@ * SPDX-License-Identifier: EPL-2.0 ********************************************************************************/ -import React, { FunctionComponent, ReactNode, useContext, useEffect, useState } from 'react'; +import React, { FunctionComponent, ReactNode, useContext, useEffect, useState, useRef } from 'react'; import { Box, Theme, Typography, Button, Link, NativeSelect, SxProps, styled } from '@mui/material'; import { Link as RouteLink, useNavigate, useParams } from 'react-router-dom'; import HomeIcon from '@mui/icons-material/Home'; @@ -33,12 +33,12 @@ export const ExtensionDetailOverview: FunctionComponent(new AbortController()); useEffect(() => { updateReadme(); return () => { - abortController.abort(); + abortController.current.abort(); }; }, []); @@ -50,7 +50,7 @@ export const ExtensionDetailOverview: FunctionComponent => { if (props.extension.files.readme) { try { - const readme = await service.getExtensionReadme(abortController, props.extension); + const readme = await service.getExtensionReadme(abortController.current, props.extension); setReadme(readme); setLoading(false); } catch (err) { diff --git a/webui/src/pages/extension-detail/extension-detail-reviews.tsx b/webui/src/pages/extension-detail/extension-detail-reviews.tsx index 876064007..9ac18bb58 100644 --- a/webui/src/pages/extension-detail/extension-detail-reviews.tsx +++ b/webui/src/pages/extension-detail/extension-detail-reviews.tsx @@ -8,7 +8,7 @@ * SPDX-License-Identifier: EPL-2.0 ********************************************************************************/ -import React, { Fragment, FunctionComponent, ReactNode, useContext, useState, useEffect } from 'react'; +import React, { Fragment, FunctionComponent, ReactNode, useContext, useState, useEffect, useRef } from 'react'; import { Box, Typography, Divider, Link } from '@mui/material'; import { MainContext } from '../../context'; import { toLocalTime } from '../../utils'; @@ -25,16 +25,16 @@ export const ExtensionDetailReviews: FunctionComponent(true); const [revoked, setRevoked] = useState(false); const context = useContext(MainContext); - const abortController = new AbortController(); + const abortController = useRef(new AbortController()); useEffect(() => { updateReviews(); - return () => abortController.abort(); + return () => abortController.current.abort(); }, []); const updateReviews = async () => { try { - const reviewList = await context.service.getExtensionReviews(abortController, props.extension); + const reviewList = await context.service.getExtensionReviews(abortController.current, props.extension); setReviewList(reviewList); } catch (err) { context.handleError(err); @@ -53,7 +53,7 @@ export const ExtensionDetailReviews: FunctionComponent { setRevoked(true); try { - const result = await context.service.deleteReview(abortController, reviewList!.deleteUrl); + const result = await context.service.deleteReview(abortController.current, reviewList!.deleteUrl); if (isError(result)) { throw result; } diff --git a/webui/src/pages/extension-detail/extension-detail.tsx b/webui/src/pages/extension-detail/extension-detail.tsx index 6e1c604c5..1967b2003 100644 --- a/webui/src/pages/extension-detail/extension-detail.tsx +++ b/webui/src/pages/extension-detail/extension-detail.tsx @@ -9,7 +9,7 @@ ********************************************************************************/ import * as React from 'react'; -import { ChangeEvent, FunctionComponent, ReactElement, ReactNode, useContext, useEffect, useState } from 'react'; +import { ChangeEvent, FunctionComponent, ReactElement, ReactNode, useContext, useEffect, useState, useRef } from 'react'; import { Typography, Box, Theme, Container, Link, Avatar, Paper, Badge, SxProps, Tabs, Tab } from '@mui/material'; import { Link as RouteLink, useNavigate, useParams } from 'react-router-dom'; import SaveAltIcon from '@mui/icons-material/SaveAlt'; @@ -78,11 +78,11 @@ export const ExtensionDetail: FunctionComponent = () => { const { namespace, name, target, version } = useParams(); const { handleError, pageSettings, service } = useContext(MainContext); - const abortController = new AbortController(); + const abortController = useRef(new AbortController()); useEffect(() => { updateExtension(); return () => { - abortController.abort(); + abortController.current.abort(); if (icon) { URL.revokeObjectURL(icon); } @@ -101,7 +101,7 @@ export const ExtensionDetail: FunctionComponent = () => { const updateExtension = async (): Promise => { const extensionUrl = getExtensionApiUrl(); try { - const response = await service.getExtensionDetail(abortController, extensionUrl); + const response = await service.getExtensionDetail(abortController.current, extensionUrl); if (isError(response)) { throw response; } @@ -132,7 +132,7 @@ export const ExtensionDetail: FunctionComponent = () => { URL.revokeObjectURL(icon); } - return await service.getExtensionIcon(abortController, extension); + return await service.getExtensionIcon(abortController.current, extension); }; const onVersionSelect = (version: string): void => { diff --git a/webui/src/pages/extension-detail/extension-review-dialog.tsx b/webui/src/pages/extension-detail/extension-review-dialog.tsx index 7867fca55..b12af8035 100644 --- a/webui/src/pages/extension-detail/extension-review-dialog.tsx +++ b/webui/src/pages/extension-detail/extension-review-dialog.tsx @@ -8,7 +8,7 @@ * SPDX-License-Identifier: EPL-2.0 ********************************************************************************/ -import React, { ChangeEvent, FunctionComponent, useContext, useEffect, useState } from 'react'; +import React, { ChangeEvent, FunctionComponent, useContext, useEffect, useState, useRef } from 'react'; import { Box, Button, Dialog, DialogTitle, DialogContent, DialogContentText, TextField, DialogActions } from '@mui/material'; import { ButtonWithProgress } from '../../components/button-with-progress'; import { Extension, StarRating, isError } from '../../extension-registry-types'; @@ -24,12 +24,12 @@ export const ExtensionReviewDialog: FunctionComponent(''); const [commentError, setCommentError] = useState(); const context = useContext(MainContext); - const abortController = new AbortController(); + const abortController = useRef(new AbortController()); useEffect(() => { document.addEventListener('keydown', handleEnter); return () => { - abortController.abort(); + abortController.current.abort(); document.removeEventListener('keydown', handleEnter); }; }, []); @@ -46,7 +46,7 @@ export const ExtensionReviewDialog: FunctionComponent { setPosted(true); try { - const result = await context.service.postReview(abortController, { rating, comment }, props.reviewPostUrl); + const result = await context.service.postReview(abortController.current, { rating, comment }, props.reviewPostUrl); if (isError(result)) { throw result; } diff --git a/webui/src/pages/extension-list/extension-list-item.tsx b/webui/src/pages/extension-list/extension-list-item.tsx index 7df628456..4d5c86ebf 100644 --- a/webui/src/pages/extension-list/extension-list-item.tsx +++ b/webui/src/pages/extension-list/extension-list-item.tsx @@ -8,7 +8,7 @@ * SPDX-License-Identifier: EPL-2.0 ********************************************************************************/ -import React, { FunctionComponent, useContext, useState, useEffect } from 'react'; +import React, { FunctionComponent, useContext, useState, useEffect, useRef } from 'react'; import { Link as RouteLink } from 'react-router-dom'; import { Paper, Typography, Box, Grid, Fade } from '@mui/material'; import SaveAltIcon from '@mui/icons-material/SaveAlt'; @@ -21,12 +21,12 @@ import { createRoute } from '../../utils'; export const ExtensionListItem: FunctionComponent = props => { const [icon, setIcon] = useState(); const context = useContext(MainContext); - const abortController = new AbortController(); + const abortController = useRef(new AbortController()); useEffect(() => { updateChanges(); return () => { - abortController.abort(); + abortController.current.abort(); if (icon) { URL.revokeObjectURL(icon); } @@ -42,7 +42,7 @@ export const ExtensionListItem: FunctionComponent = prop URL.revokeObjectURL(icon); } try { - const icon = await context.service.getExtensionIcon(abortController, props.extension); + const icon = await context.service.getExtensionIcon(abortController.current, props.extension); setIcon(icon); } catch (err) { context.handleError(err); diff --git a/webui/src/pages/extension-list/extension-list.tsx b/webui/src/pages/extension-list/extension-list.tsx index ebd005cd5..44414d98c 100644 --- a/webui/src/pages/extension-list/extension-list.tsx +++ b/webui/src/pages/extension-list/extension-list.tsx @@ -19,8 +19,8 @@ import { DelayedLoadIndicator } from '../../components/delayed-load-indicator'; import { MainContext } from '../../context'; export const ExtensionList: FunctionComponent = props => { - const abortController = new AbortController(); - const cancellationToken: { timeout?: number } = {}; + const abortController = useRef(new AbortController()); + const cancellationToken = useRef<{ timeout?: number }>({}); const enableLoadMore = useRef(false); const lastRequestedPage = useRef(0); const pageOffset = useRef(0); @@ -35,18 +35,18 @@ export const ExtensionList: FunctionComponent = props => { useEffect(() => { enableLoadMore.current = true; return () => { - abortController.abort(); - clearTimeout(cancellationToken.timeout); + abortController.current.abort(); + clearTimeout(cancellationToken.current.timeout); enableLoadMore.current = false; }; - }); + }, []); useEffect(() => { filterSize.current = props.filter.size || filterSize.current; debounce( async () => { try { - const result = await context.service.search(abortController, props.filter); + const result = await context.service.search(abortController.current, props.filter); if (isError(result)) { throw result; } @@ -70,7 +70,7 @@ export const ExtensionList: FunctionComponent = props => { setLoading(false); } }, - cancellationToken, + cancellationToken.current, props.debounceTime ); }, [props.filter.category, props.filter.query, props.filter.sortBy, props.filter.sortOrder, props.debounceTime]); @@ -85,7 +85,7 @@ export const ExtensionList: FunctionComponent = props => { } try { filter.offset = (p - pageOffset.current) * filterSize.current; - const result = await context.service.search(abortController, filter); + const result = await context.service.search(abortController.current, filter); if (isError(result)) { throw result; } diff --git a/webui/src/pages/namespace-detail/namespace-detail.tsx b/webui/src/pages/namespace-detail/namespace-detail.tsx index 15b0b9ed7..4287e6a1c 100644 --- a/webui/src/pages/namespace-detail/namespace-detail.tsx +++ b/webui/src/pages/namespace-detail/namespace-detail.tsx @@ -8,7 +8,7 @@ * SPDX-License-Identifier: EPL-2.0 ********************************************************************************/ -import React, { FunctionComponent, ReactNode, useContext, useEffect, useState } from 'react'; +import React, { FunctionComponent, ReactNode, useContext, useEffect, useState, useRef } from 'react'; import { Typography, Box, Container, Grid, Link, Divider } from '@mui/material'; import GitHubIcon from '@mui/icons-material/GitHub'; import LinkedInIcon from '@mui/icons-material/LinkedIn'; @@ -39,11 +39,11 @@ export const NamespaceDetail: FunctionComponent = () => { const { name } = useParams(); const { pageSettings, service, handleError } = useContext(MainContext); - const abortController = new AbortController(); + const abortController = useRef(new AbortController()); useEffect(() => { updateNamespaceDetails(name as string); return () => { - abortController.abort(); + abortController.current.abort(); }; }, []); @@ -55,7 +55,7 @@ export const NamespaceDetail: FunctionComponent = () => { const updateNamespaceDetails = async(name: string): Promise => { try { - const namespaceDetails = await service.getNamespaceDetails(abortController, name); + const namespaceDetails = await service.getNamespaceDetails(abortController.current, name); if (isError(namespaceDetails)) { throw namespaceDetails; } diff --git a/webui/src/pages/user/add-namespace-member-dialog.tsx b/webui/src/pages/user/add-namespace-member-dialog.tsx index d2dfb3ab6..678102051 100644 --- a/webui/src/pages/user/add-namespace-member-dialog.tsx +++ b/webui/src/pages/user/add-namespace-member-dialog.tsx @@ -8,7 +8,7 @@ * SPDX-License-Identifier: EPL-2.0 ********************************************************************************/ -import React, { ChangeEvent, FunctionComponent, KeyboardEvent, useState, useContext, useEffect } from 'react'; +import React, { ChangeEvent, FunctionComponent, KeyboardEvent, useState, useContext, useEffect, useRef } from 'react'; import { UserData } from '../..'; import { Dialog, DialogTitle, DialogContent, DialogContentText, TextField, DialogActions, Button, Popper, Fade, Paper, @@ -34,10 +34,10 @@ export const AddMemberDialog: FunctionComponent = props => const [foundUsers, setFoundUsers] = useState([]); const [showUserPopper, setShowUserPopper] = useState(false); const [popperTarget, setPopperTarget] = useState(undefined); - const abortController = new AbortController(); + const abortController = useRef(new AbortController()); useEffect(() => { return () => { - abortController.abort(); + abortController.current.abort(); }; }, []); @@ -53,7 +53,7 @@ export const AddMemberDialog: FunctionComponent = props => } props.setLoadingState(true); const endpoint = props.namespace.roleUrl; - const result = await service.setNamespaceMember(abortController, endpoint, user, config.defaultMemberRole || 'contributor'); + const result = await service.setNamespaceMember(abortController.current, endpoint, user, config.defaultMemberRole || 'contributor'); if (isError(result)) { throw result; } @@ -78,7 +78,7 @@ export const AddMemberDialog: FunctionComponent = props => let showUserPopper = false; let foundUsers: UserData[] = []; if (val) { - const users = await service.getUserByName(abortController, val); + const users = await service.getUserByName(abortController.current, val); if (users) { showUserPopper = true; foundUsers = users; diff --git a/webui/src/pages/user/avatar.tsx b/webui/src/pages/user/avatar.tsx index b74a51f6f..b78ba5361 100644 --- a/webui/src/pages/user/avatar.tsx +++ b/webui/src/pages/user/avatar.tsx @@ -37,15 +37,15 @@ export const UserAvatar: FunctionComponent = () => { const context = useContext(MainContext); const avatarButton = useRef(); - const abortController = new AbortController(); + const abortController = useRef(new AbortController()); useEffect(() => { updateCsrf(); - return () => abortController.abort(); + return () => abortController.current.abort(); }, []); const updateCsrf = async () => { try { - const csrfResponse = await context.service.getCsrfToken(abortController); + const csrfResponse = await context.service.getCsrfToken(abortController.current); if (!isError(csrfResponse)) { const csrfToken = csrfResponse as CsrfTokenJson; setCsrf(csrfToken.value); diff --git a/webui/src/pages/user/create-namespace-dialog.tsx b/webui/src/pages/user/create-namespace-dialog.tsx index ecebf9a48..404601b26 100644 --- a/webui/src/pages/user/create-namespace-dialog.tsx +++ b/webui/src/pages/user/create-namespace-dialog.tsx @@ -8,7 +8,7 @@ * SPDX-License-Identifier: EPL-2.0 * ****************************************************************************** */ -import React, { ChangeEvent, FunctionComponent, useContext, useEffect, useState } from 'react'; +import React, { ChangeEvent, FunctionComponent, useContext, useEffect, useState, useRef } from 'react'; import { Button, Dialog, DialogTitle, DialogContent, Box, TextField, DialogActions } from '@mui/material'; import { ButtonWithProgress } from '../../components/button-with-progress'; import { isError } from '../../extension-registry-types'; @@ -23,12 +23,12 @@ export const CreateNamespaceDialog: FunctionComponent(); const context = useContext(MainContext); - const abortController = new AbortController(); + const abortController = useRef(new AbortController()); useEffect(() => { document.addEventListener('keydown', handleEnter); return () => { - abortController.abort(); + abortController.current.abort(); document.removeEventListener('keydown', handleEnter); }; }, []); @@ -61,7 +61,7 @@ export const CreateNamespaceDialog: FunctionComponent = const [token, setToken] = useState(); const context = useContext(MainContext); - const abortController = new AbortController(); + const abortController = useRef(new AbortController()); useEffect(() => { document.addEventListener('keydown', handleEnter); return () => { - abortController.abort(); + abortController.current.abort(); document.removeEventListener('keydown', handleEnter); }; }, []); @@ -61,7 +61,7 @@ export const GenerateTokenDialog: FunctionComponent = } setPosted(true); try { - const token = await context.service.createAccessToken(abortController, context.user, description); + const token = await context.service.createAccessToken(abortController.current, context.user, description); if (isError(token)) { throw token; } diff --git a/webui/src/pages/user/publish-extension-dialog.tsx b/webui/src/pages/user/publish-extension-dialog.tsx index 2684112cb..426e2fa1f 100644 --- a/webui/src/pages/user/publish-extension-dialog.tsx +++ b/webui/src/pages/user/publish-extension-dialog.tsx @@ -8,7 +8,7 @@ * SPDX-License-Identifier: EPL-2.0 * ****************************************************************************** */ -import React, { FunctionComponent, useContext, useEffect, useState } from 'react'; +import React, { FunctionComponent, useContext, useEffect, useState, useRef } from 'react'; import { Button, Dialog, DialogTitle, DialogContent, DialogActions, Typography, Box, Paper } from '@mui/material'; import { CheckCircleOutline } from '@mui/icons-material'; import Dropzone from 'react-dropzone'; @@ -51,12 +51,12 @@ export const PublishExtensionDialog: FunctionComponent(); const context = useContext(MainContext); - const abortController = new AbortController(); + const abortController = useRef(new AbortController()); useEffect(() => { document.addEventListener('keydown', handleEnter); return () => { - abortController.abort(); + abortController.current.abort(); document.removeEventListener('keydown', handleEnter); }; }, []); @@ -73,7 +73,8 @@ export const PublishExtensionDialog: FunctionComponent { if (publishing) { - abortController.abort(); + abortController.current.abort(); + abortController.current = new AbortController(); } setOpen(false); @@ -140,7 +141,7 @@ export const PublishExtensionDialog: FunctionComponent => { let published = false; - const publishResponse = await context.service.publishExtension(abortController, fileToPublish); + const publishResponse = await context.service.publishExtension(abortController.current, fileToPublish); if (isError(publishResponse)) { throw publishResponse; } @@ -161,7 +162,7 @@ export const PublishExtensionDialog: FunctionComponent const LINKED_IN_PERSONAL = 'in'; const LINKED_IN_COMPANY = 'company'; - const abortController = new AbortController(); + const abortController = useRef(new AbortController()); const editor = useRef(null); const context = useContext(MainContext); @@ -103,7 +103,7 @@ export const UserNamespaceDetails: FunctionComponent useEffect(() => { getNamespaceDetails(); - return () => abortController.abort(); + return () => abortController.current.abort(); }, []); useEffect(() => { @@ -121,7 +121,7 @@ export const UserNamespaceDetails: FunctionComponent } try { - const details = await context.service.getNamespaceDetails(abortController, props.namespace.name); + const details = await context.service.getNamespaceDetails(abortController.current, props.namespace.name); if (isError(details)) { throw details; } @@ -181,7 +181,7 @@ export const UserNamespaceDetails: FunctionComponent ? 'https://twitter.com/' + details.socialLinks.twitter : undefined; - const result = await context.service.setNamespaceDetails(abortController, details); + const result = await context.service.setNamespaceDetails(abortController.current, details); if (isError(result)) { throw result; } diff --git a/webui/src/pages/user/user-namespace-extension-list-item.tsx b/webui/src/pages/user/user-namespace-extension-list-item.tsx index 20255177d..8c73fc2c5 100644 --- a/webui/src/pages/user/user-namespace-extension-list-item.tsx +++ b/webui/src/pages/user/user-namespace-extension-list-item.tsx @@ -8,7 +8,7 @@ * SPDX-License-Identifier: EPL-2.0 ********************************************************************************/ -import React, { useContext, FunctionComponent, useState, useEffect } from 'react'; +import React, { useContext, FunctionComponent, useState, useEffect, useRef } from 'react'; import { Extension } from '../../extension-registry-types'; import { Paper, Typography, Box, styled } from '@mui/material'; import { Link as RouteLink } from 'react-router-dom'; @@ -35,10 +35,10 @@ export const UserNamespaceExtensionListItem: FunctionComponent(new AbortController()); useEffect(() => { return () => { - abortController.abort(); + abortController.current.abort(); }; }, []); useEffect(() => { @@ -46,7 +46,7 @@ export const UserNamespaceExtensionListItem: FunctionComponent(true); const context = useContext(MainContext); - const abortController = new AbortController(); + const abortController = useRef(new AbortController()); useEffect(() => { updateExtensions(); - return () => abortController.abort(); + return () => abortController.current.abort(); }, []); useEffect(() => { @@ -37,7 +37,7 @@ export const UserNamespaceExtensionListContainer: FunctionComponent { let result: Extension | ErrorResult; try { - result = await context.service.getExtensionDetail(abortController, url); + result = await context.service.getExtensionDetail(abortController.current, url); if (isError(result)) { throw result; } diff --git a/webui/src/pages/user/user-namespace-member-list.tsx b/webui/src/pages/user/user-namespace-member-list.tsx index 155f0ae91..63e80ad7c 100644 --- a/webui/src/pages/user/user-namespace-member-list.tsx +++ b/webui/src/pages/user/user-namespace-member-list.tsx @@ -8,7 +8,7 @@ * SPDX-License-Identifier: EPL-2.0 ********************************************************************************/ -import React, { FunctionComponent, useEffect, useState, useContext } from 'react'; +import React, { FunctionComponent, useEffect, useState, useContext, useRef } from 'react'; import { Box, Typography, Button, Paper } from '@mui/material'; import { UserNamespaceMember } from './user-namespace-member-component'; import { Namespace, NamespaceMembership, MembershipRole, isError, UserData } from '../../extension-registry-types'; @@ -18,18 +18,19 @@ import { MainContext } from '../../context'; export const UserNamespaceMemberList: FunctionComponent = props => { const { service, user, handleError } = useContext(MainContext); const [members, setMembers] = useState([]); + const [addDialogIsOpen, setAddDialogIsOpen] = useState(false); + const abortController = useRef(new AbortController()); + useEffect(() => { fetchMembers(); }, [props.namespace]); - const abortController = new AbortController(); useEffect(() => { return () => { - abortController.abort(); + abortController.current.abort(); }; }, []); - const [addDialogIsOpen, setAddDialogIsOpen] = useState(false); const handleCloseAddDialog = async () => { setAddDialogIsOpen(false); fetchMembers(); @@ -40,7 +41,7 @@ export const UserNamespaceMemberList: FunctionComponent { try { - const membershipList = await service.getNamespaceMembers(abortController, props.namespace); + const membershipList = await service.getNamespaceMembers(abortController.current, props.namespace); const members = membershipList.namespaceMemberships; setMembers(members); } catch (err) { @@ -52,7 +53,7 @@ export const UserNamespaceMemberList: FunctionComponent(new AbortController()); + useEffect(() => { return () => { - abortController.abort(); + abortController.current.abort(); }; }, []); @@ -40,7 +42,7 @@ export const UserPublisherAgreement: FunctionComponent => { try { setWorking(true); - const result = await service.signPublisherAgreement(abortController); + const result = await service.signPublisherAgreement(abortController.current); if (isError(result)) { throw result; } @@ -64,12 +66,11 @@ export const UserPublisherAgreement: FunctionComponent { const agreementURL = pageSettings.urls.publisherAgreement; if (agreementURL) { try { - const agreementMd = await service.getStaticContent(abortController, agreementURL); + const agreementMd = await service.getStaticContent(abortController.current, agreementURL); setAgreementText(agreementMd); } catch (err) { handleError(err); diff --git a/webui/src/pages/user/user-settings-extensions.tsx b/webui/src/pages/user/user-settings-extensions.tsx index d4a88710f..200d2e55e 100644 --- a/webui/src/pages/user/user-settings-extensions.tsx +++ b/webui/src/pages/user/user-settings-extensions.tsx @@ -8,7 +8,7 @@ * SPDX-License-Identifier: EPL-2.0 * ****************************************************************************** */ -import React, { FunctionComponent, useContext, useEffect, useState } from 'react'; +import React, { FunctionComponent, useContext, useEffect, useState, useRef } from 'react'; import { Extension } from '../../extension-registry-types'; import { Box, Typography } from '@mui/material'; import { PublishExtensionDialog } from './publish-extension-dialog'; @@ -22,12 +22,12 @@ export const UserSettingsExtensions: FunctionComponent = () => { const [loading, setLoading] = useState(true); const [extensions, setExtensions] = useState(Array()); const { user, service, handleError } = useContext(MainContext); - const abortController = new AbortController(); + const abortController = useRef(new AbortController()); useEffect(() => { updateExtensions(); return () => { - abortController.abort(); + abortController.current.abort(); }; }, []); @@ -41,7 +41,7 @@ export const UserSettingsExtensions: FunctionComponent = () => { return; } try { - const response = await service.getExtensions(abortController); + const response = await service.getExtensions(abortController.current); if (isError(response)) { throw response; } diff --git a/webui/src/pages/user/user-settings-namespaces.tsx b/webui/src/pages/user/user-settings-namespaces.tsx index fc160fbff..4ca8d1e84 100644 --- a/webui/src/pages/user/user-settings-namespaces.tsx +++ b/webui/src/pages/user/user-settings-namespaces.tsx @@ -8,7 +8,7 @@ * SPDX-License-Identifier: EPL-2.0 ********************************************************************************/ -import React, { ChangeEvent, FunctionComponent, useContext, useEffect, useState } from 'react'; +import React, { ChangeEvent, FunctionComponent, useContext, useEffect, useState, useRef } from 'react'; import { Box, Typography, Tabs, Tab, useTheme, useMediaQuery, Link } from '@mui/material'; import { Namespace, UserData } from '../../extension-registry-types'; import { DelayedLoadIndicator } from '../../components/delayed-load-indicator'; @@ -60,12 +60,12 @@ export const UserSettingsNamespaces: FunctionComponent = () => { const [namespaces, setNamespaces] = useState>([]); const [chosenNamespace, setChosenNamespace] = useState(); const { pageSettings, service, user, handleError } = useContext(MainContext); - const abortController = new AbortController(); + const abortController = useRef(new AbortController()); useEffect(() => { initNamespaces(); return () => { - abortController.abort(); + abortController.current.abort(); }; }, []); @@ -79,7 +79,7 @@ export const UserSettingsNamespaces: FunctionComponent = () => { const initNamespaces = async(): Promise => { try { - const namespaces = await service.getNamespaces(abortController); + const namespaces = await service.getNamespaces(abortController.current); const chosenNamespace = namespaces.length ? namespaces[0] : undefined; setNamespaces(namespaces); setChosenNamespace(chosenNamespace); diff --git a/webui/src/pages/user/user-settings-tokens.tsx b/webui/src/pages/user/user-settings-tokens.tsx index 58dcc249d..517e1d412 100644 --- a/webui/src/pages/user/user-settings-tokens.tsx +++ b/webui/src/pages/user/user-settings-tokens.tsx @@ -8,7 +8,7 @@ * SPDX-License-Identifier: EPL-2.0 ********************************************************************************/ -import React, { FunctionComponent, ReactNode, useContext, useEffect, useState } from 'react'; +import React, { FunctionComponent, ReactNode, useContext, useEffect, useState, useRef } from 'react'; import { Theme, Typography, Box, Paper, Button, Link } from '@mui/material'; import { Link as RouteLink } from 'react-router-dom'; import { DelayedLoadIndicator } from '../../components/delayed-load-indicator'; @@ -48,11 +48,11 @@ export const UserSettingsTokens: FunctionComponent = () => { const [tokens, setTokens] = useState(new Array()); const [loading, setLoading] = useState(true); - const abortController = new AbortController(); + const abortController = useRef(new AbortController()); useEffect(() => { updateTokens(); return () => { - abortController.abort(); + abortController.current.abort(); }; }, []); @@ -61,7 +61,7 @@ export const UserSettingsTokens: FunctionComponent = () => { return; } try { - const tokens = await service.getAccessTokens(abortController, user); + const tokens = await service.getAccessTokens(abortController.current, user); setTokens(tokens); setLoading(false); } catch (err) { @@ -73,7 +73,7 @@ export const UserSettingsTokens: FunctionComponent = () => { const handleDelete = async (token: PersonalAccessToken) => { setLoading(true); try { - await service.deleteAccessToken(abortController, token); + await service.deleteAccessToken(abortController.current, token); updateTokens(); } catch (err) { handleError(err); @@ -83,7 +83,7 @@ export const UserSettingsTokens: FunctionComponent = () => { const handleDeleteAll = async () => { setLoading(true); try { - await service.deleteAllAccessTokens(abortController, tokens); + await service.deleteAllAccessTokens(abortController.current, tokens); updateTokens(); } catch (err) { handleError(err);