-
Notifications
You must be signed in to change notification settings - Fork 6
ZEN - Multiple bugfixes #231
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: v2.x/staging
Are you sure you want to change the base?
Changes from all commits
9a644e0
0bb238d
ccf7108
d97b60f
3d1f1e4
21692a6
c1d74f4
22c41f7
a9897f7
15e7661
d57f685
3b2eb91
b9da937
0322389
14421c0
756dd98
4727edb
92ef950
d20c309
5a41955
761551b
028520b
1334659
43299da
f4176a2
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
export const ROUTES = { | ||
HOME: '/', | ||
WIZARD: '/wizard', | ||
}; | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
/* | ||
* This program and the accompanying materials are made available under the terms of the | ||
* Eclipse Public License v2.0 which accompanies this distribution, and is available at | ||
* https://www.eclipse.org/legal/epl-v20.html | ||
* | ||
* SPDX-License-Identifier: EPL-2.0 | ||
* | ||
* Copyright Contributors to the Zowe Project. | ||
*/ | ||
import { Box, Button, Dialog, DialogActions, DialogContent, DialogTitle, FormControl, TextField } from '@mui/material'; | ||
import { useState } from 'react'; | ||
|
||
const WarningDialog = ({onWarningDialogSubmit}: {onWarningDialogSubmit: any}) => { | ||
|
||
const [isDialogVisible, setIsDialogVisible] = useState(true); | ||
|
||
const handleClose = () => { | ||
setIsDialogVisible(false); | ||
onWarningDialogSubmit(false); | ||
} | ||
|
||
const handleSubmit = () => { | ||
setIsDialogVisible(false); | ||
onWarningDialogSubmit(true); | ||
} | ||
|
||
return ( | ||
<div> | ||
<Dialog open={isDialogVisible} maxWidth={'xs'}> | ||
<DialogTitle>Warning!</DialogTitle> | ||
<DialogContent style={{ fontSize: '13px', fontFamily: 'Arial, sans-serif', color: 'black' }}> Starting a new installation will erase the previously stored installation data from the wizard. Do you wish to proceed? </DialogContent> | ||
<DialogActions> | ||
<div> | ||
<Button onClick={handleSubmit}>Proceed</Button> | ||
<Button onClick={handleClose}>Close</Button> | ||
</div> | ||
</DialogActions> | ||
</Dialog> | ||
</div> | ||
) | ||
} | ||
|
||
export default WarningDialog; |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -10,7 +10,7 @@ | |
|
||
import '../global.css'; | ||
import { useEffect, useState } from "react"; | ||
import { Link } from 'react-router-dom'; | ||
import { Link, useNavigate } from 'react-router-dom'; | ||
import { Box, Card, CardContent, CardMedia, Typography, Button } from '@mui/material'; | ||
import flatten, { unflatten } from 'flat'; | ||
import { IResponse, IIpcConnectionArgs } from '../../types/interfaces'; | ||
|
@@ -22,25 +22,22 @@ import { Tooltip } from '@mui/material'; | |
import installationImg from '../assets/installation.png' | ||
import installationDryImg from '../assets/installation-dry-run.png' | ||
import eventDispatcher from "../../services/eventDispatcher"; | ||
import { selectConnectionStatus} from './stages/progress/progressSlice'; | ||
import { selectConnectionStatus, setConnectionStatus} from './stages/progress/progressSlice'; | ||
import HorizontalLinearStepper from './common/Stepper'; | ||
import Wizard from './configuration-wizard/Wizard' | ||
import { ActiveState } from '../../types/stateInterfaces'; | ||
import { ActiveState, InstallationArgs } from '../../types/stateInterfaces'; | ||
import { getInstallationArguments, getPreviousInstallation } from './stages/progress/StageProgressStatus'; | ||
import { DEF_NO_OUTPUT, FALLBACK_SCHEMA, FALLBACK_YAML } from './common/Utils'; | ||
import { selectInstallationArgs, setInstallationArgs, installationSlice } from './stages/installation/installationSlice'; | ||
import { selectInstallationArgs, setInstallationArgs, installationSlice, setIsNewInstallation, selectIsNewInstallation } from './stages/installation/installationSlice'; | ||
import PasswordDialog from './common/passwordDialog'; | ||
import WarningDialog from './Dialogs/WarningDialog'; | ||
import HomeCardComponent from './HomeCardComponent'; | ||
import { ICard } from '../../types/interfaces'; | ||
import { ROUTES } from '../../Routes/RouteConstant'; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Similar with Routes, you have moved it out to a separate file structure Routes/RouteConstant.tsx which looks like an overkill to me, especially when there are just two links and routing is not actually needed, it is just a legacy leftover that should be cleaned up later. And definitely we do not need Routes outside of renderer. |
||
|
||
// REVIEW: Get rid of routing | ||
|
||
interface ICard { | ||
id: string, | ||
name: string, | ||
description: string, | ||
link: string, | ||
media: any, | ||
} | ||
|
||
// Cards Data | ||
const cards: Array<ICard> = [ | ||
{ | ||
id: "install", | ||
|
@@ -58,79 +55,39 @@ const cards: Array<ICard> = [ | |
} | ||
] | ||
|
||
// Constants | ||
const prevInstallationKey = "prev_installation"; | ||
const lastActiveState: ActiveState = { | ||
activeStepIndex: 0, | ||
isSubStep: false, | ||
activeSubStepIndex: 0, | ||
}; | ||
const defaultTooltip: string = "Resume"; | ||
|
||
// Helper Functions | ||
const getNewInstallationArgs = (id: string, currentArgs: InstallationArgs) => { | ||
return id === "install" | ||
? { ...currentArgs, dryRunMode: false } | ||
: { ...currentArgs, dryRunMode: true }; | ||
}; | ||
|
||
const Home = () => { | ||
|
||
const dispatch = useAppDispatch(); | ||
const navigate = useNavigate(); | ||
const connectionStatus = useAppSelector(selectConnectionStatus); | ||
const [showWizard, setShowWizard] = useState(false); | ||
const [showLoginDialog, setShowLogin] = useState(false); | ||
const [localYaml, setLocalYaml] = useState(useAppSelector(selectYaml)); | ||
const [schema, setLocalSchema] = useState(useAppSelector(selectSchema)); | ||
const installationArgs = useAppSelector(selectInstallationArgs); | ||
|
||
const { activeStepIndex, isSubStep, activeSubStepIndex, lastActiveDate } = getPreviousInstallation(); | ||
|
||
const [isNewInstallation, setIsNewInstallation] = useState(false); | ||
|
||
const schema = useAppSelector(selectSchema); | ||
const stages: any = []; | ||
const defaultTooltip: string = "Resume"; | ||
const resumeTooltip = connectionStatus ? defaultTooltip : `Validate Credentials & ${defaultTooltip}`; | ||
const isNewInstallation = useAppSelector(selectIsNewInstallation); | ||
const { lastActiveDate } = getPreviousInstallation(); | ||
|
||
const [showWizard, setShowWizard] = useState(false); | ||
const [localYaml, setLocalYaml] = useState(useAppSelector(selectYaml)); | ||
const [showPasswordDialog, setShowPasswordDialog] = useState(false); | ||
const [updatedConnection, setUpdatedConnection] = useState(false); | ||
const [isResume, setIsResume] = useState(useAppSelector(selectResumeProgress)); | ||
|
||
const makeCard = (card: ICard) => { | ||
const {id, name, description, link, media} = card; | ||
|
||
const handleClick = () => { | ||
let newInstallationArgs = installationSlice.getInitialState().installationArgs; | ||
if (id === "install") { | ||
newInstallationArgs = {...newInstallationArgs, dryRunMode: false}; | ||
} else if (id === "dry run") { | ||
newInstallationArgs = {...newInstallationArgs, dryRunMode: true}; | ||
} | ||
dispatch(setYaml(FALLBACK_YAML)); | ||
dispatch(setInstallationArgs(newInstallationArgs)); | ||
window.electron.ipcRenderer.setConfigByKeyNoValidate("installationArgs", newInstallationArgs); | ||
setLocalYaml(FALLBACK_YAML); | ||
window.electron.ipcRenderer.setConfig(FALLBACK_YAML); | ||
// TODO: Ideally, reset connectionArgs too | ||
// but this introduces bug with "self certificate chain" it's the checkbox, it looks checked but | ||
// it acts like it's not unless you touch it | ||
// dispatch(setConnectionArgs(connectionSlice.getInitialState().connectionArgs)); | ||
setIsResume(false); | ||
}; | ||
|
||
return ( | ||
<Link key={`link-${id}`} to={link} > | ||
<Box sx={{ width: '40vw', height: '40vh'}} onClick={handleClick}> | ||
<Card id={`card-${id}`} square={true}> | ||
<CardMedia | ||
sx={{ height: 240 }} | ||
image={media} | ||
/> | ||
<CardContent className="action-card"> | ||
<Box> | ||
<Typography variant="subtitle1" component="div"> | ||
{name} | ||
</Typography> | ||
<Typography sx={{ mb: 1.5, mt: 1.5, fontSize: '0.875rem' }} color="text.secondary"> | ||
{description} | ||
</Typography> | ||
</Box> | ||
</CardContent> | ||
</Card> | ||
</Box> | ||
</Link> | ||
) | ||
} | ||
const [newInstallationClicked, setNewInstallationClick] = useState(false); | ||
const [previousInstallation, setPreviousInstallation] = useState(false); | ||
const [defaultYaml, setDefaultYaml] = useState(FALLBACK_YAML); | ||
|
||
useEffect(() => { | ||
eventDispatcher.on('saveAndCloseEvent', () => setShowWizard(false)); | ||
|
@@ -142,8 +99,9 @@ const Home = () => { | |
window.electron.ipcRenderer.getConfig().then((res: IResponse) => { | ||
if (res.status) { | ||
dispatch(setYaml(res.details)); | ||
setDefaultYaml(res.details); | ||
} else { | ||
dispatch(setYaml(FALLBACK_YAML)); | ||
dispatch(setYaml(defaultYaml)); | ||
} | ||
}) | ||
} | ||
|
@@ -176,14 +134,10 @@ const Home = () => { | |
} | ||
}); | ||
|
||
window.electron.ipcRenderer.setStandardOutput(DEF_NO_OUTPUT).then((res: any) => { | ||
}) | ||
|
||
window.electron.ipcRenderer.findPreviousInstallations().then((res: IResponse) => { | ||
const connectionStore = res.details; | ||
if (connectionStore["connection-type"] === 'ftp') { | ||
const jobStatement = connectionStore['ftp-details'].jobStatement.trim() || useAppSelector(selectInitJobStatement); | ||
// console.log(JSON.stringify(connectionStore['ftp-details'],null,2)); | ||
const connectionArgs: IIpcConnectionArgs = { | ||
...connectionStore["ftp-details"], | ||
password: "", | ||
|
@@ -200,13 +154,14 @@ const Home = () => { | |
if (!lastInstallation) { | ||
const flattenedData = flatten(lastActiveState); | ||
localStorage.setItem(prevInstallationKey, JSON.stringify(flattenedData)); | ||
setIsNewInstallation(true); | ||
dispatch(setIsNewInstallation(true)); | ||
setPreviousInstallation(false); | ||
} else { | ||
const data: ActiveState = unflatten(JSON.parse(lastInstallation)); | ||
setIsNewInstallation(!(data && data.lastActiveDate)); | ||
dispatch(setIsNewInstallation(!(data && data.lastActiveDate))); | ||
setPreviousInstallation(!!(data && data.lastActiveDate)); | ||
} | ||
|
||
|
||
}); | ||
return () => { | ||
eventDispatcher.off('saveAndCloseEvent', () => setShowWizard(true)); | ||
|
@@ -216,33 +171,93 @@ const Home = () => { | |
const resumeProgress = () => { | ||
setShowWizard(true); | ||
dispatch(setResumeProgress(true)); | ||
|
||
dispatch(setIsNewInstallation(false)); | ||
|
||
if(connectionStatus) { | ||
setShowPasswordDialog(true); | ||
setUpdatedConnection(false); | ||
} | ||
} | ||
|
||
const confirmConnection = (status: boolean) => { | ||
setUpdatedConnection(status); | ||
setShowPasswordDialog(!status); | ||
setShowWizard(status); | ||
} | ||
|
||
const handleNewInstallation = (newInstallationArgs: InstallationArgs) => { | ||
dispatch(setYaml(defaultYaml)); | ||
dispatch(setInstallationArgs(newInstallationArgs)); | ||
|
||
window.electron.ipcRenderer.setConfigByKeyNoValidate("installationArgs", newInstallationArgs); | ||
window.electron.ipcRenderer.setConfig(defaultYaml); | ||
|
||
setLocalYaml(defaultYaml); | ||
|
||
// TODO: Ideally, reset connectionArgs too | ||
// but this introduces bug with "self certificate chain" it's the checkbox, it looks checked but | ||
// it acts like it's not unless you touch it | ||
// dispatch(setConnectionArgs(connectionSlice.getInitialState().connectionArgs)); | ||
} | ||
|
||
const handleCardClick = (id: string) => { | ||
|
||
const initialInstallationArgs = installationSlice.getInitialState().installationArgs; | ||
const newInstallationArgs = getNewInstallationArgs(id, initialInstallationArgs); | ||
|
||
if (id === "install") { | ||
setNewInstallationClick(true); | ||
if(previousInstallation) { | ||
return; | ||
} | ||
dispatch(setIsNewInstallation(true)); | ||
dispatch(setConnectionStatus(false)); | ||
dispatch(setResumeProgress(false)); | ||
} | ||
handleNewInstallation(newInstallationArgs); | ||
}; | ||
|
||
const confirmNewInstallation = (status: boolean) => { | ||
dispatch(setIsNewInstallation(status)) | ||
setNewInstallationClick(false); | ||
setPreviousInstallation(!status); | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Well, it does not clear previous information for me, it starts with a connection screen again, but all the data still there. I was going to recommend you to just drop the stores here, like every store has the deleteAll() function for that purpose, but when i tried that i realize it also has no effect until you close the app. |
||
if(status) { | ||
dispatch(setConnectionStatus(false)); | ||
dispatch(setResumeProgress(false)); | ||
handleNewInstallation({ ...installationSlice.getInitialState().installationArgs, dryRunMode: false }); | ||
navigate(ROUTES.WIZARD); | ||
} | ||
} | ||
|
||
return ( | ||
<> | ||
{ previousInstallation && newInstallationClicked && | ||
<WarningDialog onWarningDialogSubmit={confirmNewInstallation}/> | ||
} | ||
|
||
{!showWizard && <div className="home-container" style={{ display: 'flex', flexDirection: 'column' }}> | ||
|
||
<div style={{ position: 'absolute', left: '-9999px' }}> | ||
<HorizontalLinearStepper stages={stages} /> | ||
{stages.length > 0 && <HorizontalLinearStepper stages={stages} />} | ||
</div> | ||
|
||
{!connectionStatus && <div style={{marginBottom: '20px'}}></div>} | ||
|
||
<div style={{ display: 'flex', flexDirection: 'row', alignItems: 'center', marginLeft: '8%' }}> | ||
{cards.map(card => makeCard(card))} | ||
{cards.map(card => ( | ||
<HomeCardComponent | ||
key={card.id} | ||
id={card.id} | ||
name={card.name} | ||
description={card.description} | ||
link={card.link} | ||
media={card.media} | ||
handleCardClick={handleCardClick} | ||
previousInstallation={previousInstallation} | ||
/> | ||
))} | ||
</div> | ||
|
||
{!isNewInstallation && <div style={{marginBottom: '1px',marginTop: '120px',background: 'white', fontSize: 'small',marginLeft: 'calc(8% + 10px)', padding: '15px 0 15px 15px',width: 'calc(80% + 5px)', boxShadow: '1px 1px 3px #a6a6a6'}}> | ||
{previousInstallation && <div style={{marginBottom: '1px',marginTop: '120px',background: 'white', fontSize: 'small',marginLeft: 'calc(8% + 10px)', padding: '15px 0 15px 15px',width: 'calc(80% + 5px)', boxShadow: '1px 1px 3px #a6a6a6'}}> | ||
<Box sx={{display: 'flex', flexDirection: 'column'}}> | ||
|
||
<div style={{paddingBottom: '10px', color: 'black'}}> | ||
|
@@ -268,8 +283,7 @@ const Home = () => { | |
{showWizard && | ||
<> | ||
{showPasswordDialog && <PasswordDialog onPasswordSubmit={confirmConnection}></PasswordDialog>} | ||
{(showPasswordDialog && updatedConnection) && <Wizard initialization={false}/>} | ||
{!showPasswordDialog && <Wizard initialization={false}/>} | ||
{!showPasswordDialog && <Wizard initialization={isNewInstallation}/>} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. These two lines look like over-complication, what is the use of updatedConnection? Why we can't use showPasswordDialog only? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The following behavior is intentional:
This behavior originates from staging. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Great catch @skurnevich regarding the Thanks. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Additionally, I have removed unused states and variables in the Home component that originated from staging. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ok thank you, sorry for me asking on things that are not part of this PR, but even if it is already in staging we still need to fix things that are not in a good shape. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sure @skurnevich Thank you for the detailed review on my PRs. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We previously discussed these two different approaches for the resume. However, we can revisit and refine them further. |
||
</> | ||
} | ||
</> | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
import { Box, Card, CardContent, CardMedia, Typography, Tooltip, Button } from '@mui/material'; | ||
import { Link } from 'react-router-dom'; | ||
|
||
const HomeCardComponent = ({ id, name, description, link, media, previousInstallation, handleCardClick }:{id: string, name: string, description: string, link: string, media: any, previousInstallation: boolean, handleCardClick: any}) => { | ||
|
||
return ( | ||
<Link key={`link-${id}`} to={previousInstallation ? "/" : link}> | ||
<Box sx={{ width: '40vw', height: '40vh' }} onClick={() => handleCardClick(id)}> | ||
<Card id={`card-${id}`} square={true}> | ||
<CardMedia sx={{ height: 240 }} image={media} /> | ||
<CardContent className="action-card"> | ||
<Box> | ||
<Typography variant="subtitle1" component="div"> | ||
{name} | ||
</Typography> | ||
<Typography sx={{ mb: 1.5, mt: 1.5, fontSize: '0.875rem' }} color="text.secondary"> | ||
{description} | ||
</Typography> | ||
</Box> | ||
</CardContent> | ||
</Card> | ||
</Box> | ||
</Link> | ||
); | ||
}; | ||
|
||
export default HomeCardComponent; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This seems to be quite hardcoded again.
First it is better to have the WarningDialog.tsx in "common", no need to have separate structure for that.
Second we should have it as simple as possible, taking 3 properties "text", "onSubmit", "onCancel" and no logic inside, even visibility should be controlled in the parent component. In that case it could be reused in future in any other place. We actually can go even further and add 4th property to control dialog type, like error/warning/info etc.