From b4ed46095a94910a756e26a8a9f771c6844478b0 Mon Sep 17 00:00:00 2001 From: Gabriel Adrian Samfira Date: Mon, 15 Jun 2026 09:17:11 +0300 Subject: [PATCH] Improve webapp error UX and add setup wizard intro modal Redesign ErrorState to use a subtle centered layout matching EmptyState, replacing the oversized red banner and broken retry button styling. Remove duplicate inline error banners from instances and templates pages. Fix templates DataTable to pass cacheError and wire up retry. Change action errors (delete, create, update) in instances, credentials, and endpoints pages to show toasts instead of replacing the table. Add an intro modal to the setup wizard explaining what will be configured, dismissible via Begin button, Escape key, or backdrop click, with a "Don't show this again" checkbox persisted to localStorage. --- webapp/src/lib/components/ErrorState.svelte | 47 ++++++------- webapp/src/routes/credentials/+page.svelte | 4 +- webapp/src/routes/endpoints/+page.svelte | 4 +- webapp/src/routes/instances/+page.svelte | 14 +--- webapp/src/routes/setup/+page.svelte | 75 ++++++++++++++++++++- webapp/src/routes/templates/+page.svelte | 30 +-------- 6 files changed, 101 insertions(+), 73 deletions(-) diff --git a/webapp/src/lib/components/ErrorState.svelte b/webapp/src/lib/components/ErrorState.svelte index ee42c73e4..967d36b54 100644 --- a/webapp/src/lib/components/ErrorState.svelte +++ b/webapp/src/lib/components/ErrorState.svelte @@ -1,37 +1,28 @@ -
-
-
-
- - - -
-
-

{title}

-

{message}

- {#if showRetry && onRetry} -
- -
- {/if} -
+
+ + + +

{title}

+

{message}

+ {#if showRetry && onRetry} +
+
-
-
\ No newline at end of file + {/if} +
diff --git a/webapp/src/routes/credentials/+page.svelte b/webapp/src/routes/credentials/+page.svelte index a4b165078..7b50b94a1 100644 --- a/webapp/src/routes/credentials/+page.svelte +++ b/webapp/src/routes/credentials/+page.svelte @@ -312,7 +312,7 @@ ); closeModals(); } catch (err) { - error = extractAPIError(err); + toastStore.error('Create Failed', extractAPIError(err)); } } @@ -345,7 +345,7 @@ ); closeModals(); } catch (err) { - error = extractAPIError(err); + toastStore.error('Update Failed', extractAPIError(err)); } } diff --git a/webapp/src/routes/endpoints/+page.svelte b/webapp/src/routes/endpoints/+page.svelte index 6267cfddd..019da81f9 100644 --- a/webapp/src/routes/endpoints/+page.svelte +++ b/webapp/src/routes/endpoints/+page.svelte @@ -355,7 +355,7 @@ ); closeModals(); } catch (err) { - error = extractAPIError(err); + toastStore.error('Create Failed', extractAPIError(err)); } } @@ -387,7 +387,7 @@ ); closeModals(); } catch (err) { - error = extractAPIError(err); + toastStore.error('Update Failed', extractAPIError(err)); } } diff --git a/webapp/src/routes/instances/+page.svelte b/webapp/src/routes/instances/+page.svelte index b3b03da75..2afb84736 100644 --- a/webapp/src/routes/instances/+page.svelte +++ b/webapp/src/routes/instances/+page.svelte @@ -105,7 +105,7 @@ `Instance ${instanceToDelete.name} has been deleted successfully.` ); } catch (err) { - error = extractAPIError(err); + toastStore.error('Delete Failed', extractAPIError(err)); } finally { showDeleteModal = false; instanceToDelete = null; @@ -302,18 +302,6 @@ showAction={false} /> - {#if error} -
-
-
-

Error

-
{error}
-
-
-
- {/if} - - + import { onMount } from 'svelte'; import { resolve } from '$app/paths'; import SetupWizardStepper from '$lib/components/setup/SetupWizardStepper.svelte'; import EndpointStep from '$lib/components/setup/EndpointStep.svelte'; @@ -6,9 +7,32 @@ import EntityStep from '$lib/components/setup/EntityStep.svelte'; import RunnerStep from '$lib/components/setup/RunnerStep.svelte'; + const SKIP_INTRO_KEY = 'garm-setup-skip-intro'; + + let showIntro = false; + let dontShowAgain = false; let currentStep = 1; let completed = false; + onMount(() => { + try { + showIntro = localStorage.getItem(SKIP_INTRO_KEY) !== 'true'; + } catch { + showIntro = true; + } + }); + + function dismissIntro() { + if (dontShowAgain) { + try { + localStorage.setItem(SKIP_INTRO_KEY, 'true'); + } catch { + // localStorage unavailable, ignore + } + } + showIntro = false; + } + let wizardState = { endpointName: '', forgeType: '' as 'github' | 'gitea' | '', @@ -89,6 +113,8 @@ } + { if (showIntro && e.key === 'Escape') dismissIntro(); }} /> + Setup - GARM @@ -118,12 +144,59 @@ + {#if showIntro} + + + {/if} + {#if !completed}

Set Up Runner Infrastructure

- Follow the steps below to configure your GitHub Actions runner infrastructure. + Configure your runner infrastructure by selecting or creating the resources below.

diff --git a/webapp/src/routes/templates/+page.svelte b/webapp/src/routes/templates/+page.svelte index ef910a416..3e3c9fa4c 100644 --- a/webapp/src/routes/templates/+page.svelte +++ b/webapp/src/routes/templates/+page.svelte @@ -5,7 +5,6 @@ import { garmApi } from '$lib/api/client.js'; import type { Template } from '$lib/api/generated/api.js'; import PageHeader from '$lib/components/PageHeader.svelte'; - import ActionButton from '$lib/components/ActionButton.svelte'; import Button from '$lib/components/Button.svelte'; import DataTable from '$lib/components/DataTable.svelte'; import { toastStore } from '$lib/stores/toast.js'; @@ -316,36 +315,13 @@ -{#if (error || cacheError) && !loading} -
-
-
- - - -
-
-

- Error loading templates -

-
- {error || cacheError} -
-
- - Try Again - -
-
-
-
-{/if} -