{ this.node = node; }} + ref={(node) => { + this.node = node; + }} className="overlay__body" >

{title}

{actions} -
@@ -112,7 +115,7 @@ Overlay.defaultProps = { closeOverlay: null, ariaLabel: 'modal', previousPath: '/', - isFixedHeight: false, + isFixedHeight: false }; export default withTranslation()(Overlay); diff --git a/client/modules/App/components/ThemeProvider.jsx b/client/modules/App/components/ThemeProvider.jsx index eb6dcc9be5..a168d856d9 100644 --- a/client/modules/App/components/ThemeProvider.jsx +++ b/client/modules/App/components/ThemeProvider.jsx @@ -6,21 +6,18 @@ import { ThemeProvider } from 'styled-components'; import theme, { Theme } from '../../../theme'; const Provider = ({ children, currentTheme }) => ( - - {children} - + {children} ); Provider.propTypes = { children: PropTypes.node.isRequired, - currentTheme: PropTypes.oneOf(Object.keys(Theme)).isRequired, + currentTheme: PropTypes.oneOf(Object.keys(Theme)).isRequired }; function mapStateToProps(state) { return { - currentTheme: state.preferences.theme, + currentTheme: state.preferences.theme }; } - export default connect(mapStateToProps)(Provider); diff --git a/client/modules/IDE/actions/assets.js b/client/modules/IDE/actions/assets.js index 79df42850e..8c7a046121 100644 --- a/client/modules/IDE/actions/assets.js +++ b/client/modules/IDE/actions/assets.js @@ -13,7 +13,8 @@ function setAssets(assets, totalSize) { export function getAssets() { return (dispatch) => { dispatch(startLoader()); - apiClient.get('/S3/objects') + apiClient + .get('/S3/objects') .then((response) => { dispatch(setAssets(response.data.assets, response.data.totalSize)); dispatch(stopLoader()); @@ -36,7 +37,8 @@ export function deleteAsset(assetKey) { export function deleteAssetRequest(assetKey) { return (dispatch) => { - apiClient.delete(`/S3/${assetKey}`) + apiClient + .delete(`/S3/${assetKey}`) .then((response) => { dispatch(deleteAsset(assetKey)); }) diff --git a/client/modules/IDE/actions/collections.js b/client/modules/IDE/actions/collections.js index 1d2a8e2b83..69da0f23ba 100644 --- a/client/modules/IDE/actions/collections.js +++ b/client/modules/IDE/actions/collections.js @@ -4,7 +4,6 @@ import * as ActionTypes from '../../../constants'; import { startLoader, stopLoader } from './loader'; import { setToastText, showToast } from './toast'; - const TOAST_DISPLAY_TIME_MS = 1500; // eslint-disable-next-line @@ -18,7 +17,8 @@ export function getCollections(username) { url = '/collections'; } console.log(url); - apiClient.get(url) + apiClient + .get(url) .then((response) => { dispatch({ type: ActionTypes.SET_COLLECTIONS, @@ -41,7 +41,8 @@ export function createCollection(collection) { return (dispatch) => { dispatch(startLoader()); const url = '/collections'; - return apiClient.post(url, collection) + return apiClient + .post(url, collection) .then((response) => { dispatch({ type: ActionTypes.CREATE_COLLECTION @@ -73,7 +74,8 @@ export function addToCollection(collectionId, projectId) { return (dispatch) => { dispatch(startLoader()); const url = `/collections/${collectionId}/${projectId}`; - return apiClient.post(url) + return apiClient + .post(url) .then((response) => { dispatch({ type: ActionTypes.ADD_TO_COLLECTION, @@ -105,7 +107,8 @@ export function removeFromCollection(collectionId, projectId) { return (dispatch) => { dispatch(startLoader()); const url = `/collections/${collectionId}/${projectId}`; - return apiClient.delete(url) + return apiClient + .delete(url) .then((response) => { dispatch({ type: ActionTypes.REMOVE_FROM_COLLECTION, @@ -136,7 +139,8 @@ export function removeFromCollection(collectionId, projectId) { export function editCollection(collectionId, { name, description }) { return (dispatch) => { const url = `/collections/${collectionId}`; - return apiClient.patch(url, { name, description }) + return apiClient + .patch(url, { name, description }) .then((response) => { dispatch({ type: ActionTypes.EDIT_COLLECTION, @@ -159,12 +163,13 @@ export function editCollection(collectionId, { name, description }) { export function deleteCollection(collectionId) { return (dispatch) => { const url = `/collections/${collectionId}`; - return apiClient.delete(url) + return apiClient + .delete(url) .then((response) => { dispatch({ type: ActionTypes.DELETE_COLLECTION, payload: response.data, - collectionId, + collectionId }); return response.data; }) diff --git a/client/modules/IDE/actions/files.js b/client/modules/IDE/actions/files.js index faf3e18134..68ed5a5329 100644 --- a/client/modules/IDE/actions/files.js +++ b/client/modules/IDE/actions/files.js @@ -2,23 +2,31 @@ import objectID from 'bson-objectid'; import blobUtil from 'blob-util'; import apiClient from '../../../utils/apiClient'; import * as ActionTypes from '../../../constants'; -import { setUnsavedChanges, closeNewFolderModal, closeNewFileModal } from './ide'; +import { + setUnsavedChanges, + closeNewFolderModal, + closeNewFileModal +} from './ide'; import { setProjectSavedTime } from './project'; import { createError } from './ide'; - function appendToFilename(filename, string) { const dotIndex = filename.lastIndexOf('.'); if (dotIndex === -1) return filename + string; - return filename.substring(0, dotIndex) + string + filename.substring(dotIndex); + return ( + filename.substring(0, dotIndex) + string + filename.substring(dotIndex) + ); } function createUniqueName(name, parentId, files) { - const siblingFiles = files.find(file => file.id === parentId) - .children.map(childFileId => files.find(file => file.id === childFileId)); + const siblingFiles = files + .find((file) => file.id === parentId) + .children.map((childFileId) => + files.find((file) => file.id === childFileId) + ); let testName = name; let index = 1; - let existingName = siblingFiles.find(file => name === file.name); + let existingName = siblingFiles.find((file) => name === file.name); while (existingName) { testName = appendToFilename(name, `-${index}`); @@ -53,8 +61,9 @@ export function submitFile(formProps, files, parentId, projectId) { parentId, children: [] }; - return apiClient.post(`/projects/${projectId}/files`, postParams) - .then(response => ({ + return apiClient + .post(`/projects/${projectId}/files`, postParams) + .then((response) => ({ file: response.data.updatedFile, updatedAt: response.data.project.updatedAt })); @@ -80,18 +89,20 @@ export function handleCreateFile(formProps) { const { parentId } = state.ide; const projectId = state.project.id; return new Promise((resolve) => { - submitFile(formProps, files, parentId, projectId).then((response) => { - const { file, updatedAt } = response; - dispatch(createFile(file, parentId)); - if (updatedAt) dispatch(setProjectSavedTime(updatedAt)); - dispatch(closeNewFileModal()); - dispatch(setUnsavedChanges(true)); - resolve(); - }).catch((error) => { - const { response } = error; - dispatch(createError(response.data)); - resolve({ error }); - }); + submitFile(formProps, files, parentId, projectId) + .then((response) => { + const { file, updatedAt } = response; + dispatch(createFile(file, parentId)); + if (updatedAt) dispatch(setProjectSavedTime(updatedAt)); + dispatch(closeNewFileModal()); + dispatch(setUnsavedChanges(true)); + resolve(); + }) + .catch((error) => { + const { response } = error; + dispatch(createError(response.data)); + resolve({ error }); + }); }); }; } @@ -105,8 +116,9 @@ export function submitFolder(formProps, files, parentId, projectId) { parentId, fileType: 'folder' }; - return apiClient.post(`/projects/${projectId}/files`, postParams) - .then(response => ({ + return apiClient + .post(`/projects/${projectId}/files`, postParams) + .then((response) => ({ file: response.data.updatedFile, updatedAt: response.data.project.updatedAt })); @@ -134,18 +146,20 @@ export function handleCreateFolder(formProps) { const { parentId } = state.ide; const projectId = state.project.id; return new Promise((resolve) => { - submitFolder(formProps, files, parentId, projectId).then((response) => { - const { file, updatedAt } = response; - dispatch(createFile(file, parentId)); - if (updatedAt) dispatch(setProjectSavedTime(updatedAt)); - dispatch(closeNewFolderModal()); - dispatch(setUnsavedChanges(true)); - resolve(); - }).catch((error) => { - const { response } = error; - dispatch(createError(response.data)); - resolve({ error }); - }); + submitFolder(formProps, files, parentId, projectId) + .then((response) => { + const { file, updatedAt } = response; + dispatch(createFile(file, parentId)); + if (updatedAt) dispatch(setProjectSavedTime(updatedAt)); + dispatch(closeNewFolderModal()); + dispatch(setUnsavedChanges(true)); + resolve(); + }) + .catch((error) => { + const { response } = error; + dispatch(createError(response.data)); + resolve({ error }); + }); }); }; } @@ -170,7 +184,8 @@ export function deleteFile(id, parentId) { parentId } }; - apiClient.delete(`/projects/${state.project.id}/files/${id}`, deleteConfig) + apiClient + .delete(`/projects/${state.project.id}/files/${id}`, deleteConfig) .then((response) => { dispatch(setProjectSavedTime(response.data.project.updatedAt)); dispatch({ diff --git a/client/modules/IDE/actions/ide.js b/client/modules/IDE/actions/ide.js index e18d9d747c..19fc12d471 100644 --- a/client/modules/IDE/actions/ide.js +++ b/client/modules/IDE/actions/ide.js @@ -54,7 +54,9 @@ export function setSelectedFile(fileId) { export function resetSelectedFile(previousId) { return (dispatch, getState) => { const state = getState(); - const newId = state.files.find(file => file.name !== 'root' && file.id !== previousId).id; + const newId = state.files.find( + (file) => file.name !== 'root' && file.id !== previousId + ).id; dispatch({ type: ActionTypes.SET_SELECTED_FILE, selectedFile: newId @@ -215,7 +217,7 @@ export function resetInfiniteLoops() { export function justOpenedProject() { return { - type: ActionTypes.JUST_OPENED_PROJECT, + type: ActionTypes.JUST_OPENED_PROJECT }; } diff --git a/client/modules/IDE/actions/preferences.js b/client/modules/IDE/actions/preferences.js index 96f29c6739..68a4a23111 100644 --- a/client/modules/IDE/actions/preferences.js +++ b/client/modules/IDE/actions/preferences.js @@ -3,9 +3,9 @@ import apiClient from '../../../utils/apiClient'; import * as ActionTypes from '../../../constants'; function updatePreferences(formParams, dispatch) { - apiClient.put('/preferences', formParams) - .then(() => { - }) + apiClient + .put('/preferences', formParams) + .then(() => {}) .catch((error) => { const { response } = error; dispatch({ @@ -247,4 +247,3 @@ export function setLanguage(value, { persistPreference = true } = {}) { } }; } - diff --git a/client/modules/IDE/actions/project.js b/client/modules/IDE/actions/project.js index eacb4194b7..e2931f3ff4 100644 --- a/client/modules/IDE/actions/project.js +++ b/client/modules/IDE/actions/project.js @@ -54,7 +54,8 @@ export function setNewProject(project) { export function getProject(id, username) { return (dispatch, getState) => { dispatch(justOpenedProject()); - apiClient.get(`/${username}/projects/${id}`) + apiClient + .get(`/${username}/projects/${id}`) .then((response) => { dispatch(setProject(response.data)); dispatch(setUnsavedChanges(false)); @@ -72,7 +73,7 @@ export function getProject(id, username) { export function persistState() { return (dispatch, getState) => { dispatch({ - type: ActionTypes.PERSIST_STATE, + type: ActionTypes.PERSIST_STATE }); const state = getState(); saveState(state); @@ -82,7 +83,7 @@ export function persistState() { export function clearPersistedState() { return (dispatch) => { dispatch({ - type: ActionTypes.CLEAR_PERSISTED_STATE, + type: ActionTypes.CLEAR_PERSISTED_STATE }); clearState(); }; @@ -110,8 +111,12 @@ export function projectSaveSuccess() { function getSynchedProject(currentState, responseProject) { let hasChanges = false; const synchedProject = Object.assign({}, responseProject); - const currentFiles = currentState.files.map(({ name, children, content }) => ({ name, children, content })); - const responseFiles = responseProject.files.map(({ name, children, content }) => ({ name, children, content })); + const currentFiles = currentState.files.map( + ({ name, children, content }) => ({ name, children, content }) + ); + const responseFiles = responseProject.files.map( + ({ name, children, content }) => ({ name, children, content }) + ); if (!isEqual(currentFiles, responseFiles)) { synchedProject.files = currentState.files; hasChanges = true; @@ -126,29 +131,43 @@ function getSynchedProject(currentState, responseProject) { }; } -export function saveProject(selectedFile = null, autosave = false, mobile = false) { +export function saveProject( + selectedFile = null, + autosave = false, + mobile = false +) { return (dispatch, getState) => { const state = getState(); if (state.project.isSaving) { return Promise.resolve(); } dispatch(startSavingProject()); - if (state.user.id && state.project.owner && state.project.owner.id !== state.user.id) { + if ( + state.user.id && + state.project.owner && + state.project.owner.id !== state.user.id + ) { return Promise.reject(); } const formParams = Object.assign({}, state.project); formParams.files = [...state.files]; if (selectedFile) { - const fileToUpdate = formParams.files.find(file => file.id === selectedFile.id); + const fileToUpdate = formParams.files.find( + (file) => file.id === selectedFile.id + ); fileToUpdate.content = selectedFile.content; } if (state.project.id) { - return apiClient.put(`/projects/${state.project.id}`, formParams) + return apiClient + .put(`/projects/${state.project.id}`, formParams) .then((response) => { dispatch(endSavingProject()); dispatch(setUnsavedChanges(false)); - const { hasChanges, synchedProject } = getSynchedProject(getState(), response.data); + const { hasChanges, synchedProject } = getSynchedProject( + getState(), + response.data + ); if (hasChanges) { dispatch(setUnsavedChanges(true)); } @@ -158,7 +177,10 @@ export function saveProject(selectedFile = null, autosave = false, mobile = fals if (state.ide.justOpenedProject && state.preferences.autosave) { dispatch(showToast(5500)); dispatch(setToastText('Toast.SketchSaved')); - setTimeout(() => dispatch(setToastText('Toast.AutosaveEnabled')), 1500); + setTimeout( + () => dispatch(setToastText('Toast.AutosaveEnabled')), + 1500 + ); dispatch(resetJustOpenedProject()); } else { dispatch(showToast(1500)); @@ -181,14 +203,20 @@ export function saveProject(selectedFile = null, autosave = false, mobile = fals }); } - return apiClient.post('/projects', formParams) + return apiClient + .post('/projects', formParams) .then((response) => { dispatch(endSavingProject()); - const { hasChanges, synchedProject } = getSynchedProject(getState(), response.data); + const { hasChanges, synchedProject } = getSynchedProject( + getState(), + response.data + ); dispatch(setNewProject(synchedProject)); dispatch(setUnsavedChanges(false)); - browserHistory.push(`/${response.data.user.username}/sketches/${response.data.id}`); + browserHistory.push( + `/${response.data.user.username}/sketches/${response.data.id}` + ); if (hasChanges) { dispatch(setUnsavedChanges(true)); @@ -199,7 +227,10 @@ export function saveProject(selectedFile = null, autosave = false, mobile = fals if (state.preferences.autosave) { dispatch(showToast(5500)); dispatch(setToastText('Toast.SketchSaved')); - setTimeout(() => dispatch(setToastText('Toast.AutosaveEnabled')), 1500); + setTimeout( + () => dispatch(setToastText('Toast.AutosaveEnabled')), + 1500 + ); dispatch(resetJustOpenedProject()); } else { dispatch(showToast(1500)); @@ -248,7 +279,7 @@ export function newProject() { function generateNewIdsForChildren(file, files) { const newChildren = []; file.children.forEach((childId) => { - const child = files.find(childFile => childFile.id === childId); + const child = files.find((childFile) => childFile.id === childId); const newId = objectID().toHexString(); child.id = newId; child._id = newId; @@ -264,45 +295,59 @@ export function cloneProject(project) { const state = getState(); const files = project ? project.files : state.files; const projectName = project ? project.name : state.project.name; - const newFiles = files.map(file => ({ ...file })); + const newFiles = files.map((file) => ({ ...file })); // generate new IDS for all files - const rootFile = newFiles.find(file => file.name === 'root'); + const rootFile = newFiles.find((file) => file.name === 'root'); const newRootFileId = objectID().toHexString(); rootFile.id = newRootFileId; rootFile._id = newRootFileId; generateNewIdsForChildren(rootFile, newFiles); // duplicate all files hosted on S3 - each(newFiles, (file, callback) => { - if (file.url && (file.url.includes(S3_BUCKET_URL_BASE) || file.url.includes(S3_BUCKET))) { - const formParams = { - url: file.url - }; - apiClient.post('/S3/copy', formParams) - .then((response) => { + each( + newFiles, + (file, callback) => { + if ( + file.url && + (file.url.includes(S3_BUCKET_URL_BASE) || + file.url.includes(S3_BUCKET)) + ) { + const formParams = { + url: file.url + }; + apiClient.post('/S3/copy', formParams).then((response) => { file.url = response.data.url; callback(null); }); - } else { - callback(null); - } - }, (err) => { - // if not errors in duplicating the files on S3, then duplicate it - const formParams = Object.assign({}, { name: `${projectName} copy` }, { files: newFiles }); - apiClient.post('/projects', formParams) - .then((response) => { - browserHistory.push(`/${response.data.user.username}/sketches/${response.data.id}`); - dispatch(setNewProject(response.data)); - }) - .catch((error) => { - const { response } = error; - dispatch({ - type: ActionTypes.PROJECT_SAVE_FAIL, - error: response.data + } else { + callback(null); + } + }, + (err) => { + // if not errors in duplicating the files on S3, then duplicate it + const formParams = Object.assign( + {}, + { name: `${projectName} copy` }, + { files: newFiles } + ); + apiClient + .post('/projects', formParams) + .then((response) => { + browserHistory.push( + `/${response.data.user.username}/sketches/${response.data.id}` + ); + dispatch(setNewProject(response.data)); + }) + .catch((error) => { + const { response } = error; + dispatch({ + type: ActionTypes.PROJECT_SAVE_FAIL, + error: response.data + }); }); - }); - }); + } + ); }; } @@ -328,7 +373,8 @@ export function setProjectSavedTime(updatedAt) { export function changeProjectName(id, newName) { return (dispatch, getState) => { const state = getState(); - apiClient.put(`/projects/${id}`, { name: newName }) + apiClient + .put(`/projects/${id}`, { name: newName }) .then((response) => { if (response.status === 200) { dispatch({ @@ -355,7 +401,8 @@ export function changeProjectName(id, newName) { export function deleteProject(id) { return (dispatch, getState) => { - apiClient.delete(`/projects/${id}`) + apiClient + .delete(`/projects/${id}`) .then(() => { const state = getState(); if (id === state.project.id) { diff --git a/client/modules/IDE/actions/projects.js b/client/modules/IDE/actions/projects.js index d41747b5fb..fabda631a0 100644 --- a/client/modules/IDE/actions/projects.js +++ b/client/modules/IDE/actions/projects.js @@ -12,7 +12,8 @@ export function getProjects(username) { } else { url = '/projects'; } - apiClient.get(url) + apiClient + .get(url) .then((response) => { dispatch({ type: ActionTypes.SET_PROJECTS, diff --git a/client/modules/IDE/actions/sorting.js b/client/modules/IDE/actions/sorting.js index f28cf325f1..b9aa0354cb 100644 --- a/client/modules/IDE/actions/sorting.js +++ b/client/modules/IDE/actions/sorting.js @@ -30,7 +30,7 @@ export function setSearchTerm(scope, searchTerm) { return { type: ActionTypes.SET_SEARCH_TERM, query: searchTerm, - scope, + scope }; } diff --git a/client/modules/IDE/actions/uploader.js b/client/modules/IDE/actions/uploader.js index 24dcbfcf42..c8bb3aca6a 100644 --- a/client/modules/IDE/actions/uploader.js +++ b/client/modules/IDE/actions/uploader.js @@ -3,8 +3,11 @@ import getConfig from '../../../utils/getConfig'; import { createFile } from './files'; import { TEXT_FILE_REGEX } from '../../../../server/utils/fileUtils'; -const s3BucketHttps = getConfig('S3_BUCKET_URL_BASE') || - `https://s3-${getConfig('AWS_REGION')}.amazonaws.com/${getConfig('S3_BUCKET')}/`; +const s3BucketHttps = + getConfig('S3_BUCKET_URL_BASE') || + `https://s3-${getConfig('AWS_REGION')}.amazonaws.com/${getConfig( + 'S3_BUCKET' + )}/`; const MAX_LOCAL_FILE_SIZE = 80000; // bytes, aka 80 KB function localIntercept(file, options = {}) { @@ -43,27 +46,29 @@ export function dropzoneAcceptCallback(userId, file, done) { return () => { // if a user would want to edit this file as text, local interceptor if (file.name.match(TEXT_FILE_REGEX) && file.size < MAX_LOCAL_FILE_SIZE) { - localIntercept(file).then((result) => { + localIntercept(file) + .then((result) => { file.content = result; // eslint-disable-line - done('Uploading plaintext file locally.'); - file.previewElement.classList.remove('dz-error'); - file.previewElement.classList.add('dz-success'); - file.previewElement.classList.add('dz-processing'); - file.previewElement.querySelector('.dz-upload').style.width = '100%'; - }) + done('Uploading plaintext file locally.'); + file.previewElement.classList.remove('dz-error'); + file.previewElement.classList.add('dz-success'); + file.previewElement.classList.add('dz-processing'); + file.previewElement.querySelector('.dz-upload').style.width = '100%'; + }) .catch((result) => { done(`Failed to download file ${file.name}: ${result}`); console.warn(file); }); } else { file.postData = []; // eslint-disable-line - apiClient.post('/S3/sign', { - name: file.name, - type: file.type, - size: file.size, - userId - // _csrf: document.getElementById('__createPostToken').value - }) + apiClient + .post('/S3/sign', { + name: file.name, + type: file.type, + size: file.size, + userId + // _csrf: document.getElementById('__createPostToken').value + }) .then((response) => { file.custom_status = 'ready'; // eslint-disable-line file.postData = response.data; // eslint-disable-line @@ -74,7 +79,11 @@ export function dropzoneAcceptCallback(userId, file, done) { .catch((error) => { const { response } = error; file.custom_status = 'rejected'; // eslint-disable-line - if (response.data && response.data.responseText && response.data.responseText.message) { + if ( + response.data && + response.data.responseText && + response.data.responseText.message + ) { done(response.data.responseText.message); } done('Error: Reached upload limit.'); @@ -95,7 +104,10 @@ export function dropzoneSendingCallback(file, xhr, formData) { export function dropzoneCompleteCallback(file) { return (dispatch, getState) => { // eslint-disable-line - if ((!file.name.match(TEXT_FILE_REGEX) || file.size >= MAX_LOCAL_FILE_SIZE) && file.status !== 'error') { + if ( + (!file.name.match(TEXT_FILE_REGEX) || file.size >= MAX_LOCAL_FILE_SIZE) && + file.status !== 'error' + ) { let inputHidden = ' - +