Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/psolymos/clickrup

Interacting with the ClickUp v2 API from R
https://github.com/psolymos/clickrup

api clickup clickup-api project-management r rstats

Last synced: about 1 month ago
JSON representation

Interacting with the ClickUp v2 API from R

Awesome Lists containing this project

README

        

---
output:
md_document:
variant: gfm
---

```{r, echo=FALSE}
knitr::opts_chunk$set(
collapse = TRUE,
comment = "#>",
fig.path = "README-"
)
```

# clickrup

[![clickrup status badge](https://psolymos.r-universe.dev/badges/clickrup)](https://psolymos.r-universe.dev)

> Interacting with the ClickUp v2 API from R

[ClickUp](https://clickup.com/?noRedirect=true) is a cloud-based collaboration and project management tool.
Features include tasks, docs, chat, goals, and [more](https://clickup.com/features).

The {clickrup} R package wraps the ClickUp [API v2](https://clickup.com/api).
See the [roadmap](https://github.com/psolymos/clickrup/issues/1) for what is currently included in the package.

## Setup

Install the {clickrup} package:

```{r eval=FALSE}
## using remotes
remotes::install_github("psolymos/clickrup")

## with r-universe
options(repos = c(
psolymos = "https://psolymos.r-universe.dev",
CRAN = "https://cloud.r-project.org"))
install.packages('clickrup')
```

Follow this [tutorial](https://docs.clickup.com/en/articles/1367130-getting-started-with-the-clickup-api):

- sign up for ClickUp (you can use this referral [link](https://clickup.com?fp_ref=peter51) to do so, it's free),
- navigate to your personal *Settings*,
- click *Apps* in the left sidebar,
- click *Generate* to create your API token,
- click *Copy* to copy the token to your clipboard.

Now add your ClickUp token as an environment variable:

- open the file `.Renviron`: `file.edit("~/.Renviron")`,
- add a line with `CU_PAT="your_token"` to the `.Renviron` file and save it,
- check with `Sys.getenv("CU_PAT")`, it should return the token.

The ClickUp token will look something like
`pk_4753994_EXP7MPOJ7XQM5UJDV2M45MPF0YHH5YHO`.

The `cu_set_pat` function uses `Sys.setenv` to set
the `CU_PAT` environment variable for other processes called from within R or future calls to `Sys.getenv` from the same R process.

## API endpoints

The first step you want to do is to get the IDs for your workspaces (teams is the legacy term for this in the API).

If your setup was successful, `cu_get_teams()` should return a list with the workspace IDs and names.

The easiest way to get going with the various endpoints is to browse the [API v2 documentation](https://clickup.com/api).
Once you found what you are after, just look at the API heading. For example, for **Get Teams**, the R function
is prepended with `cu_` (to facilitate RStudio code completion),
then comes the heading in lower case and spaces replaced by underscores.
Similarly, **Get Filtered Team Tasks** will be `cu_get_filtered_team_tasks()`.
Articles (a, an, the) are dropped (e.g. **Create a Time Entry**)
will be `cu_create_time_entry()`.

Function arguments are the *Parameters* listed on the API page, `...` passes optional parameters, query parameters,
or elements for the body.

## Examples

Load the package and set the access token if it is not already set.
`cu_get_pat()` returns the token invisibly, so it doesn't
end up in logs.

```{r}
library(clickrup)
cu_get_pat() # returns PAT invisibly
```

### ClickUp hierarchy

The [ClickUp hierarchy](https://docs.clickup.com/en/articles/1045623-how-does-the-hierarchy-structure-work-in-clickup) includes the following levels:

- Workspaces (teams is the legacy term for this in the API)
- Spaces
- Folders
- Lists
- Tasks
- Subtasks
- Checklists

We can list Workspaces that we have access to using the `cu_get_teams()`
function. It takes no arguments, it only passes the access token
behind the scenes, so it is a good way to test if things are
working as expected

```{r}
Teams <- cu_get_teams()
str(Teams, 3)
```

Spaces within a specific Workspace defined by its `team_id`

```{r}
team_id <- Teams$teams[[2]]$id
Spaces <- cu_get_spaces(team_id)
str(Spaces, 3)
```

Folders within a specific Space defined by its `space_id`

```{r}
space_id <- Spaces$spaces[[2]]$id
Folders <- cu_get_folders(space_id)
str(Folders, 3)
```

Lists within a specific Folder defined by its `folder_id`
(or Folderless Lists based on `space_id`)

```{r}
folder_id <- Folders$folders[[1]]$id
Lists <- cu_get_lists(folder_id)
str(Lists, 3)

cu_get_lists_folderless(space_id)
```

The functions `cu_get_spaces`, `cu_get_folders`, and `cu_get_lists`
accept the argument `archived` to return archived spaces/folders/lists

```{r}
str(cu_get_lists(folder_id, archived=TRUE), 3)
```

### Tasks

We can list Tasks within a specific List defined by its `list_id`

```{r}
list_id <- Lists$lists[[1]]$id
Tasks <- cu_get_tasks(list_id)
str(Tasks, 2)
```

Notice that we have `r length(Tasks$tasks)` tasks in the list.
We can include Subtasks too

```{r}
subTasks <- cu_get_tasks(list_id, subtasks=TRUE)
length(subTasks$tasks)
```

Getting all the tasks (possibly filtered) in a Workspace
is done via the `cu_get_filtered_team_tasks` function.
This function returns tasks in batches of 100.
If you don't want to deal with paging, use the
wrapper function `cu_get_all_team_tasks`
The list of tasks returned does not include closed tasks,
to get those as well we need to pass the `include_closed`
query parameter

```{r}
## without closed tasks
length(cu_get_all_team_tasks(team_id, subtasks=TRUE)$tasks)

## with closed tasks
allSubTasks <- cu_get_all_team_tasks(team_id, subtasks=TRUE,
include_closed=TRUE)
length(allSubTasks$tasks)

Status <- sapply(allSubTasks$tasks, function(z) z$status$status)
data.frame(table(Status))
```

Let's inspect the first few elements of a Task object

```{r}
str(Tasks$tasks[[1]][1:10])
```

Dates are given as Unix time (in milliseconds),
`cu_date_from` and `cu_date_to` is there to convert back and forth

```{r}
Tasks$tasks[[1]]$date_created
cu_date_from(Tasks$tasks[[1]]$date_created)
cu_date_to(cu_date_from(Tasks$tasks[[1]]$date_created))
```

A single task can be accessed through the task ID
(note: copying the task ID from the ClickUp GUI will prepend
the task ID by a hash, `"#8ckjp5"`, but the API expects
ID without the hash `"8ckjp5"`). Use the `cu_task_id` function to get
rid of the leading hash (all API call use this function to
normalize task IDs).

The `$parent` property is `NULL` for Tasks, and
it contains the parent Task ID for Subtasks

```{r}
x1 <- cu_get_task(cu_task_id("#8ckjp5")) # task
x1$parent

x2 <- cu_get_task("8ckjru") # subtask
x2$parent
```

Dependencies are stored in the `$dependencies` property

```{r}
str(x1$dependencies)
```

### Helper functions

`cu_options` stores the API settings

```{r}
str(cu_options())
```

`cu_response` allows inspecting the response object

```{r}
cu_response(Teams)
```

Check rate limits and remaining requests (rate is limited by the minute)

```{r}
cu_ratelimit(subTasks)
```

### Formatting the request body

`PUSH` and `PUT` requests often require to send data as part of the
request body. Check the API examples and use `I()` when the API expects an
array as part of the body. For example when passing data to
`cu_create_task`, `assignees` is an array of the assignees'
userids to be added. Adding a single userid without `I()` will
drop the brackets, but
`list(name = "New Task Name", assignees = I(183))` will result in
the expected JSON object:
`{ "name": "New Task Name", "assignees": [183] }`.

### Attachments

We can upload files as attachments to tasks:

```{r eval=FALSE}
f <- file.path(tempdir(), "example.png")

png(f)
hist(rnorm(10^6), col=2, main="Example")
dev.off()

cu_post_task_attachment("8ach57", f)

unlink(f) # delete file
```

## Issues

https://github.com/psolymos/clickrup/issues

## License

[MIT](LICENSE) © 2020 Peter Solymos