Skip to content

Conversation

@matarpeles
Copy link
Member

@matarpeles matarpeles commented Nov 2, 2025

User description

Description

Please include a summary of the change and which issue is fixed. Please also include relevant motivation and context.

Added docs pages

Please also include the path for the added docs

  • Quickstart (/)
  • Blueprint (/platform-overview/port-components/blueprint)
  • ...

Updated docs pages

Please also include the path for the updated docs

  • Quickstart (/)
  • Blueprint (/platform-overview/port-components/blueprint)
  • ...

PR Type

Enhancement, Documentation


Description

  • Introduces comprehensive Ocean Custom integration feature with 13+ new React components for building custom API integrations

  • Implements interactive 3-step integration builder workflow: API configuration, data mapping, and installation

  • Adds IntegrationBuilder component that generates Docker and Helm deployment commands with environment variables

  • Provides MultiEndpointConfigurator for managing multiple API endpoints with CRUD operations and YAML generation

  • Includes BlueprintGenerator for auto-generating Port blueprints from sample API response JSON

  • Adds EndpointTester component for testing API endpoints and automatic data path detection

  • Implements IntegrationBuilderContext for centralized state management across all builder steps

  • Adds 940 lines of comprehensive CSS styling for Ocean Custom UI components with responsive design

  • Provides complete documentation with interactive guide for building Ocean Custom integrations

  • Reorganizes documentation hierarchy by adjusting section positions

  • Adds pluralize library dependency for auto-generating blueprint IDs from endpoint paths


Diagram Walkthrough

flowchart LR
  A["API Configuration<br/>Step1ApiConfig"] --> B["Data Mapping<br/>Step2DataMapping"]
  B --> C["Installation<br/>Step3Installation"]
  A --> D["IntegrationBuilder<br/>Context"]
  B --> D
  C --> D
  E["EndpointTester"] --> F["BlueprintGenerator"]
  F --> G["ConfigGenerator"]
  G --> H["MultiEndpointConfigurator"]
  I["Documentation<br/>overview.md"] --> J["Interactive Guide<br/>build-your-integration.md"]
  A -.-> I
  B -.-> I
  C -.-> I
Loading

File Walkthrough

Relevant files
Enhancement
15 files
index.js
New Ocean Custom integration component exports                     

src/components/OceanCustom/index.js

  • Exports 13 new React components for Ocean Custom integration
  • Includes builders, configurators, and installers for API integration
    setup
  • Provides modular exports for IntegrationBuilder, EndpointConfigurator,
    and related utilities
+13/-0   
styles.module.css
Complete styling for Ocean Custom integration UI components

src/components/OceanCustom/styles.module.css

  • Adds 940 lines of comprehensive CSS styling for Ocean Custom
    components
  • Covers form inputs, buttons, JSON tree visualization, and endpoint
    configuration UI
  • Includes responsive design with media queries for mobile devices
  • Styles for blueprints, mappings, installation sections, and
    multi-endpoint configurator
+940/-0 
IntegrationBuilder.jsx
Interactive integration builder with deployment generation

src/components/OceanCustom/IntegrationBuilder.jsx

  • Implements 623-line interactive integration builder component
  • Provides 3-step workflow: API configuration, endpoint selection, and
    installation
  • Generates Docker and Helm deployment commands with environment
    variables
  • Creates blueprint JSON and mapping configurations from API responses
+623/-0 
MultiEndpointConfigurator.jsx
Multi-endpoint configuration manager with CRUD operations

src/components/OceanCustom/MultiEndpointConfigurator.jsx

  • Implements 446-line component for managing multiple API endpoints
  • Supports CRUD operations (create, edit, delete) for endpoint
    configurations
  • Generates combined YAML mapping for all configured endpoints
  • Provides JSON tree visualization for data path selection
+446/-0 
Step3Installation.jsx
Installation step with deployment command generation         

src/components/OceanCustom/Step3Installation.jsx

  • Implements 299-line installation step component with context
    integration
  • Generates Helm and Docker deployment commands with advanced
    configuration options
  • Supports pagination, authentication, timeout, and SSL verification
    settings
  • Displays placeholder when prerequisites are not met
+299/-0 
Step2DataMapping.jsx
Data mapping step with auto-generation and field selection

src/components/OceanCustom/Step2DataMapping.jsx

  • Implements 341-line data mapping step with auto-generation features
  • Auto-generates blueprint ID and title from endpoint paths using
    pluralize library
  • Auto-detects first array in JSON responses for data path selection
  • Provides field selection and mapping configuration with ID/Title role
    buttons
+341/-0 
EndpointConfigurator.jsx
Standalone endpoint configurator with output generation   

src/components/OceanCustom/EndpointConfigurator.jsx

  • Implements 337-line standalone endpoint configuration component
  • Provides JSON tree visualization for selecting data paths
  • Generates blueprint JSON and mapping YAML configurations
  • Includes copy-to-clipboard functionality for generated outputs
+337/-0 
ApiConfigBuilder.jsx
API configuration builder with environment variable generation

src/components/OceanCustom/ApiConfigBuilder.jsx

  • Implements 210-line API configuration builder component
  • Generates environment variables for authentication and pagination
    settings
  • Supports bearer token, API key, basic auth, and no-auth options
  • Provides copy-to-clipboard functionality for generated configuration
+210/-0 
Step1ApiConfig.jsx
API Configuration Step Component for Integration Builder 

src/components/OceanCustom/Step1ApiConfig.jsx

  • New React component for configuring API connection settings (base URL,
    authentication types, pagination options)
  • Implements form inputs for bearer token, API key, basic auth, and
    advanced settings like timeouts and SSL verification
  • Uses useIntegrationBuilder hook to manage and persist configuration
    state across the integration builder workflow
  • Provides conditional rendering of authentication fields based on
    selected auth type
+232/-0 
ConfigGenerator.jsx
Configuration Generator Component for YAML Output               

src/components/OceanCustom/ConfigGenerator.jsx

  • New React component that generates YAML configuration for Ocean Custom
    integration based on endpoint and mapping inputs
  • Allows users to define endpoint paths, data paths, blueprint IDs, and
    property mappings between Port and API fields
  • Provides dynamic property management (add/remove) and generates
    formatted YAML output with copy-to-clipboard functionality
  • Converts form inputs into Port-compatible configuration structure with
    JQ expressions for field mapping
+189/-0 
IntegrationInstaller.jsx
Integration Installer Configuration Review Component         

src/components/OceanCustom/IntegrationInstaller.jsx

  • New React component for collecting and summarizing API configuration
    before installation
  • Displays configuration summary including base URL, authentication
    type, and pagination settings
  • Provides form inputs for basic API setup with visual feedback of
    current configuration state
  • Serves as a review step before final installation commands are
    generated
+126/-0 
BlueprintGenerator.jsx
Blueprint Auto-Generator from Sample API Data                       

src/components/OceanCustom/BlueprintGenerator.jsx

  • New React component that auto-generates Port blueprints from sample
    API response JSON
  • Parses JSON sample data to detect field types (string, number,
    boolean) and special formats (email, date-time, URL)
  • Allows users to select which fields to include in the blueprint and
    generates JSON blueprint definition
  • Provides copy-to-clipboard functionality and link to Port Builder for
    blueprint creation
+158/-0 
EndpointTester.jsx
Endpoint Testing and Data Path Detection Component             

src/components/OceanCustom/EndpointTester.jsx

  • New React component for testing API endpoints and inspecting response
    structure
  • Includes mock response simulation and automatic data_path detection
    from API responses
  • Detects common data paths (data, items, results, users, tickets) and
    suggests appropriate path configuration
  • Provides visual feedback on response structure to help users configure
    data extraction
+127/-0 
IntegrationBuilderContext.jsx
Shared State Management Context for Integration Builder   

src/components/OceanCustom/IntegrationBuilderContext.jsx

  • New React Context provider for managing state across all integration
    builder steps
  • Centralizes state management for API configuration (auth, pagination,
    timeouts) and endpoint mapping (blueprint, fields, identifiers)
  • Provides useIntegrationBuilder hook for accessing and updating shared
    state throughout the builder workflow
  • Initializes default values for all configuration options including
    sample endpoint and response data
+103/-0 
IntegrationBuilderSteps.jsx
Integration Builder Steps Wrapper Component                           

src/components/OceanCustom/IntegrationBuilderSteps.jsx

  • New React component that wraps and exports the three integration
    builder steps with shared context provider
  • Serves as the main entry point for the complete integration builder
    workflow
  • Combines Step1ApiConfig, Step2DataMapping, and Step3Installation
    components within IntegrationBuilderProvider
+17/-0   
Documentation
2 files
overview.md
Complete Ocean Custom integration documentation and guide

docs/build-your-software-catalog/custom-integration/ocean-custom-integration/overview.md

  • Adds 338-line comprehensive documentation for Ocean Custom integration
  • Covers prerequisites, authentication types, data structure handling,
    and setup workflow
  • Includes advanced configuration examples for nested endpoints,
    pagination, and rate limiting
  • Provides real-world examples and Helm installation commands
+338/-0 
build-your-integration.md
Interactive Build Guide Documentation for Ocean Custom     

docs/build-your-software-catalog/custom-integration/ocean-custom-integration/build-your-integration.md

  • New documentation page providing interactive guide for building Ocean
    Custom integrations
  • Includes three-step workflow: API configuration, data mapping, and
    installation
  • Embeds interactive React components (Step1ApiConfig, Step2DataMapping,
    Step3Installation) for hands-on configuration
  • Provides context and explanations for each step with links to Port
    credentials settings
+73/-0   
Dependencies
1 files
package.json
Add Pluralize Utility Library Dependency                                 

package.json

  • Added pluralize dependency version ^8.0.0 to project dependencies
+1/-0     
Configuration changes
2 files
_category_.json
Documentation Category Configuration for Ocean Custom       

docs/build-your-software-catalog/custom-integration/ocean-custom-integration/category.json

  • New category configuration file for Ocean Custom Integration
    documentation section
  • Sets position to 1, enables collapsible navigation, and generates
    index page
  • Organizes documentation hierarchy for the Ocean Custom Integration
    feature
+19/-0   
_category_.json
Adjust API Documentation Section Position                               

docs/build-your-software-catalog/custom-integration/api/category.json

  • Updated position value from 1 to 2 to adjust documentation navigation
    order
  • Allows Ocean Custom Integration section to appear before API section
    in documentation hierarchy
+1/-1     

- Created new Generic HTTP integration docs section (position 1 in custom integrations)
- Added Overview page explaining when to use, how it works, and advanced configurations
- Built interactive 'Build Your Integration' guide with 3 steps:
  - Step 1: Configure API (base URL, auth, pagination, advanced settings)
  - Step 2: Choose data to sync (endpoint, response, field mapping, blueprint config)
  - Step 3: Install and create in Port (dynamic Helm/Docker commands, blueprint JSON, mapping YAML)
- Implemented React components with shared context for seamless state management
- Labeled as 'Generic HTTP (New ⭐)' in sidebar to highlight new feature
- Updated API integration position to 2
- Add JQ reference link in prerequisites
- Add two-step setup link in overview
- Add descriptive text before each interactive step
- Fix field deselection (toggle ID/Title buttons)
- Auto-select first array in JSON response
- Auto-generate blueprint ID and title with singularization
- Update form hints with explicit defaults
- Simplify configuration explanations
- Remove redundant copy buttons
- Fix mapping generation (query and blueprint quoting)
- Fix authentication config (use apiToken/apiKey/username+password)
- Fix image versioning (use integration.version instead of image.tag)
- Update to version 0.1.5-dev
- Add pluralize dependency for accurate singularization
- Rename directory: ocean-http/ → ocean-custom-integration/
- Rename React components: GenericHttp/ → OceanCustom/
- Update category label to 'Ocean Custom Integration'
- Update all text references from 'Generic HTTP' to 'Ocean Custom'
- Update integration type: generic-http → custom
- Update integration identifier: generic-http → ocean-custom
- Update Docker image: port-ocean-generic-http → port-ocean-custom
- Update GitHub repo links: /integrations/generic-http → /integrations/custom
- Use :latest tag for Docker, remove version from Helm (auto-handled by chart)
@qodo-merge-pro
Copy link

qodo-merge-pro bot commented Nov 2, 2025

PR Compliance Guide 🔍

(Compliance updated until commit 526fab8)

Below is a summary of compliance checks for this PR:

Security Compliance
Sensitive information exposure

Description: The "Create in Port" link embeds full blueprint JSON in a query parameter, which could
expose sensitive blueprint names/fields in browser history and logs; consider POST-based
creation or minimizing sensitive data in URLs.
IntegrationBuilder.jsx [560-605]

Referred Code
<Tabs groupId="deploy" queryString="deploy">
  <TabItem value="docker" label="Docker" default>
    <div className={styles.codeWrapper}>
      <button onClick={() => copyToClipboard(generateDockerCommand())} className={styles.copyBtn}>
        Copy to clipboard
      </button>
      <CodeBlock language="bash" showLineNumbers>
        {generateDockerCommand()}
      </CodeBlock>
    </div>
  </TabItem>

  <TabItem value="helm" label="Helm">
    <p>Create a <code>values.yaml</code> file:</p>
    <div className={styles.codeWrapper}>
      <button onClick={() => copyToClipboard(generateHelmValues())} className={styles.copyBtn}>
        Copy to clipboard
      </button>
      <CodeBlock language="yaml" showLineNumbers title="values.yaml">
        {generateHelmValues()}
      </CodeBlock>


 ... (clipped 25 lines)
Clipboard misuse

Description: Clipboard write operations occur without feature detection or user feedback; while not a
direct vulnerability, browsers may reject it and a malicious site context could trigger it
if embedded—ensure user gesture gating and error handling.
IntegrationBuilder.jsx [264-266]

Referred Code
const copyToClipboard = (text) => {
  navigator.clipboard.writeText(text);
};
Secrets in commands

Description: Generated Docker/Helm commands include secrets inline which encourages insecure
operational practices if copied to shared channels or stored in shell history; prefer
referencing environment variables or secret stores.
Step3Installation.jsx [271-280]

Referred Code
  <CodeBlock language="bash" showLineNumbers>
    {generateHelmCommand()}
  </CodeBlock>
</TabItem>

<TabItem value="docker" label="Docker">
  <CodeBlock language="bash" showLineNumbers>
    {generateDockerCommand()}
  </CodeBlock>
</TabItem>
Ticket Compliance
🎫 No ticket provided
  • Create ticket/issue
Codebase Duplication Compliance
Codebase context is not defined

Follow the guide to enable codebase context checks.

Custom Compliance
🟢
Generic: Meaningful Naming and Self-Documenting Code

Objective: Ensure all identifiers clearly express their purpose and intent, making code
self-documenting

Status: Passed

Generic: Secure Error Handling

Objective: To prevent the leakage of sensitive system information through error messages while
providing sufficient detail for internal debugging.

Status: Passed

Generic: Secure Logging Practices

Objective: To ensure logs are useful for debugging and auditing without exposing sensitive
information like PII, PHI, or cardholder data.

Status: Passed

Generic: Comprehensive Audit Trails

Objective: To create a detailed and reliable record of critical system actions for security analysis
and compliance.

Status:
No audit logs: New UI flows generate install commands and mappings without emitting any audit or trace
logs for critical actions like copying commands or creating blueprints.

Referred Code
<h3>Install the Integration</h3>
<Tabs groupId="deploy" queryString="deploy">
  <TabItem value="docker" label="Docker" default>
    <div className={styles.codeWrapper}>
      <button onClick={() => copyToClipboard(generateDockerCommand())} className={styles.copyBtn}>
        Copy to clipboard
      </button>
      <CodeBlock language="bash" showLineNumbers>
        {generateDockerCommand()}
      </CodeBlock>
    </div>
  </TabItem>

  <TabItem value="helm" label="Helm">
    <p>Create a <code>values.yaml</code> file:</p>
    <div className={styles.codeWrapper}>
      <button onClick={() => copyToClipboard(generateHelmValues())} className={styles.copyBtn}>
        Copy to clipboard
      </button>
      <CodeBlock language="yaml" showLineNumbers title="values.yaml">
        {generateHelmValues()}


 ... (clipped 37 lines)
Generic: Robust Error Handling and Edge Case Management

Objective: Ensure comprehensive error handling that provides meaningful context and graceful
degradation

Status:
Silent JSON parse: JSON parsing failures are swallowed without user-facing guidance beyond a generic
"Invalid JSON" and no logging, potentially hiding actionable context.

Referred Code
<div className={styles.step}>
  <h3>Select Data Path</h3>
  <p className={styles.hint}>Click the array containing your data:</p>
  <div className={styles.jsonTreeContainer}>
    {(() => {
      try {
        const json = JSON.parse(responseJson);
        if (Array.isArray(json)) {
          return (
            <div 
              className={`${styles.jsonTreeNode} ${dataPath === '' ? styles.selected : ''}`}
              onClick={() => setDataPath('')}
              style={{ cursor: 'pointer' }}
            >
              <span className={styles.jsonKey}>Array (root level)</span>
              <span className={styles.arrayBadge}>{json.length} items</span>
              {dataPath === '' && <span className={styles.selectedBadge}>✓ Selected</span>}
            </div>
          );
        }
        return renderJsonTree(json);


 ... (clipped 4 lines)
Generic: Security-First Input Validation and Data Handling

Objective: Ensure all data inputs are validated, sanitized, and handled securely to prevent
vulnerabilities

Status:
Secret exposure risk: The UI binds and renders secrets like API tokens and passwords into generated
commands/values without masking, risking user copy-paste exposure if real values are
entered.

Referred Code
  envVars.push(`  -e OCEAN__INTEGRATION__CONFIG__AUTH_TYPE="bearer_token"`);
  envVars.push(`  -e OCEAN__INTEGRATION__CONFIG__AUTH_VALUE="${apiToken || '<YOUR_API_TOKEN>'}"`);
} else if (authType === 'api_key') {
  envVars.push(`  -e OCEAN__INTEGRATION__CONFIG__AUTH_TYPE="api_key"`);
  envVars.push(`  -e OCEAN__INTEGRATION__CONFIG__AUTH_VALUE="${apiKey || '<YOUR_API_KEY>'}"`);
  if (apiKeyHeader !== 'X-API-Key') {
    envVars.push(`  -e OCEAN__INTEGRATION__CONFIG__API_KEY_HEADER="${apiKeyHeader}"`);
  }
} else if (authType === 'basic') {
  envVars.push(`  -e OCEAN__INTEGRATION__CONFIG__AUTH_TYPE="basic"`);
  envVars.push(`  -e OCEAN__INTEGRATION__CONFIG__AUTH_VALUE="${username || '<USERNAME>'}:${password || '<PASSWORD>'}"`);
} else {
  envVars.push(`  -e OCEAN__INTEGRATION__CONFIG__AUTH_TYPE="none"`);
}

if (paginationType !== 'none') {
  envVars.push(`  -e OCEAN__INTEGRATION__CONFIG__PAGINATION_TYPE="${paginationType}"`);
  envVars.push(`  -e OCEAN__INTEGRATION__CONFIG__PAGE_SIZE="${pageSize}"`);

  if (paginationParam) envVars.push(`  -e OCEAN__INTEGRATION__CONFIG__PAGINATION_PARAM="${paginationParam}"`);
  if (sizeParam) envVars.push(`  -e OCEAN__INTEGRATION__CONFIG__SIZE_PARAM="${sizeParam}"`);


 ... (clipped 41 lines)
Compliance status legend 🟢 - Fully Compliant
🟡 - Partial Compliant
🔴 - Not Compliant
⚪ - Requires Further Human Verification
🏷️ - Compliance label

Previous compliance checks

Compliance check up to commit 6b3ec25
Security Compliance
Data exposure via URL

Description: The "Create in Port" link embeds full blueprint JSON in a GET URL query parameter which
may exceed URL length limits and expose potentially sensitive schema data in browser
history and logs.
IntegrationBuilder.jsx [560-606]

Referred Code
<Tabs groupId="deploy" queryString="deploy">
  <TabItem value="docker" label="Docker" default>
    <div className={styles.codeWrapper}>
      <button onClick={() => copyToClipboard(generateDockerCommand())} className={styles.copyBtn}>
        Copy to clipboard
      </button>
      <CodeBlock language="bash" showLineNumbers>
        {generateDockerCommand()}
      </CodeBlock>
    </div>
  </TabItem>

  <TabItem value="helm" label="Helm">
    <p>Create a <code>values.yaml</code> file:</p>
    <div className={styles.codeWrapper}>
      <button onClick={() => copyToClipboard(generateHelmValues())} className={styles.copyBtn}>
        Copy to clipboard
      </button>
      <CodeBlock language="yaml" showLineNumbers title="values.yaml">
        {generateHelmValues()}
      </CodeBlock>


 ... (clipped 26 lines)
Clipboard permission handling

Description: Copy-to-clipboard uses navigator.clipboard without user gesture or permission checks,
which may fail silently and could mislead users about successful copying.
IntegrationBuilder.jsx [264-270]

Referred Code
const copyToClipboard = (text) => {
  navigator.clipboard.writeText(text);
};

const renderJsonTree = (obj, path = '', level = 0) => {
  if (level > 3) return null;
Ticket Compliance
🎫 No ticket provided
  • Create ticket/issue
Codebase Duplication Compliance
Codebase context is not defined

Follow the guide to enable codebase context checks.

Custom Compliance
🟢
Generic: Meaningful Naming and Self-Documenting Code

Objective: Ensure all identifiers clearly express their purpose and intent, making code
self-documenting

Status: Passed

Generic: Secure Error Handling

Objective: To prevent the leakage of sensitive system information through error messages while
providing sufficient detail for internal debugging.

Status: Passed

Generic: Comprehensive Audit Trails

Objective: To create a detailed and reliable record of critical system actions for security analysis
and compliance.

Status:
No audit logs: Newly added components perform actions like copying config, generating commands, and
creating links without emitting any audit/log entries to trace user actions.

Referred Code
  <div className={styles.codeWrapper}>
    <button onClick={() => copyToClipboard(generateDockerCommand())} className={styles.copyBtn}>
      Copy to clipboard
    </button>
    <CodeBlock language="bash" showLineNumbers>
      {generateDockerCommand()}
    </CodeBlock>
  </div>
</TabItem>

<TabItem value="helm" label="Helm">
  <p>Create a <code>values.yaml</code> file:</p>
  <div className={styles.codeWrapper}>
    <button onClick={() => copyToClipboard(generateHelmValues())} className={styles.copyBtn}>
      Copy to clipboard
    </button>
    <CodeBlock language="yaml" showLineNumbers title="values.yaml">
      {generateHelmValues()}
    </CodeBlock>
  </div>
  <p style={{ marginTop: '1rem' }}>Then install:</p>


 ... (clipped 33 lines)
Generic: Robust Error Handling and Edge Case Management

Objective: Ensure comprehensive error handling that provides meaningful context and graceful
degradation

Status:
Weak JSON parsing: JSON parsing and data path traversal swallow errors and return empty arrays, providing no
actionable feedback beyond a generic "Invalid JSON" message and not handling
missing keys or non-array paths robustly.

Referred Code
}

try {
  const json = JSON.parse(responseJson);
  let data = json;

  if (dataPath && dataPath !== '') {
    const path = dataPath.replace(/^\./, '').split('.');
    for (const key of path) {
      data = data[key];
    }
  }

  const sample = Array.isArray(data) ? data[0] : data;

  if (!sample || typeof sample !== 'object') {
    return [];
  }

  return Object.entries(sample).map(([key, value]) => {
    let type = 'string';


 ... (clipped 22 lines)
Generic: Secure Logging Practices

Objective: To ensure logs are useful for debugging and auditing without exposing sensitive
information like PII, PHI, or cardholder data.

Status:
Secrets exposure risk: Generated Docker/Helm commands interpolate potentially real tokens, API keys, usernames,
and passwords into plain text output which users may copy to terminals or commit, posing a
risk if populated with real values.

Referred Code
const envVars = [
  `  -e OCEAN__PORT__CLIENT_ID="<PORT_CLIENT_ID>"`,
  `  -e OCEAN__PORT__CLIENT_SECRET="<PORT_CLIENT_SECRET>"`,
  `  -e OCEAN__PORT__BASE_URL="https://api.getport.io"`,
  `  -e OCEAN__EVENT_LISTENER__TYPE="POLLING"`,
  `  -e OCEAN__INTEGRATION__IDENTIFIER="ocean-custom"`,
  `  -e OCEAN__INTEGRATION__TYPE="custom"`,
  `  -e OCEAN__INTEGRATION__CONFIG__BASE_URL="${baseUrl || 'https://api.example.com'}"`,
];

if (authType === 'bearer_token') {
  envVars.push(`  -e OCEAN__INTEGRATION__CONFIG__AUTH_TYPE="bearer_token"`);
  envVars.push(`  -e OCEAN__INTEGRATION__CONFIG__AUTH_VALUE="${apiToken || '<YOUR_API_TOKEN>'}"`);
} else if (authType === 'api_key') {
  envVars.push(`  -e OCEAN__INTEGRATION__CONFIG__AUTH_TYPE="api_key"`);
  envVars.push(`  -e OCEAN__INTEGRATION__CONFIG__AUTH_VALUE="${apiKey || '<YOUR_API_KEY>'}"`);
  if (apiKeyHeader !== 'X-API-Key') {
    envVars.push(`  -e OCEAN__INTEGRATION__CONFIG__API_KEY_HEADER="${apiKeyHeader}"`);
  }
} else if (authType === 'basic') {
  envVars.push(`  -e OCEAN__INTEGRATION__CONFIG__AUTH_TYPE="basic"`);


 ... (clipped 70 lines)
Generic: Security-First Input Validation and Data Handling

Objective: Ensure all data inputs are validated, sanitized, and handled securely to prevent
vulnerabilities

Status:
Unvalidated input: User-provided JSON and path strings are parsed and traversed without validation or
sanitization, relying on try/catch with minimal feedback and no limits, which may lead to
UI issues or unsafe assumptions in generated configs.

Referred Code
const parseFields = () => {
  if (currentEndpoint.dataPath === null || !currentEndpoint.responseJson) {
    return [];
  }

  try {
    const json = JSON.parse(currentEndpoint.responseJson);
    let data = json;

    if (currentEndpoint.dataPath && currentEndpoint.dataPath !== '') {
      const path = currentEndpoint.dataPath.replace(/^\./, '').split('.');
      for (const key of path) {
        data = data[key];
      }
    }

    const sample = Array.isArray(data) ? data[0] : data;

    if (!sample || typeof sample !== 'object') {
      return [];
    }


 ... (clipped 25 lines)

@qodo-merge-pro
Copy link

qodo-merge-pro bot commented Nov 2, 2025

PR Code Suggestions ✨

Explore these optional code suggestions:

CategorySuggestion                                                                                                                                    Impact
High-level
Re-evaluate embedding this complex application

The PR adds a complex application into the documentation, causing architectural
issues and significant code duplication. It's suggested to reconsider this
approach and potentially move the feature to a separate, standalone tool.

Examples:

src/components/OceanCustom/IntegrationBuilder.jsx [135-262]
  const parseFields = () => {
    if (dataPath === null || !responseJson) {
      return [];
    }

    try {
      const json = JSON.parse(responseJson);
      let data = json;

      if (dataPath && dataPath !== '') {

 ... (clipped 118 lines)
src/components/OceanCustom/MultiEndpointConfigurator.jsx [39-184]
  const parseFields = () => {
    if (currentEndpoint.dataPath === null || !currentEndpoint.responseJson) {
      return [];
    }

    try {
      const json = JSON.parse(currentEndpoint.responseJson);
      let data = json;

      if (currentEndpoint.dataPath && currentEndpoint.dataPath !== '') {

 ... (clipped 136 lines)

Solution Walkthrough:

Before:

// IntegrationBuilder.jsx
function IntegrationBuilder() {
  // ... state management ...
  const parseFields = () => { /* ... logic to parse fields ... */ };
  const generateBlueprint = () => { /* ... logic to generate blueprint ... */ };
  const generateMapping = () => { /* ... logic to generate mapping ... */ };
  // ... render UI ...
}

// MultiEndpointConfigurator.jsx
function MultiEndpointConfigurator() {
  // ... state management ...
  const parseFields = () => { /* ... duplicated logic to parse fields ... */ };
  const generateBlueprint = () => { /* ... duplicated logic to generate blueprint ... */ };
  const generateMapping = () => { /* ... duplicated logic to generate mapping ... */ };
  // ... render UI ...
}

// Other components like Step2DataMapping.jsx, Step3Installation.jsx also have duplicated logic

After:

/* 
 * Suggestion is to move this to a separate standalone tool.
 * If kept, the code should be heavily refactored to remove duplication.
 */

// src/components/OceanCustom/utils.js (new file)
export const parseFields = (responseJson, dataPath) => { /* ... centralized logic ... */ };
export const generateBlueprint = (fields, blueprintId, ...) => { /* ... centralized logic ... */ };
export const generateMapping = (fields, endpoint, ...) => { /* ... centralized logic ... */ };

// IntegrationBuilder.jsx
import { parseFields, generateBlueprint, generateMapping } from './utils';
function IntegrationBuilder() {
  // ... state management ...
  // ... call utility functions instead of implementing logic here ...
}

// MultiEndpointConfigurator.jsx
import { parseFields, generateBlueprint, generateMapping } from './utils';
function MultiEndpointConfigurator() {
  // ... state management ...
  // ... call utility functions instead of implementing logic here ...
}
Suggestion importance[1-10]: 9

__

Why: The suggestion correctly identifies a critical architectural issue, as embedding a complex application within the documentation site leads to significant code duplication and long-term maintenance challenges.

High
Possible bug
Fix incorrect string quoting syntax

Correct the blueprint mapping by removing the redundant single quotes around the
blueprint identifier string to prevent generating invalid YAML.

src/components/OceanCustom/Step3Installation.jsx [238]

-blueprint: `'"${blueprintId || 'myBlueprint'}"'`,
+blueprint: `"${blueprintId || 'myBlueprint'}"`,
  • Apply / Chat
Suggestion importance[1-10]: 8

__

Why: The suggestion correctly identifies a quoting error that would generate invalid YAML, likely causing the integration mapping to fail. Fixing this is critical for the component's functionality.

Medium
Maintainability
Refactor YAML generation for better readability

Refactor the complex YAML template literal into a more readable array-based
construction to improve maintainability.

src/components/OceanCustom/ConfigGenerator.jsx [57-68]

-const yaml = `resources:
-- kind: ${config.resources[0].kind}
-selector:
-  query: 'true'${dataPath ? `\n      data_path: '${dataPath}'` : ''}
-port:
-  entity:
-    mappings:
-      identifier: ${config.resources[0].port.entity.mappings.identifier}
-      title: ${config.resources[0].port.entity.mappings.title}
-      blueprint: ${config.resources[0].port.entity.mappings.blueprint}${Object.keys(propertiesObj).length > 0 ? `\n          properties:` : ''}${
-  Object.entries(propertiesObj).map(([key, value]) => `\n            ${key}: ${value}`).join('')
-}`;
+const configObject = config.resources[0];
+const mappings = configObject.port.entity.mappings;
 
+const propertiesLines = Object.entries(propertiesObj)
+  .map(([key, value]) => `            ${key}: ${value}`);
+
+const yamlLines = [
+  'resources:',
+  `  - kind: ${configObject.kind}`,
+  '    selector:',
+  "      query: 'true'",
+  ...(dataPath ? [`      data_path: '${dataPath}'`] : []),
+  '    port:',
+  '      entity:',
+  '        mappings:',
+  `          identifier: ${mappings.identifier}`,
+  `          title: ${mappings.title}`,
+  `          blueprint: ${mappings.blueprint}`,
+  ...(propertiesLines.length > 0 ? ['          properties:', ...propertiesLines] : []),
+];
+
+const yaml = yamlLines.join('\n');
+
  • Apply / Chat
Suggestion importance[1-10]: 6

__

Why: The suggestion correctly identifies that the YAML generation logic is complex and proposes a much cleaner, more maintainable approach by building an array of lines before joining them into a string.

Low
Organization
best practice
Standardize sentence case headings
Suggestion Impact:The commit updated the title and all listed headings to sentence case exactly as suggested.

code diff:

-title: Build Your Integration
+title: Build your integration
 description: Interactive guide to configure and install your integration
 ---
 
 import PortApiRegionTip from "/docs/generalTemplates/_port_api_available_regions.md"
 import { IntegrationBuilderProvider, Step1ApiConfig, Step2DataMapping, Step3Installation } from '@site/src/components/OceanCustom';
 
-# Build Your Integration
+# Build your integration
 
 This interactive guide will help you generate everything you need to connect your API to Port.
 
@@ -20,7 +20,7 @@
 
 ---
 
-## Step 1: Configure Your API
+## Step 1: Configure your API
 
 Set up the connection details for your API. These settings apply globally to all endpoints you'll sync from this API.
 
@@ -36,7 +36,7 @@
 
 ---
 
-## Step 2: Choose What Data to Sync
+## Step 2: Choose what data to sync
 
 Now that your API connection is configured, let's define what data to sync. This step helps you map a specific API endpoint to a Port blueprint.
 
@@ -53,7 +53,7 @@
 
 ---
 
-## Step 3: Install and Create in Port
+## Step 3: Install and create in Port
 

Use sentence case for titles and headings; also ensure headers are sentence case
across the page.

docs/build-your-software-catalog/custom-integration/ocean-custom-integration/build-your-integration.md [3-58]

-title: Build Your Integration
+title: Build your integration
 
-# Build Your Integration
+# Build your integration
 
-## Step 1: Configure Your API
+## Step 1: Configure your API
 
-## Step 2: Choose What Data to Sync
+## Step 2: Choose what data to sync
 
-## Step 3: Install and Create in Port
+## Step 3: Install and create in Port

[To ensure code accuracy, apply this suggestion manually]

Suggestion importance[1-10]: 6

__

Why:
Relevant best practice - Pattern 11: Add queryString to Tabs components and avoid markdown headers inside tabs; and Pattern 2/8 sentence case for headings.

Low
Fix header and bullets casing
Suggestion Impact:The commit changes multiple headers to sentence case (e.g., "When to use this integration?", "How it works", "Advanced configurations"), aligning with the suggestion. However, the bullet item period changes are not shown in the diff.

code diff:

-## When to Use This Integration?
+## When to use this integration?
 
 This integration is ideal when:
 
@@ -83,11 +83,11 @@
 
 ---
 
-## How It Works
+## How it works
 
 The Ocean Custom integration uses a [**two-step setup**](/build-your-software-catalog/sync-data-to-catalog/) similar to other Ocean integrations you've used:
 
-### Step 1: Installation (Global Configuration)
+### Step 1: Installation (Global configuration)
 
 During installation, you configure the **connection settings** that apply to all API calls:
 
@@ -120,13 +120,13 @@
   --set integration.config.pageSize=100

-### Step 2: Resource Mapping
+### Step 2: Resource mapping

After installation, you define which endpoints to sync in your port-app-config.yml file (or using the integration's configuration in Port).

This is where you map each API endpoint to Port entities - similar to how you've mapped GitHub repositories or Jira issues in other integrations.

-#### 🆕 Endpoint-as-Kind Feature
+#### 🆕 Endpoint-as-kind feature

The kind field is now the endpoint path itself! This provides better visibility in Port's UI, allowing you to:

@@ -134,7 +134,7 @@

  • ✅ Debug mapping issues per endpoint
  • ✅ Monitor data ingestion per API call

-#### Example: Mapping Two Endpoints
+#### Example: Mapping two endpoints

resources:
@@ -178,7 +178,7 @@
            created: .created_date

-#### What Each Field Does
+#### What each field does

  • kind: The API endpoint path (combined with your base URL)
  • selector.query: JQ filter to include/exclude entities (use 'true' to sync all)
    @@ -189,7 +189,7 @@

-## Advanced Configurations
+## Advanced configurations

Once you have the basics working, these features handle more complex scenarios.

@@ -199,7 +199,7 @@

Use case: Get all tickets, then fetch comments for each ticket.

-#### How It Works
+#### How it works

Step 1 - Define parent endpoint:

@@ -245,7 +245,7 @@

For APIs that split data across multiple pages, configure how the integration fetches all pages.

-#### Pagination Types
+#### Pagination types

**Offset-based** (like SQL):

@@ -265,7 +265,7 @@
GET /api/users?cursor=xyz789&limit=100


-#### Custom Parameter Names
+#### Custom parameter names

APIs often use different parameter names. You can configure:

@@ -287,7 +287,7 @@
sizeParam: limit

-#### Cursor Path Configuration
+#### Cursor path configuration

For cursor-based pagination, tell the integration where to find the next cursor in responses:

@@ -308,11 +308,11 @@
hasMorePath: meta.has_more


-### Rate Limiting
+### Rate limiting

Control how the integration interacts with your API to prevent overwhelming it or hitting rate limits.

-#### Request Timeout
+#### Request timeout

How long to wait for each API call to complete.

@@ -326,12 +326,12 @@

---

-## Ready to Build?
-
-Head to [Build Your Integration](./build-your-integration) for a step-by-step guide with an interactive configuration builder.
-
----
-
-## More Resources
+## Ready to build?
+
+Head to [Build your integration](./build-your-integration) for a step-by-step guide with an interactive configuration builder.
+
+---
+
+## More resources


Change headers to sentence case and add periods to the end of bullet items for
consistency.

docs/build-your-software-catalog/custom-integration/ocean-custom-integration/overview.md [7-20]

 # Overview
 
-## When to Use This Integration?
+## When to use this integration
 
-- **No native Port integration exists** for your tool or service
-- You're working with **internal or custom-built APIs** 
-- Your API follows **REST conventions** (JSON responses, HTTP methods)
-- You want a **configuration-only solution** without custom code
+- **No native Port integration exists** for your tool or service.
+- You're working with **internal or custom-built APIs**.
+- Your API follows **REST conventions** (JSON responses, HTTP methods).
+- You want a **configuration-only solution** without custom code.

[Suggestion processed]

Suggestion importance[1-10]: 5

__

Why:
Relevant best practice - Pattern 8 and Pattern 2: Use sentence case for headers and end bullet items with periods.

Low

best practice
Consolidate duplicated CSS class definitions

Refactor the duplicated .createInPortButton CSS class by consolidating common
styles into a base class and creating a modifier class for positioning-specific
styles.

src/components/OceanCustom/styles.module.css [713-851]

 .createInPortButton {
   padding: 0.5rem 1rem;
   background: var(--ifm-color-primary);
   color: white;
   border: none;
   border-radius: 4px;
   cursor: pointer;
   font-size: 0.875rem;
   font-weight: 500;
   text-decoration: none;
   transition: background 0.2s;
   display: inline-block;
 }
 
-.createInPortButton:hover {
-  background: var(--ifm-color-primary-dark);
-  color: white;
-  text-decoration: none;
-}
-...
-.createInPortButton {
+.createInPortButton.positioned {
   position: absolute;
   top: 0.5rem;
   right: 0.5rem;
-  padding: 0.5rem 1rem;
-  background: var(--ifm-color-primary);
-  color: white;
-  border: none;
-  border-radius: 4px;
-  cursor: pointer;
-  font-size: 0.875rem;
   font-weight: 600;
-  text-decoration: none;
   transition: all 0.2s;
   z-index: 1;
 }
 
 .createInPortButton:hover {
   background: var(--ifm-color-primary-dark);
   color: white;
   text-decoration: none;
 }

[To ensure code accuracy, apply this suggestion manually]

Suggestion importance[1-10]: 5

__

Why: The suggestion correctly identifies duplicated CSS rules for .createInPortButton and proposes a valid refactoring using a modifier class, which improves code maintainability and clarity.

Low
Performance
Memoize a derived value for performance

Memoize the getConfigSummary logic using the useMemo hook to improve
performance, and replace the nested ternary operator with a map for better
readability.

src/components/OceanCustom/IntegrationInstaller.jsx [15-21]

-const getConfigSummary = () => {
+const authTypeMap = {
+  bearer_token: 'Bearer Token',
+  api_key: 'API Key',
+  basic: 'Basic Auth',
+  none: 'None',
+};
+
+const configSummary = useMemo(() => {
   const config = [];
   if (baseUrl) config.push(`Base URL: ${baseUrl}`);
-  config.push(`Authentication: ${authType === 'bearer_token' ? 'Bearer Token' : authType === 'api_key' ? 'API Key' : authType === 'basic' ? 'Basic Auth' : 'None'}`);
-  if (paginationType !== 'none') config.push(`Pagination: ${paginationType} (${pageSize} items/page)`);
+  config.push(`Authentication: ${authTypeMap[authType] || 'None'}`);
+  if (paginationType !== 'none') {
+    config.push(`Pagination: ${paginationType} (${pageSize} items/page)`);
+  }
   return config.length > 0 ? config : ['No configuration set'];
-};
+}, [baseUrl, authType, paginationType, pageSize]);
  • Apply / Chat
Suggestion importance[1-10]: 5

__

Why: The suggestion correctly proposes using useMemo to prevent re-calculating the summary on every render and also improves readability by replacing a nested ternary with a map object.

Low
Move a pure function outside component

Move the parseFields pure function outside the BlueprintGenerator component to
prevent its re-creation on every render and improve performance.

src/components/OceanCustom/BlueprintGenerator.jsx [10-44]

 const parseFields = (jsonString) => {
   try {
     const json = JSON.parse(jsonString);
     // Get first object if array
     const sample = Array.isArray(json) ? json[0] : json;
     
-    if (!sample || typeof sample !== 'object') {
+    if (!sample || typeof sample !== 'object' || Array.isArray(sample)) {
       return [];
     }
 
     return Object.entries(sample).map(([key, value]) => {
       let type = 'string';
       let format = null;
 
       if (typeof value === 'number') {
         type = 'number';
       } else if (typeof value === 'boolean') {
         type = 'boolean';
       } else if (typeof value === 'string') {
         // Try to detect special formats
-        if (value.includes('@')) {
+        if (/\S+@\S+\.\S+/.test(value)) {
           format = 'email';
-        } else if (value.match(/^\d{4}-\d{2}-\d{2}/)) {
+        } else if (/^\d{4}-\d{2}-\d{2}/.test(value)) {
           format = 'date-time';
-        } else if (value.match(/^https?:\/\//)) {
+        } else if (/^https?:\/\//.test(value)) {
           format = 'url';
         }
       }
 
       return { key, type, format, value };
     });
   } catch {
     return [];
   }
 };
 
+export function BlueprintGenerator() {
+  const [sampleData, setSampleData] = useState('');
+  //...
+

[To ensure code accuracy, apply this suggestion manually]

Suggestion importance[1-10]: 4

__

Why: The suggestion correctly points out that the pure function parseFields can be moved outside the component to prevent re-creation on each render, which is a good practice for performance and code organization.

Low
Enhancement
Remove native HTML5 validation attribute

Remove the native HTML required attribute from the input field and implement
custom validation logic for a more consistent user experience.

src/components/OceanCustom/Step2DataMapping.jsx [250-261]

 <label className={styles.label}>
   <strong>Blueprint Identifier <span style={{color: 'red'}}>*</span></strong>
   <input
     type="text"
     placeholder="user"
     value={blueprintId}
     onChange={(e) => setBlueprintId(e.target.value)}
     className={styles.input}
-    required
   />
   <span className={styles.hint}>Lowercase, no spaces (e.g., "user", "project", "ticket")</span>
 </label>
  • Apply / Chat
Suggestion importance[1-10]: 3

__

Why: The suggestion proposes a valid enhancement for UX consistency, but removing the required attribute without implementing an alternative custom validation feedback mechanism would be a minor regression.

Low
  • Update

@aws-amplify-eu-west-1
Copy link

This pull request is automatically being deployed by Amplify Hosting (learn more).

Access this pull request here: https://pr-2972.d2ngvl90zqbob8.amplifyapp.com

@hadar-co hadar-co merged commit e381dfd into main Nov 3, 2025
5 checks passed
@hadar-co hadar-co deleted the feature/rename-docs-to-ocean-custom branch November 3, 2025 09:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants