diff --git a/README.md b/README.md index 64cb5ca8..b0f8bf62 100644 --- a/README.md +++ b/README.md @@ -18,6 +18,7 @@ Built with **Tauri 2** (Rust + WebView), **React 18**, **TypeScript**, and **SQL - **Ollama Management** — Hardware detection, model recommendations, pull/delete models in-app - **Audit Trail** — Every external data send logged with SHA-256 hash - **Domain System Prompts** — Pre-built expert context for 8 IT domains (Linux, Windows, Network, Kubernetes, Databases, Virtualization, Hardware, Observability) +- **Image Attachments** — Upload and manage image files with PII detection and mandatory user approval - **Integrations** *(v0.2, coming soon)* — Confluence, ServiceNow, Azure DevOps --- diff --git a/docs/wiki/Architecture.md b/docs/wiki/Architecture.md index 0cb4284c..ce6089b7 100644 --- a/docs/wiki/Architecture.md +++ b/docs/wiki/Architecture.md @@ -46,10 +46,11 @@ All command handlers receive `State<'_, AppState>` as a Tauri-injected parameter | `commands/analysis.rs` | Log file upload, PII detection, redaction | | `commands/docs.rs` | RCA and post-mortem generation, document export | | `commands/system.rs` | Ollama management, hardware probe, settings, audit log | +| `commands/image.rs` | Image attachment upload, list, delete, paste | | `commands/integrations.rs` | Confluence / ServiceNow / ADO — v0.2 stubs | | `ai/provider.rs` | `Provider` trait + `create_provider()` factory | | `pii/detector.rs` | Multi-pattern PII scanner with overlap resolution | -| `db/migrations.rs` | Versioned schema (10 migrations in `_migrations` table) | +| `db/migrations.rs` | Versioned schema (12 migrations in `_migrations` table) | | `db/models.rs` | All DB types — see `IssueDetail` note below | | `docs/rca.rs` + `docs/postmortem.rs` | Markdown template builders | | `audit/log.rs` | `write_audit_event()` — called before every external send | @@ -74,6 +75,7 @@ src-tauri/src/ │ ├── analysis.rs │ ├── docs.rs │ ├── system.rs +│ ├── image.rs │ └── integrations.rs ├── pii/ │ ├── patterns.rs @@ -186,6 +188,15 @@ Use `detail.issue.title`, **not** `detail.title`. 7. Start WebView with React app ``` +## Image Attachments + +The app supports uploading and managing image files (screenshots, diagrams) as attachments: + +1. **Upload** via `upload_image_attachmentCmd()` or `upload_paste_imageCmd()` (clipboard paste) +2. **PII detection** runs automatically on upload +3. **User approval** required before image is stored +4. **Database storage** in `image_attachments` table with SHA-256 hash + ## Data Flow ``` diff --git a/docs/wiki/Database.md b/docs/wiki/Database.md index 68b51041..adcd0c21 100644 --- a/docs/wiki/Database.md +++ b/docs/wiki/Database.md @@ -2,7 +2,7 @@ ## Overview -TFTSR uses **SQLite** via `rusqlite` with the `bundled-sqlcipher` feature for AES-256 encryption in production. 11 versioned migrations are tracked in the `_migrations` table. +TFTSR uses **SQLite** via `rusqlite` with the `bundled-sqlcipher` feature for AES-256 encryption in production. 12 versioned migrations are tracked in the `_migrations` table. **DB file location:** `{app_data_dir}/tftsr.db` @@ -211,6 +211,29 @@ CREATE TABLE integration_config ( ); ``` +### 012 — image_attachments (v0.2.7+) + +```sql +CREATE TABLE image_attachments ( + id TEXT PRIMARY KEY, + issue_id TEXT NOT NULL REFERENCES issues(id) ON DELETE CASCADE, + file_name TEXT NOT NULL, + file_path TEXT NOT NULL DEFAULT '', + file_size INTEGER NOT NULL DEFAULT 0, + mime_type TEXT NOT NULL DEFAULT 'image/png', + upload_hash TEXT NOT NULL DEFAULT '', + uploaded_at TEXT NOT NULL DEFAULT (datetime('now')), + pii_warning_acknowledged INTEGER NOT NULL DEFAULT 1, + is_paste INTEGER NOT NULL DEFAULT 0 +); +``` + +**Features:** +- Image file metadata stored in database +- `upload_hash`: SHA-256 hash of file content (for deduplication) +- `pii_warning_acknowledged`: User confirmation that PII may be present +- `is_paste`: Flag for screenshots copied from clipboard + **Encryption:** - OAuth2 tokens encrypted with AES-256-GCM - Key derived from `TFTSR_DB_KEY` environment variable diff --git a/docs/wiki/Home.md b/docs/wiki/Home.md index fe15cb0c..954ce22d 100644 --- a/docs/wiki/Home.md +++ b/docs/wiki/Home.md @@ -24,7 +24,7 @@ - **5-Whys AI Triage** — Interactive guided root cause analysis via multi-turn AI chat - **PII Auto-Redaction** — Detects and redacts sensitive data before any AI send -- **Multi-Provider AI** — OpenAI, Anthropic Claude, Google Gemini, Mistral, AWS Bedrock (via LiteLLM), MSI GenAI (Motorola internal), local Ollama (fully offline) +- **Multi-Provider AI** — OpenAI, Anthropic Claude, Google Gemini, Mistral, AWS Bedrock (via LiteLLM), Custom REST gateways, local Ollama (fully offline) - **Custom Provider Support** — Flexible authentication (Bearer, custom headers) and API formats (OpenAI-compatible, Custom REST) - **External Integrations** — Confluence, ServiceNow, Azure DevOps with OAuth2 PKCE flows - **SQLCipher AES-256** — All issue history and credentials encrypted at rest @@ -32,12 +32,14 @@ - **Ollama Management** — Hardware detection, model recommendations, in-app model management - **Audit Trail** — Every external data send logged with SHA-256 hash - **Domain-Specific Prompts** — 8 IT domains: Linux, Windows, Network, Kubernetes, Databases, Virtualization, Hardware, Observability +- **Image Attachments** — Upload and manage image files with PII detection and mandatory user approval ## Releases | Version | Status | Highlights | |---------|--------|-----------| -| v0.2.6 | 🚀 Latest | MSI GenAI support, OAuth2 shell permissions, user ID tracking | +| v0.2.6 | 🚀 Latest | Custom REST AI gateway support, OAuth2 shell permissions, user ID tracking | +| v0.2.5 | Released | Image attachments with PII detection and approval workflow | | v0.2.3 | Released | Confluence/ServiceNow/ADO REST API clients (19 TDD tests) | | v0.1.1 | Released | Core application with PII detection, RCA generation | diff --git a/docs/wiki/IPC-Commands.md b/docs/wiki/IPC-Commands.md index d0b66498..ad931460 100644 --- a/docs/wiki/IPC-Commands.md +++ b/docs/wiki/IPC-Commands.md @@ -99,6 +99,34 @@ Rewrites file content with approved redactions. Records SHA-256 in audit log. Re --- +## Image Attachment Commands + +### `upload_image_attachment` +```typescript +uploadImageAttachmentCmd(issueId: string, filePath: string, piiWarningAcknowledged: boolean) → ImageAttachment +``` +Uploads an image file. Computes SHA-256, stores metadata in DB. Returns `ImageAttachment` record. + +### `list_image_attachments` +```typescript +listImageAttachmentsCmd(issueId: string) → ImageAttachment[] +``` +Lists all image attachments for an issue. + +### `delete_image_attachment` +```typescript +deleteImageAttachmentCmd(imageId: string) → void +``` +Deletes an image attachment from disk and database. + +### `upload_paste_image` +```typescript +uploadPasteImageCmd(issueId: string, base64Data: string, fileName: string, piiWarningAcknowledged: boolean) → ImageAttachment +``` +Uploads an image from clipboard paste (base64). Returns `ImageAttachment` record. + +--- + ## AI Commands ### `analyze_logs` diff --git a/src-tauri/Cargo.lock b/src-tauri/Cargo.lock index fb04237f..5d8ca3f4 100644 --- a/src-tauri/Cargo.lock +++ b/src-tauri/Cargo.lock @@ -2416,6 +2416,15 @@ dependencies = [ "serde_core", ] +[[package]] +name = "infer" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb33622da908807a06f9513c19b3c1ad50fab3e4137d82a78107d502075aa199" +dependencies = [ + "cfb", +] + [[package]] name = "infer" version = "0.19.0" @@ -5611,7 +5620,7 @@ dependencies = [ "glob", "html5ever 0.29.1", "http 1.4.0", - "infer", + "infer 0.19.0", "json-patch", "kuchikiki", "log", @@ -5670,47 +5679,6 @@ dependencies = [ "utf-8", ] -[[package]] -name = "tftsr" -version = "0.1.0" -dependencies = [ - "aes-gcm", - "aho-corasick", - "anyhow", - "async-trait", - "base64 0.22.1", - "chrono", - "dirs 5.0.1", - "docx-rs", - "futures", - "hex", - "lazy_static", - "mockito", - "printpdf", - "rand 0.8.5", - "regex", - "reqwest 0.12.28", - "rusqlite", - "serde", - "serde_json", - "sha2", - "tauri", - "tauri-build", - "tauri-plugin-dialog", - "tauri-plugin-fs", - "tauri-plugin-http", - "tauri-plugin-shell", - "tauri-plugin-stronghold", - "thiserror 1.0.69", - "tokio", - "tokio-test", - "tracing", - "tracing-subscriber", - "urlencoding", - "uuid", - "warp", -] - [[package]] name = "thiserror" version = "1.0.69" @@ -6168,6 +6136,48 @@ dependencies = [ "windows-sys 0.60.2", ] +[[package]] +name = "trcaa" +version = "0.1.0" +dependencies = [ + "aes-gcm", + "aho-corasick", + "anyhow", + "async-trait", + "base64 0.22.1", + "chrono", + "dirs 5.0.1", + "docx-rs", + "futures", + "hex", + "infer 0.15.0", + "lazy_static", + "mockito", + "printpdf", + "rand 0.8.5", + "regex", + "reqwest 0.12.28", + "rusqlite", + "serde", + "serde_json", + "sha2", + "tauri", + "tauri-build", + "tauri-plugin-dialog", + "tauri-plugin-fs", + "tauri-plugin-http", + "tauri-plugin-shell", + "tauri-plugin-stronghold", + "thiserror 1.0.69", + "tokio", + "tokio-test", + "tracing", + "tracing-subscriber", + "urlencoding", + "uuid", + "warp", +] + [[package]] name = "try-lock" version = "0.2.5" diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml index 43526339..38120a56 100644 --- a/src-tauri/Cargo.toml +++ b/src-tauri/Cargo.toml @@ -43,6 +43,7 @@ rand = "0.8" lazy_static = "1.4" warp = "0.3" urlencoding = "2" +infer = "0.15" [dev-dependencies] tokio-test = "0.4" diff --git a/src-tauri/src/commands/db.rs b/src-tauri/src/commands/db.rs index e667d298..4419b222 100644 --- a/src-tauri/src/commands/db.rs +++ b/src-tauri/src/commands/db.rs @@ -1,8 +1,8 @@ use tauri::State; use crate::db::models::{ - AiConversation, AiMessage, Issue, IssueDetail, IssueFilter, IssueSummary, IssueUpdate, LogFile, - ResolutionStep, + AiConversation, AiMessage, ImageAttachment, Issue, IssueDetail, IssueFilter, IssueSummary, + IssueUpdate, LogFile, ResolutionStep, }; use crate::state::AppState; @@ -100,6 +100,32 @@ pub async fn get_issue( .filter_map(|r| r.ok()) .collect(); + // Load image attachments + let mut img_stmt = db + .prepare( + "SELECT id, issue_id, file_name, file_path, file_size, mime_type, upload_hash, uploaded_at, pii_warning_acknowledged, is_paste \ + FROM image_attachments WHERE issue_id = ?1 ORDER BY uploaded_at ASC", + ) + .map_err(|e| e.to_string())?; + let image_attachments: Vec = img_stmt + .query_map([&issue_id], |row| { + Ok(ImageAttachment { + id: row.get(0)?, + issue_id: row.get(1)?, + file_name: row.get(2)?, + file_path: row.get(3)?, + file_size: row.get(4)?, + mime_type: row.get(5)?, + upload_hash: row.get(6)?, + uploaded_at: row.get(7)?, + pii_warning_acknowledged: row.get::<_, i32>(8)? != 0, + is_paste: row.get::<_, i32>(9)? != 0, + }) + }) + .map_err(|e| e.to_string())? + .filter_map(|r| r.ok()) + .collect(); + // Load resolution steps (5-whys) let mut rs_stmt = db .prepare( @@ -148,6 +174,7 @@ pub async fn get_issue( Ok(IssueDetail { issue, log_files, + image_attachments, resolution_steps, conversations, }) @@ -265,6 +292,11 @@ pub async fn delete_issue(issue_id: String, state: State<'_, AppState>) -> Resul .map_err(|e| e.to_string())?; db.execute("DELETE FROM log_files WHERE issue_id = ?1", [&issue_id]) .map_err(|e| e.to_string())?; + db.execute( + "DELETE FROM image_attachments WHERE issue_id = ?1", + [&issue_id], + ) + .map_err(|e| e.to_string())?; db.execute( "DELETE FROM resolution_steps WHERE issue_id = ?1", [&issue_id], diff --git a/src-tauri/src/commands/image.rs b/src-tauri/src/commands/image.rs new file mode 100644 index 00000000..b2675315 --- /dev/null +++ b/src-tauri/src/commands/image.rs @@ -0,0 +1,282 @@ +use base64::Engine; +use sha2::Digest; +use std::path::Path; +use tauri::State; + +use crate::audit::log::write_audit_event; +use crate::db::models::{AuditEntry, ImageAttachment}; +use crate::state::AppState; + +const MAX_IMAGE_FILE_BYTES: u64 = 10 * 1024 * 1024; +const SUPPORTED_IMAGE_MIME_TYPES: [&str; 5] = [ + "image/png", + "image/jpeg", + "image/gif", + "image/webp", + "image/svg+xml", +]; + +fn validate_image_file_path(file_path: &str) -> Result { + let path = Path::new(file_path); + let canonical = std::fs::canonicalize(path).map_err(|_| "Unable to access selected file")?; + let metadata = std::fs::metadata(&canonical).map_err(|_| "Unable to read file metadata")?; + + if !metadata.is_file() { + return Err("Selected path is not a file".to_string()); + } + + if metadata.len() > MAX_IMAGE_FILE_BYTES { + return Err(format!( + "Image file exceeds maximum supported size ({} MB)", + MAX_IMAGE_FILE_BYTES / 1024 / 1024 + )); + } + + Ok(canonical) +} + +fn is_supported_image_format(mime_type: &str) -> bool { + SUPPORTED_IMAGE_MIME_TYPES.contains(&mime_type) +} + +#[tauri::command] +pub async fn upload_image_attachment( + issue_id: String, + file_path: String, + state: State<'_, AppState>, +) -> Result { + let canonical_path = validate_image_file_path(&file_path)?; + let content = + std::fs::read(&canonical_path).map_err(|_| "Failed to read selected image file")?; + let content_hash = format!("{:x}", sha2::Sha256::digest(&content)); + let file_name = canonical_path + .file_name() + .and_then(|n| n.to_str()) + .unwrap_or("unknown") + .to_string(); + let file_size = content.len() as i64; + let mime_type: String = infer::get(&content) + .map(|m| m.mime_type().to_string()) + .unwrap_or_else(|| "image/png".to_string()); + + if !is_supported_image_format(mime_type.as_str()) { + return Err(format!( + "Unsupported image format: {}. Supported formats: {}", + mime_type, + SUPPORTED_IMAGE_MIME_TYPES.join(", ") + )); + } + + let canonical_file_path = canonical_path.to_string_lossy().to_string(); + let attachment = ImageAttachment::new( + issue_id.clone(), + file_name, + canonical_file_path, + file_size, + mime_type, + content_hash.clone(), + true, + false, + ); + + let db = state.db.lock().map_err(|e| e.to_string())?; + db.execute( + "INSERT INTO image_attachments (id, issue_id, file_name, file_path, file_size, mime_type, upload_hash, uploaded_at, pii_warning_acknowledged, is_paste) \ + VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10)", + rusqlite::params![ + attachment.id, + attachment.issue_id, + attachment.file_name, + attachment.file_path, + attachment.file_size, + attachment.mime_type, + attachment.upload_hash, + attachment.uploaded_at, + attachment.pii_warning_acknowledged as i32, + attachment.is_paste as i32, + ], + ) + .map_err(|_| "Failed to store uploaded image metadata".to_string())?; + + let entry = AuditEntry::new( + "upload_image_attachment".to_string(), + "image_attachment".to_string(), + attachment.id.clone(), + serde_json::json!({ + "issue_id": issue_id, + "file_name": attachment.file_name, + "is_paste": false, + }) + .to_string(), + ); + if let Err(err) = write_audit_event( + &db, + &entry.action, + &entry.entity_type, + &entry.entity_id, + &entry.details, + ) { + tracing::warn!(error = %err, "failed to write upload_image_attachment audit entry"); + } + + Ok(attachment) +} + +#[tauri::command] +pub async fn upload_paste_image( + issue_id: String, + base64_image: String, + mime_type: String, + state: State<'_, AppState>, +) -> Result { + if !base64_image.starts_with("data:image/") { + return Err("Invalid image data - must be a data URL".to_string()); + } + + let data_part = base64_image + .split(',') + .nth(1) + .ok_or("Invalid image data format - missing base64 content")?; + + let decoded = base64::engine::general_purpose::STANDARD + .decode(data_part) + .map_err(|_| "Failed to decode base64 image data")?; + + let content_hash = format!("{:x}", sha2::Sha256::digest(&decoded)); + let file_size = decoded.len() as i64; + let file_name = format!("pasted-image-{}.png", uuid::Uuid::now_v7()); + + if !is_supported_image_format(mime_type.as_str()) { + return Err(format!( + "Unsupported image format: {}. Supported formats: {}", + mime_type, + SUPPORTED_IMAGE_MIME_TYPES.join(", ") + )); + } + + let attachment = ImageAttachment::new( + issue_id.clone(), + file_name.clone(), + String::new(), + file_size, + mime_type, + content_hash, + true, + true, + ); + + let db = state.db.lock().map_err(|e| e.to_string())?; + db.execute( + "INSERT INTO image_attachments (id, issue_id, file_name, file_path, file_size, mime_type, upload_hash, uploaded_at, pii_warning_acknowledged, is_paste) \ + VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10)", + rusqlite::params![ + attachment.id, + attachment.issue_id, + attachment.file_name, + attachment.file_path, + attachment.file_size, + attachment.mime_type, + attachment.upload_hash, + attachment.uploaded_at, + attachment.pii_warning_acknowledged as i32, + attachment.is_paste as i32, + ], + ) + .map_err(|_| "Failed to store pasted image metadata".to_string())?; + + let entry = AuditEntry::new( + "upload_paste_image".to_string(), + "image_attachment".to_string(), + attachment.id.clone(), + serde_json::json!({ + "issue_id": issue_id, + "file_name": attachment.file_name, + "is_paste": true, + }) + .to_string(), + ); + if let Err(err) = write_audit_event( + &db, + &entry.action, + &entry.entity_type, + &entry.entity_id, + &entry.details, + ) { + tracing::warn!(error = %err, "failed to write upload_paste_image audit entry"); + } + + Ok(attachment) +} + +#[tauri::command] +pub async fn list_image_attachments( + issue_id: String, + state: State<'_, AppState>, +) -> Result, String> { + let db = state.db.lock().map_err(|e| e.to_string())?; + + let mut stmt = db + .prepare( + "SELECT id, issue_id, file_name, file_path, file_size, mime_type, upload_hash, uploaded_at, pii_warning_acknowledged, is_paste \ + FROM image_attachments WHERE issue_id = ?1 ORDER BY uploaded_at ASC", + ) + .map_err(|e| e.to_string())?; + + let attachments = stmt + .query_map([&issue_id], |row| { + Ok(ImageAttachment { + id: row.get(0)?, + issue_id: row.get(1)?, + file_name: row.get(2)?, + file_path: row.get(3)?, + file_size: row.get(4)?, + mime_type: row.get(5)?, + upload_hash: row.get(6)?, + uploaded_at: row.get(7)?, + pii_warning_acknowledged: row.get::<_, i32>(8)? != 0, + is_paste: row.get::<_, i32>(9)? != 0, + }) + }) + .map_err(|e| e.to_string())? + .filter_map(|r| r.ok()) + .collect(); + + Ok(attachments) +} + +#[tauri::command] +pub async fn delete_image_attachment( + attachment_id: String, + state: State<'_, AppState>, +) -> Result<(), String> { + let db = state.db.lock().map_err(|e| e.to_string())?; + + let affected = db + .execute( + "DELETE FROM image_attachments WHERE id = ?1", + [&attachment_id], + ) + .map_err(|e| e.to_string())?; + + if affected == 0 { + return Err("Image attachment not found".to_string()); + } + + Ok(()) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_is_supported_image_format() { + assert!(is_supported_image_format("image/png")); + assert!(is_supported_image_format("image/jpeg")); + assert!(is_supported_image_format("image/gif")); + assert!(is_supported_image_format("image/webp")); + assert!(is_supported_image_format("image/svg+xml")); + assert!(!is_supported_image_format("image/bmp")); + assert!(!is_supported_image_format("text/plain")); + } +} diff --git a/src-tauri/src/commands/mod.rs b/src-tauri/src/commands/mod.rs index 1092f243..6184fac6 100644 --- a/src-tauri/src/commands/mod.rs +++ b/src-tauri/src/commands/mod.rs @@ -2,5 +2,6 @@ pub mod ai; pub mod analysis; pub mod db; pub mod docs; +pub mod image; pub mod integrations; pub mod system; diff --git a/src-tauri/src/db/migrations.rs b/src-tauri/src/db/migrations.rs index 938e53fc..1fc6a875 100644 --- a/src-tauri/src/db/migrations.rs +++ b/src-tauri/src/db/migrations.rs @@ -155,6 +155,21 @@ pub fn run_migrations(conn: &Connection) -> anyhow::Result<()> { "ALTER TABLE audit_log ADD COLUMN prev_hash TEXT NOT NULL DEFAULT ''; ALTER TABLE audit_log ADD COLUMN entry_hash TEXT NOT NULL DEFAULT '';", ), + ( + "013_image_attachments", + "CREATE TABLE IF NOT EXISTS image_attachments ( + id TEXT PRIMARY KEY, + issue_id TEXT NOT NULL REFERENCES issues(id) ON DELETE CASCADE, + file_name TEXT NOT NULL, + file_path TEXT NOT NULL DEFAULT '', + file_size INTEGER NOT NULL DEFAULT 0, + mime_type TEXT NOT NULL DEFAULT 'image/png', + upload_hash TEXT NOT NULL DEFAULT '', + uploaded_at TEXT NOT NULL DEFAULT (datetime('now')), + pii_warning_acknowledged INTEGER NOT NULL DEFAULT 1, + is_paste INTEGER NOT NULL DEFAULT 0 + );", + ), ]; for (name, sql) in migrations { @@ -192,21 +207,21 @@ mod tests { } #[test] - fn test_create_credentials_table() { + fn test_create_image_attachments_table() { let conn = setup_test_db(); - // Verify table exists let count: i64 = conn .query_row( - "SELECT COUNT(*) FROM sqlite_master WHERE type='table' AND name='credentials'", + "SELECT COUNT(*) FROM sqlite_master WHERE type='table' AND name='image_attachments'", [], |r| r.get(0), ) .unwrap(); assert_eq!(count, 1); - // Verify columns - let mut stmt = conn.prepare("PRAGMA table_info(credentials)").unwrap(); + let mut stmt = conn + .prepare("PRAGMA table_info(image_attachments)") + .unwrap(); let columns: Vec = stmt .query_map([], |row| row.get::<_, String>(1)) .unwrap() @@ -214,11 +229,15 @@ mod tests { .unwrap(); assert!(columns.contains(&"id".to_string())); - assert!(columns.contains(&"service".to_string())); - assert!(columns.contains(&"token_hash".to_string())); - assert!(columns.contains(&"encrypted_token".to_string())); - assert!(columns.contains(&"created_at".to_string())); - assert!(columns.contains(&"expires_at".to_string())); + assert!(columns.contains(&"issue_id".to_string())); + assert!(columns.contains(&"file_name".to_string())); + assert!(columns.contains(&"file_path".to_string())); + assert!(columns.contains(&"file_size".to_string())); + assert!(columns.contains(&"mime_type".to_string())); + assert!(columns.contains(&"upload_hash".to_string())); + assert!(columns.contains(&"uploaded_at".to_string())); + assert!(columns.contains(&"pii_warning_acknowledged".to_string())); + assert!(columns.contains(&"is_paste".to_string())); } #[test] @@ -389,4 +408,64 @@ mod tests { assert_eq!(count, 1); } + + #[test] + fn test_store_and_retrieve_image_attachment() { + let conn = setup_test_db(); + + // Create an issue first (required for foreign key) + let now = chrono::Utc::now().format("%Y-%m-%d %H:%M:%S").to_string(); + conn.execute( + "INSERT INTO issues (id, title, description, severity, status, category, source, created_at, updated_at, resolved_at, assigned_to, tags) + VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10, ?11, ?12)", + rusqlite::params![ + "test-issue-1", + "Test Issue", + "Test description", + "medium", + "open", + "test", + "manual", + now.clone(), + now.clone(), + None::>, + "", + "[]", + ], + ) + .unwrap(); + + // Now insert the image attachment + conn.execute( + "INSERT INTO image_attachments (id, issue_id, file_name, file_path, file_size, mime_type, upload_hash, uploaded_at, pii_warning_acknowledged, is_paste) + VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10)", + rusqlite::params![ + "test-img-1", + "test-issue-1", + "screenshot.png", + "/path/to/screenshot.png", + 102400, + "image/png", + "abc123hash", + now, + 1, + 0, + ], + ) + .unwrap(); + + let (id, issue_id, file_name, mime_type, is_paste): (String, String, String, String, i32) = conn + .query_row( + "SELECT id, issue_id, file_name, mime_type, is_paste FROM image_attachments WHERE id = ?1", + ["test-img-1"], + |r| Ok((r.get(0)?, r.get(1)?, r.get(2)?, r.get(3)?, r.get(4)?)), + ) + .unwrap(); + + assert_eq!(id, "test-img-1"); + assert_eq!(issue_id, "test-issue-1"); + assert_eq!(file_name, "screenshot.png"); + assert_eq!(mime_type, "image/png"); + assert_eq!(is_paste, 0); + } } diff --git a/src-tauri/src/db/models.rs b/src-tauri/src/db/models.rs index 6f06b850..1524c587 100644 --- a/src-tauri/src/db/models.rs +++ b/src-tauri/src/db/models.rs @@ -44,6 +44,7 @@ impl Issue { pub struct IssueDetail { pub issue: Issue, pub log_files: Vec, + pub image_attachments: Vec, pub resolution_steps: Vec, pub conversations: Vec, } @@ -392,3 +393,46 @@ impl IntegrationConfig { } } } + +// ─── Image Attachment ──────────────────────────────────────────────────────────── + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct ImageAttachment { + pub id: String, + pub issue_id: String, + pub file_name: String, + pub file_path: String, + pub file_size: i64, + pub mime_type: String, + pub upload_hash: String, + pub uploaded_at: String, + pub pii_warning_acknowledged: bool, + pub is_paste: bool, +} + +impl ImageAttachment { + #[allow(clippy::too_many_arguments)] + pub fn new( + issue_id: String, + file_name: String, + file_path: String, + file_size: i64, + mime_type: String, + upload_hash: String, + pii_warning_acknowledged: bool, + is_paste: bool, + ) -> Self { + ImageAttachment { + id: Uuid::now_v7().to_string(), + issue_id, + file_name, + file_path, + file_size, + mime_type, + upload_hash, + uploaded_at: chrono::Utc::now().format("%Y-%m-%d %H:%M:%S").to_string(), + pii_warning_acknowledged, + is_paste, + } + } +} diff --git a/src-tauri/src/docs/postmortem.rs b/src-tauri/src/docs/postmortem.rs index 8a8df607..abddaaf2 100644 --- a/src-tauri/src/docs/postmortem.rs +++ b/src-tauri/src/docs/postmortem.rs @@ -177,6 +177,7 @@ mod tests { tags: "[]".to_string(), }, log_files: vec![], + image_attachments: vec![], resolution_steps: vec![ResolutionStep { id: "rs-pm-1".to_string(), issue_id: "pm-456".to_string(), diff --git a/src-tauri/src/docs/rca.rs b/src-tauri/src/docs/rca.rs index 66836996..f6d508bc 100644 --- a/src-tauri/src/docs/rca.rs +++ b/src-tauri/src/docs/rca.rs @@ -172,6 +172,7 @@ mod tests { uploaded_at: "2025-01-15 10:30:00".to_string(), redacted: false, }], + image_attachments: vec![], resolution_steps: vec![ ResolutionStep { id: "rs-1".to_string(), diff --git a/src-tauri/src/lib.rs b/src-tauri/src/lib.rs index 6b147e2a..3f99e8cf 100644 --- a/src-tauri/src/lib.rs +++ b/src-tauri/src/lib.rs @@ -73,6 +73,10 @@ pub fn run() { commands::analysis::upload_log_file, commands::analysis::detect_pii, commands::analysis::apply_redactions, + commands::image::upload_image_attachment, + commands::image::list_image_attachments, + commands::image::delete_image_attachment, + commands::image::upload_paste_image, // AI commands::ai::analyze_logs, commands::ai::chat_message, diff --git a/src-tauri/target/debug/.fingerprint/atk-sys-768b71c16fc41c6c/lib-atk_sys b/src-tauri/target/debug/.fingerprint/atk-sys-768b71c16fc41c6c/lib-atk_sys index 68093804..dc80967f 100644 --- a/src-tauri/target/debug/.fingerprint/atk-sys-768b71c16fc41c6c/lib-atk_sys +++ b/src-tauri/target/debug/.fingerprint/atk-sys-768b71c16fc41c6c/lib-atk_sys @@ -1 +1 @@ -87ea7716dc80a07a \ No newline at end of file +0ec3867c61057b8d \ No newline at end of file diff --git a/src-tauri/target/debug/.fingerprint/atk-sys-768b71c16fc41c6c/lib-atk_sys.json b/src-tauri/target/debug/.fingerprint/atk-sys-768b71c16fc41c6c/lib-atk_sys.json index 6916b794..2eca2cad 100644 --- a/src-tauri/target/debug/.fingerprint/atk-sys-768b71c16fc41c6c/lib-atk_sys.json +++ b/src-tauri/target/debug/.fingerprint/atk-sys-768b71c16fc41c6c/lib-atk_sys.json @@ -1 +1 @@ -{"rustc":9435880562281667341,"features":"[]","declared_features":"[\"v2_30\", \"v2_32\", \"v2_34\", \"v2_38\", \"v2_46\", \"v2_50\"]","target":9187208078048417441,"profile":2241668132362809309,"path":16630923333912248680,"deps":[[4520300193208121197,"build_script_build",false,3287691332841484387],[13626264195287554611,"glib",false,5575305324500369928],[15885457518084958445,"gobject",false,8022801781863277977],[17159683253194042242,"libc",false,9448623883530498034]],"local":[{"CheckDepInfo":{"dep_info":"debug/.fingerprint/atk-sys-768b71c16fc41c6c/dep-lib-atk_sys","checksum":false}}],"rustflags":[],"config":8247474407144887393,"compile_kind":0} \ No newline at end of file +{"rustc":9435880562281667341,"features":"[]","declared_features":"[\"v2_30\", \"v2_32\", \"v2_34\", \"v2_38\", \"v2_46\", \"v2_50\"]","target":9187208078048417441,"profile":2241668132362809309,"path":16630923333912248680,"deps":[[4520300193208121197,"build_script_build",false,3287691332841484387],[13626264195287554611,"glib",false,9264953364366423698],[15885457518084958445,"gobject",false,12045039612142251958],[17159683253194042242,"libc",false,9448623883530498034]],"local":[{"CheckDepInfo":{"dep_info":"debug/.fingerprint/atk-sys-768b71c16fc41c6c/dep-lib-atk_sys","checksum":false}}],"rustflags":[],"config":8247474407144887393,"compile_kind":0} \ No newline at end of file diff --git a/src-tauri/target/debug/.fingerprint/cairo-sys-rs-f83c0c503dd18651/lib-cairo_sys b/src-tauri/target/debug/.fingerprint/cairo-sys-rs-f83c0c503dd18651/lib-cairo_sys index 7ef43cdd..e30bf383 100644 --- a/src-tauri/target/debug/.fingerprint/cairo-sys-rs-f83c0c503dd18651/lib-cairo_sys +++ b/src-tauri/target/debug/.fingerprint/cairo-sys-rs-f83c0c503dd18651/lib-cairo_sys @@ -1 +1 @@ -4654627634d98be6 \ No newline at end of file +f18cdeecdcc959ec \ No newline at end of file diff --git a/src-tauri/target/debug/.fingerprint/cairo-sys-rs-f83c0c503dd18651/lib-cairo_sys.json b/src-tauri/target/debug/.fingerprint/cairo-sys-rs-f83c0c503dd18651/lib-cairo_sys.json index 26d18790..79a1a166 100644 --- a/src-tauri/target/debug/.fingerprint/cairo-sys-rs-f83c0c503dd18651/lib-cairo_sys.json +++ b/src-tauri/target/debug/.fingerprint/cairo-sys-rs-f83c0c503dd18651/lib-cairo_sys.json @@ -1 +1 @@ -{"rustc":9435880562281667341,"features":"[\"glib\", \"use_glib\"]","declared_features":"[\"freetype\", \"glib\", \"pdf\", \"png\", \"ps\", \"script\", \"svg\", \"use_glib\", \"v1_16\", \"v1_18\", \"win32-surface\", \"winapi\", \"x11\", \"xcb\", \"xlib\"]","target":12604004911878344227,"profile":2241668132362809309,"path":3685462284682103180,"deps":[[6885242093860886281,"build_script_build",false,12349584672223142119],[13626264195287554611,"glib",false,5575305324500369928],[17159683253194042242,"libc",false,9448623883530498034]],"local":[{"CheckDepInfo":{"dep_info":"debug/.fingerprint/cairo-sys-rs-f83c0c503dd18651/dep-lib-cairo_sys","checksum":false}}],"rustflags":[],"config":8247474407144887393,"compile_kind":0} \ No newline at end of file +{"rustc":9435880562281667341,"features":"[\"glib\", \"use_glib\"]","declared_features":"[\"freetype\", \"glib\", \"pdf\", \"png\", \"ps\", \"script\", \"svg\", \"use_glib\", \"v1_16\", \"v1_18\", \"win32-surface\", \"winapi\", \"x11\", \"xcb\", \"xlib\"]","target":12604004911878344227,"profile":2241668132362809309,"path":3685462284682103180,"deps":[[6885242093860886281,"build_script_build",false,12349584672223142119],[13626264195287554611,"glib",false,9264953364366423698],[17159683253194042242,"libc",false,9448623883530498034]],"local":[{"CheckDepInfo":{"dep_info":"debug/.fingerprint/cairo-sys-rs-f83c0c503dd18651/dep-lib-cairo_sys","checksum":false}}],"rustflags":[],"config":8247474407144887393,"compile_kind":0} \ No newline at end of file diff --git a/src-tauri/target/debug/.fingerprint/gdk-pixbuf-sys-70c7997861d3fd4d/lib-gdk_pixbuf_sys b/src-tauri/target/debug/.fingerprint/gdk-pixbuf-sys-70c7997861d3fd4d/lib-gdk_pixbuf_sys index 0affe525..d2288e85 100644 --- a/src-tauri/target/debug/.fingerprint/gdk-pixbuf-sys-70c7997861d3fd4d/lib-gdk_pixbuf_sys +++ b/src-tauri/target/debug/.fingerprint/gdk-pixbuf-sys-70c7997861d3fd4d/lib-gdk_pixbuf_sys @@ -1 +1 @@ -e63c935cfe3a4323 \ No newline at end of file +dbcbb845f19978d4 \ No newline at end of file diff --git a/src-tauri/target/debug/.fingerprint/gdk-pixbuf-sys-70c7997861d3fd4d/lib-gdk_pixbuf_sys.json b/src-tauri/target/debug/.fingerprint/gdk-pixbuf-sys-70c7997861d3fd4d/lib-gdk_pixbuf_sys.json index e88a860b..2542451e 100644 --- a/src-tauri/target/debug/.fingerprint/gdk-pixbuf-sys-70c7997861d3fd4d/lib-gdk_pixbuf_sys.json +++ b/src-tauri/target/debug/.fingerprint/gdk-pixbuf-sys-70c7997861d3fd4d/lib-gdk_pixbuf_sys.json @@ -1 +1 @@ -{"rustc":9435880562281667341,"features":"[]","declared_features":"[\"v2_40\", \"v2_42\"]","target":16919365233018027880,"profile":2241668132362809309,"path":6426732272852491483,"deps":[[2028663402560672651,"build_script_build",false,2148754194152163369],[13626264195287554611,"glib",false,5575305324500369928],[15885457518084958445,"gobject",false,8022801781863277977],[17138253974170286367,"gio",false,14268886093481619365],[17159683253194042242,"libc",false,9448623883530498034]],"local":[{"CheckDepInfo":{"dep_info":"debug/.fingerprint/gdk-pixbuf-sys-70c7997861d3fd4d/dep-lib-gdk_pixbuf_sys","checksum":false}}],"rustflags":[],"config":8247474407144887393,"compile_kind":0} \ No newline at end of file +{"rustc":9435880562281667341,"features":"[]","declared_features":"[\"v2_40\", \"v2_42\"]","target":16919365233018027880,"profile":2241668132362809309,"path":6426732272852491483,"deps":[[2028663402560672651,"build_script_build",false,2148754194152163369],[13626264195287554611,"glib",false,9264953364366423698],[15885457518084958445,"gobject",false,12045039612142251958],[17138253974170286367,"gio",false,12787692356947406432],[17159683253194042242,"libc",false,9448623883530498034]],"local":[{"CheckDepInfo":{"dep_info":"debug/.fingerprint/gdk-pixbuf-sys-70c7997861d3fd4d/dep-lib-gdk_pixbuf_sys","checksum":false}}],"rustflags":[],"config":8247474407144887393,"compile_kind":0} \ No newline at end of file diff --git a/src-tauri/target/debug/.fingerprint/gdk-sys-e9cf50084503ac90/lib-gdk_sys b/src-tauri/target/debug/.fingerprint/gdk-sys-e9cf50084503ac90/lib-gdk_sys index 03ce4c47..4ec66146 100644 --- a/src-tauri/target/debug/.fingerprint/gdk-sys-e9cf50084503ac90/lib-gdk_sys +++ b/src-tauri/target/debug/.fingerprint/gdk-sys-e9cf50084503ac90/lib-gdk_sys @@ -1 +1 @@ -6449d31d465814cb \ No newline at end of file +771443a67e1ee643 \ No newline at end of file diff --git a/src-tauri/target/debug/.fingerprint/gdk-sys-e9cf50084503ac90/lib-gdk_sys.json b/src-tauri/target/debug/.fingerprint/gdk-sys-e9cf50084503ac90/lib-gdk_sys.json index 82dedc24..84af6228 100644 --- a/src-tauri/target/debug/.fingerprint/gdk-sys-e9cf50084503ac90/lib-gdk_sys.json +++ b/src-tauri/target/debug/.fingerprint/gdk-sys-e9cf50084503ac90/lib-gdk_sys.json @@ -1 +1 @@ -{"rustc":9435880562281667341,"features":"[]","declared_features":"[\"v3_24\"]","target":17416663456093631127,"profile":2241668132362809309,"path":16809978839088644625,"deps":[[2028663402560672651,"gdk_pixbuf",false,2540939478916349158],[2184755618550678726,"pango",false,14709927256080672428],[6885242093860886281,"cairo",false,16612610469833888838],[12225316990487900155,"build_script_build",false,14435154505770388337],[13626264195287554611,"glib",false,5575305324500369928],[15885457518084958445,"gobject",false,8022801781863277977],[17138253974170286367,"gio",false,14268886093481619365],[17159683253194042242,"libc",false,9448623883530498034]],"local":[{"CheckDepInfo":{"dep_info":"debug/.fingerprint/gdk-sys-e9cf50084503ac90/dep-lib-gdk_sys","checksum":false}}],"rustflags":[],"config":8247474407144887393,"compile_kind":0} \ No newline at end of file +{"rustc":9435880562281667341,"features":"[]","declared_features":"[\"v3_24\"]","target":17416663456093631127,"profile":2241668132362809309,"path":16809978839088644625,"deps":[[2028663402560672651,"gdk_pixbuf",false,15310156194781907931],[2184755618550678726,"pango",false,9273454815819985803],[6885242093860886281,"cairo",false,17030865416582237425],[12225316990487900155,"build_script_build",false,14435154505770388337],[13626264195287554611,"glib",false,9264953364366423698],[15885457518084958445,"gobject",false,12045039612142251958],[17138253974170286367,"gio",false,12787692356947406432],[17159683253194042242,"libc",false,9448623883530498034]],"local":[{"CheckDepInfo":{"dep_info":"debug/.fingerprint/gdk-sys-e9cf50084503ac90/dep-lib-gdk_sys","checksum":false}}],"rustflags":[],"config":8247474407144887393,"compile_kind":0} \ No newline at end of file diff --git a/src-tauri/target/debug/.fingerprint/gdkwayland-sys-f1f75bfe2aa17499/lib-gdk_wayland_sys b/src-tauri/target/debug/.fingerprint/gdkwayland-sys-f1f75bfe2aa17499/lib-gdk_wayland_sys index 9d6e63b3..9bf22915 100644 --- a/src-tauri/target/debug/.fingerprint/gdkwayland-sys-f1f75bfe2aa17499/lib-gdk_wayland_sys +++ b/src-tauri/target/debug/.fingerprint/gdkwayland-sys-f1f75bfe2aa17499/lib-gdk_wayland_sys @@ -1 +1 @@ -57f4bc49b33c001c \ No newline at end of file +5803222d0e0fddb9 \ No newline at end of file diff --git a/src-tauri/target/debug/.fingerprint/gdkwayland-sys-f1f75bfe2aa17499/lib-gdk_wayland_sys.json b/src-tauri/target/debug/.fingerprint/gdkwayland-sys-f1f75bfe2aa17499/lib-gdk_wayland_sys.json index d4d139b8..89bba7ba 100644 --- a/src-tauri/target/debug/.fingerprint/gdkwayland-sys-f1f75bfe2aa17499/lib-gdk_wayland_sys.json +++ b/src-tauri/target/debug/.fingerprint/gdkwayland-sys-f1f75bfe2aa17499/lib-gdk_wayland_sys.json @@ -1 +1 @@ -{"rustc":9435880562281667341,"features":"[]","declared_features":"[\"v3_24\", \"v3_24_22\"]","target":16388744738126747546,"profile":2241668132362809309,"path":8834472141930327726,"deps":[[12225316990487900155,"gdk",false,14633418147404925284],[13626264195287554611,"glib",false,5575305324500369928],[15885457518084958445,"gobject",false,8022801781863277977],[17159683253194042242,"libc",false,9448623883530498034]],"local":[{"CheckDepInfo":{"dep_info":"debug/.fingerprint/gdkwayland-sys-f1f75bfe2aa17499/dep-lib-gdk_wayland_sys","checksum":false}}],"rustflags":[],"config":8247474407144887393,"compile_kind":0} \ No newline at end of file +{"rustc":9435880562281667341,"features":"[]","declared_features":"[\"v3_24\", \"v3_24_22\"]","target":16388744738126747546,"profile":2241668132362809309,"path":8834472141930327726,"deps":[[12225316990487900155,"gdk",false,4892631574488749175],[13626264195287554611,"glib",false,9264953364366423698],[15885457518084958445,"gobject",false,12045039612142251958],[17159683253194042242,"libc",false,9448623883530498034]],"local":[{"CheckDepInfo":{"dep_info":"debug/.fingerprint/gdkwayland-sys-f1f75bfe2aa17499/dep-lib-gdk_wayland_sys","checksum":false}}],"rustflags":[],"config":8247474407144887393,"compile_kind":0} \ No newline at end of file diff --git a/src-tauri/target/debug/.fingerprint/gdkx11-sys-9068e96e66d6b24f/lib-gdk_x11_sys b/src-tauri/target/debug/.fingerprint/gdkx11-sys-9068e96e66d6b24f/lib-gdk_x11_sys index b5a7e632..6b668fad 100644 --- a/src-tauri/target/debug/.fingerprint/gdkx11-sys-9068e96e66d6b24f/lib-gdk_x11_sys +++ b/src-tauri/target/debug/.fingerprint/gdkx11-sys-9068e96e66d6b24f/lib-gdk_x11_sys @@ -1 +1 @@ -69504a124cbc9852 \ No newline at end of file +9f974a009171d4ef \ No newline at end of file diff --git a/src-tauri/target/debug/.fingerprint/gdkx11-sys-9068e96e66d6b24f/lib-gdk_x11_sys.json b/src-tauri/target/debug/.fingerprint/gdkx11-sys-9068e96e66d6b24f/lib-gdk_x11_sys.json index 874474a4..98d30ad6 100644 --- a/src-tauri/target/debug/.fingerprint/gdkx11-sys-9068e96e66d6b24f/lib-gdk_x11_sys.json +++ b/src-tauri/target/debug/.fingerprint/gdkx11-sys-9068e96e66d6b24f/lib-gdk_x11_sys.json @@ -1 +1 @@ -{"rustc":9435880562281667341,"features":"[]","declared_features":"[\"cairo\", \"v3_24\", \"v3_24_2\"]","target":3071379305588350754,"profile":2241668132362809309,"path":12095866328805076356,"deps":[[2875657597781529139,"x11",false,7752746684588018505],[12225316990487900155,"gdk",false,14633418147404925284],[13501336027759766565,"build_script_build",false,6264265318035135988],[13626264195287554611,"glib",false,5575305324500369928],[17159683253194042242,"libc",false,9448623883530498034]],"local":[{"CheckDepInfo":{"dep_info":"debug/.fingerprint/gdkx11-sys-9068e96e66d6b24f/dep-lib-gdk_x11_sys","checksum":false}}],"rustflags":[],"config":8247474407144887393,"compile_kind":0} \ No newline at end of file +{"rustc":9435880562281667341,"features":"[]","declared_features":"[\"cairo\", \"v3_24\", \"v3_24_2\"]","target":3071379305588350754,"profile":2241668132362809309,"path":12095866328805076356,"deps":[[2875657597781529139,"x11",false,7752746684588018505],[12225316990487900155,"gdk",false,4892631574488749175],[13501336027759766565,"build_script_build",false,6264265318035135988],[13626264195287554611,"glib",false,9264953364366423698],[17159683253194042242,"libc",false,9448623883530498034]],"local":[{"CheckDepInfo":{"dep_info":"debug/.fingerprint/gdkx11-sys-9068e96e66d6b24f/dep-lib-gdk_x11_sys","checksum":false}}],"rustflags":[],"config":8247474407144887393,"compile_kind":0} \ No newline at end of file diff --git a/src-tauri/target/debug/.fingerprint/gio-sys-b3e6ea70af68d703/lib-gio_sys b/src-tauri/target/debug/.fingerprint/gio-sys-b3e6ea70af68d703/lib-gio_sys index bf11c740..096c86c3 100644 --- a/src-tauri/target/debug/.fingerprint/gio-sys-b3e6ea70af68d703/lib-gio_sys +++ b/src-tauri/target/debug/.fingerprint/gio-sys-b3e6ea70af68d703/lib-gio_sys @@ -1 +1 @@ -a5af7b5e4d4405c6 \ No newline at end of file +60eed350720277b1 \ No newline at end of file diff --git a/src-tauri/target/debug/.fingerprint/gio-sys-b3e6ea70af68d703/lib-gio_sys.json b/src-tauri/target/debug/.fingerprint/gio-sys-b3e6ea70af68d703/lib-gio_sys.json index 59620a37..046f8aff 100644 --- a/src-tauri/target/debug/.fingerprint/gio-sys-b3e6ea70af68d703/lib-gio_sys.json +++ b/src-tauri/target/debug/.fingerprint/gio-sys-b3e6ea70af68d703/lib-gio_sys.json @@ -1 +1 @@ -{"rustc":9435880562281667341,"features":"[\"v2_58\", \"v2_60\", \"v2_62\", \"v2_64\", \"v2_66\", \"v2_68\", \"v2_70\"]","declared_features":"[\"v2_58\", \"v2_60\", \"v2_62\", \"v2_64\", \"v2_66\", \"v2_68\", \"v2_70\", \"v2_72\", \"v2_74\", \"v2_76\", \"v2_78\"]","target":1236426455504356861,"profile":2241668132362809309,"path":9660104382480555911,"deps":[[13626264195287554611,"glib",false,5575305324500369928],[15885457518084958445,"gobject",false,8022801781863277977],[17138253974170286367,"build_script_build",false,9485537966158397706],[17159683253194042242,"libc",false,9448623883530498034]],"local":[{"CheckDepInfo":{"dep_info":"debug/.fingerprint/gio-sys-b3e6ea70af68d703/dep-lib-gio_sys","checksum":false}}],"rustflags":[],"config":8247474407144887393,"compile_kind":0} \ No newline at end of file +{"rustc":9435880562281667341,"features":"[\"v2_58\", \"v2_60\", \"v2_62\", \"v2_64\", \"v2_66\", \"v2_68\", \"v2_70\"]","declared_features":"[\"v2_58\", \"v2_60\", \"v2_62\", \"v2_64\", \"v2_66\", \"v2_68\", \"v2_70\", \"v2_72\", \"v2_74\", \"v2_76\", \"v2_78\"]","target":1236426455504356861,"profile":2241668132362809309,"path":9660104382480555911,"deps":[[13626264195287554611,"glib",false,9264953364366423698],[15885457518084958445,"gobject",false,12045039612142251958],[17138253974170286367,"build_script_build",false,9485537966158397706],[17159683253194042242,"libc",false,9448623883530498034]],"local":[{"CheckDepInfo":{"dep_info":"debug/.fingerprint/gio-sys-b3e6ea70af68d703/dep-lib-gio_sys","checksum":false}}],"rustflags":[],"config":8247474407144887393,"compile_kind":0} \ No newline at end of file diff --git a/src-tauri/target/debug/.fingerprint/glib-sys-a08886eb2d4291e5/lib-glib_sys b/src-tauri/target/debug/.fingerprint/glib-sys-a08886eb2d4291e5/lib-glib_sys index b91a9154..54903ee1 100644 --- a/src-tauri/target/debug/.fingerprint/glib-sys-a08886eb2d4291e5/lib-glib_sys +++ b/src-tauri/target/debug/.fingerprint/glib-sys-a08886eb2d4291e5/lib-glib_sys @@ -1 +1 @@ -08423045a7765f4d \ No newline at end of file +92f69e3fffb99380 \ No newline at end of file diff --git a/src-tauri/target/debug/.fingerprint/glib-sys-a08886eb2d4291e5/lib-glib_sys.json b/src-tauri/target/debug/.fingerprint/glib-sys-a08886eb2d4291e5/lib-glib_sys.json index 49de95db..e6abc994 100644 --- a/src-tauri/target/debug/.fingerprint/glib-sys-a08886eb2d4291e5/lib-glib_sys.json +++ b/src-tauri/target/debug/.fingerprint/glib-sys-a08886eb2d4291e5/lib-glib_sys.json @@ -1 +1 @@ -{"rustc":9435880562281667341,"features":"[\"v2_58\", \"v2_60\", \"v2_62\", \"v2_64\", \"v2_66\", \"v2_68\", \"v2_70\"]","declared_features":"[\"v2_58\", \"v2_60\", \"v2_62\", \"v2_64\", \"v2_66\", \"v2_68\", \"v2_70\", \"v2_72\", \"v2_74\", \"v2_76\", \"v2_78\"]","target":9937524938355422997,"profile":2241668132362809309,"path":13065277488400788365,"deps":[[13626264195287554611,"build_script_build",false,6222553498416741123],[17159683253194042242,"libc",false,9448623883530498034]],"local":[{"CheckDepInfo":{"dep_info":"debug/.fingerprint/glib-sys-a08886eb2d4291e5/dep-lib-glib_sys","checksum":false}}],"rustflags":[],"config":8247474407144887393,"compile_kind":0} \ No newline at end of file +{"rustc":9435880562281667341,"features":"[\"v2_58\", \"v2_60\", \"v2_62\", \"v2_64\", \"v2_66\", \"v2_68\", \"v2_70\"]","declared_features":"[\"v2_58\", \"v2_60\", \"v2_62\", \"v2_64\", \"v2_66\", \"v2_68\", \"v2_70\", \"v2_72\", \"v2_74\", \"v2_76\", \"v2_78\"]","target":9937524938355422997,"profile":2241668132362809309,"path":13065277488400788365,"deps":[[13626264195287554611,"build_script_build",false,18138387534057493481],[17159683253194042242,"libc",false,9448623883530498034]],"local":[{"CheckDepInfo":{"dep_info":"debug/.fingerprint/glib-sys-a08886eb2d4291e5/dep-lib-glib_sys","checksum":false}}],"rustflags":[],"config":8247474407144887393,"compile_kind":0} \ No newline at end of file diff --git a/src-tauri/target/debug/.fingerprint/glib-sys-f02d0a4c75864a6c/run-build-script-build-script-build b/src-tauri/target/debug/.fingerprint/glib-sys-f02d0a4c75864a6c/run-build-script-build-script-build index 43215f87..e934dd88 100644 --- a/src-tauri/target/debug/.fingerprint/glib-sys-f02d0a4c75864a6c/run-build-script-build-script-build +++ b/src-tauri/target/debug/.fingerprint/glib-sys-f02d0a4c75864a6c/run-build-script-build-script-build @@ -1 +1 @@ -037bfe3470f35a56 \ No newline at end of file +e9d3de655c7fb8fb \ No newline at end of file diff --git a/src-tauri/target/debug/.fingerprint/glib-sys-f02d0a4c75864a6c/run-build-script-build-script-build.json b/src-tauri/target/debug/.fingerprint/glib-sys-f02d0a4c75864a6c/run-build-script-build-script-build.json index f343b871..3824750b 100644 --- a/src-tauri/target/debug/.fingerprint/glib-sys-f02d0a4c75864a6c/run-build-script-build-script-build.json +++ b/src-tauri/target/debug/.fingerprint/glib-sys-f02d0a4c75864a6c/run-build-script-build-script-build.json @@ -1 +1 @@ -{"rustc":9435880562281667341,"features":"","declared_features":"","target":0,"profile":0,"path":0,"deps":[[13626264195287554611,"build_script_build",false,9828015301074265886]],"local":[{"RerunIfEnvChanged":{"var":"GLIB_2.0_NO_PKG_CONFIG","val":null}},{"RerunIfEnvChanged":{"var":"PKG_CONFIG_aarch64-unknown-linux-gnu","val":null}},{"RerunIfEnvChanged":{"var":"PKG_CONFIG_aarch64_unknown_linux_gnu","val":null}},{"RerunIfEnvChanged":{"var":"HOST_PKG_CONFIG","val":null}},{"RerunIfEnvChanged":{"var":"PKG_CONFIG","val":null}},{"RerunIfEnvChanged":{"var":"PKG_CONFIG_PATH_aarch64-unknown-linux-gnu","val":null}},{"RerunIfEnvChanged":{"var":"PKG_CONFIG_PATH_aarch64_unknown_linux_gnu","val":null}},{"RerunIfEnvChanged":{"var":"HOST_PKG_CONFIG_PATH","val":null}},{"RerunIfEnvChanged":{"var":"PKG_CONFIG_PATH","val":null}},{"RerunIfEnvChanged":{"var":"PKG_CONFIG_LIBDIR_aarch64-unknown-linux-gnu","val":null}},{"RerunIfEnvChanged":{"var":"PKG_CONFIG_LIBDIR_aarch64_unknown_linux_gnu","val":null}},{"RerunIfEnvChanged":{"var":"HOST_PKG_CONFIG_LIBDIR","val":null}},{"RerunIfEnvChanged":{"var":"PKG_CONFIG_LIBDIR","val":null}},{"RerunIfEnvChanged":{"var":"PKG_CONFIG_SYSROOT_DIR_aarch64-unknown-linux-gnu","val":null}},{"RerunIfEnvChanged":{"var":"PKG_CONFIG_SYSROOT_DIR_aarch64_unknown_linux_gnu","val":null}},{"RerunIfEnvChanged":{"var":"HOST_PKG_CONFIG_SYSROOT_DIR","val":null}},{"RerunIfEnvChanged":{"var":"PKG_CONFIG_SYSROOT_DIR","val":null}},{"RerunIfEnvChanged":{"var":"PKG_CONFIG_SYSROOT_DIR","val":null}},{"RerunIfEnvChanged":{"var":"SYSROOT","val":null}},{"RerunIfEnvChanged":{"var":"PKG_CONFIG_aarch64-unknown-linux-gnu","val":null}},{"RerunIfEnvChanged":{"var":"PKG_CONFIG_aarch64_unknown_linux_gnu","val":null}},{"RerunIfEnvChanged":{"var":"HOST_PKG_CONFIG","val":null}},{"RerunIfEnvChanged":{"var":"PKG_CONFIG","val":null}},{"RerunIfEnvChanged":{"var":"PKG_CONFIG_PATH_aarch64-unknown-linux-gnu","val":null}},{"RerunIfEnvChanged":{"var":"PKG_CONFIG_PATH_aarch64_unknown_linux_gnu","val":null}},{"RerunIfEnvChanged":{"var":"HOST_PKG_CONFIG_PATH","val":null}},{"RerunIfEnvChanged":{"var":"PKG_CONFIG_PATH","val":null}},{"RerunIfEnvChanged":{"var":"PKG_CONFIG_LIBDIR_aarch64-unknown-linux-gnu","val":null}},{"RerunIfEnvChanged":{"var":"PKG_CONFIG_LIBDIR_aarch64_unknown_linux_gnu","val":null}},{"RerunIfEnvChanged":{"var":"HOST_PKG_CONFIG_LIBDIR","val":null}},{"RerunIfEnvChanged":{"var":"PKG_CONFIG_LIBDIR","val":null}},{"RerunIfEnvChanged":{"var":"PKG_CONFIG_SYSROOT_DIR_aarch64-unknown-linux-gnu","val":null}},{"RerunIfEnvChanged":{"var":"PKG_CONFIG_SYSROOT_DIR_aarch64_unknown_linux_gnu","val":null}},{"RerunIfEnvChanged":{"var":"HOST_PKG_CONFIG_SYSROOT_DIR","val":null}},{"RerunIfEnvChanged":{"var":"PKG_CONFIG_SYSROOT_DIR","val":null}},{"RerunIfEnvChanged":{"var":"GOBJECT_2.0_NO_PKG_CONFIG","val":null}},{"RerunIfEnvChanged":{"var":"PKG_CONFIG_aarch64-unknown-linux-gnu","val":null}},{"RerunIfEnvChanged":{"var":"PKG_CONFIG_aarch64_unknown_linux_gnu","val":null}},{"RerunIfEnvChanged":{"var":"HOST_PKG_CONFIG","val":null}},{"RerunIfEnvChanged":{"var":"PKG_CONFIG","val":null}},{"RerunIfEnvChanged":{"var":"PKG_CONFIG_PATH_aarch64-unknown-linux-gnu","val":null}},{"RerunIfEnvChanged":{"var":"PKG_CONFIG_PATH_aarch64_unknown_linux_gnu","val":null}},{"RerunIfEnvChanged":{"var":"HOST_PKG_CONFIG_PATH","val":null}},{"RerunIfEnvChanged":{"var":"PKG_CONFIG_PATH","val":null}},{"RerunIfEnvChanged":{"var":"PKG_CONFIG_LIBDIR_aarch64-unknown-linux-gnu","val":null}},{"RerunIfEnvChanged":{"var":"PKG_CONFIG_LIBDIR_aarch64_unknown_linux_gnu","val":null}},{"RerunIfEnvChanged":{"var":"HOST_PKG_CONFIG_LIBDIR","val":null}},{"RerunIfEnvChanged":{"var":"PKG_CONFIG_LIBDIR","val":null}},{"RerunIfEnvChanged":{"var":"PKG_CONFIG_SYSROOT_DIR_aarch64-unknown-linux-gnu","val":null}},{"RerunIfEnvChanged":{"var":"PKG_CONFIG_SYSROOT_DIR_aarch64_unknown_linux_gnu","val":null}},{"RerunIfEnvChanged":{"var":"HOST_PKG_CONFIG_SYSROOT_DIR","val":null}},{"RerunIfEnvChanged":{"var":"PKG_CONFIG_SYSROOT_DIR","val":null}},{"RerunIfEnvChanged":{"var":"PKG_CONFIG_SYSROOT_DIR","val":null}},{"RerunIfEnvChanged":{"var":"SYSROOT","val":null}},{"RerunIfEnvChanged":{"var":"PKG_CONFIG_aarch64-unknown-linux-gnu","val":null}},{"RerunIfEnvChanged":{"var":"PKG_CONFIG_aarch64_unknown_linux_gnu","val":null}},{"RerunIfEnvChanged":{"var":"HOST_PKG_CONFIG","val":null}},{"RerunIfEnvChanged":{"var":"PKG_CONFIG","val":null}},{"RerunIfEnvChanged":{"var":"PKG_CONFIG_PATH_aarch64-unknown-linux-gnu","val":null}},{"RerunIfEnvChanged":{"var":"PKG_CONFIG_PATH_aarch64_unknown_linux_gnu","val":null}},{"RerunIfEnvChanged":{"var":"HOST_PKG_CONFIG_PATH","val":null}},{"RerunIfEnvChanged":{"var":"PKG_CONFIG_PATH","val":null}},{"RerunIfEnvChanged":{"var":"PKG_CONFIG_LIBDIR_aarch64-unknown-linux-gnu","val":null}},{"RerunIfEnvChanged":{"var":"PKG_CONFIG_LIBDIR_aarch64_unknown_linux_gnu","val":null}},{"RerunIfEnvChanged":{"var":"HOST_PKG_CONFIG_LIBDIR","val":null}},{"RerunIfEnvChanged":{"var":"PKG_CONFIG_LIBDIR","val":null}},{"RerunIfEnvChanged":{"var":"PKG_CONFIG_SYSROOT_DIR_aarch64-unknown-linux-gnu","val":null}},{"RerunIfEnvChanged":{"var":"PKG_CONFIG_SYSROOT_DIR_aarch64_unknown_linux_gnu","val":null}},{"RerunIfEnvChanged":{"var":"HOST_PKG_CONFIG_SYSROOT_DIR","val":null}},{"RerunIfEnvChanged":{"var":"PKG_CONFIG_SYSROOT_DIR","val":null}},{"RerunIfEnvChanged":{"var":"SYSTEM_DEPS_BUILD_INTERNAL","val":null}},{"RerunIfEnvChanged":{"var":"SYSTEM_DEPS_LINK","val":null}},{"RerunIfEnvChanged":{"var":"SYSTEM_DEPS_GLIB_2_0_LIB","val":null}},{"RerunIfEnvChanged":{"var":"SYSTEM_DEPS_GLIB_2_0_LIB_FRAMEWORK","val":null}},{"RerunIfEnvChanged":{"var":"SYSTEM_DEPS_GLIB_2_0_SEARCH_NATIVE","val":null}},{"RerunIfEnvChanged":{"var":"SYSTEM_DEPS_GLIB_2_0_SEARCH_FRAMEWORK","val":null}},{"RerunIfEnvChanged":{"var":"SYSTEM_DEPS_GLIB_2_0_INCLUDE","val":null}},{"RerunIfEnvChanged":{"var":"SYSTEM_DEPS_GLIB_2_0_NO_PKG_CONFIG","val":null}},{"RerunIfEnvChanged":{"var":"SYSTEM_DEPS_GLIB_2_0_BUILD_INTERNAL","val":null}},{"RerunIfEnvChanged":{"var":"SYSTEM_DEPS_GLIB_2_0_LINK","val":null}},{"RerunIfEnvChanged":{"var":"SYSTEM_DEPS_GOBJECT_2_0_LIB","val":null}},{"RerunIfEnvChanged":{"var":"SYSTEM_DEPS_GOBJECT_2_0_LIB_FRAMEWORK","val":null}},{"RerunIfEnvChanged":{"var":"SYSTEM_DEPS_GOBJECT_2_0_SEARCH_NATIVE","val":null}},{"RerunIfEnvChanged":{"var":"SYSTEM_DEPS_GOBJECT_2_0_SEARCH_FRAMEWORK","val":null}},{"RerunIfEnvChanged":{"var":"SYSTEM_DEPS_GOBJECT_2_0_INCLUDE","val":null}},{"RerunIfEnvChanged":{"var":"SYSTEM_DEPS_GOBJECT_2_0_NO_PKG_CONFIG","val":null}},{"RerunIfEnvChanged":{"var":"SYSTEM_DEPS_GOBJECT_2_0_BUILD_INTERNAL","val":null}},{"RerunIfEnvChanged":{"var":"SYSTEM_DEPS_GOBJECT_2_0_LINK","val":null}}],"rustflags":[],"config":0,"compile_kind":0} \ No newline at end of file +{"rustc":9435880562281667341,"features":"","declared_features":"","target":0,"profile":0,"path":0,"deps":[[13626264195287554611,"build_script_build",false,9828015301074265886]],"local":[{"RerunIfEnvChanged":{"var":"GLIB_2.0_NO_PKG_CONFIG","val":null}},{"RerunIfEnvChanged":{"var":"PKG_CONFIG_aarch64-unknown-linux-gnu","val":null}},{"RerunIfEnvChanged":{"var":"PKG_CONFIG_aarch64_unknown_linux_gnu","val":null}},{"RerunIfEnvChanged":{"var":"HOST_PKG_CONFIG","val":null}},{"RerunIfEnvChanged":{"var":"PKG_CONFIG","val":null}},{"RerunIfEnvChanged":{"var":"PKG_CONFIG_PATH_aarch64-unknown-linux-gnu","val":null}},{"RerunIfEnvChanged":{"var":"PKG_CONFIG_PATH_aarch64_unknown_linux_gnu","val":null}},{"RerunIfEnvChanged":{"var":"HOST_PKG_CONFIG_PATH","val":null}},{"RerunIfEnvChanged":{"var":"PKG_CONFIG_PATH","val":null}},{"RerunIfEnvChanged":{"var":"PKG_CONFIG_LIBDIR_aarch64-unknown-linux-gnu","val":null}},{"RerunIfEnvChanged":{"var":"PKG_CONFIG_LIBDIR_aarch64_unknown_linux_gnu","val":null}},{"RerunIfEnvChanged":{"var":"HOST_PKG_CONFIG_LIBDIR","val":null}},{"RerunIfEnvChanged":{"var":"PKG_CONFIG_LIBDIR","val":null}},{"RerunIfEnvChanged":{"var":"PKG_CONFIG_SYSROOT_DIR_aarch64-unknown-linux-gnu","val":null}},{"RerunIfEnvChanged":{"var":"PKG_CONFIG_SYSROOT_DIR_aarch64_unknown_linux_gnu","val":null}},{"RerunIfEnvChanged":{"var":"HOST_PKG_CONFIG_SYSROOT_DIR","val":null}},{"RerunIfEnvChanged":{"var":"PKG_CONFIG_SYSROOT_DIR","val":null}},{"RerunIfEnvChanged":{"var":"PKG_CONFIG_SYSROOT_DIR","val":null}},{"RerunIfEnvChanged":{"var":"SYSROOT","val":null}},{"RerunIfEnvChanged":{"var":"PKG_CONFIG_aarch64-unknown-linux-gnu","val":null}},{"RerunIfEnvChanged":{"var":"PKG_CONFIG_aarch64_unknown_linux_gnu","val":null}},{"RerunIfEnvChanged":{"var":"HOST_PKG_CONFIG","val":null}},{"RerunIfEnvChanged":{"var":"PKG_CONFIG","val":null}},{"RerunIfEnvChanged":{"var":"PKG_CONFIG_PATH_aarch64-unknown-linux-gnu","val":null}},{"RerunIfEnvChanged":{"var":"PKG_CONFIG_PATH_aarch64_unknown_linux_gnu","val":null}},{"RerunIfEnvChanged":{"var":"HOST_PKG_CONFIG_PATH","val":null}},{"RerunIfEnvChanged":{"var":"PKG_CONFIG_PATH","val":null}},{"RerunIfEnvChanged":{"var":"PKG_CONFIG_LIBDIR_aarch64-unknown-linux-gnu","val":null}},{"RerunIfEnvChanged":{"var":"PKG_CONFIG_LIBDIR_aarch64_unknown_linux_gnu","val":null}},{"RerunIfEnvChanged":{"var":"HOST_PKG_CONFIG_LIBDIR","val":null}},{"RerunIfEnvChanged":{"var":"PKG_CONFIG_LIBDIR","val":null}},{"RerunIfEnvChanged":{"var":"PKG_CONFIG_SYSROOT_DIR_aarch64-unknown-linux-gnu","val":null}},{"RerunIfEnvChanged":{"var":"PKG_CONFIG_SYSROOT_DIR_aarch64_unknown_linux_gnu","val":null}},{"RerunIfEnvChanged":{"var":"HOST_PKG_CONFIG_SYSROOT_DIR","val":null}},{"RerunIfEnvChanged":{"var":"PKG_CONFIG_SYSROOT_DIR","val":null}},{"RerunIfEnvChanged":{"var":"GOBJECT_2.0_NO_PKG_CONFIG","val":null}},{"RerunIfEnvChanged":{"var":"PKG_CONFIG_aarch64-unknown-linux-gnu","val":null}},{"RerunIfEnvChanged":{"var":"PKG_CONFIG_aarch64_unknown_linux_gnu","val":null}},{"RerunIfEnvChanged":{"var":"HOST_PKG_CONFIG","val":null}},{"RerunIfEnvChanged":{"var":"PKG_CONFIG","val":null}},{"RerunIfEnvChanged":{"var":"PKG_CONFIG_PATH_aarch64-unknown-linux-gnu","val":null}},{"RerunIfEnvChanged":{"var":"PKG_CONFIG_PATH_aarch64_unknown_linux_gnu","val":null}},{"RerunIfEnvChanged":{"var":"HOST_PKG_CONFIG_PATH","val":null}},{"RerunIfEnvChanged":{"var":"PKG_CONFIG_PATH","val":null}},{"RerunIfEnvChanged":{"var":"PKG_CONFIG_LIBDIR_aarch64-unknown-linux-gnu","val":null}},{"RerunIfEnvChanged":{"var":"PKG_CONFIG_LIBDIR_aarch64_unknown_linux_gnu","val":null}},{"RerunIfEnvChanged":{"var":"HOST_PKG_CONFIG_LIBDIR","val":null}},{"RerunIfEnvChanged":{"var":"PKG_CONFIG_LIBDIR","val":null}},{"RerunIfEnvChanged":{"var":"PKG_CONFIG_SYSROOT_DIR_aarch64-unknown-linux-gnu","val":null}},{"RerunIfEnvChanged":{"var":"PKG_CONFIG_SYSROOT_DIR_aarch64_unknown_linux_gnu","val":null}},{"RerunIfEnvChanged":{"var":"HOST_PKG_CONFIG_SYSROOT_DIR","val":null}},{"RerunIfEnvChanged":{"var":"PKG_CONFIG_SYSROOT_DIR","val":null}},{"RerunIfEnvChanged":{"var":"PKG_CONFIG_SYSROOT_DIR","val":null}},{"RerunIfEnvChanged":{"var":"SYSROOT","val":null}},{"RerunIfEnvChanged":{"var":"PKG_CONFIG_aarch64-unknown-linux-gnu","val":null}},{"RerunIfEnvChanged":{"var":"PKG_CONFIG_aarch64_unknown_linux_gnu","val":null}},{"RerunIfEnvChanged":{"var":"HOST_PKG_CONFIG","val":null}},{"RerunIfEnvChanged":{"var":"PKG_CONFIG","val":null}},{"RerunIfEnvChanged":{"var":"PKG_CONFIG_PATH_aarch64-unknown-linux-gnu","val":null}},{"RerunIfEnvChanged":{"var":"PKG_CONFIG_PATH_aarch64_unknown_linux_gnu","val":null}},{"RerunIfEnvChanged":{"var":"HOST_PKG_CONFIG_PATH","val":null}},{"RerunIfEnvChanged":{"var":"PKG_CONFIG_PATH","val":null}},{"RerunIfEnvChanged":{"var":"PKG_CONFIG_LIBDIR_aarch64-unknown-linux-gnu","val":null}},{"RerunIfEnvChanged":{"var":"PKG_CONFIG_LIBDIR_aarch64_unknown_linux_gnu","val":null}},{"RerunIfEnvChanged":{"var":"HOST_PKG_CONFIG_LIBDIR","val":null}},{"RerunIfEnvChanged":{"var":"PKG_CONFIG_LIBDIR","val":null}},{"RerunIfEnvChanged":{"var":"PKG_CONFIG_SYSROOT_DIR_aarch64-unknown-linux-gnu","val":null}},{"RerunIfEnvChanged":{"var":"PKG_CONFIG_SYSROOT_DIR_aarch64_unknown_linux_gnu","val":null}},{"RerunIfEnvChanged":{"var":"HOST_PKG_CONFIG_SYSROOT_DIR","val":null}},{"RerunIfEnvChanged":{"var":"PKG_CONFIG_SYSROOT_DIR","val":null}},{"RerunIfEnvChanged":{"var":"SYSTEM_DEPS_BUILD_INTERNAL","val":null}},{"RerunIfEnvChanged":{"var":"SYSTEM_DEPS_LINK","val":null}},{"RerunIfEnvChanged":{"var":"SYSTEM_DEPS_GOBJECT_2_0_LIB","val":null}},{"RerunIfEnvChanged":{"var":"SYSTEM_DEPS_GOBJECT_2_0_LIB_FRAMEWORK","val":null}},{"RerunIfEnvChanged":{"var":"SYSTEM_DEPS_GOBJECT_2_0_SEARCH_NATIVE","val":null}},{"RerunIfEnvChanged":{"var":"SYSTEM_DEPS_GOBJECT_2_0_SEARCH_FRAMEWORK","val":null}},{"RerunIfEnvChanged":{"var":"SYSTEM_DEPS_GOBJECT_2_0_INCLUDE","val":null}},{"RerunIfEnvChanged":{"var":"SYSTEM_DEPS_GOBJECT_2_0_NO_PKG_CONFIG","val":null}},{"RerunIfEnvChanged":{"var":"SYSTEM_DEPS_GOBJECT_2_0_BUILD_INTERNAL","val":null}},{"RerunIfEnvChanged":{"var":"SYSTEM_DEPS_GOBJECT_2_0_LINK","val":null}},{"RerunIfEnvChanged":{"var":"SYSTEM_DEPS_GLIB_2_0_LIB","val":null}},{"RerunIfEnvChanged":{"var":"SYSTEM_DEPS_GLIB_2_0_LIB_FRAMEWORK","val":null}},{"RerunIfEnvChanged":{"var":"SYSTEM_DEPS_GLIB_2_0_SEARCH_NATIVE","val":null}},{"RerunIfEnvChanged":{"var":"SYSTEM_DEPS_GLIB_2_0_SEARCH_FRAMEWORK","val":null}},{"RerunIfEnvChanged":{"var":"SYSTEM_DEPS_GLIB_2_0_INCLUDE","val":null}},{"RerunIfEnvChanged":{"var":"SYSTEM_DEPS_GLIB_2_0_NO_PKG_CONFIG","val":null}},{"RerunIfEnvChanged":{"var":"SYSTEM_DEPS_GLIB_2_0_BUILD_INTERNAL","val":null}},{"RerunIfEnvChanged":{"var":"SYSTEM_DEPS_GLIB_2_0_LINK","val":null}}],"rustflags":[],"config":0,"compile_kind":0} \ No newline at end of file diff --git a/src-tauri/target/debug/.fingerprint/gobject-sys-a51398dff084dc63/lib-gobject_sys b/src-tauri/target/debug/.fingerprint/gobject-sys-a51398dff084dc63/lib-gobject_sys index 85aadff1..eb1f7b66 100644 --- a/src-tauri/target/debug/.fingerprint/gobject-sys-a51398dff084dc63/lib-gobject_sys +++ b/src-tauri/target/debug/.fingerprint/gobject-sys-a51398dff084dc63/lib-gobject_sys @@ -1 +1 @@ -99e554c7b6b7566f \ No newline at end of file +b66f3fbbb59328a7 \ No newline at end of file diff --git a/src-tauri/target/debug/.fingerprint/gobject-sys-a51398dff084dc63/lib-gobject_sys.json b/src-tauri/target/debug/.fingerprint/gobject-sys-a51398dff084dc63/lib-gobject_sys.json index d5a5b952..c95f5e4c 100644 --- a/src-tauri/target/debug/.fingerprint/gobject-sys-a51398dff084dc63/lib-gobject_sys.json +++ b/src-tauri/target/debug/.fingerprint/gobject-sys-a51398dff084dc63/lib-gobject_sys.json @@ -1 +1 @@ -{"rustc":9435880562281667341,"features":"[\"v2_58\", \"v2_62\", \"v2_66\", \"v2_68\", \"v2_70\"]","declared_features":"[\"v2_58\", \"v2_62\", \"v2_66\", \"v2_68\", \"v2_70\", \"v2_72\", \"v2_74\", \"v2_76\", \"v2_78\"]","target":8496472197725967521,"profile":2241668132362809309,"path":5747273799920600823,"deps":[[13626264195287554611,"glib",false,5575305324500369928],[15885457518084958445,"build_script_build",false,8320609477498126585],[17159683253194042242,"libc",false,9448623883530498034]],"local":[{"CheckDepInfo":{"dep_info":"debug/.fingerprint/gobject-sys-a51398dff084dc63/dep-lib-gobject_sys","checksum":false}}],"rustflags":[],"config":8247474407144887393,"compile_kind":0} \ No newline at end of file +{"rustc":9435880562281667341,"features":"[\"v2_58\", \"v2_62\", \"v2_66\", \"v2_68\", \"v2_70\"]","declared_features":"[\"v2_58\", \"v2_62\", \"v2_66\", \"v2_68\", \"v2_70\", \"v2_72\", \"v2_74\", \"v2_76\", \"v2_78\"]","target":8496472197725967521,"profile":2241668132362809309,"path":5747273799920600823,"deps":[[13626264195287554611,"glib",false,9264953364366423698],[15885457518084958445,"build_script_build",false,8320609477498126585],[17159683253194042242,"libc",false,9448623883530498034]],"local":[{"CheckDepInfo":{"dep_info":"debug/.fingerprint/gobject-sys-a51398dff084dc63/dep-lib-gobject_sys","checksum":false}}],"rustflags":[],"config":8247474407144887393,"compile_kind":0} \ No newline at end of file diff --git a/src-tauri/target/debug/.fingerprint/gtk-sys-ae9238fc13eedecb/lib-gtk_sys b/src-tauri/target/debug/.fingerprint/gtk-sys-ae9238fc13eedecb/lib-gtk_sys index eb1d0bfb..dbd086a0 100644 --- a/src-tauri/target/debug/.fingerprint/gtk-sys-ae9238fc13eedecb/lib-gtk_sys +++ b/src-tauri/target/debug/.fingerprint/gtk-sys-ae9238fc13eedecb/lib-gtk_sys @@ -1 +1 @@ -1b89f0fddc51bf06 \ No newline at end of file +1ccdb81f9803dbf3 \ No newline at end of file diff --git a/src-tauri/target/debug/.fingerprint/gtk-sys-ae9238fc13eedecb/lib-gtk_sys.json b/src-tauri/target/debug/.fingerprint/gtk-sys-ae9238fc13eedecb/lib-gtk_sys.json index ffd13bcb..f83f57d3 100644 --- a/src-tauri/target/debug/.fingerprint/gtk-sys-ae9238fc13eedecb/lib-gtk_sys.json +++ b/src-tauri/target/debug/.fingerprint/gtk-sys-ae9238fc13eedecb/lib-gtk_sys.json @@ -1 +1 @@ -{"rustc":9435880562281667341,"features":"[\"v3_24\"]","declared_features":"[\"v3_24\", \"v3_24_1\", \"v3_24_11\", \"v3_24_30\", \"v3_24_8\", \"v3_24_9\"]","target":4528965810399274372,"profile":2241668132362809309,"path":18001016390602429102,"deps":[[2028663402560672651,"gdk_pixbuf",false,2540939478916349158],[2184755618550678726,"pango",false,14709927256080672428],[4520300193208121197,"atk",false,8836204151659031175],[6885242093860886281,"cairo",false,16612610469833888838],[12225316990487900155,"gdk",false,14633418147404925284],[13244166758162771746,"build_script_build",false,3260786767325860862],[13626264195287554611,"glib",false,5575305324500369928],[15885457518084958445,"gobject",false,8022801781863277977],[17138253974170286367,"gio",false,14268886093481619365],[17159683253194042242,"libc",false,9448623883530498034]],"local":[{"CheckDepInfo":{"dep_info":"debug/.fingerprint/gtk-sys-ae9238fc13eedecb/dep-lib-gtk_sys","checksum":false}}],"rustflags":[],"config":8247474407144887393,"compile_kind":0} \ No newline at end of file +{"rustc":9435880562281667341,"features":"[\"v3_24\"]","declared_features":"[\"v3_24\", \"v3_24_1\", \"v3_24_11\", \"v3_24_30\", \"v3_24_8\", \"v3_24_9\"]","target":4528965810399274372,"profile":2241668132362809309,"path":18001016390602429102,"deps":[[2028663402560672651,"gdk_pixbuf",false,15310156194781907931],[2184755618550678726,"pango",false,9273454815819985803],[4520300193208121197,"atk",false,10194748097742422798],[6885242093860886281,"cairo",false,17030865416582237425],[12225316990487900155,"gdk",false,4892631574488749175],[13244166758162771746,"build_script_build",false,3260786767325860862],[13626264195287554611,"glib",false,9264953364366423698],[15885457518084958445,"gobject",false,12045039612142251958],[17138253974170286367,"gio",false,12787692356947406432],[17159683253194042242,"libc",false,9448623883530498034]],"local":[{"CheckDepInfo":{"dep_info":"debug/.fingerprint/gtk-sys-ae9238fc13eedecb/dep-lib-gtk_sys","checksum":false}}],"rustflags":[],"config":8247474407144887393,"compile_kind":0} \ No newline at end of file diff --git a/src-tauri/target/debug/.fingerprint/javascriptcore-rs-sys-80bb3979b374ec9b/lib-javascriptcore_rs_sys b/src-tauri/target/debug/.fingerprint/javascriptcore-rs-sys-80bb3979b374ec9b/lib-javascriptcore_rs_sys index a80f05a5..a3d2c317 100644 --- a/src-tauri/target/debug/.fingerprint/javascriptcore-rs-sys-80bb3979b374ec9b/lib-javascriptcore_rs_sys +++ b/src-tauri/target/debug/.fingerprint/javascriptcore-rs-sys-80bb3979b374ec9b/lib-javascriptcore_rs_sys @@ -1 +1 @@ -24489362717cfd07 \ No newline at end of file +783fa28e59dbf287 \ No newline at end of file diff --git a/src-tauri/target/debug/.fingerprint/javascriptcore-rs-sys-80bb3979b374ec9b/lib-javascriptcore_rs_sys.json b/src-tauri/target/debug/.fingerprint/javascriptcore-rs-sys-80bb3979b374ec9b/lib-javascriptcore_rs_sys.json index e887dd37..57588854 100644 --- a/src-tauri/target/debug/.fingerprint/javascriptcore-rs-sys-80bb3979b374ec9b/lib-javascriptcore_rs_sys.json +++ b/src-tauri/target/debug/.fingerprint/javascriptcore-rs-sys-80bb3979b374ec9b/lib-javascriptcore_rs_sys.json @@ -1 +1 @@ -{"rustc":9435880562281667341,"features":"[\"v2_28\", \"v2_38\"]","declared_features":"[\"v2_28\", \"v2_38\"]","target":17217257543979948008,"profile":2241668132362809309,"path":17669955065355595971,"deps":[[12726616099386114179,"build_script_build",false,11029008866159647312],[13626264195287554611,"glib",false,5575305324500369928],[15885457518084958445,"gobject",false,8022801781863277977],[17159683253194042242,"libc",false,9448623883530498034]],"local":[{"CheckDepInfo":{"dep_info":"debug/.fingerprint/javascriptcore-rs-sys-80bb3979b374ec9b/dep-lib-javascriptcore_rs_sys","checksum":false}}],"rustflags":[],"config":8247474407144887393,"compile_kind":0} \ No newline at end of file +{"rustc":9435880562281667341,"features":"[\"v2_28\", \"v2_38\"]","declared_features":"[\"v2_28\", \"v2_38\"]","target":17217257543979948008,"profile":2241668132362809309,"path":17669955065355595971,"deps":[[12726616099386114179,"build_script_build",false,11029008866159647312],[13626264195287554611,"glib",false,9264953364366423698],[15885457518084958445,"gobject",false,12045039612142251958],[17159683253194042242,"libc",false,9448623883530498034]],"local":[{"CheckDepInfo":{"dep_info":"debug/.fingerprint/javascriptcore-rs-sys-80bb3979b374ec9b/dep-lib-javascriptcore_rs_sys","checksum":false}}],"rustflags":[],"config":8247474407144887393,"compile_kind":0} \ No newline at end of file diff --git a/src-tauri/target/debug/.fingerprint/pango-sys-7fb2c6fcda294579/lib-pango_sys b/src-tauri/target/debug/.fingerprint/pango-sys-7fb2c6fcda294579/lib-pango_sys index 9de0a8f1..a30b3d79 100644 --- a/src-tauri/target/debug/.fingerprint/pango-sys-7fb2c6fcda294579/lib-pango_sys +++ b/src-tauri/target/debug/.fingerprint/pango-sys-7fb2c6fcda294579/lib-pango_sys @@ -1 +1 @@ -ac668622e72824cc \ No newline at end of file +8bf395a905eeb180 \ No newline at end of file diff --git a/src-tauri/target/debug/.fingerprint/pango-sys-7fb2c6fcda294579/lib-pango_sys.json b/src-tauri/target/debug/.fingerprint/pango-sys-7fb2c6fcda294579/lib-pango_sys.json index d421434c..bef15708 100644 --- a/src-tauri/target/debug/.fingerprint/pango-sys-7fb2c6fcda294579/lib-pango_sys.json +++ b/src-tauri/target/debug/.fingerprint/pango-sys-7fb2c6fcda294579/lib-pango_sys.json @@ -1 +1 @@ -{"rustc":9435880562281667341,"features":"[]","declared_features":"[\"v1_42\", \"v1_44\", \"v1_46\", \"v1_48\", \"v1_50\", \"v1_52\"]","target":5892295992406752241,"profile":2241668132362809309,"path":11681504582098819980,"deps":[[2184755618550678726,"build_script_build",false,11647657745266431528],[13626264195287554611,"glib",false,5575305324500369928],[15885457518084958445,"gobject",false,8022801781863277977],[17159683253194042242,"libc",false,9448623883530498034]],"local":[{"CheckDepInfo":{"dep_info":"debug/.fingerprint/pango-sys-7fb2c6fcda294579/dep-lib-pango_sys","checksum":false}}],"rustflags":[],"config":8247474407144887393,"compile_kind":0} \ No newline at end of file +{"rustc":9435880562281667341,"features":"[]","declared_features":"[\"v1_42\", \"v1_44\", \"v1_46\", \"v1_48\", \"v1_50\", \"v1_52\"]","target":5892295992406752241,"profile":2241668132362809309,"path":11681504582098819980,"deps":[[2184755618550678726,"build_script_build",false,11647657745266431528],[13626264195287554611,"glib",false,9264953364366423698],[15885457518084958445,"gobject",false,12045039612142251958],[17159683253194042242,"libc",false,9448623883530498034]],"local":[{"CheckDepInfo":{"dep_info":"debug/.fingerprint/pango-sys-7fb2c6fcda294579/dep-lib-pango_sys","checksum":false}}],"rustflags":[],"config":8247474407144887393,"compile_kind":0} \ No newline at end of file diff --git a/src-tauri/target/debug/.fingerprint/rfd-237efcd480f81110/lib-rfd b/src-tauri/target/debug/.fingerprint/rfd-237efcd480f81110/lib-rfd index 97a9b9be..9c4cb4e8 100644 --- a/src-tauri/target/debug/.fingerprint/rfd-237efcd480f81110/lib-rfd +++ b/src-tauri/target/debug/.fingerprint/rfd-237efcd480f81110/lib-rfd @@ -1 +1 @@ -12fb31ec9153a35c \ No newline at end of file +d2f18ca9005cef98 \ No newline at end of file diff --git a/src-tauri/target/debug/.fingerprint/rfd-237efcd480f81110/lib-rfd.json b/src-tauri/target/debug/.fingerprint/rfd-237efcd480f81110/lib-rfd.json index 9bc9bf1d..db803ae7 100644 --- a/src-tauri/target/debug/.fingerprint/rfd-237efcd480f81110/lib-rfd.json +++ b/src-tauri/target/debug/.fingerprint/rfd-237efcd480f81110/lib-rfd.json @@ -1 +1 @@ -{"rustc":9435880562281667341,"features":"[\"common-controls-v6\", \"glib-sys\", \"gobject-sys\", \"gtk-sys\", \"gtk3\"]","declared_features":"[\"ashpd\", \"async-std\", \"common-controls-v6\", \"default\", \"file-handle-inner\", \"glib-sys\", \"gobject-sys\", \"gtk-sys\", \"gtk3\", \"pollster\", \"tokio\", \"urlencoding\", \"wayland\", \"xdg-portal\"]","target":4644090373205775831,"profile":2241668132362809309,"path":16910467066997891197,"deps":[[4143744114649553716,"raw_window_handle",false,13356969486201052105],[10630857666389190470,"log",false,5933974529767802847],[13244166758162771746,"gtk_sys",false,486197294374357275],[13626264195287554611,"glib_sys",false,5575305324500369928],[15885457518084958445,"gobject_sys",false,8022801781863277977],[18096261089697941857,"build_script_build",false,7365468796528817961]],"local":[{"CheckDepInfo":{"dep_info":"debug/.fingerprint/rfd-237efcd480f81110/dep-lib-rfd","checksum":false}}],"rustflags":[],"config":8247474407144887393,"compile_kind":0} \ No newline at end of file +{"rustc":9435880562281667341,"features":"[\"common-controls-v6\", \"glib-sys\", \"gobject-sys\", \"gtk-sys\", \"gtk3\"]","declared_features":"[\"ashpd\", \"async-std\", \"common-controls-v6\", \"default\", \"file-handle-inner\", \"glib-sys\", \"gobject-sys\", \"gtk-sys\", \"gtk3\", \"pollster\", \"tokio\", \"urlencoding\", \"wayland\", \"xdg-portal\"]","target":4644090373205775831,"profile":2241668132362809309,"path":16910467066997891197,"deps":[[4143744114649553716,"raw_window_handle",false,13356969486201052105],[10630857666389190470,"log",false,5933974529767802847],[13244166758162771746,"gtk_sys",false,17571642323018239260],[13626264195287554611,"glib_sys",false,9264953364366423698],[15885457518084958445,"gobject_sys",false,12045039612142251958],[18096261089697941857,"build_script_build",false,7365468796528817961]],"local":[{"CheckDepInfo":{"dep_info":"debug/.fingerprint/rfd-237efcd480f81110/dep-lib-rfd","checksum":false}}],"rustflags":[],"config":8247474407144887393,"compile_kind":0} \ No newline at end of file diff --git a/src-tauri/target/debug/.fingerprint/soup3-sys-759ec12a00a837af/lib-soup3_sys b/src-tauri/target/debug/.fingerprint/soup3-sys-759ec12a00a837af/lib-soup3_sys index 52fcf766..cd6c007b 100644 --- a/src-tauri/target/debug/.fingerprint/soup3-sys-759ec12a00a837af/lib-soup3_sys +++ b/src-tauri/target/debug/.fingerprint/soup3-sys-759ec12a00a837af/lib-soup3_sys @@ -1 +1 @@ -55aa6e20999fcd8c \ No newline at end of file +88b1680aca4836b8 \ No newline at end of file diff --git a/src-tauri/target/debug/.fingerprint/soup3-sys-759ec12a00a837af/lib-soup3_sys.json b/src-tauri/target/debug/.fingerprint/soup3-sys-759ec12a00a837af/lib-soup3_sys.json index a5949603..1d436f24 100644 --- a/src-tauri/target/debug/.fingerprint/soup3-sys-759ec12a00a837af/lib-soup3_sys.json +++ b/src-tauri/target/debug/.fingerprint/soup3-sys-759ec12a00a837af/lib-soup3_sys.json @@ -1 +1 @@ -{"rustc":9435880562281667341,"features":"[\"v3_0\"]","declared_features":"[\"v3_0\", \"v3_2\", \"v3_4\"]","target":4746024912976814357,"profile":2241668132362809309,"path":11899460850599487506,"deps":[[13626264195287554611,"glib",false,5575305324500369928],[15885457518084958445,"gobject",false,8022801781863277977],[17138253974170286367,"gio",false,14268886093481619365],[17159683253194042242,"libc",false,9448623883530498034],[17724869489793055652,"build_script_build",false,16284928507403598398]],"local":[{"CheckDepInfo":{"dep_info":"debug/.fingerprint/soup3-sys-759ec12a00a837af/dep-lib-soup3_sys","checksum":false}}],"rustflags":[],"config":8247474407144887393,"compile_kind":0} \ No newline at end of file +{"rustc":9435880562281667341,"features":"[\"v3_0\"]","declared_features":"[\"v3_0\", \"v3_2\", \"v3_4\"]","target":4746024912976814357,"profile":2241668132362809309,"path":11899460850599487506,"deps":[[13626264195287554611,"glib",false,9264953364366423698],[15885457518084958445,"gobject",false,12045039612142251958],[17138253974170286367,"gio",false,12787692356947406432],[17159683253194042242,"libc",false,9448623883530498034],[17724869489793055652,"build_script_build",false,16284928507403598398]],"local":[{"CheckDepInfo":{"dep_info":"debug/.fingerprint/soup3-sys-759ec12a00a837af/dep-lib-soup3_sys","checksum":false}}],"rustflags":[],"config":8247474407144887393,"compile_kind":0} \ No newline at end of file diff --git a/src-tauri/target/debug/.fingerprint/webkit2gtk-sys-935418f782552fab/lib-webkit2gtk_sys b/src-tauri/target/debug/.fingerprint/webkit2gtk-sys-935418f782552fab/lib-webkit2gtk_sys index 73723b6d..84f8e06d 100644 --- a/src-tauri/target/debug/.fingerprint/webkit2gtk-sys-935418f782552fab/lib-webkit2gtk_sys +++ b/src-tauri/target/debug/.fingerprint/webkit2gtk-sys-935418f782552fab/lib-webkit2gtk_sys @@ -1 +1 @@ -14e35fb7bb7956a1 \ No newline at end of file +f39cae21ec772c7e \ No newline at end of file diff --git a/src-tauri/target/debug/.fingerprint/webkit2gtk-sys-935418f782552fab/lib-webkit2gtk_sys.json b/src-tauri/target/debug/.fingerprint/webkit2gtk-sys-935418f782552fab/lib-webkit2gtk_sys.json index b37931c5..a848e2cb 100644 --- a/src-tauri/target/debug/.fingerprint/webkit2gtk-sys-935418f782552fab/lib-webkit2gtk_sys.json +++ b/src-tauri/target/debug/.fingerprint/webkit2gtk-sys-935418f782552fab/lib-webkit2gtk_sys.json @@ -1 +1 @@ -{"rustc":9435880562281667341,"features":"[\"v2_10\", \"v2_12\", \"v2_14\", \"v2_16\", \"v2_18\", \"v2_20\", \"v2_22\", \"v2_24\", \"v2_26\", \"v2_28\", \"v2_30\", \"v2_32\", \"v2_34\", \"v2_36\", \"v2_38\", \"v2_40\", \"v2_6\", \"v2_8\"]","declared_features":"[\"v2_10\", \"v2_12\", \"v2_14\", \"v2_16\", \"v2_18\", \"v2_20\", \"v2_22\", \"v2_24\", \"v2_26\", \"v2_28\", \"v2_30\", \"v2_32\", \"v2_34\", \"v2_36\", \"v2_38\", \"v2_40\", \"v2_6\", \"v2_8\"]","target":423463711184852656,"profile":2241668132362809309,"path":10664168538057484594,"deps":[[6885242093860886281,"cairo",false,16612610469833888838],[10435729446543529114,"bitflags",false,10529288711119310154],[12216365939420334724,"build_script_build",false,17249160887632110307],[12225316990487900155,"gdk",false,14633418147404925284],[12726616099386114179,"java_script_core",false,575753153800259620],[13244166758162771746,"gtk",false,486197294374357275],[13626264195287554611,"glib",false,5575305324500369928],[15885457518084958445,"gobject",false,8022801781863277977],[17138253974170286367,"gio",false,14268886093481619365],[17159683253194042242,"libc",false,9448623883530498034],[17724869489793055652,"soup",false,10145941015558531669]],"local":[{"CheckDepInfo":{"dep_info":"debug/.fingerprint/webkit2gtk-sys-935418f782552fab/dep-lib-webkit2gtk_sys","checksum":false}}],"rustflags":[],"config":8247474407144887393,"compile_kind":0} \ No newline at end of file +{"rustc":9435880562281667341,"features":"[\"v2_10\", \"v2_12\", \"v2_14\", \"v2_16\", \"v2_18\", \"v2_20\", \"v2_22\", \"v2_24\", \"v2_26\", \"v2_28\", \"v2_30\", \"v2_32\", \"v2_34\", \"v2_36\", \"v2_38\", \"v2_40\", \"v2_6\", \"v2_8\"]","declared_features":"[\"v2_10\", \"v2_12\", \"v2_14\", \"v2_16\", \"v2_18\", \"v2_20\", \"v2_22\", \"v2_24\", \"v2_26\", \"v2_28\", \"v2_30\", \"v2_32\", \"v2_34\", \"v2_36\", \"v2_38\", \"v2_40\", \"v2_6\", \"v2_8\"]","target":423463711184852656,"profile":2241668132362809309,"path":10664168538057484594,"deps":[[6885242093860886281,"cairo",false,17030865416582237425],[10435729446543529114,"bitflags",false,10529288711119310154],[12216365939420334724,"build_script_build",false,17249160887632110307],[12225316990487900155,"gdk",false,4892631574488749175],[12726616099386114179,"java_script_core",false,9796133317175820152],[13244166758162771746,"gtk",false,17571642323018239260],[13626264195287554611,"glib",false,9264953364366423698],[15885457518084958445,"gobject",false,12045039612142251958],[17138253974170286367,"gio",false,12787692356947406432],[17159683253194042242,"libc",false,9448623883530498034],[17724869489793055652,"soup",false,13273876984316342664]],"local":[{"CheckDepInfo":{"dep_info":"debug/.fingerprint/webkit2gtk-sys-935418f782552fab/dep-lib-webkit2gtk_sys","checksum":false}}],"rustflags":[],"config":8247474407144887393,"compile_kind":0} \ No newline at end of file diff --git a/src-tauri/target/debug/build/glib-sys-f02d0a4c75864a6c/output b/src-tauri/target/debug/build/glib-sys-f02d0a4c75864a6c/output index 47a212e1..6a331b91 100644 --- a/src-tauri/target/debug/build/glib-sys-f02d0a4c75864a6c/output +++ b/src-tauri/target/debug/build/glib-sys-f02d0a4c75864a6c/output @@ -74,14 +74,6 @@ cargo:rustc-link-lib=glib-2.0 cargo:include=/usr/include/glib-2.0:/usr/lib64/glib-2.0/include:/usr/include/sysprof-6:/usr/include:/usr/include:/usr/include/glib-2.0:/usr/lib64/glib-2.0/include:/usr/include/sysprof-6 cargo:rerun-if-env-changed=SYSTEM_DEPS_BUILD_INTERNAL cargo:rerun-if-env-changed=SYSTEM_DEPS_LINK -cargo:rerun-if-env-changed=SYSTEM_DEPS_GLIB_2_0_LIB -cargo:rerun-if-env-changed=SYSTEM_DEPS_GLIB_2_0_LIB_FRAMEWORK -cargo:rerun-if-env-changed=SYSTEM_DEPS_GLIB_2_0_SEARCH_NATIVE -cargo:rerun-if-env-changed=SYSTEM_DEPS_GLIB_2_0_SEARCH_FRAMEWORK -cargo:rerun-if-env-changed=SYSTEM_DEPS_GLIB_2_0_INCLUDE -cargo:rerun-if-env-changed=SYSTEM_DEPS_GLIB_2_0_NO_PKG_CONFIG -cargo:rerun-if-env-changed=SYSTEM_DEPS_GLIB_2_0_BUILD_INTERNAL -cargo:rerun-if-env-changed=SYSTEM_DEPS_GLIB_2_0_LINK cargo:rerun-if-env-changed=SYSTEM_DEPS_GOBJECT_2_0_LIB cargo:rerun-if-env-changed=SYSTEM_DEPS_GOBJECT_2_0_LIB_FRAMEWORK cargo:rerun-if-env-changed=SYSTEM_DEPS_GOBJECT_2_0_SEARCH_NATIVE @@ -90,6 +82,14 @@ cargo:rerun-if-env-changed=SYSTEM_DEPS_GOBJECT_2_0_INCLUDE cargo:rerun-if-env-changed=SYSTEM_DEPS_GOBJECT_2_0_NO_PKG_CONFIG cargo:rerun-if-env-changed=SYSTEM_DEPS_GOBJECT_2_0_BUILD_INTERNAL cargo:rerun-if-env-changed=SYSTEM_DEPS_GOBJECT_2_0_LINK +cargo:rerun-if-env-changed=SYSTEM_DEPS_GLIB_2_0_LIB +cargo:rerun-if-env-changed=SYSTEM_DEPS_GLIB_2_0_LIB_FRAMEWORK +cargo:rerun-if-env-changed=SYSTEM_DEPS_GLIB_2_0_SEARCH_NATIVE +cargo:rerun-if-env-changed=SYSTEM_DEPS_GLIB_2_0_SEARCH_FRAMEWORK +cargo:rerun-if-env-changed=SYSTEM_DEPS_GLIB_2_0_INCLUDE +cargo:rerun-if-env-changed=SYSTEM_DEPS_GLIB_2_0_NO_PKG_CONFIG +cargo:rerun-if-env-changed=SYSTEM_DEPS_GLIB_2_0_BUILD_INTERNAL +cargo:rerun-if-env-changed=SYSTEM_DEPS_GLIB_2_0_LINK cargo:rustc-cfg=system_deps_have_glib_2_0 cargo:rustc-cfg=system_deps_have_gobject_2_0 diff --git a/src-tauri/target/debug/build/libsodium-sys-stable-fcf8b83ea1efb6f7/out/installed/lib/libsodium.a b/src-tauri/target/debug/build/libsodium-sys-stable-fcf8b83ea1efb6f7/out/installed/lib/libsodium.a index 01ffca9e..25146246 100644 Binary files a/src-tauri/target/debug/build/libsodium-sys-stable-fcf8b83ea1efb6f7/out/installed/lib/libsodium.a and b/src-tauri/target/debug/build/libsodium-sys-stable-fcf8b83ea1efb6f7/out/installed/lib/libsodium.a differ diff --git a/src-tauri/target/debug/build/ring-d2e7a6d6bd975252/out/libring_core_0_17_14_.a b/src-tauri/target/debug/build/ring-d2e7a6d6bd975252/out/libring_core_0_17_14_.a index 5f8949a9..4ae2b46c 100644 Binary files a/src-tauri/target/debug/build/ring-d2e7a6d6bd975252/out/libring_core_0_17_14_.a and b/src-tauri/target/debug/build/ring-d2e7a6d6bd975252/out/libring_core_0_17_14_.a differ diff --git a/src-tauri/target/debug/build/ring-d2e7a6d6bd975252/out/libring_core_0_17_14__test.a b/src-tauri/target/debug/build/ring-d2e7a6d6bd975252/out/libring_core_0_17_14__test.a index 76899742..974021c0 100644 Binary files a/src-tauri/target/debug/build/ring-d2e7a6d6bd975252/out/libring_core_0_17_14__test.a and b/src-tauri/target/debug/build/ring-d2e7a6d6bd975252/out/libring_core_0_17_14__test.a differ diff --git a/src-tauri/target/debug/deps/libgeneric_array-adc28b423921ee8f.rmeta b/src-tauri/target/debug/deps/libgeneric_array-adc28b423921ee8f.rmeta index 6dc2b2aa..c1ee57b0 100644 Binary files a/src-tauri/target/debug/deps/libgeneric_array-adc28b423921ee8f.rmeta and b/src-tauri/target/debug/deps/libgeneric_array-adc28b423921ee8f.rmeta differ diff --git a/src-tauri/target/debug/deps/libserde_spanned-0cf36ffdb7849374.rlib b/src-tauri/target/debug/deps/libserde_spanned-0cf36ffdb7849374.rlib index c551687a..74843f5b 100644 Binary files a/src-tauri/target/debug/deps/libserde_spanned-0cf36ffdb7849374.rlib and b/src-tauri/target/debug/deps/libserde_spanned-0cf36ffdb7849374.rlib differ diff --git a/src-tauri/target/debug/deps/libserde_spanned-0cf36ffdb7849374.rmeta b/src-tauri/target/debug/deps/libserde_spanned-0cf36ffdb7849374.rmeta index 27e13a34..bf1d21c1 100644 Binary files a/src-tauri/target/debug/deps/libserde_spanned-0cf36ffdb7849374.rmeta and b/src-tauri/target/debug/deps/libserde_spanned-0cf36ffdb7849374.rmeta differ diff --git a/src-tauri/target/debug/deps/libstring_cache-c8c8aa181edb1bc1.rlib b/src-tauri/target/debug/deps/libstring_cache-c8c8aa181edb1bc1.rlib index b8e8eb2e..8c1c5812 100644 Binary files a/src-tauri/target/debug/deps/libstring_cache-c8c8aa181edb1bc1.rlib and b/src-tauri/target/debug/deps/libstring_cache-c8c8aa181edb1bc1.rlib differ diff --git a/src-tauri/target/debug/deps/libstring_cache-c8c8aa181edb1bc1.rmeta b/src-tauri/target/debug/deps/libstring_cache-c8c8aa181edb1bc1.rmeta index 3f402db0..ff660336 100644 Binary files a/src-tauri/target/debug/deps/libstring_cache-c8c8aa181edb1bc1.rmeta and b/src-tauri/target/debug/deps/libstring_cache-c8c8aa181edb1bc1.rmeta differ diff --git a/src-tauri/target/debug/deps/libsystem_deps-ed1d73dbdce9a496.rlib b/src-tauri/target/debug/deps/libsystem_deps-ed1d73dbdce9a496.rlib index f44208df..78ac2de0 100644 Binary files a/src-tauri/target/debug/deps/libsystem_deps-ed1d73dbdce9a496.rlib and b/src-tauri/target/debug/deps/libsystem_deps-ed1d73dbdce9a496.rlib differ diff --git a/src-tauri/target/debug/deps/libsystem_deps-ed1d73dbdce9a496.rmeta b/src-tauri/target/debug/deps/libsystem_deps-ed1d73dbdce9a496.rmeta index 7e8581a9..26fc54b6 100644 Binary files a/src-tauri/target/debug/deps/libsystem_deps-ed1d73dbdce9a496.rmeta and b/src-tauri/target/debug/deps/libsystem_deps-ed1d73dbdce9a496.rmeta differ diff --git a/src-tauri/target/debug/deps/libtoml-b011b516975af0e2.rlib b/src-tauri/target/debug/deps/libtoml-b011b516975af0e2.rlib index 77bcb02e..965f1701 100644 Binary files a/src-tauri/target/debug/deps/libtoml-b011b516975af0e2.rlib and b/src-tauri/target/debug/deps/libtoml-b011b516975af0e2.rlib differ diff --git a/src-tauri/target/debug/deps/libtoml-b011b516975af0e2.rmeta b/src-tauri/target/debug/deps/libtoml-b011b516975af0e2.rmeta index e384e175..0f41faea 100644 Binary files a/src-tauri/target/debug/deps/libtoml-b011b516975af0e2.rmeta and b/src-tauri/target/debug/deps/libtoml-b011b516975af0e2.rmeta differ diff --git a/src-tauri/target/debug/deps/libtoml_datetime-f43dbc998bc754b3.rlib b/src-tauri/target/debug/deps/libtoml_datetime-f43dbc998bc754b3.rlib index 18e7ecdc..14470149 100644 Binary files a/src-tauri/target/debug/deps/libtoml_datetime-f43dbc998bc754b3.rlib and b/src-tauri/target/debug/deps/libtoml_datetime-f43dbc998bc754b3.rlib differ diff --git a/src-tauri/target/debug/deps/libtoml_datetime-f43dbc998bc754b3.rmeta b/src-tauri/target/debug/deps/libtoml_datetime-f43dbc998bc754b3.rmeta index 6dbc94c4..c26deaf2 100644 Binary files a/src-tauri/target/debug/deps/libtoml_datetime-f43dbc998bc754b3.rmeta and b/src-tauri/target/debug/deps/libtoml_datetime-f43dbc998bc754b3.rmeta differ diff --git a/src-tauri/target/debug/deps/libtoml_edit-92eff86d0a979929.rlib b/src-tauri/target/debug/deps/libtoml_edit-92eff86d0a979929.rlib index d2fa5683..ed5447de 100644 Binary files a/src-tauri/target/debug/deps/libtoml_edit-92eff86d0a979929.rlib and b/src-tauri/target/debug/deps/libtoml_edit-92eff86d0a979929.rlib differ diff --git a/src-tauri/target/debug/deps/libtoml_edit-92eff86d0a979929.rmeta b/src-tauri/target/debug/deps/libtoml_edit-92eff86d0a979929.rmeta index 57354d4b..6c8081b9 100644 Binary files a/src-tauri/target/debug/deps/libtoml_edit-92eff86d0a979929.rmeta and b/src-tauri/target/debug/deps/libtoml_edit-92eff86d0a979929.rmeta differ diff --git a/src-tauri/target/debug/deps/liburl-6b85ad66c67c2522.rlib b/src-tauri/target/debug/deps/liburl-6b85ad66c67c2522.rlib index 51c72f89..18aae75c 100644 Binary files a/src-tauri/target/debug/deps/liburl-6b85ad66c67c2522.rlib and b/src-tauri/target/debug/deps/liburl-6b85ad66c67c2522.rlib differ diff --git a/src-tauri/target/debug/deps/liburl-6b85ad66c67c2522.rmeta b/src-tauri/target/debug/deps/liburl-6b85ad66c67c2522.rmeta index 3e77b747..0567bdcf 100644 Binary files a/src-tauri/target/debug/deps/liburl-6b85ad66c67c2522.rmeta and b/src-tauri/target/debug/deps/liburl-6b85ad66c67c2522.rmeta differ diff --git a/src/components/ImageGallery.tsx b/src/components/ImageGallery.tsx new file mode 100644 index 00000000..727773d6 --- /dev/null +++ b/src/components/ImageGallery.tsx @@ -0,0 +1,165 @@ +import React, { useState, useRef, useEffect } from "react"; +import { X, AlertTriangle, ExternalLink, Image as ImageIcon } from "lucide-react"; +import type { ImageAttachment } from "@/lib/tauriCommands"; + +interface ImageGalleryProps { + images: ImageAttachment[]; + onDelete?: (attachment: ImageAttachment) => void; + showWarning?: boolean; +} + +export function ImageGallery({ images, onDelete, showWarning = true }: ImageGalleryProps) { + const [selectedImage, setSelectedImage] = useState(null); + const [isModalOpen, setIsModalOpen] = useState(false); + const modalRef = useRef(null); + + useEffect(() => { + const handleKeyDown = (e: KeyboardEvent) => { + if (e.key === "Escape" && isModalOpen) { + setIsModalOpen(false); + setSelectedImage(null); + } + }; + window.addEventListener("keydown", handleKeyDown); + return () => window.removeEventListener("keydown", handleKeyDown); + }, [isModalOpen]); + + if (images.length === 0) return null; + + const base64ToDataUrl = (base64: string, mimeType: string): string => { + if (base64.startsWith("data:image/")) { + return base64; + } + return `data:${mimeType};base64,${base64}`; + }; + + const getPreviewUrl = (attachment: ImageAttachment): string => { + if (attachment.file_path && attachment.file_path.length > 0) { + return `file://${attachment.file_path}`; + } + return base64ToDataUrl(attachment.upload_hash, attachment.mime_type); + }; + + const isWebSource = (image: ImageAttachment): boolean => { + return image.file_path.length > 0 && + (image.file_path.startsWith("http://") || + image.file_path.startsWith("https://")); + }; + + return ( +
+ {showWarning && ( +
+ + + ⚠️ PII cannot be automatically redacted from images. Use at your own risk. + +
+ )} + + {images.some(img => isWebSource(img)) && ( +
+ + + ⚠️ Some images appear to be from web sources. Ensure you have permission to share. + +
+ )} + +
+ {images.map((image, idx) => ( +
+ +
+

+ {image.file_name} +

+

+ {image.is_paste ? "Paste" : "Upload"} · {(image.file_size / 1024).toFixed(1)} KB +

+
+ {onDelete && ( + + )} +
+ ))} +
+ + {isModalOpen && selectedImage && ( +
{ + setIsModalOpen(false); + setSelectedImage(null); + }} + > +
e.stopPropagation()} + > +
+
+ +

{selectedImage.file_name}

+
+ +
+
+ {selectedImage.file_name} +
+
+
+
+ Type: {selectedImage.mime_type} +
+
+ Size: {(selectedImage.file_size / 1024).toFixed(2)} KB +
+
+ Source: {selectedImage.is_paste ? "Paste" : "File"} +
+
+
+
+
+ )} +
+ ); +} + +export default ImageGallery; diff --git a/src/lib/tauriCommands.ts b/src/lib/tauriCommands.ts index b1711134..3a16e5dc 100644 --- a/src/lib/tauriCommands.ts +++ b/src/lib/tauriCommands.ts @@ -100,6 +100,7 @@ export interface ResolutionStep { export interface IssueDetail { issue: Issue; log_files: LogFile[]; + image_attachments: ImageAttachment[]; resolution_steps: ResolutionStep[]; conversations: AiConversation[]; } @@ -145,6 +146,19 @@ export interface LogFile { redacted: boolean; } +export interface ImageAttachment { + id: string; + issue_id: string; + file_name: string; + file_path: string; + file_size: number; + mime_type: string; + upload_hash: string; + uploaded_at: string; + pii_warning_acknowledged: boolean; + is_paste: boolean; +} + export interface PiiSpan { id: string; pii_type: string; @@ -263,6 +277,18 @@ export const listProvidersCmd = () => invoke("list_providers"); export const uploadLogFileCmd = (issueId: string, filePath: string) => invoke("upload_log_file", { issueId, filePath }); +export const uploadImageAttachmentCmd = (issueId: string, filePath: string) => + invoke("upload_image_attachment", { issueId, filePath }); + +export const uploadPasteImageCmd = (issueId: string, base64Image: string, mimeType: string) => + invoke("upload_paste_image", { issueId, base64Image, mimeType }); + +export const listImageAttachmentsCmd = (issueId: string) => + invoke("list_image_attachments", { issueId }); + +export const deleteImageAttachmentCmd = (attachmentId: string) => + invoke("delete_image_attachment", { attachmentId }); + export const detectPiiCmd = (logFileId: string) => invoke("detect_pii", { logFileId }); diff --git a/src/pages/LogUpload/index.tsx b/src/pages/LogUpload/index.tsx index b680f623..65e0f0fb 100644 --- a/src/pages/LogUpload/index.tsx +++ b/src/pages/LogUpload/index.tsx @@ -1,16 +1,22 @@ -import React, { useState, useCallback } from "react"; +import React, { useState, useCallback, useRef, useEffect } from "react"; import { useNavigate, useParams } from "react-router-dom"; -import { Upload, File, Trash2, ShieldCheck } from "lucide-react"; +import { Upload, File, Trash2, ShieldCheck, AlertTriangle, Image as ImageIcon } from "lucide-react"; import { Button, Card, CardHeader, CardTitle, CardContent, Badge } from "@/components/ui"; import { PiiDiffViewer } from "@/components/PiiDiffViewer"; import { useSessionStore } from "@/stores/sessionStore"; import { uploadLogFileCmd, detectPiiCmd, + uploadImageAttachmentCmd, + uploadPasteImageCmd, + listImageAttachmentsCmd, + deleteImageAttachmentCmd, type LogFile, type PiiSpan, type PiiDetectionResult, + type ImageAttachment, } from "@/lib/tauriCommands"; +import ImageGallery from "@/components/ImageGallery"; export default function LogUpload() { const { id } = useParams<{ id: string }>(); @@ -18,11 +24,14 @@ export default function LogUpload() { const { piiSpans, approvedRedactions, setPiiSpans, setApprovedRedactions } = useSessionStore(); const [files, setFiles] = useState<{ file: File; uploaded?: LogFile }[]>([]); + const [images, setImages] = useState([]); const [piiResult, setPiiResult] = useState(null); const [isUploading, setIsUploading] = useState(false); const [isDetecting, setIsDetecting] = useState(false); const [error, setError] = useState(null); + const fileInputRef = useRef(null); + const handleDrop = useCallback( (e: React.DragEvent) => { e.preventDefault(); @@ -96,9 +105,136 @@ export default function LogUpload() { } }; + const handleImageDrop = useCallback( + (e: React.DragEvent) => { + e.preventDefault(); + const droppedFiles = Array.from(e.dataTransfer.files); + const imageFiles = droppedFiles.filter((f) => f.type.startsWith("image/")); + + if (imageFiles.length > 0) { + handleImagesUpload(imageFiles); + } + }, + [id] + ); + + const handleImageFileSelect = (e: React.ChangeEvent) => { + if (e.target.files) { + const selected = Array.from(e.target.files).filter((f) => f.type.startsWith("image/")); + if (selected.length > 0) { + handleImagesUpload(selected); + } + } + }; + + const handlePaste = useCallback( + async (e: React.ClipboardEvent) => { + const items = e.clipboardData?.items; + const imageItems = items ? Array.from(items).filter((item: DataTransferItem) => item.type.startsWith("image/")) : []; + + for (const item of imageItems) { + const file = item.getAsFile(); + if (file) { + const reader = new FileReader(); + reader.onload = async () => { + const base64Data = reader.result as string; + try { + const result = await uploadPasteImageCmd(id || "", base64Data, file.type); + setImages((prev) => [...prev, result]); + } catch (err) { + setError(String(err)); + } + }; + reader.readAsDataURL(file); + } + } + }, + [id] + ); + + const handleImagesUpload = async (imageFiles: File[]) => { + if (!id || imageFiles.length === 0) return; + + setIsUploading(true); + setError(null); + try { + const uploaded = await Promise.all( + imageFiles.map(async (file) => { + const result = await uploadImageAttachmentCmd(id, file.name); + return result; + }) + ); + setImages((prev) => [...prev, ...uploaded]); + } catch (err) { + setError(String(err)); + } finally { + setIsUploading(false); + } + }; + + const handleDeleteImage = async (image: ImageAttachment) => { + try { + await deleteImageAttachmentCmd(image.id); + setImages((prev) => prev.filter((img) => img.id !== image.id)); + } catch (err) { + setError(String(err)); + } + }; + + const fileToBase64 = (file: File): Promise => { + return new Promise((resolve, reject) => { + const reader = new FileReader(); + reader.onload = () => resolve(reader.result as string); + reader.onerror = (err) => reject(err); + reader.readAsDataURL(file); + }); + }; + + const allUploaded = files.length > 0 && files.every((f) => f.uploaded); const piiReviewed = piiResult != null; + useEffect(() => { + const handleGlobalPaste = (e: ClipboardEvent) => { + if (document.activeElement?.tagName === "INPUT" || + document.activeElement?.tagName === "TEXTAREA" || + (document.activeElement as HTMLElement)?.isContentEditable || false) { + return; + } + + const items = e.clipboardData?.items; + const imageItems = items ? Array.from(items).filter((item: DataTransferItem) => item.type.startsWith("image/")) : []; + + for (const item of imageItems) { + const file = item.getAsFile(); + if (file) { + e.preventDefault(); + const reader = new FileReader(); + reader.onload = async () => { + const base64Data = reader.result as string; + try { + const result = await uploadPasteImageCmd(id || "", base64Data, file.type); + setImages((prev) => [...prev, result]); + } catch (err) { + setError(String(err)); + } + }; + reader.readAsDataURL(file); + break; + } + } + }; + + window.addEventListener("paste", handleGlobalPaste); + return () => window.removeEventListener("paste", handleGlobalPaste); + }, [id]); + + useEffect(() => { + if (id) { + listImageAttachmentsCmd(id).then(setImages).catch(setError); + } + }, [id]); + return (
@@ -165,6 +301,87 @@ export default function LogUpload() { )} + {/* Image Upload */} + {id && ( + <> +
+

+ + Image Attachments +

+

+ Upload or paste screenshots and images. +

+
+ + {/* Image drop zone */} +
e.preventDefault()} + onDrop={handleImageDrop} + className="border-2 border-dashed border-primary/30 rounded-lg p-8 text-center hover:border-primary transition-colors cursor-pointer bg-primary/5" + onClick={() => document.getElementById("image-input")?.click()} + > + +

+ Drag and drop images here, or click to browse +

+

+ Supported: PNG, JPEG, GIF, WebP, SVG +

+ +
+ + {/* Paste button */} +
+ + + Use Ctrl+V / Cmd+V or the button above to paste images + +
+ + {/* PII warning for images */} +
+ + + ⚠️ PII cannot be automatically redacted from images. Use at your own risk. + +
+ + {/* Image Gallery */} + {images.length > 0 && ( + + + + + Attached Images ({images.length}) + + + + + + + )} + + )} + {/* PII Detection */} {allUploaded && ( diff --git a/tests/unit/resolution.test.tsx b/tests/unit/resolution.test.tsx index 1b93f250..de13e933 100644 --- a/tests/unit/resolution.test.tsx +++ b/tests/unit/resolution.test.tsx @@ -21,6 +21,7 @@ const mockIssueDetail = { tags: "[]", }, log_files: [], + image_attachments: [], resolution_steps: [ { id: "step-1",