feat:
--Added new pages Dashboard, Nodes, Cluster
This commit is contained in:
1 parent
50e424bc22
commit
e9178bc340
2 files changed
+159
-5
No files matched your search
+56
@@ -257,6 +257,13 @@
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.page-actions {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 10px;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
|
||||
.primary-button,
|
||||
.secondary-button {
|
||||
display: inline-flex;
|
||||
@@ -284,6 +291,12 @@
|
||||
background: var(--accent-border);
|
||||
}
|
||||
|
||||
.primary-button:disabled,
|
||||
.secondary-button:disabled {
|
||||
cursor: not-allowed;
|
||||
opacity: 0.65;
|
||||
}
|
||||
|
||||
.secondary-button {
|
||||
border: 1px solid var(--border);
|
||||
background: var(--bg);
|
||||
@@ -295,6 +308,11 @@
|
||||
background: var(--accent-bg);
|
||||
}
|
||||
|
||||
.secondary-button:disabled:hover {
|
||||
border-color: var(--border);
|
||||
background: var(--bg);
|
||||
}
|
||||
|
||||
.primary-button:focus-visible,
|
||||
.secondary-button:focus-visible,
|
||||
.register-form input:focus-visible {
|
||||
@@ -302,6 +320,40 @@
|
||||
outline-offset: 2px;
|
||||
}
|
||||
|
||||
.status-message {
|
||||
width: fit-content;
|
||||
margin-bottom: 18px;
|
||||
border: 1px solid var(--border);
|
||||
border-radius: 6px;
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
padding: 8px 12px;
|
||||
}
|
||||
|
||||
.status-message.success {
|
||||
border-color: #86efac;
|
||||
background: #f0fdf4;
|
||||
color: #166534;
|
||||
}
|
||||
|
||||
.status-message.error {
|
||||
border-color: #fecaca;
|
||||
background: #fef2f2;
|
||||
color: #991b1b;
|
||||
}
|
||||
|
||||
.theme-dark .status-message.success {
|
||||
border-color: #166534;
|
||||
background: rgba(22, 101, 52, 0.18);
|
||||
color: #bbf7d0;
|
||||
}
|
||||
|
||||
.theme-dark .status-message.error {
|
||||
border-color: #991b1b;
|
||||
background: rgba(153, 27, 27, 0.18);
|
||||
color: #fecaca;
|
||||
}
|
||||
|
||||
.register-form {
|
||||
border: 1px solid var(--border);
|
||||
border-radius: 8px;
|
||||
@@ -379,6 +431,10 @@
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.page-actions {
|
||||
justify-content: flex-start;
|
||||
}
|
||||
|
||||
.form-grid {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
+103
-5
@@ -4,9 +4,12 @@ import './App.css'
|
||||
const navItems = [
|
||||
{ id: 'dashboard', label: 'Dashboard' },
|
||||
{ id: 'nodes', label: 'Nodes' },
|
||||
]
|
||||
{ id: 'clusters', label: 'Clusters' },
|
||||
] as const
|
||||
|
||||
type PageId = (typeof navItems)[number]['id']
|
||||
type Theme = 'light' | 'dark'
|
||||
type TokenStatus = 'idle' | 'loading' | 'success' | 'error'
|
||||
|
||||
const getSavedTheme = (): Theme => {
|
||||
try {
|
||||
@@ -24,13 +27,67 @@ const saveTheme = (theme: Theme) => {
|
||||
}
|
||||
}
|
||||
|
||||
const getSavedPage = (): PageId => {
|
||||
try {
|
||||
const savedPage = localStorage.getItem('activePage')
|
||||
|
||||
return navItems.some((item) => item.id === savedPage)
|
||||
? (savedPage as PageId)
|
||||
: 'dashboard'
|
||||
} catch {
|
||||
return 'dashboard'
|
||||
}
|
||||
}
|
||||
|
||||
const savePage = (page: PageId) => {
|
||||
try {
|
||||
localStorage.setItem('activePage', page)
|
||||
} catch {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
const getSessionToken = async () => {
|
||||
const response = await fetch('http://127.0.0.1:8000/get-token', {
|
||||
method: 'POST',
|
||||
})
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error('Failed to get token')
|
||||
}
|
||||
|
||||
const data = (await response.json()) as {
|
||||
access_token: string
|
||||
token_type: string
|
||||
}
|
||||
|
||||
localStorage.setItem('access_token', data.access_token)
|
||||
|
||||
const storedToken = localStorage.getItem('access_token')
|
||||
|
||||
if (!storedToken) {
|
||||
throw new Error('Token was not stored')
|
||||
}
|
||||
|
||||
console.log('Token successfully stored:', storedToken)
|
||||
|
||||
return storedToken
|
||||
}
|
||||
|
||||
function App() {
|
||||
const [isCollapsed, setIsCollapsed] = useState(false)
|
||||
const [activePage, setActivePage] = useState('dashboard')
|
||||
const [activePage, setActivePage] = useState<PageId>(getSavedPage)
|
||||
const [theme, setTheme] = useState<Theme>(getSavedTheme)
|
||||
const [isRegisterFormOpen, setIsRegisterFormOpen] = useState(false)
|
||||
const [tokenStatus, setTokenStatus] = useState<TokenStatus>('idle')
|
||||
const [tokenError, setTokenError] = useState('')
|
||||
const nextTheme = theme === 'light' ? 'dark' : 'light'
|
||||
|
||||
const selectPage = (page: PageId) => {
|
||||
setActivePage(page)
|
||||
savePage(page)
|
||||
}
|
||||
|
||||
const toggleTheme = () => {
|
||||
setTheme((currentTheme) => {
|
||||
const updatedTheme = currentTheme === 'light' ? 'dark' : 'light'
|
||||
@@ -41,6 +98,21 @@ function App() {
|
||||
})
|
||||
}
|
||||
|
||||
const handleTempButtonClick = async () => {
|
||||
setTokenStatus('loading')
|
||||
setTokenError('')
|
||||
|
||||
try {
|
||||
await getSessionToken()
|
||||
setTokenStatus('success')
|
||||
} catch (error) {
|
||||
setTokenStatus('error')
|
||||
setTokenError(
|
||||
error instanceof Error ? error.message : 'Failed to get token',
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<div
|
||||
className={`app-shell theme-${theme} ${isCollapsed ? 'nav-collapsed' : ''}`}
|
||||
@@ -66,7 +138,7 @@ function App() {
|
||||
type="button"
|
||||
className={`nav-link ${activePage === item.id ? 'active' : ''}`}
|
||||
title={isCollapsed ? item.label : undefined}
|
||||
onClick={() => setActivePage(item.id)}
|
||||
onClick={() => selectPage(item.id)}
|
||||
aria-current={activePage === item.id ? 'page' : undefined}
|
||||
>
|
||||
<span className="nav-icon" aria-hidden="true">
|
||||
@@ -94,7 +166,7 @@ function App() {
|
||||
</aside>
|
||||
|
||||
<main className="main-content">
|
||||
{activePage === 'dashboard' ? (
|
||||
{activePage === 'dashboard' && (
|
||||
<section className="content-panel" id="dashboard">
|
||||
<p className="eyebrow">Dashboard</p>
|
||||
<h1>Welcome back</h1>
|
||||
@@ -104,10 +176,13 @@ function App() {
|
||||
grows.
|
||||
</p>
|
||||
</section>
|
||||
) : (
|
||||
)}
|
||||
|
||||
{activePage === 'nodes' && (
|
||||
<section className="content-panel nodes-page" id="nodes">
|
||||
<div className="page-header">
|
||||
<h1>Nodes</h1>
|
||||
<div className="page-actions">
|
||||
<button
|
||||
type="button"
|
||||
className="primary-button"
|
||||
@@ -115,7 +190,24 @@ function App() {
|
||||
>
|
||||
Register Nodes
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
className="secondary-button"
|
||||
onClick={handleTempButtonClick}
|
||||
disabled={tokenStatus === 'loading'}
|
||||
>
|
||||
{tokenStatus === 'loading' ? 'Getting Token' : 'Temp Button'}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{tokenStatus === 'success' && (
|
||||
<p className="status-message success">Token successfully stored.</p>
|
||||
)}
|
||||
|
||||
{tokenStatus === 'error' && (
|
||||
<p className="status-message error">{tokenError}</p>
|
||||
)}
|
||||
|
||||
{isRegisterFormOpen ? (
|
||||
<form className="register-form">
|
||||
@@ -174,6 +266,12 @@ function App() {
|
||||
) : null}
|
||||
</section>
|
||||
)}
|
||||
|
||||
{activePage === 'clusters' && (
|
||||
<section className="content-panel" id="clusters">
|
||||
<h1>Clusters</h1>
|
||||
</section>
|
||||
)}
|
||||
</main>
|
||||
</div>
|
||||
)
|
||||
|
||||
Reference in new issue
Block a user