refactor 2
This commit is contained in:
@@ -393,16 +393,6 @@ impl InboxView {
|
|||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
let Some(announcement) = RepoListStore::global(cx)
|
|
||||||
.read(cx)
|
|
||||||
.announcements
|
|
||||||
.iter()
|
|
||||||
.find(|announcement| announcement.addr() == address)
|
|
||||||
.cloned()
|
|
||||||
else {
|
|
||||||
return;
|
|
||||||
};
|
|
||||||
|
|
||||||
let item = match kind {
|
let item = match kind {
|
||||||
Some(Kind::GitIssue) => RepoItem::Issue(root),
|
Some(Kind::GitIssue) => RepoItem::Issue(root),
|
||||||
Some(Kind::GitPullRequest) => RepoItem::PullRequest(root),
|
Some(Kind::GitPullRequest) => RepoItem::PullRequest(root),
|
||||||
@@ -410,7 +400,7 @@ impl InboxView {
|
|||||||
_ => return,
|
_ => return,
|
||||||
};
|
};
|
||||||
|
|
||||||
open_repo_item(&self.dock_area, &announcement, item, window, cx);
|
open_repo_item(&self.dock_area, &address, None, item, window, cx);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn render_entry(&self, ix: usize, cx: &Context<Self>) -> AnyElement {
|
fn render_entry(&self, ix: usize, cx: &Context<Self>) -> AnyElement {
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::time::Duration;
|
|
||||||
|
|
||||||
use anyhow::Error;
|
use anyhow::Error;
|
||||||
use dock::{DockArea, add_center_panel, panel_handle};
|
use dock::{DockArea, add_center_panel, panel_handle};
|
||||||
@@ -8,8 +7,8 @@ use gpui::prelude::*;
|
|||||||
use gpui::{App, Context, Entity, WeakEntity, Window};
|
use gpui::{App, Context, Entity, WeakEntity, Window};
|
||||||
use gpui_base::dock::PanelView;
|
use gpui_base::dock::PanelView;
|
||||||
use nostr::prelude::EventId;
|
use nostr::prelude::EventId;
|
||||||
use signed_core::{Announcement, filters};
|
use signed_core::{Announcement, RepoAddr};
|
||||||
use signed_state::{Backend, RepoListStore, RepoStore};
|
use signed_state::RepoStore;
|
||||||
|
|
||||||
use super::RepoDetailView;
|
use super::RepoDetailView;
|
||||||
use crate::views::issues::IssuesView;
|
use crate::views::issues::IssuesView;
|
||||||
@@ -114,74 +113,20 @@ impl RepoDetailView {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Open the upstream repository, the `u` tag of this fork's announcement.
|
/// Open the upstream repository, the `u` tag of this fork's announcement.
|
||||||
/// The upstream announcement may not be in the local database yet.
|
///
|
||||||
/// Subscribe for it and open the panel as soon as it lands.
|
/// The announcement may not be in the local database yet. The panel opens
|
||||||
|
/// from the address and fills in when the store loads it; the store's
|
||||||
|
/// `subscribe_remote` fetches it from the bootstrap relays.
|
||||||
pub(super) fn open_upstream(&mut self, window: &mut Window, cx: &mut Context<Self>) {
|
pub(super) fn open_upstream(&mut self, window: &mut Window, cx: &mut Context<Self>) {
|
||||||
if self.pending_upstream.is_some() {
|
let Some(addr) = self
|
||||||
return;
|
.announcement(cx)
|
||||||
}
|
.and_then(|announcement| announcement.upstream.as_ref())
|
||||||
|
.and_then(|upstream| upstream.addr.clone())
|
||||||
let Some(announcement) = self.announcement(cx).cloned() else {
|
else {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
let Some(addr) = announcement.upstream.and_then(|upstream| upstream.addr) else {
|
open_repo_panel(&self.dock_area, &addr, None, window, &mut *cx);
|
||||||
return;
|
|
||||||
};
|
|
||||||
|
|
||||||
if let Some(found) = RepoListStore::global(cx)
|
|
||||||
.read(cx)
|
|
||||||
.announcements
|
|
||||||
.iter()
|
|
||||||
.find(|a| a.addr() == addr)
|
|
||||||
.cloned()
|
|
||||||
{
|
|
||||||
open_repo_panel(&self.dock_area, &found, window, &mut *cx);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let backend = Backend::global(cx);
|
|
||||||
backend.update(cx, |backend, cx| {
|
|
||||||
backend.subscribe_bootstrap(vec![filters::announcement(&addr)], cx);
|
|
||||||
});
|
|
||||||
self.pending_upstream = Some(addr);
|
|
||||||
|
|
||||||
let task: gpui::Task<Result<(), Error>> = cx.spawn_in(window, async move |this, cx| {
|
|
||||||
for _ in 0..60 {
|
|
||||||
cx.background_executor()
|
|
||||||
.timer(Duration::from_millis(250))
|
|
||||||
.await;
|
|
||||||
|
|
||||||
let opened = this.update_in(cx, |this, window, cx| {
|
|
||||||
let Some(addr) = this.pending_upstream.clone() else {
|
|
||||||
return true;
|
|
||||||
};
|
|
||||||
let found = RepoListStore::global(cx)
|
|
||||||
.read(cx)
|
|
||||||
.announcements
|
|
||||||
.iter()
|
|
||||||
.find(|a| a.addr() == addr)
|
|
||||||
.cloned();
|
|
||||||
match found {
|
|
||||||
Some(found) => {
|
|
||||||
this.pending_upstream = None;
|
|
||||||
open_repo_panel(&this.dock_area, &found, window, &mut *cx);
|
|
||||||
true
|
|
||||||
}
|
|
||||||
None => false,
|
|
||||||
}
|
|
||||||
})?;
|
|
||||||
|
|
||||||
if opened {
|
|
||||||
return Ok(());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
this.update(cx, |this, _cx| this.pending_upstream = None)?;
|
|
||||||
Ok(())
|
|
||||||
});
|
|
||||||
|
|
||||||
task.detach();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Open the dialog guiding the user through publishing the local repository to NIP-34.
|
/// Open the dialog guiding the user through publishing the local repository to NIP-34.
|
||||||
@@ -194,15 +139,21 @@ impl RepoDetailView {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Open `announcement` as a repository panel in the dock's center.
|
/// Open `addr`'s repository as a panel in the dock's center.
|
||||||
|
///
|
||||||
|
/// `hint` is an announcement already in hand for `addr`. It seeds the store's
|
||||||
|
/// relays and lets the explorer load without waiting for the database; the
|
||||||
|
/// store loads the announcement itself when the hint is absent, so an entry
|
||||||
|
/// point with only an address works too.
|
||||||
pub(crate) fn open_repo_panel(
|
pub(crate) fn open_repo_panel(
|
||||||
dock_area: &WeakEntity<DockArea>,
|
dock_area: &WeakEntity<DockArea>,
|
||||||
announcement: &Announcement,
|
addr: &RepoAddr,
|
||||||
|
hint: Option<&Announcement>,
|
||||||
window: &mut Window,
|
window: &mut Window,
|
||||||
cx: &mut App,
|
cx: &mut App,
|
||||||
) -> Entity<RepoDetailView> {
|
) -> Entity<RepoDetailView> {
|
||||||
let detail =
|
let detail = cx
|
||||||
cx.new(|cx| RepoDetailView::new(dock_area.clone(), announcement.clone(), window, cx));
|
.new(|cx| RepoDetailView::new(dock_area.clone(), addr.clone(), hint.cloned(), window, cx));
|
||||||
|
|
||||||
if let Some(dock_area) = dock_area.upgrade() {
|
if let Some(dock_area) = dock_area.upgrade() {
|
||||||
dock_area.update(cx, |dock_area, cx| {
|
dock_area.update(cx, |dock_area, cx| {
|
||||||
@@ -213,9 +164,16 @@ pub(crate) fn open_repo_panel(
|
|||||||
detail
|
detail
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The nostr store of `announcement`'s repository, without opening a repository panel.
|
/// The nostr store of `addr`'s repository, without opening a repository panel.
|
||||||
fn repo_store(announcement: &Announcement, cx: &mut App) -> Entity<RepoStore> {
|
///
|
||||||
cx.new(|cx| RepoStore::new(announcement.addr(), announcement.relays.clone(), cx))
|
/// `hint` is an announcement already in hand for `addr`. It only seeds the
|
||||||
|
/// 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))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// An item of a repository to open from outside its detail panel.
|
/// An item of a repository to open from outside its detail panel.
|
||||||
@@ -226,16 +184,21 @@ pub(crate) enum RepoItem {
|
|||||||
Patch,
|
Patch,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Open the detail panel of `item` in `announcement`'s repository, in the dock's center.
|
/// Open the detail panel of `item` in `addr`'s repository, in the dock's center.
|
||||||
///
|
///
|
||||||
/// The repository store is built here, not taken from a `RepoDetailView`, so the
|
/// The repository store is built here, not taken from a `RepoDetailView`, so the
|
||||||
/// item panel is the only panel docked.
|
/// item panel is the only panel docked.
|
||||||
///
|
///
|
||||||
|
/// `hint` is an announcement already in hand for `addr`, e.g. the inbox row the
|
||||||
|
/// item was clicked from. The store resolves the repository from the local
|
||||||
|
/// database on its own, so an entry point with only the address works too.
|
||||||
|
///
|
||||||
/// A patch opens nothing: patches are only consumed inside a pull request's
|
/// A patch opens nothing: patches are only consumed inside a pull request's
|
||||||
/// detail panel, and have no panel of their own.
|
/// detail panel, and have no panel of their own.
|
||||||
pub(crate) fn open_repo_item(
|
pub(crate) fn open_repo_item(
|
||||||
dock_area: &WeakEntity<DockArea>,
|
dock_area: &WeakEntity<DockArea>,
|
||||||
announcement: &Announcement,
|
addr: &RepoAddr,
|
||||||
|
hint: Option<&Announcement>,
|
||||||
item: RepoItem,
|
item: RepoItem,
|
||||||
window: &mut Window,
|
window: &mut Window,
|
||||||
cx: &mut App,
|
cx: &mut App,
|
||||||
@@ -243,11 +206,11 @@ pub(crate) fn open_repo_item(
|
|||||||
let panel: Arc<dyn PanelView> =
|
let panel: Arc<dyn PanelView> =
|
||||||
match item {
|
match item {
|
||||||
RepoItem::Issue(issue_id) => {
|
RepoItem::Issue(issue_id) => {
|
||||||
let store = repo_store(announcement, cx);
|
let store = repo_store(addr, hint, cx);
|
||||||
panel_handle(cx.new(|cx| IssueDetailView::new(store, issue_id, window, cx)))
|
panel_handle(cx.new(|cx| IssueDetailView::new(store, issue_id, window, cx)))
|
||||||
}
|
}
|
||||||
RepoItem::PullRequest(pr_id) => {
|
RepoItem::PullRequest(pr_id) => {
|
||||||
let store = repo_store(announcement, cx);
|
let store = repo_store(addr, hint, cx);
|
||||||
panel_handle(cx.new(|cx| {
|
panel_handle(cx.new(|cx| {
|
||||||
PullRequestDetailView::new(dock_area.clone(), store, pr_id, window, cx)
|
PullRequestDetailView::new(dock_area.clone(), store, pr_id, window, cx)
|
||||||
}))
|
}))
|
||||||
|
|||||||
@@ -190,7 +190,7 @@ fn init_repository(
|
|||||||
window.close_dialog(cx);
|
window.close_dialog(cx);
|
||||||
if let Some(view) = view.upgrade() {
|
if let Some(view) = view.upgrade() {
|
||||||
view.update(cx, |this, cx| {
|
view.update(cx, |this, cx| {
|
||||||
this.apply_announcement(announcement, cx);
|
this.apply_announcement(announcement, window, cx);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -73,7 +73,8 @@ pub struct RepoDetailView {
|
|||||||
dock_area: WeakEntity<DockArea>,
|
dock_area: WeakEntity<DockArea>,
|
||||||
/// Snapshot taken at open time.
|
/// Snapshot taken at open time.
|
||||||
///
|
///
|
||||||
/// `None` for local repositories that haven't been published yet.
|
/// `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>,
|
initial: Option<Announcement>,
|
||||||
/// Per-repository nostr store, holding announcement, issues, PRs and statuses.
|
/// Per-repository nostr store, holding announcement, issues, PRs and statuses.
|
||||||
///
|
///
|
||||||
@@ -162,37 +163,32 @@ pub struct RepoDetailView {
|
|||||||
/// The global checkouts store's ready-to-push statuses of this repository,
|
/// The global checkouts store's ready-to-push statuses of this repository,
|
||||||
/// last seen when they drove a render.
|
/// last seen when they drove a render.
|
||||||
push_statuses: Vec<CheckoutStatus>,
|
push_statuses: Vec<CheckoutStatus>,
|
||||||
/// Upstream repository, from this fork's `u` tag, the user asked to open.
|
|
||||||
/// Its announcement is still being fetched.
|
|
||||||
pending_upstream: Option<RepoAddr>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RepoDetailView {
|
impl RepoDetailView {
|
||||||
/// Open a repository announced.
|
/// Open a repository by address.
|
||||||
///
|
///
|
||||||
/// The store connects to the announcement's relays and loads issues, PRs and statuses.
|
/// `hint` is an announcement already in hand. It seeds the store's relays
|
||||||
|
/// and the explorer's clone URLs; without it the panel waits for the store
|
||||||
|
/// to load the announcement from the local database.
|
||||||
pub fn new(
|
pub fn new(
|
||||||
dock_area: WeakEntity<DockArea>,
|
dock_area: WeakEntity<DockArea>,
|
||||||
initial: Announcement,
|
addr: RepoAddr,
|
||||||
|
hint: Option<Announcement>,
|
||||||
window: &mut Window,
|
window: &mut Window,
|
||||||
cx: &mut Context<Self>,
|
cx: &mut Context<Self>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
// The announcement we opened from already carries the NIP-34 `relays` tag.
|
// The announcement we opened from already carries the NIP-34 `relays` tag.
|
||||||
//
|
//
|
||||||
// The store connects to those relays immediately, no bootstrap fetch wait.
|
// The store connects to those relays immediately, no bootstrap fetch wait.
|
||||||
let addr = initial.addr();
|
let relays = hint
|
||||||
let relays = initial.relays.clone();
|
.as_ref()
|
||||||
|
.map(|announcement| announcement.relays.clone())
|
||||||
|
.unwrap_or_default();
|
||||||
let store = cx.new(|cx| RepoStore::new(addr, relays, cx));
|
let store = cx.new(|cx| RepoStore::new(addr, relays, cx));
|
||||||
|
|
||||||
let mut view = Self::new_common(
|
let mut view = Self::new_common(dock_area, hint, Some(store.clone()), None, window, cx);
|
||||||
dock_area,
|
view.attach_store(&store, window, cx);
|
||||||
Some(initial),
|
|
||||||
Some(store.clone()),
|
|
||||||
None,
|
|
||||||
window,
|
|
||||||
cx,
|
|
||||||
);
|
|
||||||
view.attach_store(&store, cx);
|
|
||||||
view
|
view
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -313,7 +309,6 @@ impl RepoDetailView {
|
|||||||
ready_head: None,
|
ready_head: None,
|
||||||
ready_statuses: Vec::new(),
|
ready_statuses: Vec::new(),
|
||||||
push_statuses: Vec::new(),
|
push_statuses: Vec::new(),
|
||||||
pending_upstream: None,
|
|
||||||
focus_handle: cx.focus_handle(),
|
focus_handle: cx.focus_handle(),
|
||||||
_subscriptions: subscriptions,
|
_subscriptions: subscriptions,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
use gpui::prelude::*;
|
use gpui::prelude::*;
|
||||||
use gpui::{Context, Entity};
|
use gpui::{Context, Entity, Window};
|
||||||
use signed_core::Announcement;
|
use signed_core::Announcement;
|
||||||
use signed_state::{Backend, CheckoutsStore, LocalReposStore, RepoStore};
|
use signed_state::{Backend, CheckoutsStore, LocalReposStore, RepoStore};
|
||||||
|
|
||||||
@@ -13,6 +13,7 @@ impl RepoDetailView {
|
|||||||
pub(crate) fn apply_announcement(
|
pub(crate) fn apply_announcement(
|
||||||
&mut self,
|
&mut self,
|
||||||
announcement: Announcement,
|
announcement: Announcement,
|
||||||
|
window: &mut Window,
|
||||||
cx: &mut Context<Self>,
|
cx: &mut Context<Self>,
|
||||||
) {
|
) {
|
||||||
// The repository is no longer a bare local repo.
|
// The repository is no longer a bare local repo.
|
||||||
@@ -24,7 +25,7 @@ impl RepoDetailView {
|
|||||||
cx.new(|cx| RepoStore::new(announcement.addr(), announcement.relays.clone(), cx));
|
cx.new(|cx| RepoStore::new(announcement.addr(), announcement.relays.clone(), cx));
|
||||||
// Re-render on store refreshes, issues, PRs and statuses.
|
// Re-render on store refreshes, issues, PRs and statuses.
|
||||||
// Keep the ready-to-contribute statuses of this repository requested.
|
// Keep the ready-to-contribute statuses of this repository requested.
|
||||||
self.attach_store(&store, cx);
|
self.attach_store(&store, window, cx);
|
||||||
self.store = Some(store);
|
self.store = Some(store);
|
||||||
self.initial = Some(announcement);
|
self.initial = Some(announcement);
|
||||||
cx.notify();
|
cx.notify();
|
||||||
@@ -32,11 +33,27 @@ impl RepoDetailView {
|
|||||||
|
|
||||||
/// Observe the repository's store, re-render on refreshes.
|
/// Observe the repository's store, re-render on refreshes.
|
||||||
/// Request the ready-to-contribute statuses for it.
|
/// Request the ready-to-contribute statuses for it.
|
||||||
pub(super) fn attach_store(&mut self, store: &Entity<RepoStore>, cx: &mut Context<Self>) {
|
pub(super) fn attach_store(
|
||||||
|
&mut self,
|
||||||
|
store: &Entity<RepoStore>,
|
||||||
|
window: &mut Window,
|
||||||
|
cx: &mut Context<Self>,
|
||||||
|
) {
|
||||||
self._subscriptions
|
self._subscriptions
|
||||||
.push(cx.observe(store, |this, _store, cx| {
|
.push(cx.observe_in(store, window, |this, store, window, cx| {
|
||||||
log::debug!("repo detail: store notify");
|
|
||||||
this.refresh_ready_statuses(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);
|
||||||
|
this.load_repo(window, cx);
|
||||||
|
}
|
||||||
|
|
||||||
cx.notify();
|
cx.notify();
|
||||||
}));
|
}));
|
||||||
self.refresh_ready_statuses(cx);
|
self.refresh_ready_statuses(cx);
|
||||||
|
|||||||
@@ -189,7 +189,13 @@ impl RepoListView {
|
|||||||
window: &mut Window,
|
window: &mut Window,
|
||||||
cx: &mut Context<Self>,
|
cx: &mut Context<Self>,
|
||||||
) {
|
) {
|
||||||
open_repo_panel(&self.dock_area, announcement, window, cx);
|
open_repo_panel(
|
||||||
|
&self.dock_area,
|
||||||
|
&announcement.addr(),
|
||||||
|
Some(announcement),
|
||||||
|
window,
|
||||||
|
cx,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn render_card(
|
fn render_card(
|
||||||
|
|||||||
@@ -257,5 +257,11 @@ fn open_repo(
|
|||||||
window: &mut Window,
|
window: &mut Window,
|
||||||
cx: &mut App,
|
cx: &mut App,
|
||||||
) {
|
) {
|
||||||
open_repo_panel(&dock_area, &announcement, window, cx);
|
open_repo_panel(
|
||||||
|
&dock_area,
|
||||||
|
&announcement.addr(),
|
||||||
|
Some(&announcement),
|
||||||
|
window,
|
||||||
|
cx,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -260,7 +260,13 @@ impl SidebarPanel {
|
|||||||
window: &mut Window,
|
window: &mut Window,
|
||||||
cx: &mut Context<Self>,
|
cx: &mut Context<Self>,
|
||||||
) {
|
) {
|
||||||
open_repo_panel(&self.dock_area, announcement, window, &mut *cx);
|
open_repo_panel(
|
||||||
|
&self.dock_area,
|
||||||
|
&announcement.addr(),
|
||||||
|
Some(announcement),
|
||||||
|
window,
|
||||||
|
&mut *cx,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Open a local repository's detail view in the dock's center.
|
/// Open a local repository's detail view in the dock's center.
|
||||||
|
|||||||
+24
-11
@@ -1,6 +1,6 @@
|
|||||||
# Repository state and panel flow plan
|
# Repository state and panel flow plan
|
||||||
|
|
||||||
Status: proposed (2026-09-13)
|
Status: phases 1-2 implemented, phase 3 next (2026-09-13)
|
||||||
|
|
||||||
Builds on `docs/backend-rearchitecture.md`, especially §7 (notify audit),
|
Builds on `docs/backend-rearchitecture.md`, especially §7 (notify audit),
|
||||||
§11 (split independently-observed state), §12 (one debounce at the source)
|
§11 (split independently-observed state), §12 (one debounce at the source)
|
||||||
@@ -237,10 +237,8 @@ flow for announced repositories.
|
|||||||
- `open_repo_item(dock_area, addr: &RepoAddr, item, window, cx)`.
|
- `open_repo_item(dock_area, addr: &RepoAddr, item, window, cx)`.
|
||||||
- Inbox passes its already-parsed `address` (`signed_core::InboxItem.address`,
|
- Inbox passes its already-parsed `address` (`signed_core::InboxItem.address`,
|
||||||
the root event's `a` tag) and drops the `RepoListStore` lookup.
|
the root event's `a` tag) and drops the `RepoListStore` lookup.
|
||||||
- `open_upstream` drops the 60 x 250 ms wait loop: the store's
|
- `open_upstream` no longer polls the list; it opens the panel by address and
|
||||||
`repo_filters` already include the announcement filter and
|
the store fills it in (Phase 2).
|
||||||
`subscribe_remote` runs on creation, so the panel opens immediately and
|
|
||||||
fills in.
|
|
||||||
- `RepoItem::Patch` behavior is unchanged.
|
- `RepoItem::Patch` behavior is unchanged.
|
||||||
|
|
||||||
## Phases
|
## Phases
|
||||||
@@ -271,17 +269,32 @@ Status: implemented, except step 6.
|
|||||||
|
|
||||||
### Phase 2 - entry points by identity
|
### Phase 2 - entry points by identity
|
||||||
|
|
||||||
1. `views/repo/actions.rs`: `repo_store(addr, hint, cx)`;
|
Status: implemented.
|
||||||
`open_repo_item(addr, ...)`; `open_upstream` opens directly.
|
|
||||||
2. `views/inbox.rs`: pass `address`, delete the announcement lookup and its
|
1. `views/repo/actions.rs`: `repo_store(addr, hint, cx)` seeds the store's
|
||||||
silent early-return.
|
relays from an optional hint but needs nothing else; the store loads the
|
||||||
|
announcement itself. `open_repo_item(addr, hint, item, window, cx)` takes
|
||||||
|
the address, not a hydrated announcement.
|
||||||
|
2. `views/inbox.rs`: `open` passes its already-parsed `address` and the
|
||||||
|
`RepoListStore` lookup with its silent early-return is gone. An inbox row
|
||||||
|
opens whether or not the repository is in the list yet.
|
||||||
|
3. `open_repo_panel` and `RepoDetailView::new` take an address plus an optional
|
||||||
|
hint, so a repository panel opens from a `RepoAddr` alone. This pulls the
|
||||||
|
address-based constructor forward from Phase 3 step 2.
|
||||||
|
4. `RepoDetailView::attach_store` adopts the store's first announcement when
|
||||||
|
`initial` is still empty and calls `load_repo`, so a panel opened by address
|
||||||
|
fills in instead of waiting for the caller to have the announcement.
|
||||||
|
5. `open_upstream`: the 60 x 250 ms poll and the `pending_upstream` field are
|
||||||
|
gone. It opens the panel by address; the store's `subscribe_remote` fetches
|
||||||
|
the announcement from the bootstrap relays and step 4 loads the explorer.
|
||||||
|
|
||||||
### Phase 3 - one entity for local and NIP-34
|
### Phase 3 - one entity for local and NIP-34
|
||||||
|
|
||||||
1. `signed_state/src/repo.rs`: `addr`/`path` options, `new_local`,
|
1. `signed_state/src/repo.rs`: `addr`/`path` options, `new_local`,
|
||||||
`announce`, `Option<Subscription>`, action guards.
|
`announce`, `Option<Subscription>`, action guards.
|
||||||
2. `views/repo/mod.rs`: single `store` field; `new`/`new_local`; header,
|
2. `views/repo/mod.rs`: single `store` field; `new_local`; header,
|
||||||
display name, `load_repo`, `open_init_dialog` derive from the store.
|
display name, `load_repo`, `open_init_dialog` derive from the store. The
|
||||||
|
address-based `new` is already in place from Phase 2.
|
||||||
3. `views/repo/store.rs`: always observe; `refresh_statuses` returns false
|
3. `views/repo/store.rs`: always observe; `refresh_statuses` returns false
|
||||||
when not announced.
|
when not announced.
|
||||||
4. `views/repo/actions.rs`, `header.rs`, `banners.rs`: drop
|
4. `views/repo/actions.rs`, `header.rs`, `banners.rs`: drop
|
||||||
|
|||||||
Reference in New Issue
Block a user