Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 15 additions & 1 deletion scripts/setup-bun.sh
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,21 @@ archive_path="$tmp_dir/$asset_name"
extract_path="$tmp_dir/extract"
asset_url="https://github.com/oven-sh/bun/releases/download/bun-v${BUN_VERSION}/${asset_name}"

curl -fsSL "$asset_url" -o "$archive_path"
download_attempts=5
download_ok=0
for attempt in $(seq 1 "$download_attempts"); do
if curl --retry 3 --retry-delay 2 --retry-all-errors -fsSL "$asset_url" -o "$archive_path"; then

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -eu
printf '%s\n' '--- scripts/setup-bun.sh ---'
cat -n scripts/setup-bun.sh
printf '%s\n' '--- related curl and invocation context ---'
rg -n -C 4 'setup-bun|curl|retry|max-time|connect-timeout|archive_path|asset_url' scripts package.json .github 2>/dev/null || true

Repository: Cap-go/capgo.app

Length of output: 43523


🏁 Script executed (no clone):

#!/bin/bash
set -eu
printf '%s\n' '--- curl version and timeout option descriptions ---'
curl --version | head -n 2
curl --help all | rg -n -A 2 -- '--connect-timeout|--max-time|--retry-max-time|--retry-all-errors|--retry-delay'
printf '%s\n' '--- static verifier for the setup-bun download command ---'
python3 - <<'PY'
from pathlib import Path
import re

path = Path("/workspace/scripts/setup-bun.sh")
if not path.exists():
    path = Path("scripts/setup-bun.sh")
text = path.read_text()
match = re.search(r'^\s*if (curl .+); then$', text, re.MULTILINE)
if not match:
    raise SystemExit("download curl command not found")
command = match.group(1)
options = set(re.findall(r'(--[a-z-]+)(?:=\S+|\s+\S+)?', command))
print(command)
for option in ("--connect-timeout", "--max-time", "--retry-max-time"):
    print(f"{option}: {'present' if option in options else 'absent'}")
print(f"outer attempts: {re.search(r'download_attempts=(\\d+)', text).group(1)}")
print(f"curl retry count: {re.search(r'--retry\\s+(\\d+)', command).group(1)}")
PY

Length of output: 1539


🌐 Web query:

curl man page --connect-timeout --max-time --retry-max-time transfer stalls no timeout

💡 Result:

To manage curl behavior regarding connection, transfer duration, and stalls, it is important to understand the specific scope of each option. --connect-timeout This option strictly limits the duration of the connection phase, which includes DNS resolution, TCP connection, and TLS/QUIC handshakes [1][2][3]. If the connection is not established within this time, curl aborts with a timeout error (exit code 28) [2][4]. It does not impact the time taken for the subsequent data transfer [3]. --max-time This option sets the maximum allowed duration for the entire transfer operation [2][5]. Once this time is reached, curl will terminate the operation regardless of whether it is still transferring data [2][6]. If used with --retry, the --max-time limit is reset for each retry attempt [7][5]. --retry-max-time When using the --retry option, this sets a total time limit for all retry attempts combined [7]. The timer includes the time spent transferring data and the wait times (sleep) between retries [8][9]. Retries continue until either the maximum number of retries is reached or this total time limit is exceeded [7]. Handling Stalled Transfers If a transfer "stalls" (i.e., the connection is successful but data transfer is extremely slow or stops entirely), neither --connect-timeout nor --max-time may be sufficient if you need to detect inactivity without killing long-running successful transfers [3][10][11]. To handle stalls, consider these options: 1. --speed-limit <bytes/second> and --speed-time : These options abort the transfer if the speed remains below a specified rate (speed-limit) for a specific duration (speed-time) [10]. The default speed-time is 30 seconds [10]. 2. --keepalive-time : If you suspect the connection is being dropped due to inactivity, this option helps by sending keep-alive probes on the connection [3]. In cases where libcurl hangs indefinitely, it is often recommended to ensure both --max-time (or similar transfer timeouts) and appropriate low-speed limits are configured to catch silent failures [12][11][13].

Citations:


🏁 Script executed (no clone):

#!/bin/bash
set -eu
printf '%s\n' '--- curl version and timeout option descriptions ---'
curl --version | head -n 2
curl --help all | rg -n -A 2 -- '--connect-timeout|--max-time|--retry-max-time|--retry-all-errors|--retry-delay'
printf '%s\n' '--- static verifier for the setup-bun download command ---'
python3 - <<'PY'
from pathlib import Path
import re

path = Path("scripts/setup-bun.sh")
text = path.read_text()
match = re.search(r'^\s*if (curl .+); then$', text, re.MULTILINE)
if not match:
    raise SystemExit("download curl command not found")
command = match.group(1)
options = set(re.findall(r'(--[a-z-]+)(?:=\S+|\s+\S+)?', command))
attempts = re.search(r'download_attempts=(\d+)', text)
retries = re.search(r'--retry\s+(\d+)', command)
print(command)
for option in ("--connect-timeout", "--max-time", "--retry-max-time"):
    print(f"{option}: {'present' if option in options else 'absent'}")
print(f"outer attempts: {attempts.group(1)}")
print(f"curl retry count: {retries.group(1)}")
PY

Length of output: 1807


🏁 Script executed:

#!/bin/bash
set -eu
python3 - <<'PY'
from pathlib import Path
import re

text = Path("scripts/setup-bun.sh").read_text()
match = re.search(r'^\s*if (curl .+); then$', text, re.MULTILINE)
if not match:
    raise SystemExit("download curl command not found")
command = match.group(1)
options = set(re.findall(r'(--[a-z-]+)(?:=\S+|\s+\S+)?', command))
attempts = re.search(r'download_attempts=(\d+)', text)
retries = re.search(r'--retry\s+(\d+)', command)
print(command)
for option in ("--connect-timeout", "--max-time", "--retry-max-time"):
    print(f"{option}: {'present' if option in options else 'absent'}")
print("outer attempts:", attempts.group(1))
print("curl retry count:", retries.group(1))
PY

Repository: Cap-go/capgo.app

Length of output: 350


Bound the curl operation. Without transfer and retry limits, a connected server can stop sending data and keep curl running indefinitely. Add --connect-timeout, --max-time, and --retry-max-time so the retry loop can reach its final error.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@scripts/setup-bun.sh` at line 40, Update the curl invocation in the setup
script to include bounded connection, total operation, and cumulative retry
durations via --connect-timeout, --max-time, and --retry-max-time. Keep the
existing retry behavior and archive download arguments unchanged, using
appropriate finite values so stalled connections and retries cannot run
indefinitely.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: This curl call has no --connect-timeout/--max-time bounds, so a server that stops sending data mid-transfer can hang indefinitely, bypassing the retry loop entirely. Consider adding --connect-timeout, --max-time, and --retry-max-time alongside the existing --retry flags.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At scripts/setup-bun.sh, line 40:

<comment>This curl call has no --connect-timeout/--max-time bounds, so a server that stops sending data mid-transfer can hang indefinitely, bypassing the retry loop entirely. Consider adding --connect-timeout, --max-time, and --retry-max-time alongside the existing --retry flags.</comment>

<file context>
@@ -34,7 +34,21 @@ archive_path="$tmp_dir/$asset_name"
+download_attempts=5
+download_ok=0
+for attempt in $(seq 1 "$download_attempts"); do
+  if curl --retry 3 --retry-delay 2 --retry-all-errors -fsSL "$asset_url" -o "$archive_path"; then
+    download_ok=1
+    break
</file context>
Suggested change
if curl --retry 3 --retry-delay 2 --retry-all-errors -fsSL "$asset_url" -o "$archive_path"; then
if curl --connect-timeout 10 --max-time 60 --retry 3 --retry-delay 2 --retry-all-errors --retry-max-time 60 -fsSL "$asset_url" -o "$archive_path"; then

download_ok=1
break
fi
echo "Bun download failed (attempt ${attempt}/${download_attempts}), retrying..." >&2
sleep $((attempt * 2))
Comment on lines +43 to +45

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

Skip the delay after the final failed attempt.

When attempt equals download_attempts, Lines 44-45 still print retrying... and sleep for 10 seconds. Line 48 then reports the final failure. Only log and sleep when attempt is less than download_attempts.

Proposed fix
   fi
-  echo "Bun download failed (attempt ${attempt}/${download_attempts}), retrying..." >&2
-  sleep $((attempt * 2))
+  if [ "$attempt" -lt "$download_attempts" ]; then
+    echo "Bun download failed (attempt ${attempt}/${download_attempts}), retrying..." >&2
+    sleep $((attempt * 2))
+  fi
 done
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
fi
echo "Bun download failed (attempt ${attempt}/${download_attempts}), retrying..." >&2
sleep $((attempt * 2))
fi
if [ "$attempt" -lt "$download_attempts" ]; then
echo "Bun download failed (attempt ${attempt}/${download_attempts}), retrying..." >&2
sleep $((attempt * 2))
fi
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@scripts/setup-bun.sh` around lines 43 - 45, Update the retry handling around
the download attempt loop so the “retrying...” message and backoff sleep execute
only when attempt is less than download_attempts. Preserve the final failure
reporting path without delaying after the last failed attempt.

Comment on lines +44 to +45

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P3: The final failed attempt still prints "retrying..." and sleeps for 10 seconds even though the loop is exhausted, unnecessarily delaying CI failure and misleading the logs. Restrict the message and backoff to attempts before download_attempts.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At scripts/setup-bun.sh, line 44:

<comment>The final failed attempt still prints "retrying..." and sleeps for 10 seconds even though the loop is exhausted, unnecessarily delaying CI failure and misleading the logs. Restrict the message and backoff to attempts before `download_attempts`.</comment>

<file context>
@@ -34,7 +34,21 @@ archive_path="$tmp_dir/$asset_name"
+    download_ok=1
+    break
+  fi
+  echo "Bun download failed (attempt ${attempt}/${download_attempts}), retrying..." >&2
+  sleep $((attempt * 2))
+done
</file context>
Suggested change
echo "Bun download failed (attempt ${attempt}/${download_attempts}), retrying..." >&2
sleep $((attempt * 2))
if [ "$attempt" -lt "$download_attempts" ]; then
echo "Bun download failed (attempt ${attempt}/${download_attempts}), retrying..." >&2
sleep $((attempt * 2))
fi

done

if [ "$download_ok" -ne 1 ]; then
echo "Failed to download Bun from $asset_url after ${download_attempts} attempts" >&2
exit 1
fi

if command -v shasum >/dev/null 2>&1; then
echo "$asset_sha256 $archive_path" | shasum -a 256 -c -
Expand Down
35 changes: 21 additions & 14 deletions src/components/dashboard/AppOnboardingFlow.vue
Original file line number Diff line number Diff line change
Expand Up @@ -853,11 +853,10 @@
flowStep.value = 'install'
}

function openDashboard() {
if (!createdApp.value)
return

router.push(`/app/${encodeURIComponent(createdApp.value.app_id)}`)
async function openDashboard() {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: openDashboard() awaits seedDemoData() but if seedDemoData() internally calls router.push() without awaiting/handling the result, navigation failures (e.g. an auth guard returning next(false)) will be silently ignored and isSeedingDemo may be cleared before navigation completes. Ensure the router.push() call is awaited and its NavigationFailure result is checked.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At src/components/dashboard/AppOnboardingFlow.vue, line 856:

<comment>openDashboard() awaits seedDemoData() but if seedDemoData() internally calls router.push() without awaiting/handling the result, navigation failures (e.g. an auth guard returning next(false)) will be silently ignored and isSeedingDemo may be cleared before navigation completes. Ensure the router.push() call is awaited and its NavigationFailure result is checked.</comment>

<file context>
@@ -853,11 +853,10 @@ function goToInstallStep() {
-    return
-
-  router.push(`/app/${encodeURIComponent(createdApp.value.app_id)}`)
+async function openDashboard() {
+  // Skipping the CLI step should still populate the app with demo data
+  // so the dashboard is usable to explore Capgo before a real upload.
</file context>

// Skipping the CLI step should still populate the app with demo data
// so the dashboard is usable to explore Capgo before a real upload.
await seedDemoData()

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

rg -n -C 8 \
  'router\.push\(|beforeEach\(|beforeEnter|onBeforeRoute' \
  --glob '*.{ts,tsx,vue,js}' || true

Repository: Cap-go/capgo.app

Length of output: 154


🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

printf '%s\n' '--- target file ---'
sed -n '760,875p' src/components/dashboard/AppOnboardingFlow.vue

printf '%s\n' '--- router navigation and guards ---'
rg -n -C 6 \
  'router\.(push|replace)\(|beforeEach\(|beforeEnter|onBeforeRoute|isSeedingDemo|seedDemoData|openDashboard' \
  src --glob '*.{ts,tsx,vue,js}' || true

Repository: Cap-go/capgo.app

Length of output: 50373


🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

python3 - <<'PY'
from pathlib import Path
p = Path('src/components/dashboard/AppOnboardingFlow.vue')
text = p.read_text()
for needle in ('async function seedDemoData', 'const seedDemoData', 'function seedDemoData', 'async function openDashboard', 'const openDashboard', 'function openDashboard'):
    start = text.find(needle)
    if start >= 0:
        line = text.count('\n', 0, start) + 1
        print(f'--- {needle} at line {line} ---')
        print('\n'.join(f'{i}: {line_text}' for i, line_text in enumerate(text.splitlines()[max(0,line-12):line+55], max(1,line-11))))
PY

Repository: Cap-go/capgo.app

Length of output: 7646


🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

printf '%s\n' '--- target route definition ---'
rg -n -C 12 \
  "path: '/app|path: '/dashboard|meta:.*middleware|middleware:" \
  src/main.ts src --glob '*.ts' --glob '*.vue' | head -n 240

printf '%s\n' '--- router guards ---'
sed -n '225,285p' src/main.ts
sed -n '420,475p' src/modules/auth.ts
sed -n '45,100p' src/modules/sso-enforcement.ts

Repository: Cap-go/capgo.app

Length of output: 18672


🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

printf '%s\n' '--- all local uses of the target navigation result ---'
rg -n -C 4 \
  'isNavigationFailure|NavigationFailure|await router\.(push|replace)|router\.(push|replace)\(.*\.catch|\.push\(.*\.then' \
  src --glob '*.{ts,tsx,vue,js}' || true

printf '%s\n' '--- package versions ---'
rg -n '"vue-router"|"vue"' package.json bun.lockb bun.lock package-lock.json pnpm-lock.yaml yarn.lock 2>/dev/null || true

Repository: Cap-go/capgo.app

Length of output: 35246


🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

python3 - <<'PY'
from pathlib import Path
for name in ('src/main.ts', 'src/modules/auth.ts', 'src/modules/sso-enforcement.ts'):
    p = Path(name)
    lines = p.read_text().splitlines()
    print(f'--- {name}: relevant route/guard lines ---')
    for i, line in enumerate(lines, 1):
        if ('/app/' in line or 'middleware' in line or 'next(' in line or 'return false' in line
                or 'return next' in line or 'router.beforeEach' in line):
            lo, hi = max(1, i - 3), min(len(lines), i + 5)
            print(f'[{i}]')
            for j in range(lo, hi + 1):
                print(f'{j}: {lines[j-1]}')
PY

Repository: Cap-go/capgo.app

Length of output: 25386


Await and handle dashboard navigation.

seedDemoData() does not await router.push(). The auth guard can return next(false), so openDashboard() clears isSeedingDemo while navigation is still pending and silently ignores the navigation failure. Await the push and handle its NavigationFailure result.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/components/dashboard/AppOnboardingFlow.vue` at line 859, Update the
openDashboard flow around seedDemoData() so the router.push() navigation is
awaited and its NavigationFailure result is explicitly handled. Ensure
isSeedingDemo remains active until navigation settles, and preserve the existing
behavior for successful navigation.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: The "Open Dashboard" and "Install later" buttons previously always navigated to /app/:app_id, so the user reach the dashboard regardless of backend state. Now they delegate entirely to seedDemoData(), which only calls router.push("...?refresh=true") on the success path. If the app/demo invocation fails (network/backend error) or short-circuits (e.g. currentOrg?.gid missing), the function just logs, fires a toast, and resets the spinner — the user stays stuck on the CLI onboarding step with no way to get to their dashboard. This is a UX regression in the failure path for a button whose primary purpose is to open the dashboard. Consider falling back to direct navigation when seeding cannot complete, or having seedDemoData return a success flag and navigating here regardless.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At src/components/dashboard/AppOnboardingFlow.vue, line 859:

<comment>The "Open Dashboard" and "Install later" buttons previously always navigated to `/app/:app_id`, so the user reach the dashboard regardless of backend state. Now they delegate entirely to `seedDemoData()`, which only calls `router.push("...?refresh=true")` on the success path. If the `app/demo` invocation fails (network/backend error) or short-circuits (e.g. `currentOrg?.gid` missing), the function just logs, fires a toast, and resets the spinner — the user stays stuck on the CLI onboarding step with no way to get to their dashboard. This is a UX regression in the failure path for a button whose primary purpose is to open the dashboard. Consider falling back to direct navigation when seeding cannot complete, or having `seedDemoData` return a success flag and navigating here regardless.</comment>

<file context>
@@ -853,11 +853,10 @@ function goToInstallStep() {
+async function openDashboard() {
+  // Skipping the CLI step should still populate the app with demo data
+  // so the dashboard is usable to explore Capgo before a real upload.
+  await seedDemoData()
 }
 
</file context>

}

onMounted(async () => {
Expand Down Expand Up @@ -1428,7 +1427,8 @@
{{ setupSubtitle }}
</p>
</div>
<button class="d-btn min-h-11" :class="whiteCardSecondaryButtonClass()" @click="openDashboard">
<button class="d-btn min-h-11" :class="whiteCardSecondaryButtonClass()" :disabled="isSeedingDemo" @click="openDashboard">

Check warning on line 1430 in src/components/dashboard/AppOnboardingFlow.vue

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Add an explicit "type" attribute to this button.

See more on https://sonarcloud.io/project/issues?id=Cap-go_capgo&issues=AZ_Mezj6obLt5SYYFrGe&open=AZ_Mezj6obLt5SYYFrGe&pullRequest=2854
<IconLoader v-if="isSeedingDemo" class="h-4 w-4 animate-spin" />
Comment thread
cubic-dev-ai[bot] marked this conversation as resolved.
Outdated
{{ t('app-onboarding-open-dashboard') }}
</button>
</div>
Expand Down Expand Up @@ -1473,9 +1473,12 @@
</div>

<div class="flex flex-col-reverse gap-3 sm:flex-row sm:items-center sm:justify-end">
<button class="d-btn min-h-11" :class="whiteCardPrimaryButtonClass()" @click="openDashboard">
{{ t('app-onboarding-install-later') }}
<IconArrowRight class="h-4 w-4" />
<button class="d-btn min-h-11" :class="whiteCardPrimaryButtonClass()" :disabled="isSeedingDemo" @click="openDashboard">
<IconLoader v-if="isSeedingDemo" class="h-4 w-4 animate-spin" />
<template v-else>
{{ t('app-onboarding-install-later') }}
<IconArrowRight class="h-4 w-4" />
</template>
Comment on lines +1470 to +1475

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Keep an accessible name while Install later is loading.

When isSeedingDemo is true, the v-else block removes the translated label and arrow. The button then contains only IconLoader, and the opening tag has no aria-label. Keep the original label in a visually hidden element or add an aria-label. Mark the decorative loader as aria-hidden.

Proposed fix
-              <IconLoader v-if="isSeedingDemo" class="h-4 w-4 animate-spin" />
+              <IconLoader v-if="isSeedingDemo" class="h-4 w-4 animate-spin" aria-hidden="true" />
+              <span v-if="isSeedingDemo" class="sr-only">{{ t('app-onboarding-install-later') }}</span>
               <template v-else>

Apply the same change to both install-later buttons.

Also applies to: 1619-1624

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/components/dashboard/AppOnboardingFlow.vue` around lines 1476 - 1481,
Update both install-later buttons in the onboarding flow to retain an accessible
“Install later” name while isSeedingDemo is true, using a visually hidden
translated label or aria-label. Mark each IconLoader as aria-hidden because it
is decorative, while preserving the existing loading and non-loading visual
behavior.

</button>
</div>
</div>
Expand Down Expand Up @@ -1565,7 +1568,8 @@
{{ t('app-onboarding-install-subtitle') }}
</p>
</div>
<button class="d-btn min-h-11" :class="whiteCardSecondaryButtonClass()" @click="openDashboard">
<button class="d-btn min-h-11" :class="whiteCardSecondaryButtonClass()" :disabled="isSeedingDemo" @click="openDashboard">

Check warning on line 1571 in src/components/dashboard/AppOnboardingFlow.vue

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Add an explicit "type" attribute to this button.

See more on https://sonarcloud.io/project/issues?id=Cap-go_capgo&issues=AZ_Mezj6obLt5SYYFrGf&open=AZ_Mezj6obLt5SYYFrGf&pullRequest=2854
<IconLoader v-if="isSeedingDemo" class="h-4 w-4 animate-spin" />
{{ t('app-onboarding-open-dashboard') }}
</button>
</div>
Expand Down Expand Up @@ -1609,12 +1613,15 @@
</div>

<div class="flex flex-col-reverse gap-3 sm:flex-row sm:items-center sm:justify-between">
<button class="d-btn min-h-11" :class="whiteCardSecondaryButtonClass()" @click="flowStep = 'choice'">
<button class="d-btn min-h-11" :class="whiteCardSecondaryButtonClass()" :disabled="isSeedingDemo" @click="flowStep = 'choice'">

Check warning on line 1616 in src/components/dashboard/AppOnboardingFlow.vue

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Add an explicit "type" attribute to this button.

See more on https://sonarcloud.io/project/issues?id=Cap-go_capgo&issues=AZ_Mezj6obLt5SYYFrGg&open=AZ_Mezj6obLt5SYYFrGg&pullRequest=2854
{{ t('button-back') }}
</button>
<button class="d-btn min-h-11" :class="whiteCardPrimaryButtonClass()" @click="openDashboard">
{{ t('app-onboarding-install-later') }}
<IconArrowRight class="h-4 w-4" />
<button class="d-btn min-h-11" :class="whiteCardPrimaryButtonClass()" :disabled="isSeedingDemo" @click="openDashboard">

Check warning on line 1619 in src/components/dashboard/AppOnboardingFlow.vue

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Add an explicit "type" attribute to this button.

See more on https://sonarcloud.io/project/issues?id=Cap-go_capgo&issues=AZ_Mezj6obLt5SYYFrGh&open=AZ_Mezj6obLt5SYYFrGh&pullRequest=2854
<IconLoader v-if="isSeedingDemo" class="h-4 w-4 animate-spin" />
<template v-else>
{{ t('app-onboarding-install-later') }}
<IconArrowRight class="h-4 w-4" />
</template>
</button>
</div>
</div>
Expand Down
Loading