Using cross-env and fixed login error handling.
This commit is contained in:
parent
894b6af3c8
commit
5f20f81a2c
@ -34,6 +34,7 @@
|
|||||||
"antd-style": "^3.7.1",
|
"antd-style": "^3.7.1",
|
||||||
"axios": "^1.11.0",
|
"axios": "^1.11.0",
|
||||||
"country-list": "^2.3.0",
|
"country-list": "^2.3.0",
|
||||||
|
"cross-env": "^10.0.0",
|
||||||
"dayjs": "^1.11.13",
|
"dayjs": "^1.11.13",
|
||||||
"dotenv": "^17.2.1",
|
"dotenv": "^17.2.1",
|
||||||
"eslint": "^9.33.0",
|
"eslint": "^9.33.0",
|
||||||
@ -69,12 +70,12 @@
|
|||||||
"main": "build/electron.js",
|
"main": "build/electron.js",
|
||||||
"description": "3D Printer ERP and Control Software.",
|
"description": "3D Printer ERP and Control Software.",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "vite",
|
"dev": "cross-env NODE_ENV=development vite",
|
||||||
"electron": "set ELECTRON_START_URL=http://0.0.0.0:3000 && NODE_ENV=development && electron .",
|
"electron": "cross-env ELECTRON_START_URL=http://0.0.0.0:3000 && cross-env NODE_ENV=development && electron .",
|
||||||
"start": "serve -s build",
|
"start": "serve -s build",
|
||||||
"build": "vite build",
|
"build": "vite build",
|
||||||
"dev:electron": "concurrently \"vite --no-open\" \"set ELECTRON_START_URL=http://localhost:3000 && set NODE_ENV=development && electron public/electron.js\"",
|
"dev:electron": "concurrently \"cross-env NODE_ENV=development vite --no-open\" \"cross-env ELECTRON_START_URL=http://localhost:3000 cross-env NODE_ENV=development electron public/electron.js\"",
|
||||||
"build:electron": "npm run build && electron-builder"
|
"build:electron": "vite build && electron-builder"
|
||||||
},
|
},
|
||||||
"eslintConfig": {
|
"eslintConfig": {
|
||||||
"extends": [
|
"extends": [
|
||||||
|
|||||||
@ -5,12 +5,16 @@ import ExclamationOctagonIcon from '../Icons/ExclamationOctagonIcon'
|
|||||||
import PropTypes from 'prop-types'
|
import PropTypes from 'prop-types'
|
||||||
import ArrowLeftIcon from '../Icons/ArrowLeftIcon'
|
import ArrowLeftIcon from '../Icons/ArrowLeftIcon'
|
||||||
import ReloadIcon from '../Icons/ReloadIcon'
|
import ReloadIcon from '../Icons/ReloadIcon'
|
||||||
|
import { useNavigate } from 'react-router-dom'
|
||||||
|
import VendorIcon from '../Icons/VendorIcon'
|
||||||
|
|
||||||
const AppError = ({
|
const AppError = ({
|
||||||
message = 'Error Message',
|
message = 'Error Message',
|
||||||
showBack = true,
|
showBack = true,
|
||||||
showRefresh = true
|
showRefresh = true,
|
||||||
|
showHome = true
|
||||||
}) => {
|
}) => {
|
||||||
|
const navigate = useNavigate()
|
||||||
const handleBack = () => {
|
const handleBack = () => {
|
||||||
window.history.back()
|
window.history.back()
|
||||||
}
|
}
|
||||||
@ -19,6 +23,10 @@ const AppError = ({
|
|||||||
window.location.reload()
|
window.location.reload()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const handleHome = () => {
|
||||||
|
navigate('/production/overview')
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<AuthParticles />
|
<AuthParticles />
|
||||||
@ -40,7 +48,7 @@ const AppError = ({
|
|||||||
type={'error'}
|
type={'error'}
|
||||||
showIcon
|
showIcon
|
||||||
/>
|
/>
|
||||||
{(showBack || showRefresh) && (
|
{(showBack || showRefresh || showHome) && (
|
||||||
<Flex gap='middle'>
|
<Flex gap='middle'>
|
||||||
{showBack && (
|
{showBack && (
|
||||||
<Button
|
<Button
|
||||||
@ -56,6 +64,9 @@ const AppError = ({
|
|||||||
size='large'
|
size='large'
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
{showHome && (
|
||||||
|
<Button icon={<VendorIcon />} onClick={handleHome} size='large' />
|
||||||
|
)}
|
||||||
</Flex>
|
</Flex>
|
||||||
)}
|
)}
|
||||||
</Flex>
|
</Flex>
|
||||||
@ -66,7 +77,8 @@ const AppError = ({
|
|||||||
AppError.propTypes = {
|
AppError.propTypes = {
|
||||||
message: PropTypes.string,
|
message: PropTypes.string,
|
||||||
showBack: PropTypes.bool,
|
showBack: PropTypes.bool,
|
||||||
showRefresh: PropTypes.bool
|
showRefresh: PropTypes.bool,
|
||||||
|
showHome: PropTypes.bool
|
||||||
}
|
}
|
||||||
|
|
||||||
export default AppError
|
export default AppError
|
||||||
|
|||||||
@ -21,7 +21,6 @@ import PropTypes from 'prop-types'
|
|||||||
import ExclamationOctogonIcon from '../../Icons/ExclamationOctagonIcon'
|
import ExclamationOctogonIcon from '../../Icons/ExclamationOctagonIcon'
|
||||||
import InfoCircleIcon from '../../Icons/InfoCircleIcon'
|
import InfoCircleIcon from '../../Icons/InfoCircleIcon'
|
||||||
import config from '../../../config'
|
import config from '../../../config'
|
||||||
import AppError from '../../App/AppError'
|
|
||||||
import loglevel from 'loglevel'
|
import loglevel from 'loglevel'
|
||||||
import { ElectronContext } from './ElectronContext'
|
import { ElectronContext } from './ElectronContext'
|
||||||
import { useLocation, useNavigate } from 'react-router-dom'
|
import { useLocation, useNavigate } from 'react-router-dom'
|
||||||
@ -30,7 +29,7 @@ logger.setLevel(config.logLevel)
|
|||||||
|
|
||||||
const AuthContext = createContext()
|
const AuthContext = createContext()
|
||||||
|
|
||||||
const Title = Typography
|
const { Text } = Typography
|
||||||
|
|
||||||
const AuthProvider = ({ children }) => {
|
const AuthProvider = ({ children }) => {
|
||||||
const [messageApi, contextHolder] = message.useMessage()
|
const [messageApi, contextHolder] = message.useMessage()
|
||||||
@ -46,6 +45,7 @@ const AuthProvider = ({ children }) => {
|
|||||||
const [userProfile, setUserProfile] = useState(null)
|
const [userProfile, setUserProfile] = useState(null)
|
||||||
const [showSessionExpiredModal, setShowSessionExpiredModal] = useState(false)
|
const [showSessionExpiredModal, setShowSessionExpiredModal] = useState(false)
|
||||||
const [showUnauthorizedModal, setShowUnauthorizedModal] = useState(false)
|
const [showUnauthorizedModal, setShowUnauthorizedModal] = useState(false)
|
||||||
|
const [showAuthErrorModal, setShowAuthErrorModal] = useState(false)
|
||||||
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()
|
||||||
@ -148,13 +148,19 @@ const AuthProvider = ({ children }) => {
|
|||||||
} else {
|
} else {
|
||||||
setAuthenticated(false)
|
setAuthenticated(false)
|
||||||
setAuthError('Failed to authenticate user.')
|
setAuthError('Failed to authenticate user.')
|
||||||
|
setShowAuthErrorModal(true)
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logger.debug('Auth check failed', error)
|
logger.debug('Auth check failed', error)
|
||||||
if (error.response?.status === 401) {
|
if (error.response?.status === 401) {
|
||||||
setShowUnauthorizedModal(true)
|
setShowUnauthorizedModal(true)
|
||||||
} else {
|
} else {
|
||||||
setAuthError('Error connecting to authentication service.')
|
const errorMessage =
|
||||||
|
error?.response?.data?.error ||
|
||||||
|
'Error connecting to authentication service.'
|
||||||
|
const fullStop = errorMessage.endsWith('.')
|
||||||
|
setAuthError(`${errorMessage}${!fullStop && '.'}`)
|
||||||
|
setShowAuthErrorModal(true)
|
||||||
}
|
}
|
||||||
setAuthenticated(false)
|
setAuthenticated(false)
|
||||||
} finally {
|
} finally {
|
||||||
@ -186,6 +192,7 @@ const AuthProvider = ({ children }) => {
|
|||||||
} else {
|
} else {
|
||||||
setAuthenticated(false)
|
setAuthenticated(false)
|
||||||
setAuthError('Failed to authenticate user.')
|
setAuthError('Failed to authenticate user.')
|
||||||
|
setShowAuthErrorModal(true)
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logger.debug('Auth check failed', error)
|
logger.debug('Auth check failed', error)
|
||||||
@ -193,6 +200,7 @@ const AuthProvider = ({ children }) => {
|
|||||||
setShowUnauthorizedModal(true)
|
setShowUnauthorizedModal(true)
|
||||||
} else {
|
} else {
|
||||||
setAuthError('Error connecting to authentication service.')
|
setAuthError('Error connecting to authentication service.')
|
||||||
|
setShowAuthErrorModal(true)
|
||||||
}
|
}
|
||||||
setAuthenticated(false)
|
setAuthenticated(false)
|
||||||
} finally {
|
} finally {
|
||||||
@ -342,10 +350,6 @@ const AuthProvider = ({ children }) => {
|
|||||||
retreivedTokenFromSession
|
retreivedTokenFromSession
|
||||||
])
|
])
|
||||||
|
|
||||||
if (authError) {
|
|
||||||
return <AppError message={authError} showBack={false} />
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{contextHolder}
|
{contextHolder}
|
||||||
@ -371,7 +375,7 @@ const AuthProvider = ({ children }) => {
|
|||||||
Session Expired
|
Session Expired
|
||||||
</Space>
|
</Space>
|
||||||
}
|
}
|
||||||
open={showSessionExpiredModal}
|
open={showSessionExpiredModal && !loading && !showAuthErrorModal}
|
||||||
onOk={handleSessionExpiredModalOk}
|
onOk={handleSessionExpiredModalOk}
|
||||||
okText='Log In'
|
okText='Log In'
|
||||||
style={{ maxWidth: 430 }}
|
style={{ maxWidth: 430 }}
|
||||||
@ -388,7 +392,7 @@ const AuthProvider = ({ children }) => {
|
|||||||
</Button>
|
</Button>
|
||||||
]}
|
]}
|
||||||
>
|
>
|
||||||
Your session has expired. Please log in again to continue.
|
<Text>Your session has expired. Please log in again to continue.</Text>
|
||||||
</Modal>
|
</Modal>
|
||||||
<Modal
|
<Modal
|
||||||
title={
|
title={
|
||||||
@ -397,7 +401,7 @@ const AuthProvider = ({ children }) => {
|
|||||||
Please log in to continue
|
Please log in to continue
|
||||||
</Space>
|
</Space>
|
||||||
}
|
}
|
||||||
open={showUnauthorizedModal}
|
open={showUnauthorizedModal && !loading && !showAuthErrorModal}
|
||||||
onOk={() => {
|
onOk={() => {
|
||||||
setShowUnauthorizedModal(false)
|
setShowUnauthorizedModal(false)
|
||||||
loginWithSSO()
|
loginWithSSO()
|
||||||
@ -419,8 +423,10 @@ const AuthProvider = ({ children }) => {
|
|||||||
</Button>
|
</Button>
|
||||||
]}
|
]}
|
||||||
>
|
>
|
||||||
You need to be logged in to access FarmControl. Please log in with
|
<Text>
|
||||||
tombutcher.work to continue.
|
You need to be logged in to access FarmControl. Please log in with
|
||||||
|
tombutcher.work to continue.
|
||||||
|
</Text>
|
||||||
</Modal>
|
</Modal>
|
||||||
<Modal
|
<Modal
|
||||||
open={loading}
|
open={loading}
|
||||||
@ -434,11 +440,35 @@ const AuthProvider = ({ children }) => {
|
|||||||
>
|
>
|
||||||
<Space size={'middle'}>
|
<Space size={'middle'}>
|
||||||
<LoadingOutlined />
|
<LoadingOutlined />
|
||||||
<Title level={5} style={{ margin: 0 }}>
|
<Text style={{ margin: 0 }}>Loading, please wait...</Text>
|
||||||
Loading, please wait...
|
|
||||||
</Title>
|
|
||||||
</Space>
|
</Space>
|
||||||
</Modal>
|
</Modal>
|
||||||
|
<Modal
|
||||||
|
title={
|
||||||
|
<Space size={'middle'}>
|
||||||
|
<ExclamationOctogonIcon />
|
||||||
|
Authentication Error
|
||||||
|
</Space>
|
||||||
|
}
|
||||||
|
open={showAuthErrorModal && !loading}
|
||||||
|
style={{ maxWidth: 430 }}
|
||||||
|
closable={false}
|
||||||
|
centered
|
||||||
|
maskClosable={false}
|
||||||
|
footer={[
|
||||||
|
<Button
|
||||||
|
key='submit'
|
||||||
|
onClick={() => {
|
||||||
|
showAuthErrorModal(false)
|
||||||
|
loginWithSSO()
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Retry Login
|
||||||
|
</Button>
|
||||||
|
]}
|
||||||
|
>
|
||||||
|
<Text>{authError}</Text>
|
||||||
|
</Modal>
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
13
yarn.lock
13
yarn.lock
@ -1295,6 +1295,11 @@
|
|||||||
resolved "https://registry.yarnpkg.com/@emotion/weak-memoize/-/weak-memoize-0.4.0.tgz#5e13fac887f08c44f76b0ccaf3370eb00fec9bb6"
|
resolved "https://registry.yarnpkg.com/@emotion/weak-memoize/-/weak-memoize-0.4.0.tgz#5e13fac887f08c44f76b0ccaf3370eb00fec9bb6"
|
||||||
integrity sha512-snKqtPW01tN0ui7yu9rGv69aJXr/a/Ywvl11sUjNtEcRc+ng/mQriFL0wLXMef74iHa/EkftbDzU9F8iFbH+zg==
|
integrity sha512-snKqtPW01tN0ui7yu9rGv69aJXr/a/Ywvl11sUjNtEcRc+ng/mQriFL0wLXMef74iHa/EkftbDzU9F8iFbH+zg==
|
||||||
|
|
||||||
|
"@epic-web/invariant@^1.0.0":
|
||||||
|
version "1.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/@epic-web/invariant/-/invariant-1.0.0.tgz#1073e5dee6dd540410784990eb73e4acd25c9813"
|
||||||
|
integrity sha512-lrTPqgvfFQtR/eY/qkIzp98OGdNJu0m5ji3q/nJI8v3SXkRKEnWiOxMmbvcSoAIzv/cGiuvRy57k4suKQSAdwA==
|
||||||
|
|
||||||
"@esbuild/aix-ppc64@0.25.9":
|
"@esbuild/aix-ppc64@0.25.9":
|
||||||
version "0.25.9"
|
version "0.25.9"
|
||||||
resolved "https://registry.yarnpkg.com/@esbuild/aix-ppc64/-/aix-ppc64-0.25.9.tgz#bef96351f16520055c947aba28802eede3c9e9a9"
|
resolved "https://registry.yarnpkg.com/@esbuild/aix-ppc64/-/aix-ppc64-0.25.9.tgz#bef96351f16520055c947aba28802eede3c9e9a9"
|
||||||
@ -4030,6 +4035,14 @@ crelt@^1.0.5, crelt@^1.0.6:
|
|||||||
resolved "https://registry.yarnpkg.com/crelt/-/crelt-1.0.6.tgz#7cc898ea74e190fb6ef9dae57f8f81cf7302df72"
|
resolved "https://registry.yarnpkg.com/crelt/-/crelt-1.0.6.tgz#7cc898ea74e190fb6ef9dae57f8f81cf7302df72"
|
||||||
integrity sha512-VQ2MBenTq1fWZUH9DJNGti7kKv6EeAuYr3cLwxUWhIu1baTaXh4Ib5W2CqHVqib4/MqbYGJqiL3Zb8GJZr3l4g==
|
integrity sha512-VQ2MBenTq1fWZUH9DJNGti7kKv6EeAuYr3cLwxUWhIu1baTaXh4Ib5W2CqHVqib4/MqbYGJqiL3Zb8GJZr3l4g==
|
||||||
|
|
||||||
|
cross-env@^10.0.0:
|
||||||
|
version "10.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/cross-env/-/cross-env-10.0.0.tgz#ba25823cfa1ed6af293dcded8796fa16cd162456"
|
||||||
|
integrity sha512-aU8qlEK/nHYtVuN4p7UQgAwVljzMg8hB4YK5ThRqD2l/ziSnryncPNn7bMLt5cFYsKVKBh8HqLqyCoTupEUu7Q==
|
||||||
|
dependencies:
|
||||||
|
"@epic-web/invariant" "^1.0.0"
|
||||||
|
cross-spawn "^7.0.6"
|
||||||
|
|
||||||
cross-spawn-windows-exe@^1.1.0, cross-spawn-windows-exe@^1.2.0:
|
cross-spawn-windows-exe@^1.1.0, cross-spawn-windows-exe@^1.2.0:
|
||||||
version "1.2.0"
|
version "1.2.0"
|
||||||
resolved "https://registry.yarnpkg.com/cross-spawn-windows-exe/-/cross-spawn-windows-exe-1.2.0.tgz#46253b0f497676e766faf4a7061004618b5ac5ec"
|
resolved "https://registry.yarnpkg.com/cross-spawn-windows-exe/-/cross-spawn-windows-exe-1.2.0.tgz#46253b0f497676e766faf4a7061004618b5ac5ec"
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user