Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions main/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import DevonInstancesService from './services/devon-instances/devon-instances.se
import { DevonfwConfig, IdeDistribution } from './models/devonfw-dists.model';
import { ProfileSetupService } from './services/profile-setup/profile-setup.service';
import { readdirPromise } from './modules/shared/utils/promised';
import { createDirectory } from './modules/shared/utils/create-directory';
import { InstallListener } from './modules/projects/classes/listeners/install-listener';
import { ProjectCreationListener } from './modules/projects/classes/listeners/project-creation-listener';
import {
Expand Down Expand Up @@ -154,6 +155,17 @@ async function getDirsFromPath(path: string) {
}
}

async function createWorkspace(path: string) {
try {
const created = await createDirectory(path);
mainWindow.webContents.send('wsCreation:', created);
return created;
} catch (e) {
mainWindow.webContents.send('wsCreation:', '');
return '';
}
}

/* Enable services */

new OpenIdeListener().listen();
Expand Down Expand Up @@ -209,3 +221,4 @@ ipcMain.on('set:profile', (e, profile: UserProfile) =>
ipcMain.on('find:profileStatus', () => checkProfileStatus(mainWindow));
ipcMain.handle('find:profile', () => new ProfileSetupService().getProfile());
ipcMain.handle('get:dirsFromPath', (e, path) => getDirsFromPath(path));
ipcMain.handle('create:workspace', (e, path) => createWorkspace(path));
16 changes: 16 additions & 0 deletions main/modules/shared/utils/create-directory.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import * as fs from 'fs';

export function createDirectory(path: string): Promise<string> {
const dirReader: Promise<string> = new Promise((resolve, reject) => {
fs.mkdir(path, (err: Error) => {
if (err) {
console.log(err);
reject(err);
} else {
resolve('success');
}
});
});

return dirReader;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import {
DialogTitle,
DialogContent,
DialogActions,
} from '../../../../shared/components/dialog';
import Dialog from '@material-ui/core/Dialog';
import { FormControl, Button, TextField } from '@material-ui/core';
import { ChangeEvent } from 'react';

interface ConfirmDialogProps {
newWorkspaceName: WorkspaceName;
onNameChange: (value: ChangeEvent) => void;
openDialog: boolean;
onClose: (value: boolean) => void;
}

interface WorkspaceName {
value: string;
valid?: boolean;
error?: string;
touched?: boolean;
}

export default function CreateWorkspaceDialog(
props: ConfirmDialogProps
): JSX.Element {
return (
<Dialog
disableBackdropClick
disableEscapeKeyDown
maxWidth="xs"
fullWidth={true}
open={props.openDialog}
>
<DialogTitle id="confirmation-dialog-title">
Add New Workspace
</DialogTitle>
<DialogContent dividers>
<form noValidate autoComplete="off">
<FormControl>
<TextField
id="workspace-name"
value={props.newWorkspaceName.value}
label="Workspace name"
type="search"
variant="outlined"
onChange={props.onNameChange}
/>
</FormControl>
{props.newWorkspaceName.error && props.newWorkspaceName.touched ? (
<div style={{ color: '#E01600' }}>
{props.newWorkspaceName.error}
</div>
) : null}
</form>
</DialogContent>
<DialogActions>
<Button
color="secondary"
variant="outlined"
onClick={() => props.onClose(false)}
>
Cancel
</Button>
<Button
color="secondary"
variant="outlined"
autoFocus
disabled={!props.newWorkspaceName.valid}
onClick={() => props.onClose(true)}
>
Ok
</Button>
</DialogActions>
</Dialog>
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,10 @@ import NextLink from '../../../../shared/components/nextjs-link/NextLink';
import ProjectDetail from './project-detail';
import Alerts from '../../../../shared/components/alerts/alerts';
import ConfirmDialog from '../../../../shared/components/confirm-dialog/confirm.dialog';
import CreateWorkspaceDialog from '../create-workspace-dialog/create-workspace-dialog';
import MenuList from '../menu-list/menu-list';
import NewProject from '../new-project/new-project';
import { join } from 'path';

interface DashboardProjectsProps {
projects: ProjectDetails[];
Expand All @@ -37,6 +39,13 @@ interface DashboardProjectsProps {
workspaces: string[];
}

interface WorkspaceName {
value: string;
valid?: boolean;
error?: string;
touched?: boolean;
}

export default function DashboardProjects(
props: DashboardProjectsProps
): JSX.Element {
Expand Down Expand Up @@ -66,6 +75,21 @@ export default function DashboardProjects(
HTMLInputElement
>;
const [openDialog, setOpenDialog] = useState<boolean>(false);
const [openCreateWorkspaceDialog, setOpenCreateWorkspaceDialog] = useState<
boolean
>(false);
const [newWorkspaceName, setNewWorkspaceName] = useState<WorkspaceName>({
value: '',
valid: false,
error: '',
touched: false,
});
const [workspacesInIDE, setWorkspacesInIDE] = useState<string[]>([]);
const ERRORMSG = {
workspaceNameExists: 'A workspace with this name already exists',
workspaceNameRequired: 'Please provide a name for the workspace',
pattern: 'Please enter a valid name',
};

const deleteConfimation = (value: boolean): void => {
if (value === true) {
Expand All @@ -90,8 +114,12 @@ export default function DashboardProjects(
useEffect(() => {
renderer.on('open:projectInIde', ideHandler);
renderer.on('delete:project', deleteHandler);
global.ipcRenderer
.invoke('get:dirsFromPath', join(props.dirPath, 'workspaces'))
.then((dirs: string[]) => setWorkspacesInIDE(dirs));
return () => {
renderer.removeAll();
global.ipcRenderer.removeAllListeners('get:dirsFromPath');
};
}, []);

Expand Down Expand Up @@ -186,6 +214,80 @@ export default function DashboardProjects(
};
};

const openWorkspaceDialog = () => {
setOpenCreateWorkspaceDialog(true);
};

const closeWorkspaceDialog = (value: boolean): void => {
if (value === true) {
global.ipcRenderer
.invoke(
'create:workspace',
join(props.dirPath, 'workspaces', newWorkspaceName.value)
)
.then((status: string) => console.log(status));
}
setOpenCreateWorkspaceDialog(false);
updateWsNameInDialog({
value: '',
valid: false,
error: '',
touched: false,
});
};

const handleWorkspaceNameChange = (event: ChangeEvent<HTMLInputElement>) => {
validateNewWorkspaceName(event.target.value);
};

const validateNewWorkspaceName = (name: string) => {
const wsName = name;
if (
workspacesInIDE.filter((ws) => ws.toLowerCase() === wsName.toLowerCase())
.length
) {
updateWsNameInDialog({
value: wsName,
error: ERRORMSG.workspaceNameExists,
valid: false,
});
} else if (wsName.match(/^[a-z](\-*[a-z]\d*)*$/gi) == null) {
updateWsNameInDialog({
value: wsName,
error: ERRORMSG.pattern,
valid: false,
});
} else {
updateWsNameInDialog({
value: wsName,
error: '',
valid: true,
});
}

if (!wsName) {
updateWsNameInDialog({
value: wsName,
error: ERRORMSG.workspaceNameRequired,
valid: false,
});
}
};

const updateWsNameInDialog = (formData: WorkspaceName) => {
const updatedData = newWorkspaceName;
updatedData.value = formData.value;
updatedData.error = formData.error;
updatedData.valid = formData.valid;
updatedData.touched = true;
setNewWorkspaceName((prevState: WorkspaceName) => {
return {
...prevState,
updatedData,
};
});
};

return (
<div className={classes.root}>
<DashboardSearch
Expand All @@ -201,8 +303,12 @@ export default function DashboardProjects(
!props.dirPath ? classes.disabled : ''
}`}
>
<NewProject />
<NewProject buttonText="Add New Project" />
</NextLink>
<NewProject
buttonText="Add New Workspace"
buttonAction={openWorkspaceDialog}
/>
</div>
{props.workspaces &&
props.workspaces.length &&
Expand Down Expand Up @@ -287,6 +393,12 @@ export default function DashboardProjects(
openDialog={openDialog}
onClose={deleteConfimation}
></ConfirmDialog>
<CreateWorkspaceDialog
newWorkspaceName={newWorkspaceName}
onNameChange={handleWorkspaceNameChange}
openDialog={openCreateWorkspaceDialog}
onClose={closeWorkspaceDialog}
></CreateWorkspaceDialog>
</div>
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,20 +5,25 @@ import Typography from '@material-ui/core/Typography';
import useNewProjectStyles from './new-project.styles';
import Box from '@material-ui/core/Box';

export default function NewProject(): JSX.Element {
interface NewProjectProps {
buttonText: string;
buttonAction?: () => void;
}

export default function NewProject(props: NewProjectProps): JSX.Element {
const classes = useNewProjectStyles();

return (
<Card>
<Card onClick={props.buttonAction}>
<CardMedia
className={classes.cardMedia}
image="/static/assets/add_new_project.png"
title="Add new Project"
title={props.buttonText}
/>
<CardContent className={classes.cardContent}>
<Typography component="span">
<Box fontWeight="fontWeightBold" fontSize={14}>
Add New Project
{props.buttonText}
</Box>
</Typography>
</CardContent>
Expand Down
13 changes: 9 additions & 4 deletions renderer/pages/projects/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ export default function Projects(): JSX.Element {
);
const [workspaceDir, setWorkspaceDir] = useState<string[]>([]);
const { state, dispatch } = useContext(StepperContext);
const workspaceService = new WorkspaceService(setWorkspaceDir);

useEffect(() => {
if (state.creatingProject) {
Expand All @@ -38,8 +39,8 @@ export default function Projects(): JSX.Element {
}

global.ipcRenderer.on('ide:projects', ideProjectsHandler);
const workspaceService = new WorkspaceService(setWorkspaceDir);
workspaceService.getProjectsInWorkspace(state.projectData.path);
global.ipcRenderer.on('wsCreation:', getUpdatedWorkspaces);
getUpdatedWorkspaces();
return () => {
global.ipcRenderer.removeAllListeners('ide:projects');
workspaceService.closeListener();
Expand All @@ -49,11 +50,15 @@ export default function Projects(): JSX.Element {
useEffect(() => {
if (state.projectData.path) {
global.ipcRenderer.send('ide:projects', state.projectData.path);
const workspaceService = new WorkspaceService(setWorkspaceDir);
workspaceService.getProjectsInWorkspace(state.projectData.path);
getUpdatedWorkspaces();
}
}, [state]);

const getUpdatedWorkspaces = () => {
// const workspaceService = new WorkspaceService(setWorkspaceDir);
workspaceService.getProjectsInWorkspace(state.projectData.path);
};

const ideProjectsHandler = (
_: unknown,
data: { projects: ProjectDetails[] }
Expand Down