Skip to content

Commit 092d7c0

Browse files
Move Help section to the Topbar (#12059)
Closes: https://github.com/enso-org/cloud-v2/issues/1699 This PR is stacked on top of: 1. #12079 2. #12080 And ***shall*** be reviewed in order. This PR _adds_ new 3 items in the topbar: what's new, community and docs. This should improve discoverability for the users and simplify their day-to-day job. --- ***Note***: This PR ***does not*** remove related items from the `Discovery` dialog.
1 parent b3dbfa9 commit 092d7c0

File tree

13 files changed

+499
-227
lines changed

13 files changed

+499
-227
lines changed

app/common/src/text/english.json

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -280,7 +280,7 @@
280280
"versions": "Versions",
281281
"properties": "Properties",
282282
"projectSessions": "Sessions",
283-
"docs": "Docs",
283+
"docs": "Documentation",
284284
"datalink": "Datalink",
285285
"secret": "Secret",
286286
"createDatalink": "Create Datalink",
@@ -295,6 +295,7 @@
295295
"options": "Options",
296296
"googleIcon": "Google icon",
297297
"gitHubIcon": "GitHub icon",
298+
"more": "More",
298299
"close": "Close",
299300

300301
"enterSecretPath": "Enter secret path",
@@ -587,8 +588,18 @@
587588
"newPasswordPlaceholder": "Enter your new password",
588589
"confirmNewPasswordLabel": "Confirm new password",
589590
"confirmNewPasswordPlaceholder": "Confirm your new password",
590-
591+
"projectName": "Project name",
592+
"help": "Help",
593+
"community": "Community",
594+
"componentExamples": "Component examples",
595+
"enso101": "Enso 101",
596+
"askAQuestion": "Ask a question",
597+
"whatsNew": "What's new",
591598
"selectTemplate": "Discover Enso Analytics",
599+
"chooseATemplate": "Choose a template",
600+
"basicTemplates": "Basic templates",
601+
"advancedTemplates": "Advanced templates",
602+
"startWithTemplate": "Start with a template",
592603
"welcomeSubtitle": "Explore templates, plugins, and data sources to kickstart your next big idea.",
593604
"newsItem3Beta": "Read what’s new in Enso",
594605
"newsItem3BetaDescription": "Learn about new features and whats coming soon.",

app/gui/.storybook/preview.tsx

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -47,27 +47,32 @@ const reactPreview: ReactPreview = {
4747
// Decorators are applied in the reverse order they are defined
4848
decorators: [
4949
(Story, context) => {
50-
const [portalRoot, setPortalRoot] = useState<Element | null>(null)
50+
const [roots, setRoots] = useState<{ appRoot: HTMLElement; portalRoot: HTMLElement } | null>(
51+
null,
52+
)
5153

5254
useLayoutEffect(() => {
55+
const appRoot = document.querySelector('#enso-app')
56+
invariant(appRoot instanceof HTMLElement, 'AppRoot element not found')
57+
5358
const portalRoot = document.querySelector('#enso-portal-root')
54-
invariant(portalRoot, 'PortalRoot element not found')
59+
invariant(portalRoot instanceof HTMLElement, 'PortalRoot element not found')
5560

56-
setPortalRoot(portalRoot)
61+
setRoots({ appRoot, portalRoot })
5762
}, [])
5863

59-
if (!portalRoot) return <></>
64+
if (!roots) return <></>
6065

6166
return (
62-
<UIProviders locale="en-US" portalRoot={portalRoot}>
67+
<UIProviders locale="en-US" {...roots}>
6368
<Story {...context} />
6469
</UIProviders>
6570
)
6671
},
6772

6873
(Story, context) => (
6974
<>
70-
<div className="enso-app">
75+
<div id="enso-app" className="enso-app">
7176
<Story {...context} />
7277
</div>
7378

app/gui/integration-test/dashboard/assetsTableFeatures.spec.ts

Lines changed: 0 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -31,33 +31,6 @@ function locateRootDirectoryDropzone(page: Page) {
3131

3232
const PASS_TIMEOUT = 5_000
3333

34-
test('extra columns should stick to right side of assets table', ({ page }) =>
35-
mockAllAndLogin({ page })
36-
.withAssetsTable(async (table) => {
37-
await table.evaluate((element) => {
38-
let scrollableParent: HTMLElement | SVGElement | null = element
39-
while (
40-
scrollableParent != null &&
41-
scrollableParent.scrollWidth <= scrollableParent.clientWidth
42-
) {
43-
scrollableParent = scrollableParent.parentElement
44-
}
45-
scrollableParent?.scrollTo({ left: 999999, behavior: 'instant' })
46-
})
47-
})
48-
.withAssetsTable(async (assetsTable, _, thePage) => {
49-
const extraColumns = locateExtraColumns(thePage)
50-
await expect(async () => {
51-
const extraColumnsRight = await extraColumns.evaluate(
52-
(element) => element.getBoundingClientRect().right,
53-
)
54-
const assetsTableRight = await assetsTable.evaluate(
55-
(element) => element.getBoundingClientRect().right,
56-
)
57-
expect(extraColumnsRight).toEqual(assetsTableRight - 8)
58-
}).toPass({ timeout: PASS_TIMEOUT })
59-
}))
60-
6134
test('extra columns should stick to top of scroll container', ({ page }) =>
6235
mockAllAndLogin({
6336
page,

app/gui/src/ReactRoot.tsx

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,21 +35,27 @@ export default function ReactRoot(props: ReactRootProps) {
3535
const { config, queryClient, onAuthenticated } = props
3636

3737
const httpClient = new HttpClient()
38+
3839
const supportsDeepLinks = !IS_DEV_MODE && !isOnLinux() && isOnElectron()
40+
41+
const appRoot = document.querySelector('#enso-app')
42+
invariant(appRoot instanceof HTMLElement, 'AppRoot element not found')
43+
3944
const portalRoot = document.querySelector('#enso-portal-root')
45+
invariant(portalRoot instanceof HTMLElement, 'PortalRoot element not found')
46+
4047
const shouldUseAuthentication = config.authentication.enabled
4148
const projectManagerUrl =
4249
(config.engine.projectManagerUrl || resolveEnvUrl($config.PROJECT_MANAGER_URL)) ?? null
4350
const ydocUrl = (config.engine.ydocUrl || resolveEnvUrl($config.YDOC_SERVER_URL)) ?? null
4451
const initialProjectName = config.startup.project || null
45-
invariant(portalRoot, 'PortalRoot element not found')
4652
const isCloudBuild = $config.CLOUD_BUILD === 'true'
4753

4854
return (
4955
<StrictMode>
5056
<QueryClientProvider client={queryClient}>
5157
<ErrorBoundary>
52-
<UIProviders locale="en-US" portalRoot={portalRoot}>
58+
<UIProviders locale="en-US" portalRoot={portalRoot} appRoot={appRoot}>
5359
<Suspense fallback={<LoadingScreen />}>
5460
<OfflineNotificationManager>
5561
<LoggerProvider logger={console}>

app/gui/src/dashboard/components/AnimatedBackground.tsx

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,6 @@ const DEFAULT_TRANSITION: Transition = {
3434
mass: 0.3,
3535
velocity: 8,
3636
}
37-
3837
/* eslint-enable @typescript-eslint/no-magic-numbers */
3938

4039
/** `<AnimatedBackground />` component visually highlights selected items by sliding a background into view when hovered over or clicked. */

app/gui/src/dashboard/components/AriaComponents/Dialog/Dialog.tsx

Lines changed: 100 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -12,19 +12,22 @@ import * as suspense from '#/components/Suspense'
1212

1313
import * as mergeRefs from '#/utilities/mergeRefs'
1414

15-
import { DialogDismiss } from '#/components/AriaComponents'
15+
import { DialogDismiss, ResetButtonGroupContext } from '#/components/AriaComponents'
1616
import { useEventCallback } from '#/hooks/eventCallbackHooks'
1717
import { useMeasure } from '#/hooks/measureHooks'
1818
import { LayoutGroup, motion, type Spring } from '#/utilities/motion'
1919
import type { VariantProps } from '#/utilities/tailwindVariants'
2020
import { tv } from '#/utilities/tailwindVariants'
21+
import { unsafeWriteValue } from '#/utilities/write'
22+
import { useRootContext } from '../../UIProviders'
2123
import { Close } from './Close'
2224
import * as dialogProvider from './DialogProvider'
2325
import * as dialogStackProvider from './DialogStackProvider'
2426
import { DialogTrigger } from './DialogTrigger'
2527
import type * as types from './types'
2628
import * as utlities from './utilities'
2729
import { DIALOG_BACKGROUND } from './variants'
30+
2831
// eslint-disable-next-line no-restricted-syntax
2932
const MotionDialog = motion(aria.Dialog)
3033

@@ -254,6 +257,8 @@ function DialogContent(props: DialogContentProps) {
254257
const scrollerRef = React.useRef<HTMLDivElement | null>(null)
255258
const dialogId = aria.useId()
256259

260+
const { appRoot } = useRootContext()
261+
257262
const titleId = `${dialogId}-title`
258263
const padding = paddingRaw ?? (type === 'modal' ? 'medium' : 'xlarge')
259264
const isFullscreen = type === 'fullscreen'
@@ -297,6 +302,20 @@ function DialogContent(props: DialogContentProps) {
297302
}
298303
}, [isFullscreen])
299304

305+
React.useEffect(() => {
306+
if (isFullscreen && modalState.isOpen) {
307+
unsafeWriteValue(appRoot.style, 'scale', '0.99')
308+
unsafeWriteValue(appRoot.style, 'filter', 'blur(8px)')
309+
unsafeWriteValue(appRoot.style, 'willChange', 'scale, filter')
310+
311+
return () => {
312+
unsafeWriteValue(appRoot.style, 'scale', '')
313+
unsafeWriteValue(appRoot.style, 'filter', '')
314+
unsafeWriteValue(appRoot.style, 'willChange', '')
315+
}
316+
}
317+
}, [isFullscreen, modalState, appRoot])
318+
300319
const styles = variants({
301320
className,
302321
type,
@@ -322,86 +341,88 @@ function DialogContent(props: DialogContentProps) {
322341
}
323342

324343
return (
325-
<LayoutGroup>
326-
<MotionDialog
327-
layout
328-
transition={TRANSITION}
329-
style={{ height: getDialogHeight() }}
330-
id={dialogId}
331-
onLayoutAnimationStart={() => {
332-
if (scrollerRef.current) {
333-
scrollerRef.current.style.overflowY = 'clip'
334-
}
335-
}}
336-
onLayoutAnimationComplete={() => {
337-
if (scrollerRef.current) {
338-
scrollerRef.current.style.overflowY = ''
339-
}
340-
}}
341-
ref={(ref: HTMLDivElement | null) => {
342-
mergeRefs.mergeRefs(dialogRef, (element) => {
343-
if (element) {
344-
// This is a workaround for the `data-testid` attribute not being
345-
// supported by the 'react-aria-components' library.
346-
// We need to set the `data-testid` attribute on the dialog element
347-
// so that we can use it in our tests.
348-
// This is a temporary solution until we refactor the Dialog component
349-
// to use `useDialog` hook from the 'react-aria-components' library.
350-
// this will allow us to set the `data-testid` attribute on the dialog
351-
element.dataset.testid = testId
344+
<ResetButtonGroupContext>
345+
<LayoutGroup>
346+
<MotionDialog
347+
layout
348+
transition={TRANSITION}
349+
style={{ height: getDialogHeight() }}
350+
id={dialogId}
351+
onLayoutAnimationStart={() => {
352+
if (scrollerRef.current) {
353+
scrollerRef.current.style.overflowY = 'clip'
352354
}
353-
})(ref)
354-
}}
355-
className={styles.base()}
356-
aria-labelledby={titleId}
357-
{...ariaDialogProps}
358-
>
359-
{(opts) => (
360-
<>
361-
<motion.div layout className="w-full" transition={{ duration: 0 }}>
362-
<DialogHeader
363-
closeButton={closeButton}
364-
title={title}
365-
titleId={titleId}
366-
scrollerRef={scrollerRef}
367-
fitContent={fitContent}
368-
hideCloseButton={hideCloseButton}
369-
padding={padding}
370-
rounded={rounded}
371-
size={size}
372-
type={type}
373-
headerDimensionsRef={headerDimensionsRef}
374-
close={opts.close}
375-
variants={variants}
376-
/>
377-
</motion.div>
378-
379-
<motion.div
380-
layout
381-
layoutScroll
382-
className={styles.scroller()}
383-
ref={scrollerRef}
384-
transition={{ duration: 0 }}
385-
>
386-
<DialogBody
387-
close={opts.close}
388-
contentDimensionsRef={contentDimensionsRef}
389-
dialogId={dialogId}
390-
headerDimensionsRef={headerDimensionsRef}
391-
scrollerRef={scrollerRef}
392-
measurerWrapperClassName={styles.measurerWrapper()}
393-
contentClassName={styles.content()}
394-
type={type}
355+
}}
356+
onLayoutAnimationComplete={() => {
357+
if (scrollerRef.current) {
358+
scrollerRef.current.style.overflowY = ''
359+
}
360+
}}
361+
ref={(ref: HTMLDivElement | null) => {
362+
mergeRefs.mergeRefs(dialogRef, (element) => {
363+
if (element) {
364+
// This is a workaround for the `data-testid` attribute not being
365+
// supported by the 'react-aria-components' library.
366+
// We need to set the `data-testid` attribute on the dialog element
367+
// so that we can use it in our tests.
368+
// This is a temporary solution until we refactor the Dialog component
369+
// to use `useDialog` hook from the 'react-aria-components' library.
370+
// this will allow us to set the `data-testid` attribute on the dialog
371+
element.dataset.testid = testId
372+
}
373+
})(ref)
374+
}}
375+
className={styles.base()}
376+
aria-labelledby={titleId}
377+
{...ariaDialogProps}
378+
>
379+
{(opts) => (
380+
<>
381+
<motion.div layout className="w-full" transition={{ duration: 0 }}>
382+
<DialogHeader
383+
closeButton={closeButton}
384+
title={title}
385+
titleId={titleId}
386+
scrollerRef={scrollerRef}
387+
fitContent={fitContent}
388+
hideCloseButton={hideCloseButton}
389+
padding={padding}
390+
rounded={rounded}
391+
size={size}
392+
type={type}
393+
headerDimensionsRef={headerDimensionsRef}
394+
close={opts.close}
395+
variants={variants}
396+
/>
397+
</motion.div>
398+
399+
<motion.div
400+
layout
401+
layoutScroll
402+
className={styles.scroller()}
403+
ref={scrollerRef}
404+
transition={{ duration: 0 }}
395405
>
396-
{children}
397-
</DialogBody>
398-
</motion.div>
399-
</>
400-
)}
401-
</MotionDialog>
402-
403-
<dialogStackProvider.DialogStackRegistrar id={dialogId} type={TYPE_TO_DIALOG_TYPE[type]} />
404-
</LayoutGroup>
406+
<DialogBody
407+
close={opts.close}
408+
contentDimensionsRef={contentDimensionsRef}
409+
dialogId={dialogId}
410+
headerDimensionsRef={headerDimensionsRef}
411+
scrollerRef={scrollerRef}
412+
measurerWrapperClassName={styles.measurerWrapper()}
413+
contentClassName={styles.content()}
414+
type={type}
415+
>
416+
{children}
417+
</DialogBody>
418+
</motion.div>
419+
</>
420+
)}
421+
</MotionDialog>
422+
423+
<dialogStackProvider.DialogStackRegistrar id={dialogId} type={TYPE_TO_DIALOG_TYPE[type]} />
424+
</LayoutGroup>
425+
</ResetButtonGroupContext>
405426
)
406427
}
407428

0 commit comments

Comments
 (0)