Skip to content

Commit

Permalink
feat: Show tool information
Browse files Browse the repository at this point in the history
  • Loading branch information
hverlin committed Dec 5, 2024
1 parent 3df5dfe commit 70611b7
Show file tree
Hide file tree
Showing 7 changed files with 278 additions and 36 deletions.
4 changes: 2 additions & 2 deletions src/providers/tasksProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -128,13 +128,13 @@ export class MiseTasksProvider implements vscode.TreeDataProvider<TreeNode> {
for (const flag of spec.flags) {
if (flag.arg) {
const shouldProvide = await vscode.window.showQuickPick(["Yes", "No"], {
placeHolder: `Do you want to provide ${flag.name}?`,
placeHolder: `Do you want to provide "--${flag.name}" option?`,
ignoreFocusOut: true,
});

if (shouldProvide === "Yes") {
const value = await vscode.window.showInputBox({
prompt: `Enter value for ${flag.name}`,
prompt: `Enter value for --${flag.name}=?`,
placeHolder: flag.arg,
ignoreFocusOut: true,
});
Expand Down
6 changes: 5 additions & 1 deletion src/webviewPanel.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import { readFileSync, writeFileSync } from "node:fs";
import { homedir } from "node:os";
import * as os from "node:os";
import path from "node:path";
import * as cheerio from "cheerio";
import * as vscode from "vscode";
Expand Down Expand Up @@ -248,7 +250,9 @@ export default class WebViewPanel {
);
});

$("head").append(`<meta name="view" content="${this.view}">`);
$("head")
.append(`<meta name="view" content="${this.view}">`)
.append(`<meta name="homeDir" content="${os.homedir()}">`);

return $.html();
}
Expand Down
232 changes: 215 additions & 17 deletions src/webviews/Tools.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,141 @@
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
import { VscodeButton } from "@vscode-elements/react-elements";
import { VscodeButton, VscodeCheckbox } from "@vscode-elements/react-elements";
import { useState } from "react";
import CustomTable from "./components/CustomTable";
import { vscodeClient } from "./webviewVsCodeApi";
import { IconButton } from "./components/IconButton";
import {
toDisplayPath,
trackedConfigsQueryOptions,
vscodeClient,
} from "./webviewVsCodeApi";

const styles = {
infoPanel: { padding: "10px" },
header: { marginBottom: "10px" },
title: {
display: "flex",
alignItems: "center",
gap: "8px",
fontSize: "16px",
fontWeight: "bold",
color: "var(--vscode-foreground)",
},
label: {
fontSize: "12px",
color: "var(--vscode-descriptionForeground)",
marginBottom: "4px",
},
value: {
fontSize: "14px",
wordBreak: "break-all",
color: "var(--vscode-foreground)",
},
} as const;

const ToolInfo = ({
onClose,
selectedTool,
}: { selectedTool: MiseTool; onClose: () => void }) => {
const trackedConfigQuery = useQuery(trackedConfigsQueryOptions);
const configs = trackedConfigQuery.data || [];

if (!selectedTool) {
return null;
}

const configsWithTool = configs.filter((config) => {
return Object.keys(config.tools).includes(selectedTool.name);
});

return (
<div style={styles.infoPanel}>
<div
style={{
marginBottom: "10px",
display: "flex",
justifyContent: "space-between",
alignItems: "center",
}}
>
<div style={styles.title}>
<i className="codicon codicon-tools" />
{selectedTool.name}
</div>
<IconButton iconName={"close"} onClick={onClose} />
</div>

<div>
<div
style={{
display: "grid",
gridTemplateColumns: "repeat(3, 1fr)",
marginBottom: "0",
}}
>
<div>
<p style={styles.label}>Version</p>
<p style={styles.value}>{selectedTool.version}</p>
</div>
<div>
<p style={styles.label}>Requested Version</p>
<p style={styles.value}>
{selectedTool.requested_version || "None"}
</p>
</div>
<div>
<p style={styles.label}>Status</p>
<p style={styles.value}>
{selectedTool.installed ? "Installed" : "Not Installed"}
</p>
</div>

{selectedTool.install_path && (
<div>
<p style={styles.label}>Install Path</p>
<p style={styles.value}>
{toDisplayPath(selectedTool.install_path)}
</p>
</div>
)}

{selectedTool.source?.path && (
<div>
<p style={styles.label}>Requested by</p>
<p style={styles.value}>
{toDisplayPath(selectedTool.source.path)}
</p>
</div>
)}
</div>
</div>

{configsWithTool.length > 0 && (
<div>
<p style={styles.label}>Used in</p>
<div style={styles.value}>
{configsWithTool
.map((config) => {
// @ts-ignore
const toolInfo = config.tools[selectedTool.name];
return `${toDisplayPath(config.path)} (${JSON.stringify(toolInfo)})`;
})
.join(", ")}
</div>
</div>
)}
</div>
);
};

const ActionCell = ({
tool,
outdatedToolInfo,
}: { tool: MiseTool; outdatedToolInfo?: MiseToolUpdate }) => {
onSelect,
}: {
tool: MiseTool;
outdatedToolInfo?: MiseToolUpdate;
onSelect: (tool: MiseTool) => void;
}) => {
const queryClient = useQueryClient();
const mutationKey = ["uninstallTool", tool.name, tool.version];
const removeToolMutation = useMutation({
Expand Down Expand Up @@ -49,6 +178,15 @@ const ActionCell = ({

return (
<div style={{ display: "flex", gap: "8px", alignItems: "center" }}>
<VscodeButton
title={"Info"}
className="small-button"
onClick={() => {
onSelect(tool);
}}
>
<i className="codicon codicon-info" />
</VscodeButton>
{outdatedToolInfo && (
<VscodeButton
title={"Upgrade"}
Expand Down Expand Up @@ -84,6 +222,10 @@ const ActionCell = ({

export const Tools = () => {
const queryClient = useQueryClient();
const [selectedTool, setSelectedTool] = useState<MiseTool | null>(null);
const [showOutdatedOnly, setShowOutdatedOnly] = useState(false);
const [activeOnly, setActiveOnly] = useState(false);

const toolsQuery = useQuery({
queryKey: ["tools"],
queryFn: ({ queryKey }) =>
Expand All @@ -105,11 +247,64 @@ export const Tools = () => {
return <div>Error: {toolsQuery.error.message}</div>;
}

const rows: MiseTool[] = [];
for (const tool of toolsQuery.data || []) {
if (
showOutdatedOnly &&
!outdatedToolsQuery.data?.find(
(outdatedTool) =>
outdatedTool.name === tool.name &&
outdatedTool.version === tool.version,
)
) {
continue;
}

if (activeOnly && !tool.active) {
continue;
}

rows.push(tool);
}

return (
<div>
{selectedTool && (
<ToolInfo
onClose={() => setSelectedTool(null)}
selectedTool={selectedTool}
/>
)}
<CustomTable
style={{ height: window.innerHeight - (selectedTool ? 280 : 40) }}
filterRowElement={
<div style={{ display: "flex", alignItems: "center" }}>
<div
style={{
display: "flex",
alignItems: "center",
gap: 10,
flexWrap: "wrap",
}}
>
<IconButton
title={"Refresh"}
iconName={"refresh"}
onClick={() => outdatedToolsQuery.refetch()}
/>
<VscodeCheckbox
label={"Active only"}
checked={activeOnly}
onChange={(e) => {
setActiveOnly(!activeOnly);
}}
/>
<VscodeCheckbox
label={"Outdated tools"}
checked={showOutdatedOnly}
onChange={(e) => {
setShowOutdatedOnly(!showOutdatedOnly);
}}
/>
<VscodeButton
secondary
disabled={pruneToolsMutations.isPending}
Expand All @@ -120,18 +315,7 @@ export const Tools = () => {
});
}}
>
{pruneToolsMutations.isPending
? "Pruning..."
: "Prune unused tools"}
</VscodeButton>
<VscodeButton
title={"Refresh"}
onClick={() => {
return outdatedToolsQuery.refetch();
}}
style={{ background: "none", border: "none" }}
>
<i className={"codicon codicon-refresh"} />
{pruneToolsMutations.isPending ? "Pruning..." : "Prune tools"}
</VscodeButton>
<p>
{outdatedToolsQuery.isLoading ? "Loading outdated tools..." : ""}
Expand All @@ -144,6 +328,19 @@ export const Tools = () => {
id: "name",
header: "Name",
accessorKey: "name",
cell: ({ row }) => {
return (
// biome-ignore lint/a11y/useValidAnchor: <explanation>
<a
href="#"
onClick={(e) => {
setSelectedTool(row.original);
}}
>
{row.original.name}
</a>
);
},
},
{
id: "version",
Expand Down Expand Up @@ -208,12 +405,13 @@ export const Tools = () => {
outdatedTool.name === props.row.original.name &&
outdatedTool.version === props.row.original.version,
)}
onSelect={setSelectedTool}
tool={props.row.original}
/>
),
},
]}
data={toolsQuery?.data || []}
data={rows}
/>
</div>
);
Expand Down
24 changes: 11 additions & 13 deletions src/webviews/TrackedConfigs.tsx
Original file line number Diff line number Diff line change
@@ -1,32 +1,30 @@
import { useMutation, useQuery } from "@tanstack/react-query";
import CustomTable from "./components/CustomTable";
import { vscodeClient } from "./webviewVsCodeApi";
import {
toDisplayPath,
trackedConfigsQueryOptions,
vscodeClient,
} from "./webviewVsCodeApi";

export const TrackedConfigs = () => {
const settingsQuery = useQuery({
queryKey: ["trackedConfigs"],
queryFn: ({ queryKey }) =>
vscodeClient.request({ queryKey }) as Promise<
Array<{ path: string; tools: object }>
>,
});
const trackedConfigQuery = useQuery(trackedConfigsQueryOptions);

const openFileMutation = useMutation({
mutationKey: ["openFile"],
mutationFn: (path: string) =>
vscodeClient.request({ mutationKey: ["openFile"], variables: { path } }),
});

if (settingsQuery.isError) {
return <div>Error: {settingsQuery.error.message}</div>;
if (trackedConfigQuery.isError) {
return <div>Error: {trackedConfigQuery.error.message}</div>;
}

return (
<div>
<CustomTable
filterRowElement={"Showing tracked config files"}
isLoading={settingsQuery.isLoading}
data={settingsQuery.data || []}
isLoading={trackedConfigQuery.isLoading}
data={trackedConfigQuery.data || []}
columns={[
{
id: "path",
Expand All @@ -42,7 +40,7 @@ export const TrackedConfigs = () => {
}}
title={row.original.path}
>
{row.original.path}
{toDisplayPath(row.original.path)}
</a>
);
},
Expand Down
Loading

0 comments on commit 70611b7

Please sign in to comment.