Support copy sql with result

This commit is contained in:
Spxg
2025-05-22 01:27:44 +08:00
parent 50e620ba38
commit 097133d749
5 changed files with 261 additions and 14 deletions

View File

@@ -1,12 +1,13 @@
use istyles::istyles;
use leptos::{html::Input, prelude::*, tachys::html};
use prettytable::{Cell, Row, Table};
use reactive_stores::Store;
use wasm_bindgen::{JsCast, prelude::Closure};
use web_sys::{Blob, Event, FileReader, HtmlInputElement, Url, UrlSearchParams};
use crate::{
DownloadDbOptions, FragileComfirmed, LoadDbOptions, PrepareOptions, SQLightError,
WorkerRequest,
SQLiteStatementResult, WorkerRequest,
app::{
ImportProgress,
advanced_options_menu::AdvancedOptionsMenu,
@@ -358,6 +359,44 @@ fn ShareButton() -> impl IntoView {
return;
};
let mut offset_inserts = vec![];
for result in &*state.output().read() {
let mut table_s = Table::new();
match result {
SQLiteStatementResult::Finish => continue,
SQLiteStatementResult::Step(table) => {
let end = table.position[1];
if let Some(values) = &table.values {
table_s.add_row(Row::new(
values.columns.iter().map(|s| Cell::new(s)).collect(),
));
for row in &values.rows {
table_s.add_row(Row::new(row.iter().map(|s| Cell::new(s)).collect()));
}
let result = table_s
.to_string()
.lines()
.map(|x| format!("-- {x}"))
.collect::<Vec<String>>()
.join("\n");
offset_inserts.push((end, format!("\n-- Output:\n{result}\n")));
}
}
}
}
let mut sql_with_result = code.clone();
for (idx, result) in offset_inserts.into_iter().rev() {
sql_with_result.insert_str(idx, &result);
}
state.share_sql_with_result().set(Some(sql_with_result));
if let Ok(href) = window().location().href().and_then(|href| {
let url = Url::new(&href)?;
let params = UrlSearchParams::new()?;
@@ -366,8 +405,9 @@ fn ShareButton() -> impl IntoView {
Ok(url.href())
}) {
state.share_href().set(Some(href));
change_focus(state, Some(Focus::Share));
}
change_focus(state, Some(Focus::Share));
};
view! { <Button on_click=click>"Share"</Button> }

View File

@@ -3,27 +3,29 @@ use std::{sync::Arc, time::Duration};
use istyles::istyles;
use leptos::prelude::*;
use reactive_stores::Store;
use wasm_bindgen::JsValue;
use wasm_bindgen_futures::{JsFuture, spawn_local};
use web_sys::{Blob, BlobPropertyBag, Url};
use crate::app::{GlobalState, GlobalStateStoreFields, icon::clipboard_icon};
istyles!(styles, "assets/module.postcss/output/share.module.css.map");
#[component]
fn Copied<H>(href: H, children: Children) -> impl IntoView
fn Copied<S, H>(shared: S, href: H, children: Children) -> impl IntoView
where
S: Fn() -> String + Send + Sync + 'static,
H: Fn() -> String + Send + Sync + 'static,
{
let (copied, set_copied) = signal(false);
let href = Arc::new(href);
let href1 = Arc::clone(&href);
let shared = Arc::new(shared);
let copy = move |_| {
let href = Arc::clone(&href1);
let shared = Arc::clone(&shared);
spawn_local(async move {
set_copied.set(true);
if let Err(err) =
JsFuture::from(window().navigator().clipboard().write_text(&href())).await
JsFuture::from(window().navigator().clipboard().write_text(&shared())).await
{
log::error!("Failed to write href to clipboard: {err:?}");
}
@@ -33,7 +35,9 @@ where
view! {
<p class=move || { if *copied.read() { styles::active } else { styles::container } }>
<a href=move || href()>{children()}</a>
<a href=href target="_blank">
{children()}
</a>
<button class=styles::button on:click=copy>
{clipboard_icon()}
</button>
@@ -43,13 +47,66 @@ where
}
#[component]
fn Links() -> impl IntoView {
fn EmbeddedLinks() -> impl IntoView {
let state = expect_context::<Store<GlobalState>>();
let code_url = move || state.share_href().get_untracked().unwrap_or_default();
view! { <Copied href=code_url>Embedded code in link</Copied> }
let shared = move || state.share_href().get_untracked().unwrap_or_default();
let href = move || state.share_href().get_untracked().unwrap_or_default();
view! {
<Copied shared=shared href=href>
"Embedded code in link"
</Copied>
}
}
#[component]
fn SQLWithResultLinks() -> impl IntoView {
let state = expect_context::<Store<GlobalState>>();
let shared = move || {
state
.share_sql_with_result()
.get_untracked()
.unwrap_or_default()
};
let href = move || {
let text = state
.share_sql_with_result()
.get_untracked()
.unwrap_or_default();
let string_array = js_sys::Array::new();
string_array.push(&JsValue::from(text));
let blob_properties = BlobPropertyBag::new();
blob_properties.set_type("text/plain");
let blob =
Blob::new_with_str_sequence_and_options(&string_array, &blob_properties).unwrap();
let url = Url::create_object_url_with_blob(&blob).unwrap();
let url1 = url.clone();
set_timeout(
move || Url::revoke_object_url(&url1).unwrap(),
Duration::from_millis(5000),
);
url
};
view! {
<Copied shared=shared href=href>
"[Need run first] Copy sql with result"
</Copied>
}
}
#[component]
pub fn Share() -> impl IntoView {
view! { <Links /> }
view! {
<>
<EmbeddedLinks />
<SQLWithResultLinks />
</>
}
}

View File

@@ -48,6 +48,8 @@ pub struct GlobalState {
#[serde(skip)]
share_href: Option<String>,
#[serde(skip)]
share_sql_with_result: Option<String>,
#[serde(skip)]
show_something: bool,
#[serde(skip)]
output: Vec<SQLiteStatementResult>,
@@ -75,6 +77,7 @@ impl Default for GlobalState {
is_focused: false,
opened_focus: HashSet::new(),
share_href: None,
share_sql_with_result: None,
show_something: false,
output: Vec::new(),
last_error: None,