@jupyterlab/services
Version: 
Client APIs for the Jupyter services REST APIs
188 lines • 5.91 kB
JavaScript
"use strict";
// Copyright (c) Jupyter Development Team.
// Distributed under the terms of the Modified BSD License.
Object.defineProperty(exports, "__esModule", { value: true });
exports.UserManager = void 0;
const coreutils_1 = require("@jupyterlab/coreutils");
const coreutils_2 = require("@lumino/coreutils");
const polling_1 = require("@lumino/polling");
const signaling_1 = require("@lumino/signaling");
const serverconnection_1 = require("../serverconnection");
const basemanager_1 = require("../basemanager");
/**
 * The url for the lab workspaces service.
 */
const SERVICE_USER_URL = 'api/me';
/**
 * The service's ID.
 * Used to uniquely identify the poll, and
 * the item in local storage.
 */
const SERVICE_ID = '@jupyterlab/services:UserManager#user';
/**
 * The user API service manager.
 */
class UserManager extends basemanager_1.BaseManager {
    /**
     * Create a new user manager.
     */
    constructor(options = {}) {
        var _a;
        super(options);
        this._isReady = false;
        this._userChanged = new signaling_1.Signal(this);
        this._connectionFailure = new signaling_1.Signal(this);
        // Initialize internal data.
        this._ready = this.requestUser()
            .then(() => {
            if (this.isDisposed) {
                return;
            }
            this._isReady = true;
        })
            .catch(_ => 
        // Return a promise that will never resolve, so user service is never ready
        // This typically occurs when the backend has no user service
        new Promise(() => {
            // no-op
        }));
        this._pollSpecs = new polling_1.Poll({
            auto: false,
            factory: () => this.requestUser(),
            frequency: {
                interval: 61 * 1000,
                backoff: true,
                max: 300 * 1000
            },
            name: SERVICE_ID,
            standby: (_a = options.standby) !== null && _a !== void 0 ? _a : 'when-hidden'
        });
        void this.ready.then(() => {
            void this._pollSpecs.start();
        });
    }
    /**
     * Test whether the manager is ready.
     */
    get isReady() {
        return this._isReady;
    }
    /**
     * A promise that fulfills when the manager is ready.
     */
    get ready() {
        return this._ready;
    }
    /**
     * Get the most recently fetched identity.
     */
    get identity() {
        return this._identity;
    }
    /**
     * Get the most recently fetched permissions.
     */
    get permissions() {
        return this._permissions;
    }
    /**
     * A signal emitted when the user changes.
     */
    get userChanged() {
        return this._userChanged;
    }
    /**
     * A signal emitted when there is a connection failure.
     */
    get connectionFailure() {
        return this._connectionFailure;
    }
    /**
     * Dispose of the resources used by the manager.
     */
    dispose() {
        this._pollSpecs.dispose();
        super.dispose();
    }
    /**
     * Force a refresh of the specs from the server.
     *
     * @returns A promise that resolves when the specs are fetched.
     *
     * #### Notes
     * This is intended to be called only in response to a user action,
     * since the manager maintains its internal state.
     */
    async refreshUser() {
        await this._pollSpecs.refresh();
        await this._pollSpecs.tick;
    }
    /**
     * Execute a request to the server to poll the user and update state.
     */
    async requestUser() {
        if (this.isDisposed) {
            return;
        }
        const { baseUrl } = this.serverSettings;
        const { makeRequest, ResponseError } = serverconnection_1.ServerConnection;
        const url = coreutils_1.URLExt.join(baseUrl, SERVICE_USER_URL);
        const response = await makeRequest(url, {}, this.serverSettings);
        if (response.status !== 200) {
            const err = await ResponseError.create(response);
            throw err;
        }
        const oldUser = {
            identity: this._identity,
            permissions: this._permissions
        };
        const newUser = await response.json();
        const identity = newUser.identity;
        // store the color and initials for the user
        // this info is not provided by the server
        const { localStorage } = window;
        const data = localStorage.getItem(SERVICE_ID);
        if (data && (!identity.initials || !identity.color)) {
            const localUser = JSON.parse(data);
            identity.initials =
                identity.initials ||
                    localUser.initials ||
                    identity.name.substring(0, 1);
            identity.color =
                identity.color || localUser.color || Private.getRandomColor();
        }
        if (!coreutils_2.JSONExt.deepEqual(newUser, oldUser)) {
            this._identity = identity;
            this._permissions = newUser.permissions;
            localStorage.setItem(SERVICE_ID, JSON.stringify(identity));
            this._userChanged.emit(newUser);
        }
    }
}
exports.UserManager = UserManager;
/**
 * A namespace for module-private functionality.
 *
 * Note: We do not want to export this function
 * to move it to css variables in the Theme.
 */
var Private;
(function (Private) {
    /**
     * Predefined colors for users
     */
    const userColors = [
        'var(--jp-collaborator-color1)',
        'var(--jp-collaborator-color2)',
        'var(--jp-collaborator-color3)',
        'var(--jp-collaborator-color4)',
        'var(--jp-collaborator-color5)',
        'var(--jp-collaborator-color6)',
        'var(--jp-collaborator-color7)'
    ];
    /**
     * Get a random color from the list of colors.
     */
    Private.getRandomColor = () => userColors[Math.floor(Math.random() * userColors.length)];
})(Private || (Private = {}));
//# sourceMappingURL=index.js.map