Skip to content

Commit

Permalink
Gitlab: Fix epics handling + Mark as todo action for issue and MRs (r…
Browse files Browse the repository at this point in the history
…aycast#199)

* fix duplications in epics list

* fix crash when an epic is in the todo list

* add toast message for successful closing a todo

* add action to mark as todo for issues and epics

* fix possible exception if no project is defined in a todo

* update readme
  • Loading branch information
tonka3000 committed Oct 26, 2021
1 parent 256b0d0 commit 13beb26
Show file tree
Hide file tree
Showing 7 changed files with 187 additions and 6 deletions.
98 changes: 95 additions & 3 deletions extensions/gitlab/README.md
@@ -1,10 +1,102 @@
# GitLab integration for Raycast
<div align="center">
<img
src="https://github.com/raycast/extensions/blob/main/extensions/gitlab/assets/gitlab.png?raw=true"
width="50"
/>

## Prerequisites
<h1>
GitLab
</h1>

call `npm ci`
Raycast extension to create, search and modify issues, manage merge requests, projects and more.

<p>
<a href="https://www.raycast.com/tonka3000/gitlab">
<img src="https://img.shields.io/badge/Raycast-store-red.svg"
alt="Find this extension on the Raycast store"
/>
</a>
<a
href="https://github.com/raycast/extensions/blob/master/LICENSE"
>
<img
src="https://img.shields.io/badge/license-MIT-blue.svg"
alt="raycast-extensions is released under the MIT license."
/>
</a>
<img
src="https://img.shields.io/badge/PRs-welcome-brightgreen.svg"
alt="PRs welcome!"
/>
<a href="https://twitter.com/intent/follow?screen_name=tonka_2000">
<img
src="https://img.shields.io/twitter/follow/tonka_2000.svg?label=Follow%20@tonka_2000"
alt="Follow @tonka_2000"
/>
</a>
<a href="https://open.vscode.dev/organization/repository">
<img
src="https://open.vscode.dev/badges/open-in-vscode.svg"
alt="Open in Visual Studio Code"
/>
</a>
</p>
</div>

## Features

- Manage your issue
- Manage your assigned issues
- Manage your GitLab todos
- Manage your projects
- Manage your epics
- Manage your merge requests
- Manage your reviews
- Search other users

and many more

## How to get the access token for the GitLab API

- Goto to your GitLab instance e.g. https://gitlab.com
- Click on your avatar image in the right upper corner
- Click on `Edit profile`
- Click on `Access Tokens` on the left sidebar
- Give your token a name e.g. `raycast` and set an expiration date (highly recommended)
- Select your scope of choice

You need at least `read_api`. When you want to make write operation via raycast, you should use `api`

- Store the given access token in a secret box because GitLab want show you the key again
- Go to the preferences in Raycast (or start any command of GitLab extension)
- Set your GitLab instance url

For gitlab.com this would be `https://gitlab.com`.
Your own instance could be `https://mygitlab.org`.

- Set the token from the previous step into the `API Token` field

Now you should be able to manage your GitLab instance with Raycast 🚀.

## API Token/Personal Access Token scope

For all read only commands the `read_api` scope is enough. If you want to create/modify e.g. an issue you need
the `api` scope.

## Showcases

### Todos

![todos](https://user-images.githubusercontent.com/3163807/138604198-6afbc93b-c263-4c03-812a-fc77b63d23a1.png)

### My Open Issues

![issues](https://user-images.githubusercontent.com/3163807/138604241-80629c99-6b86-4034-86ad-9400610b6350.png)

### My Groups

![groups](https://user-images.githubusercontent.com/3163807/138604274-f25a935c-50da-435f-b332-a9a72217e6e6.png)

### Epics

![epcis](https://user-images.githubusercontent.com/3163807/138604310-c6292899-232f-4902-a170-f5f93db9c998.png)
32 changes: 32 additions & 0 deletions extensions/gitlab/src/components/epic_actions.tsx
@@ -0,0 +1,32 @@
import { ActionPanel, Color, KeyboardShortcut, showToast, ToastStyle } from "@raycast/api";
import { gitlab } from "../common";
import { Epic } from "../gitlabapi";
import { GitLabIcons } from "../icons";

export function CreateEpicTodoAction(props: { epic: Epic; shortcut?: KeyboardShortcut }) {
const epic = props.epic;
async function handleAction() {
try {
await gitlab.post(`groups/${epic.group_id}/epics/${epic.iid}/todo`);
showToast(ToastStyle.Success, "To do created");
} catch (error: any) {
showToast(
ToastStyle.Failure,
"Failed to add as to do",
error instanceof Error ? error.message : error.toString()
);
}
}
if (epic.state === "opened") {
return (
<ActionPanel.Item
title="Add a to do"
shortcut={props.shortcut}
icon={{ source: GitLabIcons.todo, tintColor: Color.PrimaryText }}
onAction={handleAction}
/>
);
} else {
return null;
}
}
2 changes: 2 additions & 0 deletions extensions/gitlab/src/components/epics.tsx
Expand Up @@ -15,6 +15,7 @@ import { gitlab } from "../common";
import { Epic, Group, searchData } from "../gitlabapi";
import { GitLabIcons } from "../icons";
import { ClearLocalCacheAction } from "./cache_actions";
import { CreateEpicTodoAction } from "./epic_actions";

function getIcon(state: string): Image {
if (state == "opened") {
Expand All @@ -36,6 +37,7 @@ export function EpicListItem(props: { epic: any }) {
actions={
<ActionPanel>
<OpenInBrowserAction url={epic.web_url} />
<CreateEpicTodoAction epic={epic} shortcut={{ modifiers: ["cmd"], key: "t" }} />
<CopyToClipboardAction title="Copy Epic ID" content={epic.id} />
<ClearLocalCacheAction />
</ActionPanel>
Expand Down
30 changes: 30 additions & 0 deletions extensions/gitlab/src/components/issue_actions.tsx
Expand Up @@ -4,6 +4,7 @@ import {
Color,
CopyToClipboardAction,
Icon,
KeyboardShortcut,
PushAction,
showToast,
ToastStyle,
Expand Down Expand Up @@ -76,10 +77,39 @@ function ShowIssueLabelsAction(props: { labels: Label[] }) {
);
}

export function CreateIssueTodoAction(props: { issue: Issue; shortcut?: KeyboardShortcut }) {
const issue = props.issue;
async function handleAction() {
try {
await gitlab.post(`projects/${issue.project_id}/issues/${issue.iid}/todo`);
showToast(ToastStyle.Success, "To do created");
} catch (error: any) {
showToast(
ToastStyle.Failure,
"Failed to add as to do",
error instanceof Error ? error.message : error.toString()
);
}
}
if (issue.state === "opened") {
return (
<ActionPanel.Item
title="Add a to do"
shortcut={props.shortcut}
icon={{ source: GitLabIcons.todo, tintColor: Color.PrimaryText }}
onAction={handleAction}
/>
);
} else {
return null;
}
}

export function IssueItemActions(props: { issue: Issue }) {
const issue = props.issue;
return (
<React.Fragment>
<CreateIssueTodoAction issue={issue} shortcut={{ modifiers: ["cmd"], key: "t" }} />
<ShowIssueLabelsAction labels={issue.labels} />
{issue.state == "opened" && <CreateMRAction issue={issue} />}
{issue.state == "opened" && <CloseIssueAction issue={issue} />}
Expand Down
3 changes: 2 additions & 1 deletion extensions/gitlab/src/components/todo.tsx
Expand Up @@ -53,11 +53,12 @@ export function TodoList() {

export function TodoListItem(props: { todo: Todo }) {
const todo = props.todo;
const subtitle = todo.group ? todo.group.full_path : todo.project_with_namespace || "";
return (
<List.Item
id={todo.id.toString()}
title={todo.title}
subtitle={todo.project_with_namespace}
subtitle={subtitle}
accessoryTitle={todo.action_name}
accessoryIcon={userToIcon(todo.author)}
icon={{ source: GitLabIcons.todo, tintColor: Color.Green }}
Expand Down
8 changes: 7 additions & 1 deletion extensions/gitlab/src/components/todo_actions.tsx
Expand Up @@ -25,8 +25,13 @@ export function CloseTodoAction(props: { todo: Todo }) {
async function handleAction() {
try {
await gitlab.post(`todos/${todo.id}/mark_as_done`);
showToast(ToastStyle.Success, "Done", "Todo is now marked as done");
} catch (error: any) {
showToast(ToastStyle.Failure, "Failed to Close to do", error instanceof Error ? error.message : error.toString());
showToast(
ToastStyle.Failure,
"Failed to mark Todo as done",
error instanceof Error ? error.message : error.toString()
);
}
}
return (
Expand All @@ -43,6 +48,7 @@ export function CloseAllTodoAction() {
async function handleAction() {
try {
await gitlab.post(`todos/mark_as_done`);
showToast(ToastStyle.Success, "Done", "All Todos are now marked as done");
} catch (error: any) {
showToast(
ToastStyle.Failure,
Expand Down
20 changes: 19 additions & 1 deletion extensions/gitlab/src/gitlabapi.ts
Expand Up @@ -113,6 +113,8 @@ export interface Branch {

export interface Epic {
id: number;
iid: number;
group_id: number;
title: string;
state: string;
web_url: string;
Expand Down Expand Up @@ -173,6 +175,17 @@ export class MergeRequest {
public labels: Label[] = [];
}

export interface TodoGroup {
id: number;
name: string;
path: string;
kind: string;
full_path: string;
parent_id: number;
avatar_url?: string;
web_url: string;
}

export class Todo {
public title: string = "";
public target_url = "";
Expand All @@ -181,6 +194,7 @@ export class Todo {
public id: number = 0;
public action_name = "";
public project_with_namespace = "";
public group?: TodoGroup;
public author?: User = undefined;
}

Expand Down Expand Up @@ -552,7 +566,8 @@ export class GitLab {
target_type: issue.target_type,
target: issue.target,
id: issue.id,
project_with_namespace: issue.project.name_with_namespace,
project_with_namespace: issue.project ? issue.project.name_with_namespace : undefined,
group: issue.group ? issue.group as TodoGroup : undefined,
author: userFromJson(issue.author)
}))
});
Expand Down Expand Up @@ -609,6 +624,9 @@ export class GitLab {
delete params.scope;
}

params.include_ancestor_groups = false;
params.include_descendant_groups = false;

const groups = await this.getUserGroups();
let epics: Epic[] = [];
for (const g of groups) {
Expand Down

0 comments on commit 13beb26

Please sign in to comment.