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

feat: support list bucket files #4

Merged
merged 3 commits into from
Feb 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions client/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ serde_json = "1.0.78"
wasm-bindgen-futures = "0.4.29"
yew-router = "0.16.0"
serde = "1.0.136"
serde-wasm-bindgen = "0.6.5"

[dependencies.web-sys]
version = "0.3.57"
Expand Down
3 changes: 2 additions & 1 deletion client/src/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,12 @@ pub fn App(props: &AppProps) -> Html {
<ContextProvider<AppContext> context={AppContext {
user: props.user.clone(),
upload_file: props.upload_file.clone(),
list_bucket: props.list_bucket.clone(),
}}>
<BrowserRouter>
<Header/>
<Switch<Route> render={Switch::render(switch)} />
</BrowserRouter>
</ContextProvider<AppContext>>
}
}
}
101 changes: 101 additions & 0 deletions client/src/component/bucket.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
use js_sys::Promise;
use serde_json::{Value};
use wasm_bindgen::JsValue;
use wasm_bindgen_futures::{spawn_local, JsFuture};
use yew::{prelude::{function_component, html}, Html, Properties, use_context, use_effect, use_state, use_effect_with_deps};
use web_sys::{console};
use serde_wasm_bindgen::from_value;
use serde::{Deserialize};

use crate::constants::app::AppContext;

#[derive(Deserialize, PartialEq, Clone)]
pub struct File {
Key: Value,
Size: Value,
}

#[derive(Deserialize)]
pub struct BucketInfo {
Contents: Vec<File>,
}


#[function_component(Bucket)]
pub fn bucket() -> Html {
let list_fetch_in_content = use_context::<AppContext>()
.expect("no ctx list_fetch_in_content found").list_bucket;
let list = use_state(|| None);
let fetched = use_state(|| false);

{
let list_fetch_in_content = list_fetch_in_content.clone();
let list_clone = list.clone();
let fetched_clone = fetched.clone();
use_effect_with_deps(
move |&fetched| {
let cleanup = || {};
if fetched {
return cleanup;
}
spawn_local(async move {
let result = list_fetch_in_content.call0(&JsValue::NULL).unwrap();
let promise = Promise::from(result);
let data = JsFuture::from(promise).await.unwrap();
console::log_2(&JsValue::from_str("data"), &data);
let info: BucketInfo = from_value(data).unwrap();
list_clone.set(Some(info.Contents));
fetched_clone.set(true);
});
cleanup
},
*fetched
)
}

let list = list.as_ref();
html! {
<div>
<h2>{"Bucket"}</h2>
<ul>
{
if list.is_some() {
html! {
<table>
<thead>
<tr>
<th>{"File"}</th>
<th>{"Size (bytes)"}</th>
</tr>
</thead>
<tbody>
{for list.unwrap().iter().map(|file| file_item(file))}
</tbody>
</table>

}
} else {
html! { "loading" }
}
}

</ul>
</div>
}
}

fn file_item(file: &File) -> Html {
let file_size = file.Size.as_str().unwrap();
let href = format!("https://cdn.ebichu.cc/{}", file.Key.as_str().unwrap());
let file_key2 = file.Key.clone();
html! { <tr>
<td>
<a href={href.to_owned()} target="_blank">
{file_key2.as_str().unwrap()}
</a>
</td>
<td>
{file_size}
</td>
</tr> }
}
9 changes: 4 additions & 5 deletions client/src/component/me.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use yew::{prelude::{function_component, html}, use_context};
use js_sys::{JSON::stringify_with_replacer_and_space};
use yew_router::prelude::{Redirect};
use wasm_bindgen::{JsValue};
use yew::{use_state, use_effect_with_deps};
use yew::{use_state, use_effect};

use crate::{constants::app::Route, helpers::{request::auth::fetch_user, user::parse_user}};

Expand All @@ -17,8 +17,8 @@ pub fn me() -> Html {
{
let user_state = user_state.clone();
let fetched_clone = fetched.clone();
use_effect_with_deps(
move |_| {
use_effect(
move || {
spawn_local(async move {
let user = fetch_user().await.unwrap();
let user = parse_user(user);
Expand All @@ -27,7 +27,6 @@ pub fn me() -> Html {
});
|| {}
},
*fetched,
)
}
match &*fetched {
Expand All @@ -47,4 +46,4 @@ pub fn me() -> Html {
<pre>{stringify_with_replacer_and_space(&user_obj, &JsValue::NULL, &JsValue::from_f64(4.0)).unwrap()}</pre>
</div>
}
}
}
1 change: 1 addition & 0 deletions client/src/component/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ pub mod graph;
mod header;
mod login;
mod me;
pub mod bucket;

pub use header::*;
pub use login::*;
Expand Down
4 changes: 3 additions & 1 deletion client/src/constants/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,14 @@ use crate::constants::auth::User;
#[derive(Clone, Debug, PartialEq)]
pub struct AppContext {
pub upload_file: Function,
pub list_bucket: Function,
pub user: Option<User>,
}

#[derive(Properties, PartialEq)]
pub struct AppProps {
pub upload_file: Function,
pub list_bucket: Function,
pub user: Option<User>,
}

Expand All @@ -27,4 +29,4 @@ pub enum Route {
#[not_found]
#[at("/404")]
NotFound,
}
}
22 changes: 13 additions & 9 deletions client/src/container/home.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use yew::{prelude::*, virtual_dom::VNode,function_component};
use yew_router::prelude::*;

use crate::component::graph::Graph;
use crate::component::bucket::Bucket;
use crate::constants::app::AppContext;

pub struct HomeInner {
Expand Down Expand Up @@ -71,14 +72,17 @@ impl Component for HomeInner {
let link = context.link();
html! {
<div>
<p>{ "count " } { self.value } </p>
<button onclick={link.callback(|_| Msg::AddOne)}>{ "+1" }</button>
<p>{ "Hello world!" }</p>
<form method="post" enctype="multipart/form-data" action="/upload">
<input type="file" name="file"/>
<button type="submit">{"Submit"}</button>
</form>
<Graph/>
<div class="hidden">
<p>{ "count " } { self.value } </p>
<button onclick={link.callback(|_| Msg::AddOne)}>{ "+1" }</button>
<p>{ "Hello world!" }</p>
<form class="hidden" method="post" enctype="multipart/form-data" action="/upload">
<input type="file" name="file"/>
<button type="submit">{"Submit"}</button>
</form>
<Graph/>
</div>
<Bucket/>
<h2>{"Upload"}</h2>
<input type="file" onchange={link.callback(|e| Msg::FileChange(e))}/>
<p>
Expand All @@ -99,4 +103,4 @@ impl Component for HomeInner {
pub fn HomeHOC() -> Html {
let app_ctx = use_context::<AppContext>().expect("no ctx found");
html! { <HomeInner upload_file={app_ctx.upload_file}/> }
}
}
5 changes: 4 additions & 1 deletion client/src/css/index.styl
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,7 @@ nav
text-decoration: none
&.active
color: red
text-decoration: underline
text-decoration: underline

.hidden
display: none
23 changes: 23 additions & 0 deletions client/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -55,9 +55,32 @@ function handleFileChange(e) {
})
}

function listBucket() {
return new Promise((resolve, reject) => {
cos.getBucket({
Bucket: 'kimi-1251502833', /* 填入您自己的存储桶,必须字段 */
Region: 'ap-beijing', /* 存储桶所在地域,例如ap-beijing,必须字段 */
Prefix: 'cos-test/', /* Prefix表示列出的object的key以prefix开始,非必须 */
Delimiter: '/', /* Deliter表示分隔符, 设置为/表示列出当前目录下的object, 设置为空表示列出所有的object,非必须 */
}, function(err, data) {
if (err) {
reject(err);
console.error('list folder fail', err);
} else {
resolve(data);
console.info('list folder success', data);
}
});

})
}

window.listBucket = listBucket

wasm().then(({ run_app }) => {
run_app({
handleFileChange,
listBucket,
user: window.app.user,
});
});
7 changes: 6 additions & 1 deletion client/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,14 @@ pub fn run_app(props: Object) -> Result<(), JsValue> {
let document = window.document().expect("document not existed");
let element = document.get_element_by_id("app").unwrap_throw();
let upload_file: Function = Reflect::get(&props, &JsValue::from_str("handleFileChange")).unwrap().into();
let list_bucket: Function = Reflect::get(&props, &JsValue::from_str("listBucket")).unwrap().into();
let user_obj: JsValue = Reflect::get(&props, &JsValue::from_str("user")).unwrap();
let user: Option<User> = helpers::user::parse_user(user_obj);
yew::start_app_with_props_in_element::<app::Main>(element, AppProps { upload_file, user });
yew::start_app_with_props_in_element::<app::Main>(element, AppProps {
upload_file,
list_bucket,
user,
});

Ok(())
}
Loading