Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Coolify] view-secret-keys + update-projects #16003

Merged
merged 2 commits into from
Jan 2, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions extensions/coolify/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
# Coolify Changelog

## [Enhancements] - 2025-01-02

- In `Projects`:
- Create Project
- Update Project
- In `Private Keys`
- View Private Keys

## [Enhancements] - 2024-10-23

- Fix issue where `Resources` command would crash if the resource type is not "application" or "service"
Expand Down
4 changes: 2 additions & 2 deletions extensions/coolify/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@

# Coolify Raycast Extension

This is a Raycast extension for [Coolify](https://coolify.io/). With this extension you can view Servers, Server Details, Resources, Teams, Team Members, Projects, Environments and more in your Coolify instance.
This is a Raycast extension for [Coolify](https://coolify.io/). With this extension you can view Servers, Server Details, Resources, Teams, Team Members, Projects, Environments, Private Keys and more in your Coolify instance.

## 🚀 Getting Started

1. **Install extension**: Click the `Install Extension` button in the top right of [this page](https://www.raycast.com/xmok/coolify) OR via Raycast Store
1. **Install extension**: Click the `Install Extension` button in the top right of [this page](https://www.raycast.com/xmok/coolify) OR `install` via Raycast Store

2. **Enter your Coolify Details**: The first time you use the extension, you'll need to enter the following in Preferences OR at first prompt:

Expand Down
6 changes: 6 additions & 0 deletions extensions/coolify/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,12 @@
"title": "View Projects",
"description": "View Projects, Environments and Resources",
"mode": "view"
},
{
"name": "private-keys",
"title": "View Private Keys",
"description": "View Private Keys",
"mode": "view"
}
],
"dependencies": {
Expand Down
52 changes: 52 additions & 0 deletions extensions/coolify/src/lib/components/projects/create.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import { Action, ActionPanel, Form, Icon, useNavigation } from "@raycast/api";
import { FormValidation, useForm } from "@raycast/utils";
import { useState } from "react";
import { type CreateProject } from "../../types";
import useCoolify from "../../use-coolify";

export default function CreateProject({ onAdded }: { onAdded: () => void }) {
const { pop } = useNavigation();
const [execute, setExecute] = useState(false);

const { itemProps, handleSubmit, values } = useForm<CreateProject>({
onSubmit() {
setExecute(true);
},
validation: {
name: FormValidation.Required,
},
});

const { isLoading } = useCoolify("projects", {
method: "POST",
body: values,
execute,
onData() {
onAdded();
pop();
},
onError() {
setExecute(false);
},
});

return (
<Form
isLoading={isLoading}
actions={
<ActionPanel>
<Action.SubmitForm icon={Icon.Check} onSubmit={handleSubmit} />
</ActionPanel>
}
>
<Form.Description text="Create Project" />
<Form.TextField title="Name" placeholder="Your Cool Project" {...itemProps.name} />
<Form.TextField
title="Description"
placeholder="This is my cool project everyone knows about"
{...itemProps.description}
/>
<Form.Description text="New project will have a default production environment." />
</Form>
);
}
55 changes: 55 additions & 0 deletions extensions/coolify/src/lib/components/projects/update.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import { Action, ActionPanel, Form, Icon, useNavigation } from "@raycast/api";
import { FormValidation, useForm } from "@raycast/utils";
import { useState } from "react";
import { CreateProject, Project } from "../../types";
import useCoolify from "../../use-coolify";

export default function UpdateProject({ project, onUpdated }: { project: Project; onUpdated: () => void }) {
const { pop } = useNavigation();
const [execute, setExecute] = useState(false);

const { itemProps, handleSubmit, values } = useForm<CreateProject>({
onSubmit() {
setExecute(true);
},
validation: {
name: FormValidation.Required,
},
initialValues: {
name: project.name,
description: project.description || "",
},
});

const { isLoading } = useCoolify(`projects/${project.uuid}`, {
method: "PATCH",
body: values,
execute,
onData() {
onUpdated();
pop();
},
onError() {
setExecute(false);
},
});

return (
<Form
isLoading={isLoading}
actions={
<ActionPanel>
<Action.SubmitForm icon={Icon.Check} onSubmit={handleSubmit} />
</ActionPanel>
}
>
<Form.Description text="Update Project" />
<Form.TextField title="Name" placeholder="Your Cooler Project" {...itemProps.name} />
<Form.TextField
title="Description"
placeholder="This is my cooler project everyone knows about"
{...itemProps.description}
/>
</Form>
);
}
5 changes: 5 additions & 0 deletions extensions/coolify/src/lib/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ export type PrivateKey = {
uuid: string;
name: string;
description: string;
fingerprint: string | null;
private_key: string;
is_git_related: true;
team_id: number;
Expand Down Expand Up @@ -164,6 +165,10 @@ export type ProjectDetails = Project & {
updated_at: string;
created_at: string;
};
export type CreateProject = {
name: string;
description: string;
};

export type Environment = {
id: number;
Expand Down
40 changes: 40 additions & 0 deletions extensions/coolify/src/private-keys.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import { Action, ActionPanel, Icon, List } from "@raycast/api";
import InvalidUrl from "./lib/components/invalid-url";
import { PrivateKey } from "./lib/types";
import useCoolify from "./lib/use-coolify";
import { isValidCoolifyUrl } from "./lib/utils";
import { useState } from "react";

export default function PrivateKeys() {
if (!isValidCoolifyUrl()) return <InvalidUrl />;

const { isLoading, data: keys = [] } = useCoolify<PrivateKey[]>("security/keys");

const [isShowingDetail, setIsShowingDetail] = useState(false);

return (
<List isLoading={isLoading} searchBarPlaceholder="Search keys" isShowingDetail={isShowingDetail}>
<List.Section title="Private Keys" subtitle={`${keys.length} keys`}>
{keys.map((key) => (
<List.Item
key={key.id}
icon={Icon.Key}
title={key.name}
subtitle={isShowingDetail ? undefined : key.description}
detail={<List.Item.Detail markdown={key.private_key} />}
actions={
<ActionPanel>
<Action
icon={Icon.AppWindowSidebarLeft}
title="Toggle Private Key"
onAction={() => setIsShowingDetail((prev) => !prev)}
/>
<Action.CopyToClipboard title="Copy Private Key to Clipboard" content={key.private_key} />
</ActionPanel>
}
/>
))}
</List.Section>
</List>
);
}
18 changes: 16 additions & 2 deletions extensions/coolify/src/projects.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,18 @@
import { Action, ActionPanel, Icon, List } from "@raycast/api";
import { Action, ActionPanel, Icon, Keyboard, List } from "@raycast/api";
import { Environment, EnvironmentDetails, Project, ProjectDetails, Resource } from "./lib/types";
import useCoolify from "./lib/use-coolify";
import { isValidCoolifyUrl } from "./lib/utils";
import InvalidUrl from "./lib/components/invalid-url";
import OpenInCoolify from "./lib/components/open-in-coolify";
import { getAvatarIcon } from "@raycast/utils";
import { useMemo } from "react";
import CreateProject from "./lib/components/projects/create";
import UpdateProject from "./lib/components/projects/update";

export default function Projects() {
if (!isValidCoolifyUrl()) return <InvalidUrl />;

const { isLoading, data: projects = [] } = useCoolify<Project[]>("projects");
const { isLoading, data: projects = [], revalidate } = useCoolify<Project[]>("projects");

return (
<List isLoading={isLoading} searchBarPlaceholder="Search project">
Expand All @@ -29,6 +31,18 @@ export default function Projects() {
title="View Environments"
target={<ViewEnvironments project={project} />}
/>
<Action.Push
icon={Icon.Pencil}
title="Update Project"
target={<UpdateProject project={project} onUpdated={revalidate} />}
shortcut={Keyboard.Shortcut.Common.Edit}
/>
<Action.Push
icon={Icon.Plus}
title="Add Project"
target={<CreateProject onAdded={revalidate} />}
shortcut={Keyboard.Shortcut.Common.New}
/>
<OpenInCoolify url={`project/${project.uuid}`} />
</ActionPanel>
}
Expand Down