### Install Dependencies with Bun Source: https://github.com/indexsupply/shovel/blob/main/shovel-config-ts/build-instructions.txt Use this command to install project dependencies using the Bun package manager. ```bash bun install ``` -------------------------------- ### Download and Install Latest Shovel from Main Source: https://github.com/indexsupply/shovel/blob/main/readme.md Use these commands to download the latest Shovel version from the main branch for macOS ARM64 and make it executable. ```bash curl -LO https://indexsupply.net/bin/main/darwin/arm64/shovel --silent chmod +x shovel ``` -------------------------------- ### Download and Install Shovel v1.6 Source: https://github.com/indexsupply/shovel/blob/main/readme.md Use these commands to download Shovel version 1.6 for macOS ARM64, make it executable, and verify the installation. ```bash curl -LO https://indexsupply.net/bin/1.6/darwin/arm64/shovel --silent chmod +x shovel ./shovel -version ``` ```text v1.6 582d ``` -------------------------------- ### Display Generated Password Source: https://github.com/indexsupply/shovel/blob/main/shovel/web/login.html This example shows the format of a randomly generated temporary password found in the logs. It is used when authentication is enabled but no password has been explicitly set. ```log password=171658e9feca092b msg=random-temp-password ``` -------------------------------- ### Get Chain Configuration for Integration Source: https://github.com/indexsupply/shovel/blob/main/shovel/web/add-integration.html Extracts configuration for 'chain' type integrations. It collects names and optional start values for checked chain rows, used for defining data processing chains. ```javascript function getChains(eventDiv) { let res = [] eventDiv.querySelectorAll("tr.chain").forEach(row => { let cb = row.querySelector(`input[type="checkbox"]`); if (!cb || !cb.checked) { return; } let src = {}; src.name = row.querySelector("td.name").textContent.trim(); const s = row.querySelector(`input[type="number"]`).valueAsNumber; if (s > 0) { src.start = s; } res.push(src); }); return res; } ``` -------------------------------- ### HTML Table Row for Source Chain Information Source: https://github.com/indexsupply/shovel/blob/main/shovel/web/add-integration.html Generates an HTML table row to display information about a source chain, including its name, chain ID, and a field for backfill start. ```javascript function srcRow(src) { return ` ${src.name} ${src.chain_id} `; } ``` -------------------------------- ### JavaScript Progress Calculation Source: https://github.com/indexsupply/shovel/blob/main/shovel/web/index.html Calculates the progress percentage based on start and stop values. Returns '100%' if the stop value is 0 or if the calculated progress reaches 100%. ```javascript function progress(start, stop) { if (stop == 0) { return "100%"; } const p = (start / stop) * 100; if (p == 100) { return "100%"; } else { return `${p.toFixed(2)}%`; } }; ``` -------------------------------- ### Get Block Metadata for Integration Source: https://github.com/indexsupply/shovel/blob/main/shovel/web/add-integration.html Extracts metadata for 'block' type integrations from the UI. It iterates through rows marked as metadata, collecting names and database column mappings for checked items. ```javascript function getBlock(eventDiv) { let res = [] eventDiv.querySelectorAll("tr.metadata").forEach(row => { let cb = row.querySelector(`input[type="checkbox"]`); if (!cb || !cb.checked) { return; } let n = row.querySelector("td.name").textContent.trim() let c = row.querySelector("td.dbName span").textContent.trim(); res.push({name: n, column: c}); }); return res; } ``` -------------------------------- ### Get Event Data for Integration Source: https://github.com/indexsupply/shovel/blob/main/shovel/web/add-integration.html Retrieves the event data, including selected fields and their mapped database columns, from the UI. It updates the event schema based on user selections and returns the modified event document. ```javascript function getEvent(eventDiv, doc) { let name = eventName(eventDiv); let eventDoc = doc.find(e => { return e.type == 'event' && e.name == name; }); if (!event) { return {}; } eventDiv.querySelectorAll("tr.field:not(.metadata)").forEach(row => { let cb = row.querySelector(`input[type="checkbox"]`); if (!cb) { return; } if (cb.checked) { let dbColumn = row.querySelector("td.dbName span").textContent.trim(); setColumn(eventDoc, getPath(eventDiv, row), dbColumn); } else { setColumn(eventDoc, getPath(eventDiv, row), ""); } }); return eventDoc; } ``` -------------------------------- ### Get Table Selection Source: https://github.com/indexsupply/shovel/blob/main/shovel/web/add-integration.html Retrieves the currently selected table from the event's table selection dropdown. This is used to determine which table the event data should be associated with. ```javascript function getTable(eventDiv) { let tableSelect = eventDiv.querySelector(".eventTable select"); return tableSelect.options[tableSelect.selectedIndex].text; } ``` -------------------------------- ### Get Event Field Path Source: https://github.com/indexsupply/shovel/blob/main/shovel/web/add-integration.html Constructs the hierarchical path for a given event field row within its event div. It traverses up the parent elements using 'data-parent' attributes to build the path. ```javascript function getPath(eventDiv, row) { let path = [] for (;;) { path.push(row.dataset.field) row = eventDiv.querySelector(`[data-field="${row.dataset.parent}"]`); if (!row) { break; } } return path.reverse(); } ``` -------------------------------- ### Build Project with Bun Source: https://github.com/indexsupply/shovel/blob/main/shovel-config-ts/build-instructions.txt Execute this command to build the project using Bun. This typically compiles source code and prepares assets. ```bash bun run build ``` -------------------------------- ### Publish to npm Registry Source: https://github.com/indexsupply/shovel/blob/main/shovel-config-ts/build-instructions.txt Use this command to publish the project to the npm registry. Ensure you are logged in and have the correct version set. ```bash npm publish ``` -------------------------------- ### Publish to JSR Registry with Bunx Source: https://github.com/indexsupply/shovel/blob/main/shovel-config-ts/build-instructions.txt This command publishes the project to the JSR registry using Bunx. This is an alternative to npm publishing. ```bash bunx jsr publish ``` -------------------------------- ### Build Shovel Docker Image Source: https://github.com/indexsupply/shovel/blob/main/cmd/shovel/readme.txt Build the Shovel Docker image using the provided Dockerfile. This command should be run from the root directory of the project. ```bash docker build -t shovel:latest -f ./cmd/shovel/Dockerfile . ``` -------------------------------- ### Populate Network Details on Chain ID Input Source: https://github.com/indexsupply/shovel/blob/main/shovel/web/add-source.html This script populates the network name and ETH URL when a Chain ID is entered. It uses a map to find the corresponding details and a debounced timer to avoid excessive lookups. ```javascript let nameMap = { 1: {name: "Mainnet", url: "https://1.rlps.indexsupply.net"}, 5: {name: "Goerli", url: "https://5.rlps.indexsupply.net"}, 10: {name: "Optimism", url: "https://10.rlps.indexsupply.net"}, 420: {name: "Optimism Goerli", url: "https://420.rlps.indexsupply.net"}, 8453: {name: "Base", url: "https://8453.rlps.indexsupply.net"}, 84531: {name: "Base Goerli", url: "https://84531.rlps.indexsupply.net"} } document.addEventListener("DOMContentLoaded", function() { let done = function(v) { let config = nameMap[v]; let name = ""; let url = ""; if (config) { name = config.name; url = config.url; } document.querySelector("#name").value = name; document.querySelector("#ethURL").value = url; } const waitTime = 200; let timer; let chainID = document.querySelector("#chainID"); chainID.addEventListener("keyup", e => { clearTimeout(timer); timer = setTimeout(function() { done(e.target.value); }, waitTime); }); }); ``` -------------------------------- ### Suggest Table Name from Event Source: https://github.com/indexsupply/shovel/blob/main/shovel/web/add-integration.html Placeholder function for suggesting a database table name based on an event object. ```javascript function suggestTableName(event) ``` -------------------------------- ### Link Shovel Config Locally with Bun Source: https://github.com/indexsupply/shovel/blob/main/shovel-config-ts/build-instructions.txt This command links the local Shovel configuration package for development purposes, allowing you to test changes without publishing. ```bash bun link @indexsupply/shovel-config ``` -------------------------------- ### Generate Shovel Configuration with TypeScript Source: https://github.com/indexsupply/shovel/blob/main/shovel-config-ts/readme.md Defines a data source, a table schema, and an integration rule to capture Ethereum transfer events. Use this to script complex Shovel configurations programmatically. ```typescript import { makeConfig, toJSON } from "@indexsupply/shovel-config"; import type { Source, Table, Integration } from "@indexsupply/shovel-config"; const table: Table = { name: "transfers", columns: [ { name: "log_addr", type: "bytea" }, { name: "from", type: "bytea" }, { name: "to", type: "bytea" }, { name: "amount", type: "numeric" }, ], }; const mainnet: Source = { name: "mainnet", chain_id: 1, url: "https://ethereum.publicnode.com", }; let integrations: Integration[] = [ { enabled: true, name: "transfers", sources: [{ name: mainnet.name, start: 0n }], table: table, block: [ { name: "log_addr", column: "log_addr", filter_op: "contains", filter_arg: ["0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48"], }, ], event: { type: "event", name: "Transfer", inputs: [ { indexed: true, name: "from", type: "address", column: "from" }, { indexed: true, name: "to", type: "address", column: "to" }, { indexed: false, name: "amount", type: "uint256", column: "amount" }, ], }, }, ]; const config = makeConfig({ pg_url: "postgres:///shovel", sources: [mainnet], integrations: integrations, }); console.log(toJSON(config)); ``` -------------------------------- ### ABI Document Test Data Source: https://github.com/indexsupply/shovel/blob/main/shovel/web/add-integration.html Provides a sample ABI (Application Binary Interface) document structure used for testing purposes. This data represents event inputs and outputs, including complex types like tuples and arrays. ```json const abiDocTest = [ { "anonymous": false, "inputs": [ { "indexed": false, "internalType": "bytes32", "name": "orderHash", "type": "bytes32" }, { "indexed": true, "internalType": "address", "name": "offerer", "type": "address" }, { "indexed": true, "internalType": "address", "name": "zone", "type": "address" }, { "indexed": false, "internalType": "address", "name": "recipient", "type": "address" }, { "components": [ { "internalType": "enum ItemType", "name": "itemType", "type": "uint8" }, { "internalType": "address", "name": "token", "type": "address" }, { "internalType": "uint256", "name": "identifier", "type": "uint256" }, { "internalType": "uint256", "name": "amount", "type": "uint256" } ], "indexed": false, "internalType": "struct SpentItem[]", "name": "offer", "type": "tuple[]" }, { "components": [ { "internalType": "enum ItemType", "name": "itemType", "type": "uint8" }, { "internalType": "address", "name": "token", "type": "address" }, { "internalType": "uint256", "name": "identifier", "type": "uint256" }, { "internalType": "uint256", "name": "amount", "type": "uint256" }, { "internalType": "address payable", "name": "recipient", "type": "address" } ], "indexed": false, "internalType": "struct ReceivedItem[]", "name": "consideration", "type": "tuple[]" } ], "name": "OrderFulfilled", "type": "event" } ]; ``` -------------------------------- ### Drag and Drop ABI Document Loading Source: https://github.com/indexsupply/shovel/blob/main/shovel/web/add-integration.html Handles loading an ABI document via drag and drop. Parses the dropped file as JSON and updates the `abiDoc` variable. ```javascript var abiDoc = null; document.addEventListener("DOMContentLoaded", function() { let dropArea = document.querySelector('#abiDocDrop'); dropArea.addEventListener('dragover', (event) => { event.stopPropagation(); event.preventDefault(); event.dataTransfer.dropEffect = 'copy'; }); dropArea.addEventListener('drop', (event) => { event.stopPropagation(); event.preventDefault(); dropArea.style.display = 'none'; const reader = new FileReader(); reader.addEventListener('load', (event) => { abiDoc = JSON.parse(event.target.result); processEvents(abiDoc); }); reader.readAsText(event.dataTransfer.files[0]); }); }); ``` -------------------------------- ### Enable Debug Mode with Keyboard Shortcut Source: https://github.com/indexsupply/shovel/blob/main/shovel/web/add-integration.html Toggles debug mode on/off when the '/' key is pressed. In debug mode, outlines are added to all elements, and the ABI document display is altered. ```javascript document.addEventListener("DOMContentLoaded", function() { var debug = false; document.addEventListener('keydown', function(e) { if (e.keyCode != 191) { return; } debug = !debug; if (debug) { document.querySelectorAll('*').forEach(el => { el.style.setProperty('outline', '1px dotted red'); }); abiDoc = abiDocTest; document.querySelector('#abiDocDrop').style.display = 'none'; processEvents(abiDocTest); } else { document.querySelectorAll('*').forEach(el => { el.style.removeProperty('outline'); }); } }); }); ``` -------------------------------- ### Generate Event Mapping HTML Source: https://github.com/indexsupply/shovel/blob/main/shovel/web/add-integration.html Constructs the complete HTML structure for an event mapping, including chain sources, event data fields, and block metadata. Assumes `ethSources` is globally available. ```javascript function eventMapping(event) { let rows = []; rows.push(seperator("Chains")); ethSources.forEach(c => { rows.push(srcRow(c)) }); rows.push(seperator("Event Data")); event.inputs.forEach(field => { row(0, event, event, field).forEach(r => { rows.push(r); }); }); rows.push(seperator("Block Data")); metadata.forEach(field => { rows.push(metadataRow(0, event, event, field)); }); return `
${rows.join("\n")}
`; } ``` -------------------------------- ### Determine Database Type from ABI Type Source: https://github.com/indexsupply/shovel/blob/main/shovel/web/add-integration.html Maps an ABI type string to a database type. Currently, 'uint' types map to 'numeric', and others map to 'bytea'. ```javascript function dbType(abiType) { switch (true) { case abiType.trim().startsWith("uint"): return "numeric"; default: return "bytea"; } } ``` -------------------------------- ### Save Integration Data Source: https://github.com/indexsupply/shovel/blob/main/shovel/web/add-integration.html Handles the submission of integration configuration. It gathers data from the UI and sends it to the server via a POST request. Upon successful save, it redirects the user to the integration's detail page. ```javascript function eventName(eventDiv) { return eventDiv.querySelector(".eventMapping table").dataset.field; } document.querySelectorAll(\`.eventMapping input[type="submit"]").forEach(input => { input.addEventListener("click", e => { let eventDiv = input.closest('.event'); let integration = {}; integration["name"] = eventName(eventDiv); integration["enabled"] = true; integration["sources"] = getChains(eventDiv); integration["table"] = getTable(eventDiv); integration["block"] = getBlock(eventDiv); integration["event"] = getEvent(eventDiv, abiDoc); console.log(integration); post("/save-integration", integration).then(d => { location.href = `/integration/${integration.name}`; }).catch(e => { console.log(e); }); }); }); async function post(url, data) { const resp = await fetch(url, { method: "POST", headers: {"Content-Type": "application/json"}, body: JSON.stringify(data) }); return resp.json(); } ``` -------------------------------- ### Update Login Configuration Source: https://github.com/indexsupply/shovel/blob/main/shovel/web/login.html This snippet demonstrates how to update the Shovel configuration file to manage authentication. You can either disable authentication by setting `disable_authn` to `true` or update the password by changing `root_password`. ```json "dashboard": { "disable_authn": false, "root_password": "XXX", } ``` -------------------------------- ### Expand/Collapse Event Details Source: https://github.com/indexsupply/shovel/blob/main/shovel/web/add-integration.html Toggles the visibility of event details, including tables and mapping configurations, when an event name is clicked. This provides a way to show or hide detailed information for each event. ```javascript document.querySelectorAll('.eventName').forEach( e => { e.addEventListener('click', c => { e.classList.toggle("expand"); let eventDiv = e.closest('.event'); eventDiv.querySelectorAll('.eventTable').forEach(t => { if (t.style.display == 'flex') { t.style.display = 'none'; } else { t.style.display = 'flex'; } }); eventDiv.querySelectorAll('.eventMapping').forEach(t => { if (t.style.display == 'flex') { t.style.display = 'none'; } else { t.style.display = 'flex'; } }); }); }); ``` -------------------------------- ### JavaScript DOMContentLoaded and Event Listeners Source: https://github.com/indexsupply/shovel/blob/main/shovel/web/index.html Initializes event listeners when the DOM is fully loaded. Includes a keydown listener for toggling display of '.destinations' elements and a listener for 'task-updates' Server-Sent Events to update task information in real-time. ```javascript document.addEventListener("DOMContentLoaded", function() { document.addEventListener('keydown', function(e) { if (e.keyCode == 73) { document.querySelectorAll('.destinations').forEach(el => { const d = el.style.display; el.style.display = (d == 'none' ? '' : 'none'); }); } }); document.querySelectorAll(".addComma").forEach(e => { e.innerText = comma(e.innerText); }); let updates = new EventSource("/task-updates"); updates.onmessage = function(event) { const tu = JSON.parse(event.data); if (tu.Hash) { update(tu.DOMID, "Num", comma(tu.Num)); update(tu.DOMID, "Hash", tu.Hash); update(tu.DOMID, "Latency", tu.Latency); update(tu.DOMID, "NRows", tu.NRows); } else { update(tu.DOMID, "Latency", tu.Latency); update(tu.DOMID, "NRows", tu.NRows); } }; }); ``` -------------------------------- ### HTML Table Row for Metadata Fields Source: https://github.com/indexsupply/shovel/blob/main/shovel/web/add-integration.html Generates an HTML table row for metadata fields associated with an event. Displays name, type, database name, and database type. ```javascript function metadataRow(depth, parent, event, field) { return ` ${field.name} ${field.type} → ${dbName(parent, field)} ${dbType(field.type)} `; } ``` -------------------------------- ### Generate Database Field Name Source: https://github.com/indexsupply/shovel/blob/main/shovel/web/add-integration.html Generates a database-friendly name for a field based on its name and parent context. Special cases 'from' and 'to' fields. ```javascript function dbName(parent, field) { if (field.name == "from") { return "f" } if (field.name == "to") { return "t" } if (!parent.components) { return snake(field.name); } return `${parent.name[0]} _ ${snake(field.name)} ` } ``` -------------------------------- ### HTML Rendering Helper Source: https://github.com/indexsupply/shovel/blob/main/shovel/web/add-integration.html A utility function to render HTML content into a target DOM element. It creates a temporary div, sets its innerHTML, and appends the first child element to the target. ```javascript function render(target, html) { const tmp = document.createElement("div"); tmp.innerHTML = html; target.appendChild(tmp.firstElementChild); } ``` -------------------------------- ### Snake Case Conversion Utility Source: https://github.com/indexsupply/shovel/blob/main/shovel/web/add-integration.html Converts a string to snake_case. Handles underscores and capital letters to create the snake_case format. ```javascript function snake(s) { let res = ''; for (let i = 0; i < s.length; i++) { if (s[i] === "_") { res += s[i].toLowerCase(); } else if (i > 0 && s[i] === s[i].toUpperCase()) { res += '_' + s[i].toLowerCase(); } else { res += s[i].toLowerCase(); } } return res; } ``` -------------------------------- ### Process and Render Events Source: https://github.com/indexsupply/shovel/blob/main/shovel/web/add-integration.html Processes an array of events, rendering each event's HTML structure into the main content area of the page. It also ensures that event listeners are added after rendering. ```javascript function processEvents(events) { let main = document.querySelector("main"); events.forEach(e => { if (e.type == 'event') { let node = render(main, eventDiv(e)); } }); addListeners(); } ``` -------------------------------- ### HTML Table Row for Event Fields Source: https://github.com/indexsupply/shovel/blob/main/shovel/web/add-integration.html Generates an HTML table row for a regular event field. Includes name, type, database name, database type, and a checkbox. ```javascript function fieldRow(depth, parent, event, field) { return ` ${field.name} ${field.type} → ${dbName(parent, field)} ${dbType(field.type)} `; } ``` -------------------------------- ### Render Event HTML Source: https://github.com/indexsupply/shovel/blob/main/shovel/web/add-integration.html Renders an event's header, including its name and table selection, along with its mapping details. This function is used to construct the HTML for displaying individual events on the web page. ```javascript function eventHeader(event) { return `
${event.name}
new
`; } function eventDiv(event) { return `
${eventHeader(event)} ${eventMapping(event)}
`; } ``` -------------------------------- ### JavaScript Number Formatting Source: https://github.com/indexsupply/shovel/blob/main/shovel/web/index.html Formats a number by adding locale-specific comma separators. Converts the input string to a Number before formatting. ```javascript function comma(s) { return Number(s).toLocaleString(); }; ``` -------------------------------- ### HTML Table Row for Tuple Fields Source: https://github.com/indexsupply/shovel/blob/main/shovel/web/add-integration.html Generates an HTML table row for a tuple field within an event mapping. Includes name, type, and checkbox for selection. ```javascript function tupleRow(depth, parent, field) { return ` ${field.name} ${field.type} `; }; ``` -------------------------------- ### Metadata Fields Definition Source: https://github.com/indexsupply/shovel/blob/main/shovel/web/add-integration.html Defines a list of metadata fields with their names and types, used for event mapping. ```javascript const metadata = [{"name": "chain_id", "type": "uint16"}, {"name": "block_hash", "type": "bytes32"}, {"name": "block_num", "type": "uint256"}, {"name": "tx_hash", "type": "bytes32"}, {"name": "tx_idx", "type": "uint16"}, {"name": "tx_signer", "type": "address"}, {"name": "tx_to", "type": "address"}, {"name": "tx_value", "type": "uint256"}, {"name": "log_idx", "type": "uint16"}, {"name": "log_addr", "type": "address"} ]; ``` -------------------------------- ### HTML Table Row for Separators Source: https://github.com/indexsupply/shovel/blob/main/shovel/web/add-integration.html Generates an HTML table row to act as a visual separator with a given text label. ```javascript function seperator(text) { return ` ${text} `; } ``` -------------------------------- ### Handle Field Selection Changes Source: https://github.com/indexsupply/shovel/blob/main/shovel/web/add-integration.html Listens for changes on field checkboxes within the event mapping table. It updates the state of parent tuples and headers accordingly to maintain data integrity and UI consistency. ```javascript // fieldRow document.querySelectorAll('.eventMapping table tr.field input[type="checkbox"]').forEach(cb => { cb.addEventListener('change', c => { let row = cb.closest('tr'); let eventDiv = cb.closest('.event'); let parentKey = row.dataset.parent; let parentRow = eventDiv.querySelector(`[data-tuple="${parentKey}"]`); if (!parentRow) { checkHeader(eventDiv); return } checkTuple(parentRow); checkHeader(eventDiv); }); }); ``` -------------------------------- ### Drag and Drop Row Swapping Source: https://github.com/indexsupply/shovel/blob/main/shovel/web/add-integration.html Enables drag-and-drop functionality for table rows, allowing users to reorder fields within the event mapping. It captures the dragged row and swaps its position with the target row upon dropping. ```javascript var draggedRow = null; document.querySelectorAll('tr[draggable="true"]').forEach(d => { d.addEventListener('dragstart', function(e) { draggedRow = e.target.closest('tr'); }); d.addEventListener('dragover', function(e) { e.preventDefault(); }); d.addEventListener('drop', function(e) { swapRows(draggedRow, e.target.parentElement) }); }); ``` -------------------------------- ### Recursive Row Generation for Event Fields Source: https://github.com/indexsupply/shovel/blob/main/shovel/web/add-integration.html Recursively generates HTML table rows for event fields, handling nested components (tuples) by increasing the depth. ```javascript function row(depth, parent, event, field) { let res = []; if (!('components' in field)) { res.push(fieldRow(depth, parent, event, field)); return res; } res.push(tupleRow(depth, parent, field)); field.components.forEach(function(comp, i, arr) { row(depth+1, field, event, comp).forEach(r => { res.push(r); }); }); return res; } ``` -------------------------------- ### Toggle All Event Fields Source: https://github.com/indexsupply/shovel/blob/main/shovel/web/add-integration.html Allows users to select or deselect all field checkboxes within an event mapping by toggling a single checkbox in the event header. This simplifies bulk selection. ```javascript document.querySelectorAll('.eventHeader input[type="checkbox"]').forEach(cb => { cb.addEventListener('change', c => { cb.closest('.event').querySelectorAll('.eventMapping table input[type="checkbox"]').forEach(fcb => { fcb.checked = cb.checked; }) }); }); ``` -------------------------------- ### Update Event Header Checkbox Source: https://github.com/indexsupply/shovel/blob/main/shovel/web/add-integration.html Updates the state of the main event header checkbox based on whether any checkboxes within the event's mapping table are checked. This provides a summary status for the entire event. ```javascript // Update the event's header checkbox if any of the event's checkboxes // are checked. function checkHeader(eventDiv) { var numChecked = 0; eventDiv.querySelectorAll('.eventMapping table input[type="checkbox"]:checked').forEach(cb => { numChecked++; }); eventDiv.querySelector('.eventHeader input[type="checkbox"]').checked = numChecked > 0; } ``` -------------------------------- ### Add Event Listeners Source: https://github.com/indexsupply/shovel/blob/main/shovel/web/add-integration.html Attaches event listeners to various elements within the event display, including table cells for toggling checkboxes and checkboxes themselves for handling changes. This function enables user interaction with the event data. ```javascript function addListeners() { document.querySelectorAll('.eventMapping table td:not(.nocheck)').forEach(r => { r.addEventListener('click', c => { let row = r.closest('tr'); let cb = row.querySelector('input[type="checkbox"]'); cb.checked ^= 1; cb.dispatchEvent(new Event("change")); }); }); document.querySelectorAll('.eventMapping table tr.tuple input[type="checkbox"]').forEach(cb => { cb.addEventListener('change', c => { let eventDiv = cb.closest('.event'); let row = cb.closest('tr'); let tupleKey = row.dataset.tuple; if (tupleKey == "") { return; } // update all immediate children eventDiv.querySelectorAll(`[data-parent="${tupleKey}"] input[type="checkbox"]`).forEach(ccb => { ccb.checked = cb.checked; }); // recursively call this function // on all child tuple checkboxes. eventDiv.querySelectorAll(`[data-tuple][data-parent="${tupleKey}"] input[type="checkbox"]`).forEach(ccb => { ccb.dispatchEvent(new Event("change")); }); let parentKey = cb.closest('tr').dataset.parent; if (parentKey == "") { checkHeader(eventDiv); return } checkTuple(eventDiv.querySelector(`[data-tuple="${parentKey}"]`)); checkHeader(eventDiv); }); }); } ``` -------------------------------- ### Swap Table Row Content Source: https://github.com/indexsupply/shovel/blob/main/shovel/web/add-integration.html Swaps the text content of cells between two table rows. This is useful for reordering or rearranging data within a table structure. ```javascript function swapRows(x, y) { for (var i = 0; i < x.cells.length; i++) { var tmp = x.cells\[i\]\.textContent; x.cells\[i\]\.textContent = y.cells\[i\]\.textContent; y.cells\[i\]\.textContent = tmp; } } ``` -------------------------------- ### JavaScript DOM Update Function Source: https://github.com/indexsupply/shovel/blob/main/shovel/web/index.html Updates the text content of a specific field within a task's DOM element. It finds the task element by its ID and then the specific field element by its class name. ```javascript function update(id, field, val) { const taskDiv = document.getElementById(id); const fieldDiv = taskDiv.querySelector(`.${field}`); fieldDiv.innerText = val; }; ``` -------------------------------- ### Set Column in Event Schema Source: https://github.com/indexsupply/shovel/blob/main/shovel/web/add-integration.html Updates the 'column' property for a specific field within an event's schema definition. It traverses the schema path to find the correct input component and assigns the provided database column value. ```javascript // abidata function setColumn(doc, path, value) { path.shift(); //ignore event name let input = null; let inputs = doc.inputs; path.forEach(pathName => { input = inputs.find(inp => inp.name == pathName); if (!input) { return undefined; } inputs = input.components; }); input["column"] = value } ``` -------------------------------- ### Check Tuple Checkbox State Source: https://github.com/indexsupply/shovel/blob/main/shovel/web/add-integration.html Updates the state of a parent checkbox based on the checked status of its child checkboxes within a tuple. It recursively checks parent tuples up the hierarchy. ```javascript function checkTuple(row) { let eventDiv = row.closest('.event'); let checkBox = row.querySelector(`input[type="checkbox"]`); let tupleKey = row.dataset.tuple; if (tupleKey == "") { return; } var numChecked = 0; eventDiv.querySelectorAll(`[data-parent="${tupleKey}"] input[type="checkbox"]`).forEach(childCheckbox => { if (childCheckbox.checked) { numChecked++; } }); checkBox.checked = numChecked > 0; let parentKey = row.dataset.parent; if (parentKey == "") { return; } eventDiv.querySelectorAll(`[data-tuple="${parentKey}"]`).forEach(prow => { checkTuple(prow); }); } ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.