Archived
fix(plugins): rename updates plugin id
This commit is contained in:
@@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
"@jmfederico/pi-web": patch
|
||||||
|
---
|
||||||
|
|
||||||
|
Rename the built-in Updates plugin id from `pi-web` to `updates` for clearer plugin configuration.
|
||||||
@@ -101,7 +101,7 @@ PI WEB keeps its own state intentionally small:
|
|||||||
|
|
||||||
PI WEB production installs can load trusted local UI plugins without rebuilding PI WEB. Plugins are browser-side ES modules that can add action-palette actions, workspace panels, and workspace-label metadata. They do not run in the session daemon and are not sandboxed.
|
PI WEB production installs can load trusted local UI plugins without rebuilding PI WEB. Plugins are browser-side ES modules that can add action-palette actions, workspace panels, and workspace-label metadata. They do not run in the session daemon and are not sandboxed.
|
||||||
|
|
||||||
The supported package shape is intentionally singular: `piWeb.plugins` entries with explicit `id` and `module`, plus a browser module that exports `{ apiVersion: 1, name, activate }`. The bundled `pi-web-plugins/info` TypeScript source is the canonical minimal real example, `pi-web-plugins/pi-web` demonstrates a dynamic status panel, and built-in [Workspace Tasks](docs/plugins.md#workspace-tasks) adds a workspace tab for running configured shell commands in PI WEB terminals.
|
The supported package shape is intentionally singular: `piWeb.plugins` entries with explicit `id` and `module`, plus a browser module that exports `{ apiVersion: 1, name, activate }`. The bundled `pi-web-plugins/info` TypeScript source is the canonical minimal real example, `pi-web-plugins/updates` demonstrates a dynamic status panel, and built-in [Workspace Tasks](docs/plugins.md#workspace-tasks) adds a workspace tab for running configured shell commands in PI WEB terminals.
|
||||||
|
|
||||||
A useful prompt for AI agents:
|
A useful prompt for AI agents:
|
||||||
|
|
||||||
|
|||||||
+21
-1
@@ -162,7 +162,7 @@ After editing, check the manifest endpoint and browser-console failure cases.</c
|
|||||||
If you copy it, choose a new plugin id so it does not conflict with the bundled <code>info</code> plugin.
|
If you copy it, choose a new plugin id so it does not conflict with the bundled <code>info</code> plugin.
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
The bundled <code>pi-web</code> status plugin demonstrates dynamic <code>visible</code> and <code>badge</code>
|
The bundled <code>updates</code> plugin demonstrates dynamic <code>visible</code> and <code>badge</code>
|
||||||
callbacks for tabs that only appear when the host has status messages or needs extra install visibility.
|
callbacks for tabs that only appear when the host has status messages or needs extra install visibility.
|
||||||
</p>
|
</p>
|
||||||
</section>
|
</section>
|
||||||
@@ -179,6 +179,26 @@ After editing, check the manifest endpoint and browser-console failure cases.</c
|
|||||||
<code>plugins</code> config key.
|
<code>plugins</code> config key.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
<h3>Updates</h3>
|
||||||
|
<p>
|
||||||
|
<strong>Updates</strong> adds a conditional <strong>Updates</strong> workspace tab with PI WEB update,
|
||||||
|
restart, and installed-service guidance. It is built into PI WEB and enabled by default.
|
||||||
|
</p>
|
||||||
|
<ul>
|
||||||
|
<li>Plugin id: <code>updates</code></li>
|
||||||
|
</ul>
|
||||||
|
<div class="code-card">
|
||||||
|
<div class="copy-row">
|
||||||
|
<strong>Disable Updates</strong>
|
||||||
|
<button class="copy-button" data-copy="#updates-disable">Copy</button>
|
||||||
|
</div>
|
||||||
|
<pre id="updates-disable"><code>{
|
||||||
|
"plugins": {
|
||||||
|
"updates": { "enabled": false }
|
||||||
|
}
|
||||||
|
}</code></pre>
|
||||||
|
</div>
|
||||||
|
|
||||||
<h3>Workspace Tasks</h3>
|
<h3>Workspace Tasks</h3>
|
||||||
<p>
|
<p>
|
||||||
<strong>Workspace Tasks</strong> adds a <strong>Tasks</strong> workspace tab for running configured shell
|
<strong>Workspace Tasks</strong> adds a <strong>Tasks</strong> workspace tab for running configured shell
|
||||||
|
|||||||
+16
-1
@@ -112,7 +112,7 @@ export default {
|
|||||||
|
|
||||||
When copying the Info plugin, choose a new plugin id so it does not conflict with the bundled `info` plugin.
|
When copying the Info plugin, choose a new plugin id so it does not conflict with the bundled `info` plugin.
|
||||||
|
|
||||||
PI WEB also ships a `pi-web` status plugin that demonstrates dynamic `visible` and `badge` callbacks for tabs that only appear when the host has status messages or needs extra install visibility.
|
PI WEB also ships an `updates` plugin that demonstrates dynamic `visible` and `badge` callbacks for tabs that only appear when the host has status messages or needs extra install visibility.
|
||||||
|
|
||||||
## Local plugin usage
|
## Local plugin usage
|
||||||
|
|
||||||
@@ -157,6 +157,21 @@ PI WEB ships core, discoverable plugins in the main `@jmfederico/pi-web` npm pac
|
|||||||
|
|
||||||
Built-in plugins can be managed from **Settings → Plugins** or with the top-level `plugins` config key.
|
Built-in plugins can be managed from **Settings → Plugins** or with the top-level `plugins` config key.
|
||||||
|
|
||||||
|
### Updates
|
||||||
|
|
||||||
|
**Plugin id:** `updates`
|
||||||
|
**What it does:** adds a conditional **Updates** workspace tab with PI WEB update, restart, and installed-service guidance.
|
||||||
|
|
||||||
|
Updates is enabled by default. To hide it, disable `updates` in **Settings → Plugins** or set:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"plugins": {
|
||||||
|
"updates": { "enabled": false }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
### Workspace Tasks
|
### Workspace Tasks
|
||||||
|
|
||||||
**Plugin id:** `workspace-tasks`
|
**Plugin id:** `workspace-tasks`
|
||||||
|
|||||||
@@ -1,9 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "@pi-web/status-plugin",
|
|
||||||
"private": true,
|
|
||||||
"piWeb": {
|
|
||||||
"plugins": [
|
|
||||||
{ "id": "pi-web", "module": "pi-web-plugin.js" }
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
{
|
||||||
|
"name": "@pi-web/updates-plugin",
|
||||||
|
"private": true,
|
||||||
|
"piWeb": {
|
||||||
|
"plugins": [
|
||||||
|
{ "id": "updates", "module": "pi-web-plugin.js" }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -19,7 +19,7 @@ function isLocalOrUnknownInstallation(installation: PiWebInstallationInfo | unde
|
|||||||
return installation === undefined || installation.kind === "local" || installation.kind === "unknown";
|
return installation === undefined || installation.kind === "local" || installation.kind === "unknown";
|
||||||
}
|
}
|
||||||
|
|
||||||
function shouldShowStatusPanel(state: AppState): boolean {
|
function shouldShowUpdatesPanel(state: AppState): boolean {
|
||||||
const status = statusFor(state);
|
const status = statusFor(state);
|
||||||
if (messageCount(state) > 0) return true;
|
if (messageCount(state) > 0) return true;
|
||||||
if (status === undefined) return false;
|
if (status === undefined) return false;
|
||||||
@@ -50,7 +50,7 @@ function renderComponent(html: HtmlTemplateTag, component: PiWebComponentStatus)
|
|||||||
? "restart needed"
|
? "restart needed"
|
||||||
: "current";
|
: "current";
|
||||||
return html`
|
return html`
|
||||||
<div class="pi-web-version-row">
|
<div class="updates-version-row">
|
||||||
<strong>${component.label}</strong>
|
<strong>${component.label}</strong>
|
||||||
<span>${status}</span>
|
<span>${status}</span>
|
||||||
<small>running ${formatVersion(component.runtimeVersion)} · installed ${formatVersion(component.installedVersion)}</small>
|
<small>running ${formatVersion(component.runtimeVersion)} · installed ${formatVersion(component.installedVersion)}</small>
|
||||||
@@ -61,7 +61,7 @@ function renderComponent(html: HtmlTemplateTag, component: PiWebComponentStatus)
|
|||||||
|
|
||||||
function renderCommand(html: HtmlTemplateTag, label: string, command: string): TemplateResult {
|
function renderCommand(html: HtmlTemplateTag, label: string, command: string): TemplateResult {
|
||||||
return html`
|
return html`
|
||||||
<div class="pi-web-command">
|
<div class="updates-command">
|
||||||
<span>${label}</span>
|
<span>${label}</span>
|
||||||
<code>${command}</code>
|
<code>${command}</code>
|
||||||
<button @click=${() => { void navigator.clipboard.writeText(command); }}>Copy</button>
|
<button @click=${() => { void navigator.clipboard.writeText(command); }}>Copy</button>
|
||||||
@@ -87,7 +87,7 @@ function renderCommands(html: HtmlTemplateTag, status: PiWebStatusResponse): Tem
|
|||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
function renderStatusPanel(html: HtmlTemplateTag, state: AppState): TemplateResult {
|
function renderUpdatesPanel(html: HtmlTemplateTag, state: AppState): TemplateResult {
|
||||||
const status = statusFor(state);
|
const status = statusFor(state);
|
||||||
if (status === undefined) {
|
if (status === undefined) {
|
||||||
return html`
|
return html`
|
||||||
@@ -99,29 +99,29 @@ function renderStatusPanel(html: HtmlTemplateTag, state: AppState): TemplateResu
|
|||||||
const messages = status.messages;
|
const messages = status.messages;
|
||||||
return html`
|
return html`
|
||||||
<style>
|
<style>
|
||||||
.viewer.pi-web-status { flex: 1 1 auto; min-height: 0; box-sizing: border-box; display: flex; flex-direction: column; gap: 14px; padding: 12px; overflow-y: auto; overflow-x: hidden; }
|
.viewer.updates-status { flex: 1 1 auto; min-height: 0; box-sizing: border-box; display: flex; flex-direction: column; gap: 14px; padding: 12px; overflow-y: auto; overflow-x: hidden; }
|
||||||
.viewer.pi-web-status section { flex: 0 0 auto; min-width: 0; display: grid; gap: 8px; }
|
.viewer.updates-status section { flex: 0 0 auto; min-width: 0; display: grid; gap: 8px; }
|
||||||
.pi-web-message { display: grid; gap: 5px; border: 1px solid var(--pi-border); border-radius: 8px; padding: 10px; background: var(--pi-surface); }
|
.updates-message { display: grid; gap: 5px; border: 1px solid var(--pi-border); border-radius: 8px; padding: 10px; background: var(--pi-surface); }
|
||||||
.pi-web-message.warning { border-color: var(--pi-warning-border); background: var(--pi-warning-surface); }
|
.updates-message.warning { border-color: var(--pi-warning-border); background: var(--pi-warning-surface); }
|
||||||
.pi-web-message.error { border-color: var(--pi-danger); }
|
.updates-message.error { border-color: var(--pi-danger); }
|
||||||
.pi-web-message-title { display: flex; gap: 8px; align-items: baseline; }
|
.updates-message-title { display: flex; gap: 8px; align-items: baseline; }
|
||||||
.pi-web-message-title span { color: var(--pi-muted); font-size: 12px; text-transform: uppercase; }
|
.updates-message-title span { color: var(--pi-muted); font-size: 12px; text-transform: uppercase; }
|
||||||
.pi-web-version-row { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 3px 10px; border-bottom: 1px solid var(--pi-border-muted); padding: 6px 0; }
|
.updates-version-row { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 3px 10px; border-bottom: 1px solid var(--pi-border-muted); padding: 6px 0; }
|
||||||
.pi-web-version-row small { grid-column: 1 / -1; color: var(--pi-muted); }
|
.updates-version-row small { grid-column: 1 / -1; color: var(--pi-muted); }
|
||||||
.pi-web-command { min-width: 0; display: grid; grid-template-columns: minmax(90px, auto) minmax(0, 1fr) auto; gap: 8px; align-items: center; }
|
.updates-command { min-width: 0; display: grid; grid-template-columns: minmax(90px, auto) minmax(0, 1fr) auto; gap: 8px; align-items: center; }
|
||||||
.pi-web-command code { overflow: auto; border: 1px solid var(--pi-border-muted); border-radius: 6px; background: var(--pi-bg); padding: 5px 7px; white-space: nowrap; }
|
.updates-command code { overflow: auto; border: 1px solid var(--pi-border-muted); border-radius: 6px; background: var(--pi-bg); padding: 5px 7px; white-space: nowrap; }
|
||||||
.pi-web-meta { display: grid; gap: 2px; color: var(--pi-muted); font-size: 12px; }
|
.updates-meta { display: grid; gap: 2px; color: var(--pi-muted); font-size: 12px; }
|
||||||
@media (max-width: 520px) {
|
@media (max-width: 520px) {
|
||||||
.pi-web-command { grid-template-columns: minmax(0, 1fr) auto; }
|
.updates-command { grid-template-columns: minmax(0, 1fr) auto; }
|
||||||
.pi-web-command > span { grid-column: 1 / -1; }
|
.updates-command > span { grid-column: 1 / -1; }
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
<section class="toolbar"><strong>Updates</strong><span class="stale">beta</span>${messages.length > 0 ? html`<span class="stale">${String(messages.length)}</span>` : null}</section>
|
<section class="toolbar"><strong>Updates</strong><span class="stale">beta</span>${messages.length > 0 ? html`<span class="stale">${String(messages.length)}</span>` : null}</section>
|
||||||
<section class="viewer pi-web-status">
|
<section class="viewer updates-status">
|
||||||
<section>
|
<section>
|
||||||
${messages.length === 0 ? html`<p class="muted">No PI WEB update or restart messages.</p>` : messages.map((message) => html`
|
${messages.length === 0 ? html`<p class="muted">No PI WEB update or restart messages.</p>` : messages.map((message) => html`
|
||||||
<article class=${`pi-web-message ${message.severity}`}>
|
<article class=${`updates-message ${message.severity}`}>
|
||||||
<div class="pi-web-message-title"><strong>${message.title}</strong><span>${message.severity}</span></div>
|
<div class="updates-message-title"><strong>${message.title}</strong><span>${message.severity}</span></div>
|
||||||
<p>${message.body}</p>
|
<p>${message.body}</p>
|
||||||
${message.command === undefined ? null : html`<code>${message.command}</code>`}
|
${message.command === undefined ? null : html`<code>${message.command}</code>`}
|
||||||
</article>
|
</article>
|
||||||
@@ -136,7 +136,7 @@ function renderStatusPanel(html: HtmlTemplateTag, state: AppState): TemplateResu
|
|||||||
|
|
||||||
${renderCommands(html, status)}
|
${renderCommands(html, status)}
|
||||||
|
|
||||||
<section class="pi-web-meta">
|
<section class="updates-meta">
|
||||||
<span>Generated ${status.generatedAt}</span>
|
<span>Generated ${status.generatedAt}</span>
|
||||||
${status.release.latestVersion === undefined ? null : html`<span>Latest npm release ${status.release.latestVersion}</span>`}
|
${status.release.latestVersion === undefined ? null : html`<span>Latest npm release ${status.release.latestVersion}</span>`}
|
||||||
${status.release.skipped === true ? html`<span>Remote version check skipped.</span>` : null}
|
${status.release.skipped === true ? html`<span>Remote version check skipped.</span>` : null}
|
||||||
@@ -148,12 +148,12 @@ function renderStatusPanel(html: HtmlTemplateTag, state: AppState): TemplateResu
|
|||||||
|
|
||||||
const plugin: PiWebPlugin = {
|
const plugin: PiWebPlugin = {
|
||||||
apiVersion: 1,
|
apiVersion: 1,
|
||||||
name: "PI WEB Updates",
|
name: "Updates",
|
||||||
activate: ({ html, svg }) => ({
|
activate: ({ html, svg }) => ({
|
||||||
contributions: {
|
contributions: {
|
||||||
workspacePanels: [
|
workspacePanels: [
|
||||||
{
|
{
|
||||||
id: "workspace.status",
|
id: "workspace.updates",
|
||||||
title: "Updates",
|
title: "Updates",
|
||||||
icon: svg`
|
icon: svg`
|
||||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||||
@@ -164,12 +164,12 @@ const plugin: PiWebPlugin = {
|
|||||||
</svg>
|
</svg>
|
||||||
`,
|
`,
|
||||||
order: 100,
|
order: 100,
|
||||||
visible: (context) => shouldShowStatusPanel(context.state),
|
visible: (context) => shouldShowUpdatesPanel(context.state),
|
||||||
badge: (context) => {
|
badge: (context) => {
|
||||||
const count = messageCount(context.state);
|
const count = messageCount(context.state);
|
||||||
return html`beta${count > 0 ? html` · ${String(count)}` : null}`;
|
return html`beta${count > 0 ? html` · ${String(count)}` : null}`;
|
||||||
},
|
},
|
||||||
render: (context) => renderStatusPanel(html, context.state),
|
render: (context) => renderUpdatesPanel(html, context.state),
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
Reference in New Issue
Block a user