podman-desktop/website/docs/extensions/developing/index.md
Charlie Drage 6526388812
docs: update the extensions section (#7061)
### What does this PR do?

* Renames the extension section to just "Extensions"
* Moved Installing to #1 in the list
* Changes "Write" to "Developing" section
* Adds redirect links
* Move publishing to bottom part

### Screenshot / video of UI

<!-- If this PR is changing UI, please include
screenshots or screencasts showing the difference -->

### What issues does this PR fix or reference?

<!-- Include any related issues from Podman Desktop
repository (or from another issue tracker). -->

Part of https://github.com/containers/podman-desktop/issues/6883
discussion (does not close it though)

### How to test this PR?

<!-- Please explain steps to verify the functionality,
do not forget to provide unit/component tests -->

Visit the site :)

Signed-off-by: Charlie Drage <charlie@charliedrage.com>
2024-05-03 14:16:12 +00:00

7.9 KiB

sidebar_position title description tags keywords
2 Developing Developing a Podman Desktop extension
podman-desktop
extension
writing
podman desktop
extension
writing

Developing a Podman Desktop extension

To write a Podman Desktop extension, start a Node.js or TypeScript project calling the Podman Desktop API, and ensure all runtime dependencies are inside the final binary.

Initializing a Podman Desktop extension

Write the Podman Desktop extension Node.js package metadata.

Prerequisites

  • JavaScript or TypeScript

Procedure

  1. Create and edit a package.json file.

    {}
    
  2. Add TypeScript and Podman Desktop API to the development dependencies:

     "devDependencies": {
       "@podman-desktop/api": "latest",
       "typescript": "latest",
       "vite": "latest"
     },
    
  3. Add the required metadata:

      "name": "my-extension",
      "displayName": "My Hello World extension",
      "description": "How to write my first extension",
      "version": "0.0.1",
      "icon": "icon.png",
      "publisher": "benoitf",
    
  4. Add the Podman Desktop version that might run this extension:

      "engines": {
        "podman-desktop": "latest"
      },
    
  5. Add the main entry point:

     "main": "./dist/extension.js"
    
  6. Add a Hello World command contribution

      "contributes": {
        "commands": [
         {
           "command": "my.first.command",
           "title": "My First Extension: Hello World"
         }
       ]
      }
    
  7. Add an icon.png file to the project.

Verification

  • Full package.json example:

    {
      "devDependencies": {
        "@podman-desktop/api": "latest",
        "typescript": "latest",
        "vite": "latest"
      },
      "name": "my-extension",
      "displayName": "My Hello World extension",
      "description": "How to write my first extension",
      "version": "0.0.1",
      "icon": "icon.png",
      "publisher": "benoitf",
      "engines": {
        "podman-desktop": "latest"
      },
      "scripts": {
        "build": "vite build",
        "test": "vitest run --coverage",
        "test:watch": "vitest watch --coverage",
        "watch": "vite build --watch"
      },
      "main": "./dist/extension.js",
      "contributes": {
        "commands": [
          {
            "command": "my.first.command",
            "title": "My First Extension: Hello World"
          }
        ]
      }
    }
    

Writing a Podman Desktop extension entry point

Write the extension features.

Prerequisites

  • JavaScript or TypeScript

Procedure

  1. Create and edit a src/extension.ts file.

  2. Import the Podman Desktop API

    import * as podmanDesktopAPI from '@podman-desktop/api';
    
  3. Expose the activate function to call on activation.

    The signature of the function can be:

    • Synchronous

      export function activate(): void;
      
    • Asynchronous

      export async function activate(): Promise<void>;
      
  4. (Optional) Add an extension context to the activate function enabling the extension to register disposable resources:

    export async function activate(extensionContext: podmanDesktopAPI.ExtensionContext): Promise<void> {}
    
  5. Register the command and the callback

    import * as podmanDesktopAPI from '@podman-desktop/api';
    export async function activate(extensionContext: podmanDesktopAPI.ExtensionContext): Promise<void> {
      // register the command referenced in package.json file
      const myFirstCommand = podmanDesktopAPI.commands.registerCommand('my.first.command', async () => {
        // display a choice to the user for selecting some values
        const result = await podmanDesktopAPI.window.showQuickPick(['un', 'deux', 'trois'], {
          canPickMany: true, // user can select more than one choice
        });
    
        // display an information message with the user choice
        await podmanDesktopAPI.window.showInformationMessage(`The choice was: ${result}`);
      });
    
      // create an item in the status bar to run our command
      // it will stick on the left of the status bar
      const item = podmanDesktopAPI.window.createStatusBarItem(podmanDesktopAPI.StatusBarAlignLeft, 100);
      item.text = 'My first command';
      item.command = 'my.first.command';
      item.show();
    
      // register disposable resources to it's removed when we deactivte the extension
      extensionContext.subscriptions.push(myFirstCommand);
      extensionContext.subscriptions.push(item);
    }
    
  6. (Optional) Expose the deactivate function to call on deactivation.

    The signature of the function can be:

    • Synchronous

      export function deactivate(): void;
      
    • Asynchronous

      export async function deactivate(): Promise<void>;
      

Build dependencies

This examples uses TypeScript and Vite to build and the following files should be in the root of your extension.

Create a file named tsconfig.json with the following content:

{
  "compilerOptions": {
    "module": "esnext",
    "lib": ["ES2017"],
    "sourceMap": true,
    "rootDir": "src",
    "outDir": "dist",
    "target": "esnext",
    "moduleResolution": "Node",
    "allowSyntheticDefaultImports": true,
    "resolveJsonModule": true,
    "skipLibCheck": true,
    "types": ["node"]
  },
  "include": ["src", "types/*.d.ts"]
}

Create a file named vite.config.js with the following content:

/**********************************************************************
 * Copyright (C) 2023 Red Hat, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * SPDX-License-Identifier: Apache-2.0
 ***********************************************************************/

import { join } from 'path';
import { builtinModules } from 'module';

const PACKAGE_ROOT = __dirname;

/**
 * @type {import('vite').UserConfig}
 * @see https://vitejs.dev/config/
 */
const config = {
  mode: process.env.MODE,
  root: PACKAGE_ROOT,
  envDir: process.cwd(),
  resolve: {
    alias: {
      '/@/': join(PACKAGE_ROOT, 'src') + '/',
    },
  },
  build: {
    sourcemap: 'inline',
    target: 'esnext',
    outDir: 'dist',
    assetsDir: '.',
    minify: process.env.MODE === 'production' ? 'esbuild' : false,
    lib: {
      entry: 'src/extension.ts',
      formats: ['cjs'],
    },
    rollupOptions: {
      external: ['@podman-desktop/api', ...builtinModules.flatMap(p => [p, `node:${p}`])],
      output: {
        entryFileNames: '[name].js',
      },
    },
    emptyOutDir: true,
    reportCompressedSize: false,
  },
};

export default config;

Verification

  • The extension compiles and produces the output in the dist folder.

  • All runtime dependencies are inside the final binary.

Developing a Podman Desktop extension

Prerequisites

Procedure

  1. To start Podman Desktop with your extension loaded, run the following from your clone of the Podman Desktop repo:
yarn watch --extension-folder /path/to/your/extension

Additional resources

  • Consider a packer such as Rollup or Webpack to shrink the size of the artifact.

Next steps