Skip to content

Commit a7ea03f

Browse files
author
Ives van Hoorne
committed
Rewrite handling of saving on forked sandboxes
1 parent 4efb1c9 commit a7ea03f

File tree

4 files changed

+99
-75
lines changed

4 files changed

+99
-75
lines changed

src/app/store/entities/sandboxes/actions/files.js

Lines changed: 76 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,22 @@
11
// @flow
2-
import { values } from 'lodash';
3-
42
import type { Module, Directory } from 'common/types';
53
import logError from 'app/utils/error';
64

75
import { createAPIActions, doRequest } from '../../../api/actions';
86
import moduleEntity from '../modules/entity';
97
import directoryEntity from '../directories/entity';
108
import directoryActions from '../directories/actions';
11-
import { modulesSelector } from '../modules/selectors';
12-
import { directoriesSelector } from '../directories/selectors';
9+
import { modulesSelector, singleModuleSelector } from '../modules/selectors';
10+
import {
11+
directoriesSelector,
12+
singleDirectorySelector,
13+
} from '../directories/selectors';
1314
import moduleActions from '../modules/actions';
1415
import { singleSandboxSelector } from '../selectors';
1516
import { normalizeResult } from '../../actions';
1617
import notificationActions from '../../../notifications/actions';
1718

18-
import {
19-
getEquivalentModule,
20-
getEquivalentDirectory,
21-
maybeForkSandbox,
22-
} from './fork';
19+
import { maybeForkSandbox } from './fork';
2320

2421
export const CREATE_MODULE_API_ACTIONS = createAPIActions(
2522
'SANDBOX',
@@ -103,17 +100,17 @@ const renameModule = (id: string, moduleId: string, title: string) => async (
103100
dispatch: Function,
104101
getState: Function,
105102
) => {
106-
let modules = modulesSelector(getState());
107-
const module = modules[moduleId];
103+
const module = singleModuleSelector(getState(), { id: moduleId });
108104
const sandboxId = await dispatch(maybeForkSandbox(id));
109-
const isForked = sandboxId !== id;
110105

111-
// Modules have updated after fork
112-
modules = modulesSelector(getState());
106+
// Get eventual new source id from forked sandbox
107+
const { sourceId } = singleSandboxSelector(getState(), { id: sandboxId });
113108

114-
const newModule = isForked
115-
? getEquivalentModule(module, values(modules)) || module
116-
: module;
109+
// Maybe get new module of forked sandbox
110+
const newModule = singleModuleSelector(getState(), {
111+
sourceId,
112+
shortid: module.shortid,
113+
});
117114
// Eager rename, just undo it when something goes wrong
118115
const oldTitle = module.title;
119116
dispatch(moduleActions.renameModule(newModule.id, title));
@@ -139,17 +136,15 @@ const renameDirectory = (
139136
directoryId: string,
140137
title: string,
141138
) => async (dispatch: Function, getState: Function) => {
142-
let directories = directoriesSelector(getState());
143-
const directory = directories[directoryId];
139+
const directory = singleDirectorySelector(getState(), { id: directoryId });
144140
const sandboxId = await dispatch(maybeForkSandbox(id));
145-
const isForked = id !== sandboxId;
146-
147-
// Directories have updated after fork
148-
directories = directoriesSelector(getState());
149141

150-
const newDirectory = isForked
151-
? getEquivalentDirectory(directory, values(directories)) || directory
152-
: directory;
142+
const { sourceId } = singleSandboxSelector(getState(), { id: sandboxId });
143+
// Get the new directory in case sandbox is forked
144+
const newDirectory = singleDirectorySelector(getState(), {
145+
sourceId,
146+
shortid: directory.shortid,
147+
});
153148
// Eager rename, just undo it when something goes wrong
154149
const oldTitle = directory.title;
155150
dispatch(directoryActions.renameDirectory(newDirectory.id, title));
@@ -175,17 +170,17 @@ const moveModuleToDirectory = (
175170
moduleId: string,
176171
directoryShortid: string,
177172
) => async (dispatch: Function, getState: Function) => {
178-
let modules = modulesSelector(getState());
179-
const module = modules[moduleId];
173+
const module = singleModuleSelector(getState(), { id: moduleId });
180174
const sandboxId = await dispatch(maybeForkSandbox(id));
181-
const isForked = sandboxId !== id;
182175

183-
// Modules have updated after fork
184-
modules = modulesSelector(getState());
176+
// Get eventual new source id from forked sandbox
177+
const { sourceId } = singleSandboxSelector(getState(), { id: sandboxId });
185178

186-
const newModule = isForked
187-
? getEquivalentModule(module, values(modules)) || module
188-
: module;
179+
// Maybe get new module of forked sandbox
180+
const newModule = singleModuleSelector(getState(), {
181+
sourceId,
182+
shortid: module.shortid,
183+
});
189184
// Eager move it
190185
const olddirectoryShortid = module.directoryShortid;
191186
dispatch(moduleActions.moveModule(newModule.id, directoryShortid));
@@ -211,17 +206,15 @@ const moveDirectoryToDirectory = (
211206
directoryId: string,
212207
parentId: string,
213208
) => async (dispatch: Function, getState: Function) => {
214-
let directories = directoriesSelector(getState());
215-
const directory = directories[directoryId];
209+
const directory = singleDirectorySelector(getState(), { id: directoryId });
216210
const sandboxId = await dispatch(maybeForkSandbox(id));
217-
const isForked = id !== sandboxId;
218211

219-
// Directories have updated after fork
220-
directories = directoriesSelector(getState());
221-
222-
const newDirectory = isForked
223-
? getEquivalentDirectory(directory, values(directories)) || directory
224-
: directory;
212+
const { sourceId } = singleSandboxSelector(getState(), { id: sandboxId });
213+
// Get the new directory in case sandbox is forked
214+
const newDirectory = singleDirectorySelector(getState(), {
215+
sourceId,
216+
shortid: directory.shortid,
217+
});
225218
// Eager move it
226219
const oldDirectoryShortid = directory.directoryShortid;
227220
dispatch(directoryActions.moveDirectory(newDirectory.id, parentId));
@@ -248,17 +241,17 @@ const deleteModule = (id: string, moduleId: string) => async (
248241
dispatch: Function,
249242
getState: Function,
250243
) => {
251-
let modules = modulesSelector(getState());
252-
const module = modules[moduleId];
244+
const module = singleModuleSelector(getState(), { id: moduleId });
253245
const sandboxId = await dispatch(maybeForkSandbox(id));
254-
const isForked = sandboxId !== id;
255246

256-
// Modules have updated after fork
257-
modules = modulesSelector(getState());
247+
// Get eventual new source id from forked sandbox
248+
const { sourceId } = singleSandboxSelector(getState(), { id: sandboxId });
258249

259-
const newModule = isForked
260-
? getEquivalentModule(module, values(modules)) || module
261-
: module;
250+
// Maybe get new module of forked sandbox
251+
const newModule = singleModuleSelector(getState(), {
252+
sourceId,
253+
shortid: module.shortid,
254+
});
262255
// Eager remove it
263256
dispatch(removeModuleFromSandbox(sandboxId, newModule.id));
264257

@@ -282,17 +275,15 @@ const deleteDirectory = (id: string, directoryId: string) => async (
282275
dispatch: Function,
283276
getState: Function,
284277
) => {
285-
let directories = directoriesSelector(getState());
286-
const directory = directories[directoryId];
278+
const directory = singleDirectorySelector(getState(), { id: directoryId });
287279
const sandboxId = await dispatch(maybeForkSandbox(id));
288-
const isForked = id !== sandboxId;
289-
290-
// Directories have updated after fork
291-
directories = directoriesSelector(getState());
292280

293-
const newDirectory = isForked
294-
? getEquivalentDirectory(directory, values(directories)) || directory
295-
: directory;
281+
const { sourceId } = singleSandboxSelector(getState(), { id: sandboxId });
282+
// Get the new directory in case sandbox is forked
283+
const newDirectory = singleDirectorySelector(getState(), {
284+
sourceId,
285+
shortid: directory.shortid,
286+
});
296287

297288
dispatch(removeDirectoryFromSandbox(sandboxId, newDirectory.id));
298289

@@ -378,17 +369,17 @@ const saveModuleCode = (id: string, moduleId: string) => async (
378369
dispatch: Function,
379370
getState: Function,
380371
) => {
381-
let modules = modulesSelector(getState());
382-
const module = modules[moduleId];
372+
const module = singleModuleSelector(getState(), { id: moduleId });
383373
const sandboxId = await dispatch(maybeForkSandbox(id));
384-
const isForked = sandboxId !== id;
385374

386-
// Modules have updated after fork
387-
modules = modulesSelector(getState());
375+
// Get eventual new source id from forked sandbox
376+
const { sourceId } = singleSandboxSelector(getState(), { id: sandboxId });
388377

389-
const newModule = isForked
390-
? getEquivalentModule(module, values(modules)) || module
391-
: module;
378+
// Maybe get new module of forked sandbox
379+
const newModule = singleModuleSelector(getState(), {
380+
sourceId,
381+
shortid: module.shortid,
382+
});
392383
dispatch(moduleActions.setCode(newModule.id, module.code));
393384

394385
try {
@@ -430,6 +421,7 @@ const saveModuleCode = (id: string, moduleId: string) => async (
430421
e.message = `Could not save module: ${e.message}`;
431422
logError(e);
432423
}
424+
return false;
433425
};
434426
/**
435427
* Updates all modules in a sandbox at once (only the code)
@@ -438,14 +430,18 @@ const massUpdateModules = (id: string) => async (
438430
dispatch: Function,
439431
getState: Function,
440432
) => {
441-
const sandboxId = await dispatch(maybeForkSandbox(id));
442-
443-
const sandbox = singleSandboxSelector(getState(), { id: sandboxId });
433+
// First get the modules that changed, that way we make sure that we don't get
434+
// the non-updated modules from the forked sandbox to send. The server handles
435+
// everything by shortid, which means that we can send the old modules to the
436+
// server since shortids are preserved between forks
444437
const modules = modulesSelector(getState());
438+
const sandbox = singleSandboxSelector(getState(), { id });
445439

446440
const modulesInSandbox = sandbox.modules.map(mid => modules[mid]);
447441
const modulesNotInSyncInSandbox = modulesInSandbox.filter(m => m.isNotSynced);
448442

443+
const sandboxId = await dispatch(maybeForkSandbox(id));
444+
449445
try {
450446
await dispatch(
451447
doRequest(
@@ -459,10 +455,15 @@ const massUpdateModules = (id: string) => async (
459455
},
460456
),
461457
);
462-
// TODO validate return values from server
463-
modulesNotInSyncInSandbox.forEach(m =>
464-
dispatch(moduleActions.setModuleSynced(m.id)),
465-
);
458+
const newSandbox = singleSandboxSelector(getState(), { id: sandboxId });
459+
modulesNotInSyncInSandbox.forEach(m => {
460+
const newModule = singleModuleSelector(getState(), {
461+
shortid: m.shortid,
462+
sourceId: newSandbox.sourceId,
463+
});
464+
// Now we get the equivalent modules of the forked sandbox, if the sandbox is forked
465+
dispatch(moduleActions.setModuleSynced(newModule.id));
466+
});
466467
} catch (e) {
467468
dispatch(
468469
notificationActions.addNotification(

src/app/store/entities/sandboxes/directories/selectors.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { createSelector } from 'reselect';
2+
import { values } from 'lodash';
23

34
export const directoriesSelector = state => state.entities.directories;
45

@@ -7,3 +8,12 @@ export const directoriesFromSandboxSelector = createSelector(
78
(_, props) => props.sandbox.directories,
89
(directories, ids) => ids.map(id => directories[id]),
910
);
11+
12+
export const singleDirectorySelector = createSelector(
13+
directoriesSelector,
14+
(_, { sourceId, shortid, id }) => ({ id, sourceId, shortid }),
15+
(directories, { sourceId, id, shortid }) =>
16+
values(directories).find(
17+
d => d.id === id || (d.sourceId === sourceId && d.shortid === shortid),
18+
),
19+
);

src/app/store/entities/sandboxes/modules/selectors.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
// @flow
22
import type { Directory, Module } from 'common/types';
33
import { createSelector } from 'reselect';
4+
import { values } from 'lodash';
45

56
export const modulesSelector = state => state.entities.modules;
67

@@ -77,3 +78,12 @@ export const modulesFromSandboxNotSavedSelector = createSelector(
7778
modulesFromSandboxSelector,
7879
modules => modules.some(m => m.isNotSynced),
7980
);
81+
82+
export const singleModuleSelector = createSelector(
83+
modulesSelector,
84+
(_, { sourceId, shortid, id }) => ({ id, sourceId, shortid }),
85+
(modules, { sourceId, id, shortid }) =>
86+
values(modules).find(
87+
m => m.id === id || (m.sourceId === sourceId && m.shortid === shortid),
88+
),
89+
);

src/common/types.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,15 @@ export type Module = {
1919
shortid: string,
2020
directoryShortid: ?string,
2121
isNotSynced: boolean,
22+
sourceId: string,
2223
};
2324

2425
export type Directory = {
2526
id: string,
2627
title: string,
2728
directoryShortid: ?string,
2829
shortid: string,
30+
sourceId: string,
2931
};
3032

3133
export type Badge = {
@@ -122,6 +124,7 @@ export type Sandbox = {
122124
errors: Array<ModuleError>,
123125
git: ?GitInfo,
124126
tags: Array<string>,
127+
sourceId: string, // This is the source it's assigned to, a source contains all dependencies, modules and directories
125128
};
126129

127130
export type Preferences = {

0 commit comments

Comments
 (0)