feat: dashboard skeleton
This commit is contained in:
@@ -1,7 +1,7 @@
|
|||||||
use std::fmt::format;
|
use std::fmt::format;
|
||||||
|
|
||||||
use reqwest::{Response, dns::Resolving};
|
use reqwest::{Response, dns::Resolving};
|
||||||
use serde::Deserialize;
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::query;
|
use crate::query;
|
||||||
|
|
||||||
@@ -16,7 +16,7 @@ pub struct QueryContext {
|
|||||||
pub(crate) github: GithubCredentials,
|
pub(crate) github: GithubCredentials,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone, Serialize, Deserialize)]
|
||||||
pub(crate) struct AuthTokens {
|
pub(crate) struct AuthTokens {
|
||||||
pub(crate) access_token: String,
|
pub(crate) access_token: String,
|
||||||
}
|
}
|
||||||
|
|||||||
45
src/app.rs
45
src/app.rs
@@ -1,10 +1,6 @@
|
|||||||
use gpui::{div, prelude::*};
|
use crate::api;
|
||||||
|
|
||||||
use crate::dashboard;
|
|
||||||
use crate::query;
|
use crate::query;
|
||||||
use crate::theme;
|
use crate::theme;
|
||||||
use crate::titlebar;
|
|
||||||
use crate::{api, app};
|
|
||||||
|
|
||||||
pub struct Global {
|
pub struct Global {
|
||||||
pub safe_area: gpui::Bounds<gpui::Pixels>,
|
pub safe_area: gpui::Bounds<gpui::Pixels>,
|
||||||
@@ -13,45 +9,6 @@ pub struct Global {
|
|||||||
pub rng: rand::prelude::ThreadRng,
|
pub rng: rand::prelude::ThreadRng,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Chrome {}
|
|
||||||
|
|
||||||
impl Chrome {
|
|
||||||
pub fn new(window: &mut gpui::Window, cx: &mut gpui::Context<Self>) -> Self {
|
|
||||||
cx.observe_window_appearance(window, |_, window, cx| {
|
|
||||||
cx.update_global::<app::Global, ()>(|global, cx| {
|
|
||||||
global.current_theme = global
|
|
||||||
.theme_family
|
|
||||||
.theme_for_appearance(window.appearance());
|
|
||||||
cx.notify();
|
|
||||||
});
|
|
||||||
})
|
|
||||||
.detach();
|
|
||||||
|
|
||||||
Self {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl gpui::Render for Chrome {
|
|
||||||
fn render(
|
|
||||||
&mut self,
|
|
||||||
_window: &mut gpui::Window,
|
|
||||||
cx: &mut gpui::Context<Self>,
|
|
||||||
) -> impl gpui::IntoElement {
|
|
||||||
let title_bar = cx.new(|cx| titlebar::TitleBar::new(cx));
|
|
||||||
|
|
||||||
let dashboard = cx.new(|_| dashboard::Screen {
|
|
||||||
text: "World".into(),
|
|
||||||
});
|
|
||||||
|
|
||||||
div()
|
|
||||||
.flex()
|
|
||||||
.flex_col()
|
|
||||||
.size_full()
|
|
||||||
.child(title_bar)
|
|
||||||
.child(dashboard)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl gpui::Global for Global {}
|
impl gpui::Global for Global {}
|
||||||
|
|
||||||
pub fn current_theme(cx: &gpui::App) -> &theme::Theme {
|
pub fn current_theme(cx: &gpui::App) -> &theme::Theme {
|
||||||
|
|||||||
1
src/asset/font_icon/cat.svg
Normal file
1
src/asset/font_icon/cat.svg
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-cat-icon lucide-cat"><path d="M12 5c.67 0 1.35.09 2 .26 1.78-2 5.03-2.84 6.42-2.26 1.4.58-.42 7-.42 7 .57 1.07 1 2.24 1 3.44C21 17.9 16.97 21 12 21s-9-3-9-7.56c0-1.25.5-2.4 1-3.44 0 0-1.89-6.42-.5-7 1.39-.58 4.72.23 6.5 2.23A9.04 9.04 0 0 1 12 5Z"/><path d="M8 14v.5"/><path d="M16 14v.5"/><path d="M11.25 16.25h1.5L12 17l-.75-.75Z"/></svg>
|
||||||
|
After Width: | Height: | Size: 543 B |
@@ -26,7 +26,7 @@ macro_rules! define_font_icons {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
define_font_icons!(Check, ChevronDown, FolderGit, Github, ArrowRight);
|
define_font_icons!(Check, ChevronDown, FolderGit, Github, ArrowRight, Cat);
|
||||||
|
|
||||||
#[derive(gpui::IntoElement)]
|
#[derive(gpui::IntoElement)]
|
||||||
pub struct FontIconSvg {
|
pub struct FontIconSvg {
|
||||||
|
|||||||
@@ -1,48 +0,0 @@
|
|||||||
use gpui::{div, prelude::*};
|
|
||||||
|
|
||||||
use crate::app;
|
|
||||||
|
|
||||||
pub struct Screen {
|
|
||||||
pub text: gpui::SharedString,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Render for Screen {
|
|
||||||
fn render(
|
|
||||||
&mut self,
|
|
||||||
_window: &mut gpui::Window,
|
|
||||||
cx: &mut gpui::Context<Self>,
|
|
||||||
) -> impl IntoElement {
|
|
||||||
let theme = app::current_theme(cx);
|
|
||||||
|
|
||||||
div()
|
|
||||||
.flex()
|
|
||||||
.flex_1()
|
|
||||||
.flex_row()
|
|
||||||
.w_full()
|
|
||||||
.gap_2()
|
|
||||||
.p_2p5()
|
|
||||||
.pt_0()
|
|
||||||
.bg(theme.colors.background)
|
|
||||||
.justify_center()
|
|
||||||
.items_center()
|
|
||||||
.shadow_lg()
|
|
||||||
.text_xl()
|
|
||||||
.text_color(theme.colors.text)
|
|
||||||
.child(
|
|
||||||
div()
|
|
||||||
.h_full()
|
|
||||||
.flex()
|
|
||||||
.w_1_3()
|
|
||||||
.bg(theme.colors.surface)
|
|
||||||
.rounded_lg(),
|
|
||||||
)
|
|
||||||
.child(
|
|
||||||
div()
|
|
||||||
.h_full()
|
|
||||||
.flex()
|
|
||||||
.w_2_3()
|
|
||||||
.bg(theme.colors.surface)
|
|
||||||
.rounded_lg(),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
24
src/main.rs
24
src/main.rs
@@ -1,25 +1,23 @@
|
|||||||
use gpui::{bounds, point, prelude::*, px, size};
|
use gpui::{bounds, point, prelude::*, px, size};
|
||||||
|
|
||||||
use crate::screen::setup_wizard;
|
use crate::{query::fetch_query, screen::dashboard, screen::setup_wizard};
|
||||||
|
|
||||||
mod api;
|
mod api;
|
||||||
mod app;
|
mod app;
|
||||||
mod asset;
|
mod asset;
|
||||||
mod colors;
|
mod colors;
|
||||||
mod component;
|
mod component;
|
||||||
mod dashboard;
|
|
||||||
mod http;
|
mod http;
|
||||||
mod query;
|
mod query;
|
||||||
mod screen;
|
mod screen;
|
||||||
mod storage;
|
mod storage;
|
||||||
mod theme;
|
mod theme;
|
||||||
mod titlebar;
|
|
||||||
mod util;
|
mod util;
|
||||||
|
|
||||||
enum Start {
|
enum Start {
|
||||||
FromScratch,
|
FromScratch,
|
||||||
FromSetup(setup_wizard::StoredSetupState),
|
FromSetup(setup_wizard::StoredSetupState),
|
||||||
FromSaved,
|
FromSaved(storage::PersistedState),
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
@@ -76,19 +74,25 @@ fn setup_application(cx: &mut gpui::App) {
|
|||||||
_ = setup_wizard::open_window(screen, cx);
|
_ = setup_wizard::open_window(screen, cx);
|
||||||
}
|
}
|
||||||
|
|
||||||
_ => {}
|
Start::FromSaved(_) => {
|
||||||
|
let screen = dashboard::new(cx);
|
||||||
|
_ = dashboard::open_window(screen, cx);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
fn resume_application_state(cx: &mut gpui::App) -> Start {
|
fn resume_application_state(cx: &mut gpui::App) -> Start {
|
||||||
let state = storage::load_persisted_state();
|
let state = storage::load_persisted_state();
|
||||||
let Some(state) = state else {
|
let Some(mut state) = state else {
|
||||||
return Start::FromScratch;
|
return Start::FromScratch;
|
||||||
};
|
};
|
||||||
|
|
||||||
let auth_tokens = cx
|
let auth_tokens = if cfg!(debug_assertions) {
|
||||||
.background_executor()
|
state.debug_auth_tokens.take()
|
||||||
.block(storage::load_auth_tokens(cx, state.selected_account));
|
} else {
|
||||||
|
cx.background_executor()
|
||||||
|
.block(storage::load_auth_tokens(cx, state.selected_account))
|
||||||
|
};
|
||||||
let Some(auth_tokens) = auth_tokens else {
|
let Some(auth_tokens) = auth_tokens else {
|
||||||
return Start::FromScratch;
|
return Start::FromScratch;
|
||||||
};
|
};
|
||||||
@@ -106,6 +110,6 @@ fn resume_application_state(cx: &mut gpui::App) -> Start {
|
|||||||
match setup_status {
|
match setup_status {
|
||||||
setup_wizard::SetupStatus::NotStarted => Start::FromScratch,
|
setup_wizard::SetupStatus::NotStarted => Start::FromScratch,
|
||||||
setup_wizard::SetupStatus::InProgress(state) => Start::FromSetup(state),
|
setup_wizard::SetupStatus::InProgress(state) => Start::FromSetup(state),
|
||||||
setup_wizard::SetupStatus::Completed => Start::FromSaved,
|
setup_wizard::SetupStatus::Completed => Start::FromSaved(state),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
43
src/screen/dashboard/mod.rs
Normal file
43
src/screen/dashboard/mod.rs
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
mod screen;
|
||||||
|
mod titlebar;
|
||||||
|
|
||||||
|
use gpui::{AppContext, BorrowAppContext, point, px, size};
|
||||||
|
pub(crate) use screen::new;
|
||||||
|
|
||||||
|
use crate::{app, screen::dashboard::screen::Screen};
|
||||||
|
|
||||||
|
pub fn open_window(screen: Screen, cx: &mut gpui::App) -> anyhow::Result<()> {
|
||||||
|
let (top_left, window_bounds) = cx.read_global::<app::Global, _>(|global, cx| {
|
||||||
|
(
|
||||||
|
global.safe_area.origin,
|
||||||
|
gpui::Bounds::centered(None, size(px(800.), px(600.0)), cx),
|
||||||
|
)
|
||||||
|
});
|
||||||
|
|
||||||
|
cx.open_window(
|
||||||
|
gpui::WindowOptions {
|
||||||
|
window_bounds: Some(gpui::WindowBounds::Windowed(window_bounds)),
|
||||||
|
titlebar: Some(gpui::TitlebarOptions {
|
||||||
|
appears_transparent: true,
|
||||||
|
traffic_light_position: Some(top_left + point(px(12.), px(12.))),
|
||||||
|
..Default::default()
|
||||||
|
}),
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
|window, cx| {
|
||||||
|
cx.new(|cx| {
|
||||||
|
cx.observe_window_appearance(window, |_, window, cx| {
|
||||||
|
cx.update_global::<app::Global, ()>(|global, cx| {
|
||||||
|
global.current_theme = global
|
||||||
|
.theme_family
|
||||||
|
.theme_for_appearance(window.appearance());
|
||||||
|
cx.notify();
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.detach();
|
||||||
|
screen
|
||||||
|
})
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.map(|_| ())
|
||||||
|
}
|
||||||
41
src/screen/dashboard/screen.rs
Normal file
41
src/screen/dashboard/screen.rs
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
use gpui::{AppContext, ParentElement, Styled, div};
|
||||||
|
|
||||||
|
use crate::{app, screen::dashboard::titlebar};
|
||||||
|
|
||||||
|
pub(crate) struct Screen {
|
||||||
|
titlebar: gpui::Entity<titlebar::TitleBar>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn new(cx: &mut gpui::App) -> Screen {
|
||||||
|
Screen {
|
||||||
|
titlebar: cx.new(|cx| titlebar::new(cx)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl gpui::Render for Screen {
|
||||||
|
fn render(
|
||||||
|
&mut self,
|
||||||
|
_window: &mut gpui::Window,
|
||||||
|
cx: &mut gpui::Context<Self>,
|
||||||
|
) -> impl gpui::IntoElement {
|
||||||
|
let theme = app::current_theme(cx);
|
||||||
|
div()
|
||||||
|
.flex()
|
||||||
|
.flex_col()
|
||||||
|
.bg(theme.colors.background)
|
||||||
|
.size_full()
|
||||||
|
.child(self.titlebar.clone())
|
||||||
|
.child(
|
||||||
|
div()
|
||||||
|
.flex()
|
||||||
|
.flex_row()
|
||||||
|
.flex_1()
|
||||||
|
.w_full()
|
||||||
|
.gap_2()
|
||||||
|
.px_3()
|
||||||
|
.pb_3()
|
||||||
|
.child(div().w_1_4().h_full().rounded_lg().bg(theme.colors.surface))
|
||||||
|
.child(div().w_3_4().h_full().rounded_lg().bg(theme.colors.surface)),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
use gpui::{ParentElement, Styled, div};
|
use gpui::{ParentElement, Styled, TitlebarOptions, div};
|
||||||
|
|
||||||
use crate::component::button::button;
|
use crate::component::button::button;
|
||||||
use crate::query::{self, QueryStatus, read_query, use_query};
|
use crate::query::{self, QueryStatus, read_query, use_query};
|
||||||
@@ -16,11 +16,9 @@ pub struct TitleBar {
|
|||||||
|
|
||||||
pub struct RepoSelector {}
|
pub struct RepoSelector {}
|
||||||
|
|
||||||
impl TitleBar {
|
pub fn new(cx: &mut gpui::Context<TitleBar>) -> TitleBar {
|
||||||
pub fn new(cx: &mut gpui::Context<Self>) -> Self {
|
TitleBar {
|
||||||
Self {
|
fetch_user_query: use_query(api::user::Fetch, cx),
|
||||||
fetch_user_query: use_query(api::user::Fetch, cx),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1 +1,2 @@
|
|||||||
|
pub(crate) mod dashboard;
|
||||||
pub(crate) mod setup_wizard;
|
pub(crate) mod setup_wizard;
|
||||||
|
|||||||
@@ -2,8 +2,8 @@ use std::time::Duration;
|
|||||||
|
|
||||||
use futures_lite::StreamExt;
|
use futures_lite::StreamExt;
|
||||||
use gpui::{
|
use gpui::{
|
||||||
BorrowAppContext, InteractiveElement, ParentElement, Styled, Timer, div, img,
|
BorrowAppContext, InteractiveElement, ParentElement, StatefulInteractiveElement, Styled, Timer,
|
||||||
prelude::FluentBuilder,
|
div, img, prelude::FluentBuilder,
|
||||||
};
|
};
|
||||||
use rand::RngExt;
|
use rand::RngExt;
|
||||||
|
|
||||||
@@ -62,28 +62,28 @@ impl GithubStepView {
|
|||||||
|
|
||||||
fn on_create(&mut self, cx: &mut gpui::Context<Self>) {
|
fn on_create(&mut self, cx: &mut gpui::Context<Self>) {
|
||||||
cx.observe(&self.create_device_code_query, |this, _, cx| {
|
cx.observe(&self.create_device_code_query, |this, _, cx| {
|
||||||
let code = {
|
let codes = {
|
||||||
let data = read_query(&this.create_device_code_query, cx);
|
let data = read_query(&this.create_device_code_query, cx);
|
||||||
if let QueryStatus::Loaded(data) = data {
|
if let QueryStatus::Loaded(data) = data {
|
||||||
Some(data.device_code.clone())
|
Some((data.device_code.clone(), data.user_code.clone()))
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
if let Some(ref code) = code
|
if let Some((ref device_code, ref user_code)) = codes
|
||||||
&& !this.has_opened_link
|
&& !this.has_opened_link
|
||||||
&& !this.is_opening_link
|
&& !this.is_opening_link
|
||||||
{
|
{
|
||||||
this.is_opening_link = true;
|
this.is_opening_link = true;
|
||||||
this.copy_device_code(code, cx);
|
this.copy_user_code(user_code, cx);
|
||||||
|
|
||||||
let code = code.clone();
|
let device_code = device_code.clone();
|
||||||
set_timeout(
|
set_timeout(
|
||||||
move |weak, cx| {
|
move |weak, cx| {
|
||||||
_ = weak.update(cx, |this, cx| {
|
_ = weak.update(cx, |this, cx| {
|
||||||
this.has_opened_link = true;
|
this.has_opened_link = true;
|
||||||
this.is_opening_link = false;
|
this.is_opening_link = false;
|
||||||
this.begin_auth_flow(&code, cx);
|
this.begin_auth_flow(&device_code, cx);
|
||||||
cx.notify();
|
cx.notify();
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
@@ -137,7 +137,7 @@ impl GithubStepView {
|
|||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn copy_device_code(&mut self, code: &str, cx: &mut gpui::Context<Self>) {
|
fn copy_user_code(&mut self, code: &str, cx: &mut gpui::Context<Self>) {
|
||||||
cx.write_to_clipboard(gpui::ClipboardItem::new_string(code.to_owned()));
|
cx.write_to_clipboard(gpui::ClipboardItem::new_string(code.to_owned()));
|
||||||
|
|
||||||
self.has_copied_code = true;
|
self.has_copied_code = true;
|
||||||
@@ -262,9 +262,9 @@ impl GithubStepView {
|
|||||||
|
|
||||||
let theme = app::current_theme(cx);
|
let theme = app::current_theme(cx);
|
||||||
|
|
||||||
let displayed_code = match create_device_code_query {
|
let (displayed_code, copyable_code) = match create_device_code_query {
|
||||||
QueryStatus::Loaded(data) => &data.user_code,
|
QueryStatus::Loaded(data) => (data.user_code.as_str(), Some(data.user_code.clone())),
|
||||||
_ => &self.placeholder_code,
|
_ => (self.placeholder_code.as_str(), None),
|
||||||
};
|
};
|
||||||
|
|
||||||
let border_color = theme.colors.border.clone();
|
let border_color = theme.colors.border.clone();
|
||||||
@@ -304,6 +304,12 @@ impl GithubStepView {
|
|||||||
.items_center()
|
.items_center()
|
||||||
.justify_center()
|
.justify_center()
|
||||||
.gap_1p5()
|
.gap_1p5()
|
||||||
|
.when_some(copyable_code, |it, code| {
|
||||||
|
it.cursor_pointer()
|
||||||
|
.on_click(cx.listener(move |this, _, _, cx| {
|
||||||
|
this.copy_user_code(&code, cx);
|
||||||
|
}))
|
||||||
|
})
|
||||||
.children(letter_boxes),
|
.children(letter_boxes),
|
||||||
)
|
)
|
||||||
.child(
|
.child(
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
use gpui::{AppContext, IntoElement, ParentElement, Styled, div, prelude::FluentBuilder};
|
use gpui::{AppContext, IntoElement, ParentElement, Styled, div, prelude::FluentBuilder, rems};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
api, app,
|
api, app,
|
||||||
@@ -120,7 +120,8 @@ impl Screen {
|
|||||||
.flex_col()
|
.flex_col()
|
||||||
.items_start()
|
.items_start()
|
||||||
.w_full()
|
.w_full()
|
||||||
.px_8()
|
.pl_6()
|
||||||
|
.pr_8()
|
||||||
.justify_center()
|
.justify_center()
|
||||||
.gap_3()
|
.gap_3()
|
||||||
.text_sm()
|
.text_sm()
|
||||||
@@ -165,9 +166,17 @@ impl gpui::Render for Screen {
|
|||||||
.bg(theme.colors.surface)
|
.bg(theme.colors.surface)
|
||||||
.relative()
|
.relative()
|
||||||
.child(
|
.child(
|
||||||
text("Novem")
|
div()
|
||||||
.bold()
|
.flex()
|
||||||
.styled(|it| it.absolute().top_20().left_8()),
|
.flex_row()
|
||||||
|
.justify_center()
|
||||||
|
.items_center()
|
||||||
|
.gap_2p5()
|
||||||
|
.absolute()
|
||||||
|
.top_20()
|
||||||
|
.left_6()
|
||||||
|
.child(font_icon(FontIcon::Cat).size_4())
|
||||||
|
.child(text("Novem").bold()),
|
||||||
)
|
)
|
||||||
.child(self.step_list(cx)),
|
.child(self.step_list(cx)),
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -6,6 +6,9 @@ use crate::api;
|
|||||||
#[derive(Default, Serialize, Deserialize)]
|
#[derive(Default, Serialize, Deserialize)]
|
||||||
pub(crate) struct PersistedState {
|
pub(crate) struct PersistedState {
|
||||||
pub selected_account: api::user::Id,
|
pub selected_account: api::user::Id,
|
||||||
|
|
||||||
|
#[cfg(debug_assertions)]
|
||||||
|
pub debug_auth_tokens: Option<api::AuthTokens>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn data_dir_path() -> std::path::PathBuf {
|
pub(crate) fn data_dir_path() -> std::path::PathBuf {
|
||||||
@@ -47,11 +50,17 @@ pub(crate) async fn load_auth_tokens(
|
|||||||
cx: &gpui::App,
|
cx: &gpui::App,
|
||||||
user_id: api::user::Id,
|
user_id: api::user::Id,
|
||||||
) -> Option<api::AuthTokens> {
|
) -> Option<api::AuthTokens> {
|
||||||
cx.read_credentials(&format!("https://github.com/user/{}", user_id))
|
if cfg!(debug_assertions) {
|
||||||
.await
|
// in debug mode, credentials are loaded from persisted state
|
||||||
.ok()?
|
// to avoid being prompted for permission to access keychain on macos
|
||||||
.and_then(|(_, password)| String::from_utf8(password).ok())
|
None
|
||||||
.map(|access_token| api::AuthTokens { access_token })
|
} else {
|
||||||
|
cx.read_credentials(&format!("https://github.com/user/{}", user_id))
|
||||||
|
.await
|
||||||
|
.ok()?
|
||||||
|
.and_then(|(_, password)| String::from_utf8(password).ok())
|
||||||
|
.map(|access_token| api::AuthTokens { access_token })
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn store_auth_tokens(
|
pub(crate) fn store_auth_tokens(
|
||||||
@@ -59,9 +68,16 @@ pub(crate) fn store_auth_tokens(
|
|||||||
user: &api::user::User,
|
user: &api::user::User,
|
||||||
cx: &gpui::App,
|
cx: &gpui::App,
|
||||||
) -> gpui::Task<anyhow::Result<()>> {
|
) -> gpui::Task<anyhow::Result<()>> {
|
||||||
cx.write_credentials(
|
if cfg!(debug_assertions) {
|
||||||
&format!("https://github.com/user/{}", user.id),
|
let r = update_persisted_state(|state| {
|
||||||
&format!("{}", user.id),
|
state.debug_auth_tokens = Some(tokens.clone());
|
||||||
tokens.access_token.as_bytes(),
|
});
|
||||||
)
|
gpui::Task::ready(r)
|
||||||
|
} else {
|
||||||
|
cx.write_credentials(
|
||||||
|
&format!("https://github.com/user/{}", user.id),
|
||||||
|
&format!("{}", user.id),
|
||||||
|
tokens.access_token.as_bytes(),
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user