### Install Copado Recipes Components Source: https://context7.com/copadosolutions/copado-recipes/llms.txt Deploy the Copado Recipes components to a Salesforce org using the Salesforce CLI. Ensure you have Node.js and the Salesforce CLI installed. ```bash # Clone the repository git clone https://github.com/CopadoSolutions/copado-recipes.git cd copado-recipes # Install Node dependencies (linting/testing tooling) npm install # Deploy to a source-tracked scratch org sf project deploy start -o # OR deploy to a non-source-tracked sandbox/production org sf deploy metadata -o ``` -------------------------------- ### Scratch Org Setup Commands Source: https://context7.com/copadosolutions/copado-recipes/llms.txt Commands to set up a Developer Edition scratch org for local component development. Ensure you have authenticated to your Dev Hub first. ```bash # Authenticate to your Dev Hub sf org login web --set-default-dev-hub --alias myDevHub # Create a scratch org from the provided definition sf org create scratch \ --definition-file config/project-scratch-def.json \ --alias copado-recipes-scratch \ --duration-days 7 # Deploy source to the scratch org sf project deploy start -o copado-recipes-scratch # Open the org in a browser sf org open -o copado-recipes-scratch ``` -------------------------------- ### Deploy Metadata to Target Org Source: https://github.com/copadosolutions/copado-recipes/blob/main/README.md Use this command to deploy metadata to a target organization. Ensure your environment is source-tracked. ```bash sf project deploy start -o [target-org] ``` -------------------------------- ### LWC Unit Test Commands Source: https://context7.com/copadosolutions/copado-recipes/llms.txt Commands for running LWC unit tests and linting using npm scripts. Use 'test:unit:watch' during development for automatic re-runs. ```bash # Run all unit tests once npm run test:unit # Run in watch mode during development npm run test:unit:watch # Generate a coverage report npm run test:unit:coverage # Run linting across all Aura and LWC components npm run lint ``` -------------------------------- ### Deploy Metadata to Non-Source Tracked Org Source: https://github.com/copadosolutions/copado-recipes/blob/main/README.md Use this command to deploy metadata to an organization that is not source-tracked. ```bash sf deploy metadata -o [target-org] ``` -------------------------------- ### Wiring `resultTable` Component to `copado__Result_Data__c` Source: https://context7.com/copadosolutions/copado-recipes/llms.txt This JavaScript code demonstrates the core wiring for the `resultTable` LWC. It fetches the `copado__Result_Data__c` field from a `copado__Result__c` record and determines the appropriate display format (Table, YAML, or String). The `jsyaml` static resource is loaded for YAML parsing. ```javascript // resultTable.js — core wiring import { LightningElement, api, wire, track } from 'lwc'; import { getRecord, getFieldValue } from 'lightning/uiRecordApi'; import RESULT_DATA_FIELD from '@salesforce/schema/copado__Result__c.copado__Result_Data__c'; import jsyamllib from '@salesforce/resourceUrl/jsyamllib'; import { loadScript } from 'lightning/platformResourceLoader'; export default class ResultTable extends LightningElement { @api recordId; // Provided automatically by the Copado Result Viewer slot @track relevantFormattedJson; // Reactive: filtered subset shown in the datatable type; // 'Table' | 'YAML' | 'String' formattedJson; // Full parsed payload scriptsLoaded = false; // Fetch the result record and parse its data field @wire(getRecord, { recordId: '$recordId', fields: [RESULT_DATA_FIELD] }) wiredRecord({ data }) { this.result = data; const serializedJson = getFieldValue(this.result, RESULT_DATA_FIELD); const { type, formattedJson } = this.getFormattedData(serializedJson); this.type = type; this.formattedJson = formattedJson; this.relevantFormattedJson = formattedJson; } // Load the jsyaml static resource once the component is inserted into the DOM async connectedCallback() { if (!this.scriptsLoaded) { await loadScript(this, jsyamllib); this.scriptsLoaded = true; } } // Determine display type by inspecting the parsed JSON structure getFormattedData(serializedJson) { try { const formattedJson = JSON.parse(serializedJson); if (formattedJson?.length) { return { type: 'Table', formattedJson }; // Array → tabular view } return { type: 'YAML', formattedJson }; // Object → YAML view } catch (error) { return { type: 'String', formattedJson: serializedJson }; // Non-JSON → plain text } } } ``` -------------------------------- ### Scratch Org Definition JSON Source: https://context7.com/copadosolutions/copado-recipes/llms.txt Configuration file for creating a Developer Edition scratch org with specific features and settings. ```json { "orgName": "Copado Inc.", "edition": "Developer", "features": ["EnableSetPasswordInApi"], "settings": { "lightningExperienceSettings": { "enableS1DesktopEnabled": true }, "mobileSettings": { "enableS1EncryptedStoragePref2": false } } } ``` -------------------------------- ### Implement Live Table Filtering Source: https://context7.com/copadosolutions/copado-recipes/llms.txt The `handleSearch` method triggers filtering of `relevantFormattedJson` based on user input. It performs a case-insensitive substring match across all column values. Use `_clearSearch` to restore the full dataset. ```javascript // Triggered by handleSearch(event) { const searchTerm = event.target.value?.trim().toLowerCase() ?? ''; if (!searchTerm) { this._clearSearch(); // Restore full dataset } else { this._applySearch(searchTerm); } } _applySearch(searchTerm) { // Example: formattedJson has 1000 deployment rows; user types "failed" this.relevantFormattedJson = this.formattedJson.filter((row) => { for (const key in row) { const value = String(row[key] ?? ''); if (value.toLowerCase().includes(searchTerm)) return true; } return false; }); // Only rows where ANY column value contains "failed" are shown } _clearSearch() { this.relevantFormattedJson = this.formattedJson; // Reset to full dataset } ``` -------------------------------- ### LWC Result Table from File Source: https://context7.com/copadosolutions/copado-recipes/llms.txt Retrieves and decodes result data from a Salesforce File named 'output.json' linked to a result record. Useful for payloads exceeding field size limits. Ensure the file exists and is named 'output.json' or update the filename in the code. ```javascript import { LightningElement, api, wire, track } from 'lwc'; import { getRecord, getFieldValue } from 'lightning/uiRecordApi'; import { getRelatedListRecords } from 'lightning/uiRelatedListApi'; import VERSION_DATA_FIELD from '@salesforce/schema/ContentVersion.VersionData'; import TITLE_FIELD from '@salesforce/schema/ContentDocumentLink.ContentDocument.Title'; import LATEST_PUBLISHED_VERSION_FIELD from '@salesforce/schema/ContentDocumentLink.ContentDocument.LatestPublishedVersionId'; export default class ResultTableFromFile extends LightningElement { @api recordId; _versionId; // Resolved from the linked ContentDocumentLink // Step 1: Find the ContentDocumentLink whose file is named 'output.json' @wire(getRelatedListRecords, { parentRecordId: '$recordId', relatedListId: 'ContentDocumentLinks', fields: [ 'ContentDocumentLink.ContentDocument.LatestPublishedVersionId', 'ContentDocumentLink.ContentDocument.Title' ] }) docLinksInfo({ data }) { if (data) { const logsDoc = data.records?.find( (doc) => getFieldValue(doc, TITLE_FIELD) === 'output.json' // Change filename here if needed ); if (logsDoc) { this._versionId = getFieldValue(logsDoc, LATEST_PUBLISHED_VERSION_FIELD); } } } // Step 2: Fetch the ContentVersion body (base64-encoded) and decode it @wire(getRecord, { recordId: '$_versionId', fields: [VERSION_DATA_FIELD] }) wiredVersion({ data }) { if (data) { const rawData = getFieldValue(data, VERSION_DATA_FIELD); // Base64 string const serializedJson = this.b64DecodeUnicode(rawData); // UTF-8 decoded string const { type, formattedJson } = this.getFormattedData(serializedJson); this.type = type; this.formattedJson = formattedJson; this.relevantFormattedJson = formattedJson; } } // Safely decode base64 content that may contain multi-byte Unicode characters b64DecodeUnicode(str) { return decodeURIComponent( atob(str).split('').map((c) => '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2) ).join('') ); } } // To read from a differently-named file, change 'output.json' in docLinksInfo to the target filename. ``` -------------------------------- ### Render JSON Data as YAML Source: https://context7.com/copadosolutions/copado-recipes/llms.txt The `yamlData` getter serializes the `formattedJson` object into a YAML string for display, but only if the detected type is 'YAML' and the `jsyaml` library is loaded. ```javascript get yamlData() { if (this.isYAML && this.scriptsLoaded) { return jsyaml.dump(this.formattedJson); } return ''; } // Input formattedJson: // { pipeline: { stage: 'Production', branch: 'main', approver: 'alice' } } // Output string: // pipeline: // stage: Production // branch: main // approver: alice ``` -------------------------------- ### Parse and Format JSON Data Source: https://context7.com/copadosolutions/copado-recipes/llms.txt Use `getFormattedData` to parse raw JSON strings into structured objects. It automatically detects if the input is an array of objects (for tables), a nested object (for YAML), or plain text. ```javascript // Standalone usage example (unit test context) const component = new ResultTable(); // Case 1: Array of objects → Table const tableResult = component.getFormattedData( '[{"name":"Deploy","status":"Success"},{"name":"Test","status":"Failed"}]' ); // → { type: 'Table', formattedJson: [{name:'Deploy',status:'Success'},{name:'Test',status:'Failed'}] } // Case 2: Nested object → YAML const yamlResult = component.getFormattedData( '{"pipeline":{"stage":"QA","branch":"main"}}' ); // → { type: 'YAML', formattedJson: { pipeline: { stage: 'QA', branch: 'main' } } } // Case 3: Non-JSON string → Plain Text const stringResult = component.getFormattedData('Deployment completed in 42s'); // → { type: 'String', formattedJson: 'Deployment completed in 42s' } ``` -------------------------------- ### Dynamically Generate Table Columns Source: https://context7.com/copadosolutions/copado-recipes/llms.txt The `columns` getter derives `lightning-datatable` column definitions by collecting unique keys from the `formattedJson` array. This ensures all fields, even those missing in some rows, are represented. ```javascript // Given formattedJson = [ // { name: 'Deploy', status: 'Success', duration: '10s' }, // { name: 'Test', status: 'Failed' } // 'duration' missing // ] get columns() { if (this.type !== 'Table') return []; const allKeys = this.formattedJson.reduce((keys, item) => { return keys.concat(Object.keys(item)); }, []); const uniqueKeys = [...new Set(allKeys)]; // ['name', 'status', 'duration'] return uniqueKeys.map(key => ({ label: key.charAt(0).toUpperCase() + key.slice(1), // 'Name', 'Status', 'Duration' fieldName: key, type: 'text' })); } // Result columns: // [ // { label: 'Name', fieldName: 'name', type: 'text' }, // { label: 'Status', fieldName: 'status', type: 'text' }, // { label: 'Duration', fieldName: 'duration', type: 'text' } // ] ``` -------------------------------- ### Embed `resultTable` Component Source: https://context7.com/copadosolutions/copado-recipes/llms.txt Embed the `resultTable` component in a parent LWC or a record page. The component automatically receives the result record ID via the `recordId` property. ```html ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.