TeamCity Plugin Development Help Help

Front-End Extensions

Initially, we shared our view on the TeamCity plugins and the motivation behind revising our plugin development approach in the dedicated blog post.

This document explains the new way of the plugin development in TeamCity. The updated plugin system lets you write any sophisticated plugin and integrate it both in the experimental UI (code-named Sakura) and classic UI. There is also a Workshop from the TeamCity Technology Day.

In addition to the previous plugin development workflow, we made a significant improvement, concentrating on the front-end aspects of the plugin development.

We guarantee that previously written plugins will work as they worked before 2020.2 EAP. New plugins will work starting from TeamCity 2020.2.

Key benefits

Key features of the new plugin development approach:

  • There is a way to integrate plugins both to the Sakura UI and the Classic UI.

  • All existing plugins continue to work as they worked before 2020.2.

  • UI plugins could be written in a more frontend-centric way, which involves modern web techs.

  • UI plugins are framework-agnostic, so you can use any library, framework, and bundler.

  • For those who prefer React, we expose our internal components, so you can write a plugin composing existing components from the Sakura UI – not only by writing everything yourself.

Terminology

PlaceID – ID of a container that will render the plugin. Since 2020.2, we provide a new set of PlaceIDs, which have a prefix SAKURA_. For example, SAKURA_HEADER_RIGHT. The full list of SAKURA PlaceID's is available in the NPM module @jetbrains/teamcity-api. Those PlaceIDs are accessible only in the Sakura UI. To integrate your Frontend Plugin in the Classic UI, use the classic PlaceID (the full list is available in TeamCity OpenAPI definitions).

This list is not final. We are open to get the feedback about your expectations and needs.

The following PlaceID's work both in the Sakura and classic UI:

  • ALL_PAGES_FOOTER_PLUGIN_CONTAINER - a specific PlaceID to place plugin JavaScripts to

  • SAKURA_HEADER_NAVIGATION_AFTER

  • SAKURA_HEADER_USERNAME_BEFORE

  • SAKURA_HEADER_RIGHT

Some of PlaceID's are available only in the Sakura UI:

  • SAKURA_FOOTER_RIGHT

  • SAKURA_BEFORE_CONTENT

  • SAKURA_SIDEBAR_TOP

  • SAKURA_PROJECT_TRENDS

  • SAKURA_BUILD_CONFIGURATION_TREND_CARD

  • SAKURA_PROJECT_BUILDS

  • SAKURA_BUILD_CONFIGURATION_BUILDS

  • SAKURA_BUILD_CONFIGURATION_BRANCHES

  • SAKURA_BUILD_LINE_EXPANDED

  • SAKURA_BUILD_OVERVIEW

PluginUIContext – context object which represents the plugin location. It contains currently selected projectId, buildId, buildTypeId, agentId, agentPoolId, agentTypeId. TeamCity guarantees that each plugin will receive the latest context.

Plugin Lifecycle – set of events, each of them is invoked when the plugin content passes a certain step. For example, the plugin is mounted to a DOM, context is updated, plugin is unmounted.

Plugin Wrapper – Sakura UI entity, a React component which manages a certain PlaceID. It reacts on the plugin UI context changes, passes updates to a plugin and manages plugin lifecycles.

TeamCityAPIpublicly exposed JS toolset which helps developers to manage plugins. Available as an NPM module and as a global JS variable (window.TeamCityAPI).

Plugin Registry – JavaScript object which stores data about each rendered plugin. This register should be used to search, retrieve, and remove plugins.

Plugin Constructor – JavaScript prototype used to create a plugin instance.

Basic plugin – the simplest plugin. Its behavior and reaction to the PluginUIContext are defined implicitly. It re-renders automatically every time PluginUIContext updates.

Controlled plugin – plugin which behavior and reaction on Plugin Lifecycle are defined by the developer explicitly.

Development mode – special mode which shows PlaceID containers in DOM and makes the plugin write debug information in the console. Accessible via the GET property pluginDevelopmentMode=true.

Public API Reference

window.TeamCityAPI is a set of handy tools, which will help you retrieve, update, and manipulate plugins. It consists of:

  • Components - internal TeamCity React components we are ready to expose. Right now, there is only the one component AllBuilds. We are looking forward to your feedback on this.

  • React - exposed React library. It's vital to use the same React library version to integrate your plugin into the TeamCity React vDOM tree (see the full explanation).

  • ReactDOM - exposed ReactDOM library. It's vital to use the same React library version to integrate your plugin into the TeamCity React vDOM tree (see the full explanation).

  • utils- set of utilities:

    • requestJSON - function to request and parse a JSON from the server. It already contains all the headers for the request and automatically parses the response.

    • requestTEXT - function to request and parse a TEXT from the server. It already contains all the headers for the request and automatically parses the response.

  • Plugin - plugin constructor. It expects you to specify PlaceID and content options as arguments (read more about controlled plugins).

  • pluginRegistry - plugin registry which you could use to find a certain instance of your plugin.

Before starting the development, please checkout this demo repository. It will help you to avoid tons of a boilerplate Java code.

Types of Plugins

There are three types of plugins you can write with the new API:

  • Basic plugins rely on a simple JSP/HTML code that is requested automatically on every navigation event, for example, when a user switches between projects or build configurations or moves to a new page.

  • Controlled plugins – using this type, a developer explicitly defines, how the Plugin should react to the navigation events, for example, define the Context Update handler, add / remove custom event listeners.

  • (Single-page Application) SPA plugins are "controlled plugins" on steroids, which use React under the hood and offer you to use shared Components and Libraries.

The following documentation sections contain more detailed explanations and guides on how to create a plugin of each type:

See also Basic vs. controlled plugins.

Last modified: 04 December 2020