使用 Openkoda 构建具有 ClickUp API 集成的时间跟踪应用程序

简介: 使用 Openkoda 构建具有 ClickUp API 集成的时间跟踪应用程序

是否有可能在短短几个小时内构建一个时间跟踪应用程序?是的,在本文中,我将向您展示如何操作!

我是一名高级后端 Java 开发人员,在构建 Web 应用程序方面拥有 8 年的经验。我将向您展示节省大量时间来构建我的下一个是多么令人满意和革命性。我使用的方法如下:我想创建一个与 ClickUp API 集成的时间跟踪应用程序(我称之为 Timelog)。它提供了一个简单的功能,在这里非常有用:远程创建时间条目。

为了节省时间,我将使用 Openkoda 平台提供的一些开箱即用的功能。这些功能在设计时充分考虑了开发人员的需求。使用它们,我可以跳过构建每个 Web 应用程序中使用的标准功能(一遍又一遍)。相反,我可以专注于核心业务逻辑。

我将使用以下预构建功能来满足我的应用程序需求:

登录名/密码身份验证

用户和组织管理

不同的用户角色和权限

电子邮件发件人

日志概述

服务器端代码编辑器

Web 终结点创建者

CRUDs 发电机

让我们开始吧!

Timelog 应用程序概述

我们的示例内部应用程序创建了一个小型复杂系统,然后可以很容易地按模型扩展,并使用额外的业务逻辑或自定义视图进行扩展。

该应用程序的主要重点是:

存储与 ClickUp API 通信所需的数据。

将用户分配到其票证。

将新的时间条目发布到外部 API。

为了加快构建应用程序的过程,我们依赖于上面提到的一些开箱即用的功能。在此阶段,我们使用了以下方法:

数据模型生成器 (Form) - 允许我们定义数据结构,而无需重新编译应用程序,并能够动态调整数据架构

现成的管理功能 - 有了这个功能,我们可以忘记开发身份验证、安全性和标准仪表板视图等内容。

服务器端代码编辑器 - 用于开发负责 ClickUp API 集成的专用服务,它在 Openkoda UI 中以 JavaScript 编码。

WebEndpoint 构建器 - 允许我们创建一个自定义表单处理程序,该处理程序使用服务器端代码服务将时间跟踪条目数据发布到 ClickUp 服务器,而不是将其存储在我们的内部数据库中

步骤 1:设置体系结构

为了实现上述功能并存储所需的数据,我们设计了一个简单的数据模型,由以下五个实体组成。

ClickUpConfig、 、 和 旨在存储发送到 ClickUp API 的连接和消息所需的密钥和 ID。最后一个是 ,旨在利用现成的 HTML 表单(Thymeleaf 片段),从而节省大量开发时间。ClickUpUserTicketAssignmentTimeEntry

下面显示了用于 Timelog ClickUp 集成的预准备数据模型的详细结构。

ClickUpConfig

apiKey- ClickUp API 密钥

teamId- ClickUp 中用于创建时间条目的空间 ID

ClickUpUser

userId- 用户的内部 ID

clickUpUserId- 在 ClickUp 中分配给工作区的用户的 ID

Ticket

name- 工单的内部名称

clickUpTicketid- ClickUp 中用于创建时间条目的工单的 ID

Assignment

userId- 用户的内部 ID

ticketId- 工单的内部 ID

TimeEntry

userId- 用户的内部 ID

ticketId- 工单的内部 ID

date- 时间条目的日期

durationHours- 以小时为单位提供的时间输入持续时间

durationMinutes- 以分钟为单位提供时间输入持续时间

description- 创建时间条目的简短说明

我们希望在仪表板上最终显示五个数据磁贴:

image.png

第 2 步:与 ClickUp API 集成

我们将应用程序与 ClickUp API 集成,专门使用其端点在 ClickUp 中创建时间条目。

要将 Timelog 应用程序与我们的 ClickUp 工作区连接,需要提供 API 密钥。这可以使用个人 API 令牌或通过在 ClickUp 仪表板中创建应用程序生成的令牌来完成。有关如何检索其中之一的信息,请参阅官方 ClickUp 文档。

为了使我们的应用程序能够在 ClickUp 工作区中创建时间条目,我们需要提供一些 ClickUp ID:

teamId:这是访问工作区后 URL 中的第一个 ID 值。

userId:

要检查用户的 ClickUp ID(成员 ID),请转到 Workspace -> 管理用户。

在“用户”列表中,选择用户的“设置”,然后选择“复制成员 ID”。

taskId:

任务 ID 可在仪表板上的三个位置访问:URL、任务模式和任务列表视图。

有关详细说明,请参阅 ClickUp 帮助中心。

您可以识别以符号为前缀的任务 ID - 我们使用不带前缀的 ID。#

第 3 步:使用 Openkoda 进行数据模型魔术

Openkoda 使用 Byte Buddy 库在 Spring Boot 应用程序的运行时为动态注册的实体动态构建实体和存储库类。

以下是 Openkoda 中实体类生成的简短片段(整个服务类可在他们的 GitHub 上找到)。

1
dynamicType = new ByteBuddy()
2
       .with(SKIP_DEFAULTS)
3
       .subclass(OpenkodaEntity.class)
4
       .name(PACKAGE + name)
5
       .annotateType(entity)
6
       .annotateType(tableAnnotation)
7
       .defineConstructor(PUBLIC)
8
       .intercept(MethodCall
9
        .invoke(OpenkodaEntity.class.getDeclaredConstructor(Long.class))
10
               .with((Object) null));


Openkoda 提供了定义实体结构的自定义表单生成器语法。然后,此结构用于生成实体类和存储库类,以及 CRUD 视图的 HTML 表示形式,例如包含所有记录的分页表、设置表单和简单的只读视图。

前面描述的数据模型中的所有五个实体都以相同的方式注册,只是使用表单生成器语法。

下面显示了该实体的表单生成器代码段。Ticket

JavaScript的

1
a => a
2
.text("name")
3
.text("clickUpTaskId")


上面的定义导致实体使用一组默认字段 for 和两个名为 和 的自定义字段命名。TicketOpenkodaEntity“name”“clickUpTaskId”

动态生成实体的数据库表结构如下:Ticket

降价

1
                               Table "public.dynamic_ticket"
2
      Column      |           Type           | Collation | Nullable |        Default
3
------------------+--------------------------+-----------+----------+-----------------------
4
 id               | bigint                   |           | not null |
5
 created_by       | character varying(255)   |           |          |
6
 created_by_id    | bigint                   |           |          |
7
 created_on       | timestamp with time zone |           |          | CURRENT_TIMESTAMP
8
 index_string     | character varying(16300) |           |          | ''::character varying
9
 modified_by      | character varying(255)   |           |          |
10
 modified_by_id   | bigint                   |           |          |
11
 organization_id  | bigint                   |           |          |
12
 updated_on       | timestamp with time zone |           |          | CURRENT_TIMESTAMP
13
 click_up_task_id | character varying(255)   |           |          |
14
 name             | character varying(255)   |           |          |
15


成功注册实体的最后一步是刷新 Spring 上下文,以便它识别新的存储库 bean,并让 Hibernate 确认实体。这可以通过从管理面板(“监视”部分)重新启动应用程序来完成。

我们的最终结果是为实体自动生成的完整 CRUD。Ticket

自动生成的工单设置视图:

image.png


自动生成的所有工单列表视图:

image.png

步骤 4:设置服务器端代码即服务

image.png

我们使用 Openkoda 服务器端代码实现了 ClickUp API 集成,将 API 调用逻辑作为一项服务分开。可以在自定义表单视图请求处理程序的逻辑中进一步使用导出的 JS 函数。

然后,我们创建了一个 JavaScript 服务,该服务提供负责 ClickUp API 通信的函数。Openkoda 使用 GraalVM 在后端服务器上完全运行任何 JS 代码。

我们的 ClickupAPI 服务器端代码服务只有一个函数 (),需要它来满足我们的时间日志应用程序要求。postCreateTimeEntry

JavaScript的

1
export function postCreateTimeEntry(apiKey, teamId, duration, description, date, assignee, taskId) {
2
  let url = `https://api.clickup.com/api/v2/team/${teamId}/time_entries`;
3
  let timeEntryReq = {
4
      duration: duration,
5
      description: '[Openkoda Timelog] ' + description,
6
      billable: true,
7
      start: date,
8
      assignee: assignee,
9
      tid: taskId,
10
  };
11
  let headers = {Authorization: apiKey};
12
  return context.services.integrations.restPost(url, timeEntryReq, headers);
13
}
14


要稍后在 WebEndpoints 中使用此类服务,很容易遵循标准 JS 导入表达式。import * as clickupAPI from 'clickupAPI';

第 5 步:使用自定义 GET/POST 处理程序构建时间输入表单

在这里,我们为演示应用程序准备了基本屏幕:将数据发布到 ClickUp API 的时间输入表单。所有这些都是在 Openkoda 用户界面中通过提供简单的 HTML 内容和一些 JS 代码片段来完成的。

image.png

景观

HTML 片段就像下面发布的片段一样简单。我们使用了一个现成的 Thymeleaf 片段(参见标签),代码的其余部分是 Thymeleaf 模板的标准结构。form

[HTML全

1
<!--DEFAULT CONTENT-->
2
<!DOCTYPE html>
3
<html xmlns:th="http://www.thymeleaf.org" xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout" lang="en" layout:decorate="~{${defaultLayout}}">
4
<body>
5
<div class="container">
6
    <h1 layout:fragment="title"/>
7
    <div layout:fragment="content">
8
          <form th:replace="~{generic-forms::generic-form(${TimeEntry}, 'TimeEntry', '', '', '', 'Time Entry', #{template.save}, true)}"></form>
9
    </div>
10
</div>
11
</body>
12
</html>


HTTP 处理程序

一旦有了视图的简单HTML代码,我们就需要提供通用表单片段所需的实际表单对象。(${TimeEntry})

image.png

作为第一步,我们在 GET 端点中执行此操作,然后设置当前记录的用户 ID,以便在进入时间条目视图时选择默认值。

JavaScript的

1
flow
2
.thenSet("TimeEntry", a => a.services.data.getForm("TimeEntry"))
3
.then(a => a.model.get("TimeEntry").dto.set("userId", a.model.


get("userEntityId")))

最后,注册 POST 端点以处理从表单视图发送的实际 POST 请求(上面介绍的 HTML 代码)。它实现了用户输入时间输入表单,提供数据,然后将数据发送到 ClickUp 服务器的方案。

以下 POST 端点 JS 代码:

接收表单数据。

从内部数据库读取其他配置(如 API 密钥、团队 ID 或 ClickUp 用户 ID)。

准备要发送的数据。

触发服务与远程 API 通信。clickupAPI

JavaScript的

1
import * as clickupAPI from 'clickupAPI';
2
3
flow
4
.thenSet("clickUpConfig", a => a.services.data.getRepository("clickupConfig").search( (root, query, cb) => {
5
            let orgId = a.model.get("organizationEntityId") != null ? a.model.get("organizationEntityId") : -1;
6
            return cb.or(cb.isNull(root.get("organizationId")), cb.equal(root.get("organizationId"), orgId));
7
        }).get(0)
8
    )
9
.thenSet("clickUpUser", a => a.services.data.getRepository("clickupUser").search( (root, query, cb) => {
10
            let userId = a.model.get("userEntityId") != null ? a.model.get("userEntityId") : -1;
11
            return cb.equal(root.get("userId"), userId);
12
        })
13
)
14
.thenSet("ticket", a => a.form.dto.get("ticketId") != null ? a.services.data.getRepository("ticket").findOne(a.form.dto.get("ticketId")) : null)
15
.then(a => {
16
    let durationMs = (a.form.dto.get("durationHours") != null ? a.form.dto.get("durationHours") * 3600000 : 0)
17
        + (a.form.dto.get("durationMinutes") != null ? a.form.dto.get("durationMinutes") * 60000 : 0);
18
    return clickupAPI.postCreateTimeEntry(
19
        a.model.get("clickUpConfig").apiKey,
20
        a.model.get("clickUpConfig").teamId,
21
        durationMs,
22
        a.form.dto.get("description"),
23
        a.form.dto.get("date") != null ? (new Date(a.services.util.toString(a.form.dto.get("date")))).getTime() : Date.now().getTime(),
24
        a.model.get("clickUpUser").length ? a.model.get("clickUpUser").get(0).clickUpUserId : -1,
25
        a.model.get("ticket") != null ? a.model.get("ticket").clickUpTaskId : '')
26
})
27


第 6 步:我们的应用程序已准备就绪!

就是这样!

我构建了一个复杂的应用程序,它能够存储用户的数据、他们的票证分配以及 ClickUp API 连接所需的任何属性。它提供了一个时间条目表单,涵盖单个时间条目的票证选择、日期、持续时间和描述输入,并将数据从表单直接发送到集成 API。

image.png

不要忘记 Openkoda 中提供的所有预构建功能,例如身份验证、用户帐户管理、日志概述等。因此,创建 Timelog 应用程序的总时间只有几个小时。

我所构建的只是一个具有一个主要功能的简单应用程序。但是有很多方法可以扩展它,例如,通过向数据模型添加新结构,通过开发更多的 ClickUp API 集成,或者通过创建更复杂的屏幕,如下面的日历视图。

image.png

如果您遵循与我在此案例中介绍的几乎完全相同的场景,您将能够构建任何其他简单(或不简单)的业务应用程序,从而节省重复和无聊功能的时间,并专注于核心业务需求。

我能想到几个可以用同样方式构建的应用程序,例如法律文档管理系统、房地产应用程序、旅行社系统,仅举几例。

作为一名经验丰富的软件工程师,我总是喜欢实施新想法并快速看到结果。在这种情况下,这就是我所做的一切。我花了最少的时间创建一个根据我的需求量身定制的全功能应用程序,并跳过了单调的工作。


目录
相关文章
|
1月前
|
人工智能 IDE API
AI驱动的开发者工具:打造沉浸式API集成体验
本文介绍了阿里云在过去十年中为开发者提供的API服务演变。内容分为两大部分:一是从零开始使用API的用户旅程,涵盖API的发现、调试与集成;二是回顾阿里云过去十年为开发者提供的服务及发展历程。文中详细描述了API从最初的手写SDK到自动化生成SDK的变化,以及通过API Explorer、IDE插件和AI助手等工具提升开发者体验的过程。这些工具和服务旨在帮助开发者更高效地使用API,减少配置和调试的复杂性,提供一站式的解决方案。
|
6天前
|
人工智能 JSON 自然语言处理
AI 程序员的4个分身 | 代码生成专家+注释精灵+API集成助手+智能调试伙伴
AI 程序员的4个分身 | 代码生成专家+注释精灵+API集成助手+智能调试伙伴
139 35
|
2天前
|
机器学习/深度学习 人工智能 自然语言处理
企业级API集成方案:基于阿里云函数计算调用DeepSeek全解析
DeepSeek R1 是一款先进的大规模深度学习模型,专为自然语言处理等复杂任务设计。它具备高效的架构、强大的泛化能力和优化的参数管理,适用于文本生成、智能问答、代码生成和数据分析等领域。阿里云平台提供了高性能计算资源、合规与数据安全、低延迟覆盖和成本效益等优势,支持用户便捷部署和调用 DeepSeek R1 模型,确保快速响应和稳定服务。通过阿里云百炼模型服务,用户可以轻松体验满血版 DeepSeek R1,并享受免费试用和灵活的API调用方式。
|
1月前
|
人工智能 数据可视化 开发者
FlowiseAI:34K Star!集成多种模型和100+组件的 LLM 应用低代码开发平台,拖拽组件轻松构建程序
FlowiseAI 是一款开源的低代码工具,通过拖拽可视化组件,用户可以快速构建自定义的 LLM 应用程序,支持多模型集成和记忆功能。
117 14
FlowiseAI:34K Star!集成多种模型和100+组件的 LLM 应用低代码开发平台,拖拽组件轻松构建程序
|
1月前
|
人工智能 数据挖掘 API
R2R:开源的 RAG 集成系统,支持多模态处理、混合搜索、知识图谱构建等增强检索技术
R2R 是一款先进的 AI 检索增强生成平台,支持多模态内容处理、混合搜索和知识图谱构建,适用于复杂数据处理和分析的生产环境。
183 3
R2R:开源的 RAG 集成系统,支持多模态处理、混合搜索、知识图谱构建等增强检索技术
|
2月前
|
人工智能 数据可视化 JavaScript
NodeTool:AI 工作流可视化构建器,通过拖放节点设计复杂的工作流,集成 OpenAI 等多个平台
NodeTool 是一个开源的 AI 工作流可视化构建器,通过拖放节点的方式设计复杂的工作流,无需编码即可快速原型设计和测试。它支持本地 GPU 运行 AI 模型,并与 Hugging Face、OpenAI 等平台集成,提供模型访问能力。
154 14
NodeTool:AI 工作流可视化构建器,通过拖放节点设计复杂的工作流,集成 OpenAI 等多个平台
|
3月前
|
JSON 缓存 JavaScript
深入浅出:使用Node.js构建RESTful API
在这个数字时代,API已成为软件开发的基石之一。本文旨在引导初学者通过Node.js和Express框架快速搭建一个功能完备的RESTful API。我们将从零开始,逐步深入,不仅涉及代码编写,还包括设计原则、最佳实践及调试技巧。无论你是初探后端开发,还是希望扩展你的技术栈,这篇文章都将是你的理想指南。
|
2月前
|
安全 API 数据安全/隐私保护
自学记录HarmonyOS Next DRM API 13:构建安全的数字内容保护系统
在完成HarmonyOS Camera API开发后,我深入研究了数字版权管理(DRM)技术。最新DRM API 13提供了强大的工具,用于保护数字内容的安全传输和使用。通过学习该API的核心功能,如获取许可证、解密内容和管理权限,我实现了一个简单的数字视频保护系统。该系统包括初始化DRM模块、获取许可证、解密视频并播放。此外,我还配置了开发环境并实现了界面布局。未来,随着数字版权保护需求的增加,DRM技术将更加重要。如果你对这一领域感兴趣,欢迎一起探索和进步。
96 18
|
1月前
|
运维 监控 Cloud Native
构建深度可观测、可集成的网络智能运维平台
本文介绍了构建深度可观测、可集成的网络智能运维平台(简称NIS),旨在解决云上网络运维面临的复杂挑战。内容涵盖云网络运维的三大难题、打造云原生AIOps工具集的解决思路、可观测性对业务稳定的重要性,以及产品发布的亮点,包括流量分析NPM、网络架构巡检和自动化运维OpenAPI,助力客户实现自助运维与优化。
|
2月前
|
DataWorks 数据挖掘 大数据
方案实践测评 | DataWorks集成Hologres构建一站式高性能的OLAP数据分析
DataWorks在任务开发便捷性、任务运行速度、产品使用门槛等方面都表现出色。在数据处理场景方面仍有改进和扩展的空间,通过引入更多的智能技术、扩展数据源支持、优化任务调度和可视化功能以及提升团队协作效率,DataWorks将能够为企业提供更全面、更高效的数据处理解决方案。

热门文章

最新文章