React IDE page: add connection and SyncTex alerts (#15273)

Add connection and SyncTex alerts

GitOrigin-RevId: 5004a0d356d0a0355d125516a18db1f57e617a7f
This commit is contained in:
Tim Down 2023-10-18 10:14:58 +01:00 committed by Copybot
parent 3be937c503
commit 87199c80fe
7 changed files with 140 additions and 1 deletions

View file

@ -9,6 +9,10 @@ block vars
block entrypointVar block entrypointVar
- entrypoint = 'pages/ide' - entrypoint = 'pages/ide'
block css
each file in entrypointStyles('ide')
link(rel='stylesheet', href=file)
block content block content
main#ide-root main#ide-root
.loading-screen .loading-screen

View file

@ -260,6 +260,7 @@
"disable_sso": "", "disable_sso": "",
"disable_stop_on_first_error": "", "disable_stop_on_first_error": "",
"disabling": "", "disabling": "",
"disconnected": "",
"discount_of": "", "discount_of": "",
"dismiss": "", "dismiss": "",
"dismiss_error_popup": "", "dismiss_error_popup": "",
@ -307,6 +308,7 @@
"editing": "", "editing": "",
"editing_captions": "", "editing_captions": "",
"editor_and_pdf": "&", "editor_and_pdf": "&",
"editor_disconected_click_to_reconnect": "",
"editor_only_hide_pdf": "", "editor_only_hide_pdf": "",
"editor_theme": "", "editor_theme": "",
"educational_discount_for_groups_of_x_or_more": "", "educational_discount_for_groups_of_x_or_more": "",
@ -631,6 +633,7 @@
"logs_and_output_files": "", "logs_and_output_files": "",
"looking_multiple_licenses": "", "looking_multiple_licenses": "",
"looks_like_youre_at": "", "looks_like_youre_at": "",
"lost_connection": "",
"main_document": "", "main_document": "",
"main_file_not_found": "", "main_file_not_found": "",
"make_a_copy": "", "make_a_copy": "",
@ -678,6 +681,7 @@
"month": "", "month": "",
"more": "", "more": "",
"more_actions": "", "more_actions": "",
"more_info": "",
"more_options_for_border_settings_coming_soon": "", "more_options_for_border_settings_coming_soon": "",
"my_library": "", "my_library": "",
"n_items": "", "n_items": "",
@ -887,6 +891,8 @@
"recompile_from_scratch": "", "recompile_from_scratch": "",
"recompile_pdf": "", "recompile_pdf": "",
"reconnect": "", "reconnect": "",
"reconnecting": "",
"reconnecting_in_x_secs": "",
"recurly_email_update_needed": "", "recurly_email_update_needed": "",
"recurly_email_updated": "", "recurly_email_updated": "",
"redirect_to_editor": "", "redirect_to_editor": "",
@ -1102,6 +1108,7 @@
"sync_project_to_github_explanation": "", "sync_project_to_github_explanation": "",
"sync_to_dropbox": "", "sync_to_dropbox": "",
"sync_to_github": "", "sync_to_github": "",
"synctex_failed": "",
"syntax_validation": "", "syntax_validation": "",
"tab_connecting": "", "tab_connecting": "",
"tab_no_longer_connected": "", "tab_no_longer_connected": "",
@ -1222,6 +1229,7 @@
"tried_to_register_with_email": "", "tried_to_register_with_email": "",
"try_again": "", "try_again": "",
"try_it_for_free": "", "try_it_for_free": "",
"try_now": "",
"try_premium_for_free": "", "try_premium_for_free": "",
"try_recompile_project_or_troubleshoot": "", "try_recompile_project_or_troubleshoot": "",
"try_relinking_provider": "", "try_relinking_provider": "",

View file

@ -0,0 +1,73 @@
import { useTranslation } from 'react-i18next'
import { LostConnectionAlert } from './lost-connection-alert'
import { useConnectionContext } from '@/features/ide-react/context/connection-context'
import { debugging } from '@/utils/debugging'
import { Alert } from 'react-bootstrap'
// TODO SavingNotificationController, SystemMessagesController, out-of-sync modal
export function Alerts() {
const { t } = useTranslation()
const {
connectionState,
isConnected,
isStillReconnecting,
tryReconnectNow,
secondsUntilReconnect,
} = useConnectionContext()
// TODO: Get this from a context
const synctexError = false
return (
<div className="global-alerts">
{connectionState.forceDisconnected ? (
<Alert bsStyle="warning" className="small">
<strong>{t('disconnected')}</strong>
</Alert>
) : null}
{connectionState.reconnectAt ? (
<LostConnectionAlert
reconnectAt={connectionState.reconnectAt}
tryReconnectNow={tryReconnectNow}
/>
) : null}
{isStillReconnecting ? (
<Alert bsStyle="warning" className="small">
<strong>{t('reconnecting')}</strong>
</Alert>
) : null}
{synctexError ? (
<Alert bsStyle="warning" className="small">
<strong>{t('synctex_failed')}</strong>
<a
href="/learn/how-to/SyncTeX_Errors"
target="_blank"
id="synctex-more-info-button"
className="alert-link-as-btn pull-right"
>
{t('more_info')}
</a>
</Alert>
) : null}
{connectionState.inactiveDisconnect ||
(connectionState.readyState === WebSocket.CLOSED &&
(connectionState.error === 'rate-limited' ||
connectionState.error === 'unable-to-connect') &&
!secondsUntilReconnect()) ? (
<Alert bsStyle="warning" className="small">
<strong>{t('editor_disconected_click_to_reconnect')}</strong>
</Alert>
) : null}
{debugging ? (
<Alert bsStyle="warning" className="small">
<strong>Connected: {isConnected.toString()}</strong>
</Alert>
) : null}
</div>
)
}

View file

@ -0,0 +1,40 @@
import { useTranslation } from 'react-i18next'
import { useEffect, useState } from 'react'
import { secondsUntil } from '@/features/ide-react/connection/utils'
import { Alert } from 'react-bootstrap'
type LostConnectionAlertProps = {
reconnectAt: number
tryReconnectNow: () => void
}
export function LostConnectionAlert({
reconnectAt,
tryReconnectNow,
}: LostConnectionAlertProps) {
const { t } = useTranslation()
const [secondsUntilReconnect, setSecondsUntilReconnect] = useState(
secondsUntil(reconnectAt)
)
useEffect(() => {
const timer = window.setInterval(() => {
setSecondsUntilReconnect(secondsUntil(reconnectAt))
}, 1000)
return () => window.clearInterval(timer)
}, [reconnectAt])
return (
<Alert bsStyle="warning" className="small">
<strong>{t('lost_connection')}</strong>{' '}
{t('reconnecting_in_x_secs', { seconds: secondsUntilReconnect })}.
<button
id="try-reconnect-now-button"
className="pull-right"
onClick={() => tryReconnectNow()}
>
{t('try_now')}
</button>
</Alert>
)
}

View file

@ -2,6 +2,7 @@ import LayoutWithPlaceholders from '@/features/ide-react/components/layout/layou
import { useConnectionContext } from '@/features/ide-react/context/connection-context' import { useConnectionContext } from '@/features/ide-react/context/connection-context'
import useEventListener from '@/shared/hooks/use-event-listener' import useEventListener from '@/shared/hooks/use-event-listener'
import { useCallback, useEffect } from 'react' import { useCallback, useEffect } from 'react'
import { Alerts } from '@/features/ide-react/components/alerts/alerts'
// This is filled with placeholder content while the real content is migrated // This is filled with placeholder content while the real content is migrated
// away from Angular // away from Angular
@ -23,7 +24,8 @@ export default function IdePage() {
return ( return (
<> <>
{/* TODO: Alerts and left menu will go here */} <Alerts />
{/* TODO: Left menu will go here */}
<LayoutWithPlaceholders shouldPersistLayout /> <LayoutWithPlaceholders shouldPersistLayout />
</> </>
) )

View file

@ -1,5 +1,12 @@
#ide-root { #ide-root {
height: 100vh; height: 100vh;
.global-alerts {
position: absolute;
top: 0;
left: 0;
right: 0;
}
} }
.ide-react-main { .ide-react-main {

View file

@ -543,6 +543,7 @@
color: darken(@text-color, 10%); color: darken(@text-color, 10%);
} }
button,
.alert-link-as-btn { .alert-link-as-btn {
display: inline-block; display: inline-block;
font-weight: bold; font-weight: bold;
@ -557,6 +558,10 @@
} }
} }
button {
border-width: 0;
}
small, small,
.small { .small {
color: @text-color; color: @text-color;