diff --git a/compliance-core/src/models/onboarding.rs b/compliance-core/src/models/onboarding.rs index ebe58fb..7d255cb 100644 --- a/compliance-core/src/models/onboarding.rs +++ b/compliance-core/src/models/onboarding.rs @@ -202,6 +202,9 @@ pub enum PlcFormat { PlcopenXml, /// IEC 61131-3 Structured Text source. StructuredText, + /// A CODESYS project archive (`.projectarchive` — a zip bundling the project + /// plus its referenced libraries and runtime; the source of the control-app SBOM). + ProjectArchive, } /// PLC-specific configuration for a [`ArtifactKind::PlcProject`] artifact. diff --git a/compliance-dashboard/src/pages/onboarding.rs b/compliance-dashboard/src/pages/onboarding.rs index 2ffdc96..0fd3461 100644 --- a/compliance-dashboard/src/pages/onboarding.rs +++ b/compliance-dashboard/src/pages/onboarding.rs @@ -264,6 +264,15 @@ pub fn OnboardingPage() -> Element { onchange: move |evt| { let Some(file) = evt.files().into_iter().next() else { return; }; let name = file.name(); + // Auto-detect the PLC format from the file extension. + let lname = name.to_ascii_lowercase(); + if lname.ends_with(".projectarchive") || lname.ends_with(".project") { + new_plc_format.set("project_archive".to_string()); + } else if lname.ends_with(".xml") || lname.ends_with(".plcopen") { + new_plc_format.set("plcopen_xml".to_string()); + } else if lname.ends_with(".st") || lname.ends_with(".exp") || lname.ends_with(".scl") { + new_plc_format.set("structured_text".to_string()); + } spawn(async move { if let Ok(bytes) = file.read_bytes().await { new_file.set(Some((name, bytes.to_vec()))); @@ -278,8 +287,21 @@ pub fn OnboardingPage() -> Element { select { value: "{new_plc_format}", oninput: move |e| new_plc_format.set(e.value()), - option { value: "plcopen_xml", "PLCopen XML" } - option { value: "structured_text", "Structured Text" } + option { + value: "plcopen_xml", + selected: new_plc_format() == "plcopen_xml", + "PLCopen XML", + } + option { + value: "structured_text", + selected: new_plc_format() == "structured_text", + "Structured Text", + } + option { + value: "project_archive", + selected: new_plc_format() == "project_archive", + "Project archive (.projectarchive)", + } } } }