CouchDB workspace (part 1)
This commit is contained in:
parent
ec0d5aac3e
commit
aac305e410
4
src/assets/iconCouchdb.svg
Normal file
4
src/assets/iconCouchdb.svg
Normal file
@ -0,0 +1,4 @@
|
||||
<svg width="100%" height="100%" viewBox="0 0 500 500" version="1.1"
|
||||
xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M405.365,303.996c0,20.375 -11.207,30.563 -31.582,31.582l-248.584,0c-20.376,0 -31.583,-10.188 -31.583,-31.582c0,-20.376 11.207,-30.564 31.583,-31.583l249.602,0c20.376,1.019 30.564,11.207 30.564,31.583Zm-30.564,46.864l-249.602,0c-20.376,0 -31.583,10.188 -31.583,31.582c0,20.376 11.207,30.564 31.583,31.583l249.602,0c20.376,0 31.583,-10.188 31.583,-31.583c-1.019,-21.394 -11.207,-31.582 -31.583,-31.582Zm77.428,-172.175c-20.376,0 -31.582,10.188 -31.582,30.563l0,172.175c0,20.376 11.206,30.564 31.582,31.583c30.564,-1.019 46.864,-31.583 46.864,-93.729l0,-77.427c0,-41.771 -16.3,-62.146 -46.864,-63.165Zm-404.458,0c-30.564,1.019 -46.864,21.394 -46.864,63.165l0,77.427c0,62.146 16.3,92.71 46.864,93.729c20.376,0 31.582,-10.188 31.582,-31.583l0,-171.156c-1.019,-20.375 -11.206,-30.563 -31.582,-31.582Zm404.458,-15.282c0,-51.958 -27.507,-76.409 -77.428,-77.428l-249.602,0c-50.94,1.019 -77.428,26.489 -77.428,77.428c30.563,0 46.864,16.301 46.864,46.864c0,30.564 16.301,46.864 46.864,46.864l218.021,0c30.563,0 46.864,-16.3 46.864,-46.864c-1.019,-31.582 16.3,-45.845 45.845,-46.864Z" style="fill:#e42528;fill-rule:nonzero;"/>
|
||||
</svg>
|
After Width: | Height: | Size: 1.2 KiB |
@ -33,6 +33,8 @@
|
||||
<blogger-page-publish-modal v-else-if="config.type === 'bloggerPagePublish'"></blogger-page-publish-modal>
|
||||
<zendesk-account-modal v-else-if="config.type === 'zendeskAccount'"></zendesk-account-modal>
|
||||
<zendesk-publish-modal v-else-if="config.type === 'zendeskPublish'"></zendesk-publish-modal>
|
||||
<couchdb-workspace-modal v-else-if="config.type === 'couchdbWorkspace'"></couchdb-workspace-modal>
|
||||
<couchdb-credentials-modal v-else-if="config.type === 'couchdbCredentials'"></couchdb-credentials-modal>
|
||||
<modal-inner v-else aria-label="Dialog">
|
||||
<div class="modal__content" v-html="config.content"></div>
|
||||
<div class="modal__button-bar">
|
||||
@ -81,6 +83,8 @@ import BloggerPublishModal from './modals/providers/BloggerPublishModal';
|
||||
import BloggerPagePublishModal from './modals/providers/BloggerPagePublishModal';
|
||||
import ZendeskAccountModal from './modals/providers/ZendeskAccountModal';
|
||||
import ZendeskPublishModal from './modals/providers/ZendeskPublishModal';
|
||||
import CouchdbWorkspaceModal from './modals/providers/CouchdbWorkspaceModal';
|
||||
import CouchdbCredentialsModal from './modals/providers/CouchdbCredentialsModal';
|
||||
|
||||
const getTabbables = container => container.querySelectorAll('a[href], button, .textfield')
|
||||
// Filter enabled and visible element
|
||||
@ -122,6 +126,8 @@ export default {
|
||||
BloggerPagePublishModal,
|
||||
ZendeskAccountModal,
|
||||
ZendeskPublishModal,
|
||||
CouchdbWorkspaceModal,
|
||||
CouchdbCredentialsModal,
|
||||
},
|
||||
computed: mapGetters('modal', [
|
||||
'config',
|
||||
|
@ -3,7 +3,7 @@
|
||||
<div class="tour-step" :class="'tour-step--' + step" :style="stepStyle">
|
||||
<div class="tour-step__inner" v-if="step === 'welcome'">
|
||||
<h2>Welcome to StackEdit!</h2>
|
||||
<p>Greater, lighter, faster... StackEdit 5 is here!</p>
|
||||
<p>Greater, lighter, faster... <b>StackEdit 5</b> is here!</p>
|
||||
<p>Please click <b>Next</b> to take a quick tour.</p>
|
||||
<div class="tour-step__button-bar">
|
||||
<button class="button" @click="finish">Skip</button>
|
||||
@ -139,7 +139,7 @@ export default {
|
||||
}
|
||||
|
||||
$tour-step-background: mix(#fafafa, $selection-highlighting-color, 80%);
|
||||
$tour-step-width: 220px;
|
||||
$tour-step-width: 240px;
|
||||
|
||||
.tour-step__inner {
|
||||
position: absolute;
|
||||
|
@ -1,31 +1,29 @@
|
||||
<template>
|
||||
<div class="side-bar__panel side-bar__panel--menu">
|
||||
<div class="menu-info-entries" v-if="!loginToken">
|
||||
<div class="menu-entry menu-entry--info flex flex--row flex--align-center">
|
||||
<div class="menu-info-entries">
|
||||
<div class="menu-entry menu-entry--info flex flex--row flex--align-center" v-if="loginToken">
|
||||
<div class="menu-entry__icon menu-entry__icon--image">
|
||||
<user-image :user-id="loginToken.sub"></user-image>
|
||||
</div>
|
||||
<span>Signed in as <b>{{loginToken.name}}</b>.</span>
|
||||
</div>
|
||||
<div class="menu-entry menu-entry--info flex flex--row flex--align-center" v-if="syncToken">
|
||||
<div class="menu-entry__icon menu-entry__icon--image">
|
||||
<icon-provider :provider-id="currentWorkspace.providerId"></icon-provider>
|
||||
</div>
|
||||
<span><b>{{currentWorkspace.name}}</b> synced.</span>
|
||||
</div>
|
||||
<div class="menu-entry menu-entry--info flex flex--row flex--align-center" v-else>
|
||||
<div class="menu-entry__icon menu-entry__icon--disabled">
|
||||
<icon-sync-off></icon-sync-off>
|
||||
</div>
|
||||
<span><b>{{currentWorkspace.name}}</b> not synced.</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="menu-info-entries" v-else>
|
||||
<div class="menu-entry menu-entry--info flex flex--row flex--align-center">
|
||||
<div class="menu-entry__icon menu-entry__icon--image">
|
||||
<user-image :user-id="loginToken.sub"></user-image>
|
||||
</div>
|
||||
<span>Signed in as <b>{{loginToken.name}}</b>.</span>
|
||||
</div>
|
||||
<div class="menu-entry menu-entry--info flex flex--row flex--align-center">
|
||||
<div class="menu-entry__icon menu-entry__icon--image">
|
||||
<icon-provider :provider-id="currentWorkspace.providerId"></icon-provider>
|
||||
</div>
|
||||
<span><b>{{currentWorkspace.name}}</b> synced.</span>
|
||||
</div>
|
||||
</div>
|
||||
<menu-entry v-if="!loginToken" @click.native="signin">
|
||||
<icon-login slot="icon"></icon-login>
|
||||
<div>Sign in with Google</div>
|
||||
<span>Back up and sync your main workspace.</span>
|
||||
<span>Sync your main workspace and unlock functionalities.</span>
|
||||
</menu-entry>
|
||||
<menu-entry @click.native="setPanel('workspaces')">
|
||||
<icon-database slot="icon"></icon-database>
|
||||
@ -103,6 +101,7 @@ export default {
|
||||
computed: {
|
||||
...mapGetters('workspace', [
|
||||
'currentWorkspace',
|
||||
'syncToken',
|
||||
'loginToken',
|
||||
]),
|
||||
},
|
||||
|
@ -11,6 +11,11 @@
|
||||
<icon-provider slot="icon" provider-id="googleDriveWorkspace"></icon-provider>
|
||||
<span>Add Google Drive workspace</span>
|
||||
</menu-entry>
|
||||
<menu-entry @click.native="addCouchdbWorkspace">
|
||||
<icon-provider slot="icon" provider-id="couchdbWorkspace"></icon-provider>
|
||||
<span>Add CouchDB workspace</span>
|
||||
</menu-entry>
|
||||
<hr>
|
||||
<menu-entry @click.native="manageWorkspaces">
|
||||
<icon-database slot="icon"></icon-database>
|
||||
<span>Manage workspaces</span>
|
||||
@ -44,6 +49,12 @@ export default {
|
||||
}))
|
||||
.catch(() => {}); // Cancel
|
||||
},
|
||||
addCouchdbWorkspace() {
|
||||
return this.$store.dispatch('modal/open', {
|
||||
type: 'couchdbWorkspace',
|
||||
})
|
||||
.catch(() => {}); // Cancel
|
||||
},
|
||||
manageWorkspaces() {
|
||||
return this.$store.dispatch('modal/open', 'workspaceManagement');
|
||||
},
|
||||
@ -62,9 +73,5 @@ export default {
|
||||
.workspace__name {
|
||||
font-weight: bold;
|
||||
line-height: 1.2;
|
||||
|
||||
.menu-entry div & {
|
||||
text-decoration: none;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
@ -27,7 +27,6 @@
|
||||
<script>
|
||||
import { mapGetters } from 'vuex';
|
||||
import ModalInner from './common/ModalInner';
|
||||
import htmlSanitizer from '../../libs/htmlSanitizer';
|
||||
import markdownConversionSvc from '../../services/markdownConversionSvc';
|
||||
import faq from '../../data/faq.md';
|
||||
|
||||
@ -43,7 +42,7 @@ export default {
|
||||
'config',
|
||||
]),
|
||||
faq() {
|
||||
return htmlSanitizer.sanitizeHtml(markdownConversionSvc.defaultConverter.render(faq));
|
||||
return markdownConversionSvc.defaultConverter.render(faq);
|
||||
},
|
||||
},
|
||||
};
|
||||
|
54
src/components/modals/providers/CouchdbCredentialsModal.vue
Normal file
54
src/components/modals/providers/CouchdbCredentialsModal.vue
Normal file
@ -0,0 +1,54 @@
|
||||
<template>
|
||||
<modal-inner aria-label="Insert image">
|
||||
<div class="modal__content">
|
||||
<div class="modal__image">
|
||||
<icon-provider provider-id="couchdb"></icon-provider>
|
||||
</div>
|
||||
<p>Please provide your credentials to login to <b>CouchDB</b>.</p>
|
||||
<form-entry label="Name" error="name">
|
||||
<input slot="field" class="textfield" type="text" v-model.trim="name" @keyup.enter="resolve()">
|
||||
</form-entry>
|
||||
<form-entry label="Password" error="password">
|
||||
<input slot="field" class="textfield" type="password" v-model.trim="password" @keyup.enter="resolve()">
|
||||
</form-entry>
|
||||
</div>
|
||||
<div class="modal__button-bar">
|
||||
<button class="button" @click="config.reject()">Cancel</button>
|
||||
<button class="button" @click="resolve()">Ok</button>
|
||||
</div>
|
||||
</modal-inner>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import modalTemplate from '../common/modalTemplate';
|
||||
|
||||
export default modalTemplate({
|
||||
data: () => ({
|
||||
name: '',
|
||||
password: '',
|
||||
}),
|
||||
created() {
|
||||
this.name = this.config.token.name;
|
||||
this.password = this.config.token.password;
|
||||
},
|
||||
methods: {
|
||||
resolve() {
|
||||
if (!this.name) {
|
||||
this.setError('name');
|
||||
}
|
||||
if (!this.password) {
|
||||
this.setError('password');
|
||||
}
|
||||
if (this.name && this.password) {
|
||||
const token = {
|
||||
...this.config.token,
|
||||
name: this.name,
|
||||
password: this.password,
|
||||
};
|
||||
this.$store.dispatch('data/setCouchdbToken', token);
|
||||
this.config.resolve();
|
||||
}
|
||||
},
|
||||
},
|
||||
});
|
||||
</script>
|
63
src/components/modals/providers/CouchdbWorkspaceModal.vue
Normal file
63
src/components/modals/providers/CouchdbWorkspaceModal.vue
Normal file
@ -0,0 +1,63 @@
|
||||
<template>
|
||||
<modal-inner aria-label="Add CouchDB workspace">
|
||||
<div class="modal__content">
|
||||
<div class="modal__image">
|
||||
<icon-provider provider-id="couchdb"></icon-provider>
|
||||
</div>
|
||||
<p>This will create a workspace synchronized with a <b>CouchDB</b> database.</p>
|
||||
<form-entry label="Database URL" error="dbUrl">
|
||||
<input slot="field" class="textfield" type="text" v-model.trim="dbUrl" @keyup.enter="resolve()">
|
||||
<div class="form-entry__info">
|
||||
<b>Example:</b> https://instance.smileupps.com/stackedit-workspace
|
||||
</div>
|
||||
<div class="form-entry__actions">
|
||||
<a href="javascript:void(0)" v-if="!showInfo" @click="showInfo = true">More info</a>
|
||||
</div>
|
||||
</form-entry>
|
||||
<div class="couchdb-workspace__info" v-if="showInfo" v-html="info"></div>
|
||||
</div>
|
||||
<div class="modal__button-bar">
|
||||
<button class="button" @click="config.reject()">Cancel</button>
|
||||
<button class="button" @click="resolve()">Ok</button>
|
||||
</div>
|
||||
</modal-inner>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import modalTemplate from '../common/modalTemplate';
|
||||
import utils from '../../../services/utils';
|
||||
import couchdbSetup from '../../../data/couchdbSetup.md';
|
||||
import markdownConversionSvc from '../../../services/markdownConversionSvc';
|
||||
|
||||
export default modalTemplate({
|
||||
data: () => ({
|
||||
dbUrl: '',
|
||||
showInfo: false,
|
||||
}),
|
||||
computed: {
|
||||
info() {
|
||||
return markdownConversionSvc.defaultConverter.render(couchdbSetup);
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
resolve() {
|
||||
if (!this.dbUrl) {
|
||||
this.setError('dbUrl');
|
||||
} else {
|
||||
const url = utils.addQueryParams('app', {
|
||||
providerId: 'couchdbWorkspace',
|
||||
dbUrl: this.dbUrl,
|
||||
}, true);
|
||||
this.config.resolve();
|
||||
window.open(url);
|
||||
}
|
||||
},
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.couchdb-workspace__info {
|
||||
font-size: 0.8em;
|
||||
}
|
||||
</style>
|
27
src/data/couchdbSetup.md
Normal file
27
src/data/couchdbSetup.md
Normal file
@ -0,0 +1,27 @@
|
||||
### 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).
|
@ -7,6 +7,7 @@ We recommend syncing your workspace to make sure files won't be lost in case you
|
||||
|
||||
If you sign in with Google, your main workspace will be stored in Google Drive (in your [app data folder](https://developers.google.com/drive/v3/web/appdata)).
|
||||
If you open a Google Drive workspace, the files in the workspace will be stored inside a Google Drive folder which you can share with other users.
|
||||
If you open a CouchDB workspace, the files in the workspace will be stored in the CouchDB database which can be hosted on premises for privacy concerns.
|
||||
|
||||
**Can StackEdit access my data without telling me?**
|
||||
|
||||
|
@ -22,6 +22,8 @@ export default {
|
||||
return 'github';
|
||||
case 'bloggerPage':
|
||||
return 'blogger';
|
||||
case 'couchdbWorkspace':
|
||||
return 'couchdb';
|
||||
default:
|
||||
return this.providerId;
|
||||
}
|
||||
@ -70,4 +72,8 @@ export default {
|
||||
.icon-provider--zendesk {
|
||||
background-image: url(../assets/iconZendesk.svg);
|
||||
}
|
||||
|
||||
.icon-provider--couchdb {
|
||||
background-image: url(../assets/iconCouchdb.svg);
|
||||
}
|
||||
</style>
|
||||
|
@ -459,7 +459,7 @@ const localDbSvc = {
|
||||
*/
|
||||
removeWorkspace(id) {
|
||||
const workspaces = {
|
||||
...this.workspaces,
|
||||
...store.getters['data/workspaces'],
|
||||
};
|
||||
delete workspaces[id];
|
||||
store.dispatch('data/setWorkspaces', workspaces);
|
||||
|
@ -221,6 +221,7 @@ export default {
|
||||
store.commit('updateLastOfflineCheck');
|
||||
}
|
||||
const xhr = new window.XMLHttpRequest();
|
||||
xhr.withCredentials = config.withCredentials || false;
|
||||
let timeoutId;
|
||||
|
||||
xhr.onload = () => {
|
||||
|
87
src/services/providers/couchdbWorkspaceProvider.js
Normal file
87
src/services/providers/couchdbWorkspaceProvider.js
Normal file
@ -0,0 +1,87 @@
|
||||
import store from '../../store';
|
||||
import couchdbHelper from './helpers/couchdbHelper';
|
||||
import providerRegistry from './providerRegistry';
|
||||
import utils from '../utils';
|
||||
|
||||
export default providerRegistry.register({
|
||||
id: 'couchdbWorkspace',
|
||||
getToken() {
|
||||
return store.getters['workspace/syncToken'];
|
||||
},
|
||||
initWorkspace() {
|
||||
const dbUrl = (utils.queryParams.dbUrl || '').replace(/\/?$/, ''); // Remove trailing /
|
||||
const workspaceIdParams = {
|
||||
providerId: this.id,
|
||||
dbUrl,
|
||||
};
|
||||
const workspaceId = utils.makeWorkspaceId(workspaceIdParams);
|
||||
const getToken = () => store.getters['data/couchdbTokens'][workspaceId];
|
||||
const getWorkspace = () => store.getters['data/sanitizedWorkspaces'][workspaceId];
|
||||
|
||||
if (!getToken()) {
|
||||
// Create token
|
||||
store.dispatch('data/setCouchdbToken', {
|
||||
sub: workspaceId,
|
||||
dbUrl,
|
||||
});
|
||||
}
|
||||
|
||||
return Promise.resolve()
|
||||
.then(() => getWorkspace() || couchdbHelper.getDb(getToken())
|
||||
.then((db) => {
|
||||
store.dispatch('data/patchWorkspaces', {
|
||||
[workspaceId]: {
|
||||
id: workspaceId,
|
||||
name: db.db_name,
|
||||
providerId: this.id,
|
||||
dbUrl,
|
||||
},
|
||||
});
|
||||
return getWorkspace();
|
||||
}, () => {
|
||||
throw new Error(`${dbUrl} is not accessible. Make sure you have the right permissions.`);
|
||||
}))
|
||||
.then((workspace) => {
|
||||
// Fix the URL hash
|
||||
utils.setQueryParams(workspaceIdParams);
|
||||
if (workspace.url !== location.href) {
|
||||
store.dispatch('data/patchWorkspaces', {
|
||||
[workspace.id]: {
|
||||
...workspace,
|
||||
url: location.href,
|
||||
},
|
||||
});
|
||||
}
|
||||
return getWorkspace();
|
||||
});
|
||||
},
|
||||
getChanges() {
|
||||
const workspace = store.getters['workspace/currentWorkspace'];
|
||||
const syncToken = store.getters['workspace/syncToken'];
|
||||
const lastSeq = store.getters['data/localSettings'].syncLastSeq;
|
||||
return couchdbHelper.getChanges(syncToken, lastSeq, true)
|
||||
.then((result) => {
|
||||
const changes = result.changes.filter((change) => {
|
||||
if (change.file) {
|
||||
// Parse item from file name
|
||||
try {
|
||||
change.item = JSON.parse(change.file.name);
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
// Build sync data
|
||||
change.syncData = {
|
||||
id: change.fileId,
|
||||
itemId: change.item.id,
|
||||
type: change.item.type,
|
||||
hash: change.item.hash,
|
||||
};
|
||||
}
|
||||
change.syncDataId = change.fileId;
|
||||
return true;
|
||||
});
|
||||
changes.startPageToken = result.startPageToken;
|
||||
return changes;
|
||||
});
|
||||
},
|
||||
});
|
@ -100,7 +100,7 @@ export default providerRegistry.register({
|
||||
});
|
||||
|
||||
// Return the workspace
|
||||
return getWorkspace(folder.id);
|
||||
return store.getters['data/sanitizedWorkspaces'][workspaceId];
|
||||
});
|
||||
|
||||
return Promise.resolve()
|
||||
@ -148,7 +148,15 @@ export default providerRegistry.register({
|
||||
.then((workspace) => {
|
||||
// Fix the URL hash
|
||||
utils.setQueryParams(makeWorkspaceIdParams(workspace.folderId));
|
||||
return workspace;
|
||||
if (workspace.url !== location.href) {
|
||||
store.dispatch('data/patchWorkspaces', {
|
||||
[workspace.id]: {
|
||||
...workspace,
|
||||
url: location.href,
|
||||
},
|
||||
});
|
||||
}
|
||||
return store.getters['data/sanitizedWorkspaces'][workspace.id];
|
||||
}));
|
||||
},
|
||||
performAction() {
|
||||
|
50
src/services/providers/helpers/couchdbHelper.js
Normal file
50
src/services/providers/helpers/couchdbHelper.js
Normal file
@ -0,0 +1,50 @@
|
||||
import networkSvc from '../../networkSvc';
|
||||
import utils from '../../utils';
|
||||
import store from '../../../store';
|
||||
|
||||
const request = (token, options = {}) => {
|
||||
const baseUrl = `${token.dbUrl}/`;
|
||||
const getLastToken = () => store.getters['data/couchdbTokens'][token.sub];
|
||||
|
||||
const ifUnauthorized = cb => (err) => {
|
||||
if (err.status !== 401) {
|
||||
throw err;
|
||||
}
|
||||
return cb(err);
|
||||
};
|
||||
|
||||
const onUnauthorized = () => networkSvc.request({
|
||||
method: 'POST',
|
||||
url: utils.resolveUrl(baseUrl, '../_session'),
|
||||
withCredentials: true,
|
||||
body: {
|
||||
name: getLastToken().name,
|
||||
password: getLastToken().password,
|
||||
},
|
||||
})
|
||||
.catch(ifUnauthorized(() => store.dispatch('modal/open', {
|
||||
type: 'couchdbCredentials',
|
||||
token: getLastToken(),
|
||||
})
|
||||
.then(onUnauthorized)));
|
||||
|
||||
const config = {
|
||||
...options,
|
||||
url: utils.resolveUrl(baseUrl, options.path || '.'),
|
||||
withCredentials: true,
|
||||
};
|
||||
|
||||
return networkSvc.request(config)
|
||||
.catch(ifUnauthorized(() => onUnauthorized()
|
||||
.then(() => networkSvc.request(config))));
|
||||
};
|
||||
|
||||
export default {
|
||||
getDb(token) {
|
||||
return request(token)
|
||||
.then(res => res.body);
|
||||
},
|
||||
getChanges() {
|
||||
|
||||
},
|
||||
};
|
@ -6,6 +6,7 @@ import networkSvc from './networkSvc';
|
||||
import providerRegistry from './providers/providerRegistry';
|
||||
import googleDriveAppDataProvider from './providers/googleDriveAppDataProvider';
|
||||
import './providers/googleDriveWorkspaceProvider';
|
||||
import './providers/couchdbWorkspaceProvider';
|
||||
|
||||
const inactivityThreshold = 3 * 1000; // 3 sec
|
||||
const restartSyncAfter = 30 * 1000; // 30 sec
|
||||
|
@ -171,8 +171,19 @@ export default {
|
||||
}
|
||||
return urlParser.href;
|
||||
},
|
||||
resolveUrl(url) {
|
||||
return this.addQueryParams(url);
|
||||
resolveUrl(baseUrl, path) {
|
||||
const oldBaseElt = document.getElementsByTagName('base')[0];
|
||||
const oldHref = oldBaseElt && oldBaseElt.href;
|
||||
const newBaseElt = oldBaseElt || document.head.appendChild(document.createElement('base'));
|
||||
newBaseElt.href = baseUrl;
|
||||
urlParser.href = path;
|
||||
const result = urlParser.href;
|
||||
if (oldBaseElt) {
|
||||
oldBaseElt.href = oldHref;
|
||||
} else {
|
||||
document.head.removeChild(newBaseElt);
|
||||
}
|
||||
return result;
|
||||
},
|
||||
createHiddenIframe(url) {
|
||||
const iframeElt = document.createElement('iframe');
|
||||
|
@ -207,6 +207,7 @@ export default {
|
||||
dataSyncData: getter('dataSyncData'),
|
||||
tokens: getter('tokens'),
|
||||
googleTokens: (state, getters) => getters.tokens.google || {},
|
||||
couchdbTokens: (state, getters) => getters.tokens.couchdb || {},
|
||||
dropboxTokens: (state, getters) => getters.tokens.dropbox || {},
|
||||
githubTokens: (state, getters) => getters.tokens.github || {},
|
||||
wordpressTokens: (state, getters) => getters.tokens.wordpress || {},
|
||||
@ -281,6 +282,7 @@ export default {
|
||||
patchDataSyncData: patcher('dataSyncData'),
|
||||
patchTokens: patcher('tokens'),
|
||||
setGoogleToken: tokenSetter('google'),
|
||||
setCouchdbToken: tokenSetter('couchdb'),
|
||||
setDropboxToken: tokenSetter('dropbox'),
|
||||
setGithubToken: tokenSetter('github'),
|
||||
setWordpressToken: tokenSetter('wordpress'),
|
||||
|
@ -121,7 +121,7 @@ export default {
|
||||
onResolve,
|
||||
}),
|
||||
sponsorOnly: ({ dispatch }) => dispatch('open', {
|
||||
content: '<p>This feature is restricted to <b>sponsor users</b> as it relies on server resources.</p>',
|
||||
content: '<p>This feature is restricted to sponsors as it relies on server resources.</p>',
|
||||
resolveText: 'Ok, I understand',
|
||||
}),
|
||||
paymentSuccess: ({ dispatch }) => dispatch('open', {
|
||||
|
@ -31,13 +31,30 @@ export default {
|
||||
},
|
||||
syncToken: (state, getters, rootState, rootGetters) => {
|
||||
const workspace = getters.currentWorkspace;
|
||||
if (workspace.providerId === 'googleDriveWorkspace') {
|
||||
const googleTokens = rootGetters['data/googleTokens'];
|
||||
return googleTokens[workspace.sub];
|
||||
switch (workspace.providerId) {
|
||||
case 'googleDriveWorkspace': {
|
||||
const googleTokens = rootGetters['data/googleTokens'];
|
||||
return googleTokens[workspace.sub];
|
||||
}
|
||||
case 'couchdbWorkspace': {
|
||||
const couchdbTokens = rootGetters['data/couchdbTokens'];
|
||||
return couchdbTokens[workspace.id];
|
||||
}
|
||||
default:
|
||||
return getters.mainWorkspaceToken;
|
||||
}
|
||||
},
|
||||
loginToken: (state, getters, rootState, rootGetters) => {
|
||||
const workspace = getters.currentWorkspace;
|
||||
switch (workspace.providerId) {
|
||||
case 'googleDriveWorkspace': {
|
||||
const googleTokens = rootGetters['data/googleTokens'];
|
||||
return googleTokens[workspace.sub];
|
||||
}
|
||||
default:
|
||||
return getters.mainWorkspaceToken;
|
||||
}
|
||||
return getters.mainWorkspaceToken;
|
||||
},
|
||||
loginToken: (state, getters) => getters.syncToken,
|
||||
sponsorToken: (state, getters) => getters.mainWorkspaceToken,
|
||||
},
|
||||
actions: {
|
||||
|
Loading…
Reference in New Issue
Block a user