Let plugins add contextual workspace tools (#3465)
* feat(plugins): add workspace panels and command center contributions Give local plugins contextual UI entry points without making the daemon interpret client placement or callbacks. Panels receive stable IDs and read cached client state through required selectors with shallow equality, avoiding unrelated guest rerenders and context-discovery RPCs. * fix(plugins): align shared client state ownership Workspace panels and Command Center callbacks consume the same frozen client snapshots, so their adapter belongs to the plugin boundary rather than either contribution surface. Refresh the Nix dependency hash for the selector-store dependency added by this feature.
This commit is contained in:
@@ -42,5 +42,5 @@ export default function contribute(plugin: PluginContext) {
|
||||
return linear.search(query);
|
||||
});
|
||||
plugin.addAttachmentSource(issueAttachments);
|
||||
return () => undefined;
|
||||
return () => {};
|
||||
}
|
||||
|
||||
@@ -2,7 +2,13 @@ import React, { useCallback, useMemo } from "react";
|
||||
import { Pressable, Text, View } from "react-native";
|
||||
import { useMutation } from "@tanstack/react-query";
|
||||
import { z } from "zod";
|
||||
import { defineRpc, type PluginContext, type PluginSurfaceProps, useRpc } from "@paseo/plugin";
|
||||
import {
|
||||
defineRpc,
|
||||
type PluginContext,
|
||||
type PluginWorkspacePanelProps,
|
||||
useWorkspace,
|
||||
useRpc,
|
||||
} from "@paseo/plugin";
|
||||
|
||||
const incrementRpc = defineRpc({
|
||||
name: "increment",
|
||||
@@ -21,8 +27,9 @@ const ExampleThemeSchema = z.object({
|
||||
}),
|
||||
});
|
||||
|
||||
function ExampleSurface({ theme }: PluginSurfaceProps) {
|
||||
function ExamplePanel({ theme, workspaceId }: PluginWorkspacePanelProps) {
|
||||
const { colors } = ExampleThemeSchema.parse(theme);
|
||||
const workspace = useWorkspace(workspaceId, ({ name }) => ({ name }));
|
||||
const callIncrement = useRpc(incrementRpc);
|
||||
const { data, error, isPending, mutate } = useMutation({ mutationFn: callIncrement });
|
||||
const value = data?.value ?? 0;
|
||||
@@ -43,7 +50,8 @@ function ExampleSurface({ theme }: PluginSurfaceProps) {
|
||||
|
||||
return (
|
||||
<View style={styles.screen}>
|
||||
<Text style={styles.title}>Native plugin surface</Text>
|
||||
<Text style={styles.title}>Workspace plugin panel</Text>
|
||||
<Text style={styles.detail}>{workspace?.name}</Text>
|
||||
<Text style={styles.detail}>{data?.handledBy ?? "The RPC has not run yet."}</Text>
|
||||
<Pressable
|
||||
accessibilityRole="button"
|
||||
@@ -65,12 +73,21 @@ export default function contribute(plugin: PluginContext) {
|
||||
value: input.value + 1,
|
||||
handledBy: "plugin subprocess",
|
||||
}));
|
||||
plugin.addSurface("main", ExampleSurface);
|
||||
plugin.addSidebarItem({
|
||||
id: "main",
|
||||
title: "Local plugin",
|
||||
plugin.addWorkspacePanel({
|
||||
id: "counter",
|
||||
title: "Plugin counter",
|
||||
icon: "Blocks",
|
||||
surface: "main",
|
||||
context: "workspace",
|
||||
Component: ExamplePanel,
|
||||
});
|
||||
return () => undefined;
|
||||
plugin.addCommandCenterItem({
|
||||
id: "open-counter",
|
||||
title: "Open plugin counter",
|
||||
icon: "Blocks",
|
||||
context: "workspace",
|
||||
onSelect({ openPanel }) {
|
||||
openPanel("counter");
|
||||
},
|
||||
});
|
||||
return () => {};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user