2024-03-04 10:44:38 +00:00
<!doctype html>
2024-05-03 14:21:14 +00:00
< html lang = "en" dir = "ltr" class = "docs-wrapper plugin-docs plugin-id-default docs-version-current docs-doc-page docs-doc-id-extensions/developing/index" data-has-hydrated = "false" >
2024-03-04 10:44:38 +00:00
< head >
< meta charset = "UTF-8" >
2025-01-14 13:36:07 +00:00
< meta name = "generator" content = "Docusaurus v3.7.0" >
2024-05-03 14:21:14 +00:00
< title data-rh = "true" > Developing | Podman Desktop< / title > < meta data-rh = "true" name = "viewport" content = "width=device-width,initial-scale=1" > < meta data-rh = "true" name = "twitter:card" content = "summary_large_image" > < meta data-rh = "true" property = "og:image" content = "https://podman-desktop.io/img/banner_podman-desktop.png" > < meta data-rh = "true" name = "twitter:image" content = "https://podman-desktop.io/img/banner_podman-desktop.png" > < meta data-rh = "true" property = "og:url" content = "https://podman-desktop.io/docs/extensions/developing" > < meta data-rh = "true" property = "og:locale" content = "en" > < meta data-rh = "true" name = "docusaurus_locale" content = "en" > < meta data-rh = "true" name = "docsearch:language" content = "en" > < meta data-rh = "true" name = "docusaurus_version" content = "current" > < meta data-rh = "true" name = "docusaurus_tag" content = "docs-default-current" > < meta data-rh = "true" name = "docsearch:version" content = "current" > < meta data-rh = "true" name = "docsearch:docusaurus_tag" content = "docs-default-current" > < meta data-rh = "true" property = "og:title" content = "Developing | Podman Desktop" > < meta data-rh = "true" name = "description" content = "Developing a Podman Desktop extension" > < meta data-rh = "true" property = "og:description" content = "Developing a Podman Desktop extension" > < meta data-rh = "true" name = "keywords" content = "podman desktop,extension,writing" > < link data-rh = "true" rel = "icon" href = "/img/favicon.ico" > < link data-rh = "true" rel = "canonical" href = "https://podman-desktop.io/docs/extensions/developing" > < link data-rh = "true" rel = "alternate" href = "https://podman-desktop.io/docs/extensions/developing" hreflang = "en" > < link data-rh = "true" rel = "alternate" href = "https://podman-desktop.io/docs/extensions/developing" hreflang = "x-default" > < link data-rh = "true" rel = "preconnect" href = "https://MR01ANKQ9S-dsn.algolia.net" crossorigin = "anonymous" > < link rel = "alternate" type = "application/rss+xml" href = "/blog/rss.xml" title = "Podman Desktop RSS Feed" >
2024-03-04 10:44:38 +00:00
< link rel = "alternate" type = "application/atom+xml" href = "/blog/atom.xml" title = "Podman Desktop Atom Feed" >
< link rel = "alternate" type = "application/json" href = "/blog/feed.json" title = "Podman Desktop JSON Feed" >
2025-01-14 13:36:07 +00:00
2024-03-04 10:44:38 +00:00
< link rel = "search" type = "application/opensearchdescription+xml" title = "Podman Desktop" href = "/opensearch.xml" >
< link rel = "preconnect" href = "https://podman-desktop-website.goatcounter.com" >
2025-03-10 08:19:06 +00:00
< script async src = "//gc.zgo.at/count.js" data-goatcounter = "https://podman-desktop-website.goatcounter.com/count" > < / script > < link rel = "stylesheet" href = "/assets/css/styles.c462fc7b.css" >
2025-03-12 10:31:46 +00:00
< script src = "/assets/js/runtime~main.162b924b.js" defer = "defer" > < / script >
2025-03-12 06:29:10 +00:00
< script src = "/assets/js/main.46c998bc.js" defer = "defer" > < / script >
2024-03-04 10:44:38 +00:00
< / head >
< body class = "navigation-with-keyboard" >
2025-03-06 10:05:43 +00:00
< script > ! function ( ) { function t ( t ) { document . documentElement . setAttribute ( "data-theme" , t ) } var e = function ( ) { try { return new URLSearchParams ( window . location . search ) . get ( "docusaurus-theme" ) } catch ( t ) { } } ( ) || function ( ) { try { return window . localStorage . getItem ( "theme" ) } catch ( t ) { } } ( ) ; null !== e ? t ( e ) : window . matchMedia ( "(prefers-color-scheme: dark)" ) . matches ? t ( "dark" ) : window . matchMedia ( "(prefers-color-scheme: light)" ) . matches ? t ( "light" ) : t ( "dark" ) } ( ) , function ( ) { try { const c = new URLSearchParams ( window . location . search ) . entries ( ) ; for ( var [ t , e ] of c ) if ( t . startsWith ( "docusaurus-data-" ) ) { var a = t . replace ( "docusaurus-data-" , "data-" ) ; document . documentElement . setAttribute ( a , e ) } } catch ( t ) { } } ( ) < / script > < div id = "__docusaurus" > < div role = "region" aria-label = "Skip to main content" > < a class = "skipToContent_oPtH" href = "#__docusaurus_skipToContent_fallback" > Skip to main content< / a > < / div > < nav aria-label = "Main" class = "navbar navbar--fixed-top" > < div class = "navbar__inner" > < div class = "navbar__items" > < button aria-label = "Toggle navigation bar" aria-expanded = "false" class = "navbar__toggle clean-btn" type = "button" > < svg width = "30" height = "30" viewBox = "0 0 30 30" aria-hidden = "true" > < path stroke = "currentColor" stroke-linecap = "round" stroke-miterlimit = "10" stroke-width = "2" d = "M4 7h22M4 15h22M4 23h22" > < / path > < / svg > < / button > < a class = "navbar__brand" href = "/" > < div class = "navbar__logo" > < img src = "/img/logo.svg" alt = "Podman Desktop Logo" class = "themedComponent_siVc themedComponent--light_hHel" height = "56" > < img src = "/img/logo.svg" alt = "Podman Desktop Logo" class = "themedComponent_siVc themedComponent--dark_yETr" height = "56" > < / div > < b class = "navbar__title text--truncate" > podman desktop< / b > < / a > < a aria-current = "page" class = "navbar__item navbar__link navbar__link--active" href = "/docs/intro" > Documentation< / a > < a class = "navbar__item navbar__link" href = "/downloads" > Downloads< / a > < a class = "navbar__item navbar__link" href = "/community" > Community< / a > < div class = "navbar__item dropdown dropdown--hoverable" > < a href = "#" aria-haspopup = "true" aria-expanded = "false" role = "button" class = "navbar__link" > Resources< / a > < ul class = "dropdown__menu" > < li > < a class = "dropdown__link" href = "/features" > Features< / a > < / li > < li > < a class = "dropdown__link" href = "/tutorial" > Tutorials< / a > < / li > < li > < a class = "dropdown__link" href = "/extend" > Extend< / a > < / li > < / ul > < / div > < a class = "navbar__item navbar__link" href = "/blog" > Blog< / a > < / div > < div class = "navbar__items navbar__items--right" > < a href = "https://github.com/podman-desktop/podman-desktop" target = "_blank" rel = "noopener noreferrer" class = "navbar__item navbar__link header-github-link" > < / a > < div class = "toggle_ki11 colorModeToggle_Hewu" > < button class = "clean-btn toggleButton_MMFG toggleButtonDisabled_Uw7m" type = "button" disabled = "" title = "Switch between dark and light mode (currently dark mode)" aria-label = "Switch between dark and light mode (currently dark mode)" aria-live = "polite" aria-pressed = "true" > < svg viewBox = "0 0 24 24" width = "24" height = "24" class = "lightToggleIcon_lgto" > < path fill = "currentColor" d = "M12,9c1.65,0,3,1.35,3,3s-1.35,3-3,3s-3-1.35-3-3S10.35,9,12,9 M12,7c-2.76,0-5,2.24-5,5s2.24,5,5,5s5-2.24,5-5 S14.76,7,12,7L12,7z M2,13l2,0c0.55,0,1-0.45,1-1s-0.45-1-1-1l-2,0c-0.55,0-1,0.45-1,1S1.45,13,2,13z M20,13l2,0c0.55,0,1-0.45,1-1 s-0.45-1-1-1l-2,0c-0.55,0-1,0.45-1,1S19.45,13,20,13z M11,2v2c0,0.55,0.45,1,1,1s1-0.45,1-1V2c0-0.55-0.45-1-1-1S11,1.45,11,2z M11,20v2c0,0.55,0.45,1,1,1s1-0.45,1-1v-2c0-0.55-0.45-1-1-1C11.45,19,11,19.45,11,20z M5.99,4.58c-0.39-0.39-1.03-0.39-1.41,0 c-0.39,0.39-0.39,1.03,0,1.41l1.06,1.06c0.39,0.39,1.03,0.39,1.41,0s0.39-1.03,0-1.41L5.99,4.58z M18.36,16.95 c-0.39-0.39-1.03-0.39-1.41,0c-0.39,0.39-0.39,1.03,0,1.41l1.06,1.06c0.39,0.39,1.03,0.39,1.41,0c0.39-0.39,0.39-1.03,0-1.41 L18.36,16.95z M19.42,5.99c0.39-0.39,0.39-1.03,0-1.41c-0.39-0.39-1.03-0.39-1.41,0l-1.06,1.06c-0.39,0.39-0.39,1.03,0,1.41 s1.03,0.39,1.41,0L19.42,5.99z M7.05,18.36c0.39-0.39,0.39-1.03,0-1.41c-0.39-0.39-1.03-0.39-1.41,0l-1.06,1.06 c-0.39,0.39-0.39,1.03,0,1.41s1.03,0.39,1.41,0L7.05,18.36z" > < / path > < / svg > < svg viewBox = "0 0 24 24" width = "24" height = "24" class = "darkToggleIcon_U96C" > < path fill = "currentColor" d
2025-02-25 10:17:38 +00:00
< p > Podman Desktop is organized so that you can modularly add new functionality in the form of " extensions" as well as the corresponding extension-api. This allows you to communicate with Podman Desktop without having to know the internal workings. You look for the API call and Podman Desktop will do the rest.< / p >
< p > It is recommended that an extension be written in < code > TypeScript< / code > for type checking, but extensions can be written in < code > JavaScript< / code > .< / p >
< p > Most extensions are externally loaded; however, we also dogfood our own API by loading them as < a href = "https://github.com/podman-desktop/podman-desktop/tree/main/extensions" target = "_blank" rel = "noopener noreferrer" > internal extensions< / a > that use the same API. These internally maintained extensions can be used as an example and basis for how to build an externally loaded extension.< / p >
2024-08-14 11:49:56 +00:00
< h2 class = "anchor anchorWithStickyNavbar_JmGV" id = "overview-of-creating-a-new-extension" > Overview of creating a new extension< a href = "#overview-of-creating-a-new-extension" class = "hash-link" aria-label = "Direct link to Overview of creating a new extension" title = "Direct link to Overview of creating a new extension" > < / a > < / h2 >
2025-02-25 10:17:38 +00:00
< p > We try to simplify extension creation as much as possible by utilizing < code > package.json< / code > and by keeping activations simple within the extension, providing only two entrypoints: < code > activate()< / code > and < code > deactivate()< / code > .< / p >
< p > All Podman Desktop functionalities are communicated entirely through the API. The extension you create interacts with the Podman Desktop API through the < code > @podman-desktop/api< / code > package. The API code is located < a href = "https://github.com/podman-desktop/podman-desktop/blob/main/packages/extension-api/src/extension-api.d.ts" target = "_blank" rel = "noopener noreferrer" > here< / a > , while the website representation of the code can be found < a href = "https://podman-desktop.io/api" target = "_blank" rel = "noopener noreferrer" > here< / a > .< / p >
2024-08-14 11:49:56 +00:00
< h3 class = "anchor anchorWithStickyNavbar_JmGV" id = "activating" > Activating< a href = "#activating" class = "hash-link" aria-label = "Direct link to Activating" title = "Direct link to Activating" > < / a > < / h3 >
2024-05-27 18:05:18 +00:00
< p > When activating an extension, Podman Desktop will:< / p >
< ol >
2025-02-25 10:17:38 +00:00
< li > Search and load the < code > JavaScript< / code > file specified in < code > main< / code > entry of the < code > package.json< / code > file in the extension directory (typically < code > extension.js< / code > ).< / li >
2024-05-27 18:05:18 +00:00
< li > Run the exported < code > activate< / code > function.< / li >
< / ol >
2024-08-14 11:49:56 +00:00
< h3 class = "anchor anchorWithStickyNavbar_JmGV" id = "deactivating" > Deactivating< a href = "#deactivating" class = "hash-link" aria-label = "Direct link to Deactivating" title = "Direct link to Deactivating" > < / a > < / h3 >
2024-05-27 18:05:18 +00:00
< p > When deactivating an extension, Podman Desktop will:< / p >
< ol >
2025-02-25 10:17:38 +00:00
< li > Run the optionally exported < code > deactivate< / code > function.< / li >
2024-12-16 17:01:42 +00:00
< li > Dispose of any resources that have been added to < code > extensionContext.subscriptions< / code > , see < code > deactivateExtension< / code > in < a href = "https://github.com/podman-desktop/podman-desktop/blob/main/packages/main/src/plugin/extension-loader.ts" target = "_blank" rel = "noopener noreferrer" > extension-loader.ts< / a > .< / li >
2024-05-27 18:05:18 +00:00
< / ol >
2024-08-14 11:49:56 +00:00
< h3 class = "anchor anchorWithStickyNavbar_JmGV" id = "example-boilerplate-code" > Example boilerplate code< a href = "#example-boilerplate-code" class = "hash-link" aria-label = "Direct link to Example boilerplate code" title = "Direct link to Example boilerplate code" > < / a > < / h3 >
2025-02-25 10:17:38 +00:00
< p > This is an example < code > extensions/foobar/src/extensions.ts< / code > file with the basic < code > activate< / code > and < code > deactivate< / code > functionalities, provided that you already have a < code > package.json< / code > created as well:< / p >
2024-05-27 18:05:18 +00:00
< div class = "language-ts codeBlockContainer_mQmQ theme-code-block" style = "--prism-color:#F8F8F2;--prism-background-color:#282A36" > < div class = "codeBlockContent_D5yF" > < pre tabindex = "0" class = "prism-code language-ts codeBlock_RMoD thin-scrollbar" style = "color:#F8F8F2;background-color:#282A36" > < code class = "codeBlockLines_AclH" > < span class = "token-line" style = "color:#F8F8F2" > < span class = "token keyword" style = "color:rgb(189, 147, 249);font-style:italic" > import< / span > < span class = "token plain" > < / span > < span class = "token operator" > *< / span > < span class = "token plain" > < / span > < span class = "token keyword" style = "color:rgb(189, 147, 249);font-style:italic" > as< / span > < span class = "token plain" > extensionApi < / span > < span class = "token keyword" style = "color:rgb(189, 147, 249);font-style:italic" > from< / span > < span class = "token plain" > < / span > < span class = "token string" style = "color:rgb(255, 121, 198)" > ' @podman-desktop/api' < / span > < span class = "token punctuation" style = "color:rgb(248, 248, 242)" > ;< / span > < span class = "token plain" > < / span > < br > < / span > < span class = "token-line" style = "color:#F8F8F2" > < span class = "token plain" style = "display:inline-block" > < / span > < br > < / span > < span class = "token-line" style = "color:#F8F8F2" > < span class = "token plain" > < / span > < span class = "token comment" style = "color:rgb(98, 114, 164)" > // Activate the extension asynchronously< / span > < span class = "token plain" > < / span > < br > < / span > < span class = "token-line" style = "color:#F8F8F2" > < span class = "token plain" > < / span > < span class = "token keyword" style = "color:rgb(189, 147, 249);font-style:italic" > export< / span > < span class = "token plain" > < / span > < span class = "token keyword" style = "color:rgb(189, 147, 249);font-style:italic" > async< / span > < span class = "token plain" > < / span > < span class = "token keyword" style = "color:rgb(189, 147, 249);font-style:italic" > function< / span > < span class = "token plain" > < / span > < span class = "token function" style = "color:rgb(80, 250, 123)" > activate< / span > < span class = "token punctuation" style = "color:rgb(248, 248, 242)" > (< / span > < span class = "token plain" > extensionContext< / span > < span class = "token operator" > :< / span > < span class = "token plain" > extensionApi< / span > < span class = "token punctuation" style = "color:rgb(248, 248, 242)" > .< / span > < span class = "token plain" > ExtensionContext< / span > < span class = "token punctuation" style = "color:rgb(248, 248, 242)" > )< / span > < span class = "token operator" > :< / span > < span class = "token plain" > < / span > < span class = "token builtin" style = "color:rgb(189, 147, 249)" > Promise< / span > < span class = "token operator" > < < / span > < span class = "token keyword" style = "color:rgb(189, 147, 249);font-style:italic" > void< / span > < span class = "token operator" > > < / span > < span class = "token plain" > < / span > < span class = "token punctuation" style = "color:rgb(248, 248, 242)" > {< / span > < span class = "token plain" > < / span > < br > < / span > < span class = "token-line" style = "color:#F8F8F2" > < span class = "token plain" > < / span > < span class = "token comment" style = "color:rgb(98, 114, 164)" > // Create a provider with an example name, ID and icon< / span > < span class = "token plain" > < / span > < br > < / span > < span class = "token-line" style = "color:#F8F8F2" > < span class = "token plain" > < / span > < span class = "token keyword" style = "color:rgb(189, 147, 249);font-style:italic" > const< / span > < span class = "token plain" > provider < / span > < span class = "token operator" > =< / span > < span class = "token plain" > extensionApi< / span > < span class = "token punctuation" style = "color:rgb(248, 248, 242)" > .< / span > < span class = "token plain" > provider< / span > < span class = "token punctuation" style = "color:rgb(248, 248, 242)" > .< / span > < span class = "token function" style = "color:rgb(80, 250, 123)" > createProvider< / span > < span class = "token punctuation" style = "color:rgb(248, 248, 242)" > (< / span > < span class = "token punctuation" style = "color:rgb(248, 248, 242)" > {< / span > < span class = "token plain" > < / span > < br > < / span > < span class = "token-line" style = "color:#F8F8F2" > < span class = "token plain" > name< / span > < span class = "token operator" > :< / span > < span class = "token plain" > < / span > < span class = "token string" style = "color:rgb(255, 121, 198)" > ' FooBar' < / span > < span class = "token punctuation" style = "color:rgb(24
2024-08-14 11:49:56 +00:00
< h3 class = "anchor anchorWithStickyNavbar_JmGV" id = "interacting-with-the-ui" > Interacting with the UI< a href = "#interacting-with-the-ui" class = "hash-link" aria-label = "Direct link to Interacting with the UI" title = "Direct link to Interacting with the UI" > < / a > < / h3 >
2025-02-25 10:17:38 +00:00
< p > The extension " hooks" into the Podman Desktop UI by various means, which include:< / p >
2024-05-27 18:05:18 +00:00
< ul >
2025-02-25 10:17:38 +00:00
< li > Registering the extension as a specific provider (authentication, registry, Kubernetes, containers, CLI tools, or others).< / li >
< li > Registering to specific events (with functions starting with < code > onDid...< / code > ).< / li >
< li > Adding entries to menus (tray menu, status bar, and other types of menus).< / li >
< li > Adding fields to the configuration panel.< / li >
< li > Watching files in the filesystem.< / li >
2024-05-27 18:05:18 +00:00
< / ul >
2025-02-25 10:17:38 +00:00
< p > When the extension code is accessed through these different registrations, the extension can use utility functions provided by the API to:< / p >
2024-05-27 18:05:18 +00:00
< ul >
2025-02-25 10:17:38 +00:00
< li > Get values of configuration fields.< / li >
< li > Interact with the user through input boxes and quick picks.< / li >
< li > Display information, warnings, error messages, and notifications to the user.< / li >
< li > Get information about the environment (OS, telemetry, system clipboard).< / li >
< li > Execute the process in the system.< / li >
< li > Send data to the telemetry.< / li >
< li > Set data in the context, which is propagated in the UI.< / li >
2024-05-27 18:05:18 +00:00
< / ul >
2025-02-25 10:17:38 +00:00
< h2 class = "anchor anchorWithStickyNavbar_JmGV" id = "creating-and-running-your-extension" > Creating and running your extension< a href = "#creating-and-running-your-extension" class = "hash-link" aria-label = "Direct link to Creating and running your extension" title = "Direct link to Creating and running your extension" > < / a > < / h2 >
< p > You can create and run an extension by performing the following end-to-end tasks:< / p >
2024-03-04 10:44:38 +00:00
< ol >
2025-02-25 10:17:38 +00:00
< li > < a href = "/tutorial/creating-an-extension#initializing-an-extension" > Initializing an extension< / a > < / li >
< li > < a href = "/tutorial/creating-an-extension#writing-the-extension-entry-point" > Writing the extension' s features< / a > < / li >
< li > < a href = "/tutorial/creating-an-extension#build-dependencies" > Build dependencies< / a > < / li >
< li > < a href = "/tutorial/creating-an-extension#running-the-extension" > Running the extension< / a > < / li >
< li > < a href = "/tutorial/creating-an-extension#verifying-the-extensions-features" > Verifying the extension' s features< / a > < / li >
2024-03-04 10:44:38 +00:00
< / ol >
2024-08-14 11:49:56 +00:00
< h2 class = "anchor anchorWithStickyNavbar_JmGV" id = "expanding-your-extension" > Expanding your extension< a href = "#expanding-your-extension" class = "hash-link" aria-label = "Direct link to Expanding your extension" title = "Direct link to Expanding your extension" > < / a > < / h2 >
2024-05-27 18:05:18 +00:00
< p > Below is documentation and/or " boiler-plate" code that can help expand your extension.< / p >
2025-03-06 10:05:43 +00:00
< h3 class = "anchor anchorWithStickyNavbar_JmGV" id = "using-providerstatus" > Using < code > ProviderStatus< / code > < a href = "#using-providerstatus" class = "hash-link" aria-label = "Direct link to using-providerstatus" title = "Direct link to using-providerstatus" >