Skip to content

Commit

Permalink
feat: ui finish
Browse files Browse the repository at this point in the history
  • Loading branch information
KonecnyDavid committed Sep 17, 2024
1 parent 1c65c72 commit 2e21cab
Show file tree
Hide file tree
Showing 33 changed files with 3,598 additions and 85 deletions.
2 changes: 1 addition & 1 deletion index.html
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Tauri + React + Typescript</title>
<title>DAREG - Device app</title>
</head>

<body>
Expand Down
20 changes: 20 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "datareg",
"private": true,
"version": "0.0.0",
"version": "0.0.1",
"type": "module",
"scripts": {
"dev": "vite",
Expand All @@ -15,6 +15,8 @@
"@heroicons/react": "^2.1.5",
"@hookform/resolvers": "^3.9.0",
"@tauri-apps/api": "^1",
"class-variance-authority": "^0.7.0",
"pretty-bytes": "^6.1.1",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-hook-form": "^7.52.2",
Expand Down
103 changes: 99 additions & 4 deletions src-tauri/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,110 @@
// Prevents additional console window on Windows in release, DO NOT REMOVE!!
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]

// Learn more about Tauri commands at https://tauri.app/v1/guides/features/command
use std::collections::VecDeque;
use tauri::{Manager, Window};

#[derive(Clone, serde::Serialize)]
enum Status {
Error,
Success,
Syncing,
Prepared,
}

#[derive(Clone, serde::Serialize)]
struct File {
file: String,
size: f64,
synchronized: f64,
status: Status,
}

// the payload type must implement `Serialize` and `Clone`.
#[derive(Clone, serde::Serialize)]
struct FilesStatus {
files: Vec<File>,
}

// init a background process on the command, and emit periodic events only to the window that used the command
#[tauri::command]
fn greet(name: &str) -> String {
format!("Hello, {}! You've been greeted from Rust!", name)
fn start_measurement(window: Window) {
let delay = std::time::Duration::from_millis(200);

std::thread::spawn(move || {
let mut file_index = 0;
let mut files = vec![
File {
file: "file1".to_string(),
size: 67676767767.0,
synchronized: 0.0,
status: Status::Syncing,
},
File {
file: "file2".to_string(),
size: 67767667676.0,
synchronized: 0.0,
status: Status::Prepared,
},
File {
file: "file3".to_string(),
size: 565656565656565.0,
synchronized: 0.0,
status: Status::Prepared,
},
];

loop {
files[file_index].synchronized += files[file_index].size / (10.0 * (1.0 / delay.as_secs_f64()));
files[file_index].status = Status::Syncing;

if files[file_index].synchronized >= files[file_index].size {
files[file_index].synchronized = files[file_index].size;
files[file_index].status = Status::Success;
file_index += 1;
}

window.emit("event-name", FilesStatus {files: files.clone()}).unwrap();
if file_index == files.len() {
break;
}

std::thread::sleep(delay);
}
});
}

fn setup_handler(app: &mut tauri::App) -> Result<(), Box<dyn std::error::Error + 'static>> {
let app_handle = app.handle();

println!("{}", app_handle.path_resolver().resource_dir().unwrap_or(std::path::PathBuf::new()).to_string_lossy());
println!("{}", app_handle.path_resolver().app_config_dir().unwrap_or(std::path::PathBuf::new()).to_string_lossy());
println!("{}", app_handle.path_resolver().app_data_dir().unwrap_or(std::path::PathBuf::new()).to_string_lossy());
println!("{}", app_handle.path_resolver().app_local_data_dir().unwrap_or(std::path::PathBuf::new()).to_string_lossy());
println!("{}", app_handle.path_resolver().app_cache_dir().unwrap_or(std::path::PathBuf::new()).to_string_lossy());
println!("{}", app_handle.path_resolver().app_log_dir().unwrap_or(std::path::PathBuf::new()).to_string_lossy());
println!("{}", tauri::api::path::data_dir().unwrap_or(std::path::PathBuf::new()).to_string_lossy());
println!("{}", tauri::api::path::local_data_dir().unwrap_or(std::path::PathBuf::new()).to_string_lossy());
println!("{}", tauri::api::path::cache_dir().unwrap_or(std::path::PathBuf::new()).to_string_lossy());
println!("{}", tauri::api::path::config_dir().unwrap_or(std::path::PathBuf::new()).to_string_lossy());
println!("{}", tauri::api::path::executable_dir().unwrap_or(std::path::PathBuf::new()).to_string_lossy());
println!("{}", tauri::api::path::public_dir().unwrap_or(std::path::PathBuf::new()).to_string_lossy());
println!("{}", tauri::api::path::runtime_dir().unwrap_or(std::path::PathBuf::new()).to_string_lossy());
println!("{}", tauri::api::path::template_dir().unwrap_or(std::path::PathBuf::new()).to_string_lossy());
println!("{}", tauri::api::path::font_dir().unwrap_or(std::path::PathBuf::new()).to_string_lossy());
println!("{}", tauri::api::path::home_dir().unwrap_or(std::path::PathBuf::new()).to_string_lossy());
println!("{}", tauri::api::path::audio_dir().unwrap_or(std::path::PathBuf::new()).to_string_lossy());
println!("{}", tauri::api::path::desktop_dir().unwrap_or(std::path::PathBuf::new()).to_string_lossy());
println!("{}", tauri::api::path::document_dir().unwrap_or(std::path::PathBuf::new()).to_string_lossy());
println!("{}", tauri::api::path::download_dir().unwrap_or(std::path::PathBuf::new()).to_string_lossy());
println!("{}", tauri::api::path::picture_dir().unwrap_or(std::path::PathBuf::new()).to_string_lossy());
Ok(())
}

fn main() {
tauri::Builder::default()
.invoke_handler(tauri::generate_handler![greet])
.setup(setup_handler)
.invoke_handler(tauri::generate_handler![start_measurement])
.run(tauri::generate_context!())
.expect("error while running tauri application");
}
6 changes: 3 additions & 3 deletions src-tauri/tauri.conf.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,9 @@
},
"windows": [
{
"title": "datareg",
"width": 800,
"height": 600
"title": "DAREG - Device App",
"width": 1400,
"height": 1000
}
],
"security": {
Expand Down
8 changes: 0 additions & 8 deletions src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,6 @@ const router = createBrowserRouter([
]);

function App() {
// const [greetMsg, setGreetMsg] = useState("");
// const [name, setName] = useState("");
//
// async function greet() {
// // Learn more about Tauri commands at https://tauri.app/v1/guides/features/command
// setGreetMsg(await invoke("greet", { name }));
// }

return (
<RouterProvider router={router} />
);
Expand Down
12 changes: 6 additions & 6 deletions src/components/blocks/Agenda/Agenda.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,14 @@ export const getPosition = (agendaFrom: Date, time: Date) => {
to.setMilliseconds(0)

const hours = Math.abs(to.getTime() - start.getTime()) / 36e5 - 1;
return hours * hourHeight + ((time.getMinutes() / 60) * hourHeight);
return hours * hourHeight + ((time.getMinutes() / 60) * hourHeight) + 24; // 24 is the padding of the agenda
};

const d = new Date();

export const events: Event[] = [
{id: "0", title: "Meeting with John", start: new Date(2024, 7, 5, 14, 0), end: new Date(2024, 7, 5, 16, 0), user: "John Doe"},
{id: "1", title: "Meeting with John", start: new Date(2024, 7, 5, 17, 0), end: new Date(2024, 7, 5, 18, 30), user: "John Doe"},
{id: "0", title: "Meeting with John", start: new Date(d.getFullYear(), d.getMonth(), d.getDate(), 14, 0), end: new Date(d.getFullYear(), d.getMonth(), d.getDate(), 16, 0), user: "John Doe"},
{id: "1", title: "Meeting with John", start: new Date(d.getFullYear(), d.getMonth(), d.getDate(), 17, 0), end: new Date(d.getFullYear(), d.getMonth(), d.getDate(), 18, 30), user: "John Doe"},
]

const Agenda = () => {
Expand All @@ -43,12 +45,10 @@ const Agenda = () => {
}, [scrollContainerRef.current]);

return (
<div className="rounded-lg border border-gray-300 h-full w-full p-6">
<div className="h-full overflow-y-scroll relative" ref={scrollContainerRef}>
<div className="rounded-lg border border-gray-300 p-6 h-full overflow-y-scroll relative" ref={scrollContainerRef}>
<CurrentHour agendaFrom={agendaFrom} time={time}/>
{hours.map((hour, idx) => <AgendaHour currentTime={time} time={hour} height={hourHeight} key={idx}/>)}
{events.map((event, idx) => <AgendaEvent event={event} agendaFrom={agendaFrom} key={idx}/>)}
</div>
</div>
)
}
Expand Down
2 changes: 1 addition & 1 deletion src/components/blocks/Agenda/AgendaEvent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ const AgendaEvent = ({ event, agendaFrom }: { event: Event, agendaFrom: Date })
position: "absolute",
top: start,
height: end - start,
width: `calc(100% - ${HOUR_WIDTH}px)`,
width: `calc(100% - ${HOUR_WIDTH}px - 3rem)`,
marginLeft: HOUR_WIDTH,
}}
className={twMerge("rounded-lg text-white p-6 cursor-pointer", isNow ? "bg-cyan-800" : "bg-cyan-500")}
Expand Down
15 changes: 15 additions & 0 deletions src/components/blocks/File/FileCard.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import Pill from "../../primitives/Pills/Pill.tsx";

const FileCard = () => {
return (
<div className="flex flex-col">
<h4 className="text-lg font-semibold">sample_202426252585.json</h4>
<div className="flex flex-row gap-2">
<span>300 MB / 588 MB</span>
<Pill title="Synchronizing" variant="primary" />
</div>
</div>
)
}

export default FileCard;
31 changes: 24 additions & 7 deletions src/components/blocks/Reservation/Experiments/Experiment.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,17 @@
import Pill, {PillVariant} from "../../../primitives/Pills/Pill.tsx";
import {twMerge} from "tailwind-merge";
import {Button} from "@headlessui/react";
import {XMarkIcon} from "@heroicons/react/24/solid";
import Skeleton from "../../../primitives/skeleton/Skeleton.tsx";
import {capitalizeFirstLetters} from "../../../../utils/format.ts";
import ExperimentState from "../../../../types/experiments/ExperimentState.ts";
import IExperiment from "../../../../types/experiments/Experiment.ts";


export type ExperimentState = "active" | "done" | "failed" | "prepared";

interface ExperimentProps {
state: ExperimentState;
experiment: IExperiment;
onDelete: () => void;
onSelect: () => void;
}

const resolveState = (state: ExperimentState): { pill: PillVariant, classes: string } => {
Expand All @@ -30,16 +36,27 @@ const resolveState = (state: ExperimentState): { pill: PillVariant, classes: str
pill: "secondary",
classes: ""
};
case "new":
return {
pill: "secondary",
classes: ""
};
}
}

const Experiment = ({state}: ExperimentProps) => {
const Experiment = ({experiment, onDelete, onSelect}: ExperimentProps) => {
const {state} = experiment;
const {pill, classes} = resolveState(state);
return (
<div
className={twMerge("rounded-lg flex flex-row items-center p-2 gap-2 cursor-pointer", classes, state !== "active" ? "border border-gray-300" : "")}>
<Pill title="Active" variant={pill}/>
Experiment 123
className={twMerge("rounded-lg flex flex-row items-center p-2 gap-2 group cursor-pointer", classes, state !== "active" ? "border border-gray-300" : "")}
onClick={onSelect}
>
<Pill title={capitalizeFirstLetters(state)} variant={pill}/>
{experiment.name !== "" ? <span>{experiment.name}</span> : <Skeleton className="w-32 h-6"/>}
<Button className="group-hover:opacity-100 opacity-0 size-6 text-red-600" onClick={onDelete}>
<XMarkIcon color="size-6"/>
</Button>
</div>
)
}
Expand Down
43 changes: 38 additions & 5 deletions src/components/blocks/Reservation/Experiments/ExperimentData.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,46 @@
import Pill from "../../../primitives/Pills/Pill.tsx";
import H4 from "../../../primitives/headings/H4.tsx";
import {useSetDialog} from "../../../../contexts/DialogContextProvider.tsx";
import FilesDialog from "../../../dialog/FilesDialog.tsx";
import FileStatus from "../../../../types/files/FileStatus.ts";
import {reduceFileSize} from "../../../../utils/files.ts";
import prettyBytes from 'pretty-bytes';


interface ExperimentDataProps {
fileStatus: FileStatus | null;
}

const resolveTitle = (fileStatus: FileStatus | null) => {
if (fileStatus == null) {
return "No Data";
}
if (fileStatus.files.some(f => f.status === "Error")) {
return "Error";
}
if (fileStatus.files.every(f => f.status === "Success")) {
return "Success";
}
return "Synchronizing";
}

const ExperimentData = ({fileStatus}: ExperimentDataProps) => {
const setDialog = useSetDialog();

const size = reduceFileSize("size", fileStatus?.files || []);
const synchronized = reduceFileSize("synchronized", fileStatus?.files || []);
const totalCount = fileStatus?.files.length || 0;
const synchronizedCount = fileStatus?.files.filter(f => f.status === "Success").length || 0;

const ExperimentData = () => {
return (
<div className="rounded-lg border border-gray-300 p-6">
<div className="rounded-lg border border-gray-300 p-6 relative">
<H4>Data</H4>
<div className="flex flex-row gap-2"><strong>Status:</strong> <Pill title="Synchronizing" variant="primary" /></div>
<div><strong>Loaded:</strong> 24.5 GB (245 Files)</div>
<div><strong>Transferred:</strong> 19.6 GB (200 Files)</div>
<div className="flex flex-row gap-2"><strong>Status:</strong> <Pill title={resolveTitle(fileStatus)} variant="primary" /></div>
<div><strong>Loaded:</strong> {prettyBytes(size)} ({totalCount} Files)</div>
<div><strong>Transferred:</strong> {prettyBytes(synchronized)} ({synchronizedCount} Files)</div>
<div className="absolute right-6 top-6 underline cursor-pointer" onClick={() => setDialog(<FilesDialog />)}>
File Status
</div>
</div>
)
}
Expand Down
Loading

0 comments on commit 2e21cab

Please sign in to comment.