Skip to content

Commit

Permalink
[Coolify] view-secret-keys + update-projects (raycast#16003)
Browse files Browse the repository at this point in the history
* [Coolify] view-secret-keys + update-projects

* Update CHANGELOG.md and optimise images

---------

Co-authored-by: raycastbot <[email protected]>
  • Loading branch information
2 people authored and gogocharli committed Jan 6, 2025
1 parent 1b5985f commit a7f442e
Show file tree
Hide file tree
Showing 8 changed files with 184 additions and 4 deletions.
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

0 comments on commit a7f442e

Please sign in to comment.