diff --git a/.chronus/changes/fix-playground-program-viewer-crash-2024-5-14-15-45-7.md b/.chronus/changes/fix-playground-program-viewer-crash-2024-5-14-15-45-7.md new file mode 100644 index 0000000000..4ba954c539 --- /dev/null +++ b/.chronus/changes/fix-playground-program-viewer-crash-2024-5-14-15-45-7.md @@ -0,0 +1,8 @@ +--- +# Change versionKind to one of: internal, fix, dependencies, feature, deprecation, breaking +changeKind: feature +packages: + - "@typespec/playground" +--- + +Add error recovery for viewer that crash diff --git a/.chronus/changes/fix-playground-program-viewer-crash-2024-5-14-16-11-12.md b/.chronus/changes/fix-playground-program-viewer-crash-2024-5-14-16-11-12.md new file mode 100644 index 0000000000..b289e7c250 --- /dev/null +++ b/.chronus/changes/fix-playground-program-viewer-crash-2024-5-14-16-11-12.md @@ -0,0 +1,8 @@ +--- +# Change versionKind to one of: internal, fix, dependencies, feature, deprecation, breaking +changeKind: fix +packages: + - "@typespec/html-program-viewer" +--- + +Fix crash in program viewer when trying to display new value type diff --git a/packages/html-program-viewer/src/ui.tsx b/packages/html-program-viewer/src/ui.tsx index fe027f72a8..de69875c8d 100644 --- a/packages/html-program-viewer/src/ui.tsx +++ b/packages/html-program-viewer/src/ui.tsx @@ -1,5 +1,6 @@ import { css } from "@emotion/react"; import { + Entity, Enum, EnumMember, getNamespaceFullName, @@ -132,12 +133,12 @@ const NamedTypeUI = ({ type, name, properties }: NamedTypeU return undefined; } - const render = (x: any) => - action === "ref" ? : ; + const render = (x: Entity) => + action === "ref" ? : ; let valueUI; if (value === undefined) { valueUI = value; - } else if (value.kind) { + } else if (value.entityKind) { valueUI = render(value); } else if ( typeof value === "object" && @@ -160,10 +161,19 @@ const NamedTypeUI = ({ type, name, properties }: NamedTypeU }; interface TypeUIProps { - type: Type; + readonly entity: Entity; } -const TypeUI: FunctionComponent = ({ type }) => { +const EntityUI: FunctionComponent = ({ entity }) => { + switch (entity.entityKind) { + case "Type": + return ; + default: + return null; + } +}; + +const TypeUI: FunctionComponent<{ type: Type }> = ({ type }) => { switch (type.kind) { case "Namespace": return ; @@ -379,7 +389,7 @@ const TypeReference: FunctionComponent<{ type: Type }> = ({ type }) => { if (type.name === "") { return ( - + ); } else { diff --git a/packages/playground/package.json b/packages/playground/package.json index 889942f631..ee4b3638a9 100644 --- a/packages/playground/package.json +++ b/packages/playground/package.json @@ -85,6 +85,7 @@ "monaco-editor": "~0.46.0", "react": "~18.3.1", "react-dom": "~18.3.1", + "react-error-boundary": "^4.0.13", "swagger-ui-dist": "^5.17.10", "vscode-languageserver": "~9.0.1", "vscode-languageserver-textdocument": "~1.0.11" diff --git a/packages/playground/src/react/output-view/output-view.module.css b/packages/playground/src/react/output-view/output-view.module.css index c7e7e581a9..7dd3870693 100644 --- a/packages/playground/src/react/output-view/output-view.module.css +++ b/packages/playground/src/react/output-view/output-view.module.css @@ -26,3 +26,7 @@ .viewer-tabs-container { background-color: var(--colorNeutralBackground3); } + +.viewer-error { + padding: 20px; +} diff --git a/packages/playground/src/react/output-view/output-view.tsx b/packages/playground/src/react/output-view/output-view.tsx index 1d1dd514c6..2c3ea1871b 100644 --- a/packages/playground/src/react/output-view/output-view.tsx +++ b/packages/playground/src/react/output-view/output-view.tsx @@ -1,5 +1,6 @@ -import { Tab, TabList, type SelectTabEventHandler } from "@fluentui/react-components"; +import { Button, Tab, TabList, type SelectTabEventHandler } from "@fluentui/react-components"; import { useCallback, useMemo, useState, type FunctionComponent } from "react"; +import { ErrorBoundary, type FallbackProps } from "react-error-boundary"; import type { PlaygroundEditorsOptions } from "../playground.js"; import type { CompilationState, CompileResult, FileOutputViewer, ProgramViewer } from "../types.js"; import { createFileViewer } from "./file-viewer.js"; @@ -81,10 +82,12 @@ const OutputViewInternal: FunctionComponent<{ return (
- + + +
); }; + +function fallbackRender({ error, resetErrorBoundary }: FallbackProps) { + return ( +
+

Something went wrong:

+
{error.toString()}
+ +
+ ); +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index d2c492a416..c50746a7c8 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -754,6 +754,9 @@ importers: react-dom: specifier: ~18.3.1 version: 18.3.1(react@18.3.1) + react-error-boundary: + specifier: ^4.0.13 + version: 4.0.13(react@18.3.1) swagger-ui-dist: specifier: ^5.17.10 version: 5.17.10 @@ -14203,6 +14206,7 @@ packages: /ieee754@1.2.1: resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} + requiresBuild: true /ignore-walk@6.0.4: resolution: {integrity: sha512-t7sv42WkwFkyKbivUCglsQW5YWMskWtbEf4MNKX5u/CCWHKSPzN4FtBQGsQZgCLbxOzpVlcbWVK5KB3auIOjSw==} @@ -18161,6 +18165,15 @@ packages: react-is: 18.1.0 dev: true + /react-error-boundary@4.0.13(react@18.3.1): + resolution: {integrity: sha512-b6PwbdSv8XeOSYvjt8LpgpKrZ0yGdtZokYwkwV2wlcZbxgopHX/hgPl5VgpnoVOWd868n1hktM8Qm4b+02MiLQ==} + peerDependencies: + react: '>=16.13.1' + dependencies: + '@babel/runtime': 7.24.1 + react: 18.3.1 + dev: false + /react-error-overlay@6.0.11: resolution: {integrity: sha512-/6UZ2qgEyH2aqzYZgQPxEnz33NJ2gNsnHA2o5+o4wW9bLM/JYQitNP9xPhsXwC08hMMovfGe/8retsdDsczPRg==} dev: false