This guide assumes you're using the Bitbucket CSE template, and followed the instructions from the Getting started section.
In this first section, you will learn:
You'll be working on the tutorial page: http://localhost:7990/bitbucket/plugins/servlet/extension-points
Extension points allow you to provide a safe place for other developers to extend your UI with their own features.
An extension point uses strongly typed contracts called schemas to specify the extensions they support and the attributes they can render. The validations safeguard the extension point against runtime errors.
This contract is called a schema
, and is the central piece of CSE extension points.
You define schemas in .graphql
files using graphql-style syntax, which lets you create complex,
strongly typed structures to define lightweight validators that can run without affecting performance.
In /src/main/my-app/extensions/extension-points-tutorial
, create a file called schema.cse.graphql
and define a schema:
1 2""" --- extensionPoint: extension.points.tutorial --- """ type Schema { }
The basic structure of a CSE schema is:
Schema
.Schema
type to specify the name of the extension point to be created.In Schema
, you can declare the attributes that determine how the extension is rendered.
For example, if you want to support a Link extension, you would write a schema like the following:
1 2""" --- extensionPoint: extension.points.tutorial --- """ type Schema { type: LinkExtension! label: String url: String }
The CSE schema package provides a list of default
Scalars and Types
like LinkExtension
and String
to make it easier to define schemas.
In the above example, the type
attribute declares that only extensions of type Link are supported. The attributes label
and url
are strings
to be used when rendering the link on the screen.
When writing schemas, you should verify that the attributes you're requiring comply with CSE extension factories API.
You can require as many attributes as you need, of any type you want, but there are certain attributes like type
, onAction
, label
and url
that are expected to behave in a certain way. Make sure to check the extension factories API
reference to verify that your schema is requiring the attributes that developers expect for a certain type of extension.
In some scenarios, you might need an attribute to have more than one type. For example, you might want to support both a link extension and button extension on the same extension point.
You can declare these attributes using a graphql union syntax as follows:
1 2""" --- extensionPoint: extension.points.tutorial --- """ type Schema { type: SupportedExtensions! label: String url: String onAction: Function } union SupportedExtensions = LinkExtension | ButtonExtension
In the above example, you can see that an onAction
attribute was also declared to comply with the Button extension API.
Once the schema for an extension point is defined, it can be imported directly into the code using the CSE schema-loader.
The CSE schema-loader is already installed and configured in the Bitbucket Server template for you.
The loader will then transform your schema into a set of hooks and components that fetches all the extensions registered for your extension point, validate them against the required attributes, and return a list of extension descriptors.
An extension descriptor is an object that contains the key and location of an extension, in addition to its attributes:
1 2interface ExtensionAttribute { key: string; location: string; attributes: { // the attributes of an extension }; }
To get the helpers that fetch and validate the extensions, import them from the schema as follows.
On ./src/main/my-app/extensions/extension-points-tutorial/extension-points-page.jsx
, write:
1 2import React from 'react'; import { useExtensions } from './schema.cse.graphql'; const MyPage = () => { // get all supported extensions registered for extension.points.tutorial const extensions = useExtensions(); console.log(extensions); return ( <PageContainer> <h2>extension.points.tutorial</h2> </PageContainer> ); }; /** page declaration for guides only **/
Go to http://localhost:7990/bitbucket/plugins/servlet/extension-points and open your console.
You should see a list of extension descriptors like:
1 2[ { key: "com.atlassian.myapp.bitbucket-plugin-template:extensions__extension-points-tutorial__extensions__button-extension__js", location: "extension.points.tutorial", attributes: { label: "Tutorial: button extension", onAction: ƒ (), type: "button" } }, { key: "com.atlassian.myapp.bitbucket-plugin-template:extensions__extension-points-tutorial__extensions__link-extension__js" location: "extension.points.tutorial", attributes: { label: "Tutorial: link extension" type: "link" url: "http://go.atlassian.com/clientside-extensions" } }
These extensions are provided by the template in order to make it easier to follow these guides, and are located under
/src/main/my-app/extensions/extension-points-tutorial/extensions
folder.
The CSE schema-loader provides other helpers and components. For example, it provides a hook to tell if extensions are being loaded.
On ./src/main/my-app/extensions/extension-points-tutorial/extension-points-page.jsx
, write:
1 2import React from 'react'; import { useExtensions, useExtensionsLoadingState } from './schema.cse.graphql'; const MyPage = () => { const extensions = useExtensions(); const loading = useExtensionsLoadingState(); return ( <PageContainer> <h2>extension.points.tutorial</h2> {loading && ( <p> <b>loading...</b> </p> )} </PageContainer> ); }; /** page declaration for guides only **/
For a list of all the helpers and components provided by the schema-loader, refer to Hooks and components guide.
So far, you've learned:
Next, you're going to learn how to render your extensions.
Rate this page: