UNPKG

@seqera/node-red-seqera

Version:

Node-RED nodes for interacting with the Seqera Platform API

248 lines (219 loc) 9.99 kB
<script type="text/html" data-template-name="seqera-datalink-list"> <div class="form-row"> <label for="node-input-seqera"><i class="icon-globe"></i> Seqera config</label> <input type="text" id="node-input-seqera" data-type="seqera-config" /> </div> <div class="form-row"> <label for="node-input-name"><i class="fa fa-tag"></i> Name</label> <input type="text" id="node-input-name" /> </div> <div class="form-row"> <label for="node-input-dataLinkName"><i class="fa fa-link"></i> Data link name</label> <input type="text" id="node-input-dataLinkName" /> </div> <div class="form-row"> <label for="node-input-returnType"><i class="fa fa-filter"></i> Return type</label> <select id="node-input-returnType"> <option value="files">Files only</option> <option value="folders">Folders only</option> <option value="all">Everything</option> </select> </div> <div class="form-row"> <label for="node-input-basePath"><i class="fa fa-folder-open-o"></i> Base path</label> <input type="text" id="node-input-basePath" /> </div> <div class="form-row"> <label for="node-input-prefix"><i class="fa fa-filter"></i> Prefix</label> <input type="text" id="node-input-prefix" /> </div> <div class="form-row"> <label for="node-input-pattern"><i class="fa fa-file-code-o"></i> Pattern (regex)</label> <input type="text" id="node-input-pattern" /> </div> <div class="form-row"> <label for="node-input-maxResults"><i class="fa fa-sort-numeric-asc"></i> Max results</label> <input type="text" id="node-input-maxResults" /> </div> <div class="form-row"> <label for="node-input-depth"><i class="fa fa-level-down"></i> Depth</label> <input type="text" id="node-input-depth" /> </div> <div class="form-row"> <label for="node-input-workspaceId"><i class="icon-tasks"></i> Workspace ID</label> <input type="text" id="node-input-workspaceId" /> </div> </script> <!-- prettier-ignore --> <script type="text/markdown" data-help-name="seqera-datalink-list"> Lists files from a Seqera Platform Data Explorer link. ### Inputs : dataLinkName (string) : The name of the data explorer link. : basePath (string) : Path within the data link to start browsing. Leave blank for the root. : prefix (string) : Optional prefix filter for results (applies to folders and files) : pattern (string) : Optional regex pattern filter for results (applies to files only) : returnType (string) : Select whether to return files, folders or everything. : maxResults (number) : Maximum number of results to return (default 100). : workspaceId (string) : Override the workspace ID from the config node. All inputs support msg.*, flow.*, global.*, env, or JSONata expressions via the **typedInput**. ### Outputs 1. Standard output : payload (array) : Array of file objects aggregated from the API. : files (array) : Array of file names. ### Details This node queries the Seqera Platform Data Explorer **list** API to find a data-link ID, then uses the **browse** API to fetch files and folders. It automatically handles pagination and listing nested files. The node uses the **Seqera config** node for the base URL, workspace ID, and API token. Any of these can be overridden using the corresponding input properties. ### References - [Seqera Platform API docs](https://docs.seqera.io/platform/latest/api) - Data Explorer endpoints </script> <script type="text/javascript"> RED.nodes.registerType("seqera-datalink-list", { category: "seqera", color: "#A9A1C6", inputs: 1, outputs: 1, icon: "icons/data-explorer.svg", align: "left", paletteLabel: "List files", label: function () { return this.name || "List files"; }, outputLabels: ["files"], defaults: { name: { value: "" }, seqera: { value: "", type: "seqera-config" }, dataLinkName: { value: "", required: true, }, dataLinkNameType: { value: "str" }, basePath: { value: "" }, basePathType: { value: "str" }, prefix: { value: "" }, prefixType: { value: "str" }, pattern: { value: "" }, patternType: { value: "str" }, maxResults: { value: "100" }, maxResultsType: { value: "num" }, depth: { value: "0" }, depthType: { value: "num" }, workspaceId: { value: "" }, workspaceIdType: { value: "str" }, returnType: { value: "files" }, }, oneditprepare: function () { function ti(id, val, type, def = "str") { const types = ["str", "num", "msg", "flow", "global", "env", "jsonata"]; if (def === "num") types.splice(types.indexOf("str"), 1); $(id).typedInput({ default: def, types }); $(id).typedInput("value", val); $(id).typedInput("type", type); } ti("#node-input-dataLinkName", this.dataLinkName || "", this.dataLinkNameType || "str"); ti("#node-input-basePath", this.basePath || "", this.basePathType || "str"); ti("#node-input-prefix", this.prefix || "", this.prefixType || "str"); ti("#node-input-pattern", this.pattern || "", this.patternType || "str"); ti("#node-input-maxResults", this.maxResults || "100", this.maxResultsType || "num", "num"); ti("#node-input-depth", this.depth || "0", this.depthType || "num", "num"); ti("#node-input-workspaceId", this.workspaceId || "", this.workspaceIdType || "str"); // Set dropdown value for returnType $("#node-input-returnType").val(this.returnType || "files"); // Add auto-complete for datalink name when type is "str" const setupAutoComplete = () => { const dataLinkNameInput = $("#node-input-dataLinkName"); const currentType = dataLinkNameInput.typedInput("type"); // Ensure our custom CSS is added only once if (!document.getElementById("seqera-autocomplete-style")) { const style = document.createElement("style"); style.id = "seqera-autocomplete-style"; style.innerHTML = `.red-ui-autoComplete li a { display:block; padding:4px 8px; width:100%; box-sizing:border-box; }`; document.head.appendChild(style); } // Get the actual visible input element from the typedInput widget const actualInput = dataLinkNameInput.parent().find(".red-ui-typedInput-input"); // Remove existing auto-complete if any if (actualInput.data("autoCompleteEnabled")) { actualInput.autoComplete("destroy"); actualInput.data("autoCompleteEnabled", false); } if (currentType === "str" && actualInput.length > 0) { // Add a small delay to ensure typedInput is fully initialized setTimeout(() => { actualInput.autoComplete({ search: function (value, done) { // Only search if we have some input if (!value || value.length < 1) { done([]); return; } // Make API call to get datalink names const nodeId = (RED.editor.edit_node && RED.editor.edit_node.id) || (RED.editor.edit_stack && RED.editor.edit_stack.length > 0 && RED.editor.edit_stack[0].id) || "temp-" + Date.now(); const seqeraConfigId = $("#node-input-seqera").val(); if (!seqeraConfigId) { done([]); return; } const params = new URLSearchParams({ search: value, seqeraConfig: seqeraConfigId, }); // Add workspace ID override if configured const workspaceIdOverride = $("#node-input-workspaceId").typedInput("value"); const workspaceIdType = $("#node-input-workspaceId").typedInput("type"); if (workspaceIdType === "str" && workspaceIdOverride && workspaceIdOverride.trim()) { params.append("workspaceId", workspaceIdOverride); } $.ajax({ url: `admin/seqera/datalinks/${nodeId}?${params.toString()}`, method: "GET", success: function (data) { // data is already in the correct format: [{value, label}] done(data || []); }, error: function () { done([]); }, }); }, }); actualInput.data("autoCompleteEnabled", true); }, 100); } }; // Set up auto-complete initially setupAutoComplete(); // Re-setup auto-complete when type changes $("#node-input-dataLinkName").on("change", function (event, type) { if (type) { // Add delay to avoid conflicts with ongoing autocomplete operations setTimeout(setupAutoComplete, 200); } }); // Re-setup auto-complete when Seqera config changes $("#node-input-seqera").on("change", function () { setupAutoComplete(); }); }, oneditsave: function () { function save(id, prop, propType) { this[prop] = $(id).typedInput("value"); this[propType] = $(id).typedInput("type"); } save.call(this, "#node-input-dataLinkName", "dataLinkName", "dataLinkNameType"); save.call(this, "#node-input-basePath", "basePath", "basePathType"); save.call(this, "#node-input-prefix", "prefix", "prefixType"); save.call(this, "#node-input-pattern", "pattern", "patternType"); save.call(this, "#node-input-maxResults", "maxResults", "maxResultsType"); save.call(this, "#node-input-depth", "depth", "depthType"); save.call(this, "#node-input-workspaceId", "workspaceId", "workspaceIdType"); // Save returnType dropdown this.returnType = $("#node-input-returnType").val(); }, }); </script>