Skip to content

Commit

Permalink
minor tweak
Browse files Browse the repository at this point in the history
  • Loading branch information
XiangpengHao committed Dec 30, 2024
1 parent 9298a54 commit 19da2c3
Show file tree
Hide file tree
Showing 4 changed files with 174 additions and 127 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ Online at: https://parquet-viewer.xiangpeng.systems

### Features

- Query parquet data with SQL (if you're resistance)
- Query parquet data with natural language through LLM (if you're enlightened)
- Query parquet data with SQL ✅
- Query parquet data with natural language through LLM ✅
- View Parquet metadata ✅
- View Parquet files from anywhere -- local file, S3, or any URLs ✅
- Everything runs in the browser, no server, no external dependencies, just a web page ✅
Expand Down
13 changes: 11 additions & 2 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,15 @@ fn App() -> impl IntoView {

let (force_update_user_input, set_force_update_user_input) = signal(false);

let toggle_display = move |id: usize| {
set_query_results.update(|r| {
r.iter_mut()
.find(|r| r.id() == id)
.unwrap()
.toggle_display();
});
};

Effect::watch(
parquet_reader,
move |reader, old_reader, _| {
Expand Down Expand Up @@ -445,12 +454,12 @@ fn App() -> impl IntoView {

<div class="space-y-4">
<For
each=move || query_results.get().into_iter().rev()
each=move || query_results.get().into_iter().filter(|r| r.display()).rev()
key=|result| result.id()
children=move |result| {
view! {
<div class="transform transition-all duration-300 ease-out animate-slide-in">
<QueryResultView result=result />
<QueryResultView result=result toggle_display=toggle_display />
</div>
}
}
Expand Down
263 changes: 146 additions & 117 deletions src/query_results.rs
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ pub(crate) struct QueryResult {
sql_query: String,
query_result: Arc<Vec<RecordBatch>>,
physical_plan: Arc<dyn ExecutionPlan>,
display: bool,
}

impl QueryResult {
Expand All @@ -118,151 +119,180 @@ impl QueryResult {
sql_query,
query_result,
physical_plan,
display: true,
}
}

pub(crate) fn display(&self) -> bool {
self.display
}

pub(crate) fn toggle_display(&mut self) {
self.display = !self.display;
}

pub(crate) fn id(&self) -> usize {
self.id
}
}

#[component]
pub fn QueryResultView(result: QueryResult) -> impl IntoView {
pub fn QueryResultView(
result: QueryResult,
toggle_display: impl Fn(usize) + 'static,
) -> impl IntoView {
let (show_plan, set_show_plan) = signal(false);
let query_result_clone1 = result.query_result.clone();
let query_result_clone2 = result.query_result.clone();
let sql = result.sql_query.clone();
let sql_clone = sql.clone();
let id = result.id();

Effect::new(move |_| {
let _window = web_sys::window().unwrap();
let _ = js_sys::eval("hljs.highlightAll()");
|| ()
});
let tooltip_classes = "absolute bottom-full left-1/2 transform -translate-x-1/2 px-2 py-1 bg-gray-800 text-white text-xs rounded opacity-0 group-hover:opacity-100 whitespace-nowrap pointer-events-none";
let base_button_classes = "p-2 text-gray-500 hover:text-gray-700 relative group";
let svg_classes = "h-5 w-5";

view! {
<div class="mt-4 p-4 bg-white border border-gray-300 rounded-md hover:shadow-lg transition-shadow duration-200">
<div class="relative">
<div class="absolute top-0 right-0 z-10">
<div class="flex items-center gap-1 rounded-md">
<div class="text-sm text-gray-500 font-mono relative group">
<span class="absolute bottom-full left-1/2 transform -translate-x-1/2 px-2 py-1 bg-gray-800 text-white text-xs rounded opacity-0 group-hover:opacity-100 whitespace-nowrap pointer-events-none">
{format!("SELECT * FROM view_{}", result.id())}
<span class=tooltip_classes>
{format!("SELECT * FROM view_{}", id)}
</span>
{format!("view_{}", result.id())}
{format!("view_{}", id)}
</div>
<button
class="p-2 text-gray-500 hover:text-gray-700 relative group"
aria-label="Export to CSV"
on:click=move |_| {
export_to_csv_inner(&query_result_clone2);
}
>
<span class="absolute bottom-full left-1/2 transform -translate-x-1/2 px-2 py-1 bg-gray-800 text-white text-xs rounded opacity-0 group-hover:opacity-100 whitespace-nowrap pointer-events-none">
"Export to CSV"
</span>
<svg
xmlns="http://www.w3.org/2000/svg"
class="h-5 w-5"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M8 7H5a2 2 0 00-2 2v9a2 2 0 002 2h14a2 2 0 002-2V9a2 2 0 00-2-2h-3m-1 4l-3 3m0 0l-3-3m3 3V4"
/>
</svg>
</button>
<button
class="p-2 text-gray-500 hover:text-gray-700 relative group"
aria-label="Export to Parquet"
on:click=move |_| {
export_to_parquet_inner(&query_result_clone1);
}
>
<span class="absolute bottom-full left-1/2 transform -translate-x-1/2 px-2 py-1 bg-gray-800 text-white text-xs rounded opacity-0 group-hover:opacity-100 whitespace-nowrap pointer-events-none">
"Export to Parquet"
</span>
<svg
xmlns="http://www.w3.org/2000/svg"
class="h-5 w-5"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M8 7H5a2 2 0 00-2 2v9a2 2 0 002 2h14a2 2 0 002-2V9a2 2 0 00-2-2h-3m-1 4l-3 3m0 0l-3-3m3 3V4"
/>
</svg>
</button>
<button
class="p-2 text-gray-500 hover:text-gray-700 relative group animate-on-click"
aria-label="Copy SQL"
on:click=move |_| {
let window = web_sys::window().unwrap();
let navigator = window.navigator();
let clipboard = navigator.clipboard();
let _ = clipboard.write_text(&sql);
}
>
<style>
{".animate-on-click:active { animation: quick-bounce 0.2s; }
@keyframes quick-bounce {
0%, 100% { transform: scale(1); }
50% { transform: scale(0.95); }
}"}
</style>
<span class="absolute bottom-full left-1/2 transform -translate-x-1/2 px-2 py-1 bg-gray-800 text-white text-xs rounded opacity-0 group-hover:opacity-100 whitespace-nowrap pointer-events-none">
"Copy SQL"
</span>
<svg
xmlns="http://www.w3.org/2000/svg"
class="h-5 w-5"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M8 5H6a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2v-1M8 5a2 2 0 002 2h2a2 2 0 002-2M8 5a2 2 0 012-2h2a2 2 0 012 2m0 0h2a2 2 0 012 2v3m2 4H10m0 0l3-3m-3 3l3 3"
/>
</svg>
</button>
<button
class=move || {
format!(
"p-2 text-gray-500 hover:text-gray-700 relative group {}",
if show_plan() { "text-blue-600" } else { "" },
)
{
view! {
<button
class=base_button_classes
aria-label="Export to CSV"
on:click=move |_| export_to_csv_inner(&query_result_clone2)
>
<span class=tooltip_classes>"Export to CSV"</span>
<svg
xmlns="http://www.w3.org/2000/svg"
class=svg_classes
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M8 7H5a2 2 0 00-2 2v9a2 2 0 002 2h14a2 2 0 002-2V9a2 2 0 00-2-2h-3m-1 4l-3 3m0 0l-3-3m3 3V4"
/>
</svg>
</button>
<button
class=base_button_classes
aria-label="Export to Parquet"
on:click=move |_| export_to_parquet_inner(&query_result_clone1)
>
<span class=tooltip_classes>"Export to Parquet"</span>
<svg
xmlns="http://www.w3.org/2000/svg"
class=svg_classes
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M8 7H5a2 2 0 00-2 2v9a2 2 0 002 2h14a2 2 0 002-2V9a2 2 0 00-2-2h-3m-1 4l-3 3m0 0l-3-3m3 3V4"
/>
</svg>
</button>
<button
class=format!("{} animate-on-click", base_button_classes)
aria-label="Copy SQL"
on:click=move |_| {
let window = web_sys::window().unwrap();
let navigator = window.navigator();
let clipboard = navigator.clipboard();
let _ = clipboard.write_text(&sql);
}
>
<style>
{".animate-on-click:active { animation: quick-bounce 0.2s; }
@keyframes quick-bounce {
0%, 100% { transform: scale(1); }
50% { transform: scale(0.95); }
}"}
</style>
<span class=tooltip_classes>"Copy SQL"</span>
<svg
xmlns="http://www.w3.org/2000/svg"
class=svg_classes
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M8 5H6a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2v-1M8 5a2 2 0 002 2h2a2 2 0 002-2M8 5a2 2 0 012-2h2a2 2 0 012 2m0 0h2a2 2 0 012 2v3m2 4H10m0 0l3-3m-3 3l3 3"
/>
</svg>
</button>
<button
class=format!(
"{} {}",
base_button_classes,
if show_plan() { "text-blue-600" } else { "" },
)
aria-label="Execution plan"
on:click=move |_| set_show_plan.update(|v| *v = !*v)
>
<span class=tooltip_classes>"Execution plan"</span>
<svg
xmlns="http://www.w3.org/2000/svg"
class=svg_classes
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"
/>
</svg>
</button>
<button
class=format!("{} hover:text-red-600", base_button_classes)
aria-label="Hide"
on:click=move |_| toggle_display(id)
>
<span class=tooltip_classes>"Hide"</span>
<svg
xmlns="http://www.w3.org/2000/svg"
class=svg_classes
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M6 18L18 6M6 6l12 12"
/>
</svg>
</button>
}
aria-label="Execution plan"
on:click=move |_| set_show_plan.update(|v| *v = !*v)
>
<span class="absolute bottom-full left-1/2 transform -translate-x-1/2 px-2 py-1 bg-gray-800 text-white text-xs rounded opacity-0 group-hover:opacity-100 whitespace-nowrap pointer-events-none">
"Execution plan"
</span>
<svg
xmlns="http://www.w3.org/2000/svg"
class="h-5 w-5"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"
/>
</svg>
</button>
}
</div>
</div>

Expand All @@ -284,7 +314,6 @@ pub fn QueryResultView(result: QueryResult) -> impl IntoView {
})
}}

// Always show query results
<div class="max-h-[32rem] overflow-auto relative">
<table class="min-w-full bg-white table-fixed">
<thead class="sticky top-0 z-10">
Expand Down
Loading

0 comments on commit 19da2c3

Please sign in to comment.