← Public packages
@kentcdodds/raycast
Raycast launcher: stored execute commands via webhooks (canonical; do not use raycast-shortcuts).
extension/src/commands.tsx
127 lines · 3.3 KB · TypeScriptimport {
Action,
ActionPanel,
Color,
Detail,
Icon,
List,
showToast,
Toast,
useNavigation,
} from "@raycast/api";
import { useCallback, useEffect, useRef, useState } from "react";
import {
getErrorMessage,
listCommands,
RaycastCommandSummary,
runCommand,
stringifyResult,
} from "./kody-client";
function resolveIcon(icon: string): Icon | { source: string } {
if (!icon) return Icon.Terminal;
if ([...icon].length <= 2) return { source: icon };
const key = icon as keyof typeof Icon;
if (Icon[key]) return Icon[key];
return Icon.Terminal;
}
export default function Command() {
const { push } = useNavigation();
const [commands, setCommands] = useState<RaycastCommandSummary[]>([]);
const [isLoading, setIsLoading] = useState(true);
const [runningId, setRunningId] = useState<string | null>(null);
const commandsRef = useRef(commands);
commandsRef.current = commands;
const load = useCallback(async (forceRefresh = false) => {
// Only block the UI when we have nothing to show yet, or the user forced refresh.
if (forceRefresh || commandsRef.current.length === 0) {
setIsLoading(true);
}
try {
const next = await listCommands({
forceRefresh,
onRevalidated: setCommands,
});
setCommands(next);
} catch (error) {
await showToast({
style: Toast.Style.Failure,
title: "Failed to load Kody commands",
message: getErrorMessage(error),
});
} finally {
setIsLoading(false);
}
}, []);
useEffect(() => {
void load(false);
}, [load]);
async function run(command: RaycastCommandSummary) {
try {
setRunningId(command.id);
const result = await runCommand({ commandId: command.id });
await showToast({
style: Toast.Style.Success,
title: "Kody finished",
message: command.title,
});
push(
<Detail
markdown={[
`# ${command.title}`,
"```json",
stringifyResult(result),
"```",
].join("\n\n")}
/>,
);
} catch (error) {
await showToast({
style: Toast.Style.Failure,
title: "Kody command failed",
message: getErrorMessage(error),
});
} finally {
setRunningId(null);
}
}
return (
<List
isLoading={isLoading || runningId !== null}
searchBarPlaceholder="Search Kody commands"
>
{commands.map((command) => (
<List.Item
key={command.id}
title={command.title}
subtitle={command.description || command.id}
icon={resolveIcon(command.icon)}
accessories={[
{ tag: { value: command.id, color: Color.SecondaryText } },
]}
actions={
<ActionPanel>
<Action
title="Run Command"
icon={Icon.Play}
onAction={() => void run(command)}
/>
<Action
title="Refresh Commands"
icon={Icon.ArrowClockwise}
shortcut={{ modifiers: ["cmd"], key: "r" }}
onAction={() => void load(true)}
/>
<Action.CopyToClipboard title="Copy Command Id" content={command.id} />
</ActionPanel>
}
/>
))}
</List>
);
}