diff --git a/src/Exceptionless.Web/ClientApp.angular/app/project/configure-controller.js b/src/Exceptionless.Web/ClientApp.angular/app/project/configure-controller.js index b10b60fe1b..b47ede9ae9 100644 --- a/src/Exceptionless.Web/ClientApp.angular/app/project/configure-controller.js +++ b/src/Exceptionless.Web/ClientApp.angular/app/project/configure-controller.js @@ -141,6 +141,8 @@ platform: "JavaScript", }, { key: "Exceptionless.Node", name: "Node.js", platform: "JavaScript" }, + { key: "Exceptionless.ReactNative", name: "React Native", platform: "JavaScript" }, + { key: "Exceptionless.Expo", name: "Expo", platform: "JavaScript" }, ]; } @@ -160,6 +162,14 @@ return vm.currentProjectType.key === "Exceptionless.Node"; } + function isReactNative() { + return vm.currentProjectType.key === "Exceptionless.ReactNative"; + } + + function isExpo() { + return vm.currentProjectType.key === "Exceptionless.Expo"; + } + function isBashShell() { return vm.currentProjectType.key === "Bash Shell"; } @@ -207,9 +217,11 @@ vm.isBashShell = isBashShell; vm.isCommandLine = isCommandLine; vm.isDotNet = isDotNet; + vm.isExpo = isExpo; vm.isGeneratingSampleData = false; vm.isJavaScript = isJavaScript; vm.isNode = isNode; + vm.isReactNative = isReactNative; vm.navigateToDashboard = navigateToDashboard; vm.onCopyError = onCopyError; vm.project = {}; diff --git a/src/Exceptionless.Web/ClientApp.angular/app/project/configure.tpl.html b/src/Exceptionless.Web/ClientApp.angular/app/project/configure.tpl.html index c9fb2d6373..38c2c786d5 100644 --- a/src/Exceptionless.Web/ClientApp.angular/app/project/configure.tpl.html +++ b/src/Exceptionless.Web/ClientApp.angular/app/project/configure.tpl.html @@ -51,7 +51,7 @@
 curl "{{::vm.serverUrl}}/api/v2/events" \
     --request POST \
-    --header "Authorization: Bearer {{::vm.apiKey}}" \
+    --header "Authorization: Bearer {{vm.apiKey}}" \
     --header "Content-Type: application/json" \
     --data-binary '[{"type":"log","message":"Hello World!"}]'
@@ -61,7 +61,7 @@
 } | ConvertTo-Json
 
 $header = @{
- "Authorization"="Bearer {{::vm.apiKey}}"
+ "Authorization"="Bearer {{vm.apiKey}}"
  "Content-Type"="application/json"
 }
 
@@ -77,7 +77,7 @@
                                 
Install-Package {{vm.currentProjectType.key}}
-
+

npm install @exceptionless/browser --save

@@ -86,22 +86,42 @@

npm install @exceptionless/node --save
+
+

Install Exceptionless using the Node Package Manager. Install AsyncStorage with the client. It is a peer dependency used for persistent event queue storage.

+
npm install @exceptionless/react-native @react-native-async-storage/async-storage
+
+
+

Install Exceptionless using the Node Package Manager. Install AsyncStorage with the client. It is a peer dependency used for persistent event queue storage.

+
npx expo install @exceptionless/react-native @react-native-async-storage/async-storage
+
  • -
    +

    {{::'Configure the ExceptionlessClient with your Exceptionless API key:' | translate}}

    -
    import { Exceptionless } from "@exceptionless/browser";

    await Exceptionless.startup(c => {
      c.apiKey = "{{::vm.apiKey}}";
    });
    +
    import { Exceptionless } from "@exceptionless/browser";

    await Exceptionless.startup(c => {
      c.apiKey = "{{vm.apiKey}}";
    });

    {{::'Configure the ExceptionlessClient with your Exceptionless API key:' | translate}}

    -
    import { Exceptionless } from "@exceptionless/node";

    await Exceptionless.startup(c => {
      c.apiKey = "{{::vm.apiKey}}";
    });
    +
    import { Exceptionless } from "@exceptionless/node";

    await Exceptionless.startup(c => {
      c.apiKey = "{{vm.apiKey}}";
    });
    +
    +
    +

    Add the Exceptionless config plugin to app.json when using development or standalone builds:

    +
    {
      "expo": {
        "plugins": ["@exceptionless/react-native/expo-plugin"]
      }
    }
    +

    Native iOS crash reporting requires an Expo development build or standalone build. JavaScript error reporting works in Expo Go.

    +
    +
    +

    + {{::'Configure the ExceptionlessClient with your Exceptionless API key:' | + translate}} +

    +
    import { Exceptionless } from "@exceptionless/react-native";

    await Exceptionless.startup(c => {
      c.apiKey = "{{vm.apiKey}}";
    });
  • diff --git a/src/Exceptionless.Web/ClientApp/src/routes/(app)/project/[projectId]/configure/+page.svelte b/src/Exceptionless.Web/ClientApp/src/routes/(app)/project/[projectId]/configure/+page.svelte index 30045ae22c..f6dfbff2d4 100644 --- a/src/Exceptionless.Web/ClientApp/src/routes/(app)/project/[projectId]/configure/+page.svelte +++ b/src/Exceptionless.Web/ClientApp/src/routes/(app)/project/[projectId]/configure/+page.svelte @@ -95,6 +95,23 @@ platform: string; } + type CodeBlockLanguage = 'csharp' | 'javascript' | 'json' | 'powershell' | 'shellscript' | 'xml'; + + interface JavaScriptConfigurationStep { + code: string; + description: string; + language: CodeBlockLanguage; + note?: string; + } + + interface JavaScriptClientConfiguration { + extraSteps?: JavaScriptConfigurationStep[]; + installCommand: string; + installNote?: string; + packageName: string; + startupCode: string; + } + const projectTypes: ProjectType[] = [ { id: 'bash', label: 'Bash Shell', platform: 'Command Line' }, { id: 'powershell', label: 'PowerShell', platform: 'Command Line' }, @@ -106,6 +123,8 @@ { id: 'javascript-browser', label: 'Browser applications', package: 'Exceptionless.JavaScript', platform: 'JavaScript' }, { id: 'javascript-nodejs', label: 'Node.js', package: 'Exceptionless.Node', platform: 'JavaScript' }, + { id: 'javascript-react-native', label: 'React Native', package: '@exceptionless/react-native', platform: 'JavaScript' }, + { id: 'javascript-expo', label: 'Expo', package: '@exceptionless/react-native', platform: 'JavaScript' }, { id: 'dotnet-legacy-console', label: 'Console and Service applications', package: 'Exceptionless', platform: '.NET Legacy' }, { config: 'web.config', id: 'dotnet-legacy-mvc', label: 'ASP.NET MVC', package: 'Exceptionless.Mvc', platform: '.NET Legacy' }, @@ -148,13 +167,16 @@ const isDotNet = $derived(selectedProjectType?.platform === '.NET'); const isDotNetLegacy = $derived(selectedProjectType?.platform === '.NET Legacy'); const isJavaScript = $derived(selectedProjectType?.platform === 'JavaScript'); - const isNode = $derived(selectedProjectType?.package === 'Exceptionless.Node'); const isBashShell = $derived(selectedProjectType?.id === 'bash'); const clientDocumentationUrl = $derived.by(() => { if (isDotNet || isDotNetLegacy) { return 'https://exceptionless.com/docs/clients/dotnet/'; } + if (selectedProjectType?.id === 'javascript-react-native' || selectedProjectType?.id === 'javascript-expo') { + return 'https://github.com/exceptionless/Exceptionless.JavaScript/tree/main/packages/react-native'; + } + if (isJavaScript) { return 'https://exceptionless.com/docs/clients/javascript/'; } @@ -207,6 +229,18 @@ $header = @{ Invoke-RestMethod -Uri "${serverUrl}/api/v2/events" -Method "Post" -Body $body -Headers $header`, + reactNativeExpoPlugin: `{ + "expo": { + "plugins": ["@exceptionless/react-native/expo-plugin"] + } +}`, + + reactNativeJs: `import { Exceptionless } from "@exceptionless/react-native"; + +await Exceptionless.startup(c => { + c.apiKey = "${apiKey}"; +});`, + webApi: `public static void Register(HttpConfiguration config) { config.AddExceptionless("${apiKey}"); }`, @@ -250,6 +284,47 @@ public partial class App : Application { }` }); + const javascriptClientConfiguration = $derived.by((): JavaScriptClientConfiguration | null => { + switch (selectedProjectType?.id) { + case 'javascript-browser': + return { + installCommand: 'npm install @exceptionless/browser --save', + packageName: '@exceptionless/browser', + startupCode: codeSamples.browserJs + }; + case 'javascript-expo': + return { + extraSteps: [ + { + code: codeSamples.reactNativeExpoPlugin, + description: 'Add the Exceptionless config plugin to app.json when using development or standalone builds.', + language: 'json', + note: 'Native iOS crash reporting requires an Expo development build or standalone build. JavaScript error reporting works in Expo Go.' + } + ], + installCommand: 'npx expo install @exceptionless/react-native @react-native-async-storage/async-storage', + installNote: 'The AsyncStorage package is a peer dependency used for persistent event queue storage, so install it alongside the client.', + packageName: '@exceptionless/react-native', + startupCode: codeSamples.reactNativeJs + }; + case 'javascript-nodejs': + return { + installCommand: 'npm install @exceptionless/node --save', + packageName: '@exceptionless/node', + startupCode: codeSamples.nodeJs + }; + case 'javascript-react-native': + return { + installCommand: 'npm install @exceptionless/react-native @react-native-async-storage/async-storage', + installNote: 'The AsyncStorage package is a peer dependency used for persistent event queue storage, so install it alongside the client.', + packageName: '@exceptionless/react-native', + startupCode: codeSamples.reactNativeJs + }; + default: + return null; + } + }); + useEventListener(document, 'PersistentEventChanged', async (event) => { const message = (event as CustomEvent>).detail; @@ -563,40 +638,40 @@ public partial class App : Application { {/if} {/if} - {#if isJavaScript} + {#if isJavaScript && javascriptClientConfiguration}
  • Install the {selectedProjectType.package} npm package in your JavaScript project by running this command in the project - directory.

    Install the {javascriptClientConfiguration.packageName} npm package in your JavaScript project by running this command + in the project directory. {javascriptClientConfiguration.installNote ?? ''}

    - {#if isNode} - -
    - -
    - {:else} - + +
    + +
    +
    +
  • + {#each javascriptClientConfiguration.extraSteps ?? [] as step (step.description)} +
  • +

    {step.description}

    +
    +
    - +
    +
    + {#if step.note} +

    {step.note}

    {/if} -
  • - + + {/each}
  • Configure the ExceptionlessClient with your Exceptionless API key.

    - {#if !isNode} - -
    - -
    - {:else} - -
    - -
    - {/if} + +
    + +
  • {/if}