diff --git a/.eslintrc.js b/.eslintrc.js
index f1070507..4921e395 100644
--- a/.eslintrc.js
+++ b/.eslintrc.js
@@ -24,6 +24,7 @@ module.exports = {
],
globals: {
+ fetch: true,
window: true,
document: true,
describe: true,
diff --git a/packages/xod-client-browser/webpack.config.js b/packages/xod-client-browser/webpack.config.js
index 08ab974d..ccf37aa6 100644
--- a/packages/xod-client-browser/webpack.config.js
+++ b/packages/xod-client-browser/webpack.config.js
@@ -96,6 +96,7 @@ module.exports = {
'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV || 'development'),
'process.env.XOD_HM_DEF': JSON.stringify(process.env.XOD_HM_DEF || false),
+ 'process.env.XOD_HOSTNAME': JSON.stringify(process.env.XOD_HOSTNAME || 'xod.io'),
'process.env.XOD_SITE_DOMAIN': JSON.stringify(''),
'process.env.XOD_FORUM_DOMAIN': JSON.stringify('https://forum.xod.io/'),
'process.env.XOD_UTM_SOURCE': JSON.stringify('ide-browser'),
diff --git a/packages/xod-client-electron/src/upload/components/PopupUploadConfig.jsx b/packages/xod-client-electron/src/upload/components/PopupUploadConfig.jsx
index d339c05a..a783dd18 100644
--- a/packages/xod-client-electron/src/upload/components/PopupUploadConfig.jsx
+++ b/packages/xod-client-electron/src/upload/components/PopupUploadConfig.jsx
@@ -41,6 +41,7 @@ class PopupUploadConfig extends React.Component {
this.getSelectedBoard()
.then(selectedBoard => this.getBoards(selectedBoard));
this.getPorts();
+ this.props.updateCompileLimit();
}
onClose() {
@@ -252,6 +253,7 @@ class PopupUploadConfig extends React.Component {
render() {
const boards = this.renderBoardSelect();
const ports = this.renderPortSelect();
+ const compileLimitLeft = this.props.compileLimitLeft;
return (
@@ -300,6 +306,8 @@ class PopupUploadConfig extends React.Component {
PopupUploadConfig.propTypes = {
isVisible: PropTypes.bool,
selectedPort: PropTypes.object,
+ compileLimitLeft: PropTypes.number,
+ updateCompileLimit: PropTypes.func,
getSelectedBoard: PropTypes.func,
listBoards: PropTypes.func,
listPorts: PropTypes.func,
diff --git a/packages/xod-client-electron/src/view/containers/App.jsx b/packages/xod-client-electron/src/view/containers/App.jsx
index 9b2b455d..6ab68cda 100644
--- a/packages/xod-client-electron/src/view/containers/App.jsx
+++ b/packages/xod-client-electron/src/view/containers/App.jsx
@@ -227,6 +227,7 @@ class App extends client.App {
}
// Remove listener if process is finished.
ipcRenderer.removeAllListeners(UPLOAD_TO_ARDUINO);
+ this.props.actions.updateCompileLimit();
});
}
@@ -549,6 +550,8 @@ class App extends client.App {
selectedPort={this.props.selectedPort}
listBoards={this.listBoards}
listPorts={this.listPorts}
+ compileLimitLeft={this.props.compileLimitLeft}
+ updateCompileLimit={this.props.actions.updateCompileLimit}
onBoardChanged={this.onArduinoTargetBoardChange}
onPortChanged={this.onSerialPortChange}
onUpload={this.onUploadToArduino}
@@ -658,6 +661,7 @@ App.propTypes = R.merge(client.App.propTypes, {
project: client.sanctuaryPropType(Project),
actions: PropTypes.objectOf(PropTypes.func),
upload: PropTypes.object,
+ compileLimitLeft: PropTypes.number,
workspace: PropTypes.string,
selectedPort: PropTypes.object,
});
@@ -674,6 +678,7 @@ const mapStateToProps = R.applySpec({
saveProcess: getSaveProcess,
currentPatchPath: client.getCurrentPatchPath,
selectedPort: getSelectedSerialPort,
+ compileLimitLeft: client.getCompileLimitLeft,
popups: {
createProject: client.getPopupVisibility(client.POPUP_ID.CREATING_PROJECT),
projectSelection: client.getPopupVisibility(client.POPUP_ID.OPENING_PROJECT),
diff --git a/packages/xod-client-electron/webpack.config.js b/packages/xod-client-electron/webpack.config.js
index c401f151..dbfef6f3 100644
--- a/packages/xod-client-electron/webpack.config.js
+++ b/packages/xod-client-electron/webpack.config.js
@@ -110,6 +110,7 @@ const options = {
'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV || 'development'),
'process.env.XOD_HM_DEF': JSON.stringify(process.env.XOD_HM_DEF || false),
+ 'process.env.XOD_HOSTNAME': JSON.stringify(process.env.XOD_HOSTNAME || 'xod.io'),
'process.env.XOD_SITE_DOMAIN': JSON.stringify('https://xod.io/'),
'process.env.XOD_FORUM_DOMAIN': JSON.stringify('https://forum.xod.io/'),
'process.env.XOD_UTM_SOURCE': JSON.stringify('ide-desktop'),
diff --git a/packages/xod-client/README.md b/packages/xod-client/README.md
index 4b13d8d3..74ae762b 100644
--- a/packages/xod-client/README.md
+++ b/packages/xod-client/README.md
@@ -35,3 +35,9 @@ is used. Reducers simply delegate state update to `xod-project`’s functions,
selectors, and components use functions from `xod-project` to access project
data. This distincion is done because project state is complex and keeping all
machinery inside standard pod layout would make it messy.
+
+## Environment variables
+
+- **`XOD_HOSTNAME`**
+
+ XOD hostname. Default: `xod.io`
diff --git a/packages/xod-client/package.json b/packages/xod-client/package.json
index 424283a3..83b9c45a 100644
--- a/packages/xod-client/package.json
+++ b/packages/xod-client/package.json
@@ -23,6 +23,7 @@
"font-awesome": "^4.6.3",
"formsy-react": "^0.18.1",
"formsy-react-components": "^0.8.1",
+ "isomorphic-fetch": "^2.2.1",
"prop-types": "^15.5.10",
"ramda": "^0.24.1",
"ramda-fantasy": "^0.7.0",
diff --git a/packages/xod-client/src/core/actions.js b/packages/xod-client/src/core/actions.js
index 702763c5..d4aedd0c 100644
--- a/packages/xod-client/src/core/actions.js
+++ b/packages/xod-client/src/core/actions.js
@@ -22,6 +22,7 @@ export const showCode = code => ({
payload: { code },
});
+export * from '../user/actions';
export * from '../editor/actions';
export * from '../project/actions';
export * from '../projectBrowser/actions';
diff --git a/packages/xod-client/src/core/containers/App.jsx b/packages/xod-client/src/core/containers/App.jsx
index f5ad7b91..a63e465d 100644
--- a/packages/xod-client/src/core/containers/App.jsx
+++ b/packages/xod-client/src/core/containers/App.jsx
@@ -29,6 +29,7 @@ export default class App extends React.Component {
document.addEventListener('cut', this.props.actions.cutEntities);
document.addEventListener('copy', this.props.actions.copyEntities);
document.addEventListener('paste', this.props.actions.pasteEntities);
+ this.props.actions.updateCompileLimit();
}
onShowCodeArduino() {
@@ -128,6 +129,7 @@ App.propTypes = {
popups: PropTypes.objectOf(PropTypes.bool),
popupsData: PropTypes.objectOf(PropTypes.object),
actions: PropTypes.shape({
+ updateCompileLimit: PropTypes.func.isRequired,
createProject: PropTypes.func.isRequired,
updateProjectMeta: PropTypes.func.isRequired,
hideAllPopups: PropTypes.func.isRequired,
@@ -163,6 +165,7 @@ App.propTypes = {
};
App.actions = {
+ updateCompileLimit: actions.updateCompileLimit,
createProject: actions.createProject,
requestCreateProject: actions.requestCreateProject,
requestRenameProject: actions.requestRenameProject,
diff --git a/packages/xod-client/src/core/reducer.js b/packages/xod-client/src/core/reducer.js
index 117c38f9..31953536 100644
--- a/packages/xod-client/src/core/reducer.js
+++ b/packages/xod-client/src/core/reducer.js
@@ -1,6 +1,7 @@
import { merge } from 'ramda';
import { combineReducers } from 'redux';
+import userReducer from '../user/reducer';
import projectReducer from '../project/reducer';
import undoableProject from './undoableProject';
import projectBrowserReducer from '../projectBrowser/reducer';
@@ -15,6 +16,7 @@ import keepIntegrityAfterNavigatingHistory from './keepIntegrityAfterNavigatingH
const combineRootReducers = (extraReducers) => {
const reducers = merge(
{
+ user: userReducer,
project: projectReducer,
projectHistory: (s = {}) => s,
projectBrowser: projectBrowserReducer,
diff --git a/packages/xod-client/src/core/selectors.js b/packages/xod-client/src/core/selectors.js
index 0d59fdf5..14bb56f5 100644
--- a/packages/xod-client/src/core/selectors.js
+++ b/packages/xod-client/src/core/selectors.js
@@ -4,6 +4,7 @@ import { createSelector } from 'reselect';
import * as XP from 'xod-project';
+import * as User from '../user/selectors';
import * as Editor from '../editor/selectors';
import * as Project from '../project/selectors';
import * as ProjectBrowser from '../projectBrowser/selectors';
@@ -70,6 +71,7 @@ export const getPatchForHelpbar = createSelector(
export default {
+ User,
Editor,
Errors,
Processes,
diff --git a/packages/xod-client/src/core/state.js b/packages/xod-client/src/core/state.js
index a685f754..72cdabf4 100644
--- a/packages/xod-client/src/core/state.js
+++ b/packages/xod-client/src/core/state.js
@@ -1,9 +1,11 @@
+import userState from '../user/state';
import editorState from '../editor/state';
import projectState from '../project/state';
import debuggerState from '../debugger/state';
import projectBrowserState from '../projectBrowser/state';
export default {
+ user: userState,
project: projectState,
projectHistory: {},
projectBrowser: projectBrowserState,
diff --git a/packages/xod-client/src/editor/components/NodeInspector.jsx b/packages/xod-client/src/editor/components/NodeInspector.jsx
index 45924a01..34e3e78d 100644
--- a/packages/xod-client/src/editor/components/NodeInspector.jsx
+++ b/packages/xod-client/src/editor/components/NodeInspector.jsx
@@ -14,7 +14,7 @@ import Widgets, { WIDGET_MAPPING } from './inspectorWidgets';
import { RenderableNode } from '../../types';
import sanctuaryPropType from '../../utils/sanctuaryPropType';
-import { getUtmSiteUrl } from '../../utils/siteLinks';
+import { getUtmSiteUrl } from '../../utils/urls';
import * as MESSAGES from '../messages';
diff --git a/packages/xod-client/src/index.js b/packages/xod-client/src/index.js
index b932dd81..f6e56779 100644
--- a/packages/xod-client/src/index.js
+++ b/packages/xod-client/src/index.js
@@ -1,3 +1,4 @@
+import * as UserSelectors from './user/selectors';
import * as EditorSelectors from './editor/selectors';
import * as UtilsSelectors from './utils/selectors';
import * as ProcessSelectors from './processes/selectors';
@@ -22,7 +23,7 @@ import * as PopupConstants from './popups/constants';
import popupsReducer, { showOnlyPopup, hideOnePopup } from './popups/reducer';
-import * as siteLinkUtils from './utils/siteLinks';
+import * as siteLinkUtils from './utils/urls';
import * as BrowserUtils from './utils/browser';
import * as MenuUtils from './utils/menu';
import sanctuaryPropType from './utils/sanctuaryPropType';
@@ -63,7 +64,7 @@ export * from './debugger/selectors';
export * from './utils/browser';
export * from './utils/constants';
-export * from './utils/siteLinks';
+export * from './utils/urls';
export * from './popups/constants';
export { lowercaseKebabMask } from './utils/inputFormatting';
export { default as sanctuaryPropType } from './utils/sanctuaryPropType';
@@ -109,6 +110,7 @@ export default Object.assign({
PopupProjectPreferences,
TAB_CLOSE,
},
+ UserSelectors,
UtilsSelectors,
EditorSelectors,
ProcessSelectors,
diff --git a/packages/xod-client/src/projectBrowser/containers/ProjectBrowser.jsx b/packages/xod-client/src/projectBrowser/containers/ProjectBrowser.jsx
index 7123a66f..786406ad 100644
--- a/packages/xod-client/src/projectBrowser/containers/ProjectBrowser.jsx
+++ b/packages/xod-client/src/projectBrowser/containers/ProjectBrowser.jsx
@@ -36,7 +36,7 @@ import PatchTypeSelector from '../components/PatchTypeSelector';
import ProjectBrowserPopups from '../components/ProjectBrowserPopups';
import ProjectBrowserToolbar from '../components/ProjectBrowserToolbar';
-import { getUtmSiteUrl } from '../../utils/siteLinks';
+import { getUtmSiteUrl } from '../../utils/urls';
import { IconGuide } from '../../utils/components/IconGuide';
const PATCH_TYPE = {
diff --git a/packages/xod-client/src/user/actionTypes.js b/packages/xod-client/src/user/actionTypes.js
new file mode 100644
index 00000000..475553ea
--- /dev/null
+++ b/packages/xod-client/src/user/actionTypes.js
@@ -0,0 +1,2 @@
+export const UPDATE_COMPILE_LIMIT = 'UPDATE_COMPILE_LIMIT';
+export default {};
diff --git a/packages/xod-client/src/user/actions.js b/packages/xod-client/src/user/actions.js
new file mode 100644
index 00000000..f9797ed4
--- /dev/null
+++ b/packages/xod-client/src/user/actions.js
@@ -0,0 +1,12 @@
+import { getCompileLimitUrl } from '../utils/urls';
+import { UPDATE_COMPILE_LIMIT } from './actionTypes';
+
+export const updateCompileLimit = () => dispatch =>
+ fetch(getCompileLimitUrl())
+ .then(res => (res.ok ? res.json() : null))
+ .catch(() => null)
+ .then(limit => dispatch({
+ type: UPDATE_COMPILE_LIMIT,
+ payload: limit,
+ }));
+export default {};
diff --git a/packages/xod-client/src/user/reducer.js b/packages/xod-client/src/user/reducer.js
new file mode 100644
index 00000000..9b73b456
--- /dev/null
+++ b/packages/xod-client/src/user/reducer.js
@@ -0,0 +1,14 @@
+import { UPDATE_COMPILE_LIMIT } from './actionTypes';
+
+const userReducer = (state = {}, action) => {
+ switch (action.type) {
+ case UPDATE_COMPILE_LIMIT: {
+ const limit = action.payload;
+ return { ...state, limit };
+ }
+ default:
+ return state;
+ }
+};
+
+export default userReducer;
diff --git a/packages/xod-client/src/user/selectors.js b/packages/xod-client/src/user/selectors.js
new file mode 100644
index 00000000..152103d8
--- /dev/null
+++ b/packages/xod-client/src/user/selectors.js
@@ -0,0 +1,14 @@
+import R from 'ramda';
+import { createSelector } from 'reselect';
+
+export const getUserState = R.prop('user');
+
+export const getCompileLimit = createSelector(
+ getUserState,
+ R.prop('limit')
+);
+
+export const getCompileLimitLeft = createSelector(
+ getCompileLimit,
+ limit => (limit ? limit.limit - limit.pending - limit.used : null)
+);
diff --git a/packages/xod-client/src/user/state.js b/packages/xod-client/src/user/state.js
new file mode 100644
index 00000000..92948718
--- /dev/null
+++ b/packages/xod-client/src/user/state.js
@@ -0,0 +1,3 @@
+export default {
+ limit: null,
+};
diff --git a/packages/xod-client/src/utils/siteLinks.js b/packages/xod-client/src/utils/urls.js
similarity index 86%
rename from packages/xod-client/src/utils/siteLinks.js
rename to packages/xod-client/src/utils/urls.js
index c34f0911..93c51eee 100644
--- a/packages/xod-client/src/utils/siteLinks.js
+++ b/packages/xod-client/src/utils/urls.js
@@ -29,3 +29,9 @@ export const getUtmSiteUrl = getUtmUrl(process.env.XOD_SITE_DOMAIN);
*/
// :: String -> String
export const getUtmForumUrl = getUtmUrl(process.env.XOD_FORUM_DOMAIN, '', 'forum');
+
+const HOSTNAME = process.env.XOD_HOSTNAME || 'xod.io';
+
+// :: String -> String
+export const getCompileLimitUrl = () =>
+ `https://compile.${HOSTNAME}/limits`;
diff --git a/yarn.lock b/yarn.lock
index 6d7bbbbe..3e8e4602 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -5778,7 +5778,7 @@ isobject@^3.0.0, isobject@^3.0.1:
version "3.0.1"
resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df"
-isomorphic-fetch@2.2.1, isomorphic-fetch@^2.1.1:
+isomorphic-fetch@2.2.1, isomorphic-fetch@^2.1.1, isomorphic-fetch@^2.2.1:
version "2.2.1"
resolved "https://registry.yarnpkg.com/isomorphic-fetch/-/isomorphic-fetch-2.2.1.tgz#611ae1acf14f5e81f729507472819fe9733558a9"
dependencies: