initial frontend

This commit is contained in:
2024-10-20 12:37:40 -07:00
parent 4d5b525288
commit e22245998f
29 changed files with 338 additions and 7 deletions

7
Cargo.lock generated
View File

@@ -798,6 +798,12 @@ version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024"
[[package]]
name = "hex"
version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
[[package]]
name = "http"
version = "0.2.12"
@@ -1485,6 +1491,7 @@ dependencies = [
"chrono",
"derive_more 1.0.0",
"fern",
"hex",
"log",
"prost",
"rand",

View File

@@ -22,7 +22,7 @@ struct Telemetry {
}
struct TelemetryItemHandle {
uuid: Vec<u8>,
uuid: String,
tx: Sender<TelemetryItem>,
}

6
frontend/.editorconfig Normal file
View File

@@ -0,0 +1,6 @@
[*.{js,jsx,mjs,cjs,ts,tsx,mts,cts,vue}]
charset = utf-8
indent_size = 2
indent_style = space
insert_final_newline = true
trim_trailing_whitespace = true

30
frontend/.gitignore vendored Normal file
View File

@@ -0,0 +1,30 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*
node_modules
.DS_Store
dist
dist-ssr
coverage
*.local
/cypress/videos/
/cypress/screenshots/
# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?
*.tsbuildinfo

View File

@@ -0,0 +1,7 @@
{
"$schema": "https://json.schemastore.org/prettierrc",
"semi": false,
"singleQuote": true,
"arrowParens": "avoid"
}

7
frontend/.vscode/extensions.json vendored Normal file
View File

@@ -0,0 +1,7 @@
{
"recommendations": [
"Vue.volar",
"dbaeumer.vscode-eslint",
"esbenp.prettier-vscode"
]
}

39
frontend/README.md Normal file
View File

@@ -0,0 +1,39 @@
# frontend
This template should help get you started developing with Vue 3 in Vite.
## Recommended IDE Setup
[VSCode](https://code.visualstudio.com/) + [Volar](https://marketplace.visualstudio.com/items?itemName=Vue.volar) (and disable Vetur).
## Type Support for `.vue` Imports in TS
TypeScript cannot handle type information for `.vue` imports by default, so we replace the `tsc` CLI with `vue-tsc` for type checking. In editors, we need [Volar](https://marketplace.visualstudio.com/items?itemName=Vue.volar) to make the TypeScript language service aware of `.vue` types.
## Customize configuration
See [Vite Configuration Reference](https://vite.dev/config/).
## Project Setup
```sh
bun install
```
### Compile and Hot-Reload for Development
```sh
bun dev
```
### Type-Check, Compile and Minify for Production
```sh
bun build
```
### Lint with [ESLint](https://eslint.org/)
```sh
bun lint
```

BIN
frontend/bun.lockb Executable file

Binary file not shown.

1
frontend/env.d.ts vendored Normal file
View File

@@ -0,0 +1 @@
/// <reference types="vite/client" />

19
frontend/eslint.config.js Normal file
View File

@@ -0,0 +1,19 @@
import pluginVue from 'eslint-plugin-vue'
import vueTsEslintConfig from '@vue/eslint-config-typescript'
import skipFormatting from '@vue/eslint-config-prettier/skip-formatting'
export default [
{
name: 'app/files-to-lint',
files: ['**/*.{ts,mts,tsx,vue}'],
},
{
name: 'app/files-to-ignore',
ignores: ['**/dist/**', '**/dist-ssr/**', '**/coverage/**'],
},
...pluginVue.configs['flat/essential'],
...vueTsEslintConfig(),
skipFormatting,
]

13
frontend/index.html Normal file
View File

@@ -0,0 +1,13 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<link rel="icon" href="/favicon.ico">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Vite App</title>
</head>
<body>
<div id="app"></div>
<script type="module" src="/src/main.ts"></script>
</body>
</html>

37
frontend/package.json Normal file
View File

@@ -0,0 +1,37 @@
{
"name": "frontend",
"version": "0.1.0",
"private": true,
"type": "module",
"scripts": {
"dev": "vite",
"build": "run-p type-check \"build-only {@}\" --",
"preview": "vite preview",
"build-only": "vite build",
"type-check": "vue-tsc --build --force",
"lint": "eslint . --fix",
"format": "prettier --write src/"
},
"dependencies": {
"sass": "^1.80.3",
"sass-loader": "^16.0.2",
"vue": "^3.5.12",
"vue-router": "^4.4.5"
},
"devDependencies": {
"@tsconfig/node20": "^20.1.4",
"@types/node": "^20.16.11",
"@vitejs/plugin-vue": "^5.1.4",
"@vitejs/plugin-vue-jsx": "^4.0.1",
"@vue/eslint-config-prettier": "^10.0.0",
"@vue/eslint-config-typescript": "^14.0.1",
"@vue/tsconfig": "^0.5.1",
"eslint": "^9.12.0",
"eslint-plugin-vue": "^9.29.0",
"npm-run-all2": "^6.2.3",
"prettier": "^3.3.3",
"typescript": "~5.5.4",
"vite": "^5.4.8",
"vue-tsc": "^2.1.6"
}
}

7
frontend/src/App.vue Normal file
View File

@@ -0,0 +1,7 @@
<script setup lang="ts">
import { RouterView } from 'vue-router'
</script>
<template>
<RouterView />
</template>

View File

@@ -0,0 +1,17 @@
$light-gray: #d0d1d0;
$dark-gray: #303031;
$text-color: $light-gray;
$background-color: $dark-gray;
body {
color: $text-color;
background-color: $background-color;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
align-content: center;
min-height: 100vh;
}

View File

@@ -0,0 +1,13 @@
import { ref } from 'vue'
export function useTelemetry(name: string) {
const data = ref<any | null>(null);
const error = ref<any | null>(null);
fetch(`/api/tlm/${name}`)
.then((res) => res.json())
.then((json) => (data.value = json))
.catch((err) => (error.value = err));
return { data, error };
}

11
frontend/src/main.ts Normal file
View File

@@ -0,0 +1,11 @@
import './assets/main.scss'
import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
const app = createApp(App)
app.use(router)
app.mount('#app')

View File

@@ -0,0 +1,14 @@
import { createRouter, createWebHistory } from 'vue-router'
const router = createRouter({
history: createWebHistory(import.meta.env.BASE_URL),
routes: [
{
path: '/',
name: 'home',
component: () => import('../views/HomeView.vue'),
},
],
})
export default router

View File

@@ -0,0 +1,23 @@
<script setup lang="ts">
import { useTelemetry } from '@/composables/telemetry'
const { data: sin_data, error: sin_error } = useTelemetry("simple_producer/sin");
const { data: cos_data, error: cos_error } = useTelemetry("simple_producer/cos");
</script>
<template>
<main>
<div v-if="sin_data">
{{ sin_data.name }} ({{ sin_data.uuid }}): {{ sin_data.data_type }}
</div>
<div v-if="sin_error">
{{ sin_error }}
</div>
<div v-if="cos_data">
{{ cos_data.name }} ({{ cos_data.uuid }}): {{ cos_data.data_type }}
</div>
<div v-if="cos_error">
{{ cos_error }}
</div>
</main>
</template>

View File

@@ -0,0 +1,14 @@
{
"extends": "@vue/tsconfig/tsconfig.dom.json",
"include": ["env.d.ts", "src/**/*", "src/**/*.vue"],
"exclude": ["src/**/__tests__/*"],
"compilerOptions": {
"composite": true,
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
"baseUrl": ".",
"paths": {
"@/*": ["./src/*"]
}
}
}

11
frontend/tsconfig.json Normal file
View File

@@ -0,0 +1,11 @@
{
"files": [],
"references": [
{
"path": "./tsconfig.node.json"
},
{
"path": "./tsconfig.app.json"
}
]
}

View File

@@ -0,0 +1,19 @@
{
"extends": "@tsconfig/node20/tsconfig.json",
"include": [
"vite.config.*",
"vitest.config.*",
"cypress.config.*",
"nightwatch.conf.*",
"playwright.config.*"
],
"compilerOptions": {
"composite": true,
"noEmit": true,
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo",
"module": "ESNext",
"moduleResolution": "Bundler",
"types": ["node"]
}
}

24
frontend/vite.config.ts Normal file
View File

@@ -0,0 +1,24 @@
import { fileURLToPath, URL } from 'node:url'
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import vueJsx from '@vitejs/plugin-vue-jsx'
// https://vite.dev/config/
export default defineConfig({
plugins: [
vue(),
vueJsx(),
],
resolve: {
alias: {
'@': fileURLToPath(new URL('./src', import.meta.url))
}
},
server: {
port: 9000,
proxy: {
'/api': 'http://localhost:8080'
}
}
})

View File

@@ -19,6 +19,7 @@ tokio-util = "0.7.12"
serde = { version = "1.0.210", features = ["derive"] }
serde_json = "1.0.132"
derive_more = { version = "1.0.0", features = ["full"] }
hex = "0.4.3"
[build-dependencies]
tonic-build = "0.12.3"

View File

@@ -15,7 +15,7 @@ message TelemetryValue {
}
message UUID {
bytes value = 1;
string value = 1;
}
// UTC since UNIX

View File

@@ -102,6 +102,7 @@ pub fn setup(token: CancellationToken, telemetry_definitions: Arc<Mutex<HashMap<
cancellation_token: token.clone()
};
trace!("Starting gRPC Server");
let result = Server::builder()
.add_service(TelemetryServiceServer::new(tlm_service))
// .serve(addr)

View File

@@ -5,6 +5,7 @@ use actix_web::{error, get, web, App, HttpResponse, HttpServer, Responder};
use derive_more::{Display, Error};
use std::collections::HashMap;
use std::sync::Arc;
use log::trace;
use tokio::sync::Mutex;
#[derive(Debug, Display, Error)]
@@ -29,8 +30,10 @@ impl error::ResponseError for UserError {
#[get("/tlm/{name:[\\w\\d/_-]+}")]
async fn get_tlm_definition(data: web::Data<Arc<Mutex<HashMap<String, TelemetryDefinition>>>>, name: web::Path<String>) -> Result<impl Responder, UserError> {
let string = name.to_string();
trace!("get_tlm_definition {}", string);
let data = data.lock().await;
let tlm_def = data.get(&string);
trace!("tlm_def {:?}", tlm_def.clone());
if let Some(tlm_def) = tlm_def {
Ok(web::Json(tlm_def.clone()))
@@ -39,13 +42,19 @@ async fn get_tlm_definition(data: web::Data<Arc<Mutex<HashMap<String, TelemetryD
}
}
fn setup_api(cfg: &mut web::ServiceConfig) {
cfg
.service(get_tlm_definition);
}
pub async fn setup(telemetry_definitions: Arc<Mutex<HashMap<String, TelemetryDefinition>>>) -> Result<(), Box<dyn Error>> {
let data = web::Data::new(telemetry_definitions);
trace!("Starting HTTP Server");
HttpServer::new(move || {
App::new()
.app_data(data.clone())
.service(get_tlm_definition)
.service(web::scope("/api").configure(setup_api))
})
.bind("localhost:8080")?
.run().await?;

View File

@@ -43,7 +43,7 @@ fn tlm_data_type_deserialzier<'de, D>(deserializer: D) -> Result<TelemetryDataTy
#[derive(Debug, Clone, Serialize, Deserialize)]
struct TelemetryDefinition {
uuid: Vec<u8>,
uuid: String,
name: String,
#[serde(serialize_with = "tlm_data_type_serialzier")]
#[serde(deserialize_with = "tlm_data_type_deserialzier")]

View File

@@ -20,7 +20,8 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
message
))
})
.level(log_level)
.level(log::LevelFilter::Warn)
.level_for("server", log_level)
.chain(std::io::stdout());
if let Ok(log_file) = log_file {
log_config = log_config.chain(fern::log_file(log_file)?)

View File

@@ -3,10 +3,10 @@ use crate::core::{Uuid};
impl Uuid {
pub fn random() -> Self {
let mut uuid = vec![0u8; 16];
let mut uuid =[0u8; 16];
rand::thread_rng().fill_bytes(&mut uuid);
Self {
value: uuid,
value: hex::encode(uuid),
}
}
}