Color-code Git commit sync status
This commit is contained in:
@@ -27,7 +27,7 @@ The project is under active development. Core blogging workflows are broadly ava
|
||||
- Optional one-shot AI translation, description, analysis, taxonomy, and language-detection operations run in background tasks with editor-level waiting indicators, using provider-portable JSON-only requests through independent online and local OpenAI-compatible profiles. Each profile has secure credentials, persistently discovered chat/title/image model selections, explicit tool/vision overrides, chat testing, and restart-persistent status-bar airplane-mode routing.
|
||||
- Persistent conversational AI with safe Markdown, streamed and cancellable responses, model/session/token tracking, bounded project-aware blog tools, and localized conversation management in the Chat workspace. Allowlisted render tools add persistent native cards, charts, forms, lists, metrics, mind maps, tables, and tabs without executing assistant-provided HTML or JavaScript.
|
||||
- SSH-agent-based SCP or rsync publishing.
|
||||
- Integrated Git workflow for each blog project's current repository, with repository initialization, read-only origin discovery, Git LFS image tracking, status and diffs, branch/file history, commits, cancellable fetch/pull/push, and post-pull filesystem reconciliation; network actions respect airplane mode.
|
||||
- Integrated Git workflow for each blog project's current repository, with repository initialization, read-only origin discovery, Git LFS image tracking, status and diffs, branch/file history with bDS2-compatible sync-status colors, commits, cancellable fetch/pull/push, and post-pull filesystem reconciliation; network actions respect airplane mode.
|
||||
- Site, media, and translation validation plus `ruds://new-post` Blogmark capture and Lua transforms; captures open directly in the post editor and defer automatic translation until an explicit manual save, which queues one task per still-missing language. Publishing never starts automatic translation. bDS2 keeps its separate `bds2://` bookmarklet protocol.
|
||||
|
||||
RuDS uses no JavaScript application runtime and loads no CSS or JavaScript from CDNs. The preview is served by the Rust application and displayed by the operating-system webview.
|
||||
|
||||
@@ -7,7 +7,7 @@ use bds_core::engine::git::{
|
||||
use bds_core::i18n::UiLocale;
|
||||
use iced::widget::text::{Shaping, Wrapping};
|
||||
use iced::widget::{Space, button, column, container, row, scrollable, text, text_input};
|
||||
use iced::{Color, Element, Font, Length};
|
||||
use iced::{Alignment, Background, Color, Element, Font, Length};
|
||||
|
||||
use crate::app::Message;
|
||||
use crate::components::inputs;
|
||||
@@ -192,7 +192,16 @@ pub fn sidebar_view(
|
||||
.spacing(4)
|
||||
.wrap();
|
||||
|
||||
let mut content: Vec<Element<'static, Message>> = vec![header.into(), actions.into()];
|
||||
let sync_legend = row![
|
||||
sync_legend_item(SyncStatus::Both, locale),
|
||||
sync_legend_item(SyncStatus::LocalOnly, locale),
|
||||
sync_legend_item(SyncStatus::RemoteOnly, locale),
|
||||
]
|
||||
.spacing(8)
|
||||
.wrap();
|
||||
|
||||
let mut content: Vec<Element<'static, Message>> =
|
||||
vec![header.into(), sync_legend.into(), actions.into()];
|
||||
if offline_mode {
|
||||
content.push(
|
||||
text(t(locale, "git.airplaneBlocked"))
|
||||
@@ -299,17 +308,15 @@ fn history_button(commit: &GitCommit) -> Element<'static, Message> {
|
||||
let hash = commit.hash.clone();
|
||||
let subject = commit.subject.clone().unwrap_or_else(|| hash.clone());
|
||||
let short = hash.chars().take(7).collect::<String>();
|
||||
let marker = match commit.sync_status {
|
||||
SyncStatus::Both => "●",
|
||||
SyncStatus::LocalOnly => "↑",
|
||||
SyncStatus::RemoteOnly => "↓",
|
||||
};
|
||||
button(
|
||||
column![
|
||||
text(subject.clone()).size(11),
|
||||
text(format!("{marker} {short}"))
|
||||
.size(10)
|
||||
.color(Color::from_rgb(0.5, 0.5, 0.56)),
|
||||
row![
|
||||
sync_status_dot(commit.sync_status),
|
||||
text(short).size(10).color(Color::from_rgb(0.5, 0.5, 0.56)),
|
||||
]
|
||||
.spacing(4)
|
||||
.align_y(Alignment::Center),
|
||||
]
|
||||
.spacing(1),
|
||||
)
|
||||
@@ -320,6 +327,45 @@ fn history_button(commit: &GitCommit) -> Element<'static, Message> {
|
||||
.into()
|
||||
}
|
||||
|
||||
fn sync_legend_item(status: SyncStatus, locale: UiLocale) -> Element<'static, Message> {
|
||||
let key = match status {
|
||||
SyncStatus::Both => "git.synced",
|
||||
SyncStatus::LocalOnly => "git.localOnly",
|
||||
SyncStatus::RemoteOnly => "git.remoteOnly",
|
||||
};
|
||||
row![
|
||||
sync_status_dot(status),
|
||||
text(t(locale, key))
|
||||
.size(10)
|
||||
.color(Color::from_rgb(0.5, 0.5, 0.56)),
|
||||
]
|
||||
.spacing(4)
|
||||
.align_y(Alignment::Center)
|
||||
.into()
|
||||
}
|
||||
|
||||
fn sync_status_dot(status: SyncStatus) -> Element<'static, Message> {
|
||||
let color = sync_status_color(status);
|
||||
container(Space::new(8, 8))
|
||||
.style(move |_: &iced::Theme| container::Style {
|
||||
background: Some(Background::Color(color)),
|
||||
border: iced::Border {
|
||||
radius: 4.0.into(),
|
||||
..iced::Border::default()
|
||||
},
|
||||
..container::Style::default()
|
||||
})
|
||||
.into()
|
||||
}
|
||||
|
||||
fn sync_status_color(status: SyncStatus) -> Color {
|
||||
match status {
|
||||
SyncStatus::Both => Color::from_rgb8(0x73, 0xC9, 0x91),
|
||||
SyncStatus::LocalOnly => Color::from_rgb8(0xCC, 0xA7, 0x00),
|
||||
SyncStatus::RemoteOnly => Color::from_rgb8(0x75, 0xBE, 0xFF),
|
||||
}
|
||||
}
|
||||
|
||||
fn network_output(run: &GitNetworkRunState, locale: UiLocale) -> Element<'static, Message> {
|
||||
let output = run
|
||||
.output
|
||||
@@ -534,4 +580,20 @@ mod tests {
|
||||
let active_tree = Tree::new(sidebar_view(&initialized, false, UiLocale::En).as_widget());
|
||||
assert_eq!(count_text_inputs(&active_tree), 1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn commit_sync_colors_match_bds2() {
|
||||
assert_eq!(
|
||||
sync_status_color(SyncStatus::Both),
|
||||
Color::from_rgb8(0x73, 0xC9, 0x91)
|
||||
);
|
||||
assert_eq!(
|
||||
sync_status_color(SyncStatus::LocalOnly),
|
||||
Color::from_rgb8(0xCC, 0xA7, 0x00)
|
||||
);
|
||||
assert_eq!(
|
||||
sync_status_color(SyncStatus::RemoteOnly),
|
||||
Color::from_rgb8(0x75, 0xBE, 0xFF)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -705,6 +705,9 @@ git-fetch = Abrufen
|
||||
git-pull = Herunterladen
|
||||
git-push = Hochladen
|
||||
git-airplaneBlocked = Netzwerk-Git-Aktionen sind im Flugmodus nicht verfügbar.
|
||||
git-synced = Synchronisiert
|
||||
git-localOnly = Nur lokal
|
||||
git-remoteOnly = Nur remote
|
||||
git-remoteUrl = Origin-URL
|
||||
git-changesCount = Änderungen ({ $count })
|
||||
git-commitMessage = Commit-Nachricht
|
||||
|
||||
@@ -705,6 +705,9 @@ git-fetch = Fetch
|
||||
git-pull = Pull
|
||||
git-push = Push
|
||||
git-airplaneBlocked = Network Git actions are unavailable in airplane mode.
|
||||
git-synced = Synced
|
||||
git-localOnly = Local only
|
||||
git-remoteOnly = Remote only
|
||||
git-remoteUrl = Origin URL
|
||||
git-changesCount = Changes ({ $count })
|
||||
git-commitMessage = Commit message
|
||||
|
||||
@@ -705,6 +705,9 @@ git-fetch = Obtener
|
||||
git-pull = Descargar
|
||||
git-push = Subir
|
||||
git-airplaneBlocked = Las acciones Git de red no están disponibles en modo avión.
|
||||
git-synced = Sincronizado
|
||||
git-localOnly = Solo local
|
||||
git-remoteOnly = Solo remoto
|
||||
git-remoteUrl = URL de origin
|
||||
git-changesCount = Cambios ({ $count })
|
||||
git-commitMessage = Mensaje de commit
|
||||
|
||||
@@ -705,6 +705,9 @@ git-fetch = Récupérer
|
||||
git-pull = Tirer
|
||||
git-push = Pousser
|
||||
git-airplaneBlocked = Les actions Git réseau sont indisponibles en mode avion.
|
||||
git-synced = Synchronisé
|
||||
git-localOnly = Local uniquement
|
||||
git-remoteOnly = Distant uniquement
|
||||
git-remoteUrl = URL d’origine
|
||||
git-changesCount = Modifications ({ $count })
|
||||
git-commitMessage = Message de commit
|
||||
|
||||
@@ -705,6 +705,9 @@ git-fetch = Recupera
|
||||
git-pull = Scarica
|
||||
git-push = Carica
|
||||
git-airplaneBlocked = Le azioni Git di rete non sono disponibili in modalità aereo.
|
||||
git-synced = Sincronizzato
|
||||
git-localOnly = Solo locale
|
||||
git-remoteOnly = Solo remoto
|
||||
git-remoteUrl = URL origin
|
||||
git-changesCount = Modifiche ({ $count })
|
||||
git-commitMessage = Messaggio di commit
|
||||
|
||||
@@ -765,7 +765,9 @@ surface GitHistoryEntryView {
|
||||
|
||||
@guarantee SyncStatusIndicator
|
||||
-- sync_status rendered as a coloured dot.
|
||||
-- "synced" = both local and remote. "local_only" = local only. "remote_only" = remote only.
|
||||
-- "synced" = both local and remote, green #73c991.
|
||||
-- "local_only" = local only, warning yellow #cca700.
|
||||
-- "remote_only" = remote only, information blue #75beff.
|
||||
-- A colour legend is shown in the git view header.
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user