mirror of
https://github.com/bunny-lab-io/Borealis.git
synced 2025-12-16 11:25:48 -07:00
Standardized Position of Page-Level Action Buttons Across All of Borealis
This commit is contained in:
@@ -8,6 +8,7 @@ import {
|
|||||||
Paper,
|
Paper,
|
||||||
Typography,
|
Typography,
|
||||||
CircularProgress,
|
CircularProgress,
|
||||||
|
Stack,
|
||||||
} from "@mui/material";
|
} from "@mui/material";
|
||||||
import MoreVertIcon from "@mui/icons-material/MoreVert";
|
import MoreVertIcon from "@mui/icons-material/MoreVert";
|
||||||
import AddIcon from "@mui/icons-material/Add";
|
import AddIcon from "@mui/icons-material/Add";
|
||||||
@@ -310,6 +311,53 @@ export default function CredentialList({ isAdmin = false, onPageMetaChange }) {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
position: "fixed",
|
||||||
|
top: { xs: 72, md: 88 },
|
||||||
|
right: { xs: 12, md: 20 },
|
||||||
|
zIndex: 1400,
|
||||||
|
pointerEvents: "none",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Stack direction="row" spacing={1.25} sx={{ pointerEvents: "auto" }}>
|
||||||
|
<Button
|
||||||
|
variant="outlined"
|
||||||
|
size="small"
|
||||||
|
startIcon={<RefreshIcon />}
|
||||||
|
sx={{
|
||||||
|
borderColor: "rgba(148,163,184,0.4)",
|
||||||
|
color: "#e2e8f0",
|
||||||
|
textTransform: "none",
|
||||||
|
borderRadius: 999,
|
||||||
|
px: 1.9,
|
||||||
|
minWidth: 112,
|
||||||
|
backgroundColor: "rgba(12,18,35,0.85)",
|
||||||
|
"&:hover": {
|
||||||
|
borderColor: "rgba(125,211,252,0.85)",
|
||||||
|
backgroundColor: "rgba(16,24,44,0.95)",
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
onClick={fetchCredentials}
|
||||||
|
disabled={loading}
|
||||||
|
>
|
||||||
|
Refresh
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
variant="contained"
|
||||||
|
size="small"
|
||||||
|
startIcon={<AddIcon />}
|
||||||
|
sx={{
|
||||||
|
...gradientButtonSx,
|
||||||
|
minWidth: 150,
|
||||||
|
}}
|
||||||
|
onClick={handleCreate}
|
||||||
|
>
|
||||||
|
New Credential
|
||||||
|
</Button>
|
||||||
|
</Stack>
|
||||||
|
</Box>
|
||||||
|
|
||||||
<Paper
|
<Paper
|
||||||
sx={{
|
sx={{
|
||||||
m: 0,
|
m: 0,
|
||||||
@@ -327,46 +375,6 @@ export default function CredentialList({ isAdmin = false, onPageMetaChange }) {
|
|||||||
}}
|
}}
|
||||||
elevation={0}
|
elevation={0}
|
||||||
>
|
>
|
||||||
<Box
|
|
||||||
sx={{
|
|
||||||
display: "flex",
|
|
||||||
alignItems: "center",
|
|
||||||
justifyContent: "space-between",
|
|
||||||
px: 2,
|
|
||||||
pt: 1,
|
|
||||||
pb: 1,
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Box sx={{ display: "flex", gap: 1 }}>
|
|
||||||
<Button
|
|
||||||
variant="outlined"
|
|
||||||
size="small"
|
|
||||||
startIcon={<RefreshIcon />}
|
|
||||||
sx={{
|
|
||||||
borderColor: "rgba(148,163,184,0.35)",
|
|
||||||
color: "#e2e8f0",
|
|
||||||
textTransform: "none",
|
|
||||||
borderRadius: 999,
|
|
||||||
px: 1.7,
|
|
||||||
minWidth: 86,
|
|
||||||
"&:hover": { borderColor: "rgba(148,163,184,0.55)" },
|
|
||||||
}}
|
|
||||||
onClick={fetchCredentials}
|
|
||||||
disabled={loading}
|
|
||||||
>
|
|
||||||
Refresh
|
|
||||||
</Button>
|
|
||||||
<Button
|
|
||||||
variant="contained"
|
|
||||||
size="small"
|
|
||||||
startIcon={<AddIcon />}
|
|
||||||
sx={gradientButtonSx}
|
|
||||||
onClick={handleCreate}
|
|
||||||
>
|
|
||||||
New Credential
|
|
||||||
</Button>
|
|
||||||
</Box>
|
|
||||||
</Box>
|
|
||||||
{loading && (
|
{loading && (
|
||||||
<Box
|
<Box
|
||||||
sx={{
|
sx={{
|
||||||
|
|||||||
@@ -23,7 +23,8 @@ import {
|
|||||||
FormControl,
|
FormControl,
|
||||||
InputLabel,
|
InputLabel,
|
||||||
Checkbox,
|
Checkbox,
|
||||||
Popover
|
Popover,
|
||||||
|
Stack
|
||||||
} from "@mui/material";
|
} from "@mui/material";
|
||||||
import MoreVertIcon from "@mui/icons-material/MoreVert";
|
import MoreVertIcon from "@mui/icons-material/MoreVert";
|
||||||
import FilterListIcon from "@mui/icons-material/FilterList";
|
import FilterListIcon from "@mui/icons-material/FilterList";
|
||||||
@@ -454,15 +455,26 @@ export default function UserManagement({ isAdmin = false, onPageMetaChange }) {
|
|||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Paper sx={tablePaperSx} elevation={0}>
|
<Paper sx={tablePaperSx} elevation={0}>
|
||||||
<Box sx={{ p: 2, pb: 1, display: "flex", alignItems: "center", justifyContent: "flex-end", gap: 1 }}>
|
{/* Page-level action button (floating top-right) */}
|
||||||
<Button
|
<Box
|
||||||
variant="contained"
|
sx={{
|
||||||
size="small"
|
position: "fixed",
|
||||||
onClick={openCreate}
|
top: { xs: 72, md: 88 },
|
||||||
sx={gradientButtonSx}
|
right: { xs: 12, md: 20 },
|
||||||
>
|
zIndex: 1400,
|
||||||
Create User
|
pointerEvents: "none",
|
||||||
</Button>
|
}}
|
||||||
|
>
|
||||||
|
<Stack direction="row" spacing={1.25} alignItems="center" sx={{ pointerEvents: "auto" }}>
|
||||||
|
<Button
|
||||||
|
variant="contained"
|
||||||
|
size="small"
|
||||||
|
onClick={openCreate}
|
||||||
|
sx={gradientButtonSx}
|
||||||
|
>
|
||||||
|
Create User
|
||||||
|
</Button>
|
||||||
|
</Stack>
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
<Table size="small" sx={tableSx}>
|
<Table size="small" sx={tableSx}>
|
||||||
|
|||||||
@@ -359,8 +359,32 @@ const defaultColDef = useMemo(
|
|||||||
flexDirection: "column",
|
flexDirection: "column",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
position: "fixed",
|
||||||
|
top: { xs: 72, md: 88 },
|
||||||
|
right: { xs: 12, md: 20 },
|
||||||
|
zIndex: 1400,
|
||||||
|
pointerEvents: "none",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Stack direction="row" spacing={1.25} sx={{ pointerEvents: "auto" }}>
|
||||||
|
<Button
|
||||||
|
variant="contained"
|
||||||
|
startIcon={<RefreshIcon />}
|
||||||
|
onClick={() => {
|
||||||
|
fetchLogs();
|
||||||
|
if (selectedFile) fetchEntries(selectedFile);
|
||||||
|
}}
|
||||||
|
sx={{ ...gradientButtonSx, minWidth: 112 }}
|
||||||
|
>
|
||||||
|
Refresh
|
||||||
|
</Button>
|
||||||
|
</Stack>
|
||||||
|
</Box>
|
||||||
|
|
||||||
{!useGlobalHeader && (
|
{!useGlobalHeader && (
|
||||||
<Box sx={{ px: 3, pt: 3, pb: 1, borderBottom: `1px solid ${AURORA_SHELL.border}` }}>
|
<Box sx={{ px: 3, pt: 3, pb: 1 }}>
|
||||||
<Stack direction="row" spacing={1.25} alignItems="center">
|
<Stack direction="row" spacing={1.25} alignItems="center">
|
||||||
<LogsIcon sx={{ fontSize: 22, color: AURORA_SHELL.accent, mt: 0.25 }} />
|
<LogsIcon sx={{ fontSize: 22, color: AURORA_SHELL.accent, mt: 0.25 }} />
|
||||||
<Typography
|
<Typography
|
||||||
@@ -373,41 +397,12 @@ const defaultColDef = useMemo(
|
|||||||
>
|
>
|
||||||
Log Management
|
Log Management
|
||||||
</Typography>
|
</Typography>
|
||||||
<Box sx={{ flexGrow: 1 }} />
|
|
||||||
<Stack direction="row" spacing={1}>
|
|
||||||
<Button
|
|
||||||
variant="contained"
|
|
||||||
startIcon={<RefreshIcon />}
|
|
||||||
onClick={() => {
|
|
||||||
fetchLogs();
|
|
||||||
if (selectedFile) fetchEntries(selectedFile);
|
|
||||||
}}
|
|
||||||
sx={gradientButtonSx}
|
|
||||||
>
|
|
||||||
Refresh
|
|
||||||
</Button>
|
|
||||||
</Stack>
|
|
||||||
</Stack>
|
</Stack>
|
||||||
<Typography variant="body2" sx={{ color: AURORA_SHELL.muted, mt: 0.75, mb: 2.5 }}>
|
<Typography variant="body2" sx={{ color: AURORA_SHELL.muted, mt: 0.75, mb: 2.5 }}>
|
||||||
Analyze engine logs and adjust log retention periods for different engine services.
|
Analyze engine logs and adjust log retention periods for different engine services.
|
||||||
</Typography>
|
</Typography>
|
||||||
</Box>
|
</Box>
|
||||||
)}
|
)}
|
||||||
{useGlobalHeader && (
|
|
||||||
<Box sx={{ px: 3, pt: 2, pb: 1, display: "flex", justifyContent: "flex-end" }}>
|
|
||||||
<Button
|
|
||||||
variant="contained"
|
|
||||||
startIcon={<RefreshIcon />}
|
|
||||||
onClick={() => {
|
|
||||||
fetchLogs();
|
|
||||||
if (selectedFile) fetchEntries(selectedFile);
|
|
||||||
}}
|
|
||||||
sx={gradientButtonSx}
|
|
||||||
>
|
|
||||||
Refresh
|
|
||||||
</Button>
|
|
||||||
</Box>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{error && (
|
{error && (
|
||||||
<Box sx={{ px: 3, pt: 2 }}>
|
<Box sx={{ px: 3, pt: 2 }}>
|
||||||
@@ -425,8 +420,8 @@ const defaultColDef = useMemo(
|
|||||||
sx={{
|
sx={{
|
||||||
width: 360,
|
width: 360,
|
||||||
p: 3,
|
p: 3,
|
||||||
borderRight: `1px solid ${AURORA_SHELL.border}`,
|
borderRight: "none",
|
||||||
bgcolor: "rgba(3,7,18,0.7)",
|
bgcolor: "transparent",
|
||||||
display: "flex",
|
display: "flex",
|
||||||
flexDirection: "column",
|
flexDirection: "column",
|
||||||
gap: 2,
|
gap: 2,
|
||||||
@@ -646,9 +641,32 @@ const defaultColDef = useMemo(
|
|||||||
value={gridMode}
|
value={gridMode}
|
||||||
onChange={(_, val) => val && setGridMode(val)}
|
onChange={(_, val) => val && setGridMode(val)}
|
||||||
sx={{
|
sx={{
|
||||||
backgroundColor: "rgba(0,0,0,0.25)",
|
background: "rgba(9,14,25,0.9)",
|
||||||
borderRadius: 999,
|
borderRadius: 1,
|
||||||
p: 0.2,
|
border: `1px solid ${AURORA_SHELL.border}`,
|
||||||
|
boxShadow: "0 14px 32px rgba(2,6,23,0.55)",
|
||||||
|
overflow: "hidden",
|
||||||
|
"& .MuiToggleButton-root": {
|
||||||
|
textTransform: "none",
|
||||||
|
color: "#dce7f5",
|
||||||
|
border: "none",
|
||||||
|
px: 2.8,
|
||||||
|
py: 1,
|
||||||
|
fontWeight: 700,
|
||||||
|
fontSize: 13,
|
||||||
|
letterSpacing: 0.1,
|
||||||
|
transition: "all 0.18s ease",
|
||||||
|
backgroundColor: "#0f1627",
|
||||||
|
"&:hover": { backgroundColor: "rgba(148,163,184,0.14)" },
|
||||||
|
"&.Mui-selected": {
|
||||||
|
color: "#0c1224",
|
||||||
|
backgroundImage: "linear-gradient(135deg,#7fc9ff 0%,#b195ff 100%)",
|
||||||
|
boxShadow: "0 10px 24px rgba(124,58,237,0.4)",
|
||||||
|
},
|
||||||
|
"&.Mui-selected:hover": {
|
||||||
|
backgroundImage: "linear-gradient(135deg,#8bd8ff 0%,#c0a8ff 100%)",
|
||||||
|
},
|
||||||
|
},
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<ToggleButton value="structured" sx={{ color: AURORA_SHELL.text, textTransform: "none" }}>
|
<ToggleButton value="structured" sx={{ color: AURORA_SHELL.text, textTransform: "none" }}>
|
||||||
@@ -702,8 +720,8 @@ const defaultColDef = useMemo(
|
|||||||
flexGrow: 1,
|
flexGrow: 1,
|
||||||
minHeight: 0,
|
minHeight: 0,
|
||||||
borderRadius: 2,
|
borderRadius: 2,
|
||||||
border: `1px solid ${AURORA_SHELL.border}`,
|
border: "none",
|
||||||
bgcolor: "rgba(5,7,15,0.85)",
|
bgcolor: "transparent",
|
||||||
overflow: "hidden",
|
overflow: "hidden",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -252,6 +252,46 @@ export default function PageTemplate({ onPageMetaChange }) {
|
|||||||
}}
|
}}
|
||||||
elevation={0}
|
elevation={0}
|
||||||
>
|
>
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
position: "fixed",
|
||||||
|
top: { xs: 72, md: 88 },
|
||||||
|
right: { xs: 12, md: 20 },
|
||||||
|
zIndex: 1400,
|
||||||
|
pointerEvents: "none",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Stack direction="row" spacing={1.25} sx={{ pointerEvents: "auto" }}>
|
||||||
|
<Tooltip title="New (example)">
|
||||||
|
<span>
|
||||||
|
<Button size="small" startIcon={<AddIcon />} sx={{ ...gradientButtonSx, minWidth: 120 }}>
|
||||||
|
New Item
|
||||||
|
</Button>
|
||||||
|
</span>
|
||||||
|
</Tooltip>
|
||||||
|
<Tooltip title="Settings (example)">
|
||||||
|
<span>
|
||||||
|
<Button
|
||||||
|
size="small"
|
||||||
|
variant="outlined"
|
||||||
|
startIcon={<TuneIcon />}
|
||||||
|
sx={{
|
||||||
|
borderColor: "rgba(148,163,184,0.35)",
|
||||||
|
color: "#e2e8f0",
|
||||||
|
textTransform: "none",
|
||||||
|
borderRadius: 999,
|
||||||
|
px: 1.7,
|
||||||
|
minWidth: 100,
|
||||||
|
"&:hover": { borderColor: "rgba(148,163,184,0.55)" },
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Settings
|
||||||
|
</Button>
|
||||||
|
</span>
|
||||||
|
</Tooltip>
|
||||||
|
</Stack>
|
||||||
|
</Box>
|
||||||
|
|
||||||
<Box
|
<Box
|
||||||
sx={{
|
sx={{
|
||||||
px: 2,
|
px: 2,
|
||||||
@@ -280,33 +320,6 @@ export default function PageTemplate({ onPageMetaChange }) {
|
|||||||
</Tooltip>
|
</Tooltip>
|
||||||
</Box>
|
</Box>
|
||||||
<Stack direction="row" spacing={1}>
|
<Stack direction="row" spacing={1}>
|
||||||
<Tooltip title="New (example)">
|
|
||||||
<span>
|
|
||||||
<Button size="small" startIcon={<AddIcon />} sx={gradientButtonSx}>
|
|
||||||
New Item
|
|
||||||
</Button>
|
|
||||||
</span>
|
|
||||||
</Tooltip>
|
|
||||||
<Tooltip title="Settings (example)">
|
|
||||||
<span>
|
|
||||||
<Button
|
|
||||||
size="small"
|
|
||||||
variant="outlined"
|
|
||||||
startIcon={<TuneIcon />}
|
|
||||||
sx={{
|
|
||||||
borderColor: "rgba(148,163,184,0.35)",
|
|
||||||
color: "#e2e8f0",
|
|
||||||
textTransform: "none",
|
|
||||||
borderRadius: 999,
|
|
||||||
px: 1.7, // ~5% wider than previous
|
|
||||||
minWidth: 86,
|
|
||||||
"&:hover": { borderColor: "rgba(148,163,184,0.55)" },
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
Settings
|
|
||||||
</Button>
|
|
||||||
</span>
|
|
||||||
</Tooltip>
|
|
||||||
</Stack>
|
</Stack>
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,12 @@
|
|||||||
import React, { useEffect, useState } from "react";
|
import React, { useEffect, useMemo, useState } from "react";
|
||||||
import { Paper, Box, Typography, Button } from "@mui/material";
|
import { Paper, Box, Typography, Button, Stack } from "@mui/material";
|
||||||
import { GitHub as GitHubIcon, InfoOutlined as InfoIcon } from "@mui/icons-material";
|
import { GitHub as GitHubIcon, InfoOutlined as InfoIcon } from "@mui/icons-material";
|
||||||
|
import { AgGridReact } from "ag-grid-react";
|
||||||
|
import { ModuleRegistry, AllCommunityModule, themeQuartz } from "ag-grid-community";
|
||||||
import { CreditsDialog } from "../Dialogs.jsx";
|
import { CreditsDialog } from "../Dialogs.jsx";
|
||||||
|
|
||||||
|
ModuleRegistry.registerModules([AllCommunityModule]);
|
||||||
|
|
||||||
const gradientButtonSx = {
|
const gradientButtonSx = {
|
||||||
backgroundImage: "linear-gradient(135deg,#7dd3fc,#c084fc)",
|
backgroundImage: "linear-gradient(135deg,#7dd3fc,#c084fc)",
|
||||||
color: "#0b1220",
|
color: "#0b1220",
|
||||||
@@ -16,6 +20,19 @@ const gradientButtonSx = {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const gridTheme = themeQuartz.withParams({
|
||||||
|
accentColor: "#7dd3fc",
|
||||||
|
backgroundColor: "#050915",
|
||||||
|
browserColorScheme: "dark",
|
||||||
|
fontFamily: { googleFont: "IBM Plex Sans" },
|
||||||
|
foregroundColor: "#e2e8f0",
|
||||||
|
headerFontSize: 13,
|
||||||
|
});
|
||||||
|
|
||||||
|
const themeClassName = gridTheme.themeName || "ag-theme-quartz";
|
||||||
|
const gridFontFamily = "\"IBM Plex Sans\", \"Helvetica Neue\", Arial, sans-serif";
|
||||||
|
const iconFontFamily = "\"Quartz Regular\"";
|
||||||
|
|
||||||
export default function ServerInfo({ isAdmin = false, onPageMetaChange }) {
|
export default function ServerInfo({ isAdmin = false, onPageMetaChange }) {
|
||||||
const [serverTime, setServerTime] = useState(null);
|
const [serverTime, setServerTime] = useState(null);
|
||||||
const [error, setError] = useState(null);
|
const [error, setError] = useState(null);
|
||||||
@@ -51,50 +68,168 @@ export default function ServerInfo({ isAdmin = false, onPageMetaChange }) {
|
|||||||
return () => onPageMetaChange?.(null);
|
return () => onPageMetaChange?.(null);
|
||||||
}, [onPageMetaChange]);
|
}, [onPageMetaChange]);
|
||||||
|
|
||||||
|
const infoRows = useMemo(
|
||||||
|
() => [
|
||||||
|
{
|
||||||
|
id: "server-time",
|
||||||
|
field: "Server Time",
|
||||||
|
value: error ? `Error: ${error}` : (serverTime || "Loading..."),
|
||||||
|
description: "Internal server clock used for troubleshooting the job scheduling system.",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
[error, serverTime]
|
||||||
|
);
|
||||||
|
|
||||||
|
const columnDefs = useMemo(
|
||||||
|
() => [
|
||||||
|
{ headerName: "Field", field: "field", minWidth: 180, flex: 0.35 },
|
||||||
|
{ headerName: "Value", field: "value", minWidth: 240, flex: 0.4 },
|
||||||
|
{ headerName: "Description", field: "description", minWidth: 260, flex: 0.6 },
|
||||||
|
],
|
||||||
|
[]
|
||||||
|
);
|
||||||
|
|
||||||
if (!isAdmin) return null;
|
if (!isAdmin) return null;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Paper sx={{ m: 0, p: 0, bgcolor: "transparent", border: "none", boxShadow: "none" }} elevation={0}>
|
<Paper sx={{ m: 0, p: 0, bgcolor: "transparent", border: "none", boxShadow: "none" }} elevation={0}>
|
||||||
<Box sx={{ p: 2 }}>
|
<Box
|
||||||
|
sx={{
|
||||||
|
position: "fixed",
|
||||||
|
top: { xs: 72, md: 88 },
|
||||||
|
right: { xs: 12, md: 20 },
|
||||||
|
zIndex: 1400,
|
||||||
|
pointerEvents: "none",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Stack direction="row" spacing={1.25} sx={{ pointerEvents: "auto" }}>
|
||||||
|
<Button
|
||||||
|
variant="outlined"
|
||||||
|
startIcon={<GitHubIcon />}
|
||||||
|
onClick={() => window.open("https://github.com/bunny-lab-io/Borealis", "_blank")}
|
||||||
|
sx={{
|
||||||
|
borderColor: "rgba(148,163,184,0.4)",
|
||||||
|
color: "#e2e8f0",
|
||||||
|
textTransform: "none",
|
||||||
|
borderRadius: 999,
|
||||||
|
px: 1.9,
|
||||||
|
minWidth: 150,
|
||||||
|
backgroundColor: "rgba(12,18,35,0.85)",
|
||||||
|
"&:hover": {
|
||||||
|
borderColor: "rgba(125,211,252,0.85)",
|
||||||
|
backgroundColor: "rgba(16,24,44,0.95)",
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
GitHub Project
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
variant="contained"
|
||||||
|
startIcon={<InfoIcon />}
|
||||||
|
onClick={() => setAboutOpen(true)}
|
||||||
|
sx={{ ...gradientButtonSx, minWidth: 150 }}
|
||||||
|
>
|
||||||
|
About Borealis
|
||||||
|
</Button>
|
||||||
|
</Stack>
|
||||||
|
</Box>
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
p: 2,
|
||||||
|
pb: 3,
|
||||||
|
display: "flex",
|
||||||
|
flexDirection: "column",
|
||||||
|
minHeight: "calc(100vh - 110px)",
|
||||||
|
gap: 2,
|
||||||
|
}}
|
||||||
|
>
|
||||||
<Typography sx={{ color: '#aaa', mb: 1 }}>
|
<Typography sx={{ color: '#aaa', mb: 1 }}>
|
||||||
Basic server information for debug and support. Server time updates automatically every minute.
|
Basic server information for debug and support. Server time updates automatically every minute.
|
||||||
</Typography>
|
</Typography>
|
||||||
<Box sx={{ display: 'flex', gap: 2, alignItems: 'baseline' }}>
|
<Box
|
||||||
<Typography sx={{ color: '#ccc', fontWeight: 600, minWidth: 120 }}>Server Time</Typography>
|
className={themeClassName}
|
||||||
<Typography sx={{ color: error ? '#ff6b6b' : '#ddd', fontFamily: 'ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace' }}>
|
sx={{
|
||||||
{error ? `Error: ${error}` : (serverTime || 'Loading...')}
|
mt: 3,
|
||||||
</Typography>
|
width: "100%",
|
||||||
|
maxWidth: "100%",
|
||||||
|
minHeight: "75vh",
|
||||||
|
display: "flex",
|
||||||
|
flexDirection: "column",
|
||||||
|
background: "rgba(8,12,24,0.72)",
|
||||||
|
borderRadius: 2,
|
||||||
|
border: "1px solid rgba(148,163,184,0.35)",
|
||||||
|
boxShadow: "0 12px 36px rgba(2,6,23,0.55)",
|
||||||
|
overflow: "hidden",
|
||||||
|
fontFamily: gridFontFamily,
|
||||||
|
"--ag-font-family": gridFontFamily,
|
||||||
|
"--ag-icon-font-family": iconFontFamily,
|
||||||
|
"& .ag-root-wrapper": {
|
||||||
|
border: "none",
|
||||||
|
borderRadius: 2,
|
||||||
|
},
|
||||||
|
"& .ag-center-cols-container .ag-cell, & .ag-pinned-left-cols-container .ag-cell, & .ag-pinned-right-cols-container .ag-cell": {
|
||||||
|
display: "flex",
|
||||||
|
alignItems: "center",
|
||||||
|
justifyContent: "flex-start",
|
||||||
|
textAlign: "left",
|
||||||
|
padding: "8px 12px 8px 18px",
|
||||||
|
},
|
||||||
|
"& .ag-center-cols-container .ag-cell .ag-cell-wrapper, & .ag-pinned-left-cols-container .ag-cell .ag-cell-wrapper, & .ag-pinned-right-cols-container .ag-cell .ag-cell-wrapper": {
|
||||||
|
width: "100%",
|
||||||
|
display: "flex",
|
||||||
|
alignItems: "center",
|
||||||
|
justifyContent: "flex-start",
|
||||||
|
padding: 0,
|
||||||
|
},
|
||||||
|
"& .ag-header": {
|
||||||
|
borderBottom: "1px solid rgba(148,163,184,0.35)",
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
style={{
|
||||||
|
"--ag-background-color": "rgba(5,9,21,0.92)",
|
||||||
|
"--ag-foreground-color": "#e2e8f0",
|
||||||
|
"--ag-header-background-color": "#0b1226",
|
||||||
|
"--ag-header-foreground-color": "#cfe0ff",
|
||||||
|
"--ag-row-hover-color": "rgba(125,211,252,0.08)",
|
||||||
|
"--ag-selected-row-background-color": "rgba(64,164,255,0.16)",
|
||||||
|
"--ag-border-color": "rgba(148,163,184,0.28)",
|
||||||
|
"--ag-row-border-color": "rgba(148,163,184,0.16)",
|
||||||
|
"--ag-odd-row-background-color": "rgba(255,255,255,0.02)",
|
||||||
|
"--ag-border-radius": "12px",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<AgGridReact
|
||||||
|
rowData={infoRows}
|
||||||
|
columnDefs={columnDefs}
|
||||||
|
defaultColDef={{
|
||||||
|
sortable: false,
|
||||||
|
filter: false,
|
||||||
|
resizable: true,
|
||||||
|
flex: 1,
|
||||||
|
minWidth: 160,
|
||||||
|
cellStyle: {
|
||||||
|
color: "#e2e8f0",
|
||||||
|
fontFamily: gridFontFamily,
|
||||||
|
fontSize: 14,
|
||||||
|
},
|
||||||
|
headerClass: "server-info-grid-header",
|
||||||
|
}}
|
||||||
|
getRowId={(params) => params.data?.id || String(params.rowIndex ?? "")}
|
||||||
|
suppressCellFocus
|
||||||
|
animateRows
|
||||||
|
rowHeight={48}
|
||||||
|
headerHeight={42}
|
||||||
|
pagination={false}
|
||||||
|
theme={gridTheme}
|
||||||
|
style={{
|
||||||
|
width: "100%",
|
||||||
|
flex: 1,
|
||||||
|
fontFamily: gridFontFamily,
|
||||||
|
"--ag-icon-font-family": iconFontFamily,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
<Box sx={{ mt: 3 }}>
|
|
||||||
<Typography variant="subtitle1" sx={{ color: "#e2e8f0", mb: 1, fontWeight: 600 }}>Project Links</Typography>
|
|
||||||
<Box sx={{ display: 'flex', gap: 2, flexWrap: 'wrap' }}>
|
|
||||||
<Button
|
|
||||||
variant="outlined"
|
|
||||||
startIcon={<GitHubIcon />}
|
|
||||||
onClick={() => window.open("https://github.com/bunny-lab-io/Borealis", "_blank")}
|
|
||||||
sx={{
|
|
||||||
borderColor: "rgba(148,163,184,0.35)",
|
|
||||||
color: "#e2e8f0",
|
|
||||||
textTransform: "none",
|
|
||||||
borderRadius: 999,
|
|
||||||
px: 1.7,
|
|
||||||
minWidth: 86,
|
|
||||||
"&:hover": { borderColor: "rgba(148,163,184,0.55)" },
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
GitHub Project
|
|
||||||
</Button>
|
|
||||||
<Button
|
|
||||||
variant="contained"
|
|
||||||
startIcon={<InfoIcon />}
|
|
||||||
onClick={() => setAboutOpen(true)}
|
|
||||||
sx={gradientButtonSx}
|
|
||||||
>
|
|
||||||
About Borealis
|
|
||||||
</Button>
|
|
||||||
</Box>
|
|
||||||
</Box>
|
|
||||||
</Box>
|
</Box>
|
||||||
<CreditsDialog open={aboutOpen} onClose={() => setAboutOpen(false)} />
|
<CreditsDialog open={aboutOpen} onClose={() => setAboutOpen(false)} />
|
||||||
</Paper>
|
</Paper>
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ import {
|
|||||||
TextField,
|
TextField,
|
||||||
CircularProgress,
|
CircularProgress,
|
||||||
Link as MuiLink,
|
Link as MuiLink,
|
||||||
|
Stack,
|
||||||
} from "@mui/material";
|
} from "@mui/material";
|
||||||
import AddIcon from "@mui/icons-material/Add";
|
import AddIcon from "@mui/icons-material/Add";
|
||||||
import CachedIcon from "@mui/icons-material/Cached";
|
import CachedIcon from "@mui/icons-material/Cached";
|
||||||
@@ -633,6 +634,40 @@ export default function AssemblyList({ onOpenWorkflow, onOpenScript, userRole =
|
|||||||
}}
|
}}
|
||||||
elevation={0}
|
elevation={0}
|
||||||
>
|
>
|
||||||
|
{/* Page-level action button (floating top-right) */}
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
position: "fixed",
|
||||||
|
top: { xs: 72, md: 88 },
|
||||||
|
right: { xs: 12, md: 20 },
|
||||||
|
zIndex: 1400,
|
||||||
|
pointerEvents: "none",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Stack direction="row" spacing={1.25} alignItems="center" sx={{ pointerEvents: "auto" }}>
|
||||||
|
<Button
|
||||||
|
variant="contained"
|
||||||
|
size="small"
|
||||||
|
startIcon={<AddIcon />}
|
||||||
|
onClick={(event) => setNewMenuAnchor(event.currentTarget)}
|
||||||
|
sx={{
|
||||||
|
backgroundImage: "linear-gradient(135deg,#7dd3fc,#c084fc)",
|
||||||
|
color: "#0b1220",
|
||||||
|
borderRadius: 999,
|
||||||
|
textTransform: "none",
|
||||||
|
boxShadow: "0 10px 26px rgba(124,58,237,0.28)",
|
||||||
|
"&:hover": {
|
||||||
|
backgroundImage: "linear-gradient(135deg,#86e1ff,#d1a6ff)",
|
||||||
|
boxShadow: "0 12px 34px rgba(124,58,237,0.38)",
|
||||||
|
filter: "none",
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
New Assembly
|
||||||
|
</Button>
|
||||||
|
</Stack>
|
||||||
|
</Box>
|
||||||
|
|
||||||
<Box sx={{ px: 2, mt: 1, display: "flex", alignItems: "center", justifyContent: "space-between", gap: 1 }}>
|
<Box sx={{ px: 2, mt: 1, display: "flex", alignItems: "center", justifyContent: "space-between", gap: 1 }}>
|
||||||
<Box sx={{ display: "flex", alignItems: "center", gap: 1 }}>
|
<Box sx={{ display: "flex", alignItems: "center", gap: 1 }}>
|
||||||
<IconButton
|
<IconButton
|
||||||
@@ -653,26 +688,6 @@ export default function AssemblyList({ onOpenWorkflow, onOpenScript, userRole =
|
|||||||
</Typography>
|
</Typography>
|
||||||
) : null}
|
) : null}
|
||||||
</Box>
|
</Box>
|
||||||
<Button
|
|
||||||
variant="contained"
|
|
||||||
size="small"
|
|
||||||
startIcon={<AddIcon />}
|
|
||||||
onClick={(event) => setNewMenuAnchor(event.currentTarget)}
|
|
||||||
sx={{
|
|
||||||
backgroundImage: "linear-gradient(135deg,#7dd3fc,#c084fc)",
|
|
||||||
color: "#0b1220",
|
|
||||||
borderRadius: 999,
|
|
||||||
textTransform: "none",
|
|
||||||
boxShadow: "0 10px 26px rgba(124,58,237,0.28)",
|
|
||||||
"&:hover": {
|
|
||||||
backgroundImage: "linear-gradient(135deg,#86e1ff,#d1a6ff)",
|
|
||||||
boxShadow: "0 12px 34px rgba(124,58,237,0.38)",
|
|
||||||
filter: "none",
|
|
||||||
},
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
New Assembly
|
|
||||||
</Button>
|
|
||||||
<Menu
|
<Menu
|
||||||
anchorEl={newMenuAnchor}
|
anchorEl={newMenuAnchor}
|
||||||
open={Boolean(newMenuAnchor)}
|
open={Boolean(newMenuAnchor)}
|
||||||
|
|||||||
@@ -22,8 +22,7 @@ import {
|
|||||||
import {
|
import {
|
||||||
Schedule as HeaderIcon,
|
Schedule as HeaderIcon,
|
||||||
Cached as CachedIcon,
|
Cached as CachedIcon,
|
||||||
Add as AddIcon,
|
Add as AddIcon
|
||||||
Tune as TuneIcon
|
|
||||||
} from "@mui/icons-material";
|
} from "@mui/icons-material";
|
||||||
import { AgGridReact } from "ag-grid-react";
|
import { AgGridReact } from "ag-grid-react";
|
||||||
import { ModuleRegistry, AllCommunityModule, themeQuartz } from "ag-grid-community";
|
import { ModuleRegistry, AllCommunityModule, themeQuartz } from "ag-grid-community";
|
||||||
@@ -746,45 +745,36 @@ export default function ScheduledJobsList({ onCreateJob, onEditJob, refreshToken
|
|||||||
}}
|
}}
|
||||||
elevation={0}
|
elevation={0}
|
||||||
>
|
>
|
||||||
<Box sx={{ px: 3, pt: 3, pb: 1, display: "flex", justifyContent: "flex-end", gap: 1.5 }}>
|
{/* Page-level action buttons (floating top-right) */}
|
||||||
<Tooltip title="Refresh">
|
<Box
|
||||||
<span>
|
sx={{
|
||||||
<IconButton
|
position: "fixed",
|
||||||
size="small"
|
top: { xs: 72, md: 88 },
|
||||||
onClick={handleRefreshClick}
|
right: { xs: 12, md: 20 },
|
||||||
sx={{ color: "#cbd5e1", borderRadius: 1, "&:hover": { color: "#ffffff" } }}
|
zIndex: 1400,
|
||||||
>
|
pointerEvents: "none",
|
||||||
<CachedIcon fontSize="small" />
|
}}
|
||||||
</IconButton>
|
>
|
||||||
</span>
|
<Stack direction="row" spacing={1} alignItems="center" sx={{ pointerEvents: "auto" }}>
|
||||||
</Tooltip>
|
<Tooltip title="Refresh">
|
||||||
<Tooltip title="Create Job">
|
<span>
|
||||||
<span>
|
<IconButton
|
||||||
<Button size="small" startIcon={<AddIcon />} sx={gradientButtonSx} onClick={() => onCreateJob && onCreateJob()}>
|
size="small"
|
||||||
Create Job
|
onClick={handleRefreshClick}
|
||||||
</Button>
|
sx={{ color: "#cbd5e1", borderRadius: 1, "&:hover": { color: "#ffffff" } }}
|
||||||
</span>
|
>
|
||||||
</Tooltip>
|
<CachedIcon fontSize="small" />
|
||||||
<Tooltip title="Settings">
|
</IconButton>
|
||||||
<span>
|
</span>
|
||||||
<Button
|
</Tooltip>
|
||||||
size="small"
|
<Tooltip title="Create Job">
|
||||||
variant="outlined"
|
<span>
|
||||||
startIcon={<TuneIcon />}
|
<Button size="small" startIcon={<AddIcon />} sx={gradientButtonSx} onClick={() => onCreateJob && onCreateJob()}>
|
||||||
sx={{
|
Create Job
|
||||||
borderColor: "rgba(148,163,184,0.35)",
|
</Button>
|
||||||
color: "#e2e8f0",
|
</span>
|
||||||
textTransform: "none",
|
</Tooltip>
|
||||||
borderRadius: 999,
|
</Stack>
|
||||||
px: 1.7,
|
|
||||||
minWidth: 86,
|
|
||||||
"&:hover": { borderColor: "rgba(148,163,184,0.55)" },
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
Settings
|
|
||||||
</Button>
|
|
||||||
</span>
|
|
||||||
</Tooltip>
|
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
<Box sx={{ mt: 2, px: 2, pb: 2, flexGrow: 1, minHeight: 0, display: "flex", flexDirection: "column" }}>
|
<Box sx={{ mt: 2, px: 2, pb: 2, flexGrow: 1, minHeight: 0, display: "flex", flexDirection: "column" }}>
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
Borealis is a remote management platform with a simple, visual automation layer, enabling you to leverage scripts and advanced nodegraph-based automation workflows. I originally created Borealis to work towards consolidating the core functionality of several standalone automation platforms in my homelab, such as TacticalRMM, Ansible AWX, SemaphoreUI, and a few others.
|
Borealis is a remote management platform with a simple, visual automation layer, enabling you to leverage scripts and advanced nodegraph-based automation workflows. I originally created Borealis to work towards consolidating the core functionality of several standalone automation platforms in my homelab, such as TacticalRMM, Ansible AWX, SemaphoreUI, and a few others.
|
||||||
|
|
||||||
### A Note on Development Pace
|
### A Note on Development Pace
|
||||||
I'm the sole maintainer and still learning as I go, while working a full-time IT job. Progress is sporadic, and parts of the codebase get rebuilt when I discover better or more optimized approaches. Thank you for your patience with the slower cadence. Ko-Fi donations are always welcome and help keep m,me motivated to continue development of Borealis.
|
I'm the sole maintainer and still learning as I go, while working a full-time IT job. Progress is sporadic, and parts of the codebase get rebuilt when I discover better or more optimized approaches. Thank you for your patience with the slower cadence. Ko-Fi donations are always welcome and help keep me motivated to actively continue development of Borealis.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user