update checkout store
This commit is contained in:
@@ -271,6 +271,11 @@ impl Announcement {
|
|||||||
crate::repo_addr(self.owner, self.id.clone())
|
crate::repo_addr(self.owner, self.id.clone())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The name of the repository, or a default if none is provided.
|
||||||
|
pub fn name(&self) -> String {
|
||||||
|
self.name.clone().unwrap_or("Untitled".into())
|
||||||
|
}
|
||||||
|
|
||||||
/// Whether this announcement is a fork of the repository at `base`.
|
/// Whether this announcement is a fork of the repository at `base`.
|
||||||
/// Its `u` tag points at `base`, which also covers permanent forks whose EUC diverged.
|
/// Its `u` tag points at `base`, which also covers permanent forks whose EUC diverged.
|
||||||
///
|
///
|
||||||
|
|||||||
@@ -122,7 +122,6 @@ impl CheckoutsStore {
|
|||||||
}));
|
}));
|
||||||
|
|
||||||
// Another identity's repositories must not keep the old statuses alive.
|
// Another identity's repositories must not keep the old statuses alive.
|
||||||
// Their polls stop too.
|
|
||||||
subscriptions.push(cx.subscribe(&backend, |this, _backend, event, cx| {
|
subscriptions.push(cx.subscribe(&backend, |this, _backend, event, cx| {
|
||||||
if matches!(event, BackendEvent::SignerChanged) {
|
if matches!(event, BackendEvent::SignerChanged) {
|
||||||
this.status_requested.clear();
|
this.status_requested.clear();
|
||||||
@@ -246,7 +245,6 @@ impl CheckoutsStore {
|
|||||||
|
|
||||||
let task = cx.spawn(async move |this, cx| {
|
let task = cx.spawn(async move |this, cx| {
|
||||||
cx.background_executor().timer(REFRESH_DEBOUNCE).await;
|
cx.background_executor().timer(REFRESH_DEBOUNCE).await;
|
||||||
|
|
||||||
this.update(cx, |this, cx| this.run_refresh(cx))
|
this.update(cx, |this, cx| this.run_refresh(cx))
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -30,9 +30,7 @@ pub fn init(
|
|||||||
cx: &mut App,
|
cx: &mut App,
|
||||||
) -> Entity<Backend> {
|
) -> Entity<Backend> {
|
||||||
// rustls uses the `aws_lc_rs` provider by default.
|
// rustls uses the `aws_lc_rs` provider by default.
|
||||||
rustls::crypto::aws_lc_rs::default_provider()
|
let _ = rustls::crypto::aws_lc_rs::default_provider().install_default();
|
||||||
.install_default()
|
|
||||||
.ok();
|
|
||||||
|
|
||||||
let (client, signer) = cx.foreground_executor().block_on(async move {
|
let (client, signer) = cx.foreground_executor().block_on(async move {
|
||||||
let path = db_path.as_ref().to_path_buf();
|
let path = db_path.as_ref().to_path_buf();
|
||||||
@@ -44,9 +42,7 @@ pub fn init(
|
|||||||
let entity = cx.new(|cx| Backend::new(client, signer, cx));
|
let entity = cx.new(|cx| Backend::new(client, signer, cx));
|
||||||
Backend::set_global(entity.clone(), cx);
|
Backend::set_global(entity.clone(), cx);
|
||||||
ProfileStore::set_global(cx.new(ProfileStore::new), cx);
|
ProfileStore::set_global(cx.new(ProfileStore::new), cx);
|
||||||
|
|
||||||
RepoListStore::set_global(cx.new(|cx| RepoListStore::new(None, cx)), cx);
|
RepoListStore::set_global(cx.new(|cx| RepoListStore::new(None, cx)), cx);
|
||||||
// The local git clone cache, the grasp mirrors.
|
|
||||||
GitStore::set_global(repos_root, cx);
|
GitStore::set_global(repos_root, cx);
|
||||||
LocalReposStore::set_global(cx.new(|cx| LocalReposStore::new(scan_paths, cx)), cx);
|
LocalReposStore::set_global(cx.new(|cx| LocalReposStore::new(scan_paths, cx)), cx);
|
||||||
CheckoutsStore::set_global(cx.new(CheckoutsStore::new), cx);
|
CheckoutsStore::set_global(cx.new(CheckoutsStore::new), cx);
|
||||||
|
|||||||
@@ -1836,10 +1836,8 @@ impl RepoDetailView {
|
|||||||
fn attach_store(&mut self, store: &Entity<RepoStore>, cx: &mut Context<Self>) {
|
fn attach_store(&mut self, store: &Entity<RepoStore>, cx: &mut Context<Self>) {
|
||||||
self._subscriptions
|
self._subscriptions
|
||||||
.push(cx.observe(store, |this, _store, cx| {
|
.push(cx.observe(store, |this, _store, cx| {
|
||||||
cx.notify();
|
|
||||||
// The first refresh fills the announced HEAD.
|
|
||||||
// It defaults the banner's base branch, re-request when it changes.
|
|
||||||
this.refresh_ready_statuses(cx);
|
this.refresh_ready_statuses(cx);
|
||||||
|
cx.notify();
|
||||||
}));
|
}));
|
||||||
self.refresh_ready_statuses(cx);
|
self.refresh_ready_statuses(cx);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,14 +13,16 @@ use gpui::{
|
|||||||
SharedString, Subscription, WeakEntity, Window, div, img, px, uniform_list,
|
SharedString, Subscription, WeakEntity, Window, div, img, px, uniform_list,
|
||||||
};
|
};
|
||||||
use gpui_base::Button as BaseButton;
|
use gpui_base::Button as BaseButton;
|
||||||
|
use gpui_component::badge::Badge;
|
||||||
use gpui_component::button::{Button, ButtonVariants};
|
use gpui_component::button::{Button, ButtonVariants};
|
||||||
use gpui_component::input::InputState;
|
use gpui_component::input::InputState;
|
||||||
use gpui_component::{ActiveTheme, Icon, IconName, Sizable, StyledExt, h_flex, v_flex};
|
use gpui_component::{ActiveTheme, Icon, IconName, Sizable, StyledExt, h_flex, v_flex};
|
||||||
|
use nostr::nips::nip01::Coordinate;
|
||||||
use signed_core::{Announcement, identifier_from_name};
|
use signed_core::{Announcement, identifier_from_name};
|
||||||
use signed_state::{
|
use signed_state::{
|
||||||
Backend, BackendEvent, CheckoutsStore, LocalReposStore, Profile, ProfileStore, RepoListStore,
|
Backend, BackendEvent, CheckoutsStore, LocalReposStore, Profile, ProfileStore, RepoListStore,
|
||||||
};
|
};
|
||||||
use signed_ui::{CountBadge, NavItem, PixelAvatar, UserAvatar, title_bar_drag_handlers};
|
use signed_ui::{NavItem, PixelAvatar, UserAvatar, title_bar_drag_handlers};
|
||||||
|
|
||||||
use super::{RepoDetailView, RepoListView, open_repo_panel};
|
use super::{RepoDetailView, RepoListView, open_repo_panel};
|
||||||
|
|
||||||
@@ -33,32 +35,22 @@ mod settings_dialog;
|
|||||||
|
|
||||||
use self::onboarding_dialog::OnboardingState;
|
use self::onboarding_dialog::OnboardingState;
|
||||||
|
|
||||||
/// Left-dock panel with navigation entries.
|
|
||||||
/// Entries open content panels in the dock area.
|
|
||||||
pub struct SidebarPanel {
|
pub struct SidebarPanel {
|
||||||
focus_handle: FocusHandle,
|
focus_handle: FocusHandle,
|
||||||
dock_area: WeakEntity<DockArea>,
|
dock_area: WeakEntity<DockArea>,
|
||||||
explore: Option<WeakEntity<RepoListView>>,
|
explore: Option<WeakEntity<RepoListView>>,
|
||||||
logged_in: bool,
|
logged_in: bool,
|
||||||
/// Repositories the current user announced, listed under the All Repositories heading.
|
/// Repositories the current user announced, listed under the All Repositories heading.
|
||||||
/// Recreated when the signer changes.
|
repos: Option<Entity<RepoListStore>>,
|
||||||
my_repos: Option<Entity<RepoListStore>>,
|
|
||||||
/// Observes the current user's repo store so the list re-renders.
|
/// Observes the current user's repo store so the list re-renders.
|
||||||
my_repos_subscription: Option<Subscription>,
|
repos_subscription: Option<Subscription>,
|
||||||
/// Banner artwork behind the sign-in screen.
|
/// Banner artwork behind the sign-in screen.
|
||||||
/// Picked at random from the bundled `backgrounds/` assets.
|
|
||||||
banner: SharedString,
|
banner: SharedString,
|
||||||
/// Observes the local-repository scan so new discoveries re-render.
|
|
||||||
_local_repos_subscription: Subscription,
|
|
||||||
/// Observes the checkouts store.
|
|
||||||
/// Its ready-to-push statuses feed the badges on the user's repo rows.
|
|
||||||
_checkouts_subscription: Subscription,
|
|
||||||
_subscription: Subscription,
|
_subscription: Subscription,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SidebarPanel {
|
impl SidebarPanel {
|
||||||
pub fn new(dock_area: WeakEntity<DockArea>, cx: &mut Context<Self>) -> Self {
|
pub fn new(dock_area: WeakEntity<DockArea>, cx: &mut Context<Self>) -> Self {
|
||||||
let local_repos_store = LocalReposStore::global(cx);
|
|
||||||
let backend = Backend::global(cx);
|
let backend = Backend::global(cx);
|
||||||
let logged_in = backend.read(cx).current_user().is_some();
|
let logged_in = backend.read(cx).current_user().is_some();
|
||||||
|
|
||||||
@@ -66,70 +58,60 @@ impl SidebarPanel {
|
|||||||
match event {
|
match event {
|
||||||
BackendEvent::SignerChanged => {
|
BackendEvent::SignerChanged => {
|
||||||
this.logged_in = backend.read(cx).current_user().is_some();
|
this.logged_in = backend.read(cx).current_user().is_some();
|
||||||
this.refresh_my_repos(cx);
|
this.refresh_repos(cx);
|
||||||
}
|
}
|
||||||
BackendEvent::SignerRequired => {
|
BackendEvent::SignerRequired => {
|
||||||
this.logged_in = false;
|
this.logged_in = false;
|
||||||
this.banner = pick_banner();
|
this.banner = pick_banner();
|
||||||
this.my_repos = None;
|
this.repos = None;
|
||||||
this.my_repos_subscription = None;
|
this.repos_subscription = None;
|
||||||
}
|
}
|
||||||
_ => return,
|
_ => return,
|
||||||
}
|
}
|
||||||
cx.notify();
|
cx.notify();
|
||||||
});
|
});
|
||||||
|
|
||||||
let local_repos_subscription = cx.observe(&local_repos_store, |_, _, cx| {
|
|
||||||
cx.notify();
|
|
||||||
});
|
|
||||||
|
|
||||||
let checkouts_store = CheckoutsStore::global(cx);
|
|
||||||
let checkouts_subscription = cx.observe(&checkouts_store, |_, _, cx| {
|
|
||||||
cx.notify();
|
|
||||||
});
|
|
||||||
|
|
||||||
let mut panel = Self {
|
let mut panel = Self {
|
||||||
focus_handle: cx.focus_handle(),
|
focus_handle: cx.focus_handle(),
|
||||||
dock_area,
|
dock_area,
|
||||||
logged_in,
|
logged_in,
|
||||||
explore: None,
|
explore: None,
|
||||||
my_repos: None,
|
repos: None,
|
||||||
my_repos_subscription: None,
|
repos_subscription: None,
|
||||||
banner: pick_banner(),
|
banner: pick_banner(),
|
||||||
_local_repos_subscription: local_repos_subscription,
|
|
||||||
_checkouts_subscription: checkouts_subscription,
|
|
||||||
_subscription: subscription,
|
_subscription: subscription,
|
||||||
};
|
};
|
||||||
|
|
||||||
if logged_in {
|
if logged_in {
|
||||||
panel.refresh_my_repos(cx);
|
panel.refresh_repos(cx);
|
||||||
|
cx.notify();
|
||||||
}
|
}
|
||||||
|
|
||||||
panel
|
panel
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Recreate the store listing the current user's repositories.
|
/// Recreate the store listing the current user's repositories.
|
||||||
|
///
|
||||||
/// Watch each repository for unpushed local work.
|
/// Watch each repository for unpushed local work.
|
||||||
fn refresh_my_repos(&mut self, cx: &mut Context<Self>) {
|
fn refresh_repos(&mut self, cx: &mut Context<Self>) {
|
||||||
self.my_repos_subscription = None;
|
self.repos_subscription = None;
|
||||||
|
|
||||||
|
let checkouts = CheckoutsStore::global(cx);
|
||||||
let backend = Backend::global(cx);
|
let backend = Backend::global(cx);
|
||||||
let author = backend.read(cx).current_user();
|
let author = backend.read(cx).current_user();
|
||||||
self.my_repos = author.map(|author| cx.new(|cx| RepoListStore::new(Some(author), cx)));
|
|
||||||
|
|
||||||
if let Some(store) = self.my_repos.as_ref() {
|
// Create a new repo list store for the signed-in user, if they are logged in.
|
||||||
self.my_repos_subscription = Some(cx.observe(store, |_this, store, cx| {
|
self.repos = author.map(|author| cx.new(|cx| RepoListStore::new(Some(author), cx)));
|
||||||
cx.notify();
|
|
||||||
// These are the signed-in user's own repositories.
|
if let Some(store) = self.repos.as_ref() {
|
||||||
// Request their ready-to-push statuses, deduplicated per repository.
|
self.repos_subscription = Some(cx.observe(store, move |_, store, cx| {
|
||||||
// The rows carry a badge while local work is unpushed.
|
let addrs: Vec<Coordinate> = store
|
||||||
let addrs: Vec<_> = store
|
|
||||||
.read(cx)
|
.read(cx)
|
||||||
.announcements
|
.announcements
|
||||||
.iter()
|
.iter()
|
||||||
.map(|a| a.addr())
|
.map(|a| a.addr())
|
||||||
.collect();
|
.collect();
|
||||||
let checkouts = CheckoutsStore::global(cx);
|
|
||||||
checkouts.update(cx, |checkouts, cx| {
|
checkouts.update(cx, |checkouts, cx| {
|
||||||
for addr in addrs {
|
for addr in addrs {
|
||||||
checkouts.request_push_statuses(&addr, cx);
|
checkouts.request_push_statuses(&addr, cx);
|
||||||
@@ -193,22 +175,21 @@ impl SidebarPanel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Open a local repository's detail view in the dock's center.
|
/// Open a local repository's detail view in the dock's center.
|
||||||
|
///
|
||||||
/// The detail view offers to publish it to NIP-34.
|
/// The detail view offers to publish it to NIP-34.
|
||||||
fn open_local_repo(&mut self, path: PathBuf, window: &mut Window, cx: &mut Context<Self>) {
|
fn open_local_repo(&mut self, path: PathBuf, window: &mut Window, cx: &mut Context<Self>) {
|
||||||
let detail =
|
let detail =
|
||||||
cx.new(|cx| RepoDetailView::new_local(self.dock_area.clone(), path, window, cx));
|
cx.new(|cx| RepoDetailView::new_local(self.dock_area.clone(), path, window, cx));
|
||||||
|
|
||||||
let _ = self.dock_area.update(cx, |dock_area, cx| {
|
self.dock_area
|
||||||
|
.update(cx, |dock_area, cx| {
|
||||||
add_center_panel(dock_area, panel_handle(detail), window, cx);
|
add_center_panel(dock_area, panel_handle(detail), window, cx);
|
||||||
});
|
})
|
||||||
|
.ok();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The All Repositories section of the sidebar.
|
fn render_repos(&self, cx: &mut Context<Self>) -> impl IntoElement {
|
||||||
/// A header with the create button above the current user's repositories.
|
let store = self.repos.as_ref();
|
||||||
/// Rendered lazily through a [`uniform_list`].
|
|
||||||
/// Followed by local git repositories from the startup scan.
|
|
||||||
fn render_my_repos(&self, cx: &mut Context<Self>) -> impl IntoElement {
|
|
||||||
let store = self.my_repos.as_ref();
|
|
||||||
let local = LocalReposStore::global(cx);
|
let local = LocalReposStore::global(cx);
|
||||||
let local_repos = local.read(cx).repos.clone();
|
let local_repos = local.read(cx).repos.clone();
|
||||||
let scanning = local.read(cx).scanning;
|
let scanning = local.read(cx).scanning;
|
||||||
@@ -260,22 +241,19 @@ impl SidebarPanel {
|
|||||||
)
|
)
|
||||||
.when_some(store, |builder, store| {
|
.when_some(store, |builder, store| {
|
||||||
let announcements = store.read(cx).announcements.clone();
|
let announcements = store.read(cx).announcements.clone();
|
||||||
// Local repositories already published to NIP-34 appear above.
|
let ids: HashSet<String> = announcements.iter().map(|a| a.id.clone()).collect();
|
||||||
// Hide them from the local section here.
|
|
||||||
// Matched by the identifier derived from the directory name.
|
|
||||||
// Same derivation as the init dialog's default name.
|
|
||||||
let announced_ids: HashSet<String> =
|
|
||||||
announcements.iter().map(|a| a.id.clone()).collect();
|
|
||||||
let local_repos: Vec<PathBuf> = local_repos
|
let local_repos: Vec<PathBuf> = local_repos
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|path| {
|
.filter(|path| {
|
||||||
let Some(name) = path.file_name() else {
|
let Some(name) = path.file_name() else {
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
!announced_ids.contains(&identifier_from_name(&name.to_string_lossy()))
|
!ids.contains(&identifier_from_name(&name.to_string_lossy()))
|
||||||
})
|
})
|
||||||
.cloned()
|
.cloned()
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
// One merged list, the user's NIP-34 repositories first.
|
// One merged list, the user's NIP-34 repositories first.
|
||||||
// Local repositories discovered by the scan follow.
|
// Local repositories discovered by the scan follow.
|
||||||
let total = announcements.len() + local_repos.len();
|
let total = announcements.len() + local_repos.len();
|
||||||
@@ -288,10 +266,12 @@ impl SidebarPanel {
|
|||||||
.py_1()
|
.py_1()
|
||||||
.text_xs()
|
.text_xs()
|
||||||
.text_color(cx.theme().muted_foreground)
|
.text_color(cx.theme().muted_foreground)
|
||||||
.child(if scanning {
|
.map(|this| {
|
||||||
"Scanning for local repositories…"
|
if scanning {
|
||||||
|
this.child("Scanning for local repositories…")
|
||||||
} else {
|
} else {
|
||||||
"No repositories yet"
|
this.child("No repositories yet")
|
||||||
|
}
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
@@ -299,15 +279,10 @@ impl SidebarPanel {
|
|||||||
uniform_list(
|
uniform_list(
|
||||||
"repos",
|
"repos",
|
||||||
total,
|
total,
|
||||||
cx.processor(move |this, range: Range<usize>, _window, cx| {
|
cx.processor(move |this, range: Range<usize>, _, cx| {
|
||||||
range
|
range
|
||||||
.map(|ix| {
|
.map(|ix| {
|
||||||
this.render_repo_row_at(
|
this.render_repo_at(&announcements, &local_repos, ix, cx)
|
||||||
&announcements,
|
|
||||||
&local_repos,
|
|
||||||
ix,
|
|
||||||
cx,
|
|
||||||
)
|
|
||||||
.into_any_element()
|
.into_any_element()
|
||||||
})
|
})
|
||||||
.collect()
|
.collect()
|
||||||
@@ -321,7 +296,7 @@ impl SidebarPanel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// One row of the merged sidebar list, a NIP-34 or a local repository.
|
/// One row of the merged sidebar list, a NIP-34 or a local repository.
|
||||||
fn render_repo_row_at(
|
fn render_repo_at(
|
||||||
&self,
|
&self,
|
||||||
announcements: &[Announcement],
|
announcements: &[Announcement],
|
||||||
local_repos: &[PathBuf],
|
local_repos: &[PathBuf],
|
||||||
@@ -345,27 +320,24 @@ impl SidebarPanel {
|
|||||||
announcement: &Announcement,
|
announcement: &Announcement,
|
||||||
cx: &mut Context<Self>,
|
cx: &mut Context<Self>,
|
||||||
) -> impl IntoElement {
|
) -> impl IntoElement {
|
||||||
let name = announcement
|
let name = announcement.name().map(SharedString::from);
|
||||||
.name
|
|
||||||
.as_deref()
|
|
||||||
.map(SharedString::from)
|
|
||||||
.unwrap_or_else(|| SharedString::from(announcement.id.clone()));
|
|
||||||
let avatar = PixelAvatar::new(format!("{}:{}", announcement.owner, announcement.id));
|
let avatar = PixelAvatar::new(format!("{}:{}", announcement.owner, announcement.id));
|
||||||
|
let announcement = announcement.clone();
|
||||||
|
|
||||||
// Badge with the unpushed commit count of the repository's local checkouts.
|
// Badge with the unpushed commit count of the repository's local checkouts.
|
||||||
// The commits are ready to push to the grasp servers.
|
// The commits are ready to push to the grasp servers.
|
||||||
let unpushed: usize = CheckoutsStore::global(cx)
|
let checkout = CheckoutsStore::global(cx);
|
||||||
|
let unpushed = checkout
|
||||||
.read(cx)
|
.read(cx)
|
||||||
.push_statuses_of(&announcement.addr())
|
.push_statuses_of(&announcement.addr())
|
||||||
.iter()
|
.iter()
|
||||||
.map(|status| status.ahead as usize)
|
.map(|status| status.ahead as usize)
|
||||||
.sum();
|
.sum();
|
||||||
|
|
||||||
let announcement = announcement.clone();
|
let mut row = NavItem::new(format!("repo:{}", announcement.id), name, avatar);
|
||||||
let mut row = NavItem::new(format!("my-repo:{}", announcement.id), name, avatar);
|
|
||||||
|
|
||||||
if unpushed > 0 {
|
if unpushed > 0 {
|
||||||
row = row.suffix(CountBadge::new(unpushed));
|
row = row.suffix(Badge::new().count(unpushed).xsmall());
|
||||||
}
|
}
|
||||||
|
|
||||||
row.on_click(
|
row.on_click(
|
||||||
@@ -373,21 +345,18 @@ impl SidebarPanel {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// One local repository row, a deterministic pixel avatar seeded from the path.
|
/// One local repository row.
|
||||||
|
///
|
||||||
/// The directory name and a warning suffix, the repo is not yet set up for NIP-34.
|
/// The directory name and a warning suffix, the repo is not yet set up for NIP-34.
|
||||||
/// Clicking opens the detail view, which offers to initialize it.
|
|
||||||
fn render_local_row(&self, path: &Path, cx: &mut Context<Self>) -> impl IntoElement {
|
fn render_local_row(&self, path: &Path, cx: &mut Context<Self>) -> impl IntoElement {
|
||||||
let name = path
|
let name = path
|
||||||
.file_name()
|
.file_name()
|
||||||
.map(|name| name.to_string_lossy().into_owned())
|
.map(|name| name.to_string_lossy().into_owned())
|
||||||
.unwrap_or_else(|| path.display().to_string());
|
.unwrap_or_else(|| path.display().to_string());
|
||||||
let path = path.to_path_buf();
|
let path = path.to_path_buf();
|
||||||
|
let avatar = PixelAvatar::new(path.to_string_lossy());
|
||||||
|
|
||||||
NavItem::new(
|
NavItem::new(format!("local-repo:{}", path.display()), name, avatar)
|
||||||
format!("local-repo:{}", path.display()),
|
|
||||||
name,
|
|
||||||
PixelAvatar::new(path.to_string_lossy()),
|
|
||||||
)
|
|
||||||
.suffix(
|
.suffix(
|
||||||
Icon::new(IconName::TriangleAlert)
|
Icon::new(IconName::TriangleAlert)
|
||||||
.small()
|
.small()
|
||||||
@@ -434,7 +403,6 @@ impl SidebarPanel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Sign-in placeholder shown while logged out.
|
/// Sign-in placeholder shown while logged out.
|
||||||
/// Banner artwork behind a scrim keeps the CTA buttons readable in both themes.
|
|
||||||
fn render_sign_in(&self, window: &mut Window, cx: &mut Context<Self>) -> Div {
|
fn render_sign_in(&self, window: &mut Window, cx: &mut Context<Self>) -> Div {
|
||||||
v_flex()
|
v_flex()
|
||||||
.size_full()
|
.size_full()
|
||||||
@@ -598,7 +566,7 @@ impl Render for SidebarPanel {
|
|||||||
)),
|
)),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
.child(self.render_my_repos(cx)),
|
.child(self.render_repos(cx)),
|
||||||
)
|
)
|
||||||
.child(
|
.child(
|
||||||
v_flex()
|
v_flex()
|
||||||
|
|||||||
@@ -267,23 +267,14 @@ impl SettingsControls {
|
|||||||
/// Open the Settings dialog.
|
/// Open the Settings dialog.
|
||||||
pub fn open(window: &mut Window, cx: &mut App) {
|
pub fn open(window: &mut Window, cx: &mut App) {
|
||||||
let controls = Rc::new(SettingsControls::new(window, cx));
|
let controls = Rc::new(SettingsControls::new(window, cx));
|
||||||
let store = SettingsStore::global(cx);
|
|
||||||
let window_handle = window.window_handle();
|
|
||||||
let store_subscription = cx.observe(&store, move |_, cx| {
|
|
||||||
window_handle
|
|
||||||
.update(cx, |_, window, _| window.refresh())
|
|
||||||
.ok();
|
|
||||||
});
|
|
||||||
|
|
||||||
let dialog_state = Rc::new((controls, store_subscription));
|
|
||||||
|
|
||||||
window.open_dialog(cx, move |dialog, _window, cx| {
|
window.open_dialog(cx, move |dialog, _window, cx| {
|
||||||
let dialog_state = dialog_state.clone();
|
let controls = controls.clone();
|
||||||
dialog
|
dialog
|
||||||
.title("Settings")
|
.title("Settings")
|
||||||
.width(px(650.))
|
.width(px(650.))
|
||||||
.h(px(560.))
|
.h(px(560.))
|
||||||
.child(settings_view(&dialog_state.0, cx))
|
.child(settings_view(&controls, cx))
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user