Skip to content

Commit

Permalink
feat: Show outdated tools in tools view. Allow removing tools
Browse files Browse the repository at this point in the history
  • Loading branch information
hverlin committed Nov 17, 2024
1 parent 7fe8cd6 commit 07f2212
Show file tree
Hide file tree
Showing 9 changed files with 286 additions and 38 deletions.
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -481,6 +481,7 @@
"@tanstack/react-table": "^8.20.5",
"cheerio": "^1.0.0",
"react": "^18.3.1",
"react-dom": "^18.3.1"
"react-dom": "^18.3.1",
"react-error-boundary": "^4.1.2"
}
}
26 changes: 26 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

59 changes: 52 additions & 7 deletions src/miseService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,13 +49,17 @@ export class MiseService {
execution,
);

await vscode.tasks.executeTask(task);
const disposable = vscode.tasks.onDidEndTask((e) => {
if (e.execution.task === task) {
vscode.commands.executeCommand("mise.refreshEntry");
disposable.dispose();
}
const p = new Promise((resolve, reject) => {
const disposable = vscode.tasks.onDidEndTask((e) => {
if (e.execution.task === task) {
vscode.commands.executeCommand("mise.refreshEntry");
disposable.dispose();
resolve(undefined);
}
});
});
await vscode.tasks.executeTask(task);
return p as Promise<void>;
} catch (error) {
logger.error(`Failed to execute ${taskName}: ${error}`);
}
Expand Down Expand Up @@ -193,7 +197,7 @@ export class MiseService {
}

try {
const { stdout } = await this.execMiseCommand("ls --json");
const { stdout } = await this.execMiseCommand("ls --offline --json");
return Object.entries(JSON.parse(stdout)).flatMap(([toolName, tools]) => {
return (tools as MiseTool[]).map((tool) => {
return {
Expand All @@ -218,6 +222,47 @@ export class MiseService {
}
}

async getOutdatedTools({
bump = false,
} = {}): Promise<Array<MiseToolUpdate>> {
if (!this.getMiseBinaryPath()) {
return [];
}

const { stdout } = await this.execMiseCommand(
bump ? "outdated --bump --json" : "outdated --json",
);
return Object.entries(JSON.parse(stdout)).map(([toolName, tool]) => {
const foundTool = tool as {
name: string;
requested: string;
current: string;
latest: string;
bump: string;
source: { type: string; path: string };
};

return {
name: toolName,
version: foundTool.current,
requested_version: foundTool.requested,
source: foundTool.source,
latest: foundTool.latest,
bump: foundTool.bump,
};
});
}

async removeToolInConsole(toolName: string, version?: string) {
if (!this.getMiseBinaryPath()) {
return;
}

await this.runMiseToolActionInConsole(
version ? `rm ${toolName} ${version}` : `rm ${toolName}`,
);
}

async getEnvs(): Promise<MiseEnv[]> {
if (!this.getMiseBinaryPath()) {
return [];
Expand Down
5 changes: 1 addition & 4 deletions src/providers/toolsProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -272,10 +272,7 @@ export function registerToolsCommands(
);

if (confirmed === "Remove") {
await miseService.runMiseToolActionInConsole(
`rm ${tool.name}@${tool.version}`,
"Remove Tool",
);
await miseService.removeToolInConsole(tool.name, tool.version);
}
},
),
Expand Down
9 changes: 9 additions & 0 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,15 @@ type MiseTool = {
install_path: string;
};

type MiseToolUpdate = {
name: string;
version: string;
requested_version: string;
latest: string;
bump?: string;
source?: MiseToolSource;
};

type MiseEnv = {
name: string;
value: string;
Expand Down
48 changes: 38 additions & 10 deletions src/webviewPanel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import path from "node:path";
import * as cheerio from "cheerio";
import * as vscode from "vscode";
import type { MiseService } from "./miseService";
import { logger } from "./utils/logger";

export default class WebViewPanel {
public static currentPanel: WebViewPanel | undefined;
Expand Down Expand Up @@ -52,27 +53,54 @@ export default class WebViewPanel {
this._panel.webview.html = this._getHtmlForWebview(this._panel.webview);
this._panel.onDidDispose(() => this.dispose(), null, this._disposables);

const executeAction = async (
{ requestId }: { requestId: string },
fn: () => Promise<unknown>,
) => {
try {
const data = await fn();
this._panel.webview.postMessage({
type: "response",
requestId,
data,
});
} catch (e) {
logger.info(e);
this._panel.webview.postMessage({
type: "response",
requestId,
error: e,
});
}
};

this._panel.webview.onDidReceiveMessage(
async (message) => {
switch (message.type) {
case "query":
switch (message.queryKey[0]) {
case "tools": {
const tools = await this.miseService.getAllTools();
this._panel.webview.postMessage({
type: "response",
requestId: message.requestId,
data: tools,
});
break;
return executeAction(message, () =>
this.miseService.getAllTools(),
);
}
case "outdatedTools": {
return executeAction(message, () =>
this.miseService.getOutdatedTools(),
);
}
}
break;
case "mutation":
switch (message.mutationKey[0]) {
case "addItem":
// todo
break;
case "uninstallTool": {
return executeAction(message, async () =>
miseService.removeToolInConsole(
message.mutationKey[1],
message.mutationKey[2],
),
);
}
}
break;
}
Expand Down
87 changes: 74 additions & 13 deletions src/webviews/Tools.tsx
Original file line number Diff line number Diff line change
@@ -1,20 +1,47 @@
import { useQuery } from "@tanstack/react-query";
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
import VSCodeTable from "./VSCodeTable";
import { vscodeClient } from "./webviewVsCodeApi";

const ActionCell = ({ tool }: { tool: MiseTool }) => {
const queryClient = useQueryClient();
const mutationKey = ["uninstallTool", tool.name, tool.version];
const removeToolMutation = useMutation({
mutationKey,
mutationFn: () => vscodeClient.request({ mutationKey }),
});

if (!tool.installed) {
return null;
}

return (
<button
className={"vscode-button secondary"}
disabled={removeToolMutation.isPending}
onClick={() => {
return removeToolMutation.mutate(undefined, {
onSettled: () =>
queryClient.invalidateQueries({ queryKey: ["tools"] }),
});
}}
type={"button"}
>
{removeToolMutation.isPending ? "Removing..." : "Remove"}
</button>
);
};

export const Tools = () => {
const toolsQuery = useQuery({
queryKey: ["tools"],
queryFn: ({ queryKey }) =>
vscodeClient.request({ queryKey }) as Promise<
Array<{
name: string;
version: string;
requested_version: string;
active: boolean;
installed: boolean;
}>
>,
vscodeClient.request({ queryKey }) as Promise<Array<MiseTool>>,
});

const outdatedToolsQuery = useQuery({
queryKey: ["outdatedTools"],
queryFn: ({ queryKey }) =>
vscodeClient.request({ queryKey }) as Promise<Array<MiseToolUpdate>>,
});

if (toolsQuery.isError) {
Expand All @@ -23,6 +50,7 @@ export const Tools = () => {

return (
<div>
{outdatedToolsQuery.isLoading ? "Loading outdated tools..." : ""}
<VSCodeTable
isLoading={toolsQuery.isLoading}
columns={[
Expand All @@ -35,6 +63,25 @@ export const Tools = () => {
id: "version",
header: "Version",
accessorKey: "version",
cell: ({ row }) => {
const outdatedToolInfo = outdatedToolsQuery.data?.find(
(outdatedTool) =>
outdatedTool.name === row.original.name &&
outdatedTool.version === row.original.version,
);
return (
<div title={row.original.source?.path}>
{row.original.version}
{outdatedToolInfo ? (
<small>
<br />({outdatedToolInfo.latest} is available)
</small>
) : (
""
)}
</div>
);
},
},
{
id: "requested_version",
Expand All @@ -45,16 +92,30 @@ export const Tools = () => {
id: "active",
header: "Active",
accessorKey: "active",
cell: ({ row }) => {
return (
<div title={row.original.source?.path}>
{row.original.active ? "Yes" : "No"}
</div>
);
},
},
{
id: "installed",
header: "Installed",
accessorKey: "installed",
cell: ({ row }) => {
return (
<div title={row.original.install_path}>
{row.original.installed ? "Yes" : "No"}
</div>
);
},
},
{
id: "install_path",
header: "Install Path",
accessorKey: "install_path",
id: "Actions",
header: "Actions",
cell: (props) => <ActionCell tool={props.row.original} />,
},
]}
data={toolsQuery?.data || []}
Expand Down
Loading

0 comments on commit 07f2212

Please sign in to comment.