Merge branch '0.1.6-final' into feature/176

Resolved conflicts:
- CHANGELOG.md: Kept both HA Script Support and STL Thumbnail features
- database.py: Kept both migration sets (UNIQUE constraint removal + queue columns)
- SmartPlugCard.tsx: Merged script UI support with base styling
- static/: Rebuilt frontend with merged changes

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
maziggy
2026-01-31 14:43:45 +01:00
co-authored by Claude Opus 4.5
64 changed files with 4800 additions and 1685 deletions
+66 -4
View File
@@ -300,6 +300,7 @@ export interface Archive {
nozzle_diameter: number | null;
bed_temperature: number | null;
nozzle_temperature: number | null;
sliced_for_model: string | null; // Printer model this file was sliced for
status: string;
started_at: string | null;
completed_at: string | null;
@@ -1004,6 +1005,9 @@ export interface DiscoveredTasmotaDevice {
export interface PrintQueueItem {
id: number;
printer_id: number | null; // null = unassigned
target_model: string | null; // Target printer model for model-based assignment
required_filament_types: string[] | null; // Required filament types for model-based assignment
waiting_reason: string | null; // Why a model-based job hasn't started yet
// Either archive_id OR library_file_id must be set (archive created at print start)
archive_id: number | null;
library_file_id: number | null;
@@ -1036,6 +1040,7 @@ export interface PrintQueueItem {
export interface PrintQueueItemCreate {
printer_id?: number | null; // null = unassigned
target_model?: string | null; // Target printer model (mutually exclusive with printer_id)
// Either archive_id OR library_file_id must be provided
archive_id?: number | null;
library_file_id?: number | null;
@@ -1056,6 +1061,7 @@ export interface PrintQueueItemCreate {
export interface PrintQueueItemUpdate {
printer_id?: number | null; // null = unassign
target_model?: string | null; // Target printer model (mutually exclusive with printer_id)
position?: number;
scheduled_time?: string | null;
require_previous_success?: boolean;
@@ -1215,6 +1221,14 @@ export interface NotificationProvider {
on_ams_ht_temperature_high: boolean;
// Build plate detection
on_plate_not_empty: boolean;
// Print queue events
on_queue_job_added: boolean;
on_queue_job_assigned: boolean;
on_queue_job_started: boolean;
on_queue_job_waiting: boolean;
on_queue_job_skipped: boolean;
on_queue_job_failed: boolean;
on_queue_completed: boolean;
// Quiet hours
quiet_hours_enabled: boolean;
quiet_hours_start: string | null;
@@ -1257,6 +1271,14 @@ export interface NotificationProviderCreate {
on_ams_ht_temperature_high?: boolean;
// Build plate detection
on_plate_not_empty?: boolean;
// Print queue events
on_queue_job_added?: boolean;
on_queue_job_assigned?: boolean;
on_queue_job_started?: boolean;
on_queue_job_waiting?: boolean;
on_queue_job_skipped?: boolean;
on_queue_job_failed?: boolean;
on_queue_completed?: boolean;
// Quiet hours
quiet_hours_enabled?: boolean;
quiet_hours_start?: string | null;
@@ -1292,6 +1314,14 @@ export interface NotificationProviderUpdate {
on_ams_ht_temperature_high?: boolean;
// Build plate detection
on_plate_not_empty?: boolean;
// Print queue events
on_queue_job_added?: boolean;
on_queue_job_assigned?: boolean;
on_queue_job_started?: boolean;
on_queue_job_waiting?: boolean;
on_queue_job_skipped?: boolean;
on_queue_job_failed?: boolean;
on_queue_completed?: boolean;
// Quiet hours
quiet_hours_enabled?: boolean;
quiet_hours_start?: string | null;
@@ -3003,11 +3033,17 @@ export const api = {
return request<LibraryFileListItem[]>(`/library/files?${params}`);
},
getLibraryFile: (id: number) => request<LibraryFile>(`/library/files/${id}`),
uploadLibraryFile: async (file: File, folderId?: number | null): Promise<LibraryFileUploadResponse> => {
uploadLibraryFile: async (
file: File,
folderId?: number | null,
generateStlThumbnails: boolean = true
): Promise<LibraryFileUploadResponse> => {
const formData = new FormData();
formData.append('file', file);
const params = folderId ? `?folder_id=${folderId}` : '';
const response = await fetch(`${API_BASE}/library/files${params}`, {
const params = new URLSearchParams();
if (folderId) params.set('folder_id', String(folderId));
params.set('generate_stl_thumbnails', String(generateStlThumbnails));
const response = await fetch(`${API_BASE}/library/files?${params}`, {
method: 'POST',
body: formData,
});
@@ -3021,7 +3057,8 @@ export const api = {
file: File,
folderId?: number | null,
preserveStructure: boolean = true,
createFolderFromZip: boolean = false
createFolderFromZip: boolean = false,
generateStlThumbnails: boolean = true
): Promise<ZipExtractResponse> => {
const formData = new FormData();
formData.append('file', file);
@@ -3029,6 +3066,7 @@ export const api = {
if (folderId) params.set('folder_id', String(folderId));
params.set('preserve_structure', String(preserveStructure));
params.set('create_folder_from_zip', String(createFolderFromZip));
params.set('generate_stl_thumbnails', String(generateStlThumbnails));
const response = await fetch(`${API_BASE}/library/files/extract-zip?${params}`, {
method: 'POST',
body: formData,
@@ -3062,6 +3100,15 @@ export const api = {
body: JSON.stringify({ file_ids: fileIds, folder_ids: folderIds }),
}),
getLibraryStats: () => request<LibraryStats>('/library/stats'),
batchGenerateStlThumbnails: (options: {
file_ids?: number[];
folder_id?: number;
all_missing?: boolean;
}) =>
request<BatchThumbnailResponse>('/library/generate-stl-thumbnails', {
method: 'POST',
body: JSON.stringify(options),
}),
addLibraryFilesToQueue: (fileIds: number[]) =>
request<AddToQueueResponse>('/library/files/add-to-queue', {
method: 'POST',
@@ -3386,6 +3433,21 @@ export interface ZipExtractResponse {
errors: ZipExtractError[];
}
// STL Thumbnail Generation types
export interface BatchThumbnailResult {
file_id: number;
filename: string;
success: boolean;
error?: string | null;
}
export interface BatchThumbnailResponse {
processed: number;
succeeded: number;
failed: number;
results: BatchThumbnailResult[];
}
// Library Queue types
export interface AddToQueueResult {
file_id: number;