Recent Discussions
Anyone ping external APIs from Aras?
Hi Forums, Wondering if anyone uses Aras to send requests out to third party apps? i.e. taking a Part's form data and sending it to openAI API for a summary and waiting for its response and output the text to a new tab for example? I know there's also linking with third party software, but has anyone done any custom API development in their own C# or JS aras methods? Best, FrankFailed to Fetch error
Hi all, I have been getting a 'failed to fetch' message over the past month when opening and searching across Aras. I get the message and the content usually won't load, but sometimes does. It's very intermittent (few times per week), and I've tried local troubleshooting but am not having any luck getting it to go away permanently. Has anyone seen this? I'm on version 22 (SaaS).1like2CommentsIs it possible to change color for TGV row/cell based on some conditions
Hi Experts, We have use case to change color of TGV row/cell based on some conditions. We are exploring various options to implement color change in TGV row/cell or at least text color. But not able to get any working solutions. Could you please suggest if it possible to achieve it. If yes, could you please share steps to implement solution. Example: Change TGV cell for rows with State - Released or Change Text color 'Released' to Red/GreenExtending Permissions to Item Properties
Has anyone successfully extended permissions to the item property level? I need to configure property‑level permissions in Aras Innovator so that modification and visibility of specific properties on an ItemType are controlled by user identity, beyond the standard item‑level permission and lifecycle security. This cannot be a purely UI/visual restriction (e.g., hiding fields via Forms or client‑side methods only). It must be enforced as a true permission/authorization control so that users cannot modify restricted properties using AML, REST, external integrations, or custom clients. Example Situation: Starting with 3 ‘Property Permission’ sets, one for Electrical, Software, and Mechanical Each Permission Set has 4 identities, one for Mechanical Engineers, Electrical Engineers, Software Engineers, and Non-Engineers. The permissions allow all of the engineers to Discover / get, but only one engineering group can update, and non-engineers have no access. Then modifying the 'Property' itemtype to have a lookup property to permissions And creating an ItemType called ‘PropertyPermissionItemType’ with 3 properties 'owned' by the different engineering groups, linked to the previously created permissions And the idea is that these property Level permissions would determine who could view and update these properties. It seems like theres a basic structure for it, but what would have to be done to actually implement the permissions at this level?0likes0CommentsUse of wildcards in a Multi-value Lists
Is there a way to make multi-value lists (not in search grid) searchable via wildcards (*, $, |,...)? Many times the dropdown lists are long: codes must be known by heart, or descriptions need to be 100% correct. Having the ability to use wildcards would increase user efficiency and experience.Logging & Progressbars Inside Innovator
In Aras, we have a lot of different automations running at any given time, and there is no clean way (I know of) to see them all in one place. Further, I don't have access to the server, so I can't access the log files you might typically see so I'm looking for a way to write those directly into Aras. So I set out to address these issues, by creating an ItemType called Progressbar with fields for tracking progress and on the form I created a html object and a button to trigger a 'ProgressBarClient' Method, which repeatedly calls a 'ProgressBarServer' Method multiple times. This gets me an interface to see the status of the processing... So before I spend too much time on this, I thought I'd see if the community has any ideas on better ways to approach this or ideas for improvement. Some thoughts: Using the button on the item probably wasn't the best move, it stops processing if you close the item. It also gave me a lot of headaches getting the typing right I should probably set it up so the C# method doesn't require a return to update the progress I was hoping for a live progressbar in the search grid... but using the html on the form isn't going to work because its not a property // Javascript Client Method: ProgressBarClient console.group("---Action Trigger---"); // ProgressBar ItemType Values // barmin - int - minimum value of progressbar // barmax - int - maximum value of progressbar // barvalue - int - current value of progressbar // barpercent - decimal - % complete, barvalue / barmax // currenttask - string - text description of current action // debuglog - Text - log of all activity // errorlog - Text - log of error messages console.log("Name: ProgressBar Prototype"); console.log("Description: This will call a server side method and update a progressbar"); console.log(""); console.log("Setting up progressbar..."); // --- Instantiate Innovator object at the beginning --- var inn; try { inn = new Innovator(); console.log("Innovator object instantiated successfully."); } catch (e) { console.error("CRITICAL ERROR: Failed to instantiate Innovator. The global 'Innovator' might not be a constructor or is not available. Error: " + e.message); alert("An internal error occurred. Please contact support. (Innovator instantiation failed)"); console.groupEnd(); return; } // Basic check to ensure 'inn' is a valid object after instantiation if (!inn || typeof inn.getItemById !== 'function') { console.error("CRITICAL ERROR: The 'inn' object does not have the expected Aras API methods (e.g., getItemById) even after instantiation."); alert("An internal error occurred. Please contact support. (Invalid Innovator object)"); console.groupEnd(); return; } console.log("Innovator object retrieved and validated."); // Get the current Aras Item object (assuming parent.item is available and is an XML DOM node) var currentArasItemXml = parent.item; if (!currentArasItemXml) { console.error("CRITICAL ERROR: Aras Item XML object (parent.item) could not be retrieved."); alert("An internal error occurred. Please contact support. (Aras Item XML not found)"); console.groupEnd(); return; } console.log("Current Aras Item XML object retrieved."); var itemId = currentArasItemXml.getAttribute('id'); console.log("item ID:" + itemId); var itemTypeName = currentArasItemXml.getAttribute('type'); console.log("item Type:" + itemTypeName); if (!itemId || !itemTypeName) { console.error("CRITICAL ERROR: Item ID or ItemType name not found from parent.item."); alert("An internal error occurred. Please contact support. (Item ID/Type missing)"); console.groupEnd(); return; } var currentArasItem = inn.getItemById(itemTypeName, itemId); if (currentArasItem.isError()) { console.error("CRITICAL ERROR: Failed to fetch full Aras Item object: " + currentArasItem.getErrorString()); alert("An internal error occurred. Please contact support. (Failed to fetch item)"); console.groupEnd(); return; } console.log("Full Aras Item object fetched."); // Find the form field control for our property var propName = "html0"; // This is correct based on your HTML inspection var fieldContainerEl; // This will be the <div> with name="html0" var targetHtmlEl; // This will be the inner <div class="sys_f_value"> // --- MODIFIED: Robust way to find the field element without aras.uiFindField --- console.log("Attempting to find field for property: " + propName + " directly in the DOM..."); // Try to find the element in the current document (most likely the iframe document) fieldContainerEl = document.getElementsByName(propName)[0]; // If not found, try to find it in the top document (less likely for form fields, but a fallback) if (!fieldContainerEl) { try { fieldContainerEl = top.document.getElementsByName(propName)[0]; } catch (e) { console.warn("Could not access top.document directly to find field. Error: " + e.message); } } if (!fieldContainerEl) { console.error("CRITICAL ERROR: Progress bar field '" + propName + "' not found on form. Please ensure the field's HTML 'name' attribute is '" + propName + "' and the form is loaded."); alert("Progress bar field '" + propName + "' not found on form. Please ensure the field's HTML 'name' attribute is '" + propName + "' and the form is loaded."); console.groupEnd(); return; } console.log("Progress bar field container element found. Name attribute used: " + fieldContainerEl.name); // Find the inner div with class "sys_f_value" to inject the HTML targetHtmlEl = fieldContainerEl.querySelector('.sys_f_value'); if (!targetHtmlEl) { console.error("CRITICAL ERROR: Could not find the inner '.sys_f_value' div within the '" + propName + "' field container."); alert("An internal error occurred. Please contact support. (Target HTML element for injection not found)"); console.groupEnd(); return; } console.log("Target HTML element for injection found."); // --- END MODIFIED SECTION --- // Create basic progress bar HTML function renderBar(percent, currentTask) { percent = Math.max(0, Math.min(100, percent)); return '' + '<div style="border:1px solid #999;width:100%;height:18px;background:#f5f5f5;">' + ' <div style="height:100%;width:' + percent + '%;background:#4caf50;transition:width 0.2s;"></div>' + '</div>' + '<div style="font-size:10px;margin-top:2px;">' + percent.toFixed(2) + '% ' + (currentTask ? '(' + currentTask + ')' : '') + '</div>'; } // Helper to set the field value + UI function setProgress(barvalue, barmax, currenttask) { var percent = (barmax > 0) ? (barvalue / barmax) * 100 : 0; var renderedHtml = renderBar(percent, currenttask); // Update rendered field in current UI targetHtmlEl.innerHTML = renderedHtml; } // Initialize at 0% setProgress(0, 100, "Initializing..."); console.log("Progress bar initialized to 0%."); // --- START: Replaced simulated work with Server Method call --- // Variables to maintain state across server calls var progressItemId = null; // Stores the ID of the Progressbar item created/updated by the server var currentStep = 0; // Stores the current step to send to the server // Function to call the server method and update progress function callServerMethodForProgress(initialCall) { console.log("Calling the server-side method 'ProgressBarServer'..."); var serverMethod = inn.newItem("Method", "ProgressBarServer"); serverMethod.setProperty("itemId", itemId); // Pass the ID of the item that triggered this client method serverMethod.setProperty("itemTypeName", itemTypeName); // Pass the ItemType name serverMethod.setProperty("initialCall", initialCall ? "true" : "false"); serverMethod.setProperty("progressItemId", progressItemId || ""); // Pass the ID of the Progressbar item serverMethod.setProperty("currentStep", currentStep.toString()); // Pass the current step var result = serverMethod.apply(); if (result.isError()) { var errorMsg = result.getErrorString(); console.error("Server method 'ProgressBarServer' error: " + errorMsg); alert("Server method error: " + errorMsg); setProgress(0, 100, "Error: " + errorMsg); // Show error in progress bar console.groupEnd(); return; // Stop progress } // Parse the response from the server method var progressItem = result.getItemByIndex(0); if (!progressItem || progressItem.isError()) { console.error("Server method 'ProgressBarServer' returned an invalid or empty item."); alert("Server method returned invalid data."); setProgress(0, 100, "Error: Invalid server response"); console.groupEnd(); return; } // Extract properties from the server's response progressItemId = progressItem.getProperty("id", progressItemId); // Update progressItemId if it's the first call var barmin = parseInt(progressItem.getProperty("barmin", "0")); var barmax = parseInt(progressItem.getProperty("barmax", "100")); var barvalue = parseInt(progressItem.getProperty("barvalue", "0")); var barpercent = parseFloat(progressItem.getProperty("barpercent", "0")); var currenttask = progressItem.getProperty("currenttask", "Processing..."); var debuglog = progressItem.getProperty("debuglog", ""); var errorlog = progressItem.getProperty("errorlog", ""); var isComplete = progressItem.getProperty("is_complete", "false") === "true"; currentStep = parseInt(progressItem.getProperty("next_step", (currentStep + 1).toString())); // Get next step from server console.log("Server response - Value: " + barvalue + ", Max: " + barmax + ", Task: " + currenttask + ", Complete: " + isComplete + ", Progress Item ID: " + progressItemId); if (debuglog) console.log("Server Debug Log:\n" + debuglog); if (errorlog) console.error("Server Error Log:\n" + errorlog); // Update the client-side progress bar setProgress(barvalue, barmax, currenttask); // Persist the progress to the Progressbar ItemType (if it's the item being edited) // This assumes the form you are on *is* the Progressbar ItemType form. // If this client method is on a *different* ItemType's form, you would need to // load the Progressbar item by its ID and update its properties. if (itemTypeName === "Progressbar" && itemId === progressItemId) { currentArasItem.setProperty("barmin", barmin.toString()); currentArasItem.setProperty("barmax", barmax.toString()); currentArasItem.setProperty("barvalue", barvalue.toString()); currentArasItem.setProperty("barpercent", barpercent.toFixed(2)); currentArasItem.setProperty("currenttask", currenttask); currentArasItem.setProperty("debuglog", debuglog); currentArasItem.setProperty("errorlog", errorlog); // Note: This only updates the client-side item object. // To save to the database, the user would need to click 'Save' on the form, // or you would need to explicitly call currentArasItem.apply("update") here, // which might be too frequent and cause performance issues. // The server method already saves the Progressbar item. } else { // If the client method is on a different ItemType, we need to explicitly update the Progressbar item // This is an example of how to update the Progressbar item from a different context var updateProgressItem = inn.newItem("Progressbar", "edit"); updateProgressItem.setID(progressItemId); updateProgressItem.setProperty("barmin", barmin.toString()); updateProgressItem.setProperty("barmax", barmax.toString()); updateProgressItem.setProperty("barvalue", barvalue.toString()); updateProgressItem.setProperty("barpercent", barpercent.toFixed(2)); updateProgressItem.setProperty("currenttask", currenttask); updateProgressItem.setProperty("debuglog", debuglog); updateProgressItem.setProperty("errorlog", errorlog); // updateProgressItem.apply("update"); // Uncomment if you want to save from client, but server already does this. } if (!isComplete) { // If not complete, call the server method again after a short delay setTimeout(function () { callServerMethodForProgress(false); }, 500); // Adjust delay as needed } else { inn.showStatusMessage("Processing completed.", "info"); console.log("Processing completed."); console.groupEnd(); } } // Start the process by making the initial call to the server method callServerMethodForProgress(true); // --- END: Replaced simulated work --- console.log("Notify user of completion (handled by showStatusMessage)"); // C# Server Method: ProgressBarServer Innovator innovator = this.getInnovator(); // Get parameters from the client string progressItemId = this.getProperty("itemId"); string currentStepStr = this.getProperty("currentStep", "0"); int currentStep = int.Parse(currentStepStr); Item progressBarItem; int barmin = 0; int barmax = 10; // Define total steps for the simulated task // --- Step 1: Load the existing Progressbar Item --- if (string.IsNullOrEmpty(progressItemId)) { return innovator.newError("Error: 'progressItemId' is required but was not provided. The Progressbar item must exist."); } // Load the item first to get its current state progressBarItem = innovator.newItem("Progressbar", "get"); progressBarItem.setID(progressItemId); progressBarItem = progressBarItem.apply(); if (progressBarItem.isError()) { return innovator.newError("Failed to load Progressbar item (ID: " + progressItemId + "): " + progressBarItem.getErrorString()); } // Ensure barmax is consistent if it was set on creation barmax = int.Parse(progressBarItem.getProperty("barmax", barmax.ToString())); // --- Step 2: Attempt to lock the item for update --- // Use the loaded item to attempt the lock. // This is important: applying 'lock' on the loaded item ensures we're working with the same item instance. Item lockResult = progressBarItem.apply("lock"); if (lockResult.isError()) { string errorString = lockResult.getErrorString(); // Check for the specific Aras error message indicating it's already locked by *this* user. // The exact message for "already locked by current user" can vary slightly. // We'll use a broader check for "locked" and then check the user. if (errorString.Contains("Item is already locked") || errorString.Contains("Aras.Server.Core.ItemIsAlreadyLockedException")) { // Now, check *who* locked it. // Get the locked_by property from the item (if it exists and is populated) string lockedById = progressBarItem.getProperty("locked_by_id", ""); string currentUserId = innovator.getUserID(); if (lockedById == currentUserId) { // Item is already locked by the current user. This is expected in polling. // Proceed with the update. No error needed. System.Diagnostics.Trace.WriteLine("DEBUG: Progressbar item (ID: " + progressItemId + ") already locked by current user. Proceeding."); } else if (!string.IsNullOrEmpty(lockedById)) { // Item is locked by another user. This is a genuine conflict. Item lockedByUser = innovator.getItemById("User", lockedById); string lockedByUserName = lockedByUser.getProperty("keyed_name", "Unknown User"); return innovator.newError("Failed to lock Progressbar item (ID: " + progressItemId + "): Item is already locked by another user: " + lockedByUserName + "."); } else { // Item is locked, but locked_by_id is not set or couldn't be determined. // This might indicate a stale lock or an unexpected state. return innovator.newError("Failed to lock Progressbar item (ID: " + progressItemId + "): Item is already locked, but the locker could not be identified. Error: " + errorString); } } else { // Some other locking error occurred. return innovator.newError("Failed to lock Progressbar item (ID: " + progressItemId + "): " + errorString); } } // If lockResult is not an error, or if it was already locked by current user, // the progressBarItem is now locked by this session and ready for update. // --- Step 3: Simulate work and update progress --- string currentTaskDescription = ""; bool isComplete = false; // Simulate different steps switch (currentStep) { case 0: currentTaskDescription = "Step 1: Preparing data..."; System.Threading.Thread.Sleep(500); // Simulate work break; case 1: currentTaskDescription = "Step 2: Processing records..."; System.Threading.Thread.Sleep(700); // Simulate work break; case 2: currentTaskDescription = "Step 3: Validating inputs..."; System.Threading.Thread.Sleep(400); // Simulate work break; case 3: currentTaskDescription = "Step 4: Performing calculations..."; System.Threading.Thread.Sleep(800); // Simulate work break; case 4: currentTaskDescription = "Step 5: Generating reports..."; System.Threading.Thread.Sleep(600); // Simulate work break; case 5: currentTaskDescription = "Step 6: Saving results..."; System.Threading.Thread.Sleep(500); // Simulate work break; case 6: currentTaskDescription = "Step 7: Finalizing process..."; System.Threading.Thread.Sleep(300); // Simulate work break; case 7: currentTaskDescription = "Step 8: Cleaning up temporary files..."; System.Threading.Thread.Sleep(200); // Simulate work break; case 8: currentTaskDescription = "Step 9: Notifying stakeholders..."; System.Threading.Thread.Sleep(100); // Simulate work break; case 9: currentTaskDescription = "Step 10: Task completed."; isComplete = true; break; default: currentTaskDescription = "Unknown step or task completed."; isComplete = true; break; } // Update properties on the progressBarItem object int barvalue = currentStep + 1; // Increment value for the next step if (isComplete) barvalue = barmax; // Ensure it reaches max when complete double barpercent = (double)barvalue / barmax * 100; progressBarItem.setProperty("barvalue", barvalue.ToString()); progressBarItem.setProperty("barpercent", barpercent.ToString("F2")); // Format to 2 decimal places progressBarItem.setProperty("currenttask", currentTaskDescription); progressBarItem.setProperty("debuglog", progressBarItem.getProperty("debuglog", "") + currentTaskDescription + " at " + DateTime.Now.ToString("HH:mm:ss") + "\n"); // --- Step 4: Persist the updated Progressbar item --- // At this point, progressBarItem *must* be locked by this session. Item updateResult = progressBarItem.apply("update"); if (updateResult.isError()) { // If update fails here, it's a critical error. // This could still be a locking issue if the lock was somehow lost or not acquired correctly. return innovator.newError("Failed to update Progressbar item (ID: " + progressItemId + "): " + updateResult.getErrorString()); } // --- Step 5: Prepare the response for the client --- Item resultItem = innovator.newItem("Progressbar", "get"); // Return the updated Progressbar item resultItem.setProperty("id", progressItemId); // Ensure the ID is returned resultItem.setProperty("barmin", progressBarItem.getProperty("barmin")); resultItem.setProperty("barmax", progressBarItem.getProperty("barmax")); resultItem.setProperty("barvalue", progressBarItem.getProperty("barvalue")); resultItem.setProperty("barpercent", progressBarItem.getProperty("barpercent")); resultItem.setProperty("currenttask", progressBarItem.getProperty("currenttask")); resultItem.setProperty("debuglog", progressBarItem.getProperty("debuglog")); resultItem.setProperty("errorlog", progressBarItem.getProperty("errorlog")); resultItem.setProperty("is_complete", isComplete ? "true" : "false"); resultItem.setProperty("next_step", (currentStep + 1).ToString()); // Tell client the next step to send // --- Step 6: Unlock the item if the task is complete --- Item unlockResult = progressBarItem.apply("unlock"); // Unlock the item that was locked if (unlockResult.isError()) { // Log the unlock error, but don't fail the entire method as the task is complete. System.Diagnostics.Trace.WriteLine("ERROR: Failed to unlock Progressbar item (ID: " + progressItemId + "): " + unlockResult.getErrorString()); } return resultItem;Report Manager shows blank page on Aras Innovator 14.35 CE – Hotfix and Reporting 29 guidance needed
Hello Community, I am evaluating Aras Innovator 14.35 Community Edition and am currently facing an issue with Report Manager, where the result page is displayed as a blank screen. Before asking, I would like to clarify that I believe I understand the separation of concerns, and I am seeking confirmation on the correct and minimal path forward. Environment Aras Innovator: 14.35 Community Edition Build: 14.35.0.44037 MS Build Number: 000000.00 Browser: Chrome / Edge (same behavior) OS: Windows Server (IIS) Observed issue When executing a report (Type: General) from Report Manager, the result page is blank. From the browser network trace, I can see that blank.html is requested with an incorrect URL where an X-salt token is injected into the path, for example: .../InnovatorServer/Client/X-salt=std_14.35.0.44037-X/scripts/blank.html Instead of: .../InnovatorServer/Client/scripts/blank.html The AML itself executes successfully (InnovatorServer.aspx returns 200), so the issue seems to be on the client / UI side. What I understand so far Please correct me if anything below is wrong. 1. Hotfix / Patch Hotfixes apply to the Innovator core (Server / Client). MS Build Number = 000000.00 indicates that this environment is likely running a base build without Hotfixes applied. Therefore, this blank page issue may already be a known issue fixed by a Hotfix. 2. Reporting Aras Reporting is a separate product and installer. Reporting 29 requires a dedicated license (Aras.Reporting) and installation. Reporting 28 is not required if installing Reporting 29 as a new installation. My questions To proceed efficiently without rebuilding the environment, I would appreciate guidance on the following: 1. Is it correct that applying the appropriate Hotfix for Innovator 14.35 is a prerequisite, and that Reporting alone would not resolve the blank page issue? 2. Is the blank page / X-salt URL issue a known problem in the base 14.35 build that is addressed by a specific Hotfix? 3. For a Community Edition evaluation environment, is it realistic to: obtain the required Hotfix, and obtain the Aras Reporting 29 CD Image as part of the same guidance / recommendation? 4. If Reporting 29 is installed after the Hotfix, should Report Manager work as expected without additional undocumented steps? Goal / Constraints The goal is to evaluate Report Manager functionality. I would like to avoid rebuilding the existing test environment if possible. I am looking for the shortest correct path, even if it involves multiple steps, as long as the sequence is clear. Any advice, confirmation, or references would be greatly appreciated. Thank you in advance.
Tags
- Methods116 Topics
- ItemTypes107 Topics
- Version 1299 Topics
- Forms98 Topics
- Relationships97 Topics
- JavaScript85 Topics
- Installation70 Topics
- Workflows68 Topics
- AML68 Topics
- Server Methods53 Topics