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.
|
- 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.
|
- 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.
|
- 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.
|
- 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.
|
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 bds_core::i18n::UiLocale;
|
||||||
use iced::widget::text::{Shaping, Wrapping};
|
use iced::widget::text::{Shaping, Wrapping};
|
||||||
use iced::widget::{Space, button, column, container, row, scrollable, text, text_input};
|
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::app::Message;
|
||||||
use crate::components::inputs;
|
use crate::components::inputs;
|
||||||
@@ -192,7 +192,16 @@ pub fn sidebar_view(
|
|||||||
.spacing(4)
|
.spacing(4)
|
||||||
.wrap();
|
.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 {
|
if offline_mode {
|
||||||
content.push(
|
content.push(
|
||||||
text(t(locale, "git.airplaneBlocked"))
|
text(t(locale, "git.airplaneBlocked"))
|
||||||
@@ -299,17 +308,15 @@ fn history_button(commit: &GitCommit) -> Element<'static, Message> {
|
|||||||
let hash = commit.hash.clone();
|
let hash = commit.hash.clone();
|
||||||
let subject = commit.subject.clone().unwrap_or_else(|| hash.clone());
|
let subject = commit.subject.clone().unwrap_or_else(|| hash.clone());
|
||||||
let short = hash.chars().take(7).collect::<String>();
|
let short = hash.chars().take(7).collect::<String>();
|
||||||
let marker = match commit.sync_status {
|
|
||||||
SyncStatus::Both => "●",
|
|
||||||
SyncStatus::LocalOnly => "↑",
|
|
||||||
SyncStatus::RemoteOnly => "↓",
|
|
||||||
};
|
|
||||||
button(
|
button(
|
||||||
column![
|
column![
|
||||||
text(subject.clone()).size(11),
|
text(subject.clone()).size(11),
|
||||||
text(format!("{marker} {short}"))
|
row![
|
||||||
.size(10)
|
sync_status_dot(commit.sync_status),
|
||||||
.color(Color::from_rgb(0.5, 0.5, 0.56)),
|
text(short).size(10).color(Color::from_rgb(0.5, 0.5, 0.56)),
|
||||||
|
]
|
||||||
|
.spacing(4)
|
||||||
|
.align_y(Alignment::Center),
|
||||||
]
|
]
|
||||||
.spacing(1),
|
.spacing(1),
|
||||||
)
|
)
|
||||||
@@ -320,6 +327,45 @@ fn history_button(commit: &GitCommit) -> Element<'static, Message> {
|
|||||||
.into()
|
.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> {
|
fn network_output(run: &GitNetworkRunState, locale: UiLocale) -> Element<'static, Message> {
|
||||||
let output = run
|
let output = run
|
||||||
.output
|
.output
|
||||||
@@ -534,4 +580,20 @@ mod tests {
|
|||||||
let active_tree = Tree::new(sidebar_view(&initialized, false, UiLocale::En).as_widget());
|
let active_tree = Tree::new(sidebar_view(&initialized, false, UiLocale::En).as_widget());
|
||||||
assert_eq!(count_text_inputs(&active_tree), 1);
|
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-pull = Herunterladen
|
||||||
git-push = Hochladen
|
git-push = Hochladen
|
||||||
git-airplaneBlocked = Netzwerk-Git-Aktionen sind im Flugmodus nicht verfügbar.
|
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-remoteUrl = Origin-URL
|
||||||
git-changesCount = Änderungen ({ $count })
|
git-changesCount = Änderungen ({ $count })
|
||||||
git-commitMessage = Commit-Nachricht
|
git-commitMessage = Commit-Nachricht
|
||||||
|
|||||||
@@ -705,6 +705,9 @@ git-fetch = Fetch
|
|||||||
git-pull = Pull
|
git-pull = Pull
|
||||||
git-push = Push
|
git-push = Push
|
||||||
git-airplaneBlocked = Network Git actions are unavailable in airplane mode.
|
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-remoteUrl = Origin URL
|
||||||
git-changesCount = Changes ({ $count })
|
git-changesCount = Changes ({ $count })
|
||||||
git-commitMessage = Commit message
|
git-commitMessage = Commit message
|
||||||
|
|||||||
@@ -705,6 +705,9 @@ git-fetch = Obtener
|
|||||||
git-pull = Descargar
|
git-pull = Descargar
|
||||||
git-push = Subir
|
git-push = Subir
|
||||||
git-airplaneBlocked = Las acciones Git de red no están disponibles en modo avión.
|
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-remoteUrl = URL de origin
|
||||||
git-changesCount = Cambios ({ $count })
|
git-changesCount = Cambios ({ $count })
|
||||||
git-commitMessage = Mensaje de commit
|
git-commitMessage = Mensaje de commit
|
||||||
|
|||||||
@@ -705,6 +705,9 @@ git-fetch = Récupérer
|
|||||||
git-pull = Tirer
|
git-pull = Tirer
|
||||||
git-push = Pousser
|
git-push = Pousser
|
||||||
git-airplaneBlocked = Les actions Git réseau sont indisponibles en mode avion.
|
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-remoteUrl = URL d’origine
|
||||||
git-changesCount = Modifications ({ $count })
|
git-changesCount = Modifications ({ $count })
|
||||||
git-commitMessage = Message de commit
|
git-commitMessage = Message de commit
|
||||||
|
|||||||
@@ -705,6 +705,9 @@ git-fetch = Recupera
|
|||||||
git-pull = Scarica
|
git-pull = Scarica
|
||||||
git-push = Carica
|
git-push = Carica
|
||||||
git-airplaneBlocked = Le azioni Git di rete non sono disponibili in modalità aereo.
|
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-remoteUrl = URL origin
|
||||||
git-changesCount = Modifiche ({ $count })
|
git-changesCount = Modifiche ({ $count })
|
||||||
git-commitMessage = Messaggio di commit
|
git-commitMessage = Messaggio di commit
|
||||||
|
|||||||
@@ -765,7 +765,9 @@ surface GitHistoryEntryView {
|
|||||||
|
|
||||||
@guarantee SyncStatusIndicator
|
@guarantee SyncStatusIndicator
|
||||||
-- sync_status rendered as a coloured dot.
|
-- 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.
|
-- A colour legend is shown in the git view header.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user