Fix dashboard issues (#8347)

- Fixes https://github.com/enso-org/cloud-v2/issues/770
- Fixes https://github.com/enso-org/cloud-v2/issues/772
- Fixes https://github.com/enso-org/cloud-v2/issues/775
- Fixes #8335

# Important Notes
The fix for "Reopening cloud projects" has not been tested, as opening projects on the cloud are currently broken - *however*, the logic change is very small - the only thing it does is make the reopening conditional. This means that, at the very least, it should not be a regression.
This commit is contained in:
somebody1234 2023-11-21 20:37:45 +10:00 committed by GitHub
parent feb59be0a1
commit d136c8e40c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 61 additions and 51 deletions

View File

@ -19,25 +19,24 @@
"dependencies": {
"@types/mime-types": "^2.1.1",
"@types/opener": "^1.4.0",
"@types/tar": "^6.1.4",
"@types/yargs": "^17.0.30",
"chalk": "^5.2.0",
"create-servers": "3.2.0",
"electron-is-dev": "^2.0.0",
"mime-types": "^2.1.35",
"opener": "^1.5.2",
"string-length": "^5.0.1",
"@types/tar": "^6.1.4",
"tar": "^6.1.13",
"@types/yargs": "^17.0.30",
"yargs": "17.6.2"
},
"comments": {
"electron-builder": "Cannot be updated to a newer version because of a NSIS installer issue: https://github.com/enso-org/enso/issues/5169"
},
"devDependencies": {
"crypto-js": "4.1.1",
"@electron/notarize": "2.1.0",
"electron": "25.7.0",
"electron-builder": "^22.14.13",
"@electron/notarize": "2.1.0",
"enso-common": "^1.0.0",
"esbuild": "^0.19.3",
"fast-glob": "^3.2.12",
@ -45,10 +44,10 @@
"tsx": "^3.12.6"
},
"optionalDependencies": {
"dmg-license": "^1.0.11",
"@esbuild/darwin-x64": "^0.17.15",
"@esbuild/linux-x64": "^0.17.15",
"@esbuild/windows-x64": "^0.17.15"
"@esbuild/windows-x64": "^0.17.15",
"dmg-license": "^1.0.11"
},
"scripts": {
"typecheck": "npm run --workspace=enso-gui2 compile-server && tsc --noEmit",

View File

@ -114,8 +114,7 @@ const ALL_BUNDLES_READY = new Promise<Watches>((resolve, reject) => {
path.resolve(THIS_PATH, '..', '..', 'debugGlobals.ts')
)
contentOpts.outdir = path.resolve(IDE_DIR_PATH, 'assets')
contentOpts.define['process.env.REDIRECT_OVERRIDE'] =
JSON.stringify('http://localhost:8080')
contentOpts.define.REDIRECT_OVERRIDE = JSON.stringify('http://localhost:8080')
const contentBuilder = await esbuild.context(contentOpts)
const content = await contentBuilder.rebuild()
console.log('Result of content bundling: ', content)

View File

@ -40,7 +40,7 @@ async function watch() {
)
opts.pure.splice(opts.pure.indexOf('assert'), 1)
;(opts.inject = opts.inject ?? []).push(path.resolve(THIS_PATH, '..', '..', 'debugGlobals.ts'))
opts.define['process.env.REDIRECT_OVERRIDE'] = JSON.stringify('http://localhost:8080')
opts.define.REDIRECT_OVERRIDE = JSON.stringify('http://localhost:8080')
// This is safe as this entry point is statically known.
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
const serviceWorkerEntryPoint = opts.entryPoints.find(

View File

@ -5,12 +5,12 @@ import * as router from 'react-router-dom'
import * as toastify from 'react-toastify'
import ArrowRightIcon from 'enso-assets/arrow_right.svg'
import AtIcon from 'enso-assets/at.svg'
import GoBackIcon from 'enso-assets/go_back.svg'
import LockIcon from 'enso-assets/lock.svg'
import * as app from '../../components/app'
import * as auth from '../providers/auth'
import * as hooks from '../../hooks'
import * as string from '../../string'
import * as validation from '../../dashboard/validation'
@ -35,20 +35,30 @@ const RESET_PASSWORD_QUERY_PARAMS = {
export default function ResetPassword() {
const { resetPassword } = auth.useAuth()
const { search } = router.useLocation()
const navigate = hooks.useNavigate()
const { verificationCode: initialCode, email: initialEmail } = parseUrlSearchParams(search)
const { verificationCode, email } = parseUrlSearchParams(search)
const [email, setEmail] = React.useState(initialEmail ?? '')
const [code, setCode] = React.useState(initialCode ?? '')
const [newPassword, setNewPassword] = React.useState('')
const [newPasswordConfirm, setNewPasswordConfirm] = React.useState('')
React.useEffect(() => {
if (email == null) {
toastify.toast.error('Could not reset password: missing email address')
navigate(app.LOGIN_PATH)
} else if (verificationCode == null) {
toastify.toast.error('Could not reset password: missing verification code')
navigate(app.LOGIN_PATH)
}
}, [email, navigate, verificationCode])
const onSubmit = () => {
if (newPassword !== newPasswordConfirm) {
toastify.toast.error('Passwords do not match')
return Promise.resolve()
} else {
return resetPassword(email, code, newPassword)
// These should never be nullish, as the effect should immediately navigate away.
return resetPassword(email ?? '', verificationCode ?? '', newPassword)
}
}
@ -62,25 +72,23 @@ export default function ResetPassword() {
}}
>
<div className="font-medium self-center text-xl">Reset your password</div>
<Input
<input
required
readOnly
hidden
type="email"
autoComplete="email"
label="Email"
icon={AtIcon}
placeholder="Enter your email"
value={email}
setValue={setEmail}
value={email ?? ''}
/>
<Input
<input
required
readOnly
hidden
type="text"
autoComplete="one-time-code"
label="Confirmation code"
icon={LockIcon}
placeholder="Enter the confirmation code"
value={code}
setValue={setCode}
value={verificationCode ?? ''}
/>
<Input
required

View File

@ -494,7 +494,7 @@ export function AuthProvider(props: AuthProviderProps) {
const result = await cognito.forgotPassword(email)
if (result.ok) {
toastSuccess(MESSAGES.forgotPasswordSuccess)
navigate(app.RESET_PASSWORD_PATH)
navigate(app.LOGIN_PATH)
} else {
toastError(result.val.message)
}

View File

@ -234,7 +234,7 @@ function setDeepLinkHandler(logger: loggerProvider.Logger, navigate: (url: strin
* the password reset page, with the verification code and email passed in the URL s-o they can
* be filled in automatically. */
case app.RESET_PASSWORD_PATH: {
const resetPasswordRedirectUrl = `${app.RESET_PASSWORD_PATH}${parsedUrl.search}`
const resetPasswordRedirectUrl = app.RESET_PASSWORD_PATH + parsedUrl.search
navigate(resetPasswordRedirectUrl)
break
}

View File

@ -93,11 +93,9 @@ export default function Dashboard(props: DashboardProps) {
React.useEffect(() => {
unsetModal()
if (page === pageSwitcher.Page.editor) {
document.body.style.cursor = 'none'
} else {
document.body.style.cursor = 'auto'
}
// FIXME [sb]: https://github.com/enso-org/cloud-v2/issues/777
// Workarounds for GUI1 should be removed when they are no longer necessary.
document.body.style.cursor = page === pageSwitcher.Page.editor ? 'none' : 'auto'
}, [page, /* should never change */ unsetModal])
React.useEffect(() => {
@ -153,19 +151,29 @@ export default function Dashboard(props: DashboardProps) {
void (async () => {
const abortController = new AbortController()
setOpenProjectAbortController(abortController)
await remoteBackendModule.waitUntilProjectIsReady(
remoteBackend,
savedProjectStartupInfo.projectAsset,
abortController
const oldProject = await backend.getProjectDetails(
savedProjectStartupInfo.projectAsset.id,
savedProjectStartupInfo.projectAsset.title
)
if (!abortController.signal.aborted) {
const project = await remoteBackend.getProjectDetails(
savedProjectStartupInfo.projectAsset.id,
savedProjectStartupInfo.projectAsset.title
if (
backendModule.DOES_PROJECT_STATE_INDICATE_VM_EXISTS[
oldProject.state.type
]
) {
await remoteBackendModule.waitUntilProjectIsReady(
remoteBackend,
savedProjectStartupInfo.projectAsset,
abortController
)
setProjectStartupInfo({ ...savedProjectStartupInfo, project })
if (page === pageSwitcher.Page.editor) {
setPage(page)
if (!abortController.signal.aborted) {
const project = await remoteBackend.getProjectDetails(
savedProjectStartupInfo.projectAsset.id,
savedProjectStartupInfo.projectAsset.title
)
setProjectStartupInfo({ ...savedProjectStartupInfo, project })
if (page === pageSwitcher.Page.editor) {
setPage(page)
}
}
}
})()

View File

@ -136,7 +136,9 @@ export default function ProjectIcon(props: ProjectIconProps) {
switch (backend.type) {
case backendModule.BackendType.remote: {
if (state !== backendModule.ProjectState.opened) {
setToastId(toast.toast.loading(LOADING_MESSAGE))
if (!shouldRunInBackground) {
setToastId(toast.toast.loading(LOADING_MESSAGE))
}
await backend.openProject(
item.id,
{

View File

@ -98,7 +98,7 @@ function ProjectsEntry(props: InternalProjectsEntryProps) {
return (
<div className="flex flex-col gap-1.5 h-51">
<button
className="relative grow cursor-pointer before:absolute before:bg-frame before:rounded-2xl before:w-full before:h-full before:opacity-60"
className="relative grow cursor-pointer before:absolute before:inset-0 before:bg-frame before:rounded-2xl before:w-full before:h-full before:opacity-60"
onClick={() => {
setSpinnerState(spinner.SpinnerState.initial)
onTemplateClick(null, newSpinnerState => {

View File

@ -16,7 +16,7 @@ export default function WhatsNew() {
<h2 className="text-xl leading-144.5 py-0.5">Discover what&rsquo;s new</h2>
<div className="grid gap-3 grid-cols-fill-75">
<a
className="relative whatsnew-span-2 col-span-2 bg-v3 text-tag-text rounded-2xl h-45"
className="relative whatsnew-span-2 col-span-1 sm:col-span-2 bg-v3 text-tag-text rounded-2xl h-45"
rel="noreferrer"
target="_blank"
href="https://enso.org/"

6
package-lock.json generated
View File

@ -153,7 +153,6 @@
},
"devDependencies": {
"@electron/notarize": "2.1.0",
"crypto-js": "4.1.1",
"electron": "25.7.0",
"electron-builder": "^22.14.13",
"enso-common": "^1.0.0",
@ -6554,11 +6553,6 @@
"node": ">= 8"
}
},
"node_modules/crypto-js": {
"version": "4.1.1",
"dev": true,
"license": "MIT"
},
"node_modules/crypto-random-string": {
"version": "2.0.0",
"dev": true,