Client-side Extensions Developer

Client-side Extensions Developer

Rate this page:

Hooks and Components

CSE provides a set of React hooks and components to consume the extensions registered for a given extension point. These hooks and components will receive an optional context, and validate the resulting attributes against the provided schema.

Take for example the following schema file:

schema.cse.graphql

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
"""
---
extensionPoint: example.extension-point
---
"""
type Schema {
    type: LinkExtension!

    label: string!

    url: string!
}

type ContextSchema {
    issueKey: String
}

You can import the hooks and components directly from the schema file, and the loader will transform the file into a module that contains all the hooks and components already configured to use the schema provided.

useExtensions

Receives an optional context object, retrieves the extensions registered for the extension point declared in the schema, validates them and return an array of only valid extensions.

Signature

1
2
3
import type { ExtensionDescriptor, Context } from '@atlassian/clientside-extensions-registry';

type useExtensions = (context: Context<{}>) => ExtensionDescriptor[];

Usage

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import React from "react";
import { useExtensions } from "./schema.cse.graphql";

const ExampleExtensionPoint = ({ context }) => {
    const extensions = useExtensions(context);

    return (
        <>
            {extensions.map(({ attributes }) => (
              <a href={attributes.url} key={attributes.key}>{attributes.label}</a>
            )}
        </>
    )
}

export default ExampleExtensionPoint;

useExtensionsLoadingState

Use this hooks in order to indicate the users that the extensions are loading.

Signature

1
2
3
import type { Context } from '@atlassian/clientside-extensions-registry';

type useExtensionsLoadingState = (context: Context<{}>) => boolean;

Usage

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import React from "react";
import { useExtensions, useExtensionsLoadingState } from "./schema.cse.graphql";

const ExampleExtensionPoint = ({ context }) => {
    const extensions = useExtensions(context);
    const loading = useExtensionsLoadingState(context);

    return (
        <>
            {loading ? "loading..." : extensions.map(({ attributes }) => (
                <a href={attributes.url} key={attributes.key}>{attributes.label}</a>
            )}
        </>
    )
}

export default ExampleExtensionPoint;

useExtensionsUnsupported

Receives an optional context object, retrieves the extensions registered for the extension point and return a list of all the extensions that don't pass the validation against the schema.

This is particularly useful in case you need to support legacy WebItems that are created only using XML definitions inside atlassian-plugin.xml.

Signature

1
2
3
import type { ExtensionDescriptor, Context } from '@atlassian/clientside-extensions-registry';

type useExtensionsUnsupported = (context: Context<{}>) => ExtensionDescriptor[];

Usage

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import React from "react";
import { useExtensionsUnsupported } from "./schema.cse.graphql";

const ExampleExtensionPoint = () => {
    const extensions = useExtensionsUnsupported(null);

    return (
        <>
            {extensions.map((extension) => (
              <a href={extension.url} key={extension.key}>{extension.label}</a>
            )}
        </>
    )
}

export default ExampleExtensionPoint;

useExtensionsAll

You can use useExtensionsAll in case you need all the results from useExtensions, useExtensionsLoadingState and useExtensionsLoadingState and prefer to get the results with a single hook.

Signature

1
2
3
4
5
6
import type { ExtensionDescriptor, Context } from '@atlassian/clientside-extensions-registry';

/**
 * @return [extensions, unsupported extensions, loading state]
 */
type useExtensionsAll = (context: Context<{}>) => [ExtensionDescriptor[], ExtensionDescriptor[], boolean];

Usage

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import React from "react";
import { useExtensionsAll } from "./schema.cse.graphql";

const ExampleExtensionPoint = ({context}) => {
    const [extensions, unsupportedExtensions, loading] = useExtensionsAll(context);

    return (
        <>
            <h2>Extensions</h2>
            {loading ? "loading..." : extensions.map((extension) => (
                {/*...render as needed*/}
            )}

            <h2>Unsupported Extensions</h2>
            {loading ? "loading..." : unsupportedExtensions.map((extension) => (
                {/*...render as needed*/}
            )}
        </>
    )
}

export default ExampleExtensionPoint;

ExtensionPoint

You can use the ExtensionPoint component in case you prefer it over hooks. Keep in mind that it is using the hook internally, so you will need a compatible React version.

The component provides the same information as useExtensionsAll.

Signature

1
2
3
4
5
6
7
import type { ExtensionDescriptor, Context } from '@atlassian/clientside-extensions-registry';

type ExtensionPoint = (props: { context: Context<{}> }) => (
  ExtensionDescriptor[],
  ExtensionDescriptor[],
  boolean,
) => JSX.Element;

Usage

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import React from "react";
import { ExtensionPoint } from "./schema.cse.graphql";

const ExampleExtensionPoint = ({context}) => {
    return (
        <ExtensionPoint context={context}>
            {(extensions, unsupportedExtensions, loading) => (
                <>
                    <h2>Extensions</h2>
                    {loading ? "loading..." : extensions.map((extension) => (
                        {/*...render as needed*/}
                    )}

                    <h2>Unsupported Extensions</h2>
                    {loading ? "loading..." : unsupportedExtensions.map((extension) => (
                        {/*...render as needed*/}
                    )}
                </>
            )}
        </ExtensionPoint>
    )
}

export default ExampleExtensionPoint;

ExtensionPointInfo

You can add this component to share with extension developers the schema of your extension points and highlight their locations in the current screen.

The information will only be available if the product has enabled their display in development mode.

Usage

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import React from "react";
import { useExtensions, useExtensionsLoadingState, ExtensionPointInfo } from "./schema.cse.graphql";

const ExampleExtensionPoint = ({ context }) => {
    const extensions = useExtensions(context);
    const loading = useExtensionsLoadingState(context);

    return (
        <>
          <h2>Example extension point <ExtensionPointInfo /></h2>
          {loading ? "loading..." : extensions.map(({ attributes }) => (
            <a href={attributes.url} key={attributes.key}>{attributes.label}</a>
          )}
        </>
    )
}

export default ExampleExtensionPoint;

Rate this page: