Action
Recon
UPDATES
over 3 years ago
RECON-07:
- Added folder listing checks for Syntaxes and Themes.
- Added explicit external library check for TADpoLe.
This action has been created to help get information about a user’s set-up in Drafts when they are having issues, but can be used by anyone who is simply curious about their set-up.
The action queries the Drafts app for information. You select what sets of information to query for, and the output can be previewed as well as copied to the clipboard in various formats.
Please note file access for Drafts can be very slow. If you have a complex file structure within any of your Drafts folders, please be aware that it can take quite a while to run on iOS and iPadOS. A mitigation utilising shell scripting and the system clipboard has been used to improve the performance of these listings on macOS.
Steps
-
script
const RVER = `RECON-07`; let g_strHTMLCSS = ` <style> @charset "UTF-8"; :root { --main-bg-color: white; --main-color: black; --alternate-bg-color: #efefef; --alternate-color: #222222; --main-border-color: #BBBBBB; --link-color: #627EC9; } @media (prefers-color-scheme: dark) { :root { --main-bg-color: #222222; --main-color: #53C8D6; --alternate-bg-color: #444444; --alternate-color: #cccccc; --main-border-color: #AAAAAA; --link-color: #627EC9; } } html { font-size: 100%; font-family: -apple-system, BlinkMacSystemFont, "Noto Color Emoji", "Apple Color Emoji", "Segoe UI Emoji", "helvetica neue", helvetica, roboto, noto, "segoe ui", arial, sans-serif; line-height: 1.4; } body { margin: 0; padding: 1em; background-color: var(--main-bg-color); color: var(--main-color); } @media (max-device-width: 700px) {} @media (min-device-width: 701px) { body { margin: auto; max-width: 600px; } } blockquote { font-style: italic; margin: 1.5em 2em; padding: 1em; background-color: var(--alternate-bg-color); color: var(--alternate-color); } a { color: var(--link-color); } pre { width: 100%; background-color: var(--alternate-bg-color); margin: 1em 0; white-space: pre-wrap; } code { background-color: var(--alternate-bg-color); color: var(--alternate-color); font-family: Menlo, Courier, sans-serif; padding: 2px 3px; white-space: pre-wrap; } strong { color: white; } h1 { color: orange; } table { margin: 1.5em 0; border: 1px solid var(--main-border-color); border-collapse: collapse; } th { padding: .25em .5em; background: var(--alternate-bg-color); border: 1px solid var(--main-border-color); } td { padding: .25em .5em; border: 1px solid var(--main-border-color); } img { max-width: 90%; } form { padding: 1em; } .verticalLine { border-left: 2px solid orange; padding-left: 5px; margin-bottom: 5px; font-style: italic; } </style> ` let g_strSelectHTML = `<!DOCTYPE html> <html dir="auto"> <head> <title>Recon Select Options</title> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> ${g_strHTMLCSS} </head> <body> <form id="frmSelection" autocomplete="off" autocorrect="off"> <strong>Drafts Set-up</strong><br> <input type="checkbox" id="cbDrafts"> Drafts Info<br> <input type="checkbox" id="cbEditor"> Editor Info<br> <input type="checkbox" id="cbWorkspaces"> Workspace Info<br> <input type="checkbox" id="cbCurrentWorkspace"> Current Workspace<br> <br><strong>Device</strong><br> <input type="checkbox" id="cbDevice"> Device Info<br> <br><strong>File System</strong><br> <div class="verticalLine">Please note that file system queries on the Mac make use of the clipboard to speed up retrieval of directory listings for large and complex folder structures.</div> <input type="checkbox" id="cbPreviewListing"> Directory Listing for Previews<br> <input type="checkbox" id="cbScriptsListing"> Directory Listing for Scripts<br> <input type="checkbox" id="cbSyntaxesListing"> Directory Listing for Syntaxes<br> <input type="checkbox" id="cbTemplatesListing"> Directory Listing for Templates<br> <input type="checkbox" id="cbThemesListing"> Directory Listing for Themes<br> --- <br> <input type="checkbox" id="cbListingIncludeDotted"> <span style="color:lightgray; font-style: italic;">Include Files Beginning with a Period in Directory Listings?</span><br> <br><strong>Actions</strong><br> <input type="checkbox" id="cbActionGroupListing"> Action Group Listing<br> <input type="checkbox" id="cbActionListing"> Action Listing<br> <input type="checkbox" id="cbActionKeyboardShortcutsListing"> Action Keyboard Shortcuts Listing<br> <br><strong>Current Draft</strong><br> <input type="checkbox" id="cbCurrentInfo"> Current Draft Info<br> <input type="checkbox" id="cbCurrentVersions"> Current Draft's Versions<br> <input type="checkbox" id="cbCurrentExample"> Current Draft Content<br> <br><strong>External Libraries</strong><br> <input type="checkbox" id="cbTADpoLe"> TADpoLe<br> <hr> <input type="checkbox" id="cbPreview" checked> Preview Results<br> <p>Copy Results? <select id="selClipboard"> <option value="no" selected="selected">No</option> <option value="mmd">As MultiMarkdown</option> <option value="hidden">As MultiMarkdown in a Hidden Details Section</option> <option value="html">As HTML</option> <option value="rich">As Rich Text</option> </select> </p> <div style="margin: 1em 0 3em 0;"> <button id="sub" onclick="submitFormById('frmSelection'); return false;">Submit</button> <button id ="cancel" onclick="Drafts.cancel(); return false;">Cancel</button> </div> </form> </body> <script> function serialiseForm(p_objForm) { //Initialise let objData = {}; //Add returnable items to the data object for(let element of p_objForm.elements) { if (element.type && element.type === 'checkbox') { objData[element.id] = element.checked; } else if (element.type == 'submit') { //Ignore } else { objData[element.id] = element.value; } } //Return the data object return objData; }; function submitFormById(p_strFormID) { //Get the form let objForm = document.getElementById(p_strFormID); //Transform all of the returnable form elements into an object let objData = serialiseForm(objForm); //Send the object to Drafts and return a continue code Drafts.send("formValues", objData); Drafts.continue(); return; } function checkKeyPress(p_objKey) { if (p_objKey.keyCode == '13') submitFormById('frmSelection'); return false; } </script> </html>` function b2s(p_bBoolean) { if (p_bBoolean) return "true"; else return "false"; } //Show the HTML prompt to select what to output function selectOptions(p_strHTML) { let hp = new HTMLPreview; hp.hideInterface = true; if (hp.show(p_strHTML)) return context.previewValues["formValues"]; else return false; } function detailsTADpoLe() { let fmCloud = FileManager.createCloud(); // iCloud let strCode = fmCloud.readString("/Library/Scripts/tad.js") if (strCode != undefined) { let strVersion = strCode.match(/ \* @version.*/)[0]; return "**TADpoLe:** Version " + strVersion.substring(11) + " installed."; } else return "**TADpoLe:** Not Installed." } function detailsDevice() { return `# Device Information - **Model:** ${device.model} - **OS Version:** ${device.systemVersion} - **System Name:** ${device.systemName} - **Battery Level:** ${device.batteryLevel} ` } function detailsDrafts() { return `# Drafts Information - **Version:** ${app.version} - **Pro Subscription Enabled:** ${b2s(app.isPro)} - **Idle Disabled:** ${b2s(app.isIdleDisabled)} - **Draft List Visible:** ${b2s(app.isDraftListVisible)} - **Action List Visible:** ${b2s(app.isActionListVisible)} - **Theme:** ${app.currentThemeMode} - **Drafts in Inbox:** ${Draft.query("", "inbox", [], [], "created").length} - **Drafts in Archive:** ${Draft.query("", "archive", [], [], "created").length} - **Drafts in Flagged:** ${Draft.query("", "flagged", [], [], "created").length} - **Drafts in Trash:** ${Draft.query("", "trash", [], [], "created").length} ` } function detailsExternalLibraries(p_astrSelection) { let astrOutput = [`# External Libraries`] if (p_astrSelection.cbTADpoLe) astrOutput.push(detailsTADpoLe()); return astrOutput.join("\n"); } function detailsCurrentWorkspace() { return `# Current Workspace\n` + detailsWorkspace(app.currentWorkspace, true); } function detailsWorkspaces() { strOutput = "# Workspaces\n"; Workspace.getAll().forEach(function(wsCurrent) { strOutput += "\n## " + wsCurrent.name; strOutput += detailsWorkspace(wsCurrent, false) + "\n"; }); return strOutput; } function detailsWorkspace(p_wsToCheck, p_bIncludeName) { let strWorkspace = ""; if (p_bIncludeName) if (p_wsToCheck.name != undefined) strWorkspace += `\n- **Name:** ${p_wsToCheck.name}` if(p_wsToCheck.queryString != undefined) strWorkspace += `\n- **Query String:** ${p_wsToCheck.queryString}` if(p_wsToCheck.tagFilter != undefined) strWorkspace += `\n- **Tag Filter:** ${p_wsToCheck.tagFilter}` if(p_wsToCheck.tagFilterRequireAll != undefined) strWorkspace += `\n- **Require All Tags:** ${b2s(p_wsToCheck.tagFilterRequireAll)}` if(p_wsToCheck.startDate != undefined) { strWorkspace += `\n- **Start Date Field:** ${p_wsToCheck.startDate.field}` strWorkspace += `\n- **Start Date Type:** ${p_wsToCheck.startDate.type}` strWorkspace += `\n- **Start Date Date (>=):** ${p_wsToCheck.startDate.date}` strWorkspace += `\n- **Start Date Days (>=):** ${p_wsToCheck.startDate.days}` } if(p_wsToCheck.endDate != undefined) { strWorkspace += `\n- **End Date Field:** ${p_wsToCheck.endDate.field}` strWorkspace += `\n- **End Date Type:** ${p_wsToCheck.endDate.type}` strWorkspace += `\n- **End Date Date (<=):** ${p_wsToCheck.endDate.date}` strWorkspace += `\n- **End Date Days (<=):** ${p_wsToCheck.endDate.days}` } if(p_wsToCheck.inboxIncludesFlagged != undefined) strWorkspace += `\n- **Inbox Includes Flagged:** ${b2s(p_wsToCheck.inboxIncludesFlagged)}` if(p_wsToCheck.archiveIncludesFlagged != undefined) strWorkspace += `\n- **Archive Includes Flagged:** ${b2s(p_wsToCheck.archiveIncludesFlagged)}` if(p_wsToCheck.loadFolder != undefined) strWorkspace += `\n- **Load Folder:** ${p_wsToCheck.loadFolder}` if(p_wsToCheck.loadActionBarGroup != undefined) strWorkspace += `\n- **Load Action Bar Group:** ${p_wsToCheck.loadActionBarGroup.name} (${p_wsToCheck.loadActionBarGroup.uuid})` if(p_wsToCheck.loadActionListGroup != undefined) strWorkspace += `\n- **Load Action List Group:** ${p_wsToCheck.loadActionListGroup.name} (${p_wsToCheck.loadActionListGroup.uuid})` if(p_wsToCheck.showLastAction != undefined) strWorkspace += `\n- **Show Last Action for Draft in List:** ${b2s(p_wsToCheck.showLastAction)}` if(p_wsToCheck.showPreview != undefined) strWorkspace += `\n- **Show Body Prfeview for Draft in List:** ${b2s(p_wsToCheck.showPreview)}` if(p_wsToCheck.showTags != undefined) strWorkspace += `\n- **Show Tags for Draft in List:** ${b2s(p_wsToCheck.showTags)}` return strWorkspace; } // Get all actions. ActionGroup.getAllActions = function() { let aactAll = []; ActionGroup.getAll().forEach(function(actgrpCurrent){aactAll = aactAll.concat(actgrpCurrent.actions);}); return aactAll; } // Populate an action object with a keyboard shortcut property Action.prototype.populateKeyboardShortcut = function() { //Get the installation data for an action from its install URL let jsonActionData = JSON.parse(decodeURIComponent(this.installURL.replace("drafts5://action?data=",""))); //Keyboard shortcut if (jsonActionData.hasOwnProperty("keyCommand")) { this._keyShift = jsonActionData.keyCommand.shiftKey; this._keyControl = jsonActionData.keyCommand.controlKey; this._keyOption = jsonActionData.keyCommand.optionKey; this._keyCommand = jsonActionData.keyCommand.commandKey; if(jsonActionData.keyCommand.input.length > 0) { //Deal with the encoding for the special keys that are available switch (jsonActionData.keyCommand.input) { case "#LEFT": this._keyInput = "← "; break; case "#RIGHT": this._keyInput = "→ "; break; case "#UP": this._keyInput = "↑ "; break; case "#DOWN": this._keyInput = "↓ "; break; case "#TAB": this._keyInput = "⭾"; break; default: this._keyInput = jsonActionData.keyCommand.input; } this._keyHas = true; } else { this._keyInput = ""; this._keyHas = false; } //Build the shortcuts key let astrKeyShortcut = []; if (this._keyShift) astrKeyShortcut.push("⇧"); if (this._keyControl) astrKeyShortcut.push("^"); if (this._keyOption) astrKeyShortcut.push("⌥"); if (this._keyCommand) astrKeyShortcut.push("⌘"); if (this._keyInput.length > 0) astrKeyShortcut.push(this._keyInput); this._keyShortcut = astrKeyShortcut.join(""); } else { this._keyShortcut = ""; this._keyShift = false; this._keyControl = false; this._keyOption = false; this._keyCommand = false; this._keyInput = ""; } return; } function detailsActionShortcuts() { let astrOutput = []; ActionGroup.getAllActions().forEach(function(acCurrent) { acCurrent.populateKeyboardShortcut(); if (acCurrent._keyShortcut != "") { let strKeys = acCurrent._keyShortcut; let intLen = 1; if (acCurrent._keyShift) intLen++; if (acCurrent._keyControl) intLen++; if (acCurrent._keyOption) intLen++; if (acCurrent._keyCommand) intLen++; let intSpaces = 6 - intLen; for (let intCounter = 0; intCounter < intSpaces; intCounter++) { strKeys = strKeys + " "; } strKeys = strKeys.replaceAll("§", "§") astrOutput.push(`${strKeys}${acCurrent.name}`); } }); return "# Actions with Keyboard Shortcuts\n<pre>" + astrOutput.join("\n") + "</pre>"; } function checkFolder(p_strFolder, p_bIncludeDotted = false) { let astrOutput = []; app.displayWarningMessage(`Checking content of "${p_strFolder}...`) let fmCloud = FileManager.createCloud(); let astrListing = fmCloud.listContents(p_strFolder) astrListing.forEach(function (strItemPath) { if (!p_bIncludeDotted && !strItemPath.includes("/.")) { astrOutput.push(strItemPath); if (strItemPath.endsWith("/")) astrOutput = astrOutput.concat(checkFolder(strItemPath)); } }); return astrOutput; } function checkFolderMac(p_strFolder, p_bIncludeDotted = false) { let strLSparams = "-R1 "; if (p_bIncludeDotted) strLSparams = "-Ra1 "; let strScript = `#!/bin/zsh echo $HOME/Library/Mobile Documents/iCloud~com~agiletortoise~Drafts5/Documents${p_strFolder} ls ${strLSparams}"$HOME/Library/Mobile Documents/iCloud~com~agiletortoise~Drafts5/Documents${p_strFolder}" | pbcopy `; let shMain = ShellScript.create(strScript); if (shMain.execute()) return app.getClipboard(); else return shMain.standardError; } function detailsPreviewsListing(p_bListingIncludeDotted) { if(device.systemName == 'macOS') { return "# Previews Listing\n<pre>" + checkFolderMac("/Library/Previews", p_bListingIncludeDotted) + "</pre>"; } else { let astrListing = checkFolder("/Library/Previews", p_bListingIncludeDotted); return "# Previews Listing\n<pre>" + astrListing.join("\n") + "</pre>"; } } function detailsScriptsListing(p_bListingIncludeDotted) { if(device.systemName == 'macOS') { return "# Scripts Listing\n<pre>" + checkFolderMac("/Library/Scripts", p_bListingIncludeDotted) + "</pre>"; } else { let astrListing = checkFolder("/Library/Scripts", p_bListingIncludeDotted); return "# Scripts Listing\n<pre>" + astrListing.join("\n") + "</pre>"; } } function detailsTemplatesListing(p_bListingIncludeDotted) { if(device.systemName == 'macOS') { return "# Templates Listing\n<pre>" + checkFolderMac("/Library/Templates", p_bListingIncludeDotted) + "</pre>"; } else { let astrListing = checkFolder("/Library/Templates", p_bListingIncludeDotted); return "# Templates Listing\n<pre>" + astrListing.join("\n") + "</pre>"; } } function detailsSyntaxesListing(p_bListingIncludeDotted) { if(device.systemName == 'macOS') { return "# Syntaxes Listing\n<pre>" + checkFolderMac("/Library/Syntaxes", p_bListingIncludeDotted) + "</pre>"; } else { let astrListing = checkFolder("/Library/Syntaxes", p_bListingIncludeDotted); return "# Syntaxes Listing\n<pre>" + astrListing.join("\n") + "</pre>"; } } function detailsThemesListing(p_bListingIncludeDotted) { if(device.systemName == 'macOS') { return "# Themes Listing\n<pre>" + checkFolderMac("/Library/Themes", p_bListingIncludeDotted) + "</pre>"; } else { let astrListing = checkFolder("/Library/Themes", p_bListingIncludeDotted); return "# Themes Listing\n<pre>" + astrListing.join("\n") + "</pre>"; } } String.prototype.deMarkdown = function() { let strTemp = this; strTemp = strTemp.replaceAll("\\", "\\\\`"); strTemp = strTemp.replaceAll("-", "\\-"); strTemp = strTemp.replaceAll("_", "\\_"); strTemp = strTemp.replaceAll("*", "\\*"); strTemp = strTemp.replaceAll("`", "`"); return strTemp; } function detailsActionListing() { let strOutput = []; ActionGroup.getAll().forEach(function(agCurrent) { strOutput.push("\n## " + agCurrent.name.deMarkdown()); agCurrent.actions.forEach(function (acCurrent) { if (acCurrent.isSeparator) strOutput.push("- **" + acCurrent.name.deMarkdown() + ":**"); else strOutput.push("- " + acCurrent.name.deMarkdown()); }); }); return "# Actions\n" + strOutput.join("\n"); } function detailsActionGroupListing() { let strOutput = []; let intAGCounter = 0; let intACCounter = 0; ActionGroup.getAll().forEach(function(agCurrent) { let intCounter = 0; agCurrent.actions.forEach(function (acCurrent) { if (!acCurrent.isSeparator) intCounter++; }); intAGCounter++; intACCounter = intACCounter + intCounter; strOutput.push(`- ${agCurrent.name.deMarkdown()} (${intCounter} actions)`); }); strOutput.push(`\n\n${intAGCounter} Action Groups Containing ${intACCounter} Actions.`) return "# Action Groups\n" + strOutput.join("\n"); } function detailsEditor() { strOutput = "# Editor\n"; strOutput += `- **Focus Mode Enabled:** ${b2s(editor.focusModeEnabled)}\n`; strOutput += `- **Link Mode Enabled:** ${b2s(editor.linkModeEnabled)}\n`; strOutput += `- **Typewriter Scrolling Enabled:** ${b2s(editor.typewriterScrollingEnabled)}\n`; strOutput += "- **Editor Preferred Tab String (Text):** `\"" + editor.preferredTabString + "\"`\n"; strOutput += "- **Editor Preferred Tab String (URL Encoded):** " + encodeURIComponent(editor.preferredTabString) + "\n"; return strOutput; } function detailsCurrentInfo() { let astrMarkers = []; if (editor.navigationMarkers.length > 0) { editor.navigationMarkers.forEach(function(nmMain) { astrMarkers.push(` - [${nmMain.level}] ${nmMain.prefix} : ${nmMain.label}`); }) } return `# Current Draft Information - **UUID:** ${draft.uuid} - **Title:** ${draft.title} - **Syntax:** ${draft.languageGrammar} - **Flagged:** ${b2s(draft.isFlagged)} - **Archived:** ${b2s(draft.isArchived)} - **Trashed:** ${b2s(draft.isTrashed)} - **Line Count:** ${draft.lines.length} - **Character Count:** ${draft.content.length} - **Created:** ${draft.createdAt} - **Modified:** ${draft.modifiedAt} - **Versions:** ${draft.versions.length} - **Tags:** ${draft.tags.join(" | ")} - **Navigation Markers:**\n${astrMarkers.join("\n")} `; } function detailsCurrentVersions() { let strOutput = [`# Current Draft's Versions\n`]; draft.versions.forEach(function (verDraft) { strOutput.push(`- **${verDraft.createdAt}:** ${verDraft.content.length} characters in ${verDraft.content.split('\n').length} lines - (${verDraft.uuid})`); }); return strOutput.join("\n"); } function detailsCurrentExample() { //We'll use lots of backticks to mark our code block in case the content of the draft contains a code block defined by backticks return `# Current Draft Content \`\`\`\`\`\`\`\`\`plaintext ${draft.content} \`\`\`\`\`\`\`\`\` `; } //Display Results function displayResults(p_strHTML) { let hp = new HTMLPreview; hp.hideInterface = false; hp.show(p_strHTML); return; } function recon() { //Choose what to output let astrSelection = selectOptions(g_strSelectHTML); //alert(JSON.stringify(astrSelection)); if (astrSelection != false) { //Build the output as MMD let astrOutput = []; //Drafts if (astrSelection.cbDrafts) astrOutput.push(detailsDrafts()); if (astrSelection.cbEditor) astrOutput.push(detailsEditor()); if (astrSelection.cbWorkspaces) astrOutput.push(detailsWorkspaces()); if (astrSelection.cbCurrentWorkspace) astrOutput.push(detailsCurrentWorkspace()); //Device if (astrSelection.cbDevice) astrOutput.push(detailsDevice()); //File System if (astrSelection.cbPreviewListing) astrOutput.push(detailsPreviewsListing(astrSelection.cbListingIncludeDotted)); if (astrSelection.cbScriptsListing) astrOutput.push(detailsScriptsListing(astrSelection.cbListingIncludeDotted)); if (astrSelection.cbSyntaxesListing) astrOutput.push(detailsSyntaxesListing(astrSelection.cbListingIncludeDotted)); if (astrSelection.cbTemplatesListing) astrOutput.push(detailsTemplatesListing(astrSelection.cbListingIncludeDotted)); if (astrSelection.cbThemesListing) astrOutput.push(detailsThemesListing(astrSelection.cbListingIncludeDotted)); //Actions if (astrSelection.cbActionGroupListing) astrOutput.push(detailsActionGroupListing()); if (astrSelection.cbActionListing) astrOutput.push(detailsActionListing()); if (astrSelection.cbActionKeyboardShortcutsListing) astrOutput.push(detailsActionShortcuts()); //Current Draft if (astrSelection.cbCurrentInfo) astrOutput.push(detailsCurrentInfo()); if (astrSelection.cbCurrentVersions) astrOutput.push(detailsCurrentVersions()); if (astrSelection.cbCurrentExample) astrOutput.push(detailsCurrentExample()); //External Libraries if (astrSelection.cbTADpoLe) astrOutput.push(detailsExternalLibraries(astrSelection)); //Add a generation footer astrOutput.push(`<strong>Generated at:</strong> <span style="font-family:courier">${new Date()}</span><br> <strong>Generated by:</strong> <span style="font-family:courier">${RVER}</span>`); //Combine the MMD for output let strMMD = astrOutput.join("\n\n---\n\n") //Convert MMD output to HTML for display and copying let mmd = MultiMarkdown.create(); mmd.format = "html"; mmd.completeDocument = "false"; let strHTML = `<html><head>\n<meta charset="UTF-8">\n${g_strHTMLCSS}\n</head><body>` + mmd.render(strMMD) + `\n</body></html>`; //If the option to preview was set, display it if (astrSelection.cbPreview) displayResults(strHTML); //Populate the clipboard if necessary switch(astrSelection.selClipboard) { case "mmd": app.setClipboard(strMMD); break; case "hidden": app.setClipboard(`[details="Recon Results"]\n${strMMD}\n[/details]`); break; case "html": app.setClipboard(strHTML); break; case "rich": app.htmlToClipboard(strHTML); break; default: // Default is to leave the clipboard untouched } } return; } recon();
-
script
/* VERSION INFO ============ RECON-07: - Added folder listing checks for Syntaxes and Themes. - Added explicit external library check for TADpoLe. RECON-06: - Added inbox/archive/flagged/trash counts to the Drafts information section. RECON-05: - Added current draft information, including content dump and version information. - De-Markdown action/separator and action group names so they are not interpreted on output. - Added wrapping to code sections. RECON-04: - Added higher performance file/directory listings for macOS (only). - Removed unnecessary element spacing in action group listing. RECON-03: - Fixed an action name containing emoji display bug on macOS. RECON-02: - Added several additional data gathering sections for app and action information. RECON-01: - Initial release. */
Options
-
After Success Default Notification Error Log Level Error
Items available in the Drafts Directory are uploaded by community members. Use appropriate caution reviewing downloaded items before use.