diff --git a/build.gradle.kts b/build.gradle.kts index a3500a47bd..e30fe64fd2 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,3 +1,8 @@ +allprojects { + repositories { + mavenCentral() + } +} plugins { alias(libs.plugins.com.github.ben.manes.versions) id("com.bytechef.java-common-conventions") diff --git a/client/public/mockServiceWorker.js b/client/public/mockServiceWorker.js index 723b0714cd..325fae824a 100644 --- a/client/public/mockServiceWorker.js +++ b/client/public/mockServiceWorker.js @@ -7,8 +7,8 @@ * - Please do NOT modify this file. */ -const PACKAGE_VERSION = '2.10.5' -const INTEGRITY_CHECKSUM = 'f5825c521429caf22a4dd13b66e243af' +const PACKAGE_VERSION = '2.11.4' +const INTEGRITY_CHECKSUM = '4db4a41e972cec1b64cc569c66952d82' const IS_MOCKED_RESPONSE = Symbol('isMockedResponse') const activeClientIds = new Set() @@ -71,11 +71,6 @@ addEventListener('message', async function (event) { break } - case 'MOCK_DEACTIVATE': { - activeClientIds.delete(clientId) - break - } - case 'CLIENT_CLOSED': { activeClientIds.delete(clientId) @@ -94,6 +89,8 @@ addEventListener('message', async function (event) { }) addEventListener('fetch', function (event) { + const requestInterceptedAt = Date.now() + // Bypass navigation requests. if (event.request.mode === 'navigate') { return @@ -110,23 +107,29 @@ addEventListener('fetch', function (event) { // Bypass all requests when there are no active clients. // Prevents the self-unregistered worked from handling requests - // after it's been deleted (still remains active until the next reload). + // after it's been terminated (still remains active until the next reload). if (activeClientIds.size === 0) { return } const requestId = crypto.randomUUID() - event.respondWith(handleRequest(event, requestId)) + event.respondWith(handleRequest(event, requestId, requestInterceptedAt)) }) /** * @param {FetchEvent} event * @param {string} requestId + * @param {number} requestInterceptedAt */ -async function handleRequest(event, requestId) { +async function handleRequest(event, requestId, requestInterceptedAt) { const client = await resolveMainClient(event) const requestCloneForEvents = event.request.clone() - const response = await getResponse(event, client, requestId) + const response = await getResponse( + event, + client, + requestId, + requestInterceptedAt, + ) // Send back the response clone for the "response:*" life-cycle events. // Ensure MSW is active and ready to handle the message, otherwise @@ -202,9 +205,10 @@ async function resolveMainClient(event) { * @param {FetchEvent} event * @param {Client | undefined} client * @param {string} requestId + * @param {number} requestInterceptedAt * @returns {Promise} */ -async function getResponse(event, client, requestId) { +async function getResponse(event, client, requestId, requestInterceptedAt) { // Clone the request because it might've been already used // (i.e. its body has been read and sent to the client). const requestClone = event.request.clone() @@ -255,6 +259,7 @@ async function getResponse(event, client, requestId) { type: 'REQUEST', payload: { id: requestId, + interceptedAt: requestInterceptedAt, ...serializedRequest, }, }, diff --git a/server/libs/modules/components/figma/build.gradle.kts b/server/libs/modules/components/figma/build.gradle.kts index 190b578b89..07eadf7b8f 100644 --- a/server/libs/modules/components/figma/build.gradle.kts +++ b/server/libs/modules/components/figma/build.gradle.kts @@ -1 +1,5 @@ version="1.0" + +dependencies { + +} \ No newline at end of file diff --git a/server/libs/modules/components/figma/src/main/java/com/bytechef/component/figma/AbstractFigmaComponentHandler.java b/server/libs/modules/components/figma/src/main/java/com/bytechef/component/figma/AbstractFigmaComponentHandler.java index 9189783a80..5a7c2952a0 100644 --- a/server/libs/modules/components/figma/src/main/java/com/bytechef/component/figma/AbstractFigmaComponentHandler.java +++ b/server/libs/modules/components/figma/src/main/java/com/bytechef/component/figma/AbstractFigmaComponentHandler.java @@ -24,6 +24,7 @@ import com.bytechef.component.figma.action.FigmaGetCommentsAction; import com.bytechef.component.figma.action.FigmaPostCommentAction; import com.bytechef.component.figma.connection.FigmaConnection; +import com.bytechef.component.figma.trigger.FigmaNewCommentTrigger; /** * Provides the base implementation for the REST based component. @@ -41,7 +42,7 @@ public abstract class AbstractFigmaComponentHandler implements OpenApiComponentH .connection(modifyConnection(FigmaConnection.CONNECTION_DEFINITION)) .clusterElements(modifyClusterElements(tool(FigmaGetCommentsAction.ACTION_DEFINITION), tool(FigmaPostCommentAction.ACTION_DEFINITION))) - .triggers(getTriggers()); + .triggers(FigmaNewCommentTrigger.TRIGGER_DEFINITION); @Override public ComponentDefinition getDefinition() { diff --git a/server/libs/modules/components/figma/src/main/java/com/bytechef/component/figma/trigger/FigmaNewCommentTrigger.java b/server/libs/modules/components/figma/src/main/java/com/bytechef/component/figma/trigger/FigmaNewCommentTrigger.java new file mode 100644 index 0000000000..d376a268f6 --- /dev/null +++ b/server/libs/modules/components/figma/src/main/java/com/bytechef/component/figma/trigger/FigmaNewCommentTrigger.java @@ -0,0 +1,88 @@ +/* + * Copyright 2025 ByteChef + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.bytechef.component.figma.trigger; + +import static com.bytechef.component.definition.ComponentDsl.array; +import static com.bytechef.component.definition.ComponentDsl.object; +import static com.bytechef.component.definition.ComponentDsl.outputSchema; +import static com.bytechef.component.definition.ComponentDsl.string; +import static com.bytechef.component.definition.ComponentDsl.trigger; + +import com.bytechef.component.definition.ComponentDsl.ModifiableTriggerDefinition; +import com.bytechef.component.definition.Context.Http; +import com.bytechef.component.definition.Parameters; +import com.bytechef.component.definition.TriggerContext; +import com.bytechef.component.definition.TriggerDefinition.PollOutput; +import com.bytechef.component.definition.TriggerDefinition.TriggerType; +import com.bytechef.component.definition.TypeReference; +import java.time.OffsetDateTime; +import java.util.List; +import java.util.Map; + +public class FigmaNewCommentTrigger { + public static final ModifiableTriggerDefinition TRIGGER_DEFINITION = trigger("newComment") + .title("New Comment") + .description("Trigger when a new comment is added to a Figma file.") + .type(TriggerType.POLLING) + .output( + outputSchema( + object().properties( + string("file_key").description("Key of the Figma file."), + string("file_name").description("Name of the Figma file."), + array("comment").items(string()) + .description("List of comment messages."), + string("comment_id").description("ID of the comment."), + string("parent_id").description("Parent comment ID, if any."), + string("created_at").description("Timestamp when the comment was created."), + string("resolved_at").description("Timestamp when the comment was resolved."), + string("triggered_by").description("User who added the comment."), + string("timestamp").description("Event timestamp.")))) + .poll(FigmaNewCommentTrigger::poll); + + protected static PollOutput poll( + Parameters inputParameters, + Parameters connectionParameters, + Parameters closureParameters, + TriggerContext triggerContext) { + String fileKey = inputParameters.getRequiredString("file_key"); + String token = connectionParameters.getRequiredString("access_token"); + + Map body = triggerContext + .http(http -> http.get("https://api.figma.com/v1/files/" + fileKey + "/comments")) + .header("Authorization", "Bearer " + token) + .configuration(Http.responseType(Http.ResponseType.JSON)) + .execute() + .getBody(new TypeReference<>() {}); + + List> comments = (List>) body.get("comments"); + + List> output = comments.stream() + .map(comment -> Map.of( + "file_key", fileKey, + "file_name", body.get("fileName"), + "comment", List.of(comment.get("message")), + "comment_id", comment.get("id"), + "parent_id", comment.get("parent_id"), + "created_at", comment.get("created_at"), + "resolved_at", comment.get("resolved_at"), + "triggered_by", comment.get("user"), + "timestamp", OffsetDateTime.now() + .toString())) + .toList(); + return new PollOutput(output, Map.of(), false); + } +} diff --git a/server/libs/modules/components/figma/src/test/resources/definition/figma_v1.json b/server/libs/modules/components/figma/src/test/resources/definition/figma_v1.json index 894ba60155..6e72601e74 100644 --- a/server/libs/modules/components/figma/src/test/resources/definition/figma_v1.json +++ b/server/libs/modules/components/figma/src/test/resources/definition/figma_v1.json @@ -1667,7 +1667,518 @@ "resources": null, "tags": null, "title": "Figma", - "triggers": [ ], + "triggers": [ { + "batch": null, + "deduplicate": null, + "deprecated": null, + "description": "Trigger when a new comment is added to a Figma file.", + "dynamicWebhookRefresh": null, + "help": null, + "listenerDisable": null, + "listenerEnable": null, + "name": "newComment", + "outputDefinition": { + "output": null, + "outputResponse": { + "outputSchema": { + "additionalProperties": null, + "advancedOption": null, + "controlType": "OBJECT_BUILDER", + "defaultValue": null, + "description": null, + "displayCondition": null, + "exampleValue": null, + "expressionEnabled": null, + "hidden": null, + "label": null, + "metadata": { }, + "multipleValues": null, + "name": null, + "options": null, + "optionsDataSource": null, + "placeholder": null, + "properties": [ { + "advancedOption": null, + "controlType": "TEXT", + "defaultValue": null, + "description": "Key of the Figma file.", + "displayCondition": null, + "exampleValue": null, + "expressionEnabled": null, + "hidden": null, + "label": null, + "languageId": null, + "maxLength": null, + "metadata": { }, + "minLength": null, + "name": "file_key", + "options": null, + "optionsDataSource": null, + "optionsLoadedDynamically": null, + "placeholder": null, + "regex": null, + "required": null, + "type": "STRING" + }, { + "advancedOption": null, + "controlType": "TEXT", + "defaultValue": null, + "description": "Name of the Figma file.", + "displayCondition": null, + "exampleValue": null, + "expressionEnabled": null, + "hidden": null, + "label": null, + "languageId": null, + "maxLength": null, + "metadata": { }, + "minLength": null, + "name": "file_name", + "options": null, + "optionsDataSource": null, + "optionsLoadedDynamically": null, + "placeholder": null, + "regex": null, + "required": null, + "type": "STRING" + }, { + "advancedOption": null, + "controlType": "ARRAY_BUILDER", + "defaultValue": null, + "description": "List of comment messages.", + "displayCondition": null, + "exampleValue": null, + "expressionEnabled": null, + "hidden": null, + "items": [ { + "advancedOption": null, + "controlType": "TEXT", + "defaultValue": null, + "description": null, + "displayCondition": null, + "exampleValue": null, + "expressionEnabled": null, + "hidden": null, + "label": null, + "languageId": null, + "maxLength": null, + "metadata": { }, + "minLength": null, + "name": null, + "options": null, + "optionsDataSource": null, + "optionsLoadedDynamically": null, + "placeholder": null, + "regex": null, + "required": null, + "type": "STRING" + } ], + "label": null, + "maxItems": null, + "metadata": { }, + "minItems": null, + "multipleValues": null, + "name": "comment", + "options": null, + "optionsDataSource": null, + "placeholder": null, + "required": null, + "type": "ARRAY" + }, { + "advancedOption": null, + "controlType": "TEXT", + "defaultValue": null, + "description": "ID of the comment.", + "displayCondition": null, + "exampleValue": null, + "expressionEnabled": null, + "hidden": null, + "label": null, + "languageId": null, + "maxLength": null, + "metadata": { }, + "minLength": null, + "name": "comment_id", + "options": null, + "optionsDataSource": null, + "optionsLoadedDynamically": null, + "placeholder": null, + "regex": null, + "required": null, + "type": "STRING" + }, { + "advancedOption": null, + "controlType": "TEXT", + "defaultValue": null, + "description": "Parent comment ID, if any.", + "displayCondition": null, + "exampleValue": null, + "expressionEnabled": null, + "hidden": null, + "label": null, + "languageId": null, + "maxLength": null, + "metadata": { }, + "minLength": null, + "name": "parent_id", + "options": null, + "optionsDataSource": null, + "optionsLoadedDynamically": null, + "placeholder": null, + "regex": null, + "required": null, + "type": "STRING" + }, { + "advancedOption": null, + "controlType": "TEXT", + "defaultValue": null, + "description": "Timestamp when the comment was created.", + "displayCondition": null, + "exampleValue": null, + "expressionEnabled": null, + "hidden": null, + "label": null, + "languageId": null, + "maxLength": null, + "metadata": { }, + "minLength": null, + "name": "created_at", + "options": null, + "optionsDataSource": null, + "optionsLoadedDynamically": null, + "placeholder": null, + "regex": null, + "required": null, + "type": "STRING" + }, { + "advancedOption": null, + "controlType": "TEXT", + "defaultValue": null, + "description": "Timestamp when the comment was resolved.", + "displayCondition": null, + "exampleValue": null, + "expressionEnabled": null, + "hidden": null, + "label": null, + "languageId": null, + "maxLength": null, + "metadata": { }, + "minLength": null, + "name": "resolved_at", + "options": null, + "optionsDataSource": null, + "optionsLoadedDynamically": null, + "placeholder": null, + "regex": null, + "required": null, + "type": "STRING" + }, { + "advancedOption": null, + "controlType": "TEXT", + "defaultValue": null, + "description": "User who added the comment.", + "displayCondition": null, + "exampleValue": null, + "expressionEnabled": null, + "hidden": null, + "label": null, + "languageId": null, + "maxLength": null, + "metadata": { }, + "minLength": null, + "name": "triggered_by", + "options": null, + "optionsDataSource": null, + "optionsLoadedDynamically": null, + "placeholder": null, + "regex": null, + "required": null, + "type": "STRING" + }, { + "advancedOption": null, + "controlType": "TEXT", + "defaultValue": null, + "description": "Event timestamp.", + "displayCondition": null, + "exampleValue": null, + "expressionEnabled": null, + "hidden": null, + "label": null, + "languageId": null, + "maxLength": null, + "metadata": { }, + "minLength": null, + "name": "timestamp", + "options": null, + "optionsDataSource": null, + "optionsLoadedDynamically": null, + "placeholder": null, + "regex": null, + "required": null, + "type": "STRING" + } ], + "required": null, + "type": "OBJECT" + }, + "placeholder": null, + "sampleOutput": null + }, + "outputSchema": { + "additionalProperties": null, + "advancedOption": null, + "controlType": "OBJECT_BUILDER", + "defaultValue": null, + "description": null, + "displayCondition": null, + "exampleValue": null, + "expressionEnabled": null, + "hidden": null, + "label": null, + "metadata": { }, + "multipleValues": null, + "name": null, + "options": null, + "optionsDataSource": null, + "placeholder": null, + "properties": [ { + "advancedOption": null, + "controlType": "TEXT", + "defaultValue": null, + "description": "Key of the Figma file.", + "displayCondition": null, + "exampleValue": null, + "expressionEnabled": null, + "hidden": null, + "label": null, + "languageId": null, + "maxLength": null, + "metadata": { }, + "minLength": null, + "name": "file_key", + "options": null, + "optionsDataSource": null, + "optionsLoadedDynamically": null, + "placeholder": null, + "regex": null, + "required": null, + "type": "STRING" + }, { + "advancedOption": null, + "controlType": "TEXT", + "defaultValue": null, + "description": "Name of the Figma file.", + "displayCondition": null, + "exampleValue": null, + "expressionEnabled": null, + "hidden": null, + "label": null, + "languageId": null, + "maxLength": null, + "metadata": { }, + "minLength": null, + "name": "file_name", + "options": null, + "optionsDataSource": null, + "optionsLoadedDynamically": null, + "placeholder": null, + "regex": null, + "required": null, + "type": "STRING" + }, { + "advancedOption": null, + "controlType": "ARRAY_BUILDER", + "defaultValue": null, + "description": "List of comment messages.", + "displayCondition": null, + "exampleValue": null, + "expressionEnabled": null, + "hidden": null, + "items": [ { + "advancedOption": null, + "controlType": "TEXT", + "defaultValue": null, + "description": null, + "displayCondition": null, + "exampleValue": null, + "expressionEnabled": null, + "hidden": null, + "label": null, + "languageId": null, + "maxLength": null, + "metadata": { }, + "minLength": null, + "name": null, + "options": null, + "optionsDataSource": null, + "optionsLoadedDynamically": null, + "placeholder": null, + "regex": null, + "required": null, + "type": "STRING" + } ], + "label": null, + "maxItems": null, + "metadata": { }, + "minItems": null, + "multipleValues": null, + "name": "comment", + "options": null, + "optionsDataSource": null, + "placeholder": null, + "required": null, + "type": "ARRAY" + }, { + "advancedOption": null, + "controlType": "TEXT", + "defaultValue": null, + "description": "ID of the comment.", + "displayCondition": null, + "exampleValue": null, + "expressionEnabled": null, + "hidden": null, + "label": null, + "languageId": null, + "maxLength": null, + "metadata": { }, + "minLength": null, + "name": "comment_id", + "options": null, + "optionsDataSource": null, + "optionsLoadedDynamically": null, + "placeholder": null, + "regex": null, + "required": null, + "type": "STRING" + }, { + "advancedOption": null, + "controlType": "TEXT", + "defaultValue": null, + "description": "Parent comment ID, if any.", + "displayCondition": null, + "exampleValue": null, + "expressionEnabled": null, + "hidden": null, + "label": null, + "languageId": null, + "maxLength": null, + "metadata": { }, + "minLength": null, + "name": "parent_id", + "options": null, + "optionsDataSource": null, + "optionsLoadedDynamically": null, + "placeholder": null, + "regex": null, + "required": null, + "type": "STRING" + }, { + "advancedOption": null, + "controlType": "TEXT", + "defaultValue": null, + "description": "Timestamp when the comment was created.", + "displayCondition": null, + "exampleValue": null, + "expressionEnabled": null, + "hidden": null, + "label": null, + "languageId": null, + "maxLength": null, + "metadata": { }, + "minLength": null, + "name": "created_at", + "options": null, + "optionsDataSource": null, + "optionsLoadedDynamically": null, + "placeholder": null, + "regex": null, + "required": null, + "type": "STRING" + }, { + "advancedOption": null, + "controlType": "TEXT", + "defaultValue": null, + "description": "Timestamp when the comment was resolved.", + "displayCondition": null, + "exampleValue": null, + "expressionEnabled": null, + "hidden": null, + "label": null, + "languageId": null, + "maxLength": null, + "metadata": { }, + "minLength": null, + "name": "resolved_at", + "options": null, + "optionsDataSource": null, + "optionsLoadedDynamically": null, + "placeholder": null, + "regex": null, + "required": null, + "type": "STRING" + }, { + "advancedOption": null, + "controlType": "TEXT", + "defaultValue": null, + "description": "User who added the comment.", + "displayCondition": null, + "exampleValue": null, + "expressionEnabled": null, + "hidden": null, + "label": null, + "languageId": null, + "maxLength": null, + "metadata": { }, + "minLength": null, + "name": "triggered_by", + "options": null, + "optionsDataSource": null, + "optionsLoadedDynamically": null, + "placeholder": null, + "regex": null, + "required": null, + "type": "STRING" + }, { + "advancedOption": null, + "controlType": "TEXT", + "defaultValue": null, + "description": "Event timestamp.", + "displayCondition": null, + "exampleValue": null, + "expressionEnabled": null, + "hidden": null, + "label": null, + "languageId": null, + "maxLength": null, + "metadata": { }, + "minLength": null, + "name": "timestamp", + "options": null, + "optionsDataSource": null, + "optionsLoadedDynamically": null, + "placeholder": null, + "regex": null, + "required": null, + "type": "STRING" + } ], + "required": null, + "type": "OBJECT" + }, + "sampleOutput": null + }, + "poll": { }, + "processErrorResponse": null, + "properties": null, + "title": "New Comment", + "type": "POLLING", + "webhookDisable": null, + "webhookEnable": null, + "webhookRawBody": null, + "webhookRequest": null, + "webhookValidate": null, + "webhookValidateOnEnable": null, + "workflowNodeDescription": null, + "workflowSyncExecution": null + } ], "unifiedApi": null, "version": 1 } \ No newline at end of file