feat: add comprehensive Windows PowerShell script usage instructions

- Enhanced ScriptPreview with detailed Windows-specific installation steps including execution policy handling and winget availability checks
- Added localization support for all script preview UI elements and Windows usage instructions
- Improved script generator with automatic unblocking, admin privilege warnings, and winget validation
This commit is contained in:
Yusuf İpek
2025-11-11 16:13:29 +03:00
parent a462c18cc6
commit 299e951368
7 changed files with 457 additions and 33 deletions
+63 -23
View File
@@ -5,6 +5,7 @@ import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/com
import { Button } from '@/components/ui/button'
import { GeneratedScript, SelectedPackage, Platform } from '@/types'
import { Download, Copy, Check, Terminal, Shield } from 'lucide-react'
import { useLocale } from '@/contexts/LocaleContext'
interface ScriptPreviewProps {
generatedScript: GeneratedScript | null
@@ -20,6 +21,7 @@ export function ScriptPreview({
onClose
}: ScriptPreviewProps) {
const [copied, setCopied] = useState(false)
const { t } = useLocale()
if (!generatedScript || !selectedPlatform) {
return null
@@ -40,7 +42,8 @@ export function ScriptPreview({
const url = URL.createObjectURL(blob)
const a = document.createElement('a')
a.href = url
a.download = `install-packages-${selectedPlatform?.id || 'unknown'}.sh`
const ext = getScriptExtension()
a.download = `install-packages-${selectedPlatform?.id || 'unknown'}${ext}`
document.body.appendChild(a)
a.click()
document.body.removeChild(a)
@@ -71,58 +74,58 @@ export function ScriptPreview({
return (
<div className="fixed inset-0 bg-black/50 flex items-center justify-center p-4 z-50">
<Card className="w-full max-w-4xl max-h-[90vh] overflow-hidden">
<Card className="w-full max-w-4xl max-h-[90vh] overflow-auto">
<CardHeader>
<div className="flex items-center justify-between">
<div>
<CardTitle className="flex items-center space-x-2">
<Terminal className="h-5 w-5" />
<span>Installation Script</span>
<span>{t('script.title')}</span>
</CardTitle>
<CardDescription>
Idempotent script for {selectedPlatform?.name || 'Unknown Platform'} using {selectedPlatform?.packageManager || 'Unknown Package Manager'}
{t('script.description')} {selectedPlatform?.name || 'Unknown Platform'}
</CardDescription>
</div>
<Button variant="outline" onClick={onClose}>
Close
{t('common.close')}
</Button>
</div>
</CardHeader>
<CardContent className="space-y-4">
<CardContent className="space-y-4 overflow-y-auto max-h-[70vh] pr-2">
{/* Script Info */}
<div className="grid grid-cols-1 md:grid-cols-3 gap-4">
<div className="p-3 bg-secondary rounded-lg">
<div className="flex items-center space-x-2 mb-1">
<Shield className="h-4 w-4 text-green-600" />
<span className="font-medium text-sm">Official Repositories</span>
<span className="font-medium text-sm">{t('script.official_repos')}</span>
</div>
<p className="text-xs text-muted-foreground">
All packages from trusted sources
{t('script.official_repos_desc')}
</p>
</div>
<div className="p-3 bg-secondary rounded-lg">
<div className="flex items-center space-x-2 mb-1">
<Terminal className="h-4 w-4 text-blue-600" />
<span className="font-medium text-sm">Idempotent</span>
<span className="font-medium text-sm">{t('script.idempotent')}</span>
</div>
<p className="text-xs text-muted-foreground">
Safe to run multiple times
{t('script.idempotent_desc')}
</p>
</div>
<div className="p-3 bg-secondary rounded-lg">
<div className="flex items-center space-x-2 mb-1">
<Download className="h-4 w-4 text-purple-600" />
<span className="font-medium text-sm">{selectedPackages.length} Packages</span>
<span className="font-medium text-sm">{selectedPackages.length} {t('script.packages_count')}</span>
</div>
<p className="text-xs text-muted-foreground">
Ready for installation
{t('script.packages_count_desc')}
</p>
</div>
</div>
{/* Package List */}
<div>
<h4 className="font-medium mb-2">Included Packages:</h4>
<h4 className="font-medium mb-2">{t('script.included_packages')}</h4>
<div className="flex flex-wrap gap-2">
{selectedPackages.map((pkg) => (
<span
@@ -138,7 +141,7 @@ export function ScriptPreview({
{/* Script Content */}
<div>
<div className="flex items-center justify-between mb-2">
<h4 className="font-medium">Script Content:</h4>
<h4 className="font-medium">{t('script.script_content')}</h4>
<div className="flex space-x-2">
<Button variant="outline" size="sm" onClick={handleCopy}>
{copied ? (
@@ -146,11 +149,11 @@ export function ScriptPreview({
) : (
<Copy className="h-4 w-4 mr-2" />
)}
{copied ? 'Copied!' : 'Copy'}
{copied ? t('script.copied') : t('script.copy')}
</Button>
<Button size="sm" onClick={handleDownload}>
<Download className="h-4 w-4 mr-2" />
Download {getScriptExtension()}
{t('script.download')} {getScriptExtension()}
</Button>
</div>
</div>
@@ -163,13 +166,50 @@ export function ScriptPreview({
{/* Usage Instructions */}
<div className="p-4 bg-blue-50 border border-blue-200 rounded-lg">
<h4 className="font-medium text-blue-900 mb-2">How to use:</h4>
<ol className="text-sm text-blue-800 space-y-1 list-decimal list-inside">
<li>Download the script file to your target machine</li>
<li>Make it executable (for Linux/macOS): <code className="bg-blue-100 px-1 rounded">chmod +x install-packages-{selectedPlatform?.id || 'unknown'}{getScriptExtension()}</code></li>
<li>Run the script with appropriate permissions</li>
<li>The script will automatically handle repository setup and package installation</li>
</ol>
<h4 className="font-medium text-blue-900 mb-2">{t('script.usage')}</h4>
{selectedPlatform?.id === 'windows' ? (
<ol className="text-sm text-blue-800 space-y-2 list-decimal list-inside">
<li>
{t('script.windows_usage.download_intro')}
<code className="bg-blue-100 px-1 mx-1 rounded">{t('script.windows_usage.file_name')}</code>)
</li>
<li>
{t('script.windows_usage.open_powershell_intro')}
<code className="bg-blue-100 px-1 mx-1 rounded">{t('script.windows_usage.disabled_error')}</code>,
{t('script.windows_usage.run_one')}
<div className="mt-1 space-y-1">
<div>
{t('script.windows_usage.persistent_title')}
<code className="block bg-blue-100 px-2 py-1 mt-1 rounded">{t('script.windows_usage.persistent_cmd')}</code>
{t('script.windows_usage.then_run')} <code className="bg-blue-100 px-1 rounded">{t('script.windows_usage.then_run_cmd')}</code>
</div>
<div>
{t('script.windows_usage.onetime_title')}
<code className="block bg-blue-100 px-2 py-1 mt-1 rounded">{t('script.windows_usage.onetime_cmd')}</code>
</div>
</div>
</li>
<li>
{t('script.windows_usage.unblock_title')}
<code className="block bg-blue-100 px-2 py-1 mt-1 rounded">{t('script.windows_usage.unblock_cmd')}</code>
</li>
<li>
{t('script.windows_usage.winget_title')}
<span className="block mt-1">{t('script.windows_usage.store_link_label')}: ms-windows-store://pdp/?productId=9NBLGGH4NNS1</span>
<span className="block">{t('script.windows_usage.direct_link_label')}: https://aka.ms/getwinget</span>
</li>
</ol>
) : (
<ol className="text-sm text-blue-800 space-y-2 list-decimal list-inside">
<li>{t('script.usage_steps.0')}</li>
<li>
{t('script.usage_steps.1')}
<code className="block bg-blue-100 px-2 py-1 mt-1 rounded">chmod +x install-packages-{selectedPlatform?.id || 'unknown'}{getScriptExtension()}</code>
</li>
<li>{t('script.usage_steps.2')}</li>
<li>{t('script.usage_steps.3')}</li>
</ol>
)}
</div>
</CardContent>
</Card>