refactor 3

This commit is contained in:
2026-09-13 13:00:20 +07:00
parent 025fd15837
commit f8277e4c2e
11 changed files with 451 additions and 303 deletions
@@ -151,35 +151,37 @@ impl PullRequestDetailView {
let binding = {
let store = self.store.read(cx);
store
.pull_requests
.iter()
.find(|pr| pr.id == self.pr_id && pr.kind == Kind::GitPullRequest)
.map(|root| {
let update = latest_update(store.pull_requests.iter(), root);
store.addr().and_then(|addr| {
store
.pull_requests
.iter()
.find(|pr| pr.id == self.pr_id && pr.kind == Kind::GitPullRequest)
.map(|root| {
let update = latest_update(store.pull_requests.iter(), root);
let tip = update
.and_then(current_commit_of)
.or_else(|| current_commit_of(root));
let tip = update
.and_then(current_commit_of)
.or_else(|| current_commit_of(root));
let base = update
.and_then(merge_base_of)
.or_else(|| merge_base_of(root));
let base = update
.and_then(merge_base_of)
.or_else(|| merge_base_of(root));
let clone_urls = clone_urls_of(root)
.or_else(|| store.announcement.as_ref().map(|a| a.clone.clone()))
.unwrap_or_default();
let clone_urls = clone_urls_of(root)
.or_else(|| store.announcement.as_ref().map(|a| a.clone.clone()))
.unwrap_or_default();
PrBinding {
description: root.content.clone(),
patch: pull_request_patch(root, store.patches.iter()),
tip,
base,
clone_urls,
addr: store.addr().clone(),
has_patch_link: root.tags.event_ids().next().is_some(),
}
})
PrBinding {
description: root.content.clone(),
patch: pull_request_patch(root, store.patches.iter()),
tip,
base,
clone_urls,
addr: addr.clone(),
has_patch_link: root.tags.event_ids().next().is_some(),
}
})
})
};
let Some(binding) = binding else {
+40 -26
View File
@@ -305,7 +305,24 @@ impl NewPullRequestView {
),
];
let mut view = Self {
cx.defer_in(window, |this, window, cx| {
let Some(addr) = this.store.read(cx).addr().cloned() else {
return;
};
let Some(path) = CheckoutsStore::global(cx)
.read(cx)
.associations_of(&addr)
.into_iter()
.next()
else {
return;
};
this.apply_folder_path(path, window, cx);
});
Self {
focus_handle: cx.focus_handle(),
dock_area,
store,
@@ -330,20 +347,7 @@ impl NewPullRequestView {
scroll_handle: VirtualListScrollHandle::new(),
item_sizes: Rc::new(Vec::new()),
_subscriptions: subscriptions,
};
// Prefill with the store's freshest associated checkout, no folder dialog.
let addr = view.store.read(cx).addr().clone();
if let Some(path) = CheckoutsStore::global(cx)
.read(cx)
.associations_of(&addr)
.into_iter()
.next()
{
view.apply_folder_path(path, window, cx);
}
view
}
/// Whether a compare source, a checkout or a fork, is applied.
@@ -496,11 +500,12 @@ impl NewPullRequestView {
// Remember this folder as a checkout of the target repository.
// The next panel pre-fills it.
let addr = self.store.read(cx).addr().clone();
let checkout_store = CheckoutsStore::global(cx);
checkout_store.update(cx, |store, cx| {
store.record(PathBuf::from(&path), addr, cx);
});
if let Some(addr) = self.store.read(cx).addr().cloned() {
let checkout_store = CheckoutsStore::global(cx);
checkout_store.update(cx, |store, cx| {
store.record(PathBuf::from(&path), addr, cx);
});
}
let branches = self.branches.clone();
let base = SharedString::from(base.clone());
@@ -524,18 +529,21 @@ impl NewPullRequestView {
/// The base repository of the panel, its address and announced EUC.
///
/// Used to find fork candidates.
fn base_repo(&self, cx: &App) -> (RepoAddr, Option<String>) {
/// Used to find fork candidates. `None` while the repository is not announced.
fn base_repo(&self, cx: &App) -> Option<(RepoAddr, Option<String>)> {
let store = self.store.read(cx);
let addr = store.addr()?.clone();
let euc = store.announcement.as_ref().and_then(|a| a.euc.clone());
(store.addr().clone(), euc)
Some((addr, euc))
}
/// Announced forks of the target repository a compare can use, own first.
///
/// Re-read whenever the picker opens.
fn fork_candidates(&self, cx: &App) -> Vec<Announcement> {
let (base, euc) = self.base_repo(cx);
let Some((base, euc)) = self.base_repo(cx) else {
return Vec::new();
};
let user = Backend::global(cx).read(cx).current_user();
let announcements = RepoListStore::global(cx).read(cx).announcements.clone();
fork_candidates(&announcements, &base, euc.as_deref(), user)
@@ -556,7 +564,9 @@ impl NewPullRequestView {
.as_ref()
.is_some_and(|fork| fork.announcement.addr() == announcement.addr());
let (base, _euc) = self.base_repo(cx);
let Some((base, _euc)) = self.base_repo(cx) else {
return;
};
let cache = GitStore::global(cx).cache().clone();
let mirror_path = cache.repo_path(&base);
let namespace = fork_namespace(&announcement);
@@ -1124,8 +1134,12 @@ impl NewPullRequestView {
cx: &Context<Self>,
) -> impl Fn(PopupMenu, &mut Window, &mut Context<PopupMenu>) -> PopupMenu + 'static {
let view = cx.entity().downgrade();
let addr = self.store.read(cx).addr().clone();
let associated = CheckoutsStore::global(cx).read(cx).associations_of(&addr);
let associated = self
.store
.read(cx)
.addr()
.map(|addr| CheckoutsStore::global(cx).read(cx).associations_of(addr))
.unwrap_or_default();
let active_path = (self.fork.is_none())
.then(|| self.repo_path.clone())
+13 -21
View File
@@ -20,14 +20,10 @@ use crate::views::repo::init_dialog;
impl RepoDetailView {
/// Re-push the repository's refs to its announced grasp servers.
pub(super) fn push_repository(&mut self, _window: &mut Window, cx: &mut Context<Self>) {
let Some(store) = self.store.clone() else {
return;
};
self.error = None;
cx.notify();
store
self.store
.update(cx, |store, cx| store.push_repository(cx))
.detach();
}
@@ -39,9 +35,7 @@ impl RepoDetailView {
window: &mut Window,
cx: &mut Context<Self>,
) {
let Some(store) = self.store.clone() else {
return;
};
let store = self.store.clone();
if store.read(cx).pushing {
return;
@@ -72,23 +66,22 @@ impl RepoDetailView {
/// Delete the repository from nostr, announcement, state and activity.
pub(super) fn delete_repository(&mut self, _window: &mut Window, cx: &mut Context<Self>) {
let Some(store) = self.store.clone() else {
return;
};
store
self.store
.update(cx, |store, cx| store.delete_repository(cx))
.detach();
}
/// Open the issues list panel in the dock area.
pub(super) fn open_issue_detail(&mut self, window: &mut Window, cx: &mut Context<Self>) {
let Some(store) = self.store.clone() else {
if self.store.read(cx).addr().is_none() {
return;
};
}
let Some(dock_area) = self.dock_area.upgrade() else {
return;
};
let store = self.store.clone();
let panel = cx.new(|cx| IssuesView::new(self.dock_area.clone(), store, window, cx));
dock_area.update(cx, |dock_area, cx| {
@@ -98,13 +91,15 @@ impl RepoDetailView {
/// Open the pull requests list panel in the dock area.
pub(super) fn open_pull_request_detail(&mut self, window: &mut Window, cx: &mut Context<Self>) {
let Some(store) = self.store.clone() else {
if self.store.read(cx).addr().is_none() {
return;
};
}
let Some(dock_area) = self.dock_area.upgrade() else {
return;
};
let store = self.store.clone();
let panel = cx.new(|cx| PullRequestsView::new(self.dock_area.clone(), store, window, cx));
dock_area.update(cx, |dock_area, cx| {
@@ -131,7 +126,7 @@ impl RepoDetailView {
/// Open the dialog guiding the user through publishing the local repository to NIP-34.
pub(super) fn open_init_dialog(&mut self, window: &mut Window, cx: &mut Context<Self>) {
let Some(local_path) = self.local_path.clone() else {
let Some(local_path) = self.store.read(cx).path.clone() else {
return;
};
let view = cx.entity().downgrade();
@@ -170,10 +165,7 @@ pub(crate) fn open_repo_panel(
/// relays to connect to right away; the store loads the announcement from the
/// local database on its first pass, so the hint is optional.
fn repo_store(addr: &RepoAddr, hint: Option<&Announcement>, cx: &mut App) -> Entity<RepoStore> {
let relays = hint
.map(|announcement| announcement.relays.clone())
.unwrap_or_default();
cx.new(|cx| RepoStore::new(addr.clone(), relays, cx))
cx.new(|cx| RepoStore::new(addr.clone(), hint.cloned(), cx))
}
/// An item of a repository to open from outside its detail panel.
+20 -28
View File
@@ -17,14 +17,15 @@ impl RepoDetailView {
/// The repository's own checkouts are not suggested here.
/// Their work is pushed, see [`Self::push_suggestion`].
fn ready_suggestion(&self, cx: &App) -> Option<CheckoutStatus> {
let store = self.store.as_ref()?;
let addr = store.read(cx).addr().clone();
let store = self.store.read(cx);
let addr = store.addr()?;
let user = Backend::global(cx).read(cx).current_user()?;
if store.read(cx).is_author(&user) {
if store.is_author(&user) {
return None;
}
let statuses = CheckoutsStore::global(cx).read(cx).ready_statuses_of(&addr);
let statuses = CheckoutsStore::global(cx).read(cx).ready_statuses_of(addr);
'status: for status in statuses {
if self
@@ -33,7 +34,6 @@ impl RepoDetailView {
{
continue;
}
let store = store.read(cx);
for pr in &store.pull_requests {
if pr_proposes_checkout(pr, store.status_of(pr) == RepoStatus::Open, user, &status)
{
@@ -50,15 +50,15 @@ impl RepoDetailView {
///
/// Not dismissed in this panel.
fn push_suggestion(&self, cx: &App) -> Option<CheckoutStatus> {
let entity = self.store.as_ref()?;
let store = self.store.read(cx);
let addr = store.addr()?;
let user = Backend::global(cx).read(cx).current_user()?;
if !entity.read(cx).is_author(&user) {
if !store.is_author(&user) {
return None;
}
let addr = entity.read(cx).addr().clone();
let statuses = CheckoutsStore::global(cx).read(cx).push_statuses_of(&addr);
let statuses = CheckoutsStore::global(cx).read(cx).push_statuses_of(addr);
statuses.into_iter().find(|status| {
!self
@@ -75,10 +75,7 @@ impl RepoDetailView {
let key = (status.path.clone(), status.branch.clone());
let path = status.path.clone();
// The push busy flag lives on the store; it disables the banner's triggers.
let pushing = self
.store
.as_ref()
.is_some_and(|store| store.read(cx).pushing);
let pushing = self.store.read(cx).pushing;
let commits = if status.ahead == 1 {
SharedString::from("1 commit")
@@ -160,8 +157,7 @@ impl RepoDetailView {
/// Warning after a push that only some grasp servers accepted.
pub(super) fn render_push_warning_banner(&self, cx: &Context<Self>) -> Option<AnyElement> {
let store = self.store.as_ref()?;
let store = store.read(cx);
let store = self.store.read(cx);
let warning = store.last_push_warning.clone()?;
let pushing = store.pushing;
@@ -213,11 +209,9 @@ impl RepoDetailView {
.ghost()
.disabled(pushing)
.on_click(cx.listener(|this, _ev, _window, cx| {
if let Some(store) = this.store.clone() {
store.update(cx, |store, _| {
store.last_push_warning = None;
});
}
this.store.update(cx, |store, _| {
store.last_push_warning = None;
});
cx.notify();
})),
),
@@ -299,14 +293,12 @@ impl RepoDetailView {
.small()
.info()
.on_click(cx.listener(|this, _event, window, cx| {
if let Some(store) = this.store.clone() {
open_new_pull_panel(
this.dock_area.clone(),
store,
window,
cx,
);
}
open_new_pull_panel(
this.dock_area.clone(),
this.store.clone(),
window,
cx,
);
})),
)
.child(
+14 -17
View File
@@ -27,15 +27,11 @@ impl RepoDetailView {
/// The NIP-34 header, actions and issues/PR counts.
/// Or the local header with an Init button for an unpublished repository.
pub(super) fn render_header(&mut self, cx: &mut Context<Self>) -> AnyElement {
if self.local_path.is_some() {
if self.store.read(cx).addr().is_none() {
return self.render_local_header(cx);
}
let Some(store_entity) = self.store.as_ref() else {
return div().into_any_element();
};
let store = store_entity.read(cx);
let store = self.store.read(cx);
let issue_count = SharedString::from(store.issue_count().to_string());
let pr_count = SharedString::from(store.pull_request_count().to_string());
@@ -43,7 +39,7 @@ impl RepoDetailView {
let pushing = store.pushing;
let cloning = store.cloning;
let Some(source) = store.announcement.as_ref().or(self.initial.as_ref()) else {
let Some(source) = store.announcement.as_ref() else {
return div().into_any_element();
};
@@ -73,19 +69,18 @@ impl RepoDetailView {
.on_action(
cx.listener(|this, action: &RepoAction, window, cx| match action {
RepoAction::NewIssue => {
if let Some(store) = this.store.clone() {
open_new_issue_dialog(store, window, cx);
}
open_new_issue_dialog(this.store.clone(), window, cx);
}
RepoAction::NewPR => {
if let Some(store) = this.store.clone() {
open_new_pull_panel(this.dock_area.clone(), store, window, cx);
}
open_new_pull_panel(this.dock_area.clone(), this.store.clone(), window, cx);
}
RepoAction::SendPatch => {
if let Some(store) = this.store.clone() {
open_send_patch_panel(this.dock_area.clone(), store, window, cx);
}
open_send_patch_panel(
this.dock_area.clone(),
this.store.clone(),
window,
cx,
);
}
RepoAction::About => {
if let Some(announcement) = this.announcement(cx) {
@@ -421,7 +416,9 @@ impl RepoDetailView {
fn render_local_header(&self, cx: &mut Context<Self>) -> AnyElement {
let name = self.display_name(cx);
let path = self
.local_path
.store
.read(cx)
.path
.as_ref()
.map(|path| path.display().to_string())
.unwrap_or_default();
@@ -190,7 +190,7 @@ fn init_repository(
window.close_dialog(cx);
if let Some(view) = view.upgrade() {
view.update(cx, |this, cx| {
this.apply_announcement(announcement, window, cx);
this.apply_announcement(announcement, cx);
});
}
})
+21 -7
View File
@@ -39,9 +39,24 @@ impl RepoDetailView {
self.error = None;
cx.notify();
let (addr, announcement, local_path) = {
let store = self.store.read(cx);
(
store.addr().cloned(),
store.announcement.clone(),
store.path.clone(),
)
};
// Local repositories live on disk at their scan path.
// No clone step or network refresh applies here.
if let Some(local_path) = self.local_path.clone() {
if addr.is_none() {
self.repo_started = true;
let Some(local_path) = local_path else {
return;
};
let task: gpui::Task<Result<(), Error>> = cx.spawn_in(window, async move |this, cx| {
let data = cx
.background_spawn(async move {
@@ -67,13 +82,14 @@ impl RepoDetailView {
return;
}
let Some(initial) = self.initial.as_ref() else {
let Some(announcement) = announcement else {
return;
};
self.repo_started = true;
let cache = GitStore::global(cx).cache().clone();
let addr = initial.addr();
let clone_urls: Vec<Url> = initial.clone.clone();
let addr = announcement.addr();
let clone_urls: Vec<Url> = announcement.clone.clone();
// Captured before the loads start.
// A branch/tag switch bumps the generation, discarding the refresh below.
@@ -324,9 +340,7 @@ impl RepoDetailView {
/// Clone the repository into a user-chosen folder outside the cache.
pub(super) fn clone_to_folder(&mut self, window: &mut Window, cx: &mut Context<Self>) {
let Some(store) = self.store.clone() else {
return;
};
let store = self.store.clone();
let name = {
let Some(announcement) = self.announcement(cx) else {
+45 -53
View File
@@ -71,19 +71,14 @@ pub struct RepoDetailView {
///
/// New panels, commit diffs, are added there.
dock_area: WeakEntity<DockArea>,
/// Snapshot taken at open time.
/// Per-repository store, holding the local path and the announcement,
/// issues, PRs and statuses. The single identity of both modes.
store: Entity<RepoStore>,
/// The initial explorer load has been started.
///
/// `None` for local repositories that haven't been published yet, and for a
/// repository opened by address until its store loads the announcement.
initial: Option<Announcement>,
/// Per-repository nostr store, holding announcement, issues, PRs and statuses.
///
/// `None` until a local repository is initialized to NIP-34.
store: Option<Entity<RepoStore>>,
/// Path of the local repository when opened from the scan.
///
/// `None` once it is initialized to NIP-34, or for announced repositories.
local_path: Option<PathBuf>,
/// A repository opened by address alone starts without an announcement; the
/// store observer starts the load once the first one lands.
repo_started: bool,
/// File explorer state, the worktree of the local clone.
tree_state: Entity<TreeState>,
/// Root of the local clone, for reading files on demand.
@@ -178,18 +173,8 @@ impl RepoDetailView {
window: &mut Window,
cx: &mut Context<Self>,
) -> Self {
// The announcement we opened from already carries the NIP-34 `relays` tag.
//
// The store connects to those relays immediately, no bootstrap fetch wait.
let relays = hint
.as_ref()
.map(|announcement| announcement.relays.clone())
.unwrap_or_default();
let store = cx.new(|cx| RepoStore::new(addr, relays, cx));
let mut view = Self::new_common(dock_area, hint, Some(store.clone()), None, window, cx);
view.attach_store(&store, window, cx);
view
let store = cx.new(|cx| RepoStore::new(addr, hint, cx));
Self::new_common(dock_area, store, window, cx)
}
/// Open a local repository discovered by the scan.
@@ -199,7 +184,8 @@ impl RepoDetailView {
window: &mut Window,
cx: &mut Context<Self>,
) -> Self {
Self::new_common(dock_area, None, None, Some(local_path), window, cx)
let store = cx.new(move |_cx| RepoStore::new_local(local_path));
Self::new_common(dock_area, store, window, cx)
}
/// Shared construction.
@@ -207,9 +193,7 @@ impl RepoDetailView {
/// File explorer state, ref selectors and the deferred repository load.
fn new_common(
dock_area: WeakEntity<DockArea>,
initial: Option<Announcement>,
store: Option<Entity<RepoStore>>,
local_path: Option<PathBuf>,
store: Entity<RepoStore>,
window: &mut Window,
cx: &mut Context<Self>,
) -> Self {
@@ -271,11 +255,10 @@ impl RepoDetailView {
this.load_repo(window, cx);
});
Self {
initial,
let mut view = Self {
dock_area,
store,
local_path,
store: store.clone(),
repo_started: false,
tree_state,
worktree: None,
worktree_paths: Vec::new(),
@@ -311,31 +294,40 @@ impl RepoDetailView {
push_statuses: Vec::new(),
focus_handle: cx.focus_handle(),
_subscriptions: subscriptions,
}
};
view.attach_store(&store, window, cx);
view
}
/// The latest announcement from the store or the open-time snapshot.
/// `None` for local repositories that haven't been published yet.
/// The latest announcement of the repository, `None` while local-only or
/// until the store's first pass loads it.
fn announcement<'a>(&'a self, cx: &'a App) -> Option<&'a Announcement> {
let store = self.store.as_ref()?;
store
.read(cx)
.announcement
.as_ref()
.or(self.initial.as_ref())
self.store.read(cx).announcement.as_ref()
}
/// Display name, the announcement's name or ID for announced repositories.
/// The directory name for local ones.
fn display_name(&self, cx: &App) -> SharedString {
if let Some(path) = &self.local_path {
return SharedString::from(
path.file_name()
.map(|name| name.to_string_lossy().into_owned())
.unwrap_or_else(|| path.display().to_string()),
);
let store = self.store.read(cx);
if store.addr().is_none() {
return store
.path
.as_ref()
.map(|path| {
SharedString::from(
path.file_name()
.map(|name| name.to_string_lossy().into_owned())
.unwrap_or_else(|| path.display().to_string()),
)
})
.unwrap_or_default();
}
self.announcement(cx)
store
.announcement
.as_ref()
.map(|announcement| {
announcement
.name
@@ -386,8 +378,10 @@ impl Render for RepoDetailView {
// operations, republish, checkout push, delete and clone-to-folder.
let error = self.error.clone().or_else(|| {
self.store
.as_ref()
.and_then(|store| store.read(cx).last_error.clone().map(SharedString::from))
.read(cx)
.last_error
.clone()
.map(SharedString::from)
});
v_flex()
@@ -405,9 +399,7 @@ impl Render for RepoDetailView {
.banner()
.on_close(cx.listener(|this, _event, _window, cx| {
this.error = None;
if let Some(store) = this.store.clone() {
store.update(cx, |store, _| store.last_error = None);
}
this.store.update(cx, |store, _| store.last_error = None);
cx.notify();
})),
)
+20 -39
View File
@@ -1,4 +1,3 @@
use gpui::prelude::*;
use gpui::{Context, Entity, Window};
use signed_core::Announcement;
use signed_state::{Backend, CheckoutsStore, LocalReposStore, RepoStore};
@@ -6,33 +5,29 @@ use signed_state::{Backend, CheckoutsStore, LocalReposStore, RepoStore};
use super::RepoDetailView;
impl RepoDetailView {
/// Switch the repository into its NIP-34 mode after a successful init.
/// Creates the nostr store for the announced repository.
/// Drops the local scan identity.
/// The worktree is unchanged, so the explorer keeps its loaded content.
/// Switch a local repository into its NIP-34 mode after a successful init.
/// The store is kept, so the panel keeps its path and loaded worktree.
/// Drops the local scan identity so it leaves the sidebar's local section.
pub(crate) fn apply_announcement(
&mut self,
announcement: Announcement,
window: &mut Window,
cx: &mut Context<Self>,
) {
// The repository is no longer a bare local repo.
// Drop it from the scan results so it leaves the sidebar's local section.
if let Some(path) = self.local_path.take() {
let path = self.store.read(cx).path.clone();
if let Some(path) = path {
LocalReposStore::global(cx).update(cx, |store, cx| store.remove(&path, cx));
}
let store =
cx.new(|cx| RepoStore::new(announcement.addr(), announcement.relays.clone(), cx));
// Re-render on store refreshes, issues, PRs and statuses.
// Keep the ready-to-contribute statuses of this repository requested.
self.attach_store(&store, window, cx);
self.store = Some(store);
self.initial = Some(announcement);
self.store
.update(cx, |store, cx| store.announce(announcement, cx));
// The new address needs its ready-to-contribute statuses requested.
self.refresh_ready_statuses(cx);
cx.notify();
}
/// Observe the repository's store, re-render on refreshes.
/// Request the ready-to-contribute statuses for it.
/// Observe the repository's store and re-render on its refreshes.
/// Start the explorer once the store has an announcement.
pub(super) fn attach_store(
&mut self,
store: &Entity<RepoStore>,
@@ -42,18 +37,9 @@ impl RepoDetailView {
self._subscriptions
.push(cx.observe_in(store, window, |this, store, window, cx| {
this.refresh_ready_statuses(cx);
// A repository opened from its address alone starts without an
// announcement. Adopt the store's first one so the explorer can
// load; later passes leave the snapshot and the selection alone.
let announcement = store.read(cx).announcement.clone();
if this.initial.is_none()
&& let Some(announcement) = announcement
{
this.initial = Some(announcement);
if !this.repo_started && store.read(cx).announcement.is_some() {
this.load_repo(window, cx);
}
cx.notify();
}));
self.refresh_ready_statuses(cx);
@@ -64,11 +50,11 @@ impl RepoDetailView {
/// Owned repositories are watched for unpushed commits.
/// Other repositories for ready-to-contribute checkouts.
fn refresh_ready_statuses(&mut self, cx: &mut Context<Self>) {
let Some(entity) = self.store.clone() else {
let Some(addr) = self.store.read(cx).addr().cloned() else {
return;
};
let head = entity.read(cx).head.clone();
let head = self.store.read(cx).head.clone();
if self.ready_requested && self.ready_head == head {
return;
@@ -77,14 +63,13 @@ impl RepoDetailView {
self.ready_requested = true;
self.ready_head = head.clone();
let addr = entity.read(cx).addr().clone();
let backend = Backend::global(cx);
let checkout = CheckoutsStore::global(cx);
let owned = backend
.read(cx)
.current_user()
.is_some_and(|user| entity.read(cx).is_author(&user));
.is_some_and(|user| self.store.read(cx).is_author(&user));
checkout.update(cx, |store, cx| {
// The ready statuses keep the fast poll running while the panel is open.
@@ -97,16 +82,12 @@ impl RepoDetailView {
});
}
/// The ready-to-push statuses of this repository in the global checkouts
/// store changed since they last drove a render.
///
/// Updates the cached slices. `None` store (a local, not yet published,
/// repository) has no statuses.
/// The ready-to-contribute and ready-to-push statuses of this repository.
pub(super) fn refresh_statuses(&mut self, cx: &mut Context<Self>) -> bool {
let Some(entity) = self.store.clone() else {
let Some(addr) = self.store.read(cx).addr().cloned() else {
return false;
};
let addr = entity.read(cx).addr().clone();
let checkouts = CheckoutsStore::global(cx).read(cx);
let ready_statuses = checkouts.ready_statuses_of(&addr);
let push_statuses = checkouts.push_statuses_of(&addr);