diff --git a/src/components/modals/WorkspaceManagementModal.vue b/src/components/modals/WorkspaceManagementModal.vue
index 43356c35..2f5a2df7 100644
--- a/src/components/modals/WorkspaceManagementModal.vue
+++ b/src/components/modals/WorkspaceManagementModal.vue
@@ -51,7 +51,7 @@
- ProTip: Workspaces are accessible offline after their first use.
+ ProTip: A workspace is accessible offline once it has been opened for the first time.
diff --git a/src/components/modals/common/ModalInner.vue b/src/components/modals/common/ModalInner.vue
index 89bd9533..e54bfe6e 100644
--- a/src/components/modals/common/ModalInner.vue
+++ b/src/components/modals/common/ModalInner.vue
@@ -51,11 +51,11 @@ export default {
.modal__close-button {
position: absolute;
- top: 7px;
- right: 7px;
+ top: 8px;
+ right: 8px;
color: rgba(0, 0, 0, 0.5);
- width: 30px;
- height: 30px;
+ width: 32px;
+ height: 32px;
padding: 2px;
&:active,
diff --git a/src/services/providers/githubWorkspaceProvider.js b/src/services/providers/githubWorkspaceProvider.js
index 5d73c524..0eeef84b 100644
--- a/src/services/providers/githubWorkspaceProvider.js
+++ b/src/services/providers/githubWorkspaceProvider.js
@@ -144,11 +144,11 @@ export default new Provider({
let itemId = idsByPath[path];
if (!itemId) {
const existingItemId = itemIdsByGitPath[path];
- // We can replace the item only if it was already synced
if (existingItemId
- && (syncDataByPath[path]
- // Content may have already be synced
- || (isFile && syncDataByPath[`/${path}`]))
+ // Reuse a file ID only if it has already been synced
+ && (!isFile || syncDataByPath[path]
+ // Content may have already been synced
+ || syncDataByPath[`/${path}`])
) {
itemId = existingItemId;
} else {
@@ -332,7 +332,7 @@ export default new Provider({
// Files and folders are not in git, only contents
if (item.type === 'file' || item.type === 'folder') {
- return syncData;
+ return { syncData };
}
// locations are stored as paths, so we upload an empty file
@@ -346,9 +346,7 @@ export default new Provider({
});
// Return sync data to save
- return {
- syncData,
- };
+ return { syncData };
},
async removeWorkspaceItem({ syncData }) {
if (treeShaMap[syncData.id]) {
diff --git a/src/services/syncSvc.js b/src/services/syncSvc.js
index b3f4bd07..88dcab87 100644
--- a/src/services/syncSvc.js
+++ b/src/services/syncSvc.js
@@ -649,19 +649,22 @@ const syncWorkspace = async (skipContents = false) => {
};
const syncDataByItemId = store.getters['data/syncDataByItemId'];
+ const isGit = !!store.getters['workspace/currentWorkspaceIsGit'];
const [changedItem, syncDataToUpdate] = utils.someResult(
Object.entries(storeItemMap),
([id, item]) => {
const syncData = syncDataByItemId[id];
- if ((!syncData || syncData.hash !== item.hash)
- // Add file/folder if parent has been added
- && (!storeItemMap[item.parentId] || syncDataByItemId[item.parentId])
- // Add file if content has been added
- && (item.type !== 'file' || syncDataByItemId[`${id}/content`])
+ if ((syncData && syncData.hash === item.hash)
+ // Add file/folder only if parent folder has been added
+ || (!isGit && storeItemMap[item.parentId] && !syncDataByItemId[item.parentId])
+ // Don't create folder if it's a git workspace
+ || (isGit && item.type === 'folder')
+ // Add file only if content has been added
+ || (item.type === 'file' && !syncDataByItemId[`${id}/content`])
) {
- return [item, syncData];
+ return null;
}
- return null;
+ return [item, syncData];
},
) || [];
@@ -695,16 +698,15 @@ const syncWorkspace = async (skipContents = false) => {
const syncDataToRemove = utils.deepCopy(utils.someResult(
Object.values(syncDataById),
(syncData) => {
- if (!getItem(syncData)
+ if (getItem(syncData)
// We don't want to delete data items, especially on first sync
- && syncData.type !== 'data'
+ || syncData.type === 'data'
// Remove content only if file has been removed
- && (syncData.type !== 'content'
- || !getFileItem(syncData))
+ || (syncData.type === 'content' && getFileItem(syncData))
) {
- return syncData;
+ return null;
}
- return null;
+ return syncData;
},
));
@@ -714,9 +716,9 @@ const syncWorkspace = async (skipContents = false) => {
syncData: syncDataToRemove,
ifNotTooLate,
});
- const syncDataCopy = { ...store.getters['data/syncDataById'] };
- delete syncDataCopy[syncDataToRemove.id];
- store.dispatch('data/setSyncDataById', syncDataCopy);
+ const syncDataByIdCopy = { ...store.getters['data/syncDataById'] };
+ delete syncDataByIdCopy[syncDataToRemove.id];
+ store.dispatch('data/setSyncDataById', syncDataByIdCopy);
return true;
}));
diff --git a/test/unit/specs/components/Explorer.spec.js b/test/unit/specs/components/Explorer.spec.js
index 94c236c1..8bb88a2f 100644
--- a/test/unit/specs/components/Explorer.spec.js
+++ b/test/unit/specs/components/Explorer.spec.js
@@ -11,6 +11,7 @@ const select = (id) => {
};
const ensureExists = file => expect(store.getters.allItemsById).toHaveProperty(file.id);
const ensureNotExists = file => expect(store.getters.allItemsById).not.toHaveProperty(file.id);
+const refreshItem = item => store.getters.allItemsById[item.id];
describe('Explorer.vue', () => {
it('should create new files in the root folder', () => {
@@ -25,7 +26,7 @@ describe('Explorer.vue', () => {
});
it('should create new files in a folder', async () => {
- const folder = await fileSvc.storeItem({ type: 'folder' });
+ const folder = await workspaceSvc.storeItem({ type: 'folder' });
const wrapper = mount();
select(folder.id);
wrapper.find('.side-title__button--new-file').trigger('click');
@@ -94,7 +95,7 @@ describe('Explorer.vue', () => {
select(file.id);
wrapper.find('.side-title__button--delete').trigger('click');
ensureExists(file);
- expect(file.parentId).toEqual('trash');
+ expect(refreshItem(file).parentId).toEqual('trash');
});
it('should not delete the trash folder', async () => {
@@ -142,7 +143,7 @@ describe('Explorer.vue', () => {
ensureNotExists(folder);
// Make sure file has been moved to Trash
ensureExists(file);
- expect(file.parentId).toEqual('trash');
+ expect(refreshItem(file).parentId).toEqual('trash');
});
it('should rename files', async () => {
diff --git a/test/unit/specs/components/ExplorerNode.spec.js b/test/unit/specs/components/ExplorerNode.spec.js
index f66b1cb3..beb5827b 100644
--- a/test/unit/specs/components/ExplorerNode.spec.js
+++ b/test/unit/specs/components/ExplorerNode.spec.js
@@ -81,16 +81,16 @@ describe('ExplorerNode.vue', () => {
const wrapper = mount(node);
wrapper.trigger('contextmenu');
await specUtils.resolveContextMenu('New file');
- expect(wrapper.contains('.explorer-node__new-child--file')).toBe(true);
+ expect(wrapper.contains('.explorer-node__new-child')).toBe(true);
store.commit('explorer/setNewItemName', modifiedName);
- wrapper.find('.explorer-node__new-child--file .text-input').trigger('blur');
+ wrapper.find('.explorer-node__new-child .text-input').trigger('blur');
await new Promise(resolve => setTimeout(resolve, 1));
expect(store.getters['explorer/selectedNode'].item).toMatchObject({
name: modifiedName,
type: 'file',
parentId: node.item.id,
});
- expect(wrapper.contains('.explorer-node__new-child--file')).toBe(false);
+ expect(wrapper.contains('.explorer-node__new-child')).toBe(false);
});
it('should cancel a file creation on escape', async () => {
@@ -98,9 +98,9 @@ describe('ExplorerNode.vue', () => {
const wrapper = mount(node);
wrapper.trigger('contextmenu');
await specUtils.resolveContextMenu('New file');
- expect(wrapper.contains('.explorer-node__new-child--file')).toBe(true);
+ expect(wrapper.contains('.explorer-node__new-child')).toBe(true);
store.commit('explorer/setNewItemName', modifiedName);
- wrapper.find('.explorer-node__new-child--file .text-input').trigger('keydown', {
+ wrapper.find('.explorer-node__new-child .text-input').trigger('keydown', {
keyCode: 27,
});
await new Promise(resolve => setTimeout(resolve, 1));
@@ -109,7 +109,7 @@ describe('ExplorerNode.vue', () => {
type: 'file',
parentId: node.item.id,
});
- expect(wrapper.contains('.explorer-node__new-child--file')).toBe(false);
+ expect(wrapper.contains('.explorer-node__new-child')).toBe(false);
});
it('should not create new files in a file', async () => {