diff --git a/src/components/bottomBar/style.less b/src/components/bottomBar/style.less
index 8fb9119e..aa1d972a 100644
--- a/src/components/bottomBar/style.less
+++ b/src/components/bottomBar/style.less
@@ -69,18 +69,4 @@
}
}
}
- .note {
- background-color: #F8E71C;
- color: #262E33;
- font-weight: 600;
- padding: 1px 8px 1px 8px;
- border-radius: 4px;
-
- span {
- font-size: 10px;
- }
- }
- .noteText {
- margin-left: 10px;
- }
}
diff --git a/src/components/common/dropdown/index.js b/src/components/common/dropdown/index.js
index a94740c9..ec4a89bb 100644
--- a/src/components/common/dropdown/index.js
+++ b/src/components/common/dropdown/index.js
@@ -22,34 +22,48 @@ Dropdown.proptypes = {
* Helper component to handle the state of showing/hiding a dropdown
*/
export class DropdownContainer extends Component {
+
+ state = {
+ showMenu: this.props.showMenu,
+ }
+
constructor(props) {
super(props);
- this.state = {
- menuVisible: false,
- };
-
// the ignore class name should be specific only this instance of the component
// in order to close other dropdown in case a new one is opened
this.ignoreClassName = 'ignore-react-onclickoutside' + Date.now();
}
+ componentDidUpdate(prevProps) {
+ if (prevProps.showMenu !== this.props.showMenu) {
+ this.setState({
+ showMenu: {...this.props.showMenu}
+ });
+ }
+ }
+
showMenu = () => {
- this.setState({ menuVisible: true });
+ this.setState({ showMenu: true });
};
toggleMenu = (e) => {
e.stopPropagation();
- this.setState((state) => ({ menuVisible: !state.menuVisible }));
+ this.setState((state) => ({ showMenu: !state.showMenu }));
};
closeMenu = e => {
e.stopPropagation();
- this.setState({ menuVisible: false });
+
+ if (this.props.onCloseMenu) {
+ this.props.onCloseMenu();
+ }
+
+ this.setState({ showMenu: false });
};
render() {
- const { dropdownContent, useRightClick, ...props } = this.props;
+ const { dropdownContent, useRightClick, enableClickInside, className } = this.props;
let main;
if (useRightClick) {
@@ -59,13 +73,13 @@ export class DropdownContainer extends Component {
}
return (
-
+
{main}
- { this.state.menuVisible &&
+ { this.state.showMenu &&
{dropdownContent}
}
@@ -73,3 +87,11 @@ export class DropdownContainer extends Component {
);
}
}
+
+DropdownContainer.proptypes = {
+ enableClickInside: PropTypes.bool,
+ dropdownContent: PropTypes.object,
+ className: PropTypes.string.object,
+ showMenu: PropTypes.bool,
+ onCloseMenu: PropTypes.func,
+};
diff --git a/src/components/icons/index.js b/src/components/icons/index.js
index 93a1d055..df51ef34 100644
--- a/src/components/icons/index.js
+++ b/src/components/icons/index.js
@@ -46,6 +46,7 @@ import {faPencilAlt as iconPencil} from '@fortawesome/free-solid-svg-icons/faPen
import {faArrowAltCircleDown as iconDownload} from '@fortawesome/free-regular-svg-icons/faArrowAltCircleDown';
import {faThLarge as iconMosaic} from '@fortawesome/free-solid-svg-icons/faThLarge';
import {faLink as iconChain} from '@fortawesome/free-solid-svg-icons/faLink';
+import {faShareAlt as iconShare} from '@fortawesome/free-solid-svg-icons/faShareAlt';
import {faCopy as iconCopy} from '@fortawesome/free-regular-svg-icons/faCopy';
class IconImg extends Component {
@@ -64,6 +65,7 @@ class IconImg extends Component {
export const IconDeployGreen = ({...props}) =>
;
export const IconAddFile = ({...props}) =>
;
export const IconAddFolder = ({...props}) =>
;
+export const IconInformation = ({...props}) =>
;
export const IconRun = () =>
;
export const IconSave = () =>
;
export const IconCompile = () =>
;
@@ -75,7 +77,6 @@ export const IconInteract = ({ ...props }) => (
);
export const IconTrash = () =>
;
-export const IconCopy = () =>
;
export const IconGem = () =>
;
export const IconFile = () =>
;
export const IconFileAlt = () =>
;
@@ -99,7 +100,6 @@ export const IconClone = () =>
;
export const IconDownload = ({ ...props }) => (
);
-export const IconUpload = () =>
;
export const IconDropdown = ({ ...props }) => (
);
@@ -126,6 +126,11 @@ export const IconPublicAddress = ({ ...props }) => (
export const IconMosaic = ({ ...props }) => (
);
+export const IconCopy = ({ ...props }) => (
+
+);
+export const IconBack= ({...props}) =>
+export const IconWarning = ({...props}) =>
// Top Bar
export const IconTransactions = ({ ...props }) =>
@@ -137,6 +142,9 @@ export const IconProjectSelector = ({ ...props }) => (
);
export const IconHelp = () =>
;
export const IconCheck = () =>
;
+export const IconShare = () =>
;
+export const IconUpload = ({...props}) =>
;
+export const IconFork = ({...props}) =>
// File types
export const IconContract = ({...props}) =>
;
diff --git a/src/components/newdapp/index.js b/src/components/newdapp/index.js
index 04942a5a..65c2deb6 100644
--- a/src/components/newdapp/index.js
+++ b/src/components/newdapp/index.js
@@ -19,7 +19,7 @@ import Proptypes from 'prop-types';
import SelectedTemplate from './selectTemplate';
import ProjectDetails from './projectDetails';
import Templates from '../../templates';
-import { logEvent, Analytics, LogOnMount } from "../../utils/analytics";
+import { logEvent } from "../../utils/analytics";
import DappfileItem from '../projecteditor/control/item/dappfileItem';
import JSZipUtils from 'jszip-utils';
diff --git a/src/components/note/index.js b/src/components/note/index.js
new file mode 100644
index 00000000..4e2acad8
--- /dev/null
+++ b/src/components/note/index.js
@@ -0,0 +1,42 @@
+// Copyright 2018 Superblocks AB
+//
+// This file is part of Superblocks Lab.
+//
+// Superblocks Lab is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation version 3 of the License.
+//
+// Superblocks Lab is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Superblocks Lab. If not, see
.
+
+import React from 'react';
+import Proptypes from 'prop-types';
+import classNames from 'classnames';
+import style from './style.less';
+
+const Note = ({
+ title,
+ text,
+ backgroundColor = "#F8E71C",
+ color = "#262E33",
+ textClassName = {},
+} = props) => (
+
+ {title}
+ { text && {text} }
+
+);
+
+export default Note;
+
+Note.propTypes = {
+ title: Proptypes.string.isRequired,
+ text: Proptypes.string,
+ backgroundColor: Proptypes.string,
+ color: Proptypes.string
+}
diff --git a/src/components/note/style.less b/src/components/note/style.less
new file mode 100644
index 00000000..102d2582
--- /dev/null
+++ b/src/components/note/style.less
@@ -0,0 +1,12 @@
+.note {
+ padding: 1px 8px 1px 8px;
+ border-radius: 4px;
+ font-size: 12px;
+
+ span {
+ font-size: 10px;
+ }
+}
+.noteText {
+ margin-left: 10px;
+}
diff --git a/src/components/projecteditor/ProjectEditor.js b/src/components/projecteditor/ProjectEditor.js
index 58fc6642..43145a22 100644
--- a/src/components/projecteditor/ProjectEditor.js
+++ b/src/components/projecteditor/ProjectEditor.js
@@ -151,6 +151,7 @@ export default class ProjectEditor extends Component {
diff --git a/src/components/projecteditor/control/backend.js b/src/components/projecteditor/control/backend.js
index 7b984c54..ed58432d 100644
--- a/src/components/projecteditor/control/backend.js
+++ b/src/components/projecteditor/control/backend.js
@@ -14,18 +14,18 @@
// You should have received a copy of the GNU General Public License
// along with Superblocks Lab. If not, see
.
-const JSZip = require("jszip");
-const FileSaver = require('file-saver');
+import JSZip from 'jszip';
+import FileSaver from 'file-saver';
-const DAPP_FORMAT_VERSION = 'dapps1.1.0';
export default class Backend {
- constructor() {}
+
+ static DAPP_FORMAT_VERSION = 'dapps1.1.0';
// Make sure projects created for an older version are converted to the current format.
// dapps1.0 is the 1.0 BETA which is deprecated.
// dapps1.0.0 is the released 1.0 format and will be converted into 1.1.0.
convertProjects = cb => {
- if (!localStorage.getItem(DAPP_FORMAT_VERSION)) {
+ if (!localStorage.getItem(Backend.DAPP_FORMAT_VERSION)) {
if (localStorage.getItem('dapps1.0.0')) {
// Convert from 1.0 (beta) to 1.0.0.
const data = JSON.parse(localStorage.getItem('dapps1.0.0'));
@@ -49,7 +49,7 @@ export default class Backend {
// store projects.
const newData = { projects: newProjects };
localStorage.setItem(
- DAPP_FORMAT_VERSION,
+ Backend.DAPP_FORMAT_VERSION,
JSON.stringify(newData)
);
cb(1); // Indicate that there are converted projects.
@@ -137,7 +137,7 @@ export default class Backend {
});
const dappfile2 = {
- format: DAPP_FORMAT_VERSION.substr(5), // IMPORTANT: if the format of this variable changes this must be updated. We only want the "x.y.z" part.
+ format: Backend.DAPP_FORMAT_VERSION.substr(5), // IMPORTANT: if the format of this variable changes this must be updated. We only want the "x.y.z" part.
project: dappfile.project,
environments: dappfile.environments,
wallets: wallets,
@@ -388,13 +388,60 @@ export default class Backend {
return newProject;
};
+ // Add a new inode number to the project
+ assignNewInode = (inode, cb) => {
+ const data =
+ JSON.parse(localStorage.getItem(Backend.DAPP_FORMAT_VERSION)) || {};
+ if (!data.projects) data.projects = [];
+
+ const projects = data.projects.map(project => {
+ if (project.inode === inode) {
+ project.inode = this.generateRandomInode(data.projects);
+ return project;
+ } else {
+ return project;
+ }
+ });
+
+ data.projects = projects;
+ localStorage.setItem(Backend.DAPP_FORMAT_VERSION, JSON.stringify(data));
+ cb();
+ };
+
+ // Add additional text to dappfile when forking
+ modifyDappFile(files) {
+ let root = files['/'].children;
+ let dappfile = JSON.parse(root['dappfile.json'].contents);
+ let name = dappfile.project.info.name;
+ dappfile.project.info.name = `${name}_copy`;
+ let contents = JSON.stringify(dappfile);
+ root["dappfile.json"].contents = contents;
+
+ return files;
+ }
+
+ /**
+ * Like the newFile method but actually wrapped around a promise
+ */
+ newFilePromise = (inode, patch, file) => {
+ return new Promise((resolve, reject) => {
+ this.newFile(inode, patch, file, status => {
+ if (status !== 0) {
+ reject(status);
+ } else {
+ resolve();
+ }
+ });
+ })
+ }
+
/**
* Create a new file for a project.
*
*/
newFile = (inode, path, file, cb) => {
const data =
- JSON.parse(localStorage.getItem(DAPP_FORMAT_VERSION)) || {};
+ JSON.parse(localStorage.getItem(Backend.DAPP_FORMAT_VERSION)) || {};
if (!data.projects) data.projects = [];
@@ -403,7 +450,7 @@ export default class Backend {
})[0];
if (!project) {
- setTimeout(() => cb(3), 1);
+ setTimeout(() => cb(2), 1);
return;
}
@@ -412,7 +459,7 @@ export default class Backend {
}
if (path[0] != '/') {
- setTimeout(() => cb(3), 1);
+ setTimeout(() => cb(2), 1);
return;
}
if (!project.files)
@@ -433,14 +480,14 @@ export default class Backend {
file = file.substring(0, file.length - 1);
}
if (folder.children[file]) {
- setTimeout(() => cb(3), 1);
+ setTimeout(() => cb(1), 1);
return;
}
folder.children[file] = {
type: type,
children: type == 'd' ? {} : null,
};
- localStorage.setItem(DAPP_FORMAT_VERSION, JSON.stringify(data));
+ localStorage.setItem(Backend.DAPP_FORMAT_VERSION, JSON.stringify(data));
setTimeout(() => cb(0), 1);
};
@@ -485,7 +532,7 @@ export default class Backend {
}
const data =
- JSON.parse(localStorage.getItem(DAPP_FORMAT_VERSION)) || {};
+ JSON.parse(localStorage.getItem(Backend.DAPP_FORMAT_VERSION)) || {};
if (!data.projects) data.projects = [];
@@ -549,7 +596,7 @@ export default class Backend {
targetFolder.children[b[2]] = o;
- localStorage.setItem(DAPP_FORMAT_VERSION, JSON.stringify(data));
+ localStorage.setItem(Backend.DAPP_FORMAT_VERSION, JSON.stringify(data));
setTimeout(() => cb(0), 1);
} catch(e) {
setTimeout(() => cb(6), 1);
@@ -563,7 +610,7 @@ export default class Backend {
*/
deleteFile = (inode, path, cb) => {
const data =
- JSON.parse(localStorage.getItem(DAPP_FORMAT_VERSION)) || {};
+ JSON.parse(localStorage.getItem(Backend.DAPP_FORMAT_VERSION)) || {};
if (!data.projects) data.projects = [];
@@ -594,7 +641,7 @@ export default class Backend {
folder = folder2;
}
delete folder.children[parts[parts.length - 1]];
- localStorage.setItem(DAPP_FORMAT_VERSION, JSON.stringify(data));
+ localStorage.setItem(Backend.DAPP_FORMAT_VERSION, JSON.stringify(data));
if (cb) setTimeout(() => cb(0), 1);
};
@@ -604,7 +651,7 @@ export default class Backend {
*/
listFiles = (inode, path, cb) => {
const data =
- JSON.parse(localStorage.getItem(DAPP_FORMAT_VERSION)) || {};
+ JSON.parse(localStorage.getItem(Backend.DAPP_FORMAT_VERSION)) || {};
if (!data.projects) data.projects = [];
@@ -653,7 +700,7 @@ export default class Backend {
*/
deleteProject = (inode, cb) => {
const data =
- JSON.parse(localStorage.getItem(DAPP_FORMAT_VERSION)) || {};
+ JSON.parse(localStorage.getItem(Backend.DAPP_FORMAT_VERSION)) || {};
if (!data.projects) data.projects = [];
const projects = data.projects.filter(item => {
@@ -661,7 +708,7 @@ export default class Backend {
});
data.projects = projects;
- localStorage.setItem(DAPP_FORMAT_VERSION, JSON.stringify(data));
+ localStorage.setItem(Backend.DAPP_FORMAT_VERSION, JSON.stringify(data));
cb();
};
@@ -671,7 +718,7 @@ export default class Backend {
*/
loadProjects = cb => {
const data =
- JSON.parse(localStorage.getItem(DAPP_FORMAT_VERSION)) || {};
+ JSON.parse(localStorage.getItem(Backend.DAPP_FORMAT_VERSION)) || {};
const projects = [];
(data.projects || []).map(project => {
// We need to parse the `/dappfile.json`
@@ -692,21 +739,58 @@ export default class Backend {
setTimeout(() => cb(0, projects), 1);
};
- createProject = (files, cb) => {
+
+ /**
+ * Get Files belonging to a given inode
+ */
+ getProjectFiles = (inode) => {
+ return new Promise((resolve, reject) => {
+ const data =
+ JSON.parse(localStorage.getItem(Backend.DAPP_FORMAT_VERSION)) || {};
+ if (!data.projects) data.projects = [];
+
+ const project = data.projects.filter(item => {
+ return item.inode === inode;
+ });
+
+ if (project.length) {
+ resolve(project[0].files);
+ } else {
+ reject("Project with given inode doesn't exist");
+ }
+ })
+ }
+
+ createProject = (files, cb, isTemporary) => {
const data =
- JSON.parse(localStorage.getItem(DAPP_FORMAT_VERSION)) || {};
+ JSON.parse(localStorage.getItem(Backend.DAPP_FORMAT_VERSION)) || {};
if (!data.projects) data.projects = [];
- const inode = Math.floor(Math.random() * 10000000);
- // TODO: check if project with this inode already exists.
- const project = {
+ let inode = 1;
+
+ if (isTemporary) {
+ if (this.isDuplicateInode(data.projects, inode)) {
+ // if duplicate with inode == 1, overwrite
+ data.projects = data.projects.filter(function( project ) {
+ return project.inode !== inode;
+ });
+ }
+ }
+ else {
+ // smallest random number to be generated is 2, 1 is reserved for temporary projects
+ inode = this.generateRandomInode(data.projects);
+ }
+
+ let project = {
inode: inode,
files: files,
};
+
data.projects.push(project);
+
try {
- localStorage.setItem(DAPP_FORMAT_VERSION, JSON.stringify(data));
+ localStorage.setItem(Backend.DAPP_FORMAT_VERSION, JSON.stringify(data));
}
catch(e) {
alert("Error: The browser local storage exceeded it's quota. Please delete some projects to make room for new ones.");
@@ -716,13 +800,28 @@ export default class Backend {
setTimeout(() => cb(0), 1);
};
+ /**
+ * Like the newFile method but actually wrapped around a promise
+ */
+ saveFilePromise = (inode, payload) => {
+ return new Promise((resolve, reject) => {
+ this.saveFile(inode, payload, ({ status }) => {
+ if (status !== 0) {
+ reject(status);
+ } else {
+ resolve();
+ }
+ });
+ })
+ }
+
/**
* Save the contents of a file within a project.
*
*/
saveFile = (inode, payload, cb) => {
const data =
- JSON.parse(localStorage.getItem(DAPP_FORMAT_VERSION)) || {};
+ JSON.parse(localStorage.getItem(Backend.DAPP_FORMAT_VERSION)) || {};
if (!data.projects) data.projects = [];
@@ -756,7 +855,7 @@ export default class Backend {
contents: payload.contents,
};
try {
- localStorage.setItem(DAPP_FORMAT_VERSION, JSON.stringify(data));
+ localStorage.setItem(Backend.DAPP_FORMAT_VERSION, JSON.stringify(data));
} catch (e) {
console.error(e);
setTimeout(() => cb({ status: 1 }), 1);
@@ -765,13 +864,29 @@ export default class Backend {
setTimeout(() => cb({ status: 0 }), 1);
};
+
+ /**
+ * Like the loadFile method but actually wrapped around a promise
+ */
+ loadFilePromise = (inode, patch) => {
+ return new Promise((resolve, reject) => {
+ this.loadFile(inode, patch, ({ status, contents }) => {
+ if (status !== 0) {
+ reject(status);
+ } else {
+ resolve(contents);
+ }
+ });
+ })
+ }
+
/**
* Load the contents of a file within a project.
*
*/
loadFile = (inode, path, cb) => {
const data =
- JSON.parse(localStorage.getItem(DAPP_FORMAT_VERSION)) || {};
+ JSON.parse(localStorage.getItem(Backend.DAPP_FORMAT_VERSION)) || {};
if (!data.projects) data.projects = [];
@@ -809,13 +924,27 @@ export default class Backend {
else setTimeout(() => cb({ status: 1 }), 1);
};
+ isDuplicateInode (projects, inode) {
+ return projects.find((project) => project.inode === inode);
+ }
+
+ generateRandomInode(projects) {
+ let inode = 0;
+ do {
+ inode = Math.floor(Math.random() * 10000000 + 2);
+ }
+ while (this.isDuplicateInode(projects, inode));
+
+ return inode;
+ }
+
downloadProject = (item, keepState) => {
const exportName = 'superblocks_project_' + item.getName() + '.zip';
const zip = new JSZip();
const data =
- JSON.parse(localStorage.getItem(DAPP_FORMAT_VERSION)) || {};
+ JSON.parse(localStorage.getItem(Backend.DAPP_FORMAT_VERSION)) || {};
if (!data.projects) data.projects = [];
@@ -950,5 +1079,5 @@ export default class Backend {
reject();
});
});
- }
+ };
}
diff --git a/src/components/projecteditor/control/control.js b/src/components/projecteditor/control/control.js
index 7d772c4b..c5bb623b 100644
--- a/src/components/projecteditor/control/control.js
+++ b/src/components/projecteditor/control/control.js
@@ -23,8 +23,7 @@ import Backend from './backend';
import NewDapp from '../../newdapp';
import NetworkAccountSelector from '../../networkAccountSelector';
import LearnAndResources from '../../learnAndResources';
-import { previewService } from '../../../services';
-
+import { ipfsService, previewService } from '../../../services';
import {
IconCube,
} from '../../icons';
@@ -56,7 +55,7 @@ export default class Control extends Component {
this.state = {
activeProject: null,
menu: menu
- }
+ };
props.router.register('control', this);
}
@@ -64,8 +63,12 @@ export default class Control extends Component {
componentDidMount() {
this._loadProjects(status => {
if (status == 0) {
- if (!this._openLastProject()) {
- this._showWelcome();
+ // Make sure no project gets loaded if we are importing one from IPFS
+ if (!this.props.isImportedProject) {
+ if (!this._openLastProject()) {
+ this._setProjectActive(null);
+ this._showWelcome();
+ }
}
}
});
@@ -103,7 +106,7 @@ export default class Control extends Component {
lightProjects.map(lightProject => {
const exists =
this._projectsList.filter(project => {
- if (project.getInode() == lightProject.inode) {
+ if (project.getInode() === lightProject.inode && lightProject.inode !== 1) {
projectsList.push(project);
return true;
}
@@ -137,7 +140,7 @@ export default class Control extends Component {
let { selectedProjectId } = this.props;
let found = false;
this._projectsList.forEach(project => {
- if (selectedProjectId && selectedProjectId === project.getInode()) {
+ if (selectedProjectId && selectedProjectId === project.getInode() && selectedProjectId !== 1) {
this.openProject(project);
found = true;
}
@@ -191,6 +194,11 @@ export default class Control extends Component {
return;
}
+ // if we switch from temporary project, discard it
+ if (project.getInode() !== 1) {
+ ipfsService.clearTempProject();
+ }
+
this._closeProject(status => {
if (status == 0) {
project.load(status => {
@@ -386,7 +394,7 @@ export default class Control extends Component {
if (cb) cb(1);
};
- importProject = files => {
+ importProject = (files, isTemporary) => {
const cb = status => {
if (status == 0) {
this._loadProjects(() => {
@@ -406,7 +414,7 @@ export default class Control extends Component {
}
};
- this.props.router.control.backend.createProject(files, cb);
+ this.props.router.control.backend.createProject(files, cb, isTemporary);
};
deleteProject = (project, cb) => {
@@ -595,9 +603,7 @@ export default class Control extends Component {
);
render() {
- //const item=this._renderItem(0, 0, this.state.menu);
const item = this.state.menu.render();
- //item.key="controltree";
return (
diff --git a/src/components/projecteditor/control/index.js b/src/components/projecteditor/control/index.js
index 9b45aea2..3d7b609f 100644
--- a/src/components/projecteditor/control/index.js
+++ b/src/components/projecteditor/control/index.js
@@ -1,19 +1,18 @@
import { connect } from 'react-redux';
-
import Control from './control';
import { getAppVersion } from '../../../selectors/app';
-import { getSelectedProjectId } from '../../../selectors/projects';
-import { selectProject, explorerActions, sidePanelsActions } from '../../../actions';
+import { projectSelectors } from '../../../selectors';
+import { projectActions, explorerActions, sidePanelsActions } from '../../../actions';
const mapStateToProps = state => ({
appVersion: getAppVersion(state),
- selectedProjectId: getSelectedProjectId(state),
+ selectedProjectId: projectSelectors.getSelectedProjectId(state)
});
const mapDispatchToProps = dispatch => {
return {
selectProject: (id, name) => {
- dispatch(selectProject(id, name));
+ dispatch(projectActions.selectProject(id, name));
},
closeAllPanels: () => {
dispatch(sidePanelsActions.closeAllPanels())
diff --git a/src/components/projecteditor/control/item/dappfileItem.js b/src/components/projecteditor/control/item/dappfileItem.js
index f2af96b5..a95d9c5f 100644
--- a/src/components/projecteditor/control/item/dappfileItem.js
+++ b/src/components/projecteditor/control/item/dappfileItem.js
@@ -34,6 +34,9 @@ export default class DappfileItem extends FileItem {
this._save = this.save;
this.save = this.__save;
delete this.__save;
+ this._setContents = this.setContents;
+ this.setContents = this.__setContents;
+ delete this.__setContents;
}
/**
@@ -60,7 +63,7 @@ export default class DappfileItem extends FileItem {
})
.catch(() => {
this.props.state.dappfile = new Dappfile(
- this.getDefaultDappfile()
+ DappfileItem.getDefaultDappfile()
);
this.save()
.then(() => {
@@ -79,10 +82,27 @@ export default class DappfileItem extends FileItem {
*
*/
__save = () => {
- this.setContents(this.getDappfile().dump());
+ this._setContents(this.getDappfile().dump());
return this._save();
};
+ /**
+ * Note: This actually shadows super.setContents.
+ */
+ __setContents = (contents) => {
+ try {
+ const obj = JSON.parse(contents);
+ if (DappfileItem.validateDappfile(obj)) {
+ this.props.state.dappfile = new Dappfile(obj);
+ this._setContents(JSON.stringify(obj, null, 4));
+ return;
+ }
+ }
+ catch(e) {
+ }
+ console.error('Dappfile data invalid.');
+ };
+
getDappfile = () => {
return this.props.state.dappfile;
};
@@ -105,6 +125,8 @@ export default class DappfileItem extends FileItem {
if (!dappfile.accounts) {
dappfile.accounts = defDappfile.accounts;
}
+
+ return true;
};
static getDefaultDappfile = () => {
diff --git a/src/components/projecteditor/control/item/fileItem/directoryEntry.js b/src/components/projecteditor/control/item/fileItem/directoryEntry.js
index 78169b32..a7805600 100644
--- a/src/components/projecteditor/control/item/fileItem/directoryEntry.js
+++ b/src/components/projecteditor/control/item/fileItem/directoryEntry.js
@@ -20,7 +20,6 @@ import {
IconEdit,
IconAddFile,
IconAddFolder,
- IconImportFile
} from '../../../../icons';
import style from '../../style.less';
import { DropdownContainer } from '../../../../common';
@@ -35,12 +34,11 @@ export class DirectoryEntry extends Component {
title,
angleClicked,
clickNewFile,
- clickImportFile,
clickNewFolder,
clickRenameFile,
clickDeleteFile,
fullPath,
- icons
+ icons,
} = this.props;
const alwaysVisible = fullPath === "/";
@@ -53,12 +51,6 @@ export class DirectoryEntry extends Component {
Create File
-
@@ -129,4 +121,3 @@ export class DirectoryEntry extends Component {
);
}
}
-
diff --git a/src/components/projecteditor/control/item/projectItem.js b/src/components/projecteditor/control/item/projectItem.js
index 89f4f51b..e6452cf6 100644
--- a/src/components/projecteditor/control/item/projectItem.js
+++ b/src/components/projecteditor/control/item/projectItem.js
@@ -26,7 +26,7 @@ import WalletsItem from './walletsItem';
import WalletItem from './walletItem';
import EnvironmentsItem from './environmentsItem';
import EnvironmentItem from './environmentItem';
-import { IconShowPreview } from '../../../icons';
+import { IconConfigure } from '../../../icons';
import Backend from '../backend';
import TransactionLogData from '../../sidePanels/blockexplorer/transactionlogdata';
@@ -63,6 +63,14 @@ export default class ProjectItem extends Item {
return this.props.state.title || '';
};
+ getHeaderTitle = () => {
+ return 'Project Settings';
+ }
+
+ getIcon = () => {
+ return
;
+ };
+
getName = () => {
const dappfile = this._getDappfile();
if (dappfile) {
diff --git a/src/components/projecteditor/control/style.less b/src/components/projecteditor/control/style.less
index 1e020879..df6f0d3e 100644
--- a/src/components/projecteditor/control/style.less
+++ b/src/components/projecteditor/control/style.less
@@ -38,6 +38,7 @@ select {
text-decoration: none;
}
}
+
.treemenu {
display: block;
overflow-y: auto;
diff --git a/src/components/projecteditor/deployer/mainnetWarning/index.js b/src/components/projecteditor/deployer/mainnetWarning/index.js
index 5fa9f5b8..bfa04e53 100644
--- a/src/components/projecteditor/deployer/mainnetWarning/index.js
+++ b/src/components/projecteditor/deployer/mainnetWarning/index.js
@@ -15,11 +15,11 @@
// along with Superblocks Lab. If not, see
.
import { connect } from 'react-redux';
-import { getSelectedProject } from '../../../../selectors/projects';
+import { projectSelectors } from '../../../../selectors';
import MainnetWarning from './MainnetWarning';
const mapStateToProps = state => ({
- selectedProject: getSelectedProject(state),
+ selectedProject: projectSelectors.getSelectedProject(state),
});
export default connect(mapStateToProps, null)(MainnetWarning);
diff --git a/src/components/projecteditor/editors/editor.js b/src/components/projecteditor/editors/editor/Editor.js
similarity index 93%
rename from src/components/projecteditor/editors/editor.js
rename to src/components/projecteditor/editors/editor/Editor.js
index fc1ddcc7..e0e747e4 100644
--- a/src/components/projecteditor/editors/editor.js
+++ b/src/components/projecteditor/editors/editor/Editor.js
@@ -23,8 +23,8 @@ import {
IconDeploy,
IconConfigure,
IconInteract,
-} from '../../icons';
-import Tooltip from '../../tooltip';
+} from '../../../icons';
+import Tooltip from '../../../tooltip';
export default class Editor extends Component {
constructor(props) {
@@ -91,11 +91,17 @@ export default class Editor extends Component {
save = e => {
if (e) e.preventDefault();
+ const routerControl = this.props.router.control;
this.props.item
.save()
.then(() => {
- // Trigger other windows to refresh.
- this.props.parent.props.parent.props.parent.redraw();
+ // if save action is triggered, move temporary to normal projects
+ if (routerControl.getActiveProject().getInode() === 1) {
+ this.props.forkProject();
+ } else {
+ // Trigger other windows to refresh.
+ this.props.parent.props.parent.props.parent.redraw();
+ }
})
.catch(() => {
alert('Error: Could not save file.');
@@ -285,6 +291,13 @@ export default class Editor extends Component {
this.currentEditorWidth = width;
setTimeout(this.updateLayout, 1);
}
+
+ const requireConfig = {
+ paths: { vs: "vs" },
+ url: "/vs/loader.js",
+ baseUrl: "/"
+ };
+
return (
{toolbar}
@@ -299,6 +312,7 @@ export default class Editor extends Component {
editorDidMount={(obj, monaco) =>
this.editorDidMount(obj, monaco)
}
+ requireConfig={requireConfig}
/>
);
diff --git a/src/components/projecteditor/editors/editor/index.js b/src/components/projecteditor/editors/editor/index.js
new file mode 100644
index 00000000..cbb358b8
--- /dev/null
+++ b/src/components/projecteditor/editors/editor/index.js
@@ -0,0 +1,13 @@
+import { connect } from 'react-redux';
+import { ipfsActions } from '../../../../actions';
+import Editor from './Editor';
+
+const mapDispatchToProps = dispatch => {
+ return {
+ forkProject: () => {
+ dispatch(ipfsActions.forkProject())
+ },
+ };
+};
+
+export default connect(null,mapDispatchToProps)(Editor);
diff --git a/src/components/projecteditor/editors/style-editor.less b/src/components/projecteditor/editors/editor/style-editor.less
similarity index 100%
rename from src/components/projecteditor/editors/style-editor.less
rename to src/components/projecteditor/editors/editor/style-editor.less
diff --git a/src/components/projecteditor/editors/index.js b/src/components/projecteditor/editors/index.js
index 5386d98e..bc50a2c9 100644
--- a/src/components/projecteditor/editors/index.js
+++ b/src/components/projecteditor/editors/index.js
@@ -1,4 +1,4 @@
export { default as AccountEditor } from './editor-account';
-export { default as AppEditor } from './editor-app';
+export { default as ProjectSettings } from './projectSettings';
export { default as ContractEditor } from './editor-contract';
-export { default as Editor } from './editor';
\ No newline at end of file
+export { default as Editor } from './editor';
diff --git a/src/components/projecteditor/editors/editor-app.js b/src/components/projecteditor/editors/projectSettings/ProjectSettings.js
similarity index 88%
rename from src/components/projecteditor/editors/editor-app.js
rename to src/components/projecteditor/editors/projectSettings/ProjectSettings.js
index 9757feba..c8a429a2 100644
--- a/src/components/projecteditor/editors/editor-app.js
+++ b/src/components/projecteditor/editors/projectSettings/ProjectSettings.js
@@ -15,11 +15,11 @@
// along with Superblocks Lab. If not, see
.
import React, { Component } from 'react';
+import PropTypes from 'prop-types';
import classNames from 'classnames';
-import style from './style-editor-contract.less';
-import Backend from '../control/backend';
+import style from '../style-editor-contract.less';
-export default class AppEditor extends Component {
+export default class ProjecSettings extends Component {
state = {
form: null,
@@ -28,7 +28,6 @@ export default class AppEditor extends Component {
constructor(props) {
super(props);
- this.backend = new Backend();
this.id = props.id + '_editor';
this.props.parent.childComponent = this;
}
@@ -73,15 +72,12 @@ export default class AppEditor extends Component {
);
return false;
}
- this.props.item.getProject().setName(this.state.form.name);
- this.props.item.getProject().setTitle(this.state.form.title);
- this.props.item
- .getProject()
- .saveDappfile()
- .then(() => {
- this.setState({ isDirty: false });
- this.props.router.control.redrawMain(true);
- });
+
+ this.props.updateProjectSettings({
+ name: this.state.form.name,
+ title: this.state.form.title
+ });
+ this.setState({ isDirty: false });
};
onChange = (e, key) => {
@@ -97,7 +93,7 @@ export default class AppEditor extends Component {
-
Edit DApp Configuration
+
Project Settings