mirror of
https://github.com/gristlabs/grist-core.git
synced 2024-10-27 20:44:07 +00:00
(core) Some cleanup: remove old unused modules.
Summary: - Remove modules related to old login / profile that we don't plan to bring back. - Remove old unused DocListModel. - Remove ext* tests that have been skipped and don't work. - Remove old ModalDialog, and switch its one remaining usage to the newer way. Test Plan: All tests should pass, and as many as before. Reviewers: paulfitz Reviewed By: paulfitz Differential Revision: https://phab.getgrist.com/D2668
This commit is contained in:
parent
2e22966289
commit
f24a82e8d4
@ -1,30 +0,0 @@
|
|||||||
// Grist client libs
|
|
||||||
import * as ModalDialog from 'app/client/components/ModalDialog';
|
|
||||||
import * as dom from 'app/client/lib/dom';
|
|
||||||
import * as kd from 'app/client/lib/koDom';
|
|
||||||
import * as kf from 'app/client/lib/koForm';
|
|
||||||
|
|
||||||
export function showConfirmDialog(title: string, btnText: string, onConfirm: () => Promise<void>,
|
|
||||||
explanation?: Element|string): void {
|
|
||||||
const body = dom('div.confirm',
|
|
||||||
explanation ? kf.row(explanation, kd.style('margin-bottom', '2rem')) : null,
|
|
||||||
kf.row(
|
|
||||||
1, kf.buttonGroup(
|
|
||||||
kf.button(() => dialog.hide(), 'Cancel')
|
|
||||||
),
|
|
||||||
1, kf.buttonGroup(
|
|
||||||
kf.accentButton(async () => {
|
|
||||||
await onConfirm();
|
|
||||||
dialog.hide();
|
|
||||||
}, btnText)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
const dialog = ModalDialog.create({
|
|
||||||
title,
|
|
||||||
body,
|
|
||||||
width: '300px',
|
|
||||||
show: true
|
|
||||||
});
|
|
||||||
dialog.once('close', () => dialog.dispose());
|
|
||||||
}
|
|
@ -1,205 +0,0 @@
|
|||||||
// External dependencies
|
|
||||||
const _ = require('underscore');
|
|
||||||
const ko = require('knockout');
|
|
||||||
const BackboneEvents = require('backbone').Events;
|
|
||||||
|
|
||||||
// Grist client libs
|
|
||||||
const dispose = require('../lib/dispose');
|
|
||||||
const dom = require('../lib/dom');
|
|
||||||
const kd = require('../lib/koDom');
|
|
||||||
const kf = require('../lib/koForm');
|
|
||||||
const ModalDialog = require('./ModalDialog');
|
|
||||||
const gutil = require('app/common/gutil');
|
|
||||||
|
|
||||||
const BASE_URL = 'https://syvvdfor2a.execute-api.us-east-1.amazonaws.com/test';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* EmbedForm - Handles logic and dom for the modal embedding instruction box.
|
|
||||||
*/
|
|
||||||
function EmbedForm(gristDoc) {
|
|
||||||
this._docComm = gristDoc.docComm;
|
|
||||||
this._login = gristDoc.app.login;
|
|
||||||
this._basketId = gristDoc.docInfo.basketId;
|
|
||||||
this._tableIds = gristDoc.docModel.allTableIds.peek().sort();
|
|
||||||
|
|
||||||
// Arrays of published and unpublished tables, initialized in this._refreshTables()
|
|
||||||
this._published = ko.observable([]);
|
|
||||||
this._unpublished = ko.observable([]);
|
|
||||||
|
|
||||||
// Notify strings which are displayed to the user when set
|
|
||||||
this._errorNotify = ko.observable();
|
|
||||||
this._updateNotify = ko.observable();
|
|
||||||
|
|
||||||
// The state of initialization, either 'connecting', 'failed', or 'done'.
|
|
||||||
this._initState = ko.observable('connecting');
|
|
||||||
|
|
||||||
this._embedDialog = this.autoDispose(ModalDialog.create({
|
|
||||||
title: 'Upload for External Embedding',
|
|
||||||
body: this._buildEmbedDom(),
|
|
||||||
width: '420px'
|
|
||||||
}));
|
|
||||||
this._embedDialog.show();
|
|
||||||
|
|
||||||
this.listenTo(this._embedDialog, 'close', () => this.dispose());
|
|
||||||
|
|
||||||
// Perform the initial fetch to see which tables are published.
|
|
||||||
this._initFetch();
|
|
||||||
}
|
|
||||||
_.extend(EmbedForm.prototype, BackboneEvents);
|
|
||||||
dispose.makeDisposable(EmbedForm);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Performs the initial fetch to see which tables are published.
|
|
||||||
* Times out after 4 seconds, giving the user the option to retry.
|
|
||||||
*/
|
|
||||||
EmbedForm.prototype._initFetch = function() {
|
|
||||||
this._initState('connecting');
|
|
||||||
return this._refreshTables()
|
|
||||||
.timeout(4000)
|
|
||||||
.then(() => {
|
|
||||||
this._initState('done');
|
|
||||||
})
|
|
||||||
.catch(err => {
|
|
||||||
console.error("EmbedForm._initFetch failed", err);
|
|
||||||
this._initState('failed');
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Calls on basket to see which tables are published, then updates the published
|
|
||||||
* and unpublished local observables.
|
|
||||||
*/
|
|
||||||
EmbedForm.prototype._refreshTables = function() {
|
|
||||||
// Fetch the tables from the basket
|
|
||||||
return this._login.getBasketTables(this._docComm)
|
|
||||||
.then(basketTableIds => {
|
|
||||||
let published = [];
|
|
||||||
let unpublished = [];
|
|
||||||
gutil.sortedScan(this._tableIds, basketTableIds.sort(), (local, cloud) => {
|
|
||||||
let item = {
|
|
||||||
tableId: local || cloud,
|
|
||||||
local: Boolean(local),
|
|
||||||
cloud: Boolean(cloud)
|
|
||||||
};
|
|
||||||
if (cloud) {
|
|
||||||
published.push(item);
|
|
||||||
} else {
|
|
||||||
unpublished.push(item);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
this._published(published);
|
|
||||||
this._unpublished(unpublished);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Builds the part of the form showing the table names and their status, and
|
|
||||||
* the buttons to change their status.
|
|
||||||
*/
|
|
||||||
EmbedForm.prototype._buildTablesDom = function() {
|
|
||||||
return dom('div.embed-form-tables',
|
|
||||||
kd.scope(this._published, published => {
|
|
||||||
return published.length > 0 ? dom('div.embed-form-published',
|
|
||||||
dom('div.embed-form-desc', `Published to Basket (basketId: ${this._basketId()})`),
|
|
||||||
published.map(t => {
|
|
||||||
return kf.row(
|
|
||||||
16, dom('a.embed-form-table-id', { href: this._getUrl(t.tableId), target: "_blank" },
|
|
||||||
t.tableId),
|
|
||||||
8, t.local ? this._makeButton('Update', t.tableId, 'update') : 'Only in Basket',
|
|
||||||
1, dom('div'),
|
|
||||||
2, this._makeButton('x', t.tableId, 'delete')
|
|
||||||
);
|
|
||||||
})
|
|
||||||
) : null;
|
|
||||||
}),
|
|
||||||
dom('div.embed-form-unpublished',
|
|
||||||
kd.scope(this._unpublished, unpublished => {
|
|
||||||
return unpublished.map(t => {
|
|
||||||
return kf.row(
|
|
||||||
16, dom('span.embed-form-table-id', t.tableId),
|
|
||||||
8, this._makeButton('Publish', t.tableId, 'add'),
|
|
||||||
3, dom('div')
|
|
||||||
);
|
|
||||||
});
|
|
||||||
})
|
|
||||||
)
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Builds the body of the table publishing modal form.
|
|
||||||
*/
|
|
||||||
EmbedForm.prototype._buildEmbedDom = function() {
|
|
||||||
// TODO: Include links to the npm page and to download basket-api.js.
|
|
||||||
return dom('div.embed-form',
|
|
||||||
kd.scope(this._initState, state => {
|
|
||||||
switch (state) {
|
|
||||||
case 'connecting':
|
|
||||||
return dom('div.embed-form-connect', 'Connecting...');
|
|
||||||
case 'failed':
|
|
||||||
return dom('div',
|
|
||||||
dom('div.embed-form-connect', 'Connection to Basket failed'),
|
|
||||||
kf.buttonGroup(
|
|
||||||
kf.button(() => {
|
|
||||||
this._initFetch();
|
|
||||||
}, 'Retry')
|
|
||||||
)
|
|
||||||
);
|
|
||||||
case 'done':
|
|
||||||
return dom('div',
|
|
||||||
dom('div.embed-form-desc', 'Manage tables published to the cloud via Grist Basket.'),
|
|
||||||
dom('div.embed-form-desc', 'Note that by default, published tables are public.'),
|
|
||||||
this._buildTablesDom(),
|
|
||||||
dom('div.embed-form-desc', 'Basket is used to provide easy access to cloud-synced data:'),
|
|
||||||
dom('div.embed-form-link',
|
|
||||||
dom('a', { href: 'https://github.com/gristlabs/basket-api', target: "_blank" },
|
|
||||||
'Basket API on GitHub')
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
kd.maybe(this._updateNotify, update => {
|
|
||||||
return dom('div.login-success-notify',
|
|
||||||
dom('div.login-success-text', update)
|
|
||||||
);
|
|
||||||
}),
|
|
||||||
kd.maybe(this._errorNotify, err => {
|
|
||||||
return dom('div.login-error-notify',
|
|
||||||
dom('div.login-error-text', err)
|
|
||||||
);
|
|
||||||
})
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
// Helper to perform embedAction ('add' | 'update' | 'delete') on tableId.
|
|
||||||
EmbedForm.prototype._embedTable = function(tableId, embedAction) {
|
|
||||||
this._errorNotify('');
|
|
||||||
this._updateNotify('');
|
|
||||||
return this._docComm.embedTable(tableId, embedAction)
|
|
||||||
.then(() => {
|
|
||||||
return this._refreshTables();
|
|
||||||
})
|
|
||||||
.then(() => {
|
|
||||||
if (embedAction === 'update') {
|
|
||||||
this._updateNotify(`Updated table ${tableId}`);
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.catch(err => {
|
|
||||||
this._errorNotify(err.message);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
// Helper to make a button with text, that when pressed performs embedAction
|
|
||||||
// ('add' | 'update' | 'delete') on tableId.
|
|
||||||
EmbedForm.prototype._makeButton = function(text, tableId, embedAction) {
|
|
||||||
return kf.buttonGroup(
|
|
||||||
kf.button(() => this._embedTable(tableId, embedAction), text)
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
// Returns the URL to see the hosted data for tableId.
|
|
||||||
EmbedForm.prototype._getUrl = function(tableId) {
|
|
||||||
return `${BASE_URL}/${this._basketId()}/tables/${tableId}`;
|
|
||||||
};
|
|
||||||
|
|
||||||
module.exports = EmbedForm;
|
|
@ -1,129 +0,0 @@
|
|||||||
/* global window */
|
|
||||||
|
|
||||||
|
|
||||||
// External dependencies
|
|
||||||
const Promise = require('bluebird');
|
|
||||||
const ko = require('knockout');
|
|
||||||
|
|
||||||
// Grist client libs
|
|
||||||
const dispose = require('../lib/dispose');
|
|
||||||
const ProfileForm = require('./ProfileForm');
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Login - Handles dom and settings for the login box.
|
|
||||||
* @param {app} app - The app instance.
|
|
||||||
*/
|
|
||||||
function Login(app) {
|
|
||||||
this.app = app;
|
|
||||||
this.comm = this.app.comm;
|
|
||||||
|
|
||||||
// When logged in, an object containing user profile properties.
|
|
||||||
this._profile = ko.observable();
|
|
||||||
this.isLoggedIn = ko.observable(false);
|
|
||||||
this.emailObs = this.autoDispose(ko.computed(() => ((this._profile() && this._profile().email) || '')));
|
|
||||||
this.nameObs = this.autoDispose(ko.computed(() => ((this._profile() && this._profile().name) || '')));
|
|
||||||
this.buttonText = this.autoDispose(ko.computed(() =>
|
|
||||||
this.isLoggedIn() ? this.emailObs() : 'Log in'));
|
|
||||||
|
|
||||||
// Instantialized with createLoginForm() and createProfileForm()
|
|
||||||
this.profileForm = null;
|
|
||||||
}
|
|
||||||
dispose.makeDisposable(Login);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the current profile object.
|
|
||||||
*/
|
|
||||||
Login.prototype.getProfile = function() {
|
|
||||||
return this._profile();
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Opens the Cognito login form in a new browser window to allow the user to log in.
|
|
||||||
* The login tokens are sent back to the server to which this client belongs.
|
|
||||||
*/
|
|
||||||
Login.prototype.login = function() {
|
|
||||||
if (window.isRunningUnderElectron) {
|
|
||||||
// Under electron, we open the login URL (it opens in a user's default browser).
|
|
||||||
// With null for redirectUrl, it will close automatically when login completes.
|
|
||||||
return this.comm.getLoginUrl(null)
|
|
||||||
.then((loginUrl) => window.open(loginUrl));
|
|
||||||
} else {
|
|
||||||
// In hosted / dev version, we redirect to the login URL, and it will redirect back to the
|
|
||||||
// starting URL when login completes.
|
|
||||||
return this.comm.getLoginUrl(window.location.href)
|
|
||||||
.then((loginUrl) => { window.location.href = loginUrl; });
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tells the server to log out, and also opens a new window to the logout URL to get Cognito to
|
|
||||||
* clear its cookies. The new window will hit our page which will close the window automatically.
|
|
||||||
*/
|
|
||||||
Login.prototype.logout = function() {
|
|
||||||
// We both log out the server, and for hosted version, visit a logout URL to clear AWS cookies.
|
|
||||||
if (window.isRunningUnderElectron) {
|
|
||||||
// Under electron, only clear the server state. Don't open the user's default browser
|
|
||||||
// to clear cookies there because it serves dubious purpose and is annoying to the user.
|
|
||||||
return this.comm.logout(null);
|
|
||||||
} else {
|
|
||||||
// In hosted / dev version, we redirect to the logout URL, which will clear cookies and
|
|
||||||
// redirect back to the starting URL when logout completes.
|
|
||||||
return this.comm.logout(window.location.href)
|
|
||||||
.then((logoutUrl) => { window.location.href = logoutUrl; });
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Retrieves the updated user profile from DynamoDB and creates the profile form.
|
|
||||||
* Also sends the fetched user profile to the server to keep it up to date.
|
|
||||||
*/
|
|
||||||
Login.prototype.createProfileForm = function() {
|
|
||||||
// ProfileForm disposes itself, no need to handle disposal.
|
|
||||||
this.profileForm = ProfileForm.create(this);
|
|
||||||
};
|
|
||||||
|
|
||||||
// Called when the user logs out in this or another tab.
|
|
||||||
Login.prototype.onLogout = function() {
|
|
||||||
this._profile(null);
|
|
||||||
this.isLoggedIn(false);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Update the internally-stored profile given a profile object from the server.
|
|
||||||
*/
|
|
||||||
Login.prototype.updateProfileFromServer = function(profileObj) {
|
|
||||||
this._profile(profileObj);
|
|
||||||
this.isLoggedIn(Boolean(this._profile.peek()));
|
|
||||||
};
|
|
||||||
|
|
||||||
Login.prototype.setProfileItem = function(key, val) {
|
|
||||||
return this.comm.updateProfile({[key]: val});
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns an array of tableIds in the basket of the current document. If the current
|
|
||||||
* document has no basket, an empty array is returned.
|
|
||||||
*/
|
|
||||||
Login.prototype.getBasketTables = function(docComm) {
|
|
||||||
return docComm.getBasketTables();
|
|
||||||
};
|
|
||||||
|
|
||||||
// Execute func if the user is logged in. Otherwise, prompt the user to log in
|
|
||||||
// and then execute the function. Attempts refresh if the token is expired.
|
|
||||||
Login.prototype.tryWithLogin = function(func) {
|
|
||||||
return Promise.try(() => {
|
|
||||||
if (!this.isLoggedIn()) {
|
|
||||||
return this.login();
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.then(() => func())
|
|
||||||
.catch(err => {
|
|
||||||
if (err.code === 'LoginClosedError') {
|
|
||||||
console.log("Login#tryWithLogin", err);
|
|
||||||
} else {
|
|
||||||
throw err;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
module.exports = Login;
|
|
@ -1,125 +0,0 @@
|
|||||||
/* global $, document, window */
|
|
||||||
|
|
||||||
var _ = require('underscore');
|
|
||||||
var ko = require('knockout');
|
|
||||||
var BackboneEvents = require('backbone').Events;
|
|
||||||
var dom = require('../lib/dom');
|
|
||||||
var kd = require('../lib/koDom');
|
|
||||||
var Base = require('./Base');
|
|
||||||
|
|
||||||
/**
|
|
||||||
* ModalDialog constructor creates a new ModalDialog element. The dialog accepts a bunch of
|
|
||||||
* options, and the content can be overridde when calling .show(), so that a single ModalDialog
|
|
||||||
* component can be used for different purposes. It triggers a 'close' event (using
|
|
||||||
* Backbone.Events) when hidden.
|
|
||||||
*
|
|
||||||
* The DOM of the dialog is always attached to document.body.
|
|
||||||
*
|
|
||||||
* @param {Boolean} [options.fade] Include `fade` css class to fade the modal in/out.
|
|
||||||
* @param {Boolean} [options.close] Include a close icon in the corner (default true).
|
|
||||||
* @param {Boolean} [options.backdrop] Include a modal-backdrop element (default true).
|
|
||||||
* @param {Boolean} [options.keyboard] Close the modal on Escape key (default true).
|
|
||||||
* @param {Boolean} [options.show] Shows the modal when initialized (default true).
|
|
||||||
* @param {CSS String} [options.width] Optional css width to override default.
|
|
||||||
* @param {DOM|String} [options.title] The content to place in the title.
|
|
||||||
* @param {DOM|String} [options.body] The content to place in the body.
|
|
||||||
* @param {DOM|String} [options.footer] The content to place in the footer.
|
|
||||||
*/
|
|
||||||
function ModalDialog(options) {
|
|
||||||
Base.call(this, options);
|
|
||||||
options = options || {};
|
|
||||||
this.options = _.defaults(options, {
|
|
||||||
fade: false, // Controls whether the model pops or fades into view
|
|
||||||
close: true, // Determines whether the "x" dismiss icon appears in the modal
|
|
||||||
backdrop: true,
|
|
||||||
keyboard: true,
|
|
||||||
show: false,
|
|
||||||
});
|
|
||||||
|
|
||||||
// If the width option is set, the margins must be set to auto to keep the dialog centered.
|
|
||||||
this.style = options.width ?
|
|
||||||
`width: ${this.options.width}; margin-left: auto; margin-right: auto;` : '';
|
|
||||||
this.title = ko.observable(options.title || null);
|
|
||||||
this.body = ko.observable(options.body || null);
|
|
||||||
this.footer = ko.observable(options.footer || null);
|
|
||||||
|
|
||||||
this.modal = this.autoDispose(this._buildDom());
|
|
||||||
document.body.appendChild(this.modal);
|
|
||||||
$(this.modal).modal(_.pick(this.options, 'backdrop', 'keyboard', 'show'));
|
|
||||||
|
|
||||||
// On applyState event, close the modal.
|
|
||||||
this.onEvent(window, 'applyState', () => this.hide());
|
|
||||||
|
|
||||||
// If disposed, let the underlying JQuery Modal run its hiding logic, and trigger 'close' event.
|
|
||||||
this.autoDisposeCallback(this.hide);
|
|
||||||
}
|
|
||||||
Base.setBaseFor(ModalDialog);
|
|
||||||
_.extend(ModalDialog.prototype, BackboneEvents);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Shows the ModalDialog. It accepts the same `title`, `body`, and `footer` options as the
|
|
||||||
* constructor, which will replace previous content of those sections.
|
|
||||||
*/
|
|
||||||
ModalDialog.prototype.show = function(options) {
|
|
||||||
options = options || {};
|
|
||||||
// Allow options to specify new title, body, and footer content.
|
|
||||||
['title', 'body', 'footer'].forEach(function(prop) {
|
|
||||||
if (options.hasOwnProperty(prop)) {
|
|
||||||
this[prop](options[prop]);
|
|
||||||
}
|
|
||||||
}, this);
|
|
||||||
|
|
||||||
$(this.modal).modal('show');
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Hides the ModalDialog. This triggers the `close` to be triggered using Backbone.Events.
|
|
||||||
*/
|
|
||||||
ModalDialog.prototype.hide = function() {
|
|
||||||
$(this.modal).modal('hide');
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Internal helper to build the DOM of the dialog.
|
|
||||||
*/
|
|
||||||
ModalDialog.prototype._buildDom = function() {
|
|
||||||
var self = this;
|
|
||||||
// The .clipboard_focus class tells Clipboard.js to let this component have focus. Otherwise
|
|
||||||
// it's impossible to select text.
|
|
||||||
return dom('div.modal.clipboard_focus',
|
|
||||||
{ "role": "dialog", "tabIndex": -1 },
|
|
||||||
|
|
||||||
// Emit a 'close' Backbone.Event whenever the dialog is hidden.
|
|
||||||
dom.on('hidden.bs.modal', function() {
|
|
||||||
self.trigger('close');
|
|
||||||
}),
|
|
||||||
|
|
||||||
dom('div.modal-dialog', { style: this.style },
|
|
||||||
dom('div.modal-content',
|
|
||||||
kd.toggleClass('fade', self.options.fade),
|
|
||||||
|
|
||||||
kd.maybe(this.title, function(title) {
|
|
||||||
return dom('div.modal-header',
|
|
||||||
kd.maybe(self.options.close, function () {
|
|
||||||
return dom('button.close',
|
|
||||||
{"data-dismiss": "modal", "aria-label": "Close"},
|
|
||||||
dom('span', {"aria-hidden": true}, '×')
|
|
||||||
);
|
|
||||||
}),
|
|
||||||
dom('h4.modal-title', title)
|
|
||||||
);
|
|
||||||
}),
|
|
||||||
|
|
||||||
kd.maybe(this.body, function(body) {
|
|
||||||
return dom('div.modal-body', body);
|
|
||||||
}),
|
|
||||||
|
|
||||||
kd.maybe(this.footer, function(footer) {
|
|
||||||
return dom('div.modal-footer', footer);
|
|
||||||
})
|
|
||||||
)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
module.exports = ModalDialog;
|
|
@ -1,160 +0,0 @@
|
|||||||
/* global document */
|
|
||||||
|
|
||||||
// External dependencies
|
|
||||||
const _ = require('underscore');
|
|
||||||
const ko = require('knockout');
|
|
||||||
const BackboneEvents = require('backbone').Events;
|
|
||||||
|
|
||||||
// Grist client libs
|
|
||||||
const dispose = require('../lib/dispose');
|
|
||||||
const dom = require('../lib/dom');
|
|
||||||
const kf = require('../lib/koForm');
|
|
||||||
const kd = require('../lib/koDom');
|
|
||||||
const ModalDialog = require('./ModalDialog');
|
|
||||||
|
|
||||||
/**
|
|
||||||
* ProfileForm - Handles dom and settings for the profile box.
|
|
||||||
* @param {Login} login - The login instance.
|
|
||||||
*/
|
|
||||||
function ProfileForm(login) {
|
|
||||||
this._login = login;
|
|
||||||
this._comm = this._login.comm;
|
|
||||||
this._gristLogin = this._login.gristLogin;
|
|
||||||
this._errorNotify = ko.observable();
|
|
||||||
this._successNotify = ko.observable();
|
|
||||||
|
|
||||||
// Form data which may be filled in when modifying profile information.
|
|
||||||
this._newName = ko.observable('');
|
|
||||||
|
|
||||||
// Counter used to provide each edit profile sub-form with an id which indicates
|
|
||||||
// when it is visible.
|
|
||||||
this._formId = 1;
|
|
||||||
this._editingId = ko.observable(null);
|
|
||||||
|
|
||||||
this._profileDialog = this.autoDispose(ModalDialog.create({
|
|
||||||
title: 'User profile',
|
|
||||||
body: this._buildProfileDom(),
|
|
||||||
width: '420px'
|
|
||||||
}));
|
|
||||||
this._profileDialog.show();
|
|
||||||
|
|
||||||
// TODO: Some indication is necessary that verification is occurring between
|
|
||||||
// submitting the form and waiting for the box to close.
|
|
||||||
this.listenTo(this._comm, 'clientLogout', () => this.dispose());
|
|
||||||
this.listenTo(this._profileDialog, 'close', () => this.dispose());
|
|
||||||
}
|
|
||||||
_.extend(ProfileForm.prototype, BackboneEvents);
|
|
||||||
dispose.makeDisposable(ProfileForm);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Builds the body of the profile modal form.
|
|
||||||
*/
|
|
||||||
ProfileForm.prototype._buildProfileDom = function() {
|
|
||||||
return dom('div.profile-form',
|
|
||||||
// Email
|
|
||||||
// TODO: Allow changing email
|
|
||||||
this._buildProfileRow('Email', {
|
|
||||||
buildDisplayFunc: () => dom('div',
|
|
||||||
kd.text(this._login.emailObs),
|
|
||||||
dom.testId('ProfileForm_viewEmail')
|
|
||||||
)
|
|
||||||
}),
|
|
||||||
// Name
|
|
||||||
this._buildProfileRow('Name', {
|
|
||||||
buildDisplayFunc: () => dom('div',
|
|
||||||
kd.text(this._login.nameObs),
|
|
||||||
dom.testId('ProfileForm_viewName')
|
|
||||||
),
|
|
||||||
buildEditFunc: () => dom('div',
|
|
||||||
kf.label('New name'),
|
|
||||||
kf.text(this._newName, {}, dom.testId('ProfileForm_newName'))
|
|
||||||
),
|
|
||||||
submitFunc: () => this._submitNameChange()
|
|
||||||
}),
|
|
||||||
// TODO: Allow editing profile image.
|
|
||||||
kd.maybe(this._successNotify, success => {
|
|
||||||
return dom('div.login-success-notify',
|
|
||||||
dom('div.login-success-text', success)
|
|
||||||
);
|
|
||||||
}),
|
|
||||||
kd.maybe(this._errorNotify, err => {
|
|
||||||
return dom('div.login-error-notify',
|
|
||||||
dom('div.login-error-text', err)
|
|
||||||
);
|
|
||||||
})
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Builds a row of the profile form.
|
|
||||||
* @param {String} label - Indicates the profile item displayed by the row.
|
|
||||||
* @param {Function} options.buildDisplayFunc - A function which returns dom representing
|
|
||||||
* the value of the profile item to be displayed. If omitted, no value is visible.
|
|
||||||
* @param {Function} options.buildEditFunc - A function which returns dom to change the
|
|
||||||
* value of the profile item. If omitted, the profile item may not be edited.
|
|
||||||
* @param {Function} options.submitFunc - A function to call to save changes to the
|
|
||||||
* profile item. MUST be included if buildEditFunc is included.
|
|
||||||
*/
|
|
||||||
ProfileForm.prototype._buildProfileRow = function(label, options) {
|
|
||||||
options = options || {};
|
|
||||||
let formId = this._formId++;
|
|
||||||
|
|
||||||
return dom('div.profile-row',
|
|
||||||
kf.row(
|
|
||||||
2, kf.label(label),
|
|
||||||
5, options.buildDisplayFunc ? options.buildDisplayFunc() : '',
|
|
||||||
1, dom('div.btn.edit-profile.glyphicon.glyphicon-pencil',
|
|
||||||
{ style: `visibility: ${options.buildEditFunc ? 'visible' : 'hidden'}` },
|
|
||||||
dom.testId(`ProfileForm_edit${label}`),
|
|
||||||
dom.on('click', () => {
|
|
||||||
this._editingId(this._editingId() === formId ? null : formId);
|
|
||||||
})
|
|
||||||
)
|
|
||||||
),
|
|
||||||
kd.maybe(() => this._editingId() === formId, () => {
|
|
||||||
return dom('div',
|
|
||||||
dom.on('keydown', e => {
|
|
||||||
if (e.keyCode === 13) {
|
|
||||||
// Current element is likely a knockout text field with changes that haven't yet been
|
|
||||||
// saved to the observable. Blur the current element to ensure its value is saved.
|
|
||||||
document.activeElement.blur();
|
|
||||||
options.submitFunc();
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
dom('div.edit-profile-form',
|
|
||||||
options.buildEditFunc(),
|
|
||||||
dom('div.login-btns.flexhbox',
|
|
||||||
kf.buttonGroup(
|
|
||||||
kf.button(() => this._editingId(null), 'Cancel',
|
|
||||||
dom.testId('ProfileForm_cancel'))
|
|
||||||
),
|
|
||||||
kf.buttonGroup(
|
|
||||||
kf.accentButton(() => options.submitFunc(), 'Submit',
|
|
||||||
dom.testId('ProfileForm_submit'))
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
})
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
// Submits the profile name change form.
|
|
||||||
ProfileForm.prototype._submitNameChange = function() {
|
|
||||||
if (!this._newName()) {
|
|
||||||
throw new Error('Name may not be blank.');
|
|
||||||
}
|
|
||||||
return this._login.setProfileItem('name', this._newName())
|
|
||||||
// TODO: attemptRefreshToken() should be handled in a general way for all methods
|
|
||||||
// which require using tokens after sign in.
|
|
||||||
.then(() => {
|
|
||||||
this._editingId(null);
|
|
||||||
this._successNotify('Successfully changed name.');
|
|
||||||
})
|
|
||||||
.catch(err => {
|
|
||||||
console.error('Error changing name', err);
|
|
||||||
this._errorNotify(err.message);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
module.exports = ProfileForm;
|
|
@ -5,7 +5,6 @@ var dom = require('../lib/dom');
|
|||||||
var kd = require('../lib/koDom');
|
var kd = require('../lib/koDom');
|
||||||
var kf = require('../lib/koForm');
|
var kf = require('../lib/koForm');
|
||||||
var koArray = require('../lib/koArray');
|
var koArray = require('../lib/koArray');
|
||||||
var {showConfirmDialog} = require('./Confirm');
|
|
||||||
var SummaryConfig = require('./SummaryConfig');
|
var SummaryConfig = require('./SummaryConfig');
|
||||||
var commands = require('./commands');
|
var commands = require('./commands');
|
||||||
var {CustomSectionElement} = require('../lib/CustomSectionElement');
|
var {CustomSectionElement} = require('../lib/CustomSectionElement');
|
||||||
@ -20,6 +19,7 @@ const {basicButton, primaryButton} = require('app/client/ui2018/buttons');
|
|||||||
const {colors} = require('app/client/ui2018/cssVars');
|
const {colors} = require('app/client/ui2018/cssVars');
|
||||||
const {cssDragger} = require('app/client/ui2018/draggableList');
|
const {cssDragger} = require('app/client/ui2018/draggableList');
|
||||||
const {menu, menuItem, select} = require('app/client/ui2018/menus');
|
const {menu, menuItem, select} = require('app/client/ui2018/menus');
|
||||||
|
const {confirmModal} = require('app/client/ui2018/modals');
|
||||||
const isEqual = require('lodash/isEqual');
|
const isEqual = require('lodash/isEqual');
|
||||||
const {cssMenuItem} = require('popweasel');
|
const {cssMenuItem} = require('popweasel');
|
||||||
|
|
||||||
@ -421,18 +421,18 @@ ViewConfigTab.prototype._makeOnDemand = function(table) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (table.onDemand()) {
|
if (table.onDemand()) {
|
||||||
showConfirmDialog('Unmark table On-Demand?', 'Unmark On-Demand', onConfirm,
|
confirmModal('Unmark table On-Demand?', 'Unmark On-Demand', onConfirm,
|
||||||
dom('div', 'If you unmark table ', dom('b', table), ' as On-Demand, ' +
|
dom('div', 'If you unmark table ', dom('b', table), ' as On-Demand, ' +
|
||||||
'its data will be loaded into the calculation engine and will be available ' +
|
'its data will be loaded into the calculation engine and will be available ' +
|
||||||
'for use in formulas. For a big table, this may greatly increase load times.',
|
'for use in formulas. For a big table, this may greatly increase load times.',
|
||||||
dom('br'), 'Changing this setting will reload the document for all users.')
|
dom('br'), dom('br'), 'Changing this setting will reload the document for all users.')
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
showConfirmDialog('Make table On-Demand?', 'Make On-Demand', onConfirm,
|
confirmModal('Make table On-Demand?', 'Make On-Demand', onConfirm,
|
||||||
dom('div', 'If you make table ', dom('b', table), ' On-Demand, ' +
|
dom('div', 'If you make table ', dom('b', table), ' On-Demand, ' +
|
||||||
'its data will no longer be loaded into the calculation engine and will not be available ' +
|
'its data will no longer be loaded into the calculation engine and will not be available ' +
|
||||||
'for use in formulas. It will remain available for viewing and editing.',
|
'for use in formulas. It will remain available for viewing and editing.',
|
||||||
dom('br'), 'Changing this setting will reload the document for all users.')
|
dom('br'), dom('br'), 'Changing this setting will reload the document for all users.')
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
4
app/client/declarations.d.ts
vendored
4
app/client/declarations.d.ts
vendored
@ -3,13 +3,10 @@ declare module "app/client/components/Clipboard";
|
|||||||
declare module "app/client/components/CodeEditorPanel";
|
declare module "app/client/components/CodeEditorPanel";
|
||||||
declare module "app/client/components/DetailView";
|
declare module "app/client/components/DetailView";
|
||||||
declare module "app/client/components/DocConfigTab";
|
declare module "app/client/components/DocConfigTab";
|
||||||
declare module "app/client/components/EmbedForm";
|
|
||||||
declare module "app/client/components/FieldConfigTab";
|
declare module "app/client/components/FieldConfigTab";
|
||||||
declare module "app/client/components/GridView";
|
declare module "app/client/components/GridView";
|
||||||
declare module "app/client/components/Layout";
|
declare module "app/client/components/Layout";
|
||||||
declare module "app/client/components/LayoutEditor";
|
declare module "app/client/components/LayoutEditor";
|
||||||
declare module "app/client/components/Login";
|
|
||||||
declare module "app/client/components/ModalDialog";
|
|
||||||
declare module "app/client/components/REPLTab";
|
declare module "app/client/components/REPLTab";
|
||||||
declare module "app/client/components/commandList";
|
declare module "app/client/components/commandList";
|
||||||
declare module "app/client/lib/Mousetrap";
|
declare module "app/client/lib/Mousetrap";
|
||||||
@ -18,7 +15,6 @@ declare module "app/client/lib/dom";
|
|||||||
declare module "app/client/lib/koDom";
|
declare module "app/client/lib/koDom";
|
||||||
declare module "app/client/lib/koForm";
|
declare module "app/client/lib/koForm";
|
||||||
declare module "app/client/lib/koSession";
|
declare module "app/client/lib/koSession";
|
||||||
declare module "app/client/models/DocListModel";
|
|
||||||
declare module "app/client/widgets/UserType";
|
declare module "app/client/widgets/UserType";
|
||||||
declare module "app/client/widgets/UserTypeImpl";
|
declare module "app/client/widgets/UserTypeImpl";
|
||||||
|
|
||||||
|
@ -7,7 +7,6 @@ Object.assign(window.exposedModules, {
|
|||||||
ko: require('knockout'),
|
ko: require('knockout'),
|
||||||
moment: require('moment-timezone'),
|
moment: require('moment-timezone'),
|
||||||
Comm: require('./components/Comm'),
|
Comm: require('./components/Comm'),
|
||||||
ProfileForm: require('./components/ProfileForm'),
|
|
||||||
_loadScript: require('./lib/loadScript'),
|
_loadScript: require('./lib/loadScript'),
|
||||||
ConnectState: require('./models/ConnectState'),
|
ConnectState: require('./models/ConnectState'),
|
||||||
});
|
});
|
||||||
|
@ -1,118 +0,0 @@
|
|||||||
var koArray = require('../lib/koArray');
|
|
||||||
var dispose = require('../lib/dispose');
|
|
||||||
var _ = require('underscore');
|
|
||||||
var BackboneEvents = require('backbone').Events;
|
|
||||||
var {pageHasDocList} = require('app/common/urlUtils');
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructor for DocListModel
|
|
||||||
* @param {Object} comm: A map of server methods availble on this document.
|
|
||||||
*/
|
|
||||||
function DocListModel(app) {
|
|
||||||
this.app = app;
|
|
||||||
this.comm = this.app.comm;
|
|
||||||
this.docs = koArray();
|
|
||||||
this.docInvites = koArray();
|
|
||||||
|
|
||||||
if (pageHasDocList()) {
|
|
||||||
this.listenTo(this.comm, 'docListAction', this.docListActionHandler);
|
|
||||||
this.listenTo(this.comm, 'receiveInvites', () => this.refreshDocList());
|
|
||||||
|
|
||||||
// Initialize the DocListModel
|
|
||||||
this.refreshDocList();
|
|
||||||
} else {
|
|
||||||
console.log("Page has no DocList support");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
dispose.makeDisposable(DocListModel);
|
|
||||||
_.extend(DocListModel.prototype, BackboneEvents);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Rebuilds DocListModel with a direct call to the server.
|
|
||||||
*/
|
|
||||||
DocListModel.prototype.refreshDocList = function() {
|
|
||||||
return this.comm.getDocList()
|
|
||||||
.then(docListObj => {
|
|
||||||
this.docs.assign(docListObj.docs);
|
|
||||||
this.docInvites.assign(docListObj.docInvites);
|
|
||||||
})
|
|
||||||
.catch((err) => {
|
|
||||||
console.error('Failed to load DocListModel: %s', err);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Updates the DocListModel docs and docInvites arrays in response to docListAction events
|
|
||||||
* @param {Object} message: A docListAction message received from the server.
|
|
||||||
*/
|
|
||||||
DocListModel.prototype.docListActionHandler = function(message) {
|
|
||||||
console.log('docListActionHandler message', message);
|
|
||||||
if (message && message.data) {
|
|
||||||
_.each(message.data.addDocs, this.addDoc, this);
|
|
||||||
_.each(message.data.removeDocs, this.removeDoc, this);
|
|
||||||
_.each(message.data.changeDocs, this.changeDoc, this);
|
|
||||||
_.each(message.data.addInvites, this.addInvite, this);
|
|
||||||
_.each(message.data.removeInvites, this.removeInvite, this);
|
|
||||||
// DocListModel can ignore rename events since renames also broadcast add/remove events.
|
|
||||||
} else {
|
|
||||||
console.error('Unrecognized message', message);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
DocListModel.prototype._removeAtIndex = function(collection, index) {
|
|
||||||
collection.splice(index, 1);
|
|
||||||
};
|
|
||||||
|
|
||||||
DocListModel.prototype._removeItem = function(collection, name) {
|
|
||||||
var index = this._findItem(collection, name);
|
|
||||||
if (index !== -1) {
|
|
||||||
this._removeAtIndex(collection, index);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Binary search is disabled in _.indexOf because the docs may not be sorted by name.
|
|
||||||
DocListModel.prototype._findItem = function(collection, name) {
|
|
||||||
var matchIndex = _.indexOf(collection.all().map(item => item.name), name, false);
|
|
||||||
if (matchIndex === -1) {
|
|
||||||
console.error('DocListModel does not contain name:', name);
|
|
||||||
}
|
|
||||||
return matchIndex;
|
|
||||||
};
|
|
||||||
|
|
||||||
DocListModel.prototype.removeDoc = function(name) {
|
|
||||||
this._removeItem(this.docs, name);
|
|
||||||
};
|
|
||||||
|
|
||||||
// TODO: removeInvite is unused
|
|
||||||
DocListModel.prototype.removeInvite = function(name) {
|
|
||||||
this._removeItem(this.docInvites, name);
|
|
||||||
};
|
|
||||||
|
|
||||||
DocListModel.prototype._addItem = function(collection, fileObj) {
|
|
||||||
var insertIndex = _.sortedIndex(collection.all(), fileObj, 'name');
|
|
||||||
this._addItemAtIndex(collection, insertIndex, fileObj);
|
|
||||||
};
|
|
||||||
|
|
||||||
DocListModel.prototype._addItemAtIndex = function(collection, index, fileObj) {
|
|
||||||
collection.splice(index, 0, fileObj);
|
|
||||||
};
|
|
||||||
|
|
||||||
DocListModel.prototype.addDoc = function(fileObj) {
|
|
||||||
this._addItem(this.docs, fileObj);
|
|
||||||
};
|
|
||||||
|
|
||||||
// TODO: addInvite is unused
|
|
||||||
DocListModel.prototype.addInvite = function(fileObj) {
|
|
||||||
this._addItem(this.docInvites, fileObj);
|
|
||||||
};
|
|
||||||
|
|
||||||
// Called when the metadata for a doc changes.
|
|
||||||
DocListModel.prototype.changeDoc = function(fileObj) {
|
|
||||||
let idx = this._findItem(this.docs, fileObj.name);
|
|
||||||
if (idx !== -1) {
|
|
||||||
this._removeAtIndex(this.docs, idx);
|
|
||||||
this._addItem(this.docs, fileObj);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
module.exports = DocListModel;
|
|
@ -3,13 +3,11 @@ import * as Clipboard from 'app/client/components/Clipboard';
|
|||||||
import {Comm} from 'app/client/components/Comm';
|
import {Comm} from 'app/client/components/Comm';
|
||||||
import * as commandList from 'app/client/components/commandList';
|
import * as commandList from 'app/client/components/commandList';
|
||||||
import * as commands from 'app/client/components/commands';
|
import * as commands from 'app/client/components/commands';
|
||||||
import * as Login from 'app/client/components/Login';
|
|
||||||
import {unsavedChanges} from 'app/client/components/UnsavedChanges';
|
import {unsavedChanges} from 'app/client/components/UnsavedChanges';
|
||||||
import {get as getBrowserGlobals} from 'app/client/lib/browserGlobals';
|
import {get as getBrowserGlobals} from 'app/client/lib/browserGlobals';
|
||||||
import {isDesktop} from 'app/client/lib/browserInfo';
|
import {isDesktop} from 'app/client/lib/browserInfo';
|
||||||
import * as koUtil from 'app/client/lib/koUtil';
|
import * as koUtil from 'app/client/lib/koUtil';
|
||||||
import {reportError, TopAppModel, TopAppModelImpl} from 'app/client/models/AppModel';
|
import {reportError, TopAppModel, TopAppModelImpl} from 'app/client/models/AppModel';
|
||||||
import * as DocListModel from 'app/client/models/DocListModel';
|
|
||||||
import {setUpErrorHandling} from 'app/client/models/errors';
|
import {setUpErrorHandling} from 'app/client/models/errors';
|
||||||
import {createAppUI} from 'app/client/ui/AppUI';
|
import {createAppUI} from 'app/client/ui/AppUI';
|
||||||
import {attachCssRootVars} from 'app/client/ui2018/cssVars';
|
import {attachCssRootVars} from 'app/client/ui2018/cssVars';
|
||||||
@ -24,9 +22,6 @@ import * as ko from 'knockout';
|
|||||||
|
|
||||||
const G = getBrowserGlobals('document', 'window');
|
const G = getBrowserGlobals('document', 'window');
|
||||||
|
|
||||||
type DocListModel = any;
|
|
||||||
type Login = any;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Main Grist App UI component.
|
* Main Grist App UI component.
|
||||||
*/
|
*/
|
||||||
@ -40,9 +35,7 @@ export class App extends DisposableWithEvents {
|
|||||||
public comm = this.autoDispose(Comm.create());
|
public comm = this.autoDispose(Comm.create());
|
||||||
public clientScope: ClientScope;
|
public clientScope: ClientScope;
|
||||||
public features: ko.Computed<ISupportedFeatures>;
|
public features: ko.Computed<ISupportedFeatures>;
|
||||||
public login: Login;
|
|
||||||
public topAppModel: TopAppModel; // Exposed because used by test/nbrowser/gristUtils.
|
public topAppModel: TopAppModel; // Exposed because used by test/nbrowser/gristUtils.
|
||||||
public docListModel: DocListModel;
|
|
||||||
|
|
||||||
private _settings: ko.Observable<{features?: ISupportedFeatures}>;
|
private _settings: ko.Observable<{features?: ISupportedFeatures}>;
|
||||||
|
|
||||||
@ -64,16 +57,11 @@ export class App extends DisposableWithEvents {
|
|||||||
this._settings = ko.observable({});
|
this._settings = ko.observable({});
|
||||||
this.features = ko.computed(() => this._settings().features || {});
|
this.features = ko.computed(() => this._settings().features || {});
|
||||||
|
|
||||||
// Creates a Login instance which handles building the login form, login/signup, logout,
|
|
||||||
// and refreshing tokens. Uses .features, so instantiated after that.
|
|
||||||
this.login = this.autoDispose(Login.create(this));
|
|
||||||
|
|
||||||
if (isDesktop()) {
|
if (isDesktop()) {
|
||||||
this.autoDispose(Clipboard.create(this));
|
this.autoDispose(Clipboard.create(this));
|
||||||
}
|
}
|
||||||
|
|
||||||
this.topAppModel = this.autoDispose(TopAppModelImpl.create(null, G.window));
|
this.topAppModel = this.autoDispose(TopAppModelImpl.create(null, G.window));
|
||||||
this.docListModel = this.autoDispose(DocListModel.create(this));
|
|
||||||
|
|
||||||
const isHelpPaneVisible = ko.observable(false);
|
const isHelpPaneVisible = ko.observable(false);
|
||||||
|
|
||||||
@ -125,7 +113,6 @@ export class App extends DisposableWithEvents {
|
|||||||
this.listenTo(this.comm, 'clientConnect', (message) => {
|
this.listenTo(this.comm, 'clientConnect', (message) => {
|
||||||
console.log(`App clientConnect event: resetClientId ${message.resetClientId} version ${message.serverVersion}`);
|
console.log(`App clientConnect event: resetClientId ${message.resetClientId} version ${message.serverVersion}`);
|
||||||
this._settings(message.settings);
|
this._settings(message.settings);
|
||||||
this.login.updateProfileFromServer(message.profile);
|
|
||||||
if (message.serverVersion === 'dead' || (this._serverVersion && this._serverVersion !== message.serverVersion)) {
|
if (message.serverVersion === 'dead' || (this._serverVersion && this._serverVersion !== message.serverVersion)) {
|
||||||
console.log("Upgrading...");
|
console.log("Upgrading...");
|
||||||
// Server has upgraded. Upgrade client. TODO: be gentle and polite.
|
// Server has upgraded. Upgrade client. TODO: be gentle and polite.
|
||||||
@ -143,12 +130,6 @@ export class App extends DisposableWithEvents {
|
|||||||
this.topAppModel.notifier.setConnectState(isConnected);
|
this.topAppModel.notifier.setConnectState(isConnected);
|
||||||
});
|
});
|
||||||
|
|
||||||
this.listenTo(this.comm, 'profileFetch', (message) => {
|
|
||||||
this.login.updateProfileFromServer(message.data);
|
|
||||||
});
|
|
||||||
|
|
||||||
this.listenTo(this.comm, 'clientLogout', () => this.login.onLogout());
|
|
||||||
|
|
||||||
this.listenTo(this.comm, 'docShutdown', () => {
|
this.listenTo(this.comm, 'docShutdown', () => {
|
||||||
console.log("Received docShutdown");
|
console.log("Received docShutdown");
|
||||||
// Reload on next tick, to let other objects process 'docShutdown' before they get disposed.
|
// Reload on next tick, to let other objects process 'docShutdown' before they get disposed.
|
||||||
|
Loading…
Reference in New Issue
Block a user