Skip to content

Commit

Permalink
Merge branch 'main' into feature/git-integration
Browse files Browse the repository at this point in the history
  • Loading branch information
rahulyadav-57 committed Oct 4, 2024
2 parents 111a6e4 + 20c2152 commit cb6bb23
Show file tree
Hide file tree
Showing 19 changed files with 380 additions and 56 deletions.
25 changes: 25 additions & 0 deletions src/components/project/CloneProject/CloneProject.module.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
.root {
color: var(--color-warning);
display: flex;
align-items: center;
cursor: pointer;
animation: blinker 500ms infinite alternate;

.saveIcon {
width: 1.2rem;
height: 1.2rem;
}
}

.form {
margin-top: 2rem;
}

@keyframes blinker {
from {
opacity: 70%;
}
to {
opacity: 100%;
}
}
111 changes: 111 additions & 0 deletions src/components/project/CloneProject/CloneProject.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
import AppIcon from '@/components/ui/icon';
import { baseProjectPath, useProject } from '@/hooks/projectV2.hooks';
import fileSystem from '@/lib/fs';
import { Button, Form, Input, message, Modal, Tooltip } from 'antd';
import cloneDeep from 'lodash.clonedeep';
import { FC, useState } from 'react';
import s from './CloneProject.module.scss';

const CloneProject: FC = () => {
const [isSaveModalOpen, setIsSaveModalOpen] = useState(false);
const [isSaving, setIsSaving] = useState(false);
const { activeProject, projectFiles, createProject } = useProject();

const storeAsNewProject = async ({ name }: { name: string }) => {
try {
setIsSaving(true);

const files = cloneDeep(projectFiles);
const finalFiles = [];
for (const file of files) {
if (file.path.includes('.ide')) {
continue;
}
if (file.type === 'file') {
file.content = (await fileSystem.readFile(file.path)) as string;
}
file.path = file.path.replace(`${activeProject?.path as string}/`, '');
finalFiles.push(file);
}
if (finalFiles.length === 0) {
message.error('No files to save');
return;
}

await createProject({
name: name,
language: activeProject?.language ?? 'tact',
template: 'import',
file: null,
defaultFiles: finalFiles,
});
setIsSaveModalOpen(false);
fileSystem.clearVirtualFiles();
} catch (error) {
if (error instanceof Error) {
message.error(error.message);
return;
}
message.error('Failed to save a project');
} finally {
setIsSaving(false);
}
};

if (!activeProject || activeProject.path !== `${baseProjectPath}/temp`) {
return null;
}

return (
<>
<Tooltip
title={`The current project is not saved permanently. Click here to save it.`}
>
<div
className={s.root}
onClick={() => {
setIsSaveModalOpen(true);
}}
>
<AppIcon className={s.saveIcon} name="Save" />
</div>
</Tooltip>
<Modal
className={s.modal}
open={isSaveModalOpen}
onCancel={() => {
setIsSaveModalOpen(false);
}}
footer={null}
>
<Form
className={`${s.form} app-form`}
layout="vertical"
onFinish={storeAsNewProject}
>
<Form.Item
name="name"
rules={[
{ required: true, message: 'Please enter the project name' },
]}
>
<Input placeholder="Project name" />
</Form.Item>

<Form.Item>
<Button
className={`${s.btnAction} w-100 ant-btn-primary-gradient item-center-align`}
loading={isSaving}
type="primary"
htmlType="submit"
>
<AppIcon name="Save" /> Save
</Button>
</Form.Item>
</Form>
</Modal>
</>
);
};

export default CloneProject;
1 change: 1 addition & 0 deletions src/components/project/CloneProject/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default } from './CloneProject';
16 changes: 8 additions & 8 deletions src/components/project/MigrateToUnifiedFS/MigrateToUnifiedFS.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -86,14 +86,14 @@ const MigrateToUnifiedFS: FC<Props> = ({ hasDescription = false }) => {
const project = projects[i];
const isLastProject = i === projects.length - 1;

await createProject(
project.projectDetails.name as string,
project.projectDetails.language as ContractLanguage,
'import',
null,
project.files as Tree[],
isLastProject,
);
await createProject({
name: project.projectDetails.name as string,
language: project.projectDetails.language as ContractLanguage,
template: 'import',
file: null,
defaultFiles: project.files as Tree[],
autoActivate: isLastProject,
});

migratedProjects.push(project.projectDetails.name);
}
Expand Down
75 changes: 66 additions & 9 deletions src/components/project/NewProject/NewProject.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
import { Tooltip } from '@/components/ui';
import AppIcon, { AppIconType } from '@/components/ui/icon';
import { useProject } from '@/hooks/projectV2.hooks';
import { useFileTab } from '@/hooks';
import { useLogActivity } from '@/hooks/logActivity.hooks';
import { baseProjectPath, useProject } from '@/hooks/projectV2.hooks';
import {
ContractLanguage,
ProjectTemplate,
Tree,
} from '@/interfaces/workspace.interface';
import { Analytics } from '@/utility/analytics';
import EventEmitter from '@/utility/eventEmitter';
import { decodeBase64 } from '@/utility/utils';
import { Button, Form, Input, Modal, Radio, Upload, message } from 'antd';
import { useForm } from 'antd/lib/form/Form';
import type { RcFile } from 'antd/lib/upload';
Expand Down Expand Up @@ -43,9 +46,21 @@ const NewProject: FC<Props> = ({
const [isActive, setIsActive] = useState(active);
const { createProject } = useProject();
const [isLoading, setIsLoading] = useState(false);
const { createLog } = useLogActivity();
const { open: openTab } = useFileTab();

const router = useRouter();
const { importURL, name: projectName, lang: importLanguage } = router.query;
const {
importURL,
name: projectName,
lang: importLanguage,
code: codeToImport,
} = router.query as {
importURL?: string;
name?: string;
lang?: ContractLanguage;
code?: string;
};

const [form] = useForm();

Expand Down Expand Up @@ -83,13 +98,13 @@ const NewProject: FC<Props> = ({
// files = await downloadRepo(githubUrl as string);
}

await createProject(
projectName,
await createProject({
name: projectName,
language,
values.template ?? 'import',
values.file?.file ?? null,
files,
);
template: values.template ?? 'import',
file: values.file?.file ?? null,
defaultFiles: files,
});

form.resetFields();
closeModal();
Expand All @@ -115,7 +130,49 @@ const NewProject: FC<Props> = ({
}
};

const importFromCode = async (code: string) => {
try {
const defaultFileName = `main.${importLanguage}`;
if (!importLanguage || !['tact', 'func'].includes(importLanguage)) {
createLog(`Invalid language: ${importLanguage}`, 'error');
return;
}
await createProject({
name: 'temp',
language: importLanguage,
template: 'import',
file: null,
defaultFiles: [
{
id: '',
parent: null,
path: defaultFileName,
type: 'file' as const,
name: defaultFileName,
content: decodeBase64(code),
},
],
isTemporary: true,
});
const finalQueryParam = router.query;
delete finalQueryParam.code;
delete finalQueryParam.lang;
router.replace({ query: finalQueryParam }).catch(() => {});
openTab(defaultFileName, `${baseProjectPath}/temp/${defaultFileName}`);
} catch (error) {
if (error instanceof Error) {
createLog(error.message, 'error');
return;
}
}
};

useEffect(() => {
if (codeToImport) {
importFromCode(codeToImport as string);
return;
}

if (!importURL || !active) {
return;
}
Expand All @@ -132,7 +189,7 @@ const NewProject: FC<Props> = ({
delete finalQueryParam.name;
router.replace({ query: finalQueryParam }).catch(() => {});
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [importURL, projectName, form]);
}, [importURL, projectName, form, codeToImport]);

const closeModal = () => {
setIsActive(false);
Expand Down
1 change: 1 addition & 0 deletions src/components/project/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export { default as CloneProject } from './CloneProject';
export { default as DownloadProject } from './DownloadProject';
export { default as MigrateToUnifiedFS } from './MigrateToUnifiedFS';
export { default as NewProject } from './NewProject';
7 changes: 7 additions & 0 deletions src/components/ui/icon/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,10 @@ import {
AiOutlinePlus,
AiOutlineProject,
AiOutlineReload,
AiOutlineSave,
} from 'react-icons/ai';
import { BsShare } from 'react-icons/bs';

import { BsFillPlayFill } from 'react-icons/bs';
import { FaRegClone } from 'react-icons/fa';
import { FiEdit2, FiEye } from 'react-icons/fi';
Expand Down Expand Up @@ -70,6 +73,8 @@ export type AppIconType =
| 'Download'
| 'Import'
| 'Reload'
| 'Share'
| 'Save'
| 'GitBranch';

export interface AppIconInterface {
Expand Down Expand Up @@ -111,6 +116,8 @@ const Components = {
Download: AiOutlineDownload,
Import,
Reload: AiOutlineReload,
Share: BsShare,
Save: AiOutlineSave,
GitBranch: AiOutlineBranches,
};

Expand Down
2 changes: 1 addition & 1 deletion src/components/workspace/BuildProject/BuildProject.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -309,7 +309,7 @@ const BuildProject: FC<Props> = ({ projectId, contract, updateContract }) => {

Analytics.track('Deploy project', {
platform: 'IDE',
type: 'TON-func',
type: `TON-${activeProject?.language}`,
environment: environment.toLowerCase(),
});
createLog(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,10 @@ const FuncContractInteraction: FC<ProjectInteractionProps> = ({
src="/html/tonweb.html"
sandbox="allow-scripts allow-same-origin"
/>
<p className="color-warn">
You are using code that has been imported from an external source.
Exercise caution with the contract code before executing it.
</p>
<p>
Below options will be used to send internal message and call getter
method on contract after the contract is deployed.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@ const TactContractInteraction: FC<ProjectInteractionProps> = ({

return (
<div className={s.root}>
<p className="color-warn">
You are using code that has been imported from an external source.
Exercise caution with the contract code before executing it.
</p>
<p>
Below options will be used to call receiver and call getter method on
contract after the contract is deployed.
Expand Down
7 changes: 5 additions & 2 deletions src/components/workspace/Tabs/Tabs.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import AppIcon from '@/components/ui/icon';
import { useFileTab } from '@/hooks';
import { useProject } from '@/hooks/projectV2.hooks';
import EventEmitter from '@/utility/eventEmitter';
import { fileTypeFromFileName } from '@/utility/utils';
import { delay, fileTypeFromFileName } from '@/utility/utils';
import { FC, useEffect } from 'react';
import s from './Tabs.module.scss';

Expand All @@ -22,7 +22,10 @@ const Tabs: FC = () => {
};

useEffect(() => {
syncTabSettings();
(async () => {
await delay(200);
syncTabSettings();
})();
}, [activeProject]);

useEffect(() => {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import {
CloneProject,
DownloadProject,
MigrateToUnifiedFS,
NewProject,
Expand All @@ -9,6 +10,7 @@ import { baseProjectPath, useProject } from '@/hooks/projectV2.hooks';
import { Project } from '@/interfaces/workspace.interface';
import EventEmitter from '@/utility/eventEmitter';
import { Button, Modal, Select, message } from 'antd';
import Router from 'next/router';
import { FC, useEffect, useState } from 'react';
import s from './ManageProject.module.scss';

Expand All @@ -28,6 +30,7 @@ const ManageProject: FC = () => {
await deleteProject(id);
setActiveProject(null);
setIsDeleteConfirmOpen(false);
Router.push('/');
} catch (error) {
await message.error('Failed to delete project');
}
Expand All @@ -45,6 +48,7 @@ const ManageProject: FC = () => {
<>
<span className={s.heading}>Projects</span>
<div className={s.options}>
<CloneProject />
<NewProject />

<NewProject
Expand Down
Loading

0 comments on commit cb6bb23

Please sign in to comment.