Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open Project Dialog #5607

Merged
merged 14 commits into from
Feb 20, 2023
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions app/gui/src/controller/ide.rs
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,8 @@ pub enum Notification {
NewProjectCreated,
/// User opened an existing project.
ProjectOpened,
/// User closed the project.
ProjectClosed,
}


Expand Down Expand Up @@ -172,6 +174,9 @@ pub trait API: Debug {
/// Returns `None` if no project is opened at the moment.
fn current_project(&self) -> Option<model::Project>;

/// Close the currently opened project. Does nothing if no project is open.
fn close_project(&self);
vitvakatu marked this conversation as resolved.
Show resolved Hide resolved

/// Getter of Status Notification Publisher.
fn status_notifications(&self) -> &StatusNotificationPublisher;

Expand Down
11 changes: 8 additions & 3 deletions app/gui/src/controller/ide/desktop.rs
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,12 @@ impl API for Handle {
fn current_project(&self) -> Option<model::Project> {
self.current_project.get()
}

fn close_project(&self) {
self.current_project.set(None);
self.notifications.notify(Notification::ProjectClosed);
}

fn status_notifications(&self) -> &StatusNotificationPublisher {
&self.status_notifications
}
Expand Down Expand Up @@ -132,8 +138,7 @@ impl ManagingProjectAPI for Handle {
let project_mgr = self.project_manager.clone_ref();
let new_project = Project::new_opened(project_mgr, new_project_id);
self.current_project.set(Some(new_project.await?));
let notify = self.notifications.publish(Notification::NewProjectCreated);
executor::global::spawn(notify);
self.notifications.notify(Notification::NewProjectCreated);
Ok(())
}
.boxed_local()
Expand All @@ -150,7 +155,7 @@ impl ManagingProjectAPI for Handle {
let project_mgr = self.project_manager.clone_ref();
let new_project = model::project::Synchronized::new_opened(project_mgr, id);
self.current_project.set(Some(new_project.await?));
executor::global::spawn(self.notifications.publish(Notification::ProjectOpened));
self.notifications.notify(Notification::ProjectOpened);
Ok(())
}
.boxed_local()
Expand Down
1 change: 1 addition & 0 deletions app/gui/src/controller/ide/plain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ impl controller::ide::API for Handle {
fn current_project(&self) -> Option<model::Project> {
Some(self.project.clone_ref())
}
fn close_project(&self) {}
fn status_notifications(&self) -> &StatusNotificationPublisher {
&self.status_notifications
}
Expand Down
8 changes: 8 additions & 0 deletions app/gui/src/presenter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,11 @@ impl Model {
});
}

fn close_project(&self) {
*self.current_project.borrow_mut() = None;
self.view.project().graph().remove_all_nodes();
vitvakatu marked this conversation as resolved.
Show resolved Hide resolved
}

/// Open a project by name. It makes two calls to Project Manager: one for listing projects and
/// a second one for opening the project.
#[profile(Task)]
Expand Down Expand Up @@ -211,6 +216,9 @@ impl Presenter {
controller::ide::Notification::NewProjectCreated
| controller::ide::Notification::ProjectOpened =>
model.setup_and_display_new_project(),
controller::ide::Notification::ProjectClosed => {
model.close_project();
}
}
futures::future::ready(())
});
Expand Down
98 changes: 88 additions & 10 deletions app/gui/src/presenter/project.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ use crate::presenter;
use crate::presenter::graph::ViewNodeId;

use enso_frp as frp;
use ensogl::system::js;
use ide_view as view;
use ide_view::project::SearcherParams;
use model::module::NotificationKind;
Expand All @@ -16,6 +17,16 @@ use model::project::VcsStatus;



// =================
// === Constants ===
// =================

/// We don't know how long the project opening will take, but we still want to show a fake progress
/// indicator for the user. This constant represents a progress percentage that will be displayed.
const OPEN_PROJECT_SPINNER_PROGRESS: f32 = 0.8;



// =============
// === Model ===
// =============
Expand All @@ -24,15 +35,16 @@ use model::project::VcsStatus;
#[allow(unused)]
#[derive(Debug)]
struct Model {
controller: controller::Project,
module_model: model::Module,
graph_controller: controller::ExecutedGraph,
ide_controller: controller::Ide,
view: view::project::View,
status_bar: view::status_bar::View,
graph: presenter::Graph,
code: presenter::Code,
searcher: RefCell<Option<presenter::Searcher>>,
controller: controller::Project,
module_model: model::Module,
graph_controller: controller::ExecutedGraph,
ide_controller: controller::Ide,
view: view::project::View,
status_bar: view::status_bar::View,
graph: presenter::Graph,
code: presenter::Code,
searcher: RefCell<Option<presenter::Searcher>>,
available_projects: Rc<RefCell<Vec<(ImString, Uuid)>>>,
}

impl Model {
Expand All @@ -54,6 +66,7 @@ impl Model {
);
let code = presenter::Code::new(text_controller, &view);
let searcher = default();
let available_projects = default();
Model {
controller,
module_model,
Expand All @@ -64,6 +77,7 @@ impl Model {
graph,
code,
searcher,
available_projects,
}
}

Expand Down Expand Up @@ -201,8 +215,53 @@ impl Model {
}
})
}
}

/// Prepare a list of projects to display in the Open Project dialog.
fn project_list_opened(&self, project_list_ready: frp::Source<()>) {
let controller = self.ide_controller.clone_ref();
let projects_list = self.available_projects.clone_ref();
executor::global::spawn(async move {
if let Ok(api) = controller.manage_projects() {
if let Ok(projects) = api.list_projects().await {
let projects = projects.into_iter();
let projects = projects.map(|p| (p.name.clone().into(), p.id)).collect_vec();
*projects_list.borrow_mut() = projects;
project_list_ready.emit(());
}
}
})
}

/// User clicked a project in the Open Project dialog. Open it.
fn open_project(&self, id_in_list: &usize) {
let controller = self.ide_controller.clone_ref();
let projects_list = self.available_projects.clone_ref();
let view = self.view.clone_ref();
let status_bar = self.status_bar.clone_ref();
let id = *id_in_list;
executor::global::spawn(async move {
let app = js::app_or_panic();
app.show_progress_indicator(OPEN_PROJECT_SPINNER_PROGRESS);
view.hide_graph_editor();
controller.close_project();
if let Ok(api) = controller.manage_projects() {
let uuid = projects_list.borrow().get(id).map(|(_name, uuid)| *uuid);
if let Some(uuid) = uuid {
if let Err(error) = api.open_project(uuid).await {
error!("Error opening project: {error}.");
status_bar.add_event(format!("Error opening project: {error}."));
}
} else {
error!("Project with id {id} not found.");
}
} else {
error!("Project Manager API not available, cannot open project.");
}
app.hide_progress_indicator();
view.show_graph_editor();
})
}
}


// ===============
Expand Down Expand Up @@ -243,8 +302,27 @@ impl Project {
let view = &model.view.frp;
let breadcrumbs = &model.view.graph().model.breadcrumbs;
let graph_view = &model.view.graph().frp;
let project_list = &model.view.project_list();

frp::extend! { network
project_list_ready <- source_();

project_list.grid.reset_entries <+ project_list_ready.map(f_!([model]{
let cols = 1;
let rows = model.available_projects.borrow().len();
(rows, cols)
}));
entry_model <- project_list.grid.model_for_entry_needed.map(f!([model]((row, _)) {
model.available_projects.borrow().get(*row).map(|(name, _)| (*row, 0, name.clone_ref()))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is super complex. Also, the 0 is magic

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed

})).filter_map(|t| t.clone());
project_list.grid.model_for_entry <+ entry_model;

open_project_list <- view.project_list_shown.on_true();
eval_ open_project_list(model.project_list_opened(project_list_ready.clone_ref()));
selected_project <- project_list.grid.entry_selected.filter_map(|e| *e);
eval selected_project(((row, _col)) model.open_project(row));
project_list.grid.select_entry <+ selected_project.constant(None);

eval view.searcher ([model](params) {
if let Some(params) = params {
model.setup_searcher_presenter(*params)
Expand Down
1 change: 1 addition & 0 deletions app/gui/view/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ enso-shapely = { path = "../../../lib/rust/shapely" }
engine-protocol = { path = "../controller/engine-protocol" }
ensogl = { path = "../../../lib/rust/ensogl" }
ensogl-component = { path = "../../../lib/rust/ensogl/component" }
ensogl-derive-theme = { path = "../../../lib/rust/ensogl/app/theme/derive" }
ensogl-gui-component = { path = "../../../lib/rust/ensogl/component/gui" }
ensogl-text = { path = "../../../lib/rust/ensogl/component/text" }
ensogl-text-msdf = { path = "../../../lib/rust/ensogl/component/text/src/font/msdf" }
Expand Down
2 changes: 1 addition & 1 deletion app/gui/view/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,8 @@
pub mod code_editor;
pub mod component_browser;
pub mod debug_mode_popup;
pub mod open_dialog;
pub mod project;
pub mod project_list;
pub mod root;
pub mod searcher;
pub mod status_bar;
Expand Down
80 changes: 0 additions & 80 deletions app/gui/view/src/open_dialog.rs

This file was deleted.

Loading