Skip to content

Commit

Permalink
feat(crypto-helper): table: implement table view for jwt header and p…
Browse files Browse the repository at this point in the history
…ayload
  • Loading branch information
TheBestTvarynka committed Dec 8, 2023
1 parent 8e0ff02 commit f38ec9d
Show file tree
Hide file tree
Showing 6 changed files with 128 additions and 6 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
dist/
target/
test_keys/
.idea/
24 changes: 23 additions & 1 deletion public/styles/style.scss
Original file line number Diff line number Diff line change
Expand Up @@ -175,4 +175,26 @@ article {

.action-button:focus {
box-shadow: 0 0 0 2px #314157;
}
}

.table-container {
background: #e0e0e0;
width: 100%;
display: grid;
grid-template-columns: 30% auto;
gap: 0.2em;
}

.table-cell {
padding: 0.2em;
background: #dbcfbf;
cursor: pointer;
color: #50437f;
border-radius: 0.2em;
border: 2px solid transparent;
}

.table-cell:hover {
transition: all 0.3s;
border: 2px solid #50437f;
}
2 changes: 2 additions & 0 deletions src/common/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,14 @@ mod bytes_viewer;
mod checkbox;
mod simple_output;
mod switch;
mod table;

pub use byte_input::{build_byte_input, ByteInput, ByteInputProps};
pub use bytes_viewer::{BytesViewer, BytesViewerProps};
pub use checkbox::{Checkbox, CheckboxProps};
pub use simple_output::build_simple_output;
pub use switch::{Switch, SwitchProps};
pub use table::{TableView, TableViewProps};
use web_sys::MouseEvent;
use yew::{classes, Callback, Classes, UseStateSetter};

Expand Down
71 changes: 71 additions & 0 deletions src/common/table.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
use serde_json::Value;
use yew::virtual_dom::VNode;
use yew::{function_component, html, Callback, Html, Properties};
use yew_hooks::use_clipboard;
use yew_notifications::{use_notification, Notification, NotificationType};

#[derive(Properties, PartialEq, Debug, Clone)]
pub struct TableViewProps {
pub value: Value,
}

#[function_component(TableView)]
pub fn table_view(props: &TableViewProps) -> Html {
let clipboard = use_clipboard();
let copy_text = Callback::from(move |text: String| clipboard.write_text(text.clone()));
let notifications = use_notification::<Notification>();
let spawn_notification = Callback::from(move |notification| notifications.spawn(notification));

html! {
<div class="table-container">
{build_cells(&props.value, copy_text, spawn_notification)}
</div>
}
}

fn format_json_value(value: &Value, copy_text: Callback<String>, spawn_notification: Callback<Notification>) -> VNode {
let data = match value {
Value::Null => String::from("Null"),
Value::Bool(bool) => format!("{}", bool),
Value::Number(number) => format!("{}", number),
Value::String(string) => string.clone(),
Value::Array(array) => serde_json::to_string(array).unwrap(),
Value::Object(obj) => serde_json::to_string(obj).unwrap(),
};
let data_to_copy = data.clone();
let onclick = Callback::from(move |_| {
copy_text.emit(data_to_copy.clone());
spawn_notification.emit(Notification::from_description_and_type(
NotificationType::Info,
"Copied!",
));
});
html! {
<span class="table-cell" {onclick}>{data}</span>
}
}

fn build_cells(value: &Value, copy_text: Callback<String>, spawn_notification: Callback<Notification>) -> Vec<VNode> {
if let Some(obj) = value.as_object() {
obj.iter()
.flat_map(|(key, value)| {
let key_copy_text = copy_text.clone();
let key_notification = spawn_notification.clone();
let key_value = key.to_owned();
let on_key_click = Callback::from(move |_| {
key_copy_text.emit(key_value.clone());
key_notification.emit(Notification::from_description_and_type(
NotificationType::Info,
"Copied!",
));
});
vec![
html! { <span class="table-cell" onclick={on_key_click}>{key}</span> },
format_json_value(value, copy_text.clone(), spawn_notification.clone()),
]
})
.collect()
} else {
vec![format_json_value(value, copy_text, spawn_notification)]
}
}
34 changes: 30 additions & 4 deletions src/jwt/jwt/editor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@ use std::fmt::Debug;

use serde_json::{to_string_pretty, Value};
use web_sys::{HtmlInputElement, MouseEvent};
use yew::{function_component, html, Callback, Html, Properties, TargetCast};
use yew::{function_component, html, use_state, Callback, Html, Properties, TargetCast};
use yew_hooks::use_clipboard;
use yew_notifications::{use_notification, Notification, NotificationType};

use super::Jwt;
use crate::common::{build_simple_output, BytesFormat};
use crate::common::{build_simple_output, BytesFormat, Switch, TableView};
use crate::utils::copy_to_clipboard_with_notification;

#[derive(PartialEq, Properties)]
Expand Down Expand Up @@ -142,6 +142,14 @@ pub fn jwt_editor(props: &JwtEditorProps) -> Html {
set_jwt.emit(jwt);
});

// false - raw view
// true - table view
let header_view = use_state(|| true);
let payload_view = use_state(|| true);

let header_view_setter = header_view.setter();
let payload_view_setter = payload_view.setter();

let notifications = use_notification::<Notification>();
let clipboard = use_clipboard();

Expand All @@ -152,16 +160,34 @@ pub fn jwt_editor(props: &JwtEditorProps) -> Html {
<span class="jwt-header" onclick={copy_to_clipboard_with_notification(header.clone(), clipboard.clone(), "Header", notifications.clone())}>{"Header"}</span>
<button onclick={header_on_pretty} class="jwt-util-button">{"Prettify"}</button>
<button onclick={header_on_minify} class="jwt-util-button">{"Minify"}</button>
<div class="horizontal">
<span class="total">{"raw"}</span>
<Switch id={String::from("jwt-header-view")} state={*header_view} setter={Callback::from(move |view| header_view_setter.set(view))} />
<span class="total">{"table"}</span>
</div>
</div>
<textarea rows="4" class="base-input" value={header} oninput={on_header_input} />
{if !*header_view {html! {
<textarea rows="4" class="base-input" value={header} oninput={on_header_input} />
}} else {html! {
<TableView value={serde_json::from_str::<Value>(&props.jwt.parsed_header).unwrap()} />
}}}
</div>
<div class="vertical">
<div class="horizontal">
<span class="jwt-payload" onclick={copy_to_clipboard_with_notification(payload.clone(), clipboard.clone(), "Payload", notifications.clone())}>{"Payload"}</span>
<button onclick={payload_on_pretty} class="jwt-util-button">{"Prettify"}</button>
<button onclick={payload_on_minify} class="jwt-util-button">{"Minify"}</button>
<div class="horizontal">
<span class="total">{"raw"}</span>
<Switch id={String::from("jwt-payload-view")} state={*payload_view} setter={Callback::from(move |view| payload_view_setter.set(view))} />
<span class="total">{"table"}</span>
</div>
</div>
<textarea rows="6" class="base-input" value={payload} oninput={on_payload_input} />
{if !*payload_view {html! {
<textarea rows="6" class="base-input" value={payload} oninput={on_payload_input} />
}} else {html! {
<TableView value={serde_json::from_str::<Value>(&props.jwt.parsed_payload).unwrap()} />
}}}
</div>
<div class="vertical">
<span class="jwt-signature" onclick={copy_to_clipboard_with_notification(signature.clone(), clipboard, "Signature", notifications.clone())}>{"Signature"}</span>
Expand Down
2 changes: 1 addition & 1 deletion src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ fn switch(routes: Route) -> Html {

#[function_component(App)]
pub fn app() -> Html {
let component_creator = NotificationFactory::default();
let component_creator = NotificationFactory;

html! {
<BrowserRouter>
Expand Down

0 comments on commit f38ec9d

Please sign in to comment.