blob: cf254d441246f52240c7dcc55a0d70966c34af44 [file] [log] [blame]
/**
* @license
* Copyright (C) 2019 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* This defines the Gerrit instance. All methods directly attached to Gerrit
* should be defined or linked here.
*/
import {
getPluginLoader,
PluginOptionMap,
PluginLoader,
} from './gr-plugin-loader';
import {getRestAPI, send} from './gr-api-utils';
import {appContext} from '../../../services/app-context';
import {PluginApi} from '../../plugins/gr-plugin-types';
import {HttpMethod} from '../../../constants/constants';
import {RequestPayload} from '../../../types/common';
import {
EventCallback,
EventEmitterService,
} from '../../../services/gr-event-interface/gr-event-interface';
import {GerritNav} from '../../core/gr-navigation/gr-navigation';
import {getRootElement} from '../../../scripts/rootElement';
import {GrPluginEndpoints} from './gr-plugin-endpoints';
import {rangesEqual} from '../../diff/gr-diff/gr-diff-utils';
import {SUGGESTIONS_PROVIDERS_USERS_TYPES} from '../../../scripts/gr-reviewer-suggestions-provider/gr-reviewer-suggestions-provider';
import {CoverageType} from '../../../types/types';
import {RevisionInfo} from '../revision-info/revision-info';
export interface GerritGlobal extends EventEmitterService {
flushPreinstalls?(): void;
css(rule: string): string;
install(
callback: (plugin: PluginApi) => void,
opt_version?: string,
src?: string
): void;
getLoggedIn(): Promise<boolean>;
get(url: string, callback?: (response: unknown) => void): void;
post(
url: string,
payload?: RequestPayload,
callback?: (response: unknown) => void
): void;
put(
url: string,
payload?: RequestPayload,
callback?: (response: unknown) => void
): void;
delete(url: string, callback?: (response: unknown) => void): void;
isPluginLoaded(pathOrUrl: string): boolean;
awaitPluginsLoaded(): Promise<unknown>;
_loadPlugins(plugins: string[], opts: PluginOptionMap): void;
_arePluginsLoaded(): boolean;
_isPluginPreloaded(pathOrUrl: string): boolean;
_isPluginEnabled(pathOrUrl: string): boolean;
_isPluginLoaded(pathOrUrl: string): boolean;
_eventEmitter: EventEmitterService;
_customStyleSheet: CSSStyleSheet;
// exposed methods
Nav: typeof GerritNav;
Auth: typeof appContext.authService;
getRootElement: typeof getRootElement;
_pluginLoader: PluginLoader;
_endpoints: GrPluginEndpoints;
slotToContent(slot: unknown): unknown;
rangesEqual: typeof rangesEqual;
SUGGESTIONS_PROVIDERS_USERS_TYPES: typeof SUGGESTIONS_PROVIDERS_USERS_TYPES;
CoverageType: typeof CoverageType;
RevisionInfo: typeof RevisionInfo;
}
/**
* Trigger the preinstalls for bundled plugins.
* This needs to happen before Gerrit as plugin bundle overrides the Gerrit.
*/
function flushPreinstalls() {
const Gerrit = window.Gerrit;
if (Gerrit?.flushPreinstalls) {
Gerrit.flushPreinstalls();
}
}
export const _testOnly_flushPreinstalls = flushPreinstalls;
export function initGerritPluginApi() {
window.Gerrit = window.Gerrit || {};
flushPreinstalls();
initGerritPluginsMethods(window.Gerrit as GerritGlobal);
// Preloaded plugins should be installed after Gerrit.install() is set,
// since plugin preloader substitutes Gerrit.install() temporarily.
// (Gerrit.install() is set in initGerritPluginsMethods)
getPluginLoader().installPreloadedPlugins();
}
export function _testOnly_initGerritPluginApi(): GerritGlobal {
window.Gerrit = window.Gerrit || {};
initGerritPluginApi();
return window.Gerrit as GerritGlobal;
}
export function deprecatedDelete(
url: string,
callback?: (response: Response) => void
) {
console.warn('.delete() is deprecated! Use plugin.restApi().delete()');
return getRestAPI()
.send(HttpMethod.DELETE, url)
.then(response => {
if (response.status !== 204) {
return response.text().then(text => {
if (text) {
return Promise.reject(new Error(text));
} else {
return Promise.reject(new Error(`${response.status}`));
}
});
}
if (callback) callback(response);
return response;
});
}
function initGerritPluginsMethods(globalGerritObj: GerritGlobal) {
/**
* @deprecated Use plugin.styles().css(rulesStr) instead. Please, consult
* the documentation how to replace it accordingly.
*/
globalGerritObj.css = (rulesStr: string) => {
console.warn(
'Gerrit.css(rulesStr) is deprecated!',
'Use plugin.styles().css(rulesStr)'
);
if (!globalGerritObj._customStyleSheet) {
const styleEl = document.createElement('style');
document.head.appendChild(styleEl);
globalGerritObj._customStyleSheet = styleEl.sheet!;
}
const name = `__pg_js_api_class_${globalGerritObj._customStyleSheet.cssRules.length}`;
globalGerritObj._customStyleSheet.insertRule(
'.' + name + '{' + rulesStr + '}',
0
);
return name;
};
globalGerritObj.install = (callback, opt_version, opt_src) => {
getPluginLoader().install(callback, opt_version, opt_src);
};
globalGerritObj.getLoggedIn = () => {
console.warn(
'Gerrit.getLoggedIn() is deprecated! ' +
'Use plugin.restApi().getLoggedIn()'
);
return document.createElement('gr-rest-api-interface').getLoggedIn();
};
globalGerritObj.get = (
url: string,
callback?: (response: unknown) => void
) => {
console.warn('.get() is deprecated! Use plugin.restApi().get()');
send(HttpMethod.GET, url, callback);
};
globalGerritObj.post = (
url: string,
payload?: RequestPayload,
callback?: (response: unknown) => void
) => {
console.warn('.post() is deprecated! Use plugin.restApi().post()');
send(HttpMethod.POST, url, callback, payload);
};
globalGerritObj.put = (
url: string,
payload?: RequestPayload,
callback?: (response: unknown) => void
) => {
console.warn('.put() is deprecated! Use plugin.restApi().put()');
send(HttpMethod.PUT, url, callback, payload);
};
globalGerritObj.delete = (
url: string,
callback?: (response: Response) => void
) => {
deprecatedDelete(url, callback);
};
globalGerritObj.awaitPluginsLoaded = () => {
return getPluginLoader().awaitPluginsLoaded();
};
// TODO(taoalpha): consider removing these proxy methods
// and using getPluginLoader() directly
globalGerritObj._loadPlugins = (plugins, opt_option) => {
getPluginLoader().loadPlugins(plugins, opt_option);
};
globalGerritObj._arePluginsLoaded = () => {
return getPluginLoader().arePluginsLoaded();
};
globalGerritObj._isPluginPreloaded = url => {
return getPluginLoader().isPluginPreloaded(url);
};
globalGerritObj._isPluginEnabled = pathOrUrl => {
return getPluginLoader().isPluginEnabled(pathOrUrl);
};
globalGerritObj._isPluginLoaded = pathOrUrl => {
return getPluginLoader().isPluginLoaded(pathOrUrl);
};
const eventEmitter = appContext.eventEmitter;
// TODO(taoalpha): List all internal supported event names.
// Also convert this to inherited class once we move Gerrit to class.
globalGerritObj._eventEmitter = eventEmitter;
/**
* Enabling EventEmitter interface on Gerrit.
*
* This will enable to signal across different parts of js code without relying on DOM,
* including core to core, plugin to plugin and also core to plugin.
*
* @example
*
* // Emit this event from pluginA
* Gerrit.install(pluginA => {
* fetch("some-api").then(() => {
* Gerrit.on("your-special-event", {plugin: pluginA});
* });
* });
*
* // Listen on your-special-event from pluignB
* Gerrit.install(pluginB => {
* Gerrit.on("your-special-event", ({plugin}) => {
* // do something, plugin is pluginA
* });
* });
*/
globalGerritObj.addListener = (eventName: string, cb: EventCallback) =>
eventEmitter.addListener(eventName, cb);
// eslint-disable-next-line @typescript-eslint/no-explicit-any
globalGerritObj.dispatch = (eventName: string, detail: any) =>
eventEmitter.dispatch(eventName, detail);
// eslint-disable-next-line @typescript-eslint/no-explicit-any
globalGerritObj.emit = (eventName: string, detail: any) =>
eventEmitter.emit(eventName, detail);
globalGerritObj.off = (eventName: string, cb: EventCallback) =>
eventEmitter.off(eventName, cb);
globalGerritObj.on = (eventName: string, cb: EventCallback) =>
eventEmitter.on(eventName, cb);
globalGerritObj.once = (eventName: string, cb: EventCallback) =>
eventEmitter.once(eventName, cb);
globalGerritObj.removeAllListeners = (eventName: string) =>
eventEmitter.removeAllListeners(eventName);
globalGerritObj.removeListener = (eventName: string, cb: EventCallback) =>
eventEmitter.removeListener(eventName, cb);
}