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 @@ License - + License @@ -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 && (