Copilot commented on code in PR #3607:
URL: 
https://github.com/apache/incubator-kie-tools/pull/3607#discussion_r3325173799


##########
packages/bpmn-editor-envelope/src/BpmnEditorChannelApi.ts:
##########
@@ -19,4 +19,22 @@
 
 import { KogitoEditorChannelApi } from "@kie-tools-core/editor/dist/api";
 
-export interface BpmnEditorChannelApi extends KogitoEditorChannelApi {}
+export interface RestTaskTestRequest {
+  url: string;
+  method: string;
+  headers: Record<string, string>;
+  body?: string;
+  useCorsProxy: boolean;
+}
+
+export interface RestTaskTestResponse {
+  status: number;
+  data: string;
+  headers?: Record<string, string>;
+}

Review Comment:
   `RestTaskTestResponse.data` is typed as `string`, but both the online editor 
and VS Code implementations parse JSON responses with `response.json()` and 
return an object/array via `data: any` (see 
`packages/online-editor/src/editor/EditorPage.tsx` lines 363-366 and 
`packages/bpmn-vscode-extension/src/channelApi/BpmnEditorChannelApiImpl.ts` 
lines 52-56). The panel itself also handles non-string data by serializing with 
`JSON.stringify(testResult.data, null, 2)`. The type should be `string | 
unknown` (or `any`/`unknown`) to match the actual contract; otherwise callers 
relying on this type may pass it directly into string contexts and break.



##########
packages/bpmn-vscode-extension/src/channelApi/BpmnEditorChannelApiImpl.ts:
##########
@@ -0,0 +1,72 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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
+ *
+ *  http://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.
+ */
+
+import { DefaultVsCodeKieEditorChannelApiImpl } from 
"@kie-tools-core/vscode-extension/dist/DefaultVsCodeKieEditorChannelApiImpl";
+import {
+  BpmnEditorChannelApi,
+  RestTaskTestRequest,
+  RestTaskTestResponse,
+} from "@kie-tools/bpmn-editor-envelope/dist/BpmnEditorChannelApi";
+
+export class BpmnEditorChannelApiImpl extends 
DefaultVsCodeKieEditorChannelApiImpl implements BpmnEditorChannelApi {
+  constructor(
+    protected readonly editor: any,
+    protected readonly resourceContentService: any,
+    protected readonly vscodeWorkspace: any,
+    protected readonly vscodeNotifications: any,
+    protected readonly javaCodeCompletionApi: any,
+    protected readonly viewType: string,
+    protected readonly i18n: any
+  ) {
+    super(editor, resourceContentService, vscodeWorkspace, 
vscodeNotifications, javaCodeCompletionApi, viewType, i18n);
+  }

Review Comment:
   All constructor parameters are typed as `any`, losing type safety provided 
by `VsCodeKieEditorChannelApiProducer.get` (see 
`packages/vscode-extension/src/VsCodeKieEditorChannelApiProducer.ts:34-53`). 
Because this class extends `DefaultVsCodeKieEditorChannelApiImpl`, you can drop 
the explicit constructor entirely and let TypeScript infer the parent's 
signature, or import the proper types (`VsCodeKieEditorController`, 
`ResourceContentService`, `VsCodeWorkspaceChannelApiImpl`, 
`VsCodeNotificationsChannelApiImpl`, `JavaCodeCompletionApi`, 
`I18n<VsCodeI18n>`).



##########
packages/online-editor/src/editor/EditorPage.tsx:
##########
@@ -91,8 +95,14 @@ export function EditorPage() {
   const [_, setEditorPageError] = useState(false);
   const lastContent = useRef<string>();
   const workspaceFilePromise = useWorkspaceFilePromise(workspaceId, 
fileRelativePath);
+  const [isReady, setReady] = useState(false);

Review Comment:
   `isReady` is lifted to parent state but is never reset to `false` when the 
active file changes. `<EmbeddedEditor key={uniqueFileId} ...>` remounts on file 
switch, but the parent's `isReady` stays `true` from the previous file, so 
`EmbeddedEditor` reports `isReady: true` (via `props.isReady ?? isReady`) 
before the newly mounted editor has actually signaled `kogitoEditor_ready`. 
Consumers relying on `isReady` will act on a stale value. Consider resetting 
`setReady(false)` in an effect keyed on `uniqueFileId`/`embeddedEditorFile`, or 
only resolve `kogitoEditor_ready` after a corresponding reset on file change.



##########
packages/bpmn-editor-envelope/src/BpmnEditorChannelApi.ts:
##########
@@ -19,4 +19,22 @@
 
 import { KogitoEditorChannelApi } from "@kie-tools-core/editor/dist/api";
 
-export interface BpmnEditorChannelApi extends KogitoEditorChannelApi {}
+export interface RestTaskTestRequest {
+  url: string;
+  method: string;
+  headers: Record<string, string>;
+  body?: string;
+  useCorsProxy: boolean;
+}
+
+export interface RestTaskTestResponse {
+  status: number;
+  data: string;
+  headers?: Record<string, string>;
+}
+
+export interface BpmnServiceApi extends KogitoEditorChannelApi {
+  bpmnEditor_restTaskTest?(request: RestTaskTestRequest): 
Promise<RestTaskTestResponse>;
+}
+
+export interface BpmnEditorChannelApi extends KogitoEditorChannelApi, 
BpmnServiceApi {}

Review Comment:
   `BpmnServiceApi` already extends `KogitoEditorChannelApi`, so 
`BpmnEditorChannelApi extends KogitoEditorChannelApi, BpmnServiceApi` is 
redundant (`BpmnEditorChannelApi` is structurally identical to 
`BpmnServiceApi`). Either drop `BpmnServiceApi` and put 
`bpmnEditor_restTaskTest` directly on `BpmnEditorChannelApi`, or have 
`BpmnServiceApi` not extend `KogitoEditorChannelApi` and keep the composition 
on `BpmnEditorChannelApi` only.



##########
packages/online-editor/src/editor/EditorPage.tsx:
##########
@@ -327,11 +337,90 @@ export function EditorPage() {
     [workspaceFilePromise, workspaces, navigate, routes]
   );
 
+  const handleRestTaskTest = useCallback(
+    async (request: {
+      url: string;
+      method: string;
+      headers: Record<string, string>;
+      body?: string;
+      useCorsProxy: boolean;
+    }): Promise<{ status: number; data: string; headers?: Record<string, 
string> }> => {
+      try {
+        const targetUrl =
+          request.useCorsProxy && env.KIE_SANDBOX_CORS_PROXY_URL
+            ? 
`${env.KIE_SANDBOX_CORS_PROXY_URL}/${request.url.replace(/^https?:\/\//, "")}`
+            : request.url;
+
+        const response = await fetch(targetUrl, {
+          method: request.method,
+          headers: request.headers,
+          body: request.body,
+        });
+
+        const contentType = response.headers.get("content-type");
+        let data: any;
+
+        if (contentType?.includes("application/json")) {
+          data = await response.json();
+        } else {
+          data = await response.text();
+        }
+
+        const responseHeaders: Record<string, string> = {};
+        response.headers.forEach((value, key) => {
+          responseHeaders[key] = value;
+        });
+
+        return {
+          status: response.status,
+          data,
+          headers: responseHeaders,
+        };
+      } catch (error) {
+        console.error("REST task test request failed:", error);
+        throw error;
+      }
+    },
+    [env.KIE_SANDBOX_CORS_PROXY_URL]
+  );
+
   const handleSetContentError = useCallback(() => {
     setFileBroken(true);
     setContentErrorAlert.show();
   }, [setContentErrorAlert]);
 
+  const kieSandboxEditorChannelApiImpl = useMemo<BpmnEditorChannelApi | 
undefined>(() => {
+    if (!embeddedEditorFile) {
+      return undefined;
+    }
+    const defaultApi = new EmbeddedEditorChannelApiImpl(stateControl, 
embeddedEditorFile, locale, {});
+    return {
+      kogitoWorkspace_newEdit: (...args) => 
defaultApi.kogitoWorkspace_newEdit(...args),
+      kogitoEditor_stateControlCommandUpdate: (...args) => 
defaultApi.kogitoEditor_stateControlCommandUpdate(...args),
+      kogitoEditor_contentRequest: (...args) => 
defaultApi.kogitoEditor_contentRequest(...args),
+      kogitoWorkspace_resourceContentRequest: handleResourceContentRequest,
+      kogitoWorkspace_resourceListRequest: handleResourceListRequest,
+      kogitoWorkspace_openFile: handleOpenFile,
+      kogitoEditor_ready: () => setReady(true),
+      kogitoEditor_setContentError: handleSetContentError,
+      kogitoEditor_theme: (...args) => defaultApi.kogitoEditor_theme(...args),
+      kogitoI18n_getLocale: (...args) => 
defaultApi.kogitoI18n_getLocale(...args),
+      kogitoNotifications_createNotification: (...args) => 
defaultApi.kogitoNotifications_createNotification(...args),
+      kogitoNotifications_setNotifications: (...args) => 
defaultApi.kogitoNotifications_setNotifications(...args),
+      kogitoNotifications_removeNotifications: (...args) => 
defaultApi.kogitoNotifications_removeNotifications(...args),
+      bpmnEditor_restTaskTest: handleRestTaskTest,
+    };
+  }, [
+    embeddedEditorFile,
+    stateControl,
+    locale,
+    handleResourceContentRequest,
+    handleResourceListRequest,
+    handleOpenFile,
+    handleSetContentError,
+    handleRestTaskTest,
+  ]);

Review Comment:
   When the active file changes, `kieSandboxEditorChannelApiImpl` is rebuilt 
and a new `EmbeddedEditorChannelApiImpl` is constructed inside `useMemo`. The 
dependency list contains `stateControl`, `locale` and the various handlers, but 
the `defaultApi` instance captures `embeddedEditorFile` (via `getFileContents`) 
only at construction time. Any change to `embeddedEditorFile` that does not 
also change its identity (e.g. an updated `getFileContents` closure on the same 
object) will leave the `EmbeddedEditorChannelApiImpl` referencing stale file 
content for `kogitoEditor_contentRequest`. Consider adding 
`embeddedEditorFile.getFileContents` (or the whole `embeddedEditorFile`) 
explicitly so this stays consistent with how `EmbeddedEditor` itself rebuilds 
its default channel.



##########
packages/bpmn-editor-envelope/src/customTasks/RestServiceTaskConstants.tsx:
##########
@@ -0,0 +1,104 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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
+ *
+ *  http://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.
+ */
+
+import * as React from "react";
+import { DEFAULT_DATA_TYPES } from 
"@kie-tools/bpmn-editor/dist/mutations/addOrGetItemDefinitions";
+
+export enum RestProperties {
+  Method = "Method",
+  Url = "Url",
+  Protocol = "Protocol",
+  Host = "Host",
+  Port = "Port",
+  ContentData = "ContentData",
+  RequestTimeout = "RequestTimeout",
+  AccessTokenAcquisitionStrategy = "AccessTokenAcquisitionStrategy",
+  RestServiceCallTaskId = "RestServiceCallTaskId",
+}
+
+export enum HttpMethod {
+  GET = "GET",
+  POST = "POST",
+  PUT = "PUT",
+  PATCH = "PATCH",
+  DELETE = "DELETE",
+}
+
+export enum AuthStrategy {
+  PROPAGATED = "propagated",
+  CONFIGURED = "configured",
+  NONE = "none",
+}
+
+export const HTTP_METHODS_OPTIONS = [
+  { value: HttpMethod.GET, labelKey: "httpMethodGet" },
+  { value: HttpMethod.POST, labelKey: "httpMethodPost" },
+  { value: HttpMethod.PUT, labelKey: "httpMethodPut" },
+  { value: HttpMethod.PATCH, labelKey: "httpMethodPatch" },
+  { value: HttpMethod.DELETE, labelKey: "httpMethodDelete" },
+] as const;
+
+export const AUTH_STRATEGIES_OPTIONS = [
+  { value: AuthStrategy.PROPAGATED, labelKey: "authStrategyPropagated" },
+  { value: AuthStrategy.CONFIGURED, labelKey: "authStrategyConfigured" },
+  { value: AuthStrategy.NONE, labelKey: "authStrategyNone" },
+] as const;
+
+export const REST_PROPERTIES_KEYS = [
+  RestProperties.Method,
+  RestProperties.Url,
+  RestProperties.Protocol,
+  RestProperties.Host,
+  RestProperties.Port,
+  RestProperties.ContentData,
+  RestProperties.RequestTimeout,
+  RestProperties.AccessTokenAcquisitionStrategy,
+  RestProperties.RestServiceCallTaskId,
+] as const;
+
+export const REST_TASK_ICON = (
+  <svg
+    width="30"
+    height="30"
+    viewBox="0 0 30 30"
+    xmlns="http://www.w3.org/2000/svg";
+    fill="none"
+    stroke="black"
+    strokeWidth="1"
+  >
+    <text x="15" y="25" textAnchor="middle" fontSize="24" fontFamily="Arial" 
fontWeight={"light"}>
+      🌐
+    </text>
+  </svg>
+);

Review Comment:
   The REST task icon is a Unicode emoji (🌐) inside an SVG `<text>` element. 
Emoji glyphs render very differently across operating systems and Monaco-style 
sandboxes, and may not appear at all if the system font lacks an emoji glyph, 
leading to an empty task icon. Other built-in tasks (e.g. `MilestoneTask`) ship 
with a proper vector icon — consider using a real SVG path/icon or a PatternFly 
icon to ensure consistent rendering in VS Code, online editor, and standalone.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to