[workbench] Improve asynchronous tool use (#30184)

GitOrigin-RevId: d1bd33469b557c29968049af99b9c3c85731151d
This commit is contained in:
Alf Eaton
2025-12-10 09:06:43 +00:00
committed by Copybot
parent 851f0c92b1
commit b811da0695
13 changed files with 40 additions and 25 deletions
@@ -20,7 +20,10 @@ const EditorNavigationToolbarRoot = React.memo(
openShareProjectModal, openShareProjectModal,
}: { }: {
onlineUsersArray: OnlineUser[] onlineUsersArray: OnlineUser[]
openDoc: (doc: Doc, { gotoLine }: { gotoLine: number }) => void openDoc: (
doc: Doc,
{ gotoLine }: { gotoLine: number }
) => Promise<Doc | undefined>
openShareProjectModal: () => void openShareProjectModal: () => void
}) { }) {
const { const {
@@ -93,9 +96,9 @@ const EditorNavigationToolbarRoot = React.memo(
}, [setLeftMenuShown]) }, [setLeftMenuShown])
const goToUser = useCallback( const goToUser = useCallback(
(user: OnlineUser) => { async (user: OnlineUser) => {
if (user.doc && typeof user.row === 'number') { if (user.doc && typeof user.row === 'number') {
openDoc(user.doc, { gotoLine: user.row + 1 }) return await openDoc(user.doc, { gotoLine: user.row + 1 })
} }
}, },
[openDoc] [openDoc]
@@ -11,13 +11,14 @@ import { getBackgroundColorForUserId } from '@/shared/utils/colors'
import OLTooltip from '@/shared/components/ol/ol-tooltip' import OLTooltip from '@/shared/components/ol/ol-tooltip'
import MaterialIcon from '@/shared/components/material-icon' import MaterialIcon from '@/shared/components/material-icon'
import { OnlineUser } from '@/features/ide-react/context/online-users-context' import { OnlineUser } from '@/features/ide-react/context/online-users-context'
import { Doc } from '@ol-types/doc'
function OnlineUsersWidget({ function OnlineUsersWidget({
onlineUsers, onlineUsers,
goToUser, goToUser,
}: { }: {
onlineUsers: OnlineUser[] onlineUsers: OnlineUser[]
goToUser: (user: OnlineUser) => void goToUser: (user: OnlineUser) => Promise<Doc | undefined>
}) { }) {
const { t } = useTranslation() const { t } = useTranslation()
@@ -19,6 +19,7 @@ import TryNewEditorButton from '../try-new-editor-button'
import { OnlineUser } from '@/features/ide-react/context/online-users-context' import { OnlineUser } from '@/features/ide-react/context/online-users-context'
import { Cobranding } from '../../../../../types/cobranding' import { Cobranding } from '../../../../../types/cobranding'
import { canUseNewEditor } from '@/features/ide-redesign/utils/new-editor-utils' import { canUseNewEditor } from '@/features/ide-redesign/utils/new-editor-utils'
import { Doc } from '@ol-types/doc'
const [publishModalModules] = importOverleafModules('publishModal') as { const [publishModalModules] = importOverleafModules('publishModal') as {
import: { default: ElementType } import: { default: ElementType }
@@ -50,7 +51,7 @@ export type ToolbarHeaderProps = {
toggleHistoryOpen: () => void toggleHistoryOpen: () => void
unreadMessageCount: number unreadMessageCount: number
onlineUsers: OnlineUser[] onlineUsers: OnlineUser[]
goToUser: (user: OnlineUser) => void goToUser: (user: OnlineUser) => Promise<Doc | undefined>
isRestrictedTokenMember: boolean | undefined isRestrictedTokenMember: boolean | undefined
hasPublishPermissions: boolean hasPublishPermissions: boolean
chatVisible: boolean chatVisible: boolean
@@ -31,7 +31,7 @@ export default function FileTreeCreateNewDoc() {
}) })
if (doc) { if (doc) {
openDoc(doc) return await openDoc(doc)
} }
}, },
[finishCreatingDoc, name, openDoc] [finishCreatingDoc, name, openDoc]
@@ -54,11 +54,14 @@ export type EditorManager = {
getCurrentDocValue: () => string | null getCurrentDocValue: () => string | null
getCurrentDocumentId: () => DocId | null getCurrentDocumentId: () => DocId | null
setIgnoringExternalUpdates: (value: boolean) => void setIgnoringExternalUpdates: (value: boolean) => void
openDocWithId: (docId: string, options?: OpenDocOptions) => void openDocWithId: (
docId: string,
options?: OpenDocOptions
) => Promise<Doc | undefined>
openDoc: (document: Doc, options?: OpenDocOptions) => Promise<Doc | undefined> openDoc: (document: Doc, options?: OpenDocOptions) => Promise<Doc | undefined>
openDocs: OpenDocuments openDocs: OpenDocuments
openFileWithId: (fileId: string) => void openFileWithId: (fileId: string) => void
openInitialDoc: (docId?: string) => void openInitialDoc: (docId?: string) => Promise<Doc | undefined>
isLoading: boolean isLoading: boolean
jumpToLine: (options: GotoLineOptions) => void jumpToLine: (options: GotoLineOptions) => void
debugTimers: React.MutableRefObject<Record<string, number>> debugTimers: React.MutableRefObject<Record<string, number>>
@@ -486,12 +489,12 @@ export const EditorManagerProvider: FC<React.PropsWithChildren> = ({
) )
const openDocWithId = useCallback( const openDocWithId = useCallback(
(docId: string, options: OpenDocOptions = {}) => { async (docId: string, options: OpenDocOptions = {}) => {
const doc = findDocEntityById(fileTreeData, docId) const doc = findDocEntityById(fileTreeData, docId)
if (!doc) { if (!doc) {
return return
} }
openDoc(doc, options) return await openDoc(doc, options)
}, },
[fileTreeData, openDoc] [fileTreeData, openDoc]
) )
@@ -513,11 +516,11 @@ export const EditorManagerProvider: FC<React.PropsWithChildren> = ({
) )
const openInitialDoc = useCallback( const openInitialDoc = useCallback(
(fallbackDocId?: string) => { async (fallbackDocId?: string) => {
const docId = const docId =
customLocalStorage.getItem(currentDocumentIdStorageKey) || fallbackDocId customLocalStorage.getItem(currentDocumentIdStorageKey) || fallbackDocId
if (docId) { if (docId) {
openDocWithId(docId) return await openDocWithId(docId)
} }
}, },
[currentDocumentIdStorageKey, openDocWithId] [currentDocumentIdStorageKey, openDocWithId]
@@ -580,7 +583,7 @@ export const EditorManagerProvider: FC<React.PropsWithChildren> = ({
} }
const handleProjectJoined = () => { const handleProjectJoined = () => {
openDoc(doc, { forceReopen: true }) return openDoc(doc, { forceReopen: true })
} }
eventEmitter.once('project:joined', handleProjectJoined) eventEmitter.once('project:joined', handleProjectJoined)
@@ -14,6 +14,7 @@ import {
import classNames from 'classnames' import classNames from 'classnames'
import { useCallback, useMemo } from 'react' import { useCallback, useMemo } from 'react'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import { Doc } from '@ol-types/doc'
// Should be kept in sync with $max-user-circles-displayed CSS constant // Should be kept in sync with $max-user-circles-displayed CSS constant
const MAX_USER_CIRCLES_DISPLAYED = 5 const MAX_USER_CIRCLES_DISPLAYED = 5
@@ -26,7 +27,7 @@ export const OnlineUsersWidget = ({
goToUser, goToUser,
}: { }: {
onlineUsers: OnlineUser[] onlineUsers: OnlineUser[]
goToUser: (user: OnlineUser) => void goToUser: (user: OnlineUser) => Promise<Doc | undefined>
}) => { }) => {
const hasOverflow = onlineUsers.length > MAX_USER_CIRCLES_DISPLAYED const hasOverflow = onlineUsers.length > MAX_USER_CIRCLES_DISPLAYED
const usersBeforeOverflow = useMemo( const usersBeforeOverflow = useMemo(
@@ -11,9 +11,9 @@ export const OnlineUsers = () => {
const { onlineUsersArray } = useOnlineUsersContext() const { onlineUsersArray } = useOnlineUsersContext()
const goToUser = useCallback( const goToUser = useCallback(
(user: OnlineUser) => { async (user: OnlineUser) => {
if (user.doc && typeof user.row === 'number') { if (user.doc && typeof user.row === 'number') {
openDoc(user.doc, { gotoLine: user.row + 1 }) return await openDoc(user.doc, { gotoLine: user.row + 1 })
} }
}, },
[openDoc] [openDoc]
@@ -33,7 +33,7 @@ export const startCompileKeypress = (
} }
export default function useCompileTriggers( export default function useCompileTriggers(
startCompile: (...args: any[]) => void, startCompile: (...args: any[]) => Promise<void>,
setChangedAt: (...args: any[]) => void setChangedAt: (...args: any[]) => void
) { ) {
const handleKeyDown = useCallback( const handleKeyDown = useCallback(
@@ -120,7 +120,7 @@ export type CompileContext = {
setAnimateCompileDropdownArrow: (value: boolean) => void setAnimateCompileDropdownArrow: (value: boolean) => void
recompileFromScratch: () => void recompileFromScratch: () => void
setCompiling: (value: boolean) => void setCompiling: (value: boolean) => void
startCompile: (options?: any) => void startCompile: (options?: any) => Promise<void>
stopCompile: () => void stopCompile: () => void
setChangedAt: (value: any) => void setChangedAt: (value: any) => void
clearCache: () => void clearCache: () => void
@@ -700,14 +700,14 @@ export const LocalCompileProvider: FC<React.PropsWithChildren> = ({
const startCompile = useCallback( const startCompile = useCallback(
(options: any) => { (options: any) => {
setCompiledOnce(true) setCompiledOnce(true)
compiler.compile(options) return compiler.compile(options)
}, },
[compiler, setCompiledOnce] [compiler, setCompiledOnce]
) )
// stop a compile manually // stop a compile manually
const stopCompile = useCallback(() => { const stopCompile = useCallback(() => {
compiler.stopCompile() return compiler.stopCompile()
}, [compiler]) }, [compiler])
// clear the compile cache // clear the compile cache
@@ -21,7 +21,7 @@ export default function useDetachAction(
if (role === senderRole) { if (role === senderRole) {
broadcastEvent(eventName, { args }) broadcastEvent(eventName, { args })
} else { } else {
actionFunction(...args) return actionFunction(...args)
} }
}, },
[role, senderRole, eventName, actionFunction, broadcastEvent] [role, senderRole, eventName, actionFunction, broadcastEvent]
@@ -40,7 +40,10 @@ export const OnlineUsersRedesign = ({ users }: { users: number }) => {
padding: '20px', padding: '20px',
}} }}
> >
<OnlineUsersWidget onlineUsers={generatedUsers} goToUser={() => {}} /> <OnlineUsersWidget
onlineUsers={generatedUsers}
goToUser={(async () => {}) as any}
/>
</div> </div>
) )
} }
@@ -54,7 +57,10 @@ export const OnlineUsersOld = ({ users }: { users: number }) => {
padding: '20px', padding: '20px',
}} }}
> >
<OnlineUsersWidgetOld onlineUsers={generatedUsers} goToUser={() => {}} /> <OnlineUsersWidgetOld
onlineUsers={generatedUsers}
goToUser={(async () => {}) as any}
/>
</div> </div>
) )
} }
@@ -20,7 +20,7 @@ describe('<OnlineUsersWidget />', function () {
email: 'another_test_email', email: 'another_test_email',
}, },
], ],
goToUser: () => {}, goToUser: (async () => {}) as any,
} }
describe('with less than 4 users', function () { describe('with less than 4 users', function () {
@@ -14,7 +14,7 @@ describe('<ToolbarHeader />', function () {
toggleHistoryOpen: () => {}, toggleHistoryOpen: () => {},
unreadMessageCount: 0, unreadMessageCount: 0,
onlineUsers: [], onlineUsers: [],
goToUser: () => {}, goToUser: (async () => {}) as any,
projectName: 'test project', projectName: 'test project',
renameProject: () => {}, renameProject: () => {},
openShareModal: () => {}, openShareModal: () => {},