refactor: rename module to pipely and migrate web UI to MUI

- Rename Go module from onixbyte.com/message-converter-manifest to onixbyte.com/pipely
- Replace shadcn UI with Material UI components across all pages
- Add axios-based API client in shared/web-client with credentials management
- Organise API calls into feature modules: auth, devices, deployments, artefacts, users
- Add .env.example with VITE_API_BASE_URL pointing to pipely.onixbyte.com
- Fix deprecated FormEvent → MouseEvent in dialog submit handlers
This commit is contained in:
2026-07-07 14:40:09 +08:00
parent 5b0f33320e
commit 033082954a
44 changed files with 4240 additions and 1152 deletions
+100 -33
View File
@@ -1,42 +1,109 @@
import { NavLink, useNavigate, Outlet } from 'react-router-dom';
import { setToken } from '../api/client';
import './Layout.css';
import { NavLink, useNavigate, Outlet } from "react-router-dom"
import { setToken } from "@/shared/web-client"
import {
Drawer,
List,
ListItem,
ListItemButton,
ListItemIcon,
ListItemText,
Toolbar,
AppBar,
Typography,
Box,
Divider,
} from "@mui/material"
import {
Dashboard as DashboardIcon,
Inventory,
RocketLaunch,
People,
Logout,
} from "@mui/icons-material"
const drawerWidth = 240
export default function Layout() {
const navigate = useNavigate();
const navigate = useNavigate()
function handleLogout() {
setToken(null);
navigate('/');
setToken(null)
navigate("/")
}
const navItems = [
{ path: "/dashboard", label: "Dashboard", icon: <DashboardIcon /> },
{ path: "/artefacts", label: "Versions", icon: <Inventory /> },
{ path: "/deployments", label: "Deployments", icon: <RocketLaunch /> },
{ path: "/users", label: "Admin Users", icon: <People /> },
]
return (
<div className="app-layout">
<aside className="sidebar">
<div className="sidebar-brand">
<h2>OTA Manager</h2>
</div>
<nav>
<NavLink to="/dashboard" className={({ isActive }) => isActive ? 'nav-link active' : 'nav-link'}>
Dashboard
</NavLink>
<NavLink to="/artefacts" className={({ isActive }) => isActive ? 'nav-link active' : 'nav-link'}>
Versions
</NavLink>
<NavLink to="/deployments" className={({ isActive }) => isActive ? 'nav-link active' : 'nav-link'}>
Deployments
</NavLink>
<NavLink to="/users" className={({ isActive }) => isActive ? 'nav-link active' : 'nav-link'}>
Admin Users
</NavLink>
</nav>
<div className="sidebar-footer">
<button className="btn-logout" onClick={handleLogout}>Logout</button>
</div>
</aside>
<main className="content">
<Box sx={{ display: "flex" }}>
<AppBar
position="fixed"
sx={{
width: `calc(100% - ${drawerWidth}px)`,
ml: `${drawerWidth}px`,
}}>
<Toolbar>
<Typography variant="h6" noWrap component="div">
OTA Manager
</Typography>
</Toolbar>
</AppBar>
<Drawer
sx={{
width: drawerWidth,
flexShrink: 0,
"& .MuiDrawer-paper": {
width: drawerWidth,
boxSizing: "border-box",
},
}}
variant="permanent"
anchor="left">
<Toolbar />
<Divider />
<List>
{navItems.map((item) => (
<ListItem key={item.path} disablePadding>
<ListItemButton
component={NavLink}
to={item.path}
sx={{
"&.active": {
bgcolor: "action.selected",
},
}}>
<ListItemIcon>{item.icon}</ListItemIcon>
<ListItemText primary={item.label} />
</ListItemButton>
</ListItem>
))}
</List>
<Divider />
<List>
<ListItem disablePadding>
<ListItemButton onClick={handleLogout}>
<ListItemIcon>
<Logout />
</ListItemIcon>
<ListItemText primary="Logout" />
</ListItemButton>
</ListItem>
</List>
</Drawer>
<Box
component="main"
sx={{
flexGrow: 1,
p: 3,
width: `calc(100% - ${drawerWidth}px)`,
mt: 8,
}}>
<Outlet />
</main>
</div>
);
</Box>
</Box>
)
}