CouchDB workspace (part 3)

This commit is contained in:
benweet 2018-02-01 22:39:14 +00:00
parent 2374f459df
commit f66f120afc
8 changed files with 53 additions and 81 deletions

View File

@ -160,20 +160,23 @@ export default {
}, { immediate: true }); }, { immediate: true });
const loadOne = () => { const loadOne = () => {
this.$store.dispatch('queue/enqueue', if (!this.destroyed) {
() => { this.$store.dispatch('queue/enqueue',
let loadPromise; () => {
this.revisions.some((revision) => { let loadPromise;
if (!revision.created) { this.revisions.some((revision) => {
const syncToken = this.$store.getters['workspace/syncToken']; if (!revision.created) {
const currentFile = this.$store.getters['file/current']; const syncToken = this.$store.getters['workspace/syncToken'];
loadPromise = this.workspaceProvider.loadRevision(syncToken, currentFile.id, revision) const currentFile = this.$store.getters['file/current'];
.then(() => loadOne()); loadPromise = this.workspaceProvider
} .loadRevision(syncToken, currentFile.id, revision)
.then(() => loadOne());
}
return loadPromise;
});
return loadPromise; return loadPromise;
}); });
return loadPromise; }
});
}; };
this.$watch( this.$watch(
@ -203,7 +206,7 @@ export default {
// Remove event listener // Remove event listener
window.removeEventListener('keyup', this.onKeyup); window.removeEventListener('keyup', this.onKeyup);
// Cancel loading revisions // Cancel loading revisions
this.showCount = 0; this.destroyed = true;
}, },
}; };
</script> </script>

View File

@ -1,6 +1,6 @@
<template> <template>
<div class="side-bar__panel side-bar__panel--menu"> <div class="side-bar__panel side-bar__panel--menu">
<div class="workspace" v-for="(workspace, id) in workspaces" :key="id"> <div class="workspace" v-for="(workspace, id) in sanitizedWorkspaces" :key="id">
<menu-entry :href="workspace.url" target="_blank"> <menu-entry :href="workspace.url" target="_blank">
<icon-provider slot="icon" :provider-id="workspace.providerId"></icon-provider> <icon-provider slot="icon" :provider-id="workspace.providerId"></icon-provider>
<div class="workspace__name"><div class="menu-entry__label" v-if="currentWorkspace === workspace">current</div>{{workspace.name}}</div> <div class="workspace__name"><div class="menu-entry__label" v-if="currentWorkspace === workspace">current</div>{{workspace.name}}</div>
@ -34,7 +34,7 @@ export default {
}, },
computed: { computed: {
...mapGetters('data', [ ...mapGetters('data', [
'workspaces', 'sanitizedWorkspaces',
]), ]),
...mapGetters('workspace', [ ...mapGetters('workspace', [
'currentWorkspace', 'currentWorkspace',

View File

@ -1,7 +1,7 @@
<template> <template>
<modal-inner class="modal__inner-1--workspace-management" aria-label="Manage workspaces"> <modal-inner class="modal__inner-1--workspace-management" aria-label="Manage workspaces">
<div class="modal__content"> <div class="modal__content">
<div class="workspace-entry flex flex--row flex--align-center" v-for="(workspace, id) in workspaces" :key="id"> <div class="workspace-entry flex flex--row flex--align-center" v-for="(workspace, id) in sanitizedWorkspaces" :key="id">
<div class="workspace-entry__icon flex flex--column flex--center"> <div class="workspace-entry__icon flex flex--column flex--center">
<icon-provider :provider-id="workspace.providerId"></icon-provider> <icon-provider :provider-id="workspace.providerId"></icon-provider>
</div> </div>
@ -49,6 +49,7 @@ export default {
]), ]),
...mapGetters('data', [ ...mapGetters('data', [
'workspaces', 'workspaces',
'sanitizedWorkspaces',
]), ]),
...mapGetters('workspace', [ ...mapGetters('workspace', [
'mainWorkspace', 'mainWorkspace',

View File

@ -11,10 +11,9 @@
<b>Example:</b> https://instance.smileupps.com/stackedit-workspace <b>Example:</b> https://instance.smileupps.com/stackedit-workspace
</div> </div>
<div class="form-entry__actions"> <div class="form-entry__actions">
<a href="javascript:void(0)" v-if="!showInfo" @click="showInfo = true">More info</a> <a href="https://community.stackedit.io/t/couchdb-workspace-setup/" target="_blank">More info</a>
</div> </div>
</form-entry> </form-entry>
<div class="couchdb-workspace__info" v-if="showInfo" v-html="info"></div>
</div> </div>
<div class="modal__button-bar"> <div class="modal__button-bar">
<button class="button" @click="config.reject()">Cancel</button> <button class="button" @click="config.reject()">Cancel</button>
@ -26,19 +25,11 @@
<script> <script>
import modalTemplate from '../common/modalTemplate'; import modalTemplate from '../common/modalTemplate';
import utils from '../../../services/utils'; import utils from '../../../services/utils';
import couchdbSetup from '../../../data/couchdbSetup.md';
import markdownConversionSvc from '../../../services/markdownConversionSvc';
export default modalTemplate({ export default modalTemplate({
data: () => ({ data: () => ({
dbUrl: '', dbUrl: '',
showInfo: false,
}), }),
computed: {
info() {
return markdownConversionSvc.defaultConverter.render(couchdbSetup);
},
},
methods: { methods: {
resolve() { resolve() {
if (!this.dbUrl) { if (!this.dbUrl) {

View File

@ -1,27 +0,0 @@
### Pre-requisites
- CouchDB 0.11 or later,
- In order to work with https://stackedit.io, your database needs to be accessible over HTTPS.
> **Tip:** [Smileupps](https://www.smileupps.com/) provide free CouchDB hosting.
### Enable CORS
Add the following key/value pairs to your CouchDB configuration:
```
[httpd]
enable_cors = true
[cors]
origins = https://stackedit.io
```
### Create the database
```bash
curl -X PUT https://instance.smileupps.com/stackedit-workspace
```
> You may want to restrict access to the database by [specifying members](http://docs.couchdb.org/en/latest/api/database/security.html).

View File

@ -4,6 +4,13 @@ import providerRegistry from './providerRegistry';
import providerUtils from './providerUtils'; import providerUtils from './providerUtils';
import utils from '../utils'; import utils from '../utils';
const getSyncData = (fileId) => {
const syncData = store.getters['data/syncDataByItemId'][`${fileId}/content`];
return syncData
? Promise.resolve(syncData)
: Promise.reject(); // No need for a proper error message.
};
export default providerRegistry.register({ export default providerRegistry.register({
id: 'couchdbWorkspace', id: 'couchdbWorkspace',
getToken() { getToken() {
@ -184,11 +191,8 @@ export default providerRegistry.register({
})); }));
}, },
listRevisions(token, fileId) { listRevisions(token, fileId) {
const syncData = store.getters['data/syncDataByItemId'][`${fileId}/content`]; return getSyncData(fileId)
if (!syncData) { .then(syncData => couchdbHelper.retrieveDocumentWithRevisions(token, syncData.id))
return Promise.reject(); // No need for a proper error message.
}
return couchdbHelper.retrieveDocumentWithRevisions(token, syncData.id)
.then((body) => { .then((body) => {
const revisions = []; const revisions = [];
body._revs_info.forEach((revInfo) => { // eslint-disable-line no-underscore-dangle body._revs_info.forEach((revInfo) => { // eslint-disable-line no-underscore-dangle
@ -204,22 +208,17 @@ export default providerRegistry.register({
}); });
}, },
loadRevision(token, fileId, revision) { loadRevision(token, fileId, revision) {
const syncData = store.getters['data/syncDataByItemId'][`${fileId}/content`]; return getSyncData(fileId)
if (!syncData) { .then(syncData => couchdbHelper.retrieveDocument(token, syncData.id, revision.id))
return Promise.reject(); // No need for a proper error message.
}
return couchdbHelper.retrieveDocument(token, syncData.id, revision.id)
.then((body) => { .then((body) => {
revision.sub = body.sub; revision.sub = body.sub;
revision.created = body.created; revision.created = body.time || 1; // Has to be truthy to prevent from loading several times
}); });
}, },
getRevisionContent(token, fileId, revisionId) { getRevisionContent(token, fileId, revisionId) {
const syncData = store.getters['data/syncDataByItemId'][`${fileId}/content`]; return getSyncData(fileId)
if (!syncData) { .then(syncData => couchdbHelper
return Promise.reject(); // No need for a proper error message. .retrieveDocumentWithAttachments(token, syncData.id, revisionId))
}
return couchdbHelper.retrieveDocumentWithAttachments(token, syncData.id, revisionId)
.then(body => providerUtils.parseContent(body.attachments.data, body.item.id)); .then(body => providerUtils.parseContent(body.attachments.data, body.item.id));
}, },
}); });

View File

@ -6,6 +6,13 @@ import utils from '../utils';
let fileIdToOpen; let fileIdToOpen;
const getSyncData = (fileId) => {
const syncData = store.getters['data/syncDataByItemId'][`${fileId}/content`];
return syncData
? Promise.resolve(syncData)
: Promise.reject(); // No need for a proper error message.
};
export default providerRegistry.register({ export default providerRegistry.register({
id: 'googleDriveWorkspace', id: 'googleDriveWorkspace',
getToken() { getToken() {
@ -441,7 +448,7 @@ export default providerRegistry.register({
uploadContent(token, content, syncLocation, ifNotTooLate) { uploadContent(token, content, syncLocation, ifNotTooLate) {
const contentSyncData = store.getters['data/syncDataByItemId'][`${syncLocation.fileId}/content`]; const contentSyncData = store.getters['data/syncDataByItemId'][`${syncLocation.fileId}/content`];
if (contentSyncData && contentSyncData.hash === content.hash) { if (contentSyncData && contentSyncData.hash === content.hash) {
return Promise.resolve(); return Promise.resolve(syncLocation);
} }
return Promise.resolve() return Promise.resolve()
.then(() => { .then(() => {
@ -534,11 +541,8 @@ export default providerRegistry.register({
})); }));
}, },
listRevisions(token, fileId) { listRevisions(token, fileId) {
const syncData = store.getters['data/syncDataByItemId'][fileId]; return getSyncData(fileId)
if (!syncData) { .then(syncData => googleHelper.getFileRevisions(token, syncData.id))
return Promise.reject(); // No need for a proper error message.
}
return googleHelper.getFileRevisions(token, syncData.id)
.then(revisions => revisions.map(revision => ({ .then(revisions => revisions.map(revision => ({
id: revision.id, id: revision.id,
sub: revision.lastModifyingUser && revision.lastModifyingUser.permissionId, sub: revision.lastModifyingUser && revision.lastModifyingUser.permissionId,
@ -547,11 +551,8 @@ export default providerRegistry.register({
.sort((revision1, revision2) => revision2.created - revision1.created)); .sort((revision1, revision2) => revision2.created - revision1.created));
}, },
getRevisionContent(token, fileId, revisionId) { getRevisionContent(token, fileId, revisionId) {
const syncData = store.getters['data/syncDataByItemId'][fileId]; return getSyncData(fileId)
if (!syncData) { .then(syncData => googleHelper.downloadFileRevision(token, syncData.id, revisionId))
return Promise.reject(); // No need for a proper error message.
}
return googleHelper.downloadFileRevision(token, syncData.id, revisionId)
.then(content => providerUtils.parseContent(content, `${fileId}/content`)); .then(content => providerUtils.parseContent(content, `${fileId}/content`));
}, },
}); });

View File

@ -89,8 +89,12 @@ export default {
) { ) {
const options = { const options = {
method: 'POST', method: 'POST',
body: { item }, body: { item, time: Date.now() },
}; };
const loginToken = store.getters['workspace/loginToken'];
if (loginToken) {
options.body.sub = loginToken.sub;
}
if (documentId) { if (documentId) {
options.method = 'PUT'; options.method = 'PUT';
options.path = documentId; options.path = documentId;