11 KiB
| title | description | keywords | redirect_from | |||
|---|---|---|---|---|---|---|
| Set up an advanced frontend extension | Advanced frontend extension tutorial | Docker, extensions, sdk, build |
|
To start creating your extension, you first need a directory with files which range from the extension’s source code to the required extension-specific files. This page provides information on how to set up a simple Docker extension that contains only a UI part.
Note
Before you start, make sure you have installed the latest version of Docker Desktop.
Extension folder structure
The quickest way to create a new extension is to run docker extension init my-extension as in the
Quickstart. This will create a new directory my-extension that contains a fully functional extension.
Tip
The
docker extension initgenerates a React based extension. But you can still use it as a starting point for your own extension and use any other frontend framework, like Vue, Angular, Svelte, etc. or event stay with vanilla Javascript. {: .tip }
Although you can start from an empty directory or from the react-extension sample folder{:target="blank" rel="noopener" class=""},
it's highly recommended that you start from the docker extension init command and change it to suit your needs.
.
├── Dockerfile # (1)
├── ui # (2)
│ ├── public # (3)
│ │ └── index.html
│ ├── src # (4)
│ │ ├── App.tsx
│ │ ├── index.tsx
│ ├── package.json
│ └── package-lock.lock
│ ├── tsconfig.json
├── docker.svg # (5)
└── metadata.json # (6)
- Contains everything required to build the extension and run it in Docker Desktop.
- High-level folder containing your front-end app source code.
- Assets that aren’t compiled or dynamically generated are stored here. These can be static assets like logos or the robots.txt file.
- The src, or source folder contains all the React components, external CSS files, and dynamic assets that are brought into the component files.
- The icon that is displayed in the left-menu of the Docker Desktop Dashboard.
- A file that provides information about the extension such as the name, description, and version.
Adapting the Dockerfile
Note
When using the
docker extension init, it creates aDockerfilethat already contains what is needed for a React extension.
Once the extension is created, you need to configure the Dockerfile to build the extension and configure the labels
that are used to populate the extension's card in the Marketplace. Here is an example of a Dockerfile for a React
extension:
- For React
- For Vue
- For Angular
- For Svelte
FROM --platform=$BUILDPLATFORM node:18.9-alpine3.15 AS client-builder
WORKDIR /ui
# cache packages in layer
COPY ui/package.json /ui/package.json
COPY ui/package-lock.json /ui/package-lock.json
RUN --mount=type=cache,target=/usr/src/app/.npm \
npm set cache /usr/src/app/.npm && \
npm ci
# install
COPY ui /ui
RUN npm run build
FROM alpine
LABEL org.opencontainers.image.title="My extension" \
org.opencontainers.image.description="Your Desktop Extension Description" \
org.opencontainers.image.vendor="Awesome Inc." \
com.docker.desktop.extension.api.version="0.3.0" \
com.docker.desktop.extension.icon="https://www.docker.com/wp-content/uploads/2022/03/Moby-logo.png"
com.docker.extension.screenshots="" \
com.docker.extension.detailed-description="" \
com.docker.extension.publisher-url="" \
com.docker.extension.additional-urls="" \
com.docker.extension.changelog=""
COPY metadata.json .
COPY docker.svg .
COPY --from=client-builder /ui/build ui
Important
We don't have a working Dockerfile for Vue yet. Fill out the form and let us know you'd like a Dockerfile for Vue. {: .important }
Important
We don't have a working Dockerfile for Angular yet. Fill out the form and let us know you'd like a Dockerfile for Angular. {: .important }
Important
We don't have a working Dockerfile for Svelte yet. Fill out the form and let us know you'd like a Dockerfile for Svelte. {: .important }
Configure the metadata file
A metadata.json file is required at the root of your extension directory.
{
"icon": "docker.svg",
"ui": {
"dashboard-tab": {
"title": "UI Extension",
"root": "/ui",
"src": "index.html"
}
}
}
Use the Extension APIs client
To use the Extension APIs and perform actions with Docker Desktop, the extension must first import the
@docker/extension-api-client library. To install it, run the command below:
npm install @docker/extension-api-client
Then call the createDockerDesktopClient function to create a client object to call the extension APIs.
import { createDockerDesktopClient } from '@docker/extension-api-client';
const ddClient = createDockerDesktopClient();
When using Typescript, you can also install @docker/extension-api-client-types as a dev dependency. This will
provide you with type definitions for the extension APIs and auto-completion in your IDE.
npm install @docker/extension-api-client-types --save-dev
For example, you can use the docker.cli.exec function to get the list of all the containers via the docker ps --all
command and display the result in a table.
- React
- Vue
- Angular
- Svelte
Replace the ui/src/App.tsx file with the following code:
{% raw %}
// ui/src/App.tsx
import React, { useEffect } from 'react';
import {
Paper,
Stack,
Table,
TableBody,
TableCell,
TableContainer,
TableHead,
TableRow,
Typography
} from "@mui/material";
import { createDockerDesktopClient } from "@docker/extension-api-client";
//obtain docker destkop extension client
const ddClient = createDockerDesktopClient();
export function App() {
const [containers, setContainers] = React.useState([]);
useEffect(() => {
// List all containers
ddClient.docker.cli.exec('ps', ['--all', '--format', '"{{json .}}"']).then((result) => {
// result.parseJsonLines() parses the output of the command into an array of objects
setContainers(result.parseJsonLines());
});
}, []);
return (
<Stack>
<Typography data-testid="heading" variant="h3" role="title">
Container list
</Typography>
<Typography
data-testid="subheading"
variant="body1"
color="text.secondary"
sx={{ mt: 2 }}
>
Simple list of containers using Docker Extensions SDK.
</Typography>
<TableContainer sx={{mt:2}}>
<Table>
<TableHead>
<TableRow>
<TableCell>Container id</TableCell>
<TableCell>Image</TableCell>
<TableCell>Command</TableCell>
<TableCell>Created</TableCell>
<TableCell>Status</TableCell>
</TableRow>
</TableHead>
<TableBody>
{containers.map((container) => (
<TableRow
key={container.ID}
sx={{ '&:last-child td, &:last-child th': { border: 0 } }}
>
<TableCell>{container.ID}</TableCell>
<TableCell>{container.Image}</TableCell>
<TableCell>{container.Command}</TableCell>
<TableCell>{container.CreatedAt}</TableCell>
<TableCell>{container.Status}</TableCell>
</TableRow>
))}
</TableBody>
</Table>
</TableContainer>
</Stack>
);
}
{% endraw %}
Important
We don't have an example for Vue yet. Fill out the form and let us know you'd like a sample with Vue. {: .important }
Important
We don't have an example for Angular yet. Fill out the form and let us know you'd like a sample with Angular. {: .important }
Important
We don't have an example for Svelte yet. Fill out the form and let us know you'd like a sample with Svelte. {: .important }
What's next?
- Learn how to build and install your extension.
- For more information and guidelines on building the UI, see the Design and UI styling section.
- If you want to set up user authentication for the extension, see Authentication.

