CouchDB workspace (part 3)
This commit is contained in:
		
							parent
							
								
									2374f459df
								
							
						
					
					
						commit
						f66f120afc
					
				| @ -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> | ||||||
|  | |||||||
| @ -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', | ||||||
|  | |||||||
| @ -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', | ||||||
|  | |||||||
| @ -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) { | ||||||
|  | |||||||
| @ -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). |  | ||||||
| @ -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)); | ||||||
|   }, |   }, | ||||||
| }); | }); | ||||||
|  | |||||||
| @ -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`)); | ||||||
|   }, |   }, | ||||||
| }); | }); | ||||||
|  | |||||||
| @ -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; | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user
	 benweet
						benweet