Merge "Fix show more button"
diff --git a/javatests/com/google/gerrit/acceptance/git/RefAdvertisementIT.java b/javatests/com/google/gerrit/acceptance/git/RefAdvertisementIT.java
index 8aca887..b7acbe2 100644
--- a/javatests/com/google/gerrit/acceptance/git/RefAdvertisementIT.java
+++ b/javatests/com/google/gerrit/acceptance/git/RefAdvertisementIT.java
@@ -58,7 +58,6 @@
 import com.google.gerrit.server.permissions.PermissionBackend.RefFilterOptions;
 import com.google.gerrit.server.query.change.ChangeData;
 import com.google.gerrit.testing.ConfigSuite;
-import com.google.gerrit.testing.TestCommentHelper;
 import com.google.inject.Inject;
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -87,7 +86,6 @@
   @Inject private PermissionBackend permissionBackend;
   @Inject private ProjectOperations projectOperations;
   @Inject private RequestScopeOperations requestScopeOperations;
-  @Inject private TestCommentHelper testCommentHelper;
 
   private AccountGroup.UUID admins;
   private AccountGroup.UUID nonInteractiveUsers;
diff --git a/polygerrit-ui/app/api/admin.ts b/polygerrit-ui/app/api/admin.ts
new file mode 100644
index 0000000..a7b549d
--- /dev/null
+++ b/polygerrit-ui/app/api/admin.ts
@@ -0,0 +1,29 @@
+/**
+ * @license
+ * Copyright (C) 2020 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.
+ */
+
+/** Interface for menu link */
+export interface MenuLink {
+  text: string;
+  url: string;
+  capability: string | null;
+}
+
+export interface AdminPluginApi {
+  addMenuLink(text: string, url: string, capability?: string): void;
+
+  getMenuLinks(): MenuLink[];
+}
diff --git a/polygerrit-ui/app/api/annotation.ts b/polygerrit-ui/app/api/annotation.ts
new file mode 100644
index 0000000..c046b4f
--- /dev/null
+++ b/polygerrit-ui/app/api/annotation.ts
@@ -0,0 +1,130 @@
+/**
+ * @license
+ * Copyright (C) 2020 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.
+ */
+import {CoverageRange, Side} from './diff';
+import {StyleObject} from './styles';
+
+export type AddLayerFunc = (ctx: AnnotationContext) => void;
+
+export type NotifyFunc = (
+  path: string,
+  start: number,
+  end: number,
+  side: Side
+) => void;
+
+export type CoverageProvider = (
+  changeNum: number,
+  path: string,
+  basePatchNum?: number,
+  patchNum?: number,
+  /**
+   * This is a ChangeInfo object as defined here:
+   * https://gerrit-review.googlesource.com/Documentation/rest-api-changes.html#change-info
+   * We neither want to repeat it nor add a dependency on it here.
+   */
+  change?: unknown
+) => Promise<Array<CoverageRange>>;
+
+export interface AnnotationContext {
+  /**
+   * Method to add annotations to a content line.
+   *
+   * @param offset The char offset where the update starts.
+   * @param length The number of chars that the update covers.
+   * @param styleObject The style object for the range.
+   * @param side The side of the update. ('left' or 'right')
+   */
+  annotateRange(
+    offset: number,
+    length: number,
+    styleObject: StyleObject,
+    side: string
+  ): void;
+
+  /**
+   * Method to add a CSS class to the line number TD element.
+   *
+   * @param styleObject The style object for the range.
+   * @param side The side of the update. ('left' or 'right')
+   */
+  annotateLineNumber(styleObject: StyleObject, side: string): void;
+}
+
+export interface AnnotationPluginApi {
+  /**
+   * Register a function to call to apply annotations. Plugins should use
+   * GrAnnotationActionsContext.annotateRange and
+   * GrAnnotationActionsContext.annotateLineNumber to apply a CSS class to the
+   * line content or the line number.
+   *
+   * @param addLayerFunc The function
+   * that will be called when the AnnotationLayer is ready to annotate.
+   */
+  addLayer(addLayerFunc: AddLayerFunc): AnnotationPluginApi;
+
+  /**
+   * The specified function will be called with a notify function for the plugin
+   * to call when it has all required data for annotation. Optional.
+   *
+   * @param notifyFunc See doc of the notify function below to see what it does.
+   */
+  addNotifier(notifyFunc: (n: NotifyFunc) => void): AnnotationPluginApi;
+
+  /**
+   * The specified function will be called when a gr-diff component is built,
+   * and feeds the returned coverage data into the diff. Optional.
+   *
+   * Be sure to call this only once and only from one plugin. Multiple coverage
+   * providers are not supported. A second call will just overwrite the
+   * provider of the first call.
+   */
+  setCoverageProvider(coverageProvider: CoverageProvider): AnnotationPluginApi;
+
+  /**
+   * Returns a checkbox HTMLElement that can be used to toggle annotations
+   * on/off. The checkbox will be initially disabled. Plugins should enable it
+   * when data is ready and should add a click handler to toggle CSS on/off.
+   *
+   * Note1: Calling this method from multiple plugins will only work for the
+   * 1st call. It will print an error message for all subsequent calls
+   * and will not invoke their onAttached functions.
+   * Note2: This method will be deprecated and eventually removed when
+   * https://bugs.chromium.org/p/gerrit/issues/detail?id=8077 is
+   * implemented.
+   *
+   * @param checkboxLabel Will be used as the label for the checkbox.
+   * Optional. "Enable" is used if this is not specified.
+   * @param onAttached The function that will be called
+   * when the checkbox is attached to the page.
+   */
+  enableToggleCheckbox(
+    checkboxLabel: string,
+    onAttached: (checkboxEl: Element | null) => void
+  ): AnnotationPluginApi;
+
+  /**
+   * The notify function will call the listeners of all required annotation
+   * layers. Intended to be called by the plugin when all required data for
+   * annotation is available.
+   *
+   * @param path The file path whose listeners should be notified.
+   * @param start The line where the update starts.
+   * @param end The line where the update ends.
+   * @param side The side of the update ('left' or 'right').
+   */
+  notify(path: string, start: number, end: number, side: Side): void;
+}
diff --git a/polygerrit-ui/app/api/attribute-helper.ts b/polygerrit-ui/app/api/attribute-helper.ts
new file mode 100644
index 0000000..cd52259
--- /dev/null
+++ b/polygerrit-ui/app/api/attribute-helper.ts
@@ -0,0 +1,39 @@
+/**
+ * @license
+ * Copyright (C) 2020 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.
+ */
+
+export interface AttributeHelperPluginApi {
+  /**
+   * Binds callback to property updates.
+   *
+   * @param name Property name.
+   * @return Unbind function.
+   */
+  // eslint-disable-next-line @typescript-eslint/no-explicit-any
+  bind(name: string, callback: (value: any) => void): () => any;
+
+  /**
+   * Get value of the property from wrapped object. Waits for the property
+   * to be initialized if it isn't defined.
+   */
+  get(name: string): Promise<unknown>;
+
+  /**
+   * Sets value and dispatches event to force notify.
+   */
+  // eslint-disable-next-line @typescript-eslint/no-explicit-any
+  set(name: string, value: any): void;
+}
diff --git a/polygerrit-ui/app/api/change-actions.ts b/polygerrit-ui/app/api/change-actions.ts
new file mode 100644
index 0000000..792f31e
--- /dev/null
+++ b/polygerrit-ui/app/api/change-actions.ts
@@ -0,0 +1,113 @@
+/**
+ * @license
+ * Copyright (C) 2020 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.
+ */
+import {HttpMethod} from './rest';
+
+export interface ActionInfo {
+  method?: HttpMethod;
+  label?: string;
+  title?: string;
+  enabled?: boolean;
+}
+
+export enum ActionType {
+  CHANGE = 'change',
+  REVISION = 'revision',
+}
+
+export enum ActionPriority {
+  CHANGE = 2,
+  DEFAULT = 0,
+  PRIMARY = 3,
+  REVIEW = -3,
+  REVISION = 1,
+}
+
+export enum ChangeActions {
+  ABANDON = 'abandon',
+  DELETE = '/',
+  DELETE_EDIT = 'deleteEdit',
+  EDIT = 'edit',
+  FOLLOW_UP = 'followup',
+  IGNORE = 'ignore',
+  MOVE = 'move',
+  PRIVATE = 'private',
+  PRIVATE_DELETE = 'private.delete',
+  PUBLISH_EDIT = 'publishEdit',
+  REBASE = 'rebase',
+  REBASE_EDIT = 'rebaseEdit',
+  READY = 'ready',
+  RESTORE = 'restore',
+  REVERT = 'revert',
+  REVERT_SUBMISSION = 'revert_submission',
+  REVIEWED = 'reviewed',
+  STOP_EDIT = 'stopEdit',
+  SUBMIT = 'submit',
+  UNIGNORE = 'unignore',
+  UNREVIEWED = 'unreviewed',
+  WIP = 'wip',
+}
+
+export enum RevisionActions {
+  CHERRYPICK = 'cherrypick',
+  REBASE = 'rebase',
+  SUBMIT = 'submit',
+  DOWNLOAD = 'download',
+}
+
+export type PrimaryActionKey = ChangeActions | RevisionActions;
+
+export interface ChangeActionsPluginApi {
+  addPrimaryActionKey(key: PrimaryActionKey): void;
+
+  removePrimaryActionKey(key: string): void;
+
+  hideQuickApproveAction(): void;
+
+  setActionOverflow(type: ActionType, key: string, overflow: boolean): void;
+
+  setActionPriority(
+    type: ActionType,
+    key: string,
+    priority: ActionPriority
+  ): void;
+
+  setActionHidden(type: ActionType, key: string, hidden: boolean): void;
+
+  add(type: ActionType, label: string): string;
+
+  remove(key: string): void;
+
+  addTapListener(
+    key: string,
+    handler: EventListenerOrEventListenerObject
+  ): void;
+
+  removeTapListener(
+    key: string,
+    handler: EventListenerOrEventListenerObject
+  ): void;
+
+  setLabel(key: string, text: string): void;
+
+  setTitle(key: string, text: string): void;
+
+  setEnabled(key: string, enabled: boolean): void;
+
+  setIcon(key: string, icon: string): void;
+
+  getActionDetails(action: string): ActionInfo | undefined;
+}
diff --git a/polygerrit-ui/app/api/change-metadata.ts b/polygerrit-ui/app/api/change-metadata.ts
new file mode 100644
index 0000000..effe661
--- /dev/null
+++ b/polygerrit-ui/app/api/change-metadata.ts
@@ -0,0 +1,20 @@
+/**
+ * @license
+ * Copyright (C) 2020 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.
+ */
+
+export interface ChangeMetadataPluginApi {
+  onLabelsChanged(callback: (value: unknown) => void): ChangeMetadataPluginApi;
+}
diff --git a/polygerrit-ui/app/api/change-reply.ts b/polygerrit-ui/app/api/change-reply.ts
new file mode 100644
index 0000000..37c96ee
--- /dev/null
+++ b/polygerrit-ui/app/api/change-reply.ts
@@ -0,0 +1,39 @@
+/**
+ * @license
+ * Copyright (C) 2020 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.
+ */
+export interface LabelsChangedDetail {
+  name: string;
+  value: string;
+}
+export interface ValueChangedDetail {
+  value: string;
+}
+export type ReplyChangedCallback = (text: string) => void;
+export type LabelsChangedCallback = (detail: LabelsChangedDetail) => void;
+
+export interface ChangeReplyPluginApi {
+  getLabelValue(label: string): string;
+
+  setLabelValue(label: string, value: string): void;
+
+  send(includeComments?: boolean): void;
+
+  addReplyTextChangedCallback(handler: ReplyChangedCallback): void;
+
+  addLabelValuesChangedCallback(handler: LabelsChangedCallback): void;
+
+  showMessage(message: string): void;
+}
diff --git a/polygerrit-ui/app/api/checks.ts b/polygerrit-ui/app/api/checks.ts
index 87d7a2a..143fbd1 100644
--- a/polygerrit-ui/app/api/checks.ts
+++ b/polygerrit-ui/app/api/checks.ts
@@ -20,7 +20,7 @@
 // Changes to all type and interfaces are expected.
 // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
 
-export interface GrChecksApiInterface {
+export interface ChecksPluginApi {
   /**
    * Must only be called once. You cannot register twice. You cannot unregister.
    */
diff --git a/polygerrit-ui/app/api/event-helper.ts b/polygerrit-ui/app/api/event-helper.ts
new file mode 100644
index 0000000..c4a559b
--- /dev/null
+++ b/polygerrit-ui/app/api/event-helper.ts
@@ -0,0 +1,49 @@
+/**
+ * @license
+ * Copyright (C) 2020 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.
+ */
+export type UnsubscribeCallback = () => void;
+
+export interface EventHelperPluginApi {
+  /**
+   * Add a callback to arbitrary event.
+   * The callback may return false to prevent event bubbling.
+   */
+  on(event: string, callback: (event: Event) => boolean): UnsubscribeCallback;
+
+  /**
+   * Alias for @see onClick
+   */
+  onTap(callback: (event: Event) => boolean): UnsubscribeCallback;
+
+  /**
+   * Add a callback to element click or touch.
+   * The callback may return false to prevent event bubbling.
+   */
+  onClick(callback: (event: Event) => boolean): UnsubscribeCallback;
+
+  /**
+   * Alias for @see captureClick
+   */
+  captureTap(callback: (event: Event) => boolean): UnsubscribeCallback;
+
+  /**
+   * Add a callback to element click or touch ahead of normal flow.
+   * Callback is installed on parent during capture phase.
+   * https://www.w3.org/TR/DOM-Level-3-Events/#event-flow
+   * The callback may return false to cancel regular event listeners.
+   */
+  captureClick(callback: (event: Event) => boolean): UnsubscribeCallback;
+}
diff --git a/polygerrit-ui/app/api/hook.ts b/polygerrit-ui/app/api/hook.ts
new file mode 100644
index 0000000..179b967
--- /dev/null
+++ b/polygerrit-ui/app/api/hook.ts
@@ -0,0 +1,52 @@
+/**
+ * @license
+ * Copyright (C) 2020 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.
+ */
+interface GerritElementExtensions {
+  content?: HTMLElement & {hidden?: boolean};
+  change?: unknown;
+  revision?: unknown;
+  token?: string;
+  repoName?: string;
+  /**
+   * This is a ConfigInfo object as defined here:
+   * https://gerrit-review.googlesource.com/Documentation/rest-api-projects.html#config-info
+   * We neither want to repeat it nor add a dependency on it here.
+   */
+  config?: unknown;
+}
+
+export type HookCallback = (el: HTMLElement & GerritElementExtensions) => void;
+
+export interface RegisterOptions {
+  slot?: string;
+  replace: unknown;
+}
+
+export interface HookApi {
+  onAttached(callback: HookCallback): HookApi;
+
+  onDetached(callback: HookCallback): HookApi;
+
+  getAllAttached(): HTMLElement[];
+
+  getLastAttached(): Promise<HTMLElement>;
+
+  getModuleName(): string;
+
+  handleInstanceDetached(instance: HTMLElement): void;
+
+  handleInstanceAttached(instance: HTMLElement): void;
+}
diff --git a/polygerrit-ui/app/api/plugin.ts b/polygerrit-ui/app/api/plugin.ts
new file mode 100644
index 0000000..cd742a2
--- /dev/null
+++ b/polygerrit-ui/app/api/plugin.ts
@@ -0,0 +1,92 @@
+/**
+ * @license
+ * Copyright (C) 2020 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.
+ */
+import {AdminPluginApi} from './admin';
+import {AnnotationPluginApi} from './annotation';
+import {AttributeHelperPluginApi} from './attribute-helper';
+import {ChangeMetadataPluginApi} from './change-metadata';
+import {ChangeReplyPluginApi} from './change-reply';
+import {ChecksPluginApi} from './checks';
+import {EventHelperPluginApi} from './event-helper';
+import {PopupPluginApi} from './popup';
+import {RepoPluginApi} from './repo';
+import {ReportingPluginApi} from './reporting';
+import {SettingsPluginApi} from './settings';
+import {StylesPluginApi} from './styles';
+import {ThemePluginApi} from './theme';
+import {ChangeActionsPluginApi} from './change-actions';
+import {RestPluginApi} from './rest';
+import {HookApi, RegisterOptions} from './hook';
+
+export enum TargetElement {
+  CHANGE_ACTIONS = 'changeactions',
+  REPLY_DIALOG = 'replydialog',
+}
+
+// Note: for new events, naming convention should be: `a-b`
+export enum EventType {
+  HISTORY = 'history',
+  LABEL_CHANGE = 'labelchange',
+  SHOW_CHANGE = 'showchange',
+  SUBMIT_CHANGE = 'submitchange',
+  SHOW_REVISION_ACTIONS = 'show-revision-actions',
+  COMMIT_MSG_EDIT = 'commitmsgedit',
+  COMMENT = 'comment',
+  REVERT = 'revert',
+  REVERT_SUBMISSION = 'revert_submission',
+  POST_REVERT = 'postrevert',
+  ANNOTATE_DIFF = 'annotatediff',
+  ADMIN_MENU_LINKS = 'admin-menu-links',
+  HIGHLIGHTJS_LOADED = 'highlightjs-loaded',
+}
+
+export interface PluginApi {
+  _url?: URL;
+  admin(): AdminPluginApi;
+  annotationApi(): AnnotationPluginApi;
+  attributeHelper(element: Element): AttributeHelperPluginApi;
+  changeActions(): ChangeActionsPluginApi;
+  changeMetadata(): ChangeMetadataPluginApi;
+  changeReply(): ChangeReplyPluginApi;
+  checks(): ChecksPluginApi;
+  eventHelper(element: Node): EventHelperPluginApi;
+  getPluginName(): string;
+  hook(endpointName: string, opt_options?: RegisterOptions): HookApi;
+  // eslint-disable-next-line @typescript-eslint/no-explicit-any
+  on(eventName: EventType, target: any): void;
+  popup(): Promise<PopupPluginApi>;
+  popup(moduleName: string): Promise<PopupPluginApi>;
+  popup(moduleName?: string): Promise<PopupPluginApi | null>;
+  project(): RepoPluginApi;
+  registerCustomComponent(
+    endpointName: string,
+    moduleName?: string,
+    options?: RegisterOptions
+  ): HookApi;
+  registerDynamicCustomComponent(
+    endpointName: string,
+    moduleName?: string,
+    options?: RegisterOptions
+  ): HookApi;
+  registerStyleModule(endpoint: string, moduleName: string): void;
+  reporting(): ReportingPluginApi;
+  restApi(): RestPluginApi;
+  // eslint-disable-next-line @typescript-eslint/no-explicit-any
+  screen(screenName: string, moduleName?: string): any;
+  settings(): SettingsPluginApi;
+  styles(): StylesPluginApi;
+  theme(): ThemePluginApi;
+}
diff --git a/polygerrit-ui/app/api/popup.ts b/polygerrit-ui/app/api/popup.ts
new file mode 100644
index 0000000..60772cc
--- /dev/null
+++ b/polygerrit-ui/app/api/popup.ts
@@ -0,0 +1,30 @@
+/**
+ * @license
+ * Copyright (C) 2020 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.
+ */
+
+export interface PopupPluginApi {
+  /**
+   * Opens the popup, inserts it into DOM over current UI.
+   * Creates the popup if not previously created. Creates popup content element,
+   * if it was provided with constructor.
+   */
+  open(): Promise<PopupPluginApi>;
+
+  /**
+   * Hides the popup.
+   */
+  close(): void;
+}
diff --git a/polygerrit-ui/app/api/repo.ts b/polygerrit-ui/app/api/repo.ts
new file mode 100644
index 0000000..a626471
--- /dev/null
+++ b/polygerrit-ui/app/api/repo.ts
@@ -0,0 +1,31 @@
+/**
+ * @license
+ * Copyright (C) 2020 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.
+ */
+export type RepoCommandCallback = (
+  repo?: string,
+  /**
+   * This is a ConfigInfo object as defined here:
+   * https://gerrit-review.googlesource.com/Documentation/rest-api-projects.html#config-info
+   * We neither want to repeat it nor add a dependency on it here.
+   */
+  config?: unknown
+) => boolean;
+
+export interface RepoPluginApi {
+  createCommand(title: string, callback: RepoCommandCallback): RepoPluginApi;
+
+  onTap(callback: (event: Event) => boolean): RepoPluginApi;
+}
diff --git a/polygerrit-ui/app/api/reporting.ts b/polygerrit-ui/app/api/reporting.ts
new file mode 100644
index 0000000..65bdc3f
--- /dev/null
+++ b/polygerrit-ui/app/api/reporting.ts
@@ -0,0 +1,25 @@
+/**
+ * @license
+ * Copyright (C) 2020 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.
+ */
+
+// eslint-disable-next-line @typescript-eslint/no-explicit-any
+export type EventDetails = any;
+
+export interface ReportingPluginApi {
+  reportInteraction(eventName: string, details?: EventDetails): void;
+
+  reportLifeCycle(eventName: string, details?: EventDetails): void;
+}
diff --git a/polygerrit-ui/app/api/rest.ts b/polygerrit-ui/app/api/rest.ts
new file mode 100644
index 0000000..fd9cada
--- /dev/null
+++ b/polygerrit-ui/app/api/rest.ts
@@ -0,0 +1,106 @@
+/**
+ * @license
+ * Copyright (C) 2020 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.
+ */
+export type RequestPayload = string | object;
+
+export enum HttpMethod {
+  HEAD = 'HEAD',
+  POST = 'POST',
+  GET = 'GET',
+  DELETE = 'DELETE',
+  PUT = 'PUT',
+}
+
+export type ErrorCallback = (response?: Response | null, err?: Error) => void;
+
+export interface RestPluginApi {
+  getLoggedIn(): Promise<boolean>;
+
+  getVersion(): Promise<string | undefined>;
+
+  /**
+   * Returns a ServerInfo object as defined here:
+   * https://gerrit-review.googlesource.com/Documentation/rest-api-config.html#server-info
+   * We neither want to repeat it nor add a dependency on it here.
+   */
+  getConfig(): Promise<unknown>;
+
+  invalidateReposCache(): void;
+
+  fetch(
+    method: HttpMethod,
+    url: string,
+    payload?: RequestPayload,
+    errFn?: undefined,
+    contentType?: string
+  ): Promise<Response>;
+
+  fetch(
+    method: HttpMethod,
+    url: string,
+    payload: RequestPayload | undefined,
+    errFn: ErrorCallback,
+    contentType?: string
+  ): Promise<Response | void>;
+
+  fetch(
+    method: HttpMethod,
+    url: string,
+    payload: RequestPayload | undefined,
+    errFn?: ErrorCallback,
+    contentType?: string
+  ): Promise<Response | void>;
+
+  /**
+   * Fetch and return native browser REST API Response.
+   */
+  fetch(
+    method: HttpMethod,
+    url: string,
+    payload?: RequestPayload,
+    errFn?: ErrorCallback,
+    contentType?: string
+  ): Promise<Response | void>;
+
+  /**
+   * Fetch and parse REST API response, if request succeeds.
+   */
+  send(
+    method: HttpMethod,
+    url: string,
+    payload?: RequestPayload,
+    errFn?: ErrorCallback,
+    contentType?: string
+  ): Promise<unknown>;
+
+  get(url: string): Promise<unknown>;
+
+  post(
+    url: string,
+    payload?: RequestPayload,
+    errFn?: ErrorCallback,
+    contentType?: string
+  ): Promise<unknown>;
+
+  put(
+    url: string,
+    payload?: RequestPayload,
+    errFn?: ErrorCallback,
+    contentType?: string
+  ): Promise<unknown>;
+
+  delete(url: string): Promise<Response>;
+}
diff --git a/polygerrit-ui/app/api/settings.ts b/polygerrit-ui/app/api/settings.ts
new file mode 100644
index 0000000..03cf474
--- /dev/null
+++ b/polygerrit-ui/app/api/settings.ts
@@ -0,0 +1,27 @@
+/**
+ * @license
+ * Copyright (C) 2020 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.
+ */
+import {HookApi} from './hook';
+
+export interface SettingsPluginApi {
+  title(newTitle: string): SettingsPluginApi;
+
+  token(newToken: string): SettingsPluginApi;
+
+  module(newModuleName: string): SettingsPluginApi;
+
+  build(): HookApi;
+}
diff --git a/polygerrit-ui/app/api/styles.ts b/polygerrit-ui/app/api/styles.ts
new file mode 100644
index 0000000..233c3e2
--- /dev/null
+++ b/polygerrit-ui/app/api/styles.ts
@@ -0,0 +1,35 @@
+/**
+ * @license
+ * Copyright (C) 2020 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.
+ */
+
+export interface StyleObject {
+  /**
+   * Creates a new unique CSS class and injects it in a root node of the element
+   * if it hasn't been added yet. A root node is an document or is the
+   * associated shadowRoot. This class can be added to any element with the same
+   * root node.
+   */
+  getClassName(element: Element): string;
+
+  /**
+   * Apply shared style to the element.
+   */
+  apply(element: Element): void;
+}
+
+export interface StylesPluginApi {
+  css(ruleStr: string): StyleObject;
+}
diff --git a/polygerrit-ui/app/api/theme.ts b/polygerrit-ui/app/api/theme.ts
new file mode 100644
index 0000000..70ffcb3
--- /dev/null
+++ b/polygerrit-ui/app/api/theme.ts
@@ -0,0 +1,20 @@
+/**
+ * @license
+ * Copyright (C) 2020 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.
+ */
+
+export interface ThemePluginApi {
+  setHeaderLogoAndTitle(logoUrl: string, title: string): void;
+}
diff --git a/polygerrit-ui/app/elements/admin/gr-group-audit-log/gr-group-audit-log.ts b/polygerrit-ui/app/elements/admin/gr-group-audit-log/gr-group-audit-log.ts
index 3aeea3b..bc4750f 100644
--- a/polygerrit-ui/app/elements/admin/gr-group-audit-log/gr-group-audit-log.ts
+++ b/polygerrit-ui/app/elements/admin/gr-group-audit-log/gr-group-audit-log.ts
@@ -26,7 +26,6 @@
 import {ListViewMixin} from '../../../mixins/gr-list-view-mixin/gr-list-view-mixin';
 import {GerritNav} from '../../core/gr-navigation/gr-navigation';
 import {customElement, property} from '@polymer/decorators';
-import {ErrorCallback} from '../../../services/gr-rest-api/gr-rest-api';
 import {
   GroupInfo,
   AccountInfo,
@@ -35,6 +34,7 @@
 } from '../../../types/common';
 import {firePageError, fireTitleChange} from '../../../utils/event-util';
 import {appContext} from '../../../services/app-context';
+import {ErrorCallback} from '../../../api/rest';
 
 const GROUP_EVENTS = ['ADD_GROUP', 'REMOVE_GROUP'];
 
diff --git a/polygerrit-ui/app/elements/admin/gr-group-members/gr-group-members.ts b/polygerrit-ui/app/elements/admin/gr-group-members/gr-group-members.ts
index f5602a3..451139c 100644
--- a/polygerrit-ui/app/elements/admin/gr-group-members/gr-group-members.ts
+++ b/polygerrit-ui/app/elements/admin/gr-group-members/gr-group-members.ts
@@ -30,7 +30,6 @@
 import {htmlTemplate} from './gr-group-members_html';
 import {getBaseUrl} from '../../../utils/url-util';
 import {customElement, property} from '@polymer/decorators';
-import {ErrorCallback} from '../../../services/gr-rest-api/gr-rest-api';
 import {GrOverlay} from '../../shared/gr-overlay/gr-overlay';
 import {
   GroupId,
@@ -50,6 +49,7 @@
   fireTitleChange,
 } from '../../../utils/event-util';
 import {appContext} from '../../../services/app-context';
+import {ErrorCallback} from '../../../api/rest';
 
 const SUGGESTIONS_LIMIT = 15;
 const SAVING_ERROR_TEXT =
diff --git a/polygerrit-ui/app/elements/admin/gr-group/gr-group.ts b/polygerrit-ui/app/elements/admin/gr-group/gr-group.ts
index 058f86b..6f00445 100644
--- a/polygerrit-ui/app/elements/admin/gr-group/gr-group.ts
+++ b/polygerrit-ui/app/elements/admin/gr-group/gr-group.ts
@@ -32,13 +32,13 @@
   AutocompleteQuery,
 } from '../../shared/gr-autocomplete/gr-autocomplete';
 import {GroupId, GroupInfo, GroupName} from '../../../types/common';
-import {ErrorCallback} from '../../../services/gr-rest-api/gr-rest-api';
 import {
   fireEvent,
   firePageError,
   fireTitleChange,
 } from '../../../utils/event-util';
 import {appContext} from '../../../services/app-context';
+import {ErrorCallback} from '../../../api/rest';
 
 const INTERNAL_GROUP_REGEX = /^[\da-f]{40}$/;
 
diff --git a/polygerrit-ui/app/elements/admin/gr-plugin-list/gr-plugin-list.ts b/polygerrit-ui/app/elements/admin/gr-plugin-list/gr-plugin-list.ts
index ceb08b6..fc1ceee 100644
--- a/polygerrit-ui/app/elements/admin/gr-plugin-list/gr-plugin-list.ts
+++ b/polygerrit-ui/app/elements/admin/gr-plugin-list/gr-plugin-list.ts
@@ -26,11 +26,11 @@
   ListViewParams,
 } from '../../../mixins/gr-list-view-mixin/gr-list-view-mixin';
 import {customElement, property} from '@polymer/decorators';
-import {ErrorCallback} from '../../../services/gr-rest-api/gr-rest-api';
 import {PluginInfo} from '../../../types/common';
 import {firePageError} from '../../../utils/event-util';
 import {fireTitleChange} from '../../../utils/event-util';
 import {appContext} from '../../../services/app-context';
+import {ErrorCallback} from '../../../api/rest';
 
 interface PluginInfoWithName extends PluginInfo {
   name: string;
diff --git a/polygerrit-ui/app/elements/admin/gr-repo-commands/gr-repo-commands.ts b/polygerrit-ui/app/elements/admin/gr-repo-commands/gr-repo-commands.ts
index 9bc0466..14cf234 100644
--- a/polygerrit-ui/app/elements/admin/gr-repo-commands/gr-repo-commands.ts
+++ b/polygerrit-ui/app/elements/admin/gr-repo-commands/gr-repo-commands.ts
@@ -29,7 +29,6 @@
 import {htmlTemplate} from './gr-repo-commands_html';
 import {GerritNav} from '../../core/gr-navigation/gr-navigation';
 import {customElement, property} from '@polymer/decorators';
-import {ErrorCallback} from '../../../services/gr-rest-api/gr-rest-api';
 import {
   BranchName,
   ConfigInfo,
@@ -44,6 +43,7 @@
   fireTitleChange,
 } from '../../../utils/event-util';
 import {appContext} from '../../../services/app-context';
+import {ErrorCallback} from '../../../api/rest';
 
 const GC_MESSAGE = 'Garbage collection completed successfully.';
 const CONFIG_BRANCH = 'refs/meta/config' as BranchName;
diff --git a/polygerrit-ui/app/elements/admin/gr-repo-dashboards/gr-repo-dashboards.ts b/polygerrit-ui/app/elements/admin/gr-repo-dashboards/gr-repo-dashboards.ts
index b30d1f4..5f6cd29 100644
--- a/polygerrit-ui/app/elements/admin/gr-repo-dashboards/gr-repo-dashboards.ts
+++ b/polygerrit-ui/app/elements/admin/gr-repo-dashboards/gr-repo-dashboards.ts
@@ -24,9 +24,9 @@
 import {GerritNav} from '../../core/gr-navigation/gr-navigation';
 import {customElement, property} from '@polymer/decorators';
 import {RepoName, DashboardId, DashboardInfo} from '../../../types/common';
-import {ErrorCallback} from '../../../services/gr-rest-api/gr-rest-api';
 import {firePageError} from '../../../utils/event-util';
 import {appContext} from '../../../services/app-context';
+import {ErrorCallback} from '../../../api/rest';
 
 interface DashboardRef {
   section: string;
diff --git a/polygerrit-ui/app/elements/admin/gr-repo-detail-list/gr-repo-detail-list.ts b/polygerrit-ui/app/elements/admin/gr-repo-detail-list/gr-repo-detail-list.ts
index 5325dc7..a486e27 100644
--- a/polygerrit-ui/app/elements/admin/gr-repo-detail-list/gr-repo-detail-list.ts
+++ b/polygerrit-ui/app/elements/admin/gr-repo-detail-list/gr-repo-detail-list.ts
@@ -35,7 +35,6 @@
 import {ListViewMixin} from '../../../mixins/gr-list-view-mixin/gr-list-view-mixin';
 import {encodeURL} from '../../../utils/url-util';
 import {customElement, property} from '@polymer/decorators';
-import {ErrorCallback} from '../../../services/gr-rest-api/gr-rest-api';
 import {GrOverlay} from '../../shared/gr-overlay/gr-overlay';
 import {GrCreatePointerDialog} from '../gr-create-pointer-dialog/gr-create-pointer-dialog';
 import {
@@ -51,6 +50,7 @@
 import {RepoDetailView} from '../../core/gr-navigation/gr-navigation';
 import {firePageError} from '../../../utils/event-util';
 import {appContext} from '../../../services/app-context';
+import {ErrorCallback} from '../../../api/rest';
 
 const PGP_START = '-----BEGIN PGP SIGNATURE-----';
 
diff --git a/polygerrit-ui/app/elements/admin/gr-repo/gr-repo.ts b/polygerrit-ui/app/elements/admin/gr-repo/gr-repo.ts
index 3543e3b..bcc6039 100644
--- a/polygerrit-ui/app/elements/admin/gr-repo/gr-repo.ts
+++ b/polygerrit-ui/app/elements/admin/gr-repo/gr-repo.ts
@@ -30,7 +30,6 @@
 import {htmlTemplate} from './gr-repo_html';
 import {GerritNav} from '../../core/gr-navigation/gr-navigation';
 import {customElement, property, observe} from '@polymer/decorators';
-import {ErrorCallback} from '../../../services/gr-rest-api/gr-rest-api';
 import {
   ConfigInfo,
   RepoName,
@@ -47,6 +46,7 @@
 import {firePageError, fireTitleChange} from '../../../utils/event-util';
 import {appContext} from '../../../services/app-context';
 import {WebLinkInfo} from '../../../types/diff';
+import {ErrorCallback} from '../../../api/rest';
 
 const STATES = {
   active: {value: ProjectState.ACTIVE, label: 'Active'},
diff --git a/polygerrit-ui/app/elements/change/gr-change-actions/gr-change-actions.ts b/polygerrit-ui/app/elements/change/gr-change-actions/gr-change-actions.ts
index 903afaa..89ca4ef 100644
--- a/polygerrit-ui/app/elements/change/gr-change-actions/gr-change-actions.ts
+++ b/polygerrit-ui/app/elements/change/gr-change-actions/gr-change-actions.ts
@@ -50,17 +50,9 @@
   HttpMethod,
   NotifyType,
 } from '../../../constants/constants';
-import {
-  EventType as PluginEventType,
-  TargetElement,
-} from '../../plugins/gr-plugin-types';
+import {EventType as PluginEventType, TargetElement} from '../../../api/plugin';
 import {customElement, observe, property} from '@polymer/decorators';
 import {
-  ActionPriority,
-  ActionType,
-  ErrorCallback,
-} from '../../../services/gr-rest-api/gr-rest-api';
-import {
   AccountInfo,
   ActionInfo,
   ActionNameToActionInfoMap,
@@ -102,10 +94,7 @@
 import {PolymerDeepPropertyChange} from '@polymer/polymer/interfaces';
 import {GrButton} from '../../shared/gr-button/gr-button';
 import {
-  ChangeActions,
   GrChangeActionsElement,
-  PrimaryActionKey,
-  RevisionActions,
   UIActionInfo,
 } from '../../shared/gr-js-api-interface/gr-change-actions-js-api';
 import {fireAlert} from '../../../utils/event-util';
@@ -116,6 +105,14 @@
 } from '../../../utils/label-util';
 import {CommentThread} from '../../../utils/comment-util';
 import {ShowAlertEventDetail} from '../../../types/events';
+import {
+  ActionPriority,
+  ActionType,
+  ChangeActions,
+  PrimaryActionKey,
+  RevisionActions,
+} from '../../../api/change-actions';
+import {ErrorCallback} from '../../../api/rest';
 
 const ERR_BRANCH_EMPTY = 'The destination branch can’t be empty.';
 const ERR_COMMIT_EMPTY = 'The commit message can’t be empty.';
diff --git a/polygerrit-ui/app/elements/change/gr-change-metadata/gr-change-metadata_test.ts b/polygerrit-ui/app/elements/change/gr-change-metadata/gr-change-metadata_test.ts
index 11f1050..59287b2 100644
--- a/polygerrit-ui/app/elements/change/gr-change-metadata/gr-change-metadata_test.ts
+++ b/polygerrit-ui/app/elements/change/gr-change-metadata/gr-change-metadata_test.ts
@@ -61,7 +61,7 @@
 import {RestApiService} from '../../../services/gr-rest-api/gr-rest-api';
 import {tap} from '@polymer/iron-test-helpers/mock-interactions';
 import {GrEditableLabel} from '../../shared/gr-editable-label/gr-editable-label';
-import {PluginApi} from '../../plugins/gr-plugin-types';
+import {PluginApi} from '../../../api/plugin';
 import {GrEndpointDecorator} from '../../plugins/gr-endpoint-decorator/gr-endpoint-decorator';
 import {stubRestApi} from '../../../test/test-utils.js';
 import {ParsedChangeInfo} from '../../../types/types';
diff --git a/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view.ts b/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view.ts
index 5afcafc..61006f9 100644
--- a/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view.ts
+++ b/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view.ts
@@ -78,7 +78,7 @@
   PatchSet,
 } from '../../../utils/patch-set-util';
 import {changeStatuses, changeStatusString} from '../../../utils/change-util';
-import {EventType as PluginEventType} from '../../plugins/gr-plugin-types';
+import {EventType as PluginEventType} from '../../../api/plugin';
 import {customElement, property, observe} from '@polymer/decorators';
 import {GrApplyFixDialog} from '../../diff/gr-apply-fix-dialog/gr-apply-fix-dialog';
 import {GrFileListHeader} from '../gr-file-list-header/gr-file-list-header';
diff --git a/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view_test.ts b/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view_test.ts
index b9e925c..99e5356 100644
--- a/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view_test.ts
+++ b/polygerrit-ui/app/elements/change/gr-change-view/gr-change-view_test.ts
@@ -33,7 +33,7 @@
 import {GerritNav} from '../../core/gr-navigation/gr-navigation';
 import {getPluginLoader} from '../../shared/gr-js-api-interface/gr-plugin-loader';
 import {_testOnly_initGerritPluginApi} from '../../shared/gr-js-api-interface/gr-gerrit';
-import {EventType, PluginApi} from '../../plugins/gr-plugin-types';
+import {EventType, PluginApi} from '../../../api/plugin';
 
 import 'lodash/lodash';
 import {
diff --git a/polygerrit-ui/app/elements/change/gr-reply-dialog/gr-reply-dialog.ts b/polygerrit-ui/app/elements/change/gr-reply-dialog/gr-reply-dialog.ts
index e5396c3..95a6af9 100644
--- a/polygerrit-ui/app/elements/change/gr-reply-dialog/gr-reply-dialog.ts
+++ b/polygerrit-ui/app/elements/change/gr-reply-dialog/gr-reply-dialog.ts
@@ -46,9 +46,8 @@
 import {accountKey, removeServiceUsers} from '../../../utils/account-util';
 import {getDisplayName} from '../../../utils/display-name-util';
 import {IronA11yAnnouncer} from '@polymer/iron-a11y-announcer/iron-a11y-announcer';
-import {TargetElement} from '../../plugins/gr-plugin-types';
+import {TargetElement} from '../../../api/plugin';
 import {customElement, observe, property} from '@polymer/decorators';
-import {ErrorCallback} from '../../../services/gr-rest-api/gr-rest-api';
 import {FixIronA11yAnnouncer} from '../../../types/types';
 import {
   AccountAddition,
@@ -110,6 +109,7 @@
 import {isUnresolved} from '../../../utils/comment-util';
 import {pluralize} from '../../../utils/string-util';
 import {fireAlert, fireEvent, fireServerError} from '../../../utils/event-util';
+import {ErrorCallback} from '../../../api/rest';
 
 const STORAGE_DEBOUNCE_INTERVAL_MS = 400;
 
diff --git a/polygerrit-ui/app/elements/edit/gr-editor-view/gr-editor-view.ts b/polygerrit-ui/app/elements/edit/gr-editor-view/gr-editor-view.ts
index e9637af..f6f4395 100644
--- a/polygerrit-ui/app/elements/edit/gr-editor-view/gr-editor-view.ts
+++ b/polygerrit-ui/app/elements/edit/gr-editor-view/gr-editor-view.ts
@@ -32,7 +32,6 @@
 } from '../../core/gr-navigation/gr-navigation';
 import {computeTruncatedPath} from '../../../utils/path-list-util';
 import {customElement, property} from '@polymer/decorators';
-import {ErrorCallback} from '../../../services/gr-rest-api/gr-rest-api';
 import {
   ChangeInfo,
   PatchSetNum,
@@ -45,6 +44,7 @@
 import {HttpMethod, NotifyType} from '../../../constants/constants';
 import {fireAlert, fireTitleChange} from '../../../utils/event-util';
 import {appContext} from '../../../services/app-context';
+import {ErrorCallback} from '../../../api/rest';
 
 const RESTORED_MESSAGE = 'Content restored from a previous edit.';
 const SAVING_MESSAGE = 'Saving changes...';
diff --git a/polygerrit-ui/app/elements/plugins/gr-admin-api/gr-admin-api.ts b/polygerrit-ui/app/elements/plugins/gr-admin-api/gr-admin-api.ts
index 1332118..897be67 100644
--- a/polygerrit-ui/app/elements/plugins/gr-admin-api/gr-admin-api.ts
+++ b/polygerrit-ui/app/elements/plugins/gr-admin-api/gr-admin-api.ts
@@ -14,27 +14,20 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-
-import {PluginApi} from '../gr-plugin-types';
-
-/** Interface for menu link */
-export interface MenuLink {
-  text: string;
-  url: string;
-  capability: string | null;
-}
+import {EventType, PluginApi} from '../../../api/plugin';
+import {AdminPluginApi, MenuLink} from '../../../api/admin';
 
 /**
  * GrAdminApi class.
  *
  * Defines common methods to register / retrieve menu links.
  */
-export class GrAdminApi {
+export class GrAdminApi implements AdminPluginApi {
   // TODO(TS): maybe define as enum if its a limited set
   private menuLinks: MenuLink[] = [];
 
   constructor(private readonly plugin: PluginApi) {
-    this.plugin.on('admin-menu-links', this);
+    this.plugin.on(EventType.ADMIN_MENU_LINKS, this);
   }
 
   addMenuLink(text: string, url: string, capability?: string) {
diff --git a/polygerrit-ui/app/elements/plugins/gr-attribute-helper/gr-attribute-helper.ts b/polygerrit-ui/app/elements/plugins/gr-attribute-helper/gr-attribute-helper.ts
index 0641b49..e0b4ee9 100644
--- a/polygerrit-ui/app/elements/plugins/gr-attribute-helper/gr-attribute-helper.ts
+++ b/polygerrit-ui/app/elements/plugins/gr-attribute-helper/gr-attribute-helper.ts
@@ -14,8 +14,9 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+import {AttributeHelperPluginApi} from '../../../api/attribute-helper';
 
-export class GrAttributeHelper {
+export class GrAttributeHelper implements AttributeHelperPluginApi {
   // eslint-disable-next-line @typescript-eslint/no-explicit-any
   private readonly _promises = new Map<string, Promise<any>>();
 
diff --git a/polygerrit-ui/app/elements/plugins/gr-change-metadata-api/gr-change-metadata-api.ts b/polygerrit-ui/app/elements/plugins/gr-change-metadata-api/gr-change-metadata-api.ts
index 322d32e..3a61bce 100644
--- a/polygerrit-ui/app/elements/plugins/gr-change-metadata-api/gr-change-metadata-api.ts
+++ b/polygerrit-ui/app/elements/plugins/gr-change-metadata-api/gr-change-metadata-api.ts
@@ -14,9 +14,11 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-import {HookApi, PluginApi} from '../gr-plugin-types';
+import {PluginApi} from '../../../api/plugin';
+import {ChangeMetadataPluginApi} from '../../../api/change-metadata';
+import {HookApi} from '../../../api/hook';
 
-export class GrChangeMetadataApi {
+export class GrChangeMetadataApi implements ChangeMetadataPluginApi {
   private _hook: HookApi | null;
 
   public plugin: PluginApi;
diff --git a/polygerrit-ui/app/elements/plugins/gr-checks-api/gr-checks-api.ts b/polygerrit-ui/app/elements/plugins/gr-checks-api/gr-checks-api.ts
index 82c1087..404fc71 100644
--- a/polygerrit-ui/app/elements/plugins/gr-checks-api/gr-checks-api.ts
+++ b/polygerrit-ui/app/elements/plugins/gr-checks-api/gr-checks-api.ts
@@ -14,11 +14,11 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-import {PluginApi} from '../gr-plugin-types';
+import {PluginApi} from '../../../api/plugin';
 import {
   ChecksApiConfig,
   ChecksProvider,
-  GrChecksApiInterface,
+  ChecksPluginApi,
 } from '../../../api/checks';
 import {appContext} from '../../../services/app-context';
 
@@ -38,7 +38,7 @@
  * Plugins normally just call register() once at startup and then wait for
  * fetch() being called on the provider interface.
  */
-export class GrChecksApi implements GrChecksApiInterface {
+export class GrChecksApi implements ChecksPluginApi {
   private state = State.NOT_REGISTERED;
 
   private readonly checksService = appContext.checksService;
diff --git a/polygerrit-ui/app/elements/plugins/gr-checks-api/gr-checks-api_test.ts b/polygerrit-ui/app/elements/plugins/gr-checks-api/gr-checks-api_test.ts
index 45cbb47..3ab3efb 100644
--- a/polygerrit-ui/app/elements/plugins/gr-checks-api/gr-checks-api_test.ts
+++ b/polygerrit-ui/app/elements/plugins/gr-checks-api/gr-checks-api_test.ts
@@ -18,13 +18,13 @@
 import '../../../test/common-test-setup-karma.js';
 import {getPluginLoader} from '../../shared/gr-js-api-interface/gr-plugin-loader.js';
 import {_testOnly_initGerritPluginApi} from '../../shared/gr-js-api-interface/gr-gerrit.js';
-import {GrChecksApi} from './gr-checks-api';
-import {PluginApi} from '../gr-plugin-types';
+import {PluginApi} from '../../../api/plugin';
+import {ChecksPluginApi} from '../../../api/checks';
 
 const gerritPluginApi = _testOnly_initGerritPluginApi();
 
 suite('gr-settings-api tests', () => {
-  let checksApi: GrChecksApi | undefined;
+  let checksApi: ChecksPluginApi | undefined;
 
   setup(() => {
     let pluginApi: PluginApi | undefined = undefined;
diff --git a/polygerrit-ui/app/elements/plugins/gr-dom-hooks/gr-dom-hooks.ts b/polygerrit-ui/app/elements/plugins/gr-dom-hooks/gr-dom-hooks.ts
index dd76be4..d2568ad 100644
--- a/polygerrit-ui/app/elements/plugins/gr-dom-hooks/gr-dom-hooks.ts
+++ b/polygerrit-ui/app/elements/plugins/gr-dom-hooks/gr-dom-hooks.ts
@@ -15,7 +15,8 @@
  * limitations under the License.
  */
 import {PolymerElement} from '@polymer/polymer/polymer-element';
-import {HookApi, HookCallback, PluginApi} from '../gr-plugin-types';
+import {PluginApi} from '../../../api/plugin';
+import {HookApi, HookCallback} from '../../../api/hook';
 
 export class GrDomHooksManager {
   private _hooks: Record<string, GrDomHook>;
diff --git a/polygerrit-ui/app/elements/plugins/gr-endpoint-decorator/gr-endpoint-decorator.ts b/polygerrit-ui/app/elements/plugins/gr-endpoint-decorator/gr-endpoint-decorator.ts
index 12863fd..423cff9 100644
--- a/polygerrit-ui/app/elements/plugins/gr-endpoint-decorator/gr-endpoint-decorator.ts
+++ b/polygerrit-ui/app/elements/plugins/gr-endpoint-decorator/gr-endpoint-decorator.ts
@@ -24,7 +24,8 @@
 } from '../../shared/gr-js-api-interface/gr-plugin-endpoints';
 import {getPluginLoader} from '../../shared/gr-js-api-interface/gr-plugin-loader';
 import {customElement, property} from '@polymer/decorators';
-import {HookApi, PluginApi} from '../gr-plugin-types';
+import {PluginApi} from '../../../api/plugin';
+import {HookApi} from '../../../api/hook';
 
 const INIT_PROPERTIES_TIMEOUT_MS = 10000;
 
diff --git a/polygerrit-ui/app/elements/plugins/gr-event-helper/gr-event-helper.ts b/polygerrit-ui/app/elements/plugins/gr-event-helper/gr-event-helper.ts
index 5a4d2ae..4b34d56 100644
--- a/polygerrit-ui/app/elements/plugins/gr-event-helper/gr-event-helper.ts
+++ b/polygerrit-ui/app/elements/plugins/gr-event-helper/gr-event-helper.ts
@@ -14,13 +14,17 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+import {
+  EventHelperPluginApi,
+  UnsubscribeCallback,
+} from '../../../api/event-helper';
 
 export interface ListenOptions {
   event?: string;
   capture?: boolean;
 }
 
-export class GrEventHelper {
+export class GrEventHelper implements EventHelperPluginApi {
   constructor(readonly element: HTMLElement) {}
 
   /**
@@ -50,7 +54,7 @@
    * Alias for @see captureClick
    */
   captureTap(callback: (event: Event) => boolean) {
-    this.captureClick(callback);
+    return this.captureClick(callback);
   }
 
   /**
@@ -68,7 +72,7 @@
     container: HTMLElement,
     callback: (event: Event) => boolean,
     options?: ListenOptions | null
-  ) {
+  ): UnsubscribeCallback {
     const capture = options?.capture;
     const event = options?.event || 'click';
     const handler = (e: Event) => {
diff --git a/polygerrit-ui/app/elements/plugins/gr-plugin-types.ts b/polygerrit-ui/app/elements/plugins/gr-plugin-types.ts
deleted file mode 100644
index 2cd0f78..0000000
--- a/polygerrit-ui/app/elements/plugins/gr-plugin-types.ts
+++ /dev/null
@@ -1,105 +0,0 @@
-/**
- * @license
- * Copyright (C) 2020 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.
- */
-import {GrAttributeHelper} from './gr-attribute-helper/gr-attribute-helper';
-import {GrPluginRestApi} from '../shared/gr-js-api-interface/gr-plugin-rest-api';
-import {GrEventHelper} from './gr-event-helper/gr-event-helper';
-import {GrPopupInterface} from './gr-popup-interface/gr-popup-interface';
-import {ConfigInfo} from '../../types/common';
-import {GrChecksApi} from './gr-checks-api/gr-checks-api';
-
-interface GerritElementExtensions {
-  content?: HTMLElement & {hidden?: boolean};
-  change?: unknown;
-  revision?: unknown;
-  token?: string;
-  repoName?: string;
-  config?: ConfigInfo;
-}
-export type HookCallback = (el: HTMLElement & GerritElementExtensions) => void;
-
-export interface HookApi {
-  onAttached(callback: HookCallback): HookApi;
-  onDetached(callback: HookCallback): HookApi;
-  getAllAttached(): HTMLElement[];
-  getLastAttached(): Promise<HTMLElement>;
-  getModuleName(): string;
-  handleInstanceDetached(instance: HTMLElement): void;
-  handleInstanceAttached(instance: HTMLElement): void;
-}
-
-export enum TargetElement {
-  CHANGE_ACTIONS = 'changeactions',
-  REPLY_DIALOG = 'replydialog',
-}
-
-// Note: for new events, naming convention should be: `a-b`
-export enum EventType {
-  HISTORY = 'history',
-  LABEL_CHANGE = 'labelchange',
-  SHOW_CHANGE = 'showchange',
-  SUBMIT_CHANGE = 'submitchange',
-  SHOW_REVISION_ACTIONS = 'show-revision-actions',
-  COMMIT_MSG_EDIT = 'commitmsgedit',
-  COMMENT = 'comment',
-  REVERT = 'revert',
-  REVERT_SUBMISSION = 'revert_submission',
-  POST_REVERT = 'postrevert',
-  ANNOTATE_DIFF = 'annotatediff',
-  ADMIN_MENU_LINKS = 'admin-menu-links',
-  HIGHLIGHTJS_LOADED = 'highlightjs-loaded',
-}
-
-export interface RegisterOptions {
-  slot?: string;
-  replace: unknown;
-}
-
-export interface PanelInfo {
-  body: Element;
-  // eslint-disable-next-line @typescript-eslint/no-explicit-any
-  p: {[key: string]: any};
-  onUnload: () => void;
-}
-
-export interface SettingsInfo {
-  body: Element;
-  token?: string;
-  onUnload: () => void;
-  setTitle: () => void;
-  setWindowTitle: () => void;
-  show: () => void;
-}
-
-export interface PluginApi {
-  _url?: URL;
-  popup(): Promise<GrPopupInterface>;
-  popup(moduleName: string): Promise<GrPopupInterface>;
-  popup(moduleName?: string): Promise<GrPopupInterface | null>;
-  hook(endpointName: string, opt_options?: RegisterOptions): HookApi;
-  getPluginName(): string;
-  // eslint-disable-next-line @typescript-eslint/no-explicit-any
-  on(eventName: string, target: any): void;
-  attributeHelper(element: Element): GrAttributeHelper;
-  checks(): GrChecksApi;
-  restApi(): GrPluginRestApi;
-  eventHelper(element: Node): GrEventHelper;
-  registerDynamicCustomComponent(
-    endpointName: string,
-    moduleName?: string,
-    options?: RegisterOptions
-  ): HookApi;
-}
diff --git a/polygerrit-ui/app/elements/plugins/gr-popup-interface/gr-popup-interface.ts b/polygerrit-ui/app/elements/plugins/gr-popup-interface/gr-popup-interface.ts
index d45c263..07d11ec 100644
--- a/polygerrit-ui/app/elements/plugins/gr-popup-interface/gr-popup-interface.ts
+++ b/polygerrit-ui/app/elements/plugins/gr-popup-interface/gr-popup-interface.ts
@@ -17,7 +17,8 @@
 import './gr-plugin-popup';
 import {dom, flush} from '@polymer/polymer/lib/legacy/polymer.dom';
 import {GrPluginPopup} from './gr-plugin-popup';
-import {PluginApi} from '../gr-plugin-types';
+import {PluginApi} from '../../../api/plugin';
+import {PopupPluginApi} from '../../../api/popup';
 
 interface CustomPolymerPluginEl extends HTMLElement {
   plugin: PluginApi;
@@ -29,7 +30,7 @@
  * opt_moduleName is a name of custom element that will be automatically
  * inserted on popup opening.
  */
-export class GrPopupInterface {
+export class GrPopupInterface implements PopupPluginApi {
   private _openingPromise: Promise<GrPopupInterface> | null = null;
 
   private _popup: GrPluginPopup | null = null;
@@ -50,7 +51,7 @@
    * Creates the popup if not previously created. Creates popup content element,
    * if it was provided with constructor.
    */
-  open(): Promise<GrPopupInterface> {
+  open(): Promise<PopupPluginApi> {
     if (!this._openingPromise) {
       this._openingPromise = this.plugin
         .hook('plugin-overlay')
diff --git a/polygerrit-ui/app/elements/plugins/gr-repo-api/gr-repo-api.ts b/polygerrit-ui/app/elements/plugins/gr-repo-api/gr-repo-api.ts
index 701a560..e42ca08 100644
--- a/polygerrit-ui/app/elements/plugins/gr-repo-api/gr-repo-api.ts
+++ b/polygerrit-ui/app/elements/plugins/gr-repo-api/gr-repo-api.ts
@@ -16,9 +16,9 @@
  */
 import './gr-plugin-repo-command';
 import {ConfigInfo} from '../../../types/common';
-import {HookApi, PluginApi} from '../gr-plugin-types';
-
-type RepoCommandCallback = (repo?: string, config?: ConfigInfo) => boolean;
+import {PluginApi} from '../../../api/plugin';
+import {RepoCommandCallback, RepoPluginApi} from '../../../api/repo';
+import {HookApi} from '../../../api/hook';
 
 /**
  * Parameters provided on repo-command endpoint
@@ -28,7 +28,7 @@
   config: ConfigInfo;
 }
 
-export class GrRepoApi {
+export class GrRepoApi implements RepoPluginApi {
   private _hook?: HookApi;
 
   constructor(readonly plugin: PluginApi) {}
@@ -45,7 +45,7 @@
   createCommand(title: string, callback: RepoCommandCallback) {
     if (this._hook) {
       console.warn('Already set up.');
-      return this._hook;
+      return this;
     }
     this._hook = this._createHook(title);
     this._hook.onAttached(element => {
diff --git a/polygerrit-ui/app/elements/plugins/gr-settings-api/gr-settings-api.ts b/polygerrit-ui/app/elements/plugins/gr-settings-api/gr-settings-api.ts
index c7f1ecd..4bdd40e 100644
--- a/polygerrit-ui/app/elements/plugins/gr-settings-api/gr-settings-api.ts
+++ b/polygerrit-ui/app/elements/plugins/gr-settings-api/gr-settings-api.ts
@@ -16,9 +16,10 @@
  */
 import '../../settings/gr-settings-view/gr-settings-item';
 import '../../settings/gr-settings-view/gr-settings-menu-item';
-import {PluginApi} from '../gr-plugin-types';
+import {PluginApi} from '../../../api/plugin';
+import {SettingsPluginApi} from '../../../api/settings';
 
-export class GrSettingsApi {
+export class GrSettingsApi implements SettingsPluginApi {
   private _token: string;
 
   private _title = '(no title)';
diff --git a/polygerrit-ui/app/elements/plugins/gr-styles-api/gr-styles-api.ts b/polygerrit-ui/app/elements/plugins/gr-styles-api/gr-styles-api.ts
index 5c57208..a91b8d3 100644
--- a/polygerrit-ui/app/elements/plugins/gr-styles-api/gr-styles-api.ts
+++ b/polygerrit-ui/app/elements/plugins/gr-styles-api/gr-styles-api.ts
@@ -14,6 +14,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+import {StyleObject, StylesPluginApi} from '../../../api/styles';
 
 /**
  * @fileoverview We should consider dropping support for this API:
@@ -30,7 +31,7 @@
   };
 }
 
-export class GrStyleObject {
+export class GrStyleObject implements StyleObject {
   private className = '';
 
   constructor(private readonly rulesStr: string) {
@@ -66,7 +67,6 @@
 
   /**
    * Apply shared style to the element.
-   *
    */
   apply(element: Element) {
     element.classList.add(this.getClassName(element));
@@ -76,7 +76,7 @@
 /**
  * TODO(TS): move to util
  */
-export class GrStylesApi {
+export class GrStylesApi implements StylesPluginApi {
   /**
    * Creates a new GrStyleObject with specified style properties.
    */
diff --git a/polygerrit-ui/app/elements/plugins/gr-theme-api/gr-theme-api.ts b/polygerrit-ui/app/elements/plugins/gr-theme-api/gr-theme-api.ts
index 821e4bf..894ec6c 100644
--- a/polygerrit-ui/app/elements/plugins/gr-theme-api/gr-theme-api.ts
+++ b/polygerrit-ui/app/elements/plugins/gr-theme-api/gr-theme-api.ts
@@ -16,12 +16,13 @@
  */
 import './gr-custom-plugin-header';
 import {GrCustomPluginHeader} from './gr-custom-plugin-header';
-import {PluginApi} from '../gr-plugin-types';
+import {PluginApi} from '../../../api/plugin';
+import {ThemePluginApi} from '../../../api/theme';
 
 /**
  * Defines api for theme, can be used to set header logo and title.
  */
-export class GrThemeApi {
+export class GrThemeApi implements ThemePluginApi {
   constructor(private readonly plugin: PluginApi) {}
 
   setHeaderLogoAndTitle(logoUrl: string, title: string) {
diff --git a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-annotation-actions-context.ts b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-annotation-actions-context.ts
index a493e51..6a4da7b 100644
--- a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-annotation-actions-context.ts
+++ b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-annotation-actions-context.ts
@@ -19,6 +19,7 @@
 import {GrStyleObject} from '../../plugins/gr-styles-api/gr-styles-api';
 import {GrDiffLine} from '../../diff/gr-diff/gr-diff-line';
 import {appContext} from '../../../services/app-context';
+import {AnnotationContext} from '../../../api/annotation';
 
 /**
  * Used to create a context for GrAnnotationActionsInterface.
@@ -32,7 +33,7 @@
  * @param changeNum The Gerrit change number.
  * @param patchNum The Gerrit patch number.
  */
-export class GrAnnotationActionsContext {
+export class GrAnnotationActionsContext implements AnnotationContext {
   private _contentEl: HTMLElement;
 
   private _lineNumberEl: HTMLElement;
diff --git a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-annotation-actions-js-api.ts b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-annotation-actions-js-api.ts
index f160807..4abc6e1 100644
--- a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-annotation-actions-js-api.ts
+++ b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-annotation-actions-js-api.ts
@@ -16,34 +16,18 @@
  */
 import {GrAnnotationActionsContext} from './gr-annotation-actions-context';
 import {GrDiffLine} from '../../diff/gr-diff/gr-diff-line';
-import {
-  CoverageRange,
-  DiffLayer,
-  DiffLayerListener,
-} from '../../../types/types';
+import {DiffLayer, DiffLayerListener} from '../../../types/types';
 import {Side} from '../../../constants/constants';
-import {PluginApi} from '../../plugins/gr-plugin-types';
-import {ChangeInfo, NumericChangeId} from '../../../types/common';
+import {EventType, PluginApi} from '../../../api/plugin';
 import {appContext} from '../../../services/app-context';
+import {
+  AddLayerFunc,
+  AnnotationPluginApi,
+  CoverageProvider,
+  NotifyFunc,
+} from '../../../api/annotation';
 
-type AddLayerFunc = (ctx: GrAnnotationActionsContext) => void;
-
-type NotifyFunc = (
-  path: string,
-  start: number,
-  end: number,
-  side: Side
-) => void;
-
-export type CoverageProvider = (
-  changeNum: NumericChangeId,
-  path: string,
-  basePatchNum?: number,
-  patchNum?: number,
-  change?: ChangeInfo
-) => Promise<Array<CoverageRange>>;
-
-export class GrAnnotationActionsInterface {
+export class GrAnnotationActionsInterface implements AnnotationPluginApi {
   // Collect all annotation layers instantiated by getLayer. Will be used when
   // notifying their listeners in the notify function.
   private annotationLayers: AnnotationLayer[] = [];
@@ -57,7 +41,7 @@
 
   constructor(private readonly plugin: PluginApi) {
     // Return this instance when there is an annotatediff event.
-    plugin.on('annotatediff', this);
+    plugin.on(EventType.ANNOTATE_DIFF, this);
   }
 
   /**
diff --git a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-change-actions-js-api.ts b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-change-actions-js-api.ts
index 9ae2900..2f2b5ce 100644
--- a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-change-actions-js-api.ts
+++ b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-change-actions-js-api.ts
@@ -14,47 +14,17 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-import {
-  ActionType,
-  ActionPriority,
-} from '../../../services/gr-rest-api/gr-rest-api';
-import {PluginApi, TargetElement} from '../../plugins/gr-plugin-types';
+import {PluginApi, TargetElement} from '../../../api/plugin';
 import {ActionInfo, RequireProperties} from '../../../types/common';
 import {appContext} from '../../../services/app-context';
-
-export enum ChangeActions {
-  ABANDON = 'abandon',
-  DELETE = '/',
-  DELETE_EDIT = 'deleteEdit',
-  EDIT = 'edit',
-  FOLLOW_UP = 'followup',
-  IGNORE = 'ignore',
-  MOVE = 'move',
-  PRIVATE = 'private',
-  PRIVATE_DELETE = 'private.delete',
-  PUBLISH_EDIT = 'publishEdit',
-  REBASE = 'rebase',
-  REBASE_EDIT = 'rebaseEdit',
-  READY = 'ready',
-  RESTORE = 'restore',
-  REVERT = 'revert',
-  REVERT_SUBMISSION = 'revert_submission',
-  REVIEWED = 'reviewed',
-  STOP_EDIT = 'stopEdit',
-  SUBMIT = 'submit',
-  UNIGNORE = 'unignore',
-  UNREVIEWED = 'unreviewed',
-  WIP = 'wip',
-}
-
-export enum RevisionActions {
-  CHERRYPICK = 'cherrypick',
-  REBASE = 'rebase',
-  SUBMIT = 'submit',
-  DOWNLOAD = 'download',
-}
-
-export type PrimaryActionKey = ChangeActions | RevisionActions;
+import {
+  ActionPriority,
+  ActionType,
+  ChangeActions,
+  ChangeActionsPluginApi,
+  PrimaryActionKey,
+  RevisionActions,
+} from '../../../api/change-actions';
 
 export interface UIActionInfo extends RequireProperties<ActionInfo, 'label'> {
   __key: string;
@@ -89,7 +59,7 @@
   getActionDetails(actionName: string): ActionInfo | undefined;
 }
 
-export class GrChangeActionsInterface {
+export class GrChangeActionsInterface implements ChangeActionsPluginApi {
   private _el?: GrChangeActionsElement;
 
   RevisionActions = RevisionActions;
diff --git a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-change-reply-js-api.ts b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-change-reply-js-api.ts
index 74130af..effebe1 100644
--- a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-change-reply-js-api.ts
+++ b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-change-reply-js-api.ts
@@ -16,25 +16,20 @@
  */
 
 import {GrReplyDialog} from '../../../services/gr-rest-api/gr-rest-api';
-import {PluginApi, TargetElement} from '../../plugins/gr-plugin-types';
+import {PluginApi, TargetElement} from '../../../api/plugin';
 import {JsApiService} from './gr-js-api-types';
-
-// TODO(TS): maybe move interfaces\types to other files when convertion complete
-interface LabelsChangedDetail {
-  name: string;
-  value: string;
-}
-interface ValueChangedDetail {
-  value: string;
-}
-
-type ReplyChangedCallback = (text: string) => void;
-type LabelsChangedCallback = (detail: LabelsChangedDetail) => void;
+import {
+  ChangeReplyPluginApi,
+  LabelsChangedCallback,
+  LabelsChangedDetail,
+  ReplyChangedCallback,
+  ValueChangedDetail,
+} from '../../../api/change-reply';
 
 /**
  * GrChangeReplyInterface, provides a set of handy methods on reply dialog.
  */
-export class GrChangeReplyInterface {
+export class GrChangeReplyInterface implements ChangeReplyPluginApi {
   constructor(
     readonly plugin: PluginApi,
     readonly sharedApiElement: JsApiService
@@ -46,7 +41,7 @@
     ) as unknown) as GrReplyDialog;
   }
 
-  getLabelValue(label: string) {
+  getLabelValue(label: string): string {
     return this._el.getLabelValue(label);
   }
 
@@ -100,6 +95,6 @@
   }
 
   showMessage(message: string) {
-    return this._el.setPluginMessage(message);
+    this._el.setPluginMessage(message);
   }
 }
diff --git a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-gerrit.ts b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-gerrit.ts
index 32a9238..27bc591 100644
--- a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-gerrit.ts
+++ b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-gerrit.ts
@@ -26,7 +26,7 @@
 } from './gr-plugin-loader';
 import {send} from './gr-api-utils';
 import {appContext} from '../../../services/app-context';
-import {PluginApi} from '../../plugins/gr-plugin-types';
+import {PluginApi} from '../../../api/plugin';
 import {HttpMethod} from '../../../constants/constants';
 import {RequestPayload} from '../../../types/common';
 import {
diff --git a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-js-api-interface-element.ts b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-js-api-interface-element.ts
index 412165d..830fb92 100644
--- a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-js-api-interface-element.ts
+++ b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-js-api-interface-element.ts
@@ -23,16 +23,17 @@
   RevisionInfo,
 } from '../../../types/common';
 import {GrAnnotationActionsInterface} from './gr-annotation-actions-js-api';
-import {GrAdminApi, MenuLink} from '../../plugins/gr-admin-api/gr-admin-api';
+import {GrAdminApi} from '../../plugins/gr-admin-api/gr-admin-api';
 import {
   JsApiService,
   EventCallback,
   ShowChangeDetail,
   ShowRevisionActionsDetail,
 } from './gr-js-api-types';
-import {EventType, TargetElement} from '../../plugins/gr-plugin-types';
+import {EventType, TargetElement} from '../../../api/plugin';
 import {DiffLayer, HighlightJS, ParsedChangeInfo} from '../../../types/types';
 import {appContext} from '../../../services/app-context';
+import {MenuLink} from '../../../api/admin';
 
 const elements: {[key: string]: HTMLElement} = {};
 const eventCallbacks: {[key: string]: EventCallback[]} = {};
diff --git a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-js-api-interface_test.js b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-js-api-interface_test.js
index 47b6006..6a8a0dd 100644
--- a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-js-api-interface_test.js
+++ b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-js-api-interface_test.js
@@ -19,7 +19,7 @@
 import './gr-js-api-interface.js';
 import {GrPopupInterface} from '../../plugins/gr-popup-interface/gr-popup-interface.js';
 import {GrSettingsApi} from '../../plugins/gr-settings-api/gr-settings-api.js';
-import {EventType} from '../../plugins/gr-plugin-types.js';
+import {EventType} from '../../../api/plugin.js';
 import {PLUGIN_LOADING_TIMEOUT_MS} from './gr-api-utils.js';
 import {getPluginLoader} from './gr-plugin-loader.js';
 import {_testOnly_initGerritPluginApi} from './gr-gerrit.js';
diff --git a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-js-api-types.ts b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-js-api-types.ts
index 37db662..0b28c5e 100644
--- a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-js-api-types.ts
+++ b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-js-api-types.ts
@@ -21,10 +21,10 @@
   ReviewInput,
   RevisionInfo,
 } from '../../../types/common';
-import {EventType, TargetElement} from '../../plugins/gr-plugin-types';
+import {EventType, TargetElement} from '../../../api/plugin';
 import {DiffLayer, ParsedChangeInfo} from '../../../types/types';
 import {GrAnnotationActionsInterface} from './gr-annotation-actions-js-api';
-import {MenuLink} from '../../plugins/gr-admin-api/gr-admin-api';
+import {MenuLink} from '../../../api/admin';
 
 export interface ShowChangeDetail {
   change: ChangeInfo;
diff --git a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-plugin-action-context.ts b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-plugin-action-context.ts
index d4a2bd6..21e4876 100644
--- a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-plugin-action-context.ts
+++ b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-plugin-action-context.ts
@@ -17,20 +17,18 @@
 
 import {RevisionInfo, ChangeInfo, RequestPayload} from '../../../types/common';
 import {ShowAlertEventDetail} from '../../../types/events';
-import {PluginApi} from '../../plugins/gr-plugin-types';
+import {PluginApi} from '../../../api/plugin';
 import {UIActionInfo} from './gr-change-actions-js-api';
 import {windowLocationReload} from '../../../utils/dom-util';
-
-interface GrPopupInterface {
-  close(): void;
-}
+import {PopupPluginApi} from '../../../api/popup';
+import {GrPopupInterface} from '../../plugins/gr-popup-interface/gr-popup-interface';
 
 interface ButtonCallBacks {
   onclick: (event: Event) => boolean;
 }
 
 export class GrPluginActionContext {
-  private _popups: GrPopupInterface[] = [];
+  private _popups: PopupPluginApi[] = [];
 
   constructor(
     public readonly plugin: PluginApi,
@@ -41,7 +39,7 @@
 
   popup(element: Node) {
     this.plugin.popup().then(popApi => {
-      const popupEl = popApi._getElement();
+      const popupEl = (popApi as GrPopupInterface)._getElement();
       if (!popupEl) {
         throw new Error('Popup element not found');
       }
diff --git a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-plugin-endpoints.ts b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-plugin-endpoints.ts
index da19e5b..2752c74 100644
--- a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-plugin-endpoints.ts
+++ b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-plugin-endpoints.ts
@@ -16,8 +16,9 @@
  */
 
 import {importHref} from '../../../scripts/import-href';
-import {HookApi, PluginApi} from '../../plugins/gr-plugin-types';
+import {PluginApi} from '../../../api/plugin';
 import {notUndefined} from '../../../types/types';
+import {HookApi} from '../../../api/hook';
 
 // eslint-disable-next-line @typescript-eslint/no-explicit-any
 type Callback = (value: any) => void;
diff --git a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-plugin-loader.ts b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-plugin-loader.ts
index aacef0e..8c0fce26 100644
--- a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-plugin-loader.ts
+++ b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-plugin-loader.ts
@@ -24,7 +24,7 @@
 import {Plugin} from './gr-public-js-api';
 import {getBaseUrl} from '../../../utils/url-util';
 import {getPluginEndpoints} from './gr-plugin-endpoints';
-import {PluginApi} from '../../plugins/gr-plugin-types';
+import {PluginApi} from '../../../api/plugin';
 import {ReportingService} from '../../../services/gr-reporting/gr-reporting';
 import {hasOwnProperty} from '../../../utils/common-util';
 import {ShowAlertEventDetail} from '../../../types/events';
diff --git a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-plugin-rest-api.ts b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-plugin-rest-api.ts
index e640ba1..cd35d4e 100644
--- a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-plugin-rest-api.ts
+++ b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-plugin-rest-api.ts
@@ -14,10 +14,10 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-import {ErrorCallback} from '../../../services/gr-rest-api/gr-rest-api';
 import {HttpMethod} from '../../../constants/constants';
 import {RequestPayload} from '../../../types/common';
 import {appContext} from '../../../services/app-context';
+import {ErrorCallback, RestPluginApi} from '../../../api/rest';
 
 async function getErrorMessage(response: Response): Promise<string> {
   const text = await response.text();
@@ -33,7 +33,7 @@
   }
 }
 
-export class GrPluginRestApi {
+export class GrPluginRestApi implements RestPluginApi {
   private readonly restApi = appContext.restApiService;
 
   constructor(private readonly prefix = '') {}
diff --git a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-public-js-api.ts b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-public-js-api.ts
index f21ddc6..45ffdcd9 100644
--- a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-public-js-api.ts
+++ b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-public-js-api.ts
@@ -32,20 +32,28 @@
 import {GrStylesApi} from '../../plugins/gr-styles-api/gr-styles-api';
 import {getPluginEndpoints} from './gr-plugin-endpoints';
 
-import {PRELOADED_PROTOCOL, getPluginNameFromUrl, send} from './gr-api-utils';
+import {getPluginNameFromUrl, PRELOADED_PROTOCOL, send} from './gr-api-utils';
 import {GrReportingJsApi} from './gr-reporting-js-api';
-import {
-  EventType,
-  HookApi,
-  PluginApi,
-  RegisterOptions,
-  TargetElement,
-} from '../../plugins/gr-plugin-types';
+import {EventType, PluginApi, TargetElement} from '../../../api/plugin';
 import {RequestPayload} from '../../../types/common';
 import {HttpMethod} from '../../../constants/constants';
 import {GrChangeActions} from '../../change/gr-change-actions/gr-change-actions';
 import {GrChecksApi} from '../../plugins/gr-checks-api/gr-checks-api';
 import {appContext} from '../../../services/app-context';
+import {AdminPluginApi} from '../../../api/admin';
+import {AnnotationPluginApi} from '../../../api/annotation';
+import {StylesPluginApi} from '../../../api/styles';
+import {ThemePluginApi} from '../../../api/theme';
+import {EventHelperPluginApi} from '../../../api/event-helper';
+import {PopupPluginApi} from '../../../api/popup';
+import {SettingsPluginApi} from '../../../api/settings';
+import {ReportingPluginApi} from '../../../api/reporting';
+import {ChangeActionsPluginApi} from '../../../api/change-actions';
+import {ChangeMetadataPluginApi} from '../../../api/change-metadata';
+import {RepoPluginApi} from '../../../api/repo';
+import {ChangeReplyPluginApi} from '../../../api/change-reply';
+import {RestPluginApi} from '../../../api/rest';
+import {HookApi, RegisterOptions} from '../../../api/hook';
 
 /**
  * Plugin-provided custom components can affect content in extension
@@ -232,11 +240,11 @@
       });
   }
 
-  annotationApi() {
+  annotationApi(): AnnotationPluginApi {
     return new GrAnnotationActionsInterface(this);
   }
 
-  changeActions() {
+  changeActions(): ChangeActionsPluginApi {
     return new GrChangeActionsInterface(
       this,
       (this.jsApi.getElement(
@@ -245,7 +253,7 @@
     );
   }
 
-  changeReply() {
+  changeReply(): ChangeReplyPluginApi {
     return new GrChangeReplyInterface(this, this.jsApi);
   }
 
@@ -253,42 +261,35 @@
     return new GrChecksApi(this);
   }
 
-  reporting() {
+  reporting(): ReportingPluginApi {
     return new GrReportingJsApi(this);
   }
 
-  theme() {
+  theme(): ThemePluginApi {
     return new GrThemeApi(this);
   }
 
-  project() {
+  project(): RepoPluginApi {
     return new GrRepoApi(this);
   }
 
-  changeMetadata() {
+  changeMetadata(): ChangeMetadataPluginApi {
     return new GrChangeMetadataApi(this);
   }
 
-  admin() {
+  admin(): AdminPluginApi {
     return new GrAdminApi(this);
   }
 
-  settings() {
+  settings(): SettingsPluginApi {
     return new GrSettingsApi(this);
   }
 
-  styles() {
+  styles(): StylesPluginApi {
     return new GrStylesApi();
   }
 
-  /**
-   * To make REST requests for plugin-provided endpoints, use
-   *
-   * @example
-   * const pluginRestApi = plugin.restApi(plugin.url());
-   * @param prefix url for subsequent .get(), .post() etc requests.
-   */
-  restApi(prefix?: string) {
+  restApi(prefix?: string): RestPluginApi {
     return new GrPluginRestApi(prefix);
   }
 
@@ -296,15 +297,15 @@
     return new GrAttributeHelper(element);
   }
 
-  eventHelper(element: HTMLElement) {
+  eventHelper(element: HTMLElement): EventHelperPluginApi {
     return new GrEventHelper(element);
   }
 
-  popup(): Promise<GrPopupInterface>;
+  popup(): Promise<PopupPluginApi>;
 
-  popup(moduleName: string): Promise<GrPopupInterface>;
+  popup(moduleName: string): Promise<PopupPluginApi>;
 
-  popup(moduleName?: string): Promise<GrPopupInterface | null> {
+  popup(moduleName?: string): Promise<PopupPluginApi | null> {
     if (moduleName !== undefined && typeof moduleName !== 'string') {
       console.error('.popup(element) deprecated, use .popup(moduleName)!');
       return Promise.resolve(null);
diff --git a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-reporting-js-api.ts b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-reporting-js-api.ts
index 87b320c4..d4b51a8 100644
--- a/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-reporting-js-api.ts
+++ b/polygerrit-ui/app/elements/shared/gr-js-api-interface/gr-reporting-js-api.ts
@@ -16,26 +16,26 @@
  */
 
 import {appContext} from '../../../services/app-context';
-import {EventDetails} from '../../../services/gr-reporting/gr-reporting';
-import {PluginApi} from '../../plugins/gr-plugin-types';
+import {PluginApi} from '../../../api/plugin';
+import {EventDetails, ReportingPluginApi} from '../../../api/reporting';
 
 /**
  * Defines all methods that will be exported to plugin from reporting service.
  */
-export class GrReportingJsApi {
+export class GrReportingJsApi implements ReportingPluginApi {
   private readonly reporting = appContext.reportingService;
 
   constructor(private readonly plugin: PluginApi) {}
 
   reportInteraction(eventName: string, details?: EventDetails) {
-    return this.reporting.reportInteraction(
+    this.reporting.reportInteraction(
       `${this.plugin.getPluginName()}-${eventName}`,
       details
     );
   }
 
   reportLifeCycle(eventName: string, details?: EventDetails) {
-    return this.reporting.reportLifeCycle(
+    this.reporting.reportLifeCycle(
       `${this.plugin.getPluginName()}-${eventName}`,
       details
     );
diff --git a/polygerrit-ui/app/elements/shared/gr-lib-loader/gr-lib-loader.ts b/polygerrit-ui/app/elements/shared/gr-lib-loader/gr-lib-loader.ts
index 329cc7e..655acde 100644
--- a/polygerrit-ui/app/elements/shared/gr-lib-loader/gr-lib-loader.ts
+++ b/polygerrit-ui/app/elements/shared/gr-lib-loader/gr-lib-loader.ts
@@ -15,7 +15,7 @@
  * limitations under the License.
  */
 import '../gr-js-api-interface/gr-js-api-interface';
-import {EventType} from '../../plugins/gr-plugin-types';
+import {EventType} from '../../../api/plugin';
 import {HighlightJS} from '../../../types/types';
 import {appContext} from '../../../services/app-context';
 
diff --git a/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-rest-api-interface.ts b/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-rest-api-interface.ts
index 84d84b1..6e17c75 100644
--- a/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-rest-api-interface.ts
+++ b/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-rest-api-interface.ts
@@ -139,7 +139,6 @@
 } from '../../../types/diff';
 import {
   CancelConditionCallback,
-  ErrorCallback,
   GetDiffCommentsOutput,
   GetDiffRobotCommentsOutput,
   RestApiService,
@@ -155,6 +154,7 @@
 } from '../../../constants/constants';
 import {firePageError, fireServerError} from '../../../utils/event-util';
 import {ParsedChangeInfo} from '../../../types/types';
+import {ErrorCallback} from '../../../api/rest';
 
 const MAX_PROJECT_RESULTS = 25;
 // This value is somewhat arbitrary and not based on research or calculations.
diff --git a/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-rest-apis/gr-rest-api-helper.ts b/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-rest-apis/gr-rest-api-helper.ts
index 710445c..fa2a28e 100644
--- a/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-rest-apis/gr-rest-api-helper.ts
+++ b/polygerrit-ui/app/elements/shared/gr-rest-api-interface/gr-rest-apis/gr-rest-api-helper.ts
@@ -15,10 +15,7 @@
  * limitations under the License.
  */
 import {getBaseUrl} from '../../../../utils/url-util';
-import {
-  CancelConditionCallback,
-  ErrorCallback,
-} from '../../../../services/gr-rest-api/gr-rest-api';
+import {CancelConditionCallback} from '../../../../services/gr-rest-api/gr-rest-api';
 import {
   AuthRequestInit,
   AuthService,
@@ -33,6 +30,7 @@
 import {RpcLogEventDetail} from '../../../../types/events';
 import {fireNetworkError, fireServerError} from '../../../../utils/event-util';
 import {FetchRequest} from '../../../../types/types';
+import {ErrorCallback} from '../../../../api/rest';
 
 export const JSON_PREFIX = ")]}'";
 
diff --git a/polygerrit-ui/app/services/gr-reporting/gr-reporting.ts b/polygerrit-ui/app/services/gr-reporting/gr-reporting.ts
index 7035f26..4ca983a 100644
--- a/polygerrit-ui/app/services/gr-reporting/gr-reporting.ts
+++ b/polygerrit-ui/app/services/gr-reporting/gr-reporting.ts
@@ -16,13 +16,10 @@
  */
 
 import {NumericChangeId} from '../../types/common';
+import {EventDetails} from '../../api/reporting';
 
 export type EventValue = string | number | {error?: Error};
 
-// TODO(dmfilippov): TS-fix-any use more specific type instead if possible
-// eslint-disable-next-line @typescript-eslint/no-explicit-any
-export type EventDetails = any;
-
 export interface Timer {
   reset(): this;
   end(): this;
diff --git a/polygerrit-ui/app/services/gr-reporting/gr-reporting_impl.ts b/polygerrit-ui/app/services/gr-reporting/gr-reporting_impl.ts
index 657a3f4..f80cb75 100644
--- a/polygerrit-ui/app/services/gr-reporting/gr-reporting_impl.ts
+++ b/polygerrit-ui/app/services/gr-reporting/gr-reporting_impl.ts
@@ -16,14 +16,10 @@
  */
 import {AppContext} from '../app-context';
 import {FlagsService} from '../flags/flags';
-import {
-  EventDetails,
-  EventValue,
-  ReportingService,
-  Timer,
-} from './gr-reporting';
+import {EventValue, ReportingService, Timer} from './gr-reporting';
 import {hasOwnProperty} from '../../utils/common-util';
 import {NumericChangeId} from '../../types/common';
+import {EventDetails} from '../../api/reporting';
 
 // Latency reporting constants.
 
diff --git a/polygerrit-ui/app/services/gr-reporting/gr-reporting_mock.ts b/polygerrit-ui/app/services/gr-reporting/gr-reporting_mock.ts
index 2b42a6b..484ce45 100644
--- a/polygerrit-ui/app/services/gr-reporting/gr-reporting_mock.ts
+++ b/polygerrit-ui/app/services/gr-reporting/gr-reporting_mock.ts
@@ -14,7 +14,8 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-import {EventDetails, ReportingService, Timer} from './gr-reporting';
+import {ReportingService, Timer} from './gr-reporting';
+import {EventDetails} from '../../api/reporting';
 
 export class MockTimer implements Timer {
   end(): this {
diff --git a/polygerrit-ui/app/services/gr-rest-api/gr-rest-api.ts b/polygerrit-ui/app/services/gr-rest-api/gr-rest-api.ts
index 6fec5f0..4742e65 100644
--- a/polygerrit-ui/app/services/gr-rest-api/gr-rest-api.ts
+++ b/polygerrit-ui/app/services/gr-rest-api/gr-rest-api.ts
@@ -17,88 +17,88 @@
 
 import {HttpMethod} from '../../constants/constants';
 import {
+  AccountCapabilityInfo,
   AccountDetailInfo,
   AccountExternalIdInfo,
+  AccountId,
   AccountInfo,
-  NumericChangeId,
-  ServerInfo,
-  ProjectInfo,
-  AccountCapabilityInfo,
-  SuggestedReviewerInfo,
-  GroupNameToGroupInfoMap,
-  ParsedJSON,
-  PatchSetNum,
-  RequestPayload,
-  PreferencesInput,
-  EditPreferencesInfo,
-  DiffPreferenceInput,
-  SshKeyInfo,
-  RepoName,
-  BranchName,
-  BranchInput,
-  TagInput,
-  GpgKeysInput,
-  GpgKeyId,
-  GpgKeyInfo,
-  PreferencesInfo,
-  EmailInfo,
-  ProjectAccessInfo,
-  CapabilityInfoMap,
-  ProjectAccessInput,
-  ChangeInfo,
-  ProjectInfoWithName,
-  GroupId,
-  GroupInfo,
-  GroupOptionsInput,
+  ActionNameToActionInfoMap,
+  Base64FileContent,
+  BlameInfo,
   BranchInfo,
-  ConfigInfo,
-  ReviewInput,
-  EditInfo,
+  BranchInput,
+  BranchName,
+  CapabilityInfoMap,
   ChangeId,
-  DashboardInfo,
-  ProjectAccessInfoMap,
-  IncludedInInfo,
-  RobotCommentInfo,
+  ChangeInfo,
+  ChangeMessageId,
   CommentInfo,
-  PathToCommentsInfoMap,
-  PathToRobotCommentsInfoMap,
   CommentInput,
-  GroupInput,
-  PluginInfo,
-  DocResult,
+  CommitInfo,
+  ConfigInfo,
+  ConfigInput,
   ContributorAgreementInfo,
   ContributorAgreementInput,
-  Password,
-  ProjectWatchInfo,
-  NameToProjectInfoMap,
-  ProjectInput,
-  AccountId,
-  ChangeMessageId,
-  GroupAuditEventInfo,
-  EncodedGroupId,
-  Base64FileContent,
-  UrlEncodedCommentId,
-  TagInfo,
-  GitRef,
-  ConfigInput,
-  RelatedChangesInfo,
-  SubmittedTogetherInfo,
-  EmailAddress,
-  FixId,
-  FilePathToDiffInfoMap,
-  BlameInfo,
-  PatchRange,
-  ImagesForDiff,
-  ActionNameToActionInfoMap,
-  RevisionId,
-  GroupName,
   DashboardId,
-  HashtagsInput,
-  Hashtag,
+  DashboardInfo,
+  DiffPreferenceInput,
+  DocResult,
+  EditInfo,
+  EditPreferencesInfo,
+  EmailAddress,
+  EmailInfo,
+  EncodedGroupId,
   FileNameToFileInfoMap,
-  TopMenuEntryInfo,
+  FilePathToDiffInfoMap,
+  FixId,
+  GitRef,
+  GpgKeyId,
+  GpgKeyInfo,
+  GpgKeysInput,
+  GroupAuditEventInfo,
+  GroupId,
+  GroupInfo,
+  GroupInput,
+  GroupName,
+  GroupNameToGroupInfoMap,
+  GroupOptionsInput,
+  Hashtag,
+  HashtagsInput,
+  ImagesForDiff,
+  IncludedInInfo,
   MergeableInfo,
-  CommitInfo,
+  NameToProjectInfoMap,
+  NumericChangeId,
+  ParsedJSON,
+  Password,
+  PatchRange,
+  PatchSetNum,
+  PathToCommentsInfoMap,
+  PathToRobotCommentsInfoMap,
+  PluginInfo,
+  PreferencesInfo,
+  PreferencesInput,
+  ProjectAccessInfo,
+  ProjectAccessInfoMap,
+  ProjectAccessInput,
+  ProjectInfo,
+  ProjectInfoWithName,
+  ProjectInput,
+  ProjectWatchInfo,
+  RelatedChangesInfo,
+  RepoName,
+  RequestPayload,
+  ReviewInput,
+  RevisionId,
+  RobotCommentInfo,
+  ServerInfo,
+  SshKeyInfo,
+  SubmittedTogetherInfo,
+  SuggestedReviewerInfo,
+  TagInfo,
+  TagInput,
+  TopMenuEntryInfo,
+  UrlEncodedCommentId,
 } from '../../types/common';
 import {
   DiffInfo,
@@ -106,8 +106,8 @@
   IgnoreWhitespaceType,
 } from '../../types/diff';
 import {ParsedChangeInfo} from '../../types/types';
+import {ErrorCallback} from '../../api/rest';
 
-export type ErrorCallback = (response?: Response | null, err?: Error) => void;
 export type CancelConditionCallback = () => boolean;
 
 // TODO(TS): remove when GrReplyDialog converted to typescript
@@ -118,21 +118,6 @@
   setPluginMessage(message: string): void;
 }
 
-// Copied from gr-change-actions.js
-export enum ActionType {
-  CHANGE = 'change',
-  REVISION = 'revision',
-}
-
-// Copied from gr-change-actions.js
-export enum ActionPriority {
-  CHANGE = 2,
-  DEFAULT = 0,
-  PRIMARY = 3,
-  REVIEW = -3,
-  REVISION = 1,
-}
-
 export interface GetDiffCommentsOutput {
   baseComments: CommentInfo[];
   comments: CommentInfo[];
diff --git a/polygerrit-ui/app/utils/admin-nav-util.ts b/polygerrit-ui/app/utils/admin-nav-util.ts
index b144313..275f9e6 100644
--- a/polygerrit-ui/app/utils/admin-nav-util.ts
+++ b/polygerrit-ui/app/utils/admin-nav-util.ts
@@ -25,9 +25,9 @@
   AccountDetailInfo,
   AccountCapabilityInfo,
 } from '../types/common';
-import {MenuLink} from '../elements/plugins/gr-admin-api/gr-admin-api';
 import {hasOwnProperty} from './common-util';
 import {GerritView} from '../services/router/router-model';
+import {MenuLink} from '../api/admin';
 
 const ADMIN_LINKS: NavLink[] = [
   {