diff --git a/frontend/src/components/CodeBoxWithCopy.tsx b/frontend/src/components/CodeBoxWithCopy.tsx new file mode 100644 index 000000000..770160beb --- /dev/null +++ b/frontend/src/components/CodeBoxWithCopy.tsx @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2026, WSO2 LLC. (https://www.wso2.com). + * + * WSO2 LLC. 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 React, { useState, useRef, useEffect } from 'react'; +import { Box, IconButton } from '@wso2/oxygen-ui'; +import { Check, Copy } from '@wso2/oxygen-ui-icons-react'; + +interface CodeBoxWithCopyProps { + code: string; +} + +const CodeBoxWithCopy: React.FC = ({ code }) => { + const [copied, setCopied] = useState(false); + const copyTimeoutRef = useRef | null>(null); + + const handleCopy = async () => { + if (copyTimeoutRef.current) { + clearTimeout(copyTimeoutRef.current); + } + try { + await navigator.clipboard.writeText(code); + setCopied(true); + copyTimeoutRef.current = setTimeout(() => setCopied(false), 2000); + } catch (err) { + // Optionally, show a fallback UI or error message + // For now, just log the error + console.error('Failed to copy to clipboard:', err); + } + }; + + useEffect(() => { + return () => { + if (copyTimeoutRef.current) { + clearTimeout(copyTimeoutRef.current); + } + }; + }, []); + return ( + + + {code} + + + {copied ? : } + + + ); +}; + +export default CodeBoxWithCopy; diff --git a/frontend/src/pages/OrgRuntimes.tsx b/frontend/src/pages/OrgRuntimes.tsx index 91abd96cb..cb835bab7 100644 --- a/frontend/src/pages/OrgRuntimes.tsx +++ b/frontend/src/pages/OrgRuntimes.tsx @@ -41,10 +41,12 @@ import { Tabs, Typography, } from '@wso2/oxygen-ui'; -import { Check, Copy, FileText, Key, Plus, RefreshCw, Server, Trash2, X } from '@wso2/oxygen-ui-icons-react'; -import { useCallback, useEffect, useState, type JSX } from 'react'; -import { useQueries } from '@tanstack/react-query'; +import { FileText, Key, Plus, RefreshCw, Server, Trash2, X } from '@wso2/oxygen-ui-icons-react'; +import CodeBoxWithCopy from '../components/CodeBoxWithCopy'; +import { useState, useEffect, useCallback } from 'react'; import { useLocation, useNavigate } from 'react-router'; +import type { JSX } from 'react'; +import { useQueries } from '@tanstack/react-query'; import { gql } from '../api/graphql'; import { useAllEnvironments, useOrgSecrets, ORG_RUNTIMES_QUERY, type GqlEnvironment, type GqlRuntime } from '../api/queries'; import { useCreateOrgSecret, useDeleteRuntime, useRevokeOrgSecret } from '../api/mutations'; @@ -153,7 +155,7 @@ project = "" integration = "" runtime = "" secret = "${secret}" -# icp_url = "https://:9445"`; +#icp_url = "https://:9445"`; } function biToml(envName: string, secret: string): string { @@ -163,14 +165,13 @@ project = "" integration = "" runtime = "" secret = "${secret}" -# serverUrl="https://:9445"`; +#serverUrl="https://:9445"`; } function AddRuntimeModal({ env, onClose }: { env: GqlEnvironment; onClose: () => void }) { const createMutation = useCreateOrgSecret(); const [secret, setSecret] = useState(null); const [tab, setTab] = useState(0); - const [copied, setCopied] = useState(false); const [error, setError] = useState(null); const handleGenerate = () => { @@ -186,13 +187,6 @@ function AddRuntimeModal({ env, onClose }: { env: GqlEnvironment; onClose: () => const config = secret ? (tab === 0 ? biToml(env.handler, secret) : miToml(env.handler, secret)) : null; - const handleCopy = async () => { - if (!config) return; - await navigator.clipboard.writeText(config); - setCopied(true); - setTimeout(() => setCopied(false), 2000); - }; - return ( Add Runtime: {env.name} environment @@ -224,27 +218,25 @@ function AddRuntimeModal({ env, onClose }: { env: GqlEnvironment; onClose: () => - Add the following configuration to your runtime's {tab === 0 ? 'Config.toml' : 'deployment.toml'} file: + Add the following configuration to your runtime's {tab === 0 ? 'Config.toml' : 'deployment.toml'} file. Change the project, integration and runtime values as needed. The runtime value must be unique for each + runtime you register. - - - {config} - - - {copied ? : } - - + {config && } + {tab === 0 && ( + <> + + Add the following configuration to your runtime's Ballerina.toml file: + + + + Import wso2/icp.runtime.bridge to your runtime's main.bal file: + + + + The above configuration is for runtimes using the BI integration. If you're using the MI integration, switch to the MI tab to see the correct configuration. + + + )} )} diff --git a/frontend/src/pages/Runtime.tsx b/frontend/src/pages/Runtime.tsx index 90cefc01e..ecd6caa97 100644 --- a/frontend/src/pages/Runtime.tsx +++ b/frontend/src/pages/Runtime.tsx @@ -41,7 +41,8 @@ import { TablePagination, Typography, } from '@wso2/oxygen-ui'; -import { Check, Copy, FileText, Key, Plus, RefreshCw, Trash2, X } from '@wso2/oxygen-ui-icons-react'; +import { FileText, Key, Plus, RefreshCw, Trash2, X } from '@wso2/oxygen-ui-icons-react'; +import CodeBoxWithCopy from '../components/CodeBoxWithCopy'; import SearchField from '../components/SearchField'; import { LogFilesDrawer } from '../components/LogFilesDrawer'; import { useCallback, useEffect, useState, type JSX } from 'react'; @@ -110,7 +111,6 @@ function AddRuntimeModal({ const createMutation = useCreateOrgSecret(); const queryClient = useQueryClient(); const [secret, setSecret] = useState(null); - const [copied, setCopied] = useState(false); const [error, setError] = useState(null); const isBI = componentType === 'BI'; @@ -132,13 +132,6 @@ function AddRuntimeModal({ const config = secret ? (isBI ? biToml(environmentName, secret, projectHandle, integrationHandle) : miToml(environmentName, secret, projectHandle, integrationHandle)) : null; - const handleCopy = async () => { - if (!config) return; - await navigator.clipboard.writeText(config); - setCopied(true); - setTimeout(() => setCopied(false), 2000); - }; - const handleDialogClose = (_event: unknown, reason: string) => { if (createMutation.isPending && (reason === 'backdropClick' || reason === 'escapeKeyDown')) return; onClose(); @@ -171,27 +164,21 @@ function AddRuntimeModal({ Copy this secret now. It will not be shown again. - Add the following configuration to your runtime's {isBI ? 'Config.toml' : 'deployment.toml'} file: + Add the following configuration to your runtime's {isBI ? 'Config.toml' : 'deployment.toml'} file. Change the runtime value; it must be unique for each registered runtime. - - - {config} - - - {copied ? : } - - + {config && } + {isBI && ( + <> + + Add the following configuration to your runtime's Ballerina.toml file: + + + + Import wso2/icp.runtime.bridge to your runtime's main.bal file: + + + + )} )}