diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS
index 281f3bd426c..adbe92a59fe 100644
--- a/.github/CODEOWNERS
+++ b/.github/CODEOWNERS
@@ -19,14 +19,30 @@ Cargo.toml
/lib/rust/parser/ @farmaazon @kazcw @vitvakatu @Frizi @jaroslavtulach @AdRiley
/tools/build-performance/ @kazcw @Akirathan
+# Global JS configuration
+esling.config.mjs
+tsconfig.json
+
# Scala Libraries
/lib/scala/ @4e6 @jaroslavtulach @hubertp @Akirathan
# Java libraries
/lib/java/ @4e6 @jaroslavtulach @hubertp @Akirathan
-# GUI
-/app/gui2/ @Frizi @farmaazon @vitvakatu @kazcw @AdRiley
+# GUI/Dashboard
+/app @Frizi @farmaazon @vitvakatu @kazcw @AdRiley @PabloBuchu @indiv0 @somebody1234 @MrFlashAccount
+/app/gui/e2e/dashboard @PabloBuchu @indiv0 @somebody1234 @MrFlashAccount
+/app/gui/e2e/project-view @Frizi @farmaazon @vitvakatu @kazcw @AdRiley
+/app/gui/src/dashboard @PabloBuchu @indiv0 @somebody1234 @MrFlashAccount
+/app/gui/src/project-view @Frizi @farmaazon @vitvakatu @kazcw @AdRiley
+/app/ide-desktop/ @PabloBuchu @indiv0 @somebody1234 @MrFlashAccount
+/app/ydoc-server/ @Frizi @farmaazon @vitvakatu @kazcw @AdRiley
+/app/ydoc-server-nodejs/ @Frizi @farmaazon @vitvakatu @kazcw @AdRiley
+/app/ydoc-server-polyglot/ @Frizi @farmaazon @vitvakatu @kazcw @AdRiley
+/app/ydoc-shared/ @Frizi @farmaazon @vitvakatu @kazcw @AdRiley
+# The data-link schema is owned by the libraries team
+/app/gui/src/dashboard/data/datalinkSchema.json @radeusgd @jdunkerley @GregoryTravis @AdRiley @marthasharkey
+/app/gui/src/dashboard/data/__tests__ @radeusgd @jdunkerley @GregoryTravis @AdRiley @marthasharkey @PabloBuchu @indiv0 @somebody1234 @MrFlashAccount
# Engine (old)
# This section should be removed once the engine moves to /app/engine
@@ -45,14 +61,3 @@ Cargo.toml
# The default project template is owned by the libraries team
/lib/scala/pkg/src/main/resources/default/src/ @radeusgd @jdunkerley @GregoryTravis @AdRiley @marthasharkey
-
-# Dashboard, Cloud, Authentication & Electron
-/app/ide-desktop/ @PabloBuchu @indiv0 @somebody1234 @MrFlashAccount
-/app/dashboard/ @PabloBuchu @indiv0 @somebody1234 @MrFlashAccount
-# The data-link schema is owned by the libraries team
-/app/dashboard/src/data/datalinkSchema.json @radeusgd @jdunkerley @GregoryTravis @AdRiley @marthasharkey
-/app/dashboard/src/data/__tests__ @radeusgd @jdunkerley @GregoryTravis @AdRiley @marthasharkey @PabloBuchu @indiv0 @somebody1234 @MrFlashAccount
-
-# GUI / Dashboard shared
-/app/*.* @Frizi @farmaazon @vitvakatu @kazcw @AdRiley @PabloBuchu @indiv0 @somebody1234 @MrFlashAccount
-/app/ide-desktop/common @PabloBuchu @indiv0 @somebody1234 @MrFlashAccount @Frizi @farmaazon @vitvakatu @kazcw @AdRiley
diff --git a/.prettierignore b/.prettierignore
index 0e2f83fa81f..85868a33504 100644
--- a/.prettierignore
+++ b/.prettierignore
@@ -39,10 +39,10 @@ app/ide-desktop/lib/dashboard/playwright/.cache/
app/ide-desktop/lib/dashboard/dist/
app/gui/view/documentation/assets/stylesheet.css
app/rust-ffi/pkg
-app/gui2/src/assets/font-*.css
+app/gui/src/project-view/assets/font-*.css
Cargo.lock
build.json
-app/gui2/playwright-report/
+app/gui/playwright-report/
# Engine Builds can leave these nested working copies.
# TODO [mwu]: Adjust Engine build to not leave them.
diff --git a/.vscode/settings.json b/.vscode/settings.json
index 66b38a7efec..87e9aba73bb 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -12,7 +12,7 @@
}
],
"typescript.tsdk": "node_modules/typescript/lib",
- "eslint.experimental.useFlatConfig": true,
+ "eslint.useFlatConfig": true,
"eslint.useESLintClass": true,
"[javascript][typescript][typescriptreact][vue]": {
"editor.defaultFormatter": "esbenp.prettier-vscode",
diff --git a/README.md b/README.md
index 228d56f367f..5db0424da28 100644
--- a/README.md
+++ b/README.md
@@ -21,7 +21,7 @@
-
+
@@ -207,11 +207,11 @@ Enso consists of several sub projects:
command line tools.
- **Enso IDE:** The
- [Enso IDE](https://github.com/enso-org/enso/tree/develop/app/gui2) is a
- desktop application that allows working with the visual form of Enso. It
- consists of an Electron application, a high performance WebGL UI framework,
- and the searcher which provides contextual search, hints, and documentation
- for all of Enso's functionality.
+ [Enso IDE](https://github.com/enso-org/enso/tree/develop/app/gui) is a desktop
+ application that allows working with the visual form of Enso. It consists of
+ an Electron application, a high performance WebGL UI framework, and the
+ searcher which provides contextual search, hints, and documentation for all of
+ Enso's functionality.
@@ -222,7 +222,7 @@ The Enso Engine is licensed under the
[LICENSE](https://github.com/enso-org/enso/blob/develop/LICENSE) file. The Enso
IDE is licensed under the [AGPL 3.0](https://opensource.org/licenses/AGPL-3.0),
as specified in the
-[LICENSE](https://github.com/enso-org/enso/blob/develop/app/gui2/LICENSE) file.
+[LICENSE](https://github.com/enso-org/enso/blob/develop/app/gui/LICENSE) file.
This license set was chosen to provide you with complete freedom to use Enso,
create libraries, and release them under any license of your choice, while also
diff --git a/app/.vscode/launch.json b/app/.vscode/launch.json
index ef2d7ab58f4..021d9385d58 100644
--- a/app/.vscode/launch.json
+++ b/app/.vscode/launch.json
@@ -46,7 +46,7 @@
"request": "launch",
"name": "GUI (Storybook)",
"runtimeExecutable": "pnpm",
- "runtimeArgs": ["run", "--filter", "enso-gui2", "story:dev"],
+ "runtimeArgs": ["run", "--filter", "enso-gui", "story:dev"],
"outputCapture": "std"
},
{
@@ -70,7 +70,7 @@
"request": "launch",
"name": "GUI (E2E UI)",
"runtimeExecutable": "pnpm",
- "runtimeArgs": ["run", "--filter", "enso-gui2", "test:e2e", "--", "--ui"],
+ "runtimeArgs": ["run", "--filter", "enso-gui", "test:e2e", "--", "--ui"],
"outputCapture": "std"
},
{
@@ -102,14 +102,14 @@
"request": "launch",
"name": "GUI (All tests)",
"runtimeExecutable": "pnpm",
- "runtimeArgs": ["run", "--filter", "enso-gui2", "test"]
+ "runtimeArgs": ["run", "--filter", "enso-gui", "test"]
},
{
"type": "node",
"request": "launch",
"name": "GUI (E2E tests)",
"runtimeExecutable": "pnpm",
- "runtimeArgs": ["run", "--filter", "enso-gui2", "test:e2e"],
+ "runtimeArgs": ["run", "--filter", "enso-gui", "test:e2e"],
"outputCapture": "std"
},
{
@@ -117,7 +117,7 @@
"request": "launch",
"name": "GUI (Unit tests)",
"runtimeExecutable": "pnpm",
- "runtimeArgs": ["run", "--filter", "enso-gui2", "test:unit", "--", "run"],
+ "runtimeArgs": ["run", "--filter", "enso-gui", "test:unit", "--", "run"],
"outputCapture": "std"
}
]
diff --git a/app/ide-desktop/common/package.json b/app/common/package.json
similarity index 96%
rename from app/ide-desktop/common/package.json
rename to app/common/package.json
index 5b38e91f70b..b904631c500 100644
--- a/app/ide-desktop/common/package.json
+++ b/app/common/package.json
@@ -6,6 +6,7 @@
"exports": {
".": "./src/index.js",
"./src/config.json": "./src/config.json",
+ "./src/accessToken": "./src/accessToken.ts",
"./src/appConfig": "./src/appConfig.js",
"./src/buildUtils": "./src/buildUtils.js",
"./src/detect": "./src/detect.ts",
diff --git a/app/dashboard/src/utilities/accessToken.ts b/app/common/src/accessToken.ts
similarity index 100%
rename from app/dashboard/src/utilities/accessToken.ts
rename to app/common/src/accessToken.ts
diff --git a/app/ide-desktop/common/src/appConfig.d.ts b/app/common/src/appConfig.d.ts
similarity index 100%
rename from app/ide-desktop/common/src/appConfig.d.ts
rename to app/common/src/appConfig.d.ts
diff --git a/app/ide-desktop/common/src/appConfig.js b/app/common/src/appConfig.js
similarity index 100%
rename from app/ide-desktop/common/src/appConfig.js
rename to app/common/src/appConfig.js
diff --git a/app/ide-desktop/common/src/backendQuery.ts b/app/common/src/backendQuery.ts
similarity index 100%
rename from app/ide-desktop/common/src/backendQuery.ts
rename to app/common/src/backendQuery.ts
diff --git a/app/ide-desktop/common/src/buildUtils.d.ts b/app/common/src/buildUtils.d.ts
similarity index 100%
rename from app/ide-desktop/common/src/buildUtils.d.ts
rename to app/common/src/buildUtils.d.ts
diff --git a/app/ide-desktop/common/src/buildUtils.js b/app/common/src/buildUtils.js
similarity index 100%
rename from app/ide-desktop/common/src/buildUtils.js
rename to app/common/src/buildUtils.js
diff --git a/app/ide-desktop/common/src/config.json b/app/common/src/config.json
similarity index 100%
rename from app/ide-desktop/common/src/config.json
rename to app/common/src/config.json
diff --git a/app/ide-desktop/common/src/detect.ts b/app/common/src/detect.ts
similarity index 100%
rename from app/ide-desktop/common/src/detect.ts
rename to app/common/src/detect.ts
diff --git a/app/ide-desktop/common/src/gtag.ts b/app/common/src/gtag.ts
similarity index 100%
rename from app/ide-desktop/common/src/gtag.ts
rename to app/common/src/gtag.ts
diff --git a/app/ide-desktop/common/src/index.d.ts b/app/common/src/index.d.ts
similarity index 100%
rename from app/ide-desktop/common/src/index.d.ts
rename to app/common/src/index.d.ts
diff --git a/app/ide-desktop/common/src/index.js b/app/common/src/index.js
similarity index 100%
rename from app/ide-desktop/common/src/index.js
rename to app/common/src/index.js
diff --git a/app/ide-desktop/common/src/load.ts b/app/common/src/load.ts
similarity index 100%
rename from app/ide-desktop/common/src/load.ts
rename to app/common/src/load.ts
diff --git a/app/ide-desktop/common/src/queryClient.ts b/app/common/src/queryClient.ts
similarity index 100%
rename from app/ide-desktop/common/src/queryClient.ts
rename to app/common/src/queryClient.ts
diff --git a/app/ide-desktop/common/src/services/Backend.ts b/app/common/src/services/Backend.ts
similarity index 99%
rename from app/ide-desktop/common/src/services/Backend.ts
rename to app/common/src/services/Backend.ts
index eac7565420c..f7658ad4221 100644
--- a/app/ide-desktop/common/src/services/Backend.ts
+++ b/app/common/src/services/Backend.ts
@@ -445,8 +445,7 @@ export interface CheckoutSessionStatus {
/** Status of the payment for the checkout session. */
readonly paymentStatus: string
/** Status of the checkout session. */
- // eslint-disable-next-line @typescript-eslint/ban-types
- readonly status: 'active' | 'trialing' | (string & {})
+ readonly status: 'active' | 'trialing' | (string & NonNullable)
}
/** Resource usage of a VM. */
diff --git a/app/ide-desktop/common/src/text/english.json b/app/common/src/text/english.json
similarity index 100%
rename from app/ide-desktop/common/src/text/english.json
rename to app/common/src/text/english.json
diff --git a/app/ide-desktop/common/src/text/index.ts b/app/common/src/text/index.ts
similarity index 100%
rename from app/ide-desktop/common/src/text/index.ts
rename to app/common/src/text/index.ts
diff --git a/app/ide-desktop/common/src/utilities/data/array.ts b/app/common/src/utilities/data/array.ts
similarity index 100%
rename from app/ide-desktop/common/src/utilities/data/array.ts
rename to app/common/src/utilities/data/array.ts
diff --git a/app/ide-desktop/common/src/utilities/data/dateTime.ts b/app/common/src/utilities/data/dateTime.ts
similarity index 100%
rename from app/ide-desktop/common/src/utilities/data/dateTime.ts
rename to app/common/src/utilities/data/dateTime.ts
diff --git a/app/ide-desktop/common/src/utilities/data/newtype.ts b/app/common/src/utilities/data/newtype.ts
similarity index 100%
rename from app/ide-desktop/common/src/utilities/data/newtype.ts
rename to app/common/src/utilities/data/newtype.ts
diff --git a/app/ide-desktop/common/src/utilities/data/object.ts b/app/common/src/utilities/data/object.ts
similarity index 100%
rename from app/ide-desktop/common/src/utilities/data/object.ts
rename to app/common/src/utilities/data/object.ts
diff --git a/app/ide-desktop/common/src/utilities/permissions.ts b/app/common/src/utilities/permissions.ts
similarity index 100%
rename from app/ide-desktop/common/src/utilities/permissions.ts
rename to app/common/src/utilities/permissions.ts
diff --git a/app/ide-desktop/common/src/utilities/style/__tests__/tabBar.test.ts b/app/common/src/utilities/style/__tests__/tabBar.test.ts
similarity index 100%
rename from app/ide-desktop/common/src/utilities/style/__tests__/tabBar.test.ts
rename to app/common/src/utilities/style/__tests__/tabBar.test.ts
diff --git a/app/ide-desktop/common/src/utilities/style/tabBar.ts b/app/common/src/utilities/style/tabBar.ts
similarity index 100%
rename from app/ide-desktop/common/src/utilities/style/tabBar.ts
rename to app/common/src/utilities/style/tabBar.ts
diff --git a/app/ide-desktop/common/src/utilities/uniqueString.ts b/app/common/src/utilities/uniqueString.ts
similarity index 100%
rename from app/ide-desktop/common/src/utilities/uniqueString.ts
rename to app/common/src/utilities/uniqueString.ts
diff --git a/app/ide-desktop/common/tsconfig.json b/app/common/tsconfig.json
similarity index 100%
rename from app/ide-desktop/common/tsconfig.json
rename to app/common/tsconfig.json
diff --git a/app/dashboard/.prettierignore b/app/dashboard/.prettierignore
deleted file mode 100644
index 569c0391bbb..00000000000
--- a/app/dashboard/.prettierignore
+++ /dev/null
@@ -1,4 +0,0 @@
-playwright-report/
-playwright/.cache/
-test-results/
-dist/
\ No newline at end of file
diff --git a/app/dashboard/404.html b/app/dashboard/404.html
deleted file mode 100644
index 5522400d55c..00000000000
--- a/app/dashboard/404.html
+++ /dev/null
@@ -1,44 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
- Enso
-
-
-
-
-
-
-
-
-
diff --git a/app/dashboard/README.md b/app/dashboard/README.md
deleted file mode 100644
index f67227c9c56..00000000000
--- a/app/dashboard/README.md
+++ /dev/null
@@ -1,76 +0,0 @@
-# Dashboard
-
-The dashboard is the entrypoint into the application. It includes project
-management, project sharing, and user accounts and authentication.
-
-## Further documentation
-
-Further documentation is provided in the `docs/` folder:
-
-- [Browser-specific behavior](./docs/browser_specific_behavior.md) details
- behavior that is inconsistent between browsers and needs to be worked around.
-
-## Folder structure
-
-- `mock/`: Overrides for specific files in `src/` when running Playwright tests.
-- `e2e/`: Contains end-to-end tests.
-- `**/__tests__/`: Contains all unit tests. Unit tests MUST be in a `__tests__/`
- subfolder, not beside (and not inside) the module they are testing.
-- `src/`: The dashboard application.
- - `index.html`: The sole HTML file used by this SPA. It imports the TS entry
- point.
- - `authentication/src/`: The main body of the app.
- - `index.tsx`: The TS entry point.
- - `providers/`: Contains React `Context`s used by the main app.
- - `components/`: Contains the root component for the app.
- - `dashboard/`: The main body of the app. Directly in the folder, there are
- some utility modules that do not belong elsewhere.
- - `components/`: Contains all components used by the main app.
- - `events/`: Custom discriminated unions used to communicate messages
- between unrelated components.
- - `authentication/`: The authentication flow. This includes login,
- registration, and changing passwords.
- - `components/`: Contains all components used by the authentication flow.
- - `providers/`: Contains React `Context`s required for authentication, and
- used by the main app.
-- `index.html`: The entrypoint, in the format required by Vite.
-- `404.html`: A copy of the entrypoint. This is served on unknown routes by
- certain static hosting providers.
-- `esbuild-config.ts`: Configuration for ESBuild based on the environment
- variables. This is a dependency of `esbuild-config.ts` in sibling modules.
-
-## Cloud environment variables
-
-These are environment variables related to the cloud backend. If these variables
-are not set, the build will still work, however access to the cloud backend will
-be disabled.
-
-Note that `ENSO_CLOUD_ENVIRONMENT` may be set to instead load the files from a
-`.env` file. If `ENSO_CLOUD_ENVIRONMENT` is not set, or it is `production` or
-`''`, then variables are attempted to be read from `.env`. If it is set to any
-other value (say, `foo`), then it is loaded from `.foo.env`.
-
-(While the convention in the Node.js ecosystem is to name the variants like
-`.env.foo`, `.foo.env` has been chosen here because `.env` should be more like
-a file extension. Visual Studio Code also understands `.foo.env` but not
-`.env.foo`.)
-
-- `ENSO_CLOUD_REDIRECT`: The domain (or `localhost:8080`) where the login link
- should redirect. Should include neither a path, nor a trailing slash.
-- `ENSO_CLOUD_ENVIRONMENT`: The name of backend environment matching the
- provided configuration keys. For most builds this should be `production`,
- meaning that requests go to the production cloud backend.
-- `ENSO_CLOUD_API_URL`: The root path for all API endpoints. Should not include
- a trailing slash.
-- `ENSO_CLOUD_SENTRY_DSN`: The Sentry Data Source Name (DSN) for this
- environment. This should normally be the same for all environments.
-- `ENSO_CLOUD_STRIPE_KEY`: Stripe's publishable client-side key.
-- `ENSO_CLOUD_CHAT_URL`: The URL for the WebSocket server serving as the chat
- backend.
-- `ENSO_CLOUD_COGNITO_USER_POOL_ID`: The ID of the Cognito user pool.
-- `ENSO_CLOUD_COGNITO_USER_POOL_WEB_CLIENT_ID`: The client-side key of the
- Cognito user pool.
-- `ENSO_CLOUD_COGNITO_DOMAIN`: The domain which all Cognito requests should go
- to.
-- `ENSO_CLOUD_COGNITO_REGION`: The AWS region for which Cognito is configured.
- Should match the region of the domain in `ENSO_CLOUD_COGNITO_DOMAIN`.
diff --git a/app/dashboard/favicon.ico b/app/dashboard/favicon.ico
deleted file mode 100644
index 8ca9e02d62b..00000000000
Binary files a/app/dashboard/favicon.ico and /dev/null differ
diff --git a/app/dashboard/package.json b/app/dashboard/package.json
deleted file mode 100644
index a0e904ada01..00000000000
--- a/app/dashboard/package.json
+++ /dev/null
@@ -1,105 +0,0 @@
-{
- "name": "enso-dashboard",
- "version": "0.1.0",
- "type": "module",
- "main": "./src/index.tsx",
- "private": true,
- "imports": {
- "#/*": "./src/*"
- },
- "exports": {
- ".": "./src/index.tsx",
- "./tailwind.config": "./tailwind.config.js",
- "./src/platform": "./src/platform.ts",
- "./src/tailwind.css": "./src/tailwind.css"
- },
- "scripts": {
- "compile": "tsc",
- "typecheck": "tsc",
- "build": "vite build",
- "lint": "eslint .",
- "dev": "vite",
- "dev:e2e": "vite -c vite.test.config.ts",
- "dev:e2e:ci": "vite -c vite.test.config.ts build && vite preview --port 8080 --strictPort",
- "test": "corepack pnpm run /^^^^test:.*/",
- "test:unit": "vitest run",
- "test-dev:unit": "vitest",
- "test:e2e": "cross-env NODE_ENV=production playwright test",
- "test-dev:e2e": "cross-env NODE_ENV=production playwright test --ui"
- },
- "dependencies": {
- "@aws-amplify/auth": "5.6.5",
- "@aws-amplify/core": "5.8.5",
- "@hookform/resolvers": "^3.4.0",
- "@internationalized/date": "^3.5.5",
- "@monaco-editor/react": "4.6.0",
- "@react-aria/interactions": "^3.22.3",
- "@sentry/react": "^7.74.0",
- "@stripe/react-stripe-js": "^2.7.1",
- "@stripe/stripe-js": "^3.5.0",
- "@tanstack/react-query": "5.55.0",
- "@tanstack/vue-query": ">= 5.54.0 < 5.56.0",
- "ajv": "^8.12.0",
- "amazon-cognito-identity-js": "6.3.6",
- "clsx": "^2.1.1",
- "enso-common": "workspace:*",
- "framer-motion": "11.3.0",
- "input-otp": "1.2.4",
- "is-network-error": "^1.0.1",
- "monaco-editor": "0.48.0",
- "qrcode.react": "3.1.0",
- "react": "^18.3.1",
- "react-aria": "^3.34.3",
- "react-aria-components": "^1.3.3",
- "react-dom": "^18.3.1",
- "react-error-boundary": "4.0.13",
- "react-hook-form": "^7.51.4",
- "react-router": "^6.23.1",
- "react-router-dom": "^6.23.1",
- "react-stately": "^3.32.2",
- "react-toastify": "^9.1.3",
- "tailwind-merge": "^2.3.0",
- "tailwind-variants": "0.2.1",
- "tiny-invariant": "^1.3.3",
- "ts-results": "^3.3.0",
- "validator": "^13.12.0",
- "zod": "^3.23.8",
- "zustand": "^4.5.4"
- },
- "devDependencies": {
- "@fast-check/vitest": "^0.0.8",
- "@modyfi/vite-plugin-yaml": "^1.0.4",
- "@playwright/test": "^1.40.0",
- "@react-types/shared": "^3.22.1",
- "@tanstack/react-query-devtools": "5.45.1",
- "@types/eslint__js": "^8.42.3",
- "@types/node": "^20.11.21",
- "@types/react": "^18.0.27",
- "@types/react-dom": "^18.0.10",
- "@types/validator": "^13.11.7",
- "@typescript-eslint/eslint-plugin": "^7.15.0",
- "@typescript-eslint/parser": "^7.15.0",
- "@vitejs/plugin-react": "^4.2.1",
- "chalk": "^5.3.0",
- "cross-env": "^7.0.3",
- "enso-chat": "git://github.com/enso-org/enso-bot",
- "eslint": "^8.49.0",
- "eslint-plugin-react": "^7.32.1",
- "fast-check": "^3.15.0",
- "playwright": "^1.38.0",
- "postcss": "^8.4.29",
- "prettier-plugin-organize-imports": "^4.0.0",
- "prettier-plugin-tailwindcss": "^0.5.11",
- "react-toastify": "^9.1.3",
- "tailwindcss": "^3.4.1",
- "tailwindcss-animate": "1.0.7",
- "tailwindcss-react-aria-components": "^1.1.1",
- "typescript": "^5.5.3",
- "vite": "^5.3.5",
- "vitest": "^1.3.1"
- },
- "overrides": {
- "@aws-amplify/auth": "../_IGNORED_",
- "react-native-url-polyfill": "../_IGNORED_"
- }
-}
diff --git a/app/dashboard/playwright.config.ts b/app/dashboard/playwright.config.ts
deleted file mode 100644
index f0bf92b3fcf..00000000000
--- a/app/dashboard/playwright.config.ts
+++ /dev/null
@@ -1,64 +0,0 @@
-/** @file Playwright browser testing configuration. */
-/** Note that running Playwright in CI poses a number of issues:
- * - `backdrop-filter: blur` is disabled, due to issues with Chromium's `--disable-gpu` flag
- * (see below).
- * - System validation dialogs are not reliable between computers, as they may have different
- * default fonts. */
-import * as test from '@playwright/test'
-
-import * as appConfig from 'enso-common/src/appConfig'
-
-appConfig.loadTestEnvironmentVariables()
-
-/* eslint-disable @typescript-eslint/no-magic-numbers, @typescript-eslint/strict-boolean-expressions */
-
-const DEBUG = process.env.PWDEBUG === '1'
-const TIMEOUT_MS = DEBUG ? 100_000_000 : 30_000
-
-export default test.defineConfig({
- testDir: './e2e',
- fullyParallel: true,
- forbidOnly: true,
- workers: process.env.PROD ? 8 : 1,
- repeatEach: process.env.CI ? 3 : 1,
- expect: {
- toHaveScreenshot: { threshold: 0 },
- timeout: TIMEOUT_MS,
- },
- timeout: TIMEOUT_MS,
- reporter: 'html',
- use: {
- baseURL: 'http://localhost:8080',
- trace: 'retain-on-failure',
- launchOptions: {
- ignoreDefaultArgs: ['--headless'],
- args: [
- ...(DEBUG ?
- []
- : [
- // Much closer to headful Chromium than classic headless.
- '--headless=new',
- ]),
- // Required for `backdrop-filter: blur` to work.
- '--use-angle=swiftshader',
- // FIXME: `--disable-gpu` disables `backdrop-filter: blur`, which is not handled by
- // the software (CPU) compositor. This SHOULD be fixed eventually, but this flag
- // MUST stay as CI does not have a GPU.
- '--disable-gpu',
- // Fully disable GPU process.
- '--disable-software-rasterizer',
- // Disable text subpixel antialiasing.
- '--font-render-hinting=none',
- '--disable-skia-runtime-opts',
- '--disable-system-font-check',
- '--disable-font-subpixel-positioning',
- '--disable-lcd-text',
- ],
- },
- },
- webServer: {
- command: `corepack pnpm run ${process.env.CI || process.env.PROD ? 'dev:e2e:ci' : 'dev:e2e'}`,
- port: 8080,
- reuseExistingServer: false,
- },
-})
diff --git a/app/dashboard/postcss.config.js b/app/dashboard/postcss.config.js
deleted file mode 100644
index d27d68f3e9a..00000000000
--- a/app/dashboard/postcss.config.js
+++ /dev/null
@@ -1,9 +0,0 @@
-/** @file Configuration for PostCSS. */
-/* eslint-disable no-restricted-syntax */
-export default {
- plugins: {
- // eslint-disable-next-line @typescript-eslint/naming-convention
- 'tailwindcss/nesting': {},
- tailwindcss: {},
- },
-}
diff --git a/app/dashboard/src/TestAppRunner.tsx b/app/dashboard/src/TestAppRunner.tsx
deleted file mode 100644
index a01636e62ba..00000000000
--- a/app/dashboard/src/TestAppRunner.tsx
+++ /dev/null
@@ -1,8 +0,0 @@
-/** @file Placeholder component for GUI used during e2e tests. */
-import type * as editor from '#/layouts/Editor'
-
-/** Placeholder component for GUI used during e2e tests. */
-export function TestAppRunner(props: editor.GraphEditorProps) {
- // eslint-disable-next-line no-restricted-syntax
- return props.hidden ? <>> :
Vue app loads here.
-}
diff --git a/app/dashboard/src/assets/background.jpg b/app/dashboard/src/assets/background.jpg
deleted file mode 100644
index 0c357456db4..00000000000
Binary files a/app/dashboard/src/assets/background.jpg and /dev/null differ
diff --git a/app/dashboard/src/entrypoint.ts b/app/dashboard/src/entrypoint.ts
deleted file mode 100644
index def182513db..00000000000
--- a/app/dashboard/src/entrypoint.ts
+++ /dev/null
@@ -1,33 +0,0 @@
-/** @file Entry point into the cloud dashboard. */
-import * as commonQuery from 'enso-common/src/queryClient'
-
-import '#/tailwind.css'
-
-import * as main from '#/index'
-import * as testAppRunner from '#/TestAppRunner'
-
-// ===================
-// === Entry point ===
-// ===================
-
-main.run({
- logger: console,
- // Browsers usually do not support vibrancy for webpages.
- vibrancy: false,
- // This file is only included when building for the cloud.
- supportsLocalBackend: false,
- supportsDeepLinks: false,
- isAuthenticationDisabled: false,
- shouldShowDashboard: true,
- initialProjectName: null,
- /** The `onAuthenticated` option is mandatory but is not needed here,
- * so this function is empty. */
- onAuthenticated() {
- // eslint-disable-next-line @typescript-eslint/no-empty-function
- },
- /** The cloud frontend is not capable of running a Project Manager. */
- projectManagerUrl: null,
- ydocUrl: null,
- appRunner: testAppRunner.TestAppRunner,
- queryClient: commonQuery.createQueryClient(),
-})
diff --git a/app/dashboard/tsconfig.json b/app/dashboard/tsconfig.json
deleted file mode 100644
index 3ed52dcedc5..00000000000
--- a/app/dashboard/tsconfig.json
+++ /dev/null
@@ -1,23 +0,0 @@
-{
- "extends": "../tsconfig.json",
- "include": [
- "src",
- "e2e",
- "../types",
- "./src/**/*.json",
- "./e2e/**/*.json",
- "../../utils.ts",
- ".prettierrc.cjs",
- "*.js",
- "*.ts"
- ],
- "exclude": ["./dist"],
- "compilerOptions": {
- "composite": true,
- "noEmit": false,
- "outDir": "../../node_modules/.cache/tsc",
- "paths": { "#/*": ["./src/*"] },
- "target": "ESNext",
- "lib": ["ESNext", "DOM", "DOM.Iterable", "ES2023"]
- }
-}
diff --git a/app/dashboard/vite.config.ts b/app/dashboard/vite.config.ts
deleted file mode 100644
index d0beca979a4..00000000000
--- a/app/dashboard/vite.config.ts
+++ /dev/null
@@ -1,71 +0,0 @@
-/** @file Configuration for vite. */
-import * as fsSync from 'node:fs'
-import * as url from 'node:url'
-
-import vitePluginYaml from '@modyfi/vite-plugin-yaml'
-import vitePluginReact from '@vitejs/plugin-react'
-import * as vite from 'vite'
-
-import * as common from 'enso-common'
-import * as appConfig from 'enso-common/src/appConfig'
-
-// =====================
-// === Configuration ===
-// =====================
-
-const HTTP_STATUS_OK = 200
-const SERVER_PORT = 8080
-await appConfig.readEnvironmentFromFile()
-
-/* eslint-disable @typescript-eslint/naming-convention */
-export default vite.defineConfig({
- server: { port: SERVER_PORT, headers: Object.fromEntries(common.COOP_COEP_CORP_HEADERS) },
- plugins: [
- vitePluginReact({
- include: '**/*.tsx',
- babel: { plugins: ['@babel/plugin-syntax-import-attributes'] },
- }),
- vitePluginYaml(),
- serveFavicon(),
- ],
- resolve: {
- alias: {
- '#': url.fileURLToPath(new URL('./src', import.meta.url)),
- },
- },
- build: {
- rollupOptions: {
- input: {
- main: url.fileURLToPath(new URL('./index.html', import.meta.url)),
- '404': url.fileURLToPath(new URL('./404.html', import.meta.url)),
- },
- },
- },
- define: {
- // The sole hardcoded usage of `global` in aws-amplify.
- 'global.TYPED_ARRAY_SUPPORT': JSON.stringify(true),
- ...appConfig.getDefines(),
- },
-})
-
-/** A plugin to serve a favicon, in development mode only. */
-function serveFavicon(): vite.Plugin {
- const favicon = fsSync.readFileSync(url.fileURLToPath(new URL('./favicon.ico', import.meta.url)))
- const headers: HeadersInit = [
- ['Content-Length', String(favicon.length)],
- ['Content-Type', 'image/png'],
- ...common.COOP_COEP_CORP_HEADERS,
- ]
- return {
- name: 'serve-favicon',
- configureServer: (server) => {
- server.middlewares.use((req, res, next) => {
- if (req.url === '/favicon.ico') {
- res.writeHead(HTTP_STATUS_OK, headers).end(favicon)
- } else {
- next()
- }
- })
- },
- }
-}
diff --git a/app/dashboard/vitest.config.ts b/app/dashboard/vitest.config.ts
deleted file mode 100644
index 6f3d0d8acc9..00000000000
--- a/app/dashboard/vitest.config.ts
+++ /dev/null
@@ -1,25 +0,0 @@
-/** @file Configuration for vitest. */
-import * as url from 'node:url'
-
-import * as vitestConfig from 'vitest/config'
-
-import * as appConfig from 'enso-common/src/appConfig'
-
-appConfig.loadTestEnvironmentVariables()
-// @ts-expect-error This is required, otherwise importing node modules is broken.
-// This is required for `datalinkSchema.test.ts`.
-process.env.NODE_ENV = 'development'
-
-const VITE_CONFIG = (await import('./vite.config')).default
-
-export default vitestConfig.mergeConfig(
- VITE_CONFIG,
- vitestConfig.defineConfig({
- test: {
- environment: 'jsdom',
- exclude: [...vitestConfig.configDefaults.exclude, '**/*.spec.{ts,tsx}'],
- root: url.fileURLToPath(new URL('./', import.meta.url)),
- restoreMocks: true,
- },
- }),
-)
diff --git a/app/gui2/.gitignore b/app/gui/.gitignore
similarity index 62%
rename from app/gui2/.gitignore
rename to app/gui/.gitignore
index 6c5b2f47db0..4dfa7178b59 100644
--- a/app/gui2/.gitignore
+++ b/app/gui/.gitignore
@@ -8,6 +8,7 @@ node_modules
dist
dist-ssr
coverage
+mockDist
*.local
*.tsbuildinfo
@@ -25,12 +26,11 @@ coverage
test-results/
playwright-report/
-src/util/iconList.json
-src/util/iconName.ts
-src/stores/visualization/metadata.json
public/font-dejavu/
public/font-enso/
public/font-mplus1/
-src/assets/font-dejavu.css
-src/assets/font-enso.css
-src/assets/font-mplus1.css
+src/project-view/assets/font-dejavu.css
+src/project-view/assets/font-enso.css
+src/project-view/assets/font-mplus1.css
+src/project-view/util/iconList.json
+src/project-view/util/iconName.ts
diff --git a/app/dashboard/.prettierrc.json b/app/gui/.prettierrc.json
similarity index 100%
rename from app/dashboard/.prettierrc.json
rename to app/gui/.prettierrc.json
diff --git a/app/gui2/.vscode/settings.json b/app/gui/.vscode/settings.json
similarity index 100%
rename from app/gui2/.vscode/settings.json
rename to app/gui/.vscode/settings.json
diff --git a/app/gui2/LICENSE b/app/gui/LICENSE
similarity index 100%
rename from app/gui2/LICENSE
rename to app/gui/LICENSE
diff --git a/app/dashboard/docs/browser_specific_behavior.md b/app/gui/docs/browser_specific_behavior.md
similarity index 100%
rename from app/dashboard/docs/browser_specific_behavior.md
rename to app/gui/docs/browser_specific_behavior.md
diff --git a/app/dashboard/e2e/README.md b/app/gui/e2e/dashboard/README.md
similarity index 100%
rename from app/dashboard/e2e/README.md
rename to app/gui/e2e/dashboard/README.md
diff --git a/app/dashboard/e2e/actions/BaseActions.ts b/app/gui/e2e/dashboard/actions/BaseActions.ts
similarity index 85%
rename from app/dashboard/e2e/actions/BaseActions.ts
rename to app/gui/e2e/dashboard/actions/BaseActions.ts
index 61b87e5a708..2a325c4a477 100644
--- a/app/dashboard/e2e/actions/BaseActions.ts
+++ b/app/gui/e2e/dashboard/actions/BaseActions.ts
@@ -3,7 +3,7 @@ import * as test from '@playwright/test'
import type * as inputBindings from '#/utilities/inputBindings'
-import { modModifier } from '../actions'
+import { modModifier } from '.'
// ====================
// === PageCallback ===
@@ -27,7 +27,8 @@ export interface LocatorCallback {
// === BaseActions ===
// ===================
-/** The base class from which all `Actions` classes are derived.
+/**
+ * The base class from which all `Actions` classes are derived.
* It contains method common to all `Actions` subclasses.
* This is a [`thenable`], so it can be used as if it was a {@link Promise}.
*
@@ -40,14 +41,18 @@ export default class BaseActions implements Promise {
private readonly promise = Promise.resolve(),
) {}
- /** Get the string name of the class of this instance. Required for this class to implement
- * {@link Promise}. */
+ /**
+ * Get the string name of the class of this instance. Required for this class to implement
+ * {@link Promise}.
+ */
get [Symbol.toStringTag]() {
return this.constructor.name
}
- /** Press a key, replacing the text `Mod` with `Meta` (`Cmd`) on macOS, and `Control`
- * on all other platforms. */
+ /**
+ * Press a key, replacing the text `Mod` with `Meta` (`Cmd`) on macOS, and `Control`
+ * on all other platforms.
+ */
static press(page: test.Page, keyOrShortcut: string): Promise {
return test.test.step(`Press '${keyOrShortcut}'`, async () => {
if (/\bMod\b|\bDelete\b/.test(keyOrShortcut)) {
@@ -77,18 +82,22 @@ export default class BaseActions implements Promise {
return await this.promise.then(onfulfilled, onrejected)
}
- /** Proxies the `catch` method of the internal {@link Promise}.
+ /**
+ * Proxies the `catch` method of the internal {@link Promise}.
* This method is not required for this to be a `thenable`, but it is still useful
- * to treat this class as a {@link Promise}. */
+ * to treat this class as a {@link Promise}.
+ */
// The following types are copied almost verbatim from the type definitions for `Promise`.
// eslint-disable-next-line no-restricted-syntax
async catch(onrejected?: ((reason: unknown) => PromiseLike | T) | null | undefined) {
return await this.promise.catch(onrejected)
}
- /** Proxies the `catch` method of the internal {@link Promise}.
+ /**
+ * Proxies the `catch` method of the internal {@link Promise}.
* This method is not required for this to be a `thenable`, but it is still useful
- * to treat this class as a {@link Promise}. */
+ * to treat this class as a {@link Promise}.
+ */
async finally(onfinally?: (() => void) | null | undefined): Promise {
await this.promise.finally(onfinally)
}
@@ -101,9 +110,11 @@ export default class BaseActions implements Promise {
return new clazz(this.page, this.promise, ...args)
}
- /** Perform an action on the current page. This should generally be avoided in favor of using
+ /**
+ * Perform an action on the current page. This should generally be avoided in favor of using
* specific methods; this is more or less an escape hatch used ONLY when the methods do not
- * support desired functionality. */
+ * support desired functionality.
+ */
do(callback: PageCallback): this {
// @ts-expect-error This is SAFE, but only when the constructor of this class has the exact
// same parameters as `BaseActions`.
@@ -119,8 +130,10 @@ export default class BaseActions implements Promise {
return this.do(() => test.test.step(name, () => callback(this.page)))
}
- /** Press a key, replacing the text `Mod` with `Meta` (`Cmd`) on macOS, and `Control`
- * on all other platforms. */
+ /**
+ * Press a key, replacing the text `Mod` with `Meta` (`Cmd`) on macOS, and `Control`
+ * on all other platforms.
+ */
press(keyOrShortcut: inputBindings.AutocompleteKeybind) {
return this.do((page) => BaseActions.press(page, keyOrShortcut))
}
@@ -157,8 +170,10 @@ export default class BaseActions implements Promise {
})
}
- /** Expect an input to have an error (or no error if the expected value is `null`).
- * If the expected value is `undefined`, the assertion is skipped. */
+ /**
+ * Expect an input to have an error (or no error if the expected value is `null`).
+ * If the expected value is `undefined`, the assertion is skipped.
+ */
expectInputError(testId: string, description: string, expected: string | null | undefined) {
if (expected === undefined) {
return this
diff --git a/app/dashboard/e2e/actions/DrivePageActions.ts b/app/gui/e2e/dashboard/actions/DrivePageActions.ts
similarity index 96%
rename from app/dashboard/e2e/actions/DrivePageActions.ts
rename to app/gui/e2e/dashboard/actions/DrivePageActions.ts
index 72e67944b1c..7eca26f1ab3 100644
--- a/app/dashboard/e2e/actions/DrivePageActions.ts
+++ b/app/gui/e2e/dashboard/actions/DrivePageActions.ts
@@ -12,7 +12,7 @@ import {
locateSecretNameInput,
locateSecretValueInput,
TEXT,
-} from '../actions'
+} from '.'
import type * as baseActions from './BaseActions'
import * as contextMenuActions from './contextMenuActions'
import EditorPageActions from './EditorPageActions'
@@ -120,8 +120,10 @@ export default class DrivePageActions extends PageActions {
locateAssetRows(page).nth(index).click({ position: ASSET_ROW_SAFE_POSITION }),
)
},
- /** Right click a specific row to bring up its context menu, or the context menu for multiple
- * assets when right clicking on a selected asset when multiple assets are selected. */
+ /**
+ * Right click a specific row to bring up its context menu, or the context menu for multiple
+ * assets when right clicking on a selected asset when multiple assets are selected.
+ */
rightClickRow(index: number) {
return self.step(`Right click drive table row #${index}`, (page) =>
locateAssetRows(page)
@@ -164,8 +166,10 @@ export default class DrivePageActions extends PageActions {
}),
)
},
- /** A test assertion to confirm that there is only one row visible, and that row is the
- * placeholder row displayed when there are no assets to show. */
+ /**
+ * A test assertion to confirm that there is only one row visible, and that row is the
+ * placeholder row displayed when there are no assets to show.
+ */
expectPlaceholderRow() {
return self.step('Expect placeholder row', async (page) => {
await test.expect(locateAssetRows(page)).toHaveCount(0)
@@ -174,8 +178,10 @@ export default class DrivePageActions extends PageActions {
await test.expect(nonAssetRows).toHaveText(/This folder is empty/)
})
},
- /** A test assertion to confirm that there is only one row visible, and that row is the
- * placeholder row displayed when there are no assets in Trash. */
+ /**
+ * A test assertion to confirm that there is only one row visible, and that row is the
+ * placeholder row displayed when there are no assets in Trash.
+ */
expectTrashPlaceholderRow() {
return self.step('Expect trash placeholder row', async (page) => {
await test.expect(locateAssetRows(page)).toHaveCount(0)
diff --git a/app/dashboard/e2e/actions/EditorPageActions.ts b/app/gui/e2e/dashboard/actions/EditorPageActions.ts
similarity index 100%
rename from app/dashboard/e2e/actions/EditorPageActions.ts
rename to app/gui/e2e/dashboard/actions/EditorPageActions.ts
diff --git a/app/dashboard/e2e/actions/ForgotPasswordPageActions.ts b/app/gui/e2e/dashboard/actions/ForgotPasswordPageActions.ts
similarity index 97%
rename from app/dashboard/e2e/actions/ForgotPasswordPageActions.ts
rename to app/gui/e2e/dashboard/actions/ForgotPasswordPageActions.ts
index b3dade2d112..738975c79fe 100644
--- a/app/dashboard/e2e/actions/ForgotPasswordPageActions.ts
+++ b/app/gui/e2e/dashboard/actions/ForgotPasswordPageActions.ts
@@ -1,7 +1,7 @@
/** @file Available actions for the login page. */
import * as test from '@playwright/test'
-import { TEXT, VALID_EMAIL } from '../actions'
+import { TEXT, VALID_EMAIL } from '.'
import BaseActions, { type LocatorCallback } from './BaseActions'
import LoginPageActions from './LoginPageActions'
diff --git a/app/dashboard/e2e/actions/LoginPageActions.ts b/app/gui/e2e/dashboard/actions/LoginPageActions.ts
similarity index 99%
rename from app/dashboard/e2e/actions/LoginPageActions.ts
rename to app/gui/e2e/dashboard/actions/LoginPageActions.ts
index 31093ad2424..5af5d534dbe 100644
--- a/app/dashboard/e2e/actions/LoginPageActions.ts
+++ b/app/gui/e2e/dashboard/actions/LoginPageActions.ts
@@ -1,7 +1,7 @@
/** @file Available actions for the login page. */
import * as test from '@playwright/test'
-import { TEXT, VALID_EMAIL, VALID_PASSWORD, passAgreementsDialog } from '../actions'
+import { TEXT, VALID_EMAIL, VALID_PASSWORD, passAgreementsDialog } from '.'
import BaseActions, { type LocatorCallback } from './BaseActions'
import DrivePageActions from './DrivePageActions'
import ForgotPasswordPageActions from './ForgotPasswordPageActions'
diff --git a/app/dashboard/e2e/actions/NewDataLinkModalActions.ts b/app/gui/e2e/dashboard/actions/NewDataLinkModalActions.ts
similarity index 97%
rename from app/dashboard/e2e/actions/NewDataLinkModalActions.ts
rename to app/gui/e2e/dashboard/actions/NewDataLinkModalActions.ts
index 273b8c3d5e6..9a583574334 100644
--- a/app/dashboard/e2e/actions/NewDataLinkModalActions.ts
+++ b/app/gui/e2e/dashboard/actions/NewDataLinkModalActions.ts
@@ -1,7 +1,7 @@
/** @file Actions for a "new Data Link" modal. */
import type * as test from 'playwright/test'
-import { TEXT } from '../actions'
+import { TEXT } from '.'
import type * as baseActions from './BaseActions'
import BaseActions from './BaseActions'
import DrivePageActions from './DrivePageActions'
diff --git a/app/dashboard/e2e/actions/PageActions.ts b/app/gui/e2e/dashboard/actions/PageActions.ts
similarity index 100%
rename from app/dashboard/e2e/actions/PageActions.ts
rename to app/gui/e2e/dashboard/actions/PageActions.ts
diff --git a/app/dashboard/e2e/actions/RegisterPageActions.ts b/app/gui/e2e/dashboard/actions/RegisterPageActions.ts
similarity index 98%
rename from app/dashboard/e2e/actions/RegisterPageActions.ts
rename to app/gui/e2e/dashboard/actions/RegisterPageActions.ts
index 00d169fc141..dcdd3d8fc46 100644
--- a/app/dashboard/e2e/actions/RegisterPageActions.ts
+++ b/app/gui/e2e/dashboard/actions/RegisterPageActions.ts
@@ -1,7 +1,7 @@
/** @file Available actions for the login page. */
import * as test from '@playwright/test'
-import { TEXT, VALID_EMAIL, VALID_PASSWORD } from '../actions'
+import { TEXT, VALID_EMAIL, VALID_PASSWORD } from '.'
import BaseActions, { type LocatorCallback } from './BaseActions'
import LoginPageActions from './LoginPageActions'
diff --git a/app/dashboard/e2e/actions/SettingsPageActions.ts b/app/gui/e2e/dashboard/actions/SettingsPageActions.ts
similarity index 100%
rename from app/dashboard/e2e/actions/SettingsPageActions.ts
rename to app/gui/e2e/dashboard/actions/SettingsPageActions.ts
diff --git a/app/dashboard/e2e/actions/SetupDonePageActions.ts b/app/gui/e2e/dashboard/actions/SetupDonePageActions.ts
similarity index 94%
rename from app/dashboard/e2e/actions/SetupDonePageActions.ts
rename to app/gui/e2e/dashboard/actions/SetupDonePageActions.ts
index a1af0f9d20d..ca417a883af 100644
--- a/app/dashboard/e2e/actions/SetupDonePageActions.ts
+++ b/app/gui/e2e/dashboard/actions/SetupDonePageActions.ts
@@ -1,5 +1,5 @@
/** @file Actions for the fourth step of the "setup" page. */
-import { TEXT } from '../actions'
+import { TEXT } from '.'
import BaseActions from './BaseActions'
import DrivePageActions from './DrivePageActions'
diff --git a/app/dashboard/e2e/actions/SetupInvitePageActions.ts b/app/gui/e2e/dashboard/actions/SetupInvitePageActions.ts
similarity index 96%
rename from app/dashboard/e2e/actions/SetupInvitePageActions.ts
rename to app/gui/e2e/dashboard/actions/SetupInvitePageActions.ts
index a99ad2efd41..062dce8c5ff 100644
--- a/app/dashboard/e2e/actions/SetupInvitePageActions.ts
+++ b/app/gui/e2e/dashboard/actions/SetupInvitePageActions.ts
@@ -1,5 +1,5 @@
/** @file Actions for the third step of the "setup" page. */
-import { TEXT } from '../actions'
+import { TEXT } from '.'
import BaseActions from './BaseActions'
import SetupTeamPageActions from './SetupTeamPageActions'
diff --git a/app/dashboard/e2e/actions/SetupOrganizationPageActions.ts b/app/gui/e2e/dashboard/actions/SetupOrganizationPageActions.ts
similarity index 96%
rename from app/dashboard/e2e/actions/SetupOrganizationPageActions.ts
rename to app/gui/e2e/dashboard/actions/SetupOrganizationPageActions.ts
index aea051629bb..6f1a5eca686 100644
--- a/app/dashboard/e2e/actions/SetupOrganizationPageActions.ts
+++ b/app/gui/e2e/dashboard/actions/SetupOrganizationPageActions.ts
@@ -1,5 +1,5 @@
/** @file Actions for the third step of the "setup" page. */
-import { TEXT } from '../actions'
+import { TEXT } from '.'
import BaseActions from './BaseActions'
import SetupInvitePageActions from './SetupInvitePageActions'
diff --git a/app/dashboard/e2e/actions/SetupPlanPageActions.ts b/app/gui/e2e/dashboard/actions/SetupPlanPageActions.ts
similarity index 98%
rename from app/dashboard/e2e/actions/SetupPlanPageActions.ts
rename to app/gui/e2e/dashboard/actions/SetupPlanPageActions.ts
index 4e32726e07b..cf8228138cc 100644
--- a/app/dashboard/e2e/actions/SetupPlanPageActions.ts
+++ b/app/gui/e2e/dashboard/actions/SetupPlanPageActions.ts
@@ -1,7 +1,7 @@
/** @file Actions for the second step of the "setup" page. */
import { PLAN_TO_UPGRADE_LABEL_ID } from '#/modules/payments/constants'
import { Plan } from 'enso-common/src/services/Backend'
-import { TEXT } from '../actions'
+import { TEXT } from '.'
import BaseActions from './BaseActions'
import SetupDonePageActions from './SetupDonePageActions'
import SetupOrganizationPageActions from './SetupOrganizationPageActions'
diff --git a/app/dashboard/e2e/actions/SetupTeamPageActions.ts b/app/gui/e2e/dashboard/actions/SetupTeamPageActions.ts
similarity index 95%
rename from app/dashboard/e2e/actions/SetupTeamPageActions.ts
rename to app/gui/e2e/dashboard/actions/SetupTeamPageActions.ts
index 85fb6fd06bf..fe2010d9b10 100644
--- a/app/dashboard/e2e/actions/SetupTeamPageActions.ts
+++ b/app/gui/e2e/dashboard/actions/SetupTeamPageActions.ts
@@ -1,5 +1,5 @@
/** @file Actions for the "setup" page. */
-import { TEXT } from '../actions'
+import { TEXT } from '.'
import BaseActions from './BaseActions'
import SetupDonePageActions from './SetupDonePageActions'
diff --git a/app/dashboard/e2e/actions/SetupUsernamePageActions.ts b/app/gui/e2e/dashboard/actions/SetupUsernamePageActions.ts
similarity index 95%
rename from app/dashboard/e2e/actions/SetupUsernamePageActions.ts
rename to app/gui/e2e/dashboard/actions/SetupUsernamePageActions.ts
index 642797cd6eb..0a91f27837b 100644
--- a/app/dashboard/e2e/actions/SetupUsernamePageActions.ts
+++ b/app/gui/e2e/dashboard/actions/SetupUsernamePageActions.ts
@@ -1,5 +1,5 @@
/** @file Actions for the "setup" page. */
-import { TEXT } from '../actions'
+import { TEXT } from '.'
import BaseActions from './BaseActions'
import SetupPlanPageActions from './SetupPlanPageActions'
diff --git a/app/dashboard/e2e/actions/StartModalActions.ts b/app/gui/e2e/dashboard/actions/StartModalActions.ts
similarity index 95%
rename from app/dashboard/e2e/actions/StartModalActions.ts
rename to app/gui/e2e/dashboard/actions/StartModalActions.ts
index 7a760c06c63..9202fe4b8b2 100644
--- a/app/dashboard/e2e/actions/StartModalActions.ts
+++ b/app/gui/e2e/dashboard/actions/StartModalActions.ts
@@ -1,5 +1,5 @@
/** @file Actions for the "home" page. */
-import * as actions from '../actions'
+import * as actions from '.'
import BaseActions from './BaseActions'
import DrivePageActions from './DrivePageActions'
import EditorPageActions from './EditorPageActions'
diff --git a/app/dashboard/e2e/actions/contextMenuActions.ts b/app/gui/e2e/dashboard/actions/contextMenuActions.ts
similarity index 99%
rename from app/dashboard/e2e/actions/contextMenuActions.ts
rename to app/gui/e2e/dashboard/actions/contextMenuActions.ts
index 47de5ea5d85..a9e443b36ea 100644
--- a/app/dashboard/e2e/actions/contextMenuActions.ts
+++ b/app/gui/e2e/dashboard/actions/contextMenuActions.ts
@@ -1,5 +1,5 @@
/** @file Actions for the context menu. */
-import { TEXT } from '../actions'
+import { TEXT } from '.'
import type * as baseActions from './BaseActions'
import type BaseActions from './BaseActions'
import EditorPageActions from './EditorPageActions'
diff --git a/app/dashboard/e2e/actions/goToPageActions.ts b/app/gui/e2e/dashboard/actions/goToPageActions.ts
similarity index 100%
rename from app/dashboard/e2e/actions/goToPageActions.ts
rename to app/gui/e2e/dashboard/actions/goToPageActions.ts
diff --git a/app/dashboard/e2e/actions.ts b/app/gui/e2e/dashboard/actions/index.ts
similarity index 97%
rename from app/dashboard/e2e/actions.ts
rename to app/gui/e2e/dashboard/actions/index.ts
index 1371c40a527..5798effea6f 100644
--- a/app/dashboard/e2e/actions.ts
+++ b/app/gui/e2e/dashboard/actions/index.ts
@@ -4,9 +4,9 @@ import * as test from '@playwright/test'
import { TEXTS } from 'enso-common/src/text'
-import DrivePageActions from './actions/DrivePageActions'
-import LoginPageActions from './actions/LoginPageActions'
-import * as apiModule from './api'
+import * as apiModule from '../api'
+import DrivePageActions from './DrivePageActions'
+import LoginPageActions from './LoginPageActions'
/* eslint-disable @typescript-eslint/no-namespace */
@@ -292,7 +292,7 @@ export function locateSamples(page: test.Locator | test.Page) {
/** Find an editor container (if any) on the current page. */
export function locateEditor(page: test.Page) {
// Test ID of a placeholder editor component used during testing.
- return page.getByTestId('gui-editor-root')
+ return page.locator('.App')
}
/** Find an assets table (if any) on the current page. */
@@ -315,16 +315,20 @@ export function locateAssetName(locator: test.Locator) {
return locator.locator('> :nth-child(1)')
}
-/** Find assets table rows that represent directories that can be expanded (if any)
- * on the current page. */
+/**
+ * Find assets table rows that represent directories that can be expanded (if any)
+ * on the current page.
+ */
export function locateExpandableDirectories(page: test.Page) {
// The icon is hidden when not hovered so `getByLabel` will not work.
// eslint-disable-next-line no-restricted-properties
return locateAssetRows(page).filter({ has: page.locator('[aria-label=Expand]') })
}
-/** Find assets table rows that represent directories that can be collapsed (if any)
- * on the current page. */
+/**
+ * Find assets table rows that represent directories that can be collapsed (if any)
+ * on the current page.
+ */
export function locateCollapsibleDirectories(page: test.Page) {
// The icon is hidden when not hovered so `getByLabel` will not work.
// eslint-disable-next-line no-restricted-properties
@@ -390,9 +394,11 @@ export function locateExtraColumns(page: test.Page) {
return page.getByTestId('extra-columns')
}
-/** Find a root directory dropzone (if any) on the current page.
+/**
+ * Find a root directory dropzone (if any) on the current page.
* This is the empty space below the assets table, if it doesn't take up the whole screen
- * vertically. */
+ * vertically.
+ */
export function locateRootDirectoryDropzone(page: test.Page) {
// This has no identifying features.
return page.getByTestId('root-directory-dropzone')
@@ -591,9 +597,11 @@ export namespace settings {
// === Visual layout utilities ===
// ===============================
-/** Get the left side of the bounding box of an asset row. The locator MUST be for an asset row.
+/**
+ * Get the left side of the bounding box of an asset row. The locator MUST be for an asset row.
* DO NOT assume the left side of the outer container will change. This means that it is NOT SAFE
- * to do anything with the returned values other than comparing them. */
+ * to do anything with the returned values other than comparing them.
+ */
export function getAssetRowLeftPx(locator: test.Locator) {
return locator.evaluate((el) => el.children[0]?.children[0]?.getBoundingClientRect().left ?? 0)
}
@@ -688,8 +696,10 @@ export async function modModifier(page: test.Page) {
return /\bMac OS\b/i.test(userAgent) ? 'Meta' : 'Control'
}
-/** Press a key, replacing the text `Mod` with `Meta` (`Cmd`) on macOS, and `Control`
- * on all other platforms. */
+/**
+ * Press a key, replacing the text `Mod` with `Meta` (`Cmd`) on macOS, and `Control`
+ * on all other platforms.
+ */
export async function press(page: test.Page, keyOrShortcut: string) {
await test.test.step(`Press '${keyOrShortcut}'`, async () => {
if (/\bMod\b|\bDelete\b/.test(keyOrShortcut)) {
@@ -837,8 +847,10 @@ export function mockAllAndLogin({ page, setupAPI }: MockParams) {
.do((thePage) => login({ page: thePage, setupAPI }))
}
-/** Set up all mocks, and log in with dummy credentials.
- * @deprecated Prefer {@link mockAllAndLogin}. */
+/**
+ * Set up all mocks, and log in with dummy credentials.
+ * @deprecated Prefer {@link mockAllAndLogin}.
+ */
// This syntax is required for Playwright to work properly.
// eslint-disable-next-line no-restricted-syntax
export async function mockAllAndLoginAndExposeAPI({ page, setupAPI }: MockParams) {
diff --git a/app/dashboard/e2e/actions/openUserMenuAction.ts b/app/gui/e2e/dashboard/actions/openUserMenuAction.ts
similarity index 93%
rename from app/dashboard/e2e/actions/openUserMenuAction.ts
rename to app/gui/e2e/dashboard/actions/openUserMenuAction.ts
index 7de885b6929..554a4f42251 100644
--- a/app/dashboard/e2e/actions/openUserMenuAction.ts
+++ b/app/gui/e2e/dashboard/actions/openUserMenuAction.ts
@@ -1,5 +1,5 @@
/** @file An action to open the User Menu. */
-import { TEXT } from '../actions'
+import { TEXT } from '.'
import type BaseActions from './BaseActions'
import type { PageCallback } from './BaseActions'
diff --git a/app/dashboard/e2e/actions/userMenuActions.ts b/app/gui/e2e/dashboard/actions/userMenuActions.ts
similarity index 100%
rename from app/dashboard/e2e/actions/userMenuActions.ts
rename to app/gui/e2e/dashboard/actions/userMenuActions.ts
diff --git a/app/dashboard/e2e/api.ts b/app/gui/e2e/dashboard/api.ts
similarity index 99%
rename from app/dashboard/e2e/api.ts
rename to app/gui/e2e/dashboard/api.ts
index fe17a52bc8f..ab5f5694cc6 100644
--- a/app/dashboard/e2e/api.ts
+++ b/app/gui/e2e/dashboard/api.ts
@@ -58,7 +58,7 @@ export interface SetupAPI {
}
/** The return type of {@link mockApi}. */
-export interface MockApi extends Awaited> {}
+export type MockApi = Awaited>
// This is a function, even though it does not contain function syntax.
// eslint-disable-next-line no-restricted-syntax
@@ -582,7 +582,7 @@ async function mockApiInternal({ page, setupAPI }: MockParams) {
'Development' satisfies `${backend.VersionLifecycle.development}` as backend.VersionLifecycle.development,
value: '2023.2.1-dev',
},
- // eslint-disable-next-line @typescript-eslint/naming-convention, no-restricted-syntax
+ // eslint-disable-next-line @typescript-eslint/naming-convention, camelcase, no-restricted-syntax
version_type: (new URL(request.url()).searchParams.get('version_type') ??
'') as backend.VersionType,
} satisfies backend.Version,
@@ -603,9 +603,9 @@ async function mockApiInternal({ page, setupAPI }: MockParams) {
name: 'example project name',
state: project.projectState,
packageName: 'Project_root',
- // eslint-disable-next-line @typescript-eslint/naming-convention
+ // eslint-disable-next-line @typescript-eslint/naming-convention, camelcase
ide_version: null,
- // eslint-disable-next-line @typescript-eslint/naming-convention
+ // eslint-disable-next-line @typescript-eslint/naming-convention, camelcase
engine_version: {
value: '2023.2.1-nightly.2023.9.29',
lifecycle: backend.VersionLifecycle.development,
diff --git a/app/dashboard/e2e/assetPanel.spec.ts b/app/gui/e2e/dashboard/assetPanel.spec.ts
similarity index 100%
rename from app/dashboard/e2e/assetPanel.spec.ts
rename to app/gui/e2e/dashboard/assetPanel.spec.ts
diff --git a/app/dashboard/e2e/assetSearchBar.spec.ts b/app/gui/e2e/dashboard/assetSearchBar.spec.ts
similarity index 100%
rename from app/dashboard/e2e/assetSearchBar.spec.ts
rename to app/gui/e2e/dashboard/assetSearchBar.spec.ts
diff --git a/app/dashboard/e2e/assetsTableFeatures.spec.ts b/app/gui/e2e/dashboard/assetsTableFeatures.spec.ts
similarity index 100%
rename from app/dashboard/e2e/assetsTableFeatures.spec.ts
rename to app/gui/e2e/dashboard/assetsTableFeatures.spec.ts
diff --git a/app/dashboard/e2e/authPreserveEmail.spec.ts b/app/gui/e2e/dashboard/authPreserveEmail.spec.ts
similarity index 100%
rename from app/dashboard/e2e/authPreserveEmail.spec.ts
rename to app/gui/e2e/dashboard/authPreserveEmail.spec.ts
diff --git a/app/dashboard/e2e/copy.spec.ts b/app/gui/e2e/dashboard/copy.spec.ts
similarity index 100%
rename from app/dashboard/e2e/copy.spec.ts
rename to app/gui/e2e/dashboard/copy.spec.ts
diff --git a/app/dashboard/e2e/createAsset.spec.ts b/app/gui/e2e/dashboard/createAsset.spec.ts
similarity index 100%
rename from app/dashboard/e2e/createAsset.spec.ts
rename to app/gui/e2e/dashboard/createAsset.spec.ts
diff --git a/app/dashboard/e2e/dataLinkEditor.spec.ts b/app/gui/e2e/dashboard/dataLinkEditor.spec.ts
similarity index 100%
rename from app/dashboard/e2e/dataLinkEditor.spec.ts
rename to app/gui/e2e/dashboard/dataLinkEditor.spec.ts
diff --git a/app/dashboard/e2e/delete.spec.ts b/app/gui/e2e/dashboard/delete.spec.ts
similarity index 100%
rename from app/dashboard/e2e/delete.spec.ts
rename to app/gui/e2e/dashboard/delete.spec.ts
diff --git a/app/dashboard/e2e/driveView.spec.ts b/app/gui/e2e/dashboard/driveView.spec.ts
similarity index 100%
rename from app/dashboard/e2e/driveView.spec.ts
rename to app/gui/e2e/dashboard/driveView.spec.ts
diff --git a/app/dashboard/e2e/editAssetName.spec.ts b/app/gui/e2e/dashboard/editAssetName.spec.ts
similarity index 100%
rename from app/dashboard/e2e/editAssetName.spec.ts
rename to app/gui/e2e/dashboard/editAssetName.spec.ts
diff --git a/app/dashboard/e2e/labels.spec.ts b/app/gui/e2e/dashboard/labels.spec.ts
similarity index 100%
rename from app/dashboard/e2e/labels.spec.ts
rename to app/gui/e2e/dashboard/labels.spec.ts
diff --git a/app/dashboard/e2e/labelsPanel.spec.ts b/app/gui/e2e/dashboard/labelsPanel.spec.ts
similarity index 100%
rename from app/dashboard/e2e/labelsPanel.spec.ts
rename to app/gui/e2e/dashboard/labelsPanel.spec.ts
diff --git a/app/dashboard/e2e/latestGithubReleases.json b/app/gui/e2e/dashboard/latestGithubReleases.json
similarity index 100%
rename from app/dashboard/e2e/latestGithubReleases.json
rename to app/gui/e2e/dashboard/latestGithubReleases.json
diff --git a/app/dashboard/e2e/loginLogout.spec.ts b/app/gui/e2e/dashboard/loginLogout.spec.ts
similarity index 100%
rename from app/dashboard/e2e/loginLogout.spec.ts
rename to app/gui/e2e/dashboard/loginLogout.spec.ts
diff --git a/app/dashboard/e2e/loginScreen.spec.ts b/app/gui/e2e/dashboard/loginScreen.spec.ts
similarity index 100%
rename from app/dashboard/e2e/loginScreen.spec.ts
rename to app/gui/e2e/dashboard/loginScreen.spec.ts
diff --git a/app/dashboard/e2e/membersSettings.spec.ts b/app/gui/e2e/dashboard/membersSettings.spec.ts
similarity index 100%
rename from app/dashboard/e2e/membersSettings.spec.ts
rename to app/gui/e2e/dashboard/membersSettings.spec.ts
diff --git a/app/dashboard/e2e/mock/react-stripe.tsx b/app/gui/e2e/dashboard/mock/react-stripe.tsx
similarity index 94%
rename from app/dashboard/e2e/mock/react-stripe.tsx
rename to app/gui/e2e/dashboard/mock/react-stripe.tsx
index 2a4e1e5cddc..3cc07da9409 100644
--- a/app/dashboard/e2e/mock/react-stripe.tsx
+++ b/app/gui/e2e/dashboard/mock/react-stripe.tsx
@@ -9,12 +9,7 @@ import type {
import { createContext, useContext, useEffect, useState } from 'react'
/** */
-type ElementsContextValue_ = Parameters[0]['children']>[0]
-
-/** */
-interface ElementsContextValue extends ElementsContextValue_ {
- //
-}
+type ElementsContextValue = Parameters[0]['children']>[0]
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
const ElementsContext = createContext(null!)
diff --git a/app/dashboard/e2e/mock/stripe.ts b/app/gui/e2e/dashboard/mock/stripe.ts
similarity index 97%
rename from app/dashboard/e2e/mock/stripe.ts
rename to app/gui/e2e/dashboard/mock/stripe.ts
index 1356fddfda6..133b28f86e3 100644
--- a/app/dashboard/e2e/mock/stripe.ts
+++ b/app/gui/e2e/dashboard/mock/stripe.ts
@@ -10,7 +10,7 @@ export const loadStripe = (): Promise =>
paymentMethod: {
id: '',
object: 'payment_method',
- // eslint-disable-next-line @typescript-eslint/naming-convention
+ // eslint-disable-next-line @typescript-eslint/naming-convention, camelcase
billing_details: {
address: null,
email: null,
diff --git a/app/dashboard/e2e/organizationSettings.spec.ts b/app/gui/e2e/dashboard/organizationSettings.spec.ts
similarity index 100%
rename from app/dashboard/e2e/organizationSettings.spec.ts
rename to app/gui/e2e/dashboard/organizationSettings.spec.ts
diff --git a/app/dashboard/e2e/pageSwitcher.spec.ts b/app/gui/e2e/dashboard/pageSwitcher.spec.ts
similarity index 100%
rename from app/dashboard/e2e/pageSwitcher.spec.ts
rename to app/gui/e2e/dashboard/pageSwitcher.spec.ts
diff --git a/app/dashboard/e2e/setup.spec.ts b/app/gui/e2e/dashboard/setup.spec.ts
similarity index 100%
rename from app/dashboard/e2e/setup.spec.ts
rename to app/gui/e2e/dashboard/setup.spec.ts
diff --git a/app/dashboard/e2e/signUp.spec.ts b/app/gui/e2e/dashboard/signUp.spec.ts
similarity index 100%
rename from app/dashboard/e2e/signUp.spec.ts
rename to app/gui/e2e/dashboard/signUp.spec.ts
diff --git a/app/dashboard/e2e/sort.spec.ts b/app/gui/e2e/dashboard/sort.spec.ts
similarity index 100%
rename from app/dashboard/e2e/sort.spec.ts
rename to app/gui/e2e/dashboard/sort.spec.ts
diff --git a/app/dashboard/e2e/startModal.spec.ts b/app/gui/e2e/dashboard/startModal.spec.ts
similarity index 100%
rename from app/dashboard/e2e/startModal.spec.ts
rename to app/gui/e2e/dashboard/startModal.spec.ts
diff --git a/app/dashboard/e2e/userMenu.spec.ts b/app/gui/e2e/dashboard/userMenu.spec.ts
similarity index 100%
rename from app/dashboard/e2e/userMenu.spec.ts
rename to app/gui/e2e/dashboard/userMenu.spec.ts
diff --git a/app/dashboard/e2e/userSettings.spec.ts b/app/gui/e2e/dashboard/userSettings.spec.ts
similarity index 100%
rename from app/dashboard/e2e/userSettings.spec.ts
rename to app/gui/e2e/dashboard/userSettings.spec.ts
diff --git a/app/gui2/e2e/actions.ts b/app/gui/e2e/project-view/actions.ts
similarity index 100%
rename from app/gui2/e2e/actions.ts
rename to app/gui/e2e/project-view/actions.ts
diff --git a/app/gui2/e2e/collapsingAndEntering.spec.ts b/app/gui/e2e/project-view/collapsingAndEntering.spec.ts
similarity index 99%
rename from app/gui2/e2e/collapsingAndEntering.spec.ts
rename to app/gui/e2e/project-view/collapsingAndEntering.spec.ts
index 6c2b07377cc..87fa0f76c71 100644
--- a/app/gui2/e2e/collapsingAndEntering.spec.ts
+++ b/app/gui/e2e/project-view/collapsingAndEntering.spec.ts
@@ -46,7 +46,7 @@ test('Using breadcrumbs to navigate', async ({ page }) => {
await expectInsideMain(page)
// Breadcrumbs still have all the crumbs, but the last two are dimmed.
await expect(locate.navBreadcrumb(page)).toHaveText(['Mock Project', 'func1', 'func2'])
- await expect(locate.navBreadcrumb(page, (f) => f.class('inactive'))).toHaveText([
+ await expect(locate.navBreadcrumb(page).and(page.locator('.inactive'))).toHaveText([
'func1',
'func2',
])
diff --git a/app/gui2/e2e/componentBrowser.spec.ts b/app/gui/e2e/project-view/componentBrowser.spec.ts
similarity index 100%
rename from app/gui2/e2e/componentBrowser.spec.ts
rename to app/gui/e2e/project-view/componentBrowser.spec.ts
diff --git a/app/gui2/e2e/css.ts b/app/gui/e2e/project-view/css.ts
similarity index 100%
rename from app/gui2/e2e/css.ts
rename to app/gui/e2e/project-view/css.ts
diff --git a/app/gui2/e2e/customExpect.ts b/app/gui/e2e/project-view/customExpect.ts
similarity index 95%
rename from app/gui2/e2e/customExpect.ts
rename to app/gui/e2e/project-view/customExpect.ts
index aa5b6d8ee09..9dc89a2bc1d 100644
--- a/app/gui2/e2e/customExpect.ts
+++ b/app/gui/e2e/project-view/customExpect.ts
@@ -13,7 +13,7 @@ export const expect = baseExpect.extend({
try {
await expect(locator.first()).toBeVisible()
pass = true
- } catch (e: any) {
+ } catch (e) {
console.log(e)
pass = false
}
@@ -36,7 +36,8 @@ export const expect = baseExpect.extend({
try {
await baseExpect(locator).toHaveClass(/(?<=^| )selected(?=$| )/, { timeout: 50 })
pass = true
- } catch (e: any) {
+ } catch {
+ // Do not log the error.
pass = false
}
diff --git a/app/gui2/e2e/edgeInteractions.spec.ts b/app/gui/e2e/project-view/edgeInteractions.spec.ts
similarity index 100%
rename from app/gui2/e2e/edgeInteractions.spec.ts
rename to app/gui/e2e/project-view/edgeInteractions.spec.ts
diff --git a/app/gui2/e2e/edgeRendering.spec.ts b/app/gui/e2e/project-view/edgeRendering.spec.ts
similarity index 97%
rename from app/gui2/e2e/edgeRendering.spec.ts
rename to app/gui/e2e/project-view/edgeRendering.spec.ts
index 25d7208e2ad..32e99bff05b 100644
--- a/app/gui2/e2e/edgeRendering.spec.ts
+++ b/app/gui/e2e/project-view/edgeRendering.spec.ts
@@ -1,5 +1,6 @@
-import { expect, test, type Page } from '@playwright/test'
+import { test, type Page } from '@playwright/test'
import * as actions from './actions'
+import { expect } from './customExpect'
import { edgesFromNodeWithBinding, edgesToNodeWithBinding } from './locate'
// For each outgoing edge we expect two elements: an element for io and an element for the rendered edge itself.
diff --git a/app/gui2/e2e/expressionUpdates.ts b/app/gui/e2e/project-view/expressionUpdates.ts
similarity index 94%
rename from app/gui2/e2e/expressionUpdates.ts
rename to app/gui/e2e/project-view/expressionUpdates.ts
index 5846ef888f1..a4bb533969e 100644
--- a/app/gui2/e2e/expressionUpdates.ts
+++ b/app/gui/e2e/project-view/expressionUpdates.ts
@@ -35,6 +35,7 @@ export async function mockExpressionUpdate(
update: Partial,
) {
await page.evaluate(
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
({ expression, update }) => (window as any)._mockExpressionUpdate(expression, update),
{ expression, update },
)
diff --git a/app/gui2/e2e/fullscreenVisualisation.spec.ts b/app/gui/e2e/project-view/fullscreenVisualisation.spec.ts
similarity index 100%
rename from app/gui2/e2e/fullscreenVisualisation.spec.ts
rename to app/gui/e2e/project-view/fullscreenVisualisation.spec.ts
diff --git a/app/gui2/e2e/graphNavigator.spec.ts b/app/gui/e2e/project-view/graphNavigator.spec.ts
similarity index 100%
rename from app/gui2/e2e/graphNavigator.spec.ts
rename to app/gui/e2e/project-view/graphNavigator.spec.ts
diff --git a/app/gui2/e2e/graphNodeVisualization.spec.ts b/app/gui/e2e/project-view/graphNodeVisualization.spec.ts
similarity index 100%
rename from app/gui2/e2e/graphNodeVisualization.spec.ts
rename to app/gui/e2e/project-view/graphNodeVisualization.spec.ts
diff --git a/app/gui2/e2e/graphRenderNodes.spec.ts b/app/gui/e2e/project-view/graphRenderNodes.spec.ts
similarity index 100%
rename from app/gui2/e2e/graphRenderNodes.spec.ts
rename to app/gui/e2e/project-view/graphRenderNodes.spec.ts
diff --git a/app/gui2/e2e/keyboard.ts b/app/gui/e2e/project-view/keyboard.ts
similarity index 100%
rename from app/gui2/e2e/keyboard.ts
rename to app/gui/e2e/project-view/keyboard.ts
diff --git a/app/gui2/e2e/locate.ts b/app/gui/e2e/project-view/locate.ts
similarity index 78%
rename from app/gui2/e2e/locate.ts
rename to app/gui/e2e/project-view/locate.ts
index 96932d8799d..f4867422c64 100644
--- a/app/gui2/e2e/locate.ts
+++ b/app/gui/e2e/project-view/locate.ts
@@ -1,38 +1,5 @@
import { expect, type Locator, type Page } from '@playwright/test'
import assert from 'assert'
-import cssEscape from 'css.escape'
-
-// ==============
-// === Filter ===
-// ==============
-
-class Filter {
- constructor(public selector = '') {}
-
- visible(this: T): Omit {
- return new Filter(this.selector + ':visible') as any
- }
-
- first(this: T): Omit {
- return new Filter(this.selector + ':first') as any
- }
-
- last(this: T): Omit {
- return new Filter(this.selector + ':last') as any
- }
-
- id(this: T, id: string): Omit {
- return new Filter(this.selector + '#' + cssEscape(id)) as any
- }
-
- class(...classes: string[]) {
- return new Filter(this.selector + '.' + classes.map(cssEscape).join('.'))
- }
-
- toString() {
- return this.selector
- }
-}
// ================
// === Locators ===
@@ -103,8 +70,8 @@ export function outputNode(page: Page | Locator): Node {
// === Data locators ===
function componentLocator(locatorStr: string) {
- return (page: Locator | Page, filter?: (f: Filter) => { selector: string }) => {
- return page.locator(`${locatorStr}${filter?.(new Filter()) ?? ''}`)
+ return (page: Locator | Page) => {
+ return page.locator(`${locatorStr}`)
}
}
@@ -124,23 +91,13 @@ export const lexicalContent = componentLocator('.LexicalContent')
*
* It may be covered by selected one due to way we display them.
*/
-export function componentBrowserEntry(
- page: Locator | Page,
- filter?: (f: Filter) => { selector: string },
-) {
- return page.locator(
- `.ComponentBrowser .list-variant:not(.selected) .component${filter?.(new Filter()) ?? ''}`,
- )
+export function componentBrowserEntry(page: Locator | Page) {
+ return page.locator(`.ComponentBrowser .list-variant:not(.selected) .component`)
}
/** A selected variant of Component Browser Entry */
-export function componentBrowserSelectedEntry(
- page: Locator | Page,
- filter?: (f: Filter) => { selector: string },
-) {
- return page.locator(
- `.ComponentBrowser .list-variant.selected .component${filter?.(new Filter()) ?? ''}`,
- )
+export function componentBrowserSelectedEntry(page: Locator | Page) {
+ return page.locator(`.ComponentBrowser .list-variant.selected .component`)
}
/** A not-selected variant of Component Browser entry with given label */
@@ -170,9 +127,9 @@ function visualizationLocator(visSelector: string) {
// Playwright pierces shadow roots, but not within a single XPath.
// Locate the visualization content, then locate the descendant.
const visLocator = componentLocator(visSelector)
- return (page: Locator | Page, filter?: (f: Filter) => { selector: string }) => {
+ return (page: Locator | Page) => {
const hostLocator = page.locator('.VisualizationHostContainer')
- return visLocator(hostLocator, filter)
+ return visLocator(hostLocator)
}
}
diff --git a/app/gui2/e2e/nodeClipboard.spec.ts b/app/gui/e2e/project-view/nodeClipboard.spec.ts
similarity index 100%
rename from app/gui2/e2e/nodeClipboard.spec.ts
rename to app/gui/e2e/project-view/nodeClipboard.spec.ts
diff --git a/app/gui2/e2e/pm-openrpc.json b/app/gui/e2e/project-view/pm-openrpc.json
similarity index 100%
rename from app/gui2/e2e/pm-openrpc.json
rename to app/gui/e2e/project-view/pm-openrpc.json
diff --git a/app/gui2/mock/projectManager.ts b/app/gui/e2e/project-view/projectManager.ts
similarity index 96%
rename from app/gui2/mock/projectManager.ts
rename to app/gui/e2e/project-view/projectManager.ts
index a10e4b952e4..8abeae52df6 100644
--- a/app/gui2/mock/projectManager.ts
+++ b/app/gui/e2e/project-view/projectManager.ts
@@ -60,4 +60,5 @@ export const methods = {
projects: numberOfProjects != null ? projectsList.slice(0, numberOfProjects) : projectsList,
}
},
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
} satisfies Record Promise>
diff --git a/app/gui2/e2e/removingNodes.spec.ts b/app/gui/e2e/project-view/removingNodes.spec.ts
similarity index 100%
rename from app/gui2/e2e/removingNodes.spec.ts
rename to app/gui/e2e/project-view/removingNodes.spec.ts
diff --git a/app/gui2/e2e/rightPanel.spec.ts b/app/gui/e2e/project-view/rightPanel.spec.ts
similarity index 94%
rename from app/gui2/e2e/rightPanel.spec.ts
rename to app/gui/e2e/project-view/rightPanel.spec.ts
index d8cc94aa464..5e83d3ca123 100644
--- a/app/gui2/e2e/rightPanel.spec.ts
+++ b/app/gui/e2e/project-view/rightPanel.spec.ts
@@ -32,6 +32,7 @@ test('Doc panel focus (regression #10471)', async ({ page }) => {
await locate.bottomDock(page).click()
await page.evaluate(() => {
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
const codeEditor = (window as any).__codeEditorApi
const docStart = codeEditor.indexOf('The main method')
codeEditor.placeCursor(docStart + 8)
@@ -43,6 +44,7 @@ test('Doc panel focus (regression #10471)', async ({ page }) => {
await page.keyboard.press('T')
const content = await page.evaluate(() => {
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
const codeEditor = (window as any).__codeEditorApi
return codeEditor.textContent()
})
diff --git a/app/gui2/e2e/selectingNodes.spec.ts b/app/gui/e2e/project-view/selectingNodes.spec.ts
similarity index 100%
rename from app/gui2/e2e/selectingNodes.spec.ts
rename to app/gui/e2e/project-view/selectingNodes.spec.ts
diff --git a/app/gui2/e2e/setup.ts b/app/gui/e2e/project-view/setup.ts
similarity index 96%
rename from app/gui2/e2e/setup.ts
rename to app/gui/e2e/project-view/setup.ts
index ddc8bcb2ea1..99ccf57dee5 100644
--- a/app/gui2/e2e/setup.ts
+++ b/app/gui/e2e/project-view/setup.ts
@@ -1,13 +1,13 @@
import { Server } from '@open-rpc/server-js'
import * as random from 'lib0/random'
+import pmSpec from './pm-openrpc.json' assert { type: 'json' }
import {
methods as pmMethods,
projects,
type ProjectId,
type ProjectName,
type UTCDateTime,
-} from '../mock/projectManager'
-import pmSpec from './pm-openrpc.json' assert { type: 'json' }
+} from './projectManager'
/**
* Setup for all E2E tests.
diff --git a/app/gui2/e2e/suggestionUpdates.ts b/app/gui/e2e/project-view/suggestionUpdates.ts
similarity index 100%
rename from app/gui2/e2e/suggestionUpdates.ts
rename to app/gui/e2e/project-view/suggestionUpdates.ts
diff --git a/app/gui2/e2e/tableVisualisation.spec.ts b/app/gui/e2e/project-view/tableVisualisation.spec.ts
similarity index 100%
rename from app/gui2/e2e/tableVisualisation.spec.ts
rename to app/gui/e2e/project-view/tableVisualisation.spec.ts
diff --git a/app/gui2/e2e/typesOnNodeHover.spec.ts b/app/gui/e2e/project-view/typesOnNodeHover.spec.ts
similarity index 100%
rename from app/gui2/e2e/typesOnNodeHover.spec.ts
rename to app/gui/e2e/project-view/typesOnNodeHover.spec.ts
diff --git a/app/gui2/e2e/undoRedo.spec.ts b/app/gui/e2e/project-view/undoRedo.spec.ts
similarity index 100%
rename from app/gui2/e2e/undoRedo.spec.ts
rename to app/gui/e2e/project-view/undoRedo.spec.ts
diff --git a/app/gui2/e2e/widgets.spec.ts b/app/gui/e2e/project-view/widgets.spec.ts
similarity index 100%
rename from app/gui2/e2e/widgets.spec.ts
rename to app/gui/e2e/project-view/widgets.spec.ts
diff --git a/app/dashboard/src/globals.d.ts b/app/gui/env.d.ts
similarity index 86%
rename from app/dashboard/src/globals.d.ts
rename to app/gui/env.d.ts
index 6c399e31ff2..82601efa78e 100644
--- a/app/dashboard/src/globals.d.ts
+++ b/app/gui/env.d.ts
@@ -1,13 +1,15 @@
-/** @file Globals defined outside of TypeScript files.
+/**
+ * @file Globals defined outside of TypeScript files.
* These are from variables defined at build time, environment variables,
- * monkeypatching on `window` and generated code. */
+ * monkeypatching on `window` and generated code.
+ */
///
-import type * as saveAccessToken from '#/utilities/accessToken'
+import type * as saveAccessToken from 'enso-common/src/accessToken'
// This file is being imported for its types.
// prettier-ignore
// eslint-disable-next-line no-restricted-syntax, @typescript-eslint/consistent-type-imports
-import * as buildJson from './../../build.json' with { type: 'json' };
+import * as buildJson from '../../build.json' with { type: 'json' };
// =============
// === Types ===
@@ -27,8 +29,10 @@ interface Enso {
// === Backend API ===
// ===================
-/** `window.backendApi` is a context bridge to the main process, when we're running in an
- * Electron context. It contains non-authentication-related functionality. */
+/**
+ * `window.backendApi` is a context bridge to the main process, when we're running in an
+ * Electron context. It contains non-authentication-related functionality.
+ */
interface BackendApi {
/** Return the ID of the new project. */
readonly importProjectFromPath: (
@@ -42,7 +46,8 @@ interface BackendApi {
// === Authentication API ===
// ==========================
-/** `window.authenticationApi` is a context bridge to the main process, when we're running in an
+/**
+ * `window.authenticationApi` is a context bridge to the main process, when we're running in an
* Electron context.
*
* # Safety
@@ -50,12 +55,15 @@ interface BackendApi {
* We're assuming that the main process has exposed the `authenticationApi` context bridge (see
* `lib/client/src/preload.ts` for details), and that it contains the functions defined in this
* interface. Our app can't function if these assumptions are not met, so we're disabling the
- * TypeScript checks for this interface when we use it. */
+ * TypeScript checks for this interface when we use it.
+ */
interface AuthenticationApi {
/** Open a URL in the system browser. */
readonly openUrlInSystemBrowser: (url: string) => void
- /** Set the callback to be called when the system browser redirects back to a URL in the app,
- * via a deep link. See `setDeepLinkHandler` for details. */
+ /**
+ * Set the callback to be called when the system browser redirects back to a URL in the app,
+ * via a deep link. See `setDeepLinkHandler` for details.
+ */
readonly setDeepLinkHandler: (callback: (url: string) => void) => void
/** Saves the access token to a file. */
readonly saveAccessToken: (accessToken: saveAccessToken.AccessToken | null) => void
@@ -65,8 +73,10 @@ interface AuthenticationApi {
// === Navigation API ===
// ======================
-/** `window.navigationApi` is a context bridge to the main process, when we're running in an
- * Electron context. It contains navigation-related functionality. */
+/**
+ * `window.navigationApi` is a context bridge to the main process, when we're running in an
+ * Electron context. It contains navigation-related functionality.
+ */
interface NavigationApi {
/** Go back in the navigation history. */
readonly goBack: () => void
@@ -105,8 +115,10 @@ interface ProjectInfo {
readonly parentDirectory: string
}
-/** `window.projectManagementApi` exposes functionality related to system events related to
- * project management. */
+/**
+ * `window.projectManagementApi` exposes functionality related to system events related to
+ * project management.
+ */
interface ProjectManagementApi {
readonly setOpenProjectHandler: (handler: (projectInfo: ProjectInfo) => void) => void
}
@@ -115,7 +127,8 @@ interface ProjectManagementApi {
// === File Browser API ===
// ========================
-/** `window.fileBrowserApi` is a context bridge to the main process, when we're running in an
+/**
+ * `window.fileBrowserApi` is a context bridge to the main process, when we're running in an
* Electron context.
*
* # Safety
@@ -239,4 +252,15 @@ declare global {
/* eslint-disable @typescript-eslint/naming-convention */
const BUILD_INFO: buildJson.BuildInfo
const PROJECT_MANAGER_IN_BUNDLE_PATH: StringConstructor
+ const PROJECT_MANAGER_URL: string | undefined
+ const YDOC_SERVER_URL: string | undefined
+ const IS_CLOUD_BUILD: boolean
+
+ interface Document {
+ caretPositionFromPoint(x: number, y: number): { offsetNode: Node; offset: number } | null
+ }
+
+ interface LogEvent {
+ (message: string, projectId?: string | null, metadata?: object | null): void
+ }
}
diff --git a/app/dashboard/index.html b/app/gui/index.html
similarity index 76%
rename from app/dashboard/index.html
rename to app/gui/index.html
index fee8497e492..055ad35bde1 100644
--- a/app/dashboard/index.html
+++ b/app/gui/index.html
@@ -1,13 +1,16 @@
-
-
+
+
+
+
+
@@ -34,14 +37,14 @@
maximum-scale = 1.0,
user-scalable = no"
/>
- Enso
-
+ Enso Analytics
+
diff --git a/app/gui2/lib0-ext.d.ts b/app/gui/lib0-ext.d.ts
similarity index 100%
rename from app/gui2/lib0-ext.d.ts
rename to app/gui/lib0-ext.d.ts
diff --git a/app/gui2/package.json b/app/gui/package.json
similarity index 64%
rename from app/gui2/package.json
rename to app/gui/package.json
index fc91dea69db..87fa24bcaa9 100644
--- a/app/gui2/package.json
+++ b/app/gui/package.json
@@ -1,40 +1,78 @@
{
+ "name": "enso-gui",
"version": "0.1.0",
- "name": "enso-gui2",
- "private": true,
"type": "module",
+ "private": true,
"author": {
"name": "Enso Team",
"email": "contact@enso.org"
},
+ "homepage": "https://github.com/enso-org/enso/tree/develop/app/gui",
+ "repository": {
+ "type": "git",
+ "url": "git@github.com:enso-org/enso.git"
+ },
+ "bugs": {
+ "url": "https://github.com/enso-org/enso/issues"
+ },
+ "//": {},
"scripts": {
- "dev": "echo DEPRECATED! Use `pnpm -w dev:gui` instead.",
- "dev:vite": "vite",
- "build": "corepack pnpm -r --filter enso-dashboard run compile && corepack pnpm run build:vite",
+ "typecheck": "vue-tsc --noEmit -p tsconfig.app.json",
+ "build": "vite build",
"build-cloud": "cross-env CLOUD_BUILD=true corepack pnpm run build",
"preview": "vite preview",
+ "lint": "cross-env eslint . --max-warnings=0",
+ "format": "prettier --version && prettier --write src/ && eslint . --fix",
+ "dev:vite": "vite",
"test": "corepack pnpm run /^^^^test:.*/",
"test:unit": "vitest run",
"test-dev:unit": "vitest",
- "test:e2e": "playwright test",
- "test-dev:e2e": "playwright test --ui",
- "story:dev": "histoire dev",
- "story:build": "histoire build",
- "story:preview": "histoire preview",
- "build:vite": "vite build",
- "typecheck": "vue-tsc --noEmit -p tsconfig.app.json",
- "lint": "eslint .",
- "format": "prettier --version && prettier --write src/ && eslint . --fix",
- "build-rust-ffi": "wasm-pack build ./rust-ffi --release --target web && wasm-pack build ./rust-ffi --out-dir node-pkg --target nodejs",
+ "test:e2e": "cross-env NODE_ENV=production playwright test",
+ "test-dev:e2e": "cross-env NODE_ENV=production playwright test --ui",
"preinstall": "corepack pnpm run generate-metadata && corepack pnpm run download-fonts",
"postinstall": "playwright install",
+ "build-rust-ffi": "wasm-pack build ./rust-ffi --release --target web && wasm-pack build ./rust-ffi --out-dir node-pkg --target nodejs",
"generate-metadata": "node scripts/generateIconMetadata.js",
"download-fonts": "node scripts/downloadFonts.js"
},
- "//": [
- "'ag-grid-community' is required as a peer dependency of 'ag-grid-enterprise'."
- ],
"dependencies": {
+ "@aws-amplify/auth": "5.6.5",
+ "@aws-amplify/core": "5.8.5",
+ "@hookform/resolvers": "^3.4.0",
+ "@internationalized/date": "^3.5.5",
+ "@monaco-editor/react": "4.6.0",
+ "@sentry/react": "^7.74.0",
+ "@react-aria/interactions": "^3.22.3",
+ "@stripe/react-stripe-js": "^2.7.1",
+ "@stripe/stripe-js": "^3.5.0",
+ "@tanstack/react-query": "5.55.0",
+ "@tanstack/vue-query": ">= 5.54.0 < 5.56.0",
+ "ajv": "^8.12.0",
+ "amazon-cognito-identity-js": "6.3.6",
+ "clsx": "^2.1.1",
+ "enso-common": "workspace:*",
+ "framer-motion": "11.3.0",
+ "input-otp": "1.2.4",
+ "is-network-error": "^1.0.1",
+ "monaco-editor": "0.48.0",
+ "qrcode.react": "3.1.0",
+ "react": "^18.3.1",
+ "react-aria": "^3.34.3",
+ "react-aria-components": "^1.3.3",
+ "react-dom": "^18.3.1",
+ "react-error-boundary": "4.0.13",
+ "react-hook-form": "^7.51.4",
+ "react-router": "^6.23.1",
+ "react-router-dom": "^6.23.1",
+ "react-stately": "^3.32.2",
+ "react-toastify": "^9.1.3",
+ "tailwind-merge": "^2.3.0",
+ "tailwind-variants": "0.2.1",
+ "tiny-invariant": "^1.3.3",
+ "ts-results": "^3.3.0",
+ "validator": "^13.12.0",
+ "zod": "^3.23.8",
+ "zustand": "^4.5.4",
"@ag-grid-community/client-side-row-model": "^31.1.1",
"@ag-grid-community/core": "^31.1.1",
"@ag-grid-community/styles": "^31.1.1",
@@ -61,7 +99,6 @@
"@lezer/common": "^1.1.0",
"@lezer/highlight": "^1.1.6",
"@noble/hashes": "^1.4.0",
- "@tanstack/vue-query": ">= 5.54.0 < 5.56.0",
"@vueuse/core": "^10.4.1",
"@vueuse/gesture": "^2.0.0",
"ag-grid-community": "^31.1.1",
@@ -69,7 +106,6 @@
"ag-grid-vue3": "^31.1.1",
"codemirror": "^6.0.1",
"culori": "^3.2.0",
- "enso-dashboard": "workspace:*",
"events": "^3.3.0",
"hash-sum": "^2.0.0",
"install": "^0.13.0",
@@ -80,7 +116,6 @@
"murmurhash": "^2.0.1",
"postcss-inline-svg": "^6.0.0",
"postcss-nesting": "^12.0.1",
- "react-toastify": "^9.1.3",
"sucrase": "^3.34.0",
"veaury": "^2.3.18",
"vue": "^3.5.2",
@@ -90,18 +125,38 @@
"y-textarea": "^1.0.0",
"y-websocket": "^1.5.0",
"ydoc-shared": "workspace:*",
- "yjs": "^13.6.7",
- "zod": "^3.23.8"
+ "yjs": "^13.6.7"
},
"devDependencies": {
+ "@fast-check/vitest": "^0.0.8",
+ "@modyfi/vite-plugin-yaml": "^1.0.4",
+ "@playwright/test": "^1.40.0",
+ "@react-types/shared": "^3.22.1",
+ "@tanstack/react-query-devtools": "5.45.1",
+ "@types/node": "^20.11.21",
+ "@types/react": "^18.0.27",
+ "@types/react-dom": "^18.0.10",
+ "@types/validator": "^13.11.7",
+ "@vitejs/plugin-react": "^4.2.1",
+ "chalk": "^5.3.0",
+ "cross-env": "^7.0.3",
+ "enso-chat": "git://github.com/enso-org/enso-bot",
+ "fast-check": "^3.15.0",
+ "playwright": "^1.39.0",
+ "postcss": "^8.4.29",
+ "prettier-plugin-organize-imports": "^4.0.0",
+ "prettier-plugin-tailwindcss": "^0.5.11",
+ "react-toastify": "^9.1.3",
+ "tailwindcss": "^3.4.1",
+ "tailwindcss-animate": "1.0.7",
+ "tailwindcss-react-aria-components": "^1.1.1",
+ "typescript": "^5.5.3",
+ "vite": "^5.3.5",
+ "vitest": "^1.3.1",
"@codemirror/theme-one-dark": "^6.1.2",
"@danmarshall/deckgl-typings": "^4.9.28",
- "@eslint/eslintrc": "^3.0.2",
- "@eslint/js": "^8.57.0",
"@histoire/plugin-vue": "^0.17.12",
"@open-rpc/server-js": "^1.9.4",
- "@playwright/test": "^1.40.0",
- "@rushstack/eslint-patch": "^1.3.2",
"@tsconfig/node20": "^20.1.4",
"@types/css.escape": "^1.5.2",
"@types/culori": "^2.0.1",
@@ -109,49 +164,40 @@
"@types/hash-sum": "^1.0.0",
"@types/jsdom": "^21.1.1",
"@types/mapbox-gl": "^2.7.13",
- "@types/node": "^20.11.21",
"@types/shuffle-seed": "^1.1.0",
"@types/tar": "^6.1.4",
"@types/unbzip2-stream": "^1.4.3",
"@types/wicg-file-system-access": "^2023.10.2",
"@types/ws": "^8.5.5",
- "@vitejs/plugin-react": "^4.0.4",
"@vitejs/plugin-vue": "^5.0.4",
"@vitest/coverage-v8": "^1.3.1",
- "@vue/eslint-config-prettier": "^9.0.0",
- "@vue/eslint-config-typescript": "^13.0.0",
"@vue/test-utils": "^2.4.6",
"@vue/tsconfig": "^0.5.1",
- "cross-env": "^7.0.3",
"css.escape": "^1.5.1",
"d3": "^7.4.0",
"enso-common": "workspace:*",
- "eslint": "^8.49.0",
- "eslint-plugin-vue": "^9.22.0",
"floating-vue": "^2.0.0-beta.24",
"hash-wasm": "^4.11.0",
"histoire": "^0.17.2",
"jsdom": "^24.1.0",
- "playwright": "^1.39.0",
"postcss-nesting": "^12.0.1",
"prettier": "^3.3.2",
- "prettier-plugin-organize-imports": "^4.0.0",
"react": "^18.3.1",
"react-dom": "^18.3.1",
"shuffle-seed": "^1.1.6",
"sql-formatter": "^13.0.0",
- "tailwindcss": "^3.2.7",
"tar": "^6.2.1",
"tsx": "^4.7.1",
- "typescript": "^5.5.3",
"unbzip2-stream": "^1.4.3",
- "vite": "^5.3.5",
"vite-plugin-vue-devtools": "7.3.7",
"vite-plugin-wasm": "^3.3.0",
- "vitest": "^1.3.1",
"vue-react-wrapper": "^0.3.1",
"vue-tsc": "^2.0.24",
"yaml": "^2.4.5",
"ydoc-server": "workspace:*"
+ },
+ "overrides": {
+ "@aws-amplify/auth": "../_IGNORED_",
+ "react-native-url-polyfill": "../_IGNORED_"
}
}
diff --git a/app/gui/playwright.config.ts b/app/gui/playwright.config.ts
new file mode 100644
index 00000000000..05ecc421c8f
--- /dev/null
+++ b/app/gui/playwright.config.ts
@@ -0,0 +1,146 @@
+/** @file Playwright browser testing configuration. */
+/**
+ * Note that running Playwright in CI poses a number of issues:
+ * - `backdrop-filter: blur` is disabled, due to issues with Chromium's `--disable-gpu` flag
+ * (see below).
+ * - System validation dialogs are not reliable between computers, as they may have different
+ * default fonts.
+ */
+import { defineConfig } from '@playwright/test'
+import net from 'net'
+
+const DEBUG = process.env.DEBUG_E2E === 'true'
+const TIMEOUT_MS = DEBUG ? 100_000_000 : 30_000
+
+async function findFreePortInRange(min: number, max: number) {
+ for (let i = 0; i < 50; i++) {
+ const portToCheck = Math.floor(Math.random() * (max - min + 1)) + min
+ if (await checkAvailablePort(portToCheck)) return portToCheck
+ }
+ throw new Error('Failed to find a free port.')
+}
+
+function checkAvailablePort(port: number) {
+ return new Promise((resolve, reject) => {
+ const server = net.createServer()
+ server
+ .unref()
+ .on('error', (e: any) => ('EADDRINUSE' === e.code ? resolve(false) : reject(e)))
+ .listen({ host: '0.0.0.0', port }, () => server.close(() => resolve(true)))
+ })
+}
+
+const portsFromEnv = {
+ projectView: parseInt(process.env.PLAYWRIGHT_PORT_PV ?? '', 10),
+ dashboard: parseInt(process.env.PLAYWRIGHT_PORT ?? '', 10),
+}
+const ports = {
+ projectView:
+ Number.isFinite(portsFromEnv.projectView) ?
+ portsFromEnv.projectView
+ : await findFreePortInRange(4300, 4999),
+ dashboard:
+ Number.isFinite(portsFromEnv.dashboard) ?
+ portsFromEnv.dashboard
+ : await findFreePortInRange(4300, 4999),
+}
+console.log(`Selected playwright servers' ports: ${ports.projectView} and ${ports.dashboard}`)
+// Make sure to set the env to actual port that is being used. This is necessary for workers to
+// pick up the same configuration.
+process.env.PLAYWRIGHT_PORT = `${ports.dashboard}`
+process.env.PLAYWRIGHT_PORT_PV = `${ports.projectView}`
+
+export default defineConfig({
+ fullyParallel: true,
+ forbidOnly: !!process.env.CI,
+ repeatEach: process.env.CI ? 3 : 1,
+ reporter: 'html',
+ use: {
+ headless: !DEBUG,
+ actionTimeout: 5000,
+ trace: 'retain-on-failure',
+ ...(DEBUG ?
+ {}
+ : {
+ launchOptions: {
+ ignoreDefaultArgs: ['--headless'],
+ args: [
+ // Much closer to headful Chromium than classic headless.
+ '--headless=new',
+ // Required for `backdrop-filter: blur` to work.
+ '--use-angle=swiftshader',
+ // FIXME: `--disable-gpu` disables `backdrop-filter: blur`, which is not handled by
+ // the software (CPU) compositor. This SHOULD be fixed eventually, but this flag
+ // MUST stay as CI does not have a GPU.
+ '--disable-gpu',
+ // Fully disable GPU process.
+ '--disable-software-rasterizer',
+ // Disable text subpixel antialiasing.
+ '--font-render-hinting=none',
+ '--disable-skia-runtime-opts',
+ '--disable-system-font-check',
+ '--disable-font-subpixel-positioning',
+ '--disable-lcd-text',
+ ],
+ },
+ }),
+ },
+ projects: [
+ {
+ name: 'Dashboard',
+ testDir: './e2e/dashboard',
+ expect: {
+ toHaveScreenshot: { threshold: 0 },
+ timeout: TIMEOUT_MS,
+ },
+ timeout: TIMEOUT_MS,
+ use: {
+ baseURL: `http://localhost:${ports.dashboard}`,
+ actionTimeout: TIMEOUT_MS,
+ },
+ },
+ {
+ name: 'Setup Tests for Project View',
+ testMatch: /e2e\/project-view\/setup\.ts/,
+ },
+ {
+ name: 'Project View',
+ dependencies: ['Setup Tests for Project View'],
+ testDir: './e2e/project-view',
+ timeout: 60000,
+ expect: {
+ timeout: 5000,
+ toHaveScreenshot: { threshold: 0 },
+ },
+ use: {
+ viewport: { width: 1920, height: 1750 },
+ baseURL: `http://localhost:${ports.projectView}`,
+ },
+ },
+ ],
+ webServer: [
+ {
+ env: {
+ E2E: 'true',
+ },
+ command:
+ process.env.CI || process.env.PROD ?
+ `corepack pnpm build && corepack pnpm exec vite preview --port ${ports.projectView} --strictPort`
+ : `corepack pnpm exec vite dev --port ${ports.projectView}`,
+ // Build from scratch apparently can take a while on CI machines.
+ timeout: 240 * 1000,
+ port: ports.projectView,
+ // We use our special, mocked version of server, thus do not want to re-use user's one.
+ reuseExistingServer: false,
+ },
+ {
+ command:
+ process.env.CI || process.env.PROD ?
+ `corepack pnpm exec vite -c vite.test.config.ts build && vite -c vite.test.config.ts preview --port ${ports.dashboard} --strictPort`
+ : `corepack pnpm exec vite -c vite.test.config.ts --port ${ports.dashboard}`,
+ timeout: 240 * 1000,
+ port: ports.dashboard,
+ reuseExistingServer: false,
+ },
+ ],
+})
diff --git a/app/gui2/project-manager-shim-middleware/desktopEnvironment.ts b/app/gui/project-manager-shim-middleware/desktopEnvironment.ts
similarity index 100%
rename from app/gui2/project-manager-shim-middleware/desktopEnvironment.ts
rename to app/gui/project-manager-shim-middleware/desktopEnvironment.ts
diff --git a/app/gui2/project-manager-shim-middleware/index.ts b/app/gui/project-manager-shim-middleware/index.ts
similarity index 100%
rename from app/gui2/project-manager-shim-middleware/index.ts
rename to app/gui/project-manager-shim-middleware/index.ts
diff --git a/app/gui2/project-manager-shim-middleware/projectManagement.ts b/app/gui/project-manager-shim-middleware/projectManagement.ts
similarity index 100%
rename from app/gui2/project-manager-shim-middleware/projectManagement.ts
rename to app/gui/project-manager-shim-middleware/projectManagement.ts
diff --git a/app/gui2/public/apple-touch-icon.png b/app/gui/public/apple-touch-icon.png
similarity index 100%
rename from app/gui2/public/apple-touch-icon.png
rename to app/gui/public/apple-touch-icon.png
diff --git a/app/gui2/public/favicon-16x16.png b/app/gui/public/favicon-16x16.png
similarity index 100%
rename from app/gui2/public/favicon-16x16.png
rename to app/gui/public/favicon-16x16.png
diff --git a/app/gui2/public/favicon-32x32.png b/app/gui/public/favicon-32x32.png
similarity index 100%
rename from app/gui2/public/favicon-32x32.png
rename to app/gui/public/favicon-32x32.png
diff --git a/app/gui2/public/favicon.ico b/app/gui/public/favicon.ico
similarity index 100%
rename from app/gui2/public/favicon.ico
rename to app/gui/public/favicon.ico
diff --git a/app/gui/public/font-dejavu/DejaVuSansMono-Bold.ttf b/app/gui/public/font-dejavu/DejaVuSansMono-Bold.ttf
new file mode 100644
index 00000000000..9cb0a5e795d
Binary files /dev/null and b/app/gui/public/font-dejavu/DejaVuSansMono-Bold.ttf differ
diff --git a/app/gui/public/font-dejavu/DejaVuSansMono.ttf b/app/gui/public/font-dejavu/DejaVuSansMono.ttf
new file mode 100644
index 00000000000..f5786022f18
Binary files /dev/null and b/app/gui/public/font-dejavu/DejaVuSansMono.ttf differ
diff --git a/app/gui2/public/font-enso-naming/Enso-Naming-Black.woff2 b/app/gui/public/font-enso-naming/Enso-Naming-Black.woff2
similarity index 100%
rename from app/gui2/public/font-enso-naming/Enso-Naming-Black.woff2
rename to app/gui/public/font-enso-naming/Enso-Naming-Black.woff2
diff --git a/app/gui2/public/font-enso-naming/Enso-Naming-Bold.woff2 b/app/gui/public/font-enso-naming/Enso-Naming-Bold.woff2
similarity index 100%
rename from app/gui2/public/font-enso-naming/Enso-Naming-Bold.woff2
rename to app/gui/public/font-enso-naming/Enso-Naming-Bold.woff2
diff --git a/app/gui2/public/font-enso-naming/Enso-Naming-ExtraBold.woff2 b/app/gui/public/font-enso-naming/Enso-Naming-ExtraBold.woff2
similarity index 100%
rename from app/gui2/public/font-enso-naming/Enso-Naming-ExtraBold.woff2
rename to app/gui/public/font-enso-naming/Enso-Naming-ExtraBold.woff2
diff --git a/app/gui2/public/font-enso-naming/Enso-Naming-ExtraLight.woff2 b/app/gui/public/font-enso-naming/Enso-Naming-ExtraLight.woff2
similarity index 100%
rename from app/gui2/public/font-enso-naming/Enso-Naming-ExtraLight.woff2
rename to app/gui/public/font-enso-naming/Enso-Naming-ExtraLight.woff2
diff --git a/app/gui2/public/font-enso-naming/Enso-Naming-Light.woff2 b/app/gui/public/font-enso-naming/Enso-Naming-Light.woff2
similarity index 100%
rename from app/gui2/public/font-enso-naming/Enso-Naming-Light.woff2
rename to app/gui/public/font-enso-naming/Enso-Naming-Light.woff2
diff --git a/app/gui2/public/font-enso-naming/Enso-Naming-Medium.woff2 b/app/gui/public/font-enso-naming/Enso-Naming-Medium.woff2
similarity index 100%
rename from app/gui2/public/font-enso-naming/Enso-Naming-Medium.woff2
rename to app/gui/public/font-enso-naming/Enso-Naming-Medium.woff2
diff --git a/app/gui2/public/font-enso-naming/Enso-Naming-Regular.woff2 b/app/gui/public/font-enso-naming/Enso-Naming-Regular.woff2
similarity index 100%
rename from app/gui2/public/font-enso-naming/Enso-Naming-Regular.woff2
rename to app/gui/public/font-enso-naming/Enso-Naming-Regular.woff2
diff --git a/app/gui2/public/font-enso-naming/Enso-Naming-SemiBold.woff2 b/app/gui/public/font-enso-naming/Enso-Naming-SemiBold.woff2
similarity index 100%
rename from app/gui2/public/font-enso-naming/Enso-Naming-SemiBold.woff2
rename to app/gui/public/font-enso-naming/Enso-Naming-SemiBold.woff2
diff --git a/app/gui2/public/font-enso-naming/Enso-Naming-Thin.woff2 b/app/gui/public/font-enso-naming/Enso-Naming-Thin.woff2
similarity index 100%
rename from app/gui2/public/font-enso-naming/Enso-Naming-Thin.woff2
rename to app/gui/public/font-enso-naming/Enso-Naming-Thin.woff2
diff --git a/app/gui2/public/font-enso-prose/Enso-Prose-Black.woff2 b/app/gui/public/font-enso-prose/Enso-Prose-Black.woff2
similarity index 100%
rename from app/gui2/public/font-enso-prose/Enso-Prose-Black.woff2
rename to app/gui/public/font-enso-prose/Enso-Prose-Black.woff2
diff --git a/app/gui2/public/font-enso-prose/Enso-Prose-Bold.woff2 b/app/gui/public/font-enso-prose/Enso-Prose-Bold.woff2
similarity index 100%
rename from app/gui2/public/font-enso-prose/Enso-Prose-Bold.woff2
rename to app/gui/public/font-enso-prose/Enso-Prose-Bold.woff2
diff --git a/app/gui2/public/font-enso-prose/Enso-Prose-ExtraBold.woff2 b/app/gui/public/font-enso-prose/Enso-Prose-ExtraBold.woff2
similarity index 100%
rename from app/gui2/public/font-enso-prose/Enso-Prose-ExtraBold.woff2
rename to app/gui/public/font-enso-prose/Enso-Prose-ExtraBold.woff2
diff --git a/app/gui2/public/font-enso-prose/Enso-Prose-ExtraLight.woff2 b/app/gui/public/font-enso-prose/Enso-Prose-ExtraLight.woff2
similarity index 100%
rename from app/gui2/public/font-enso-prose/Enso-Prose-ExtraLight.woff2
rename to app/gui/public/font-enso-prose/Enso-Prose-ExtraLight.woff2
diff --git a/app/gui2/public/font-enso-prose/Enso-Prose-Light.woff2 b/app/gui/public/font-enso-prose/Enso-Prose-Light.woff2
similarity index 100%
rename from app/gui2/public/font-enso-prose/Enso-Prose-Light.woff2
rename to app/gui/public/font-enso-prose/Enso-Prose-Light.woff2
diff --git a/app/gui2/public/font-enso-prose/Enso-Prose-Medium.woff2 b/app/gui/public/font-enso-prose/Enso-Prose-Medium.woff2
similarity index 100%
rename from app/gui2/public/font-enso-prose/Enso-Prose-Medium.woff2
rename to app/gui/public/font-enso-prose/Enso-Prose-Medium.woff2
diff --git a/app/gui2/public/font-enso-prose/Enso-Prose-Regular.woff2 b/app/gui/public/font-enso-prose/Enso-Prose-Regular.woff2
similarity index 100%
rename from app/gui2/public/font-enso-prose/Enso-Prose-Regular.woff2
rename to app/gui/public/font-enso-prose/Enso-Prose-Regular.woff2
diff --git a/app/gui2/public/font-enso-prose/Enso-Prose-SemiBold.woff2 b/app/gui/public/font-enso-prose/Enso-Prose-SemiBold.woff2
similarity index 100%
rename from app/gui2/public/font-enso-prose/Enso-Prose-SemiBold.woff2
rename to app/gui/public/font-enso-prose/Enso-Prose-SemiBold.woff2
diff --git a/app/gui2/public/font-enso-prose/Enso-Prose-Thin.woff2 b/app/gui/public/font-enso-prose/Enso-Prose-Thin.woff2
similarity index 100%
rename from app/gui2/public/font-enso-prose/Enso-Prose-Thin.woff2
rename to app/gui/public/font-enso-prose/Enso-Prose-Thin.woff2
diff --git a/app/gui/public/font-enso/Enso-Black.ttf b/app/gui/public/font-enso/Enso-Black.ttf
new file mode 100644
index 00000000000..946e6824d4d
Binary files /dev/null and b/app/gui/public/font-enso/Enso-Black.ttf differ
diff --git a/app/gui/public/font-enso/Enso-Bold.ttf b/app/gui/public/font-enso/Enso-Bold.ttf
new file mode 100644
index 00000000000..1a5e9f6ff0b
Binary files /dev/null and b/app/gui/public/font-enso/Enso-Bold.ttf differ
diff --git a/app/gui/public/font-enso/Enso-ExtraBold.ttf b/app/gui/public/font-enso/Enso-ExtraBold.ttf
new file mode 100644
index 00000000000..51107a45125
Binary files /dev/null and b/app/gui/public/font-enso/Enso-ExtraBold.ttf differ
diff --git a/app/gui/public/font-enso/Enso-ExtraLight.ttf b/app/gui/public/font-enso/Enso-ExtraLight.ttf
new file mode 100644
index 00000000000..35d59be0eae
Binary files /dev/null and b/app/gui/public/font-enso/Enso-ExtraLight.ttf differ
diff --git a/app/gui/public/font-enso/Enso-Light.ttf b/app/gui/public/font-enso/Enso-Light.ttf
new file mode 100644
index 00000000000..f51360844e3
Binary files /dev/null and b/app/gui/public/font-enso/Enso-Light.ttf differ
diff --git a/app/gui/public/font-enso/Enso-Medium.ttf b/app/gui/public/font-enso/Enso-Medium.ttf
new file mode 100644
index 00000000000..07105f9690e
Binary files /dev/null and b/app/gui/public/font-enso/Enso-Medium.ttf differ
diff --git a/app/gui/public/font-enso/Enso-Regular.ttf b/app/gui/public/font-enso/Enso-Regular.ttf
new file mode 100644
index 00000000000..a119c7157a8
Binary files /dev/null and b/app/gui/public/font-enso/Enso-Regular.ttf differ
diff --git a/app/gui/public/font-enso/Enso-SemiBold.ttf b/app/gui/public/font-enso/Enso-SemiBold.ttf
new file mode 100644
index 00000000000..39f107e87c6
Binary files /dev/null and b/app/gui/public/font-enso/Enso-SemiBold.ttf differ
diff --git a/app/gui/public/font-enso/Enso-Thin.ttf b/app/gui/public/font-enso/Enso-Thin.ttf
new file mode 100644
index 00000000000..9bba8fa37cd
Binary files /dev/null and b/app/gui/public/font-enso/Enso-Thin.ttf differ
diff --git a/app/gui/public/font-mplus1/MPLUS1[wght].ttf b/app/gui/public/font-mplus1/MPLUS1[wght].ttf
new file mode 100644
index 00000000000..078795d27fe
Binary files /dev/null and b/app/gui/public/font-mplus1/MPLUS1[wght].ttf differ
diff --git a/app/gui2/scripts/downloadFonts.js b/app/gui/scripts/downloadFonts.js
similarity index 93%
rename from app/gui2/scripts/downloadFonts.js
rename to app/gui/scripts/downloadFonts.js
index f2108073bc3..da1eaf88a6d 100644
--- a/app/gui2/scripts/downloadFonts.js
+++ b/app/gui/scripts/downloadFonts.js
@@ -90,7 +90,7 @@ const DEJAVU_FONT_VARIANTS = [
].map((variant) => ({ font: 'DejaVu Sans Mono', ...variant }))
try {
- await fs.access(`./src/assets/font-enso.css`)
+ await fs.access(`./src/project-view/assets/font-enso.css`)
for (const { variant } of ENSO_FONT_VARIANTS) {
await fs.access(`./public/font-enso/Enso-${variant}.ttf`)
}
@@ -133,11 +133,11 @@ try {
}
`)
}
- await fs.writeFile('./src/assets/font-enso.css', css.join('\n'))
+ await fs.writeFile('./src/project-view/assets/font-enso.css', css.join('\n'))
}
}
try {
- await fs.access(`./src/assets/font-mplus1.css`)
+ await fs.access(`./src/project-view/assets/font-mplus1.css`)
await fs.access(`./public/font-mplus1/MPLUS1[wght].ttf`)
console.info('M PLUS 1 font already downloaded, skipping...')
} catch (error) {
@@ -164,11 +164,11 @@ try {
src: url('/font-mplus1/MPLUS1[wght].ttf');
}
`
- await fs.writeFile('./src/assets/font-mplus1.css', css)
+ await fs.writeFile('./src/project-view/assets/font-mplus1.css', css)
}
}
try {
- await fs.access(`./src/assets/font-dejavu.css`)
+ await fs.access(`./src/project-view/assets/font-dejavu.css`)
for (const variant of ['', '-Bold']) {
await fs.access(`./public/font-dejavu/DejaVuSansMono${variant}.ttf`)
}
@@ -210,8 +210,8 @@ try {
}
`)
}
- await fs.writeFile('./src/assets/font-dejavu.css', css.join('\n'))
+ await fs.writeFile('./src/project-view/assets/font-dejavu.css', css.join('\n'))
}
}
console.info('Done.')
-if (exitCode !== 0) process.exit(exitCode)
+process.exit(exitCode)
diff --git a/app/gui2/scripts/generateIconMetadata.js b/app/gui/scripts/generateIconMetadata.js
similarity index 61%
rename from app/gui2/scripts/generateIconMetadata.js
rename to app/gui/scripts/generateIconMetadata.js
index b358110a04a..377f1e6743c 100644
--- a/app/gui2/scripts/generateIconMetadata.js
+++ b/app/gui/scripts/generateIconMetadata.js
@@ -1,15 +1,18 @@
import * as fs from 'node:fs/promises'
-console.info('Reading icons from "./src/assets/icons.svg"...')
-const icons = await fs.readFile('./src/assets/icons.svg', { encoding: 'utf-8' })
+console.info('Reading icons from "./src/project-view/assets/icons.svg"...')
+const icons = await fs.readFile('./src/project-view/assets/icons.svg', { encoding: 'utf-8' })
const iconNames = icons.match(/(?<= {
const date = Math.floor(Number(new Date()) / SEC_MS)
const expirationDate = date + TEN_HOURS_S
if (!this.isSignedIn) {
- // eslint-disable-next-line @typescript-eslint/no-throw-literal
+ // The error MUST be a string to match AWS Amplify's behavior.
+ // eslint-disable-next-line @typescript-eslint/only-throw-error
throw 'No current user'
} else {
return Promise.resolve({
@@ -129,7 +134,7 @@ export class Cognito {
getJwtToken: () =>
`.${window.btoa(
JSON.stringify({
- /* eslint-disable @typescript-eslint/naming-convention */
+ /* eslint-disable @typescript-eslint/naming-convention, camelcase */
sub: '62bdf414-c47f-4c76-a333-c564f841c256',
iss: 'https://cognito-idp.eu-west-1.amazonaws.com/eu-west-1_9Kycu2SbD',
client_id: '4j9bfs8e7415erf82l129v0qhe',
@@ -142,7 +147,7 @@ export class Cognito {
iat: date,
jti: '5ab178b7-97a6-4956-8913-1cffee4a0da1',
username: mockEmail,
- /* eslint-enable @typescript-eslint/naming-convention */
+ /* eslint-enable @typescript-eslint/naming-convention, camelcase */
}),
)}.`,
}),
@@ -153,15 +158,19 @@ export class Cognito {
return amplifySession.map(parseUserSession).unwrapOr(null)
}
- /** Returns the associated organization ID of the current user, which is passed during signup,
- * or `null` if the user is not associated with an existing organization. */
+ /**
+ * Returns the associated organization ID of the current user, which is passed during signup,
+ * or `null` if the user is not associated with an existing organization.
+ */
async organizationId() {
return Promise.resolve(mockOrganizationId)
}
- /** Sign up with username and password.
+ /**
+ * Sign up with username and password.
*
- * Does not rely on federated identity providers (e.g., Google or GitHub). */
+ * Does not rely on federated identity providers (e.g., Google or GitHub).
+ */
signUp(username: string, password: string, organizationId: string | null) {
mockOrganizationId = organizationId
if (organizationId != null) {
@@ -172,34 +181,40 @@ export class Cognito {
return signUp(this.supportsDeepLinks, username, password, organizationId)
}
- /** Send the email address verification code.
+ /**
+ * Send the email address verification code.
*
* The user will receive a link in their email. The user must click the link to go to the email
* verification page. The email verification page will parse the verification code from the URL.
* If the verification code matches, the email address is marked as verified. Once the email
- * address is verified, the user can sign in. */
+ * address is verified, the user can sign in.
+ */
confirmSignUp(email: string, code: string) {
mockEmail = email
localStorage.setItem(MOCK_EMAIL_KEY, email)
return confirmSignUp(email, code)
}
- /** Sign in via the Google federated identity provider.
+ /**
+ * Sign in via the Google federated identity provider.
*
* This function will open the Google authentication page in the user's browser. The user will
* be asked to log in to their Google account, and then to grant access to the application.
- * After the user has granted access, the browser will be redirected to the application. */
+ * After the user has granted access, the browser will be redirected to the application.
+ */
async signInWithGoogle() {
this.isSignedIn = true
listen.authEventListener?.(listen.AuthEvent.signIn)
await Promise.resolve()
}
- /** Sign in via the GitHub federated identity provider.
+ /**
+ * Sign in via the GitHub federated identity provider.
*
* This function will open the GitHub authentication page in the user's browser. The user will
* be asked to log in to their GitHub account, and then to grant access to the application.
- * After the user has granted access, the browser will be redirected to the application. */
+ * After the user has granted access, the browser will be redirected to the application.
+ */
signInWithGitHub() {
this.isSignedIn = true
listen.authEventListener?.(listen.AuthEvent.signIn)
@@ -213,9 +228,11 @@ export class Cognito {
})
}
- /** Sign in with the given username and password.
+ /**
+ * Sign in with the given username and password.
*
- * Does not rely on external identity providers (e.g., Google or GitHub). */
+ * Does not rely on external identity providers (e.g., Google or GitHub).
+ */
async signInWithPassword(username: string, _password: string) {
this.isSignedIn = true
mockEmail = username
@@ -236,11 +253,13 @@ export class Cognito {
return Promise.resolve(null)
}
- /** Send a password reset email.
+ /**
+ * Send a password reset email.
*
* The user will be able to reset their password by following the link in the email, which takes
* them to the "reset password" page of the application. The verification code will be filled in
- * automatically. */
+ * automatically.
+ */
async forgotPassword(_email: string) {
const result = await results.Result.wrapAsync(async () => {
// Ignored.
@@ -250,11 +269,13 @@ export class Cognito {
.mapErr(original.intoForgotPasswordErrorOrThrow)
}
- /** Submit a new password for the given email address.
+ /**
+ * Submit a new password for the given email address.
*
* The user will have received a verification code in an email, which they will have entered on
* the "reset password" page of the application. This function will submit the new password
- * along with the verification code, changing the user's password. */
+ * along with the verification code, changing the user's password.
+ */
async forgotPasswordSubmit(_email: string, _code: string, _password: string) {
const result = await results.Result.wrapAsync(async () => {
// Ignored.
@@ -262,12 +283,14 @@ export class Cognito {
return result.mapErr(original.intoForgotPasswordSubmitErrorOrThrow)
}
- /** Change a password for current authenticated user.
+ /**
+ * Change a password for current authenticated user.
*
* Allow users to independently modify their passwords. The user needs to provide the old
* password, new password, and repeat new password to change their old password to the new
* one. The validation of the repeated new password is handled by the `changePasswordModel`
- * component. */
+ * component.
+ */
async changePassword(oldPassword: string, newPassword: string) {
const cognitoUserResult = await currentAuthenticatedUser()
if (cognitoUserResult.ok) {
@@ -304,13 +327,15 @@ export class Cognito {
/** User's session, provides information for identifying and authenticating the user. */
export interface UserSession {
- /** User's email address, used to uniquely identify the user.
+ /**
+ * User's email address, used to uniquely identify the user.
*
* Provided by the identity provider the user used to log in. One of:
*
* - GitHub,
* - Google, or
- * - Email. */
+ * - Email.
+ */
readonly email: string
/** User's access token, used to authenticate the user (e.g., when making API calls). */
readonly accessToken: string
@@ -318,8 +343,10 @@ export interface UserSession {
readonly clientId?: string
}
-/** Parse a {@link cognito.CognitoUserSession} into a {@link UserSession}.
- * @throws If the `email` field of the payload is not a string. */
+/**
+ * Parse a {@link cognito.CognitoUserSession} into a {@link UserSession}.
+ * @throws If the `email` field of the payload is not a string.
+ */
function parseUserSession(session: cognito.CognitoUserSession): UserSession {
const payload: Readonly> = session.getIdToken().payload
const email = payload.email
@@ -336,8 +363,10 @@ function parseUserSession(session: cognito.CognitoUserSession): UserSession {
// === SignUp ===
// ==============
-/** A wrapper around the Amplify "sign up" endpoint that converts known errors
- * to `SignUpError`s. */
+/**
+ * A wrapper around the Amplify "sign up" endpoint that converts known errors
+ * to `SignUpError`s.
+ */
async function signUp(
_supportsDeepLinks: boolean,
_username: string,
@@ -354,8 +383,10 @@ async function signUp(
// === ConfirmSignUp ===
// =====================
-/** A wrapper around the Amplify "confirm sign up" endpoint that converts known errors
- * to `ConfirmSignUpError`s. */
+/**
+ * A wrapper around the Amplify "confirm sign up" endpoint that converts known errors
+ * to `ConfirmSignUpError`s.
+ */
async function confirmSignUp(_email: string, _code: string) {
return results.Result.wrapAsync(async () => {
// Ignored.
@@ -368,8 +399,10 @@ async function confirmSignUp(_email: string, _code: string) {
// === ChangePassword ===
// ======================
-/** A wrapper around the Amplify "current authenticated user" endpoint that converts known errors
- * to `AmplifyError`s. */
+/**
+ * A wrapper around the Amplify "current authenticated user" endpoint that converts known errors
+ * to `AmplifyError`s.
+ */
async function currentAuthenticatedUser() {
const result = await results.Result.wrapAsync(
// The methods are not needed.
diff --git a/app/dashboard/src/authentication/cognito.ts b/app/gui/src/dashboard/authentication/cognito.ts
similarity index 88%
rename from app/dashboard/src/authentication/cognito.ts
rename to app/gui/src/dashboard/authentication/cognito.ts
index 595c6355e1d..0983b88507f 100644
--- a/app/dashboard/src/authentication/cognito.ts
+++ b/app/gui/src/dashboard/authentication/cognito.ts
@@ -1,4 +1,5 @@
-/** @file Provides {@link Cognito} class which is the entrypoint into the AWS Amplify library.
+/**
+ * @file Provides {@link Cognito} class which is the entrypoint into the AWS Amplify library.
*
* All of the functions used for authentication are provided by the AWS Amplify library, but we
* provide a thin wrapper around them to make them easier to use. Mainly, we perform some error
@@ -28,7 +29,8 @@
*
* Amplify reuses some codes for multiple kinds of errors. In the case of ambiguous errors, the
* `kind` field provides a unique string that can be used to brand the error in place of the
- * `internalCode`, when rethrowing the error. */
+ * `internalCode`, when rethrowing the error.
+ */
import * as amplify from '@aws-amplify/auth'
import * as cognito from 'amazon-cognito-identity-js'
import * as results from 'ts-results'
@@ -37,8 +39,8 @@ import * as detect from 'enso-common/src/detect'
import type * as loggerProvider from '#/providers/LoggerProvider'
-import type * as saveAccessToken from '#/utilities/accessToken'
import * as dateTime from '#/utilities/dateTime'
+import type * as saveAccessToken from 'enso-common/src/accessToken'
import * as service from '#/authentication/service'
@@ -46,10 +48,12 @@ import * as service from '#/authentication/service'
// === Constants ===
// =================
-/** String used to identify the GitHub federated identity provider in AWS Amplify.
+/**
+ * String used to identify the GitHub federated identity provider in AWS Amplify.
*
* This provider alone requires a string because it is not a standard provider, and thus has no
- * constant defined in the AWS Amplify library. */
+ * constant defined in the AWS Amplify library.
+ */
const GITHUB_PROVIDER = 'Github'
/** One second, in milliseconds. */
const SEC_MS = 1_000
@@ -95,7 +99,8 @@ interface UserInfo {
// === AmplifyError ===
// ====================
-/** Error thrown by the AWS Amplify library when an Amplify error occurs.
+/**
+ * Error thrown by the AWS Amplify library when an Amplify error occurs.
*
* Some Amplify errors (e.g., network connectivity errors) can not be resolved within the
* application. Un-resolvable errors are allowed to flow up to the top-level error handler. Errors
@@ -107,7 +112,8 @@ interface UserInfo {
* {@link AmplifyError}. If it is, use the {@link intoAmplifyErrorOrThrow} function to convert it
* from `unknown` to a typed object. Then, use one of the response error handling functions (e.g.
* {@link intoSignUpErrorOrThrow}) to see if the error is one that must be handled by the
- * application (i.e., it is an error that is relevant to our business logic). */
+ * application (i.e., it is an error that is relevant to our business logic).
+ */
export interface AmplifyError extends Error {
/** Error code for disambiguating the error. */
readonly code: string
@@ -122,9 +128,11 @@ function isAmplifyError(error: unknown): error is AmplifyError {
}
}
-/** Convert the `unknown` error into an {@link AmplifyError} and returns it, or re-throws it if
+/**
+ * Convert the `unknown` error into an {@link AmplifyError} and returns it, or re-throws it if
* conversion is not possible.
- * @throws If the error is not an amplify error. */
+ * @throws If the error is not an amplify error.
+ */
export function intoAmplifyErrorOrThrow(error: unknown): AmplifyError {
if (isAmplifyError(error)) {
return error
@@ -171,8 +179,10 @@ export enum CognitoErrorType {
noCurrentUser = 'NoCurrentUser',
}
-/** Base interface for all errors output from this module.
- * Every user-facing error MUST extend this interface. */
+/**
+ * Base interface for all errors output from this module.
+ * Every user-facing error MUST extend this interface.
+ */
interface CognitoError {
readonly type: CognitoErrorType
readonly message: string
@@ -182,9 +192,11 @@ interface CognitoError {
// === Cognito ===
// ===============
-/** Thin wrapper around Cognito endpoints from the AWS Amplify library with error handling added.
+/**
+ * Thin wrapper around Cognito endpoints from the AWS Amplify library with error handling added.
* This way, the methods don't throw all errors, but define exactly which errors they return.
- * The caller can then handle them via pattern matching on the {@link results.Result} type. */
+ * The caller can then handle them via pattern matching on the {@link results.Result} type.
+ */
export class Cognito {
/** Create a new Cognito wrapper. */
constructor(
@@ -192,10 +204,12 @@ export class Cognito {
private readonly supportsDeepLinks: boolean,
private readonly amplifyConfig: service.AmplifyConfig,
) {
- /** Amplify expects `Auth.configure` to be called before any other `Auth` methods are
+ /**
+ * Amplify expects `Auth.configure` to be called before any other `Auth` methods are
* called. By wrapping all the `Auth` methods we care about and returning an `Cognito` API
* object containing them, we ensure that `Auth.configure` is called before any other `Auth`
- * methods are called. */
+ * methods are called.
+ */
const nestedAmplifyConfig = service.toNestedAmplifyConfig(amplifyConfig)
amplify.Auth.configure(nestedAmplifyConfig)
}
@@ -205,9 +219,11 @@ export class Cognito {
this.amplifyConfig.saveAccessToken?.(accessTokenPayload)
}
- /** Return the current {@link UserSession}, or `None` if the user is not logged in.
+ /**
+ * Return the current {@link UserSession}, or `None` if the user is not logged in.
*
- * Will refresh the {@link UserSession} if it has expired. */
+ * Will refresh the {@link UserSession} if it has expired.
+ */
async userSession() {
const currentSession = await results.Result.wrapAsync(() => amplify.Auth.currentSession())
const amplifySession = currentSession.mapErr(intoCurrentSessionErrorType)
@@ -217,8 +233,10 @@ export class Cognito {
.unwrapOr(null)
}
- /** Returns the associated organization ID of the current user, which is passed during signup,
- * or `null` if the user is not associated with an existing organization. */
+ /**
+ * Returns the associated organization ID of the current user, which is passed during signup,
+ * or `null` if the user is not associated with an existing organization.
+ */
async organizationId() {
// This `any` comes from a third-party API and cannot be avoided.
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
@@ -236,9 +254,11 @@ export class Cognito {
return userInfo.attributes.email
}
- /** Sign up with username and password.
+ /**
+ * Sign up with username and password.
*
- * Does not rely on federated identity providers (e.g., Google or GitHub). */
+ * Does not rely on federated identity providers (e.g., Google or GitHub).
+ */
async signUp(username: string, password: string, organizationId: string | null) {
const result = await results.Result.wrapAsync(async () => {
const params = intoSignUpParams(this.supportsDeepLinks, username, password, organizationId)
@@ -247,12 +267,14 @@ export class Cognito {
return result.mapErr(intoAmplifyErrorOrThrow).mapErr(intoSignUpErrorOrThrow)
}
- /** Send the email address verification code.
+ /**
+ * Send the email address verification code.
*
* The user will receive a link in their email. The user must click the link to go to the email
* verification page. The email verification page will parse the verification code from the URL.
* If the verification code matches, the email address is marked as verified. Once the email
- * address is verified, the user can sign in. */
+ * address is verified, the user can sign in.
+ */
async confirmSignUp(email: string, code: string) {
const result = await results.Result.wrapAsync(async () => {
await amplify.Auth.confirmSignUp(email, code)
@@ -260,11 +282,13 @@ export class Cognito {
return result.mapErr(intoAmplifyErrorOrThrow).mapErr(intoConfirmSignUpErrorOrThrow)
}
- /** Sign in via the Google federated identity provider.
+ /**
+ * Sign in via the Google federated identity provider.
*
* This function will open the Google authentication page in the user's browser. The user will
* be asked to log in to their Google account, and then to grant access to the application.
- * After the user has granted access, the browser will be redirected to the application. */
+ * After the user has granted access, the browser will be redirected to the application.
+ */
async signInWithGoogle() {
const customState = this.customState()
const provider = amplify.CognitoHostedUIIdentityProvider.Google
@@ -274,20 +298,24 @@ export class Cognito {
})
}
- /** Sign in via the GitHub federated identity provider.
+ /**
+ * Sign in via the GitHub federated identity provider.
*
* This function will open the GitHub authentication page in the user's browser. The user will
* be asked to log in to their GitHub account, and then to grant access to the application.
- * After the user has granted access, the browser will be redirected to the application. */
+ * After the user has granted access, the browser will be redirected to the application.
+ */
async signInWithGitHub() {
await amplify.Auth.federatedSignIn({
customProvider: GITHUB_PROVIDER,
})
}
- /** Sign in with the given username and password.
+ /**
+ * Sign in with the given username and password.
*
- * Does not rely on external identity providers (e.g., Google or GitHub). */
+ * Does not rely on external identity providers (e.g., Google or GitHub).
+ */
async signInWithPassword(username: string, password: string) {
const result = await results.Result.wrapAsync(async () => {
// This `any` comes from a third-party API and cannot be avoided.
@@ -355,11 +383,13 @@ export class Cognito {
}
}
- /** Send a password reset email.
+ /**
+ * Send a password reset email.
*
* The user will be able to reset their password by following the link in the email, which takes
* them to the "reset password" page of the application. The verification code will be filled in
- * automatically. */
+ * automatically.
+ */
async forgotPassword(email: string) {
const result = await results.Result.wrapAsync(async () => {
await amplify.Auth.forgotPassword(email)
@@ -367,11 +397,13 @@ export class Cognito {
return result.mapErr(intoAmplifyErrorOrThrow).mapErr(intoForgotPasswordErrorOrThrow)
}
- /** Submit a new password for the given email address.
+ /**
+ * Submit a new password for the given email address.
*
* The user will have received a verification code in an email, which they will have entered on
* the "reset password" page of the application. This function will submit the new password
- * along with the verification code, changing the user's password. */
+ * along with the verification code, changing the user's password.
+ */
async forgotPasswordSubmit(email: string, code: string, password: string) {
const result = await results.Result.wrapAsync(async () => {
await amplify.Auth.forgotPasswordSubmit(email, code, password)
@@ -379,12 +411,14 @@ export class Cognito {
return result.mapErr(intoForgotPasswordSubmitErrorOrThrow)
}
- /** Change a password for current authenticated user.
+ /**
+ * Change a password for current authenticated user.
*
* Allow users to independently modify their passwords. The user needs to provide the old
* password, new password, and repeat new password to change their old password to the new
* one. The validation of the repeated new password is handled by the `changePasswordModel`
- * component. */
+ * component.
+ */
async changePassword(oldPassword: string, newPassword: string) {
const cognitoUserResult = await currentAuthenticatedUser()
if (cognitoUserResult.ok) {
@@ -504,7 +538,8 @@ export class Cognito {
return result.mapErr(intoAmplifyErrorOrThrow)
}
- /** We want to signal to Amplify to fire a "custom state change" event when the user is
+ /**
+ * We want to signal to Amplify to fire a "custom state change" event when the user is
* redirected back to the application after signing in via an external identity provider. This
* is done so we get a chance to fix the location history. The location history is the history
* of the pages visited within the application. Amplify messes up the history when it redirects
@@ -521,7 +556,8 @@ export class Cognito {
* We use `null` outside of the desktop application because Amplify only messes up the
* location history in the desktop application.
*
- * See: https://github.com/aws-amplify/amplify-js/issues/3391#issuecomment-756473970 */
+ * See: https://github.com/aws-amplify/amplify-js/issues/3391#issuecomment-756473970
+ */
private customState() {
return detect.isOnElectron() ? window.location.pathname : null
}
@@ -533,13 +569,15 @@ export class Cognito {
/** User's session, provides information for identifying and authenticating the user. */
export interface UserSession {
- /** User's email address, used to uniquely identify the user.
+ /**
+ * User's email address, used to uniquely identify the user.
*
* Provided by the identity provider the user used to log in. One of:
*
* - GitHub,
* - Google, or
- * - Email. */
+ * - Email.
+ */
readonly email: string
/** User's access token, used to authenticate the user (e.g., when making API calls). */
readonly accessToken: string
@@ -553,8 +591,10 @@ export interface UserSession {
readonly clientId: string
}
-/** Parse a `CognitoUserSession` into a {@link UserSession}.
- * @throws If the `email` field of the payload is not a string. */
+/**
+ * Parse a `CognitoUserSession` into a {@link UserSession}.
+ * @throws If the `email` field of the payload is not a string.
+ */
function parseUserSession(session: cognito.CognitoUserSession, clientId: string): UserSession {
const payload: Readonly> = session.getIdToken().payload
const email = payload.email
@@ -587,19 +627,21 @@ function extractRefreshUrlFromSession(session: cognito.CognitoUserSession): stri
const { iss } = session.getAccessToken().payload
if (typeof iss !== 'string') {
- throw new Error('Payload does not have an iss field.')
+ throw new Error('Payload does not have an `iss` field.')
} else {
try {
return new URL(iss).toString()
- } catch (e) {
- throw new Error('iss field is not a valid URL')
+ } catch {
+ throw new Error('`iss` field is not a valid URL')
}
}
}
-/** Convert an {@link AmplifyError} into a {@link CognitoErrorType} if it is a known error,
+/**
+ * Convert an {@link AmplifyError} into a {@link CognitoErrorType} if it is a known error,
* else re-throws the error.
- * @throws {Error} If the error is not recognized. */
+ * @throws {Error} If the error is not recognized.
+ */
export function intoCurrentSessionErrorType(error: unknown): CognitoErrorType.noCurrentUser {
if (error === 'No current user') {
return CognitoErrorType.noCurrentUser
@@ -624,7 +666,8 @@ function intoSignUpParams(
password,
attributes: {
email: username,
- /** Add a custom attribute indicating whether the user is signing up from the desktop.
+ /**
+ * Add a custom attribute indicating whether the user is signing up from the desktop.
* This is used to determine the schema used in the callback links sent in the
* verification emails. For example, `http://` for the Cloud, and `enso://` for the
* desktop.
@@ -632,7 +675,8 @@ function intoSignUpParams(
* # Naming Convention
*
* It is necessary to disable the naming convention rule here, because the key is
- * expected to appear exactly as-is in Cognito, so we must match it. */
+ * expected to appear exactly as-is in Cognito, so we must match it.
+ */
// eslint-disable-next-line @typescript-eslint/naming-convention
...(supportsDeepLinks ? { 'custom:fromDesktop': JSON.stringify(true) } : {}),
// eslint-disable-next-line @typescript-eslint/naming-convention
@@ -686,18 +730,22 @@ export interface ConfirmSignUpError extends CognitoError {
readonly message: string
}
-/** Convert an {@link AmplifyError} into a {@link ConfirmSignUpError} if it is a known error,
+/**
+ * Convert an {@link AmplifyError} into a {@link ConfirmSignUpError} if it is a known error,
* else re-throws the error.
- * @throws {Error} If the error is not recognized. */
+ * @throws {Error} If the error is not recognized.
+ */
export function intoConfirmSignUpErrorOrThrow(error: AmplifyError): ConfirmSignUpError {
if (
error.code === 'NotAuthorizedException' &&
error.message === 'User cannot be confirmed. Current status is CONFIRMED'
) {
return {
- /** Don't re-use the original `error.code` here because Amplify overloads the same code
+ /**
+ * Don't re-use the original `error.code` here because Amplify overloads the same code
* for multiple kinds of errors. We replace it with a custom code that has no
- * ambiguity. */
+ * ambiguity.
+ */
type: CognitoErrorType.userAlreadyConfirmed,
message: error.message,
}
@@ -706,9 +754,11 @@ export function intoConfirmSignUpErrorOrThrow(error: AmplifyError): ConfirmSignU
error.message === 'Username/client id combination not found.'
) {
return {
- /** Don't re-use the original `error.code` here because Amplify overloads the same code
+ /**
+ * Don't re-use the original `error.code` here because Amplify overloads the same code
* for multiple kinds of errors. We replace it with a custom code that has no
- * ambiguity. */
+ * ambiguity.
+ */
type: CognitoErrorType.userNotFound,
message: 'Incorrect email or confirmation code.',
}
@@ -730,9 +780,11 @@ export interface SignInWithPasswordError extends CognitoError {
readonly message: string
}
-/** Convert an {@link AmplifyError} into a {@link SignInWithPasswordError} if it is a known error,
+/**
+ * Convert an {@link AmplifyError} into a {@link SignInWithPasswordError} if it is a known error,
* else re-throws the error.
- * @throws {Error} If the error is not recognized. */
+ * @throws {Error} If the error is not recognized.
+ */
export function intoSignInWithPasswordErrorOrThrow(error: AmplifyError): SignInWithPasswordError {
switch (error.code) {
case 'UserNotFoundException':
@@ -768,9 +820,11 @@ export interface ForgotPasswordError extends CognitoError {
readonly message: string
}
-/** Convert an {@link AmplifyError} into a {@link ForgotPasswordError} if it is a known error,
+/**
+ * Convert an {@link AmplifyError} into a {@link ForgotPasswordError} if it is a known error,
* else re-throws the error.
- * @throws {Error} If the error is not recognized. */
+ * @throws {Error} If the error is not recognized.
+ */
export function intoForgotPasswordErrorOrThrow(error: AmplifyError): ForgotPasswordError {
if (error.code === 'UserNotFoundException') {
return {
@@ -812,9 +866,11 @@ export interface ForgotPasswordSubmitError extends CognitoError {
readonly message: string
}
-/** Convert an {@link AmplifyError} into a {@link ForgotPasswordSubmitError}
+/**
+ * Convert an {@link AmplifyError} into a {@link ForgotPasswordSubmitError}
* if it is a known error, else re-throws the error.
- * @throws {Error} If the error is not recognized. */
+ * @throws {Error} If the error is not recognized.
+ */
export function intoForgotPasswordSubmitErrorOrThrow(error: unknown): ForgotPasswordSubmitError {
if (isAuthError(error)) {
return {
@@ -835,14 +891,18 @@ export function intoForgotPasswordSubmitErrorOrThrow(error: unknown): ForgotPass
// === ChangePassword ===
// ======================
-/** A wrapper around the Amplify "current authenticated user" endpoint that converts known errors
- * to {@link AmplifyError}s. */
+/**
+ * A wrapper around the Amplify "current authenticated user" endpoint that converts known errors
+ * to {@link AmplifyError}s.
+ */
async function currentAuthenticatedUser() {
const result = await results.Result.wrapAsync(
- /** The interface provided by Amplify declares that the return type is
+ /**
+ * The interface provided by Amplify declares that the return type is
* `Promise`, but TypeScript automatically converts it to `Promise`.
* Therefore, it is necessary to use `as` to narrow down the type to
- * `Promise`. */
+ * `Promise`.
+ */
// eslint-disable-next-line no-restricted-syntax
() => amplify.Auth.currentAuthenticatedUser() as Promise,
)
diff --git a/app/dashboard/src/authentication/listen.mock.ts b/app/gui/src/dashboard/authentication/listen.mock.ts
similarity index 100%
rename from app/dashboard/src/authentication/listen.mock.ts
rename to app/gui/src/dashboard/authentication/listen.mock.ts
diff --git a/app/dashboard/src/authentication/listen.ts b/app/gui/src/dashboard/authentication/listen.ts
similarity index 78%
rename from app/dashboard/src/authentication/listen.ts
rename to app/gui/src/dashboard/authentication/listen.ts
index 129d332a02d..036c2fdaeef 100644
--- a/app/dashboard/src/authentication/listen.ts
+++ b/app/gui/src/dashboard/authentication/listen.ts
@@ -1,8 +1,10 @@
-/** @file Module for listening to authentication events emitted by Amplify.
+/**
+ * @file Module for listening to authentication events emitted by Amplify.
*
* Listening to authentication events is necessary to update the authentication state of the
* application. For example, if the user signs out, we want to clear the authentication state so
- * that the login screen is rendered. */
+ * that the login screen is rendered.
+ */
import * as amplify from '@aws-amplify/core'
// =================
@@ -16,10 +18,12 @@ const AUTHENTICATION_HUB = 'auth'
// === AuthEvent ===
// =================
-/** Authentication state change events.
+/**
+ * Authentication state change events.
*
* These are issues by AWS Amplify when it detects a change in authentication state. For example,
- * when the user signs in or signs out by accessing a page like `enso://auth?code=...&state=...`. */
+ * when the user signs in or signs out by accessing a page like `enso://auth?code=...&state=...`.
+ */
export enum AuthEvent {
/** Issued when the user has passed custom OAuth state parameters to some other auth event. */
customOAuthState = 'customOAuthState',
@@ -40,18 +44,24 @@ function isAuthEvent(value: string): value is AuthEvent {
// === RegisterAuthEventListener ===
// =================================
-/** Callback called in response to authentication state changes.
- * @see {@link amplify.Hub.listen}. */
+/**
+ * Callback called in response to authentication state changes.
+ * @see {@link amplify.Hub.listen}.
+ */
export type ListenerCallback = (event: AuthEvent, data?: unknown) => void
-/** Unsubscribe the {@link ListenerCallback} from authentication state changes.
- * @see {@link amplify.Hub.listen}. */
+/**
+ * Unsubscribe the {@link ListenerCallback} from authentication state changes.
+ * @see {@link amplify.Hub.listen}.
+ */
type UnsubscribeFunction = () => void
-/** Used to subscribe to {@link AuthEvent}s.
+/**
+ * Used to subscribe to {@link AuthEvent}s.
*
* Returns a function that MUST be called before re-subscribing,
- * to avoid memory leaks or duplicate event handlers. */
+ * to avoid memory leaks or duplicate event handlers.
+ */
export type ListenFunction = (listener: ListenerCallback) => UnsubscribeFunction
/** Listen to authentication state changes. */
diff --git a/app/dashboard/src/authentication/service.ts b/app/gui/src/dashboard/authentication/service.ts
similarity index 92%
rename from app/dashboard/src/authentication/service.ts
rename to app/gui/src/dashboard/authentication/service.ts
index e4caeafab38..5242ec9af3d 100644
--- a/app/dashboard/src/authentication/service.ts
+++ b/app/gui/src/dashboard/authentication/service.ts
@@ -1,6 +1,8 @@
-/** @file Provides an {@link AuthService} which consists of an underyling `Cognito` API
+/**
+ * @file Provides an {@link AuthService} which consists of an underyling `Cognito` API
* wrapper, along with some convenience callbacks to make URL redirects for the authentication flows
- * work with Electron. */
+ * work with Electron.
+ */
import * as React from 'react'
import * as amplify from '@aws-amplify/auth'
@@ -13,7 +15,7 @@ import * as appUtils from '#/appUtils'
import { useLogger, type Logger } from '#/providers/LoggerProvider'
-import type * as saveAccessTokenModule from '#/utilities/accessToken'
+import type * as saveAccessTokenModule from 'enso-common/src/accessToken'
import * as cognitoModule from '#/authentication/cognito'
import * as listen from '#/authentication/listen'
@@ -22,11 +24,13 @@ import * as listen from '#/authentication/listen'
// === AmplifyConfig ===
// =====================
-/** Configuration for the AWS Amplify library.
+/**
+ * Configuration for the AWS Amplify library.
*
* This details user pools, federated identity providers, etc. that are used to authenticate users.
* The values in this object are not secret, and can be swapped out for testing values to avoid
- * creating authenticated users in the production environment. */
+ * creating authenticated users in the production environment.
+ */
export interface AmplifyConfig {
readonly region: string
readonly userPoolId: string
@@ -67,10 +71,12 @@ export interface NestedAmplifyConfig {
readonly oauth: OauthAmplifyConfig
}
-/** Convert the flattened `AmplifyConfig` struct to a form recognizable to the AWS Amplify library.
+/**
+ * Convert the flattened `AmplifyConfig` struct to a form recognizable to the AWS Amplify library.
*
* We use a flattened form of the config for easier object manipulation, but the AWS Amplify library
- * expects a nested form. */
+ * expects a nested form.
+ */
export function toNestedAmplifyConfig(config: AmplifyConfig): NestedAmplifyConfig {
return {
region: config.region,
@@ -93,8 +99,10 @@ export function toNestedAmplifyConfig(config: AmplifyConfig): NestedAmplifyConfi
/** Configuration for the authentication service. */
export interface AuthConfig {
- /** Whether the application supports deep links. This is only true when using
- * the installed app on macOS and Windows. */
+ /**
+ * Whether the application supports deep links. This is only true when using
+ * the installed app on macOS and Windows.
+ */
readonly supportsDeepLinks: boolean
}
@@ -110,12 +118,14 @@ export interface AuthService {
readonly registerAuthEventListener: listen.ListenFunction
}
-/** Create an instance of the authentication service.
+/**
+ * Create an instance of the authentication service.
*
* # Warning
*
* This hook should only be called in a single place, as it performs global configuration of the
- * Amplify library. */
+ * Amplify library.
+ */
export function useInitAuthService(authConfig: AuthConfig): AuthService {
const { supportsDeepLinks } = authConfig
@@ -186,7 +196,8 @@ function loadAmplifyConfig(
}
}
-/** Set the callback that will be invoked when a deep link to the application is opened.
+/**
+ * Set the callback that will be invoked when a deep link to the application is opened.
*
* Typically this callback is invoked when the user is redirected back to the app after:
*
@@ -202,7 +213,8 @@ function loadAmplifyConfig(
* because it's a deep link into the app, and Amplify doesn't handle deep links.
*
* All URLs that don't have a pathname that starts with `AUTHENTICATION_PATHNAME_BASE` will be
- * ignored by this handler. */
+ * ignored by this handler.
+ */
function setDeepLinkHandler(logger: Logger, navigate: (url: string) => void) {
window.authenticationApi.setDeepLinkHandler((urlString: string) => {
const url = new URL(urlString)
diff --git a/app/dashboard/src/components/AnimatedBackground.tsx b/app/gui/src/dashboard/components/AnimatedBackground.tsx
similarity index 100%
rename from app/dashboard/src/components/AnimatedBackground.tsx
rename to app/gui/src/dashboard/components/AnimatedBackground.tsx
diff --git a/app/dashboard/src/components/AriaComponents/Alert/Alert.tsx b/app/gui/src/dashboard/components/AriaComponents/Alert/Alert.tsx
similarity index 100%
rename from app/dashboard/src/components/AriaComponents/Alert/Alert.tsx
rename to app/gui/src/dashboard/components/AriaComponents/Alert/Alert.tsx
diff --git a/app/dashboard/src/components/AriaComponents/Alert/index.ts b/app/gui/src/dashboard/components/AriaComponents/Alert/index.ts
similarity index 100%
rename from app/dashboard/src/components/AriaComponents/Alert/index.ts
rename to app/gui/src/dashboard/components/AriaComponents/Alert/index.ts
diff --git a/app/dashboard/src/components/AriaComponents/Button/Button.tsx b/app/gui/src/dashboard/components/AriaComponents/Button/Button.tsx
similarity index 99%
rename from app/dashboard/src/components/AriaComponents/Button/Button.tsx
rename to app/gui/src/dashboard/components/AriaComponents/Button/Button.tsx
index 78ad0e34b1a..2fc504a6ee4 100644
--- a/app/dashboard/src/components/AriaComponents/Button/Button.tsx
+++ b/app/gui/src/dashboard/components/AriaComponents/Button/Button.tsx
@@ -65,8 +65,10 @@ export interface BaseButtonProps
readonly testId?: string
readonly isDisabled?: boolean
readonly formnovalidate?: boolean
- /** Defaults to `full`. When `full`, the entire button will be replaced with the loader.
- * When `icon`, only the icon will be replaced with the loader. */
+ /**
+ * Defaults to `full`. When `full`, the entire button will be replaced with the loader.
+ * When `icon`, only the icon will be replaced with the loader.
+ */
readonly loaderPosition?: 'full' | 'icon'
readonly styles?: ExtractFunction | undefined
}
diff --git a/app/dashboard/src/components/AriaComponents/Button/ButtonGroup.tsx b/app/gui/src/dashboard/components/AriaComponents/Button/ButtonGroup.tsx
similarity index 100%
rename from app/dashboard/src/components/AriaComponents/Button/ButtonGroup.tsx
rename to app/gui/src/dashboard/components/AriaComponents/Button/ButtonGroup.tsx
diff --git a/app/dashboard/src/components/AriaComponents/Button/CloseButton.tsx b/app/gui/src/dashboard/components/AriaComponents/Button/CloseButton.tsx
similarity index 100%
rename from app/dashboard/src/components/AriaComponents/Button/CloseButton.tsx
rename to app/gui/src/dashboard/components/AriaComponents/Button/CloseButton.tsx
diff --git a/app/dashboard/src/components/AriaComponents/Button/CopyButton.tsx b/app/gui/src/dashboard/components/AriaComponents/Button/CopyButton.tsx
similarity index 90%
rename from app/dashboard/src/components/AriaComponents/Button/CopyButton.tsx
rename to app/gui/src/dashboard/components/AriaComponents/Button/CopyButton.tsx
index 49bae1b3103..5a35c003292 100644
--- a/app/dashboard/src/components/AriaComponents/Button/CopyButton.tsx
+++ b/app/gui/src/dashboard/components/AriaComponents/Button/CopyButton.tsx
@@ -19,16 +19,20 @@ import * as button from './Button'
export interface CopyButtonProps extends Omit {
/** The text to copy to the clipboard. */
readonly copyText: string
- /** Custom icon
- * If `false` is provided, no icon will be shown. */
+ /**
+ * Custom icon
+ * If `false` is provided, no icon will be shown.
+ */
readonly copyIcon?: string | false
readonly errorIcon?: string
readonly successIcon?: string
readonly onCopy?: () => void
- /** Show a toast message when the copy is successful.
+ /**
+ * Show a toast message when the copy is successful.
* If a string is provided, it will be used as the toast message.
* If `true` is provided, a default toast message will be shown with the text "Copied to clipboard".
- * If `false` is provided, no toast message will be shown. */
+ * If `false` is provided, no toast message will be shown.
+ */
readonly successToastMessage?: boolean | string
}
diff --git a/app/dashboard/src/components/AriaComponents/Button/index.ts b/app/gui/src/dashboard/components/AriaComponents/Button/index.ts
similarity index 100%
rename from app/dashboard/src/components/AriaComponents/Button/index.ts
rename to app/gui/src/dashboard/components/AriaComponents/Button/index.ts
diff --git a/app/dashboard/src/components/AriaComponents/Checkbox/Checkbox.tsx b/app/gui/src/dashboard/components/AriaComponents/Checkbox/Checkbox.tsx
similarity index 98%
rename from app/dashboard/src/components/AriaComponents/Checkbox/Checkbox.tsx
rename to app/gui/src/dashboard/components/AriaComponents/Checkbox/Checkbox.tsx
index 2d230432df3..399d0aa019e 100644
--- a/app/dashboard/src/components/AriaComponents/Checkbox/Checkbox.tsx
+++ b/app/gui/src/dashboard/components/AriaComponents/Checkbox/Checkbox.tsx
@@ -58,8 +58,10 @@ interface CheckboxGroupCheckboxProps extends AriaCheckboxProps {
/**
* Props for the {@link Checkbox} component when used outside of a {@link CheckboxGroup}.
*/
-interface StandaloneCheckboxProps>
- extends FieldStateProps {}
+type StandaloneCheckboxProps<
+ Schema extends TSchema,
+ TFieldName extends FieldPath,
+> = FieldStateProps
export const CHECKBOX_STYLES = tv({
base: 'group flex gap-2 items-center cursor-pointer select-none',
diff --git a/app/dashboard/src/components/AriaComponents/Checkbox/CheckboxContext.tsx b/app/gui/src/dashboard/components/AriaComponents/Checkbox/CheckboxContext.tsx
similarity index 100%
rename from app/dashboard/src/components/AriaComponents/Checkbox/CheckboxContext.tsx
rename to app/gui/src/dashboard/components/AriaComponents/Checkbox/CheckboxContext.tsx
diff --git a/app/dashboard/src/components/AriaComponents/Checkbox/CheckboxGroup.tsx b/app/gui/src/dashboard/components/AriaComponents/Checkbox/CheckboxGroup.tsx
similarity index 100%
rename from app/dashboard/src/components/AriaComponents/Checkbox/CheckboxGroup.tsx
rename to app/gui/src/dashboard/components/AriaComponents/Checkbox/CheckboxGroup.tsx
diff --git a/app/dashboard/src/components/AriaComponents/Checkbox/index.ts b/app/gui/src/dashboard/components/AriaComponents/Checkbox/index.ts
similarity index 100%
rename from app/dashboard/src/components/AriaComponents/Checkbox/index.ts
rename to app/gui/src/dashboard/components/AriaComponents/Checkbox/index.ts
diff --git a/app/dashboard/src/components/AriaComponents/CopyBlock/CopyBlock.tsx b/app/gui/src/dashboard/components/AriaComponents/CopyBlock/CopyBlock.tsx
similarity index 100%
rename from app/dashboard/src/components/AriaComponents/CopyBlock/CopyBlock.tsx
rename to app/gui/src/dashboard/components/AriaComponents/CopyBlock/CopyBlock.tsx
diff --git a/app/dashboard/src/components/AriaComponents/CopyBlock/index.ts b/app/gui/src/dashboard/components/AriaComponents/CopyBlock/index.ts
similarity index 100%
rename from app/dashboard/src/components/AriaComponents/CopyBlock/index.ts
rename to app/gui/src/dashboard/components/AriaComponents/CopyBlock/index.ts
diff --git a/app/dashboard/src/components/AriaComponents/Dialog/Close.tsx b/app/gui/src/dashboard/components/AriaComponents/Dialog/Close.tsx
similarity index 100%
rename from app/dashboard/src/components/AriaComponents/Dialog/Close.tsx
rename to app/gui/src/dashboard/components/AriaComponents/Dialog/Close.tsx
diff --git a/app/dashboard/src/components/AriaComponents/Dialog/Dialog.tsx b/app/gui/src/dashboard/components/AriaComponents/Dialog/Dialog.tsx
similarity index 98%
rename from app/dashboard/src/components/AriaComponents/Dialog/Dialog.tsx
rename to app/gui/src/dashboard/components/AriaComponents/Dialog/Dialog.tsx
index 862e1b3adb8..b55489d0471 100644
--- a/app/dashboard/src/components/AriaComponents/Dialog/Dialog.tsx
+++ b/app/gui/src/dashboard/components/AriaComponents/Dialog/Dialog.tsx
@@ -1,5 +1,7 @@
-/** @file A dialog is an overlay shown above other content in an application.
- * Can be used to display alerts, confirmations, or other content. */
+/**
+ * @file A dialog is an overlay shown above other content in an application.
+ * Can be used to display alerts, confirmations, or other content.
+ */
import * as React from 'react'
import * as aria from '#/components/aria'
@@ -148,8 +150,10 @@ const DIALOG_STYLES = tv({
// === Dialog ===
// ==============
-/** A dialog is an overlay shown above other content in an application.
- * Can be used to display alerts, confirmations, or other content. */
+/**
+ * A dialog is an overlay shown above other content in an application.
+ * Can be used to display alerts, confirmations, or other content.
+ */
export function Dialog(props: DialogProps) {
const {
children,
diff --git a/app/dashboard/src/components/AriaComponents/Dialog/DialogProvider.tsx b/app/gui/src/dashboard/components/AriaComponents/Dialog/DialogProvider.tsx
similarity index 100%
rename from app/dashboard/src/components/AriaComponents/Dialog/DialogProvider.tsx
rename to app/gui/src/dashboard/components/AriaComponents/Dialog/DialogProvider.tsx
diff --git a/app/dashboard/src/components/AriaComponents/Dialog/DialogStackProvider.tsx b/app/gui/src/dashboard/components/AriaComponents/Dialog/DialogStackProvider.tsx
similarity index 100%
rename from app/dashboard/src/components/AriaComponents/Dialog/DialogStackProvider.tsx
rename to app/gui/src/dashboard/components/AriaComponents/Dialog/DialogStackProvider.tsx
diff --git a/app/dashboard/src/components/AriaComponents/Dialog/DialogTrigger.tsx b/app/gui/src/dashboard/components/AriaComponents/Dialog/DialogTrigger.tsx
similarity index 100%
rename from app/dashboard/src/components/AriaComponents/Dialog/DialogTrigger.tsx
rename to app/gui/src/dashboard/components/AriaComponents/Dialog/DialogTrigger.tsx
diff --git a/app/dashboard/src/components/AriaComponents/Dialog/Popover.tsx b/app/gui/src/dashboard/components/AriaComponents/Dialog/Popover.tsx
similarity index 100%
rename from app/dashboard/src/components/AriaComponents/Dialog/Popover.tsx
rename to app/gui/src/dashboard/components/AriaComponents/Dialog/Popover.tsx
diff --git a/app/dashboard/src/components/AriaComponents/Dialog/index.ts b/app/gui/src/dashboard/components/AriaComponents/Dialog/index.ts
similarity index 100%
rename from app/dashboard/src/components/AriaComponents/Dialog/index.ts
rename to app/gui/src/dashboard/components/AriaComponents/Dialog/index.ts
diff --git a/app/dashboard/src/components/AriaComponents/Dialog/types.ts b/app/gui/src/dashboard/components/AriaComponents/Dialog/types.ts
similarity index 100%
rename from app/dashboard/src/components/AriaComponents/Dialog/types.ts
rename to app/gui/src/dashboard/components/AriaComponents/Dialog/types.ts
diff --git a/app/dashboard/src/components/AriaComponents/Dialog/utilities.ts b/app/gui/src/dashboard/components/AriaComponents/Dialog/utilities.ts
similarity index 100%
rename from app/dashboard/src/components/AriaComponents/Dialog/utilities.ts
rename to app/gui/src/dashboard/components/AriaComponents/Dialog/utilities.ts
diff --git a/app/dashboard/src/components/AriaComponents/Dialog/variants.ts b/app/gui/src/dashboard/components/AriaComponents/Dialog/variants.ts
similarity index 100%
rename from app/dashboard/src/components/AriaComponents/Dialog/variants.ts
rename to app/gui/src/dashboard/components/AriaComponents/Dialog/variants.ts
diff --git a/app/dashboard/src/components/AriaComponents/Form/Form.tsx b/app/gui/src/dashboard/components/AriaComponents/Form/Form.tsx
similarity index 98%
rename from app/dashboard/src/components/AriaComponents/Form/Form.tsx
rename to app/gui/src/dashboard/components/AriaComponents/Form/Form.tsx
index 944da4afe74..1faef3c35ab 100644
--- a/app/dashboard/src/components/AriaComponents/Form/Form.tsx
+++ b/app/gui/src/dashboard/components/AriaComponents/Form/Form.tsx
@@ -12,9 +12,11 @@ import * as components from './components'
import * as styles from './styles'
import type * as types from './types'
-/** Form component. It wraps a `form` and provides form context.
+/**
+ * Form component. It wraps a `form` and provides form context.
* It also handles form submission.
- * Provides better error handling and form state management and better UX out of the box. */
+ * Provides better error handling and form state management and better UX out of the box.
+ */
// There is no way to avoid type casting here
// eslint-disable-next-line no-restricted-syntax
export const Form = forwardRef(function Form<
diff --git a/app/dashboard/src/components/AriaComponents/Form/components/Field.tsx b/app/gui/src/dashboard/components/AriaComponents/Form/components/Field.tsx
similarity index 100%
rename from app/dashboard/src/components/AriaComponents/Form/components/Field.tsx
rename to app/gui/src/dashboard/components/AriaComponents/Form/components/Field.tsx
diff --git a/app/dashboard/src/components/AriaComponents/Form/components/FormError.tsx b/app/gui/src/dashboard/components/AriaComponents/Form/components/FormError.tsx
similarity index 100%
rename from app/dashboard/src/components/AriaComponents/Form/components/FormError.tsx
rename to app/gui/src/dashboard/components/AriaComponents/Form/components/FormError.tsx
diff --git a/app/dashboard/src/components/AriaComponents/Form/components/FormProvider.tsx b/app/gui/src/dashboard/components/AriaComponents/Form/components/FormProvider.tsx
similarity index 97%
rename from app/dashboard/src/components/AriaComponents/Form/components/FormProvider.tsx
rename to app/gui/src/dashboard/components/AriaComponents/Form/components/FormProvider.tsx
index 7e7843e6990..a6f9eb9245d 100644
--- a/app/dashboard/src/components/AriaComponents/Form/components/FormProvider.tsx
+++ b/app/gui/src/dashboard/components/AriaComponents/Form/components/FormProvider.tsx
@@ -40,7 +40,7 @@ export function FormProvider(
* Returns the form instance from the context.
*/
export function useFormContext(
- form?: FormInstanceValidated | undefined,
+ form?: FormInstanceValidated,
): FormInstance {
if (form != null && 'control' in form) {
return form
diff --git a/app/dashboard/src/components/AriaComponents/Form/components/Reset.tsx b/app/gui/src/dashboard/components/AriaComponents/Form/components/Reset.tsx
similarity index 100%
rename from app/dashboard/src/components/AriaComponents/Form/components/Reset.tsx
rename to app/gui/src/dashboard/components/AriaComponents/Form/components/Reset.tsx
diff --git a/app/dashboard/src/components/AriaComponents/Form/components/Submit.tsx b/app/gui/src/dashboard/components/AriaComponents/Form/components/Submit.tsx
similarity index 100%
rename from app/dashboard/src/components/AriaComponents/Form/components/Submit.tsx
rename to app/gui/src/dashboard/components/AriaComponents/Form/components/Submit.tsx
diff --git a/app/dashboard/src/components/AriaComponents/Form/components/index.ts b/app/gui/src/dashboard/components/AriaComponents/Form/components/index.ts
similarity index 100%
rename from app/dashboard/src/components/AriaComponents/Form/components/index.ts
rename to app/gui/src/dashboard/components/AriaComponents/Form/components/index.ts
diff --git a/app/dashboard/src/components/AriaComponents/Form/components/schema.ts b/app/gui/src/dashboard/components/AriaComponents/Form/components/schema.ts
similarity index 100%
rename from app/dashboard/src/components/AriaComponents/Form/components/schema.ts
rename to app/gui/src/dashboard/components/AriaComponents/Form/components/schema.ts
diff --git a/app/dashboard/src/components/AriaComponents/Form/components/types.ts b/app/gui/src/dashboard/components/AriaComponents/Form/components/types.ts
similarity index 97%
rename from app/dashboard/src/components/AriaComponents/Form/components/types.ts
rename to app/gui/src/dashboard/components/AriaComponents/Form/components/types.ts
index 1879f1ff315..fd52fcc35da 100644
--- a/app/dashboard/src/components/AriaComponents/Form/components/types.ts
+++ b/app/gui/src/dashboard/components/AriaComponents/Form/components/types.ts
@@ -87,7 +87,6 @@ export interface UseFormProps
* Debug name for the form. Use it to identify the form in the tanstack query devtools.
*/
readonly debugName?: string
- // eslint-disable-next-line @typescript-eslint/ban-types
readonly method?: 'dialog' | (string & {}) | undefined
}
@@ -130,7 +129,7 @@ export interface UseFormReturn
'onSubmit' | 'resetOptions' | 'resolver'
> {
readonly register: UseFormRegister
- readonly submit: (event?: FormEvent | null | undefined) => Promise
+ readonly submit: (event?: FormEvent | null) => Promise
readonly schema: Schema
readonly setFormError: (error: string) => void
readonly closeRef: React.MutableRefObject<() => void>
@@ -178,8 +177,8 @@ export interface FormWithValueValidation<
export type FormInstanceValidated<
Schema extends TSchema,
// We use any here because we want to bypass the type check for Error type as it won't be a case here
- // eslint-disable-next-line @typescript-eslint/no-explicit-any,@typescript-eslint/ban-types
-> = FormInstance | (any[] & {})
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+> = FormInstance | (any[] & NonNullable)
/**
* Props for the Field component.
@@ -218,7 +217,7 @@ export interface FieldProps {
}
/**
* Base Props for a Form Field.
- * @private
+ * @internal
*/
export interface FormFieldProps<
BaseValueType,
diff --git a/app/dashboard/src/components/AriaComponents/Form/components/useField.ts b/app/gui/src/dashboard/components/AriaComponents/Form/components/useField.ts
similarity index 100%
rename from app/dashboard/src/components/AriaComponents/Form/components/useField.ts
rename to app/gui/src/dashboard/components/AriaComponents/Form/components/useField.ts
diff --git a/app/dashboard/src/components/AriaComponents/Form/components/useFieldRegister.ts b/app/gui/src/dashboard/components/AriaComponents/Form/components/useFieldRegister.ts
similarity index 97%
rename from app/dashboard/src/components/AriaComponents/Form/components/useFieldRegister.ts
rename to app/gui/src/dashboard/components/AriaComponents/Form/components/useFieldRegister.ts
index 13413e2e812..6d49080b5f8 100644
--- a/app/dashboard/src/components/AriaComponents/Form/components/useFieldRegister.ts
+++ b/app/gui/src/dashboard/components/AriaComponents/Form/components/useFieldRegister.ts
@@ -66,7 +66,7 @@ export function useFieldRegister<
* Tried to extract validation details from the schema.
*/
// This name is intentional to highlight that this function is unsafe and should be used with caution.
-// eslint-disable-next-line @typescript-eslint/naming-convention
+// eslint-disable-next-line camelcase, @typescript-eslint/naming-convention
function unsafe__extractValidationDetailsFromSchema<
Schema extends TSchema,
TFieldName extends FieldPath,
diff --git a/app/dashboard/src/components/AriaComponents/Form/components/useFieldState.ts b/app/gui/src/dashboard/components/AriaComponents/Form/components/useFieldState.ts
similarity index 100%
rename from app/dashboard/src/components/AriaComponents/Form/components/useFieldState.ts
rename to app/gui/src/dashboard/components/AriaComponents/Form/components/useFieldState.ts
diff --git a/app/dashboard/src/components/AriaComponents/Form/components/useForm.ts b/app/gui/src/dashboard/components/AriaComponents/Form/components/useForm.ts
similarity index 100%
rename from app/dashboard/src/components/AriaComponents/Form/components/useForm.ts
rename to app/gui/src/dashboard/components/AriaComponents/Form/components/useForm.ts
diff --git a/app/dashboard/src/components/AriaComponents/Form/components/useFormSchema.tsx b/app/gui/src/dashboard/components/AriaComponents/Form/components/useFormSchema.tsx
similarity index 100%
rename from app/dashboard/src/components/AriaComponents/Form/components/useFormSchema.tsx
rename to app/gui/src/dashboard/components/AriaComponents/Form/components/useFormSchema.tsx
diff --git a/app/dashboard/src/components/AriaComponents/Form/index.ts b/app/gui/src/dashboard/components/AriaComponents/Form/index.ts
similarity index 100%
rename from app/dashboard/src/components/AriaComponents/Form/index.ts
rename to app/gui/src/dashboard/components/AriaComponents/Form/index.ts
diff --git a/app/dashboard/src/components/AriaComponents/Form/styles.ts b/app/gui/src/dashboard/components/AriaComponents/Form/styles.ts
similarity index 100%
rename from app/dashboard/src/components/AriaComponents/Form/styles.ts
rename to app/gui/src/dashboard/components/AriaComponents/Form/styles.ts
diff --git a/app/dashboard/src/components/AriaComponents/Form/types.ts b/app/gui/src/dashboard/components/AriaComponents/Form/types.ts
similarity index 97%
rename from app/dashboard/src/components/AriaComponents/Form/types.ts
rename to app/gui/src/dashboard/components/AriaComponents/Form/types.ts
index 30b767e3a02..2903e2674b8 100644
--- a/app/dashboard/src/components/AriaComponents/Form/types.ts
+++ b/app/gui/src/dashboard/components/AriaComponents/Form/types.ts
@@ -51,8 +51,7 @@ interface BaseFormProps
/**
* When set to `dialog`, form submission will close the parent dialog on successful submission.
*/
- // eslint-disable-next-line @typescript-eslint/ban-types,no-restricted-syntax
- readonly method?: 'dialog' | (string & {})
+ readonly method?: 'dialog' | (NonNullable & string)
readonly canSubmitOffline?: boolean
}
diff --git a/app/dashboard/src/components/AriaComponents/Inputs/ComboBox/ComboBox.tsx b/app/gui/src/dashboard/components/AriaComponents/Inputs/ComboBox/ComboBox.tsx
similarity index 100%
rename from app/dashboard/src/components/AriaComponents/Inputs/ComboBox/ComboBox.tsx
rename to app/gui/src/dashboard/components/AriaComponents/Inputs/ComboBox/ComboBox.tsx
diff --git a/app/dashboard/src/components/AriaComponents/Inputs/ComboBox/index.ts b/app/gui/src/dashboard/components/AriaComponents/Inputs/ComboBox/index.ts
similarity index 100%
rename from app/dashboard/src/components/AriaComponents/Inputs/ComboBox/index.ts
rename to app/gui/src/dashboard/components/AriaComponents/Inputs/ComboBox/index.ts
diff --git a/app/dashboard/src/components/AriaComponents/Inputs/DatePicker/DatePicker.tsx b/app/gui/src/dashboard/components/AriaComponents/Inputs/DatePicker/DatePicker.tsx
similarity index 100%
rename from app/dashboard/src/components/AriaComponents/Inputs/DatePicker/DatePicker.tsx
rename to app/gui/src/dashboard/components/AriaComponents/Inputs/DatePicker/DatePicker.tsx
diff --git a/app/dashboard/src/components/AriaComponents/Inputs/DatePicker/index.ts b/app/gui/src/dashboard/components/AriaComponents/Inputs/DatePicker/index.ts
similarity index 100%
rename from app/dashboard/src/components/AriaComponents/Inputs/DatePicker/index.ts
rename to app/gui/src/dashboard/components/AriaComponents/Inputs/DatePicker/index.ts
diff --git a/app/dashboard/src/components/AriaComponents/Inputs/Dropdown/Dropdown.tsx b/app/gui/src/dashboard/components/AriaComponents/Inputs/Dropdown/Dropdown.tsx
similarity index 100%
rename from app/dashboard/src/components/AriaComponents/Inputs/Dropdown/Dropdown.tsx
rename to app/gui/src/dashboard/components/AriaComponents/Inputs/Dropdown/Dropdown.tsx
diff --git a/app/dashboard/src/components/AriaComponents/Inputs/Dropdown/index.ts b/app/gui/src/dashboard/components/AriaComponents/Inputs/Dropdown/index.ts
similarity index 100%
rename from app/dashboard/src/components/AriaComponents/Inputs/Dropdown/index.ts
rename to app/gui/src/dashboard/components/AriaComponents/Inputs/Dropdown/index.ts
diff --git a/app/dashboard/src/components/AriaComponents/Inputs/Input/Input.tsx b/app/gui/src/dashboard/components/AriaComponents/Inputs/Input/Input.tsx
similarity index 100%
rename from app/dashboard/src/components/AriaComponents/Inputs/Input/Input.tsx
rename to app/gui/src/dashboard/components/AriaComponents/Inputs/Input/Input.tsx
diff --git a/app/dashboard/src/components/AriaComponents/Inputs/Input/index.ts b/app/gui/src/dashboard/components/AriaComponents/Inputs/Input/index.ts
similarity index 100%
rename from app/dashboard/src/components/AriaComponents/Inputs/Input/index.ts
rename to app/gui/src/dashboard/components/AriaComponents/Inputs/Input/index.ts
diff --git a/app/dashboard/src/components/AriaComponents/Inputs/MultiSelector/MultiSelector.tsx b/app/gui/src/dashboard/components/AriaComponents/Inputs/MultiSelector/MultiSelector.tsx
similarity index 100%
rename from app/dashboard/src/components/AriaComponents/Inputs/MultiSelector/MultiSelector.tsx
rename to app/gui/src/dashboard/components/AriaComponents/Inputs/MultiSelector/MultiSelector.tsx
diff --git a/app/dashboard/src/components/AriaComponents/Inputs/MultiSelector/MultiSelectorOption.tsx b/app/gui/src/dashboard/components/AriaComponents/Inputs/MultiSelector/MultiSelectorOption.tsx
similarity index 100%
rename from app/dashboard/src/components/AriaComponents/Inputs/MultiSelector/MultiSelectorOption.tsx
rename to app/gui/src/dashboard/components/AriaComponents/Inputs/MultiSelector/MultiSelectorOption.tsx
diff --git a/app/dashboard/src/components/AriaComponents/Inputs/MultiSelector/index.ts b/app/gui/src/dashboard/components/AriaComponents/Inputs/MultiSelector/index.ts
similarity index 100%
rename from app/dashboard/src/components/AriaComponents/Inputs/MultiSelector/index.ts
rename to app/gui/src/dashboard/components/AriaComponents/Inputs/MultiSelector/index.ts
diff --git a/app/dashboard/src/components/AriaComponents/Inputs/OTPInput/OTPInput.tsx b/app/gui/src/dashboard/components/AriaComponents/Inputs/OTPInput/OTPInput.tsx
similarity index 100%
rename from app/dashboard/src/components/AriaComponents/Inputs/OTPInput/OTPInput.tsx
rename to app/gui/src/dashboard/components/AriaComponents/Inputs/OTPInput/OTPInput.tsx
diff --git a/app/dashboard/src/components/AriaComponents/Inputs/OTPInput/index.ts b/app/gui/src/dashboard/components/AriaComponents/Inputs/OTPInput/index.ts
similarity index 100%
rename from app/dashboard/src/components/AriaComponents/Inputs/OTPInput/index.ts
rename to app/gui/src/dashboard/components/AriaComponents/Inputs/OTPInput/index.ts
diff --git a/app/dashboard/src/components/AriaComponents/Inputs/Password/Password.tsx b/app/gui/src/dashboard/components/AriaComponents/Inputs/Password/Password.tsx
similarity index 89%
rename from app/dashboard/src/components/AriaComponents/Inputs/Password/Password.tsx
rename to app/gui/src/dashboard/components/AriaComponents/Inputs/Password/Password.tsx
index f5e81b5f0a6..d6f971f2ee5 100644
--- a/app/dashboard/src/components/AriaComponents/Inputs/Password/Password.tsx
+++ b/app/gui/src/dashboard/components/AriaComponents/Inputs/Password/Password.tsx
@@ -18,8 +18,10 @@ import {
// ================
/** Props for a {@link Password}. */
-export interface PasswordProps>
- extends Omit, 'type'> {}
+export type PasswordProps> = Omit<
+ InputProps,
+ 'type'
+>
/** A component wrapping {@link Input} with the ability to show and hide password. */
export function Password>>(
diff --git a/app/dashboard/src/components/AriaComponents/Inputs/Password/index.ts b/app/gui/src/dashboard/components/AriaComponents/Inputs/Password/index.ts
similarity index 100%
rename from app/dashboard/src/components/AriaComponents/Inputs/Password/index.ts
rename to app/gui/src/dashboard/components/AriaComponents/Inputs/Password/index.ts
diff --git a/app/dashboard/src/components/AriaComponents/Inputs/ResizableInput/ResizableContentEditableInput.tsx b/app/gui/src/dashboard/components/AriaComponents/Inputs/ResizableInput/ResizableContentEditableInput.tsx
similarity index 100%
rename from app/dashboard/src/components/AriaComponents/Inputs/ResizableInput/ResizableContentEditableInput.tsx
rename to app/gui/src/dashboard/components/AriaComponents/Inputs/ResizableInput/ResizableContentEditableInput.tsx
diff --git a/app/dashboard/src/components/AriaComponents/Inputs/ResizableInput/ResizableInput.tsx b/app/gui/src/dashboard/components/AriaComponents/Inputs/ResizableInput/ResizableInput.tsx
similarity index 100%
rename from app/dashboard/src/components/AriaComponents/Inputs/ResizableInput/ResizableInput.tsx
rename to app/gui/src/dashboard/components/AriaComponents/Inputs/ResizableInput/ResizableInput.tsx
diff --git a/app/dashboard/src/components/AriaComponents/Inputs/ResizableInput/index.ts b/app/gui/src/dashboard/components/AriaComponents/Inputs/ResizableInput/index.ts
similarity index 100%
rename from app/dashboard/src/components/AriaComponents/Inputs/ResizableInput/index.ts
rename to app/gui/src/dashboard/components/AriaComponents/Inputs/ResizableInput/index.ts
diff --git a/app/dashboard/src/components/AriaComponents/Inputs/Selector/Selector.tsx b/app/gui/src/dashboard/components/AriaComponents/Inputs/Selector/Selector.tsx
similarity index 100%
rename from app/dashboard/src/components/AriaComponents/Inputs/Selector/Selector.tsx
rename to app/gui/src/dashboard/components/AriaComponents/Inputs/Selector/Selector.tsx
diff --git a/app/dashboard/src/components/AriaComponents/Inputs/Selector/SelectorOption.tsx b/app/gui/src/dashboard/components/AriaComponents/Inputs/Selector/SelectorOption.tsx
similarity index 100%
rename from app/dashboard/src/components/AriaComponents/Inputs/Selector/SelectorOption.tsx
rename to app/gui/src/dashboard/components/AriaComponents/Inputs/Selector/SelectorOption.tsx
diff --git a/app/dashboard/src/components/AriaComponents/Inputs/Selector/index.ts b/app/gui/src/dashboard/components/AriaComponents/Inputs/Selector/index.ts
similarity index 100%
rename from app/dashboard/src/components/AriaComponents/Inputs/Selector/index.ts
rename to app/gui/src/dashboard/components/AriaComponents/Inputs/Selector/index.ts
diff --git a/app/dashboard/src/components/AriaComponents/Inputs/index.ts b/app/gui/src/dashboard/components/AriaComponents/Inputs/index.ts
similarity index 100%
rename from app/dashboard/src/components/AriaComponents/Inputs/index.ts
rename to app/gui/src/dashboard/components/AriaComponents/Inputs/index.ts
diff --git a/app/dashboard/src/components/AriaComponents/Inputs/variants.ts b/app/gui/src/dashboard/components/AriaComponents/Inputs/variants.ts
similarity index 100%
rename from app/dashboard/src/components/AriaComponents/Inputs/variants.ts
rename to app/gui/src/dashboard/components/AriaComponents/Inputs/variants.ts
diff --git a/app/dashboard/src/components/AriaComponents/Radio/Radio.tsx b/app/gui/src/dashboard/components/AriaComponents/Radio/Radio.tsx
similarity index 100%
rename from app/dashboard/src/components/AriaComponents/Radio/Radio.tsx
rename to app/gui/src/dashboard/components/AriaComponents/Radio/Radio.tsx
diff --git a/app/dashboard/src/components/AriaComponents/Radio/RadioGroup.tsx b/app/gui/src/dashboard/components/AriaComponents/Radio/RadioGroup.tsx
similarity index 100%
rename from app/dashboard/src/components/AriaComponents/Radio/RadioGroup.tsx
rename to app/gui/src/dashboard/components/AriaComponents/Radio/RadioGroup.tsx
diff --git a/app/dashboard/src/components/AriaComponents/Radio/RadioGroupContext.tsx b/app/gui/src/dashboard/components/AriaComponents/Radio/RadioGroupContext.tsx
similarity index 100%
rename from app/dashboard/src/components/AriaComponents/Radio/RadioGroupContext.tsx
rename to app/gui/src/dashboard/components/AriaComponents/Radio/RadioGroupContext.tsx
diff --git a/app/dashboard/src/components/AriaComponents/Radio/index.ts b/app/gui/src/dashboard/components/AriaComponents/Radio/index.ts
similarity index 100%
rename from app/dashboard/src/components/AriaComponents/Radio/index.ts
rename to app/gui/src/dashboard/components/AriaComponents/Radio/index.ts
diff --git a/app/dashboard/src/components/AriaComponents/Separator.tsx b/app/gui/src/dashboard/components/AriaComponents/Separator.tsx
similarity index 100%
rename from app/dashboard/src/components/AriaComponents/Separator.tsx
rename to app/gui/src/dashboard/components/AriaComponents/Separator.tsx
diff --git a/app/dashboard/src/components/AriaComponents/Switch/Switch.tsx b/app/gui/src/dashboard/components/AriaComponents/Switch/Switch.tsx
similarity index 100%
rename from app/dashboard/src/components/AriaComponents/Switch/Switch.tsx
rename to app/gui/src/dashboard/components/AriaComponents/Switch/Switch.tsx
diff --git a/app/dashboard/src/components/AriaComponents/Switch/index.ts b/app/gui/src/dashboard/components/AriaComponents/Switch/index.ts
similarity index 100%
rename from app/dashboard/src/components/AriaComponents/Switch/index.ts
rename to app/gui/src/dashboard/components/AriaComponents/Switch/index.ts
diff --git a/app/dashboard/src/components/AriaComponents/Text/Text.tsx b/app/gui/src/dashboard/components/AriaComponents/Text/Text.tsx
similarity index 100%
rename from app/dashboard/src/components/AriaComponents/Text/Text.tsx
rename to app/gui/src/dashboard/components/AriaComponents/Text/Text.tsx
diff --git a/app/dashboard/src/components/AriaComponents/Text/TextProvider.tsx b/app/gui/src/dashboard/components/AriaComponents/Text/TextProvider.tsx
similarity index 100%
rename from app/dashboard/src/components/AriaComponents/Text/TextProvider.tsx
rename to app/gui/src/dashboard/components/AriaComponents/Text/TextProvider.tsx
diff --git a/app/dashboard/src/components/AriaComponents/Text/index.ts b/app/gui/src/dashboard/components/AriaComponents/Text/index.ts
similarity index 100%
rename from app/dashboard/src/components/AriaComponents/Text/index.ts
rename to app/gui/src/dashboard/components/AriaComponents/Text/index.ts
diff --git a/app/dashboard/src/components/AriaComponents/Text/useVisualTooltip.tsx b/app/gui/src/dashboard/components/AriaComponents/Text/useVisualTooltip.tsx
similarity index 100%
rename from app/dashboard/src/components/AriaComponents/Text/useVisualTooltip.tsx
rename to app/gui/src/dashboard/components/AriaComponents/Text/useVisualTooltip.tsx
diff --git a/app/dashboard/src/components/AriaComponents/Tooltip/Tooltip.tsx b/app/gui/src/dashboard/components/AriaComponents/Tooltip/Tooltip.tsx
similarity index 100%
rename from app/dashboard/src/components/AriaComponents/Tooltip/Tooltip.tsx
rename to app/gui/src/dashboard/components/AriaComponents/Tooltip/Tooltip.tsx
diff --git a/app/dashboard/src/components/AriaComponents/Tooltip/index.ts b/app/gui/src/dashboard/components/AriaComponents/Tooltip/index.ts
similarity index 100%
rename from app/dashboard/src/components/AriaComponents/Tooltip/index.ts
rename to app/gui/src/dashboard/components/AriaComponents/Tooltip/index.ts
diff --git a/app/dashboard/src/components/AriaComponents/VisuallyHidden.tsx b/app/gui/src/dashboard/components/AriaComponents/VisuallyHidden.tsx
similarity index 91%
rename from app/dashboard/src/components/AriaComponents/VisuallyHidden.tsx
rename to app/gui/src/dashboard/components/AriaComponents/VisuallyHidden.tsx
index be6ac07ae51..9198d3d4317 100644
--- a/app/dashboard/src/components/AriaComponents/VisuallyHidden.tsx
+++ b/app/gui/src/dashboard/components/AriaComponents/VisuallyHidden.tsx
@@ -11,7 +11,7 @@ import * as twv from '#/utilities/tailwindVariants'
/**
* Props for the {@link VisuallyHidden} component.
*/
-export interface VisuallyHiddenProps extends React.HTMLProps {}
+export type VisuallyHiddenProps = React.HTMLProps
export const VISUALLY_HIDDEN_STYLES = twv.tv({ base: 'sr-only' })
diff --git a/app/dashboard/src/components/AriaComponents/index.ts b/app/gui/src/dashboard/components/AriaComponents/index.ts
similarity index 100%
rename from app/dashboard/src/components/AriaComponents/index.ts
rename to app/gui/src/dashboard/components/AriaComponents/index.ts
diff --git a/app/dashboard/src/components/AriaComponents/types.ts b/app/gui/src/dashboard/components/AriaComponents/types.ts
similarity index 100%
rename from app/dashboard/src/components/AriaComponents/types.ts
rename to app/gui/src/dashboard/components/AriaComponents/types.ts
diff --git a/app/dashboard/src/components/Autocomplete.tsx b/app/gui/src/dashboard/components/Autocomplete.tsx
similarity index 98%
rename from app/dashboard/src/components/Autocomplete.tsx
rename to app/gui/src/dashboard/components/Autocomplete.tsx
index 3f81110dd68..bde95a2b0a0 100644
--- a/app/dashboard/src/components/Autocomplete.tsx
+++ b/app/gui/src/dashboard/components/Autocomplete.tsx
@@ -55,8 +55,10 @@ interface InternalSingleAutocompleteProps extends InternalBaseAutocompletePro
interface InternalMultipleAutocompleteProps extends InternalBaseAutocompleteProps {
/** Whether selecting multiple values is allowed. */
readonly multiple: true
- /** This is `null` when multiple values are selected, causing the input to switch to a
- * {@link HTMLTextAreaElement}. */
+ /**
+ * This is `null` when multiple values are selected, causing the input to switch to a
+ * {@link HTMLTextAreaElement}.
+ */
readonly inputRef?: MutableRefObject
readonly setValues: (value: readonly T[]) => void
readonly itemsToString: (items: readonly T[]) => string
diff --git a/app/dashboard/src/components/Badge/Badge.tsx b/app/gui/src/dashboard/components/Badge/Badge.tsx
similarity index 100%
rename from app/dashboard/src/components/Badge/Badge.tsx
rename to app/gui/src/dashboard/components/Badge/Badge.tsx
diff --git a/app/dashboard/src/components/Badge/index.ts b/app/gui/src/dashboard/components/Badge/index.ts
similarity index 100%
rename from app/dashboard/src/components/Badge/index.ts
rename to app/gui/src/dashboard/components/Badge/index.ts
diff --git a/app/dashboard/src/components/ColorPicker.tsx b/app/gui/src/dashboard/components/ColorPicker.tsx
similarity index 100%
rename from app/dashboard/src/components/ColorPicker.tsx
rename to app/gui/src/dashboard/components/ColorPicker.tsx
diff --git a/app/dashboard/src/components/ContextMenu.tsx b/app/gui/src/dashboard/components/ContextMenu.tsx
similarity index 100%
rename from app/dashboard/src/components/ContextMenu.tsx
rename to app/gui/src/dashboard/components/ContextMenu.tsx
diff --git a/app/dashboard/src/components/ContextMenuEntry.tsx b/app/gui/src/dashboard/components/ContextMenuEntry.tsx
similarity index 81%
rename from app/dashboard/src/components/ContextMenuEntry.tsx
rename to app/gui/src/dashboard/components/ContextMenuEntry.tsx
index 252751fd9ea..28332f7e470 100644
--- a/app/dashboard/src/components/ContextMenuEntry.tsx
+++ b/app/gui/src/dashboard/components/ContextMenuEntry.tsx
@@ -9,8 +9,7 @@ import MenuEntry from '#/components/MenuEntry'
// ========================
/** Props for a {@link ContextMenuEntry}. */
-export interface ContextMenuEntryProps
- extends Omit {}
+export type ContextMenuEntryProps = Omit
/** An item in a menu. */
export default function ContextMenuEntry(props: ContextMenuEntryProps) {
diff --git a/app/dashboard/src/components/ContextMenus.tsx b/app/gui/src/dashboard/components/ContextMenus.tsx
similarity index 100%
rename from app/dashboard/src/components/ContextMenus.tsx
rename to app/gui/src/dashboard/components/ContextMenus.tsx
diff --git a/app/dashboard/src/components/Devtools/EnsoDevtools.tsx b/app/gui/src/dashboard/components/Devtools/EnsoDevtools.tsx
similarity index 100%
rename from app/dashboard/src/components/Devtools/EnsoDevtools.tsx
rename to app/gui/src/dashboard/components/Devtools/EnsoDevtools.tsx
diff --git a/app/dashboard/src/components/Devtools/EnsoDevtoolsProvider.tsx b/app/gui/src/dashboard/components/Devtools/EnsoDevtoolsProvider.tsx
similarity index 100%
rename from app/dashboard/src/components/Devtools/EnsoDevtoolsProvider.tsx
rename to app/gui/src/dashboard/components/Devtools/EnsoDevtoolsProvider.tsx
diff --git a/app/dashboard/src/components/Devtools/ReactQueryDevtools.tsx b/app/gui/src/dashboard/components/Devtools/ReactQueryDevtools.tsx
similarity index 100%
rename from app/dashboard/src/components/Devtools/ReactQueryDevtools.tsx
rename to app/gui/src/dashboard/components/Devtools/ReactQueryDevtools.tsx
diff --git a/app/dashboard/src/components/Devtools/index.ts b/app/gui/src/dashboard/components/Devtools/index.ts
similarity index 100%
rename from app/dashboard/src/components/Devtools/index.ts
rename to app/gui/src/dashboard/components/Devtools/index.ts
diff --git a/app/dashboard/src/components/EditableSpan.tsx b/app/gui/src/dashboard/components/EditableSpan.tsx
similarity index 100%
rename from app/dashboard/src/components/EditableSpan.tsx
rename to app/gui/src/dashboard/components/EditableSpan.tsx
diff --git a/app/dashboard/src/components/ErrorBoundary.tsx b/app/gui/src/dashboard/components/ErrorBoundary.tsx
similarity index 97%
rename from app/dashboard/src/components/ErrorBoundary.tsx
rename to app/gui/src/dashboard/components/ErrorBoundary.tsx
index 93d990ec57f..50c0e6a8f29 100644
--- a/app/dashboard/src/components/ErrorBoundary.tsx
+++ b/app/gui/src/dashboard/components/ErrorBoundary.tsx
@@ -25,9 +25,11 @@ export interface ErrorBoundaryProps
extends Readonly,
Readonly> {}
-/** Catches errors in child components
+/**
+ * Catches errors in child components
* Shows a fallback UI when there is an error.
- * The error can also be logged to an error reporting service. */
+ * The error can also be logged to an error reporting service.
+ */
export function ErrorBoundary(props: ErrorBoundaryProps) {
const {
FallbackComponent = ErrorDisplay,
diff --git a/app/dashboard/src/components/JSONSchemaInput.tsx b/app/gui/src/dashboard/components/JSONSchemaInput.tsx
similarity index 99%
rename from app/dashboard/src/components/JSONSchemaInput.tsx
rename to app/gui/src/dashboard/components/JSONSchemaInput.tsx
index df1841c19b0..82dac953c4f 100644
--- a/app/dashboard/src/components/JSONSchemaInput.tsx
+++ b/app/gui/src/dashboard/components/JSONSchemaInput.tsx
@@ -237,6 +237,7 @@ export default function JSONSchemaInput(props: JSONSchemaInputProps) {
value={((value ?? {}) as Record)[key] ?? null}
onChange={(newValue) => {
if (typeof newValue === 'function') {
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-call
const unsafeValue: unknown = newValue(
// This is SAFE; but there is no way to tell TypeScript that an object
// has an index signature.
diff --git a/app/dashboard/src/components/Link.tsx b/app/gui/src/dashboard/components/Link.tsx
similarity index 100%
rename from app/dashboard/src/components/Link.tsx
rename to app/gui/src/dashboard/components/Link.tsx
diff --git a/app/dashboard/src/components/Loader.tsx b/app/gui/src/dashboard/components/Loader.tsx
similarity index 100%
rename from app/dashboard/src/components/Loader.tsx
rename to app/gui/src/dashboard/components/Loader.tsx
diff --git a/app/dashboard/src/components/MenuEntry.tsx b/app/gui/src/dashboard/components/MenuEntry.tsx
similarity index 100%
rename from app/dashboard/src/components/MenuEntry.tsx
rename to app/gui/src/dashboard/components/MenuEntry.tsx
diff --git a/app/dashboard/src/components/Modal.tsx b/app/gui/src/dashboard/components/Modal.tsx
similarity index 94%
rename from app/dashboard/src/components/Modal.tsx
rename to app/gui/src/dashboard/components/Modal.tsx
index f5391bb4fd3..134c0095d73 100644
--- a/app/dashboard/src/components/Modal.tsx
+++ b/app/gui/src/dashboard/components/Modal.tsx
@@ -36,9 +36,11 @@ export interface ModalProps
readonly onContextMenu?: React.MouseEventHandler
}
-/** A fullscreen modal with content at the center. The background is fully opaque by default;
+/**
+ * A fullscreen modal with content at the center. The background is fully opaque by default;
* background transparency can be enabled with Tailwind's `bg-opacity` classes, like
- * `className="bg-opacity-50"`. */
+ * `className="bg-opacity-50"`.
+ */
export default function Modal(props: ModalProps) {
const { hidden = false, children, style, onClick, onContextMenu, ...variantProps } = props
const { unsetModal } = modalProvider.useSetModal()
diff --git a/app/dashboard/src/components/OfflineNotificationManager.tsx b/app/gui/src/dashboard/components/OfflineNotificationManager.tsx
similarity index 94%
rename from app/dashboard/src/components/OfflineNotificationManager.tsx
rename to app/gui/src/dashboard/components/OfflineNotificationManager.tsx
index 84803b31a07..21ac6bb27b5 100644
--- a/app/dashboard/src/components/OfflineNotificationManager.tsx
+++ b/app/gui/src/dashboard/components/OfflineNotificationManager.tsx
@@ -17,7 +17,7 @@ import * as textProvider from '#/providers/TextProvider'
/**
* Props for {@link OfflineNotificationManager}
*/
-export interface OfflineNotificationManagerProps extends React.PropsWithChildren {}
+export type OfflineNotificationManagerProps = Readonly
/**
* Context props for {@link OfflineNotificationManager}
diff --git a/app/dashboard/src/components/Page.tsx b/app/gui/src/dashboard/components/Page.tsx
similarity index 100%
rename from app/dashboard/src/components/Page.tsx
rename to app/gui/src/dashboard/components/Page.tsx
diff --git a/app/dashboard/src/components/Paywall/ContextMenuEntry.tsx b/app/gui/src/dashboard/components/Paywall/ContextMenuEntry.tsx
similarity index 100%
rename from app/dashboard/src/components/Paywall/ContextMenuEntry.tsx
rename to app/gui/src/dashboard/components/Paywall/ContextMenuEntry.tsx
diff --git a/app/dashboard/src/components/Paywall/PaywallAlert.tsx b/app/gui/src/dashboard/components/Paywall/PaywallAlert.tsx
similarity index 100%
rename from app/dashboard/src/components/Paywall/PaywallAlert.tsx
rename to app/gui/src/dashboard/components/Paywall/PaywallAlert.tsx
diff --git a/app/dashboard/src/components/Paywall/PaywallDialog.tsx b/app/gui/src/dashboard/components/Paywall/PaywallDialog.tsx
similarity index 100%
rename from app/dashboard/src/components/Paywall/PaywallDialog.tsx
rename to app/gui/src/dashboard/components/Paywall/PaywallDialog.tsx
diff --git a/app/dashboard/src/components/Paywall/PaywallDialogButton.tsx b/app/gui/src/dashboard/components/Paywall/PaywallDialogButton.tsx
similarity index 100%
rename from app/dashboard/src/components/Paywall/PaywallDialogButton.tsx
rename to app/gui/src/dashboard/components/Paywall/PaywallDialogButton.tsx
diff --git a/app/dashboard/src/components/Paywall/PaywallScreen.tsx b/app/gui/src/dashboard/components/Paywall/PaywallScreen.tsx
similarity index 100%
rename from app/dashboard/src/components/Paywall/PaywallScreen.tsx
rename to app/gui/src/dashboard/components/Paywall/PaywallScreen.tsx
diff --git a/app/dashboard/src/components/Paywall/UpgradeButton.tsx b/app/gui/src/dashboard/components/Paywall/UpgradeButton.tsx
similarity index 100%
rename from app/dashboard/src/components/Paywall/UpgradeButton.tsx
rename to app/gui/src/dashboard/components/Paywall/UpgradeButton.tsx
diff --git a/app/dashboard/src/components/Paywall/components/PaywallBulletPoints.tsx b/app/gui/src/dashboard/components/Paywall/components/PaywallBulletPoints.tsx
similarity index 100%
rename from app/dashboard/src/components/Paywall/components/PaywallBulletPoints.tsx
rename to app/gui/src/dashboard/components/Paywall/components/PaywallBulletPoints.tsx
diff --git a/app/dashboard/src/components/Paywall/components/PaywallButton.tsx b/app/gui/src/dashboard/components/Paywall/components/PaywallButton.tsx
similarity index 100%
rename from app/dashboard/src/components/Paywall/components/PaywallButton.tsx
rename to app/gui/src/dashboard/components/Paywall/components/PaywallButton.tsx
diff --git a/app/dashboard/src/components/Paywall/components/PaywallLock.tsx b/app/gui/src/dashboard/components/Paywall/components/PaywallLock.tsx
similarity index 100%
rename from app/dashboard/src/components/Paywall/components/PaywallLock.tsx
rename to app/gui/src/dashboard/components/Paywall/components/PaywallLock.tsx
diff --git a/app/dashboard/src/components/Paywall/components/index.ts b/app/gui/src/dashboard/components/Paywall/components/index.ts
similarity index 100%
rename from app/dashboard/src/components/Paywall/components/index.ts
rename to app/gui/src/dashboard/components/Paywall/components/index.ts
diff --git a/app/dashboard/src/components/Paywall/index.ts b/app/gui/src/dashboard/components/Paywall/index.ts
similarity index 100%
rename from app/dashboard/src/components/Paywall/index.ts
rename to app/gui/src/dashboard/components/Paywall/index.ts
diff --git a/app/dashboard/src/components/Portal/Portal.tsx b/app/gui/src/dashboard/components/Portal/Portal.tsx
similarity index 93%
rename from app/dashboard/src/components/Portal/Portal.tsx
rename to app/gui/src/dashboard/components/Portal/Portal.tsx
index bfa2e7298b1..2a83e2c8c0b 100644
--- a/app/dashboard/src/components/Portal/Portal.tsx
+++ b/app/gui/src/dashboard/components/Portal/Portal.tsx
@@ -6,7 +6,8 @@ import * as reactDom from 'react-dom'
import type * as types from './types'
import * as usePortal from './usePortal'
-/** This component renders its children outside the current DOM hierarchy.
+/**
+ * This component renders its children outside the current DOM hierarchy.
*
* React [doesn't support](https://github.com/facebook/react/issues/13097) portal API in SSR, so, if you want to
* render a Portal in SSR, use prop `disabled`.
diff --git a/app/dashboard/src/components/Portal/PortalProvider.ts b/app/gui/src/dashboard/components/Portal/PortalProvider.ts
similarity index 100%
rename from app/dashboard/src/components/Portal/PortalProvider.ts
rename to app/gui/src/dashboard/components/Portal/PortalProvider.ts
diff --git a/app/dashboard/src/components/Portal/index.ts b/app/gui/src/dashboard/components/Portal/index.ts
similarity index 100%
rename from app/dashboard/src/components/Portal/index.ts
rename to app/gui/src/dashboard/components/Portal/index.ts
diff --git a/app/dashboard/src/components/Portal/types.ts b/app/gui/src/dashboard/components/Portal/types.ts
similarity index 100%
rename from app/dashboard/src/components/Portal/types.ts
rename to app/gui/src/dashboard/components/Portal/types.ts
diff --git a/app/dashboard/src/components/Portal/usePortal.ts b/app/gui/src/dashboard/components/Portal/usePortal.ts
similarity index 100%
rename from app/dashboard/src/components/Portal/usePortal.ts
rename to app/gui/src/dashboard/components/Portal/usePortal.ts
diff --git a/app/dashboard/src/components/README.md b/app/gui/src/dashboard/components/README.md
similarity index 100%
rename from app/dashboard/src/components/README.md
rename to app/gui/src/dashboard/components/README.md
diff --git a/app/dashboard/src/components/Result.tsx b/app/gui/src/dashboard/components/Result.tsx
similarity index 98%
rename from app/dashboard/src/components/Result.tsx
rename to app/gui/src/dashboard/components/Result.tsx
index 8b97af7e200..8be17c8971a 100644
--- a/app/dashboard/src/components/Result.tsx
+++ b/app/gui/src/dashboard/components/Result.tsx
@@ -95,8 +95,10 @@ export interface ResultProps extends React.PropsWithChildren, VariantProps` custom Tailwind
- * classes. */
+/**
+ * @file A spinning arc that animates using the `dasharray-` custom Tailwind
+ * classes.
+ */
import * as React from 'react'
import * as tailwindMerge from '#/utilities/tailwindMerge'
diff --git a/app/dashboard/src/components/StatelessSpinner.tsx b/app/gui/src/dashboard/components/StatelessSpinner.tsx
similarity index 86%
rename from app/dashboard/src/components/StatelessSpinner.tsx
rename to app/gui/src/dashboard/components/StatelessSpinner.tsx
index 308a2d4d6aa..3c418c33e24 100644
--- a/app/dashboard/src/components/StatelessSpinner.tsx
+++ b/app/gui/src/dashboard/components/StatelessSpinner.tsx
@@ -12,10 +12,12 @@ import Spinner, * as spinner from '#/components/Spinner'
export { SpinnerState } from './Spinner'
/** Props for a {@link StatelessSpinner}. */
-export interface StatelessSpinnerProps extends spinner.SpinnerProps {}
+export type StatelessSpinnerProps = spinner.SpinnerProps
-/** A spinner that does not expose its {@link spinner.SpinnerState}. Instead, it begins at
- * {@link spinner.SpinnerState.initial} and immediately changes to the given state. */
+/**
+ * A spinner that does not expose its {@link spinner.SpinnerState}. Instead, it begins at
+ * {@link spinner.SpinnerState.initial} and immediately changes to the given state.
+ */
export default function StatelessSpinner(props: StatelessSpinnerProps) {
const { size, state: rawState, ...spinnerProps } = props
const [, startTransition] = React.useTransition()
diff --git a/app/dashboard/src/components/Stepper/Step.tsx b/app/gui/src/dashboard/components/Stepper/Step.tsx
similarity index 100%
rename from app/dashboard/src/components/Stepper/Step.tsx
rename to app/gui/src/dashboard/components/Stepper/Step.tsx
diff --git a/app/dashboard/src/components/Stepper/StepContent.tsx b/app/gui/src/dashboard/components/Stepper/StepContent.tsx
similarity index 100%
rename from app/dashboard/src/components/Stepper/StepContent.tsx
rename to app/gui/src/dashboard/components/Stepper/StepContent.tsx
diff --git a/app/dashboard/src/components/Stepper/Stepper.tsx b/app/gui/src/dashboard/components/Stepper/Stepper.tsx
similarity index 100%
rename from app/dashboard/src/components/Stepper/Stepper.tsx
rename to app/gui/src/dashboard/components/Stepper/Stepper.tsx
diff --git a/app/dashboard/src/components/Stepper/StepperProvider.tsx b/app/gui/src/dashboard/components/Stepper/StepperProvider.tsx
similarity index 98%
rename from app/dashboard/src/components/Stepper/StepperProvider.tsx
rename to app/gui/src/dashboard/components/Stepper/StepperProvider.tsx
index c3566b6f5cc..0d9d2175464 100644
--- a/app/dashboard/src/components/Stepper/StepperProvider.tsx
+++ b/app/gui/src/dashboard/components/Stepper/StepperProvider.tsx
@@ -25,7 +25,7 @@ const StepperContext = React.createContext(null)
/**
* Hook to use the stepper context
- * @private
+ * @internal
*/
export function useStepperContext() {
const context = React.useContext(StepperContext)
diff --git a/app/dashboard/src/components/Stepper/index.ts b/app/gui/src/dashboard/components/Stepper/index.ts
similarity index 100%
rename from app/dashboard/src/components/Stepper/index.ts
rename to app/gui/src/dashboard/components/Stepper/index.ts
diff --git a/app/dashboard/src/components/Stepper/types.ts b/app/gui/src/dashboard/components/Stepper/types.ts
similarity index 100%
rename from app/dashboard/src/components/Stepper/types.ts
rename to app/gui/src/dashboard/components/Stepper/types.ts
diff --git a/app/dashboard/src/components/Stepper/useStepperState.ts b/app/gui/src/dashboard/components/Stepper/useStepperState.ts
similarity index 100%
rename from app/dashboard/src/components/Stepper/useStepperState.ts
rename to app/gui/src/dashboard/components/Stepper/useStepperState.ts
diff --git a/app/dashboard/src/components/SubmitButton.tsx b/app/gui/src/dashboard/components/SubmitButton.tsx
similarity index 100%
rename from app/dashboard/src/components/SubmitButton.tsx
rename to app/gui/src/dashboard/components/SubmitButton.tsx
diff --git a/app/dashboard/src/components/Suspense.tsx b/app/gui/src/dashboard/components/Suspense.tsx
similarity index 100%
rename from app/dashboard/src/components/Suspense.tsx
rename to app/gui/src/dashboard/components/Suspense.tsx
diff --git a/app/dashboard/src/components/SvgIcon.tsx b/app/gui/src/dashboard/components/SvgIcon.tsx
similarity index 100%
rename from app/dashboard/src/components/SvgIcon.tsx
rename to app/gui/src/dashboard/components/SvgIcon.tsx
diff --git a/app/dashboard/src/components/SvgMask.tsx b/app/gui/src/dashboard/components/SvgMask.tsx
similarity index 100%
rename from app/dashboard/src/components/SvgMask.tsx
rename to app/gui/src/dashboard/components/SvgMask.tsx
diff --git a/app/dashboard/src/components/TextLink.tsx b/app/gui/src/dashboard/components/TextLink.tsx
similarity index 100%
rename from app/dashboard/src/components/TextLink.tsx
rename to app/gui/src/dashboard/components/TextLink.tsx
diff --git a/app/dashboard/src/components/Twemoji.tsx b/app/gui/src/dashboard/components/Twemoji.tsx
similarity index 93%
rename from app/dashboard/src/components/Twemoji.tsx
rename to app/gui/src/dashboard/components/Twemoji.tsx
index 75289bd8da1..46a952ad02c 100644
--- a/app/dashboard/src/components/Twemoji.tsx
+++ b/app/gui/src/dashboard/components/Twemoji.tsx
@@ -19,8 +19,10 @@ export interface TwemojiProps {
}
// Only accepts strings that are two code points - for example, emojis.
-/** Returns the input type if it consists of two codepoints. Otherwise, it returns
- * an error message. */
+/**
+ * Returns the input type if it consists of two codepoints. Otherwise, it returns
+ * an error message.
+ */
type MustBeLength2String =
T extends `${string}${string}${infer Rest}` ?
Rest extends '' ?
diff --git a/app/dashboard/src/components/UIProviders.tsx b/app/gui/src/dashboard/components/UIProviders.tsx
similarity index 100%
rename from app/dashboard/src/components/UIProviders.tsx
rename to app/gui/src/dashboard/components/UIProviders.tsx
diff --git a/app/dashboard/src/components/aria.tsx b/app/gui/src/dashboard/components/aria.tsx
similarity index 95%
rename from app/dashboard/src/components/aria.tsx
rename to app/gui/src/dashboard/components/aria.tsx
index 3e26dcd48f5..5f019d08bda 100644
--- a/app/dashboard/src/components/aria.tsx
+++ b/app/gui/src/dashboard/components/aria.tsx
@@ -15,12 +15,14 @@ export { useTooltipTriggerState, type OverlayTriggerState } from 'react-stately'
// === mergeProps ===
// ==================
-/** Merges multiple props objects together.
+/**
+ * Merges multiple props objects together.
* Event handlers are chained, classNames are combined, and ids are deduplicated -
* different ids will trigger a side-effect and re-render components hooked up with `useId`.
* For all other props, the last prop object overrides all previous ones.
*
- * The constraint is defaulted to `never` to make an explicit constraint mandatory. */
+ * The constraint is defaulted to `never` to make an explicit constraint mandatory.
+ */
export function mergeProps() {
return | null | undefined)[]>(
...args: T & { [K in keyof T]: Pick }
diff --git a/app/dashboard/src/components/dashboard/AssetIcon.tsx b/app/gui/src/dashboard/components/dashboard/AssetIcon.tsx
similarity index 100%
rename from app/dashboard/src/components/dashboard/AssetIcon.tsx
rename to app/gui/src/dashboard/components/dashboard/AssetIcon.tsx
diff --git a/app/dashboard/src/components/dashboard/AssetRow.tsx b/app/gui/src/dashboard/components/dashboard/AssetRow.tsx
similarity index 99%
rename from app/dashboard/src/components/dashboard/AssetRow.tsx
rename to app/gui/src/dashboard/components/dashboard/AssetRow.tsx
index c8dae90fed2..3b08d83f41c 100644
--- a/app/dashboard/src/components/dashboard/AssetRow.tsx
+++ b/app/gui/src/dashboard/components/dashboard/AssetRow.tsx
@@ -57,8 +57,10 @@ import { useMutation, useQuery } from '@tanstack/react-query'
/** The height of the header row. */
const HEADER_HEIGHT_PX = 40
-/** The amount of time (in milliseconds) the drag item must be held over this component
- * to make a directory row expand. */
+/**
+ * The amount of time (in milliseconds) the drag item must be held over this component
+ * to make a directory row expand.
+ */
const DRAG_EXPAND_DELAY_MS = 500
// ================
diff --git a/app/dashboard/src/components/dashboard/AssetRow/assetRowUtils.tsx b/app/gui/src/dashboard/components/dashboard/AssetRow/assetRowUtils.tsx
similarity index 100%
rename from app/dashboard/src/components/dashboard/AssetRow/assetRowUtils.tsx
rename to app/gui/src/dashboard/components/dashboard/AssetRow/assetRowUtils.tsx
diff --git a/app/dashboard/src/components/dashboard/AssetSummary.tsx b/app/gui/src/dashboard/components/dashboard/AssetSummary.tsx
similarity index 100%
rename from app/dashboard/src/components/dashboard/AssetSummary.tsx
rename to app/gui/src/dashboard/components/dashboard/AssetSummary.tsx
diff --git a/app/dashboard/src/components/dashboard/DatalinkInput.tsx b/app/gui/src/dashboard/components/dashboard/DatalinkInput.tsx
similarity index 92%
rename from app/dashboard/src/components/dashboard/DatalinkInput.tsx
rename to app/gui/src/dashboard/components/dashboard/DatalinkInput.tsx
index f9653c30faf..89605b4ee2e 100644
--- a/app/dashboard/src/components/dashboard/DatalinkInput.tsx
+++ b/app/gui/src/dashboard/components/dashboard/DatalinkInput.tsx
@@ -20,8 +20,10 @@ const DEFS: Record = SCHEMA.$defs
// === getValidator ===
// ====================
-/** Get a known schema using a path.
- * @throws {Error} when there is no schema present at the given path. */
+/**
+ * Get a known schema using a path.
+ * @throws {Error} when there is no schema present at the given path.
+ */
function getValidator(path: string) {
return error.assert<(value: unknown) => boolean>(() => datalinkValidator.AJV.getSchema(path))
}
@@ -31,8 +33,10 @@ function getValidator(path: string) {
// =====================
/** Props for a {@link DatalinkInput}. */
-export interface DatalinkInputProps
- extends Omit {}
+export type DatalinkInputProps = Omit<
+ jsonSchemaInput.JSONSchemaInputProps,
+ 'defs' | 'getValidator' | 'path' | 'schema'
+>
/** A dynamic wizard for creating an arbitrary type of Datalink. */
export default function DatalinkInput(props: DatalinkInputProps) {
diff --git a/app/dashboard/src/components/dashboard/DatalinkNameColumn.tsx b/app/gui/src/dashboard/components/dashboard/DatalinkNameColumn.tsx
similarity index 96%
rename from app/dashboard/src/components/dashboard/DatalinkNameColumn.tsx
rename to app/gui/src/dashboard/components/dashboard/DatalinkNameColumn.tsx
index ac416307c60..6ade7168041 100644
--- a/app/dashboard/src/components/dashboard/DatalinkNameColumn.tsx
+++ b/app/gui/src/dashboard/components/dashboard/DatalinkNameColumn.tsx
@@ -24,9 +24,11 @@ export interface DatalinkNameColumnProps extends column.AssetColumnProps {
readonly item: AssetTreeNode
}
-/** The icon and name of a {@link backendModule.DatalinkAsset}.
+/**
+ * The icon and name of a {@link backendModule.DatalinkAsset}.
* @throws {Error} when the asset is not a {@link backendModule.DatalinkAsset}.
- * This should never happen. */
+ * This should never happen.
+ */
export default function DatalinkNameColumn(props: DatalinkNameColumnProps) {
const { item, setItem, selected, rowState, setRowState, isEditable } = props
const setIsAssetPanelTemporarilyVisible = useSetIsAssetPanelTemporarilyVisible()
diff --git a/app/dashboard/src/components/dashboard/DirectoryNameColumn.tsx b/app/gui/src/dashboard/components/dashboard/DirectoryNameColumn.tsx
similarity index 97%
rename from app/dashboard/src/components/dashboard/DirectoryNameColumn.tsx
rename to app/gui/src/dashboard/components/dashboard/DirectoryNameColumn.tsx
index 58ce666c2f1..49df8a8aa65 100644
--- a/app/dashboard/src/components/dashboard/DirectoryNameColumn.tsx
+++ b/app/gui/src/dashboard/components/dashboard/DirectoryNameColumn.tsx
@@ -35,9 +35,11 @@ export interface DirectoryNameColumnProps extends column.AssetColumnProps {
readonly item: AssetTreeNode
}
-/** The icon and name of a {@link backendModule.DirectoryAsset}.
+/**
+ * The icon and name of a {@link backendModule.DirectoryAsset}.
* @throws {Error} when the asset is not a {@link backendModule.DirectoryAsset}.
- * This should never happen. */
+ * This should never happen.
+ */
export default function DirectoryNameColumn(props: DirectoryNameColumnProps) {
const { item, setItem, selected, state, rowState, setRowState, isEditable } = props
const { backend, nodeMap } = state
diff --git a/app/dashboard/src/components/dashboard/FileNameColumn.tsx b/app/gui/src/dashboard/components/dashboard/FileNameColumn.tsx
similarity index 97%
rename from app/dashboard/src/components/dashboard/FileNameColumn.tsx
rename to app/gui/src/dashboard/components/dashboard/FileNameColumn.tsx
index dc90008146d..c1a69d21b0f 100644
--- a/app/dashboard/src/components/dashboard/FileNameColumn.tsx
+++ b/app/gui/src/dashboard/components/dashboard/FileNameColumn.tsx
@@ -28,9 +28,11 @@ export interface FileNameColumnProps extends column.AssetColumnProps {
readonly item: AssetTreeNode
}
-/** The icon and name of a {@link backendModule.FileAsset}.
+/**
+ * The icon and name of a {@link backendModule.FileAsset}.
* @throws {Error} when the asset is not a {@link backendModule.FileAsset}.
- * This should never happen. */
+ * This should never happen.
+ */
export default function FileNameColumn(props: FileNameColumnProps) {
const { item, setItem, selected, state, rowState, setRowState, isEditable } = props
const { backend, nodeMap } = state
diff --git a/app/dashboard/src/components/dashboard/KeyboardShortcut.tsx b/app/gui/src/dashboard/components/dashboard/KeyboardShortcut.tsx
similarity index 100%
rename from app/dashboard/src/components/dashboard/KeyboardShortcut.tsx
rename to app/gui/src/dashboard/components/dashboard/KeyboardShortcut.tsx
diff --git a/app/dashboard/src/components/dashboard/Label.tsx b/app/gui/src/dashboard/components/dashboard/Label.tsx
similarity index 96%
rename from app/dashboard/src/components/dashboard/Label.tsx
rename to app/gui/src/dashboard/components/dashboard/Label.tsx
index 4768ec3c58a..b224ab0d1f2 100644
--- a/app/dashboard/src/components/dashboard/Label.tsx
+++ b/app/gui/src/dashboard/components/dashboard/Label.tsx
@@ -18,8 +18,10 @@ interface InternalLabelProps extends Readonly {
readonly 'data-testid'?: string
/** When true, the button is not faded out even when not hovered. */
readonly active?: boolean
- /** When true, the button has a red border signifying that it will be deleted,
- * or that it is excluded from search. */
+ /**
+ * When true, the button has a red border signifying that it will be deleted,
+ * or that it is excluded from search.
+ */
readonly negated?: boolean
/** When true, the button cannot be clicked. */
readonly isDisabled?: boolean
diff --git a/app/dashboard/src/components/dashboard/Permission.tsx b/app/gui/src/dashboard/components/dashboard/Permission.tsx
similarity index 100%
rename from app/dashboard/src/components/dashboard/Permission.tsx
rename to app/gui/src/dashboard/components/dashboard/Permission.tsx
diff --git a/app/dashboard/src/components/dashboard/PermissionDisplay.tsx b/app/gui/src/dashboard/components/dashboard/PermissionDisplay.tsx
similarity index 100%
rename from app/dashboard/src/components/dashboard/PermissionDisplay.tsx
rename to app/gui/src/dashboard/components/dashboard/PermissionDisplay.tsx
diff --git a/app/dashboard/src/components/dashboard/PermissionSelector.tsx b/app/gui/src/dashboard/components/dashboard/PermissionSelector.tsx
similarity index 98%
rename from app/dashboard/src/components/dashboard/PermissionSelector.tsx
rename to app/gui/src/dashboard/components/dashboard/PermissionSelector.tsx
index f2b38ec1f73..e87ad357a7f 100644
--- a/app/dashboard/src/components/dashboard/PermissionSelector.tsx
+++ b/app/gui/src/dashboard/components/dashboard/PermissionSelector.tsx
@@ -20,8 +20,10 @@ import * as tailwindMerge from '#/utilities/tailwindMerge'
const TYPE_SELECTOR_X_OFFSET_PX = -8
/** The vertical offset of the {@link PermissionTypeSelector} from its parent element. */
const TYPE_SELECTOR_Y_OFFSET_PX = 28
-/** The vertical offset of the label's clip path from its parent element.
- * Optimized for 100% zoom. */
+/**
+ * The vertical offset of the label's clip path from its parent element.
+ * Optimized for 100% zoom.
+ */
const LABEL_CLIP_Y_OFFSET_PX = 0.5
/** The border radius of the permission label. */
const LABEL_BORDER_RADIUS_PX = 12
diff --git a/app/dashboard/src/components/dashboard/PermissionTypeSelector.tsx b/app/gui/src/dashboard/components/dashboard/PermissionTypeSelector.tsx
similarity index 100%
rename from app/dashboard/src/components/dashboard/PermissionTypeSelector.tsx
rename to app/gui/src/dashboard/components/dashboard/PermissionTypeSelector.tsx
diff --git a/app/dashboard/src/components/dashboard/ProjectIcon.tsx b/app/gui/src/dashboard/components/dashboard/ProjectIcon.tsx
similarity index 96%
rename from app/dashboard/src/components/dashboard/ProjectIcon.tsx
rename to app/gui/src/dashboard/components/dashboard/ProjectIcon.tsx
index 199eaeb9df7..99db417b7ee 100644
--- a/app/dashboard/src/components/dashboard/ProjectIcon.tsx
+++ b/app/gui/src/dashboard/components/dashboard/ProjectIcon.tsx
@@ -27,8 +27,10 @@ import { useMemo } from 'react'
export const CLOSED_PROJECT_STATE = { type: backendModule.ProjectState.closed } as const
-/** The corresponding {@link spinner.SpinnerState} for each {@link backendModule.ProjectState},
- * when using the remote backend. */
+/**
+ * The corresponding {@link spinner.SpinnerState} for each {@link backendModule.ProjectState},
+ * when using the remote backend.
+ */
const REMOTE_SPINNER_STATE: Readonly> = {
[backendModule.ProjectState.closed]: spinner.SpinnerState.loadingSlow,
[backendModule.ProjectState.closing]: spinner.SpinnerState.loadingMedium,
@@ -40,8 +42,10 @@ const REMOTE_SPINNER_STATE: Readonly> = {
[backendModule.ProjectState.closed]: spinner.SpinnerState.loadingSlow,
[backendModule.ProjectState.closing]: spinner.SpinnerState.loadingMedium,
@@ -144,7 +148,6 @@ export default function ProjectIcon(props: ProjectIconProps) {
}
switch (state) {
- case null:
case backendModule.ProjectState.new:
case backendModule.ProjectState.closing:
case backendModule.ProjectState.closed:
diff --git a/app/dashboard/src/components/dashboard/ProjectNameColumn.tsx b/app/gui/src/dashboard/components/dashboard/ProjectNameColumn.tsx
similarity index 98%
rename from app/dashboard/src/components/dashboard/ProjectNameColumn.tsx
rename to app/gui/src/dashboard/components/dashboard/ProjectNameColumn.tsx
index 9d5349d6acb..555fec7e442 100644
--- a/app/dashboard/src/components/dashboard/ProjectNameColumn.tsx
+++ b/app/gui/src/dashboard/components/dashboard/ProjectNameColumn.tsx
@@ -35,9 +35,11 @@ export interface ProjectNameColumnProps extends column.AssetColumnProps {
readonly item: AssetTreeNode
}
-/** The icon and name of a {@link backendModule.ProjectAsset}.
+/**
+ * The icon and name of a {@link backendModule.ProjectAsset}.
* @throws {Error} when the asset is not a {@link backendModule.ProjectAsset}.
- * This should never happen. */
+ * This should never happen.
+ */
export default function ProjectNameColumn(props: ProjectNameColumnProps) {
const {
item,
diff --git a/app/dashboard/src/components/dashboard/SecretNameColumn.tsx b/app/gui/src/dashboard/components/dashboard/SecretNameColumn.tsx
similarity index 96%
rename from app/dashboard/src/components/dashboard/SecretNameColumn.tsx
rename to app/gui/src/dashboard/components/dashboard/SecretNameColumn.tsx
index 241883b5365..3527fd29045 100644
--- a/app/dashboard/src/components/dashboard/SecretNameColumn.tsx
+++ b/app/gui/src/dashboard/components/dashboard/SecretNameColumn.tsx
@@ -31,9 +31,11 @@ export interface SecretNameColumnProps extends column.AssetColumnProps {
readonly item: AssetTreeNode
}
-/** The icon and name of a {@link backendModule.SecretAsset}.
+/**
+ * The icon and name of a {@link backendModule.SecretAsset}.
* @throws {Error} when the asset is not a {@link backendModule.SecretAsset}.
- * This should never happen. */
+ * This should never happen.
+ */
export default function SecretNameColumn(props: SecretNameColumnProps) {
const { item, selected, state, rowState, setRowState, isEditable } = props
const { backend } = state
diff --git a/app/dashboard/src/components/dashboard/TheModal.tsx b/app/gui/src/dashboard/components/dashboard/TheModal.tsx
similarity index 100%
rename from app/dashboard/src/components/dashboard/TheModal.tsx
rename to app/gui/src/dashboard/components/dashboard/TheModal.tsx
diff --git a/app/dashboard/src/components/dashboard/column.ts b/app/gui/src/dashboard/components/dashboard/column.ts
similarity index 100%
rename from app/dashboard/src/components/dashboard/column.ts
rename to app/gui/src/dashboard/components/dashboard/column.ts
diff --git a/app/dashboard/src/components/dashboard/column/DocsColumn.tsx b/app/gui/src/dashboard/components/dashboard/column/DocsColumn.tsx
similarity index 100%
rename from app/dashboard/src/components/dashboard/column/DocsColumn.tsx
rename to app/gui/src/dashboard/components/dashboard/column/DocsColumn.tsx
diff --git a/app/dashboard/src/components/dashboard/column/LabelsColumn.tsx b/app/gui/src/dashboard/components/dashboard/column/LabelsColumn.tsx
similarity index 100%
rename from app/dashboard/src/components/dashboard/column/LabelsColumn.tsx
rename to app/gui/src/dashboard/components/dashboard/column/LabelsColumn.tsx
diff --git a/app/dashboard/src/components/dashboard/column/ModifiedColumn.tsx b/app/gui/src/dashboard/components/dashboard/column/ModifiedColumn.tsx
similarity index 100%
rename from app/dashboard/src/components/dashboard/column/ModifiedColumn.tsx
rename to app/gui/src/dashboard/components/dashboard/column/ModifiedColumn.tsx
diff --git a/app/dashboard/src/components/dashboard/column/NameColumn.tsx b/app/gui/src/dashboard/components/dashboard/column/NameColumn.tsx
similarity index 95%
rename from app/dashboard/src/components/dashboard/column/NameColumn.tsx
rename to app/gui/src/dashboard/components/dashboard/column/NameColumn.tsx
index 1249db6ad10..d510a00508a 100644
--- a/app/dashboard/src/components/dashboard/column/NameColumn.tsx
+++ b/app/gui/src/dashboard/components/dashboard/column/NameColumn.tsx
@@ -15,7 +15,7 @@ import * as backendModule from '#/services/Backend'
// =================
/** Props for a {@link AssetNameColumn}. */
-export interface AssetNameColumnProps extends column.AssetColumnProps {}
+export type AssetNameColumnProps = column.AssetColumnProps
/** The icon and name of an {@link backendModule.Asset}. */
export default function AssetNameColumn(props: AssetNameColumnProps) {
diff --git a/app/dashboard/src/components/dashboard/column/PlaceholderColumn.tsx b/app/gui/src/dashboard/components/dashboard/column/PlaceholderColumn.tsx
similarity index 100%
rename from app/dashboard/src/components/dashboard/column/PlaceholderColumn.tsx
rename to app/gui/src/dashboard/components/dashboard/column/PlaceholderColumn.tsx
diff --git a/app/dashboard/src/components/dashboard/column/SharedWithColumn.tsx b/app/gui/src/dashboard/components/dashboard/column/SharedWithColumn.tsx
similarity index 100%
rename from app/dashboard/src/components/dashboard/column/SharedWithColumn.tsx
rename to app/gui/src/dashboard/components/dashboard/column/SharedWithColumn.tsx
diff --git a/app/dashboard/src/components/dashboard/column/columnUtils.ts b/app/gui/src/dashboard/components/dashboard/column/columnUtils.ts
similarity index 100%
rename from app/dashboard/src/components/dashboard/column/columnUtils.ts
rename to app/gui/src/dashboard/components/dashboard/column/columnUtils.ts
diff --git a/app/dashboard/src/components/dashboard/columnHeading.ts b/app/gui/src/dashboard/components/dashboard/columnHeading.ts
similarity index 100%
rename from app/dashboard/src/components/dashboard/columnHeading.ts
rename to app/gui/src/dashboard/components/dashboard/columnHeading.ts
diff --git a/app/dashboard/src/components/dashboard/columnHeading/AccessedByProjectsColumnHeading.tsx b/app/gui/src/dashboard/components/dashboard/columnHeading/AccessedByProjectsColumnHeading.tsx
similarity index 100%
rename from app/dashboard/src/components/dashboard/columnHeading/AccessedByProjectsColumnHeading.tsx
rename to app/gui/src/dashboard/components/dashboard/columnHeading/AccessedByProjectsColumnHeading.tsx
diff --git a/app/dashboard/src/components/dashboard/columnHeading/AccessedDataColumnHeading.tsx b/app/gui/src/dashboard/components/dashboard/columnHeading/AccessedDataColumnHeading.tsx
similarity index 100%
rename from app/dashboard/src/components/dashboard/columnHeading/AccessedDataColumnHeading.tsx
rename to app/gui/src/dashboard/components/dashboard/columnHeading/AccessedDataColumnHeading.tsx
diff --git a/app/dashboard/src/components/dashboard/columnHeading/DocsColumnHeading.tsx b/app/gui/src/dashboard/components/dashboard/columnHeading/DocsColumnHeading.tsx
similarity index 100%
rename from app/dashboard/src/components/dashboard/columnHeading/DocsColumnHeading.tsx
rename to app/gui/src/dashboard/components/dashboard/columnHeading/DocsColumnHeading.tsx
diff --git a/app/dashboard/src/components/dashboard/columnHeading/LabelsColumnHeading.tsx b/app/gui/src/dashboard/components/dashboard/columnHeading/LabelsColumnHeading.tsx
similarity index 100%
rename from app/dashboard/src/components/dashboard/columnHeading/LabelsColumnHeading.tsx
rename to app/gui/src/dashboard/components/dashboard/columnHeading/LabelsColumnHeading.tsx
diff --git a/app/dashboard/src/components/dashboard/columnHeading/ModifiedColumnHeading.tsx b/app/gui/src/dashboard/components/dashboard/columnHeading/ModifiedColumnHeading.tsx
similarity index 100%
rename from app/dashboard/src/components/dashboard/columnHeading/ModifiedColumnHeading.tsx
rename to app/gui/src/dashboard/components/dashboard/columnHeading/ModifiedColumnHeading.tsx
diff --git a/app/dashboard/src/components/dashboard/columnHeading/NameColumnHeading.tsx b/app/gui/src/dashboard/components/dashboard/columnHeading/NameColumnHeading.tsx
similarity index 100%
rename from app/dashboard/src/components/dashboard/columnHeading/NameColumnHeading.tsx
rename to app/gui/src/dashboard/components/dashboard/columnHeading/NameColumnHeading.tsx
diff --git a/app/dashboard/src/components/dashboard/columnHeading/SharedWithColumnHeading.tsx b/app/gui/src/dashboard/components/dashboard/columnHeading/SharedWithColumnHeading.tsx
similarity index 100%
rename from app/dashboard/src/components/dashboard/columnHeading/SharedWithColumnHeading.tsx
rename to app/gui/src/dashboard/components/dashboard/columnHeading/SharedWithColumnHeading.tsx
diff --git a/app/dashboard/src/components/styled/FocusArea.tsx b/app/gui/src/dashboard/components/styled/FocusArea.tsx
similarity index 100%
rename from app/dashboard/src/components/styled/FocusArea.tsx
rename to app/gui/src/dashboard/components/styled/FocusArea.tsx
diff --git a/app/dashboard/src/components/styled/FocusRing.tsx b/app/gui/src/dashboard/components/styled/FocusRing.tsx
similarity index 89%
rename from app/dashboard/src/components/styled/FocusRing.tsx
rename to app/gui/src/dashboard/components/styled/FocusRing.tsx
index c2c85896705..3690f41f969 100644
--- a/app/dashboard/src/components/styled/FocusRing.tsx
+++ b/app/gui/src/dashboard/components/styled/FocusRing.tsx
@@ -14,8 +14,10 @@ export type FocusRingPlacement = 'after' | 'before' | 'outset'
export interface FocusRingProps extends Readonly> {
/** Whether to show the focus ring on `:focus-within` instead of `:focus`. */
readonly within?: boolean
- /** Which pseudo-element to place the focus ring on (if any).
- * Defaults to placement on the actual element. */
+ /**
+ * Which pseudo-element to place the focus ring on (if any).
+ * Defaults to placement on the actual element.
+ */
readonly placement?: FocusRingPlacement
}
diff --git a/app/dashboard/src/components/styled/FocusRoot.tsx b/app/gui/src/dashboard/components/styled/FocusRoot.tsx
similarity index 100%
rename from app/dashboard/src/components/styled/FocusRoot.tsx
rename to app/gui/src/dashboard/components/styled/FocusRoot.tsx
diff --git a/app/dashboard/src/components/styled/RadioGroup.tsx b/app/gui/src/dashboard/components/styled/RadioGroup.tsx
similarity index 97%
rename from app/dashboard/src/components/styled/RadioGroup.tsx
rename to app/gui/src/dashboard/components/styled/RadioGroup.tsx
index 1dfcb1f93b2..87a67424bae 100644
--- a/app/dashboard/src/components/styled/RadioGroup.tsx
+++ b/app/gui/src/dashboard/components/styled/RadioGroup.tsx
@@ -1,5 +1,7 @@
-/** @file A copy of `RadioGroup` from `react-aria-components`, with the sole difference being that
- * `onKeyDown` is omitted from `useRadioGroup`. */
+/**
+ * @file A copy of `RadioGroup` from `react-aria-components`, with the sole difference being that
+ * `onKeyDown` is omitted from `useRadioGroup`.
+ */
// NOTE: Some of `react-aria-components/utils.ts` has also been inlined, in order to avoid needing
// to export them, and by extension polluting auto-imports.
/*
diff --git a/app/dashboard/src/components/styled/Separator.tsx b/app/gui/src/dashboard/components/styled/Separator.tsx
similarity index 100%
rename from app/dashboard/src/components/styled/Separator.tsx
rename to app/gui/src/dashboard/components/styled/Separator.tsx
diff --git a/app/dashboard/src/components/styled/SidebarTabButton.tsx b/app/gui/src/dashboard/components/styled/SidebarTabButton.tsx
similarity index 100%
rename from app/dashboard/src/components/styled/SidebarTabButton.tsx
rename to app/gui/src/dashboard/components/styled/SidebarTabButton.tsx
diff --git a/app/dashboard/src/components/styled/withFocusScope.tsx b/app/gui/src/dashboard/components/styled/withFocusScope.tsx
similarity index 88%
rename from app/dashboard/src/components/styled/withFocusScope.tsx
rename to app/gui/src/dashboard/components/styled/withFocusScope.tsx
index 8fb679b4cd8..0db50db8c5d 100644
--- a/app/dashboard/src/components/styled/withFocusScope.tsx
+++ b/app/gui/src/dashboard/components/styled/withFocusScope.tsx
@@ -7,8 +7,10 @@ import * as aria from '#/components/aria'
// === withFocusScope ===
// ======================
-/** Wrap a component in a {@link aria.FocusScope}. This allows {@link aria.useFocusManager} to be
- * used in the component. */
+/**
+ * Wrap a component in a {@link aria.FocusScope}. This allows {@link aria.useFocusManager} to be
+ * used in the component.
+ */
// This is not a React component, even though it contains JSX.
// eslint-disable-next-line no-restricted-syntax, @typescript-eslint/no-explicit-any
export function withFocusScope React.ReactNode>(
diff --git a/app/dashboard/src/configurations/inputBindings.ts b/app/gui/src/dashboard/configurations/inputBindings.ts
similarity index 98%
rename from app/dashboard/src/configurations/inputBindings.ts
rename to app/gui/src/dashboard/configurations/inputBindings.ts
index 5a200d39686..6936f5d13c3 100644
--- a/app/dashboard/src/configurations/inputBindings.ts
+++ b/app/gui/src/dashboard/configurations/inputBindings.ts
@@ -41,7 +41,7 @@ export type * from '#/utilities/inputBindings'
// ======================
/** The type of the keybind and mousebind namespace for the dashboard. */
-export interface DashboardBindingNamespace extends ReturnType {}
+export type DashboardBindingNamespace = ReturnType
/** The nameof a dashboard binding */
export type DashboardBindingKey = keyof typeof BINDINGS
diff --git a/app/dashboard/src/data/__tests__/dataLinkSchema.test.ts b/app/gui/src/dashboard/data/__tests__/dataLinkSchema.test.ts
similarity index 99%
rename from app/dashboard/src/data/__tests__/dataLinkSchema.test.ts
rename to app/gui/src/dashboard/data/__tests__/dataLinkSchema.test.ts
index e44ef308b83..7f1f2b47eba 100644
--- a/app/dashboard/src/data/__tests__/dataLinkSchema.test.ts
+++ b/app/gui/src/dashboard/data/__tests__/dataLinkSchema.test.ts
@@ -29,7 +29,7 @@ function testSchema(json: unknown, fileName: string): void {
}
// We need to go up from `app/dashboard/` to the root of the repo
-const DIR_DEPTH = 5
+const DIR_DEPTH = 6
const REPO_ROOT = url.fileURLToPath(new URL('../'.repeat(DIR_DEPTH), import.meta.url))
const BASE_DATA_LINKS_ROOT = path.resolve(REPO_ROOT, 'test/Base_Tests/data/datalinks/')
const S3_DATA_LINKS_ROOT = path.resolve(REPO_ROOT, 'test/AWS_Tests/data/')
diff --git a/app/dashboard/src/data/datalinkSchema.json b/app/gui/src/dashboard/data/datalinkSchema.json
similarity index 100%
rename from app/dashboard/src/data/datalinkSchema.json
rename to app/gui/src/dashboard/data/datalinkSchema.json
diff --git a/app/dashboard/src/data/datalinkValidator.ts b/app/gui/src/dashboard/data/datalinkValidator.ts
similarity index 100%
rename from app/dashboard/src/data/datalinkValidator.ts
rename to app/gui/src/dashboard/data/datalinkValidator.ts
diff --git a/app/dashboard/src/data/mimeTypes.ts b/app/gui/src/dashboard/data/mimeTypes.ts
similarity index 73%
rename from app/dashboard/src/data/mimeTypes.ts
rename to app/gui/src/dashboard/data/mimeTypes.ts
index 69962fb0898..f526a2707a6 100644
--- a/app/dashboard/src/data/mimeTypes.ts
+++ b/app/gui/src/dashboard/data/mimeTypes.ts
@@ -1,8 +1,10 @@
/** @file Mime types used by the application. */
-/** The MIME type for a JSON object representing a list of assets.
+/**
+ * The MIME type for a JSON object representing a list of assets.
* NOTE: This should eventually be replaced with multiple payloads,
- * each representing a single asset. */
+ * each representing a single asset.
+ */
export const ASSETS_MIME_TYPE = 'application/vnd.enso.assets+json'
/** The MIME type for a JSON object representing a user. */
diff --git a/app/dashboard/src/events/AssetEventType.ts b/app/gui/src/dashboard/events/AssetEventType.ts
similarity index 100%
rename from app/dashboard/src/events/AssetEventType.ts
rename to app/gui/src/dashboard/events/AssetEventType.ts
diff --git a/app/dashboard/src/events/AssetListEventType.ts b/app/gui/src/dashboard/events/AssetListEventType.ts
similarity index 100%
rename from app/dashboard/src/events/AssetListEventType.ts
rename to app/gui/src/dashboard/events/AssetListEventType.ts
diff --git a/app/dashboard/src/events/assetEvent.ts b/app/gui/src/dashboard/events/assetEvent.ts
similarity index 95%
rename from app/dashboard/src/events/assetEvent.ts
rename to app/gui/src/dashboard/events/assetEvent.ts
index f6e311e6de0..491e6fd2d6d 100644
--- a/app/dashboard/src/events/assetEvent.ts
+++ b/app/gui/src/dashboard/events/assetEvent.ts
@@ -86,8 +86,10 @@ export interface AssetNewSecretEvent extends AssetBaseEvent {
readonly ids: ReadonlySet
readonly newParentKey: backend.AssetId
@@ -132,8 +134,7 @@ export interface AssetDownloadEvent extends AssetBaseEvent {}
+export type AssetDownloadSelectedEvent = AssetBaseEvent
/** A signal to remove the current user's permissions for an asset. */
export interface AssetRemoveSelfEvent extends AssetBaseEvent {
@@ -177,8 +178,10 @@ export interface AssetSetItemEvent extends AssetBaseEvent
}
-/** A signal that a project was closed. In this case, the consumer should not fire a
- * "close project" request to the backend. */
+/**
+ * A signal that a project was closed. In this case, the consumer should not fire a
+ * "close project" request to the backend.
+ */
export interface AssetProjectClosedEvent extends AssetBaseEvent {
readonly id: backend.AssetId
}
diff --git a/app/dashboard/src/events/assetListEvent.ts b/app/gui/src/dashboard/events/assetListEvent.ts
similarity index 96%
rename from app/dashboard/src/events/assetListEvent.ts
rename to app/gui/src/dashboard/events/assetListEvent.ts
index 7c7a8fcbc07..8df141a9431 100644
--- a/app/dashboard/src/events/assetListEvent.ts
+++ b/app/gui/src/dashboard/events/assetListEvent.ts
@@ -123,14 +123,16 @@ interface AssetListWillDeleteEvent extends AssetListBaseEvent {
readonly key: backend.AssetId
}
/** A signal to permanently delete all files in Trash. */
-interface AssetListEmptyTrashEvent extends AssetListBaseEvent {}
+type AssetListEmptyTrashEvent = AssetListBaseEvent
/** A signal for a file to remove itself from the asset list, without being deleted. */
interface AssetListRemoveSelfEvent extends AssetListBaseEvent {
diff --git a/app/dashboard/src/hooks/README.md b/app/gui/src/dashboard/hooks/README.md
similarity index 100%
rename from app/dashboard/src/hooks/README.md
rename to app/gui/src/dashboard/hooks/README.md
diff --git a/app/dashboard/src/hooks/animationHooks.ts b/app/gui/src/dashboard/hooks/animationHooks.ts
similarity index 100%
rename from app/dashboard/src/hooks/animationHooks.ts
rename to app/gui/src/dashboard/hooks/animationHooks.ts
diff --git a/app/dashboard/src/hooks/autoFocusHooks.ts b/app/gui/src/dashboard/hooks/autoFocusHooks.ts
similarity index 100%
rename from app/dashboard/src/hooks/autoFocusHooks.ts
rename to app/gui/src/dashboard/hooks/autoFocusHooks.ts
diff --git a/app/dashboard/src/hooks/autoScrollHooks.ts b/app/gui/src/dashboard/hooks/autoScrollHooks.ts
similarity index 94%
rename from app/dashboard/src/hooks/autoScrollHooks.ts
rename to app/gui/src/dashboard/hooks/autoScrollHooks.ts
index 10e31da792d..e45d5eb5c3b 100644
--- a/app/dashboard/src/hooks/autoScrollHooks.ts
+++ b/app/gui/src/dashboard/hooks/autoScrollHooks.ts
@@ -27,9 +27,11 @@ export type AutoScrollDirection = 'both' | 'horizontal' | 'none' | 'vertical'
export interface AutoScrollOptions {
readonly direction?: AutoScrollDirection
readonly insets?: AutoScrollInsets
- /** If the drag pointer is less than this distance away from the top or bottom of the
+ /**
+ * If the drag pointer is less than this distance away from the top or bottom of the
* scroll container, then the scroll container automatically scrolls upwards if the cursor is near
- * the top of the scroll container, or downwards if the cursor is near the bottom. */
+ * the top of the scroll container, or downwards if the cursor is near the bottom.
+ */
readonly threshold?: number
/** An arbitrary constant that controls the speed of autoscroll. */
readonly speed?: number
@@ -41,9 +43,11 @@ export interface AutoScrollOptions {
// === AutoScrollOffsets ===
// =========================
-/** The amount of space on which side on which scrolling should have no effect.
+/**
+ * The amount of space on which side on which scrolling should have no effect.
* The container is treated as this much smaller, meaning that autoscroll speed will be calculated
- * as though the pointer is that much closer to an edge. */
+ * as though the pointer is that much closer to an edge.
+ */
interface AutoScrollInsets {
readonly top?: number
readonly bottom?: number
diff --git a/app/dashboard/src/hooks/backendHooks.ts b/app/gui/src/dashboard/hooks/backendHooks.ts
similarity index 100%
rename from app/dashboard/src/hooks/backendHooks.ts
rename to app/gui/src/dashboard/hooks/backendHooks.ts
diff --git a/app/dashboard/src/hooks/billing/FeaturesConfiguration.ts b/app/gui/src/dashboard/hooks/billing/FeaturesConfiguration.ts
similarity index 100%
rename from app/dashboard/src/hooks/billing/FeaturesConfiguration.ts
rename to app/gui/src/dashboard/hooks/billing/FeaturesConfiguration.ts
diff --git a/app/dashboard/src/hooks/billing/index.ts b/app/gui/src/dashboard/hooks/billing/index.ts
similarity index 100%
rename from app/dashboard/src/hooks/billing/index.ts
rename to app/gui/src/dashboard/hooks/billing/index.ts
diff --git a/app/dashboard/src/hooks/billing/paywallFeaturesHooks.ts b/app/gui/src/dashboard/hooks/billing/paywallFeaturesHooks.ts
similarity index 100%
rename from app/dashboard/src/hooks/billing/paywallFeaturesHooks.ts
rename to app/gui/src/dashboard/hooks/billing/paywallFeaturesHooks.ts
diff --git a/app/dashboard/src/hooks/billing/paywallHooks.ts b/app/gui/src/dashboard/hooks/billing/paywallHooks.ts
similarity index 100%
rename from app/dashboard/src/hooks/billing/paywallHooks.ts
rename to app/gui/src/dashboard/hooks/billing/paywallHooks.ts
diff --git a/app/dashboard/src/hooks/contextMenuHooks.tsx b/app/gui/src/dashboard/hooks/contextMenuHooks.tsx
similarity index 96%
rename from app/dashboard/src/hooks/contextMenuHooks.tsx
rename to app/gui/src/dashboard/hooks/contextMenuHooks.tsx
index c0cf1288f47..47467ebb923 100644
--- a/app/dashboard/src/hooks/contextMenuHooks.tsx
+++ b/app/gui/src/dashboard/hooks/contextMenuHooks.tsx
@@ -11,8 +11,10 @@ import { useSyncRef } from '#/hooks/syncRefHooks'
// === contextMenuRef ===
// ======================
-/** Return a ref that attaches a context menu event listener.
- * Should be used ONLY if the element does not expose an `onContextMenu` prop. */
+/**
+ * Return a ref that attaches a context menu event listener.
+ * Should be used ONLY if the element does not expose an `onContextMenu` prop.
+ */
export function useContextMenuRef(
key: string,
label: string,
diff --git a/app/dashboard/src/hooks/copyHooks.ts b/app/gui/src/dashboard/hooks/copyHooks.ts
similarity index 100%
rename from app/dashboard/src/hooks/copyHooks.ts
rename to app/gui/src/dashboard/hooks/copyHooks.ts
diff --git a/app/dashboard/src/hooks/debounceCallbackHooks.ts b/app/gui/src/dashboard/hooks/debounceCallbackHooks.ts
similarity index 100%
rename from app/dashboard/src/hooks/debounceCallbackHooks.ts
rename to app/gui/src/dashboard/hooks/debounceCallbackHooks.ts
diff --git a/app/dashboard/src/hooks/debounceStateHooks.ts b/app/gui/src/dashboard/hooks/debounceStateHooks.ts
similarity index 100%
rename from app/dashboard/src/hooks/debounceStateHooks.ts
rename to app/gui/src/dashboard/hooks/debounceStateHooks.ts
diff --git a/app/dashboard/src/hooks/debounceValueHooks.ts b/app/gui/src/dashboard/hooks/debounceValueHooks.ts
similarity index 100%
rename from app/dashboard/src/hooks/debounceValueHooks.ts
rename to app/gui/src/dashboard/hooks/debounceValueHooks.ts
diff --git a/app/dashboard/src/hooks/debugHooks.ts b/app/gui/src/dashboard/hooks/debugHooks.ts
similarity index 100%
rename from app/dashboard/src/hooks/debugHooks.ts
rename to app/gui/src/dashboard/hooks/debugHooks.ts
diff --git a/app/dashboard/src/hooks/dimensionsHooks.ts b/app/gui/src/dashboard/hooks/dimensionsHooks.ts
similarity index 100%
rename from app/dashboard/src/hooks/dimensionsHooks.ts
rename to app/gui/src/dashboard/hooks/dimensionsHooks.ts
diff --git a/app/dashboard/src/hooks/dragAndDropHooks.ts b/app/gui/src/dashboard/hooks/dragAndDropHooks.ts
similarity index 89%
rename from app/dashboard/src/hooks/dragAndDropHooks.ts
rename to app/gui/src/dashboard/hooks/dragAndDropHooks.ts
index 3d93cf4a029..c0e3e461311 100644
--- a/app/dashboard/src/hooks/dragAndDropHooks.ts
+++ b/app/gui/src/dashboard/hooks/dragAndDropHooks.ts
@@ -3,12 +3,14 @@ import * as React from 'react'
import * as eventModule from '#/utilities/event'
-/** Whether an element is actually draggable. This should be used on ALL
+/**
+ * Whether an element is actually draggable. This should be used on ALL
* elements that are parents of text inputs.
*
* This is required to work around a Firefox bug:
* https://bugzilla.mozilla.org/show_bug.cgi?id=800050
- * @returns An object that should be merged into the element's props. */
+ * @returns An object that should be merged into the element's props.
+ */
export function useDraggable() {
const [isDraggable, setIsDraggable] = React.useState(true)
diff --git a/app/dashboard/src/hooks/eventCallbackHooks.ts b/app/gui/src/dashboard/hooks/eventCallbackHooks.ts
similarity index 100%
rename from app/dashboard/src/hooks/eventCallbackHooks.ts
rename to app/gui/src/dashboard/hooks/eventCallbackHooks.ts
diff --git a/app/dashboard/src/hooks/focusHooks.ts b/app/gui/src/dashboard/hooks/focusHooks.ts
similarity index 86%
rename from app/dashboard/src/hooks/focusHooks.ts
rename to app/gui/src/dashboard/hooks/focusHooks.ts
index 27456d0b6e1..0e8b4640ceb 100644
--- a/app/dashboard/src/hooks/focusHooks.ts
+++ b/app/gui/src/dashboard/hooks/focusHooks.ts
@@ -10,8 +10,10 @@ import * as aria from '#/components/aria'
// === useHandleFocusMove ===
// ==========================
-/** The type of `react-aria` keyboard events. It must be extracted out of this type as it is not
- * exposed from the library itself. */
+/**
+ * The type of `react-aria` keyboard events. It must be extracted out of this type as it is not
+ * exposed from the library itself.
+ */
// eslint-disable-next-line @typescript-eslint/no-magic-numbers
type AriaKeyboardEvent = Parameters>[0]
@@ -65,8 +67,10 @@ export function useHandleFocusMove(direction: 'horizontal' | 'vertical') {
// === useSoleFocusChild ===
// =========================
-/** Return JSX props to make a child focusable by `Navigator2D`. DOES NOT handle arrow keys,
- * because this hook assumes the child is the only focus child. */
+/**
+ * Return JSX props to make a child focusable by `Navigator2D`. DOES NOT handle arrow keys,
+ * because this hook assumes the child is the only focus child.
+ */
export function useSoleFocusChild() {
const { focusChildClass } = focusClassProvider.useFocusClasses()
@@ -79,8 +83,10 @@ export function useSoleFocusChild() {
// === useFocusChild ===
// =====================
-/** Return JSX props to make a child focusable by `Navigator2D`, and make the child handle arrow
- * keys to navigate to siblings. */
+/**
+ * Return JSX props to make a child focusable by `Navigator2D`, and make the child handle arrow
+ * keys to navigate to siblings.
+ */
export function useFocusChild() {
const focusDirection = focusDirectionProvider.useFocusDirection()
const handleFocusMove = useHandleFocusMove(focusDirection)
diff --git a/app/dashboard/src/hooks/gtagHooks.ts b/app/gui/src/dashboard/hooks/gtagHooks.ts
similarity index 76%
rename from app/dashboard/src/hooks/gtagHooks.ts
rename to app/gui/src/dashboard/hooks/gtagHooks.ts
index c950d7c9454..f295601253d 100644
--- a/app/dashboard/src/hooks/gtagHooks.ts
+++ b/app/gui/src/dashboard/hooks/gtagHooks.ts
@@ -7,8 +7,10 @@ import * as gtag from 'enso-common/src/gtag'
// === useGtagEvent ===
// ====================
-/** A hook that returns a no-op if the user is offline, otherwise it returns
- * a transparent wrapper around `gtag.event`. */
+/**
+ * A hook that returns a no-op if the user is offline, otherwise it returns
+ * a transparent wrapper around `gtag.event`.
+ */
export function useGtagEvent() {
return React.useCallback((name: string, params?: object) => {
gtag.event(name, params)
@@ -19,10 +21,12 @@ export function useGtagEvent() {
// === gtagOpenCloseCallback ===
// =============================
-/** Send an event indicating that something has been opened, and return a cleanup function
+/**
+ * Send an event indicating that something has been opened, and return a cleanup function
* sending an event indicating that it has been closed.
*
- * Also sends the close event when the window is unloaded. */
+ * Also sends the close event when the window is unloaded.
+ */
export function gtagOpenCloseCallback(
gtagEvent: ReturnType,
openEvent: string,
diff --git a/app/dashboard/src/hooks/intersectionHooks.ts b/app/gui/src/dashboard/hooks/intersectionHooks.ts
similarity index 97%
rename from app/dashboard/src/hooks/intersectionHooks.ts
rename to app/gui/src/dashboard/hooks/intersectionHooks.ts
index 845f019f972..b5508d3f5c4 100644
--- a/app/dashboard/src/hooks/intersectionHooks.ts
+++ b/app/gui/src/dashboard/hooks/intersectionHooks.ts
@@ -21,10 +21,12 @@ export function useIntersectionRatio(
// eslint-disable-next-line no-restricted-syntax
initialValue: Exclude,
): T
-/** Track changes in intersection ratio between an element and one of its ancestors.
+/**
+ * Track changes in intersection ratio between an element and one of its ancestors.
*
* Note that if `threshold` is an array, it MUST be memoized.
- * Similarly, `rootRef` and `targetRef` MUST be stable across renders. */
+ * Similarly, `rootRef` and `targetRef` MUST be stable across renders.
+ */
export function useIntersectionRatio(
rootRef: Readonly> | null,
targetRef: Readonly>,
diff --git a/app/dashboard/src/hooks/mountHooks.ts b/app/gui/src/dashboard/hooks/mountHooks.ts
similarity index 100%
rename from app/dashboard/src/hooks/mountHooks.ts
rename to app/gui/src/dashboard/hooks/mountHooks.ts
diff --git a/app/dashboard/src/hooks/offlineHooks.ts b/app/gui/src/dashboard/hooks/offlineHooks.ts
similarity index 100%
rename from app/dashboard/src/hooks/offlineHooks.ts
rename to app/gui/src/dashboard/hooks/offlineHooks.ts
diff --git a/app/dashboard/src/hooks/projectHooks.ts b/app/gui/src/dashboard/hooks/projectHooks.ts
similarity index 97%
rename from app/dashboard/src/hooks/projectHooks.ts
rename to app/gui/src/dashboard/hooks/projectHooks.ts
index 30d5dd9a690..388a7d3dc38 100644
--- a/app/dashboard/src/hooks/projectHooks.ts
+++ b/app/gui/src/dashboard/hooks/projectHooks.ts
@@ -31,11 +31,15 @@ import type RemoteBackend from '#/services/RemoteBackend'
// ====================================
/** Default interval for refetching project status when the project is opened. */
const OPENED_INTERVAL_MS = 30_000
-/** Interval when we open a cloud project.
- * Since opening a cloud project is a long operation, we want to check the status less often. */
+/**
+ * Interval when we open a cloud project.
+ * Since opening a cloud project is a long operation, we want to check the status less often.
+ */
const CLOUD_OPENING_INTERVAL_MS = 5_000
-/** Interval when we open a local project or when we want to sync the project status as soon as
- * possible. */
+/**
+ * Interval when we open a local project or when we want to sync the project status as soon as
+ * possible.
+ */
const ACTIVE_SYNC_INTERVAL_MS = 100
/** Options for {@link createGetProjectDetailsQuery}. */
@@ -372,6 +376,8 @@ export function useCloseProject() {
})
removeLaunchedProject(project.id)
+ // There is no shared enum type, but the other union member is the same type.
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-enum-comparison
if (projectsStore.getState().page === project.id) {
setPage(TabType.drive)
}
diff --git a/app/dashboard/src/hooks/refreshHooks.ts b/app/gui/src/dashboard/hooks/refreshHooks.ts
similarity index 87%
rename from app/dashboard/src/hooks/refreshHooks.ts
rename to app/gui/src/dashboard/hooks/refreshHooks.ts
index 1e39e06ca7d..58b3dbe1e02 100644
--- a/app/dashboard/src/hooks/refreshHooks.ts
+++ b/app/gui/src/dashboard/hooks/refreshHooks.ts
@@ -7,7 +7,7 @@ import * as React from 'react'
// This must not be a `symbol` as it cannot be sent to Playright.
/** The type of the state returned by {@link useRefresh}. */
-// eslint-disable-next-line no-restricted-syntax
+// eslint-disable-next-line no-restricted-syntax, @typescript-eslint/no-empty-object-type
export interface RefreshState {}
/** A hook that contains no state. It is used to trigger React re-renders. */
diff --git a/app/dashboard/src/hooks/scrollHooks.ts b/app/gui/src/dashboard/hooks/scrollHooks.ts
similarity index 94%
rename from app/dashboard/src/hooks/scrollHooks.ts
rename to app/gui/src/dashboard/hooks/scrollHooks.ts
index 447be9c9f75..8fcee8b82d3 100644
--- a/app/dashboard/src/hooks/scrollHooks.ts
+++ b/app/gui/src/dashboard/hooks/scrollHooks.ts
@@ -12,14 +12,16 @@ interface UseStickyTableHeaderOnScrollOptions {
readonly trackShadowClass?: boolean
}
-/** Properly clip the table body to avoid the table header on scroll.
+/**
+ * Properly clip the table body to avoid the table header on scroll.
* This is required to prevent the table body from overlapping the table header,
* because the table header is transparent.
*
* NOTE: The returned event handler should be attached to the scroll container
* (the closest ancestor element with `overflow-y-auto`).
* @param rootRef - a {@link React.useRef} to the scroll container
- * @param bodyRef - a {@link React.useRef} to the `tbody` element that needs to be clipped. */
+ * @param bodyRef - a {@link React.useRef} to the `tbody` element that needs to be clipped.
+ */
export function useStickyTableHeaderOnScroll(
rootRef: React.MutableRefObject,
bodyRef: React.RefObject,
diff --git a/app/dashboard/src/hooks/searchParamsStateHooks.ts b/app/gui/src/dashboard/hooks/searchParamsStateHooks.ts
similarity index 100%
rename from app/dashboard/src/hooks/searchParamsStateHooks.ts
rename to app/gui/src/dashboard/hooks/searchParamsStateHooks.ts
diff --git a/app/dashboard/src/hooks/setAssetHooks.ts b/app/gui/src/dashboard/hooks/setAssetHooks.ts
similarity index 84%
rename from app/dashboard/src/hooks/setAssetHooks.ts
rename to app/gui/src/dashboard/hooks/setAssetHooks.ts
index 9c87213aa36..19eedcd337c 100644
--- a/app/dashboard/src/hooks/setAssetHooks.ts
+++ b/app/gui/src/dashboard/hooks/setAssetHooks.ts
@@ -1,5 +1,7 @@
-/** @file A hook that turns a `set` function for an {@link AssetTreeNode} to a `set` function
- * on its item, for a specific type of item. */
+/**
+ * @file A hook that turns a `set` function for an {@link AssetTreeNode} to a `set` function
+ * on its item, for a specific type of item.
+ */
import * as React from 'react'
import type * as backend from '#/services/Backend'
@@ -11,11 +13,13 @@ import AssetTreeNode from '#/utilities/AssetTreeNode'
// === useSetAsset ===
// ===================
-/** Converts a React set state action for an {@link AssetTreeNode} to a set state action for any
+/**
+ * Converts a React set state action for an {@link AssetTreeNode} to a set state action for any
* subset of {@link backend.AnyAsset}. This is unsafe when `T` does not match the type of the
* item contained in the `AssetTreeNode`, so this MUST be guarded by checking that the item is of
* the correct type. A value of type `T` must be provided as the first parameter to ensure that this
- * has been done. */
+ * has been done.
+ */
export function useSetAsset(
_value: T,
setNode: React.Dispatch>,
diff --git a/app/dashboard/src/hooks/spotlightHooks.tsx b/app/gui/src/dashboard/hooks/spotlightHooks.tsx
similarity index 100%
rename from app/dashboard/src/hooks/spotlightHooks.tsx
rename to app/gui/src/dashboard/hooks/spotlightHooks.tsx
diff --git a/app/dashboard/src/hooks/syncRefHooks.ts b/app/gui/src/dashboard/hooks/syncRefHooks.ts
similarity index 100%
rename from app/dashboard/src/hooks/syncRefHooks.ts
rename to app/gui/src/dashboard/hooks/syncRefHooks.ts
diff --git a/app/dashboard/src/hooks/toastAndLogHooks.ts b/app/gui/src/dashboard/hooks/toastAndLogHooks.ts
similarity index 94%
rename from app/dashboard/src/hooks/toastAndLogHooks.ts
rename to app/gui/src/dashboard/hooks/toastAndLogHooks.ts
index 410ae47f742..32379b587cd 100644
--- a/app/dashboard/src/hooks/toastAndLogHooks.ts
+++ b/app/gui/src/dashboard/hooks/toastAndLogHooks.ts
@@ -21,8 +21,10 @@ export type ToastAndLogCallback = ReturnType
// === useToastAndLog ===
// ======================
-/** Return a function to send a toast with rendered error message. The same message is also logged
- * as an error. */
+/**
+ * Return a function to send a toast with rendered error message. The same message is also logged
+ * as an error.
+ */
export function useToastAndLog() {
const { getText } = textProvider.useText()
const logger = loggerProvider.useLogger()
diff --git a/app/dashboard/src/hooks/tooltipHooks.ts b/app/gui/src/dashboard/hooks/tooltipHooks.ts
similarity index 100%
rename from app/dashboard/src/hooks/tooltipHooks.ts
rename to app/gui/src/dashboard/hooks/tooltipHooks.ts
diff --git a/app/dashboard/src/hooks/unmountHooks.ts b/app/gui/src/dashboard/hooks/unmountHooks.ts
similarity index 100%
rename from app/dashboard/src/hooks/unmountHooks.ts
rename to app/gui/src/dashboard/hooks/unmountHooks.ts
diff --git a/app/dashboard/src/hooks/useLazyMemoHooks.ts b/app/gui/src/dashboard/hooks/useLazyMemoHooks.ts
similarity index 100%
rename from app/dashboard/src/hooks/useLazyMemoHooks.ts
rename to app/gui/src/dashboard/hooks/useLazyMemoHooks.ts
diff --git a/app/dashboard/src/hooks/useOnScroll.ts b/app/gui/src/dashboard/hooks/useOnScroll.ts
similarity index 100%
rename from app/dashboard/src/hooks/useOnScroll.ts
rename to app/gui/src/dashboard/hooks/useOnScroll.ts
diff --git a/app/dashboard/src/index.tsx b/app/gui/src/dashboard/index.tsx
similarity index 94%
rename from app/dashboard/src/index.tsx
rename to app/gui/src/dashboard/index.tsx
index 10050dbe807..e9c1240b28d 100644
--- a/app/dashboard/src/index.tsx
+++ b/app/gui/src/dashboard/index.tsx
@@ -1,6 +1,8 @@
-/** @file Authentication module used by Enso IDE & Cloud.
+/**
+ * @file Authentication module used by Enso IDE & Cloud.
*
- * This module declares the main DOM structure for the authentication/dashboard app. */
+ * This module declares the main DOM structure for the authentication/dashboard app.
+ */
import * as React from 'react'
import * as sentry from '@sentry/react'
@@ -27,8 +29,6 @@ import UIProviders from '#/components/UIProviders'
import HttpClient from '#/utilities/HttpClient'
-export type { AccessToken } from '#/utilities/accessToken'
-
export type { GraphEditorRunner } from '#/layouts/Editor'
// =================
@@ -53,11 +53,13 @@ export interface DashboardProps extends app.AppProps {
// === run ===
// ===========
-/** Entrypoint for the authentication/dashboard app.
+/**
+ * Entrypoint for the authentication/dashboard app.
*
* Running this function finds a `div` element with the ID `dashboard`, and renders the
* authentication/dashboard UI using React. It also handles routing and other interactions (e.g.,
- * for redirecting the user to/from the login page). */
+ * for redirecting the user to/from the login page).
+ */
export // This export declaration must be broken up to satisfy the `require-jsdoc` rule.
// This is not a React component even though it contains JSX.
// eslint-disable-next-line no-restricted-syntax
diff --git a/app/dashboard/src/layouts/AssetContextMenu.tsx b/app/gui/src/dashboard/layouts/AssetContextMenu.tsx
similarity index 100%
rename from app/dashboard/src/layouts/AssetContextMenu.tsx
rename to app/gui/src/dashboard/layouts/AssetContextMenu.tsx
diff --git a/app/dashboard/src/layouts/AssetDiffView/AssetDiffView.tsx b/app/gui/src/dashboard/layouts/AssetDiffView/AssetDiffView.tsx
similarity index 100%
rename from app/dashboard/src/layouts/AssetDiffView/AssetDiffView.tsx
rename to app/gui/src/dashboard/layouts/AssetDiffView/AssetDiffView.tsx
diff --git a/app/dashboard/src/layouts/AssetDiffView/index.ts b/app/gui/src/dashboard/layouts/AssetDiffView/index.ts
similarity index 100%
rename from app/dashboard/src/layouts/AssetDiffView/index.ts
rename to app/gui/src/dashboard/layouts/AssetDiffView/index.ts
diff --git a/app/dashboard/src/layouts/AssetDiffView/useFetchVersionContent.ts b/app/gui/src/dashboard/layouts/AssetDiffView/useFetchVersionContent.ts
similarity index 100%
rename from app/dashboard/src/layouts/AssetDiffView/useFetchVersionContent.ts
rename to app/gui/src/dashboard/layouts/AssetDiffView/useFetchVersionContent.ts
diff --git a/app/dashboard/src/layouts/AssetPanel.tsx b/app/gui/src/dashboard/layouts/AssetPanel.tsx
similarity index 100%
rename from app/dashboard/src/layouts/AssetPanel.tsx
rename to app/gui/src/dashboard/layouts/AssetPanel.tsx
diff --git a/app/dashboard/src/layouts/AssetProjectSession.tsx b/app/gui/src/dashboard/layouts/AssetProjectSession.tsx
similarity index 100%
rename from app/dashboard/src/layouts/AssetProjectSession.tsx
rename to app/gui/src/dashboard/layouts/AssetProjectSession.tsx
diff --git a/app/dashboard/src/layouts/AssetProjectSessions.tsx b/app/gui/src/dashboard/layouts/AssetProjectSessions.tsx
similarity index 87%
rename from app/dashboard/src/layouts/AssetProjectSessions.tsx
rename to app/gui/src/dashboard/layouts/AssetProjectSessions.tsx
index becdfc40745..8d8b275b1e8 100644
--- a/app/dashboard/src/layouts/AssetProjectSessions.tsx
+++ b/app/gui/src/dashboard/layouts/AssetProjectSessions.tsx
@@ -34,15 +34,8 @@ export default function AssetProjectSessions(props: AssetProjectSessionsProps) {
)
}
-// ====================================
-// === AssetProjectSessionsInternal ===
-// ====================================
-
-/** Props for a {@link AssetProjectSessionsInternal}. */
-interface AssetProjectSessionsInternalProps extends AssetProjectSessionsProps {}
-
/** A list of previous versions of an asset. */
-function AssetProjectSessionsInternal(props: AssetProjectSessionsInternalProps) {
+function AssetProjectSessionsInternal(props: AssetProjectSessionsProps) {
const { backend, item } = props
const projectSessionsQuery = reactQuery.useSuspenseQuery({
diff --git a/app/dashboard/src/layouts/AssetProperties.tsx b/app/gui/src/dashboard/layouts/AssetProperties.tsx
similarity index 99%
rename from app/dashboard/src/layouts/AssetProperties.tsx
rename to app/gui/src/dashboard/layouts/AssetProperties.tsx
index b1ea0306bbb..abf26585b06 100644
--- a/app/dashboard/src/layouts/AssetProperties.tsx
+++ b/app/gui/src/dashboard/layouts/AssetProperties.tsx
@@ -162,7 +162,7 @@ export default function AssetProperties(props: AssetPropertiesProps) {
{ parentDirectoryId: null, description },
item.item.title,
])
- } catch (error) {
+ } catch {
toastAndLog('editDescriptionError')
setItem((oldItem) =>
oldItem.with({ item: object.merge(oldItem.item, { description: oldDescription }) }),
diff --git a/app/dashboard/src/layouts/AssetSearchBar.tsx b/app/gui/src/dashboard/layouts/AssetSearchBar.tsx
similarity index 99%
rename from app/dashboard/src/layouts/AssetSearchBar.tsx
rename to app/gui/src/dashboard/layouts/AssetSearchBar.tsx
index 34930850403..b96d0b9d954 100644
--- a/app/dashboard/src/layouts/AssetSearchBar.tsx
+++ b/app/gui/src/dashboard/layouts/AssetSearchBar.tsx
@@ -32,8 +32,10 @@ import * as tailwindMerge from '#/utilities/tailwindMerge'
/** The reason behind a new query. */
enum QuerySource {
- /** A query change initiated by tabbing. While *technically* internal, it is semantically
- * different in that tabbing does not update the base query. */
+ /**
+ * A query change initiated by tabbing. While *technically* internal, it is semantically
+ * different in that tabbing does not update the base query.
+ */
tabbing = 'tabbing',
/** A query change initiated from code in this component. */
internal = 'internal',
diff --git a/app/dashboard/src/layouts/AssetVersions/AssetVersion.tsx b/app/gui/src/dashboard/layouts/AssetVersions/AssetVersion.tsx
similarity index 100%
rename from app/dashboard/src/layouts/AssetVersions/AssetVersion.tsx
rename to app/gui/src/dashboard/layouts/AssetVersions/AssetVersion.tsx
diff --git a/app/dashboard/src/layouts/AssetVersions/AssetVersions.tsx b/app/gui/src/dashboard/layouts/AssetVersions/AssetVersions.tsx
similarity index 100%
rename from app/dashboard/src/layouts/AssetVersions/AssetVersions.tsx
rename to app/gui/src/dashboard/layouts/AssetVersions/AssetVersions.tsx
diff --git a/app/dashboard/src/layouts/AssetVersions/useAssetVersions.ts b/app/gui/src/dashboard/layouts/AssetVersions/useAssetVersions.ts
similarity index 100%
rename from app/dashboard/src/layouts/AssetVersions/useAssetVersions.ts
rename to app/gui/src/dashboard/layouts/AssetVersions/useAssetVersions.ts
diff --git a/app/dashboard/src/layouts/AssetsTable.tsx b/app/gui/src/dashboard/layouts/AssetsTable.tsx
similarity index 99%
rename from app/dashboard/src/layouts/AssetsTable.tsx
rename to app/gui/src/dashboard/layouts/AssetsTable.tsx
index d26bdf478cb..a395ce53874 100644
--- a/app/dashboard/src/layouts/AssetsTable.tsx
+++ b/app/gui/src/dashboard/layouts/AssetsTable.tsx
@@ -177,16 +177,22 @@ LocalStorage.registerKey('enabledColumns', {
// === Constants ===
// =================
-/** If the ratio of intersection between the main dropzone that should be visible, and the
- * scrollable container, is below this value, then the backup dropzone will be shown. */
+/**
+ * If the ratio of intersection between the main dropzone that should be visible, and the
+ * scrollable container, is below this value, then the backup dropzone will be shown.
+ */
const MINIMUM_DROPZONE_INTERSECTION_RATIO = 0.5
-/** The height of each row in the table body. MUST be identical to the value as set by the
- * Tailwind styling. */
+/**
+ * The height of each row in the table body. MUST be identical to the value as set by the
+ * Tailwind styling.
+ */
const ROW_HEIGHT_PX = 38
/** The size of the loading spinner. */
const LOADING_SPINNER_SIZE_PX = 36
-/** The number of pixels the header bar should shrink when the column selector is visible,
- * assuming 0 icons are visible in the column selector. */
+/**
+ * The number of pixels the header bar should shrink when the column selector is visible,
+ * assuming 0 icons are visible in the column selector.
+ */
const COLUMNS_SELECTOR_BASE_WIDTH_PX = 4
/** The number of pixels the header bar should shrink per collapsed column. */
const COLUMNS_SELECTOR_ICON_WIDTH_PX = 28
@@ -1744,7 +1750,8 @@ export default function AssetsTable(props: AssetsTableProps) {
if (
'backendApi' in window &&
// This non-standard property is defined in Electron.
- 'path' in file
+ 'path' in file &&
+ typeof file.path === 'string'
) {
const projectInfo = await window.backendApi.importProjectFromPath(
file.path,
@@ -2342,7 +2349,8 @@ export default function AssetsTable(props: AssetsTableProps) {
selectAdditional: () => {},
selectAdditionalRange: () => {},
[DEFAULT_HANDLER]: (event) => {
- /** When the document is clicked, deselect the keys, but only if the clicked element
+ /**
+ * When the document is clicked, deselect the keys, but only if the clicked element
* is not inside a `Dialog`. To detect whether an element is a `Dialog`,
* we check whether it is inside the `portal-root` where all the `Dialog`s are mounted.
* If this check is omitted, when the user clicks inside a Datalink dialog,
diff --git a/app/dashboard/src/layouts/AssetsTable/EventListProvider.tsx b/app/gui/src/dashboard/layouts/AssetsTable/EventListProvider.tsx
similarity index 94%
rename from app/dashboard/src/layouts/AssetsTable/EventListProvider.tsx
rename to app/gui/src/dashboard/layouts/AssetsTable/EventListProvider.tsx
index 205f60b664b..de615fd5fce 100644
--- a/app/dashboard/src/layouts/AssetsTable/EventListProvider.tsx
+++ b/app/gui/src/dashboard/layouts/AssetsTable/EventListProvider.tsx
@@ -24,19 +24,21 @@ interface EventListStore {
// ========================
/** State contained in a `EventListContext`. */
-export interface EventListContextType extends zustand.StoreApi {}
+export type EventListContextType = zustand.StoreApi
const EventListContext = React.createContext(null)
/** Props for a {@link EventListProvider}. */
-export interface EventListProviderProps extends Readonly {}
+export type EventListProviderProps = Readonly
// =========================
// === EventListProvider ===
// =========================
-/** A React provider (and associated hooks) for determining whether the current area
- * containing the current element is focused. */
+/**
+ * A React provider (and associated hooks) for determining whether the current area
+ * containing the current element is focused.
+ */
export default function EventListProvider(props: EventListProviderProps) {
const { children } = props
const [store] = React.useState(() =>
diff --git a/app/dashboard/src/layouts/AssetsTableContextMenu.tsx b/app/gui/src/dashboard/layouts/AssetsTableContextMenu.tsx
similarity index 97%
rename from app/dashboard/src/layouts/AssetsTableContextMenu.tsx
rename to app/gui/src/dashboard/layouts/AssetsTableContextMenu.tsx
index 783b4f70cda..d70b621a215 100644
--- a/app/dashboard/src/layouts/AssetsTableContextMenu.tsx
+++ b/app/gui/src/dashboard/layouts/AssetsTableContextMenu.tsx
@@ -1,5 +1,7 @@
-/** @file A context menu for an `AssetsTable`, when no row is selected, or multiple rows
- * are selected. */
+/**
+ * @file A context menu for an `AssetsTable`, when no row is selected, or multiple rows
+ * are selected.
+ */
import * as React from 'react'
import * as authProvider from '#/providers/AuthProvider'
@@ -52,8 +54,10 @@ export interface AssetsTableContextMenuProps {
readonly doDelete: (assetId: backendModule.AssetId, forever?: boolean) => Promise
}
-/** A context menu for an `AssetsTable`, when no row is selected, or multiple rows
- * are selected. */
+/**
+ * A context menu for an `AssetsTable`, when no row is selected, or multiple rows
+ * are selected.
+ */
export default function AssetsTableContextMenu(props: AssetsTableContextMenuProps) {
const { hidden = false, backend, category, pasteData } = props
const { nodeMapRef, event, rootDirectoryId } = props
diff --git a/app/dashboard/src/layouts/CategorySwitcher.tsx b/app/gui/src/dashboard/layouts/CategorySwitcher.tsx
similarity index 100%
rename from app/dashboard/src/layouts/CategorySwitcher.tsx
rename to app/gui/src/dashboard/layouts/CategorySwitcher.tsx
diff --git a/app/dashboard/src/layouts/CategorySwitcher/Category.ts b/app/gui/src/dashboard/layouts/CategorySwitcher/Category.ts
similarity index 100%
rename from app/dashboard/src/layouts/CategorySwitcher/Category.ts
rename to app/gui/src/dashboard/layouts/CategorySwitcher/Category.ts
diff --git a/app/dashboard/src/layouts/Chat.tsx b/app/gui/src/dashboard/layouts/Chat.tsx
similarity index 98%
rename from app/dashboard/src/layouts/Chat.tsx
rename to app/gui/src/dashboard/layouts/Chat.tsx
index c047966708b..b970333e41a 100644
--- a/app/dashboard/src/layouts/Chat.tsx
+++ b/app/gui/src/dashboard/layouts/Chat.tsx
@@ -57,9 +57,11 @@ const NON_WHITESPACE_CHARACTER_REGEX = /\S/
const AUTOGENERATED_THREAD_TITLE_REGEX = /^New chat thread (\d+)$/
/** The maximum number of lines to show in the message input, past which a scrollbar is shown. */
const MAX_MESSAGE_INPUT_LINES = 10
-/** The maximum number of messages to fetch when opening a new thread.
+/**
+ * The maximum number of messages to fetch when opening a new thread.
* This SHOULD be the same limit as the chat backend (the maximum number of messages sent in
- * `serverThread` events). */
+ * `serverThread` events).
+ */
const MAX_MESSAGE_HISTORY = 25
// ==========================
@@ -69,8 +71,10 @@ const MAX_MESSAGE_HISTORY = 25
/** Information needed to display a chat message. */
interface ChatDisplayMessage {
readonly id: chat.MessageId
- /** If `true`, this is a message from the staff to the user.
- * If `false`, this is a message from the user to the staff. */
+ /**
+ * If `true`, this is a message from the staff to the user.
+ * If `false`, this is a message from the user to the staff.
+ */
readonly isStaffMessage: boolean
readonly avatar: string | null
/** Name of the author of the message. */
@@ -422,8 +426,10 @@ export default function Chat(props: ChatProps) {
}
}, [isOpen, gtagEvent])
- /** This is SAFE, because this component is only rendered when `accessToken` is present.
- * See `dashboard.tsx` for its sole usage. */
+ /**
+ * This is SAFE, because this component is only rendered when `accessToken` is present.
+ * See `dashboard.tsx` for its sole usage.
+ */
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
const accessToken = rawAccessToken
diff --git a/app/dashboard/src/layouts/ChatPlaceholder.tsx b/app/gui/src/dashboard/layouts/ChatPlaceholder.tsx
similarity index 100%
rename from app/dashboard/src/layouts/ChatPlaceholder.tsx
rename to app/gui/src/dashboard/layouts/ChatPlaceholder.tsx
diff --git a/app/dashboard/src/layouts/Drive.tsx b/app/gui/src/dashboard/layouts/Drive.tsx
similarity index 100%
rename from app/dashboard/src/layouts/Drive.tsx
rename to app/gui/src/dashboard/layouts/Drive.tsx
diff --git a/app/dashboard/src/layouts/DriveBar.tsx b/app/gui/src/dashboard/layouts/DriveBar.tsx
similarity index 97%
rename from app/dashboard/src/layouts/DriveBar.tsx
rename to app/gui/src/dashboard/layouts/DriveBar.tsx
index c5301724707..cc45be647ab 100644
--- a/app/dashboard/src/layouts/DriveBar.tsx
+++ b/app/gui/src/dashboard/layouts/DriveBar.tsx
@@ -1,5 +1,7 @@
-/** @file Header menubar for the directory listing, containing information about
- * the current directory and some configuration options. */
+/**
+ * @file Header menubar for the directory listing, containing information about
+ * the current directory and some configuration options.
+ */
import * as React from 'react'
import { skipToken, useQuery } from '@tanstack/react-query'
@@ -63,8 +65,10 @@ export interface DriveBarProps {
readonly doUploadFiles: (files: File[]) => void
}
-/** Displays the current directory path and permissions, upload and download buttons,
- * and a column display mode switcher. */
+/**
+ * Displays the current directory path and permissions, upload and download buttons,
+ * and a column display mode switcher.
+ */
export default function DriveBar(props: DriveBarProps) {
const { backend, query, setQuery, category } = props
const { doEmptyTrash, doCreateProject, doCreateDirectory } = props
diff --git a/app/dashboard/src/layouts/Editor.tsx b/app/gui/src/dashboard/layouts/Editor.tsx
similarity index 98%
rename from app/dashboard/src/layouts/Editor.tsx
rename to app/gui/src/dashboard/layouts/Editor.tsx
index ab02f08eee1..6e75e5b4cc6 100644
--- a/app/dashboard/src/layouts/Editor.tsx
+++ b/app/gui/src/dashboard/layouts/Editor.tsx
@@ -48,8 +48,10 @@ export interface GraphEditorProps {
// === GraphEditorRunner ===
// =========================
-/** The value passed from the entrypoint to the dashboard, which enables the dashboard to
- * open a new IDE instance. */
+/**
+ * The value passed from the entrypoint to the dashboard, which enables the dashboard to
+ * open a new IDE instance.
+ */
export type GraphEditorRunner = React.ComponentType
// =================
diff --git a/app/dashboard/src/layouts/GlobalContextMenu.tsx b/app/gui/src/dashboard/layouts/GlobalContextMenu.tsx
similarity index 100%
rename from app/dashboard/src/layouts/GlobalContextMenu.tsx
rename to app/gui/src/dashboard/layouts/GlobalContextMenu.tsx
diff --git a/app/dashboard/src/layouts/InfoBar.tsx b/app/gui/src/dashboard/layouts/InfoBar.tsx
similarity index 97%
rename from app/dashboard/src/layouts/InfoBar.tsx
rename to app/gui/src/dashboard/layouts/InfoBar.tsx
index 5fcdb54a5dd..5327730822b 100644
--- a/app/dashboard/src/layouts/InfoBar.tsx
+++ b/app/gui/src/dashboard/layouts/InfoBar.tsx
@@ -31,7 +31,7 @@ export default function InfoBar(props: InfoBarProps) {
>
{/* FIXME [sb]: https://github.com/enso-org/cloud-v2/issues/1227
* Make help chat work even when signed out. */}
- {/* eslint-disable-next-line @typescript-eslint/no-unnecessary-condition */}
+ {/* eslint-disable-next-line @typescript-eslint/no-unnecessary-condition, no-constant-binary-expression */}
{false && (