Still more dashboard fixes (#10573)

- Close https://github.com/enso-org/cloud-v2/issues/1369
- Add button to refresh project logs
- Fix https://github.com/enso-org/cloud-v2/issues/1385
- Fix issues related to Data Links
- Fix freeze when closing tab (e.g. project tab) (regression introduced when switching to `react-aria` Tabs, oops...)

# Important Notes
None
This commit is contained in:
somebody1234 2024-07-18 09:52:27 +10:00 committed by GitHub
parent 700a638f1e
commit 836a7e1272
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
18 changed files with 70 additions and 36 deletions

8
.gitignore vendored
View File

@ -171,3 +171,11 @@ test-results
##################
.direnv
##########################
## Playwright artifacts ##
##########################
test-results/
playwright-report/
playwright/.cache/

View File

@ -1,5 +0,0 @@
node_modules/
/test-results/
/playwright-report/
/playwright/.cache/
!/src/assets/background.jpg

View File

@ -102,7 +102,6 @@ export const BUTTON_STYLES = twv.tv({
fullWidthText: { true: { text: 'w-full' } },
size: {
custom: { base: '', extraClickZone: '', icon: 'h-full' },
icon: { icon: 'h-4' },
hero: { base: 'px-8 py-4 text-lg font-bold', content: 'gap-[0.75em]' },
large: {
base: text.TEXT_STYLE({

View File

@ -143,7 +143,7 @@ export default function EditableSpan(props: EditableSpanProps) {
<ariaComponents.ButtonGroup gap="xsmall" className="grow-0 items-center">
{isSubmittable && (
<ariaComponents.Button
size="icon"
size="medium"
variant="ghost"
icon={TickIcon}
aria-label={getText('confirmEdit')}
@ -151,7 +151,7 @@ export default function EditableSpan(props: EditableSpanProps) {
/>
)}
<ariaComponents.Button
size="icon"
size="medium"
variant="ghost"
icon={CrossIcon}
aria-label={getText('cancelEdit')}

View File

@ -259,16 +259,28 @@ export default function JSONSchemaInput(props: JSONSchemaInputProps) {
// eslint-disable-next-line no-restricted-syntax
value={(value as Record<string, unknown>)[key] ?? null}
setValue={newValue => {
setValue(oldValue =>
typeof oldValue === 'object' &&
oldValue != null &&
// This is SAFE; but there is no way to tell TypeScript that an object
// has an index signature.
// eslint-disable-next-line no-restricted-syntax
(oldValue as Readonly<Record<string, unknown>>)[key] === newValue
setValue(oldValue => {
if (typeof newValue === 'function') {
const unsafeValue: unknown = newValue(
// This is SAFE; but there is no way to tell TypeScript that an object
// has an index signature.
// eslint-disable-next-line no-restricted-syntax
(oldValue as Readonly<Record<string, unknown>>)[key] ?? null
)
// The value MAY be `null`, but it is better than the value being a
// function (which is *never* the intended result).
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
newValue = unsafeValue!
}
return typeof oldValue === 'object' &&
oldValue != null &&
// This is SAFE; but there is no way to tell TypeScript that an object
// has an index signature.
// eslint-disable-next-line no-restricted-syntax
(oldValue as Readonly<Record<string, unknown>>)[key] === newValue
? oldValue
: { ...oldValue, [key]: newValue }
)
})
}}
/>
)}
@ -299,7 +311,7 @@ export default function JSONSchemaInput(props: JSONSchemaInputProps) {
const childSchemas = schema.anyOf.flatMap(object.singletonObjectOrNull)
const selectedChildSchema =
selectedChildIndex == null ? null : childSchemas[selectedChildIndex]
const selectedChildPath = `${path}/anyOf/${selectedChildIndex}`
const selectedChildPath = `${path}/anyOf/${selectedChildIndex ?? 0}`
const childValue =
selectedChildSchema == null ? [] : jsonSchema.constantValue(defs, selectedChildSchema)
if (

View File

@ -174,7 +174,7 @@ export default function DirectoryNameColumn(props: DirectoryNameColumnProps) {
>
<ariaComponents.Button
icon={FolderArrowIcon}
size="icon"
size="medium"
variant="custom"
aria-label={isExpanded ? getText('collapse') : getText('expand')}
tooltipPlacement="left"

View File

@ -142,7 +142,7 @@ export default function LabelsColumn(props: column.AssetColumnProps) {
{managesThisAsset && (
<ariaComponents.Button
ref={plusButtonRef}
size="icon"
size="medium"
variant="ghost"
showIconOnHover
icon={Plus2Icon}

View File

@ -110,7 +110,7 @@ export default function SharedWithColumn(props: SharedWithColumnPropsInternal) {
{managesThisAsset && !isUnderPaywall && (
<ariaComponents.Button
ref={plusButtonRef}
size="icon"
size="medium"
variant="ghost"
icon={Plus2Icon}
showIconOnHover

View File

@ -139,7 +139,7 @@ export default function AssetProperties(props: AssetPropertiesProps) {
{getText('description')}
{!isReadonly && ownsThisAsset && !isEditingDescription && (
<ariaComponents.Button
size="icon"
size="medium"
variant="icon"
icon={PenIcon}
onPress={() => {

View File

@ -174,7 +174,7 @@ export default function DriveBar(props: DriveBarProps) {
>
{getText('newEmptyProject')}
</ariaComponents.Button>
<div className="flex h-row items-center gap-4 rounded-full border-0.5 border-primary/20 px-[11px] text-primary/50">
<div className="flex h-row items-center gap-4 rounded-full border-0.5 border-primary/20 px-[11px]">
<ariaComponents.Button
variant="icon"
size="medium"

View File

@ -132,7 +132,7 @@ export default function KeyboardShortcutsSettingsSection() {
<KeyboardShortcut shortcut={binding} />
<ariaComponents.Button
variant="ghost"
size="icon"
size="medium"
aria-label={getText('removeShortcut')}
tooltipPlacement="top left"
icon={CrossIcon}
@ -148,7 +148,7 @@ export default function KeyboardShortcutsSettingsSection() {
<div className="gap-keyboard-shortcuts-buttons flex shrink-0 items-center">
<ariaComponents.Button
variant="ghost"
size="icon"
size="medium"
aria-label={getText('addShortcut')}
tooltipPlacement="top left"
icon={Plus2Icon}
@ -168,7 +168,7 @@ export default function KeyboardShortcutsSettingsSection() {
/>
<ariaComponents.Button
variant="ghost"
size="icon"
size="medium"
aria-label={getText('resetShortcut')}
tooltipPlacement="top left"
icon={ReloadIcon}

View File

@ -134,7 +134,7 @@ export default function TabBar(props: TabBarProps) {
className="flex h-12 shrink-0 grow cursor-default items-center rounded-full"
{...innerProps}
>
<aria.Tab>
<aria.Tab isDisabled>
{/* Putting the background in a `Tab` is a hack, but it is required otherwise there
* are issues with the ref to the background being detached, resulting in the clip
* path cutout for the current tab not applying at all. */}
@ -214,7 +214,6 @@ export function Tab(props: InternalTabProps) {
}
}}
id={id}
isDisabled={isActive}
aria-label={getText(labelId)}
className={tailwindMerge.twMerge(
'relative flex h-full items-center gap-3 rounded-t-2xl px-4',

View File

@ -3,6 +3,8 @@ import * as React from 'react'
import * as reactQuery from '@tanstack/react-query'
import ReloadIcon from '#/assets/reload.svg'
import * as textProvider from '#/providers/TextProvider'
import * as ariaComponents from '#/components/AriaComponents'
@ -44,6 +46,7 @@ interface ProjectLogsModalInternalProps extends ProjectLogsModalProps {}
/** A modal for showing logs for a project. */
function ProjectLogsModalInternal(props: ProjectLogsModalInternalProps) {
const { backend, projectSessionId, projectTitle } = props
const { getText } = textProvider.useText()
const logsQuery = reactQuery.useSuspenseQuery({
queryKey: ['projectLogs', { projectSessionId, projectTitle }],
queryFn: async () => {
@ -53,8 +56,21 @@ function ProjectLogsModalInternal(props: ProjectLogsModalInternalProps) {
})
return (
<pre className="relative overflow-auto whitespace-pre-wrap">
<code>{logsQuery.data}</code>
</pre>
<div className="flex flex-col">
<div className="flex items-center gap-4 self-start rounded-full border-0.5 border-primary/20 px-[11px] py-2">
<ariaComponents.Button
size="medium"
variant="icon"
icon={ReloadIcon}
aria-label={getText('reload')}
onPress={async () => {
await logsQuery.refetch()
}}
/>
</div>
<pre className="relative overflow-auto whitespace-pre-wrap">
<code>{logsQuery.data}</code>
</pre>
</div>
)
}

View File

@ -158,7 +158,9 @@ function constantValueHelper(
? SINGLETON_NULL
: EMPTY_ARRAY
const results: (NonNullable<unknown> | null)[] = []
if ('type' in schema) {
if ('default' in schema && schema.default != null && partial) {
return [schema.default]
} else if ('type' in schema) {
switch (schema.type) {
case 'null': {
results.push(null)

View File

@ -55,7 +55,9 @@ export function bundlerOptions(
projectManagerInBundlePath
),
'process.env.ELECTRON_DEV_MODE': JSON.stringify(String(devMode)),
'process.env.GUI_CONFIG_PATH': JSON.stringify(path.resolve('../gui2/vite.config.ts')),
'process.env.GUI_CONFIG_PATH': JSON.stringify(
path.resolve('../../gui2/vite.config.ts')
),
},
/* eslint-enable @typescript-eslint/naming-convention */
sourcemap: true,

View File

@ -63,8 +63,8 @@
"typecheck": "npm run --workspace=enso-gui2 compile-server && tsc --build",
"build": "tsx bundle.ts",
"dist": "tsx dist.ts",
"watch:windows": "cross-env ENSO_BUILD_IDE=%LOCALAPPDATA%/Temp/enso/dist/ide ENSO_BUILD_PROJECT_MANAGER=%CD%/../../dist/backend ENSO_BUILD_PROJECT_MANAGER_IN_BUNDLE_PATH=bin/project-manager.exe ENSO_BUILD_IDE_BUNDLED_ENGINE_VERSION=0 tsx watch.ts",
"watch:linux": "ENSO_BUILD_IDE=\"${ENSO_BUILD_IDE:-/tmp/enso/dist/ide}\" ENSO_BUILD_PROJECT_MANAGER=\"${ENSO_BUILD_PROJECT_MANAGER:-\"$(pwd)/../../dist/backend\"}\" ENSO_BUILD_PROJECT_MANAGER_IN_BUNDLE_PATH=\"${ENSO_BUILD_PROJECT_MANAGER_IN_BUNDLE_PATH:-bin/project-manager}\" ENSO_BUILD_IDE_BUNDLED_ENGINE_VERSION=\"${ENSO_BUILD_IDE_BUNDLED_ENGINE_VERSION:-0}\" tsx watch.ts \"$@\"",
"watch:macos": "ENSO_BUILD_IDE=\"${ENSO_BUILD_IDE:-/tmp/enso/dist/ide}\" ENSO_BUILD_PROJECT_MANAGER=\"${ENSO_BUILD_PROJECT_MANAGER:-\"$(pwd)/../../dist/backend\"}\" ENSO_BUILD_PROJECT_MANAGER_IN_BUNDLE_PATH=\"${ENSO_BUILD_PROJECT_MANAGER_IN_BUNDLE_PATH:-bin/project-manager}\" ENSO_BUILD_IDE_BUNDLED_ENGINE_VERSION=\"${ENSO_BUILD_IDE_BUNDLED_ENGINE_VERSION:-0}\" tsx watch.ts \"$@\""
"watch:windows": "cross-env ENSO_BUILD_IDE=%LOCALAPPDATA%/Temp/enso/dist/ide ENSO_BUILD_PROJECT_MANAGER=%CD%/../../../dist/backend ENSO_BUILD_PROJECT_MANAGER_IN_BUNDLE_PATH=bin/project-manager.exe ENSO_BUILD_IDE_BUNDLED_ENGINE_VERSION=0 tsx watch.ts",
"watch:linux": "ENSO_BUILD_IDE=\"${ENSO_BUILD_IDE:-/tmp/enso/dist/ide}\" ENSO_BUILD_PROJECT_MANAGER=\"${ENSO_BUILD_PROJECT_MANAGER:-\"$(pwd)/../../../dist/backend\"}\" ENSO_BUILD_PROJECT_MANAGER_IN_BUNDLE_PATH=\"${ENSO_BUILD_PROJECT_MANAGER_IN_BUNDLE_PATH:-bin/project-manager}\" ENSO_BUILD_IDE_BUNDLED_ENGINE_VERSION=\"${ENSO_BUILD_IDE_BUNDLED_ENGINE_VERSION:-0}\" tsx watch.ts \"$@\"",
"watch:macos": "ENSO_BUILD_IDE=\"${ENSO_BUILD_IDE:-/tmp/enso/dist/ide}\" ENSO_BUILD_PROJECT_MANAGER=\"${ENSO_BUILD_PROJECT_MANAGER:-\"$(pwd)/../../../dist/backend\"}\" ENSO_BUILD_PROJECT_MANAGER_IN_BUNDLE_PATH=\"${ENSO_BUILD_PROJECT_MANAGER_IN_BUNDLE_PATH:-bin/project-manager}\" ENSO_BUILD_IDE_BUNDLED_ENGINE_VERSION=\"${ENSO_BUILD_IDE_BUNDLED_ENGINE_VERSION:-0}\" tsx watch.ts \"$@\""
}
}

View File

@ -150,7 +150,7 @@ export class Server {
)
const rustFFIWasmPath =
process.env.ELECTRON_DEV_MODE === 'true'
? path.resolve('../../../gui2/rust-ffi/pkg/rust_ffi_bg.wasm')
? path.resolve('../../gui2/rust-ffi/pkg/rust_ffi_bg.wasm')
: rustFFIWasmName == null
? null
: path.join(assets, rustFFIWasmName)

View File

@ -224,6 +224,7 @@
"organization": "Organization",
"metadata": "Metadata",
"path": "Path",
"reload": "Reload",
"enterSecretPath": "Enter secret path",
"enterText": "Enter text",