Refactor routing logic in App component to conditionally use HashRouter or BrowserRouter based on the environment. Update AuthContext and related components to replace 'authenticated' with 'token' for improved authentication handling. Enhance NotesPanel and ObjectTable components to manage loading states and data fetching more effectively, ensuring better user experience and error handling.
This commit is contained in:
parent
66e137fac2
commit
a20235a953
14
src/App.jsx
14
src/App.jsx
@ -1,6 +1,7 @@
|
|||||||
import React from 'react'
|
import React from 'react'
|
||||||
import {
|
import {
|
||||||
BrowserRouter as Router,
|
HashRouter,
|
||||||
|
BrowserRouter,
|
||||||
Routes,
|
Routes,
|
||||||
Route,
|
Route,
|
||||||
Navigate
|
Navigate
|
||||||
@ -70,8 +71,19 @@ import Hosts from './components/Dashboard/Management/Hosts.jsx'
|
|||||||
import { ElectronProvider } from './components/Dashboard/context/ElectronContext.js'
|
import { ElectronProvider } from './components/Dashboard/context/ElectronContext.js'
|
||||||
import AuthCallback from './components/App/AuthCallback.jsx'
|
import AuthCallback from './components/App/AuthCallback.jsx'
|
||||||
|
|
||||||
|
const getRouter = () => {
|
||||||
|
if (
|
||||||
|
typeof window !== 'undefined' &&
|
||||||
|
window.location.href.includes('index.html')
|
||||||
|
) {
|
||||||
|
return HashRouter
|
||||||
|
}
|
||||||
|
return BrowserRouter
|
||||||
|
}
|
||||||
|
|
||||||
const AppContent = () => {
|
const AppContent = () => {
|
||||||
const { themeConfig } = useThemeContext()
|
const { themeConfig } = useThemeContext()
|
||||||
|
const Router = getRouter()
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ConfigProvider theme={themeConfig}>
|
<ConfigProvider theme={themeConfig}>
|
||||||
|
|||||||
@ -44,7 +44,7 @@ const EditObjectForm = ({ id, type, style, children }) => {
|
|||||||
subscribeToObject,
|
subscribeToObject,
|
||||||
subscribeToLock
|
subscribeToLock
|
||||||
} = useContext(ApiServerContext)
|
} = useContext(ApiServerContext)
|
||||||
const { authenticated } = useContext(AuthContext)
|
const { token } = useContext(AuthContext)
|
||||||
// Validate form on change
|
// Validate form on change
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
form
|
form
|
||||||
@ -92,11 +92,11 @@ const EditObjectForm = ({ id, type, style, children }) => {
|
|||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!initialized && id && authenticated == true) {
|
if (!initialized && id && token != null) {
|
||||||
setInitialized(true)
|
setInitialized(true)
|
||||||
handleFetchObject()
|
handleFetchObject()
|
||||||
}
|
}
|
||||||
}, [id, initialized, handleFetchObject, authenticated])
|
}, [id, initialized, handleFetchObject, token])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (id && connected) {
|
if (id && connected) {
|
||||||
|
|||||||
@ -264,6 +264,7 @@ const NotesPanel = ({ _id, onNewNote, type }) => {
|
|||||||
const [newNoteOpen, setNewNoteOpen] = useState(false)
|
const [newNoteOpen, setNewNoteOpen] = useState(false)
|
||||||
const [showMarkdown, setShowMarkdown] = useState(false)
|
const [showMarkdown, setShowMarkdown] = useState(false)
|
||||||
const [loading, setLoading] = useState(true)
|
const [loading, setLoading] = useState(true)
|
||||||
|
const [initialized, setInitialized] = useState(false)
|
||||||
const [messageApi, contextHolder] = message.useMessage()
|
const [messageApi, contextHolder] = message.useMessage()
|
||||||
const [newNoteFormLoading, setNewNoteFormLoading] = useState(false)
|
const [newNoteFormLoading, setNewNoteFormLoading] = useState(false)
|
||||||
const [newNoteFormValues, setNewNoteFormValues] = useState({})
|
const [newNoteFormValues, setNewNoteFormValues] = useState({})
|
||||||
@ -290,19 +291,17 @@ const NotesPanel = ({ _id, onNewNote, type }) => {
|
|||||||
.catch(() => setDoneEnabled(false))
|
.catch(() => setDoneEnabled(false))
|
||||||
}, [newNoteForm, newNoteFormUpdateValues])
|
}, [newNoteForm, newNoteFormUpdateValues])
|
||||||
|
|
||||||
const { authenticated, userProfile } = useContext(AuthContext)
|
const { token, userProfile } = useContext(AuthContext)
|
||||||
const { fetchNotes } = useContext(ApiServerContext)
|
const { fetchNotes } = useContext(ApiServerContext)
|
||||||
|
|
||||||
const fetchData = useCallback(
|
const fetchData = useCallback(
|
||||||
async (id) => {
|
async (id) => {
|
||||||
try {
|
try {
|
||||||
const newData = await fetchNotes(id)
|
const newData = await fetchNotes(id)
|
||||||
setLoading(false)
|
|
||||||
return newData
|
return newData
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
setNotes([])
|
|
||||||
setError(error)
|
setError(error)
|
||||||
setLoading(false)
|
return null
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[fetchNotes]
|
[fetchNotes]
|
||||||
@ -322,10 +321,14 @@ const NotesPanel = ({ _id, onNewNote, type }) => {
|
|||||||
const generateNotes = useCallback(
|
const generateNotes = useCallback(
|
||||||
async (id) => {
|
async (id) => {
|
||||||
const notesData = await fetchData(id)
|
const notesData = await fetchData(id)
|
||||||
|
setLoading(false)
|
||||||
|
|
||||||
|
if (notesData == null) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
if (notesData.length <= 0) {
|
if (notesData.length <= 0) {
|
||||||
return (
|
return (
|
||||||
<Spin indicator={<LoadingOutlined />} spinning={loading}>
|
|
||||||
<Card>
|
<Card>
|
||||||
<Flex
|
<Flex
|
||||||
justify='center'
|
justify='center'
|
||||||
@ -339,7 +342,6 @@ const NotesPanel = ({ _id, onNewNote, type }) => {
|
|||||||
<Text type='secondary'>No notes added.</Text>
|
<Text type='secondary'>No notes added.</Text>
|
||||||
</Flex>
|
</Flex>
|
||||||
</Card>
|
</Card>
|
||||||
</Spin>
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -458,10 +460,11 @@ const NotesPanel = ({ _id, onNewNote, type }) => {
|
|||||||
}, [_id, generateNotes])
|
}, [_id, generateNotes])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (authenticated) {
|
if (token != null && !initialized) {
|
||||||
handleReloadData()
|
handleReloadData()
|
||||||
|
setInitialized(true)
|
||||||
}
|
}
|
||||||
}, [authenticated, handleReloadData])
|
}, [token, handleReloadData, initialized])
|
||||||
|
|
||||||
const handleModalOk = async () => {
|
const handleModalOk = async () => {
|
||||||
try {
|
try {
|
||||||
|
|||||||
@ -56,7 +56,7 @@ const ObjectTable = forwardRef(
|
|||||||
},
|
},
|
||||||
ref
|
ref
|
||||||
) => {
|
) => {
|
||||||
const { authenticated } = useContext(AuthContext)
|
const { token } = useContext(AuthContext)
|
||||||
const { fetchObjects, connected, subscribeToObject, subscribeToType } =
|
const { fetchObjects, connected, subscribeToObject, subscribeToType } =
|
||||||
useContext(ApiServerContext)
|
useContext(ApiServerContext)
|
||||||
const isMobile = useMediaQuery({ maxWidth: 768 })
|
const isMobile = useMediaQuery({ maxWidth: 768 })
|
||||||
@ -163,7 +163,7 @@ const ObjectTable = forwardRef(
|
|||||||
|
|
||||||
setLoading(false)
|
setLoading(false)
|
||||||
setLazyLoading(false)
|
setLazyLoading(false)
|
||||||
return result.data
|
return result.data || []
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
setPages((prev) =>
|
setPages((prev) =>
|
||||||
prev.map((page) => ({
|
prev.map((page) => ({
|
||||||
@ -302,6 +302,7 @@ const ObjectTable = forwardRef(
|
|||||||
|
|
||||||
// Subscribe to each item in all pages
|
// Subscribe to each item in all pages
|
||||||
pages.forEach((page) => {
|
pages.forEach((page) => {
|
||||||
|
if (page?.items && page?.items?.length > 0) {
|
||||||
page.items.forEach((item) => {
|
page.items.forEach((item) => {
|
||||||
if (!item.isSkeleton) {
|
if (!item.isSkeleton) {
|
||||||
const unsubscribe = subscribeToObject(
|
const unsubscribe = subscribeToObject(
|
||||||
@ -314,6 +315,7 @@ const ObjectTable = forwardRef(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
@ -378,11 +380,11 @@ const ObjectTable = forwardRef(
|
|||||||
}))
|
}))
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (authenticated && !pages.includes(initialPage) && !initialized) {
|
if (token != null && !pages.includes(initialPage) && !initialized) {
|
||||||
loadInitialPage()
|
loadInitialPage()
|
||||||
setInitialized(true)
|
setInitialized(true)
|
||||||
}
|
}
|
||||||
}, [authenticated, loadInitialPage, initialPage, pages, initialized])
|
}, [token, loadInitialPage, initialPage, pages, initialized])
|
||||||
|
|
||||||
const getFilterDropdown = ({
|
const getFilterDropdown = ({
|
||||||
setSelectedKeys,
|
setSelectedKeys,
|
||||||
@ -497,7 +499,7 @@ const ObjectTable = forwardRef(
|
|||||||
fixed: fixed,
|
fixed: fixed,
|
||||||
key: prop.name,
|
key: prop.name,
|
||||||
render: (text, record) => {
|
render: (text, record) => {
|
||||||
if (record.isSkeleton) {
|
if (record?.isSkeleton) {
|
||||||
return (
|
return (
|
||||||
<Skeleton.Input active size='small' style={{ width: '100%' }} />
|
<Skeleton.Input active size='small' style={{ width: '100%' }} />
|
||||||
)
|
)
|
||||||
|
|||||||
@ -23,7 +23,8 @@ logger.setLevel(config.logLevel)
|
|||||||
const ApiServerContext = createContext()
|
const ApiServerContext = createContext()
|
||||||
|
|
||||||
const ApiServerProvider = ({ children }) => {
|
const ApiServerProvider = ({ children }) => {
|
||||||
const { token, userProfile, authenticated } = useContext(AuthContext)
|
const { token, userProfile, authenticated, setUnauthenticated } =
|
||||||
|
useContext(AuthContext)
|
||||||
const socketRef = useRef(null)
|
const socketRef = useRef(null)
|
||||||
const [connected, setConnected] = useState(false)
|
const [connected, setConnected] = useState(false)
|
||||||
const [connecting, setConnecting] = useState(false)
|
const [connecting, setConnecting] = useState(false)
|
||||||
@ -347,6 +348,11 @@ const ApiServerProvider = ({ children }) => {
|
|||||||
)
|
)
|
||||||
|
|
||||||
const showError = (error, callback = null) => {
|
const showError = (error, callback = null) => {
|
||||||
|
const code = error.response.data.code || 'UNKNOWN'
|
||||||
|
if (code == 'UNAUTHORIZED') {
|
||||||
|
setUnauthenticated()
|
||||||
|
return
|
||||||
|
}
|
||||||
var content = `Error ${error.code} (${error.status}): ${error.message}`
|
var content = `Error ${error.code} (${error.status}): ${error.message}`
|
||||||
if (error.response?.data?.error) {
|
if (error.response?.data?.error) {
|
||||||
content = `${error.response?.data?.error} (${error.status})`
|
content = `${error.response?.data?.error} (${error.status})`
|
||||||
@ -377,14 +383,13 @@ const ApiServerProvider = ({ children }) => {
|
|||||||
Authorization: `Bearer ${token}`
|
Authorization: `Bearer ${token}`
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
setFetchLoading(false)
|
||||||
return response.data
|
return response.data
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
showError(err, () => {
|
showError(err, () => {
|
||||||
fetchObject(id, type)
|
fetchObject(id, type)
|
||||||
})
|
})
|
||||||
return {}
|
return {}
|
||||||
} finally {
|
|
||||||
setFetchLoading(false)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -397,7 +402,9 @@ const ApiServerProvider = ({ children }) => {
|
|||||||
sorter = {},
|
sorter = {},
|
||||||
onDataChange
|
onDataChange
|
||||||
} = params
|
} = params
|
||||||
|
if (token == null) {
|
||||||
|
return []
|
||||||
|
}
|
||||||
logger.debug('Fetching table data from:', type, {
|
logger.debug('Fetching table data from:', type, {
|
||||||
page,
|
page,
|
||||||
limit,
|
limit,
|
||||||
@ -449,6 +456,9 @@ const ApiServerProvider = ({ children }) => {
|
|||||||
|
|
||||||
// Fetch table data with pagination, filtering, and sorting
|
// Fetch table data with pagination, filtering, and sorting
|
||||||
const fetchObjectsByProperty = async (type, params = {}) => {
|
const fetchObjectsByProperty = async (type, params = {}) => {
|
||||||
|
if (token == null) {
|
||||||
|
return []
|
||||||
|
}
|
||||||
const { filter = {}, properties = [] } = params
|
const { filter = {}, properties = [] } = params
|
||||||
|
|
||||||
logger.debug('Fetching property object data from:', type, {
|
logger.debug('Fetching property object data from:', type, {
|
||||||
@ -476,8 +486,9 @@ const ApiServerProvider = ({ children }) => {
|
|||||||
return newData
|
return newData
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
showError(err, () => {
|
showError(err, () => {
|
||||||
fetchObjectsByProperty(type, params)
|
fetchObjects(type, params)
|
||||||
})
|
})
|
||||||
|
|
||||||
return []
|
return []
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -604,7 +615,7 @@ const ApiServerProvider = ({ children }) => {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
const notesData = response.data
|
const notesData = response.data || []
|
||||||
logger.debug('Fetched notes:', notesData.length)
|
logger.debug('Fetched notes:', notesData.length)
|
||||||
return notesData
|
return notesData
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|||||||
@ -15,7 +15,7 @@ import config from '../../../config'
|
|||||||
import AppError from '../../App/AppError'
|
import AppError from '../../App/AppError'
|
||||||
import loglevel from 'loglevel'
|
import loglevel from 'loglevel'
|
||||||
import { ElectronContext } from './ElectronContext'
|
import { ElectronContext } from './ElectronContext'
|
||||||
import { useLocation } from 'react-router-dom'
|
import { useLocation, useNavigate } from 'react-router-dom'
|
||||||
const logger = loglevel.getLogger('ApiServerContext')
|
const logger = loglevel.getLogger('ApiServerContext')
|
||||||
logger.setLevel(config.logLevel)
|
logger.setLevel(config.logLevel)
|
||||||
|
|
||||||
@ -36,6 +36,7 @@ const AuthProvider = ({ children }) => {
|
|||||||
const [authError, setAuthError] = useState(null)
|
const [authError, setAuthError] = useState(null)
|
||||||
const { openExternalUrl, isElectron } = useContext(ElectronContext)
|
const { openExternalUrl, isElectron } = useContext(ElectronContext)
|
||||||
const location = useLocation()
|
const location = useLocation()
|
||||||
|
const navigate = useNavigate()
|
||||||
|
|
||||||
// Read token from session storage if present
|
// Read token from session storage if present
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@ -147,6 +148,11 @@ const AuthProvider = ({ children }) => {
|
|||||||
}
|
}
|
||||||
}, [token])
|
}, [token])
|
||||||
|
|
||||||
|
const setUnauthenticated = () => {
|
||||||
|
setAuthenticated(false)
|
||||||
|
setShowUnauthorizedModal(true)
|
||||||
|
}
|
||||||
|
|
||||||
const refreshToken = useCallback(async () => {
|
const refreshToken = useCallback(async () => {
|
||||||
try {
|
try {
|
||||||
const response = await axios.get(`${config.backendUrl}/auth/refresh`, {
|
const response = await axios.get(`${config.backendUrl}/auth/refresh`, {
|
||||||
@ -260,22 +266,28 @@ const AuthProvider = ({ children }) => {
|
|||||||
new URLSearchParams(location.search).get('authCode') || null
|
new URLSearchParams(location.search).get('authCode') || null
|
||||||
if (authCode != null) {
|
if (authCode != null) {
|
||||||
getLoginToken(authCode)
|
getLoginToken(authCode)
|
||||||
if (window && window.history && window.location) {
|
const searchParams = new URLSearchParams(location.search)
|
||||||
const url = new URL(window.location.href)
|
if (searchParams.has('authCode')) {
|
||||||
if (url.searchParams.has('authCode')) {
|
searchParams.delete('authCode')
|
||||||
url.searchParams.delete('authCode')
|
const newSearch = searchParams.toString()
|
||||||
window.history.replaceState(
|
const newPath = location.pathname + (newSearch ? `?${newSearch}` : '')
|
||||||
{},
|
navigate(newPath, { replace: true })
|
||||||
document.title,
|
|
||||||
url.pathname + url.search
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
} else if (token == null) {
|
||||||
|
setShowUnauthorizedModal(true)
|
||||||
|
setAuthenticated(false)
|
||||||
}
|
}
|
||||||
setInitialized(true)
|
setInitialized(true)
|
||||||
return
|
|
||||||
}
|
}
|
||||||
}
|
}, [
|
||||||
}, [checkAuthStatus, location.search, getLoginToken, initialized])
|
checkAuthStatus,
|
||||||
|
location.search,
|
||||||
|
getLoginToken,
|
||||||
|
initialized,
|
||||||
|
location.pathname,
|
||||||
|
navigate,
|
||||||
|
token
|
||||||
|
])
|
||||||
|
|
||||||
if (authError) {
|
if (authError) {
|
||||||
return <AppError message={authError} showBack={false} />
|
return <AppError message={authError} showBack={false} />
|
||||||
@ -288,6 +300,7 @@ const AuthProvider = ({ children }) => {
|
|||||||
<AuthContext.Provider
|
<AuthContext.Provider
|
||||||
value={{
|
value={{
|
||||||
authenticated,
|
authenticated,
|
||||||
|
setUnauthenticated,
|
||||||
loginWithSSO,
|
loginWithSSO,
|
||||||
getLoginToken,
|
getLoginToken,
|
||||||
token,
|
token,
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user