Skip to content

Commit 49dc8db

Browse files
Push comments, fix localstorage
1 parent 148cbe4 commit 49dc8db

File tree

8 files changed

+126
-34
lines changed

8 files changed

+126
-34
lines changed

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

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
/** @file A Markdown viewer component. */
2-
import * as React from 'react'
32

43
import { useLogger } from '#/providers/LoggerProvider'
54
import { useText } from '#/providers/TextProvider'
65
import { type UrlTransformer } from '@/components/MarkdownEditor/imageUrlTransformer'
76
import { Err, Ok } from '@/util/data/result'
87
import { type TestIdProps } from '../AriaComponents'
8+
import { MarkdownEditor } from './defaultRenderer'
99

1010
/** Props for a {@link MarkdownViewer}. */
1111
export interface MarkdownViewerProps extends TestIdProps {
@@ -14,13 +14,6 @@ export interface MarkdownViewerProps extends TestIdProps {
1414
readonly imgUrlResolver: (relativePath: string) => Promise<string>
1515
}
1616

17-
const LazyMarkdownEditor = React.lazy(() =>
18-
import('#/components/MarkdownViewer/defaultRenderer').then(
19-
// eslint-disable-next-line @typescript-eslint/naming-convention
20-
({ MarkdownEditor }) => MarkdownEditor,
21-
),
22-
)
23-
2417
/**
2518
* Markdown viewer component.
2619
* Parses markdown passed in as a `text` prop into HTML and displays it.
@@ -42,8 +35,9 @@ export function MarkdownViewer(props: MarkdownViewerProps) {
4235
},
4336
)
4437

38+
console.log('MarkdownViewer', { text })
4539
return (
46-
<LazyMarkdownEditor
40+
<MarkdownEditor
4741
content={text}
4842
transformImageUrl={transformImageUrl}
4943
toolbar={false}

app/gui/src/dashboard/components/MarkdownViewer/defaultRenderer.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,4 @@ import { vueComponent } from '#/utilities/vue'
44
import MarkdownEditorVue from '@/components/MarkdownEditor.vue'
55

66
// eslint-disable-next-line no-restricted-syntax
7-
export const MarkdownEditor = vueComponent(MarkdownEditorVue)
7+
export const MarkdownEditor = vueComponent(MarkdownEditorVue).default

app/gui/src/dashboard/layouts/AssetPanel/AssetPanel.tsx

Lines changed: 35 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
* It is used to view and interact with assets in the drive.
55
*/
66
import { AnimatePresence, motion } from 'framer-motion'
7-
import { memo, startTransition } from 'react'
7+
import { lazy, memo, startTransition } from 'react'
88

99
import type { BackendType } from 'enso-common/src/services/Backend'
1010

@@ -16,24 +16,18 @@ import InspectIcon from '#/assets/inspect.svg'
1616
import VersionsIcon from '#/assets/versions.svg'
1717
import { ErrorBoundary } from '#/components/ErrorBoundary'
1818
import { useEventCallback } from '#/hooks/eventCallbackHooks'
19-
import { AssetDocs } from '#/layouts/AssetDocs'
2019
import { isLocalCategory, type Category } from '#/layouts/CategorySwitcher/Category'
2120
import { useBackend } from '#/providers/BackendProvider'
21+
import { useFeatureFlag } from '#/providers/FeatureFlagsProvider'
2222
import { useText } from '#/providers/TextProvider'
2323
import { useStore } from '#/utilities/zustand'
24-
import { useFeatureFlag } from '../../providers/FeatureFlagsProvider'
2524
import {
2625
assetPanelStore,
2726
useIsAssetPanelExpanded,
2827
useSetIsAssetPanelExpanded,
2928
} from './AssetPanelState'
3029
import { AssetPanelTabs } from './components/AssetPanelTabs'
3130
import { AssetPanelToggle } from './components/AssetPanelToggle'
32-
import { AssetProperties } from './components/AssetProperties'
33-
import { AssetVersions } from './components/AssetVersions'
34-
import { ProjectExecutions } from './components/ProjectExecutions'
35-
import { ProjectExecutionsCalendar } from './components/ProjectExecutionsCalendar'
36-
import { ProjectSessions } from './components/ProjectSessions'
3731
import type { AssetPanelTab } from './types'
3832

3933
const ASSET_SIDEBAR_COLLAPSED_WIDTH = 48
@@ -46,6 +40,29 @@ export interface AssetPanelProps {
4640
readonly category: Category
4741
}
4842

43+
const LazyAssetDocs = lazy(() =>
44+
import('#/layouts/AssetDocs').then((module) => ({ default: module.AssetDocs })),
45+
)
46+
const LazyAssetProperties = lazy(() =>
47+
import('./components/AssetProperties').then((module) => ({ default: module.AssetProperties })),
48+
)
49+
const LazyAssetVersions = lazy(() =>
50+
import('./components/AssetVersions').then((module) => ({ default: module.AssetVersions })),
51+
)
52+
const LazyProjectSessions = lazy(() =>
53+
import('./components/ProjectSessions').then((module) => ({ default: module.ProjectSessions })),
54+
)
55+
const LazyProjectExecutions = lazy(() =>
56+
import('./components/ProjectExecutions').then((module) => ({
57+
default: module.ProjectExecutions,
58+
})),
59+
)
60+
const LazyProjectExecutionsCalendar = lazy(() =>
61+
import('./components/ProjectExecutionsCalendar').then((module) => ({
62+
default: module.ProjectExecutionsCalendar,
63+
})),
64+
)
65+
4966
/**
5067
* The asset panel is a sidebar that can be expanded or collapsed.
5168
* It is used to view and interact with assets in the drive.
@@ -182,27 +199,31 @@ const InternalAssetPanelTabs = memo(function InternalAssetPanelTabs(
182199
<div className="flex h-full flex-col bg-background-hex">
183200
<ErrorBoundary resetKeys={[itemId]}>
184201
<AssetPanelTabs.TabPanel id="settings">
185-
<AssetProperties backend={backend} isReadonly={isReadonly} category={category} />
202+
<LazyAssetProperties
203+
backend={backend}
204+
isReadonly={isReadonly}
205+
category={category}
206+
/>
186207
</AssetPanelTabs.TabPanel>
187208

188209
<AssetPanelTabs.TabPanel id="versions">
189-
<AssetVersions backend={backend} />
210+
<LazyAssetVersions backend={backend} />
190211
</AssetPanelTabs.TabPanel>
191212

192213
<AssetPanelTabs.TabPanel id="sessions">
193-
<ProjectSessions backend={backend} />
214+
<LazyProjectSessions backend={backend} />
194215
</AssetPanelTabs.TabPanel>
195216

196217
<AssetPanelTabs.TabPanel id="executions">
197-
<ProjectExecutions backend={backend} />
218+
<LazyProjectExecutions backend={backend} />
198219
</AssetPanelTabs.TabPanel>
199220

200221
<AssetPanelTabs.TabPanel id="executionsCalendar">
201-
<ProjectExecutionsCalendar backend={backend} />
222+
<LazyProjectExecutionsCalendar backend={backend} />
202223
</AssetPanelTabs.TabPanel>
203224

204225
<AssetPanelTabs.TabPanel id="docs">
205-
<AssetDocs backend={backend} />
226+
<LazyAssetDocs backend={backend} />
206227
</AssetPanelTabs.TabPanel>
207228
</ErrorBoundary>
208229
</div>

app/gui/src/dashboard/providers/LocalStorageProvider.tsx

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -68,20 +68,29 @@ export function useLocalStorageState<K extends LocalStorageKey>(
6868
const { localStorage } = useLocalStorage()
6969
const { sanitize } = options
7070

71+
const id = React.useId()
72+
7173
const [value, privateSetValue] = React.useState<LocalStorageData[K] | undefined>(() => {
7274
let savedValue: LocalStorageData[K] | undefined = localStorage.get(key)
7375
if (savedValue !== undefined && sanitize) {
7476
savedValue = sanitize(savedValue)
7577
}
78+
7679
if (savedValue === undefined) {
7780
return defaultValue
7881
}
82+
7983
return savedValue
8084
})
8185

8286
const setValue = useEventCallback(
8387
(newValue: React.SetStateAction<LocalStorageData[K] | undefined>) => {
88+
console.trace('setValue', key, newValue)
8489
privateSetValue((currentValue) => {
90+
console.log('privateSetValue', {
91+
currentValue,
92+
newValue,
93+
})
8594
const nextValue = typeof newValue === 'function' ? newValue(currentValue) : newValue
8695

8796
if (nextValue === undefined) {
@@ -95,13 +104,13 @@ export function useLocalStorageState<K extends LocalStorageKey>(
95104
},
96105
)
97106

98-
React.useEffect(
99-
() =>
100-
localStorage.subscribe(key, (newValue) => {
101-
privateSetValue(newValue ?? defaultValue)
102-
}),
103-
[defaultValue, key, localStorage],
104-
)
107+
React.useEffect(() => {
108+
localStorage.lock(key, id)
109+
110+
return () => {
111+
localStorage.unlock(key, id)
112+
}
113+
}, [key, localStorage, id])
105114

106115
return [value, setValue]
107116
}

app/gui/src/dashboard/providers/ProjectsProvider.tsx

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -124,15 +124,24 @@ export default function ProjectsProvider(props: ProjectsProviderProps) {
124124
)
125125

126126
const addLaunchedProject = eventCallbacks.useEventCallback((project: LaunchedProject) => {
127-
setLaunchedProjects((current) => [...current, project])
127+
console.trace('addLaunchedProject', project)
128+
setLaunchedProjects((current) => {
129+
console.log('addLaunchedProject', {
130+
current,
131+
project,
132+
})
133+
return [...current, project]
134+
})
128135
})
129136
const removeLaunchedProject = eventCallbacks.useEventCallback((projectId: LaunchedProjectId) => {
137+
console.log('removeLaunchedProject', projectId)
130138
setLaunchedProjects((current) =>
131139
current.filter(({ id, hybrid }) => id !== projectId && hybrid?.cloudProjectId !== projectId),
132140
)
133141
})
134142
const updateLaunchedProjects = eventCallbacks.useEventCallback(
135143
(update: (projects: readonly LaunchedProject[]) => readonly LaunchedProject[]) => {
144+
console.log('updateLaunchedProjects', update)
136145
setLaunchedProjects((current) => update(current))
137146
},
138147
)

app/gui/src/dashboard/utilities/LocalStorage.ts

Lines changed: 57 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,20 @@ export default class LocalStorage {
5353
localStorageKey = common.PRODUCT_NAME.toLowerCase()
5454
protected values: Partial<LocalStorageData>
5555
private readonly eventTarget = new EventTarget()
56+
private readonly locks = new Map<
57+
LocalStorageKey,
58+
{
59+
/**
60+
* Whether the key is locked.
61+
*/
62+
readonly locked: true
63+
/**
64+
* The ID of the function that locked the key.
65+
* Only this function can unlock the key or change the value.
66+
*/
67+
readonly allowedIdToChange: string
68+
}
69+
>()
5670

5771
/** Create a {@link LocalStorage}. */
5872
private constructor() {
@@ -119,10 +133,44 @@ export default class LocalStorage {
119133
return this.values[key]
120134
}
121135

136+
/**
137+
* Lock a key.
138+
* When a key is locked, it will not be updated until it is unlocked.
139+
*/
140+
lock<K extends LocalStorageKey>(key: K, allowedIdToChange: string) {
141+
this.locks.set(key, {
142+
locked: true,
143+
allowedIdToChange,
144+
})
145+
}
146+
147+
/**
148+
* Unlock a key.
149+
*/
150+
unlock<K extends LocalStorageKey>(key: K, allowedIdToChange: string) {
151+
const lock = this.locks.get(key)
152+
if (lock == null) {
153+
return
154+
}
155+
156+
if (lock.allowedIdToChange !== allowedIdToChange) {
157+
return
158+
}
159+
160+
this.locks.delete(key)
161+
}
162+
122163
/** Write an entry to the stored data, and save. */
123-
set<K extends LocalStorageKey>(key: K, value: LocalStorageData[K]) {
164+
set<K extends LocalStorageKey>(key: K, value: LocalStorageData[K], idToChange?: string) {
124165
this.assertRegisteredKey(key)
125166

167+
const lock = this.locks.get(key)
168+
if (lock != null) {
169+
if (lock.allowedIdToChange !== idToChange) {
170+
return
171+
}
172+
}
173+
126174
this.values[key] = value
127175

128176
this.eventTarget.dispatchEvent(new Event(key))
@@ -197,9 +245,16 @@ export default class LocalStorage {
197245
/**
198246
* Delete an entry from the stored data, and save.
199247
*/
200-
delete<K extends LocalStorageKey>(key: K) {
248+
delete<K extends LocalStorageKey>(key: K, idToChange?: string) {
201249
this.assertRegisteredKey(key)
202250

251+
const lock = this.locks.get(key)
252+
if (lock != null) {
253+
if (lock.allowedIdToChange !== idToChange) {
254+
return
255+
}
256+
}
257+
203258
// The key being deleted is one of a statically known set of keys.
204259
// eslint-disable-next-line @typescript-eslint/no-dynamic-delete
205260
delete this.values[key]

app/gui/src/project-view/components/MarkdownEditor.vue

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@ defineExpose({
3939
inner.value?.putTextAtCoords(text, coords)
4040
},
4141
})
42+
43+
console.log('MarkdownEditor', { content: props.content })
4244
</script>
4345

4446
<template>

app/gui/src/project-view/components/MarkdownEditor/MarkdownEditorImpl.vue

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,8 @@ defineExpose({
6767
putTextAt(text, pos, pos)
6868
},
6969
})
70+
71+
console.log('MarkdownEditorImpl', {})
7072
</script>
7173

7274
<template>

0 commit comments

Comments
 (0)