11 Commits
Author SHA1 Message Date
gronod 18a6d9394c ci(macos): compile tests with --no-run on cross-target Apple Silicon
Build Linux Packages / Build Linux (push) Successful in 7m9s
Build Windows Packages / Build Windows (push) Successful in 6m48s
Build macOS Packages / Build macOS (Apple Silicon) (push) Successful in 20m33s
Build macOS Packages / Build macOS (Intel) (push) Successful in 20m38s
Build macOS Packages / Build macOS (Universal (Intel + Apple Silicon)) (push) Successful in 26m25s
2026-09-05 21:25:13 +01:00
gronod 9016932547 ci(macos): remove hanging rust-cache and run native cargo test for all platforms
Build Windows Packages / Build Windows (push) Successful in 7m13s
Build macOS Packages / Build macOS (Apple Silicon) (push) Failing after 7m15s
Build Linux Packages / Build Linux (push) Successful in 8m0s
Build macOS Packages / Build macOS (Intel) (push) Canceled after 10m57s
Build macOS Packages / Build macOS (Universal (Intel + Apple Silicon)) (push) Canceled after 12m4s
2026-09-05 21:14:14 +01:00
gronod 2f7d8f3ca7 ci(macos): run cargo test without target for universal-apple-darwin
Build Windows Packages / Build Windows (push) Successful in 7m6s
Build Linux Packages / Build Linux (push) Successful in 7m43s
Build macOS Packages / Build macOS (Apple Silicon) (push) Failing after 9m16s
Build macOS Packages / Build macOS (Universal (Intel + Apple Silicon)) (push) Canceled after 43m44s
Build macOS Packages / Build macOS (Intel) (push) Canceled after 43m44s
2026-09-05 20:34:17 +01:00
gronod 41efac68ed Merge pull request 'Release v0.8.1' (#206) from development into main
Build macOS Packages / Build macOS (Universal (Intel + Apple Silicon)) (push) Failing after 1m27s
Build macOS Packages / Build macOS (Apple Silicon) (push) Canceled after 6m4s
Build macOS Packages / Build macOS (Intel) (push) Canceled after 6m4s
Build Windows Packages / Build Windows (push) Canceled after 6m1s
Build Linux Packages / Build Linux (push) Canceled after 6m12s
Merge pull request 'Release v0.8.1' (#206) from development into main
2026-09-05 20:27:52 +01:00
gronod 9aad7b083a Merge pull request 'feat(chartread): support -Y l switch for i1Pro 2 LED feedback (closes #204)' (#205) from feat/204-i1pro2-led-feedback into development
Merge pull request 'feat(chartread): support -Y l switch for i1Pro 2 LED feedback (closes #204)' (#205) from feat/204-i1pro2-led-feedback into development
2026-09-05 20:27:41 +01:00
gronod 5ee1b07263 feat(chartread): support -Y l switch for i1Pro 2 LED feedback (#204) 2026-09-05 20:26:44 +01:00
gronod 53ce298bc1 chore(release): bump version to 0.8.1 2026-09-05 20:24:46 +01:00
gronod 45ed7dbfe5 ci: uncomment Intel and Apple Silicon build targets in macos workflow matrix 2026-09-05 17:49:41 +01:00
gronod f553f10399 Update .gitea/workflows/build-macos.yml
made macos build on gitea universal only
2026-09-05 17:36:37 +01:00
gronod a9112445bb Update .gitea/workflows/build-macos.yml
Build Windows Packages / Build Windows (push) Canceled after 14s
Build Linux Packages / Build Linux (push) Canceled after 32s
Build macOS Packages / Build macOS (Intel) (push) Canceled after 32m48s
commennted arm64 and universal builds from macos gitea workflow and updated node version to 24
2026-09-05 17:24:16 +01:00
gronod a584b9746f Update .gitea/workflows/build-macos.yml
Build Linux Packages / Build Linux (push) Canceled after 14s
Build Windows Packages / Build Windows (push) Canceled after 15s
Build macOS Packages / Build macOS (Intel) (push) Canceled after 0s
Build macOS Packages / Build macOS (Universal (Intel + Apple Silicon)) (push) Canceled after 0s
Build macOS Packages / Build macOS (Apple Silicon) (push) Canceled after 2m2s
2026-09-05 17:18:31 +01:00
11 changed files with 121 additions and 21 deletions
+11 -8
View File
@@ -13,17 +13,17 @@ jobs:
matrix: matrix:
platform: platform:
- name: Intel - name: Intel
os: macos-15-intel os: macos
target: x86_64-apple-darwin target: x86_64-apple-darwin
binary_dir: macos-x86_64 binary_dir: macos-x86_64
arch: x86_64 arch: x86_64
- name: Apple Silicon - name: Apple Silicon
os: macos-15 os: macos
target: aarch64-apple-darwin target: aarch64-apple-darwin
binary_dir: macos-aarch64 binary_dir: macos-aarch64
arch: arm64 arch: arm64
- name: Universal (Intel + Apple Silicon) - name: Universal (Intel + Apple Silicon)
os: macos-15 os: macos
target: universal-apple-darwin target: universal-apple-darwin
binary_dir: macos-universal binary_dir: macos-universal
arch: universal arch: universal
@@ -35,7 +35,7 @@ jobs:
- name: Setup Node.js - name: Setup Node.js
uses: actions/setup-node@v4 uses: actions/setup-node@v4
with: with:
node-version: 20 node-version: 24
cache: 'npm' cache: 'npm'
- name: Install Rust stable - name: Install Rust stable
@@ -44,9 +44,6 @@ jobs:
toolchain: stable toolchain: stable
targets: ${{ matrix.platform.target == 'universal-apple-darwin' && 'x86_64-apple-darwin, aarch64-apple-darwin' || matrix.platform.target }} targets: ${{ matrix.platform.target == 'universal-apple-darwin' && 'x86_64-apple-darwin, aarch64-apple-darwin' || matrix.platform.target }}
- name: Rust Cache
uses: Swatinem/rust-cache@v2
- name: Install Node dependencies - name: Install Node dependencies
run: npm ci run: npm ci
@@ -69,7 +66,13 @@ jobs:
CARGO_TARGET_DIR: "${{ runner.temp }}/cargo-target" CARGO_TARGET_DIR: "${{ runner.temp }}/cargo-target"
run: | run: |
cd src-tauri cd src-tauri
cargo test --target ${{ matrix.platform.target }} if [ "${{ matrix.platform.target }}" = "universal-apple-darwin" ]; then
cargo test
elif [ "${{ matrix.platform.target }}" = "aarch64-apple-darwin" ] && [ "$(uname -m)" != "arm64" ]; then
cargo test --no-run --target ${{ matrix.platform.target }}
else
cargo test --target ${{ matrix.platform.target }}
fi
- name: Set Release Environment - name: Set Release Environment
id: set_env id: set_env
+1 -1
View File
@@ -1,7 +1,7 @@
{ {
"name": "iccery", "name": "iccery",
"private": true, "private": true,
"version": "0.7.4", "version": "0.8.1",
"type": "module", "type": "module",
"scripts": { "scripts": {
"fetch-argyll": "node scripts/fetch-argyll.mjs", "fetch-argyll": "node scripts/fetch-argyll.mjs",
+1 -1
View File
@@ -1423,7 +1423,7 @@ dependencies = [
[[package]] [[package]]
name = "iccery" name = "iccery"
version = "0.8.0" version = "0.8.1"
dependencies = [ dependencies = [
"base64 0.22.1", "base64 0.22.1",
"image", "image",
+1 -1
View File
@@ -1,6 +1,6 @@
[package] [package]
name = "iccery" name = "iccery"
version = "0.8.0" version = "0.8.1"
description = "Modern Printer Profiling UI frontend for ArgyllCMS" description = "Modern Printer Profiling UI frontend for ArgyllCMS"
authors = ["Gordon"] authors = ["Gordon"]
edition = "2021" edition = "2021"
+52 -2
View File
@@ -829,11 +829,13 @@ pub async fn read_tiff_preview_png(path: String) -> Result<String, String> {
Ok(base64::engine::general_purpose::STANDARD.encode(png_bytes.into_inner())) Ok(base64::engine::general_purpose::STANDARD.encode(png_bytes.into_inner()))
} }
#[derive(Debug, Deserialize, Serialize)] #[derive(Debug, Deserialize, Serialize, Clone)]
pub struct ChartreadConfig { pub struct ChartreadConfig {
pub basename: String, pub basename: String,
pub cwd: String, pub cwd: String,
pub port: Option<String>, pub port: Option<String>,
#[serde(default)]
pub enable_i1pro2_leds: Option<bool>,
} }
pub fn build_chartread_args(config: &ChartreadConfig) -> Vec<String> { pub fn build_chartread_args(config: &ChartreadConfig) -> Vec<String> {
@@ -849,6 +851,11 @@ pub fn build_chartread_args(config: &ChartreadConfig) -> Vec<String> {
} }
} }
if config.enable_i1pro2_leds.unwrap_or(false) {
args.push("-Y".to_string());
args.push("l".to_string());
}
args.push(config.basename.clone()); args.push(config.basename.clone());
args args
} }
@@ -857,8 +864,12 @@ pub fn build_chartread_args(config: &ChartreadConfig) -> Vec<String> {
pub async fn run_chartread( pub async fn run_chartread(
app: AppHandle, app: AppHandle,
state: State<'_, ProcessManager>, state: State<'_, ProcessManager>,
config: ChartreadConfig, mut config: ChartreadConfig,
) -> Result<(), String> { ) -> Result<(), String> {
if config.enable_i1pro2_leds.is_none() {
let settings = crate::settings::load_settings(app.clone()).unwrap_or_default();
config.enable_i1pro2_leds = Some(settings.enable_i1pro2_leds);
}
let binary = resolve_binary(app.clone(), "chartread".to_string()).await?; let binary = resolve_binary(app.clone(), "chartread".to_string()).await?;
let args = build_chartread_args(&config); let args = build_chartread_args(&config);
let id = format!("chartread_{}", config.basename); let id = format!("chartread_{}", config.basename);
@@ -1558,6 +1569,7 @@ mod tests {
basename: "my_profile".to_string(), basename: "my_profile".to_string(),
cwd: "/home/user".to_string(), cwd: "/home/user".to_string(),
port: None, port: None,
enable_i1pro2_leds: None,
}; };
let args = build_chartread_args(&config); let args = build_chartread_args(&config);
assert_eq!(args, vec!["-v", "-u", "my_profile"]); assert_eq!(args, vec!["-v", "-u", "my_profile"]);
@@ -1569,6 +1581,7 @@ mod tests {
basename: "my_profile".to_string(), basename: "my_profile".to_string(),
cwd: "/home/user".to_string(), cwd: "/home/user".to_string(),
port: Some("".to_string()), port: Some("".to_string()),
enable_i1pro2_leds: None,
}; };
let args = build_chartread_args(&config); let args = build_chartread_args(&config);
assert_eq!(args, vec!["-v", "-u", "my_profile"]); assert_eq!(args, vec!["-v", "-u", "my_profile"]);
@@ -1580,11 +1593,48 @@ mod tests {
basename: "my_profile".to_string(), basename: "my_profile".to_string(),
cwd: "/home/user".to_string(), cwd: "/home/user".to_string(),
port: Some("1".to_string()), port: Some("1".to_string()),
enable_i1pro2_leds: None,
}; };
let args = build_chartread_args(&config); let args = build_chartread_args(&config);
assert_eq!(args, vec!["-v", "-u", "-c", "1", "my_profile"]); assert_eq!(args, vec!["-v", "-u", "-c", "1", "my_profile"]);
} }
#[test]
fn test_build_chartread_args_leds_enabled() {
let config = ChartreadConfig {
basename: "my_profile".to_string(),
cwd: "/home/user".to_string(),
port: None,
enable_i1pro2_leds: Some(true),
};
let args = build_chartread_args(&config);
assert_eq!(args, vec!["-v", "-u", "-Y", "l", "my_profile"]);
}
#[test]
fn test_build_chartread_args_with_port_and_leds() {
let config = ChartreadConfig {
basename: "my_profile".to_string(),
cwd: "/home/user".to_string(),
port: Some("1".to_string()),
enable_i1pro2_leds: Some(true),
};
let args = build_chartread_args(&config);
assert_eq!(args, vec!["-v", "-u", "-c", "1", "-Y", "l", "my_profile"]);
}
#[test]
fn test_build_chartread_args_leds_disabled() {
let config = ChartreadConfig {
basename: "my_profile".to_string(),
cwd: "/home/user".to_string(),
port: None,
enable_i1pro2_leds: Some(false),
};
let args = build_chartread_args(&config);
assert_eq!(args, vec!["-v", "-u", "my_profile"]);
}
#[test] #[test]
fn test_build_average_args() { fn test_build_average_args() {
let config = AverageConfig { let config = AverageConfig {
+1 -1
View File
@@ -276,7 +276,7 @@ mod tests {
let pm = ProcessManager::new(); let pm = ProcessManager::new();
// Test helper using dummy/mock or direct map operations // Test helper using dummy/mock or direct map operations
{ {
let mut stdins = pm.stdins.lock().await; let stdins = pm.stdins.lock().await;
assert!(!stdins.contains_key("test_proc")); assert!(!stdins.contains_key("test_proc"));
} }
} }
+27
View File
@@ -74,6 +74,8 @@ pub struct AppSettings {
pub delta_e_warning_max: f64, pub delta_e_warning_max: f64,
#[serde(default)] #[serde(default)]
pub custom_presets: Vec<ProfilingPreset>, pub custom_presets: Vec<ProfilingPreset>,
#[serde(default)]
pub enable_i1pro2_leds: bool,
} }
impl Default for AppSettings { impl Default for AppSettings {
@@ -85,6 +87,7 @@ impl Default for AppSettings {
delta_e_good_max: default_delta_e_good_max(), delta_e_good_max: default_delta_e_good_max(),
delta_e_warning_max: default_delta_e_warning_max(), delta_e_warning_max: default_delta_e_warning_max(),
custom_presets: Vec::new(), custom_presets: Vec::new(),
enable_i1pro2_leds: false,
} }
} }
} }
@@ -466,4 +469,28 @@ mod tests {
assert_eq!(parse_log_level_filter(Some("unknown")), log::LevelFilter::Info); assert_eq!(parse_log_level_filter(Some("unknown")), log::LevelFilter::Info);
} }
} }
#[test]
fn test_default_enable_i1pro2_leds() {
let settings = AppSettings::default();
assert_eq!(settings.enable_i1pro2_leds, false);
}
#[test]
fn test_enable_i1pro2_leds_serialization() {
// Missing field defaults to false
let json_empty = "{}";
let settings_empty: AppSettings = serde_json::from_str(json_empty).unwrap();
assert_eq!(settings_empty.enable_i1pro2_leds, false);
// Explicit true
let json_true = r#"{"enable_i1pro2_leds": true}"#;
let settings_true: AppSettings = serde_json::from_str(json_true).unwrap();
assert_eq!(settings_true.enable_i1pro2_leds, true);
// Explicit false
let json_false = r#"{"enable_i1pro2_leds": false}"#;
let settings_false: AppSettings = serde_json::from_str(json_false).unwrap();
assert_eq!(settings_false.enable_i1pro2_leds, false);
}
} }
+1 -1
View File
@@ -1,7 +1,7 @@
{ {
"$schema": "https://schema.tauri.app/config/2", "$schema": "https://schema.tauri.app/config/2",
"productName": "ICCery", "productName": "ICCery",
"version": "0.8.0", "version": "0.8.1",
"identifier": "com.gronod.iccery", "identifier": "com.gronod.iccery",
"build": { "build": {
"frontendDist": "../src" "frontendDist": "../src"
+14 -4
View File
@@ -883,9 +883,19 @@
<label for="argyll_binary_dir">ArgyllCMS Binary Directory Override</label> <label for="argyll_binary_dir">ArgyllCMS Binary Directory Override</label>
<input type="text" id="argyll_binary_dir" placeholder="Leave empty for bundled sidecars (e.g. /usr/bin)"> <input type="text" id="argyll_binary_dir" placeholder="Leave empty for bundled sidecars (e.g. /usr/bin)">
</div> </div>
<div class="form-group"> <div class="form-group" style="margin-top: 16px; padding-top: 14px; border-top: 1px solid var(--border-color, #333);">
<label for="default_instrument">Default Instrument Override</label> <label style="font-weight: 600;">Instrument &amp; Measurement Preferences</label>
<input type="text" id="default_instrument" placeholder="e.g. i1"> <div style="margin-top: 8px;">
<label for="default_instrument" class="sub-label">Default Instrument Override</label>
<input type="text" id="default_instrument" placeholder="e.g. i1">
</div>
<div style="margin-top: 12px;">
<label class="checkbox-label" for="enable_i1pro2_leds" style="display: flex; align-items: center; gap: 8px; cursor: pointer;">
<input type="checkbox" id="enable_i1pro2_leds">
<span>Enable i1Pro 2 status LEDs (<code>-Y l</code>)</span>
</label>
<small class="help-hint" style="display:block; font-size:0.75rem; color:var(--text-muted, #888); margin-top:3px;">Provides visual status feedback via the instrument ring LEDs during patch reading. Requires patched ArgyllCMS build.</small>
</div>
</div> </div>
<div class="form-group" style="margin-top: 16px; padding-top: 14px; border-top: 1px solid var(--border-color, #333);"> <div class="form-group" style="margin-top: 16px; padding-top: 14px; border-top: 1px solid var(--border-color, #333);">
<label style="font-weight: 600;">Stage 3 ΔE₀₀ Traffic-Light Thresholds</label> <label style="font-weight: 600;">Stage 3 ΔE₀₀ Traffic-Light Thresholds</label>
@@ -940,7 +950,7 @@
<img src="./assets/ICCery-logo.svg" alt="ICCery Logo" class="about-logo" /> <img src="./assets/ICCery-logo.svg" alt="ICCery Logo" class="about-logo" />
</div> </div>
<h2>About ICCery</h2> <h2>About ICCery</h2>
<p><strong>Version:</strong> <span id="aboutVersion">v0.7.2</span> &bull; <strong>Build Date:</strong> <span id="aboutBuildDate">September 2026</span></p> <p><strong>Version:</strong> <span id="aboutVersion">v0.8.1</span> &bull; <strong>Build Date:</strong> <span id="aboutBuildDate">September 2026</span></p>
<p><strong>Copyright &copy; 2026 Gordon Bolton. All rights reserved.</strong></p> <p><strong>Copyright &copy; 2026 Gordon Bolton. All rights reserved.</strong></p>
<h3>Licences & EULA</h3> <h3>Licences & EULA</h3>
<div class="license-text-container"> <div class="license-text-container">
+7 -2
View File
@@ -426,8 +426,11 @@ export function initChartread() {
} }
}); });
let lastStderrLine = "";
const unlistenStderr = await listen("process:stderr", (event) => { const unlistenStderr = await listen("process:stderr", (event) => {
if (event.payload.id === currentProcessId && event.payload.line) { if (event.payload.id === currentProcessId && event.payload.line) {
lastStderrLine = event.payload.line;
logPre.textContent += "ERR: " + event.payload.line + "\n"; logPre.textContent += "ERR: " + event.payload.line + "\n";
logPre.scrollTop = logPre.scrollHeight; logPre.scrollTop = logPre.scrollHeight;
} }
@@ -471,8 +474,10 @@ export function initChartread() {
} }
} else { } else {
setState(STATE.FINISHED); setState(STATE.FINISHED);
setPrompt(`❌ chartread exited with code ${event.payload.code}.`); if (logContainer) logContainer.open = true;
logPre.textContent += `\n[ERROR] chartread exited with code ${event.payload.code}.\n`; const errDetail = lastStderrLine ? ` (${lastStderrLine})` : "";
setPrompt(`❌ chartread exited with code ${event.payload.code}.${errDetail}`);
logPre.textContent += `\n[ERROR] chartread exited with code ${event.payload.code}.${errDetail}\n`;
} }
setMeasurementBusy(false); setMeasurementBusy(false);
+5
View File
@@ -21,6 +21,7 @@ export async function initSettings() {
const deltaEGoodMax = document.getElementById('deltaEGoodMax'); const deltaEGoodMax = document.getElementById('deltaEGoodMax');
const deltaEWarningMax = document.getElementById('deltaEWarningMax'); const deltaEWarningMax = document.getElementById('deltaEWarningMax');
const deltaEThresholdError = document.getElementById('deltaEThresholdError'); const deltaEThresholdError = document.getElementById('deltaEThresholdError');
const enableI1Pro2Leds = document.getElementById('enable_i1pro2_leds');
if (!dialog || !openBtn) return; if (!dialog || !openBtn) return;
@@ -57,6 +58,9 @@ export async function initSettings() {
const settings = await invoke('load_settings'); const settings = await invoke('load_settings');
document.getElementById('argyll_binary_dir').value = settings.argyll_binary_dir || ''; document.getElementById('argyll_binary_dir').value = settings.argyll_binary_dir || '';
document.getElementById('default_instrument').value = settings.default_instrument || ''; document.getElementById('default_instrument').value = settings.default_instrument || '';
if (enableI1Pro2Leds) {
enableI1Pro2Leds.checked = Boolean(settings.enable_i1pro2_leds);
}
if (logLevelSelect && settings.log_level) { if (logLevelSelect && settings.log_level) {
logLevelSelect.value = settings.log_level; logLevelSelect.value = settings.log_level;
} }
@@ -145,6 +149,7 @@ export async function initSettings() {
log_level: logLevelSelect ? logLevelSelect.value : (currentSettings.log_level || 'info'), log_level: logLevelSelect ? logLevelSelect.value : (currentSettings.log_level || 'info'),
delta_e_good_max: getInputValueAsFloat('deltaEGoodMax', 2.0), delta_e_good_max: getInputValueAsFloat('deltaEGoodMax', 2.0),
delta_e_warning_max: getInputValueAsFloat('deltaEWarningMax', 5.0), delta_e_warning_max: getInputValueAsFloat('deltaEWarningMax', 5.0),
enable_i1pro2_leds: enableI1Pro2Leds ? enableI1Pro2Leds.checked : false,
}; };
await invoke('save_settings', { settings }); await invoke('save_settings', { settings });
logger.info(`Settings saved. Log level set to: ${settings.log_level}`, 'Settings'); logger.info(`Settings saved. Log level set to: ${settings.log_level}`, 'Settings');