feat(events): restore PDF→webp convert button in event file table
Adds a per-row "Convert PDF → Image" button in ae_comp__event_file_obj_tbl.
Only shown when edit_mode is on, the file is a PDF, and the session
type_code is 'poster' — poster sessions need images in the Launcher modal
(which uses <img>, not a PDF viewer).
Calls GET /v3/action/hosted_file/{id}/convert_file (pdf2image, 3840px wide,
first page, saves as a new hosted_file linked to the same parent object).
Per-row status tracking: idle → converting → done | error with retry.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -65,6 +65,53 @@
|
|||||||
let horiz_scroll_warning: boolean = $state(false);
|
let horiz_scroll_warning: boolean = $state(false);
|
||||||
let horiz_check_element: HTMLElement | null = $state(null);
|
let horiz_check_element: HTMLElement | null = $state(null);
|
||||||
|
|
||||||
|
// PDF → Image conversion state (keyed by event_file_id)
|
||||||
|
// WHY: Poster sessions display files in the Launcher modal via <img> tag — PDFs can't render there.
|
||||||
|
// Presenters upload PDFs which must be converted server-side to high-res webp images.
|
||||||
|
// Button is only shown in edit_mode for PDF files linked to a poster-type session.
|
||||||
|
// Backend: /v3/action/hosted_file/{id}/convert_file runs pdf2image (3840px wide, first page only)
|
||||||
|
// and saves the result as a new hosted_file record linked to the same parent object.
|
||||||
|
type ConvertStatus = 'idle' | 'converting' | 'done' | 'error';
|
||||||
|
let convert_status_kv: Record<string, ConvertStatus> = $state({});
|
||||||
|
let convert_result_kv: Record<string, any> = $state({});
|
||||||
|
|
||||||
|
async function handle_convert_pdf_to_image(event_file_obj: any) {
|
||||||
|
const file_id = event_file_obj.event_file_id;
|
||||||
|
convert_status_kv[file_id] = 'converting';
|
||||||
|
try {
|
||||||
|
// Link the new image to the most specific parent available
|
||||||
|
const link_to_type = event_file_obj.event_session_id ? 'event_session'
|
||||||
|
: event_file_obj.event_presentation_id ? 'event_presentation'
|
||||||
|
: 'event';
|
||||||
|
const link_to_id = event_file_obj.event_session_id
|
||||||
|
|| event_file_obj.event_presentation_id
|
||||||
|
|| event_file_obj.event_id;
|
||||||
|
const filename_no_ext = (event_file_obj.filename ?? 'poster_image').replace(/\.pdf$/i, '');
|
||||||
|
const url = `${$ae_api.base_url}/v3/action/hosted_file/${event_file_obj.hosted_file_id}/convert_file`
|
||||||
|
+ `?link_to_type=${encodeURIComponent(link_to_type)}`
|
||||||
|
+ `&link_to_id=${encodeURIComponent(link_to_id)}`
|
||||||
|
+ `&filename_no_ext=${encodeURIComponent(filename_no_ext)}`
|
||||||
|
+ `&to_type=webp`;
|
||||||
|
const resp = await fetch(url, {
|
||||||
|
headers: {
|
||||||
|
'x-aether-api-key': $ae_api.api_secret_key,
|
||||||
|
'x-account-id': String($ae_api.account_id ?? '')
|
||||||
|
}
|
||||||
|
});
|
||||||
|
const body = await resp.json();
|
||||||
|
if (resp.ok && body?.data) {
|
||||||
|
convert_result_kv[file_id] = body.data;
|
||||||
|
convert_status_kv[file_id] = 'done';
|
||||||
|
} else {
|
||||||
|
console.error('[convert_pdf] API error:', body);
|
||||||
|
convert_status_kv[file_id] = 'error';
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.error('[convert_pdf] Fetch failed:', err);
|
||||||
|
convert_status_kv[file_id] = 'error';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Check if element is scrolling horizontally
|
// Check if element is scrolling horizontally
|
||||||
$effect(() => {
|
$effect(() => {
|
||||||
if (
|
if (
|
||||||
@@ -437,7 +484,44 @@
|
|||||||
max_filename={50}
|
max_filename={50}
|
||||||
classes="btn btn-sm preset-tonal-primary hover:preset-filled-primary-500 min-w-72"
|
classes="btn btn-sm preset-tonal-primary hover:preset-filled-primary-500 min-w-72"
|
||||||
/>
|
/>
|
||||||
<!-- {event_file_obj?.filename} -->
|
<!-- PDF → webp convert button: only for poster sessions in edit mode -->
|
||||||
|
{#if $ae_loc.edit_mode && event_file_obj?.extension === 'pdf' && event_file_obj?.event_session_type_code === 'poster'}
|
||||||
|
<div class="mt-1">
|
||||||
|
{#if !convert_status_kv[event_file_obj.event_file_id] || convert_status_kv[event_file_obj.event_file_id] === 'idle'}
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
class="btn btn-sm preset-tonal-warning border border-warning-500"
|
||||||
|
title="Convert this PDF to a high-res webp image for use in the Launcher poster display."
|
||||||
|
onclick={() => handle_convert_pdf_to_image(event_file_obj)}
|
||||||
|
>
|
||||||
|
<span class="fas fa-file-image mx-1"></span>
|
||||||
|
Convert PDF → Image
|
||||||
|
</button>
|
||||||
|
{:else if convert_status_kv[event_file_obj.event_file_id] === 'converting'}
|
||||||
|
<span class="btn btn-sm preset-tonal-surface opacity-60 cursor-wait">
|
||||||
|
<span class="fas fa-spinner fa-spin mx-1"></span>
|
||||||
|
Converting…
|
||||||
|
</span>
|
||||||
|
{:else if convert_status_kv[event_file_obj.event_file_id] === 'done'}
|
||||||
|
<span class="btn btn-sm preset-tonal-success" title="Conversion complete. New webp hosted_file created: {convert_result_kv[event_file_obj.event_file_id]?.filename ?? ''}">
|
||||||
|
<span class="fas fa-check mx-1"></span>
|
||||||
|
Done — {convert_result_kv[event_file_obj.event_file_id]?.filename ?? 'image created'}
|
||||||
|
</span>
|
||||||
|
{:else if convert_status_kv[event_file_obj.event_file_id] === 'error'}
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
class="btn btn-sm preset-tonal-error border border-error-500"
|
||||||
|
title="Conversion failed. Click to retry."
|
||||||
|
onclick={() => {
|
||||||
|
convert_status_kv[event_file_obj.event_file_id] = 'idle';
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<span class="fas fa-exclamation-triangle mx-1"></span>
|
||||||
|
Failed — Retry?
|
||||||
|
</button>
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
</td>
|
</td>
|
||||||
<td
|
<td
|
||||||
class="px-4 py-2 flex flex-col gap-0.5"
|
class="px-4 py-2 flex flex-col gap-0.5"
|
||||||
|
|||||||
Reference in New Issue
Block a user