diff --git a/README.md b/README.md
index 3210d9a..0adb84b 100755
--- a/README.md
+++ b/README.md
@@ -60,3 +60,9 @@ you can import/export with json file.
you can cutomize shortcut and other settings fron icon-menu.
- whether or not confirm before delete
+
+### Sync
+
+To sync your notes in the cloud (and share them across several browsers automatically) you will need to register and login from the menu.
+
+This setup can be customized from icon-menu: icon-menu where you can specify a custom url. The url must point to a running backend instance. You can learn how to self host one using the [dedicated project](https://github.com/kumabook/stickynotes-backend/).
\ No newline at end of file
diff --git a/src/background.js b/src/background.js
index 1f8e7da..9333c31 100644
--- a/src/background.js
+++ b/src/background.js
@@ -234,7 +234,7 @@ function handlePopupMessage(msg) {
break;
}
case 'reset-password':
- browser.tabs.create({ url: api.resetPasswordUrl });
+ browser.tabs.create({ url: api.getResetPasswordUrl() });
break;
default:
break;
@@ -348,6 +348,10 @@ function handleOptionsUIMessage(msg) {
})));
break;
}
+ case 'updated-server-url': {
+ browser.storage.local.get().then(payload => api.setOnPremiseUrl(payload));
+ break;
+ }
default:
break;
}
diff --git a/src/containers/OptionsUI.jsx b/src/containers/OptionsUI.jsx
index caeb34b..f7e7ba7 100644
--- a/src/containers/OptionsUI.jsx
+++ b/src/containers/OptionsUI.jsx
@@ -1,4 +1,5 @@
/* global confirm: false */
+/* global chrome */
import React from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
@@ -21,6 +22,43 @@ class OptionsUI extends React.Component {
);
}
+ renderSetOnPremise() {
+ return (
+
@@ -43,6 +81,7 @@ class OptionsUI extends React.Component {
{this.renderFiles()}
{this.renderCanMoveFocusByTab()}
+ {this.renderSetOnPremise()}
);
}
@@ -54,6 +93,11 @@ OptionsUI.propTypes = {
handleInputFiles: PropTypes.func.isRequired,
handleCanMoveFocusByTabChange: PropTypes.func.isRequired,
canMoveFocusByTab: PropTypes.bool.isRequired,
+ handleUseCustomerBackupServer: PropTypes.func.isRequired,
+ hasCustomBaseUrl: PropTypes.func.isRequired,
+ BASE_URL: PropTypes.string,
+ CLIENT_ID: PropTypes.string,
+ CLIENT_SECRET: PropTypes.string,
};
OptionsUI.defaultProps = {
@@ -62,6 +106,10 @@ OptionsUI.defaultProps = {
function mapStateToProps(state) {
return {
canMoveFocusByTab: state.canMoveFocusByTab,
+ hasCustomBaseUrl: state.hasCustomBaseUrl,
+ BASE_URL: state.BASE_URL,
+ CLIENT_ID: state.CLIENT_ID,
+ CLIENT_SECRET: state.CLIENT_SECRET,
};
}
@@ -90,6 +138,10 @@ function mapDispatchToProps(dispatch) {
type: 'UPDATE_CAN_MOVE_FOCUS_BY_TAB',
payload,
}),
+ handleUseCustomerBackupServer: payload => dispatch({
+ type: 'UPDATE_USE_CUSTOM_BACKUP_SERVER',
+ payload,
+ }),
};
}
diff --git a/src/reducers/options_ui.js b/src/reducers/options_ui.js
index a5c9e77..137c448 100644
--- a/src/reducers/options_ui.js
+++ b/src/reducers/options_ui.js
@@ -9,9 +9,49 @@ const canMoveFocusByTab = (state = true, action) => {
}
};
+const hasCustomBaseUrl = (state = false, action) => {
+ switch (action.type) {
+ case 'UPDATE_USE_CUSTOM_BACKUP_SERVER':
+ return action.payload.hasCustomBaseUrl;
+ default:
+ return state;
+ }
+};
+
+const BASE_URL = (state = "", action) => {
+ switch (action.type) {
+ case 'UPDATE_USE_CUSTOM_BACKUP_SERVER':
+ return action.payload.BASE_URL;
+ default:
+ return state;
+ }
+};
+
+const CLIENT_ID = (state = "", action) => {
+ switch (action.type) {
+ case 'UPDATE_USE_CUSTOM_BACKUP_SERVER':
+ return action.payload.CLIENT_ID;
+ default:
+ return state;
+ }
+};
+
+const CLIENT_SECRET = (state = "", action) => {
+ switch (action.type) {
+ case 'UPDATE_USE_CUSTOM_BACKUP_SERVER':
+ return action.payload.CLIENT_SECRET;
+ default:
+ return state;
+ }
+};
+
const rootReducer = combineReducers({
canMoveFocusByTab,
+ hasCustomBaseUrl,
+ BASE_URL,
+ CLIENT_ID,
+ CLIENT_SECRET,
});
export default rootReducer;
diff --git a/src/sagas/options_ui.js b/src/sagas/options_ui.js
index a0d4656..c8d8e3d 100644
--- a/src/sagas/options_ui.js
+++ b/src/sagas/options_ui.js
@@ -94,6 +94,14 @@ function* watchCanMoveFocusByTab() {
});
}
+function* watchUseCustomerBackupServer() {
+ yield takeEvery('UPDATE_USE_CUSTOM_BACKUP_SERVER', function* update() {
+ const { BASE_URL, CLIENT_ID, CLIENT_SECRET, hasCustomBaseUrl } = yield select(state => state);
+ yield browser.storage.local.set({ BASE_URL, CLIENT_ID, CLIENT_SECRET, hasCustomBaseUrl });
+ port.postMessage({ type: 'updated-server-url', portName });
+ });
+}
+
export default function* root() {
yield [
@@ -101,5 +109,6 @@ export default function* root() {
fork(watchImport),
fork(watchExport),
fork(watchCanMoveFocusByTab),
+ fork(watchUseCustomerBackupServer),
];
}
diff --git a/src/utils/api.js b/src/utils/api.js
index 5408155..8d890a6 100644
--- a/src/utils/api.js
+++ b/src/utils/api.js
@@ -2,7 +2,40 @@
import browser from 'webextension-polyfill';
import logger from './logger';
-const { BASE_URL, CLIENT_ID, CLIENT_SECRET } = process.env;
+let { BASE_URL, CLIENT_ID, CLIENT_SECRET } = process.env;
+
+browser.storage.local.get('hasCustomBaseUrl').then((hasCustomBaseUrl) => {
+ if (hasCustomBaseUrl) {
+ ['BASE_URL', 'CLIENT_ID', 'CLIENT_SECRET'].forEach(key=>browser.storage.local.get(key).then((v) => {
+ if (v && v[key]) {
+ if (key=='BASE_URL')
+ BASE_URL = v[key];
+ if (key=='CLIENT_ID')
+ CLIENT_ID = v[key];
+ if (key=='CLIENT_SECRET')
+ CLIENT_SECRET = v[key];
+ }
+ }));
+ }
+});
+
+
+function setOnPremiseUrl(payload) {
+ let server = {};
+ ['BASE_URL', 'CLIENT_ID', 'CLIENT_SECRET'].forEach(key=>{
+ if (!payload.hasCustomBaseUrl || typeof(payload[key]) == "undefined" || payload[key] == "") {
+ server[key] = process.env[key];
+ } else {
+ server[key] = payload[key];
+ }
+ });
+ ({ BASE_URL, CLIENT_ID, CLIENT_SECRET } = server);
+}
+
+
+function getResetPasswordUrl() {
+ return `${BASE_URL}/password_resets/new`;
+}
function getAccessToken() {
return browser.storage.local.get('accessToken').then((v) => {
@@ -84,6 +117,9 @@ function sendRequest(method, url, params) {
logger.trace(JSON.stringify(params));
return fetch(u, { method, headers, body })
+ .catch(function(e) {
+ return {ok: false, status: e.code, exception: e}
+ })
.then((response) => {
logger.trace(response);
if (response.ok) {
@@ -158,6 +194,6 @@ export default {
isLoggedIn,
getUser,
setUser,
- signUpUrl: `${BASE_URL}/users/new`,
- resetPasswordUrl: `${BASE_URL}/password_resets/new`,
+ getResetPasswordUrl,
+ setOnPremiseUrl,
};