Merge branch 'develop' of https://github.com/processing/p5.js-web-editor into feature/mobile-canvas
This commit is contained in:
commit
96261db108
25 changed files with 165 additions and 126 deletions
3
.github/FUNDING.yml
vendored
3
.github/FUNDING.yml
vendored
|
@ -1 +1,2 @@
|
||||||
custom: https://processingfoundation.org/support
|
github: processing
|
||||||
|
custom: https://processingfoundation.org/
|
||||||
|
|
|
@ -10,14 +10,13 @@ import * as projectActions from '../modules/IDE/actions/project';
|
||||||
import { setAllAccessibleOutput } from '../modules/IDE/actions/preferences';
|
import { setAllAccessibleOutput } from '../modules/IDE/actions/preferences';
|
||||||
import { logoutUser } from '../modules/User/actions';
|
import { logoutUser } from '../modules/User/actions';
|
||||||
|
|
||||||
|
import getConfig from '../utils/getConfig';
|
||||||
import { metaKeyName, } from '../utils/metaKey';
|
import { metaKeyName, } from '../utils/metaKey';
|
||||||
|
|
||||||
import CaretLeftIcon from '../images/left-arrow.svg';
|
import CaretLeftIcon from '../images/left-arrow.svg';
|
||||||
import TriangleIcon from '../images/down-filled-triangle.svg';
|
import TriangleIcon from '../images/down-filled-triangle.svg';
|
||||||
import LogoIcon from '../images/p5js-logo-small.svg';
|
import LogoIcon from '../images/p5js-logo-small.svg';
|
||||||
|
|
||||||
const __process = (typeof global !== 'undefined' ? global : window).process;
|
|
||||||
|
|
||||||
class Nav extends React.PureComponent {
|
class Nav extends React.PureComponent {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
|
@ -272,7 +271,7 @@ class Nav extends React.PureComponent {
|
||||||
New
|
New
|
||||||
</button>
|
</button>
|
||||||
</li>
|
</li>
|
||||||
{ __process.env.LOGIN_ENABLED && (!this.props.project.owner || this.isUserOwner()) &&
|
{ getConfig('LOGIN_ENABLED') && (!this.props.project.owner || this.isUserOwner()) &&
|
||||||
<li className="nav__dropdown-item">
|
<li className="nav__dropdown-item">
|
||||||
<button
|
<button
|
||||||
onClick={this.handleSave}
|
onClick={this.handleSave}
|
||||||
|
@ -324,7 +323,7 @@ class Nav extends React.PureComponent {
|
||||||
Open
|
Open
|
||||||
</Link>
|
</Link>
|
||||||
</li> }
|
</li> }
|
||||||
{__process.env.UI_COLLECTIONS_ENABLED &&
|
{getConfig('UI_COLLECTIONS_ENABLED') &&
|
||||||
this.props.user.authenticated &&
|
this.props.user.authenticated &&
|
||||||
this.props.project.id &&
|
this.props.project.id &&
|
||||||
<li className="nav__dropdown-item">
|
<li className="nav__dropdown-item">
|
||||||
|
@ -337,7 +336,7 @@ class Nav extends React.PureComponent {
|
||||||
Add to Collection
|
Add to Collection
|
||||||
</Link>
|
</Link>
|
||||||
</li>}
|
</li>}
|
||||||
{ __process.env.EXAMPLES_ENABLED &&
|
{ getConfig('EXAMPLES_ENABLED') &&
|
||||||
<li className="nav__dropdown-item">
|
<li className="nav__dropdown-item">
|
||||||
<Link
|
<Link
|
||||||
to="/p5/sketches"
|
to="/p5/sketches"
|
||||||
|
@ -587,7 +586,7 @@ class Nav extends React.PureComponent {
|
||||||
My sketches
|
My sketches
|
||||||
</Link>
|
</Link>
|
||||||
</li>
|
</li>
|
||||||
{__process.env.UI_COLLECTIONS_ENABLED &&
|
{getConfig('UI_COLLECTIONS_ENABLED') &&
|
||||||
<li className="nav__dropdown-item">
|
<li className="nav__dropdown-item">
|
||||||
<Link
|
<Link
|
||||||
to={`/${this.props.user.username}/collections`}
|
to={`/${this.props.user.username}/collections`}
|
||||||
|
@ -635,7 +634,7 @@ class Nav extends React.PureComponent {
|
||||||
}
|
}
|
||||||
|
|
||||||
renderUserMenu(navDropdownState) {
|
renderUserMenu(navDropdownState) {
|
||||||
const isLoginEnabled = __process.env.LOGIN_ENABLED;
|
const isLoginEnabled = getConfig('LOGIN_ENABLED');
|
||||||
const isAuthenticated = this.props.user.authenticated;
|
const isAuthenticated = this.props.user.authenticated;
|
||||||
|
|
||||||
if (isLoginEnabled && isAuthenticated) {
|
if (isLoginEnabled && isAuthenticated) {
|
||||||
|
|
|
@ -1,11 +1,10 @@
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
|
import getConfig from '../../utils/getConfig';
|
||||||
import DevTools from './components/DevTools';
|
import DevTools from './components/DevTools';
|
||||||
import { setPreviousPath } from '../IDE/actions/ide';
|
import { setPreviousPath } from '../IDE/actions/ide';
|
||||||
|
|
||||||
const __process = (typeof global !== 'undefined' ? global : window).process;
|
|
||||||
|
|
||||||
class App extends React.Component {
|
class App extends React.Component {
|
||||||
constructor(props, context) {
|
constructor(props, context) {
|
||||||
super(props, context);
|
super(props, context);
|
||||||
|
@ -35,7 +34,7 @@ class App extends React.Component {
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<div className="app">
|
<div className="app">
|
||||||
{this.state.isMounted && !window.devToolsExtension && __process.env.NODE_ENV === 'development' && <DevTools />}
|
{this.state.isMounted && !window.devToolsExtension && getConfig('NODE_ENV') === 'development' && <DevTools />}
|
||||||
{this.props.children}
|
{this.props.children}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
|
@ -1,10 +1,7 @@
|
||||||
import axios from 'axios';
|
import apiClient from '../../../utils/apiClient';
|
||||||
import * as ActionTypes from '../../../constants';
|
import * as ActionTypes from '../../../constants';
|
||||||
import { startLoader, stopLoader } from './loader';
|
import { startLoader, stopLoader } from './loader';
|
||||||
|
|
||||||
const __process = (typeof global !== 'undefined' ? global : window).process;
|
|
||||||
const ROOT_URL = __process.env.API_URL;
|
|
||||||
|
|
||||||
function setAssets(assets, totalSize) {
|
function setAssets(assets, totalSize) {
|
||||||
return {
|
return {
|
||||||
type: ActionTypes.SET_ASSETS,
|
type: ActionTypes.SET_ASSETS,
|
||||||
|
@ -16,7 +13,7 @@ function setAssets(assets, totalSize) {
|
||||||
export function getAssets() {
|
export function getAssets() {
|
||||||
return (dispatch) => {
|
return (dispatch) => {
|
||||||
dispatch(startLoader());
|
dispatch(startLoader());
|
||||||
axios.get(`${ROOT_URL}/S3/objects`, { withCredentials: true })
|
apiClient.get('/S3/objects')
|
||||||
.then((response) => {
|
.then((response) => {
|
||||||
dispatch(setAssets(response.data.assets, response.data.totalSize));
|
dispatch(setAssets(response.data.assets, response.data.totalSize));
|
||||||
dispatch(stopLoader());
|
dispatch(stopLoader());
|
||||||
|
@ -39,7 +36,7 @@ export function deleteAsset(assetKey) {
|
||||||
|
|
||||||
export function deleteAssetRequest(assetKey) {
|
export function deleteAssetRequest(assetKey) {
|
||||||
return (dispatch) => {
|
return (dispatch) => {
|
||||||
axios.delete(`${ROOT_URL}/S3/${assetKey}`, { withCredentials: true })
|
apiClient.delete(`/S3/${assetKey}`)
|
||||||
.then((response) => {
|
.then((response) => {
|
||||||
dispatch(deleteAsset(assetKey));
|
dispatch(deleteAsset(assetKey));
|
||||||
})
|
})
|
||||||
|
|
|
@ -1,11 +1,9 @@
|
||||||
import axios from 'axios';
|
|
||||||
import { browserHistory } from 'react-router';
|
import { browserHistory } from 'react-router';
|
||||||
|
import apiClient from '../../../utils/apiClient';
|
||||||
import * as ActionTypes from '../../../constants';
|
import * as ActionTypes from '../../../constants';
|
||||||
import { startLoader, stopLoader } from './loader';
|
import { startLoader, stopLoader } from './loader';
|
||||||
import { setToastText, showToast } from './toast';
|
import { setToastText, showToast } from './toast';
|
||||||
|
|
||||||
const __process = (typeof global !== 'undefined' ? global : window).process;
|
|
||||||
const ROOT_URL = __process.env.API_URL;
|
|
||||||
|
|
||||||
const TOAST_DISPLAY_TIME_MS = 1500;
|
const TOAST_DISPLAY_TIME_MS = 1500;
|
||||||
|
|
||||||
|
@ -15,11 +13,11 @@ export function getCollections(username) {
|
||||||
dispatch(startLoader());
|
dispatch(startLoader());
|
||||||
let url;
|
let url;
|
||||||
if (username) {
|
if (username) {
|
||||||
url = `${ROOT_URL}/${username}/collections`;
|
url = `/${username}/collections`;
|
||||||
} else {
|
} else {
|
||||||
url = `${ROOT_URL}/collections`;
|
url = '/collections';
|
||||||
}
|
}
|
||||||
axios.get(url, { withCredentials: true })
|
apiClient.get(url)
|
||||||
.then((response) => {
|
.then((response) => {
|
||||||
dispatch({
|
dispatch({
|
||||||
type: ActionTypes.SET_COLLECTIONS,
|
type: ActionTypes.SET_COLLECTIONS,
|
||||||
|
@ -41,8 +39,8 @@ export function getCollections(username) {
|
||||||
export function createCollection(collection) {
|
export function createCollection(collection) {
|
||||||
return (dispatch) => {
|
return (dispatch) => {
|
||||||
dispatch(startLoader());
|
dispatch(startLoader());
|
||||||
const url = `${ROOT_URL}/collections`;
|
const url = '/collections';
|
||||||
return axios.post(url, collection, { withCredentials: true })
|
return apiClient.post(url, collection)
|
||||||
.then((response) => {
|
.then((response) => {
|
||||||
dispatch({
|
dispatch({
|
||||||
type: ActionTypes.CREATE_COLLECTION
|
type: ActionTypes.CREATE_COLLECTION
|
||||||
|
@ -73,8 +71,8 @@ export function createCollection(collection) {
|
||||||
export function addToCollection(collectionId, projectId) {
|
export function addToCollection(collectionId, projectId) {
|
||||||
return (dispatch) => {
|
return (dispatch) => {
|
||||||
dispatch(startLoader());
|
dispatch(startLoader());
|
||||||
const url = `${ROOT_URL}/collections/${collectionId}/${projectId}`;
|
const url = `/collections/${collectionId}/${projectId}`;
|
||||||
return axios.post(url, { withCredentials: true })
|
return apiClient.post(url)
|
||||||
.then((response) => {
|
.then((response) => {
|
||||||
dispatch({
|
dispatch({
|
||||||
type: ActionTypes.ADD_TO_COLLECTION,
|
type: ActionTypes.ADD_TO_COLLECTION,
|
||||||
|
@ -105,8 +103,8 @@ export function addToCollection(collectionId, projectId) {
|
||||||
export function removeFromCollection(collectionId, projectId) {
|
export function removeFromCollection(collectionId, projectId) {
|
||||||
return (dispatch) => {
|
return (dispatch) => {
|
||||||
dispatch(startLoader());
|
dispatch(startLoader());
|
||||||
const url = `${ROOT_URL}/collections/${collectionId}/${projectId}`;
|
const url = `/collections/${collectionId}/${projectId}`;
|
||||||
return axios.delete(url, { withCredentials: true })
|
return apiClient.delete(url)
|
||||||
.then((response) => {
|
.then((response) => {
|
||||||
dispatch({
|
dispatch({
|
||||||
type: ActionTypes.REMOVE_FROM_COLLECTION,
|
type: ActionTypes.REMOVE_FROM_COLLECTION,
|
||||||
|
@ -136,8 +134,8 @@ export function removeFromCollection(collectionId, projectId) {
|
||||||
|
|
||||||
export function editCollection(collectionId, { name, description }) {
|
export function editCollection(collectionId, { name, description }) {
|
||||||
return (dispatch) => {
|
return (dispatch) => {
|
||||||
const url = `${ROOT_URL}/collections/${collectionId}`;
|
const url = `/collections/${collectionId}`;
|
||||||
return axios.patch(url, { name, description }, { withCredentials: true })
|
return apiClient.patch(url, { name, description })
|
||||||
.then((response) => {
|
.then((response) => {
|
||||||
dispatch({
|
dispatch({
|
||||||
type: ActionTypes.EDIT_COLLECTION,
|
type: ActionTypes.EDIT_COLLECTION,
|
||||||
|
@ -159,8 +157,8 @@ export function editCollection(collectionId, { name, description }) {
|
||||||
|
|
||||||
export function deleteCollection(collectionId) {
|
export function deleteCollection(collectionId) {
|
||||||
return (dispatch) => {
|
return (dispatch) => {
|
||||||
const url = `${ROOT_URL}/collections/${collectionId}`;
|
const url = `/collections/${collectionId}`;
|
||||||
return axios.delete(url, { withCredentials: true })
|
return apiClient.delete(url)
|
||||||
.then((response) => {
|
.then((response) => {
|
||||||
dispatch({
|
dispatch({
|
||||||
type: ActionTypes.DELETE_COLLECTION,
|
type: ActionTypes.DELETE_COLLECTION,
|
||||||
|
|
|
@ -1,13 +1,11 @@
|
||||||
import axios from 'axios';
|
|
||||||
import objectID from 'bson-objectid';
|
import objectID from 'bson-objectid';
|
||||||
import blobUtil from 'blob-util';
|
import blobUtil from 'blob-util';
|
||||||
import { reset } from 'redux-form';
|
import { reset } from 'redux-form';
|
||||||
|
import apiClient from '../../../utils/apiClient';
|
||||||
import * as ActionTypes from '../../../constants';
|
import * as ActionTypes from '../../../constants';
|
||||||
import { setUnsavedChanges, closeNewFolderModal, closeNewFileModal } from './ide';
|
import { setUnsavedChanges, closeNewFolderModal, closeNewFileModal } from './ide';
|
||||||
import { setProjectSavedTime } from './project';
|
import { setProjectSavedTime } from './project';
|
||||||
|
|
||||||
const __process = (typeof global !== 'undefined' ? global : window).process;
|
|
||||||
const ROOT_URL = __process.env.API_URL;
|
|
||||||
|
|
||||||
function appendToFilename(filename, string) {
|
function appendToFilename(filename, string) {
|
||||||
const dotIndex = filename.lastIndexOf('.');
|
const dotIndex = filename.lastIndexOf('.');
|
||||||
|
@ -50,7 +48,7 @@ export function createFile(formProps) {
|
||||||
parentId,
|
parentId,
|
||||||
children: []
|
children: []
|
||||||
};
|
};
|
||||||
axios.post(`${ROOT_URL}/projects/${state.project.id}/files`, postParams, { withCredentials: true })
|
apiClient.post(`/projects/${state.project.id}/files`, postParams)
|
||||||
.then((response) => {
|
.then((response) => {
|
||||||
dispatch({
|
dispatch({
|
||||||
type: ActionTypes.CREATE_FILE,
|
type: ActionTypes.CREATE_FILE,
|
||||||
|
@ -106,7 +104,7 @@ export function createFolder(formProps) {
|
||||||
parentId,
|
parentId,
|
||||||
fileType: 'folder'
|
fileType: 'folder'
|
||||||
};
|
};
|
||||||
axios.post(`${ROOT_URL}/projects/${state.project.id}/files`, postParams, { withCredentials: true })
|
apiClient.post(`/projects/${state.project.id}/files`, postParams)
|
||||||
.then((response) => {
|
.then((response) => {
|
||||||
dispatch({
|
dispatch({
|
||||||
type: ActionTypes.CREATE_FILE,
|
type: ActionTypes.CREATE_FILE,
|
||||||
|
@ -161,7 +159,7 @@ export function deleteFile(id, parentId) {
|
||||||
parentId
|
parentId
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
axios.delete(`${ROOT_URL}/projects/${state.project.id}/files/${id}`, deleteConfig, { withCredentials: true })
|
apiClient.delete(`/projects/${state.project.id}/files/${id}`, deleteConfig)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
dispatch({
|
dispatch({
|
||||||
type: ActionTypes.DELETE_FILE,
|
type: ActionTypes.DELETE_FILE,
|
||||||
|
|
|
@ -1,11 +1,8 @@
|
||||||
import axios from 'axios';
|
import apiClient from '../../../utils/apiClient';
|
||||||
import * as ActionTypes from '../../../constants';
|
import * as ActionTypes from '../../../constants';
|
||||||
|
|
||||||
const __process = (typeof global !== 'undefined' ? global : window).process;
|
|
||||||
const ROOT_URL = __process.env.API_URL;
|
|
||||||
|
|
||||||
function updatePreferences(formParams, dispatch) {
|
function updatePreferences(formParams, dispatch) {
|
||||||
axios.put(`${ROOT_URL}/preferences`, formParams, { withCredentials: true })
|
apiClient.put('/preferences', formParams)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
import { browserHistory } from 'react-router';
|
import { browserHistory } from 'react-router';
|
||||||
import axios from 'axios';
|
|
||||||
import objectID from 'bson-objectid';
|
import objectID from 'bson-objectid';
|
||||||
import each from 'async/each';
|
import each from 'async/each';
|
||||||
import isEqual from 'lodash/isEqual';
|
import isEqual from 'lodash/isEqual';
|
||||||
|
import apiClient from '../../../utils/apiClient';
|
||||||
|
import getConfig from '../../../utils/getConfig';
|
||||||
import * as ActionTypes from '../../../constants';
|
import * as ActionTypes from '../../../constants';
|
||||||
import { showToast, setToastText } from './toast';
|
import { showToast, setToastText } from './toast';
|
||||||
import {
|
import {
|
||||||
|
@ -14,8 +15,7 @@ import {
|
||||||
} from './ide';
|
} from './ide';
|
||||||
import { clearState, saveState } from '../../../persistState';
|
import { clearState, saveState } from '../../../persistState';
|
||||||
|
|
||||||
const __process = (typeof global !== 'undefined' ? global : window).process;
|
const ROOT_URL = getConfig('API_URL');
|
||||||
const ROOT_URL = __process.env.API_URL;
|
|
||||||
|
|
||||||
export function setProject(project) {
|
export function setProject(project) {
|
||||||
return {
|
return {
|
||||||
|
@ -52,7 +52,7 @@ export function setNewProject(project) {
|
||||||
export function getProject(id, username) {
|
export function getProject(id, username) {
|
||||||
return (dispatch, getState) => {
|
return (dispatch, getState) => {
|
||||||
dispatch(justOpenedProject());
|
dispatch(justOpenedProject());
|
||||||
axios.get(`${ROOT_URL}/${username}/projects/${id}`, { withCredentials: true })
|
apiClient.get(`/${username}/projects/${id}`)
|
||||||
.then((response) => {
|
.then((response) => {
|
||||||
dispatch(setProject(response.data));
|
dispatch(setProject(response.data));
|
||||||
dispatch(setUnsavedChanges(false));
|
dispatch(setUnsavedChanges(false));
|
||||||
|
@ -142,7 +142,7 @@ export function saveProject(selectedFile = null, autosave = false) {
|
||||||
fileToUpdate.content = selectedFile.content;
|
fileToUpdate.content = selectedFile.content;
|
||||||
}
|
}
|
||||||
if (state.project.id) {
|
if (state.project.id) {
|
||||||
return axios.put(`${ROOT_URL}/projects/${state.project.id}`, formParams, { withCredentials: true })
|
return apiClient.put(`/projects/${state.project.id}`, formParams)
|
||||||
.then((response) => {
|
.then((response) => {
|
||||||
dispatch(endSavingProject());
|
dispatch(endSavingProject());
|
||||||
dispatch(setUnsavedChanges(false));
|
dispatch(setUnsavedChanges(false));
|
||||||
|
@ -177,7 +177,7 @@ export function saveProject(selectedFile = null, autosave = false) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return axios.post(`${ROOT_URL}/projects`, formParams, { withCredentials: true })
|
return apiClient.post('/projects', formParams)
|
||||||
.then((response) => {
|
.then((response) => {
|
||||||
dispatch(endSavingProject());
|
dispatch(endSavingProject());
|
||||||
const { hasChanges, synchedProject } = getSynchedProject(getState(), response.data);
|
const { hasChanges, synchedProject } = getSynchedProject(getState(), response.data);
|
||||||
|
@ -260,7 +260,7 @@ export function cloneProject(id) {
|
||||||
if (!id) {
|
if (!id) {
|
||||||
resolve(getState());
|
resolve(getState());
|
||||||
} else {
|
} else {
|
||||||
fetch(`${ROOT_URL}/projects/${id}`)
|
apiClient.get(`/projects/${id}`)
|
||||||
.then(res => res.json())
|
.then(res => res.json())
|
||||||
.then(data => resolve({
|
.then(data => resolve({
|
||||||
files: data.files,
|
files: data.files,
|
||||||
|
@ -287,7 +287,7 @@ export function cloneProject(id) {
|
||||||
const formParams = {
|
const formParams = {
|
||||||
url: file.url
|
url: file.url
|
||||||
};
|
};
|
||||||
axios.post(`${ROOT_URL}/S3/copy`, formParams, { withCredentials: true })
|
apiClient.post('/S3/copy', formParams)
|
||||||
.then((response) => {
|
.then((response) => {
|
||||||
file.url = response.data.url;
|
file.url = response.data.url;
|
||||||
callback(null);
|
callback(null);
|
||||||
|
@ -298,7 +298,7 @@ export function cloneProject(id) {
|
||||||
}, (err) => {
|
}, (err) => {
|
||||||
// if not errors in duplicating the files on S3, then duplicate it
|
// if not errors in duplicating the files on S3, then duplicate it
|
||||||
const formParams = Object.assign({}, { name: `${state.project.name} copy` }, { files: newFiles });
|
const formParams = Object.assign({}, { name: `${state.project.name} copy` }, { files: newFiles });
|
||||||
axios.post(`${ROOT_URL}/projects`, formParams, { withCredentials: true })
|
apiClient.post('/projects', formParams)
|
||||||
.then((response) => {
|
.then((response) => {
|
||||||
browserHistory.push(`/${response.data.user.username}/sketches/${response.data.id}`);
|
browserHistory.push(`/${response.data.user.username}/sketches/${response.data.id}`);
|
||||||
dispatch(setNewProject(response.data));
|
dispatch(setNewProject(response.data));
|
||||||
|
@ -337,7 +337,7 @@ export function setProjectSavedTime(updatedAt) {
|
||||||
export function changeProjectName(id, newName) {
|
export function changeProjectName(id, newName) {
|
||||||
return (dispatch, getState) => {
|
return (dispatch, getState) => {
|
||||||
const state = getState();
|
const state = getState();
|
||||||
axios.put(`${ROOT_URL}/projects/${id}`, { name: newName }, { withCredentials: true })
|
apiClient.put(`/projects/${id}`, { name: newName })
|
||||||
.then((response) => {
|
.then((response) => {
|
||||||
if (response.status === 200) {
|
if (response.status === 200) {
|
||||||
dispatch({
|
dispatch({
|
||||||
|
@ -364,7 +364,7 @@ export function changeProjectName(id, newName) {
|
||||||
|
|
||||||
export function deleteProject(id) {
|
export function deleteProject(id) {
|
||||||
return (dispatch, getState) => {
|
return (dispatch, getState) => {
|
||||||
axios.delete(`${ROOT_URL}/projects/${id}`, { withCredentials: true })
|
apiClient.delete(`/projects/${id}`)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
const state = getState();
|
const state = getState();
|
||||||
if (id === state.project.id) {
|
if (id === state.project.id) {
|
||||||
|
|
|
@ -1,21 +1,18 @@
|
||||||
import axios from 'axios';
|
import apiClient from '../../../utils/apiClient';
|
||||||
import * as ActionTypes from '../../../constants';
|
import * as ActionTypes from '../../../constants';
|
||||||
import { startLoader, stopLoader } from './loader';
|
import { startLoader, stopLoader } from './loader';
|
||||||
|
|
||||||
const __process = (typeof global !== 'undefined' ? global : window).process;
|
|
||||||
const ROOT_URL = __process.env.API_URL;
|
|
||||||
|
|
||||||
// eslint-disable-next-line
|
// eslint-disable-next-line
|
||||||
export function getProjects(username) {
|
export function getProjects(username) {
|
||||||
return (dispatch) => {
|
return (dispatch) => {
|
||||||
dispatch(startLoader());
|
dispatch(startLoader());
|
||||||
let url;
|
let url;
|
||||||
if (username) {
|
if (username) {
|
||||||
url = `${ROOT_URL}/${username}/projects`;
|
url = `/${username}/projects`;
|
||||||
} else {
|
} else {
|
||||||
url = `${ROOT_URL}/projects`;
|
url = '/projects';
|
||||||
}
|
}
|
||||||
axios.get(url, { withCredentials: true })
|
apiClient.get(url)
|
||||||
.then((response) => {
|
.then((response) => {
|
||||||
dispatch({
|
dispatch({
|
||||||
type: ActionTypes.SET_PROJECTS,
|
type: ActionTypes.SET_PROJECTS,
|
||||||
|
|
|
@ -1,11 +1,10 @@
|
||||||
import axios from 'axios';
|
import apiClient from '../../../utils/apiClient';
|
||||||
|
import getConfig from '../../../utils/getConfig';
|
||||||
import { createFile } from './files';
|
import { createFile } from './files';
|
||||||
import { TEXT_FILE_REGEX } from '../../../../server/utils/fileUtils';
|
import { TEXT_FILE_REGEX } from '../../../../server/utils/fileUtils';
|
||||||
|
|
||||||
const __process = (typeof global !== 'undefined' ? global : window).process;
|
const s3BucketHttps = getConfig('S3_BUCKET_URL_BASE') ||
|
||||||
const s3BucketHttps = __process.env.S3_BUCKET_URL_BASE ||
|
`https://s3-${getConfig('AWS_REGION')}.amazonaws.com/${getConfig('S3_BUCKET')}/`;
|
||||||
`https://s3-${__process.env.AWS_REGION}.amazonaws.com/${__process.env.S3_BUCKET}/`;
|
|
||||||
const ROOT_URL = __process.env.API_URL;
|
|
||||||
const MAX_LOCAL_FILE_SIZE = 80000; // bytes, aka 80 KB
|
const MAX_LOCAL_FILE_SIZE = 80000; // bytes, aka 80 KB
|
||||||
|
|
||||||
function localIntercept(file, options = {}) {
|
function localIntercept(file, options = {}) {
|
||||||
|
@ -46,18 +45,13 @@ export function dropzoneAcceptCallback(userId, file, done) {
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
file.postData = []; // eslint-disable-line
|
file.postData = []; // eslint-disable-line
|
||||||
axios.post(
|
apiClient.post('/S3/sign', {
|
||||||
`${ROOT_URL}/S3/sign`, {
|
name: file.name,
|
||||||
name: file.name,
|
type: file.type,
|
||||||
type: file.type,
|
size: file.size,
|
||||||
size: file.size,
|
userId
|
||||||
userId
|
|
||||||
// _csrf: document.getElementById('__createPostToken').value
|
// _csrf: document.getElementById('__createPostToken').value
|
||||||
},
|
})
|
||||||
{
|
|
||||||
withCredentials: true
|
|
||||||
}
|
|
||||||
)
|
|
||||||
.then((response) => {
|
.then((response) => {
|
||||||
file.custom_status = 'ready'; // eslint-disable-line
|
file.custom_status = 'ready'; // eslint-disable-line
|
||||||
file.postData = response.data; // eslint-disable-line
|
file.postData = response.data; // eslint-disable-line
|
||||||
|
|
|
@ -3,8 +3,9 @@ import React from 'react';
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import prettyBytes from 'pretty-bytes';
|
import prettyBytes from 'pretty-bytes';
|
||||||
|
|
||||||
const __process = (typeof global !== 'undefined' ? global : window).process;
|
import getConfig from '../../../utils/getConfig';
|
||||||
const limit = __process.env.UPLOAD_LIMIT || 250000000;
|
|
||||||
|
const limit = getConfig('UPLOAD_LIMIT') || 250000000;
|
||||||
const MAX_SIZE_B = limit;
|
const MAX_SIZE_B = limit;
|
||||||
|
|
||||||
const formatPercent = (percent) => {
|
const formatPercent = (percent) => {
|
||||||
|
|
|
@ -4,11 +4,11 @@ import Dropzone from 'dropzone';
|
||||||
import { bindActionCreators } from 'redux';
|
import { bindActionCreators } from 'redux';
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import * as UploaderActions from '../actions/uploader';
|
import * as UploaderActions from '../actions/uploader';
|
||||||
|
import getConfig from '../../../utils/getConfig';
|
||||||
import { fileExtensionsAndMimeTypes } from '../../../../server/utils/fileUtils';
|
import { fileExtensionsAndMimeTypes } from '../../../../server/utils/fileUtils';
|
||||||
|
|
||||||
const __process = (typeof global !== 'undefined' ? global : window).process;
|
const s3Bucket = getConfig('S3_BUCKET_URL_BASE') ||
|
||||||
const s3Bucket = __process.env.S3_BUCKET_URL_BASE ||
|
`https://s3-${getConfig('AWS_REGION')}.amazonaws.com/${getConfig('S3_BUCKET')}/`;
|
||||||
`https://s3-${__process.env.AWS_REGION}.amazonaws.com/${__process.env.S3_BUCKET}/`;
|
|
||||||
|
|
||||||
class FileUploader extends React.Component {
|
class FileUploader extends React.Component {
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
|
|
|
@ -3,12 +3,12 @@ import PropTypes from 'prop-types';
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import { Link } from 'react-router';
|
import { Link } from 'react-router';
|
||||||
import prettyBytes from 'pretty-bytes';
|
import prettyBytes from 'pretty-bytes';
|
||||||
|
import getConfig from '../../../utils/getConfig';
|
||||||
import FileUploader from './FileUploader';
|
import FileUploader from './FileUploader';
|
||||||
import { getreachedTotalSizeLimit } from '../selectors/users';
|
import { getreachedTotalSizeLimit } from '../selectors/users';
|
||||||
import ExitIcon from '../../../images/exit.svg';
|
import ExitIcon from '../../../images/exit.svg';
|
||||||
|
|
||||||
const __process = (typeof global !== 'undefined' ? global : window).process;
|
const limit = getConfig('UPLOAD_LIMIT') || 250000000;
|
||||||
const limit = __process.env.UPLOAD_LIMIT || 250000000;
|
|
||||||
const limitText = prettyBytes(limit);
|
const limitText = prettyBytes(limit);
|
||||||
|
|
||||||
class UploadFileModal extends React.Component {
|
class UploadFileModal extends React.Component {
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
import { createSelector } from 'reselect';
|
import { createSelector } from 'reselect';
|
||||||
|
import getConfig from '../../../utils/getConfig';
|
||||||
|
|
||||||
const __process = (typeof global !== 'undefined' ? global : window).process;
|
|
||||||
const getAuthenticated = state => state.user.authenticated;
|
const getAuthenticated = state => state.user.authenticated;
|
||||||
const getTotalSize = state => state.user.totalSize;
|
const getTotalSize = state => state.user.totalSize;
|
||||||
const getAssetsTotalSize = state => state.assets.totalSize;
|
const getAssetsTotalSize = state => state.assets.totalSize;
|
||||||
const limit = __process.env.UPLOAD_LIMIT || 250000000;
|
const limit = getConfig('UPLOAD_LIMIT') || 250000000;
|
||||||
|
|
||||||
export const getCanUploadMedia = createSelector(
|
export const getCanUploadMedia = createSelector(
|
||||||
getAuthenticated,
|
getAuthenticated,
|
||||||
|
|
|
@ -1,13 +1,9 @@
|
||||||
import { browserHistory } from 'react-router';
|
import { browserHistory } from 'react-router';
|
||||||
import axios from 'axios';
|
|
||||||
import * as ActionTypes from '../../constants';
|
import * as ActionTypes from '../../constants';
|
||||||
|
import apiClient from '../../utils/apiClient';
|
||||||
import { showErrorModal, justOpenedProject } from '../IDE/actions/ide';
|
import { showErrorModal, justOpenedProject } from '../IDE/actions/ide';
|
||||||
import { showToast, setToastText } from '../IDE/actions/toast';
|
import { showToast, setToastText } from '../IDE/actions/toast';
|
||||||
|
|
||||||
|
|
||||||
const __process = (typeof global !== 'undefined' ? global : window).process;
|
|
||||||
const ROOT_URL = __process.env.API_URL;
|
|
||||||
|
|
||||||
export function authError(error) {
|
export function authError(error) {
|
||||||
return {
|
return {
|
||||||
type: ActionTypes.AUTH_ERROR,
|
type: ActionTypes.AUTH_ERROR,
|
||||||
|
@ -17,7 +13,7 @@ export function authError(error) {
|
||||||
|
|
||||||
export function signUpUser(previousPath, formValues) {
|
export function signUpUser(previousPath, formValues) {
|
||||||
return (dispatch) => {
|
return (dispatch) => {
|
||||||
axios.post(`${ROOT_URL}/signup`, formValues, { withCredentials: true })
|
apiClient.post('/signup', formValues)
|
||||||
.then((response) => {
|
.then((response) => {
|
||||||
dispatch({
|
dispatch({
|
||||||
type: ActionTypes.AUTH_USER,
|
type: ActionTypes.AUTH_USER,
|
||||||
|
@ -34,7 +30,7 @@ export function signUpUser(previousPath, formValues) {
|
||||||
}
|
}
|
||||||
|
|
||||||
export function loginUser(formValues) {
|
export function loginUser(formValues) {
|
||||||
return axios.post(`${ROOT_URL}/login`, formValues, { withCredentials: true });
|
return apiClient.post('/login', formValues);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function loginUserSuccess(user) {
|
export function loginUserSuccess(user) {
|
||||||
|
@ -74,7 +70,7 @@ export function validateAndLoginUser(previousPath, formProps, dispatch) {
|
||||||
|
|
||||||
export function getUser() {
|
export function getUser() {
|
||||||
return (dispatch) => {
|
return (dispatch) => {
|
||||||
axios.get(`${ROOT_URL}/session`, { withCredentials: true })
|
apiClient.get('/session')
|
||||||
.then((response) => {
|
.then((response) => {
|
||||||
dispatch({
|
dispatch({
|
||||||
type: ActionTypes.AUTH_USER,
|
type: ActionTypes.AUTH_USER,
|
||||||
|
@ -95,7 +91,7 @@ export function getUser() {
|
||||||
|
|
||||||
export function validateSession() {
|
export function validateSession() {
|
||||||
return (dispatch, getState) => {
|
return (dispatch, getState) => {
|
||||||
axios.get(`${ROOT_URL}/session`, { withCredentials: true })
|
apiClient.get('/session')
|
||||||
.then((response) => {
|
.then((response) => {
|
||||||
const state = getState();
|
const state = getState();
|
||||||
if (state.user.username !== response.data.username) {
|
if (state.user.username !== response.data.username) {
|
||||||
|
@ -113,7 +109,7 @@ export function validateSession() {
|
||||||
|
|
||||||
export function logoutUser() {
|
export function logoutUser() {
|
||||||
return (dispatch) => {
|
return (dispatch) => {
|
||||||
axios.get(`${ROOT_URL}/logout`, { withCredentials: true })
|
apiClient.get('/logout')
|
||||||
.then(() => {
|
.then(() => {
|
||||||
dispatch({
|
dispatch({
|
||||||
type: ActionTypes.UNAUTH_USER
|
type: ActionTypes.UNAUTH_USER
|
||||||
|
@ -131,7 +127,7 @@ export function initiateResetPassword(formValues) {
|
||||||
dispatch({
|
dispatch({
|
||||||
type: ActionTypes.RESET_PASSWORD_INITIATE
|
type: ActionTypes.RESET_PASSWORD_INITIATE
|
||||||
});
|
});
|
||||||
axios.post(`${ROOT_URL}/reset-password`, formValues, { withCredentials: true })
|
apiClient.post('/reset-password', formValues)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
// do nothing
|
// do nothing
|
||||||
})
|
})
|
||||||
|
@ -150,7 +146,7 @@ export function initiateVerification() {
|
||||||
dispatch({
|
dispatch({
|
||||||
type: ActionTypes.EMAIL_VERIFICATION_INITIATE
|
type: ActionTypes.EMAIL_VERIFICATION_INITIATE
|
||||||
});
|
});
|
||||||
axios.post(`${ROOT_URL}/verify/send`, {}, { withCredentials: true })
|
apiClient.post('/verify/send', {})
|
||||||
.then(() => {
|
.then(() => {
|
||||||
// do nothing
|
// do nothing
|
||||||
})
|
})
|
||||||
|
@ -170,7 +166,7 @@ export function verifyEmailConfirmation(token) {
|
||||||
type: ActionTypes.EMAIL_VERIFICATION_VERIFY,
|
type: ActionTypes.EMAIL_VERIFICATION_VERIFY,
|
||||||
state: 'checking',
|
state: 'checking',
|
||||||
});
|
});
|
||||||
return axios.get(`${ROOT_URL}/verify?t=${token}`, {}, { withCredentials: true })
|
return apiClient.get(`/verify?t=${token}`, {})
|
||||||
.then(response => dispatch({
|
.then(response => dispatch({
|
||||||
type: ActionTypes.EMAIL_VERIFICATION_VERIFIED,
|
type: ActionTypes.EMAIL_VERIFICATION_VERIFIED,
|
||||||
message: response.data,
|
message: response.data,
|
||||||
|
@ -194,7 +190,7 @@ export function resetPasswordReset() {
|
||||||
|
|
||||||
export function validateResetPasswordToken(token) {
|
export function validateResetPasswordToken(token) {
|
||||||
return (dispatch) => {
|
return (dispatch) => {
|
||||||
axios.get(`${ROOT_URL}/reset-password/${token}`)
|
apiClient.get(`/reset-password/${token}`)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
// do nothing if the token is valid
|
// do nothing if the token is valid
|
||||||
})
|
})
|
||||||
|
@ -206,7 +202,7 @@ export function validateResetPasswordToken(token) {
|
||||||
|
|
||||||
export function updatePassword(token, formValues) {
|
export function updatePassword(token, formValues) {
|
||||||
return (dispatch) => {
|
return (dispatch) => {
|
||||||
axios.post(`${ROOT_URL}/reset-password/${token}`, formValues)
|
apiClient.post(`/reset-password/${token}`, formValues)
|
||||||
.then((response) => {
|
.then((response) => {
|
||||||
dispatch(loginUserSuccess(response.data));
|
dispatch(loginUserSuccess(response.data));
|
||||||
browserHistory.push('/');
|
browserHistory.push('/');
|
||||||
|
@ -226,7 +222,7 @@ export function updateSettingsSuccess(user) {
|
||||||
|
|
||||||
export function updateSettings(formValues) {
|
export function updateSettings(formValues) {
|
||||||
return dispatch =>
|
return dispatch =>
|
||||||
axios.put(`${ROOT_URL}/account`, formValues, { withCredentials: true })
|
apiClient.put('/account', formValues)
|
||||||
.then((response) => {
|
.then((response) => {
|
||||||
dispatch(updateSettingsSuccess(response.data));
|
dispatch(updateSettingsSuccess(response.data));
|
||||||
browserHistory.push('/');
|
browserHistory.push('/');
|
||||||
|
@ -248,7 +244,7 @@ export function createApiKeySuccess(user) {
|
||||||
|
|
||||||
export function createApiKey(label) {
|
export function createApiKey(label) {
|
||||||
return dispatch =>
|
return dispatch =>
|
||||||
axios.post(`${ROOT_URL}/account/api-keys`, { label }, { withCredentials: true })
|
apiClient.post('/account/api-keys', { label })
|
||||||
.then((response) => {
|
.then((response) => {
|
||||||
dispatch(createApiKeySuccess(response.data));
|
dispatch(createApiKeySuccess(response.data));
|
||||||
})
|
})
|
||||||
|
@ -260,7 +256,7 @@ export function createApiKey(label) {
|
||||||
|
|
||||||
export function removeApiKey(keyId) {
|
export function removeApiKey(keyId) {
|
||||||
return dispatch =>
|
return dispatch =>
|
||||||
axios.delete(`${ROOT_URL}/account/api-keys/${keyId}`, { withCredentials: true })
|
apiClient.delete(`/account/api-keys/${keyId}`)
|
||||||
.then((response) => {
|
.then((response) => {
|
||||||
dispatch({
|
dispatch({
|
||||||
type: ActionTypes.API_KEY_REMOVED,
|
type: ActionTypes.API_KEY_REMOVED,
|
||||||
|
|
|
@ -3,18 +3,15 @@ import React from 'react';
|
||||||
import { reduxForm } from 'redux-form';
|
import { reduxForm } from 'redux-form';
|
||||||
import { bindActionCreators } from 'redux';
|
import { bindActionCreators } from 'redux';
|
||||||
import { Tab, Tabs, TabList, TabPanel } from 'react-tabs';
|
import { Tab, Tabs, TabList, TabPanel } from 'react-tabs';
|
||||||
import axios from 'axios';
|
|
||||||
import { Helmet } from 'react-helmet';
|
import { Helmet } from 'react-helmet';
|
||||||
import { updateSettings, initiateVerification, createApiKey, removeApiKey } from '../actions';
|
import { updateSettings, initiateVerification, createApiKey, removeApiKey } from '../actions';
|
||||||
import AccountForm from '../components/AccountForm';
|
import AccountForm from '../components/AccountForm';
|
||||||
|
import apiClient from '../../../utils/apiClient';
|
||||||
import { validateSettings } from '../../../utils/reduxFormUtils';
|
import { validateSettings } from '../../../utils/reduxFormUtils';
|
||||||
import SocialAuthButton from '../components/SocialAuthButton';
|
import SocialAuthButton from '../components/SocialAuthButton';
|
||||||
import APIKeyForm from '../components/APIKeyForm';
|
import APIKeyForm from '../components/APIKeyForm';
|
||||||
import Nav from '../../../components/Nav';
|
import Nav from '../../../components/Nav';
|
||||||
|
|
||||||
const __process = (typeof global !== 'undefined' ? global : window).process;
|
|
||||||
const ROOT_URL = __process.env.API_URL;
|
|
||||||
|
|
||||||
function SocialLoginPanel(props) {
|
function SocialLoginPanel(props) {
|
||||||
return (
|
return (
|
||||||
<React.Fragment>
|
<React.Fragment>
|
||||||
|
@ -96,7 +93,7 @@ function asyncValidate(formProps, dispatch, props) {
|
||||||
const queryParams = {};
|
const queryParams = {};
|
||||||
queryParams[fieldToValidate] = formProps[fieldToValidate];
|
queryParams[fieldToValidate] = formProps[fieldToValidate];
|
||||||
queryParams.check_type = fieldToValidate;
|
queryParams.check_type = fieldToValidate;
|
||||||
return axios.get(`${ROOT_URL}/signup/duplicate_check`, { params: queryParams })
|
return apiClient.get('/signup/duplicate_check', { params: queryParams })
|
||||||
.then((response) => {
|
.then((response) => {
|
||||||
if (response.data.exists) {
|
if (response.data.exists) {
|
||||||
const error = {};
|
const error = {};
|
||||||
|
|
|
@ -1,19 +1,16 @@
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { bindActionCreators } from 'redux';
|
import { bindActionCreators } from 'redux';
|
||||||
import axios from 'axios';
|
|
||||||
import { Link, browserHistory } from 'react-router';
|
import { Link, browserHistory } from 'react-router';
|
||||||
import { Helmet } from 'react-helmet';
|
import { Helmet } from 'react-helmet';
|
||||||
import { reduxForm } from 'redux-form';
|
import { reduxForm } from 'redux-form';
|
||||||
import * as UserActions from '../actions';
|
import * as UserActions from '../actions';
|
||||||
import SignupForm from '../components/SignupForm';
|
import SignupForm from '../components/SignupForm';
|
||||||
|
import apiClient from '../../../utils/apiClient';
|
||||||
import { validateSignup } from '../../../utils/reduxFormUtils';
|
import { validateSignup } from '../../../utils/reduxFormUtils';
|
||||||
import SocialAuthButton from '../components/SocialAuthButton';
|
import SocialAuthButton from '../components/SocialAuthButton';
|
||||||
import Nav from '../../../components/Nav';
|
import Nav from '../../../components/Nav';
|
||||||
|
|
||||||
const __process = (typeof global !== 'undefined' ? global : window).process;
|
|
||||||
const ROOT_URL = __process.env.API_URL;
|
|
||||||
|
|
||||||
class SignupView extends React.Component {
|
class SignupView extends React.Component {
|
||||||
gotoHomePage = () => {
|
gotoHomePage = () => {
|
||||||
browserHistory.push('/');
|
browserHistory.push('/');
|
||||||
|
@ -86,7 +83,7 @@ function asyncValidate(formProps, dispatch, props) {
|
||||||
const queryParams = {};
|
const queryParams = {};
|
||||||
queryParams[fieldToValidate] = formProps[fieldToValidate];
|
queryParams[fieldToValidate] = formProps[fieldToValidate];
|
||||||
queryParams.check_type = fieldToValidate;
|
queryParams.check_type = fieldToValidate;
|
||||||
return axios.get(`${ROOT_URL}/signup/duplicate_check`, { params: queryParams })
|
return apiClient.get('/signup/duplicate_check', { params: queryParams })
|
||||||
.then((response) => {
|
.then((response) => {
|
||||||
if (response.data.exists) {
|
if (response.data.exists) {
|
||||||
errors[fieldToValidate] = response.data.message;
|
errors[fieldToValidate] = response.data.message;
|
||||||
|
|
|
@ -3,15 +3,14 @@ import thunk from 'redux-thunk';
|
||||||
import DevTools from './modules/App/components/DevTools';
|
import DevTools from './modules/App/components/DevTools';
|
||||||
import rootReducer from './reducers';
|
import rootReducer from './reducers';
|
||||||
import { clearState, loadState } from './persistState';
|
import { clearState, loadState } from './persistState';
|
||||||
|
import getConfig from './utils/getConfig';
|
||||||
const __process = (typeof global !== 'undefined' ? global : window).process;
|
|
||||||
|
|
||||||
export default function configureStore(initialState) {
|
export default function configureStore(initialState) {
|
||||||
const enhancers = [
|
const enhancers = [
|
||||||
applyMiddleware(thunk),
|
applyMiddleware(thunk),
|
||||||
];
|
];
|
||||||
|
|
||||||
if (__process.env.CLIENT && __process.env.NODE_ENV === 'development') {
|
if (getConfig('CLIENT') && getConfig('NODE_ENV') === 'development') {
|
||||||
// Enable DevTools only when rendering on client and during development.
|
// Enable DevTools only when rendering on client and during development.
|
||||||
enhancers.push(window.devToolsExtension ? window.devToolsExtension() : DevTools.instrument());
|
enhancers.push(window.devToolsExtension ? window.devToolsExtension() : DevTools.instrument());
|
||||||
}
|
}
|
||||||
|
|
17
client/utils/apiClient.js
Normal file
17
client/utils/apiClient.js
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
import axios from 'axios';
|
||||||
|
|
||||||
|
import getConfig from './getConfig';
|
||||||
|
|
||||||
|
const ROOT_URL = getConfig('API_URL');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configures an Axios instance with the correct API URL
|
||||||
|
*/
|
||||||
|
function createClientInstance() {
|
||||||
|
return axios.create({
|
||||||
|
baseURL: ROOT_URL,
|
||||||
|
withCredentials: true
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export default createClientInstance();
|
|
@ -60,7 +60,7 @@ export const getAllScriptOffsets = (htmlFile) => {
|
||||||
if (ind === -1) {
|
if (ind === -1) {
|
||||||
foundJSScript = false;
|
foundJSScript = false;
|
||||||
} else {
|
} else {
|
||||||
endFilenameInd = htmlFile.indexOf('.js', ind + startTag.length + 3);
|
endFilenameInd = htmlFile.indexOf('.js', ind + startTag.length + 1);
|
||||||
filename = htmlFile.substring(ind + startTag.length, endFilenameInd);
|
filename = htmlFile.substring(ind + startTag.length, endFilenameInd);
|
||||||
lineOffset = htmlFile.substring(0, ind).split('\n').length + hijackConsoleErrorsScriptLength;
|
lineOffset = htmlFile.substring(0, ind).split('\n').length + hijackConsoleErrorsScriptLength;
|
||||||
offs.push([lineOffset, filename]);
|
offs.push([lineOffset, filename]);
|
||||||
|
|
24
client/utils/getConfig.js
Normal file
24
client/utils/getConfig.js
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
function isTestEnvironment() {
|
||||||
|
// eslint-disable-next-line no-use-before-define
|
||||||
|
return getConfig('NODE_ENV', { warn: false }) === 'test';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns config item from environment
|
||||||
|
*/
|
||||||
|
function getConfig(key, options = { warn: !isTestEnvironment() }) {
|
||||||
|
if (key == null) {
|
||||||
|
throw new Error('"key" must be provided to getConfig()');
|
||||||
|
}
|
||||||
|
|
||||||
|
const env = (typeof global !== 'undefined' ? global : window)?.process?.env || {};
|
||||||
|
const value = env[key];
|
||||||
|
|
||||||
|
if (value == null && options?.warn !== false) {
|
||||||
|
console.warn(`getConfig("${key}") returned null`);
|
||||||
|
}
|
||||||
|
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default getConfig;
|
28
client/utils/getConfig.test.js
Normal file
28
client/utils/getConfig.test.js
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
import getConfig from './getConfig';
|
||||||
|
|
||||||
|
describe('utils/getConfig()', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
delete global.process.env.CONFIG_TEST_KEY_NAME;
|
||||||
|
delete window.process.env.CONFIG_TEST_KEY_NAME;
|
||||||
|
});
|
||||||
|
|
||||||
|
it('throws if key is not defined', () => {
|
||||||
|
expect(() => getConfig(/* key is missing */)).toThrow(/must be provided/);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('fetches from global.process', () => {
|
||||||
|
global.process.env.CONFIG_TEST_KEY_NAME = 'editor.p5js.org';
|
||||||
|
|
||||||
|
expect(getConfig('CONFIG_TEST_KEY_NAME')).toBe('editor.p5js.org');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('fetches from window.process', () => {
|
||||||
|
window.process.env.CONFIG_TEST_KEY_NAME = 'editor.p5js.org';
|
||||||
|
|
||||||
|
expect(getConfig('CONFIG_TEST_KEY_NAME')).toBe('editor.p5js.org');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('warns but does not throw if no value found', () => {
|
||||||
|
expect(() => getConfig('CONFIG_TEST_KEY_NAME')).not.toThrow();
|
||||||
|
});
|
||||||
|
});
|
|
@ -13,19 +13,19 @@ This project release guide is based on
|
||||||
1. `$ git checkout develop`
|
1. `$ git checkout develop`
|
||||||
2. `$ git checkout -b release-<newversion>`
|
2. `$ git checkout -b release-<newversion>`
|
||||||
3. Do all of the release branch testing necessary. This could be as simple as running `npm test:ci`, or it could take user testing over a few days.
|
3. Do all of the release branch testing necessary. This could be as simple as running `npm test:ci`, or it could take user testing over a few days.
|
||||||
4. `$ git checkout release`
|
4. `$ npm version <newversion>` (see [npm-version](https://docs.npmjs.com/cli/version) for valid values of <newversion>).
|
||||||
5. `$ git merge --no-ff release-<newversion>`
|
5. `$ git checkout release`
|
||||||
6. `$ npm version <newversion>` (see [npm-version](https://docs.npmjs.com/cli/version) for valid values of <newversion>).
|
6. `$ git merge --no-ff release-<newversion>`
|
||||||
7. `$ git push && git push --tags`
|
7. `$ git push && git push --tags`
|
||||||
8. `$ git checkout develop`
|
8. `$ git checkout develop`
|
||||||
9. `$ git merge --no-ff release-<newversion>`
|
9. Create a release on GitHub. Make sure that you release from the `release` branch! You can do this in one of two ways:
|
||||||
10. Create a release on GitHub. You can do this in one of two ways:
|
|
||||||
1. (Preferred) Use the [`hub` command line tool](https://hub.github.com/). You can automate adding all commit messages since the last release with the following command:
|
1. (Preferred) Use the [`hub` command line tool](https://hub.github.com/). You can automate adding all commit messages since the last release with the following command:
|
||||||
```sh
|
```sh
|
||||||
$ hub release create -d -m "<newversion>" -m "$(git log `git describe --tags --abbrev=0 HEAD^`..HEAD --oneline)" <newversion>`
|
$ hub release create -d -m "<newversion>" -m "$(git log `git describe --tags --abbrev=0 HEAD^`..HEAD --oneline)" <newversion>`
|
||||||
```
|
```
|
||||||
Note that this creates a draft release, which you can then edit on GitHub. This allows you to create release notes from the list of commit messages, but then edit these notes as you wish.
|
Note that this creates a draft release, which you can then edit on GitHub. This allows you to create release notes from the list of commit messages, but then edit these notes as you wish.
|
||||||
2. [Draft a new release on Github](https://github.com/processing/p5.js-web-editor/releases/new).
|
2. [Draft a new release on Github](https://github.com/processing/p5.js-web-editor/releases/new).
|
||||||
|
10. `$ git merge --no-ff release-<newversion>`
|
||||||
|
|
||||||
Travis CI will automatically deploy the release to production, as well as push a production tagged Docker image to DockerHub.
|
Travis CI will automatically deploy the release to production, as well as push a production tagged Docker image to DockerHub.
|
||||||
|
|
||||||
|
|
2
package-lock.json
generated
2
package-lock.json
generated
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "p5.js-web-editor",
|
"name": "p5.js-web-editor",
|
||||||
"version": "0.0.1",
|
"version": "1.0.3",
|
||||||
"lockfileVersion": 1,
|
"lockfileVersion": 1,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "p5.js-web-editor",
|
"name": "p5.js-web-editor",
|
||||||
"version": "0.0.1",
|
"version": "1.0.3",
|
||||||
"description": "The web editor for p5.js.",
|
"description": "The web editor for p5.js.",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"clean": "rimraf dist",
|
"clean": "rimraf dist",
|
||||||
|
|
Loading…
Reference in a new issue