mirror of
https://github.com/wailsapp/wails.git
synced 2026-03-16 23:55:52 +01:00
Improve wizard UX and fix CodeRabbit issues
- Add docker-options intermediate step with two choices: - "Download official image" (red outline) → SDK license → download - "Build your own image" (gray outline) → opens docs in new tab - Update SDK license page to match other pages (back button at bottom) - Add Wails favicon to wizard - Fix shutdown channel panic on repeated /api/close (sync.Once guard) - Fix Go version parsing for beta/rc versions like go1.25beta1 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
017133e48e
commit
20f46380d4
12 changed files with 164 additions and 49 deletions
File diff suppressed because one or more lines are too long
1
v3/internal/setupwizard/frontend/dist/assets/index-DJ0m3TY_.css
vendored
Normal file
1
v3/internal/setupwizard/frontend/dist/assets/index-DJ0m3TY_.css
vendored
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
BIN
v3/internal/setupwizard/frontend/dist/favicon.ico
vendored
Normal file
BIN
v3/internal/setupwizard/frontend/dist/favicon.ico
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 15 KiB |
1
v3/internal/setupwizard/frontend/dist/favicon.svg
vendored
Normal file
1
v3/internal/setupwizard/frontend/dist/favicon.svg
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="100%" height="100%" version="1.1" viewBox="0 0 180 167" xml:space="preserve" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2"><g><path d="M196,19.285C196,14.712 192.095,11 187.286,11L27.714,11C22.905,11 19,14.712 19,19.285L19,158.715C19,163.288 22.905,167 27.714,167L187.286,167C192.095,167 196,163.288 196,158.715L196,19.285Z" transform="matrix(1.00565,0,0,1.05769,-18.1073,-10.6346)" style="fill:#fff"/></g><g><path d="M0,-51.891L14.429,-51.891L13.043,-21.183L22.568,-51.891L34.226,-51.891L34.084,-21.183L42.365,-51.891L56.794,-51.891L38.526,0L25.198,0L25.34,-32.45L15.211,0L1.919,0L0,-51.891Z" transform="matrix(2.51258,0,0,2.51258,20.0103,151.138)" style="fill-rule:nonzero"/></g></svg>
|
||||
|
After Width: | Height: | Size: 774 B |
|
|
@ -3,12 +3,14 @@
|
|||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
|
||||
<link rel="icon" type="image/x-icon" href="/favicon.ico" />
|
||||
<title>Wails Setup Wizard</title>
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&display=swap" rel="stylesheet">
|
||||
<script type="module" crossorigin src="/assets/index-BSN5vgpJ.js"></script>
|
||||
<link rel="stylesheet" crossorigin href="/assets/index-DIBmoXie.css">
|
||||
<script type="module" crossorigin src="/assets/index-VD1eW7Ti.js"></script>
|
||||
<link rel="stylesheet" crossorigin href="/assets/index-DJ0m3TY_.css">
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
|
|
|
|||
|
|
@ -3,6 +3,8 @@
|
|||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
|
||||
<link rel="icon" type="image/x-icon" href="/favicon.ico" />
|
||||
<title>Wails Setup Wizard</title>
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
|
|
|
|||
BIN
v3/internal/setupwizard/frontend/public/favicon.ico
Normal file
BIN
v3/internal/setupwizard/frontend/public/favicon.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 15 KiB |
1
v3/internal/setupwizard/frontend/public/favicon.svg
Normal file
1
v3/internal/setupwizard/frontend/public/favicon.svg
Normal file
|
|
@ -0,0 +1 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" width="100%" height="100%" version="1.1" viewBox="0 0 180 167" xml:space="preserve" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2"><g><path d="M196,19.285C196,14.712 192.095,11 187.286,11L27.714,11C22.905,11 19,14.712 19,19.285L19,158.715C19,163.288 22.905,167 27.714,167L187.286,167C192.095,167 196,163.288 196,158.715L196,19.285Z" transform="matrix(1.00565,0,0,1.05769,-18.1073,-10.6346)" style="fill:#fff"/></g><g><path d="M0,-51.891L14.429,-51.891L13.043,-21.183L22.568,-51.891L34.226,-51.891L34.084,-21.183L42.365,-51.891L56.794,-51.891L38.526,0L25.198,0L25.34,-32.45L15.211,0L1.919,0L0,-51.891Z" transform="matrix(2.51258,0,0,2.51258,20.0103,151.138)" style="fill-rule:nonzero"/></g></svg>
|
||||
|
After Width: | Height: | Size: 774 B |
|
|
@ -12,6 +12,7 @@ type OOBEStep =
|
|||
| 'deps-ready'
|
||||
| 'deps-missing'
|
||||
| 'cross-platform'
|
||||
| 'docker-options'
|
||||
| 'sdk-license'
|
||||
| 'docker-setup'
|
||||
| 'projects'
|
||||
|
|
@ -42,6 +43,8 @@ function getWizardStage(step: OOBEStep): WizardStage {
|
|||
case 'deps-missing':
|
||||
return 'dependencies';
|
||||
case 'cross-platform':
|
||||
case 'docker-options':
|
||||
case 'sdk-license':
|
||||
case 'docker-setup':
|
||||
return 'platform';
|
||||
case 'projects':
|
||||
|
|
@ -840,6 +843,87 @@ function CrossPlatformPage({
|
|||
);
|
||||
}
|
||||
|
||||
// Docker Options Page - choose between official download or build your own
|
||||
function DockerOptionsPage({
|
||||
onDownloadOfficial,
|
||||
onSkip,
|
||||
onBack,
|
||||
canGoBack
|
||||
}: {
|
||||
onDownloadOfficial: () => void;
|
||||
onSkip: () => void;
|
||||
onBack?: () => void;
|
||||
canGoBack?: boolean;
|
||||
}) {
|
||||
return (
|
||||
<motion.div
|
||||
variants={pageVariants}
|
||||
initial="initial"
|
||||
animate="animate"
|
||||
exit="exit"
|
||||
transition={{ duration: 0.3 }}
|
||||
className="flex-1 flex flex-col items-center justify-center"
|
||||
>
|
||||
<div className="w-16 h-16 rounded-2xl bg-blue-500/20 flex items-center justify-center mb-6">
|
||||
<svg className="w-10 h-10" viewBox="0 0 756.26 596.9">
|
||||
<path fill="#1d63ed" d="M743.96,245.25c-18.54-12.48-67.26-17.81-102.68-8.27-1.91-35.28-20.1-65.01-53.38-90.95l-12.32-8.27-8.21,12.4c-16.14,24.5-22.94,57.14-20.53,86.81,1.9,18.28,8.26,38.83,20.53,53.74-46.1,26.74-88.59,20.67-276.77,20.67H.06c-.85,42.49,5.98,124.23,57.96,190.77,5.74,7.35,12.04,14.46,18.87,21.31,42.26,42.32,106.11,73.35,201.59,73.44,145.66.13,270.46-78.6,346.37-268.97,24.98.41,90.92,4.48,123.19-57.88.79-1.05,8.21-16.54,8.21-16.54l-12.3-8.27ZM189.67,206.39h-81.7v81.7h81.7v-81.7ZM295.22,206.39h-81.7v81.7h81.7v-81.7ZM400.77,206.39h-81.7v81.7h81.7v-81.7ZM506.32,206.39h-81.7v81.7h81.7v-81.7ZM84.12,206.39H2.42v81.7h81.7v-81.7ZM189.67,103.2h-81.7v81.7h81.7v-81.7ZM295.22,103.2h-81.7v81.7h81.7v-81.7ZM400.77,103.2h-81.7v81.7h81.7v-81.7ZM400.77,0h-81.7v81.7h81.7V0Z"/>
|
||||
</svg>
|
||||
</div>
|
||||
|
||||
<h2 className="text-xl font-semibold text-gray-900 dark:text-white mb-2">
|
||||
Set up cross-compiler
|
||||
</h2>
|
||||
<p className="text-gray-500 dark:text-gray-400 mb-8 text-center max-w-sm">
|
||||
Choose how to get the Docker cross-compilation image
|
||||
</p>
|
||||
|
||||
<div className="flex flex-col gap-3 mb-6 w-full max-w-xs">
|
||||
<button
|
||||
onClick={onDownloadOfficial}
|
||||
className="w-full px-5 py-3 rounded-lg border border-red-500 text-red-600 dark:text-red-400 text-sm font-medium hover:bg-red-500/10 transition-colors flex items-center justify-center gap-2"
|
||||
>
|
||||
<svg className="w-5 h-5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-4l-4 4m0 0l-4-4m4 4V4" />
|
||||
</svg>
|
||||
Download official image
|
||||
</button>
|
||||
|
||||
<a
|
||||
href="https://wails.io/docs/guides/build/cross-platform#build-your-own-image"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="w-full px-5 py-3 rounded-lg border border-gray-300 dark:border-gray-600 text-gray-700 dark:text-gray-300 text-sm font-medium hover:bg-gray-50 dark:hover:bg-gray-800 transition-colors flex items-center justify-center gap-2"
|
||||
>
|
||||
<svg className="w-5 h-5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M10 20l4-16m4 4l4 4-4 4M6 16l-4-4 4-4" />
|
||||
</svg>
|
||||
Build your own image
|
||||
<svg className="w-4 h-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14" />
|
||||
</svg>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div className="flex flex-col items-center gap-2">
|
||||
{canGoBack && onBack && (
|
||||
<button
|
||||
onClick={onBack}
|
||||
className="px-4 py-2 rounded-lg text-sm font-medium transition-colors border border-gray-300 dark:border-gray-600 text-gray-600 dark:text-gray-400 hover:bg-gray-100 dark:hover:bg-gray-800"
|
||||
>
|
||||
Back
|
||||
</button>
|
||||
)}
|
||||
<button
|
||||
onClick={onSkip}
|
||||
className="text-xs text-gray-500 dark:text-gray-400 hover:text-gray-700 dark:hover:text-gray-300 transition-colors"
|
||||
>
|
||||
Skip for now
|
||||
</button>
|
||||
</div>
|
||||
</motion.div>
|
||||
);
|
||||
}
|
||||
|
||||
function DockerBuildError({
|
||||
onBuildImage,
|
||||
onSkip
|
||||
|
|
@ -967,24 +1051,6 @@ function SDKLicensePage({
|
|||
transition={{ duration: 0.3 }}
|
||||
className="flex-1 flex flex-col items-center justify-center"
|
||||
>
|
||||
{canGoBack && onBack && (
|
||||
<button
|
||||
onClick={onBack}
|
||||
className="absolute top-4 left-4 p-2 rounded-lg text-gray-500 hover:text-gray-700 dark:text-gray-400 dark:hover:text-gray-200 hover:bg-gray-100 dark:hover:bg-gray-800 transition-colors"
|
||||
aria-label="Go back"
|
||||
>
|
||||
<svg className="w-5 h-5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M15 19l-7-7 7-7" />
|
||||
</svg>
|
||||
</button>
|
||||
)}
|
||||
|
||||
<div className="w-12 h-12 rounded-xl bg-gray-100 dark:bg-gray-800 flex items-center justify-center mb-4">
|
||||
<svg className="w-6 h-6 text-gray-600 dark:text-gray-300" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z" />
|
||||
</svg>
|
||||
</div>
|
||||
|
||||
<h2 className="text-lg font-semibold text-gray-900 dark:text-white mb-1">
|
||||
Apple SDK License Agreement
|
||||
</h2>
|
||||
|
|
@ -1013,23 +1079,33 @@ function SDKLicensePage({
|
|||
</span>
|
||||
</label>
|
||||
|
||||
<div className="flex gap-3">
|
||||
<div className="flex flex-col items-center gap-2">
|
||||
<div className="flex gap-3">
|
||||
{canGoBack && onBack && (
|
||||
<button
|
||||
onClick={onBack}
|
||||
className="px-4 py-2 rounded-lg text-sm font-medium transition-colors border border-gray-300 dark:border-gray-600 text-gray-600 dark:text-gray-400 hover:bg-gray-100 dark:hover:bg-gray-800"
|
||||
>
|
||||
Back
|
||||
</button>
|
||||
)}
|
||||
<button
|
||||
onClick={onAgree}
|
||||
disabled={!agreed}
|
||||
className={`px-5 py-2.5 rounded-lg text-sm font-medium transition-colors ${
|
||||
agreed
|
||||
? 'bg-red-500 text-white hover:bg-red-600'
|
||||
: 'bg-gray-200 text-gray-400 cursor-not-allowed'
|
||||
}`}
|
||||
>
|
||||
Continue
|
||||
</button>
|
||||
</div>
|
||||
<button
|
||||
onClick={onDecline}
|
||||
className="px-5 py-2.5 rounded-lg border border-gray-300 dark:border-gray-600 text-gray-700 dark:text-gray-300 text-sm font-medium hover:bg-gray-50 dark:hover:bg-gray-800 transition-colors"
|
||||
className="text-xs text-gray-500 dark:text-gray-400 hover:text-gray-700 dark:hover:text-gray-300 transition-colors"
|
||||
>
|
||||
Skip cross-platform
|
||||
</button>
|
||||
<button
|
||||
onClick={onAgree}
|
||||
disabled={!agreed}
|
||||
className={`px-5 py-2.5 rounded-lg text-sm font-medium transition-colors ${
|
||||
agreed
|
||||
? 'bg-blue-500 text-white hover:bg-blue-600'
|
||||
: 'bg-gray-200 text-gray-400 cursor-not-allowed'
|
||||
}`}
|
||||
>
|
||||
Continue
|
||||
Skip for now
|
||||
</button>
|
||||
</div>
|
||||
</motion.div>
|
||||
|
|
@ -1985,9 +2061,20 @@ export default function App() {
|
|||
};
|
||||
|
||||
const handleCrossPlatformYes = async () => {
|
||||
navigateTo('docker-options');
|
||||
};
|
||||
|
||||
const handleDockerOptionsDownload = async () => {
|
||||
navigateTo('sdk-license');
|
||||
};
|
||||
|
||||
const handleDockerOptionsSkip = async () => {
|
||||
const loadedDefaults = await getDefaults();
|
||||
setDefaults(loadedDefaults);
|
||||
setUseInterfaces(loadedDefaults.project?.useInterfaces ?? true);
|
||||
navigateTo('projects');
|
||||
};
|
||||
|
||||
const handleSDKLicenseAgree = async () => {
|
||||
const docker = await getDockerStatus();
|
||||
setDockerStatus(docker);
|
||||
|
|
@ -2193,6 +2280,15 @@ export default function App() {
|
|||
canGoBack={canGoBack}
|
||||
/>
|
||||
)}
|
||||
{step === 'docker-options' && (
|
||||
<DockerOptionsPage
|
||||
key="docker-options"
|
||||
onDownloadOfficial={handleDockerOptionsDownload}
|
||||
onSkip={handleDockerOptionsSkip}
|
||||
onBack={goBack}
|
||||
canGoBack={canGoBack}
|
||||
/>
|
||||
)}
|
||||
{step === 'sdk-license' && (
|
||||
<SDKLicensePage
|
||||
key="sdk-license"
|
||||
|
|
|
|||
|
|
@ -243,6 +243,7 @@ type Wizard struct {
|
|||
dockerMu sync.RWMutex
|
||||
done chan struct{}
|
||||
shutdown chan struct{}
|
||||
shutdownOnce sync.Once
|
||||
buildWg sync.WaitGroup
|
||||
}
|
||||
|
||||
|
|
@ -510,7 +511,7 @@ func (w *Wizard) handleClose(rw http.ResponseWriter, r *http.Request) {
|
|||
// Wait for any running Docker builds to complete before shutting down
|
||||
go func() {
|
||||
w.buildWg.Wait()
|
||||
close(w.shutdown)
|
||||
w.shutdownOnce.Do(func() { close(w.shutdown) })
|
||||
}()
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -105,8 +105,20 @@ func checkGo() DependencyStatus {
|
|||
|
||||
versionParts := strings.Split(versionStr, ".")
|
||||
if len(versionParts) >= 2 {
|
||||
major, _ := strconv.Atoi(versionParts[0])
|
||||
minor, _ := strconv.Atoi(versionParts[1])
|
||||
major, majorErr := strconv.Atoi(versionParts[0])
|
||||
// Handle versions like "25beta1" by extracting leading digits
|
||||
minorStr := versionParts[1]
|
||||
for i, c := range minorStr {
|
||||
if c < '0' || c > '9' {
|
||||
minorStr = minorStr[:i]
|
||||
break
|
||||
}
|
||||
}
|
||||
minor, minorErr := strconv.Atoi(minorStr)
|
||||
if majorErr != nil || minorErr != nil {
|
||||
// Couldn't parse version; assume it's acceptable
|
||||
return dep
|
||||
}
|
||||
if major < 1 || (major == 1 && minor < 25) {
|
||||
dep.Status = "needs_update"
|
||||
dep.Message = "Go 1.25+ is required (found " + versionStr + ")"
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue