@props([]) {{-- | The release editor's fields — one definition, two hosts. | | The standalone page (versions/form.blade.php) and the upload modal on the | index both render this, so a field can never exist on one and not the other. | Plain named inputs with server-rendered values: the page submits normally, and | the modal reads the same fields out of the form with FormData. | | Requires in scope: $version (a UpdateVersion, possibly unsaved), $errorFor | (a closure returning an Alpine expression or null — the modal shows XHR | validation errors, the page shows @error output). --}} @php $old = fn (string $field, $fallback = null) => old($field, $version->$field ?? $fallback); $products = ['cms' => 'TaxPilot CMS', 'ai' => 'TaxPilot AI']; $channels = [ 'stable' => ['Stable', 'Every installation'], 'beta' => ['Beta', 'Opt-in installs only'], ]; @endphp

Semantic versioning — 1.3.2 or 1.3.2-beta.

@error('version')

{{ $message }}

@enderror

Optional. Shown beside the number.

@error('release_name')

{{ $message }}

@enderror
Product *
@foreach ($products as $value => $label) @endforeach

An installation only ever receives releases of the product it asks for.

@error('product')

{{ $message }}

@enderror
Channel *
@foreach ($channels as $value => [$label, $description]) @endforeach
@error('channel')

{{ $message }}

@enderror
@error('release_date')

{{ $message }}

@enderror
@error('min_supported_version')

{{ $message }}

@enderror

{{-- package_type is a select the request still validates, but attachPackage overwrites it by reading the archive. It stays here so a package-less draft has a value, with the truth stated rather than hidden. --}}

Re-detected from inside the archive on upload — what is in the ZIP wins.

@error('package_type')

{{ $message }}

@enderror

Markdown. Group into New Features / Improvements / Bug Fixes / Security Fixes / Database Changes.

@error('release_notes')

{{ $message }}

@enderror
{{-- ── Package ─────────────────────────────────────────────────── --}}
Update package (ZIP) @if ($version->exists && $version->hasPackage())

{{ $version->downloadName() }} · {{ number_format($version->file_size / 1048576, 1) }} MB

sha256: {{ $version->checksum_sha256 }}

Re-uploading replaces this file, clears its signature and returns the release to draft.

@endif {{-- Drag and drop, with a real file input behind it: the input is what submits, the dropzone only ever sets its files. No nested x-data here on purpose — x-ref registers on the closest component root, and pickFile() lives on the page component. A local scope would hide the input from the very method that fills it. --}} @error('package')

{{ $message }}

@enderror

A package must also be signed offline with updates:sign before it can be published — clients reject unsigned releases.