Add publisher release versions to plugins
This commit is contained in:
@@ -28,7 +28,7 @@ export async function GET({ url }: { url: URL }) {
|
||||
target_rel_path: script?.target_rel_path ?? '',
|
||||
kind: script?.kind ?? bs.kind ?? 'script',
|
||||
version: version
|
||||
? { id: version.id, version: version.version, sha256: version.sha256 }
|
||||
? { id: version.id, version: version.version, release_version: version.release_version, sha256: version.sha256 }
|
||||
: null
|
||||
};
|
||||
});
|
||||
|
||||
@@ -24,7 +24,7 @@ export async function GET({ params }: { params: { id: string } }) {
|
||||
target_rel_path: script?.target_rel_path ?? '',
|
||||
kind: script?.kind ?? bs.kind ?? 'script',
|
||||
version: version
|
||||
? { id: version.id, version: version.version, sha256: version.sha256 }
|
||||
? { id: version.id, version: version.version, release_version: version.release_version, sha256: version.sha256 }
|
||||
: null
|
||||
};
|
||||
});
|
||||
|
||||
@@ -42,6 +42,7 @@ export async function GET({ url }: { url: URL }) {
|
||||
? {
|
||||
id: versions[0].id,
|
||||
version: versions[0].version,
|
||||
release_version: versions[0].release_version,
|
||||
sha256: versions[0].sha256,
|
||||
size: versions[0].size,
|
||||
state: versions[0].state,
|
||||
@@ -58,7 +59,7 @@ export async function GET({ url }: { url: URL }) {
|
||||
|
||||
// Multipart POST — creates an artifact + version 1 from either an uploaded
|
||||
// file (script/plugin/baseline) or a text body (config overlay). Fields:
|
||||
// name, scopeType, scopeValue, notes, kind (defaults to 'script'),
|
||||
// name, scopeType, scopeValue, notes, releaseVersion, kind (defaults to 'script'),
|
||||
// content (file). Configs may alternatively send `text` as a form field.
|
||||
export async function POST({ request, url }: { request: Request; url: URL }) {
|
||||
const form = await request.formData();
|
||||
@@ -104,6 +105,7 @@ export async function POST({ request, url }: { request: Request; url: URL }) {
|
||||
scopeValue,
|
||||
content,
|
||||
notes,
|
||||
releaseVersion: form.has('releaseVersion') ? String(form.get('releaseVersion')) : undefined,
|
||||
kind
|
||||
});
|
||||
return json({ ok: true, script, versionId: version.id });
|
||||
|
||||
@@ -23,6 +23,7 @@ export async function GET({ params }: { params: { id: string } }) {
|
||||
const versions = listVersions(id).map((v) => ({
|
||||
id: v.id,
|
||||
version: v.version,
|
||||
release_version: v.release_version,
|
||||
sha256: v.sha256,
|
||||
size: v.size,
|
||||
notes: v.notes,
|
||||
|
||||
@@ -7,7 +7,7 @@ function parseId(idRaw: string): number | null {
|
||||
}
|
||||
|
||||
// Multipart POST — creates a new version from an uploaded file. Fields:
|
||||
// content (file), notes (optional). Response includes a "betaRequired" hint
|
||||
// content (file), notes and releaseVersion (optional). Response includes a "betaRequired" hint
|
||||
// when the script has a scope so the UI can nudge the operator to open a beta.
|
||||
export async function POST({ params, request }: { params: { id: string }; request: Request }) {
|
||||
const scriptId = parseId(params.id);
|
||||
@@ -22,12 +22,14 @@ export async function POST({ params, request }: { params: { id: string }; reques
|
||||
|
||||
const content = Buffer.from(await file.arrayBuffer());
|
||||
try {
|
||||
const version = uploadNewVersion(scriptId, content, notes);
|
||||
const releaseVersion = form.has('releaseVersion') ? String(form.get('releaseVersion')) : undefined;
|
||||
const version = uploadNewVersion(scriptId, content, notes, releaseVersion);
|
||||
return json({
|
||||
ok: true,
|
||||
version: {
|
||||
id: version.id,
|
||||
version: version.version,
|
||||
release_version: version.release_version,
|
||||
sha256: version.sha256,
|
||||
size: version.size,
|
||||
notes: version.notes,
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
import BetaPlanBuilder from "$ui/components/BetaPlanBuilder.svelte";
|
||||
import { defaultPlan, parseBetaPlan } from "$lib/beta-plan.js";
|
||||
import { onMount, onDestroy } from 'svelte';
|
||||
import { artifactVersionLabel } from '$lib/artifact-version.js';
|
||||
import { goto } from '$app/navigation';
|
||||
import Card from '$ui/components/primitives/Card.svelte';
|
||||
import Badge from '$ui/components/primitives/Badge.svelte';
|
||||
@@ -21,7 +22,7 @@
|
||||
closed_at: string | null;
|
||||
scripts: Array<{
|
||||
id: number; name: string; target_rel_path: string; kind: ArtifactKind;
|
||||
version: { id: number; version: number; sha256: string } | null;
|
||||
version: { id: number; version: number; release_version: string | null; sha256: string } | null;
|
||||
}>;
|
||||
servers: Array<{ server: string; stage: string; error: string | null }>;
|
||||
}
|
||||
@@ -35,7 +36,7 @@
|
||||
} | null;
|
||||
runningBetaId: number | null;
|
||||
}
|
||||
interface Version { id: number; version: number; sha256: string; size: number; state: 'untested' | 'tested' | 'test-failed'; }
|
||||
interface Version { id: number; version: number; release_version: string | null; sha256: string; size: number; state: 'untested' | 'tested' | 'test-failed'; }
|
||||
interface ServerRow { name: string; game: string | null; map: string | null; }
|
||||
interface ScriptDetail { script: ScriptListRow; versions: Version[]; matchedServers: string[]; }
|
||||
interface Pick { key: number; scriptId: number | null; versionId: number | null; }
|
||||
@@ -205,7 +206,7 @@
|
||||
if (b.scripts.length === 0) return '(no artifacts)';
|
||||
if (b.scripts.length === 1) {
|
||||
const s = b.scripts[0];
|
||||
return `[${s.kind}] ${s.name} · v${s.version?.version ?? '?'}`;
|
||||
return `[${s.kind}] ${s.name} · ${artifactVersionLabel(s.version)}`;
|
||||
}
|
||||
const byKind: Record<string, number> = {};
|
||||
for (const s of b.scripts) byKind[s.kind] = (byKind[s.kind] ?? 0) + 1;
|
||||
@@ -265,7 +266,7 @@
|
||||
<option value={null}>—</option>
|
||||
{:else}
|
||||
{#each versionsForRow(row) as v (v.id)}
|
||||
<option value={v.id}>v{v.version} · {v.sha256.slice(0, 8)} · {v.state}</option>
|
||||
<option value={v.id}>{artifactVersionLabel(v)} · {v.sha256.slice(0, 8)} · {v.state}</option>
|
||||
{/each}
|
||||
{/if}
|
||||
</select>
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<script lang="ts">
|
||||
import { artifactVersionLabel } from '$lib/artifact-version.js';
|
||||
import BetaTestProgress from "$ui/components/BetaTestProgress.svelte";
|
||||
import type { BetaTestView } from "$lib/beta-plan.js";
|
||||
import { onMount, onDestroy } from 'svelte';
|
||||
@@ -29,7 +30,7 @@
|
||||
interface BetaScript {
|
||||
id: number; name: string; target_rel_path: string;
|
||||
kind: 'script' | 'config' | 'plugin' | 'baseline';
|
||||
version: { id: number; version: number; sha256: string } | null;
|
||||
version: { id: number; version: number; release_version: string | null; sha256: string } | null;
|
||||
}
|
||||
|
||||
let test = $state<BetaTestView | null>(null);
|
||||
@@ -164,7 +165,7 @@
|
||||
<Badge variant="neutral" size="sm" uppercase>{s.kind}</Badge>
|
||||
<a class="s-name" href="/scripts/{s.id}">{s.name}</a>
|
||||
<span class="s-target">{s.target_rel_path}</span>
|
||||
<span class="s-ver">v{s.version?.version ?? '?'}</span>
|
||||
<span class="s-ver">{artifactVersionLabel(s.version)}</span>
|
||||
<span class="s-sha">{s.version?.sha256.slice(0, 8) ?? ''}</span>
|
||||
</div>
|
||||
{/each}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
<script lang="ts">
|
||||
import { onMount } from 'svelte';
|
||||
import { artifactVersionLabel } from '$lib/artifact-version.js';
|
||||
import Card from '$ui/components/primitives/Card.svelte';
|
||||
import Badge from '$ui/components/primitives/Badge.svelte';
|
||||
import Button from '$ui/components/primitives/Button.svelte';
|
||||
@@ -20,6 +21,7 @@
|
||||
kind: ArtifactKind;
|
||||
latestVersion: {
|
||||
id: number; version: number; sha256: string; size: number;
|
||||
release_version: string | null;
|
||||
state: 'untested' | 'tested' | 'test-failed'; uploaded_at: string;
|
||||
} | null;
|
||||
versionCount: number;
|
||||
@@ -33,9 +35,10 @@
|
||||
let flash = $state<string | null>(null);
|
||||
let uploading = $state(false);
|
||||
let scopeOptions = $state<ScopeOptions>({ games: [], mapsByGame: {} });
|
||||
let successBanner = $state<{ name: string; artifactId: number; version: number } | null>(null);
|
||||
let successBanner = $state<{ name: string; artifactId: number; version: number; release_version: string | null } | null>(null);
|
||||
|
||||
let newName = $state('');
|
||||
let newReleaseVersion = $state('');
|
||||
let newScopeType = $state<'none' | 'game' | 'map'>('none');
|
||||
let newScopeGame = $state('');
|
||||
let newScopeMap = $state('');
|
||||
@@ -85,6 +88,7 @@
|
||||
const form = new FormData();
|
||||
form.append('name', newName.trim());
|
||||
form.append('kind', 'plugin');
|
||||
form.append('releaseVersion', newReleaseVersion.trim());
|
||||
form.append('scopeType', newScopeType);
|
||||
if (scopeValue) form.append('scopeValue', scopeValue);
|
||||
if (newNotes.trim()) form.append('notes', newNotes.trim());
|
||||
@@ -94,9 +98,10 @@
|
||||
const body = (await res.json()) as { ok: boolean; error?: string; script?: { id: number; name: string } };
|
||||
if (!res.ok || !body.ok) { flash = body.error ?? `HTTP ${res.status}`; return; }
|
||||
successBanner = body.script
|
||||
? { name: body.script.name, artifactId: body.script.id, version: 1 }
|
||||
? { name: body.script.name, artifactId: body.script.id, version: 1, release_version: newReleaseVersion.trim() || null }
|
||||
: null;
|
||||
newName = ''; newScopeType = 'none'; newScopeGame = ''; newScopeMap = ''; newNotes = ''; newFile = null;
|
||||
newReleaseVersion = '';
|
||||
await load();
|
||||
} finally {
|
||||
uploading = false;
|
||||
@@ -121,7 +126,7 @@
|
||||
if (!a.latestVersion) return '';
|
||||
if (a.current_version_id === null) return 'untested';
|
||||
if (a.latestVersion.id !== a.current_version_id) {
|
||||
return `v${a.latestVersion.version} ${a.latestVersion.state.replace('-', ' ')}`;
|
||||
return `${artifactVersionLabel(a.latestVersion)} ${a.latestVersion.state.replace('-', ' ')}`;
|
||||
}
|
||||
return '';
|
||||
}
|
||||
@@ -148,7 +153,7 @@
|
||||
<h2 class="panel-title">Upload a plugin</h2>
|
||||
{#if successBanner}
|
||||
<div class="banner">
|
||||
<strong>v{successBanner.version} of "{successBanner.name}" uploaded — untested.</strong>
|
||||
<strong>{artifactVersionLabel(successBanner)} of "{successBanner.name}" uploaded — untested.</strong>
|
||||
<span>Open a beta on <a href="/betas">the betas page</a> to test it before promotion.</span>
|
||||
</div>
|
||||
{/if}
|
||||
@@ -156,6 +161,9 @@
|
||||
<Field label="Name">
|
||||
<Input bind:value={newName} placeholder="my plugin" disabled={uploading} />
|
||||
</Field>
|
||||
<Field label="Release version" hint="Optional. Use the publisher’s version or release tag, such as v3.1.0.">
|
||||
<Input bind:value={newReleaseVersion} placeholder="v3.1.0" disabled={uploading} />
|
||||
</Field>
|
||||
<Field label="Notes" hint="Optional. What changed in this version.">
|
||||
<Input bind:value={newNotes} placeholder="what changed" disabled={uploading} />
|
||||
</Field>
|
||||
@@ -218,7 +226,7 @@
|
||||
</div>
|
||||
<div class="row-meta">
|
||||
<span class="path">{a.target_rel_path}</span>
|
||||
<span>v{a.latestVersion?.version ?? '—'} · {a.versionCount} version{a.versionCount === 1 ? '' : 's'}</span>
|
||||
<span>{artifactVersionLabel(a.latestVersion)} · {a.versionCount} version{a.versionCount === 1 ? '' : 's'}</span>
|
||||
{#if a.servers.length}
|
||||
<span>{a.servers.length} matching server{a.servers.length === 1 ? '' : 's'}</span>
|
||||
{/if}
|
||||
|
||||
Reference in New Issue
Block a user