From 5093b2fb667c0b953746fd7b3aa0b03dc8b59138 Mon Sep 17 00:00:00 2001 From: Lushang Date: Mon, 15 Jul 2019 16:33:06 +0800 Subject: [PATCH 01/46] lwc basic part 1 --- config/templates/LWC/{Basic.html => lwc.html} | 0 config/templates/LWC/{Basic.js => lwc.js} | 0 .../{Basic.js-meta.xml => lwc.js-meta.xml} | 0 config/templates/templates.json | 34 +++++++++++++++++++ docs/lwc.md | 25 ++++++++++++++ lwc.py | 2 +- 6 files changed, 60 insertions(+), 1 deletion(-) rename config/templates/LWC/{Basic.html => lwc.html} (100%) rename config/templates/LWC/{Basic.js => lwc.js} (100%) rename config/templates/LWC/{Basic.js-meta.xml => lwc.js-meta.xml} (100%) create mode 100644 docs/lwc.md diff --git a/config/templates/LWC/Basic.html b/config/templates/LWC/lwc.html similarity index 100% rename from config/templates/LWC/Basic.html rename to config/templates/LWC/lwc.html diff --git a/config/templates/LWC/Basic.js b/config/templates/LWC/lwc.js similarity index 100% rename from config/templates/LWC/Basic.js rename to config/templates/LWC/lwc.js diff --git a/config/templates/LWC/Basic.js-meta.xml b/config/templates/LWC/lwc.js-meta.xml similarity index 100% rename from config/templates/LWC/Basic.js-meta.xml rename to config/templates/LWC/lwc.js-meta.xml diff --git a/config/templates/templates.json b/config/templates/templates.json index 015570a..1e743d9 100644 --- a/config/templates/templates.json +++ b/config/templates/templates.json @@ -152,5 +152,39 @@ "extension": ".page", "description": "Visualforce Page Template" } + }, + + "Lwc": { + "HTLM": { + "directory": "Lwc/lwc.html", + "extension": ".html" + }, + + "JavaScript": { + "directory": "Lwc/lwc.js", + "extension": ".js" + }, + + "Configuration": { + "directory": "Lwc/lwc.js-meta.xml", + "extension": ".js-meta.xml" + } + }, + + "LwcElement": { + "AdditionalJS": { + "directory": "LwcElement/additional.js", + "extension": ".js" + }, + + "CSS": { + "directory": "LwcElement/style.css", + "extension": ".css" + }, + + "SVG": { + "directory": "LwcElement/svg.svg", + "extension": ".svg" + } } } \ No newline at end of file diff --git a/docs/lwc.md b/docs/lwc.md new file mode 100644 index 0000000..3b35db6 --- /dev/null +++ b/docs/lwc.md @@ -0,0 +1,25 @@ +# Lightning Web Componnent + Lightning web components are custom HTML elements built using HTML and modern JavaScript. + + ## Create Lightning Web Component + +For better convenience, will create the `lwc` as `LightningComponentBundle` with three `LwcResources`: HTML File, JavaScript File and Configuration File. + + ``` + myComponent + ├──myComponent.html + ├──myComponent.js + └──myComponent.js-meta.xml +``` + +## Add CSS File + +## Add SVG Icon + +## Add Additional JavaScript File + +## Component Tests + +## Destruct File + +## Destruct lwc \ No newline at end of file diff --git a/lwc.py b/lwc.py index fe809f2..3b4bf66 100644 --- a/lwc.py +++ b/lwc.py @@ -48,7 +48,7 @@ def on_input(self, lwc_name): # Get template attribute templates = util.load_templates() - template_bundle = templates.get("LWC") + template_bundle = templates.get("Lwc") for tpl_name in template_bundle: template = template_bundle.get(tpl_name) with open(os.path.join(self._workspace, ".templates", template["directory"])) as fp: From 33cd30df19ca98867e9d1e779650b4d5fec3c090 Mon Sep 17 00:00:00 2001 From: Hao Liu Date: Mon, 15 Jul 2019 19:21:31 +0800 Subject: [PATCH 02/46] fix duplicate meta-xml file in lwc or aura --- util.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/util.py b/util.py index 168babd..c46f9f7 100644 --- a/util.py +++ b/util.py @@ -1468,10 +1468,10 @@ def build_deploy_package(files): else: zf.write(f["dir"], "%s%s/%s.%s" % write_to) - # If -meta.xml is exist, add it to folder - met_xml = f["dir"] + "-meta.xml" - if os.path.isfile(met_xml): - zf.write(met_xml, "%s%s/%s.%s-meta.xml" % write_to) + # If -meta.xml is exist, add it to folder + met_xml = f["dir"] + "-meta.xml" + if os.path.isfile(met_xml): + zf.write(met_xml, "%s%s/%s.%s-meta.xml" % write_to) # Prepare package XML content package_xml_content = build_package_xml(settings, package_dict) From 0e52c25c6f1f1e42a445ea37216e5aaa9f0dbe05 Mon Sep 17 00:00:00 2001 From: Hao Liu Date: Mon, 15 Jul 2019 19:23:27 +0800 Subject: [PATCH 03/46] fix deployment exception track for unknow exception --- salesforce/api/metadata.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/salesforce/api/metadata.py b/salesforce/api/metadata.py index b7c0345..a4327c3 100644 --- a/salesforce/api/metadata.py +++ b/salesforce/api/metadata.py @@ -720,7 +720,8 @@ def deploy(self, base64_zip, test_classes=[]): failure.get("message") )) - elif "errorMessage" in body: + # Unknown exception printer + if "errorMessage" in body: Printer.get('log').write("\n" + body["errorMessage"], False) warning_messages = [] From eb3ed309377d41c9c355157b9c5b01830eb0d693 Mon Sep 17 00:00:00 2001 From: Hao Liu Date: Mon, 15 Jul 2019 19:54:39 +0800 Subject: [PATCH 04/46] enhancement for lwc completion --- config/snippets/LWC/targets.sublime-snippet | 4 + salesforce/lib/lightning.py | 156 ++++++++++++++++---- 2 files changed, 134 insertions(+), 26 deletions(-) diff --git a/config/snippets/LWC/targets.sublime-snippet b/config/snippets/LWC/targets.sublime-snippet index 535164b..6396109 100644 --- a/config/snippets/LWC/targets.sublime-snippet +++ b/config/snippets/LWC/targets.sublime-snippet @@ -4,6 +4,10 @@ lightning__AppPage lightning__RecordPage lightning__HomePage + lightning__Inbox + lightningCommunity__Page + lightningCommunity__Default + lightningSnapin__ChatMessage ]]> targets diff --git a/salesforce/lib/lightning.py b/salesforce/lib/lightning.py index e7eb0f2..e21bf02 100644 --- a/salesforce/lib/lightning.py +++ b/salesforce/lib/lightning.py @@ -2369,7 +2369,7 @@ "Integer", "Long", "String", - "Function", + "Method", "Object", "String[]", "Integer[]", @@ -10734,7 +10734,7 @@ "access": "global", "required": False, "default": "", - "description": "Displays tooltip text when the mouse moves over the element." + "description": "Use this directive to iterate over an array and render a list." }, "for:item": { "type": "TrackObject", @@ -10748,14 +10748,28 @@ "access": "global", "required": False, "default": "", - "description": "" + "description": "Use this directive to conditionally render DOM elements in a template." }, "if:false": { "type": "TrackObject", "access": "global", "required": False, "default": "", - "description": "" + "description": "Use this directive to conditionally render DOM elements in a template." + }, + "key": { + "type": "TrackObject", + "access": "global", + "required": False, + "default": "", + "description": "Use this directive to improve rendering performance by assigning a unique identifier to each item in a list. The key must be a string or a number, it can’t be an object. The engine uses the keys to determine which items have changed." + }, + "lwc:dom": { + "type": "TrackObject", + "access": "global", + "required": False, + "default": "", + "description": "Add this directive to a native HTML element to call appendChild() on the element from the owner’s JavaScript class and preserve styling." } } }, @@ -10865,7 +10879,7 @@ }, "variant": { "type": "Picklist", - "values": ["", "circle", "square"], + "values": ["square", "circle", ""], "access": "global", "required": False, "default": "", @@ -10948,7 +10962,15 @@ "description": "" }, "variant": { - "type": "String", + "type": "Picklist", + "values": [ + "base", + "neutral", + "brand", + "destructive", + "inverse", + "success" + ], "access": "global", "required": False, "default": "neutral", @@ -11006,7 +11028,15 @@ "description": "" }, "variant": { - "type": "String", + "type": "Picklist", + "values": [ + "base", + "neutral", + "brand", + "destructive", + "inverse", + "success" + ], "access": "global", "required": False, "default": "", @@ -11036,7 +11066,8 @@ "description": "" }, "type": { - "type": "String", + "type": "Picklis", + "values": ["button", "rest", "submit"], "access": "global", "required": False, "default": "", @@ -11078,7 +11109,15 @@ "description": "" }, "variant": { - "type": "String", + "type": "Picklist", + "values": [ + "base", + "neutral", + "brand", + "destructive", + "inverse", + "success" + ], "access": "global", "required": False, "default": "", @@ -11568,6 +11607,7 @@ }, "variant": { "type": "Picklist", + "values": ["standard", "label-inline", "label-hidden", "label-stacked"], "access": "global", "required": False, "default": "standard", @@ -11602,7 +11642,7 @@ "description": "InheritedRepresents the validity states that an element can be in, with respect to constraint validation." }, "onchange": { - "type": "Function", + "type": "Method", "access": "global", "required": False, "default": "", @@ -11623,14 +11663,14 @@ "description": "InheritedSpecifies the tab order of an element when the Tab key is used for navigating. The tabindex value can be set to 0 or -1. The default is 0, which means that the component is focusable and participates in sequential keyboard navigation. -1 means that the component is focusable but does not participate in keyboard navigation." }, "onfocus": { - "type": "Function", + "type": "Method", "access": "global", "required": False, "default": "", "description": "InheritedThe action triggered when the element receives focus." }, "onblur": { - "type": "Function", + "type": "Method", "access": "global", "required": False, "default": "", @@ -11651,8 +11691,7 @@ "description": "InheritedDisplays tooltip text when the mouse moves over the element." }, "options": { - "type": "Picklist", - "values": ["label", "value"], + "type": "List", "access": "global", "required": False, "default": "", @@ -11892,8 +11931,7 @@ "description": "Label for the dual listbox." }, "options": { - "type": "Picklist", - "values": ["label", "value"], + "type": "List", "access": "global", "required": False, "default": "", @@ -12098,13 +12136,23 @@ }, "accept": { "type": "Picklist", + "values": [ + ".avi", ".doc", ".dot", ".docx", ".exe", + ".msg", ".wrf", ".html", ".acgi", ".htm", + ".htx", ".shtm", ".shtml", ".htt", ".mht", + ".mhtm", ".mhtml", ".mov", ".mp3", ".mp4", + ".mpeg", ".mpg", ".pdf", ".ppt", ".pot", + ".pps", ".pptx", ".svg", ".svgz", ".swf", + ".txml", ".unknown", ".wav", ".wma", ".wmv", + ".xhtml", ".xls", ".xlt", ".xlsx", ".xm" + ], "access": "global", "required": False, "default": "", "description": "Comma-separated list of file extensions that can be uploaded\nin the format .ext, such as .pdf, .jpg, or .png." }, "record-id": { - "type": "String", + "type": "TrackObject", "access": "global", "required": False, "default": "", @@ -12891,7 +12939,7 @@ "description": "The type of the input. This value defaults to text." }, "is-loading": { - "type": "String", + "type": "Boolean", "access": "global", "required": False, "default": "", @@ -12912,7 +12960,17 @@ "description": "The maximum number of characters allowed in the field." }, "accept": { - "type": "String", + "type": "Picklist", + "values": [ + ".avi", ".doc", ".dot", ".docx", ".exe", + ".msg", ".wrf", ".html", ".acgi", ".htm", + ".htx", ".shtm", ".shtml", ".htt", ".mht", + ".mhtm", ".mhtml", ".mov", ".mp3", ".mp4", + ".mpeg", ".mpg", ".pdf", ".ppt", ".pot", + ".pps", ".pptx", ".svg", ".svgz", ".swf", + ".txml", ".unknown", ".wav", ".wma", ".wmv", + ".xhtml", ".xls", ".xlt", ".xlsx", ".xm" + ], "access": "global", "required": False, "default": "", @@ -14114,7 +14172,7 @@ "description": "Sets the arrangement style of fields and labels in the form.\nAccepted values are compact, comfy, and auto (default).\nUse compact to display fields and their labels on the same line.\nUse comfy to display fields below their labels.\nUse auto to let the component dynamically set\nthe density according to the user's Display Density setting\nand the width of the form." }, "record-id": { - "type": "String", + "type": "TrackObject", "access": "global", "required": False, "default": "", @@ -14150,7 +14208,8 @@ "description": "Specifies the interaction and display style for the form.\nPossible values: view, edit, readonly.\nIf a record ID is not provided, the default mode is edit, which displays a form to create new records.\nIf a record ID is provided, the default mode is view, which displays field values with edit icons on updateable fields." }, "layout-type": { - "type": "String", + "type": "Picklist", + "values": ["Compact", "Full"], "access": "global", "required": False, "default": "", @@ -14165,7 +14224,7 @@ "description": "Sets the arrangement style of fields and labels in the form.\nAccepted values are compact, comfy, and auto (default).\nUse compact to display fields and their labels on the same line.\nUse comfy to display fields below their labels.\nUse auto to let the component dynamically set\nthe density according to the user's Display Density setting\nand the width of the form." }, "record-id": { - "type": "String", + "type": "TrackObject", "access": "global", "required": False, "default": "", @@ -14208,7 +14267,7 @@ "description": "Sets the arrangement style of fields and labels in the form.\nAccepted values are compact, comfy, and auto (default).\nUse compact to display fields and their labels on the same line.\nUse comfy to display fields below their labels.\nUse auto to let the component dynamically set\nthe density according to the user's Display Density setting\nand the width of the form." }, "record-id": { - "type": "String", + "type": "TrackObject", "access": "global", "required": False, "default": "", @@ -14407,7 +14466,52 @@ "lightning-tab": { "simple": False, "type": "lwc", - "attribs": {} + "attribs": { + "value": { + "type": "String", + "access": "global", + "required": False, + "default": "", + "description": "The optional string to be used during tabset's select event to determine which tab was clicked.\nThis string is also used by active-tab-value in tabset to open a tab." + }, + "label": { + "type": "String", + "access": "global", + "required": False, + "default": "", + "description": "The text displayed in the tab header." + }, + "title": { + "type": "String", + "access": "global", + "required": False, + "default": "", + "description": "Specifies text that displays in a tooltip over the tab content." + }, + "icon-name": { + "type": "Picklist", + "values": icon_names, + "access": "global", + "required": False, + "default": "", + "description": "The Lightning Design System name of an icon to display to the left of the tab label.\nSpecify the name in the format 'utility:down' where 'utility' is the category, and\n'down' is the icon to be displayed. Only utility icons can be used." + + }, + "icon-assistive-text": { + "type": "String", + "access": "global", + "required": False, + "default": "", + "description": "The alternative text for the icon specified by icon-name." + }, + "show-error-indicator": { + "type": "Boolean", + "access": "global", + "required": False, + "default": "", + "description": "Specifies whether there's an error in the tab content.\nAn error icon is displayed to the right of the tab label." + } + } }, "lightning-tabset": { @@ -14585,7 +14689,7 @@ "description": "The URL of the page that the link goes to." }, "actions": { - "type": "String", + "type": "List", "access": "global", "required": False, "default": "", @@ -14677,7 +14781,7 @@ "description": "Determines where to start counting the row number. The default is 0." }, "selected-rows": { - "type": "String", + "type": "List", "access": "global", "required": False, "default": "[]", From 62060ab6f07e3aab41807591b5c453c263a3af29 Mon Sep 17 00:00:00 2001 From: Hao Liu Date: Mon, 15 Jul 2019 19:55:00 +0800 Subject: [PATCH 05/46] Fix some minor bug for lwc feature --- completions.py | 2 +- lwc.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/completions.py b/completions.py index cd4aea7..72be5dd 100644 --- a/completions.py +++ b/completions.py @@ -796,7 +796,7 @@ def on_query_completions(self, view, prefix, locations): if not mr.contains(pt): continue class_name = view.substr(mr).split("=")[0] - if class_name.lower() == "class": + if class_name.lower() in ["class", "icon-class"]: for class_name in slds.classes: completion_list.append(("%s\tSLDS" % class_name, class_name)) break diff --git a/lwc.py b/lwc.py index bdeeaed..b24fb9d 100644 --- a/lwc.py +++ b/lwc.py @@ -55,7 +55,7 @@ def on_input(self, lwc_name): body = fp.read() # Update dynamic parameters in the template - body = body.replace("{class_name__c}", lwc_name) + body = body.replace("{class_name__c}", lwc_name.capitalize()) body = body.replace("{api_version}", str(settings["api_version"])) lwc_file = os.path.join(component_dir, lwc_name + v["extension"]) From 2a2f5c5b8f0ba77293003cd9edf1613de0262fa3 Mon Sep 17 00:00:00 2001 From: Hao Liu Date: Mon, 15 Jul 2019 20:06:31 +0800 Subject: [PATCH 06/46] Release v3.5.5 --- config/messages/3.5.5.md | 7 +++++++ config/settings/package.sublime-settings | 2 +- messages.json | 1 + 3 files changed, 9 insertions(+), 1 deletion(-) create mode 100644 config/messages/3.5.5.md diff --git a/config/messages/3.5.5.md b/config/messages/3.5.5.md new file mode 100644 index 0000000..511be71 --- /dev/null +++ b/config/messages/3.5.5.md @@ -0,0 +1,7 @@ +Build 3.5.5 +----------- +Release Date: 15 Jul 2019 + +* LWC Support, just like Aura development experience +* Enhancement for many features, see more at https://github.com/xjsender/haoide/commits/master?after=62060ab6f07e3aab41807591b5c453c263a3af29+34 +* Fix many bugs \ No newline at end of file diff --git a/config/settings/package.sublime-settings b/config/settings/package.sublime-settings index 38c29db..95caf00 100644 --- a/config/settings/package.sublime-settings +++ b/config/settings/package.sublime-settings @@ -1,6 +1,6 @@ { "name": "haoide", - "version": "3.5.4", + "version": "3.5.5", "description": "haoide is a Sublime Text 3 plugin for Salesforce and used for swift development on Force.com", "author": "Hao Liu", "email": "mouse.mliu@gmail.com", diff --git a/messages.json b/messages.json index 21fda61..e82fab1 100644 --- a/messages.json +++ b/messages.json @@ -6,5 +6,6 @@ "3.4.4": "config/messages/3.4.4.md", "3.4.5": "config/messages/3.4.5.md", "3.4.6": "config/messages/3.4.6.md", + "3.5.5": "config/messages/3.5.5.md", "install": "config/messages/install.txt" } \ No newline at end of file From 51bce17517fcac5d95cb740ad68cd2cd65e5ecfa Mon Sep 17 00:00:00 2001 From: Lushang Date: Mon, 15 Jul 2019 20:35:29 +0800 Subject: [PATCH 07/46] Implementing lwc suport stage 1 part 2 --- .../snippets/Apex/Class Header - class header.sublime-snippet | 4 ++-- lwc.py | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/config/snippets/Apex/Class Header - class header.sublime-snippet b/config/snippets/Apex/Class Header - class header.sublime-snippet index 3babad5..fcc0873 100644 --- a/config/snippets/Apex/Class Header - class header.sublime-snippet +++ b/config/snippets/Apex/Class Header - class header.sublime-snippet @@ -5,9 +5,9 @@ * Object: $2 * Purpose: $3 * Author: $4 ($5) - * Create Date: 2018-${6:05-07} + * Create Date: 2019-${6:07-15} * Modify History: - * 2019-${6:02-25} $4 ${7:Create this class} + * 2019-${6:07-15} $4 ${7:Create this class} **************************************************************************************************/ ]]> ch diff --git a/lwc.py b/lwc.py index 3b4bf66..3f41f1a 100644 --- a/lwc.py +++ b/lwc.py @@ -48,6 +48,7 @@ def on_input(self, lwc_name): # Get template attribute templates = util.load_templates() + # print('templates', templates) template_bundle = templates.get("Lwc") for tpl_name in template_bundle: template = template_bundle.get(tpl_name) From a2f8a36866c919216b8f38bca48cbdaf3c27042c Mon Sep 17 00:00:00 2001 From: Lushang Date: Mon, 15 Jul 2019 20:38:05 +0800 Subject: [PATCH 08/46] Implementing lwc support stage 1 part 3 --- config/commands/main.sublime-commands | 7 +++++++ config/templates/{LWC => Lwc}/Basic.html | 0 config/templates/{LWC => Lwc}/Basic.js | 0 config/templates/{LWC => Lwc}/Basic.js-meta.xml | 0 config/templates/LwcElement/Basic.css | 0 config/templates/LwcElement/Basic.svg | 0 lwc.py | 4 ++-- util.py | 2 +- 8 files changed, 10 insertions(+), 3 deletions(-) rename config/templates/{LWC => Lwc}/Basic.html (100%) rename config/templates/{LWC => Lwc}/Basic.js (100%) rename config/templates/{LWC => Lwc}/Basic.js-meta.xml (100%) create mode 100644 config/templates/LwcElement/Basic.css create mode 100644 config/templates/LwcElement/Basic.svg diff --git a/config/commands/main.sublime-commands b/config/commands/main.sublime-commands index 394252f..85ae6f4 100644 --- a/config/commands/main.sublime-commands +++ b/config/commands/main.sublime-commands @@ -103,6 +103,13 @@ } }, + {"caption": "-"}, + + { + "caption": "HaoIDE: New Lightning Web Component", + "command": "create_lightning_web_component" + }, + { "caption": "HaoIDE: Toggle Metdata Objects", "command": "toggle_metadata_objects", diff --git a/config/templates/LWC/Basic.html b/config/templates/Lwc/Basic.html similarity index 100% rename from config/templates/LWC/Basic.html rename to config/templates/Lwc/Basic.html diff --git a/config/templates/LWC/Basic.js b/config/templates/Lwc/Basic.js similarity index 100% rename from config/templates/LWC/Basic.js rename to config/templates/Lwc/Basic.js diff --git a/config/templates/LWC/Basic.js-meta.xml b/config/templates/Lwc/Basic.js-meta.xml similarity index 100% rename from config/templates/LWC/Basic.js-meta.xml rename to config/templates/Lwc/Basic.js-meta.xml diff --git a/config/templates/LwcElement/Basic.css b/config/templates/LwcElement/Basic.css new file mode 100644 index 0000000..e69de29 diff --git a/config/templates/LwcElement/Basic.svg b/config/templates/LwcElement/Basic.svg new file mode 100644 index 0000000..e69de29 diff --git a/lwc.py b/lwc.py index fe809f2..d44d158 100644 --- a/lwc.py +++ b/lwc.py @@ -26,7 +26,7 @@ def run(self, *args): def on_input(self, lwc_name): # Create component to local according to user input - if not re.match('^[a-zA-Z]+\\w+$', lwc_name): + if not re.match('^[a-z]+\\w*[A-Za-z0-9]$', lwc_name) or re.match('__+', lwc_name): message = 'Invalid format, do you want to try again?' if not sublime.ok_cancel_dialog(message): return @@ -48,7 +48,7 @@ def on_input(self, lwc_name): # Get template attribute templates = util.load_templates() - template_bundle = templates.get("LWC") + template_bundle = templates.get("Lwc") for tpl_name in template_bundle: template = template_bundle.get(tpl_name) with open(os.path.join(self._workspace, ".templates", template["directory"])) as fp: diff --git a/util.py b/util.py index 076981b..2f71d01 100644 --- a/util.py +++ b/util.py @@ -1538,7 +1538,7 @@ def compress_resource_folder(resource_folder): return base64_package -# Build zip package for Aura or LWC deployment +# Build zip package for Aura or Lwc deployment def build_package(files_or_dirs, meta_type="aura"): # Build package From 26705d228d3125a179aea3a691051021f449fd7e Mon Sep 17 00:00:00 2001 From: Lushang Date: Mon, 15 Jul 2019 21:17:27 +0800 Subject: [PATCH 09/46] Implemented basic lwc support: create new `Lightning Web Component` --- util.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/util.py b/util.py index 2f71d01..03a6524 100644 --- a/util.py +++ b/util.py @@ -1546,7 +1546,7 @@ def build_package(files_or_dirs, meta_type="aura"): workspace = settings["workspace"] if not os.path.exists(workspace): os.makedirs(workspace) - zipfile_path = workspace + "/aura.zip" if meta_type is 'aura' else "/lwc.zip" + zipfile_path = workspace + ("/aura.zip" if meta_type is 'aura' else "/lwc.zip") zf = zipfile.ZipFile(zipfile_path, "w", zipfile.ZIP_DEFLATED) aura_names = [] From 328ceb26209ef8523533015bc6f0506fbf995aa3 Mon Sep 17 00:00:00 2001 From: Hao Liu Date: Tue, 16 Jul 2019 19:20:00 +0800 Subject: [PATCH 10/46] fix bug for meta file deployment --- util.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/util.py b/util.py index c46f9f7..f4d13fa 100644 --- a/util.py +++ b/util.py @@ -1261,9 +1261,9 @@ def build_package_dict(files, ignore_folder=True): if ignore_folder and not os.path.isfile(f): continue - # Ignore "-meta.xml" + # Replace meta file with source file if f.endswith("-meta.xml"): - continue + f = f.replace("-meta.xml", "") # If ignore_folder is true and f is folder attributes = get_file_attributes(f) From 41da7201cc5b183bfb0b943e22dc0fdc102d5184 Mon Sep 17 00:00:00 2001 From: Hao Liu Date: Tue, 16 Jul 2019 20:04:38 +0800 Subject: [PATCH 11/46] add user interface api doc reference toc --- config/settings/toolingapi.sublime-settings | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/config/settings/toolingapi.sublime-settings b/config/settings/toolingapi.sublime-settings index 7566f73..26cc3f5 100644 --- a/config/settings/toolingapi.sublime-settings +++ b/config/settings/toolingapi.sublime-settings @@ -532,6 +532,7 @@ "Force.com Workbook": "workbook", "Integration Workbook": "integration_workbook", "Identity Implementation Guide": "identityImplGuide", - "Formulas Quick Reference": "salesforce_formulas_cheatsheet" + "Formulas Quick Reference": "salesforce_formulas_cheatsheet", + "User Interface API Developer Guide": "uiapi" } } \ No newline at end of file From d4d25d3a7661c019c4a076ff288be2c26dabc47a Mon Sep 17 00:00:00 2001 From: Hao Liu Date: Tue, 16 Jul 2019 20:05:02 +0800 Subject: [PATCH 12/46] add import snippet for lwc --- config/snippets/LWC/import.sublime-snippet | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 config/snippets/LWC/import.sublime-snippet diff --git a/config/snippets/LWC/import.sublime-snippet b/config/snippets/LWC/import.sublime-snippet new file mode 100644 index 0000000..81f4529 --- /dev/null +++ b/config/snippets/LWC/import.sublime-snippet @@ -0,0 +1,8 @@ + + + import + source.js,source.ts + Import module + From 28b34005a80b4038087696ccf9b2685f916c65d7 Mon Sep 17 00:00:00 2001 From: Hao Liu Date: Tue, 16 Jul 2019 20:11:43 +0800 Subject: [PATCH 13/46] add import default and import module --- config/snippets/LWC/import default.sublime-snippet | 8 ++++++++ config/snippets/LWC/import.sublime-snippet | 4 ++-- 2 files changed, 10 insertions(+), 2 deletions(-) create mode 100644 config/snippets/LWC/import default.sublime-snippet diff --git a/config/snippets/LWC/import default.sublime-snippet b/config/snippets/LWC/import default.sublime-snippet new file mode 100644 index 0000000..120df53 --- /dev/null +++ b/config/snippets/LWC/import default.sublime-snippet @@ -0,0 +1,8 @@ + + + import default + source.js,source.ts + import from '' + \ No newline at end of file diff --git a/config/snippets/LWC/import.sublime-snippet b/config/snippets/LWC/import.sublime-snippet index 81f4529..91a5a45 100644 --- a/config/snippets/LWC/import.sublime-snippet +++ b/config/snippets/LWC/import.sublime-snippet @@ -4,5 +4,5 @@ import { $2 } from '$1;$0 ]]> import source.js,source.ts - Import module - + import {} from '' + \ No newline at end of file From 32ade0ae64b83de282cc9d86cd35faacf0126df0 Mon Sep 17 00:00:00 2001 From: Hao Liu Date: Tue, 16 Jul 2019 20:12:15 +0800 Subject: [PATCH 14/46] fix issue for lwc name --- lwc.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lwc.py b/lwc.py index b24fb9d..403c1ff 100644 --- a/lwc.py +++ b/lwc.py @@ -55,7 +55,7 @@ def on_input(self, lwc_name): body = fp.read() # Update dynamic parameters in the template - body = body.replace("{class_name__c}", lwc_name.capitalize()) + body = body.replace("{class_name__c}", lwc_name[:1].upper() + lwc_name[1:]) body = body.replace("{api_version}", str(settings["api_version"])) lwc_file = os.path.join(component_dir, lwc_name + v["extension"]) From b7fddb5c5606be577e9b2942347aae241f499d6b Mon Sep 17 00:00:00 2001 From: Hao Liu Date: Tue, 16 Jul 2019 20:12:56 +0800 Subject: [PATCH 15/46] lwc supports labe, staticresource, custom object and fields import --- completions.py | 60 +++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 59 insertions(+), 1 deletion(-) diff --git a/completions.py b/completions.py index 72be5dd..f53fcc8 100644 --- a/completions.py +++ b/completions.py @@ -435,7 +435,7 @@ def on_query_completions(self, view, prefix, locations): return completion_list -class LightningCompletions(sublime_plugin.EventListener): +class AuraCompletions(sublime_plugin.EventListener): """ Lightning Javascript completion 1. Standard Event Completion @@ -566,6 +566,64 @@ def on_query_completions(self, view, prefix, locations): return completion_list + +class LwcCompletions(sublime_plugin.EventListener): + def on_query_completions(self, view, prefix, locations): + # Only trigger within JS + if not view.match_selector(locations[0], "source.js"): + return + + settings = context.get_settings() + workspace = settings["workspace"] + username = settings["username"] + + metadata = load_sobject_cache(username=username) + sobjects_describe = metadata.get("sobjects", {}) + + pt = locations[0] - len(prefix) - 1 + ch = view.substr(sublime.Region(pt, pt + 1)) + var_name = view.substr(view.word(pt-1)) + + completion_list = [] + if ch == "/": + # Add salesforce meta resource + if var_name == "salesforce": + modules = [ + "apex", "apexContinuation", "contentAssertUrl", + "i18n", "label", "resourceUrl", "schema", "user" + ] + + for module in modules: + completion_list.append(( + "%s\tModule" % module, module + )) + + return completion_list + + if var_name == "schema": + for key, desc in sobjects_describe.items(): + sobject = desc["name"] + + # Add sobject schema + completion_list.append((sobject + "\tsObject", sobject)) + + # Add sobject field schema + for k, v in desc["fields"].items(): + completion_list.append(( + "%s.%s" % (sobject, k), + "%s.%s" % (sobject, v) + )) + elif var_name == "resourceUrl": + completion_list = util.get_completion_from_cache( + settings, "StaticResource", True + ) + elif var_name == "label": + completion_list = util.get_completion_from_cache( + settings, "CustomLabel", True + ) + + return completion_list + class PageCompletions(sublime_plugin.EventListener): """ There are three kinds of completion, Visualforce, Html and Custom Lightning component Visualforce Lib is based on Mavensmate From 8613dcbc4ee1d1b9ec97f636a84cdf3e4232a20d Mon Sep 17 00:00:00 2001 From: Hao Liu Date: Tue, 16 Jul 2019 20:13:51 +0800 Subject: [PATCH 16/46] update js completion trigger character --- config/settings/Preferences.sublime-settings | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/config/settings/Preferences.sublime-settings b/config/settings/Preferences.sublime-settings index 44f75a3..639675a 100644 --- a/config/settings/Preferences.sublime-settings +++ b/config/settings/Preferences.sublime-settings @@ -10,6 +10,7 @@ "characters": ".<: =#\"", "selector": "text.html - source" }, { - "selector": "source.js", "characters": "." + "selector": "source.js,source.ts", + "characters": "/." }] } \ No newline at end of file From d95c4bea29ddb34fd87c64154fee5acfc9dd2ccf Mon Sep 17 00:00:00 2001 From: Khavish Anshudass Bhundoo Date: Sun, 21 Jul 2019 17:34:29 +0400 Subject: [PATCH 17/46] Fix startURL for CustomLabel --- config/menus/Main.sublime-menu | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/menus/Main.sublime-menu b/config/menus/Main.sublime-menu index 8734181..29e6ec1 100644 --- a/config/menus/Main.sublime-menu +++ b/config/menus/Main.sublime-menu @@ -487,7 +487,7 @@ "caption": "Custom Labels", "command": "login_to_sfdc", "args": { - "startURL": "/ui/setup/ExternalStrings/home" + "startURL": "101?retURL=/ui/setup/Setup?setupid=DevTools&setupid=ExternalStrings" } }, From 2c04592b17aa2c1fe15910475eb72ea04562f863 Mon Sep 17 00:00:00 2001 From: Hao Liu Date: Tue, 23 Jul 2019 21:49:48 +0800 Subject: [PATCH 18/46] enhancement for lwc boolean attr completion --- completions.py | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/completions.py b/completions.py index f53fcc8..cfac169 100644 --- a/completions.py +++ b/completions.py @@ -882,13 +882,20 @@ def on_query_completions(self, view, prefix, locations): # Get the Attribute Values if matched_tag in tag_defs and matched_attr_name in tag_defs[matched_tag]["attribs"]: - tag_attribute = tag_defs[matched_tag]["attribs"][matched_attr_name] + tag_def = tag_defs[matched_tag] + tag_attribute = tag_def["attribs"][matched_attr_name] - # If attr type boolean, add {!} to it + # If attr type boolean, add {!} or {} to it according to type if tag_attribute["type"] == "Boolean": - completion_list.append(("{!}" + "\t" + matched_attr_name, '"{!$1}"$0')) - completion_list.append(("true" + "\t" + matched_attr_name, '"true"$0')) - completion_list.append(("false" + "\t" + matched_attr_name, '"false"$0')) + if tag_def["type"] == "aura": + completion_list.append(("{!}" + "\t" + matched_attr_name, '"{!$1}"$0')) + + if tag_def["type"] == "lwc": + completion_list.append(("{}" + "\t" + matched_attr_name, '{$1}$0')) + + if tag_def["type"] in ["aura", "lwc"]: + completion_list.append(("true" + "\t" + matched_attr_name, '"true"$0')) + completion_list.append(("false" + "\t" + matched_attr_name, '"false"$0')) if "values" in tag_attribute: for value in tag_attribute["values"]: From 3777af676624ca63d75ff68f9c19fee6accef9db Mon Sep 17 00:00:00 2001 From: Hao Liu Date: Tue, 23 Jul 2019 21:50:31 +0800 Subject: [PATCH 19/46] add component tag attr desc completion when hover on attr --- events.py | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/events.py b/events.py index 64dd156..535e6a1 100644 --- a/events.py +++ b/events.py @@ -7,9 +7,40 @@ from . import context from . import util from .salesforce.lib.panel import Printer +from .salesforce.lib import lightning class SFDCEventListener(sublime_plugin.EventListener): + """ Tag attribute description completion when hover + """ + def on_hover(self, view, pt, hover_zone): + tag_defs = lightning.tag_defs + + word = view.substr(view.extract_scope(pt-1)) + matched_regions = view.find_all("<\\w+[:-]*\\w+[\\s\\S]*?>") + + matched_region = None + for mr in matched_regions: + if mr.contains(pt): + matched_region = mr + + if matched_region: + matched_str = view.substr(matched_region)[1:-1] + matched_tag = matched_str.split(" ")[0].strip() + matched_attr = view.substr(view.extract_scope(pt-1))[:-1] + + if matched_tag in tag_defs and matched_attr in tag_defs[matched_tag]["attribs"]: + tag_attrib = tag_defs[matched_tag]["attribs"][matched_attr] + if "description" in tag_attrib and tag_attrib["description"]: + view.show_popup( + """

{name}

+
+ {desc} +
+ """.format(name=matched_attr, desc=tag_attrib["description"]), + sublime.HIDE_ON_MOUSE_MOVE_AWAY + ) + def on_new(self, view): """ 1. Eveytime when you open a new view, default syntax is Apex From 8e65d788158d9b4aa93d0709f85e535958829139 Mon Sep 17 00:00:00 2001 From: Hao Liu Date: Wed, 31 Jul 2019 22:33:04 +0800 Subject: [PATCH 20/46] release v3.5.6, maybe the last version --- HISTORY.rst | 8 ++++++++ config/messages/3.5.6.md | 13 +++++++++++++ config/settings/package.sublime-settings | 2 +- messages.json | 8 +------- 4 files changed, 23 insertions(+), 8 deletions(-) create mode 100644 config/messages/3.5.6.md diff --git a/HISTORY.rst b/HISTORY.rst index fb87c0c..870b489 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -4,6 +4,14 @@ Release History --------------- +Release 3.5.4 (2019-07-31) +++++++++++++++++++ +* Add component tag attr desc completion when hover on attr +* Add user interface api doc reference toc +* lwc supports label, staticresource, custom object and fields import +* Enhancement for lwc boolean attr completion +* Fix bug for meta file deployment + Release 3.5.4 (2018-02-12) ++++++++++++++++++ diff --git a/config/messages/3.5.6.md b/config/messages/3.5.6.md new file mode 100644 index 0000000..c81f65a --- /dev/null +++ b/config/messages/3.5.6.md @@ -0,0 +1,13 @@ +Build 3.5.6 +----------- +Release Date: 31 Jul 2019 + +* Add component tag attr desc completion when hover on attr +* Add user interface api doc reference toc +* lwc supports label, staticresource, custom object and fields import +* Enhancement for lwc boolean attr completion +* Fix bug for meta file deployment + +Notice: +------------ +We may not continue to upgrade haoide for sublime, in the next months, we will work on migrate haoide from sublime to vscode, we have been working on [haoide-vscode](https://github.com/xjsender/haoide-vscode) for weeks, there already has some basic completions, check [here](https://raw.githubusercontent.com/xjsender/haoide-vscode/master/docs/haoide-vscode.gif) for demo show. diff --git a/config/settings/package.sublime-settings b/config/settings/package.sublime-settings index 95caf00..39f099d 100644 --- a/config/settings/package.sublime-settings +++ b/config/settings/package.sublime-settings @@ -1,6 +1,6 @@ { "name": "haoide", - "version": "3.5.5", + "version": "3.5.6", "description": "haoide is a Sublime Text 3 plugin for Salesforce and used for swift development on Force.com", "author": "Hao Liu", "email": "mouse.mliu@gmail.com", diff --git a/messages.json b/messages.json index e82fab1..7cbba22 100644 --- a/messages.json +++ b/messages.json @@ -1,11 +1,5 @@ { - "3.4.0": "config/messages/3.4.0.md", - "3.4.1": "config/messages/3.4.1.md", - "3.4.2": "config/messages/3.4.2.md", - "3.4.3": "config/messages/3.4.3.md", - "3.4.4": "config/messages/3.4.4.md", - "3.4.5": "config/messages/3.4.5.md", - "3.4.6": "config/messages/3.4.6.md", "3.5.5": "config/messages/3.5.5.md", + "3.5.6": "config/messages/3.5.6.md", "install": "config/messages/install.txt" } \ No newline at end of file From abdf6c8243bcb1076ffd0059664f7a89f504c2bc Mon Sep 17 00:00:00 2001 From: Lushang Date: Thu, 26 Mar 2020 13:12:01 +0800 Subject: [PATCH 21/46] Git bug about directory --- config/templates/lwc/lwc.html | 1 + config/templates/lwc/lwc.js | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/config/templates/lwc/lwc.html b/config/templates/lwc/lwc.html index ba53413..af9fa97 100644 --- a/config/templates/lwc/lwc.html +++ b/config/templates/lwc/lwc.html @@ -1,2 +1,3 @@ \ No newline at end of file diff --git a/config/templates/lwc/lwc.js b/config/templates/lwc/lwc.js index 2bfae5b..0ddaf1d 100644 --- a/config/templates/lwc/lwc.js +++ b/config/templates/lwc/lwc.js @@ -1,5 +1,5 @@ import { LightningElement, track, wire } from 'lwc'; export default class {class_name__c} extends LightningElement { - + } \ No newline at end of file From d839c3fa7fc836357d5872c55084155161c9c5c6 Mon Sep 17 00:00:00 2001 From: Lushang Date: Thu, 26 Mar 2020 13:22:29 +0800 Subject: [PATCH 22/46] fix git directory recognizing bug step 1 --- config/templates/Lwc/lwc.html | 9 --------- config/templates/Lwc/lwc.js | 5 ----- config/templates/Lwc/lwc.js-meta.xml | 10 ---------- config/templates/lwc/lwc.html | 3 --- config/templates/lwc/lwc.js | 5 ----- config/templates/lwc/lwc.js-meta.xml | 5 ----- 6 files changed, 37 deletions(-) delete mode 100644 config/templates/Lwc/lwc.html delete mode 100644 config/templates/Lwc/lwc.js delete mode 100644 config/templates/Lwc/lwc.js-meta.xml delete mode 100644 config/templates/lwc/lwc.html delete mode 100644 config/templates/lwc/lwc.js delete mode 100644 config/templates/lwc/lwc.js-meta.xml diff --git a/config/templates/Lwc/lwc.html b/config/templates/Lwc/lwc.html deleted file mode 100644 index d8122fa..0000000 --- a/config/templates/Lwc/lwc.html +++ /dev/null @@ -1,9 +0,0 @@ - \ No newline at end of file diff --git a/config/templates/Lwc/lwc.js b/config/templates/Lwc/lwc.js deleted file mode 100644 index 810f0b7..0000000 --- a/config/templates/Lwc/lwc.js +++ /dev/null @@ -1,5 +0,0 @@ -import { LightningElement, track } from 'lwc'; - -export default class Hello extends LightningElement { - @track greeting = 'World'; -} \ No newline at end of file diff --git a/config/templates/Lwc/lwc.js-meta.xml b/config/templates/Lwc/lwc.js-meta.xml deleted file mode 100644 index 5d558c6..0000000 --- a/config/templates/Lwc/lwc.js-meta.xml +++ /dev/null @@ -1,10 +0,0 @@ - - - 45.0 - true - - lightning__AppPage - lightning__RecordPage - lightning__HomePage - - \ No newline at end of file diff --git a/config/templates/lwc/lwc.html b/config/templates/lwc/lwc.html deleted file mode 100644 index af9fa97..0000000 --- a/config/templates/lwc/lwc.html +++ /dev/null @@ -1,3 +0,0 @@ - \ No newline at end of file diff --git a/config/templates/lwc/lwc.js b/config/templates/lwc/lwc.js deleted file mode 100644 index 0ddaf1d..0000000 --- a/config/templates/lwc/lwc.js +++ /dev/null @@ -1,5 +0,0 @@ -import { LightningElement, track, wire } from 'lwc'; - -export default class {class_name__c} extends LightningElement { - -} \ No newline at end of file diff --git a/config/templates/lwc/lwc.js-meta.xml b/config/templates/lwc/lwc.js-meta.xml deleted file mode 100644 index cfee44c..0000000 --- a/config/templates/lwc/lwc.js-meta.xml +++ /dev/null @@ -1,5 +0,0 @@ - - - {api_version}.0 - true - \ No newline at end of file From a37dc1704a7c6154f51864bba65fc2145b159a12 Mon Sep 17 00:00:00 2001 From: Lushang Date: Thu, 26 Mar 2020 13:23:52 +0800 Subject: [PATCH 23/46] fix Git directory recognizing bug step 2 --- config/templates/Lwc/lwc.html | 3 +++ config/templates/Lwc/lwc.js | 5 +++++ config/templates/Lwc/lwc.js-meta.xml | 5 +++++ 3 files changed, 13 insertions(+) create mode 100644 config/templates/Lwc/lwc.html create mode 100644 config/templates/Lwc/lwc.js create mode 100644 config/templates/Lwc/lwc.js-meta.xml diff --git a/config/templates/Lwc/lwc.html b/config/templates/Lwc/lwc.html new file mode 100644 index 0000000..af9fa97 --- /dev/null +++ b/config/templates/Lwc/lwc.html @@ -0,0 +1,3 @@ + \ No newline at end of file diff --git a/config/templates/Lwc/lwc.js b/config/templates/Lwc/lwc.js new file mode 100644 index 0000000..0ddaf1d --- /dev/null +++ b/config/templates/Lwc/lwc.js @@ -0,0 +1,5 @@ +import { LightningElement, track, wire } from 'lwc'; + +export default class {class_name__c} extends LightningElement { + +} \ No newline at end of file diff --git a/config/templates/Lwc/lwc.js-meta.xml b/config/templates/Lwc/lwc.js-meta.xml new file mode 100644 index 0000000..cfee44c --- /dev/null +++ b/config/templates/Lwc/lwc.js-meta.xml @@ -0,0 +1,5 @@ + + + {api_version}.0 + true + \ No newline at end of file From 6229821aa1cfc06c4432f26bed7924ed5b867ab4 Mon Sep 17 00:00:00 2001 From: Lushang Date: Thu, 26 Mar 2020 14:14:38 +0800 Subject: [PATCH 24/46] Support Retrieving lwc from server --- aura.py | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/aura.py b/aura.py index a60d95b..cd78771 100644 --- a/aura.py +++ b/aura.py @@ -143,6 +143,7 @@ def is_visible(self): class RetrieveLightningFromServer(sublime_plugin.WindowCommand): def __init__(self, *args, **kwargs): super(RetrieveLightningFromServer, self).__init__(*args, **kwargs) + self.settings = context.get_settings() def run(self, dirs): message = "Are you sure you really want to continue refreshing" @@ -154,28 +155,37 @@ def run(self, dirs): ) def is_visible(self, dirs): - if len(dirs) == 0: return False - self.settings = context.get_settings() self.types = {} + if len(dirs) == 0: + return False for _dir in dirs: - if os.path.isfile(_dir): continue + if os.path.isfile(_dir): + continue base, _name = os.path.split(_dir) base, _folder = os.path.split(base) # Check Metadata Type - if _folder != "aura": continue + if _folder not in ["aura", "lwc"]: + continue # Check Project Name pn = self.settings["default_project_name"] - if pn not in _dir: continue + if pn not in _dir: + continue if "AuraDefinitionBundle" in self.types: self.types["AuraDefinitionBundle"].append(_name) - else: + elif "LightningComponentBundle" in self.types: + self.types["LightningComponentBundle"].append(_name) + elif _folder == 'aura': self.types["AuraDefinitionBundle"] = [_name] + elif _folder == 'lwc': + self.types["LightningComponentBundle"] = [_name] # Check whether any aura components are chosen - if not self.types: return False + print(self.types) + if not self.types: + return False return True From e9d0f997904eebf2ec784e5ca9ecc11904ad4294 Mon Sep 17 00:00:00 2001 From: Lushang Date: Thu, 26 Mar 2020 16:40:41 +0800 Subject: [PATCH 25/46] Lwc refinement for retrieve, deploy, destruct and lwc css, svg elements * Add Retrieving, Destructing, Deploying lwc from both sidebar and context menu * Add Creating CSS style, SVG file for lwc in context menu --- HISTORY.rst | 460 +++++++++++----------- aura.py | 9 +- config/menus/Side bar.sublime-menu | 19 + config/templates/LwcElement/Additional.js | 1 + config/templates/LwcElement/Basic.css | 0 config/templates/LwcElement/Basic.svg | 0 config/templates/LwcElement/SVG.svg | 7 + config/templates/LwcElement/Style.css | 1 + config/templates/templates.json | 6 +- lwc.py | 63 ++- util.py | 10 +- 11 files changed, 338 insertions(+), 238 deletions(-) create mode 100644 config/templates/LwcElement/Additional.js delete mode 100644 config/templates/LwcElement/Basic.css delete mode 100644 config/templates/LwcElement/Basic.svg create mode 100644 config/templates/LwcElement/SVG.svg create mode 100644 config/templates/LwcElement/Style.css diff --git a/HISTORY.rst b/HISTORY.rst index f5b00b8..f295900 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -1,11 +1,19 @@ .. :changelog: Release History - --------------- +Release 3.5.7 (2020-03-26) +++++++++++++++++++++++++++++++++++++ + +* Refine Creating Lightning Web Component (``lwc``) process +* Add Retrieving, Destructing, Deploying lwc from both sidebar and context menu +* Add Creating CSS style, SVG file for lwc in context menu +* Fix auto completion for aura component bug + + Release 3.5.4 (2019-07-31) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ * Add component tag attr desc completion when hover on attr * Add user interface api doc reference toc * lwc supports label, staticresource, custom object and fields import @@ -14,20 +22,20 @@ Release 3.5.4 (2019-07-31) Release 3.5.4 (2018-02-12) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ * Fix issue #172 * Fix issue #173 Release 3.5.3 (2018-02-06) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ * Add missing base components from lightning developer guide by script: https://gist.github.com/xjsender/265d237fbeafebabff6c8669f9359fff#file-read-json-from-lightning-compnent-js * Add $A.localizationService lib * Fix some minor bugs Release 3.5.2 (2018-02-03) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ * Support oAuth2 Login, check https://github.com/xjsender/haoide#project-configuration for guide * Add Lightning event methods completion * Add customlabel and staticresource completions for lightning component @@ -42,12 +50,12 @@ Release 3.5.2 (2018-02-03) Release 3.5.1 (2018-01-25) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ * Basic completion support for component controller or helper Release 3.5.0 (2018-01-21) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ * Add aura component and attribute completion, contributed by @lushang * Add some missed base component * Add lightning component implements completion @@ -60,7 +68,7 @@ Release 3.5.0 (2018-01-21) Release 3.4.7 (2017-07-29) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ * Really and still busy on project delivery work in the past year, will continue in the next days. * New Fetaure: Combine package.xml in selected folders * New Feature: Custom Label completion support, which is fetched from ``project/.config/package.json`` by ``Reload Project Cache`` command @@ -69,7 +77,7 @@ Release 3.4.7 (2017-07-29) Release 3.4.6 (2016-09-26) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ * Deliver enhancement for issue #132 * Deliver enhancement for issue #134 * Deliver enhancement for issue #140 @@ -77,7 +85,7 @@ Release 3.4.6 (2016-09-26) Release 3.4.5 (2016-06-16) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ * Fix bug: sublime will be closed when view debug log by logId with pressing alt + dblclick left mouse * Fix issue #126 * Deliver feature #119 @@ -85,12 +93,12 @@ Release 3.4.5 (2016-06-16) Release 3.4.4 (2016-06-11) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ * Fix Urgent ``FileNotFoundError`` problem when create new code Release 3.4.3 (2016-06-06) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ * Hide ``execute query`` command in the context menu, use ``REST TEST Query`` instead * Rename Snippet ``HttpRequest - Authorization Basic Credentials.sublime-snippet`` to ``HttpRequest - Callout.sublime-snippet`` * Add new snippet named ``Page - loading action status.sublime-snippet`` @@ -101,12 +109,12 @@ Release 3.4.3 (2016-06-06) Release 3.4.2 (2016-05-23) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ * Change api version back to 35, fix issue #116 Release 3.4.1 (2016-05-23) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ * Fix issue #113 * Fix issue #115 * Fix Bug for conflict checking bug caused by solution for issue #108 @@ -115,7 +123,7 @@ Release 3.4.1 (2016-05-23) Release 3.4.0 (2016-05-20) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ - Deliver enhancement for issue #108 - Deliver enhancement for issue #111 - Fix bug when test class failed caused by dependency compilation @@ -134,7 +142,7 @@ Release 3.4.0 (2016-05-20) Release 3.3.9 (2016-04-18) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ * Force login every two hours * Add retry operation for list package if session is expired * Change display format for REST TEST Response, add a new setting ``remove_slash_for_rest_response`` @@ -146,7 +154,7 @@ Release 3.3.9 (2016-04-18) Release 3.3.8 (2016-04-12) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ * Enhancement for code template, welcome new template pull request * Add runSpecifiedTest support for deploying files * Change mousemap key mapping, see more detail at Q&A @@ -154,7 +162,7 @@ Release 3.3.8 (2016-04-12) Release 3.3.7 (2016-03-28) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ * Fix issue #88 * Fix issue #99, problem of ``reload document`` * Deliver enhancement for issue #96 @@ -162,7 +170,7 @@ Release 3.3.7 (2016-03-28) Release 3.3.6 (2016-03-28) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ * Fix issue #98 * Add ``Return to First Step`` feature when open documentation by type * Remove build-in reference settings which is replaced ``Reload Salesforce Document`` @@ -171,7 +179,7 @@ Release 3.3.6 (2016-03-28) Release 3.3.5 (2016-03-26) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ * Greatly improve performance of code completion * Fix invalid scope problem for custom class completion * Enhancement for document reference @@ -179,7 +187,7 @@ Release 3.3.5 (2016-03-26) Release 3.3.4 (2016-03-23) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ * Fix issue #93 * Fix issue #97 * Optimize for methods in ``metadata.py`` @@ -187,19 +195,19 @@ Release 3.3.4 (2016-03-23) Release 3.3.3 (2016-03-14) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ * Fix issue #94 * Enhance ``refresh package`` command * Add package.xml update support for command ``build_package_xml`` Release 3.3.2 (2016-03-12) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ * Fix issue #92 Release 3.3.1 (2016-03-11) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ * Rename ``deploy_package_to_server`` command to ``deploy_package`` * Add new command ``refresh_package``, see issue #91 for detail * Add LastModifiedBy check for conflict check logic, see issue #89 @@ -207,14 +215,14 @@ Release 3.3.1 (2016-03-11) Release 3.3.0 (2016-03-11) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ * Deliver enhancement #91 * Fix bug issue #92 * Fix package.xml onload XML parse exception Release 3.2.9 (2016-03-10) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ * Enhancement for ``role hierarchy exporting`` * Add new settings ``include_users_in_role_hierarchy`` to control whether including user in the CSV * Deliver new feature, see issue #89 @@ -223,7 +231,7 @@ Release 3.2.9 (2016-03-10) Release 3.2.8 (2016-02-26) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ * Fix issue #88 * Fix bug for ``export workflow rules`` feature * Add parameter ``vertical`` for ``export_data_template`` command for exporting Layout Workbook @@ -232,26 +240,26 @@ Release 3.2.8 (2016-02-26) Release 3.2.7 (2015-12-21) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ * Fix issue #86 Release 3.2.6 (2015-12-20) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ * Fix issue #84 * Fix issue #85 * New ``Export > Export Role Hierarchy`` command Release 3.2.5 (2015-12-15) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ * Fix urgent bug issue #83 * Fix urgent bug for sobject cache reloading * Remove ``allowed_sobjects`` setting Release 3.2.4 (2015-12-09) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ * Enhancement for lightning development * Add new command for creating ``SVG`` and ``design`` * Update lightning related library @@ -259,7 +267,7 @@ Release 3.2.4 (2015-12-09) Release 3.2.3 (2015-12-01) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ * Bug Fix: Fix bug for lightning development when deploying cmp or app @@ -274,7 +282,7 @@ Release 3.2.3 (2015-12-01) Release 3.2.2 (2015-11-19) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ * Bug Fix: - Fix TypeError when export soql to csv - Fix aura app preview problem @@ -292,25 +300,25 @@ Release 3.2.2 (2015-11-19) Release 3.2.1 (2015-11-10) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ * Fix issue #81 Release 3.2.0 (2015-10-07) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ * Deliver enhancement #73 * Deliver enhancement #77 Release 3.1.9 (2015-08-26) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ * Fix issue #71, export workbooks by user input * Fix bug for visibility problem of ``Retrieve Package.xml`` * Add bootstrap3 support for styleClass attribute of salesforce standard components Release 3.1.8 (2015-08-08) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ * Bug Fix: - Fix bug for bootstrap3 completion - Fix bug for ``toggle_metadata_objects`` command if project is not initiated @@ -334,7 +342,7 @@ Release 3.1.8 (2015-08-08) Release 3.1.7 (2015-08-05) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ * Enhancement: - Add `with sharing` for `Utility Class` in template - When you want to view code coverage, if you didn't download code, you can't view code coverage and you will get the reminder message in the status bar @@ -355,7 +363,7 @@ Release 3.1.7 (2015-08-05) Release 3.1.6 (2015-07-29) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ * Bug fix: - If controller name is same with page name, there will have problem when view code coverage - Fix bug when file is loaded @@ -369,7 +377,7 @@ Release 3.1.6 (2015-07-29) Release 3.1.5 (2015-07-27) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ * New Feature: - Add bootstrap3 support for html class completion - Add a new setting ``disable_bootstrap_completion`` to control bootstrap completion @@ -383,7 +391,7 @@ Release 3.1.5 (2015-07-27) Release 3.1.4 (2015-07-25) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ * Bug Fix: - Fix issue #23? - Fix issue #58 @@ -412,18 +420,18 @@ Release 3.1.4 (2015-07-25) Release 3.1.3 (2015-07-18) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ * Fix issue #54 * Fix issue #56 Release 3.1.2 (2015-07-17) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ * Fix issue #55 Release 3.1.1 (2015-07-16) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ * Bug fix: - Fix a issue for ``save_to_server`` command when ``api_version`` is less than 29 - Fix problem in ``Class Body - test data util body-sublime-snippet.sublime-snippet`` @@ -442,7 +450,7 @@ Release 3.1.1 (2015-07-16) Release 3.1.0 (2015-07-09) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ * Enhancement: - Sometimes, the inner class name is same with standard class or sObject, if this inner class is matched, ignore the standard completion - Add Notation [EU] for external or unique field in field completion, ``E`` means External, ``U`` means Unique @@ -462,7 +470,7 @@ Release 3.1.0 (2015-07-09) Release 3.0.9 (2015-07-01) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ * Bug Fix: - Fix bug for snippet ``SOQL - SELECT * FROM.sublime-snippet`` - Fix bug for ``extract_to_here`` command @@ -473,7 +481,7 @@ Release 3.0.9 (2015-07-01) Release 3.0.8 (2015-06-28) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ * Bug Fix: - Fix bug when build package.xml for whole org @@ -489,7 +497,7 @@ Release 3.0.8 (2015-06-28) Release 3.0.7 (2015-06-26) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ * Bug Fix: - Fix issue #46 - Fix bugs caused by ``describe_global`` change in the ``tooling.py`` @@ -504,7 +512,7 @@ Release 3.0.7 (2015-06-26) Release 3.0.6 (2015-06-23) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ * Bug Fix: - Merge pull request #42 by @pgAdmin(https://github.com/pgAdmin) - Merge pull request #43 by @reyesml(https://github.com/reyesml), fixed issue #6 @@ -512,7 +520,7 @@ Release 3.0.6 (2015-06-23) Release 3.0.5 (2015-06-15) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ * Bug Fix: - Custom component attributes completion bug when component file is not exist in the target path @@ -521,7 +529,7 @@ Release 3.0.5 (2015-06-15) Release 3.0.4 (2015-06-15) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ * Bug Fix: - Fix bug for issue #41 - Fix bug for ``delete_file_from_server`` keybinding for windows @@ -543,7 +551,7 @@ Release 3.0.4 (2015-06-15) Release 3.0.3 (2015-06-11) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ * Bug Fix: - Fix duplicate save check bug caused by release 3.0.2 - Fix fields completion bug for cross sObjects between tooling and non-tooling, for example ``User``, ``RecordType`` @@ -557,7 +565,7 @@ Release 3.0.3 (2015-06-11) Release 3.0.2 (2015-06-07) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ * Bug fix: - Fix NoneType exception in the console when open context menu, this is caused by release 3.0.1 - Fix bug for ``Debug > Track All Debug Logs`` in the main menu @@ -580,7 +588,7 @@ Release 3.0.2 (2015-06-07) Release 3.0.1 (2015-06-04) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ * Bug fix: - Fix bug #39 - Fix bug #40 @@ -602,7 +610,7 @@ Release 3.0.1 (2015-06-04) Release 3.0.0 (2015-05-26) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ * Bug fix: - Fix bug #38 - Fix bug for SOQL fields completion @@ -613,7 +621,7 @@ Release 3.0.0 (2015-05-26) Release 2.9.9 (2015-05-25) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ * Enhancement - SOQL fields completion, see demo at plugin home page @@ -622,7 +630,7 @@ Release 2.9.9 (2015-05-25) Release 2.9.8 (2015-05-24) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ * Update: - Update the plugin install message for package control @@ -639,7 +647,7 @@ Release 2.9.8 (2015-05-24) Release 2.9.7 (2015-05-22) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ * Bug Fix: - Fix issue #36 - Fix bug for ``childXmlNames`` parsing and ``childXmlNames`` completion for package.xml @@ -663,7 +671,7 @@ Release 2.9.7 (2015-05-22) Release 2.9.6 (2015-05-20) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ * Bug Fix: - Fix issue #33 - Fix issue #35 @@ -685,7 +693,7 @@ Release 2.9.6 (2015-05-20) Release 2.9.5 (2015-05-16) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ * Enhancement: - Add callback for ``toggle_metadata_objects`` if ``.config/metadata.json`` is not exist - Move ``export_query_to_csv`` command from context menu to ``Data Loader`` in the main menu, add check logic for input soql and allow to try again. @@ -709,7 +717,7 @@ Release 2.9.5 (2015-05-16) Release 2.9.4 (2015-05-13) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ * Bug Fix: - If there is only one member, just remove the type and the related member when ``build package xml`` - When execute ``query_to_csv`` command and field value contains ``"`` or ``,`` @@ -730,7 +738,7 @@ Release 2.9.4 (2015-05-13) Release 2.9.3 (2015-05-11) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ * Enhancement: - Package.xml completion read cache from ``.config/package.json``, no longer read cache from project file - Sort for items in quick panel of package.xml building @@ -742,7 +750,7 @@ Release 2.9.3 (2015-05-11) Release 2.9.2 (2015-05-10) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ * Bug Fix: - Fix bug for ``combine_soql`` which is invoked by ``Generate SOQL`` and ``Bulk Query`` - Fix bug for ``export_profile`` command @@ -772,7 +780,7 @@ Release 2.9.2 (2015-05-10) Release 2.9.1 (2015-05-05) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ * Fix bug for ``switch_project``, see issue #24 * Enhancement for speeding up ``Save To Server`` operation * Rename ``save_component`` command to ``save_to_server`` @@ -783,7 +791,7 @@ Release 2.9.1 (2015-05-05) Release 2.9.0 (2015-05-03) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ * Fix bug for messy code in debug log detail * Enhancement for not refreshing sidebar when ``retrieve_files_from_other_server`` * Enhancement for adding folder name to retrieve request when ``list_package`` for folders @@ -800,7 +808,7 @@ Release 2.9.0 (2015-05-03) Release 2.8.9 (2015-04-28) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ * Fix urgent bug for issue #22 * Enhancement for speeding up ``Save To Server`` operation * Enhancement for supporting ``list_package`` when execute retrieve operation @@ -811,7 +819,7 @@ Release 2.8.9 (2015-04-28) Release 2.8.8 (2015-04-26) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ * Fix bug: If user don't have `Author Apex` privilege, plugin will give wrong information * Fix bug: Show alert message if no available package.xml to combine * Enhancement: Issue 15 about linking ``sublime-project`` with plugin project, deliver Windows solution but keep unchanged for OSX @@ -822,7 +830,7 @@ Release 2.8.8 (2015-04-26) Release 2.8.7 (2015-04-22) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ * Fix plugin loading NoneType issue * Combine ``retrieve_package_file`` and ``retrieve_package_xml`` command to only ``retrieve_package_xml`` * Allow user to input extractTo path, enhancement for issue #19 @@ -831,7 +839,7 @@ Release 2.8.7 (2015-04-22) Release 2.8.6 (2015-04-20) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ * Optimization for parsing project name by path or file * Change the default workspace of plugin level to empty * Change the workspace to optional, if workspace of plugin level and project level are both empty, plugin will save the project to ``/User/HaoIDE``, @@ -843,7 +851,7 @@ Release 2.8.6 (2015-04-20) Release 2.8.5 (2015-04-10) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ * Biggest optimization for variable completion: - Exclude comment statement - Choose the nearest matched one @@ -852,7 +860,7 @@ Release 2.8.5 (2015-04-10) Release 2.8.4 (2015-04-09) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ * Add error popup display for latest version of sublime * Add a new settings ``disable_html_completion`` to disable html completion * Set default value of ``disable_html_completion`` as true because of conflict with sublime @@ -867,13 +875,13 @@ Release 2.8.4 (2015-04-09) Release 2.8.3 (2015-04-02) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ * If no CRUD privilege on profile object, just leave blank in the output csv * Add field FLS export feature, it's a wonderful feature for document Release 2.8.2 (2015-03-28) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ * Fix package.xml completion bug if file name contains multiple dot * Fix package.xml completion bug if there have extracted zip resource * Pull request for #14 @@ -883,19 +891,19 @@ Release 2.8.2 (2015-03-28) Release 2.8.1 (2015-03-05) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ * Fix issue #6 * Enhancement for issue #13 Release 2.8.0 (2015-02-11) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ * Fix issue #11, #12 * Add two commands ``Retrieve All`` and ``Retrieve sObject and Workflow`` in the command palette Release 2.7.9 (2015-02-06) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ * Fix issue #4 * Fix issue #7 * Enhancement for ``diff_with_server``, allow diff compare with different project @@ -904,7 +912,7 @@ Release 2.7.9 (2015-02-06) Release 2.7.8 (2015-02-02) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ * Rename ``refresh_component`` command to ``refresh_file_from_server`` * Rename ``refresh_selected_components`` command to ``refresh_files_from_server`` * Rename ``delete_selected_components`` command to ``delete_files_from_server`` @@ -916,7 +924,7 @@ Release 2.7.8 (2015-02-02) Release 2.7.7 (2015-01-22) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ * Fix bug for ``Package.xml Completion`` * Enhancement: display error column in XML if deploy failed * Enhancement for ``json_to_apex`` @@ -928,7 +936,7 @@ Release 2.7.7 (2015-01-22) Release 2.7.6 (2015-01-20) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ * Enhancement for ``create_trace_flag`` command * Add a enabled check logic for ``export profiles`` command * Add a new ``haoide > Utilities > Convert JSON to Apex`` command for converting JSON to Apex @@ -937,7 +945,7 @@ Release 2.7.6 (2015-01-20) Release 2.7.5 (2015-01-18) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ * Fix bug: messy code when view debug log detail in sublime * Fix bug: timeout exception is not caught when save component * Enhancement for completions @@ -947,7 +955,7 @@ Release 2.7.5 (2015-01-18) Release 2.7.4 (2015-01-16) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ * Fix bug for issue #75 * Update ``Chanel`` to ``Channel`` in the plugin copyright information * Update license information @@ -959,7 +967,7 @@ Release 2.7.4 (2015-01-16) Release 2.7.3 (2015-01-14) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ * Fix bug for ``extract here`` command * Fix bug for ``bulk api`` caused by release 2.7.2 * Fix long-term bug for inProgress message of deployment @@ -971,7 +979,7 @@ Release 2.7.3 (2015-01-14) Release 2.7.2 (2015-01-12) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ * Fix bug for issue #74 * Fix bug for ``cancel_deployment`` * Fix bug for ``reload symbol table`` when symbol_table is None @@ -983,7 +991,7 @@ Release 2.7.2 (2015-01-12) Release 2.7.1 (2015-01-09) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ * Enhancement for ``standardController completion`` in `` Email`` for ``Debug Log User List`` * Milestone change for soap body request @@ -1005,21 +1013,21 @@ Release 2.7.0 (2015-01-03) Release 2.6.0 (2014-12-20) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ * Enhancement for ``refresh_folder`` * Enhancement for ``retrieve_all`` and ``retrieve_sobjects_and_workflows`` * Move export csv files to ``.export`` folder, for example, CustomFields, ValidationRules, Workflows and Workbooks, etc. Release 2.5.9 (2014-12-17) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ * Completion enhancement for building package.xml * Fix duplicate MetadataContainerId for issue #69 * `Build Package.xml Demo `_ Release 2.5.8 (2014-12-15) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ * Add all ``sharingRules`` metadata types to default components setting * Rename ``.package`` to ``.deploy`` for ``deploy to server`` execution * Remove ``subscribe_component`` and ``unsubscribe_component`` commands @@ -1031,7 +1039,7 @@ Release 2.5.8 (2014-12-15) Release 2.5.7 (2014-12-14) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ * Fix Bug for creating extension or controller after input # in visualforce page * Adjust the location of ``Cache`` menu item * Add a new command for ``retrieve package.xml`` in sidebar menu @@ -1046,7 +1054,7 @@ Release 2.5.7 (2014-12-14) Release 2.5.6 (2014-12-13) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ * Fix Bug for issue #65 * Fix Bug for issue #66 * Enhancement for issue #48, after deployed, the `package.xml` is saved to `.package` in workspace @@ -1056,7 +1064,7 @@ Release 2.5.6 (2014-12-13) Release 2.5.5 (2014-12-09) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ * Fix Bug for creating Lightning Component Element * When deploy failed due to lower code coverage, display the coverage warning message * When new component is created, create the meta.xml file for it @@ -1067,7 +1075,7 @@ Release 2.5.5 (2014-12-09) Release 2.5.4 (2014-12-07) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ * Add `dateutil` module for supporting timezone converting * Fix Bug for `track debug log` * Trim the space for `REST URI` automatically @@ -1076,7 +1084,7 @@ Release 2.5.4 (2014-12-07) Release 2.5.3 (2014-12-05) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ * Adjust the context menu from most bottom to center * Adjust the sidebar menu from most bottom to center * Fix Bug for issue #62: 'module' object has no attribute 'populate_classes' @@ -1086,21 +1094,21 @@ Release 2.5.3 (2014-12-05) Release 2.5.2 (2014-11-27) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ * After new lightning component is created, deploy it to server * Add a new command for ``pretty json`` in the context menu * hide the status message in progress bar when track self debug log after save succeed Release 2.5.1 (2014-11-26) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ * Fix Bug: NoneType Exception when destruct files from server * Fix Bug: when saving component, the active view is not file * Add a new settings ``track_log_after_saved`` to control whether track log after save succeed Release 2.5.0 (2014-11-26) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ * Fix Bug: when delete component, if there is a open view which is not bind to file, it will throw TypeError: argument of type 'NoneType' is not iterable, and then, file is deleted from server but local file is not removed * Fix Bug: After folder is refreshed or project is updated, update the component cache * Add `Lightning Component` document reference @@ -1122,7 +1130,7 @@ Release 2.5.0 (2014-11-26) Release 2.4.0 (2014-11-18) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ * Fix issue #55 * Fix issue: non-english words are encoded to Unicode in result of ``Rest Test`` * Fix issue: when read local cache of record type, ``global name 'users' is not defined`` exception @@ -1133,7 +1141,7 @@ Release 2.4.0 (2014-11-18) Release 2.3.0 (2014-11-14) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ * Use local ``/.config/session.json`` to reuse session but not globals() again * Use local ``/.config/recordtype.json`` to ``record type`` but not globals() again * Use local ``/.config/users.json`` to ``users`` but not globals() again @@ -1144,7 +1152,7 @@ Release 2.3.0 (2014-11-14) Release 2.2.0 (2014-11-12) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ Fix Issue: * Fix issue: TypeError: string indices must be integers when refreshed folder is empty @@ -1165,7 +1173,7 @@ New Feature: Release 2.1.0 (2014-11-10) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ + Fix Bug: ``IndexError: list index out of range`` caused by release 2.0.0 + Fix Bug for test class judgment: test class is that starts with `test` or ends with `test` + Add a new apex.py module, move execute_anonymous method from metadata.py to apex.py @@ -1177,7 +1185,7 @@ Release 2.1.0 (2014-11-10) Release 2.0.0 (2014-11-08) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ + Fix minor bug for ``Duplicate Save Execution of Same Component`` + Remove useless message from ``message.py`` + Add a space between parameters for completion of standard apex class @@ -1191,7 +1199,7 @@ Release 2.0.0 (2014-11-08) Release 1.9.0 (2014-11-04) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ + Fix issue #50 + Fix minor issue for ``delete_component`` + Fix potential issue for retrieve and deploy @@ -1202,14 +1210,14 @@ Release 1.9.0 (2014-11-04) Release 1.8.0 (2014-11-03) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ + In order to prevent UI freeze, use thread to extract encoded zipFile to path + Solution for issue #49, add a new settings ``maximum_concurrent_connections`` to control concurrent connections + In order to prevent UI freeze, set default value of ``maximum_concurrent_connections`` to ``30`` Release 1.7.0 (2014-10-31) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ + Fix Bug: If just compile component but not save, no need to keep history + Fix Bug: SOQL Field Completion problem if there is more than one character between from and sObject + Fix Bug: Replace all `LIST` to `List` @@ -1217,7 +1225,7 @@ Release 1.7.0 (2014-10-31) Release 1.6.0 (2014-10-25) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ + Fix Bug: issue #44 caused by release 1.5.0 + Fix Bug: display ExpatError when retrieve package + Fix Bug: display json parse error message when execute rest test @@ -1231,14 +1239,14 @@ Release 1.6.0 (2014-10-25) Release 1.5.0 (2014-10-21) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ + Fix Bug for package import error in ``bulk api`` + Add more detailed action summary for ``save component``, issue #45, issue #46 + Add description for ``quick controller`` in README.MD Release 1.4.0 (2014-10-18) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ + Fix bug for completion: No completions for ``strMap`` if there has ``// Populate Map\nMap strMap = new Map();`` + Fix Bug: ``deploy open files to server`` + Add a new command for ``preview_page`` in the command palette @@ -1247,14 +1255,14 @@ Release 1.4.0 (2014-10-18) Release 1.3.0 (2014-10-14) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ + Fix Minor bug for standard class completion: duplicate class in different namespace, for example, Communities, TimeZone, UnsupportedOperationException, Test, QueryException, Action + Fix Critical bug: non code file can't be retrieve from server, now, objects, reports and others can be retrieve from server + Fix Critical bug: Deploy exception after session cache is expired Release 1.2.0 (2014-10-11) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ + ``get_static_resource_body`` settings is deprecated + Change default ``api_version`` from ``30`` to ``31`` + Add a new command ``deploy open files to server`` in the main menu, which is used to deploy open files in the sublime to target server @@ -1265,7 +1273,7 @@ Release 1.2.0 (2014-10-11) Release 1.1.0 (2014-10-09) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ + Fix Bug for Windows: After ``export`` is finished, refresh the project folders to ensure the new folder is shown in the sidebar + Fix Bug: display deploy failed message if deploy is failed. + Fix Bug: symbol table is null when iterate symbol table @@ -1273,17 +1281,17 @@ Release 1.1.0 (2014-10-09) Release 1.0.9 (2014-10-04) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ + Fix Bug: After open a new view, open context menu, it will throw NoneType exception Release 1.0.8 (2014-10-02) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ + Fix issue at ``https://success.salesforce.com/answers?id=90630000000gxvwAAA`` Release 1.0.7 (2014-09-30) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ + Fix Minor Bug for windows: After ``.config`` is generated, invoke the sublime command: ``refresh_folder_list`` + Enhancement for checking whether current project is active project + Fix Critical Bug: If session is expired, we want to refresh the folder or update project, the console will always stop at the step of ``[sf:retrieve] Start request for a retrieve...`` @@ -1291,7 +1299,7 @@ Release 1.0.7 (2014-09-30) Release 1.0.6 (2014-09-28) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ + Fix Minor Bug: After ``retrieve_package_file`` is succeed, hide the output panel + Fix Minor Bug: If current project is not ``active project``, disable the ``Retrieve Files From Server`` functionality + Fix Minor Bug: If current project is not ``active project``, disable the ``Retrieve File From Server`` functionality @@ -1299,14 +1307,14 @@ Release 1.0.6 (2014-09-28) Release 1.0.5 (2014-09-27) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ + Fix bug: Exception when ``new project`` in a new org + Fix bug: If there is no any trigger, after ``new project``, the folder of ``trigger`` is not created. + Fix bug: ``subscribed_meta_folders`` and ``meta_folders`` in settings are not correct Release 1.0.4 (2014-09-25) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ + Fix urgent issue #40 + Remove the useless soap related codes, for example, ``retrieve_apex_code_body``, ``retrieve_static_resource_body`` and so on + Fix minor bug: Don't allow to refresh or delete ``*-meta.xml`` file @@ -1325,14 +1333,14 @@ Release 1.0.4 (2014-09-25) Release 1.0.3 (2014-09-24) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ + After ``Update Project`` is finished, remove the original ``src`` tree and then extract the zipFile to ``src`` + After ``Refresh Folder`` is finished, remove the original folders and then extract the zipFile to specified folders + Fix urgent bug: if no project in sidebar and sidebar is hidden, after ``new project`` or ``update project``, the sidebar is not open automatically. Release 1.0.2 (2014-09-23) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ + Update the default value of ``checkOnly`` in ``deploy_options`` settings from ``true`` to ``false`` + Fix Urgent bug: If one class is created in the server, after ``refresh folder``, cache of this folder will override all components + Remove some useless ``print`` statement @@ -1343,7 +1351,7 @@ Release 1.0.2 (2014-09-23) Release 1.0.1 (2014-09-22) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ + Add ``LogLength`` column to result of ``fetch debug logs`` + Update default value of ``display_field_name_and_label`` setting from ``false`` to ``true`` + Remove the ``\n`` from success message in ``document.py`` @@ -1353,7 +1361,7 @@ Release 1.0.1 (2014-09-22) Release 1.0.0 (2014-09-21) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ + Add a new command ``Deploy To Server`` in the context menu + Fix bug for ``retrieve`` when session is expired + Fix bug for ``New ApexClass``, ``New ApexTrigger``, ``New ApexComponent`` and ``New ApexPage`` @@ -1363,13 +1371,13 @@ Release 1.0.0 (2014-09-21) Release 0.9.9 (2014-09-20) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ + Try to fix bug for ``new release messages display`` or who can tell me how to display ``release message`` + Fix bug for ``quick go to component`` Release 0.9.8 (2014-09-20) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ + Support multiply folder refresh + Add standard sObjects to CustomObject Package Members when create new project if CustomObject is subscribed + Update default subscribed components @@ -1380,7 +1388,7 @@ Release 0.9.8 (2014-09-20) Release 0.9.7 (2014-09-19) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ + Milestone for Metadata Api Migration from ``Tooling Api`` for non-code meta + remove some time stamp for deploy + Functionality check for ``convert xml to json`` @@ -1393,21 +1401,21 @@ Release 0.9.7 (2014-09-19) Release 0.9.6 (2014-09-16) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ + Fix bug for issue #38, remove ``ownerRules``, ``criteriaBasedRules`` and ``installedPackages`` from default package.xml + Add a command to export CustomLables to csv + Update ``SOQL - SELECT FROM`` snippet Release 0.9.5 (2014-09-15) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ + Add confirm request for ``new project`` + Add screenshot for ``Convert XML to JSON`` + Fix KeyError Exception bug: cancel save operation if conflict. Release 0.9.4 (2014-09-14) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ + Move ``check_enabled`` from ``main.py`` to ``util.py`` + If ``deploy status`` is in ``canceling``, continue to check deploy status until it's canceled. + Remove useless ``mkdir`` method from context.py @@ -1416,14 +1424,14 @@ Release 0.9.4 (2014-09-14) Release 0.9.3 (2014-09-13) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ + Add a command to convert selection to JSON if selection is valid XML format + Add context menu item, commands for this command + Fix a bug for parsing ``apexrest`` url when executing rest test Release 0.9.2 (2014-09-13) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ + Fix bug when ``sosl_string`` contains ``-, ?, *`` + Update ``query`` method in ``api.py`` + Separate ``api.py`` to ``metadata.py`` and ``tooling.py`` and move them to new ``api`` folder @@ -1433,12 +1441,12 @@ Release 0.9.2 (2014-09-13) Release 0.9.1 (2014-09-12) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ + Fix bug when code has conflict and user cancel the save operation Release 0.9.0 (2014-09-12) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ + Fix bug for windows sidebar folder refresh + Not keep ``default_project`` settings in the settings of ``.config`` + Add ``reload_symbol_tables_when_create_project`` setting @@ -1447,7 +1455,7 @@ Release 0.9.0 (2014-09-12) Release 0.8.9 (2014-09-11) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ + If ``retrieve`` is in ``Queued``, thread sleep 2 seconds, else, thread sleep 1 seconds + If ``deploy`` is in ``Pending``, thread sleep 2 seconds, else, thread sleep 1 seconds + After project is switched, set status for all view of all window. @@ -1456,25 +1464,25 @@ Release 0.8.9 (2014-09-11) Release 0.8.8 (2014-09-11) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ + Fix some bug for ``deploy`` Release 0.8.7 (2014-09-10) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ + Update README + When ``New Project``, no need to select project + Fix bug ``c:`` completion Release 0.8.6 (2014-09-09) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ + Add ``c:`` prefix for custom component completion + Add space between timestamp and message in the panel Release 0.8.5 (2014-09-08) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ + Move some methods from processor.py to util.py + Optimize sObject Cache download + Add time stamp prefix for panel message @@ -1488,7 +1496,7 @@ Release 0.8.5 (2014-09-08) Release 0.8.4 (2014-09-08) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ + If just checkOnly, output VALIDATE, otherwise, output DEPLOY + Update comments for ``mousemap`` + Big Milestone, originally, we use ``tooling api`` to download apex code, now it is changed to retrieving by ``metadata api`` @@ -1496,7 +1504,7 @@ Release 0.8.4 (2014-09-08) Release 0.8.3 (2014-09-07) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ + Rearrange the attribute position in ``soap_bodies.py`` + Update README.MD + When start ``deploy`` command, if clipboard content is not valid zip file path, set path with empty, otherwise, paste it to input panel @@ -1520,13 +1528,13 @@ Release 0.8.3 (2014-09-07) Release 0.8.2 (2014-09-05) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ + when ``retrieve package.xml``, if file in package.xml is not found in target org, display the message + Add ``deploy package.zip`` command to deploy zip file Release 0.8.1 (2014-09-05) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ + Change the UI of ``retrieve`` + Add a command ``retrieve_package`` in the main menu to retrieve metadata by specified package.xml + Fix a bug for ``get_static_resource_body`` when creating a new project @@ -1535,7 +1543,7 @@ Release 0.8.1 (2014-09-05) Release 0.8.0 (2014-09-04) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ - Change ``se`` Snippet from ``SELECT Id, $2 FROM $1$0`` to ``SELECT Id$2 FROM $1$0`` - Stop to open console when ``Refresh Selected Component`` - Originally, press ``shift+button1*3`` to open class in background and press ``shift+button1*2`` to open class in foreground, now it is changed to ``shift+button1*3`` for background and ``shift+button1*2`` for foreground @@ -1544,20 +1552,20 @@ Release 0.8.0 (2014-09-04) Patch for Release 0.7.9 (2014-09-01) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ + ``output_session_info`` setting is deprecated and replaced by ``.config/session.json`` + Do not keep ``projects`` settings in the ``.config/settings.json``, because it's private confidential Release 0.7.9 (2014-09-01) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ + Fix the display problem of ``Run Test`` and ``LoginTo ApexCode`` cause by History Item 1 of release 0.7.7 + Rename the path name of ``Test Operation History`` from ``test`` to ``Test`` + Fix bug for ``Create Component`` and ``Refresh Component Folder`` caused by History Item 1 of release 0.7.7 Release 0.7.8 (2014-08-31) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ + Fix Operation History Format Problem + Inner class completion format ``Inner Class `` + After Project is created, automatically keep the settings to ``.config`` path @@ -1566,7 +1574,7 @@ Release 0.7.8 (2014-08-31) Release 0.7.7 (2014-08-30) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ + In order to avoid component is not available to CRUD to server because of Sensitive Case, save the component name with lower case into local cache + Read custom class from ``Component Attribute Cache`` but not read them from ``Symbol Table Cache`` + After input ``Page.``, list all custom visualforce page if have @@ -1575,21 +1583,21 @@ Release 0.7.7 (2014-08-30) Release 0.7.6 (2014-08-29) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ + Deep process for result of ``Execute Rest`` if result is json string + Change Operation History Format + Add ``report_issue`` command Release 0.7.5 (2014-08-24) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ - Add snippet ``Class Body - Get Child Roles By Role`` - ``Local Change History`` functionality is removed from events.py, just if ``save to server`` is succeed, the local change history will be kept - Inner class completion format ``Inner Class `` Release 0.7.4 (2014-08-17) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ - Inner Class Completion format - Add compress header for ``get`` method in api.py - Fix ``Reload Sobject Cache`` bug caused by release 0.7.3 @@ -1597,7 +1605,7 @@ Release 0.7.4 (2014-08-17) Release 0.7.3 (2014-08-16) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ - Add MIT-LICENSE - Remove ``quick visualforce`` functionality - Rename method name ``get_toolingapi_settings`` in context.py to ``get_settings`` and update corresponding invoker @@ -1607,7 +1615,7 @@ Release 0.7.3 (2014-08-16) Release 0.7.2 (2014-08-15) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ - Rename ``Toggle Log Panel`` menu item to ``Open Output Panel`` - Update README.MD - Add ``Preview Page`` command to preview visualforce page in server, just enabled when opening page @@ -1615,20 +1623,20 @@ Release 0.7.2 (2014-08-15) Release 0.7.1 (2014-08-12) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ - Add ``delay_seconds_for_hidden_output_panel_when_succeed`` for control delay seconds to hide output panel when saving succeed - Rename setting ``delay_seconds_for_hidden_console`` to ``delay_seconds_for_hidden_output_panel_when_failed`` Release 0.7.0 (2014-08-11) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ - Even if component saving is succeed, show the output panel - If component saving is succeed, hide the open output panel after 1.5 seconds - When generating workbook or describe sobject, write the type column with Formula() or Release 0.6.9 (2014-08-09) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ - When export workbooks, check whether input are valid, if any one is not valid, allow user to input again - ``Folder Refresh`` reminder message is changed - Add ``Update Project`` command to just update the apex code but not include sobject metadata @@ -1642,12 +1650,12 @@ Release 0.6.9 (2014-08-09) Release 0.6.8 (2014-08-08) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ - Add remind message to show output panel Release 0.6.7 (2014-08-06) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ - Console Message --> OutputPanel Message - Add a new command ``Open Log Panel`` for display log panel - Click ``super+``` to open output panel @@ -1655,51 +1663,51 @@ Release 0.6.7 (2014-08-06) Release 0.6.6 (2014-08-05) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ - Set ``delay_seconds_for_hidden_console`` default value from ``15`` to ``9999`` - Update description for default settings - Add property and method completion for inner class Release 0.6.5 (2014-08-03) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ - Fix picklist completion bug - Add keymap for ``Execute Rest Test`` command - Remove catalog from README Release 0.6.4 (2014-07-30) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ - fix TypeError: save_component() missing 1 required positional argument: 'is_check_only' - Compatible to api 31 because `compile fail response change `_ Release 0.6.3 (2014-07-30) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ - Optimize Rest Test when response result is str - Add ``proxies`` support, just beta Release 0.6.2 (2014-07-29) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ - Fix issue for ``Delete`` command when list in returned json result is empty Release 0.6.1 (2014-07-22) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ - **Picklist Value** completion from ``value`` to ``value(label)`` - **Save Conflict** functionality new format: **Modified by at 2014-05-04 10:03:31, continue?** Release 0.6.0 (2014-07-19) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ - Add search class and its methods for apex lib - Fix bug for picklist value completion - Change ``user`` to ``User`` for issue #31 Release 0.5.9 (2014-07-10) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ - Remove useless message from message.py - Add some buld-in emmet supported snippets - Add command ``quick_visualforce`` for emmet supported snippets @@ -1707,7 +1715,7 @@ Release 0.5.9 (2014-07-10) Release 0.5.8 (2014-06-13) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ - Add a new class template ``Test Class`` - Add description for class template quick choose panel - ``Clear Cache`` functionality change, display ``project name`` not ``username`` any more @@ -1715,7 +1723,7 @@ Release 0.5.8 (2014-06-13) Release 0.5.7 (2014-06-05) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ - Optimize for opening url with browser - Update OSX Keymap - Fix bug for ``generate workbook`` in OSX @@ -1724,7 +1732,7 @@ Release 0.5.7 (2014-06-05) Release 0.5.6 (2014-05-18) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ - Fix bug for ``SELECT * FROM Sobject``, issue #30 - Add time stamp for ``save conflict`` confirm message - Optimize for ``Fetch Debug Log`` @@ -1732,7 +1740,7 @@ Release 0.5.6 (2014-05-18) Release 0.5.5 (2014-05-15) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ - Add ``*`` support for ``Rest Query``, if ``*`` query, just replace it with all fields of related sobject - Add doc for Wild-card Character query - Fix ``Run Test`` bug caused by previous release @@ -1741,14 +1749,14 @@ Release 0.5.5 (2014-05-15) Release 0.5.4 (2014-05-15) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ - Narrow down the code coverage column of test run result - When run specified test class by main menu, if no test class, show the alert message - Try to fix issue # 23 Release 0.5.3 (2014-05-12) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ - Add new snippet ``Sobject - sobject bracket`` - Update description of ``Update Sobjects``, ``Delete Sobjects`` - Add two commands for command ``Reload Cache`` and ``Clear Cache`` @@ -1756,13 +1764,13 @@ Release 0.5.3 (2014-05-12) Release 0.5.2 (2014-05-10) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ - Since from API 30, compound field (queryByDistance=true) can't be in soql field list - Fix bug for bulk api caused by release 0.5.1 Release 0.5.1 (2014-05-10) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ - Fix Bug: ``Export CustomField`` - Update OSX keymap - Add ``Export SOQL`` command to export sobject records by specified soql @@ -1771,21 +1779,21 @@ Release 0.5.1 (2014-05-10) Release 0.5.0 (2014-05-09) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ - Update ``README.MD`` - Fix bug UnicodeError for ``Export Workflows`` and ``Export Validation Rule`` in OSX - Remove some useless code, for example, ``Export Field Dependency`` Release 0.4.9 (2014-05-04) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ - Change default setting ``delay_seconds_for_hidden_console`` from ``10`` to ``15`` - Change default ``api_version`` from ``29`` to ``30`` - Add command ``Retrieve Sobject And Workflow`` Release 0.4.8 (2014-04-27) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ - Optimize picklist value completion - Remove ``.no-sublime-package`` - Replace ``excluded_sobjects`` settings with ``allowed_sobjects`` settings @@ -1794,7 +1802,7 @@ Release 0.4.8 (2014-04-27) Release 0.4.7 (2014-04-26) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ - Fix some flaw for trigger completion - Optimize Apex Completion - Update READMD.MD @@ -1802,13 +1810,13 @@ Release 0.4.7 (2014-04-26) Release 0.4.6 (2014-04-21) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ - Add ``last_n_logs`` setting to control the return number by fetching logs - Add ``check_save_conflict`` setting to control saving conflict when LastModifiedBy is not running user Release 0.4.5 (2014-04-20) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ - Update snippet: ``Exception - try catch finally`` and ``Exception - try catch`` - Add doc for api.py - Originally, Keyword completion will exclude the existing-variable completion, now, bug mei le. @@ -1818,7 +1826,7 @@ Release 0.4.5 (2014-04-20) Release 0.4.4 (2014-04-17) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ - Optimize SOQL Field completion - Update build-in apex lib - Update ``query_all`` rest api from ``query`` to ``queryAll`` which is available since winter 14 @@ -1827,14 +1835,14 @@ Release 0.4.4 (2014-04-17) Release 0.4.3 (2014-04-16) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ - Add ``Search`` and ``Quick Search`` for ``Execute Rest Test`` - Update ``README.MD`` - When view is activated, display the default project in the sidebar Release 0.4.2 (2014-04-16) (Millstone for fixing some flaw in completion) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ - Change ``display_field_name_and_label`` setting default value to false - BUG: Find variable type by variable name in view (Ignore comment code) - BUG: Find matched block in visualforce page (the matched region must contains current cursor point) @@ -1843,20 +1851,20 @@ Release 0.4.2 (2014-04-16) (Millstone for fixing some flaw in completion) Release 0.4.1 (2014-04-14) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ - Update ``Visualforce`` xPath and Document source code - Change ``api_version`` back to 29 - Change the default test org password to updated one Release 0.4.0 (2014-04-14) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ - ``Track Trace Flag`` expiration date verify logic change - Return all sobjects when call ``Global Describe`` method in api.py, originally default return value is createable and queryable sobjects Release 0.3.9 (2014-04-12) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ - Update project folder structure, you can change it to original strcture by remove the ``src/`` from every component attribute - If visualforce component attribute type is ``Object`` in visualforce completion, return ```_ Release 0.3.6 (2014-03-30) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ - Add thread progress for document reloading - Add confirm request for document reloading @@ -1897,19 +1905,19 @@ Release 0.3.6 (2014-03-30) Release 0.3.5 (2014-03-29) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ - Clarify Usage of kinds of feature in README.MD Release 0.3.4 (2014-03-26) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ - Fix urgent bug for `Issue #22 `_ Release 0.3.3 (2014-03-22) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ - Add confirmation request for ``Refresh Component`` - Add a new command for ``Compile Component`` @@ -1917,14 +1925,14 @@ Release 0.3.3 (2014-03-22) Release 0.3.2 (2014-03-22) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ - Upgrade ``xmltodict`` lib to latest - Add ``namespace`` for standard class in the completion **Release 0.3.1** (Milestone of Code Completion) (2014-03-22) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ - Fix bug: ``KeyError: 'symbol_table'`` when save component is not ``ApexClass`` - Add some new standard class to completion @@ -1933,7 +1941,7 @@ Release 0.3.2 (2014-03-22) Release 0.3.0 (2014-03-20) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ - Remove the duplicate ``New Component`` command and add ``New ApexPage`` command in the quick command palette - Update the apex standard class lib @@ -1941,7 +1949,7 @@ Release 0.3.0 (2014-03-20) Release 0.2.9 (2014-03-20) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ - Move the fields describe part from the bottom to top in the sobject describe result - Change the default apex log level from ``Finest`` to ``Debug`` @@ -1950,7 +1958,7 @@ Release 0.2.9 (2014-03-20) Release 0.2.8 (2014-03-19) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ - Add ``Tooling Query`` for ``Rest Explorer`` - Add ``SOQL & SOSL`` for Salesforce Document Reference @@ -1959,13 +1967,13 @@ Release 0.2.8 (2014-03-19) Release 0.2.7 (2014-03-17) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ - Update the tabTrigger from muti-bytes to less than 5-bytes for all snippets Release 0.2.6 (2014-03-16) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ - Fix the bug of ``Rest Post`` - Remove ``Request``, ``Application``, ``LogLength``, ``DurationMilliseconds`` from ``List Debug Log`` columns @@ -1974,7 +1982,7 @@ Release 0.2.6 (2014-03-16) Release 0.2.5 (2014-03-15) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ - Remove the command ``New Component`` from the side bar - Remove four shortcut keys for the four new component @@ -1984,7 +1992,7 @@ Release 0.2.5 (2014-03-15) Release 0.2.4 (2014-03-11) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ - Update README.MD - Remove shortcut key ``Ctrl+Alt+N`` for creating new component @@ -1992,7 +2000,7 @@ Release 0.2.4 (2014-03-11) Release 0.2.3 (2014-03-10) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ - Add ``Console Toolkit``, ``Standard Objects``, ``Data Model`` and ``Tooling APi`` references to document list - Update Main Menu Item @@ -2004,21 +2012,21 @@ Release 0.2.3 (2014-03-10) Release 0.2.2 (2014-03-07) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ - Remove some useless print statement in the document.py - Update README.MD for latest release Release 0.2.1 (2014-03-07) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ - Add ``Rest Api``, ``Visualforce``, ``Chatter Api``, ``Streaming Api`` and ``Bulk Api`` to document list - Add methods redirect to document list Release 0.2.0 (2014-03-07) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ - Change ``default_browser_path`` setting name to ``default_chrome_path`` - Add a new salesforce reference function from `Salesforce Reference `_ @@ -2026,7 +2034,7 @@ Release 0.2.0 (2014-03-07) Release 0.1.9 (2014-03-06) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ - Fix the static resource bug ``Can't convert 'dict' object to str implicitly`` - When creating trigger, just list the triggerable sobject - If project is not created, ``New Component`` and ``Refresh Folder`` are disabled @@ -2034,7 +2042,7 @@ Release 0.1.9 (2014-03-06) Pre-release 0.1.8 (2014-03-05) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ - When save component and error happened, ``go to`` the error line - Change the ``new component`` to separate ones @@ -2047,7 +2055,7 @@ Pre-release 0.1.8 (2014-03-05) Release 0.1.7 (2014-03-04) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ - If project is not created, ``New Component`` and ``Refresh Folder`` are disabled - Allow empty json body for ``Post`` Action @@ -2057,14 +2065,14 @@ Release 0.1.7 (2014-03-04) Release 0.1.6 (2014-03-01) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ - Update README.MD - Refractoring api.py Release 0.1.5 (2014-02-28) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ - Change new view event type from ``on_new_sync`` to ``on_new`` - Set the default format for rest test result to ``JavaScript`` @@ -2072,21 +2080,21 @@ Release 0.1.5 (2014-02-28) Release 0.1.4 (2014-02-26) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ - Update comments for ``toolingapi.sublime-settings`` - Fix the bug for ``open console`` Release 0.1.3 (2014-02-24) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ - Add the support the static resource refresh functionality for the side bar menu - Add the support the static resource refresh functionality for the context menu - Add ``Patch`` method for ``Rest Explorer`` Release 0.1.2 (2014-02-22) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ - Add a new setting ``default_chrome_path`` - Optimize the ``Rest Explorer`` functionality @@ -2094,7 +2102,7 @@ Release 0.1.2 (2014-02-22) Release 0.1.1 (2014-02-22) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ - Add snippets for console toolkit - Add time stamp for success message of save component result @@ -2103,7 +2111,7 @@ Release 0.1.1 (2014-02-22) Release 0.1.0 (2014-02-20) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ - Add snippets for console toolkit - Update README @@ -2111,7 +2119,7 @@ Release 0.1.0 (2014-02-20) Release 0.0.9 (2014-02-19) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ - Update the snippets for debug - Add a new snippet "ReRender Form in JavaScript" @@ -2121,39 +2129,39 @@ Release 0.0.9 (2014-02-19) Patch for 0.0.8 (2014-02-12) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ - Add two template for new component command: Controller and Utility Class - Add two snippets Patch for 0.0.7 (2014-02-12) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ - Fix bug for `Issue #11 `_ Release 0.0.7 (2014-02-08) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ - Fix problem when execute anonymous return error - Change ``disable_keyword_completion`` from true to false Release 0.0.6 (2014-02-08) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ - Fix retrieve metadata exception Patch for 0.0.5 (2014-01-31) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ - Update README.MD 0.0.5 (2014-01-22) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ - Add Run All Test functionality - Adjust the format of test run result of single test class @@ -2161,13 +2169,13 @@ Patch for 0.0.5 (2014-01-31) 0.0.4 (2014-01-21) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ - Remove ``Widget.sublime-settings`` from plugin 0.0.3 (2014-01-20) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ - Add time stamp for all error message displayed in console - Disable deploy metadata command @@ -2176,13 +2184,13 @@ Patch for 0.0.5 (2014-01-31) Patch 0.0.2 (2014-01-11) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ - Change the default test project 0.0.2 (2014-01-07) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ - Remove ``debug_log_headers`` and ``debug_log_headers_properties`` settings - Unquote and unescape the error message returned by ``Save to Server`` @@ -2190,7 +2198,7 @@ Patch 0.0.2 (2014-01-11) Patch for 0.0.1 (2014-01-06) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ - When creating new component, if user input is not valid, user can try again if need - Bug: if project is not created, just create the project for the new component @@ -2200,7 +2208,7 @@ Patch for 0.0.1 (2014-01-06) 0.0.1 (2014-01-05) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ - Remove ``Loop - for.sublime-snippet`` snippet - Remove ``all_views_completions.py`` dependency lib @@ -2208,7 +2216,7 @@ Patch for 0.0.1 (2014-01-06) Pre-release x.x.x (2013-12-06 -> 2013-12-31) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++++++++++ - There is a long confusing term on github version control - Add picklist value completions feature @@ -2236,7 +2244,7 @@ Pre-release x.x.x (2013-12-06 -> 2013-12-31) 0.0.0 (2013-04-14) -++++++++++++++++++ +++++++++++++++++++++++++++++++++++++ * Birth! diff --git a/aura.py b/aura.py index cd78771..66d35e7 100644 --- a/aura.py +++ b/aura.py @@ -31,6 +31,7 @@ def is_enabled(self): class DeployLightningToServer(sublime_plugin.WindowCommand): def __init__(self, *args, **kwargs): super(DeployLightningToServer, self).__init__(*args, **kwargs) + self.meta_type = '' def run(self, dirs, switch_project=True, source_org=None, element=None, update_meta=False): if switch_project: @@ -47,7 +48,7 @@ def run(self, dirs, switch_project=True, source_org=None, element=None, update_m } }) - base64_package = util.build_lightning_package(dirs, meta_type=element) + base64_package = util.build_lightning_package(dirs, meta_type=self.meta_type) processor.handle_deploy_thread( base64_package, source_org=source_org, @@ -62,9 +63,10 @@ def is_visible(self, dirs, switch_project=True): self.settings = context.get_settings() for _dir in dirs: attributes = util.get_file_attributes(_dir) - metadata_folder = attributes["metadata_folder"] - if metadata_folder not in ["aura", "lwc"]: + meta_folder = attributes["metadata_folder"] + if meta_folder not in ["aura", "lwc"]: return False + self.meta_type = 'AuraDefinitionBundle' if meta_folder == 'aura' else 'LightningComponentBundle' if self.settings["default_project_name"] not in _dir: return False @@ -183,7 +185,6 @@ def is_visible(self, dirs): self.types["LightningComponentBundle"] = [_name] # Check whether any aura components are chosen - print(self.types) if not self.types: return False diff --git a/config/menus/Side bar.sublime-menu b/config/menus/Side bar.sublime-menu index a4dd6a1..1773989 100644 --- a/config/menus/Side bar.sublime-menu +++ b/config/menus/Side bar.sublime-menu @@ -141,6 +141,25 @@ "args": {"dirs": [], "element": "SVG"} }, + { + "caption": "Create Lwc Style", + "command": "create_lwc_element", + "args": {"dirs": [], "element": "CSS"} + }, + + { + "caption": "Create Lwc SVG", + "command": "create_lwc_element", + "args": {"dirs": [], "element": "SVG"} + }, + + // do not support additional js current + // { +// "caption": "Add Lwc Additional JS", +// "command": "create_lwc_element", +// "args": {"dirs": [], "element": "AdditionalJS"} +// }, + {"caption": "-"}, { diff --git a/config/templates/LwcElement/Additional.js b/config/templates/LwcElement/Additional.js new file mode 100644 index 0000000..8fae127 --- /dev/null +++ b/config/templates/LwcElement/Additional.js @@ -0,0 +1 @@ +//sample additional js file \ No newline at end of file diff --git a/config/templates/LwcElement/Basic.css b/config/templates/LwcElement/Basic.css deleted file mode 100644 index e69de29..0000000 diff --git a/config/templates/LwcElement/Basic.svg b/config/templates/LwcElement/Basic.svg deleted file mode 100644 index e69de29..0000000 diff --git a/config/templates/LwcElement/SVG.svg b/config/templates/LwcElement/SVG.svg new file mode 100644 index 0000000..3e1b694 --- /dev/null +++ b/config/templates/LwcElement/SVG.svg @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/config/templates/LwcElement/Style.css b/config/templates/LwcElement/Style.css new file mode 100644 index 0000000..1fabb2c --- /dev/null +++ b/config/templates/LwcElement/Style.css @@ -0,0 +1 @@ +/* sample css file */ \ No newline at end of file diff --git a/config/templates/templates.json b/config/templates/templates.json index 8ea4829..f70a14a 100644 --- a/config/templates/templates.json +++ b/config/templates/templates.json @@ -188,17 +188,17 @@ "LwcElement": { "AdditionalJS": { - "directory": "LwcElement/additional.js", + "directory": "LwcElement/Additional.js", "extension": ".js" }, "CSS": { - "directory": "LwcElement/style.css", + "directory": "LwcElement/Style.css", "extension": ".css" }, "SVG": { - "directory": "LwcElement/svg.svg", + "directory": "LwcElement/SVG.svg", "extension": ".svg" } } diff --git a/lwc.py b/lwc.py index 99e3df7..deb3489 100644 --- a/lwc.py +++ b/lwc.py @@ -103,7 +103,7 @@ def run(self, dirs, switch_project=True, source_org=None, update_meta=False): } }) - base64_package = util.build_lightning_package(dirs, 'lwc') + base64_package = util.build_lightning_package(dirs, 'LightningComponentBundle') processor.handle_deploy_thread(base64_package, source_org=source_org, update_meta=update_meta) def is_visible(self, dirs, switch_project=True): @@ -120,3 +120,64 @@ def is_visible(self, dirs, switch_project=True): visible = False return visible + + +class CreateLwcElement(sublime_plugin.WindowCommand): + def __init__(self, *args, **kwargs): + super(CreateLwcElement, self).__init__(*args, **kwargs) + self.settings = context.get_settings() + + def run(self, dirs, element=""): + """ element: Component, Controller, Helper, Style, Documentation, Render + """ + + # Get template attribute + templates = util.load_templates() + template = templates.get("LwcElement").get(element) + templates_path = os.path.join(self.settings["workspace"], + ".templates", template["directory"]) + with open(templates_path) as fp: + body = fp.read() + + extension = template["extension"] + element_name = self.lwc_name + extension + + # Combine lwc element component name + element_file = os.path.join(self._dir, element_name) + + # If element file is already exist, just alert + if os.path.isfile(element_file): + return self.window.open_file(element_file) + + # Create lwc Element file + with open(element_file, "w") as fp: + fp.write(body) + + # If created succeed, just open it and refresh project + self.window.open_file(element_file) + self.window.run_command("refresh_folder_list") + + # Deploy Aura to server + self.window.run_command("deploy_lightning_to_server", { + "dirs": [self._dir], + "switch_project": False, + "element": element, + "update_meta": True + }) + + def is_visible(self, dirs, element=""): + if not dirs or len(dirs) != 1: + return False + self._dir = dirs[0] + + # Check whether project is the active one + if self.settings["default_project_name"] not in self._dir: + return False + + # Check metadata folder + attributes = util.get_file_attributes(self._dir) + if attributes["metadata_folder"] != "lwc": + return False + self.lwc_name = attributes["name"] + + return True diff --git a/util.py b/util.py index fea7829..7fcdc42 100644 --- a/util.py +++ b/util.py @@ -33,14 +33,16 @@ def load_templates(): os.makedirs(target_dir) templates_dir = os.path.join(target_dir, "templates.json") - lwc_dir = os.path.join(target_dir, "lwc") # Check exist lwc logic - if not os.path.isfile(templates_dir) or not os.path.exists(lwc_dir): + lwc_dir = os.path.join(target_dir, "Lwc") # Check exist lwc logic + lwc_ele_dir = os.path.join(target_dir, "LwcElement") # Check exist lwc element logic + + if not os.path.isfile(templates_dir) or not os.path.exists(lwc_dir) or not os.path.exists(lwc_ele_dir): source_dir = os.path.join( sublime.installed_packages_path(), "haoide.sublime-package" ) - if os.path.isfile(source_dir): + if os.path.isfile(source_dir) and os.path.exists(lwc_dir) and os.path.exists(lwc_ele_dir): zfile = zipfile.ZipFile(source_dir, 'r') for filename in zfile.namelist(): if filename.endswith('/'): @@ -60,7 +62,7 @@ def load_templates(): zfile.close() else: source_dir = os.path.join( - sublime.packages_path(), "haoide/config/templates" + sublime.packages_path(), "haoide", "config", "templates" ) copy_files_in_folder(source_dir, target_dir) From 59546e918de8185ef49a85e20da203718a5091da Mon Sep 17 00:00:00 2001 From: Lushang Date: Thu, 26 Mar 2020 18:51:05 +0800 Subject: [PATCH 26/46] Fixed bug #198 --- HISTORY.rst | 1 + util.py | 88 +++++++++++++++++++++++++++-------------------------- 2 files changed, 46 insertions(+), 43 deletions(-) diff --git a/HISTORY.rst b/HISTORY.rst index f295900..1ca9c64 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -10,6 +10,7 @@ Release 3.5.7 (2020-03-26) * Add Retrieving, Destructing, Deploying lwc from both sidebar and context menu * Add Creating CSS style, SVG file for lwc in context menu * Fix auto completion for aura component bug +* Fix issue #198 Release 3.5.4 (2019-07-31) diff --git a/util.py b/util.py index 7fcdc42..14bd44e 100644 --- a/util.py +++ b/util.py @@ -3401,7 +3401,8 @@ def export_profile_settings(): return Printer.get("log").write_start().write("Start to read all file name in profile folder") - profiles = get_metadata_elements(profile_dir) + profiles = get_metadata_elements(profile_dir, 'profile') + print('profiles:', profiles) profile_settings = {} sobject_names = [] @@ -3542,47 +3543,47 @@ def export_profile_settings(): all_rows.append(",".join(rows)) - # cruds_translation = { - # "allowRead": "Read", - # "allowCreate": "Create", - # "allowEdit": "Edit", - # "allowDelete": "Delete", - # "modifyAllRecords": "ModifyAll", - # "viewAllRecords": "ViewAll" - # } - - # # Define the column that contains profile - # profile_headers = ["Object"] - # for profile in profiles: - # profile_headers.append(profile) - # for i in range(len(cruds) - 1): - # profile_headers.append("") - - # # Define the column - # crud_headers = [""] - # for profile in profiles: - # for crud in cruds: - # crud_headers.append(cruds_translation[crud]) - - # sobject_names = sorted(sobject_names) - # all_rows = [",".join(profile_headers), ",".join(crud_headers)] - # for sobject in sobject_names: - # rows = [sobject] - # for profile in profiles: - # # Some standard sObject is not configurable - # if "objectPermissions" in profile_settings[profile]: - # if sobject in profile_settings[profile]["objectPermissions"]: - # object_permission = profile_settings[profile]["objectPermissions"][sobject] - # for crud in cruds: - # rows.append("√" if object_permission[crud] == "true" else "") - # else: - # for crud in cruds: - # rows.append("") - # else: - # for crud in cruds: - # rows.append("") - - # all_rows.append(",".join(rows)) + cruds_translation = { + "allowRead": "Read", + "allowCreate": "Create", + "allowEdit": "Edit", + "allowDelete": "Delete", + "modifyAllRecords": "ModifyAll", + "viewAllRecords": "ViewAll" + } + + # Define the column that contains profile + profile_headers = ["SObject"] + for profile in profiles: + profile_headers.append(profile) + for i in range(len(cruds) - 1): + profile_headers.append("") + + # Define the column + crud_headers = [""] + for profile in profiles: + for crud in cruds: + crud_headers.append(cruds_translation[crud]) + + sobject_names = sorted(sobject_names) + all_rows = [",".join(profile_headers), ",".join(crud_headers)] + for sobject in sobject_names: + rows = [sobject] + for profile in profiles: + # Some standard sObject is not configurable + if "objectPermissions" in profile_settings[profile]: + if sobject in profile_settings[profile]["objectPermissions"]: + object_permission = profile_settings[profile]["objectPermissions"][sobject] + for crud in cruds: + rows.append("√" if object_permission[crud] == "true" else "") + else: + for crud in cruds: + rows.append("") + else: + for crud in cruds: + rows.append("") + + all_rows.append(",".join(rows)) outputdir = settings["workspace"]+ "/.export/profile" if not os.path.exists(outputdir): @@ -3632,7 +3633,8 @@ def export_profile_settings(): for permission_name in permission_names: rows = [permission_name] for profile in profiles: - if permission_name in profile_settings[profile]["userPermissions"]: + prf_setting = profile_settings[profile] + if prf_setting.get('userPermissions') is not None and permission_name in prf_setting.get('userPermissions'): if profile_settings[profile]["userPermissions"][permission_name] == "true": rows.append("√") else: From 92620e334a2fd3d92568e152e72e2ffa51b7c6a3 Mon Sep 17 00:00:00 2001 From: Lushang Date: Thu, 26 Mar 2020 22:28:21 +0800 Subject: [PATCH 27/46] Disable Code coverage funcationality for updating --- main.py | 3 ++- util.py | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/main.py b/main.py index 33a10f6..5ef7d3a 100644 --- a/main.py +++ b/main.py @@ -740,7 +740,8 @@ def is_enabled(self): return True def is_visible(self): - return self.is_enabled() + # return self.is_enabled() + return False class ViewSelectedCodeCoverageCommand(sublime_plugin.TextCommand): diff --git a/util.py b/util.py index 14bd44e..bacb6bb 100644 --- a/util.py +++ b/util.py @@ -254,7 +254,8 @@ def view_coverage(name, file_name, body): numLocationsNotCovered = coverage["numLocationsNotCovered"] numLocations = coverage["numLocations"] numLocationsCovered = numLocations - numLocationsNotCovered - linesNotCovered = [l["line"] for l in coverage["locationsNotCovered"]] + linesNotCovered = [] + # linesNotCovered = [l["line"] for l in coverage["locationsNotCovered"]] if numLocations == 0: return Printer.get("error").write("There is no code coverage") @@ -3402,7 +3403,6 @@ def export_profile_settings(): Printer.get("log").write_start().write("Start to read all file name in profile folder") profiles = get_metadata_elements(profile_dir, 'profile') - print('profiles:', profiles) profile_settings = {} sobject_names = [] From 2f03277854cf5edc1e4ab6bf45c04175551b9b32 Mon Sep 17 00:00:00 2001 From: Lushang Date: Thu, 26 Mar 2020 22:57:18 +0800 Subject: [PATCH 28/46] v3.5.7 --- config/messages/3.5.7.md | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 config/messages/3.5.7.md diff --git a/config/messages/3.5.7.md b/config/messages/3.5.7.md new file mode 100644 index 0000000..58ac617 --- /dev/null +++ b/config/messages/3.5.7.md @@ -0,0 +1,17 @@ +Build 3.5.7 +----------- +Release Date: 26 Mar 2020 + +* Refine Creating Lightning Web Component (``lwc``) process +* Add Retrieving, Destructing, Deploying lwc from both sidebar and context menu +* Add Creating CSS style, SVG file for lwc in context menu +* Fix auto completion for aura component bug +* Fix issue #198 + +Update +---------- +Currently there are still lots of developers using `haoide` for SFDC development. Since @xjsender has less time on the project, I will continue to maintain this project and [haoide-vscode](https://github.com/xjsender/haoide-vscode) for the community. + +Thanks @xjsender for the years contributions on the project and Salesforce developing community. + +by @lushang \ No newline at end of file From 1ef34998931c4f131d86e736e9784c58a224c4a6 Mon Sep 17 00:00:00 2001 From: Lushang Date: Fri, 27 Mar 2020 14:57:01 +0800 Subject: [PATCH 29/46] fix get lwc templates bug --- util.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/util.py b/util.py index bacb6bb..4e4895e 100644 --- a/util.py +++ b/util.py @@ -27,6 +27,9 @@ def load_templates(): + """ + Load code template files from haoide package to working project .templates folder + """ settings = context.get_settings() target_dir = os.path.join(settings["workspace"], ".templates") if not os.path.exists(target_dir): @@ -36,13 +39,16 @@ def load_templates(): lwc_dir = os.path.join(target_dir, "Lwc") # Check exist lwc logic lwc_ele_dir = os.path.join(target_dir, "LwcElement") # Check exist lwc element logic + # for the updating of Lwc, old project should update the template files if not os.path.isfile(templates_dir) or not os.path.exists(lwc_dir) or not os.path.exists(lwc_ele_dir): + # get the installed haoide package directory source_dir = os.path.join( sublime.installed_packages_path(), "haoide.sublime-package" ) - if os.path.isfile(source_dir) and os.path.exists(lwc_dir) and os.path.exists(lwc_ele_dir): + if os.path.isfile(source_dir): + # default situation, installed haoide package, copy files from zip file sub folders zfile = zipfile.ZipFile(source_dir, 'r') for filename in zfile.namelist(): if filename.endswith('/'): @@ -61,8 +67,9 @@ def load_templates(): zfile.close() else: + # when develop haoide, use local package templates files source_dir = os.path.join( - sublime.packages_path(), "haoide", "config", "templates" + sublime.packages_path(), "haoide2/config/templates" ) copy_files_in_folder(source_dir, target_dir) From e4e16fdcdcddfb1a0f132c86ac623a7beae3c367 Mon Sep 17 00:00:00 2001 From: Lushang Date: Fri, 27 Mar 2020 18:45:16 +0800 Subject: [PATCH 30/46] Refined Get Apex Class/Trigger code coverage. fixed bug #197 --- main.py | 8 +- processor.py | 573 +++++++++++++++++++++++++++++++-------------------- util.py | 3 + 3 files changed, 351 insertions(+), 233 deletions(-) diff --git a/main.py b/main.py index 5ef7d3a..ea9654f 100644 --- a/main.py +++ b/main.py @@ -711,7 +711,8 @@ def run(self, edit, mark): class ViewCodeCoverageCommand(sublime_plugin.TextCommand): def run(self, edit): - util.view_coverage(self.attributes["name"], self.file_name, self.body) + # util.view_coverage(self.attributes["name"], self.file_name, self.body) + processor.handle_fetch_code_coverage(self.attributes["name"], self.body) def is_enabled(self): # Must Be File @@ -740,8 +741,7 @@ def is_enabled(self): return True def is_visible(self): - # return self.is_enabled() - return False + return self.is_enabled() class ViewSelectedCodeCoverageCommand(sublime_plugin.TextCommand): @@ -1935,7 +1935,7 @@ class AboutCommand(sublime_plugin.ApplicationCommand): def run(command): package_info = sublime.load_settings("package.sublime-settings") - version_info = "\n%s\n\n%s\n\nCopyright © 2013-2016 By %s\n\tDev Channel, Build v%s" % ( + version_info = "\n%s\n\n%s\n\nCopyright © 2013-2019 By %s\n\tDev Channel, Build v%s" % ( package_info.get("description"), package_info.get("homepage"), package_info.get("author"), diff --git a/processor.py b/processor.py index ada3f98..8bef61a 100644 --- a/processor.py +++ b/processor.py @@ -29,9 +29,9 @@ def handle_populate_users(callback_command, timeout=120): def handle_thread(thread, timeout): if thread.is_alive(): - sublime.set_timeout(lambda:handle_thread(thread, timeout), timeout) + sublime.set_timeout(lambda: handle_thread(thread, timeout), timeout) return - + if api.result or api.result["success"]: records = api.result["records"] users = {} @@ -40,7 +40,7 @@ def handle_thread(thread, timeout): name = "%s => %s" % (record["LastName"], record["Username"]) else: name = "%s => %s" % ( - "%s %s" % (record["LastName"], record["FirstName"]), + "%s %s" % (record["LastName"], record["FirstName"]), record["Username"] ) @@ -57,11 +57,12 @@ def handle_thread(thread, timeout): # If not exist, we need to use callback function api = ToolingApi(settings) query = "SELECT Id, FirstName, LastName, Username FROM User WHERE IsActive = true" - thread = threading.Thread(target=api.query_all, args=(query, )) + thread = threading.Thread(target=api.query_all, args=(query,)) thread.start() handle_thread(thread, timeout) ThreadProgress(api, thread, "Downloading Users List", "Succeed to download users list") + def populate_sobject_recordtypes(): """ Get dict ([sobject, recordtype name] => recordtype id) in whole org @@ -78,7 +79,7 @@ def populate_sobject_recordtypes(): settings = context.get_settings() # If sobjects is exist in `/.config/recordtype.json`, just return it - recordtype_path = settings["workspace"]+"/.config/recordtype.json" + recordtype_path = settings["workspace"] + "/.config/recordtype.json" if os.path.isfile(recordtype_path): recordtype = json.loads(open(recordtype_path).read()) return recordtype @@ -86,7 +87,7 @@ def populate_sobject_recordtypes(): # If sobjects is not exist in globals(), post request to pouplate it api = ToolingApi(settings) query = "SELECT Id, Name, SobjectType FROM RecordType" - thread = threading.Thread(target=api.query_all, args=(query, )) + thread = threading.Thread(target=api.query_all, args=(query,)) thread.start() while thread.is_alive() or not api.result: @@ -115,6 +116,7 @@ def populate_sobject_recordtypes(): util.add_config_history("recordtype", sobject_recordtypes, settings) return sobject_recordtypes + def handle_update_user_language(language, timeout=120): settings = context.get_settings() api = ToolingApi(settings) @@ -123,33 +125,36 @@ def handle_update_user_language(language, timeout=120): return Printer.get('error').write("Login is required before this action") patch_url = "/sobjects/User/%s" % session["user_id"] - thread = threading.Thread(target=api.patch, - args=(patch_url, {"LanguageLocaleKey": language}, )) + thread = threading.Thread(target=api.patch, + args=(patch_url, {"LanguageLocaleKey": language},)) thread.start() - ThreadProgress(api, thread, "Updating User Language to " + language, - "User language is updated to " + language) + ThreadProgress(api, thread, "Updating User Language to " + language, + "User language is updated to " + language) + def handle_enable_development_mode(user_id, timeout=120): settings = context.get_settings() api = ToolingApi(settings) patch_url = "/sobjects/User/%s" % user_id - thread = threading.Thread(target=api.patch, - args=(patch_url, {"UserPreferencesApexPagesDeveloperMode": True}, )) + thread = threading.Thread(target=api.patch, + args=(patch_url, {"UserPreferencesApexPagesDeveloperMode": True},)) thread.start() ThreadProgress(api, thread, "Enabling User Development Mode", - "Succeed to Enabling User Development Mode") + "Succeed to Enabling User Development Mode") + def handle_update_user_password(user_id, new_password, timeout=120): settings = context.get_settings() api = ToolingApi(settings) thread = threading.Thread(target=api.manage_password, args=( - user_id, {"NewPassword": new_password}, + user_id, {"NewPassword": new_password}, )) thread.start() masked_password = new_password[:5] + "*" * len(new_password[3:]) - ThreadProgress(api, thread, "Updating User Password to " + masked_password, - "Succeed to update user password to " + masked_password) + ThreadProgress(api, thread, "Updating User Password to " + masked_password, + "Succeed to update user password to " + masked_password) + def handle_login_thread(callback_options={}, force=False, timeout=120): def handle_thread(thread, timeout): @@ -166,13 +171,14 @@ def handle_thread(thread, timeout): settings = context.get_settings() api = ToolingApi(settings) - thread = threading.Thread(target=api.login, args=(force, )) + thread = threading.Thread(target=api.login, args=(force,)) thread.start() handle_thread(thread, timeout) default_project_name = settings["default_project_name"] - ThreadProgress(api, thread, "Login to %s" % default_project_name, - default_project_name + " Login Succeed") + ThreadProgress(api, thread, "Login to %s" % default_project_name, + default_project_name + " Login Succeed") + def handle_view_code_coverage(component_name, component_id, body, timeout=120): def handle_thread(thread, timeout): @@ -181,7 +187,7 @@ def handle_thread(thread, timeout): return result = api.result - if not result["success"]: + if not result["success"]: return if result["totalSize"] == 0: @@ -201,17 +207,17 @@ def handle_thread(thread, timeout): # Append coverage statistic info coverage_statistic = "%s Coverage: %.2f%%(%s/%s)" % ( - component_name, coverage_percent, + component_name, coverage_percent, covered_lines_count, total_lines_count ) - + # If has coverage, just add coverage info to new view view = sublime.active_window().new_file() view.run_command("new_view", { "name": coverage_statistic, "input": body }) - + # Calculate line coverage split_lines = view.lines(sublime.Region(0, view.size())) uncovered_region = [] @@ -223,24 +229,25 @@ def handle_thread(thread, timeout): # Append body with uncovered line view.add_regions("uncovered_lines", uncovered_region, "invalid", "dot", - sublime.DRAW_SOLID_UNDERLINE | sublime.DRAW_EMPTY_AS_OVERWRITE) + sublime.DRAW_SOLID_UNDERLINE | sublime.DRAW_EMPTY_AS_OVERWRITE) settings = context.get_settings() api = ToolingApi(settings) - query = "SELECT Coverage FROM ApexCodeCoverageAggregate " +\ - "WHERE ApexClassOrTriggerId = '{0}'".format(component_id) - thread = threading.Thread(target=api.query, args=(query, True, )) + query = "SELECT Coverage FROM ApexCodeCoverageAggregate " + \ + "WHERE ApexClassOrTriggerId = '{0}'".format(component_id) + thread = threading.Thread(target=api.query, args=(query, True,)) thread.start() ThreadProgress(api, thread, "View Code Coverage of " + component_name, - "View Code Coverage of " + component_name + " Succeed") + "View Code Coverage of " + component_name + " Succeed") handle_thread(thread, timeout) + def handle_refresh_folder(types, ignore_package_xml=True, timeout=120): def handle_thread(thread, timeout): if thread.is_alive(): - sublime.set_timeout(lambda:handle_thread(thread, timeout), timeout) + sublime.set_timeout(lambda: handle_thread(thread, timeout), timeout) return - + # Not succeed if not api.result or not api.result["success"]: return @@ -251,8 +258,8 @@ def handle_thread(thread, timeout): extract_to = settings["workspace"] # Extract zip, True means not override package.xml - thread = threading.Thread(target=util.extract_encoded_zipfile, - args=(result["zipFile"], extract_to, ignore_package_xml, )) + thread = threading.Thread(target=util.extract_encoded_zipfile, + args=(result["zipFile"], extract_to, ignore_package_xml,)) thread.start() util.reload_file_attributes(result["fileProperties"], settings) @@ -263,11 +270,12 @@ def handle_thread(thread, timeout): # Start to request settings = context.get_settings() api = MetadataApi(settings) - thread = threading.Thread(target=api.retrieve, args=({"types": types}, )) + thread = threading.Thread(target=api.retrieve, args=({"types": types},)) thread.start() handle_thread(thread, timeout) message = "Refresh Folder" - ThreadProgress(api, thread, message, message+" Succeed") + ThreadProgress(api, thread, message, message + " Succeed") + def handle_reload_symbol_tables(timeout=120): """ @@ -295,7 +303,7 @@ def handle_thread(thread, timeout): # Outer completions outer = util.parse_symbol_table(record["SymbolTable"]) symboltable_dict[record["Name"].lower()] = { - "outer" : outer, + "outer": outer, "name": record["Name"] } @@ -311,12 +319,13 @@ def handle_thread(thread, timeout): settings = context.get_settings() api = ToolingApi(settings) - thread = threading.Thread(target=api.query_symbol_table, args=(30, )) + thread = threading.Thread(target=api.query_symbol_table, args=(30,)) thread.start() wating_message = "Reloading Symbol Tables" ThreadProgress(api, thread, wating_message, wating_message + " Succeed") handle_thread(thread, timeout) + def handle_reload_sobjects_completions(timeout=120): """ Save sobject describe to local which is used in completions @@ -327,7 +336,7 @@ def handle_threads(apis, threads, timeout): if thread.is_alive(): sublime.set_timeout(lambda: handle_threads(apis, threads, timeout), timeout) return - + # If succeed, get the all sobject describe result results = [] for api in apis: @@ -341,7 +350,7 @@ def handle_threads(apis, threads, timeout): all_child_relationship_dict = {} for sobject_describe in results: # Initiate Sobject completions - if "name" not in sobject_describe: + if "name" not in sobject_describe: continue sobject_name = sobject_describe["name"] @@ -406,7 +415,7 @@ def handle_threads(apis, threads, timeout): # Display field type with specified format field_type_desc = field_desc_dict[field_type] if field_type \ - in field_desc_dict else field_desc_dict["other"] + in field_desc_dict else field_desc_dict["other"] fd = "%s%s\t%s" % (externalUniqueNotation, field_name_desc, field_type_desc) fields_dict[fd] = field_name @@ -441,7 +450,7 @@ def handle_threads(apis, threads, timeout): # Add Parent Relationship Name parent_relationship_dict[f["relationshipName"]] = parentSobject - + # Child Relationship dict for f in sobject_describe["childRelationships"]: childRelationshipName = f["relationshipName"] @@ -471,23 +480,23 @@ def handle_threads(apis, threads, timeout): # Reload cache for completions from . import completions - sublime.set_timeout(lambda:completions.load_sobject_cache( + sublime.set_timeout(lambda: completions.load_sobject_cache( True, username ), 5) def handle_thread(api, thread, timeout=120): if thread.is_alive(): - sublime.set_timeout(lambda:handle_thread(api, thread, timeout), timeout) + sublime.set_timeout(lambda: handle_thread(api, thread, timeout), timeout) return # Exception Process - if not api.result or not api.result["success"]: + if not api.result or not api.result["success"]: return # Get describe result of all sObjects sobjects_describe = api.result["sobjects"] sobjects = list(sobjects_describe.keys()) - + mcc = settings["maximum_concurrent_connections"] chunked_sobjects = util.list_chunks(sobjects, math.ceil(len(sobjects) / mcc)) @@ -499,7 +508,7 @@ def handle_thread(api, thread, timeout=120): for so in sobjects ] api = ToolingApi(settings) - thread = threading.Thread(target=api.describe_sobjects, args=(sobjects, )) + thread = threading.Thread(target=api.describe_sobjects, args=(sobjects,)) thread.start() threads.append(thread) apis.append(api) @@ -514,10 +523,11 @@ def handle_thread(api, thread, timeout=120): ThreadProgress(api, thread, "Global Describe", "Global Describe Succeed") handle_thread(api, thread, timeout) + def handle_destructive_files(dirs_or_files, ignore_folder=True, timeout=120): def handle_thread(thread, timeout=120): if thread.is_alive(): - sublime.set_timeout(lambda:handle_thread(thread, timeout), timeout) + sublime.set_timeout(lambda: handle_thread(thread, timeout), timeout) return # After succeed, remove dirs_or_files and related *-meta.xml from local @@ -526,7 +536,7 @@ def handle_thread(thread, timeout=120): for _file_or_dir in dirs_or_files: # Remove file from local disk and close the related view view = util.get_view_by_file_name(_file_or_dir) - if view: + if view: win.focus_view(view) win.run_command("close") @@ -536,41 +546,43 @@ def handle_thread(thread, timeout=120): shutil.rmtree(_file_or_dir) # Remove related *-meta.xml file from local disk and close the related view - if ignore_folder and os.path.isfile(_file_or_dir+"-meta.xml"): - view = util.get_view_by_file_name(_file_or_dir+"-meta.xml") - if view: + if ignore_folder and os.path.isfile(_file_or_dir + "-meta.xml"): + view = util.get_view_by_file_name(_file_or_dir + "-meta.xml") + if view: win.focus_view(view) win.run_command("close") - os.remove(_file_or_dir+"-meta.xml") + os.remove(_file_or_dir + "-meta.xml") settings = context.get_settings() api = MetadataApi(settings) base64_encoded_zip = util.build_destructive_package_by_files(dirs_or_files, ignore_folder) - thread = threading.Thread(target=api.deploy, args=(base64_encoded_zip, )) + thread = threading.Thread(target=api.deploy, args=(base64_encoded_zip,)) thread.start() ThreadProgress(api, thread, "Destructing Files", "Destructing Files Succeed") handle_thread(thread, timeout) + def handle_destructive_package_xml(types, timeout=120): def handle_thread(thread, timeout=120): if thread.is_alive(): - sublime.set_timeout(lambda:handle_thread(thread, timeout), timeout) + sublime.set_timeout(lambda: handle_thread(thread, timeout), timeout) return settings = context.get_settings() api = MetadataApi(settings) base64_encoded_zip = util.build_destructive_package_by_package_xml(types) - thread = threading.Thread(target=api.deploy, args=(base64_encoded_zip, )) + thread = threading.Thread(target=api.deploy, args=(base64_encoded_zip,)) thread.start() ThreadProgress(api, thread, "Destructing Package.xml", "Destructing Package.xml Succeed") handle_thread(thread, timeout) -def handle_deploy_thread(base64_encoded_zip, - source_org=None, element=None, chosen_classes=[], timeout=120, update_meta=False): + +def handle_deploy_thread(base64_encoded_zip, + source_org=None, element=None, chosen_classes=[], timeout=120, update_meta=False): def handle_thread(thread, timeout=120): if thread.is_alive(): - sublime.set_timeout(lambda:handle_thread(thread, timeout), timeout) + sublime.set_timeout(lambda: handle_thread(thread, timeout), timeout) return # If source_org is not None, we need to switch project back @@ -585,16 +597,16 @@ def handle_thread(thread, timeout=120): settings = context.get_settings() api = MetadataApi(settings) thread = threading.Thread(target=api.deploy, args=( - base64_encoded_zip, - chosen_classes, + base64_encoded_zip, + chosen_classes, )) thread.start() - ThreadProgress(api, thread, "Deploy Metadata to %s" % settings["default_project_name"], - "Metadata Deployment Finished") + ThreadProgress(api, thread, "Deploy Metadata to %s" % settings["default_project_name"], + "Metadata Deployment Finished") handle_thread(thread, timeout) -def handle_update_aura_meta(body, element, timeout=120, type = "AuraDefinitionBundle"): +def handle_update_aura_meta(body, element, timeout=120, type="AuraDefinitionBundle"): """ :param body: body data returned from SOAP API @@ -603,6 +615,7 @@ def handle_update_aura_meta(body, element, timeout=120, type = "AuraDefinitionBu :param type: type :return: """ + def handle_thread(thread, full_name, timeout): if thread.is_alive(): sublime.set_timeout(lambda: handle_thread(thread, full_name, timeout), timeout) @@ -654,9 +667,9 @@ def handle_thread(thread, full_name, timeout): # Build components dict api = ToolingApi(settings) - query_str = "SELECT Id, DefType, LastModifiedDate, LastModifiedById " +\ - "FROM AuraDefinition WHERE AuraDefinitionBundleId = '%s' and DefType = '%s'" % ( - item['id'], element.upper()) + query_str = "SELECT Id, DefType, LastModifiedDate, LastModifiedById " + \ + "FROM AuraDefinition WHERE AuraDefinitionBundleId = '%s' and DefType = '%s'" % ( + item['id'], element.upper()) thread = threading.Thread(target=api.query, args=(query_str,)) thread.start() ThreadProgress(api, thread, "Update Component Metadata", "Update Component Metadata Finished") @@ -674,27 +687,29 @@ def handle_track_all_debug_logs_thread(users, timeout=120): split = math.ceil(len(users) / maximum_concurrent_connections) for item in util.dict_chunks(users, split): pieces.append(item) - + threads = [] for users in pieces: api = ToolingApi(settings) - thread = threading.Thread(target=api.create_trace_flags, args=(users, )) + thread = threading.Thread(target=api.create_trace_flags, args=(users,)) thread.start() threads.append(thread) ThreadsProgress(threads, "Creating Trace Flags", "Creating Trace Flags Finished") + def handle_cancel_deployment_thread(async_process_id, timeout=120): settings = context.get_settings() api = MetadataApi(settings) thread = threading.Thread(target=api._invoke_method, args=( "cancelDeploy", { - "async_process_id": async_process_id, + "async_process_id": async_process_id, } )) thread.start() ThreadProgress(api, thread, "Canceling Deploy", "Canceling Deploy Succeed") + def handle_close_jobs_thread(job_ids, timeout=120): settings = context.get_settings() bulkjob = BulkJob(settings, None, None) @@ -702,6 +717,7 @@ def handle_close_jobs_thread(job_ids, timeout=120): thread = threading.Thread(target=bulkjob.close_job, args=(job_id,)) thread.start() + def handle_bulk_operation_thread(sobject, inputfile, operation, timeout=120): settings = context.get_settings() bulkapi = BulkApi(settings, sobject, inputfile) @@ -718,6 +734,7 @@ def handle_bulk_operation_thread(sobject, inputfile, operation, timeout=120): progress_message = operation + " " + sobject ThreadProgress(bulkapi, thread, progress_message, progress_message + " Succeed") + def handle_backup_sobject_thread(sobject, soql=None, timeout=120): settings = context.get_settings() bulkapi = BulkApi(settings, sobject, soql) @@ -726,15 +743,16 @@ def handle_backup_sobject_thread(sobject, soql=None, timeout=120): wait_message = "Export Records of " + sobject ThreadProgress(bulkapi, thread, wait_message, wait_message + " Succeed") + def handle_backup_all_sobjects_thread(timeout=120): def handle_thread(thread, timeout): if thread.is_alive(): - sublime.set_timeout(lambda:handle_thread(thread, timeout), timeout) + sublime.set_timeout(lambda: handle_thread(thread, timeout), timeout) return result = api.result if not result or not result["success"]: return - + threads = [] for sobject_describe in api.result["sobjects"]: if "name" not in sobject_describe: continue @@ -753,12 +771,13 @@ def handle_thread(thread, timeout): ThreadProgress(api, thread, "Describe Global", "Describe Global Succeed") handle_thread(thread, timeout) + def handle_export_workflows(settings, timeout=120): def handle_thread(thread, timeout): if thread.is_alive(): sublime.set_timeout(lambda: handle_thread(thread, timeout), timeout) return - + # If succeed sObjects = [] for sd in api.result["sobjects"]: @@ -775,6 +794,7 @@ def handle_thread(thread, timeout): ThreadProgress(api, thread, "Export All Workflows", "Outputdir: " + outputdir) handle_thread(thread, 10) + def handle_export_validation_rules(settings, timeout=120): def handle_thread(thread, timeout): if thread.is_alive(): @@ -796,12 +816,13 @@ def handle_thread(thread, timeout): ThreadProgress(api, thread, "Export All Validation Rules", "Validation Rules Export Succeed") handle_thread(thread, 10) + def handle_export_customfield(timeout=120): def handle_thread(thread, timeout): if thread.is_alive(): sublime.set_timeout(lambda: handle_thread(thread, timeout), timeout) return - + # If succeed result = api.result if not result or not result["success"]: return @@ -809,7 +830,7 @@ def handle_thread(thread, timeout): # Write list to csv outputdir = os.path.join(settings["workspace"], ".export") if not os.path.exists(outputdir): os.makedirs(outputdir) - records = sorted(result["records"], key=lambda k : k['TableEnumOrId']) + records = sorted(result["records"], key=lambda k: k['TableEnumOrId']) outputfile = os.path.join(outputdir, "CustomField.csv") util.list2csv(outputfile, records) @@ -824,12 +845,13 @@ def handle_thread(thread, timeout): ThreadProgress(api, thread, 'Exporting CustomFields', "Exporting CustomFields Succeed") handle_thread(thread, 10) + def handle_export_role_hierarchy(timeout=120): def handle_thread(thread, timeout): if thread.is_alive(): sublime.set_timeout(lambda: handle_thread(thread, timeout), timeout) return - + # If succeed result = api.result if not result or not result["success"]: return @@ -843,21 +865,22 @@ def handle_thread(thread, timeout): settings = context.get_settings() api = ToolingApi(settings) - soql = "SELECT Id, ParentRoleId, Name, " +\ - "(SELECT Id, FirstName, LastName, Username FROM Users " +\ - " WHERE IsActive = true AND Profile.UserLicense.Name = 'Salesforce') " +\ - "FROM UserRole WHERE PortalType = 'None'" + soql = "SELECT Id, ParentRoleId, Name, " + \ + "(SELECT Id, FirstName, LastName, Username FROM Users " + \ + " WHERE IsActive = true AND Profile.UserLicense.Name = 'Salesforce') " + \ + "FROM UserRole WHERE PortalType = 'None'" thread = threading.Thread(target=api.query_all, args=(soql,)) thread.start() ThreadProgress(api, thread, 'Exporting Role Hierarchy', "Role Hierarchy Exporting Succeed") handle_thread(thread, 10) + def handle_export_data_template_thread(sobject, recordtype_name, recordtype_id, vertical, timeout=120): def handle_thread(thread, timeout): if thread.is_alive(): sublime.set_timeout(lambda: handle_thread(thread, timeout), timeout) return - + # If succeed result = api.result if not result or not result["success"]: return @@ -880,18 +903,19 @@ def handle_thread(thread, timeout): ) api = ToolingApi(settings) url = "/sobjects/%s/describe/layouts/%s" % (sobject, recordtype_id) - thread = threading.Thread(target=api.get, args=(url, )) + thread = threading.Thread(target=api.get, args=(url,)) thread.start() wait_message = "Export Data Template of %s=>%s" % (sobject, recordtype_name) ThreadProgress(api, thread, wait_message, "Outputdir: " + output_file_dir) handle_thread(thread, 120) + def handle_export_query_to_csv(tooling, soql, csv_name, data=None, timeout=120): def handle_new_view_thread(thread, timeout): if thread.is_alive(): sublime.set_timeout(lambda: handle_new_view_thread(thread, timeout), timeout) return - + result = api.result if "success" in result and not result["success"]: return @@ -902,31 +926,32 @@ def handle_new_view_thread(thread, timeout): outputfile = os.path.join(outputdir, "%s.csv" % csv_name) with open(outputfile, "wb") as fp: fp.write(util.query_to_csv(result, soql)) - + view = sublime.active_window().open_file(outputfile) settings = context.get_settings() api = ToolingApi(settings) - thread = threading.Thread(target=api.query_all, args=(soql, tooling, )) + thread = threading.Thread(target=api.query_all, args=(soql, tooling,)) thread.start() progress_message = "Export Query To %s.csv" % csv_name ThreadProgress(api, thread, progress_message, progress_message + " Succeed") handle_new_view_thread(thread, timeout) + def handle_execute_rest_test(operation, url, data=None, timeout=120): def handle_new_view_thread(thread, timeout): if thread.is_alive(): sublime.set_timeout(lambda: handle_new_view_thread(thread, timeout), timeout) return - + result = api.result - + # If succeed - if "list" in result: + if "list" in result: result = result["list"] - if "str" in result: + if "str" in result: result = result["str"] - + # If response result is just like '"{\\"name\\":\\"test\\"}"' # we will remove the \\ and convert it to json automatically if settings.get("remove_slash_for_rest_response", False): @@ -941,13 +966,13 @@ def handle_new_view_thread(thread, timeout): # Remove the useless success attribute if isinstance(result, dict) and "success" in result: del result["success"] - + # No error, just display log in a new view view = sublime.active_window().new_file() view.set_syntax_file("Packages/JavaScript/JSON.tmLanguage") time_stamp = time.strftime("%H:%M:%S", time.localtime(time.time())) view.run_command("new_view", { - "name": "Rest %s-%s" % (operation, time_stamp), + "name": "Rest %s-%s" % (operation, time_stamp), "input": json.dumps(result, ensure_ascii=False, indent=4) }) @@ -967,7 +992,7 @@ def handle_new_view_thread(thread, timeout): "Search": api.search, "Quick Search": api.quick_search } - + target = http_methods_target[operation] if operation in ['Put', 'Post', 'Patch']: thread = threading.Thread(target=target, args=(url, data,)) @@ -980,16 +1005,17 @@ def handle_new_view_thread(thread, timeout): ThreadProgress(api, thread, progress_message, progress_message + " Succeed", show_error=False) handle_new_view_thread(thread, timeout) + def handle_execute_query(soql, timeout=120): def handle_new_view_thread(thread, timeout): if thread.is_alive(): sublime.set_timeout(lambda: handle_new_view_thread(thread, timeout), timeout) return - + # If succeed result = api.result if not result["success"]: return - + # No error, just display log in a new view view = sublime.active_window().new_file() view.run_command("new_view", { @@ -1007,12 +1033,13 @@ def handle_new_view_thread(thread, timeout): ThreadProgress(api, thread, "Execute Query", "Execute Query Succeed") handle_new_view_thread(thread, timeout) + def handle_execute_anonymous(apex_string, timeout=120): def handle_new_view_thread(thread, timeout): if thread.is_alive(): sublime.set_timeout(lambda: handle_new_view_thread(thread, timeout), timeout) return - + # If succeed result = api.result if not result["success"]: return @@ -1033,11 +1060,12 @@ def handle_new_view_thread(thread, timeout): settings = context.get_settings() api = ApexApi(settings) - thread = threading.Thread(target=api.execute_anonymous, args=(apex_string, )) + thread = threading.Thread(target=api.execute_anonymous, args=(apex_string,)) thread.start() ThreadProgress(api, thread, "Execute Anonymous", "Execute Anonymous Succeed") handle_new_view_thread(thread, timeout) + def handle_fetch_debug_logs(user_full_name, user_id, timeout=120): def handle_thread(thread, timeout): if thread.is_alive(): @@ -1045,7 +1073,7 @@ def handle_thread(thread, timeout): return result = api.result - if not result or "records" not in result: + if not result or "records" not in result: return records = result["records"] @@ -1054,11 +1082,12 @@ def handle_thread(thread, timeout): settings = context.get_settings() api = ToolingApi(settings) - thread = threading.Thread(target=api.query_logs, args=(settings["last_n_logs"], user_id, )) + thread = threading.Thread(target=api.query_logs, args=(settings["last_n_logs"], user_id,)) thread.start() - ThreadProgress(api, thread, "List Debug Logs for " + user_full_name, - "List Debug Logs for " + user_full_name + " Succeed") - handle_thread(thread, timeout) + ThreadProgress(api, thread, "List Debug Logs for " + user_full_name, + "List Debug Logs for " + user_full_name + " Succeed") + handle_thread(thread, timeout) + def handle_create_debug_log(user_name, user_id, timeout=120): def handle_thread(thread, timeout): @@ -1068,22 +1097,23 @@ def handle_thread(thread, timeout): result = api.result if not result["success"]: return - print (result) + print(result) settings = context.get_settings() api = ToolingApi(settings) - thread = threading.Thread(target=api.create_trace_flag, args=(user_id, )) + thread = threading.Thread(target=api.create_trace_flag, args=(user_id,)) thread.start() - ThreadProgress(api, thread, "Create Debug Log for " + user_name, - "Create Debug Log for " + user_name + " Succeed") + ThreadProgress(api, thread, "Create Debug Log for " + user_name, + "Create Debug Log for " + user_name + " Succeed") handle_thread(thread, timeout) + def handle_view_debug_log_detail(log_id, timeout=120): def handle_thread(thread, timeout): if thread.is_alive(): sublime.set_timeout(lambda: handle_thread(thread, timeout), timeout) return - + if not api.result["success"]: return view = sublime.active_window().new_file() @@ -1096,12 +1126,13 @@ def handle_thread(thread, timeout): settings = context.get_settings() api = ToolingApi(settings) url = "/sobjects/ApexLog/" + log_id + "/Body" - thread = threading.Thread(target=api.retrieve_body, args=(url, )) + thread = threading.Thread(target=api.retrieve_body, args=(url,)) thread.start() - ThreadProgress(api, thread, "Get Log Detail of " + log_id, - "Get Log Detail of " + log_id + " Succeed") + ThreadProgress(api, thread, "Get Log Detail of " + log_id, + "Get Log Detail of " + log_id + " Succeed") handle_thread(thread, timeout) + def handle_run_test(class_name, class_id, timeout=120): def handle_thread(thread, timeout): if thread.is_alive(): @@ -1126,14 +1157,14 @@ def handle_thread(thread, timeout): "view_name": "Test Result", "input": test_result }) - + # Keep the history in the local history rep util.add_operation_history('Test/' + class_name, test_result) # After run test succeed, get ApexCodeCoverageAggreate - query = "SELECT ApexClassOrTrigger.Name, NumLinesCovered, NumLinesUncovered, Coverage " +\ + query = "SELECT ApexClassOrTrigger.Name, NumLinesCovered, NumLinesUncovered, Coverage " + \ "FROM ApexCodeCoverageAggregate" - thread = threading.Thread(target=api.query, args=(query, True, )) + thread = threading.Thread(target=api.query, args=(query, True,)) thread.start() wait_message = "Get Code Coverage of " + class_name ThreadProgress(api, thread, wait_message, wait_message + " Succeed") @@ -1158,11 +1189,12 @@ def handle_code_coverage_thread(thread, view, timeout): settings = context.get_settings() api = ToolingApi(settings) - thread = threading.Thread(target=api.run_test, args=(class_id, )) + thread = threading.Thread(target=api.run_test, args=(class_id,)) thread.start() ThreadProgress(api, thread, "Run Test Class " + class_name, "Run Test for " + class_name + " Succeed") handle_thread(thread, timeout) + def handle_run_sync_test(class_names, test_names, timeout=120): def handle_thread(thread, timeout): if thread.is_alive(): @@ -1188,23 +1220,23 @@ def handle_thread(thread, timeout): }) # Keep the coverage to local cache - codeCoverages = result["codeCoverage"] - cache_dir = os.path.join(settings["workspace"], ".config") - cache_file = os.path.join(cache_dir, "coverage.json") - - coverages = {} - if not os.path.exists(cache_dir): - os.makedirs(cache_dir) - elif os.path.isfile(cache_file): - coverages = json.loads(open(cache_file).read()) - - # Upsert exist code coverage info - for codeCoverage in codeCoverages: - lowerName = codeCoverage["name"].lower() - coverages[lowerName] = codeCoverage - - with open(cache_file, "w") as fp: - fp.write(json.dumps(coverages, indent=4)) + # codeCoverages = result["codeCoverage"] + # cache_dir = os.path.join(settings["workspace"], ".config") + # cache_file = os.path.join(cache_dir, "coverage.json") + # + # coverages = {} + # if not os.path.exists(cache_dir): + # os.makedirs(cache_dir) + # elif os.path.isfile(cache_file): + # coverages = json.loads(open(cache_file).read()) + # + # # Upsert exist code coverage info + # for codeCoverage in codeCoverages: + # lowerName = codeCoverage["name"].lower() + # coverages[lowerName] = codeCoverage + # + # with open(cache_file, "w") as fp: + # fp.write(json.dumps(coverages, indent=4)) # Get the latest debug log sublime.active_window().run_command('fetch_debug_log', { @@ -1221,6 +1253,75 @@ def handle_thread(thread, timeout): ThreadProgress(api, thread, wait_message, wait_message + " Succeed") handle_thread(thread, timeout) + +def handle_fetch_code_coverage(file_name, body, timeout=120): + def handle_thread(thread, timeout): + if thread.is_alive(): + sublime.set_timeout(lambda: handle_thread(thread, timeout), timeout) + return + + # If succeed + result = api.result + if "size" not in result or result["size"] == 0: + return Printer.get("error").write("No code coverage for %s, " % file_name + + "please run related test class before view code coverage") + + record = result["records"][0] + coverage = record.get("Coverage") + + num_lines_uncovered = record.get("NumLinesUncovered", 0) + num_lines_cover = record.get("NumLinesCovered", 0) + num_lines = num_lines_uncovered + num_lines_cover + if num_lines == 0: + return Printer.get("error").write("There is no code coverage (0% coverage)") + + # Append coverage statistic info + coverage_statistic = "%s Coverage: %.2f%%(%s/%s)" % ( + file_name, num_lines_cover / num_lines * 100, + num_lines_cover, num_lines + ) + + # If has coverage, just add coverage info to new view + view = sublime.active_window().new_file() + view.run_command("new_view", { + "name": coverage_statistic, + "input": body + }) + + # Calculate line coverage + lines_uncovered = coverage.get("uncoveredLines") + lines_covered = coverage.get("coveredLines") + split_lines = view.lines(sublime.Region(0, view.size())) + uncovered_region = [] + covered_region = [] + for region in split_lines: + # The first four Lines are the coverage info + line = view.rowcol(region.begin() + 1)[0] + 1 + if line in lines_uncovered: + uncovered_region.append(region) + elif line in lines_covered: + covered_region.append(region) + + # Append body with uncovered line + view.add_regions("numLocationsNotCovered", uncovered_region, "invalid", "dot", + sublime.DRAW_SOLID_UNDERLINE | sublime.DRAW_EMPTY_AS_OVERWRITE) + + view.add_regions("numLocationsCovered", covered_region, "comment", "cross", + sublime.DRAW_SOLID_UNDERLINE | sublime.DRAW_EMPTY_AS_OVERWRITE) + + # Setup and start the thread + settings = context.get_settings() + api = ToolingApi(settings) + q_str = "Select Id, ApexTestClassId, TestMethodName, ApexClassOrTriggerId," + \ + " ApexClassOrTrigger.Name, NumLinesCovered, NumLinesUncovered, Coverage" + \ + " From ApexCodeCoverage Where ApexClassOrTrigger.Name = '%s'" % file_name + thread = threading.Thread(target=api.query, args=(q_str, True)) + thread.start() + wait_message = "Get Code Coverage of " + file_name + ThreadProgress(api, thread, wait_message, wait_message + " Succeed") + handle_thread(thread, timeout) + + def handle_generate_sobject_soql(sobject, filter, timeout=120): def handle_new_view_thread(thread, timeout): if thread.is_alive(): @@ -1229,7 +1330,7 @@ def handle_new_view_thread(thread, timeout): # If succeed result = api.result - + # Error Message are prcoessed in ThreadProgress if not result["success"]: return @@ -1246,15 +1347,16 @@ def handle_new_view_thread(thread, timeout): settings = context.get_settings() api = ToolingApi(settings) if filter != "all": - args = (sobject, filter, ) + args = (sobject, filter,) else: - args = (sobject, ) + args = (sobject,) thread = threading.Thread(target=api.combine_soql, args=args) thread.start() wait_message = 'Generate SOQL for ' + sobject ThreadProgress(api, thread, wait_message, wait_message + ' Succeed') handle_new_view_thread(thread, timeout) + def handle_describe_sobject(sobject, timeout=120): def handle_new_view_thread(thread, timeout): if thread.is_alive(): @@ -1263,7 +1365,7 @@ def handle_new_view_thread(thread, timeout): # If succeed result = api.result - + # Error Message are prcoessed in ThreadProgress if not result["success"]: return @@ -1283,11 +1385,12 @@ def handle_new_view_thread(thread, timeout): settings = context.get_settings() api = ToolingApi(settings) sobject_url = "/sobjects/" + sobject + "/describe" - thread = threading.Thread(target=api.get, args=(sobject_url, )) + thread = threading.Thread(target=api.get, args=(sobject_url,)) thread.start() ThreadProgress(api, thread, 'Describe ' + sobject, 'Describe ' + sobject + ' Succeed') handle_new_view_thread(thread, timeout) + def handle_export_specified_workbooks(sobjects, timeout=120): settings = context.get_settings() api = ToolingApi(settings) @@ -1297,19 +1400,20 @@ def handle_export_specified_workbooks(sobjects, timeout=120): chunked_sobjects = util.list_chunks(sobjects, math.ceil(len(sobjects) / mcc)) for cs in chunked_sobjects: - thread = threading.Thread(target=api.generate_workbook, args=(cs, )) + thread = threading.Thread(target=api.generate_workbook, args=(cs,)) threads.append(thread) thread.start() - ThreadsProgress(threads, "Generating Sobjects Workbook", - "Sobjects Workbook are Generated") + ThreadsProgress(threads, "Generating Sobjects Workbook", + "Sobjects Workbook are Generated") + def handle_export_all_workbooks(timeout=120): def handle_thread(thread, timeout): if thread.is_alive(): sublime.set_timeout(lambda: handle_thread(thread, timeout), timeout) return - + # Exception Process if not api.result["success"]: return @@ -1323,7 +1427,7 @@ def handle_thread(thread, timeout): chunked_sobjects = util.list_chunks(sobjects, math.ceil(len(sobjects) / mcc)) for sobjects in chunked_sobjects: - thread = threading.Thread(target=api.generate_workbook, args=(sobjects, )) + thread = threading.Thread(target=api.generate_workbook, args=(sobjects,)) thread.start() settings = context.get_settings() @@ -1339,7 +1443,7 @@ def handle_thread(thread, timeout): if thread.is_alive(): sublime.set_timeout(lambda: handle_thread(thread, timeout), timeout) return - + # If failed, but something may happen, # for example, user password is expired result = api.result @@ -1363,8 +1467,8 @@ def handle_thread(thread, timeout): if not os.path.exists(outputdir): os.makedirs(outputdir) # Extract the zipFile to extract_to - thread = threading.Thread(target=util.extract_encoded_zipfile, - args=(result["zipFile"], extract_to, )) + thread = threading.Thread(target=util.extract_encoded_zipfile, + args=(result["zipFile"], extract_to,)) thread.start() # Apex Code Cache @@ -1372,15 +1476,15 @@ def handle_thread(thread, timeout): util.reload_file_attributes(result["fileProperties"], settings) else: if settings["debug_mode"]: - print ('[Debug] fileProperties:\n' + json.dumps(result, indent=4)) + print('[Debug] fileProperties:\n' + json.dumps(result, indent=4)) # Hide panel sublime.set_timeout_async(Printer.get("log").hide_panel, 500) # Reload sObject Cache and SymbolTables - if not is_update: + if not is_update: handle_reload_sobjects_completions() - + if settings["reload_symbol_tables_when_create_project"]: handle_reload_symbol_tables() @@ -1399,9 +1503,9 @@ def handle_thread(thread, timeout): types[xml_name] = ["*"] thread = threading.Thread(target=api.retrieve, args=({ - "types": types, - "package_names": settings["allowed_packages"] - }, )) + "types": types, + "package_names": settings["allowed_packages"] + },)) thread.start() wating_message = ("Creating New " if not is_update else "Updating ") + " Project" ThreadProgress(api, thread, wating_message, wating_message + " Finished") @@ -1411,7 +1515,7 @@ def handle_thread(thread, timeout): def handle_describe_metadata(callback_options, timeout=120): def handle_thread(thread, timeout): if thread.is_alive(): - sublime.set_timeout(lambda:handle_thread(thread, timeout), timeout) + sublime.set_timeout(lambda: handle_thread(thread, timeout), timeout) return # Exception is processed in ThreadProgress @@ -1447,18 +1551,19 @@ def handle_thread(thread, timeout): # Start to request settings = context.get_settings() api = MetadataApi(settings) - thread = threading.Thread(target=api._invoke_method, args=("describeMetadata", )) + thread = threading.Thread(target=api._invoke_method, args=("describeMetadata",)) thread.start() handle_thread(thread, timeout) - ThreadProgress(api, thread, "Describe Metadata of v%s.0" % settings["api_version"], - "Describe Metadata Finished") + ThreadProgress(api, thread, "Describe Metadata of v%s.0" % settings["api_version"], + "Describe Metadata Finished") + def handle_rename_metadata(file_name, meta_type, old_name, new_name, timeout=120): def handle_thread(thread, timeout): if thread.is_alive(): - sublime.set_timeout(lambda:handle_thread(thread, timeout), timeout) + sublime.set_timeout(lambda: handle_thread(thread, timeout), timeout) return - + # If not succeed, just stop if not api.result or not api.result["success"]: return result = api.result @@ -1472,7 +1577,7 @@ def handle_thread(thread, timeout): settings = context.get_settings() api = MetadataApi(settings) options = {"type": meta_type, "old_name": old_name, "new_name": new_name} - thread = threading.Thread(target=api._invoke_method, args=("renameMetadata", options, )) + thread = threading.Thread(target=api._invoke_method, args=("renameMetadata", options,)) thread.start() handle_thread(thread, timeout) message = "Renaming %s from %s to %s" % ( @@ -1480,10 +1585,11 @@ def handle_thread(thread, timeout): ) ThreadProgress(api, thread, message, "Renaming Finished") + def handle_reload_project_cache(types, callback_command, timeout=120): def handle_thread(thread, timeout): if thread.is_alive(): - sublime.set_timeout(lambda:handle_thread(thread, timeout), timeout) + sublime.set_timeout(lambda: handle_thread(thread, timeout), timeout) return if not api.result or not api.result["success"]: return @@ -1509,47 +1615,49 @@ def handle_thread(thread, timeout): # Start to request settings = context.get_settings() api = MetadataApi(settings) - thread = threading.Thread(target=api.prepare_members, args=(types, True, )) + thread = threading.Thread(target=api.prepare_members, args=(types, True,)) thread.start() handle_thread(thread, timeout) ThreadProgress(api, thread, "Reloading Project Cache", "Reload Project Cache Succeed") + def handle_retrieve_package(types, extract_to, source_org=None, ignore_package_xml=False, timeout=120): def handle_thread(thread, timeout): if thread.is_alive(): - sublime.set_timeout(lambda:handle_thread(thread, timeout), timeout) + sublime.set_timeout(lambda: handle_thread(thread, timeout), timeout) return - + # If source_org is not None, we need to switch project back if settings["switch_back_after_migration"] and source_org: util.switch_project(source_org) - + # Extract the zipFile to extract_to if api.result and api.result["success"]: - thread = threading.Thread(target=util.extract_encoded_zipfile, - args=(api.result["zipFile"], extract_to, ignore_package_xml, )) + thread = threading.Thread(target=util.extract_encoded_zipfile, + args=(api.result["zipFile"], extract_to, ignore_package_xml,)) thread.start() # Apex Code Cache if isinstance(api.result.get("fileProperties", None), list): util.reload_file_attributes( - api.result["fileProperties"], + api.result["fileProperties"], settings, append=True ) # Start to request settings = context.get_settings() api = MetadataApi(settings) - thread = threading.Thread(target=api.retrieve, args=({"types": types}, )) + thread = threading.Thread(target=api.retrieve, args=({"types": types},)) thread.start() handle_thread(thread, timeout) - ThreadProgress(api, thread, "Retrieve File From Server", - "Retrieve File From Server Succeed") + ThreadProgress(api, thread, "Retrieve File From Server", + "Retrieve File From Server Succeed") + def handle_save_to_server(file_name, is_check_only=False, timeout=120): def handle_thread(thread, timeout): if thread.is_alive(): - sublime.set_timeout(lambda:handle_thread(thread, timeout), timeout) + sublime.set_timeout(lambda: handle_thread(thread, timeout), timeout) return # Set Thread alive flag to False @@ -1570,13 +1678,13 @@ def handle_thread(thread, timeout): Printer.get('log').write("Start to keep local change history") # Get Workspace, if not exist, make it - workspace = settings["workspace"]+"/.history/"+component_attribute["type"] + workspace = settings["workspace"] + "/.history/" + component_attribute["type"] if not os.path.exists(workspace): os.makedirs(workspace) # Backup current file time_stamp = time.strftime("%Y-%m-%d-%H-%M", time.localtime()) - outputdir = workspace+"/"+component_name+"-"+time_stamp+"-history"+extension + outputdir = workspace + "/" + component_name + "-" + time_stamp + "-history" + extension with open(outputdir, "wb") as fp: fp.write(body.encode("utf-8")) @@ -1593,7 +1701,7 @@ def handle_thread(thread, timeout): view = util.get_view_by_file_name(file_name) if view: component_id = component_attribute["id"] - view.run_command("remove_check_point", {"mark":component_id+"build_error"}) + view.run_command("remove_check_point", {"mark": component_id + "build_error"}) # If succeed, just hide it in several seconds later delay_seconds = settings["delay_seconds_for_hidden_output_panel_when_succeed"] @@ -1614,8 +1722,8 @@ def handle_thread(thread, timeout): if "problem" not in result: return message = "Compile Error for %s: %s at line %s column %s" % ( - file_base_name, - result["problem"], + file_base_name, + result["problem"], result["lineNumber"], result["columnNumber"] ) @@ -1635,11 +1743,11 @@ def handle_thread(thread, timeout): line = result["lineNumber"] else: return - + if isinstance(line, list): line = line[0] if extension == ".page" and line < 2: return view.run_command("goto_line", {"line": line}) - view.run_command("expand_selection", {"to":"line"}) + view.run_command("expand_selection", {"to": "line"}) if hasattr(view, 'show_popup'): error = """ @@ -1650,8 +1758,8 @@ def handle_thread(thread, timeout):

""" % ( - file_base_name, - result["problem"], + file_base_name, + result["problem"], result["lineNumber"], result["columnNumber"] ) @@ -1659,14 +1767,14 @@ def handle_thread(thread, timeout): # Add highlight for error line and remove the highlight after several seconds component_id = component_attribute["id"] - view.run_command("set_check_point", {"mark":component_id+"build_error"}) + view.run_command("set_check_point", {"mark": component_id + "build_error"}) component_attribute, component_name = util.get_component_attribute(file_name) body = open(file_name, encoding="utf-8").read() # Component Full Name extension = component_attribute["extension"] - file_base_name = component_name + extension + file_base_name = component_name + extension # Log start_time start_time = datetime.datetime.now() @@ -1677,7 +1785,7 @@ def handle_thread(thread, timeout): if username + file_base_name in globals(): is_thread_alive = globals()[username + file_base_name] if is_thread_alive: - print ('%s is in process' % file_base_name); + print('%s is in process' % file_base_name); return # Open panel @@ -1690,7 +1798,7 @@ def handle_thread(thread, timeout): else: target = api.save_to_server thread = threading.Thread(target=target, - args=(component_attribute, body, is_check_only, )) + args=(component_attribute, body, is_check_only,)) thread.start() # If saving thread is started, set the flag to True @@ -1701,12 +1809,13 @@ def handle_thread(thread, timeout): ThreadProgress(api, thread, wait_message, wait_message + " Succeed", show_error=False) handle_thread(thread, timeout) + def handle_create_component(data, component_name, component_type, markup_or_body, file_name, timeout=120): def handle_thread(thread, timeout): if thread.is_alive(): - sublime.set_timeout(lambda:handle_thread(thread, timeout), timeout) + sublime.set_timeout(lambda: handle_thread(thread, timeout), timeout) return - + # If create Succeed result = api.result @@ -1721,7 +1830,7 @@ def handle_thread(thread, timeout): # Get the created component id component_id = result.get("id") extension = "." + settings[component_type]["suffix"] - + # Save it to component.sublime-settings s = sublime.load_settings(COMPONENT_METADATA_SETTINGS) username = settings["username"] @@ -1730,7 +1839,7 @@ def handle_thread(thread, timeout): # Prevent exception for creating component if no component in org if component_type not in components_dict: if not components_dict: - components_dict = {component_type : {}} + components_dict = {component_type: {}} else: components_dict[component_type] = {} @@ -1752,46 +1861,47 @@ def handle_thread(thread, timeout): sublime.save_settings(COMPONENT_METADATA_SETTINGS) # After new component is stored into cache, reload cache in globals() - sublime.set_timeout(lambda:util.load_metadata_cache(True), 50) + sublime.set_timeout(lambda: util.load_metadata_cache(True), 50) # Create Meta.xml File if component_type in ["ApexClass", "ApexTrigger"]: - meta_file_content = ("\n" +\ - "<{0} xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n" +\ - " {1}.0\n" +\ - " Active\n" +\ - "").format(component_type, settings["api_version"]) + meta_file_content = ("\n" + \ + "<{0} xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n" + \ + " {1}.0\n" + \ + " Active\n" + \ + "").format(component_type, settings["api_version"]) elif component_type in ["ApexPage", "ApexComponent"]: - meta_file_content = ("\n" +\ - "<{0} xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n" +\ - " {1}.0\n" +\ - " \n" +\ - "").format(component_type, settings["api_version"], component_name) + meta_file_content = ("\n" + \ + "<{0} xmlns=\"http://soap.sforce.com/2006/04/metadata\">\n" + \ + " {1}.0\n" + \ + " \n" + \ + "").format(component_type, settings["api_version"], component_name) # Generate new meta.xml file - with open(file_name+"-meta.xml", "w") as fp: + with open(file_name + "-meta.xml", "w") as fp: fp.write(meta_file_content) # After all are finished, we need to keep the lastModifiedDate handle_set_component_attribute(attributes) - + settings = context.get_settings() api = ToolingApi(settings) post_url = "/sobjects/" + component_type - thread = threading.Thread(target=api.post, args=(post_url, data, )) + thread = threading.Thread(target=api.post, args=(post_url, data,)) thread.start() fullName = os.path.basename(file_name) - ThreadProgress(api, thread, "Creating Component %s" % fullName, - "Creating Component %s Succeed" % fullName) + ThreadProgress(api, thread, "Creating Component %s" % fullName, + "Creating Component %s Succeed" % fullName) handle_thread(thread, timeout) + def handle_set_component_attribute(attributes, timeout=120): def handle_thread(thread, timeout): if thread.is_alive(): - sublime.set_timeout(lambda:handle_thread(thread, timeout), timeout) + sublime.set_timeout(lambda: handle_thread(thread, timeout), timeout) return - + result = api.result if result["success"] and result["records"]: lastModifiedDate = result["records"][0]["LastModifiedDate"] @@ -1807,54 +1917,57 @@ def handle_thread(thread, timeout): soql = "SELECT LastModifiedDate FROM %s WHERE Id = '%s'" % ( attributes["type"], attributes["id"] ) - thread = threading.Thread(target=api.query, args=(soql, True, )) + thread = threading.Thread(target=api.query, args=(soql, True,)) thread.start() handle_thread(thread, timeout) + def handle_refresh_static_resource(component_attribute, file_name, timeout=120): def handle_thread(thread, timeout): if thread.is_alive(): - sublime.set_timeout(lambda:handle_thread(thread, timeout), timeout) + sublime.set_timeout(lambda: handle_thread(thread, timeout), timeout) return - + if not api.result["success"]: return - with open (file_name, "wb") as fp: + with open(file_name, "wb") as fp: fp.write(api.result["body"].encode("utf-8")) settings = context.get_settings() api = ToolingApi(settings) url = component_attribute["url"] + "/body" - thread = threading.Thread(target=api.retrieve_body, args=(url, )) + thread = threading.Thread(target=api.retrieve_body, args=(url,)) thread.start() ThreadProgress(api, thread, 'Refresh StaticResource', 'Refresh StaticResource Succeed') handle_thread(thread, timeout) - + + def handle_create_static_resource(data, timeout=120): def handle_thread(thread, timeout): if thread.is_alive(): - sublime.set_timeout(lambda:handle_thread(thread, timeout), timeout) + sublime.set_timeout(lambda: handle_thread(thread, timeout), timeout) return - - if not api.result["success"]: + + if not api.result["success"]: return - print (api.result) + print(api.result) settings = context.get_settings() api = ToolingApi(settings) url = "/tooling/sobjects/StaticResource" - thread = threading.Thread(target=api.post, args=(url, data, )) + thread = threading.Thread(target=api.post, args=(url, data,)) thread.start() ThreadProgress(api, thread, 'Creating StaticResource', 'Creating StaticResource Succeed') handle_thread(thread, timeout) + def handle_diff_with_server(component_attribute, file_name, source_org=None, timeout=120): def handle_thread(thread, timeout): if thread.is_alive(): - sublime.set_timeout(lambda:handle_thread(thread, timeout), timeout) + sublime.set_timeout(lambda: handle_thread(thread, timeout), timeout) return - + result = api.result - + # If error, just skip, error is processed in ThreadProgress if not result["success"]: return @@ -1867,35 +1980,37 @@ def handle_thread(thread, timeout): settings = context.get_settings() api = ToolingApi(settings) - thread = threading.Thread(target=api.get, args=(component_attribute["url"], )) + thread = threading.Thread(target=api.get, args=(component_attribute["url"],)) thread.start() handle_thread(thread, timeout) ThreadProgress(api, thread, 'Diff With Server', 'Diff With Server Succeed') + def handle_refresh_file_from_server(attr, file_name, timeout=120): def handle_thread(thread, timeout): if thread.is_alive(): - sublime.set_timeout(lambda:handle_thread(thread, timeout), timeout) + sublime.set_timeout(lambda: handle_thread(thread, timeout), timeout) return - + result = api.result - if not result["success"]: + if not result["success"]: return - + with open(file_name, "wb") as fp: fp.write(result[attr["body"]].encode("utf-8")) settings = context.get_settings() api = ToolingApi(settings) - thread = threading.Thread(target=api.get, args=(attr["url"], )) + thread = threading.Thread(target=api.get, args=(attr["url"],)) thread.start() ThreadProgress(api, thread, 'Refreshing %s' % os.path.basename(file_name), 'Refresh Succeed') handle_thread(thread, timeout) + def handle_delete_component(component_url, file_name, timeout=120): def handle_thread(thread, timeout): if thread.is_alive(): - sublime.set_timeout(lambda:handle_thread(thread, timeout), timeout) + sublime.set_timeout(lambda: handle_thread(thread, timeout), timeout) return # If succeed @@ -1913,18 +2028,18 @@ def handle_thread(thread, timeout): os.remove(file_name) # Remove the related cls-meta.xml - if os.path.exists(file_name+"-meta.xml"): - view = util.get_view_by_file_name(file_name+"-meta.xml") + if os.path.exists(file_name + "-meta.xml"): + view = util.get_view_by_file_name(file_name + "-meta.xml") if view: window.focus_view(view) window.run_command("close") - os.remove(file_name+"-meta.xml") + os.remove(file_name + "-meta.xml") settings = context.get_settings() api = ToolingApi(settings) - thread = threading.Thread(target=api.delete, args=(component_url, )) + thread = threading.Thread(target=api.delete, args=(component_url,)) thread.start() file_base_name = os.path.basename(file_name) ThreadProgress(api, thread, "Deleting " + file_base_name, - "Delete " + file_base_name + " Succeed") - handle_thread(thread, timeout) \ No newline at end of file + "Delete " + file_base_name + " Succeed") + handle_thread(thread, timeout) diff --git a/util.py b/util.py index 4e4895e..5669049 100644 --- a/util.py +++ b/util.py @@ -247,6 +247,9 @@ def get_completion_from_cache(settings, component_type, is_lightning=False): return completion_list def view_coverage(name, file_name, body): + """ + @deprecated + """ settings = context.get_settings() cache_file = os.path.join(settings["workspace"], ".config", "coverage.json") coverages = {} From 3ab2b284c6cf4e3e72d5f6df68112a96c993952a Mon Sep 17 00:00:00 2001 From: Lushang Date: Fri, 27 Mar 2020 23:51:10 +0800 Subject: [PATCH 31/46] Implemented viewing Apex class/trigger code coverage after Run Test (async) --- main.py | 67 ++++++++++++++++++++++++++++++++++++++---- processor.py | 50 ++++---------------------------- util.py | 82 ++++++++++++++++++++++++++++------------------------ 3 files changed, 112 insertions(+), 87 deletions(-) diff --git a/main.py b/main.py index ea9654f..a796f55 100644 --- a/main.py +++ b/main.py @@ -711,7 +711,6 @@ def run(self, edit, mark): class ViewCodeCoverageCommand(sublime_plugin.TextCommand): def run(self, edit): - # util.view_coverage(self.attributes["name"], self.file_name, self.body) processor.handle_fetch_code_coverage(self.attributes["name"], self.body) def is_enabled(self): @@ -973,15 +972,19 @@ def is_visible(self, files): return True + class CancelDeployment(sublime_plugin.TextCommand): def run(self, edit): processor.handle_cancel_deployment_thread(self.sel_text) def is_enabled(self): - sel = self.view.sel()[0] - self.sel_text = self.view.substr(self.view.word(sel.begin())) + if len(self.view.sel()) == 0: + return False + region = self.view.sel()[0] + self.sel_text = self.view.substr(self.view.word(region.begin())) return self.sel_text.startswith("0Af") + class DestructFileFromServer(sublime_plugin.TextCommand): def run(self, edit): files = [self.view.file_name()] @@ -1693,7 +1696,11 @@ def is_enabled(self): def is_visible(self): return self.is_enabled() + class RunAsyncTest(sublime_plugin.WindowCommand): + """ + @deprecated + """ def __init__(self, *args, **kwargs): super(RunAsyncTest, self).__init__(*args, **kwargs) @@ -1718,7 +1725,11 @@ def is_enabled(self, files): def is_visible(self): return self.is_enabled() + class RunTestCommand(sublime_plugin.TextCommand): + """ + Run Async Test + """ def run(self, view): # Get component_attribute by file_name attributes = util.get_file_attributes(self.view.file_name()) @@ -1800,14 +1811,18 @@ def on_done(self, index): user_id = self.users[user_name] processor.handle_fetch_debug_logs(user_name, user_id) + class ViewDebugLogDetail(sublime_plugin.TextCommand): def run(self, view): processor.handle_view_debug_log_detail(self.log_id) def is_enabled(self): # Choose the valid Id, you will see this command - sel = self.view.sel()[0] - self.log_id = self.view.substr(self.view.word(sel.begin())) + # make sure selection has region in it + if len(self.view.sel()) == 0: + return False + region = self.view.sel()[0] + self.log_id = self.view.substr(self.view.word(region.begin())) if len(self.log_id) != 15 and len(self.log_id) != 18: return False if not re.compile(r'^[a-zA-Z0-9]*$').match(self.log_id): return False @@ -1815,6 +1830,48 @@ def is_enabled(self): return True + +class ViewCodeCoverageAfterSyncTest(sublime_plugin.TextCommand): + def run(self, edit): + # get code coverage cache + settings = context.get_settings() + work_dir = os.path.join(settings["workspace"]) + cache_file = os.path.join(work_dir, ".config", "coverage.json") + if not os.path.isfile(cache_file): + return + coverages = json.loads(open(cache_file).read()) + record = coverages.get(self.file_name) + + # get file content, may be apex class or trigger + class_path = os.path.join(work_dir, 'src', + 'classes', self.file_name+'.cls') + trigger_path = os.path.join(work_dir, 'src', + 'triggers', self.file_name + '.trigger') + _path = class_path if os.path.isfile(class_path) else trigger_path + with open(_path, encoding="utf-8") as fp: + file_content = fp.read() + if record and record.get("Coverage"): + util.view_coverage(self.file_name, record, file_content) + + def is_enabled(self): + if len(self.view.sel()) == 0 or self.view.name() != 'Test Result': + return False + region = self.view.sel()[0] + + # Make sure only enable for classes or triggers + start_reg = self.view.find('Trigger Or Class Code Coverage:', 0) + start_r, _ = self.view.rowcol(start_reg.begin()) + r, _ = self.view.rowcol(region.begin()) + if r - start_r < 4: + return False + self.file_name = self.view.substr(self.view.word(region.begin())) + if not re.compile(r'^[\w]+$').match(self.file_name): + return False + return self.file_name and self.file_name[0].isalpha() + + def is_visible(self): + return self.view.name() == 'Test Result' + class ViewDebugOnly(sublime_plugin.TextCommand): def run(self, view): whole_region = sublime.Region(0, self.view.size()) diff --git a/processor.py b/processor.py index 8bef61a..a9c98be 100644 --- a/processor.py +++ b/processor.py @@ -1177,7 +1177,8 @@ def handle_code_coverage_thread(thread, view, timeout): # If error, just skip result = api.result - if "success" in result and not result["success"]: return + if "success" in result and not result["success"]: + return code_coverage = util.parse_code_coverage(result) view.run_command("new_dynamic_view", { @@ -1267,54 +1268,13 @@ def handle_thread(thread, timeout): "please run related test class before view code coverage") record = result["records"][0] - coverage = record.get("Coverage") - - num_lines_uncovered = record.get("NumLinesUncovered", 0) - num_lines_cover = record.get("NumLinesCovered", 0) - num_lines = num_lines_uncovered + num_lines_cover - if num_lines == 0: - return Printer.get("error").write("There is no code coverage (0% coverage)") - - # Append coverage statistic info - coverage_statistic = "%s Coverage: %.2f%%(%s/%s)" % ( - file_name, num_lines_cover / num_lines * 100, - num_lines_cover, num_lines - ) - - # If has coverage, just add coverage info to new view - view = sublime.active_window().new_file() - view.run_command("new_view", { - "name": coverage_statistic, - "input": body - }) - - # Calculate line coverage - lines_uncovered = coverage.get("uncoveredLines") - lines_covered = coverage.get("coveredLines") - split_lines = view.lines(sublime.Region(0, view.size())) - uncovered_region = [] - covered_region = [] - for region in split_lines: - # The first four Lines are the coverage info - line = view.rowcol(region.begin() + 1)[0] + 1 - if line in lines_uncovered: - uncovered_region.append(region) - elif line in lines_covered: - covered_region.append(region) - - # Append body with uncovered line - view.add_regions("numLocationsNotCovered", uncovered_region, "invalid", "dot", - sublime.DRAW_SOLID_UNDERLINE | sublime.DRAW_EMPTY_AS_OVERWRITE) - - view.add_regions("numLocationsCovered", covered_region, "comment", "cross", - sublime.DRAW_SOLID_UNDERLINE | sublime.DRAW_EMPTY_AS_OVERWRITE) + util.view_coverage(file_name, record, body) # Setup and start the thread settings = context.get_settings() api = ToolingApi(settings) - q_str = "Select Id, ApexTestClassId, TestMethodName, ApexClassOrTriggerId," + \ - " ApexClassOrTrigger.Name, NumLinesCovered, NumLinesUncovered, Coverage" + \ - " From ApexCodeCoverage Where ApexClassOrTrigger.Name = '%s'" % file_name + q_str = "Select ApexClassOrTrigger.Name, NumLinesCovered, NumLinesUncovered, Coverage" + \ + " From ApexCodeCoverageAggregate Where ApexClassOrTrigger.Name = '%s'" % file_name thread = threading.Thread(target=api.query, args=(q_str, True)) thread.start() wait_message = "Get Code Coverage of " + file_name diff --git a/util.py b/util.py index 5669049..41fd710 100644 --- a/util.py +++ b/util.py @@ -246,60 +246,56 @@ def get_completion_from_cache(settings, component_type, is_lightning=False): return completion_list -def view_coverage(name, file_name, body): +def view_coverage(file_name, record, body): """ - @deprecated - """ - settings = context.get_settings() - cache_file = os.path.join(settings["workspace"], ".config", "coverage.json") - coverages = {} - if os.path.isfile(cache_file): - coverages = json.loads(open(cache_file).read()) - coverage = coverages.get(name.lower(), {}) + View Apex Class/Trigger code coverage like developer console UI - if not coverage: - return Printer.get("error").write("No code coverage cache, " +\ - "please execute `Run Sync Test` on related test class before view code coverage") + @param file_name: name of the apex class/trigger file + @param record: dict of {Coverage:{coveredLines:[], uncoveredLines:[]}, NumLinesUncovered:0, NumLinesCovered:0} + @param body: the apex class/trigger file body + @return: a new view with code coverage information + """ + coverage = record.get("Coverage") - numLocationsNotCovered = coverage["numLocationsNotCovered"] - numLocations = coverage["numLocations"] - numLocationsCovered = numLocations - numLocationsNotCovered - linesNotCovered = [] - # linesNotCovered = [l["line"] for l in coverage["locationsNotCovered"]] - if numLocations == 0: - return Printer.get("error").write("There is no code coverage") + num_lines_uncovered = record.get("NumLinesUncovered", 0) + num_lines_cover = record.get("NumLinesCovered", 0) + num_lines = num_lines_uncovered + num_lines_cover + if num_lines == 0: + return Printer.get("error").write("There is no code coverage (0% coverage)") # Append coverage statistic info coverage_statistic = "%s Coverage: %.2f%%(%s/%s)" % ( - name, numLocationsCovered / numLocations * 100, - numLocationsCovered, numLocations + file_name, num_lines_cover / num_lines * 100, + num_lines_cover, num_lines ) - + # If has coverage, just add coverage info to new view view = sublime.active_window().new_file() view.run_command("new_view", { "name": coverage_statistic, "input": body }) - + # Calculate line coverage + lines_uncovered = coverage.get("uncoveredLines") + lines_covered = coverage.get("coveredLines") split_lines = view.lines(sublime.Region(0, view.size())) uncovered_region = [] covered_region = [] for region in split_lines: # The first four Lines are the coverage info line = view.rowcol(region.begin() + 1)[0] + 1 - if line in linesNotCovered: + if line in lines_uncovered: uncovered_region.append(region) - else: + elif line in lines_covered: covered_region.append(region) # Append body with uncovered line view.add_regions("numLocationsNotCovered", uncovered_region, "invalid", "dot", - sublime.DRAW_SOLID_UNDERLINE | sublime.DRAW_EMPTY_AS_OVERWRITE) + sublime.DRAW_SOLID_UNDERLINE | sublime.DRAW_EMPTY_AS_OVERWRITE) view.add_regions("numLocationsCovered", covered_region, "comment", "cross", - sublime.DRAW_SOLID_UNDERLINE | sublime.DRAW_EMPTY_AS_OVERWRITE) + sublime.DRAW_SOLID_UNDERLINE | sublime.DRAW_EMPTY_AS_OVERWRITE) def get_local_timezone_offset(): @@ -2118,16 +2114,27 @@ def parse_all(apex): return apex_completions + def parse_code_coverage(result): records = {} - for record in result["records"]: - name = record["ApexClassOrTrigger"]["Name"] + for _record in result["records"]: + name = _record["ApexClassOrTrigger"]["Name"] records[name] = { - "NumLinesCovered" : record["NumLinesCovered"], - "NumLinesUncovered": record["NumLinesUncovered"] + "NumLinesCovered": _record["NumLinesCovered"], + "NumLinesUncovered": _record["NumLinesUncovered"], + "Coverage": _record.get("Coverage") } - code_coverage_desc = message.SEPRATE.format("TriggerOrClass Code Coverage:") + code_coverage_desc =("Trigger Or Class Code Coverage:\n" + + "Select Apex trigger or class name and " + + "view code coverage by context menu\n") + + # Keep the coverage to local cache, will overwrite the old one + settings = context.get_settings() + cache_dir = os.path.join(settings["workspace"], ".config") + cache_file = os.path.join(cache_dir, "coverage.json") + with open(cache_file, "w") as fp: + fp.write(json.dumps(records, indent=4)) columns = "" header_width = { @@ -2141,7 +2148,7 @@ def parse_code_coverage(result): row = "" row += "%-*s" % (header_width["Name"], name) coverage = records[name] - if not coverage["NumLinesCovered"] or not coverage["NumLinesUncovered"]: + if coverage.get("NumLinesCovered", 0) + coverage.get("NumLinesUncovered", 0) == 0: continue covered_lines = coverage["NumLinesCovered"] total_lines = covered_lines + coverage["NumLinesUncovered"] @@ -2150,7 +2157,8 @@ def parse_code_coverage(result): row += "%-*s" % (header_width["Lines"], "%s/%s" % (covered_lines, total_lines)) code_coverage += row + "\n" - return message.SEPRATE.format(code_coverage_desc + columns + "\n"*2 + code_coverage) + return message.SEPRATE.format(code_coverage_desc + "-"*79 + "\n" + + columns + "\n"*2 + code_coverage) def parse_sync_test_coverage(result): successes = result["successes"] @@ -2260,14 +2268,14 @@ def parse_test_result(test_result): return_result = class_name + test_result_desc + test_result_content[:-1] # Parse Debug Log Part - info = "You can choose the LogId and view log detail " +\ + info = "Select LogId and view log detail " +\ "in Sublime or Salesforce by context menu" - debug_log_desc = message.SEPRATE.format(info) debug_log_content = "LogId: " if len(test_result) > 0 and test_result[0]["ApexLogId"] != None: debug_log_content += test_result[0]["ApexLogId"] - return_result += debug_log_desc + debug_log_content + debug_log_content += '\n' + info + return_result += message.SEPRATE.format(debug_log_content) return return_result From 801529801bea1749c37ed3ba81998b5a5d09d131 Mon Sep 17 00:00:00 2001 From: Lushang Date: Sat, 28 Mar 2020 00:01:46 +0800 Subject: [PATCH 32/46] Release 3.5.8 --- HISTORY.rst | 4516 +++++++++-------- config/menus/Context.sublime-menu | 1 + config/messages/3.5.8.md | 8 + config/settings/package.sublime-settings | 2 +- config/settings/toolingapi.sublime-settings | 2 +- ...lass Header - class header.sublime-snippet | 4 +- messages.json | 9 +- 7 files changed, 2281 insertions(+), 2261 deletions(-) create mode 100644 config/messages/3.5.8.md diff --git a/HISTORY.rst b/HISTORY.rst index 1ca9c64..16c99b7 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -1,2253 +1,2263 @@ -.. :changelog: - -Release History ---------------- - -Release 3.5.7 (2020-03-26) -++++++++++++++++++++++++++++++++++++ - -* Refine Creating Lightning Web Component (``lwc``) process -* Add Retrieving, Destructing, Deploying lwc from both sidebar and context menu -* Add Creating CSS style, SVG file for lwc in context menu -* Fix auto completion for aura component bug -* Fix issue #198 - - -Release 3.5.4 (2019-07-31) -++++++++++++++++++++++++++++++++++++ -* Add component tag attr desc completion when hover on attr -* Add user interface api doc reference toc -* lwc supports label, staticresource, custom object and fields import -* Enhancement for lwc boolean attr completion -* Fix bug for meta file deployment - - -Release 3.5.4 (2018-02-12) -++++++++++++++++++++++++++++++++++++ -* Fix issue #172 -* Fix issue #173 - - -Release 3.5.3 (2018-02-06) -++++++++++++++++++++++++++++++++++++ -* Add missing base components from lightning developer guide by script: https://gist.github.com/xjsender/265d237fbeafebabff6c8669f9359fff#file-read-json-from-lightning-compnent-js -* Add $A.localizationService lib -* Fix some minor bugs - - -Release 3.5.2 (2018-02-03) -++++++++++++++++++++++++++++++++++++ -* Support oAuth2 Login, check https://github.com/xjsender/haoide#project-configuration for guide -* Add Lightning event methods completion -* Add customlabel and staticresource completions for lightning component -* Add lightning component iconName support -* Add package.zip to file_exclude_patterns -* Add attributes completion after v. -* Update apex lib to v41 -* Deliver enhancement for issue #145 -* Fix custom label completion bug in Lightning mode -* Fix bug for open_aura_document_reference command -* Fix bug #147 - - -Release 3.5.1 (2018-01-25) -++++++++++++++++++++++++++++++++++++ -* Basic completion support for component controller or helper - - -Release 3.5.0 (2018-01-21) -++++++++++++++++++++++++++++++++++++ -* Add aura component and attribute completion, contributed by @lushang -* Add some missed base component -* Add lightning component implements completion -* Add Queueable Apex Template -* Add SLDS classes completion -* Add some console snippets -* Add sObject completion when attribute support sObjects, such as type for aura:attribute -* Update export format for ``Export Profile`` command -* Fix some bugs, such as, aura app preview, custom label completion, etc. - - -Release 3.4.7 (2017-07-29) -++++++++++++++++++++++++++++++++++++ -* Really and still busy on project delivery work in the past year, will continue in the next days. -* New Fetaure: Combine package.xml in selected folders -* New Feature: Custom Label completion support, which is fetched from ``project/.config/package.json`` by ``Reload Project Cache`` command -* Update Aura completion lib by ``lushang`` -* Others - - -Release 3.4.6 (2016-09-26) -++++++++++++++++++++++++++++++++++++ -* Deliver enhancement for issue #132 -* Deliver enhancement for issue #134 -* Deliver enhancement for issue #140 -* Fix issue #138 - - -Release 3.4.5 (2016-06-16) -++++++++++++++++++++++++++++++++++++ -* Fix bug: sublime will be closed when view debug log by logId with pressing alt + dblclick left mouse -* Fix issue #126 -* Deliver feature #119 -* Add a new setting ``force_login_interval`` for controlling login cache refresh interval - - -Release 3.4.4 (2016-06-11) -++++++++++++++++++++++++++++++++++++ -* Fix Urgent ``FileNotFoundError`` problem when create new code - - -Release 3.4.3 (2016-06-06) -++++++++++++++++++++++++++++++++++++ -* Hide ``execute query`` command in the context menu, use ``REST TEST Query`` instead -* Rename Snippet ``HttpRequest - Authorization Basic Credentials.sublime-snippet`` to ``HttpRequest - Callout.sublime-snippet`` -* Add new snippet named ``Page - loading action status.sublime-snippet`` -* Add visibility control for ``Extract To Here`` in the sidebar menu -* Fix bug for custom components completion -* Fix bug for variable type fetching for code completion -* Fix issue #117 - - -Release 3.4.2 (2016-05-23) -++++++++++++++++++++++++++++++++++++ -* Change api version back to 35, fix issue #116 - - -Release 3.4.1 (2016-05-23) -++++++++++++++++++++++++++++++++++++ -* Fix issue #113 -* Fix issue #115 -* Fix Bug for conflict checking bug caused by solution for issue #108 -* Fix Bug for ``fetch debug log`` -* Execute ``fetch_debug_log`` operation after ``run sync test`` - - -Release 3.4.0 (2016-05-20) -++++++++++++++++++++++++++++++++++++ -- Deliver enhancement for issue #108 -- Deliver enhancement for issue #111 -- Fix bug when test class failed caused by dependency compilation -- Fix bug when view debug log detail -- Fix bug when read csv encoding -- Fix bug When create first new code that will clear the cache of others -- Fix bug When deploy files, default project is not switched back -- Remove duplicate command ``Reload Sobject Cache`` from command palette -- Remove snippet ``Class Body - class comments`` -- Add new snippet: ``Page - close window and refresh opener`` -- Add keymap for ``Open All Documents``, check the keymap setting for detail -- Add new command ``copy_files_to_project`` for issue #113 -- Update snippet: ``Debug - debug info``, ``Debug - debug error``, ``Class Header - class header`` -- Update include_users_in_role_hierarchy to false on default -- Update ``folder_exclude_patterns`` pattern to exclude ``.templates`` folder in the sidebar - - -Release 3.3.9 (2016-04-18) -++++++++++++++++++++++++++++++++++++ -* Force login every two hours -* Add retry operation for list package if session is expired -* Change display format for REST TEST Response, add a new setting ``remove_slash_for_rest_response`` -* Fix bug for aura creation -* Add AuraEnabled template class -* Add a snippet for class comments header -* Add a snippet for LoggingLevel.ERROR debug -* Update a snippet for LoggingLevel.INFO debug - - -Release 3.3.8 (2016-04-12) -++++++++++++++++++++++++++++++++++++ -* Enhancement for code template, welcome new template pull request -* Add runSpecifiedTest support for deploying files -* Change mousemap key mapping, see more detail at Q&A -* Update Q&A in the pulgin home page - - -Release 3.3.7 (2016-03-28) -++++++++++++++++++++++++++++++++++++ -* Fix issue #88 -* Fix issue #99, problem of ``reload document`` -* Deliver enhancement for issue #96 -* Open exported CSV file when execute ``Export CustomField`` command - - -Release 3.3.6 (2016-03-28) -++++++++++++++++++++++++++++++++++++ -* Fix issue #98 -* Add ``Return to First Step`` feature when open documentation by type -* Remove build-in reference settings which is replaced ``Reload Salesforce Document`` -* Enhancement for ``Open Documentation`` feature -* Enhancement for ``Reload Project Cache`` feature - - -Release 3.3.5 (2016-03-26) -++++++++++++++++++++++++++++++++++++ -* Greatly improve performance of code completion -* Fix invalid scope problem for custom class completion -* Enhancement for document reference -* Change panel message format - - -Release 3.3.4 (2016-03-23) -++++++++++++++++++++++++++++++++++++ -* Fix issue #93 -* Fix issue #97 -* Optimize for methods in ``metadata.py`` -* Update README.md - - -Release 3.3.3 (2016-03-14) -++++++++++++++++++++++++++++++++++++ -* Fix issue #94 -* Enhance ``refresh package`` command -* Add package.xml update support for command ``build_package_xml`` - - -Release 3.3.2 (2016-03-12) -++++++++++++++++++++++++++++++++++++ -* Fix issue #92 - - -Release 3.3.1 (2016-03-11) -++++++++++++++++++++++++++++++++++++ -* Rename ``deploy_package_to_server`` command to ``deploy_package`` -* Add new command ``refresh_package``, see issue #91 for detail -* Add LastModifiedBy check for conflict check logic, see issue #89 -* Remove setting ``ignore_project_package_xml`` and related logic - - -Release 3.3.0 (2016-03-11) -++++++++++++++++++++++++++++++++++++ -* Deliver enhancement #91 -* Fix bug issue #92 -* Fix package.xml onload XML parse exception - - -Release 3.2.9 (2016-03-10) -++++++++++++++++++++++++++++++++++++ -* Enhancement for ``role hierarchy exporting`` -* Add new settings ``include_users_in_role_hierarchy`` to control whether including user in the CSV -* Deliver new feature, see issue #89 -* upgrade build-in requests lib to 2.9.1 -* change display message for list metadata in the output panel - - -Release 3.2.8 (2016-02-26) -++++++++++++++++++++++++++++++++++++ -* Fix issue #88 -* Fix bug for ``export workflow rules`` feature -* Add parameter ``vertical`` for ``export_data_template`` command for exporting Layout Workbook -* Add a command for copying login url, which can be used for login with different browser -* Update version and copyright information - - -Release 3.2.7 (2015-12-21) -++++++++++++++++++++++++++++++++++++ -* Fix issue #86 - - -Release 3.2.6 (2015-12-20) -++++++++++++++++++++++++++++++++++++ -* Fix issue #84 -* Fix issue #85 -* New ``Export > Export Role Hierarchy`` command - - -Release 3.2.5 (2015-12-15) -++++++++++++++++++++++++++++++++++++ -* Fix urgent bug issue #83 -* Fix urgent bug for sobject cache reloading -* Remove ``allowed_sobjects`` setting - - -Release 3.2.4 (2015-12-09) -++++++++++++++++++++++++++++++++++++ -* Enhancement for lightning development -* Add new command for creating ``SVG`` and ``design`` -* Update lightning related library -* Change default ``api_version`` from ``34`` to ``35`` - - -Release 3.2.3 (2015-12-01) -++++++++++++++++++++++++++++++++++++ -* Bug Fix: - Fix bug for lightning development when deploying cmp or app - -* Enhancement: - - Display the lightning type in the input panel when creating lightning components - - Change ``No change`` to ``no difference`` in non-difference message when executing ``diff_with_server`` command - -* Update: - - Remove four commands ``create_lightning_application``, ``create_lightning_component``, ``create_lightning_interface``, ``create_lightning_event``, bind the four features to ``create_lightning_definition`` by difference ``_type`` - - Optimize completion for Boolean attribute in the html related page - - Stop keeping useless ``settings.json`` to ``.config`` folder - - -Release 3.2.2 (2015-11-19) -++++++++++++++++++++++++++++++++++++ -* Bug Fix: - - Fix TypeError when export soql to csv - - Fix aura app preview problem - - Fix bug for missing standard Objects when retrieve all - - Fix bug for `deploy selected open files` fetaure - - Fix instance parse problem for lightning app preview - - Fix bug of aura helperjs or controoler deploy - -* New Feature: - - Add new command to open aura document reference in the command palette - -* Enhancement: - - Improve output message of debug mode - - Update README.MD - - -Release 3.2.1 (2015-11-10) -++++++++++++++++++++++++++++++++++++ -* Fix issue #81 - - -Release 3.2.0 (2015-10-07) -++++++++++++++++++++++++++++++++++++ -* Deliver enhancement #73 -* Deliver enhancement #77 - - -Release 3.1.9 (2015-08-26) -++++++++++++++++++++++++++++++++++++ -* Fix issue #71, export workbooks by user input -* Fix bug for visibility problem of ``Retrieve Package.xml`` -* Add bootstrap3 support for styleClass attribute of salesforce standard components - - -Release 3.1.8 (2015-08-08) -++++++++++++++++++++++++++++++++++++ -* Bug Fix: - - Fix bug for bootstrap3 completion - - Fix bug for ``toggle_metadata_objects`` command if project is not initiated - - Fix bug for ``SOQL - SELECT FROM.sublime.snippet`` in windows - -* Enhancement: - - Add confirm request for ``retrieve files from server`` and ``retrieve files from this server`` - - Add confirm request for ``destruct package.xml from server`` and ``retrieve files from this server`` - - Identify ``this file`` or ``these files`` in confirm request message according to number of chosen files - -* Update: - - Add project name and remove [LOG] or [ERROR] notation in log or error panel - - Rename ``destruct package.xml`` command to ``destruct package.xml from server`` - - Rename ``retrieve package.xml`` command to ``retrieve package.xml from server`` - - Update ``to`` or ``from`` in context menu item name to ``To`` or ``From`` - - Update confirm request message for ``destruct files from server`` - -* New: - - Add a new command ``Enable Development Mode`` to quickly enable visualforce page development mode - - Add bootstrap3 completion document - - -Release 3.1.7 (2015-08-05) -++++++++++++++++++++++++++++++++++++ -* Enhancement: - - Add `with sharing` for `Utility Class` in template - - When you want to view code coverage, if you didn't download code, you can't view code coverage and you will get the reminder message in the status bar - - Before v33.0, tooling API doesn't support relationship query just like ``ApexClass.LastModifiedBy.Name``, when you save code to server, plugin will check your code has conflict with server and tell you ``who change the code at when?``, because relationship query is not supported, plugin will need to issue a query request to fetch the LastModifiedBy Name by the LastModifiedById, from this version, it will not necessary. - - Add comments for some settings - - Move metadata.json from ``metadata.sublime-settings`` to ``.config/metadata.json``, when you create new project, if the ``metadata.json`` is exist in the ``.config`` path, plugin will skip the describe process, however, if you want to refresh the cache, you can execute ``Metadata > Describe Metadata`` to refresh the ``metadata.json`` cache file - -* Bug Fix: - - After you select all test class, you can't deselect all when you run tests - - Problem when ``diff with other server``, see detail in issue #61 - -* New Feature: - - Add a new command named ``destruct_package_xml`` in the context menu, which is used for destructing members defined in ``package.xml`` from current server, so if you want to remove some components from production, you can get the package.xml by ``Metadata > Build Package.xml``, and then execute ``destruct_package_xml`` to remove them from production - -* Update: - - Update keymap of ``retrieve from this server`` from ``super+shift+r`` to ``alt+shift+r``, fix issue #68 - - Update keymap of ``deploy to this server`` from ``super+shift+s`` to ``alt+shift+s`` - - -Release 3.1.6 (2015-07-29) -++++++++++++++++++++++++++++++++++++ -* Bug fix: - - If controller name is same with page name, there will have problem when view code coverage - - Fix bug when file is loaded - - Fix issue #62 - - Fix issue #63 - -* Enhancement: - - Deliver enhancement #64 - - Deliver enhancement #65 - - Deliver enhancement #66 - - -Release 3.1.5 (2015-07-27) -++++++++++++++++++++++++++++++++++++ -* New Feature: - - Add bootstrap3 support for html class completion - - Add a new setting ``disable_bootstrap_completion`` to control bootstrap completion - -* Update: - - Remove ``Metadata > Describe Metadata`` menu item in the main menu - -* Fix Bug: - - Fix bug for running sync test for class with namespace or not - - Fix bug for ``get_file_attributes`` method - - -Release 3.1.4 (2015-07-25) -++++++++++++++++++++++++++++++++++++ -* Bug Fix: - - Fix issue #23? - - Fix issue #58 - - Fix issue #59 - -* Enhancement: - - Add filters support for ``Build Package.xml`` command, which is used to filter members which contains the input filters - - Add update feature for ``Build Package.xml`` command, which is used to add or remove members from exist package.xml - - Add keymap for some frequently-used commands - - Add visibility control for some CURD command on code file - - Aura related features - - Merge ``Deploy Lightning To Server`` command with ``Deploy File to Server`` command - - Merge ``Retrieve Lightning To Server`` command with ``Retrieve File to Server`` command - - Use file full name as key in ``component_metadata.sublime-settings``, originally, we use name as key, for example, originally, ``AccountController`` is key, now is ``AccountController.cls`` - - Change ``Diff With Server`` command to just visible when code file is ``classes, triggers, components or pages`` - -* New Feature: - - New ``Run Sync Test`` command for replacing ``Run Test`` feature - - Read code coverage information from local cache kept by ``Run Sync Test`` command - - New ``Retrieve from This Server`` command in the context menu - - New ``Diff With This Server`` command in the context menu - - New ``View File Attributes`` command in the context menu - -* Update: - - ``Quick Goto`` is switched to standard sublime build-in, I changed the mousemap to bind with the standard feature , with this feature, you can quickly view the symbols in sublime, for example, when you see a statement like this ``AccountUtil.populateField()``, you can put focus in the method name, hold down ``shift`` and triple-click your left mouse, sublime will open the ``AccountUtil`` class and put focus in the selected method - - -Release 3.1.3 (2015-07-18) -++++++++++++++++++++++++++++++++++++ -* Fix issue #54 -* Fix issue #56 - - -Release 3.1.2 (2015-07-17) -++++++++++++++++++++++++++++++++++++ -* Fix issue #55 - - -Release 3.1.1 (2015-07-16) -++++++++++++++++++++++++++++++++++++ -* Bug fix: - - Fix a issue for ``save_to_server`` command when ``api_version`` is less than 29 - - Fix problem in ``Class Body - test data util body-sublime-snippet.sublime-snippet`` - -* Enhancement: - - Enhancement for issue #53 - - Enhancement for issue #54 - - Support deploy and retrieve for metadataObject which is in folder - - Add support for visualforce email template development - - Add select all feature for ``toggle_metadata_objects`` command - - Add ``Territory2`` to ``allowed_sobjects`` list - -* Update: - - Remove ``disable_visualforce_completion`` setting - - Add four settings to disable part of completion in visualforce page, see more in ``docs/completion.md`` - - -Release 3.1.0 (2015-07-09) -++++++++++++++++++++++++++++++++++++ -* Enhancement: - - Sometimes, the inner class name is same with standard class or sObject, if this inner class is matched, ignore the standard completion - - Add Notation [EU] for external or unique field in field completion, ``E`` means External, ``U`` means Unique - - Add a new setting named ``disable_visualforce_completion`` to control visualforce completion - -* Bug Fix: - - Fix issue #49 - - Fix issue #50 - - Catch exception for ``check retrieve status`` request when retrieve - -* New - - Add a new snippet ``Bracket - sobject parenthesis.sublime-snippet``, see ``/docs/snippets.md`` for more detail - -* Update - - Change default ``api_version`` from 33 to 34 - - Move document for ``execute anonymous`` from ``project.md`` to ``debug.md`` - - -Release 3.0.9 (2015-07-01) -++++++++++++++++++++++++++++++++++++ -* Bug Fix: - - Fix bug for snippet ``SOQL - SELECT * FROM.sublime-snippet`` - - Fix bug for ``extract_to_here`` command - -* Enhancement: - - Don't need confirmation to reload project cache after choose metadata objects - - In order to avoid timeout exception, increase max_retries from 5 to 10 for retrieve zipFile request - - -Release 3.0.8 (2015-06-28) -++++++++++++++++++++++++++++++++++++ -* Bug Fix: - - Fix bug when build package.xml for whole org - -* Enhancement: - - Display chosen sObject Name when input trigger name - - Enhancement for #39, open a new view, set status bar and close the new view - - Add success message for ``extract_to_here`` command - - Update all snippets - -* New: - - Add a quick link to view all snippets, see it in plugin home page - - Add command to access all snippets in ``Utilities`` of main menu - - -Release 3.0.7 (2015-06-26) -++++++++++++++++++++++++++++++++++++ -* Bug Fix: - - Fix issue #46 - - Fix bugs caused by ``describe_global`` change in the ``tooling.py`` - -* Enhancement - - Merge pull request #45 by @reyesml(https://github.com/reyesml) - -* New - - Add a snippets: ``Page Variable - get and set in one line.sublime-snippet`` - - Add a snippets: ``Page Variable - get and set in multiply line.sublime-snippet`` - - Add a new command for building package.xml for whole org - - -Release 3.0.6 (2015-06-23) -++++++++++++++++++++++++++++++++++++ -* Bug Fix: - - Merge pull request #42 by @pgAdmin(https://github.com/pgAdmin) - - Merge pull request #43 by @reyesml(https://github.com/reyesml), fixed issue #6 - - Fix bug for ``export_workbook`` feature - - -Release 3.0.5 (2015-06-15) -++++++++++++++++++++++++++++++++++++ -* Bug Fix: - - Custom component attributes completion bug when component file is not exist in the target path - -* Enhancement: - - Improve regular expression for SOQL fields completion - - -Release 3.0.4 (2015-06-15) -++++++++++++++++++++++++++++++++++++ -* Bug Fix: - - Fix bug for issue #41 - - Fix bug for ``delete_file_from_server`` keybinding for windows - - Fix bug for ``auto_update_on_save`` feature in windows - - Fix ``KeyError: '\n\n'`` for converting complex JSON to Apex - -* Enhancement: - - Improve the regular expression for SOQL fields completion - - Improve the regular expression for Apex class method completion - - Improve the regular expression for visualforce component attribute completion - - Improve the visualforce tag name completion, add ``>`` for tag name automatically - - As the original design, you need to input your JSON when you execute JSON related commands, since this version, you just need to open any JSON file or select valid JSON content - - Add ``JSON/XML Tool`` into context menu, which is same with ``Utilities`` in main menu - - Update content for some docs - -* New Feature: - - Add attribute completion for custom component - - Add document for all code completion, you can see the link in the plugin home page - - -Release 3.0.3 (2015-06-11) -++++++++++++++++++++++++++++++++++++ -* Bug Fix: - - Fix duplicate save check bug caused by release 3.0.2 - - Fix fields completion bug for cross sObjects between tooling and non-tooling, for example ``User``, ``RecordType`` - -* Enhancement: - - Add session expired message for ``describe_metadata`` - - Enhancement for ``refresh_file_from_server`` - -* Update - - Update pop-up compile message for ``save_to_server`` command - - -Release 3.0.2 (2015-06-07) -++++++++++++++++++++++++++++++++++++ -* Bug fix: - - Fix NoneType exception in the console when open context menu, this is caused by release 3.0.1 - - Fix bug for ``Debug > Track All Debug Logs`` in the main menu - -* Enhancement - - Duplicate save_to_server check logic change: use file name with extension but not only file name, as the original design, if the controller name is same with page name, if you are saving page, you can't save the related controller at the same time - - Add timeout for query of conflict checking when ``save_to_server`` - - Prevent duplicate save conflict check when ``save_to_server``, as the original design, if you latest saving is interrupted, when you save it again, plugin will delete the metadata container Id for the saving file, at this time, save conflict checking will be executed again. - -* New: - - Add sObject completion for ``tooling sObjects``, for example, ``Validation Rule``, ``WorkflowRule``, ``ValidationRule``, ``WorkflowFieldUpdate``, ``WorkflowOutboundMessage``, ``WorkflowAlert`` or ``WorkflowTask`` - - Add * support for ``export query to CSV`` or ``export tooling query to CSV``, if you use * in the query statement, plugin will get all fields of this object and set them as the column headers - - Add export command for tooling query into the ``Data Loader`` in the main menu, you can use this command to export records for tooling objects - - Add a new markdown document related to debug - - Add a menu item for quick accessing document related to debug - -* Update: - - Update the menu item names and location in command palette and the ``Debug`` of main menu - - Change the default key binding for ``Debug > Run Test`` in the main menu - - -Release 3.0.1 (2015-06-04) -++++++++++++++++++++++++++++++++++++ -* Bug fix: - - Fix bug #39 - - Fix bug #40 - - Fix bug for SOQL completion - -* Enhancement: - - Enhancement for boolean attribute completion of standard visualforce component - - Set ``word_wrap`` setting of new view to false when describe sObject - - Keep attributes of all metadataObjects to local ``component_metadata.sublime-settings`` - - Prevent potential issue caused by change of ``component_metadata.sublime-settings`` - -* Update: - - Add output panel message for ``describe_metadata`` command - - Disable document reference reload feature - - Add a ``salesforce_reference.sublime-settings`` for ``Document > Open Document`` in the main menu - -* New API for metadata: - - Add a new ``read_metadata`` method for ``metadata.py``, which will be used for ``diff_with_server`` feature in the future - - -Release 3.0.0 (2015-05-26) -++++++++++++++++++++++++++++++++++++ -* Bug fix: - - Fix bug #38 - - Fix bug for SOQL fields completion - - Fix bug for attributes completion for value of ``apex:includeScript`` - -* New - - Add a new snippet named ``Page - field label.sublime-snippet`` - - -Release 2.9.9 (2015-05-25) -++++++++++++++++++++++++++++++++++++ -* Enhancement - - SOQL fields completion, see demo at plugin home page - -* New - - Add two demos at home page - - -Release 2.9.8 (2015-05-24) -++++++++++++++++++++++++++++++++++++ -* Update: - - Update the plugin install message for package control - -* Enhancement: - - Add the missed attributes for some standard components since v29.0 - - Add attribute values for standard components if attribute value is picklist attribute - -* New: - - Add a new setting ``auto_update_on_save``, default value is false - - If ``auto_update_on_save`` is set to true, when you update the code file, ``save_to_server`` will be executed automatically - -* Note: - - From this version on, I will not keep frequently release on this plugin, I will move on to build Haoide plugin for brackets - - -Release 2.9.7 (2015-05-22) -++++++++++++++++++++++++++++++++++++ -* Bug Fix: - - Fix issue #36 - - Fix bug for ``childXmlNames`` parsing and ``childXmlNames`` completion for package.xml - - Fix bug for timeout exception message for ``query`` method in ``tooling.py`` - - Fix NoneType exception for automatic extension or controller creation if current view is not local file - - Tag plugin fix a bug for that tag name contains colon, `see tag issue https://github.com/titoBouzout/Tag/issues/79`_ - -* Enhancement: - - Enhancement for attribute completion in visualforce page, if attribute value is already exist, it will not insert ``=""`` or ``="{!}"`` again - - Enhancement for ``standardController`` sObject name completion in visualforce page, it will just work when attribute is ``standardController`` - - Add custom class completion for ``extension`` and ``controller`` attribute in visualforce page - - Add values completion for some attributes of standard components which type should be picklist, for example, "apiVersion", "layout", "event" or "target" for link and so on, in this time I just updated to apex:composition, I will check the remaining standard component - - Add two missed standard component into ``vf.py``, "apex:component" and "apex:componentBody" - - Add custom page completion for these four attributes: "page", "template", "pageName", "finishLocation", for example, if you input `_ - -* Update: - - Rename ``View Release Notes`` command to ``Release Notes`` - - Rename ``json_pretty`` command to ``json_format`` - - Rename ``convert_xml_to_json`` command to ``xml_to_json`` - - Move ``xml_to_json`` from context menu to ``Utilites`` in the main menu - - Add access to ``toggle_metadata_objects`` for both ``Settings`` and ``Metadata`` in the main menu - - Upgrade build-in ``xmltodict`` module to ``0.9.2`` - - Update document for the change in this release - -* New Feature: - - New commands for ``HaoIDE > Utilities`` of the main menu: - - Add a new command ``haoide_help`` to view related document - - Add a new command ``json_to_xml`` to convert xml back to json, see issue #32 - - Add a new command ``xml_format`` to format selected xml content or whole file content, see issue #32 - - -Release 2.9.4 (2015-05-13) -++++++++++++++++++++++++++++++++++++ -* Bug Fix: - - If there is only one member, just remove the type and the related member when ``build package xml`` - - When execute ``query_to_csv`` command and field value contains ``"`` or ``,`` - -* Enhancement: - - Show the error message when list package for metadata objects if have - - Support quick clear for symbol_table and sobject cache - - Automatic ``{!}`` enhancement for vf tag just if type is "Object" or "ApexPages.Action" - - Update type of some visualforce standard components from ``Object`` to ``String`` - - Change the item format in the quick panel when ``build package xml`` - - Add ``EmailTemplate`` to ``allowed_sobjects`` setting - - Allow user to choose reloading specified ``metadata_object`` cache when execute reload_project_cache command - - When operation is depends on login session, so login firstly and callback with this operation - -* Update: - - Rollback the delivered function for issue #15 - - Optimize on ``metadata.py`` - - -Release 2.9.3 (2015-05-11) -++++++++++++++++++++++++++++++++++++ -* Enhancement: - - Package.xml completion read cache from ``.config/package.json``, no longer read cache from project file - - Sort for items in quick panel of package.xml building - - Add alert message for package.xml completion - -* Bug Fix: - - Add the folder into member when list_package for DocumentFolder, EmailFolder, ReportFolder and DashboardFolder - - No four spaces in the quick panel of package.xml building for windows - - -Release 2.9.2 (2015-05-10) -++++++++++++++++++++++++++++++++++++ -* Bug Fix: - - Fix bug for ``combine_soql`` which is invoked by ``Generate SOQL`` and ``Bulk Query`` - - Fix bug for ``export_profile`` command - - Fix bug for completion of building ``package.xml`` - - Fix bug for ``export_validation_rules`` command - -* New Feature: - - Deprecated ``metadataObjects`` since this release, which is replaced by ``/.config/metadata.json`` - - Add ``describe_metadata`` command, ``/.config/metadata.json`` will be generated by this command - - Add ``reload_project_cache`` command, ``/.config/package.json`` will be generated by this command - - Add ``build_package_xml`` command, see `more `_ - - Add key bindings for ``build_package_xml`` command - -* Enhancement: - - Move package related logic from ``main.py`` to the new ``package.py`` - - Add thread progress for ``track_debug_log``, ``fetch_debug_log`` and ``track_all_debug_logs`` - - `create_new_project`` start supporting callback - - Add metadata object for input description for ``create_new_component`` module - - Add list_package support for ``CustomObject`` retrieve - - Add availability check for ``.config/metadata.json`` for all related commands - - Add ``api_version`` message into the sidebar message - - Update ``api_version`` from ``32`` to ``33`` - - Update ``Metadata Migration`` to ``Metadata`` in the main menu - - Update ``generate_soql`` logic to include ``Id`` field if no available matched fields - - Update description for default settings - - Update README.md - - -Release 2.9.1 (2015-05-05) -++++++++++++++++++++++++++++++++++++ -* Fix bug for ``switch_project``, see issue #24 -* Enhancement for speeding up ``Save To Server`` operation -* Rename ``save_component`` command to ``save_to_server`` -* Rename ``delete_component`` command to ``delete_file_from_server`` -* Simplify ``delete_file_from_server`` and ``refresh_file_from_server`` -* Add two new value issue_url and history_url into package info -* Update ``report_issue`` and ``view_release_notes`` command to read url from package info - - -Release 2.9.0 (2015-05-03) -++++++++++++++++++++++++++++++++++++ -* Fix bug for messy code in debug log detail -* Enhancement for not refreshing sidebar when ``retrieve_files_from_other_server`` -* Enhancement for adding folder name to retrieve request when ``list_package`` for folders -* Enhancement for package.xml completion for folder name of Document, EmailTemplate, Dashboard and Report -* Enhancement for package.xml completion for AuraDefinitionBundle -* Enhancement for sobject completion, if there are two matched statements, ``insert prd`` and ``Product2 prd``, plugin will choose the second one as matched -* Enhancement for ``toggle_metadata_objects``, you can toggle metadata objects continually util you press ``ESC`` to exit -* Enhancement for ``generate_sobject_soql``, you can choose whether generate sobject SOQL of ``Custom``, ``Updateable`` or ``Createable`` -* Update workspace of default build-in project from ``C:/ForcedotcomWorkspace`` to empty -* Update name of default build-in project from ``pro-test`` to ``pro-sublime`` -* Update for ``toggle_metadata_objects``, after subscribe a new metadata object, don't refresh its folder again, just after you finish all toggle, you will need to confirm whether use refresh all subscribed metadata together -* Add ``toggle_metadata_objects`` document in ``docs/utilities.md`` -* Remove four deprecated settings, ``keep_config_history``, ``output_session_info``, ``delay_seconds_for_hidden_output_panel_when_failed`` and ``get_static_resource_body`` - - -Release 2.8.9 (2015-04-28) -++++++++++++++++++++++++++++++++++++ -* Fix urgent bug for issue #22 -* Enhancement for speeding up ``Save To Server`` operation -* Enhancement for supporting ``list_package`` when execute retrieve operation -* Enhancement for package.xml completion for Document, EmailTemplate, Dashboard and Report -* Enhancement for ``add_project_to_workspace`` just if login succeed -* Add a new ``link_project_with_sublime_project`` setting to control linking, default is false -* Update documents regarding to issue #18 - - -Release 2.8.8 (2015-04-26) -++++++++++++++++++++++++++++++++++++ -* Fix bug: If user don't have `Author Apex` privilege, plugin will give wrong information -* Fix bug: Show alert message if no available package.xml to combine -* Enhancement: Issue 15 about linking ``sublime-project`` with plugin project, deliver Windows solution but keep unchanged for OSX -* Enhancement: Add scope control for ``JSON to Apex`` -* Enhancement: Set ``word_wrap`` of ``Test Run`` result to false -* Enhancement: Simplify retrieve status check for API version 31 and later, check more detail at `here `_ -* Update documents - - -Release 2.8.7 (2015-04-22) -++++++++++++++++++++++++++++++++++++ -* Fix plugin loading NoneType issue -* Combine ``retrieve_package_file`` and ``retrieve_package_xml`` command to only ``retrieve_package_xml`` -* Allow user to input extractTo path, enhancement for issue #19 -* Add a new command ``combine_package_xml`` to combine all package.xml in many folders, see ``Salesforce Utilites`` quick link -* Update Documents - - -Release 2.8.6 (2015-04-20) -++++++++++++++++++++++++++++++++++++ -* Optimization for parsing project name by path or file -* Change the default workspace of plugin level to empty -* Change the workspace to optional, if workspace of plugin level and project level are both empty, plugin will save the project to ``/User/HaoIDE``, -* Change the name of ``execute_soql`` command to ``execute_query`` -* If there has network connection issue, just display ``Network connection timeout`` but no more detail again -* Add a new command for export query to csv, you should be aware, query statement contains parent-to-child statement will not be enabled for this command -* Add a new ``auto_switch_project_on_file_activated`` setting to control project switching when file of non-default project is open, this feature is disabled by default -* Add a new ``reveal_file_in_sidebar_on_file_activated`` setting to control sidebar file revealing when the file is open, this feature is disabled by default - - -Release 2.8.5 (2015-04-10) -++++++++++++++++++++++++++++++++++++ -* Biggest optimization for variable completion: - - Exclude comment statement - - Choose the nearest matched one -* Add a new ``remove_comments`` command in the ``Utilities`` -* Allow ``extract_to_here`` command to support all zip resources - - -Release 2.8.4 (2015-04-09) -++++++++++++++++++++++++++++++++++++ -* Add error popup display for latest version of sublime -* Add a new settings ``disable_html_completion`` to disable html completion -* Set default value of ``disable_html_completion`` as true because of conflict with sublime -* Optimize component attribute completion to support current line and next line -* Fix Bug: Wrong completion for Picklist2 when ``if (acc.Picklist1 == 'abc' && acc.Picklist2 == 'bcd')`` -* Fix Bug: Plugin found the wrong variable type in the commented code for variable completion -* Ignore exception when keep package.xml for every deploy action -* Rename Heroku to Haoku in the ``Main Menu > Utilities`` -* Remove useless ``.travis.yml`` -* Remove ugly code for check whether statement is comment for code -* Update ``execute_soql`` command to execute query in heroku - - -Release 2.8.3 (2015-04-02) -++++++++++++++++++++++++++++++++++++ -* If no CRUD privilege on profile object, just leave blank in the output csv -* Add field FLS export feature, it's a wonderful feature for document - - -Release 2.8.2 (2015-03-28) -++++++++++++++++++++++++++++++++++++ -* Fix package.xml completion bug if file name contains multiple dot -* Fix package.xml completion bug if there have extracted zip resource -* Pull request for #14 -* Spell problem of `Toggle Metadata Settings` -* Add entry point for ``Haoku`` in the ``Utilities`` of main menu -* Remove ``AuraDefinitionBundle`` from default subscribed Metadata settings - - -Release 2.8.1 (2015-03-05) -++++++++++++++++++++++++++++++++++++ -* Fix issue #6 -* Enhancement for issue #13 - - -Release 2.8.0 (2015-02-11) -++++++++++++++++++++++++++++++++++++ -* Fix issue #11, #12 -* Add two commands ``Retrieve All`` and ``Retrieve sObject and Workflow`` in the command palette - - -Release 2.7.9 (2015-02-06) -++++++++++++++++++++++++++++++++++++ -* Fix issue #4 -* Fix issue #7 -* Enhancement for ``diff_with_server``, allow diff compare with different project -* Upgrade ``requests`` to v2.5.1 and disable the InsecureRequestWarning -* Display line number before column number when ``save_component`` failed - - -Release 2.7.8 (2015-02-02) -++++++++++++++++++++++++++++++++++++ -* Rename ``refresh_component`` command to ``refresh_file_from_server`` -* Rename ``refresh_selected_components`` command to ``refresh_files_from_server`` -* Rename ``delete_selected_components`` command to ``delete_files_from_server`` -* Add a new command for ``retrieve file from other server`` for retrieve file from different project. -* Add a settings ``switch_back_after_migration`` to control whether switch back to original project after ``deploy to server``, ``deploy package to server``, ``deploy lightning to server`` or ``retrieve file from other server``, issue haoide:#3 -* Fix issue #5 -* Move ``pretty_json`` command from context menu to ``HaoIDE > Utilities > JSON Pretty`` in the main menu -* Update README.MD - - -Release 2.7.7 (2015-01-22) -++++++++++++++++++++++++++++++++++++ -* Fix bug for ``Package.xml Completion`` -* Enhancement: display error column in XML if deploy failed -* Enhancement for ``json_to_apex`` -* Enhancement for ``describe_sobject`` -* Add a new ``json_serialization`` command to serialize JSON to string -* Add a new ``panel`` menu item in Main Menu -* Rearrange Utilities menu item in Main Menu -* Update ``haoide`` to ``HaoIDE`` - - -Release 2.7.6 (2015-01-20) -++++++++++++++++++++++++++++++++++++ -* Enhancement for ``create_trace_flag`` command -* Add a enabled check logic for ``export profiles`` command -* Add a new ``haoide > Utilities > Convert JSON to Apex`` command for converting JSON to Apex -* Add commands for ``convert_json_to_apex`` in command palette -* Update README.MD about the `Convert JSON to Apex `_ - - -Release 2.7.5 (2015-01-18) -++++++++++++++++++++++++++++++++++++ -* Fix bug: messy code when view debug log detail in sublime -* Fix bug: timeout exception is not caught when save component -* Enhancement for completions -* Enhancement for ``export profile`` feature -* Add feature for export of ``userPermission`` and ``tabVisibility`` -* Update README.MD - - -Release 2.7.4 (2015-01-16) -++++++++++++++++++++++++++++++++++++ -* Fix bug for issue #75 -* Update ``Chanel`` to ``Channel`` in the plugin copyright information -* Update license information -* Remove ``InstalledPackage`` from ``metadataObjects`` settings -* No longer check save conflict when compile code -* Add commands for ``export_profile`` in command palette -* Update default keymap for ``open log panel``, ``open error panel`` and ``open diff panel`` in the ``Utilities`` menu item -* Enhancement for login module, decrease the timeout seconds and repeat login until repeat times exceed 12 times - - -Release 2.7.3 (2015-01-14) -++++++++++++++++++++++++++++++++++++ -* Fix bug for ``extract here`` command -* Fix bug for ``bulk api`` caused by release 2.7.2 -* Fix long-term bug for inProgress message of deployment -* Enhancement for ``list debug log``, for example, sort logs order by StartTime ASC, remove the useless "\n" -* Add missed standard objects for ``CustomObject`` when retrieve metadata -* Add new command for exporting profile object security settings, it's a very useful feature -* Add ``Translations`` to metadataObjects settings -* Update snippet description for ``Debug - debug json.sublime-snippet`` - - -Release 2.7.2 (2015-01-12) -++++++++++++++++++++++++++++++++++++ -* Fix bug for issue #74 -* Fix bug for ``cancel_deployment`` -* Fix bug for ``reload symbol table`` when symbol_table is None -* Fix bug for ``execute anonymous`` when anonymous code contains non-english words since release 2.7.0 -* Enhancement for message tracking in output panel -* Enhancement for settings check, if settings is valid, just display it in output panel -* Update snippet ``Debug - debug variable.sublime-snippet`` -* Add snippet ``Debug - debug json.sublime-snippet`` - - -Release 2.7.1 (2015-01-09) -++++++++++++++++++++++++++++++++++++ -* Enhancement for ``standardController completion`` in `` Email`` for ``Debug Log User List`` -* Milestone change for soap body request -* Enhancement for quick extension and quick controller -* Fix Bug for Package Completion -* Fix Bug for ``opps`` completions in ``getAccountList(List opps)`` -* Fix Bug for ``allowed_sobjects``, change ``Assert`` to ``Asset`` -* Fix Bug for ``reload_sobject_cache`` -* Fix Bug for ``bulkapi`` -* Change default value of ``last_n_logs`` from ``10`` to ``20`` - - -Release 2.6.0 (2014-12-20) -++++++++++++++++++++++++++++++++++++ -* Enhancement for ``refresh_folder`` -* Enhancement for ``retrieve_all`` and ``retrieve_sobjects_and_workflows`` -* Move export csv files to ``.export`` folder, for example, CustomFields, ValidationRules, Workflows and Workbooks, etc. - - -Release 2.5.9 (2014-12-17) -++++++++++++++++++++++++++++++++++++ -* Completion enhancement for building package.xml -* Fix duplicate MetadataContainerId for issue #69 -* `Build Package.xml Demo `_ - - -Release 2.5.8 (2014-12-15) -++++++++++++++++++++++++++++++++++++ -* Add all ``sharingRules`` metadata types to default components setting -* Rename ``.package`` to ``.deploy`` for ``deploy to server`` execution -* Remove ``subscribe_component`` and ``unsubscribe_component`` commands -* Add a new ``toggle_commands`` command to replace above two commands -* After a new component is subscribed, refresh the new folder from server -* Rename "ok" in confirm dialog to related message -* Add workspace check when create new project -* Update README.MD - - -Release 2.5.7 (2014-12-14) -++++++++++++++++++++++++++++++++++++ -* Fix Bug for creating extension or controller after input # in visualforce page -* Adjust the location of ``Cache`` menu item -* Add a new command for ``retrieve package.xml`` in sidebar menu -* Add a new command for ``create package.xml`` in sidebar menu -* Add a new command for ``subscribe component`` in ``settings`` of main menu -* Add a new command for ``unsubscribe component`` in ``settings`` of main menu -* Add quick command for ``subscribe component`` in quick command palette -* Add quick command for ``unsubscribe component`` in quick command palette -* Remove ``retrieve_package_xml`` command from ``Metadata Migration`` of main menu -* Rename ``soap_bodies`` to ``soap`` -* Update visibility for ``Update User Language`` - - -Release 2.5.6 (2014-12-13) -++++++++++++++++++++++++++++++++++++ -* Fix Bug for issue #65 -* Fix Bug for issue #66 -* Enhancement for issue #48, after deployed, the `package.xml` is saved to `.package` in workspace -* Before files are deployed to server, save them to local -* When you deploy any lightning element, just deploy the whole lightning component -* Convert StartTime of debug log to local time by timezone module - - -Release 2.5.5 (2014-12-09) -++++++++++++++++++++++++++++++++++++ -* Fix Bug for creating Lightning Component Element -* When deploy failed due to lower code coverage, display the coverage warning message -* When new component is created, create the meta.xml file for it -* Hide ``Retrieve Lightning from Server`` command when chosen folder is not aura folder -* Hide ``Destruct Lightning from Server`` command when chosen folder is not aura folder -* Hide ``Extract to Here`` command if file extension is not `zip` or `resource` -* Update the Documentation - - -Release 2.5.4 (2014-12-07) -++++++++++++++++++++++++++++++++++++ -* Add `dateutil` module for supporting timezone converting -* Fix Bug for `track debug log` -* Trim the space for `REST URI` automatically -* Remove `lib` from `Packages` in `.gitignore` file -* Support project level workspace for issue #63, see more detail at `workspace `_ - - -Release 2.5.3 (2014-12-05) -++++++++++++++++++++++++++++++++++++ -* Adjust the context menu from most bottom to center -* Adjust the sidebar menu from most bottom to center -* Fix Bug for issue #62: 'module' object has no attribute 'populate_classes' -* Fix Bug for issue #61: KeyError: 'name' in `get_component_completion` -* Fix Bug for issue #60: Error with 'Update Project' -* Add lightning component description for `Lightning Component` development - - -Release 2.5.2 (2014-11-27) -++++++++++++++++++++++++++++++++++++ -* After new lightning component is created, deploy it to server -* Add a new command for ``pretty json`` in the context menu -* hide the status message in progress bar when track self debug log after save succeed - - -Release 2.5.1 (2014-11-26) -++++++++++++++++++++++++++++++++++++ -* Fix Bug: NoneType Exception when destruct files from server -* Fix Bug: when saving component, the active view is not file -* Add a new settings ``track_log_after_saved`` to control whether track log after save succeed - - -Release 2.5.0 (2014-11-26) -++++++++++++++++++++++++++++++++++++ -* Fix Bug: when delete component, if there is a open view which is not bind to file, it will throw TypeError: argument of type 'NoneType' is not iterable, and then, file is deleted from server but local file is not removed -* Fix Bug: After folder is refreshed or project is updated, update the component cache -* Add `Lightning Component` document reference -* Add `Lightning Component` component tags to completions -* Add `Lightning Component` to `components` settings and set it as default subscribed component -* Add `Lightning Component` update feature -* Add `Lightning Component` components update feature -* Add `Lightning Component` component create feature -* Add `Lightning Component` component destruct feature -* Change default ``api_version`` from 31 to 32 -* Remove ``Open Coverage Panel`` menu item in the main menu -* Add ``duration`` column for debug logs and rearrange it's columns order -* Add new document reference for ``Analytic Api``, ``Analytics Cloud Dashboard JSON``, ``Security Implementation`` - and ``Lightning Component`` -* Add new command for viewing release notes -* Rename ``Extract Static Resource`` command to ``Extract To Here``, which command can be used to extract all zip source file but not only static resource for Salesforce -* Add ``settings`` to ``components`` settings -* If project is not created, all ``export`` feature and ``new component`` feature are not enabled - - -Release 2.4.0 (2014-11-18) -++++++++++++++++++++++++++++++++++++ -* Fix issue #55 -* Fix issue: non-english words are encoded to Unicode in result of ``Rest Test`` -* Fix issue: when read local cache of record type, ``global name 'users' is not defined`` exception -* Rollback feature of ``view_code_coverage``, see issue #56 -* Deprecate ``keep_config_history`` setting -* Update the description of ``keep_local_change_history`` setting -* When save operation has conflict and we cancel it, compare the local with server automatically - - -Release 2.3.0 (2014-11-14) -++++++++++++++++++++++++++++++++++++ -* Use local ``/.config/session.json`` to reuse session but not globals() again -* Use local ``/.config/recordtype.json`` to ``record type`` but not globals() again -* Use local ``/.config/users.json`` to ``users`` but not globals() again -* If ``execute_anonymous`` compiled succeed, use new view to display result, else, use output panel to display result -* Use frontdoor method to login to SFDC -* Add new document reference for ``Analytic Api`` -* Display session expired message in the output panel - - -Release 2.2.0 (2014-11-12) -++++++++++++++++++++++++++++++++++++ -Fix Issue: - -* Fix issue: TypeError: string indices must be integers when refreshed folder is empty -* Fix issue: In windows, change of folder or file in sidebar is not reflect in real time -* Fix issue: Sometimes, file is not remove from local after ``destruct file from server`` -* Fix issue: format problem of local ``.config`` info -* Fix issue: #52 - -Enhancement: - -* Add time stamp for new view name of ``rest test`` -* Show logs of ``fetch debug logs`` and ``execute_anonymous`` in the output panel but not new view -* Change default value of ``folder_exclude_patterns`` and ``file_exclude_patterns`` settings - -New Feature: - -* Add new command for ``fetch self debug log`` in the main menu and command palette - - -Release 2.1.0 (2014-11-10) -++++++++++++++++++++++++++++++++++++ -+ Fix Bug: ``IndexError: list index out of range`` caused by release 2.0.0 -+ Fix Bug for test class judgment: test class is that starts with `test` or ends with `test` -+ Add a new apex.py module, move execute_anonymous method from metadata.py to apex.py -+ Add a new command for ``diff with server`` in the context menu -+ Optimization on ``view_code_coverage`` feature -+ Add a new command ``Utilities > Open Coverage Panel`` in the main menu to open coverage panel -+ Rename ``Open Output Panel`` command to ``Open Log Panel`` and move it from ``Debug`` to ``Utilities`` in the main menu -+ Temporarily remove the ``Run All Test`` feature from ``Debug`` in the main menu - - -Release 2.0.0 (2014-11-08) -++++++++++++++++++++++++++++++++++++ -+ Fix minor bug for ``Duplicate Save Execution of Same Component`` -+ Remove useless message from ``message.py`` -+ Add a space between parameters for completion of standard apex class -+ Rename ``Describe`` menu item in the main menu to ``Utilities`` -+ Add a new command for ``Convert 15 Id to 18 Id`` -+ Add a new command for ``Track Self Debug Log`` -+ Add new feature for updating ZIP Static Resource, see demo ``https://raw.githubusercontent.com/xjsender/SublimeApexScreenshot/master/UpdateStaticResource.gif`` -+ Add commands for ``Convert 15 Id to 18 Id`` and ``track self debug log`` in the command palette -+ Add ``StaticResource`` to default subscribed components -+ Update README.MD - - -Release 1.9.0 (2014-11-04) -++++++++++++++++++++++++++++++++++++ -+ Fix issue #50 -+ Fix minor issue for ``delete_component`` -+ Fix potential issue for retrieve and deploy -+ Add ``Destruct Files From Server`` command in the sidebar menu for deleting files from sandbox or production -+ Add ``Destruct From Server`` command in the context menu for deleting file from sandbox or production -+ Add new command ``cancel_deployment`` for quickly canceling deployment of specified -+ Add mousemap for canceling deployment: Put the focus in the task Id, and then press alt and click Left Mouse for triple will cancel deployment of specified task Id - - -Release 1.8.0 (2014-11-03) -++++++++++++++++++++++++++++++++++++ -+ In order to prevent UI freeze, use thread to extract encoded zipFile to path -+ Solution for issue #49, add a new settings ``maximum_concurrent_connections`` to control concurrent connections -+ In order to prevent UI freeze, set default value of ``maximum_concurrent_connections`` to ``30`` - - -Release 1.7.0 (2014-10-31) -++++++++++++++++++++++++++++++++++++ -+ Fix Bug: If just compile component but not save, no need to keep history -+ Fix Bug: SOQL Field Completion problem if there is more than one character between from and sObject -+ Fix Bug: Replace all `LIST` to `List` -+ Remove ``Settings – Completions`` and ``Settings – Apex Template`` from main menu - - -Release 1.6.0 (2014-10-25) -++++++++++++++++++++++++++++++++++++ -+ Fix Bug: issue #44 caused by release 1.5.0 -+ Fix Bug: display ExpatError when retrieve package -+ Fix Bug: display json parse error message when execute rest test -+ Stop to hide output panel after retrieve is finished -+ show status message 'Not valid SFDC component' if current file is not valid SFDC component -+ Deprecate the delay_seconds_for_hidden_output_panel_when_failed settings -+ Stop to remove the error line highlight after ``save to server``, just remove it in the next save action -+ After save succeed, remove the highlight from view -+ Support error line highlight for visualforce page just if error line > 2 -+ Add ``OpenCTI Api`` document to document reference - - -Release 1.5.0 (2014-10-21) -++++++++++++++++++++++++++++++++++++ -+ Fix Bug for package import error in ``bulk api`` -+ Add more detailed action summary for ``save component``, issue #45, issue #46 -+ Add description for ``quick controller`` in README.MD - - -Release 1.4.0 (2014-10-18) -++++++++++++++++++++++++++++++++++++ -+ Fix bug for completion: No completions for ``strMap`` if there has ``// Populate Map\nMap strMap = new Map();`` -+ Fix Bug: ``deploy open files to server`` -+ Add a new command for ``preview_page`` in the command palette -+ Input ``#`` after controller or extension name in the visualforce page, plugin will automatically create it for you -+ Remove ``static resource`` from default subscribed components - - -Release 1.3.0 (2014-10-14) -++++++++++++++++++++++++++++++++++++ -+ Fix Minor bug for standard class completion: duplicate class in different namespace, for example, Communities, TimeZone, UnsupportedOperationException, Test, QueryException, Action -+ Fix Critical bug: non code file can't be retrieve from server, now, objects, reports and others can be retrieve from server -+ Fix Critical bug: Deploy exception after session cache is expired - - -Release 1.2.0 (2014-10-11) -++++++++++++++++++++++++++++++++++++ -+ ``get_static_resource_body`` settings is deprecated -+ Change default ``api_version`` from ``30`` to ``31`` -+ Add a new command ``deploy open files to server`` in the main menu, which is used to deploy open files in the sublime to target server -+ Add command for ``deploy open files to server`` in the Command Palette -+ Add ``static resource`` to default subscribed components -+ Fix Bug for Windows: After ``retrieve all`` is finished, invoke the ``refresh_folder_list`` standard function to display the new folders generated by ``retrieve all`` -+ Fix Bug: ``Save to Server`` command (Use Tooling Api) can be only used on ``classes``, ``components``, ``pages`` and ``triggers`` but not other components, however, we can use ``Deploy to Server`` command (Use Metadata Api) to save all components - - -Release 1.1.0 (2014-10-09) -++++++++++++++++++++++++++++++++++++ -+ Fix Bug for Windows: After ``export`` is finished, refresh the project folders to ensure the new folder is shown in the sidebar -+ Fix Bug: display deploy failed message if deploy is failed. -+ Fix Bug: symbol table is null when iterate symbol table -+ Update README.MD - - -Release 1.0.9 (2014-10-04) -++++++++++++++++++++++++++++++++++++ -+ Fix Bug: After open a new view, open context menu, it will throw NoneType exception - - -Release 1.0.8 (2014-10-02) -++++++++++++++++++++++++++++++++++++ -+ Fix issue at ``https://success.salesforce.com/answers?id=90630000000gxvwAAA`` - - -Release 1.0.7 (2014-09-30) -++++++++++++++++++++++++++++++++++++ -+ Fix Minor Bug for windows: After ``.config`` is generated, invoke the sublime command: ``refresh_folder_list`` -+ Enhancement for checking whether current project is active project -+ Fix Critical Bug: If session is expired, we want to refresh the folder or update project, the console will always stop at the step of ``[sf:retrieve] Start request for a retrieve...`` -+ Fix issue #42, stop to remove folder when refresh folder or update project but just override, Notice: if you delete some file in the server, after ``update project`` and ``refresh folder``, these files will not deleted in the sublime, so, I suggest you should delete code in the sublime but not in the server - - -Release 1.0.6 (2014-09-28) -++++++++++++++++++++++++++++++++++++ -+ Fix Minor Bug: After ``retrieve_package_file`` is succeed, hide the output panel -+ Fix Minor Bug: If current project is not ``active project``, disable the ``Retrieve Files From Server`` functionality -+ Fix Minor Bug: If current project is not ``active project``, disable the ``Retrieve File From Server`` functionality -+ Fix Minor Bug: If current project is not ``active project``, disable the ``Run Test Class`` functionality - - -Release 1.0.5 (2014-09-27) -++++++++++++++++++++++++++++++++++++ -+ Fix bug: Exception when ``new project`` in a new org -+ Fix bug: If there is no any trigger, after ``new project``, the folder of ``trigger`` is not created. -+ Fix bug: ``subscribed_meta_folders`` and ``meta_folders`` in settings are not correct - - -Release 1.0.4 (2014-09-25) -++++++++++++++++++++++++++++++++++++ -+ Fix urgent issue #40 -+ Remove the useless soap related codes, for example, ``retrieve_apex_code_body``, ``retrieve_static_resource_body`` and so on -+ Fix minor bug: Don't allow to refresh or delete ``*-meta.xml`` file -+ Fix bug: ``allowed_packages`` is not working -+ Fix bug: mass refresh multiply folders -+ Fix minor bug: deploy failed message in the output panel -+ Add a new sidebar command ``Retrieve Files From Server`` -+ Add a new context command ``Retrieve File From Server`` -+ If ``allowed_packages`` is not empty, all packages are extracted to ``packages`` path, - Project - > .config - > src - > packages - > package 1 - > package 2 - - -Release 1.0.3 (2014-09-24) -++++++++++++++++++++++++++++++++++++ -+ After ``Update Project`` is finished, remove the original ``src`` tree and then extract the zipFile to ``src`` -+ After ``Refresh Folder`` is finished, remove the original folders and then extract the zipFile to specified folders -+ Fix urgent bug: if no project in sidebar and sidebar is hidden, after ``new project`` or ``update project``, the sidebar is not open automatically. - - -Release 1.0.2 (2014-09-23) -++++++++++++++++++++++++++++++++++++ -+ Update the default value of ``checkOnly`` in ``deploy_options`` settings from ``true`` to ``false`` -+ Fix Urgent bug: If one class is created in the server, after ``refresh folder``, cache of this folder will override all components -+ Remove some useless ``print`` statement -+ Fix minor bug: After code is saved, duplicate extension is displayed in the console -+ Add two settings ``folder_exclude_patterns`` and ``files_exclude_patterns`` to hide everything you want to hide in the sidebar -+ Update the ``add project to workspace`` logic to compatible with the above two settings -+ Add a new command ``Update Project Patterns`` in the main menu, see [Pattern Demo](https://raw.githubusercontent.com/xjsender/SublimeApexScreenshot/master/ProjectPattern.gif) - - -Release 1.0.1 (2014-09-22) -++++++++++++++++++++++++++++++++++++ -+ Add ``LogLength`` column to result of ``fetch debug logs`` -+ Update default value of ``display_field_name_and_label`` setting from ``false`` to ``true`` -+ Remove the ``\n`` from success message in ``document.py`` -+ Add description for ``save multiple components`` feature in the README.MD -+ Change output directory of ``retrieve package.xml`` from current directory to ``[ProjectName]-201409221812`` -+ Add ``messages`` notes - - -Release 1.0.0 (2014-09-21) -++++++++++++++++++++++++++++++++++++ -+ Add a new command ``Deploy To Server`` in the context menu -+ Fix bug for ``retrieve`` when session is expired -+ Fix bug for ``New ApexClass``, ``New ApexTrigger``, ``New ApexComponent`` and ``New ApexPage`` -+ Fix bug ``TypeError: is_visible() missing 1 required positional argument: 'dirs'`` when open ``Command Palette`` -+ Fix bug: If there is no any trigger or class, we want to create the first one, there has exception -+ Fix bug: ``Package.xml`` was overridden by ``refresh folder`` - - -Release 0.9.9 (2014-09-20) -++++++++++++++++++++++++++++++++++++ -+ Try to fix bug for ``new release messages display`` or who can tell me how to display ``release message`` -+ Fix bug for ``quick go to component`` - - -Release 0.9.8 (2014-09-20) -++++++++++++++++++++++++++++++++++++ -+ Support multiply folder refresh -+ Add standard sObjects to CustomObject Package Members when create new project if CustomObject is subscribed -+ Update default subscribed components -+ Add a new command ``Deploy Files to Server`` -+ Fix bug: Display debugLog info after deploy is finished -+ Upsert demo in README.MD -+ Display the new release message after new released upgrade is finished - - -Release 0.9.7 (2014-09-19) -++++++++++++++++++++++++++++++++++++ -+ Milestone for Metadata Api Migration from ``Tooling Api`` for non-code meta -+ remove some time stamp for deploy -+ Functionality check for ``convert xml to json`` -+ Optimize the zip utility for ``extract`` zip file or ``compress`` folder -+ Remove ``hidden_console_on_modify`` settings -+ Fix bug: the output console message for ``compile`` -+ Use ``metadata api`` to new project -+ Use ``metadata api`` to refresh folder -+ Change the default settings content for ``components``, you can subscribe what you want to retrieve, default subscribe just include ``ApexPage``, ``ApexComponent``, ``ApexClass`` and ``ApexTrigger`` - - -Release 0.9.6 (2014-09-16) -++++++++++++++++++++++++++++++++++++ -+ Fix bug for issue #38, remove ``ownerRules``, ``criteriaBasedRules`` and ``installedPackages`` from default package.xml -+ Add a command to export CustomLables to csv -+ Update ``SOQL - SELECT FROM`` snippet - - -Release 0.9.5 (2014-09-15) -++++++++++++++++++++++++++++++++++++ -+ Add confirm request for ``new project`` -+ Add screenshot for ``Convert XML to JSON`` -+ Fix KeyError Exception bug: cancel save operation if conflict. - - -Release 0.9.4 (2014-09-14) -++++++++++++++++++++++++++++++++++++ -+ Move ``check_enabled`` from ``main.py`` to ``util.py`` -+ If ``deploy status`` is in ``canceling``, continue to check deploy status until it's canceled. -+ Remove useless ``mkdir`` method from context.py -+ Move some methods from ``context.py`` to ``util.py`` -+ Fix bug for ``deploy`` and change the syntax highlight from ``Java`` to ``JavaScript`` - - -Release 0.9.3 (2014-09-13) -++++++++++++++++++++++++++++++++++++ -+ Add a command to convert selection to JSON if selection is valid XML format -+ Add context menu item, commands for this command -+ Fix a bug for parsing ``apexrest`` url when executing rest test - - -Release 0.9.2 (2014-09-13) -++++++++++++++++++++++++++++++++++++ -+ Fix bug when ``sosl_string`` contains ``-, ?, *`` -+ Update ``query`` method in ``api.py`` -+ Separate ``api.py`` to ``metadata.py`` and ``tooling.py`` and move them to new ``api`` folder -+ Rename ``bulkapi.py`` to ``bulk.py`` and move it to ``api`` folder -+ After ``New Project`` is finished, invoke the sublime command ``refresh_folder_list`` to reflect files change in the sidebar -+ After the code file is deleted, the related ``-meta.xml`` file is also deleted - - -Release 0.9.1 (2014-09-12) -++++++++++++++++++++++++++++++++++++ -+ Fix bug when code has conflict and user cancel the save operation - - -Release 0.9.0 (2014-09-12) -++++++++++++++++++++++++++++++++++++ -+ Fix bug for windows sidebar folder refresh -+ Not keep ``default_project`` settings in the settings of ``.config`` -+ Add ``reload_symbol_tables_when_create_project`` setting -+ Set default value of ``reload_symbol_tables_when_create_project`` setting to ``false`` -+ Fix bug for ``execute anonymous`` - - -Release 0.8.9 (2014-09-11) -++++++++++++++++++++++++++++++++++++ -+ If ``retrieve`` is in ``Queued``, thread sleep 2 seconds, else, thread sleep 1 seconds -+ If ``deploy`` is in ``Pending``, thread sleep 2 seconds, else, thread sleep 1 seconds -+ After project is switched, set status for all view of all window. -+ Fix the bug of ``remove temp zip`` -+ When deploying, if component parse is finished, display the TestRun Progress - - -Release 0.8.8 (2014-09-11) -++++++++++++++++++++++++++++++++++++ -+ Fix some bug for ``deploy`` - - -Release 0.8.7 (2014-09-10) -++++++++++++++++++++++++++++++++++++ -+ Update README -+ When ``New Project``, no need to select project -+ Fix bug ``c:`` completion - - -Release 0.8.6 (2014-09-09) -++++++++++++++++++++++++++++++++++++ -+ Add ``c:`` prefix for custom component completion -+ Add space between timestamp and message in the panel - - -Release 0.8.5 (2014-09-08) -++++++++++++++++++++++++++++++++++++ -+ Move some methods from processor.py to util.py -+ Optimize sObject Cache download -+ Add time stamp prefix for panel message -+ Fix bulkapi bug caused by release 0.8.3 -+ Move ``allowed_packages`` to project of projects settings -+ Add metadata retrieve support for ``allowed_packages`` -+ Catch all ``requests`` exception -+ Use panel to display the progress information of ``document reloading`` -+ From release 0.8.3 to this version, there have lots of big change, issue is welcomed -+ Add "Accept-Encoding": 'identity, deflate, compress, gzip' header for ``check_status``, ``check_deploy_status`` and ``check_retrieve_status`` in api.py - - -Release 0.8.4 (2014-09-08) -++++++++++++++++++++++++++++++++++++ -+ If just checkOnly, output VALIDATE, otherwise, output DEPLOY -+ Update comments for ``mousemap`` -+ Big Milestone, originally, we use ``tooling api`` to download apex code, now it is changed to retrieving by ``metadata api`` -+ Happy to remove the ugly method ``refresh_components`` in api.py, this method is very very ugly - - -Release 0.8.3 (2014-09-07) -++++++++++++++++++++++++++++++++++++ -+ Rearrange the attribute position in ``soap_bodies.py`` -+ Update README.MD -+ When start ``deploy`` command, if clipboard content is not valid zip file path, set path with empty, otherwise, paste it to input panel -+ Rename ``Retrieve Metadata`` item in main menu to ``Retrieve All`` -+ Rename ``Migration`` item in main menu to ``Metadata Migration`` -+ Add confirmation request for ``Retrieve All`` and ``Retrieve sObjects and Workflow`` -+ Rename ``Describe Sobject`` item in main menu to ``sObject`` -+ Rename ``Generate SOQL`` item in main menu to ``sObject SOQL`` -+ Rename ``SOQL History`` path from ``soql`` to ``SOQL`` -+ Rename ``Workbook Export`` path from ``workbooks`` to ``Workbooks`` -+ Rename ``CustomField`` path from ``customfield/customfield.csv`` to ``CustomField/CustomField.csv`` -+ Rename ``Validation Rule`` path from ``validation/validation rules.csv`` to ``Validation/Validation Rules.csv`` -+ Add ``Apex Code`` related sObject to ``allowed_sobjects`` settings -+ Remove ``proxies`` settings -+ Fix bug: Parse content from package.xml when there is only one types in package.xml -+ Add a new ``Retrieve Package.xml`` command in the context menu, just available when open file is ``package.xml`` -+ Add a new ``Deploy to Server`` command in the sidebar menu, just available when the chosen folder is valid package path -+ Put the focus in the log id, press ``Alt`` and click left button, the debug log detail will be retrieved and displayed in the new view -+ Error message when export workflow or validation rule if not retrieve yet -+ Remove ``SnapshotAuditEvent``, ``SnapshotBin``, ``Question``, ``SnapshotConfig``, ``Reply`` and ``UserLicense`` from default ``retrieve_sobjects_workflow_task_body`` in ``soap_bodies.py`` - - -Release 0.8.2 (2014-09-05) -++++++++++++++++++++++++++++++++++++ -+ when ``retrieve package.xml``, if file in package.xml is not found in target org, display the message -+ Add ``deploy package.zip`` command to deploy zip file - - -Release 0.8.1 (2014-09-05) -++++++++++++++++++++++++++++++++++++ -+ Change the UI of ``retrieve`` -+ Add a command ``retrieve_package`` in the main menu to retrieve metadata by specified package.xml -+ Fix a bug for ``get_static_resource_body`` when creating a new project -+ Fix a bug for displaying the latest debug logs ``ORDER BY StartTime DESC`` when ``fetch logs`` -+ Add a new demo link ``Retrieve Package.xml`` in README.MD - - -Release 0.8.0 (2014-09-04) -++++++++++++++++++++++++++++++++++++ -- Change ``se`` Snippet from ``SELECT Id, $2 FROM $1$0`` to ``SELECT Id$2 FROM $1$0`` -- Stop to open console when ``Refresh Selected Component`` -- Originally, press ``shift+button1*3`` to open class in background and press ``shift+button1*2`` to open class in foreground, now it is changed to ``shift+button1*3`` for background and ``shift+button1*2`` for foreground -- Change screenshots to demo link -- Fix ``query_all`` bug in api.py - - -Patch for Release 0.7.9 (2014-09-01) -++++++++++++++++++++++++++++++++++++ -+ ``output_session_info`` setting is deprecated and replaced by ``.config/session.json`` -+ Do not keep ``projects`` settings in the ``.config/settings.json``, because it's private confidential - - -Release 0.7.9 (2014-09-01) -++++++++++++++++++++++++++++++++++++ -+ Fix the display problem of ``Run Test`` and ``LoginTo ApexCode`` cause by History Item 1 of release 0.7.7 -+ Rename the path name of ``Test Operation History`` from ``test`` to ``Test`` -+ Fix bug for ``Create Component`` and ``Refresh Component Folder`` caused by History Item 1 of release 0.7.7 - - -Release 0.7.8 (2014-08-31) -++++++++++++++++++++++++++++++++++++ -+ Fix Operation History Format Problem -+ Inner class completion format ``Inner Class `` -+ After Project is created, automatically keep the settings to ``.config`` path -+ Add ``keep_config_history`` to control whether keep config info when ``New Project`` -+ Update README.MD - - -Release 0.7.7 (2014-08-30) -++++++++++++++++++++++++++++++++++++ -+ In order to avoid component is not available to CRUD to server because of Sensitive Case, save the component name with lower case into local cache -+ Read custom class from ``Component Attribute Cache`` but not read them from ``Symbol Table Cache`` -+ After input ``Page.``, list all custom visualforce page if have -+ After input ```` - - -Release 0.7.4 (2014-08-17) -++++++++++++++++++++++++++++++++++++ -- Inner Class Completion format -- Add compress header for ``get`` method in api.py -- Fix ``Reload Sobject Cache`` bug caused by release 0.7.3 -- Fix Symbol Table completions bug caused by Legacy Symbol Table Cache - - -Release 0.7.3 (2014-08-16) -++++++++++++++++++++++++++++++++++++ -- Add MIT-LICENSE -- Remove ``quick visualforce`` functionality -- Rename method name ``get_toolingapi_settings`` in context.py to ``get_settings`` and update corresponding invoker -- Add two new commands: ``Reload SymbolTable Cache`` and ``Clear SymolTable Cache`` -- When creating new project, not only download ``Apex Code`` and ``sObject Cache`` but also ``SymbolTable Cache`` -- when class number is more than 400, original symbol table cache structure is stupid and highly reduce the user experience of symbol table completion, in order to speedup symbol table completion, when saving the symbol table cache, store them as the completion format in the cache. - - -Release 0.7.2 (2014-08-15) -++++++++++++++++++++++++++++++++++++ -- Rename ``Toggle Log Panel`` menu item to ``Open Output Panel`` -- Update README.MD -- Add ``Preview Page`` command to preview visualforce page in server, just enabled when opening page -- Update About format - - -Release 0.7.1 (2014-08-12) -++++++++++++++++++++++++++++++++++++ -- Add ``delay_seconds_for_hidden_output_panel_when_succeed`` for control delay seconds to hide output panel when saving succeed -- Rename setting ``delay_seconds_for_hidden_console`` to ``delay_seconds_for_hidden_output_panel_when_failed`` - - -Release 0.7.0 (2014-08-11) -++++++++++++++++++++++++++++++++++++ -- Even if component saving is succeed, show the output panel -- If component saving is succeed, hide the open output panel after 1.5 seconds -- When generating workbook or describe sobject, write the type column with Formula() or - - -Release 0.6.9 (2014-08-09) -++++++++++++++++++++++++++++++++++++ -- When export workbooks, check whether input are valid, if any one is not valid, allow user to input again -- ``Folder Refresh`` reminder message is changed -- Add ``Update Project`` command to just update the apex code but not include sobject metadata -- Add ``Update User Language`` command to update language for running user, which can be used in ``Generate Workbook``, ``Field Completion`` and all related -- Add keymap and commands for ``Update Project`` and ``Update User Language`` -- Add a new setting ``user_language`` for ``Update User Language`` command -- Update the main menu, add ``Update`` main menu -- Add settings for package info, including ``name``, ``version``, ``homepage`` and so on -- Rename ``Help`` in main menu to ``About``, after click this item, not open browser and just display the plugin version info -- Add confirm request for ``update cache`` - - -Release 0.6.8 (2014-08-08) -++++++++++++++++++++++++++++++++++++ -- Add remind message to show output panel - - -Release 0.6.7 (2014-08-06) -++++++++++++++++++++++++++++++++++++ -- Console Message --> OutputPanel Message -- Add a new command ``Open Log Panel`` for display log panel -- Click ``super+``` to open output panel -- Inner class completion - - -Release 0.6.6 (2014-08-05) -++++++++++++++++++++++++++++++++++++ -- Set ``delay_seconds_for_hidden_console`` default value from ``15`` to ``9999`` -- Update description for default settings -- Add property and method completion for inner class - - -Release 0.6.5 (2014-08-03) -++++++++++++++++++++++++++++++++++++ -- Fix picklist completion bug -- Add keymap for ``Execute Rest Test`` command -- Remove catalog from README - - -Release 0.6.4 (2014-07-30) -++++++++++++++++++++++++++++++++++++ -- fix TypeError: save_component() missing 1 required positional argument: 'is_check_only' -- Compatible to api 31 because `compile fail response change `_ - - -Release 0.6.3 (2014-07-30) -++++++++++++++++++++++++++++++++++++ -- Optimize Rest Test when response result is str -- Add ``proxies`` support, just beta - - -Release 0.6.2 (2014-07-29) -++++++++++++++++++++++++++++++++++++ -- Fix issue for ``Delete`` command when list in returned json result is empty - - -Release 0.6.1 (2014-07-22) -++++++++++++++++++++++++++++++++++++ -- **Picklist Value** completion from ``value`` to ``value(label)`` -- **Save Conflict** functionality new format: **Modified by at 2014-05-04 10:03:31, continue?** - - -Release 0.6.0 (2014-07-19) -++++++++++++++++++++++++++++++++++++ -- Add search class and its methods for apex lib -- Fix bug for picklist value completion -- Change ``user`` to ``User`` for issue #31 - - -Release 0.5.9 (2014-07-10) -++++++++++++++++++++++++++++++++++++ -- Remove useless message from message.py -- Add some buld-in emmet supported snippets -- Add command ``quick_visualforce`` for emmet supported snippets -- Add TOC for README - - -Release 0.5.8 (2014-06-13) -++++++++++++++++++++++++++++++++++++ -- Add a new class template ``Test Class`` -- Add description for class template quick choose panel -- ``Clear Cache`` functionality change, display ``project name`` not ``username`` any more -- Add confirm request for ``Run All Test`` - - -Release 0.5.7 (2014-06-05) -++++++++++++++++++++++++++++++++++++ -- Optimize for opening url with browser -- Update OSX Keymap -- Fix bug for ``generate workbook`` in OSX -- Add ``Close Job`` command -- Update README.MD - - -Release 0.5.6 (2014-05-18) -++++++++++++++++++++++++++++++++++++ -- Fix bug for ``SELECT * FROM Sobject``, issue #30 -- Add time stamp for ``save conflict`` confirm message -- Optimize for ``Fetch Debug Log`` -- TraceFlag Bug: Delete the old one and create a new one every time request to create trace flag, issue #29 - - -Release 0.5.5 (2014-05-15) -++++++++++++++++++++++++++++++++++++ -- Add ``*`` support for ``Rest Query``, if ``*`` query, just replace it with all fields of related sobject -- Add doc for Wild-card Character query -- Fix ``Run Test`` bug caused by previous release -- Add ``view_selected_code_coverage`` command to view code coverage by selected class name -- Add mousemap to quick view code coverage - - -Release 0.5.4 (2014-05-15) -++++++++++++++++++++++++++++++++++++ -- Narrow down the code coverage column of test run result -- When run specified test class by main menu, if no test class, show the alert message -- Try to fix issue # 23 - - -Release 0.5.3 (2014-05-12) -++++++++++++++++++++++++++++++++++++ -- Add new snippet ``Sobject - sobject bracket`` -- Update description of ``Update Sobjects``, ``Delete Sobjects`` -- Add two commands for command ``Reload Cache`` and ``Clear Cache`` -- Fix bug for ``Export Workflow`` - - -Release 0.5.2 (2014-05-10) -++++++++++++++++++++++++++++++++++++ -- Since from API 30, compound field (queryByDistance=true) can't be in soql field list -- Fix bug for bulk api caused by release 0.5.1 - - -Release 0.5.1 (2014-05-10) -++++++++++++++++++++++++++++++++++++ -- Fix Bug: ``Export CustomField`` -- Update OSX keymap -- Add ``Export SOQL`` command to export sobject records by specified soql -- Add command for ``Export SOQL`` -- Fix install message alert - - -Release 0.5.0 (2014-05-09) -++++++++++++++++++++++++++++++++++++ -- Update ``README.MD`` -- Fix bug UnicodeError for ``Export Workflows`` and ``Export Validation Rule`` in OSX -- Remove some useless code, for example, ``Export Field Dependency`` - - -Release 0.4.9 (2014-05-04) -++++++++++++++++++++++++++++++++++++ -- Change default setting ``delay_seconds_for_hidden_console`` from ``10`` to ``15`` -- Change default ``api_version`` from ``29`` to ``30`` -- Add command ``Retrieve Sobject And Workflow`` - - -Release 0.4.8 (2014-04-27) -++++++++++++++++++++++++++++++++++++ -- Optimize picklist value completion -- Remove ``.no-sublime-package`` -- Replace ``excluded_sobjects`` settings with ``allowed_sobjects`` settings -- Optimize the sobject cache initiation for OSX -- Upgrade ``requests`` to latest version - - -Release 0.4.7 (2014-04-26) -++++++++++++++++++++++++++++++++++++ -- Fix some flaw for trigger completion -- Optimize Apex Completion -- Update READMD.MD -- Add ``.no-sublime-package`` to tell sublime to unzip the package - - -Release 0.4.6 (2014-04-21) -++++++++++++++++++++++++++++++++++++ -- Add ``last_n_logs`` setting to control the return number by fetching logs -- Add ``check_save_conflict`` setting to control saving conflict when LastModifiedBy is not running user - - -Release 0.4.5 (2014-04-20) -++++++++++++++++++++++++++++++++++++ -- Update snippet: ``Exception - try catch finally`` and ``Exception - try catch`` -- Add doc for api.py -- Originally, Keyword completion will exclude the existing-variable completion, now, bug mei le. -- Bug: ``Execute Anonymous`` apex string contains non-english character -- Combine ApexCompletion and SobjectCompletion -- If save error happened, the error line will be highlighted and the highlight line will be canceled after ``delay_seconds_for_hidden_console`` seconds - - -Release 0.4.4 (2014-04-17) -++++++++++++++++++++++++++++++++++++ -- Optimize SOQL Field completion -- Update build-in apex lib -- Update ``query_all`` rest api from ``query`` to ``queryAll`` which is available since winter 14 -- Add ``disable_soql_field_completion`` setting for controlling soql field completion -- In order to keep high efficient for code completion, add some not common used standard sobjects to ``Excluded_Sobjects`` setting for code completion - - -Release 0.4.3 (2014-04-16) -++++++++++++++++++++++++++++++++++++ -- Add ``Search`` and ``Quick Search`` for ``Execute Rest Test`` -- Update ``README.MD`` -- When view is activated, display the default project in the sidebar - - -Release 0.4.2 (2014-04-16) (Millstone for fixing some flaw in completion) -++++++++++++++++++++++++++++++++++++ -- Change ``display_field_name_and_label`` setting default value to false -- BUG: Find variable type by variable name in view (Ignore comment code) -- BUG: Find matched block in visualforce page (the matched region must contains current cursor point) -- Add SOQL field completion, it's very useful feature -- Add a new snippet for ``SELECT * FROM Account``, which is useful for corporation with SOQL field completion - - -Release 0.4.1 (2014-04-14) -++++++++++++++++++++++++++++++++++++ -- Update ``Visualforce`` xPath and Document source code -- Change ``api_version`` back to 29 -- Change the default test org password to updated one - - -Release 0.4.0 (2014-04-14) -++++++++++++++++++++++++++++++++++++ -- ``Track Trace Flag`` expiration date verify logic change -- Return all sobjects when call ``Global Describe`` method in api.py, originally default return value is createable and queryable sobjects - - -Release 0.3.9 (2014-04-12) -++++++++++++++++++++++++++++++++++++ - -- Update project folder structure, you can change it to original strcture by remove the ``src/`` from every component attribute -- If visualforce component attribute type is ``Object`` in visualforce completion, return ```_ - - -Release 0.3.6 (2014-03-30) -++++++++++++++++++++++++++++++++++++ - -- Add thread progress for document reloading -- Add confirm request for document reloading -- Add default ``docs`` setting for `user customization `_ - - -Release 0.3.5 (2014-03-29) -++++++++++++++++++++++++++++++++++++ - -- Clarify Usage of kinds of feature in README.MD - - -Release 0.3.4 (2014-03-26) -++++++++++++++++++++++++++++++++++++ - -- Fix urgent bug for `Issue #22 `_ - - -Release 0.3.3 (2014-03-22) -++++++++++++++++++++++++++++++++++++ - -- Add confirmation request for ``Refresh Component`` -- Add a new command for ``Compile Component`` -- Update README - - -Release 0.3.2 (2014-03-22) -++++++++++++++++++++++++++++++++++++ - -- Upgrade ``xmltodict`` lib to latest -- Add ``namespace`` for standard class in the completion - - -**Release 0.3.1** (Milestone of Code Completion) (2014-03-22) -++++++++++++++++++++++++++++++++++++ - -- Fix bug: ``KeyError: 'symbol_table'`` when save component is not ``ApexClass`` -- Add some new standard class to completion -- Keep the parameter info in the completion result -- Update README.MD - - -Release 0.3.0 (2014-03-20) -++++++++++++++++++++++++++++++++++++ - -- Remove the duplicate ``New Component`` command and add ``New ApexPage`` command in the quick command palette -- Update the apex standard class lib -- Add SymbolTable support for completions (Completion Parser is copy from Mavensmate) - - -Release 0.2.9 (2014-03-20) -++++++++++++++++++++++++++++++++++++ - -- Move the fields describe part from the bottom to top in the sobject describe result -- Change the default apex log level from ``Finest`` to ``Debug`` -- Fix a completion regular expression bug for sobject and class which is start with ``j`` or ``J`` -- When create new component, if there just have only one template, just choose the only one and no need to manually choose it. - - -Release 0.2.8 (2014-03-19) -++++++++++++++++++++++++++++++++++++ - -- Add ``Tooling Query`` for ``Rest Explorer`` -- Add ``SOQL & SOSL`` for Salesforce Document Reference -- Change ``ListDebugLogs`` and ``CreateDebugLog`` commands to ``FetchDebugLog`` and ``TrackDebugLog`` -- Remove shortcuts for four new commands - - -Release 0.2.7 (2014-03-17) -++++++++++++++++++++++++++++++++++++ - -- Update the tabTrigger from muti-bytes to less than 5-bytes for all snippets - - -Release 0.2.6 (2014-03-16) -++++++++++++++++++++++++++++++++++++ - -- Fix the bug of ``Rest Post`` -- Remove ``Request``, ``Application``, ``LogLength``, ``DurationMilliseconds`` from ``List Debug Log`` columns -- Update description for ``display_field_name_and_label`` settings -- Fix bug: saving conflict on the same component - - -Release 0.2.5 (2014-03-15) -++++++++++++++++++++++++++++++++++++ - -- Remove the command ``New Component`` from the side bar -- Remove four shortcut keys for the four new component -- Add a new command for ``Update Project`` -- Update the menu item and shortcuts for ``New Project`` -- Optimize ``Quick Goto`` functionality, just choosing code name will work. - - -Release 0.2.4 (2014-03-11) -++++++++++++++++++++++++++++++++++++ - -- Update README.MD -- Remove shortcut key ``Ctrl+Alt+N`` for creating new component -- Add new shortcut keys for separated four new component commands - - -Release 0.2.3 (2014-03-10) -++++++++++++++++++++++++++++++++++++ - -- Add ``Console Toolkit``, ``Standard Objects``, ``Data Model`` and ``Tooling APi`` references to document list -- Update Main Menu Item -- Open ``View Debug Log Detail`` context menu item -- Add a new command ``Update Project``, you can invoke this command by press ``Alt+f7`` -- Add sublime commands for new commands -- Add time stamp to succeed message for ``Create Code`` and ``Delete Code`` -- Update README.MD for ``Update Project`` - - -Release 0.2.2 (2014-03-07) -++++++++++++++++++++++++++++++++++++ - -- Remove some useless print statement in the document.py -- Update README.MD for latest release - - -Release 0.2.1 (2014-03-07) -++++++++++++++++++++++++++++++++++++ - -- Add ``Rest Api``, ``Visualforce``, ``Chatter Api``, ``Streaming Api`` and ``Bulk Api`` to document list -- Add methods redirect to document list - - -Release 0.2.0 (2014-03-07) -++++++++++++++++++++++++++++++++++++ - -- Change ``default_browser_path`` setting name to ``default_chrome_path`` -- Add a new salesforce reference function from `Salesforce Reference `_ -- Add a new snippet ``Custom Button - Disable Button`` - - -Release 0.1.9 (2014-03-06) -++++++++++++++++++++++++++++++++++++ -- Fix the static resource bug ``Can't convert 'dict' object to str implicitly`` -- When creating trigger, just list the triggerable sobject -- If project is not created, ``New Component`` and ``Refresh Folder`` are disabled -- Update snippets(``Debug - schedule test`` and ``Debug - debug variable``) - - -Pre-release 0.1.8 (2014-03-05) -++++++++++++++++++++++++++++++++++++ - -- When save component and error happened, ``go to`` the error line -- Change the ``new component`` to separate ones -- When creating ``trigger``, we just need to choose sobject and input the trigger name -- When creating ``class``, ``component`` or ``page``, we need to choose template and input the name -- Change the ``Component Template`` -- Change the ``Main Menu`` and ``Sidebar Menu`` -- Move ``Refresh Folder`` function to ``Side Bar`` menu -- When ``New Project``, we need to choose the project, and then create project - - -Release 0.1.7 (2014-03-04) -++++++++++++++++++++++++++++++++++++ - -- If project is not created, ``New Component`` and ``Refresh Folder`` are disabled -- Allow empty json body for ``Post`` Action -- If rest response is list, return the list -- When switching project, stop checking login if login session is already in cache -- Fix a completion bug on ``__kav`` - - -Release 0.1.6 (2014-03-01) -++++++++++++++++++++++++++++++++++++ - -- Update README.MD -- Refractoring api.py - - -Release 0.1.5 (2014-02-28) -++++++++++++++++++++++++++++++++++++ - -- Change new view event type from ``on_new_sync`` to ``on_new`` -- Set the default format for rest test result to ``JavaScript`` -- Add ``Query`` and ``Query All`` function for ``Rest Explorer`` - - -Release 0.1.4 (2014-02-26) -++++++++++++++++++++++++++++++++++++ - -- Update comments for ``toolingapi.sublime-settings`` -- Fix the bug for ``open console`` - - -Release 0.1.3 (2014-02-24) -++++++++++++++++++++++++++++++++++++ - -- Add the support the static resource refresh functionality for the side bar menu -- Add the support the static resource refresh functionality for the context menu -- Add ``Patch`` method for ``Rest Explorer`` - -Release 0.1.2 (2014-02-22) -++++++++++++++++++++++++++++++++++++ - -- Add a new setting ``default_chrome_path`` -- Optimize the ``Rest Explorer`` functionality -- When execute ``Rest Explorer``, if input json body is not valid, allow trying again. - - -Release 0.1.1 (2014-02-22) -++++++++++++++++++++++++++++++++++++ - -- Add snippets for console toolkit -- Add time stamp for success message of save component result -- Remove some useless message from message.py -- Enhancement for `Issue #12 `_ - - -Release 0.1.0 (2014-02-20) -++++++++++++++++++++++++++++++++++++ - -- Add snippets for console toolkit -- Update README -- When menu item is not enabled, show the message in the status bar - - -Release 0.0.9 (2014-02-19) -++++++++++++++++++++++++++++++++++++ - -- Update the snippets for debug -- Add a new snippet "ReRender Form in JavaScript" -- Display the exception when delete MetadataContainerId, ie., unable to obtain exclusive access to this record -- When creating trigger by template, automatically remove the space input by user -- Change the create component input guide - - -Patch for 0.0.8 (2014-02-12) -++++++++++++++++++++++++++++++++++++ - -- Add two template for new component command: Controller and Utility Class -- Add two snippets - - -Patch for 0.0.7 (2014-02-12) -++++++++++++++++++++++++++++++++++++ - -- Fix bug for `Issue #11 `_ - - -Release 0.0.7 (2014-02-08) -++++++++++++++++++++++++++++++++++++ - -- Fix problem when execute anonymous return error -- Change ``disable_keyword_completion`` from true to false - - -Release 0.0.6 (2014-02-08) -++++++++++++++++++++++++++++++++++++ - -- Fix retrieve metadata exception - - -Patch for 0.0.5 (2014-01-31) -++++++++++++++++++++++++++++++++++++ - -- Update README.MD - - -0.0.5 (2014-01-22) -++++++++++++++++++++++++++++++++++++ - -- Add Run All Test functionality -- Adjust the format of test run result of single test class -- Update README.MD - - -0.0.4 (2014-01-21) -++++++++++++++++++++++++++++++++++++ - -- Remove ``Widget.sublime-settings`` from plugin - - -0.0.3 (2014-01-20) -++++++++++++++++++++++++++++++++++++ - -- Add time stamp for all error message displayed in console -- Disable deploy metadata command -- When use bulk CUD, If clipboard content is file, just paste it into file path input panel -- Remove the ``(0)`` from ``Datetime(0)`` and ``Date(0)`` completion for Date and Datetime field - - -Patch 0.0.2 (2014-01-11) -++++++++++++++++++++++++++++++++++++ - -- Change the default test project - - -0.0.2 (2014-01-07) -++++++++++++++++++++++++++++++++++++ - -- Remove ``debug_log_headers`` and ``debug_log_headers_properties`` settings -- Unquote and unescape the error message returned by ``Save to Server`` -- If ``testMethod`` or ``@IsTest`` is in class body, run test command should be enabled - - -Patch for 0.0.1 (2014-01-06) -++++++++++++++++++++++++++++++++++++ - -- When creating new component, if user input is not valid, user can try again if need -- Bug: if project is not created, just create the project for the new component -- Bug: 'BulkApi' object has no attribute 'monitor_batchs' -- Remove ``Widget`` settings and ``Setting - Console`` main menu -- Roll back save_component function to last version - - -0.0.1 (2014-01-05) -++++++++++++++++++++++++++++++++++++ - -- Remove ``Loop - for.sublime-snippet`` snippet -- Remove ``all_views_completions.py`` dependency lib -- Move ``commands``, ``keymap``, ``menus``, ``mousemap``, ``settings`` and ``snippet`` path to new config folder - - -Pre-release x.x.x (2013-12-06 -> 2013-12-31) -++++++++++++++++++++++++++++++++++++++++++++ - -- There is a long confusing term on github version control -- Add picklist value completions feature -- Export Sobject Data Template by Record Type -- Refactoring sobject completion for those complicated orgs -- Add four settings to permit user to close the code completion feature -- Disable keyword completion by default, need enable manually -- Change default workspace to ``C:/ForcedotcomWorkspace`` -- Add support for log levels of anonymous code -- Add a new setting for disabling field name and label completion -- Fix bug for completion: variable in method parameter -- Add picklist value completion support for ``sObject.PicklistFrield =`` -- Allow us to input file path when using Bulk Api to CRUD on data -- Automatically detect BOM header when CRUD on data -- After CRUD on csv data, put the log at the same path of this csv data -- Refactoring code completion for sobject field, relationship and picklist value -- Add command for reloading cache of sobjects -- Refactoring sobject field cache structure for speeding up field completion -- [Fix bulk api issue](https://github.com/kennethreitz/requests/issues/1833) -- Add command for clearing cache of sobjects -- Rearrange main menu items -- Automatically divide upload record by 10K every batch -- Add two settings for bulk load: ``maximum_batch_size`` and ``maximum_batch_bytes`` -- Support data upload for ``ANSI`` and ``UTF-8`` with or without BOM - - -0.0.0 (2013-04-14) -++++++++++++++++++++++++++++++++++++ - -* Birth! - -* Frustration -* Conception +.. :changelog: + +Release History +----------------- + + +Release 3.5.8 (2020-03-28) +++++++++++++++++++++++++++++++++++++ + +* Refined Code coverage functionality: + - View code coverage for certain Apex class/trigger file via context menu + - View code coverage from (async) Test Result via context menu +* Miscellaneous bug fix and update + + +Release 3.5.7 (2020-03-26) +++++++++++++++++++++++++++++++++++++ + +* Refine Creating Lightning Web Component (``lwc``) process +* Add Retrieving, Destructing, Deploying lwc from both sidebar and context menu +* Add Creating CSS style, SVG file for lwc in context menu +* Fix auto completion for aura component bug +* Fix issue #198 + + +Release 3.5.4 (2019-07-31) +++++++++++++++++++++++++++++++++++++ +* Add component tag attr desc completion when hover on attr +* Add user interface api doc reference toc +* lwc supports label, staticresource, custom object and fields import +* Enhancement for lwc boolean attr completion +* Fix bug for meta file deployment + + +Release 3.5.4 (2018-02-12) +++++++++++++++++++++++++++++++++++++ +* Fix issue #172 +* Fix issue #173 + + +Release 3.5.3 (2018-02-06) +++++++++++++++++++++++++++++++++++++ +* Add missing base components from lightning developer guide by script: https://gist.github.com/xjsender/265d237fbeafebabff6c8669f9359fff#file-read-json-from-lightning-compnent-js +* Add $A.localizationService lib +* Fix some minor bugs + + +Release 3.5.2 (2018-02-03) +++++++++++++++++++++++++++++++++++++ +* Support oAuth2 Login, check https://github.com/xjsender/haoide#project-configuration for guide +* Add Lightning event methods completion +* Add customlabel and staticresource completions for lightning component +* Add lightning component iconName support +* Add package.zip to file_exclude_patterns +* Add attributes completion after v. +* Update apex lib to v41 +* Deliver enhancement for issue #145 +* Fix custom label completion bug in Lightning mode +* Fix bug for open_aura_document_reference command +* Fix bug #147 + + +Release 3.5.1 (2018-01-25) +++++++++++++++++++++++++++++++++++++ +* Basic completion support for component controller or helper + + +Release 3.5.0 (2018-01-21) +++++++++++++++++++++++++++++++++++++ +* Add aura component and attribute completion, contributed by @lushang +* Add some missed base component +* Add lightning component implements completion +* Add Queueable Apex Template +* Add SLDS classes completion +* Add some console snippets +* Add sObject completion when attribute support sObjects, such as type for aura:attribute +* Update export format for ``Export Profile`` command +* Fix some bugs, such as, aura app preview, custom label completion, etc. + + +Release 3.4.7 (2017-07-29) +++++++++++++++++++++++++++++++++++++ +* Really and still busy on project delivery work in the past year, will continue in the next days. +* New Fetaure: Combine package.xml in selected folders +* New Feature: Custom Label completion support, which is fetched from ``project/.config/package.json`` by ``Reload Project Cache`` command +* Update Aura completion lib by ``lushang`` +* Others + + +Release 3.4.6 (2016-09-26) +++++++++++++++++++++++++++++++++++++ +* Deliver enhancement for issue #132 +* Deliver enhancement for issue #134 +* Deliver enhancement for issue #140 +* Fix issue #138 + + +Release 3.4.5 (2016-06-16) +++++++++++++++++++++++++++++++++++++ +* Fix bug: sublime will be closed when view debug log by logId with pressing alt + dblclick left mouse +* Fix issue #126 +* Deliver feature #119 +* Add a new setting ``force_login_interval`` for controlling login cache refresh interval + + +Release 3.4.4 (2016-06-11) +++++++++++++++++++++++++++++++++++++ +* Fix Urgent ``FileNotFoundError`` problem when create new code + + +Release 3.4.3 (2016-06-06) +++++++++++++++++++++++++++++++++++++ +* Hide ``execute query`` command in the context menu, use ``REST TEST Query`` instead +* Rename Snippet ``HttpRequest - Authorization Basic Credentials.sublime-snippet`` to ``HttpRequest - Callout.sublime-snippet`` +* Add new snippet named ``Page - loading action status.sublime-snippet`` +* Add visibility control for ``Extract To Here`` in the sidebar menu +* Fix bug for custom components completion +* Fix bug for variable type fetching for code completion +* Fix issue #117 + + +Release 3.4.2 (2016-05-23) +++++++++++++++++++++++++++++++++++++ +* Change api version back to 35, fix issue #116 + + +Release 3.4.1 (2016-05-23) +++++++++++++++++++++++++++++++++++++ +* Fix issue #113 +* Fix issue #115 +* Fix Bug for conflict checking bug caused by solution for issue #108 +* Fix Bug for ``fetch debug log`` +* Execute ``fetch_debug_log`` operation after ``run sync test`` + + +Release 3.4.0 (2016-05-20) +++++++++++++++++++++++++++++++++++++ +- Deliver enhancement for issue #108 +- Deliver enhancement for issue #111 +- Fix bug when test class failed caused by dependency compilation +- Fix bug when view debug log detail +- Fix bug when read csv encoding +- Fix bug When create first new code that will clear the cache of others +- Fix bug When deploy files, default project is not switched back +- Remove duplicate command ``Reload Sobject Cache`` from command palette +- Remove snippet ``Class Body - class comments`` +- Add new snippet: ``Page - close window and refresh opener`` +- Add keymap for ``Open All Documents``, check the keymap setting for detail +- Add new command ``copy_files_to_project`` for issue #113 +- Update snippet: ``Debug - debug info``, ``Debug - debug error``, ``Class Header - class header`` +- Update include_users_in_role_hierarchy to false on default +- Update ``folder_exclude_patterns`` pattern to exclude ``.templates`` folder in the sidebar + + +Release 3.3.9 (2016-04-18) +++++++++++++++++++++++++++++++++++++ +* Force login every two hours +* Add retry operation for list package if session is expired +* Change display format for REST TEST Response, add a new setting ``remove_slash_for_rest_response`` +* Fix bug for aura creation +* Add AuraEnabled template class +* Add a snippet for class comments header +* Add a snippet for LoggingLevel.ERROR debug +* Update a snippet for LoggingLevel.INFO debug + + +Release 3.3.8 (2016-04-12) +++++++++++++++++++++++++++++++++++++ +* Enhancement for code template, welcome new template pull request +* Add runSpecifiedTest support for deploying files +* Change mousemap key mapping, see more detail at Q&A +* Update Q&A in the pulgin home page + + +Release 3.3.7 (2016-03-28) +++++++++++++++++++++++++++++++++++++ +* Fix issue #88 +* Fix issue #99, problem of ``reload document`` +* Deliver enhancement for issue #96 +* Open exported CSV file when execute ``Export CustomField`` command + + +Release 3.3.6 (2016-03-28) +++++++++++++++++++++++++++++++++++++ +* Fix issue #98 +* Add ``Return to First Step`` feature when open documentation by type +* Remove build-in reference settings which is replaced ``Reload Salesforce Document`` +* Enhancement for ``Open Documentation`` feature +* Enhancement for ``Reload Project Cache`` feature + + +Release 3.3.5 (2016-03-26) +++++++++++++++++++++++++++++++++++++ +* Greatly improve performance of code completion +* Fix invalid scope problem for custom class completion +* Enhancement for document reference +* Change panel message format + + +Release 3.3.4 (2016-03-23) +++++++++++++++++++++++++++++++++++++ +* Fix issue #93 +* Fix issue #97 +* Optimize for methods in ``metadata.py`` +* Update README.md + + +Release 3.3.3 (2016-03-14) +++++++++++++++++++++++++++++++++++++ +* Fix issue #94 +* Enhance ``refresh package`` command +* Add package.xml update support for command ``build_package_xml`` + + +Release 3.3.2 (2016-03-12) +++++++++++++++++++++++++++++++++++++ +* Fix issue #92 + + +Release 3.3.1 (2016-03-11) +++++++++++++++++++++++++++++++++++++ +* Rename ``deploy_package_to_server`` command to ``deploy_package`` +* Add new command ``refresh_package``, see issue #91 for detail +* Add LastModifiedBy check for conflict check logic, see issue #89 +* Remove setting ``ignore_project_package_xml`` and related logic + + +Release 3.3.0 (2016-03-11) +++++++++++++++++++++++++++++++++++++ +* Deliver enhancement #91 +* Fix bug issue #92 +* Fix package.xml onload XML parse exception + + +Release 3.2.9 (2016-03-10) +++++++++++++++++++++++++++++++++++++ +* Enhancement for ``role hierarchy exporting`` +* Add new settings ``include_users_in_role_hierarchy`` to control whether including user in the CSV +* Deliver new feature, see issue #89 +* upgrade build-in requests lib to 2.9.1 +* change display message for list metadata in the output panel + + +Release 3.2.8 (2016-02-26) +++++++++++++++++++++++++++++++++++++ +* Fix issue #88 +* Fix bug for ``export workflow rules`` feature +* Add parameter ``vertical`` for ``export_data_template`` command for exporting Layout Workbook +* Add a command for copying login url, which can be used for login with different browser +* Update version and copyright information + + +Release 3.2.7 (2015-12-21) +++++++++++++++++++++++++++++++++++++ +* Fix issue #86 + + +Release 3.2.6 (2015-12-20) +++++++++++++++++++++++++++++++++++++ +* Fix issue #84 +* Fix issue #85 +* New ``Export > Export Role Hierarchy`` command + + +Release 3.2.5 (2015-12-15) +++++++++++++++++++++++++++++++++++++ +* Fix urgent bug issue #83 +* Fix urgent bug for sobject cache reloading +* Remove ``allowed_sobjects`` setting + + +Release 3.2.4 (2015-12-09) +++++++++++++++++++++++++++++++++++++ +* Enhancement for lightning development +* Add new command for creating ``SVG`` and ``design`` +* Update lightning related library +* Change default ``api_version`` from ``34`` to ``35`` + + +Release 3.2.3 (2015-12-01) +++++++++++++++++++++++++++++++++++++ +* Bug Fix: + Fix bug for lightning development when deploying cmp or app + +* Enhancement: + - Display the lightning type in the input panel when creating lightning components + - Change ``No change`` to ``no difference`` in non-difference message when executing ``diff_with_server`` command + +* Update: + - Remove four commands ``create_lightning_application``, ``create_lightning_component``, ``create_lightning_interface``, ``create_lightning_event``, bind the four features to ``create_lightning_definition`` by difference ``_type`` + - Optimize completion for Boolean attribute in the html related page + - Stop keeping useless ``settings.json`` to ``.config`` folder + + +Release 3.2.2 (2015-11-19) +++++++++++++++++++++++++++++++++++++ +* Bug Fix: + - Fix TypeError when export soql to csv + - Fix aura app preview problem + - Fix bug for missing standard Objects when retrieve all + - Fix bug for `deploy selected open files` fetaure + - Fix instance parse problem for lightning app preview + - Fix bug of aura helperjs or controoler deploy + +* New Feature: + - Add new command to open aura document reference in the command palette + +* Enhancement: + - Improve output message of debug mode + - Update README.MD + + +Release 3.2.1 (2015-11-10) +++++++++++++++++++++++++++++++++++++ +* Fix issue #81 + + +Release 3.2.0 (2015-10-07) +++++++++++++++++++++++++++++++++++++ +* Deliver enhancement #73 +* Deliver enhancement #77 + + +Release 3.1.9 (2015-08-26) +++++++++++++++++++++++++++++++++++++ +* Fix issue #71, export workbooks by user input +* Fix bug for visibility problem of ``Retrieve Package.xml`` +* Add bootstrap3 support for styleClass attribute of salesforce standard components + + +Release 3.1.8 (2015-08-08) +++++++++++++++++++++++++++++++++++++ +* Bug Fix: + - Fix bug for bootstrap3 completion + - Fix bug for ``toggle_metadata_objects`` command if project is not initiated + - Fix bug for ``SOQL - SELECT FROM.sublime.snippet`` in windows + +* Enhancement: + - Add confirm request for ``retrieve files from server`` and ``retrieve files from this server`` + - Add confirm request for ``destruct package.xml from server`` and ``retrieve files from this server`` + - Identify ``this file`` or ``these files`` in confirm request message according to number of chosen files + +* Update: + - Add project name and remove [LOG] or [ERROR] notation in log or error panel + - Rename ``destruct package.xml`` command to ``destruct package.xml from server`` + - Rename ``retrieve package.xml`` command to ``retrieve package.xml from server`` + - Update ``to`` or ``from`` in context menu item name to ``To`` or ``From`` + - Update confirm request message for ``destruct files from server`` + +* New: + - Add a new command ``Enable Development Mode`` to quickly enable visualforce page development mode + - Add bootstrap3 completion document + + +Release 3.1.7 (2015-08-05) +++++++++++++++++++++++++++++++++++++ +* Enhancement: + - Add `with sharing` for `Utility Class` in template + - When you want to view code coverage, if you didn't download code, you can't view code coverage and you will get the reminder message in the status bar + - Before v33.0, tooling API doesn't support relationship query just like ``ApexClass.LastModifiedBy.Name``, when you save code to server, plugin will check your code has conflict with server and tell you ``who change the code at when?``, because relationship query is not supported, plugin will need to issue a query request to fetch the LastModifiedBy Name by the LastModifiedById, from this version, it will not necessary. + - Add comments for some settings + - Move metadata.json from ``metadata.sublime-settings`` to ``.config/metadata.json``, when you create new project, if the ``metadata.json`` is exist in the ``.config`` path, plugin will skip the describe process, however, if you want to refresh the cache, you can execute ``Metadata > Describe Metadata`` to refresh the ``metadata.json`` cache file + +* Bug Fix: + - After you select all test class, you can't deselect all when you run tests + - Problem when ``diff with other server``, see detail in issue #61 + +* New Feature: + - Add a new command named ``destruct_package_xml`` in the context menu, which is used for destructing members defined in ``package.xml`` from current server, so if you want to remove some components from production, you can get the package.xml by ``Metadata > Build Package.xml``, and then execute ``destruct_package_xml`` to remove them from production + +* Update: + - Update keymap of ``retrieve from this server`` from ``super+shift+r`` to ``alt+shift+r``, fix issue #68 + - Update keymap of ``deploy to this server`` from ``super+shift+s`` to ``alt+shift+s`` + + +Release 3.1.6 (2015-07-29) +++++++++++++++++++++++++++++++++++++ +* Bug fix: + - If controller name is same with page name, there will have problem when view code coverage + - Fix bug when file is loaded + - Fix issue #62 + - Fix issue #63 + +* Enhancement: + - Deliver enhancement #64 + - Deliver enhancement #65 + - Deliver enhancement #66 + + +Release 3.1.5 (2015-07-27) +++++++++++++++++++++++++++++++++++++ +* New Feature: + - Add bootstrap3 support for html class completion + - Add a new setting ``disable_bootstrap_completion`` to control bootstrap completion + +* Update: + - Remove ``Metadata > Describe Metadata`` menu item in the main menu + +* Fix Bug: + - Fix bug for running sync test for class with namespace or not + - Fix bug for ``get_file_attributes`` method + + +Release 3.1.4 (2015-07-25) +++++++++++++++++++++++++++++++++++++ +* Bug Fix: + - Fix issue #23? + - Fix issue #58 + - Fix issue #59 + +* Enhancement: + - Add filters support for ``Build Package.xml`` command, which is used to filter members which contains the input filters + - Add update feature for ``Build Package.xml`` command, which is used to add or remove members from exist package.xml + - Add keymap for some frequently-used commands + - Add visibility control for some CURD command on code file + - Aura related features + - Merge ``Deploy Lightning To Server`` command with ``Deploy File to Server`` command + - Merge ``Retrieve Lightning To Server`` command with ``Retrieve File to Server`` command + - Use file full name as key in ``component_metadata.sublime-settings``, originally, we use name as key, for example, originally, ``AccountController`` is key, now is ``AccountController.cls`` + - Change ``Diff With Server`` command to just visible when code file is ``classes, triggers, components or pages`` + +* New Feature: + - New ``Run Sync Test`` command for replacing ``Run Test`` feature + - Read code coverage information from local cache kept by ``Run Sync Test`` command + - New ``Retrieve from This Server`` command in the context menu + - New ``Diff With This Server`` command in the context menu + - New ``View File Attributes`` command in the context menu + +* Update: + - ``Quick Goto`` is switched to standard sublime build-in, I changed the mousemap to bind with the standard feature , with this feature, you can quickly view the symbols in sublime, for example, when you see a statement like this ``AccountUtil.populateField()``, you can put focus in the method name, hold down ``shift`` and triple-click your left mouse, sublime will open the ``AccountUtil`` class and put focus in the selected method + + +Release 3.1.3 (2015-07-18) +++++++++++++++++++++++++++++++++++++ +* Fix issue #54 +* Fix issue #56 + + +Release 3.1.2 (2015-07-17) +++++++++++++++++++++++++++++++++++++ +* Fix issue #55 + + +Release 3.1.1 (2015-07-16) +++++++++++++++++++++++++++++++++++++ +* Bug fix: + - Fix a issue for ``save_to_server`` command when ``api_version`` is less than 29 + - Fix problem in ``Class Body - test data util body-sublime-snippet.sublime-snippet`` + +* Enhancement: + - Enhancement for issue #53 + - Enhancement for issue #54 + - Support deploy and retrieve for metadataObject which is in folder + - Add support for visualforce email template development + - Add select all feature for ``toggle_metadata_objects`` command + - Add ``Territory2`` to ``allowed_sobjects`` list + +* Update: + - Remove ``disable_visualforce_completion`` setting + - Add four settings to disable part of completion in visualforce page, see more in ``docs/completion.md`` + + +Release 3.1.0 (2015-07-09) +++++++++++++++++++++++++++++++++++++ +* Enhancement: + - Sometimes, the inner class name is same with standard class or sObject, if this inner class is matched, ignore the standard completion + - Add Notation [EU] for external or unique field in field completion, ``E`` means External, ``U`` means Unique + - Add a new setting named ``disable_visualforce_completion`` to control visualforce completion + +* Bug Fix: + - Fix issue #49 + - Fix issue #50 + - Catch exception for ``check retrieve status`` request when retrieve + +* New + - Add a new snippet ``Bracket - sobject parenthesis.sublime-snippet``, see ``/docs/snippets.md`` for more detail + +* Update + - Change default ``api_version`` from 33 to 34 + - Move document for ``execute anonymous`` from ``project.md`` to ``debug.md`` + + +Release 3.0.9 (2015-07-01) +++++++++++++++++++++++++++++++++++++ +* Bug Fix: + - Fix bug for snippet ``SOQL - SELECT * FROM.sublime-snippet`` + - Fix bug for ``extract_to_here`` command + +* Enhancement: + - Don't need confirmation to reload project cache after choose metadata objects + - In order to avoid timeout exception, increase max_retries from 5 to 10 for retrieve zipFile request + + +Release 3.0.8 (2015-06-28) +++++++++++++++++++++++++++++++++++++ +* Bug Fix: + - Fix bug when build package.xml for whole org + +* Enhancement: + - Display chosen sObject Name when input trigger name + - Enhancement for #39, open a new view, set status bar and close the new view + - Add success message for ``extract_to_here`` command + - Update all snippets + +* New: + - Add a quick link to view all snippets, see it in plugin home page + - Add command to access all snippets in ``Utilities`` of main menu + + +Release 3.0.7 (2015-06-26) +++++++++++++++++++++++++++++++++++++ +* Bug Fix: + - Fix issue #46 + - Fix bugs caused by ``describe_global`` change in the ``tooling.py`` + +* Enhancement + - Merge pull request #45 by @reyesml(https://github.com/reyesml) + +* New + - Add a snippets: ``Page Variable - get and set in one line.sublime-snippet`` + - Add a snippets: ``Page Variable - get and set in multiply line.sublime-snippet`` + - Add a new command for building package.xml for whole org + + +Release 3.0.6 (2015-06-23) +++++++++++++++++++++++++++++++++++++ +* Bug Fix: + - Merge pull request #42 by @pgAdmin(https://github.com/pgAdmin) + - Merge pull request #43 by @reyesml(https://github.com/reyesml), fixed issue #6 + - Fix bug for ``export_workbook`` feature + + +Release 3.0.5 (2015-06-15) +++++++++++++++++++++++++++++++++++++ +* Bug Fix: + - Custom component attributes completion bug when component file is not exist in the target path + +* Enhancement: + - Improve regular expression for SOQL fields completion + + +Release 3.0.4 (2015-06-15) +++++++++++++++++++++++++++++++++++++ +* Bug Fix: + - Fix bug for issue #41 + - Fix bug for ``delete_file_from_server`` keybinding for windows + - Fix bug for ``auto_update_on_save`` feature in windows + - Fix ``KeyError: '\n\n'`` for converting complex JSON to Apex + +* Enhancement: + - Improve the regular expression for SOQL fields completion + - Improve the regular expression for Apex class method completion + - Improve the regular expression for visualforce component attribute completion + - Improve the visualforce tag name completion, add ``>`` for tag name automatically + - As the original design, you need to input your JSON when you execute JSON related commands, since this version, you just need to open any JSON file or select valid JSON content + - Add ``JSON/XML Tool`` into context menu, which is same with ``Utilities`` in main menu + - Update content for some docs + +* New Feature: + - Add attribute completion for custom component + - Add document for all code completion, you can see the link in the plugin home page + + +Release 3.0.3 (2015-06-11) +++++++++++++++++++++++++++++++++++++ +* Bug Fix: + - Fix duplicate save check bug caused by release 3.0.2 + - Fix fields completion bug for cross sObjects between tooling and non-tooling, for example ``User``, ``RecordType`` + +* Enhancement: + - Add session expired message for ``describe_metadata`` + - Enhancement for ``refresh_file_from_server`` + +* Update + - Update pop-up compile message for ``save_to_server`` command + + +Release 3.0.2 (2015-06-07) +++++++++++++++++++++++++++++++++++++ +* Bug fix: + - Fix NoneType exception in the console when open context menu, this is caused by release 3.0.1 + - Fix bug for ``Debug > Track All Debug Logs`` in the main menu + +* Enhancement + - Duplicate save_to_server check logic change: use file name with extension but not only file name, as the original design, if the controller name is same with page name, if you are saving page, you can't save the related controller at the same time + - Add timeout for query of conflict checking when ``save_to_server`` + - Prevent duplicate save conflict check when ``save_to_server``, as the original design, if you latest saving is interrupted, when you save it again, plugin will delete the metadata container Id for the saving file, at this time, save conflict checking will be executed again. + +* New: + - Add sObject completion for ``tooling sObjects``, for example, ``Validation Rule``, ``WorkflowRule``, ``ValidationRule``, ``WorkflowFieldUpdate``, ``WorkflowOutboundMessage``, ``WorkflowAlert`` or ``WorkflowTask`` + - Add * support for ``export query to CSV`` or ``export tooling query to CSV``, if you use * in the query statement, plugin will get all fields of this object and set them as the column headers + - Add export command for tooling query into the ``Data Loader`` in the main menu, you can use this command to export records for tooling objects + - Add a new markdown document related to debug + - Add a menu item for quick accessing document related to debug + +* Update: + - Update the menu item names and location in command palette and the ``Debug`` of main menu + - Change the default key binding for ``Debug > Run Test`` in the main menu + + +Release 3.0.1 (2015-06-04) +++++++++++++++++++++++++++++++++++++ +* Bug fix: + - Fix bug #39 + - Fix bug #40 + - Fix bug for SOQL completion + +* Enhancement: + - Enhancement for boolean attribute completion of standard visualforce component + - Set ``word_wrap`` setting of new view to false when describe sObject + - Keep attributes of all metadataObjects to local ``component_metadata.sublime-settings`` + - Prevent potential issue caused by change of ``component_metadata.sublime-settings`` + +* Update: + - Add output panel message for ``describe_metadata`` command + - Disable document reference reload feature + - Add a ``salesforce_reference.sublime-settings`` for ``Document > Open Document`` in the main menu + +* New API for metadata: + - Add a new ``read_metadata`` method for ``metadata.py``, which will be used for ``diff_with_server`` feature in the future + + +Release 3.0.0 (2015-05-26) +++++++++++++++++++++++++++++++++++++ +* Bug fix: + - Fix bug #38 + - Fix bug for SOQL fields completion + - Fix bug for attributes completion for value of ``apex:includeScript`` + +* New + - Add a new snippet named ``Page - field label.sublime-snippet`` + + +Release 2.9.9 (2015-05-25) +++++++++++++++++++++++++++++++++++++ +* Enhancement + - SOQL fields completion, see demo at plugin home page + +* New + - Add two demos at home page + + +Release 2.9.8 (2015-05-24) +++++++++++++++++++++++++++++++++++++ +* Update: + - Update the plugin install message for package control + +* Enhancement: + - Add the missed attributes for some standard components since v29.0 + - Add attribute values for standard components if attribute value is picklist attribute + +* New: + - Add a new setting ``auto_update_on_save``, default value is false + - If ``auto_update_on_save`` is set to true, when you update the code file, ``save_to_server`` will be executed automatically + +* Note: + - From this version on, I will not keep frequently release on this plugin, I will move on to build Haoide plugin for brackets + + +Release 2.9.7 (2015-05-22) +++++++++++++++++++++++++++++++++++++ +* Bug Fix: + - Fix issue #36 + - Fix bug for ``childXmlNames`` parsing and ``childXmlNames`` completion for package.xml + - Fix bug for timeout exception message for ``query`` method in ``tooling.py`` + - Fix NoneType exception for automatic extension or controller creation if current view is not local file + - Tag plugin fix a bug for that tag name contains colon, `see tag issue https://github.com/titoBouzout/Tag/issues/79`_ + +* Enhancement: + - Enhancement for attribute completion in visualforce page, if attribute value is already exist, it will not insert ``=""`` or ``="{!}"`` again + - Enhancement for ``standardController`` sObject name completion in visualforce page, it will just work when attribute is ``standardController`` + - Add custom class completion for ``extension`` and ``controller`` attribute in visualforce page + - Add values completion for some attributes of standard components which type should be picklist, for example, "apiVersion", "layout", "event" or "target" for link and so on, in this time I just updated to apex:composition, I will check the remaining standard component + - Add two missed standard component into ``vf.py``, "apex:component" and "apex:componentBody" + - Add custom page completion for these four attributes: "page", "template", "pageName", "finishLocation", for example, if you input `_ + +* Update: + - Rename ``View Release Notes`` command to ``Release Notes`` + - Rename ``json_pretty`` command to ``json_format`` + - Rename ``convert_xml_to_json`` command to ``xml_to_json`` + - Move ``xml_to_json`` from context menu to ``Utilites`` in the main menu + - Add access to ``toggle_metadata_objects`` for both ``Settings`` and ``Metadata`` in the main menu + - Upgrade build-in ``xmltodict`` module to ``0.9.2`` + - Update document for the change in this release + +* New Feature: + - New commands for ``HaoIDE > Utilities`` of the main menu: + - Add a new command ``haoide_help`` to view related document + - Add a new command ``json_to_xml`` to convert xml back to json, see issue #32 + - Add a new command ``xml_format`` to format selected xml content or whole file content, see issue #32 + + +Release 2.9.4 (2015-05-13) +++++++++++++++++++++++++++++++++++++ +* Bug Fix: + - If there is only one member, just remove the type and the related member when ``build package xml`` + - When execute ``query_to_csv`` command and field value contains ``"`` or ``,`` + +* Enhancement: + - Show the error message when list package for metadata objects if have + - Support quick clear for symbol_table and sobject cache + - Automatic ``{!}`` enhancement for vf tag just if type is "Object" or "ApexPages.Action" + - Update type of some visualforce standard components from ``Object`` to ``String`` + - Change the item format in the quick panel when ``build package xml`` + - Add ``EmailTemplate`` to ``allowed_sobjects`` setting + - Allow user to choose reloading specified ``metadata_object`` cache when execute reload_project_cache command + - When operation is depends on login session, so login firstly and callback with this operation + +* Update: + - Rollback the delivered function for issue #15 + - Optimize on ``metadata.py`` + + +Release 2.9.3 (2015-05-11) +++++++++++++++++++++++++++++++++++++ +* Enhancement: + - Package.xml completion read cache from ``.config/package.json``, no longer read cache from project file + - Sort for items in quick panel of package.xml building + - Add alert message for package.xml completion + +* Bug Fix: + - Add the folder into member when list_package for DocumentFolder, EmailFolder, ReportFolder and DashboardFolder + - No four spaces in the quick panel of package.xml building for windows + + +Release 2.9.2 (2015-05-10) +++++++++++++++++++++++++++++++++++++ +* Bug Fix: + - Fix bug for ``combine_soql`` which is invoked by ``Generate SOQL`` and ``Bulk Query`` + - Fix bug for ``export_profile`` command + - Fix bug for completion of building ``package.xml`` + - Fix bug for ``export_validation_rules`` command + +* New Feature: + - Deprecated ``metadataObjects`` since this release, which is replaced by ``/.config/metadata.json`` + - Add ``describe_metadata`` command, ``/.config/metadata.json`` will be generated by this command + - Add ``reload_project_cache`` command, ``/.config/package.json`` will be generated by this command + - Add ``build_package_xml`` command, see `more `_ + - Add key bindings for ``build_package_xml`` command + +* Enhancement: + - Move package related logic from ``main.py`` to the new ``package.py`` + - Add thread progress for ``track_debug_log``, ``fetch_debug_log`` and ``track_all_debug_logs`` + - `create_new_project`` start supporting callback + - Add metadata object for input description for ``create_new_component`` module + - Add list_package support for ``CustomObject`` retrieve + - Add availability check for ``.config/metadata.json`` for all related commands + - Add ``api_version`` message into the sidebar message + - Update ``api_version`` from ``32`` to ``33`` + - Update ``Metadata Migration`` to ``Metadata`` in the main menu + - Update ``generate_soql`` logic to include ``Id`` field if no available matched fields + - Update description for default settings + - Update README.md + + +Release 2.9.1 (2015-05-05) +++++++++++++++++++++++++++++++++++++ +* Fix bug for ``switch_project``, see issue #24 +* Enhancement for speeding up ``Save To Server`` operation +* Rename ``save_component`` command to ``save_to_server`` +* Rename ``delete_component`` command to ``delete_file_from_server`` +* Simplify ``delete_file_from_server`` and ``refresh_file_from_server`` +* Add two new value issue_url and history_url into package info +* Update ``report_issue`` and ``view_release_notes`` command to read url from package info + + +Release 2.9.0 (2015-05-03) +++++++++++++++++++++++++++++++++++++ +* Fix bug for messy code in debug log detail +* Enhancement for not refreshing sidebar when ``retrieve_files_from_other_server`` +* Enhancement for adding folder name to retrieve request when ``list_package`` for folders +* Enhancement for package.xml completion for folder name of Document, EmailTemplate, Dashboard and Report +* Enhancement for package.xml completion for AuraDefinitionBundle +* Enhancement for sobject completion, if there are two matched statements, ``insert prd`` and ``Product2 prd``, plugin will choose the second one as matched +* Enhancement for ``toggle_metadata_objects``, you can toggle metadata objects continually util you press ``ESC`` to exit +* Enhancement for ``generate_sobject_soql``, you can choose whether generate sobject SOQL of ``Custom``, ``Updateable`` or ``Createable`` +* Update workspace of default build-in project from ``C:/ForcedotcomWorkspace`` to empty +* Update name of default build-in project from ``pro-test`` to ``pro-sublime`` +* Update for ``toggle_metadata_objects``, after subscribe a new metadata object, don't refresh its folder again, just after you finish all toggle, you will need to confirm whether use refresh all subscribed metadata together +* Add ``toggle_metadata_objects`` document in ``docs/utilities.md`` +* Remove four deprecated settings, ``keep_config_history``, ``output_session_info``, ``delay_seconds_for_hidden_output_panel_when_failed`` and ``get_static_resource_body`` + + +Release 2.8.9 (2015-04-28) +++++++++++++++++++++++++++++++++++++ +* Fix urgent bug for issue #22 +* Enhancement for speeding up ``Save To Server`` operation +* Enhancement for supporting ``list_package`` when execute retrieve operation +* Enhancement for package.xml completion for Document, EmailTemplate, Dashboard and Report +* Enhancement for ``add_project_to_workspace`` just if login succeed +* Add a new ``link_project_with_sublime_project`` setting to control linking, default is false +* Update documents regarding to issue #18 + + +Release 2.8.8 (2015-04-26) +++++++++++++++++++++++++++++++++++++ +* Fix bug: If user don't have `Author Apex` privilege, plugin will give wrong information +* Fix bug: Show alert message if no available package.xml to combine +* Enhancement: Issue 15 about linking ``sublime-project`` with plugin project, deliver Windows solution but keep unchanged for OSX +* Enhancement: Add scope control for ``JSON to Apex`` +* Enhancement: Set ``word_wrap`` of ``Test Run`` result to false +* Enhancement: Simplify retrieve status check for API version 31 and later, check more detail at `here `_ +* Update documents + + +Release 2.8.7 (2015-04-22) +++++++++++++++++++++++++++++++++++++ +* Fix plugin loading NoneType issue +* Combine ``retrieve_package_file`` and ``retrieve_package_xml`` command to only ``retrieve_package_xml`` +* Allow user to input extractTo path, enhancement for issue #19 +* Add a new command ``combine_package_xml`` to combine all package.xml in many folders, see ``Salesforce Utilites`` quick link +* Update Documents + + +Release 2.8.6 (2015-04-20) +++++++++++++++++++++++++++++++++++++ +* Optimization for parsing project name by path or file +* Change the default workspace of plugin level to empty +* Change the workspace to optional, if workspace of plugin level and project level are both empty, plugin will save the project to ``/User/HaoIDE``, +* Change the name of ``execute_soql`` command to ``execute_query`` +* If there has network connection issue, just display ``Network connection timeout`` but no more detail again +* Add a new command for export query to csv, you should be aware, query statement contains parent-to-child statement will not be enabled for this command +* Add a new ``auto_switch_project_on_file_activated`` setting to control project switching when file of non-default project is open, this feature is disabled by default +* Add a new ``reveal_file_in_sidebar_on_file_activated`` setting to control sidebar file revealing when the file is open, this feature is disabled by default + + +Release 2.8.5 (2015-04-10) +++++++++++++++++++++++++++++++++++++ +* Biggest optimization for variable completion: + - Exclude comment statement + - Choose the nearest matched one +* Add a new ``remove_comments`` command in the ``Utilities`` +* Allow ``extract_to_here`` command to support all zip resources + + +Release 2.8.4 (2015-04-09) +++++++++++++++++++++++++++++++++++++ +* Add error popup display for latest version of sublime +* Add a new settings ``disable_html_completion`` to disable html completion +* Set default value of ``disable_html_completion`` as true because of conflict with sublime +* Optimize component attribute completion to support current line and next line +* Fix Bug: Wrong completion for Picklist2 when ``if (acc.Picklist1 == 'abc' && acc.Picklist2 == 'bcd')`` +* Fix Bug: Plugin found the wrong variable type in the commented code for variable completion +* Ignore exception when keep package.xml for every deploy action +* Rename Heroku to Haoku in the ``Main Menu > Utilities`` +* Remove useless ``.travis.yml`` +* Remove ugly code for check whether statement is comment for code +* Update ``execute_soql`` command to execute query in heroku + + +Release 2.8.3 (2015-04-02) +++++++++++++++++++++++++++++++++++++ +* If no CRUD privilege on profile object, just leave blank in the output csv +* Add field FLS export feature, it's a wonderful feature for document + + +Release 2.8.2 (2015-03-28) +++++++++++++++++++++++++++++++++++++ +* Fix package.xml completion bug if file name contains multiple dot +* Fix package.xml completion bug if there have extracted zip resource +* Pull request for #14 +* Spell problem of `Toggle Metadata Settings` +* Add entry point for ``Haoku`` in the ``Utilities`` of main menu +* Remove ``AuraDefinitionBundle`` from default subscribed Metadata settings + + +Release 2.8.1 (2015-03-05) +++++++++++++++++++++++++++++++++++++ +* Fix issue #6 +* Enhancement for issue #13 + + +Release 2.8.0 (2015-02-11) +++++++++++++++++++++++++++++++++++++ +* Fix issue #11, #12 +* Add two commands ``Retrieve All`` and ``Retrieve sObject and Workflow`` in the command palette + + +Release 2.7.9 (2015-02-06) +++++++++++++++++++++++++++++++++++++ +* Fix issue #4 +* Fix issue #7 +* Enhancement for ``diff_with_server``, allow diff compare with different project +* Upgrade ``requests`` to v2.5.1 and disable the InsecureRequestWarning +* Display line number before column number when ``save_component`` failed + + +Release 2.7.8 (2015-02-02) +++++++++++++++++++++++++++++++++++++ +* Rename ``refresh_component`` command to ``refresh_file_from_server`` +* Rename ``refresh_selected_components`` command to ``refresh_files_from_server`` +* Rename ``delete_selected_components`` command to ``delete_files_from_server`` +* Add a new command for ``retrieve file from other server`` for retrieve file from different project. +* Add a settings ``switch_back_after_migration`` to control whether switch back to original project after ``deploy to server``, ``deploy package to server``, ``deploy lightning to server`` or ``retrieve file from other server``, issue haoide:#3 +* Fix issue #5 +* Move ``pretty_json`` command from context menu to ``HaoIDE > Utilities > JSON Pretty`` in the main menu +* Update README.MD + + +Release 2.7.7 (2015-01-22) +++++++++++++++++++++++++++++++++++++ +* Fix bug for ``Package.xml Completion`` +* Enhancement: display error column in XML if deploy failed +* Enhancement for ``json_to_apex`` +* Enhancement for ``describe_sobject`` +* Add a new ``json_serialization`` command to serialize JSON to string +* Add a new ``panel`` menu item in Main Menu +* Rearrange Utilities menu item in Main Menu +* Update ``haoide`` to ``HaoIDE`` + + +Release 2.7.6 (2015-01-20) +++++++++++++++++++++++++++++++++++++ +* Enhancement for ``create_trace_flag`` command +* Add a enabled check logic for ``export profiles`` command +* Add a new ``haoide > Utilities > Convert JSON to Apex`` command for converting JSON to Apex +* Add commands for ``convert_json_to_apex`` in command palette +* Update README.MD about the `Convert JSON to Apex `_ + + +Release 2.7.5 (2015-01-18) +++++++++++++++++++++++++++++++++++++ +* Fix bug: messy code when view debug log detail in sublime +* Fix bug: timeout exception is not caught when save component +* Enhancement for completions +* Enhancement for ``export profile`` feature +* Add feature for export of ``userPermission`` and ``tabVisibility`` +* Update README.MD + + +Release 2.7.4 (2015-01-16) +++++++++++++++++++++++++++++++++++++ +* Fix bug for issue #75 +* Update ``Chanel`` to ``Channel`` in the plugin copyright information +* Update license information +* Remove ``InstalledPackage`` from ``metadataObjects`` settings +* No longer check save conflict when compile code +* Add commands for ``export_profile`` in command palette +* Update default keymap for ``open log panel``, ``open error panel`` and ``open diff panel`` in the ``Utilities`` menu item +* Enhancement for login module, decrease the timeout seconds and repeat login until repeat times exceed 12 times + + +Release 2.7.3 (2015-01-14) +++++++++++++++++++++++++++++++++++++ +* Fix bug for ``extract here`` command +* Fix bug for ``bulk api`` caused by release 2.7.2 +* Fix long-term bug for inProgress message of deployment +* Enhancement for ``list debug log``, for example, sort logs order by StartTime ASC, remove the useless "\n" +* Add missed standard objects for ``CustomObject`` when retrieve metadata +* Add new command for exporting profile object security settings, it's a very useful feature +* Add ``Translations`` to metadataObjects settings +* Update snippet description for ``Debug - debug json.sublime-snippet`` + + +Release 2.7.2 (2015-01-12) +++++++++++++++++++++++++++++++++++++ +* Fix bug for issue #74 +* Fix bug for ``cancel_deployment`` +* Fix bug for ``reload symbol table`` when symbol_table is None +* Fix bug for ``execute anonymous`` when anonymous code contains non-english words since release 2.7.0 +* Enhancement for message tracking in output panel +* Enhancement for settings check, if settings is valid, just display it in output panel +* Update snippet ``Debug - debug variable.sublime-snippet`` +* Add snippet ``Debug - debug json.sublime-snippet`` + + +Release 2.7.1 (2015-01-09) +++++++++++++++++++++++++++++++++++++ +* Enhancement for ``standardController completion`` in `` Email`` for ``Debug Log User List`` +* Milestone change for soap body request +* Enhancement for quick extension and quick controller +* Fix Bug for Package Completion +* Fix Bug for ``opps`` completions in ``getAccountList(List opps)`` +* Fix Bug for ``allowed_sobjects``, change ``Assert`` to ``Asset`` +* Fix Bug for ``reload_sobject_cache`` +* Fix Bug for ``bulkapi`` +* Change default value of ``last_n_logs`` from ``10`` to ``20`` + + +Release 2.6.0 (2014-12-20) +++++++++++++++++++++++++++++++++++++ +* Enhancement for ``refresh_folder`` +* Enhancement for ``retrieve_all`` and ``retrieve_sobjects_and_workflows`` +* Move export csv files to ``.export`` folder, for example, CustomFields, ValidationRules, Workflows and Workbooks, etc. + + +Release 2.5.9 (2014-12-17) +++++++++++++++++++++++++++++++++++++ +* Completion enhancement for building package.xml +* Fix duplicate MetadataContainerId for issue #69 +* `Build Package.xml Demo `_ + + +Release 2.5.8 (2014-12-15) +++++++++++++++++++++++++++++++++++++ +* Add all ``sharingRules`` metadata types to default components setting +* Rename ``.package`` to ``.deploy`` for ``deploy to server`` execution +* Remove ``subscribe_component`` and ``unsubscribe_component`` commands +* Add a new ``toggle_commands`` command to replace above two commands +* After a new component is subscribed, refresh the new folder from server +* Rename "ok" in confirm dialog to related message +* Add workspace check when create new project +* Update README.MD + + +Release 2.5.7 (2014-12-14) +++++++++++++++++++++++++++++++++++++ +* Fix Bug for creating extension or controller after input # in visualforce page +* Adjust the location of ``Cache`` menu item +* Add a new command for ``retrieve package.xml`` in sidebar menu +* Add a new command for ``create package.xml`` in sidebar menu +* Add a new command for ``subscribe component`` in ``settings`` of main menu +* Add a new command for ``unsubscribe component`` in ``settings`` of main menu +* Add quick command for ``subscribe component`` in quick command palette +* Add quick command for ``unsubscribe component`` in quick command palette +* Remove ``retrieve_package_xml`` command from ``Metadata Migration`` of main menu +* Rename ``soap_bodies`` to ``soap`` +* Update visibility for ``Update User Language`` + + +Release 2.5.6 (2014-12-13) +++++++++++++++++++++++++++++++++++++ +* Fix Bug for issue #65 +* Fix Bug for issue #66 +* Enhancement for issue #48, after deployed, the `package.xml` is saved to `.package` in workspace +* Before files are deployed to server, save them to local +* When you deploy any lightning element, just deploy the whole lightning component +* Convert StartTime of debug log to local time by timezone module + + +Release 2.5.5 (2014-12-09) +++++++++++++++++++++++++++++++++++++ +* Fix Bug for creating Lightning Component Element +* When deploy failed due to lower code coverage, display the coverage warning message +* When new component is created, create the meta.xml file for it +* Hide ``Retrieve Lightning from Server`` command when chosen folder is not aura folder +* Hide ``Destruct Lightning from Server`` command when chosen folder is not aura folder +* Hide ``Extract to Here`` command if file extension is not `zip` or `resource` +* Update the Documentation + + +Release 2.5.4 (2014-12-07) +++++++++++++++++++++++++++++++++++++ +* Add `dateutil` module for supporting timezone converting +* Fix Bug for `track debug log` +* Trim the space for `REST URI` automatically +* Remove `lib` from `Packages` in `.gitignore` file +* Support project level workspace for issue #63, see more detail at `workspace `_ + + +Release 2.5.3 (2014-12-05) +++++++++++++++++++++++++++++++++++++ +* Adjust the context menu from most bottom to center +* Adjust the sidebar menu from most bottom to center +* Fix Bug for issue #62: 'module' object has no attribute 'populate_classes' +* Fix Bug for issue #61: KeyError: 'name' in `get_component_completion` +* Fix Bug for issue #60: Error with 'Update Project' +* Add lightning component description for `Lightning Component` development + + +Release 2.5.2 (2014-11-27) +++++++++++++++++++++++++++++++++++++ +* After new lightning component is created, deploy it to server +* Add a new command for ``pretty json`` in the context menu +* hide the status message in progress bar when track self debug log after save succeed + + +Release 2.5.1 (2014-11-26) +++++++++++++++++++++++++++++++++++++ +* Fix Bug: NoneType Exception when destruct files from server +* Fix Bug: when saving component, the active view is not file +* Add a new settings ``track_log_after_saved`` to control whether track log after save succeed + + +Release 2.5.0 (2014-11-26) +++++++++++++++++++++++++++++++++++++ +* Fix Bug: when delete component, if there is a open view which is not bind to file, it will throw TypeError: argument of type 'NoneType' is not iterable, and then, file is deleted from server but local file is not removed +* Fix Bug: After folder is refreshed or project is updated, update the component cache +* Add `Lightning Component` document reference +* Add `Lightning Component` component tags to completions +* Add `Lightning Component` to `components` settings and set it as default subscribed component +* Add `Lightning Component` update feature +* Add `Lightning Component` components update feature +* Add `Lightning Component` component create feature +* Add `Lightning Component` component destruct feature +* Change default ``api_version`` from 31 to 32 +* Remove ``Open Coverage Panel`` menu item in the main menu +* Add ``duration`` column for debug logs and rearrange it's columns order +* Add new document reference for ``Analytic Api``, ``Analytics Cloud Dashboard JSON``, ``Security Implementation`` + and ``Lightning Component`` +* Add new command for viewing release notes +* Rename ``Extract Static Resource`` command to ``Extract To Here``, which command can be used to extract all zip source file but not only static resource for Salesforce +* Add ``settings`` to ``components`` settings +* If project is not created, all ``export`` feature and ``new component`` feature are not enabled + + +Release 2.4.0 (2014-11-18) +++++++++++++++++++++++++++++++++++++ +* Fix issue #55 +* Fix issue: non-english words are encoded to Unicode in result of ``Rest Test`` +* Fix issue: when read local cache of record type, ``global name 'users' is not defined`` exception +* Rollback feature of ``view_code_coverage``, see issue #56 +* Deprecate ``keep_config_history`` setting +* Update the description of ``keep_local_change_history`` setting +* When save operation has conflict and we cancel it, compare the local with server automatically + + +Release 2.3.0 (2014-11-14) +++++++++++++++++++++++++++++++++++++ +* Use local ``/.config/session.json`` to reuse session but not globals() again +* Use local ``/.config/recordtype.json`` to ``record type`` but not globals() again +* Use local ``/.config/users.json`` to ``users`` but not globals() again +* If ``execute_anonymous`` compiled succeed, use new view to display result, else, use output panel to display result +* Use frontdoor method to login to SFDC +* Add new document reference for ``Analytic Api`` +* Display session expired message in the output panel + + +Release 2.2.0 (2014-11-12) +++++++++++++++++++++++++++++++++++++ +Fix Issue: + +* Fix issue: TypeError: string indices must be integers when refreshed folder is empty +* Fix issue: In windows, change of folder or file in sidebar is not reflect in real time +* Fix issue: Sometimes, file is not remove from local after ``destruct file from server`` +* Fix issue: format problem of local ``.config`` info +* Fix issue: #52 + +Enhancement: + +* Add time stamp for new view name of ``rest test`` +* Show logs of ``fetch debug logs`` and ``execute_anonymous`` in the output panel but not new view +* Change default value of ``folder_exclude_patterns`` and ``file_exclude_patterns`` settings + +New Feature: + +* Add new command for ``fetch self debug log`` in the main menu and command palette + + +Release 2.1.0 (2014-11-10) +++++++++++++++++++++++++++++++++++++ ++ Fix Bug: ``IndexError: list index out of range`` caused by release 2.0.0 ++ Fix Bug for test class judgment: test class is that starts with `test` or ends with `test` ++ Add a new apex.py module, move execute_anonymous method from metadata.py to apex.py ++ Add a new command for ``diff with server`` in the context menu ++ Optimization on ``view_code_coverage`` feature ++ Add a new command ``Utilities > Open Coverage Panel`` in the main menu to open coverage panel ++ Rename ``Open Output Panel`` command to ``Open Log Panel`` and move it from ``Debug`` to ``Utilities`` in the main menu ++ Temporarily remove the ``Run All Test`` feature from ``Debug`` in the main menu + + +Release 2.0.0 (2014-11-08) +++++++++++++++++++++++++++++++++++++ ++ Fix minor bug for ``Duplicate Save Execution of Same Component`` ++ Remove useless message from ``message.py`` ++ Add a space between parameters for completion of standard apex class ++ Rename ``Describe`` menu item in the main menu to ``Utilities`` ++ Add a new command for ``Convert 15 Id to 18 Id`` ++ Add a new command for ``Track Self Debug Log`` ++ Add new feature for updating ZIP Static Resource, see demo ``https://raw.githubusercontent.com/xjsender/SublimeApexScreenshot/master/UpdateStaticResource.gif`` ++ Add commands for ``Convert 15 Id to 18 Id`` and ``track self debug log`` in the command palette ++ Add ``StaticResource`` to default subscribed components ++ Update README.MD + + +Release 1.9.0 (2014-11-04) +++++++++++++++++++++++++++++++++++++ ++ Fix issue #50 ++ Fix minor issue for ``delete_component`` ++ Fix potential issue for retrieve and deploy ++ Add ``Destruct Files From Server`` command in the sidebar menu for deleting files from sandbox or production ++ Add ``Destruct From Server`` command in the context menu for deleting file from sandbox or production ++ Add new command ``cancel_deployment`` for quickly canceling deployment of specified ++ Add mousemap for canceling deployment: Put the focus in the task Id, and then press alt and click Left Mouse for triple will cancel deployment of specified task Id + + +Release 1.8.0 (2014-11-03) +++++++++++++++++++++++++++++++++++++ ++ In order to prevent UI freeze, use thread to extract encoded zipFile to path ++ Solution for issue #49, add a new settings ``maximum_concurrent_connections`` to control concurrent connections ++ In order to prevent UI freeze, set default value of ``maximum_concurrent_connections`` to ``30`` + + +Release 1.7.0 (2014-10-31) +++++++++++++++++++++++++++++++++++++ ++ Fix Bug: If just compile component but not save, no need to keep history ++ Fix Bug: SOQL Field Completion problem if there is more than one character between from and sObject ++ Fix Bug: Replace all `LIST` to `List` ++ Remove ``Settings – Completions`` and ``Settings – Apex Template`` from main menu + + +Release 1.6.0 (2014-10-25) +++++++++++++++++++++++++++++++++++++ ++ Fix Bug: issue #44 caused by release 1.5.0 ++ Fix Bug: display ExpatError when retrieve package ++ Fix Bug: display json parse error message when execute rest test ++ Stop to hide output panel after retrieve is finished ++ show status message 'Not valid SFDC component' if current file is not valid SFDC component ++ Deprecate the delay_seconds_for_hidden_output_panel_when_failed settings ++ Stop to remove the error line highlight after ``save to server``, just remove it in the next save action ++ After save succeed, remove the highlight from view ++ Support error line highlight for visualforce page just if error line > 2 ++ Add ``OpenCTI Api`` document to document reference + + +Release 1.5.0 (2014-10-21) +++++++++++++++++++++++++++++++++++++ ++ Fix Bug for package import error in ``bulk api`` ++ Add more detailed action summary for ``save component``, issue #45, issue #46 ++ Add description for ``quick controller`` in README.MD + + +Release 1.4.0 (2014-10-18) +++++++++++++++++++++++++++++++++++++ ++ Fix bug for completion: No completions for ``strMap`` if there has ``// Populate Map\nMap strMap = new Map();`` ++ Fix Bug: ``deploy open files to server`` ++ Add a new command for ``preview_page`` in the command palette ++ Input ``#`` after controller or extension name in the visualforce page, plugin will automatically create it for you ++ Remove ``static resource`` from default subscribed components + + +Release 1.3.0 (2014-10-14) +++++++++++++++++++++++++++++++++++++ ++ Fix Minor bug for standard class completion: duplicate class in different namespace, for example, Communities, TimeZone, UnsupportedOperationException, Test, QueryException, Action ++ Fix Critical bug: non code file can't be retrieve from server, now, objects, reports and others can be retrieve from server ++ Fix Critical bug: Deploy exception after session cache is expired + + +Release 1.2.0 (2014-10-11) +++++++++++++++++++++++++++++++++++++ ++ ``get_static_resource_body`` settings is deprecated ++ Change default ``api_version`` from ``30`` to ``31`` ++ Add a new command ``deploy open files to server`` in the main menu, which is used to deploy open files in the sublime to target server ++ Add command for ``deploy open files to server`` in the Command Palette ++ Add ``static resource`` to default subscribed components ++ Fix Bug for Windows: After ``retrieve all`` is finished, invoke the ``refresh_folder_list`` standard function to display the new folders generated by ``retrieve all`` ++ Fix Bug: ``Save to Server`` command (Use Tooling Api) can be only used on ``classes``, ``components``, ``pages`` and ``triggers`` but not other components, however, we can use ``Deploy to Server`` command (Use Metadata Api) to save all components + + +Release 1.1.0 (2014-10-09) +++++++++++++++++++++++++++++++++++++ ++ Fix Bug for Windows: After ``export`` is finished, refresh the project folders to ensure the new folder is shown in the sidebar ++ Fix Bug: display deploy failed message if deploy is failed. ++ Fix Bug: symbol table is null when iterate symbol table ++ Update README.MD + + +Release 1.0.9 (2014-10-04) +++++++++++++++++++++++++++++++++++++ ++ Fix Bug: After open a new view, open context menu, it will throw NoneType exception + + +Release 1.0.8 (2014-10-02) +++++++++++++++++++++++++++++++++++++ ++ Fix issue at ``https://success.salesforce.com/answers?id=90630000000gxvwAAA`` + + +Release 1.0.7 (2014-09-30) +++++++++++++++++++++++++++++++++++++ ++ Fix Minor Bug for windows: After ``.config`` is generated, invoke the sublime command: ``refresh_folder_list`` ++ Enhancement for checking whether current project is active project ++ Fix Critical Bug: If session is expired, we want to refresh the folder or update project, the console will always stop at the step of ``[sf:retrieve] Start request for a retrieve...`` ++ Fix issue #42, stop to remove folder when refresh folder or update project but just override, Notice: if you delete some file in the server, after ``update project`` and ``refresh folder``, these files will not deleted in the sublime, so, I suggest you should delete code in the sublime but not in the server + + +Release 1.0.6 (2014-09-28) +++++++++++++++++++++++++++++++++++++ ++ Fix Minor Bug: After ``retrieve_package_file`` is succeed, hide the output panel ++ Fix Minor Bug: If current project is not ``active project``, disable the ``Retrieve Files From Server`` functionality ++ Fix Minor Bug: If current project is not ``active project``, disable the ``Retrieve File From Server`` functionality ++ Fix Minor Bug: If current project is not ``active project``, disable the ``Run Test Class`` functionality + + +Release 1.0.5 (2014-09-27) +++++++++++++++++++++++++++++++++++++ ++ Fix bug: Exception when ``new project`` in a new org ++ Fix bug: If there is no any trigger, after ``new project``, the folder of ``trigger`` is not created. ++ Fix bug: ``subscribed_meta_folders`` and ``meta_folders`` in settings are not correct + + +Release 1.0.4 (2014-09-25) +++++++++++++++++++++++++++++++++++++ ++ Fix urgent issue #40 ++ Remove the useless soap related codes, for example, ``retrieve_apex_code_body``, ``retrieve_static_resource_body`` and so on ++ Fix minor bug: Don't allow to refresh or delete ``*-meta.xml`` file ++ Fix bug: ``allowed_packages`` is not working ++ Fix bug: mass refresh multiply folders ++ Fix minor bug: deploy failed message in the output panel ++ Add a new sidebar command ``Retrieve Files From Server`` ++ Add a new context command ``Retrieve File From Server`` ++ If ``allowed_packages`` is not empty, all packages are extracted to ``packages`` path, + Project + > .config + > src + > packages + > package 1 + > package 2 + + +Release 1.0.3 (2014-09-24) +++++++++++++++++++++++++++++++++++++ ++ After ``Update Project`` is finished, remove the original ``src`` tree and then extract the zipFile to ``src`` ++ After ``Refresh Folder`` is finished, remove the original folders and then extract the zipFile to specified folders ++ Fix urgent bug: if no project in sidebar and sidebar is hidden, after ``new project`` or ``update project``, the sidebar is not open automatically. + + +Release 1.0.2 (2014-09-23) +++++++++++++++++++++++++++++++++++++ ++ Update the default value of ``checkOnly`` in ``deploy_options`` settings from ``true`` to ``false`` ++ Fix Urgent bug: If one class is created in the server, after ``refresh folder``, cache of this folder will override all components ++ Remove some useless ``print`` statement ++ Fix minor bug: After code is saved, duplicate extension is displayed in the console ++ Add two settings ``folder_exclude_patterns`` and ``files_exclude_patterns`` to hide everything you want to hide in the sidebar ++ Update the ``add project to workspace`` logic to compatible with the above two settings ++ Add a new command ``Update Project Patterns`` in the main menu, see [Pattern Demo](https://raw.githubusercontent.com/xjsender/SublimeApexScreenshot/master/ProjectPattern.gif) + + +Release 1.0.1 (2014-09-22) +++++++++++++++++++++++++++++++++++++ ++ Add ``LogLength`` column to result of ``fetch debug logs`` ++ Update default value of ``display_field_name_and_label`` setting from ``false`` to ``true`` ++ Remove the ``\n`` from success message in ``document.py`` ++ Add description for ``save multiple components`` feature in the README.MD ++ Change output directory of ``retrieve package.xml`` from current directory to ``[ProjectName]-201409221812`` ++ Add ``messages`` notes + + +Release 1.0.0 (2014-09-21) +++++++++++++++++++++++++++++++++++++ ++ Add a new command ``Deploy To Server`` in the context menu ++ Fix bug for ``retrieve`` when session is expired ++ Fix bug for ``New ApexClass``, ``New ApexTrigger``, ``New ApexComponent`` and ``New ApexPage`` ++ Fix bug ``TypeError: is_visible() missing 1 required positional argument: 'dirs'`` when open ``Command Palette`` ++ Fix bug: If there is no any trigger or class, we want to create the first one, there has exception ++ Fix bug: ``Package.xml`` was overridden by ``refresh folder`` + + +Release 0.9.9 (2014-09-20) +++++++++++++++++++++++++++++++++++++ ++ Try to fix bug for ``new release messages display`` or who can tell me how to display ``release message`` ++ Fix bug for ``quick go to component`` + + +Release 0.9.8 (2014-09-20) +++++++++++++++++++++++++++++++++++++ ++ Support multiply folder refresh ++ Add standard sObjects to CustomObject Package Members when create new project if CustomObject is subscribed ++ Update default subscribed components ++ Add a new command ``Deploy Files to Server`` ++ Fix bug: Display debugLog info after deploy is finished ++ Upsert demo in README.MD ++ Display the new release message after new released upgrade is finished + + +Release 0.9.7 (2014-09-19) +++++++++++++++++++++++++++++++++++++ ++ Milestone for Metadata Api Migration from ``Tooling Api`` for non-code meta ++ remove some time stamp for deploy ++ Functionality check for ``convert xml to json`` ++ Optimize the zip utility for ``extract`` zip file or ``compress`` folder ++ Remove ``hidden_console_on_modify`` settings ++ Fix bug: the output console message for ``compile`` ++ Use ``metadata api`` to new project ++ Use ``metadata api`` to refresh folder ++ Change the default settings content for ``components``, you can subscribe what you want to retrieve, default subscribe just include ``ApexPage``, ``ApexComponent``, ``ApexClass`` and ``ApexTrigger`` + + +Release 0.9.6 (2014-09-16) +++++++++++++++++++++++++++++++++++++ ++ Fix bug for issue #38, remove ``ownerRules``, ``criteriaBasedRules`` and ``installedPackages`` from default package.xml ++ Add a command to export CustomLables to csv ++ Update ``SOQL - SELECT FROM`` snippet + + +Release 0.9.5 (2014-09-15) +++++++++++++++++++++++++++++++++++++ ++ Add confirm request for ``new project`` ++ Add screenshot for ``Convert XML to JSON`` ++ Fix KeyError Exception bug: cancel save operation if conflict. + + +Release 0.9.4 (2014-09-14) +++++++++++++++++++++++++++++++++++++ ++ Move ``check_enabled`` from ``main.py`` to ``util.py`` ++ If ``deploy status`` is in ``canceling``, continue to check deploy status until it's canceled. ++ Remove useless ``mkdir`` method from context.py ++ Move some methods from ``context.py`` to ``util.py`` ++ Fix bug for ``deploy`` and change the syntax highlight from ``Java`` to ``JavaScript`` + + +Release 0.9.3 (2014-09-13) +++++++++++++++++++++++++++++++++++++ ++ Add a command to convert selection to JSON if selection is valid XML format ++ Add context menu item, commands for this command ++ Fix a bug for parsing ``apexrest`` url when executing rest test + + +Release 0.9.2 (2014-09-13) +++++++++++++++++++++++++++++++++++++ ++ Fix bug when ``sosl_string`` contains ``-, ?, *`` ++ Update ``query`` method in ``api.py`` ++ Separate ``api.py`` to ``metadata.py`` and ``tooling.py`` and move them to new ``api`` folder ++ Rename ``bulkapi.py`` to ``bulk.py`` and move it to ``api`` folder ++ After ``New Project`` is finished, invoke the sublime command ``refresh_folder_list`` to reflect files change in the sidebar ++ After the code file is deleted, the related ``-meta.xml`` file is also deleted + + +Release 0.9.1 (2014-09-12) +++++++++++++++++++++++++++++++++++++ ++ Fix bug when code has conflict and user cancel the save operation + + +Release 0.9.0 (2014-09-12) +++++++++++++++++++++++++++++++++++++ ++ Fix bug for windows sidebar folder refresh ++ Not keep ``default_project`` settings in the settings of ``.config`` ++ Add ``reload_symbol_tables_when_create_project`` setting ++ Set default value of ``reload_symbol_tables_when_create_project`` setting to ``false`` ++ Fix bug for ``execute anonymous`` + + +Release 0.8.9 (2014-09-11) +++++++++++++++++++++++++++++++++++++ ++ If ``retrieve`` is in ``Queued``, thread sleep 2 seconds, else, thread sleep 1 seconds ++ If ``deploy`` is in ``Pending``, thread sleep 2 seconds, else, thread sleep 1 seconds ++ After project is switched, set status for all view of all window. ++ Fix the bug of ``remove temp zip`` ++ When deploying, if component parse is finished, display the TestRun Progress + + +Release 0.8.8 (2014-09-11) +++++++++++++++++++++++++++++++++++++ ++ Fix some bug for ``deploy`` + + +Release 0.8.7 (2014-09-10) +++++++++++++++++++++++++++++++++++++ ++ Update README ++ When ``New Project``, no need to select project ++ Fix bug ``c:`` completion + + +Release 0.8.6 (2014-09-09) +++++++++++++++++++++++++++++++++++++ ++ Add ``c:`` prefix for custom component completion ++ Add space between timestamp and message in the panel + + +Release 0.8.5 (2014-09-08) +++++++++++++++++++++++++++++++++++++ ++ Move some methods from processor.py to util.py ++ Optimize sObject Cache download ++ Add time stamp prefix for panel message ++ Fix bulkapi bug caused by release 0.8.3 ++ Move ``allowed_packages`` to project of projects settings ++ Add metadata retrieve support for ``allowed_packages`` ++ Catch all ``requests`` exception ++ Use panel to display the progress information of ``document reloading`` ++ From release 0.8.3 to this version, there have lots of big change, issue is welcomed ++ Add "Accept-Encoding": 'identity, deflate, compress, gzip' header for ``check_status``, ``check_deploy_status`` and ``check_retrieve_status`` in api.py + + +Release 0.8.4 (2014-09-08) +++++++++++++++++++++++++++++++++++++ ++ If just checkOnly, output VALIDATE, otherwise, output DEPLOY ++ Update comments for ``mousemap`` ++ Big Milestone, originally, we use ``tooling api`` to download apex code, now it is changed to retrieving by ``metadata api`` ++ Happy to remove the ugly method ``refresh_components`` in api.py, this method is very very ugly + + +Release 0.8.3 (2014-09-07) +++++++++++++++++++++++++++++++++++++ ++ Rearrange the attribute position in ``soap_bodies.py`` ++ Update README.MD ++ When start ``deploy`` command, if clipboard content is not valid zip file path, set path with empty, otherwise, paste it to input panel ++ Rename ``Retrieve Metadata`` item in main menu to ``Retrieve All`` ++ Rename ``Migration`` item in main menu to ``Metadata Migration`` ++ Add confirmation request for ``Retrieve All`` and ``Retrieve sObjects and Workflow`` ++ Rename ``Describe Sobject`` item in main menu to ``sObject`` ++ Rename ``Generate SOQL`` item in main menu to ``sObject SOQL`` ++ Rename ``SOQL History`` path from ``soql`` to ``SOQL`` ++ Rename ``Workbook Export`` path from ``workbooks`` to ``Workbooks`` ++ Rename ``CustomField`` path from ``customfield/customfield.csv`` to ``CustomField/CustomField.csv`` ++ Rename ``Validation Rule`` path from ``validation/validation rules.csv`` to ``Validation/Validation Rules.csv`` ++ Add ``Apex Code`` related sObject to ``allowed_sobjects`` settings ++ Remove ``proxies`` settings ++ Fix bug: Parse content from package.xml when there is only one types in package.xml ++ Add a new ``Retrieve Package.xml`` command in the context menu, just available when open file is ``package.xml`` ++ Add a new ``Deploy to Server`` command in the sidebar menu, just available when the chosen folder is valid package path ++ Put the focus in the log id, press ``Alt`` and click left button, the debug log detail will be retrieved and displayed in the new view ++ Error message when export workflow or validation rule if not retrieve yet ++ Remove ``SnapshotAuditEvent``, ``SnapshotBin``, ``Question``, ``SnapshotConfig``, ``Reply`` and ``UserLicense`` from default ``retrieve_sobjects_workflow_task_body`` in ``soap_bodies.py`` + + +Release 0.8.2 (2014-09-05) +++++++++++++++++++++++++++++++++++++ ++ when ``retrieve package.xml``, if file in package.xml is not found in target org, display the message ++ Add ``deploy package.zip`` command to deploy zip file + + +Release 0.8.1 (2014-09-05) +++++++++++++++++++++++++++++++++++++ ++ Change the UI of ``retrieve`` ++ Add a command ``retrieve_package`` in the main menu to retrieve metadata by specified package.xml ++ Fix a bug for ``get_static_resource_body`` when creating a new project ++ Fix a bug for displaying the latest debug logs ``ORDER BY StartTime DESC`` when ``fetch logs`` ++ Add a new demo link ``Retrieve Package.xml`` in README.MD + + +Release 0.8.0 (2014-09-04) +++++++++++++++++++++++++++++++++++++ +- Change ``se`` Snippet from ``SELECT Id, $2 FROM $1$0`` to ``SELECT Id$2 FROM $1$0`` +- Stop to open console when ``Refresh Selected Component`` +- Originally, press ``shift+button1*3`` to open class in background and press ``shift+button1*2`` to open class in foreground, now it is changed to ``shift+button1*3`` for background and ``shift+button1*2`` for foreground +- Change screenshots to demo link +- Fix ``query_all`` bug in api.py + + +Patch for Release 0.7.9 (2014-09-01) +++++++++++++++++++++++++++++++++++++ ++ ``output_session_info`` setting is deprecated and replaced by ``.config/session.json`` ++ Do not keep ``projects`` settings in the ``.config/settings.json``, because it's private confidential + + +Release 0.7.9 (2014-09-01) +++++++++++++++++++++++++++++++++++++ ++ Fix the display problem of ``Run Test`` and ``LoginTo ApexCode`` cause by History Item 1 of release 0.7.7 ++ Rename the path name of ``Test Operation History`` from ``test`` to ``Test`` ++ Fix bug for ``Create Component`` and ``Refresh Component Folder`` caused by History Item 1 of release 0.7.7 + + +Release 0.7.8 (2014-08-31) +++++++++++++++++++++++++++++++++++++ ++ Fix Operation History Format Problem ++ Inner class completion format ``Inner Class `` ++ After Project is created, automatically keep the settings to ``.config`` path ++ Add ``keep_config_history`` to control whether keep config info when ``New Project`` ++ Update README.MD + + +Release 0.7.7 (2014-08-30) +++++++++++++++++++++++++++++++++++++ ++ In order to avoid component is not available to CRUD to server because of Sensitive Case, save the component name with lower case into local cache ++ Read custom class from ``Component Attribute Cache`` but not read them from ``Symbol Table Cache`` ++ After input ``Page.``, list all custom visualforce page if have ++ After input ```` + + +Release 0.7.4 (2014-08-17) +++++++++++++++++++++++++++++++++++++ +- Inner Class Completion format +- Add compress header for ``get`` method in api.py +- Fix ``Reload Sobject Cache`` bug caused by release 0.7.3 +- Fix Symbol Table completions bug caused by Legacy Symbol Table Cache + + +Release 0.7.3 (2014-08-16) +++++++++++++++++++++++++++++++++++++ +- Add MIT-LICENSE +- Remove ``quick visualforce`` functionality +- Rename method name ``get_toolingapi_settings`` in context.py to ``get_settings`` and update corresponding invoker +- Add two new commands: ``Reload SymbolTable Cache`` and ``Clear SymolTable Cache`` +- When creating new project, not only download ``Apex Code`` and ``sObject Cache`` but also ``SymbolTable Cache`` +- when class number is more than 400, original symbol table cache structure is stupid and highly reduce the user experience of symbol table completion, in order to speedup symbol table completion, when saving the symbol table cache, store them as the completion format in the cache. + + +Release 0.7.2 (2014-08-15) +++++++++++++++++++++++++++++++++++++ +- Rename ``Toggle Log Panel`` menu item to ``Open Output Panel`` +- Update README.MD +- Add ``Preview Page`` command to preview visualforce page in server, just enabled when opening page +- Update About format + + +Release 0.7.1 (2014-08-12) +++++++++++++++++++++++++++++++++++++ +- Add ``delay_seconds_for_hidden_output_panel_when_succeed`` for control delay seconds to hide output panel when saving succeed +- Rename setting ``delay_seconds_for_hidden_console`` to ``delay_seconds_for_hidden_output_panel_when_failed`` + + +Release 0.7.0 (2014-08-11) +++++++++++++++++++++++++++++++++++++ +- Even if component saving is succeed, show the output panel +- If component saving is succeed, hide the open output panel after 1.5 seconds +- When generating workbook or describe sobject, write the type column with Formula() or + + +Release 0.6.9 (2014-08-09) +++++++++++++++++++++++++++++++++++++ +- When export workbooks, check whether input are valid, if any one is not valid, allow user to input again +- ``Folder Refresh`` reminder message is changed +- Add ``Update Project`` command to just update the apex code but not include sobject metadata +- Add ``Update User Language`` command to update language for running user, which can be used in ``Generate Workbook``, ``Field Completion`` and all related +- Add keymap and commands for ``Update Project`` and ``Update User Language`` +- Add a new setting ``user_language`` for ``Update User Language`` command +- Update the main menu, add ``Update`` main menu +- Add settings for package info, including ``name``, ``version``, ``homepage`` and so on +- Rename ``Help`` in main menu to ``About``, after click this item, not open browser and just display the plugin version info +- Add confirm request for ``update cache`` + + +Release 0.6.8 (2014-08-08) +++++++++++++++++++++++++++++++++++++ +- Add remind message to show output panel + + +Release 0.6.7 (2014-08-06) +++++++++++++++++++++++++++++++++++++ +- Console Message --> OutputPanel Message +- Add a new command ``Open Log Panel`` for display log panel +- Click ``super+``` to open output panel +- Inner class completion + + +Release 0.6.6 (2014-08-05) +++++++++++++++++++++++++++++++++++++ +- Set ``delay_seconds_for_hidden_console`` default value from ``15`` to ``9999`` +- Update description for default settings +- Add property and method completion for inner class + + +Release 0.6.5 (2014-08-03) +++++++++++++++++++++++++++++++++++++ +- Fix picklist completion bug +- Add keymap for ``Execute Rest Test`` command +- Remove catalog from README + + +Release 0.6.4 (2014-07-30) +++++++++++++++++++++++++++++++++++++ +- fix TypeError: save_component() missing 1 required positional argument: 'is_check_only' +- Compatible to api 31 because `compile fail response change `_ + + +Release 0.6.3 (2014-07-30) +++++++++++++++++++++++++++++++++++++ +- Optimize Rest Test when response result is str +- Add ``proxies`` support, just beta + + +Release 0.6.2 (2014-07-29) +++++++++++++++++++++++++++++++++++++ +- Fix issue for ``Delete`` command when list in returned json result is empty + + +Release 0.6.1 (2014-07-22) +++++++++++++++++++++++++++++++++++++ +- **Picklist Value** completion from ``value`` to ``value(label)`` +- **Save Conflict** functionality new format: **Modified by at 2014-05-04 10:03:31, continue?** + + +Release 0.6.0 (2014-07-19) +++++++++++++++++++++++++++++++++++++ +- Add search class and its methods for apex lib +- Fix bug for picklist value completion +- Change ``user`` to ``User`` for issue #31 + + +Release 0.5.9 (2014-07-10) +++++++++++++++++++++++++++++++++++++ +- Remove useless message from message.py +- Add some buld-in emmet supported snippets +- Add command ``quick_visualforce`` for emmet supported snippets +- Add TOC for README + + +Release 0.5.8 (2014-06-13) +++++++++++++++++++++++++++++++++++++ +- Add a new class template ``Test Class`` +- Add description for class template quick choose panel +- ``Clear Cache`` functionality change, display ``project name`` not ``username`` any more +- Add confirm request for ``Run All Test`` + + +Release 0.5.7 (2014-06-05) +++++++++++++++++++++++++++++++++++++ +- Optimize for opening url with browser +- Update OSX Keymap +- Fix bug for ``generate workbook`` in OSX +- Add ``Close Job`` command +- Update README.MD + + +Release 0.5.6 (2014-05-18) +++++++++++++++++++++++++++++++++++++ +- Fix bug for ``SELECT * FROM Sobject``, issue #30 +- Add time stamp for ``save conflict`` confirm message +- Optimize for ``Fetch Debug Log`` +- TraceFlag Bug: Delete the old one and create a new one every time request to create trace flag, issue #29 + + +Release 0.5.5 (2014-05-15) +++++++++++++++++++++++++++++++++++++ +- Add ``*`` support for ``Rest Query``, if ``*`` query, just replace it with all fields of related sobject +- Add doc for Wild-card Character query +- Fix ``Run Test`` bug caused by previous release +- Add ``view_selected_code_coverage`` command to view code coverage by selected class name +- Add mousemap to quick view code coverage + + +Release 0.5.4 (2014-05-15) +++++++++++++++++++++++++++++++++++++ +- Narrow down the code coverage column of test run result +- When run specified test class by main menu, if no test class, show the alert message +- Try to fix issue # 23 + + +Release 0.5.3 (2014-05-12) +++++++++++++++++++++++++++++++++++++ +- Add new snippet ``Sobject - sobject bracket`` +- Update description of ``Update Sobjects``, ``Delete Sobjects`` +- Add two commands for command ``Reload Cache`` and ``Clear Cache`` +- Fix bug for ``Export Workflow`` + + +Release 0.5.2 (2014-05-10) +++++++++++++++++++++++++++++++++++++ +- Since from API 30, compound field (queryByDistance=true) can't be in soql field list +- Fix bug for bulk api caused by release 0.5.1 + + +Release 0.5.1 (2014-05-10) +++++++++++++++++++++++++++++++++++++ +- Fix Bug: ``Export CustomField`` +- Update OSX keymap +- Add ``Export SOQL`` command to export sobject records by specified soql +- Add command for ``Export SOQL`` +- Fix install message alert + + +Release 0.5.0 (2014-05-09) +++++++++++++++++++++++++++++++++++++ +- Update ``README.MD`` +- Fix bug UnicodeError for ``Export Workflows`` and ``Export Validation Rule`` in OSX +- Remove some useless code, for example, ``Export Field Dependency`` + + +Release 0.4.9 (2014-05-04) +++++++++++++++++++++++++++++++++++++ +- Change default setting ``delay_seconds_for_hidden_console`` from ``10`` to ``15`` +- Change default ``api_version`` from ``29`` to ``30`` +- Add command ``Retrieve Sobject And Workflow`` + + +Release 0.4.8 (2014-04-27) +++++++++++++++++++++++++++++++++++++ +- Optimize picklist value completion +- Remove ``.no-sublime-package`` +- Replace ``excluded_sobjects`` settings with ``allowed_sobjects`` settings +- Optimize the sobject cache initiation for OSX +- Upgrade ``requests`` to latest version + + +Release 0.4.7 (2014-04-26) +++++++++++++++++++++++++++++++++++++ +- Fix some flaw for trigger completion +- Optimize Apex Completion +- Update READMD.MD +- Add ``.no-sublime-package`` to tell sublime to unzip the package + + +Release 0.4.6 (2014-04-21) +++++++++++++++++++++++++++++++++++++ +- Add ``last_n_logs`` setting to control the return number by fetching logs +- Add ``check_save_conflict`` setting to control saving conflict when LastModifiedBy is not running user + + +Release 0.4.5 (2014-04-20) +++++++++++++++++++++++++++++++++++++ +- Update snippet: ``Exception - try catch finally`` and ``Exception - try catch`` +- Add doc for api.py +- Originally, Keyword completion will exclude the existing-variable completion, now, bug mei le. +- Bug: ``Execute Anonymous`` apex string contains non-english character +- Combine ApexCompletion and SobjectCompletion +- If save error happened, the error line will be highlighted and the highlight line will be canceled after ``delay_seconds_for_hidden_console`` seconds + + +Release 0.4.4 (2014-04-17) +++++++++++++++++++++++++++++++++++++ +- Optimize SOQL Field completion +- Update build-in apex lib +- Update ``query_all`` rest api from ``query`` to ``queryAll`` which is available since winter 14 +- Add ``disable_soql_field_completion`` setting for controlling soql field completion +- In order to keep high efficient for code completion, add some not common used standard sobjects to ``Excluded_Sobjects`` setting for code completion + + +Release 0.4.3 (2014-04-16) +++++++++++++++++++++++++++++++++++++ +- Add ``Search`` and ``Quick Search`` for ``Execute Rest Test`` +- Update ``README.MD`` +- When view is activated, display the default project in the sidebar + + +Release 0.4.2 (2014-04-16) (Millstone for fixing some flaw in completion) +++++++++++++++++++++++++++++++++++++ +- Change ``display_field_name_and_label`` setting default value to false +- BUG: Find variable type by variable name in view (Ignore comment code) +- BUG: Find matched block in visualforce page (the matched region must contains current cursor point) +- Add SOQL field completion, it's very useful feature +- Add a new snippet for ``SELECT * FROM Account``, which is useful for corporation with SOQL field completion + + +Release 0.4.1 (2014-04-14) +++++++++++++++++++++++++++++++++++++ +- Update ``Visualforce`` xPath and Document source code +- Change ``api_version`` back to 29 +- Change the default test org password to updated one + + +Release 0.4.0 (2014-04-14) +++++++++++++++++++++++++++++++++++++ +- ``Track Trace Flag`` expiration date verify logic change +- Return all sobjects when call ``Global Describe`` method in api.py, originally default return value is createable and queryable sobjects + + +Release 0.3.9 (2014-04-12) +++++++++++++++++++++++++++++++++++++ + +- Update project folder structure, you can change it to original strcture by remove the ``src/`` from every component attribute +- If visualforce component attribute type is ``Object`` in visualforce completion, return ```_ + + +Release 0.3.6 (2014-03-30) +++++++++++++++++++++++++++++++++++++ + +- Add thread progress for document reloading +- Add confirm request for document reloading +- Add default ``docs`` setting for `user customization `_ + + +Release 0.3.5 (2014-03-29) +++++++++++++++++++++++++++++++++++++ + +- Clarify Usage of kinds of feature in README.MD + + +Release 0.3.4 (2014-03-26) +++++++++++++++++++++++++++++++++++++ + +- Fix urgent bug for `Issue #22 `_ + + +Release 0.3.3 (2014-03-22) +++++++++++++++++++++++++++++++++++++ + +- Add confirmation request for ``Refresh Component`` +- Add a new command for ``Compile Component`` +- Update README + + +Release 0.3.2 (2014-03-22) +++++++++++++++++++++++++++++++++++++ + +- Upgrade ``xmltodict`` lib to latest +- Add ``namespace`` for standard class in the completion + + +**Release 0.3.1** (Milestone of Code Completion) (2014-03-22) +++++++++++++++++++++++++++++++++++++ + +- Fix bug: ``KeyError: 'symbol_table'`` when save component is not ``ApexClass`` +- Add some new standard class to completion +- Keep the parameter info in the completion result +- Update README.MD + + +Release 0.3.0 (2014-03-20) +++++++++++++++++++++++++++++++++++++ + +- Remove the duplicate ``New Component`` command and add ``New ApexPage`` command in the quick command palette +- Update the apex standard class lib +- Add SymbolTable support for completions (Completion Parser is copy from Mavensmate) + + +Release 0.2.9 (2014-03-20) +++++++++++++++++++++++++++++++++++++ + +- Move the fields describe part from the bottom to top in the sobject describe result +- Change the default apex log level from ``Finest`` to ``Debug`` +- Fix a completion regular expression bug for sobject and class which is start with ``j`` or ``J`` +- When create new component, if there just have only one template, just choose the only one and no need to manually choose it. + + +Release 0.2.8 (2014-03-19) +++++++++++++++++++++++++++++++++++++ + +- Add ``Tooling Query`` for ``Rest Explorer`` +- Add ``SOQL & SOSL`` for Salesforce Document Reference +- Change ``ListDebugLogs`` and ``CreateDebugLog`` commands to ``FetchDebugLog`` and ``TrackDebugLog`` +- Remove shortcuts for four new commands + + +Release 0.2.7 (2014-03-17) +++++++++++++++++++++++++++++++++++++ + +- Update the tabTrigger from muti-bytes to less than 5-bytes for all snippets + + +Release 0.2.6 (2014-03-16) +++++++++++++++++++++++++++++++++++++ + +- Fix the bug of ``Rest Post`` +- Remove ``Request``, ``Application``, ``LogLength``, ``DurationMilliseconds`` from ``List Debug Log`` columns +- Update description for ``display_field_name_and_label`` settings +- Fix bug: saving conflict on the same component + + +Release 0.2.5 (2014-03-15) +++++++++++++++++++++++++++++++++++++ + +- Remove the command ``New Component`` from the side bar +- Remove four shortcut keys for the four new component +- Add a new command for ``Update Project`` +- Update the menu item and shortcuts for ``New Project`` +- Optimize ``Quick Goto`` functionality, just choosing code name will work. + + +Release 0.2.4 (2014-03-11) +++++++++++++++++++++++++++++++++++++ + +- Update README.MD +- Remove shortcut key ``Ctrl+Alt+N`` for creating new component +- Add new shortcut keys for separated four new component commands + + +Release 0.2.3 (2014-03-10) +++++++++++++++++++++++++++++++++++++ + +- Add ``Console Toolkit``, ``Standard Objects``, ``Data Model`` and ``Tooling APi`` references to document list +- Update Main Menu Item +- Open ``View Debug Log Detail`` context menu item +- Add a new command ``Update Project``, you can invoke this command by press ``Alt+f7`` +- Add sublime commands for new commands +- Add time stamp to succeed message for ``Create Code`` and ``Delete Code`` +- Update README.MD for ``Update Project`` + + +Release 0.2.2 (2014-03-07) +++++++++++++++++++++++++++++++++++++ + +- Remove some useless print statement in the document.py +- Update README.MD for latest release + + +Release 0.2.1 (2014-03-07) +++++++++++++++++++++++++++++++++++++ + +- Add ``Rest Api``, ``Visualforce``, ``Chatter Api``, ``Streaming Api`` and ``Bulk Api`` to document list +- Add methods redirect to document list + + +Release 0.2.0 (2014-03-07) +++++++++++++++++++++++++++++++++++++ + +- Change ``default_browser_path`` setting name to ``default_chrome_path`` +- Add a new salesforce reference function from `Salesforce Reference `_ +- Add a new snippet ``Custom Button - Disable Button`` + + +Release 0.1.9 (2014-03-06) +++++++++++++++++++++++++++++++++++++ +- Fix the static resource bug ``Can't convert 'dict' object to str implicitly`` +- When creating trigger, just list the triggerable sobject +- If project is not created, ``New Component`` and ``Refresh Folder`` are disabled +- Update snippets(``Debug - schedule test`` and ``Debug - debug variable``) + + +Pre-release 0.1.8 (2014-03-05) +++++++++++++++++++++++++++++++++++++ + +- When save component and error happened, ``go to`` the error line +- Change the ``new component`` to separate ones +- When creating ``trigger``, we just need to choose sobject and input the trigger name +- When creating ``class``, ``component`` or ``page``, we need to choose template and input the name +- Change the ``Component Template`` +- Change the ``Main Menu`` and ``Sidebar Menu`` +- Move ``Refresh Folder`` function to ``Side Bar`` menu +- When ``New Project``, we need to choose the project, and then create project + + +Release 0.1.7 (2014-03-04) +++++++++++++++++++++++++++++++++++++ + +- If project is not created, ``New Component`` and ``Refresh Folder`` are disabled +- Allow empty json body for ``Post`` Action +- If rest response is list, return the list +- When switching project, stop checking login if login session is already in cache +- Fix a completion bug on ``__kav`` + + +Release 0.1.6 (2014-03-01) +++++++++++++++++++++++++++++++++++++ + +- Update README.MD +- Refractoring api.py + + +Release 0.1.5 (2014-02-28) +++++++++++++++++++++++++++++++++++++ + +- Change new view event type from ``on_new_sync`` to ``on_new`` +- Set the default format for rest test result to ``JavaScript`` +- Add ``Query`` and ``Query All`` function for ``Rest Explorer`` + + +Release 0.1.4 (2014-02-26) +++++++++++++++++++++++++++++++++++++ + +- Update comments for ``toolingapi.sublime-settings`` +- Fix the bug for ``open console`` + + +Release 0.1.3 (2014-02-24) +++++++++++++++++++++++++++++++++++++ + +- Add the support the static resource refresh functionality for the side bar menu +- Add the support the static resource refresh functionality for the context menu +- Add ``Patch`` method for ``Rest Explorer`` + +Release 0.1.2 (2014-02-22) +++++++++++++++++++++++++++++++++++++ + +- Add a new setting ``default_chrome_path`` +- Optimize the ``Rest Explorer`` functionality +- When execute ``Rest Explorer``, if input json body is not valid, allow trying again. + + +Release 0.1.1 (2014-02-22) +++++++++++++++++++++++++++++++++++++ + +- Add snippets for console toolkit +- Add time stamp for success message of save component result +- Remove some useless message from message.py +- Enhancement for `Issue #12 `_ + + +Release 0.1.0 (2014-02-20) +++++++++++++++++++++++++++++++++++++ + +- Add snippets for console toolkit +- Update README +- When menu item is not enabled, show the message in the status bar + + +Release 0.0.9 (2014-02-19) +++++++++++++++++++++++++++++++++++++ + +- Update the snippets for debug +- Add a new snippet "ReRender Form in JavaScript" +- Display the exception when delete MetadataContainerId, ie., unable to obtain exclusive access to this record +- When creating trigger by template, automatically remove the space input by user +- Change the create component input guide + + +Patch for 0.0.8 (2014-02-12) +++++++++++++++++++++++++++++++++++++ + +- Add two template for new component command: Controller and Utility Class +- Add two snippets + + +Patch for 0.0.7 (2014-02-12) +++++++++++++++++++++++++++++++++++++ + +- Fix bug for `Issue #11 `_ + + +Release 0.0.7 (2014-02-08) +++++++++++++++++++++++++++++++++++++ + +- Fix problem when execute anonymous return error +- Change ``disable_keyword_completion`` from true to false + + +Release 0.0.6 (2014-02-08) +++++++++++++++++++++++++++++++++++++ + +- Fix retrieve metadata exception + + +Patch for 0.0.5 (2014-01-31) +++++++++++++++++++++++++++++++++++++ + +- Update README.MD + + +0.0.5 (2014-01-22) +++++++++++++++++++++++++++++++++++++ + +- Add Run All Test functionality +- Adjust the format of test run result of single test class +- Update README.MD + + +0.0.4 (2014-01-21) +++++++++++++++++++++++++++++++++++++ + +- Remove ``Widget.sublime-settings`` from plugin + + +0.0.3 (2014-01-20) +++++++++++++++++++++++++++++++++++++ + +- Add time stamp for all error message displayed in console +- Disable deploy metadata command +- When use bulk CUD, If clipboard content is file, just paste it into file path input panel +- Remove the ``(0)`` from ``Datetime(0)`` and ``Date(0)`` completion for Date and Datetime field + + +Patch 0.0.2 (2014-01-11) +++++++++++++++++++++++++++++++++++++ + +- Change the default test project + + +0.0.2 (2014-01-07) +++++++++++++++++++++++++++++++++++++ + +- Remove ``debug_log_headers`` and ``debug_log_headers_properties`` settings +- Unquote and unescape the error message returned by ``Save to Server`` +- If ``testMethod`` or ``@IsTest`` is in class body, run test command should be enabled + + +Patch for 0.0.1 (2014-01-06) +++++++++++++++++++++++++++++++++++++ + +- When creating new component, if user input is not valid, user can try again if need +- Bug: if project is not created, just create the project for the new component +- Bug: 'BulkApi' object has no attribute 'monitor_batchs' +- Remove ``Widget`` settings and ``Setting - Console`` main menu +- Roll back save_component function to last version + + +0.0.1 (2014-01-05) +++++++++++++++++++++++++++++++++++++ + +- Remove ``Loop - for.sublime-snippet`` snippet +- Remove ``all_views_completions.py`` dependency lib +- Move ``commands``, ``keymap``, ``menus``, ``mousemap``, ``settings`` and ``snippet`` path to new config folder + + +Pre-release x.x.x (2013-12-06 -> 2013-12-31) +++++++++++++++++++++++++++++++++++++++++++++ + +- There is a long confusing term on github version control +- Add picklist value completions feature +- Export Sobject Data Template by Record Type +- Refactoring sobject completion for those complicated orgs +- Add four settings to permit user to close the code completion feature +- Disable keyword completion by default, need enable manually +- Change default workspace to ``C:/ForcedotcomWorkspace`` +- Add support for log levels of anonymous code +- Add a new setting for disabling field name and label completion +- Fix bug for completion: variable in method parameter +- Add picklist value completion support for ``sObject.PicklistFrield =`` +- Allow us to input file path when using Bulk Api to CRUD on data +- Automatically detect BOM header when CRUD on data +- After CRUD on csv data, put the log at the same path of this csv data +- Refactoring code completion for sobject field, relationship and picklist value +- Add command for reloading cache of sobjects +- Refactoring sobject field cache structure for speeding up field completion +- [Fix bulk api issue](https://github.com/kennethreitz/requests/issues/1833) +- Add command for clearing cache of sobjects +- Rearrange main menu items +- Automatically divide upload record by 10K every batch +- Add two settings for bulk load: ``maximum_batch_size`` and ``maximum_batch_bytes`` +- Support data upload for ``ANSI`` and ``UTF-8`` with or without BOM + + +0.0.0 (2013-04-14) +++++++++++++++++++++++++++++++++++++ + +* Birth! + +* Frustration +* Conception diff --git a/config/menus/Context.sublime-menu b/config/menus/Context.sublime-menu index 37488bb..09d5b5c 100644 --- a/config/menus/Context.sublime-menu +++ b/config/menus/Context.sublime-menu @@ -104,6 +104,7 @@ {"caption": "View Code Coverage","command": "view_code_coverage"}, {"caption": "View Debug Log Detail","command": "view_debug_log_detail"}, + {"caption": "View Apex Code Coverage","command": "view_code_coverage_after_sync_test"}, {"caption": "View Debug Only","command": "view_debug_only"}, {"caption": "View Id in Salesforce Web","command": "view_id_in_sfdc_web"}, {"caption": "View in Salesforce Web","command": "show_in_sfdc_web"}, diff --git a/config/messages/3.5.8.md b/config/messages/3.5.8.md new file mode 100644 index 0000000..027a50c --- /dev/null +++ b/config/messages/3.5.8.md @@ -0,0 +1,8 @@ +Build 3.5.8 +----------- +Release Date: 28 Mar 2020 + +* Refined Code coverage functionality: + - View code coverage for certain Apex class/trigger file via context menu + - View code coverage from (async) Test Result via context menu +* Miscellaneous bug fix and update \ No newline at end of file diff --git a/config/settings/package.sublime-settings b/config/settings/package.sublime-settings index 39f099d..650c708 100644 --- a/config/settings/package.sublime-settings +++ b/config/settings/package.sublime-settings @@ -1,6 +1,6 @@ { "name": "haoide", - "version": "3.5.6", + "version": "3.5.8", "description": "haoide is a Sublime Text 3 plugin for Salesforce and used for swift development on Force.com", "author": "Hao Liu", "email": "mouse.mliu@gmail.com", diff --git a/config/settings/toolingapi.sublime-settings b/config/settings/toolingapi.sublime-settings index 26cc3f5..c88c3ea 100644 --- a/config/settings/toolingapi.sublime-settings +++ b/config/settings/toolingapi.sublime-settings @@ -103,7 +103,7 @@ "maximum_concurrent_connections": 30, // API version - "api_version" : 35, + "api_version" : 46, // Browser Path Setting, // You should set a valid browser path, otherwise, it will have problem. diff --git a/config/snippets/Apex/Class Header - class header.sublime-snippet b/config/snippets/Apex/Class Header - class header.sublime-snippet index fcc0873..ac651ca 100644 --- a/config/snippets/Apex/Class Header - class header.sublime-snippet +++ b/config/snippets/Apex/Class Header - class header.sublime-snippet @@ -5,9 +5,9 @@ * Object: $2 * Purpose: $3 * Author: $4 ($5) - * Create Date: 2019-${6:07-15} + * Create Date: 2020-${6:03-27} * Modify History: - * 2019-${6:07-15} $4 ${7:Create this class} + * 2020-${6:03-27} $4 ${7:Create this class} **************************************************************************************************/ ]]> ch diff --git a/messages.json b/messages.json index 7cbba22..5854a94 100644 --- a/messages.json +++ b/messages.json @@ -1,5 +1,6 @@ -{ - "3.5.5": "config/messages/3.5.5.md", - "3.5.6": "config/messages/3.5.6.md", - "install": "config/messages/install.txt" +{ + "3.5.6": "config/messages/3.5.6.md", + "3.5.7": "config/messages/3.5.7.md", + "3.5.8": "config/messages/3.5.8.md", + "install": "config/messages/install.txt" } \ No newline at end of file From 1c2e99c9ae509c8695509adb67c5ca5bfb61ec25 Mon Sep 17 00:00:00 2001 From: Lushang Date: Sat, 28 Mar 2020 11:12:21 +0800 Subject: [PATCH 33/46] Refinement of get lwc template, code coverage --- config/templates/templates.json | 393 +++++++++++++++----------------- main.py | 2 + util.py | 4 +- 3 files changed, 193 insertions(+), 206 deletions(-) diff --git a/config/templates/templates.json b/config/templates/templates.json index f70a14a..2a093fc 100644 --- a/config/templates/templates.json +++ b/config/templates/templates.json @@ -1,205 +1,190 @@ -{ - "Aura": { - "Application": { - "directory": "Aura/Application.app", - "extension": ".app", - "children": ["Controller", "Helper", "Style", "Documentation", "Renderer", "Design", "SVG"] - }, - - "Component": { - "directory": "Aura/Component.cmp", - "extension": ".cmp", - "children": ["Controller", "Helper", "Style", "Documentation", "Renderer", "Design", "SVG"] - }, - - "Interface": { - "directory": "Aura/Interface.intf", - "extension": ".intf", - "children": [] - }, - - "Event": { - "directory": "Aura/Event.evt", - "extension": ".evt", - "children": [] - } - }, - - "AuraElement": { - "Controller": { - "directory": "AuraElement/Controller.js", - "extension": ".js" - }, - - "Helper": { - "directory": "AuraElement/Helper.js", - "extension": ".js" - }, - - "Style": { - "directory": "AuraElement/Style.css", - "extension": ".css" - }, - - "Documentation": { - "directory": "AuraElement/Documentation.auradoc", - "extension": ".auradoc" - }, - - "Renderer": { - "directory": "AuraElement/Renderer.js", - "extension": ".js" - }, - - "Design": { - "directory": "AuraElement/Design.design", - "extension": ".design" - }, - - "SVG": { - "directory": "AuraElement/SVG.svg", - "extension": ".svg" - } - }, - - "lwc": { - "html": { - "directory": "lwc/lwc.html", - "extension": ".html" - }, - "js": { - "directory": "lwc/lwc.js", - "extension": ".js" - }, - "js-meta": { - "directory": "lwc/lwc.js-meta.xml", - "extension": ".js-meta.xml" - } - }, - - "ApexClass": { - "Aura": { - "directory": "ApexClass/Aura.cls", - "extension": ".cls", - "description": "Basic template for Aura Class" - }, - "Basic": { - "directory": "ApexClass/Basic.cls", - "extension": ".cls", - "description": "Basic Pattern" - }, - "Batch": { - "directory": "ApexClass/Batch.cls", - "extension": ".cls", - "description": "Batch Class Template" - }, - "Controller": { - "directory": "ApexClass/Controller.cls", - "extension": ".cls", - "description": "Custom Controller" - }, - "Queueable": { - "directory": "ApexClass/Queueable.cls", - "extension": ".cls", - "description": "Queueable Apex Template" - }, - "StandardController Extension": { - "directory": "ApexClass/StandardController Extension.cls", - "extension": ".cls", - "description": "directory for StandardController" - }, - "StandardSetController Extension": { - "directory": "ApexClass/StandardSetController Extension.cls", - "extension": ".cls", - "description": "directory for StandardSetController" - }, - "Schedule": { - "directory": "ApexClass/Schedule.cls", - "extension": ".cls", - "description": "Schedule Class Template" - }, - "Exception": { - "directory": "ApexClass/Exception.cls", - "extension": ".cls", - "description": "Exception Class" - }, - "Apex REST": { - "directory": "ApexClass/Apex REST.cls", - "extension": ".cls", - "description": "REST Class" - }, - "Test": { - "directory": "ApexClass/Test.cls", - "extension": ".cls", - "description": "Test Class" - }, - "Triggers Template": { - "directory": "ApexClass/Triggers Template.cls", - "extension": ".cls", - "description": "Triggers Template" - }, - "Triggers Implementation": { - "directory": "ApexClass/Triggers Implementation.cls", - "extension": ".cls", - "description": "Implementation Class for Triggers Template" - } - }, - - "ApexTrigger": { - "Basic": { - "directory": "ApexTrigger/Basic.trigger", - "extension": ".trigger", - "description": "Trigger Template" - } - }, - - "ApexComponent": { - "Basic": { - "directory": "ApexComponent/Basic.component", - "extension": ".component", - "description": "component Template" - } - }, - - "ApexPage": { - "Basic": { - "directory": "ApexPage/Basic.page", - "extension": ".page", - "description": "Visualforce Page Template" - } - }, - - "Lwc": { - "HTLM": { - "directory": "Lwc/lwc.html", - "extension": ".html" - }, - - "JavaScript": { - "directory": "Lwc/lwc.js", - "extension": ".js" - }, - - "Configuration": { - "directory": "Lwc/lwc.js-meta.xml", - "extension": ".js-meta.xml" - } - }, - - "LwcElement": { - "AdditionalJS": { - "directory": "LwcElement/Additional.js", - "extension": ".js" - }, - - "CSS": { - "directory": "LwcElement/Style.css", - "extension": ".css" - }, - - "SVG": { - "directory": "LwcElement/SVG.svg", - "extension": ".svg" - } - } +{ + "Aura": { + "Application": { + "directory": "Aura/Application.app", + "extension": ".app", + "children": ["Controller", "Helper", "Style", "Documentation", "Renderer", "Design", "SVG"] + }, + + "Component": { + "directory": "Aura/Component.cmp", + "extension": ".cmp", + "children": ["Controller", "Helper", "Style", "Documentation", "Renderer", "Design", "SVG"] + }, + + "Interface": { + "directory": "Aura/Interface.intf", + "extension": ".intf", + "children": [] + }, + + "Event": { + "directory": "Aura/Event.evt", + "extension": ".evt", + "children": [] + } + }, + + "AuraElement": { + "Controller": { + "directory": "AuraElement/Controller.js", + "extension": ".js" + }, + + "Helper": { + "directory": "AuraElement/Helper.js", + "extension": ".js" + }, + + "Style": { + "directory": "AuraElement/Style.css", + "extension": ".css" + }, + + "Documentation": { + "directory": "AuraElement/Documentation.auradoc", + "extension": ".auradoc" + }, + + "Renderer": { + "directory": "AuraElement/Renderer.js", + "extension": ".js" + }, + + "Design": { + "directory": "AuraElement/Design.design", + "extension": ".design" + }, + + "SVG": { + "directory": "AuraElement/SVG.svg", + "extension": ".svg" + } + }, + + "ApexClass": { + "Aura": { + "directory": "ApexClass/Aura.cls", + "extension": ".cls", + "description": "Basic template for Aura Class" + }, + "Basic": { + "directory": "ApexClass/Basic.cls", + "extension": ".cls", + "description": "Basic Pattern" + }, + "Batch": { + "directory": "ApexClass/Batch.cls", + "extension": ".cls", + "description": "Batch Class Template" + }, + "Controller": { + "directory": "ApexClass/Controller.cls", + "extension": ".cls", + "description": "Custom Controller" + }, + "Queueable": { + "directory": "ApexClass/Queueable.cls", + "extension": ".cls", + "description": "Queueable Apex Template" + }, + "StandardController Extension": { + "directory": "ApexClass/StandardController Extension.cls", + "extension": ".cls", + "description": "directory for StandardController" + }, + "StandardSetController Extension": { + "directory": "ApexClass/StandardSetController Extension.cls", + "extension": ".cls", + "description": "directory for StandardSetController" + }, + "Schedule": { + "directory": "ApexClass/Schedule.cls", + "extension": ".cls", + "description": "Schedule Class Template" + }, + "Exception": { + "directory": "ApexClass/Exception.cls", + "extension": ".cls", + "description": "Exception Class" + }, + "Apex REST": { + "directory": "ApexClass/Apex REST.cls", + "extension": ".cls", + "description": "REST Class" + }, + "Test": { + "directory": "ApexClass/Test.cls", + "extension": ".cls", + "description": "Test Class" + }, + "Triggers Template": { + "directory": "ApexClass/Triggers Template.cls", + "extension": ".cls", + "description": "Triggers Template" + }, + "Triggers Implementation": { + "directory": "ApexClass/Triggers Implementation.cls", + "extension": ".cls", + "description": "Implementation Class for Triggers Template" + } + }, + + "ApexTrigger": { + "Basic": { + "directory": "ApexTrigger/Basic.trigger", + "extension": ".trigger", + "description": "Trigger Template" + } + }, + + "ApexComponent": { + "Basic": { + "directory": "ApexComponent/Basic.component", + "extension": ".component", + "description": "component Template" + } + }, + + "ApexPage": { + "Basic": { + "directory": "ApexPage/Basic.page", + "extension": ".page", + "description": "Visualforce Page Template" + } + }, + + "Lwc": { + "HTLM": { + "directory": "Lwc/lwc.html", + "extension": ".html" + }, + + "JavaScript": { + "directory": "Lwc/lwc.js", + "extension": ".js" + }, + + "Configuration": { + "directory": "Lwc/lwc.js-meta.xml", + "extension": ".js-meta.xml" + } + }, + + "LwcElement": { + "AdditionalJS": { + "directory": "LwcElement/Additional.js", + "extension": ".js" + }, + + "CSS": { + "directory": "LwcElement/Style.css", + "extension": ".css" + }, + + "SVG": { + "directory": "LwcElement/SVG.svg", + "extension": ".svg" + } + } } \ No newline at end of file diff --git a/main.py b/main.py index a796f55..2e542be 100644 --- a/main.py +++ b/main.py @@ -1848,6 +1848,8 @@ def run(self, edit): trigger_path = os.path.join(work_dir, 'src', 'triggers', self.file_name + '.trigger') _path = class_path if os.path.isfile(class_path) else trigger_path + if not os.path.isfile(_path): + return with open(_path, encoding="utf-8") as fp: file_content = fp.read() if record and record.get("Coverage"): diff --git a/util.py b/util.py index 41fd710..50757a2 100644 --- a/util.py +++ b/util.py @@ -36,8 +36,8 @@ def load_templates(): os.makedirs(target_dir) templates_dir = os.path.join(target_dir, "templates.json") - lwc_dir = os.path.join(target_dir, "Lwc") # Check exist lwc logic - lwc_ele_dir = os.path.join(target_dir, "LwcElement") # Check exist lwc element logic + lwc_dir = os.path.join(target_dir, "Lwc") # Check exist lwc logic + lwc_ele_dir = os.path.join(target_dir, "LwcElement") # Check exist lwc element logic # for the updating of Lwc, old project should update the template files if not os.path.isfile(templates_dir) or not os.path.exists(lwc_dir) or not os.path.exists(lwc_ele_dir): From b0eae4ccf619e0950686997cea51aa7a379b9986 Mon Sep 17 00:00:00 2001 From: Lushang Date: Sun, 29 Mar 2020 13:47:37 +0800 Subject: [PATCH 34/46] Implemented Save lwc's resource file to Salesforce --- main.py | 9 ++++- processor.py | 49 +++++++++++++++--------- salesforce/api/metadata.py | 20 ++++++---- salesforce/api/tooling.py | 77 +++++++++++++++++++++----------------- util.py | 30 ++++++++++----- 5 files changed, 114 insertions(+), 71 deletions(-) diff --git a/main.py b/main.py index 2e542be..84b74a7 100644 --- a/main.py +++ b/main.py @@ -2294,7 +2294,11 @@ def create_component(self): self.markup_or_body, file_name) + class SaveToServer(sublime_plugin.TextCommand): + """ + Save Metadata to Server using Tooling API or Metadata API + """ def run(self, edit, is_check_only=False): # Check whether need confirm settings = context.get_settings() @@ -2311,9 +2315,10 @@ def run(self, edit, is_check_only=False): processor.handle_save_to_server(self.view.file_name(), is_check_only) def is_enabled(self): - if not self.view or not self.view.file_name(): return False + if not self.view or not self.view.file_name(): + return False attributes = util.get_file_attributes(self.view.file_name()) - if attributes["metadata_folder"] not in ["classes", "components", "pages", "triggers", "aura"]: + if attributes["metadata_folder"] not in ["classes", "components", "pages", "triggers", "aura", "lwc"]: return False return util.check_enabled(self.view.file_name()) diff --git a/processor.py b/processor.py index a9c98be..cd1f8b3 100644 --- a/processor.py +++ b/processor.py @@ -1582,9 +1582,9 @@ def handle_thread(thread, timeout): def handle_retrieve_package(types, extract_to, source_org=None, ignore_package_xml=False, timeout=120): - def handle_thread(thread, timeout): - if thread.is_alive(): - sublime.set_timeout(lambda: handle_thread(thread, timeout), timeout) + def handle_thread(_thread, timeout): + if _thread.is_alive(): + sublime.set_timeout(lambda: handle_thread(_thread, timeout), timeout) return # If source_org is not None, we need to switch project back @@ -1593,11 +1593,11 @@ def handle_thread(thread, timeout): # Extract the zipFile to extract_to if api.result and api.result["success"]: - thread = threading.Thread(target=util.extract_encoded_zipfile, - args=(api.result["zipFile"], extract_to, ignore_package_xml,)) - thread.start() + _thread = threading.Thread(target=util.extract_encoded_zipfile, + args=(api.result["zipFile"], extract_to, ignore_package_xml,)) + _thread.start() - # Apex Code Cache + # Code Cache if isinstance(api.result.get("fileProperties", None), list): util.reload_file_attributes( api.result["fileProperties"], @@ -1610,11 +1610,19 @@ def handle_thread(thread, timeout): thread = threading.Thread(target=api.retrieve, args=({"types": types},)) thread.start() handle_thread(thread, timeout) - ThreadProgress(api, thread, "Retrieve File From Server", + ThreadProgress(api, thread, + "Retrieve File From Server", "Retrieve File From Server Succeed") def handle_save_to_server(file_name, is_check_only=False, timeout=120): + """ + Handle Save metadata to Salesforce + @param file_name: file name with path format + @param is_check_only: only check the file from Salesforce, do not really save + @param timeout: timeout in seconds + @return: None + """ def handle_thread(thread, timeout): if thread.is_alive(): sublime.set_timeout(lambda: handle_thread(thread, timeout), timeout) @@ -1679,15 +1687,18 @@ def handle_thread(thread, timeout): # Because error line in page is always at the line 1, so just work in class or trigger elif "success" in result and not result["success"]: # Maybe network issue - if "problem" not in result: return + _message = "Unknown Problem!" + if "problem" in result: + _message = "Compile Error for %s: %s at line %s column %s" % ( + file_base_name, + result["problem"], + result["lineNumber"], + result["columnNumber"] + ) + elif "message" in result: + _message = result["message"] - message = "Compile Error for %s: %s at line %s column %s" % ( - file_base_name, - result["problem"], - result["lineNumber"], - result["columnNumber"] - ) - Printer.get('log').write(message) + Printer.get('log').write(_message) # Get the active view view = util.get_view_by_file_name(file_name) @@ -1753,8 +1764,10 @@ def handle_thread(thread, timeout): Printer.get('log').write_start().write("Start to %s %s" % (compile_or_save, file_base_name)) api = ToolingApi(settings) - if component_attribute["type"] in ["AuraDefinitionBundle", "AuraDefinition"]: - target = api.save_aura_to_server + lngt_meta_type = ["AuraDefinitionBundle", "AuraDefinition", + "LightningComponentBundle", "LightningComponentResource"] + if component_attribute["type"] in lngt_meta_type: + target = api.save_lightning_to_server else: target = api.save_to_server thread = threading.Thread(target=target, diff --git a/salesforce/api/metadata.py b/salesforce/api/metadata.py index 65bef25..a201f93 100644 --- a/salesforce/api/metadata.py +++ b/salesforce/api/metadata.py @@ -179,7 +179,7 @@ def retrieve(self, options, timeout=120): Arguments: - * options -- {"types" : types, "package_names": package_names} + * options -- {"types" : types_dict, "package_names": package_names} """ result = self.login() if not result or not result["success"]: @@ -223,8 +223,8 @@ def retrieve(self, options, timeout=120): # Post retrieve request try: - response = requests.post(self.metadata_url, soap_body, verify=False, - headers=self.headers, timeout=120) + response = requests.post(self.metadata_url, soap_body, verify=False, + headers=self.headers, timeout=120) except requests.exceptions.RequestException as e: self.result = { "Error Message": "Network connection timeout when issuing retrieve request", @@ -322,11 +322,13 @@ def retrieve(self, options, timeout=120): # Total time total_seconds = (datetime.datetime.now() - start_time).seconds Printer.get('log').write("Total time: %s seconds" % total_seconds, False) + # print('meta retrive result', result) self.result = result def prepare_members(self, _types, list_package_for_all=False): - if not self.login(): return + if not self.login(): + return if list_package_for_all: Printer.get("log").write_start() @@ -335,7 +337,8 @@ def prepare_members(self, _types, list_package_for_all=False): # EmailFolder, DocumentFolder, DashboardFolder and ReportFolder records = [] for _type in _types: - if "*" not in _types[_type]: continue + if "*" not in _types[_type]: + continue if _type in self.settings["metadata_objects_in_folder"]: # List package for ``suffix.capitalize() + 'Folder'`` metadata_object = _type + "Folder" if _type != "EmailTemplate" else "EmailFolder" @@ -377,19 +380,20 @@ def prepare_members(self, _types, list_package_for_all=False): # In order to speed up retrieve request, we will not list package for them # just when we want to get full copy or build package.xml, we will list_package for all - # Note: CustomObject must be retrieved by ``list_package`` request + # Note: CustomObject must be retrieved by ``list_package`` request # list package for metadata object which supports wildcard retrieve _types_list = [] + # print("retrieve types: ", _types) if not list_package_for_all: if "CustomObject" in _types and "*" in _types["CustomObject"]: _types_list.append("CustomObject") - print(_types) if "InstalledPackage" in _types and "*" in _types["InstalledPackage"]: _types_list.append("InstalledPackage") else: for _type in _types: - if "*" not in _types[_type]: continue + if "*" not in _types[_type]: + continue if _type not in self.settings["metadata_objects_in_folder"]: _types_list.append(_type) diff --git a/salesforce/api/tooling.py b/salesforce/api/tooling.py index bb0c636..ff09e9a 100644 --- a/salesforce/api/tooling.py +++ b/salesforce/api/tooling.py @@ -958,7 +958,7 @@ def save_to_server(self, component_attribute, body, is_check_only, check_save_co # Component Attribute component_type = component_attribute["type"] component_id = component_attribute["id"] - component_body = component_attribute["body"] + # component_body = component_attribute["body"] if self.settings["check_save_conflict"] and not is_check_only and check_save_conflict: Printer.get('log').write("Start to check saving conflict") @@ -1159,45 +1159,54 @@ def save_to_server(self, component_attribute, body, is_check_only, check_save_co # Result used in thread invoke self.result = return_result - def save_aura_to_server(self, component_attribute, body, check_save_conflict=True): - """ Save AuraDefinition such as Lightning component makeup, controller and helper + def save_lightning_to_server(self, component_attribute, body, check_save_conflict=True): + """ + Save Lightning AuraDefinition or LightningComponentResource such as component makeup, controller and helper or + Lightning Web component teampl to Salesforce Arguments: - - * component_attribute - attribute of component, e.g., component id, url - * body -- Code content - * check_save_conflict -- indicate whether to check saving conflict + @param component_attribute: attribute of component, e.g., component id, url + @param body: Code content + @param check_save_conflict: indicate whether to check saving conflict + @return: saving result """ def handle_error_message(result): + if self.settings["debug_mode"]: + print('Error: ', result) _result = dict() _result["success"] = False _result["errorCode"] = result["errorCode"] - if "\n" in result["message"]: - error_messages = result["message"].split('\n') - if "CSS Parser" in error_messages[0] : - error_msg = error_messages[2] - _result["problem"] = error_msg - error_line_info = error_msg[error_msg.find("(")+1: error_msg.find(")")] - _result["lineNumber"] = error_line_info.split(",")[0][5:] - _result["columnNumber"] = error_line_info.split(",")[1][5:] + try: + if "\n" in result["message"]: + error_messages = result["message"].split('\n') + if "CSS Parser" in error_messages[0] : + error_msg = error_messages[2] + _result["problem"] = error_msg + error_line_info = error_msg[error_msg.find("(")+1: error_msg.find(")")] + _result["lineNumber"] = error_line_info.split(",")[0][5:] + _result["columnNumber"] = error_line_info.split(",")[1][5:] + else: + error_base_info = error_messages[0].split(': ') + error_line_info = error_base_info[1].split(':')[1] + error_line_info = error_line_info[1 : len(error_line_info) - 1] + _result['id'] = error_base_info[0] + _result["lineNumber"] = error_line_info.split(',')[0] + _result["columnNumber"] = error_line_info.split(',')[1] + _result["problem"] = error_messages[1] else: - error_base_info = error_messages[0].split(': ') - error_line_info = error_base_info[1].split(':')[1] - error_line_info = error_line_info[1 : len(error_line_info) - 1] - _result['id'] = error_base_info[0] - _result["lineNumber"] = error_line_info.split(',')[0] - _result["columnNumber"] = error_line_info.split(',')[1] - _result["problem"] = error_messages[1] - else: - _result["problem"] = result["message"] - _result['id'] = result["message"].split(':')[0] - m = re.search(r'\[\d+,\s*\d+\]', result["message"]) - if m: - col_row = m.group(0) - col_row = col_row[1:len(col_row)-1] - _result["lineNumber"] = col_row.split(',')[0] - _result["columnNumber"] = col_row.split(',')[1] + _result["problem"] = result["message"] + _result['id'] = result["message"].split(':')[0] + m = re.search(r'\[\d+,\s*\d+\]', result["message"]) + if m: + col_row = m.group(0) + col_row = col_row[1:len(col_row)-1] + _result["lineNumber"] = col_row.split(',')[0] + _result["columnNumber"] = col_row.split(',')[1] + except Exception as _ex: + if self.settings["debug_mode"]: + print('Error parsing error result: ', _ex) + _result["message"] = result["message"] return _result # 1. Firstly Login @@ -1207,10 +1216,10 @@ def handle_error_message(result): return self.result # Component Attribute - # component_type = component_attribute["type"] - component_type = 'AuraDefinition' + bundle_type = component_attribute["type"] + component_type = 'AuraDefinition' if bundle_type == "AuraDefinitionBundle" else 'LightningComponentResource' component_id = component_attribute["id"] - component_url = self.base_url + '/tooling/sobjects/AuraDefinition/' + component_id + component_url = self.base_url + '/tooling/sobjects/' + component_type + '/' + component_id # 2. Check conflict if self.settings["check_save_conflict"] and check_save_conflict: diff --git a/util.py b/util.py index 50757a2..dd09c0d 100644 --- a/util.py +++ b/util.py @@ -1687,13 +1687,21 @@ def extract_zipfile(zipfile_path, extract_to): zfile.close() + def extract_file(zipfile_path, extract_to, ignore_package_xml=False): - zfile = zipfile.ZipFile(zipfile_path, 'r') - for filename in zfile.namelist(): + """ + extract packaged Zip file from metadata API + @param zipfile_path: + @param extract_to: + @param ignore_package_xml: + @return: + """ + zip_file = zipfile.ZipFile(zipfile_path, 'r') + for filename in zip_file.namelist(): if filename.endswith('/'): continue - if ignore_package_xml and filename == "unpackaged/package.xml": + if ignore_package_xml and filename == "unpackaged/package.xml": continue if filename.startswith("unpackaged"): @@ -1705,9 +1713,9 @@ def extract_file(zipfile_path, extract_to, ignore_package_xml=False): os.makedirs(os.path.dirname(f)) with open(f, "wb") as fp: - fp.write(zfile.read(filename)) + fp.write(zip_file.read(filename)) - zfile.close() + zip_file.close() def extract_zip(base64String, extract_to): """ @@ -1802,6 +1810,8 @@ def reload_file_attributes(file_properties, settings=None, append=False): "ApexComponent": "Markup" } + # print(file_properties) + # If the package only contains `package.xml` if isinstance(file_properties, dict): file_properties = [file_properties] @@ -2194,8 +2204,9 @@ def parse_sync_test_coverage(result): allrows.append("\n".join(success_row)) allrows.append("~" * 80) - allrows.append("Follow the instruction as below, you can quickly view code coverage,") - allrows.append(" * Put focus on code name, hold down 'alt' and Dblclick the 'Left Mouse'") + allrows.append("Apex Class Or Trigger Code Coverage Statistics:") + # allrows.append("Follow the instruction as below, you can quickly view code coverage,") + # allrows.append(" * Put focus on code name, hold down 'alt' and Dblclick the 'Left Mouse'") header_width = { "Type": 15, "Name": 50, "Percent": 10, "Lines": 10 @@ -3148,7 +3159,8 @@ def check_enabled(file_name, check_cache=True): * Bool -- check whether current file is apex code file and has local cache """ - if not file_name: return False + if not file_name: + return False # Get toolingapi settings settings = context.get_settings() @@ -3593,7 +3605,7 @@ def export_profile_settings(): if sobject in profile_settings[profile]["objectPermissions"]: object_permission = profile_settings[profile]["objectPermissions"][sobject] for crud in cruds: - rows.append("√" if object_permission[crud] == "true" else "") + rows.append("True" if object_permission[crud] == "true" else "") else: for crud in cruds: rows.append("") From f5a52355f45d83fc66d5e8f9b7df421a5be1024b Mon Sep 17 00:00:00 2001 From: Lushang Date: Sun, 29 Mar 2020 13:52:06 +0800 Subject: [PATCH 35/46] Update documentation --- README.md | 5 ++- config/menus/Side bar.sublime-menu | 7 --- docs/completion.md | 22 +++++----- docs/debug.md | 7 ++- docs/lwc.md | 69 +++++++++++++++++++++++++++--- docs/snippets.md | 6 +++ 6 files changed, 87 insertions(+), 29 deletions(-) diff --git a/README.md b/README.md index 83c45a1..27b8a9a 100644 --- a/README.md +++ b/README.md @@ -43,15 +43,16 @@ If you don't want to keep your user credential information in the plugin , you j * Debug and Test * Retrieve * Deploy +* Lightning Aura Component Development +* Lightning Web Component Development * Static Resource Bundle * Export CSV * Salesforce Utilities * Convert JSON to Apex -* REST Test +* REST API Support * Data Loader * Document Quick Reference * Plugin Operation -* Lightning Development * Completions Demo * Request Proxies diff --git a/config/menus/Side bar.sublime-menu b/config/menus/Side bar.sublime-menu index 1773989..3e0753c 100644 --- a/config/menus/Side bar.sublime-menu +++ b/config/menus/Side bar.sublime-menu @@ -153,13 +153,6 @@ "args": {"dirs": [], "element": "SVG"} }, - // do not support additional js current - // { -// "caption": "Add Lwc Additional JS", -// "command": "create_lwc_element", -// "args": {"dirs": [], "element": "AdditionalJS"} -// }, - {"caption": "-"}, { diff --git a/docs/completion.md b/docs/completion.md index b319db7..23b60cf 100644 --- a/docs/completion.md +++ b/docs/completion.md @@ -1,7 +1,11 @@ ## Completions +HaoIDE supports following auto completion: * Visualforce Components Completion * HTML Standard Tag Completion * Apex Code Completion +* Lightning Aura Standard/Custom Component Completion +* Lightning Web Standard Component Completion +* Lightning Design System Css tag Completion * Package.xml Completion ### Visualforce Page Completion @@ -9,23 +13,17 @@ - Component Name Completion + After input ``<`` in visualforce page, plugin will list all standard components + After input tag prefix, for example, `` - Component Attribute Completion + Input ``space`` after tage name, for example, `` - Component Attribute Value Completion + Input ``=`` after attribute name, if this attribute has fixed values, plugin will list all available values for it, for example, if you input `` - - Sobject names and custom classes completion + - SObject names and custom classes completion * If you input `` - Quick creation for controller or extension * Input ``#`` after controller or extension name, if it is already exist, plugin will show you the error message, otherwise, plugin will create the controller or extension for you -
- Custom Field Completion in visualforce Page + After input ``acc.``, if acc is defined as ``Account`` Type in the corresponding controller or extension, plugin will list the available fields and relationship names -
* Custom Component - After input ``, plugin will read attributes from the corresponding component file if exists @@ -42,7 +40,7 @@ * When you input any characters after space in the class attribute, plugin will list all available bootstrap3 classes, for example, if you have input ``class="btn "``, when you input any characters at the focus place, you will see the completion ### Settings for Visualforce and HTML completion -```json +``` // Indicate whether disable attribute completion "disable_component_attribute_completion": false, @@ -65,13 +63,13 @@ * Keyword completion * Stand Class Completion * Custom Class Completion -* Sobject fields completion - - [EUR] notation for field, +* SObject fields completion + - \[EUR] notation for field, - ``E`` means External - ``U`` means Unique - ``R`` means Required -* Sobject relationship name completion -* Sobject relationship fields completion +* SObject relationship name completion +* SObject relationship fields completion * Picklist value completion after input ``Account.Type =`` * Visualforce page completion after input ``page.`` * [SOQL Fields completion](https://github.com/xjsender/SublimeApexScreenshot/raw/master/BuildSOQL.gif) diff --git a/docs/debug.md b/docs/debug.md index 797de72..0c7e616 100644 --- a/docs/debug.md +++ b/docs/debug.md @@ -69,11 +69,14 @@ There has a ```log_levels``` setting in the default settings to control the anon - Put the focus in the LogId got by fetch command, press alt and click left button, the debug log detail will be retrieved and displayed in the new view. ## Run Test -* This feature will be deprecated in the release v3.1.5, because this feature is executed in async way, it's very slow. +* Click ``HaoIDE > Run Test Class`` in the context menu or press ctrl+alt+t in opened test class file +* You can get the *Test Result* and related coverage report after the test run async +* In the Test Result file, you can view the debug log or certain class/trigger code coverage via contest menu command +* The coverage information will be kept in ``.config/coverages.json`` cache file, when you execute ``view_code_coverage`` command next time, plugin will read code coverage information from here ## Run Sync Test * Click ``HaoIDE > Run Sync Test`` in the context menu or press alt/command + shift + u, you can get the test run result and related coverage report -* The coverage information will be kept in ``.config/coverages.json`` cache file, when you execute ``view_code_coverage`` command next time, plugin will read code coverage information from here +* You cannot get certain class/trigger code coverage since Salesforce Tooling API does not return Correct code coverage now ## View Code Coverage * This feature just works when api version is >= 29.0 diff --git a/docs/lwc.md b/docs/lwc.md index 3b35db6..341b2ea 100644 --- a/docs/lwc.md +++ b/docs/lwc.md @@ -1,9 +1,15 @@ -# Lightning Web Componnent - Lightning web components are custom HTML elements built using HTML and modern JavaScript. +# Lightning Web Component + Lightning web components (`lwc`) are custom HTML elements built using HTML and modern JavaScript. + +**This feature works when api version is >= 45.0** ## Create Lightning Web Component -For better convenience, will create the `lwc` as `LightningComponentBundle` with three `LwcResources`: HTML File, JavaScript File and Configuration File. +Create `lwc` by clicking `HaoIDE -> New -> New Lightning Web Component` from the menu, +and inputting the valid `lwc` name. + +For better convenience, will create the `lwc` as `LightningComponentBundle` with three `LwcResources` +-- HTML file, JavaScript file and configuration file under the component's folder. ``` myComponent @@ -13,13 +19,64 @@ For better convenience, will create the `lwc` as `LightningComponentBundle` with ``` ## Add CSS File +From the component folder or file's sidebar context menu, +click `HaoIDE -> Create Lwc Style`. ## Add SVG Icon +From the component folder or file's sidebar context menu, +click `HaoIDE -> Create Lwc SVG`. + +## Add Additional JavaScript File(s) + +You can create Additional JavaScript files under the component's folder by yourself. -## Add Additional JavaScript File +Notice: +>These additional JavaScript files must be ES6 modules and must have names that are unique within the component’s folder. ## Component Tests -## Destruct File +You can create Jest tests files following the official guide by yourself: + +>To create Jest tests for a component, create a folder called `__tests__` at the top level of the component’s folder. +Save the tests inside the `__tests__` folder. +Test files must have names that end in “.js”, and we recommend that tests end in “.test.js. +>You can have a single test file with all of your component tests, or you can have multiple files to organize related tests. Test files can be placed in sub folders. +## Retrieve Bundle/File +Two Approaches: + +1. From the component folder or file's sidebar context menu, +click `HaoIDE -> Retrieve Lightning From Server`. +2. From the opened component file's context menu, click `HaoIDE -> Retrieve From Server` or +`HaoIDE -> Retrieve From This Server`. + +## Deploy Bundle/File +Two Approaches: + +1. From the component folder or file's sidebar context menu, +click `HaoIDE -> Deploy Lightning From Server`. +2. From the opened component file's context menu, click `HaoIDE -> Deploy To Server` or +`HaoIDE -> Deploy To This Server`. + +## Save Component File to Server +`lwc`'s HTML markup, JavaScript code, CSS file, SVG resource, additional JS files +can save to Salesforce as `LightningComponentResource` separately. + +From the opened component file's context menu, click `HaoIDE -> Deploy From Server` or +`HaoIDE -> Save To Server`. or simply press `ctrl+alt+s`(Windows). + +If you cannot save certain file to server, try retrieving it from server first. + +**Notice:** +XML configuration file (`js-meta.xml`) cannot save to server since the Metadata API does not support it. + +## Destruct Component +Two Approaches: + +1. From the component folder or file's sidebar context menu, +click `HaoIDE -> Destruct Lightning From Server`. +2. From the opened component file's context menu, click `HaoIDE -> Destruct From Server`. + +## Reference +[Lightning Web Components Developer Guide][1] -## Destruct lwc \ No newline at end of file +[1]: https://developer.salesforce.com/docs/atlas.en-us.lwc.meta/lwc/lwc_intro.htm \ No newline at end of file diff --git a/docs/snippets.md b/docs/snippets.md index a276ff8..1a6b5e7 100644 --- a/docs/snippets.md +++ b/docs/snippets.md @@ -62,6 +62,12 @@ source.java, source.apex Class Template + + Apex + ch + source.java, source.apex + Class Header + Apex class comments From 4d144ac1117eb98057de1f32075694b93c81c976 Mon Sep 17 00:00:00 2001 From: Lushang Date: Sun, 29 Mar 2020 13:59:54 +0800 Subject: [PATCH 36/46] Build 3.5.9 --- config/messages/3.5.9.md | 10 ++++++++++ config/settings/package.sublime-settings | 4 ++-- messages.json | 2 +- 3 files changed, 13 insertions(+), 3 deletions(-) create mode 100644 config/messages/3.5.9.md diff --git a/config/messages/3.5.9.md b/config/messages/3.5.9.md new file mode 100644 index 0000000..8e17aae --- /dev/null +++ b/config/messages/3.5.9.md @@ -0,0 +1,10 @@ +Build 3.5.9 +----------- +Release Date: 29 Mar 2020 + +* Implemente Save lwc file to Server + - Now you can save `lwc` HTML markup, JavaScript code, CSS file, SVG resource and additional JS files + to Salesforce separately +* Update documents + - updated documentations on auto completion, debug, lwc and etc. +* Miscellaneous bug fix and refinement \ No newline at end of file diff --git a/config/settings/package.sublime-settings b/config/settings/package.sublime-settings index 650c708..ec4d9eb 100644 --- a/config/settings/package.sublime-settings +++ b/config/settings/package.sublime-settings @@ -1,8 +1,8 @@ { "name": "haoide", - "version": "3.5.8", + "version": "3.5.9", "description": "haoide is a Sublime Text 3 plugin for Salesforce and used for swift development on Force.com", - "author": "Hao Liu", + "author": "Hao Liu @ 2013-2019", "email": "mouse.mliu@gmail.com", "homepage": "https://github.com/xjsender/haoide", "issue_url": "https://github.com/xjsender/haoide/issues", diff --git a/messages.json b/messages.json index 5854a94..6ceafc0 100644 --- a/messages.json +++ b/messages.json @@ -1,6 +1,6 @@ { - "3.5.6": "config/messages/3.5.6.md", "3.5.7": "config/messages/3.5.7.md", "3.5.8": "config/messages/3.5.8.md", + "3.5.9": "config/messages/3.5.9.md", "install": "config/messages/install.txt" } \ No newline at end of file From 6a3e8db78cb01e761a774e150417dd2a48fbfff5 Mon Sep 17 00:00:00 2001 From: Lushang Date: Mon, 30 Mar 2020 17:12:44 +0800 Subject: [PATCH 37/46] fixed typo of `Lwc` --- lwc.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lwc.py b/lwc.py index deb3489..b21cdd4 100644 --- a/lwc.py +++ b/lwc.py @@ -48,7 +48,7 @@ def on_input(self, lwc_name): # Get template attribute templates = util.load_templates() - template_bundle = templates.get("lwc") + template_bundle = templates.get("Lwc") for tpl_name in template_bundle: template = template_bundle.get(tpl_name) with open(os.path.join(self._workspace, ".templates", template["directory"])) as fp: From e64eba2e4de008389b1845d044699f1ef1a04e20 Mon Sep 17 00:00:00 2001 From: Lushang Date: Mon, 30 Mar 2020 22:17:18 +0800 Subject: [PATCH 38/46] Update component metadata cache after creating Lightning Web Component --- main.py | 30 +++++++++++++++++++------- processor.py | 61 ++++++++++++++++++++++++++++++++++++---------------- 2 files changed, 64 insertions(+), 27 deletions(-) diff --git a/main.py b/main.py index 84b74a7..800a6fc 100644 --- a/main.py +++ b/main.py @@ -458,7 +458,8 @@ def __init__(self, *args, **kwargs): def run(self): message = "Are you sure you really want to reload symbol table cache?" - if not sublime.ok_cancel_dialog(message, "Confirm Reload"): return + if not sublime.ok_cancel_dialog(message, "Confirm Reload"): + return processor.handle_reload_symbol_tables() @@ -882,7 +883,11 @@ def is_enabled(self): return True + class RetrieveFileFromServer(sublime_plugin.TextCommand): + """ + Retrieve Single File From Salesforce + """ def run(self, edit, switch=True): files = [self.view.file_name()] sublime.active_window().run_command("retrieve_files_from_server", { @@ -904,17 +909,21 @@ def is_enabled(self): def is_visible(self): return self.is_enabled() + class RetrieveFilesFromServer(sublime_plugin.WindowCommand): + """ + Retrieve List of files from Salesforce + """ def __init__(self, *args, **kwargs): super(RetrieveFilesFromServer, self).__init__(*args, **kwargs) def run(self, files, switch=True, source_org=None, confirmed=False, extract_to=None): # Prevent duplicate confirmation if not confirmed: - message = "Confirm retrieving %s from server?" % ( + _message = "Confirm retrieving %s from server?" % ( "these files" if len(files) > 1 else "this file" ) - if not sublime.ok_cancel_dialog(message, "Confirm?"): + if not sublime.ok_cancel_dialog(_message, "Confirm?"): return settings = context.get_settings() @@ -949,7 +958,7 @@ def run(self, files, switch=True, source_org=None, confirmed=False, extract_to=N name = "%s/%s" % (attributes["folder"], attributes["name"]) # If file is AuraDefinitionBundle, we need to add folder - if metadata_folder == "aura": + if metadata_folder in ["aura", "lwc"]: name = "%s" % attributes["folder"] if metadata_object in types: @@ -957,14 +966,16 @@ def run(self, files, switch=True, source_org=None, confirmed=False, extract_to=N else: types[metadata_object] = [name] - processor.handle_retrieve_package(types, extract_to, - source_org=source_org, ignore_package_xml=True) + processor.handle_retrieve_package(types, extract_to, + source_org=source_org, ignore_package_xml=True) def is_visible(self, files): - if not files: return False + if not files: + return False settings = context.get_settings() for _file in files: - if not os.path.isfile(_file): continue # Ignore folder + if not os.path.isfile(_file): + continue # Ignore folder metadata_folder = util.get_metadata_folder(_file) if metadata_folder not in settings["all_metadata_folders"]: return False if not util.check_enabled(_file, check_cache=False): @@ -1175,6 +1186,9 @@ def is_visible(self): return self.is_enabled() class DeployFileToThisServer(sublime_plugin.TextCommand): + """ + Deploy a opened file to current active Salesforce org + """ def run(self, edit): files = [self.view.file_name()] sublime.active_window().run_command("deploy_files_to_server", { diff --git a/processor.py b/processor.py index cd1f8b3..88972a4 100644 --- a/processor.py +++ b/processor.py @@ -592,7 +592,7 @@ def handle_thread(thread, timeout=120): result = api.result body = result["body"] if body["status"] == "Succeeded" and update_meta: - handle_update_aura_meta(body, element) + handle_update_lightning_meta(body, element) settings = context.get_settings() api = MetadataApi(settings) @@ -606,13 +606,13 @@ def handle_thread(thread, timeout=120): handle_thread(thread, timeout) -def handle_update_aura_meta(body, element, timeout=120, type="AuraDefinitionBundle"): +def handle_update_lightning_meta(body, element, timeout=120): """ :param body: body data returned from SOAP API - :param element: Aura type in `COMPONENT`, `CONTROLLER`, `HELPER`, `SVG`... + :param element: Aura Bunlde type in `COMPONENT`, `CONTROLLER`, `HELPER`, `SVG`... :param timeout: timeout in second - :param type: type + :param cmp_type: type :return: """ @@ -628,22 +628,38 @@ def handle_thread(thread, full_name, timeout): if result["totalSize"] == 0: Printer.get("log").write("There is no component data") return - elif result["totalSize"] == 1: + elif result["totalSize"] == 1 and bundle_type == "AuraDefinitionBundle": + # save single aura definition file record = result["records"][0] cmp_meta = { "name": full_name[:full_name.find('.')], "extension": full_name[full_name.find('.'):], "id": record["Id"], "lastModifiedDate": record["LastModifiedDate"], - "type": type, + "type": bundle_type, "DefType": record["DefType"] } - components_dict[type][full_name.lower()] = cmp_meta + components_dict[bundle_type][full_name.lower()] = cmp_meta + s.set(username, components_dict) + sublime.save_settings(context.COMPONENT_METADATA_SETTINGS) + elif bundle_type == "LightningComponentBundle": + # save multiple Lightning Component Resource files + for record in result["records"]: + _lwc, bundle_name, full_name = record["FilePath"].split("/") # lwc/t2/t2.js-meta.xml + + cmp_meta = { + "name": full_name[:full_name.find('.')], # t2.js-meta + "extension": full_name[full_name.find('.'):], # .xml + "id": record["Id"], + "lastModifiedDate": record["LastModifiedDate"], + "type": bundle_type + } + components_dict[bundle_type][full_name.lower()] = cmp_meta s.set(username, components_dict) sublime.save_settings(context.COMPONENT_METADATA_SETTINGS) - # Refresh metadata settings - sublime.set_timeout(lambda: util.load_metadata_cache(True, settings["username"]), 5) + # Refresh metadata settings + sublime.set_timeout(lambda: util.load_metadata_cache(True, settings["username"]), 5) settings = context.get_settings() username = settings["username"] @@ -656,21 +672,27 @@ def handle_thread(thread, full_name, timeout): component_successes = [component_successes] for item in component_successes: - if item["componentType"] == "AuraDefinitionBundle": + bundle_type = item["componentType"] + if bundle_type in ["AuraDefinitionBundle", "LightningComponentBundle"]: base_name = item["fullName"] - full_name = base_name + context.EXT_DICT.get(element.lower()) + full_name = (base_name + context.EXT_DICT.get(element.lower())) \ + if element is not None and bundle_type == "AuraDefinitionBundle" else "" components_dict = s.get(username, {}) # Prevent exception if no component in org - if type not in components_dict: - components_dict = {type: {}} + if bundle_type not in components_dict: + components_dict = {bundle_type: {}} # Build components dict api = ToolingApi(settings) - query_str = "SELECT Id, DefType, LastModifiedDate, LastModifiedById " + \ - "FROM AuraDefinition WHERE AuraDefinitionBundleId = '%s' and DefType = '%s'" % ( - item['id'], element.upper()) - thread = threading.Thread(target=api.query, args=(query_str,)) + query_str = "SELECT Id, Format, LastModifiedDate, LastModifiedById " + if bundle_type == 'AuraDefinitionBundle': + query_str += ", DefType FROM AuraDefinition WHERE AuraDefinitionBundleId = '%s' and DefType = '%s'"\ + % (item['id'], element.upper()) + elif bundle_type == 'LightningComponentBundle': + query_str += ", FilePath FROM LightningComponentResource WHERE LightningComponentBundleId = '%s'"\ + % (item['id']) + thread = threading.Thread(target=api.query, args=(query_str, True)) thread.start() ThreadProgress(api, thread, "Update Component Metadata", "Update Component Metadata Finished") handle_thread(thread, full_name, timeout) @@ -1096,8 +1118,8 @@ def handle_thread(thread, timeout): return result = api.result - if not result["success"]: return - print(result) + if not result["success"]: + return settings = context.get_settings() api = ToolingApi(settings) @@ -1598,6 +1620,7 @@ def handle_thread(_thread, timeout): _thread.start() # Code Cache + # print("fileProperties:", api.result.get("fileProperties", None)) if isinstance(api.result.get("fileProperties", None), list): util.reload_file_attributes( api.result["fileProperties"], From 79b1a0909b4419377cead312574b30698d08f110 Mon Sep 17 00:00:00 2001 From: Lushang Date: Mon, 30 Mar 2020 23:29:41 +0800 Subject: [PATCH 39/46] Implemented Add Additional JS file to lwc --- config/menus/Side bar.sublime-menu | 6 +++ config/templates/LwcElement/Additional.js | 3 +- lwc.py | 49 +++++++++++++++++------ 3 files changed, 45 insertions(+), 13 deletions(-) diff --git a/config/menus/Side bar.sublime-menu b/config/menus/Side bar.sublime-menu index 3e0753c..d971784 100644 --- a/config/menus/Side bar.sublime-menu +++ b/config/menus/Side bar.sublime-menu @@ -153,6 +153,12 @@ "args": {"dirs": [], "element": "SVG"} }, + { + "caption": "Add Additional JavaScript File", + "command": "create_lwc_element", + "args": {"dirs": [], "element": "AdditionalJS"} + }, + {"caption": "-"}, { diff --git a/config/templates/LwcElement/Additional.js b/config/templates/LwcElement/Additional.js index 8fae127..f602a21 100644 --- a/config/templates/LwcElement/Additional.js +++ b/config/templates/LwcElement/Additional.js @@ -1 +1,2 @@ -//sample additional js file \ No newline at end of file +export class {class_name} { +} \ No newline at end of file diff --git a/lwc.py b/lwc.py index b21cdd4..0d8e0a9 100644 --- a/lwc.py +++ b/lwc.py @@ -12,9 +12,6 @@ class CreateLightningWebComponent(sublime_plugin.WindowCommand): def __init__(self, *args, **kwargs): super(CreateLightningWebComponent, self).__init__(*args, **kwargs) - # Get settings - self._settings = context.get_settings() - self._workspace = self._settings["workspace"] def run(self, *args): if self._settings["api_version"] < 45: @@ -35,6 +32,7 @@ def on_input(self, lwc_name): return # Build dir for new Lightning web component + self._workspace = self._settings["workspace"] component_dir = os.path.join(self._workspace, "src", "lwc", lwc_name) if not os.path.exists(component_dir): os.makedirs(component_dir) @@ -79,6 +77,7 @@ def is_enabled(self): return util.check_action_enabled() def is_visible(self): + self._settings = context.get_settings() if self._settings["api_version"] < 45: return False return True @@ -87,7 +86,6 @@ def is_visible(self): class DeployLwcToServer(sublime_plugin.WindowCommand): def __init__(self, *args, **kwargs): super(DeployLwcToServer, self).__init__(*args, **kwargs) - self.settings = context.get_settings() def run(self, dirs, switch_project=True, source_org=None, update_meta=False): if switch_project: @@ -107,6 +105,7 @@ def run(self, dirs, switch_project=True, source_org=None, update_meta=False): processor.handle_deploy_thread(base64_package, source_org=source_org, update_meta=update_meta) def is_visible(self, dirs, switch_project=True): + self.settings = context.get_settings() visible = True if not dirs or len(dirs) == 0: visible = False @@ -125,22 +124,41 @@ def is_visible(self, dirs, switch_project=True): class CreateLwcElement(sublime_plugin.WindowCommand): def __init__(self, *args, **kwargs): super(CreateLwcElement, self).__init__(*args, **kwargs) - self.settings = context.get_settings() def run(self, dirs, element=""): """ element: Component, Controller, Helper, Style, Documentation, Render """ - # Get template attribute + self.resource_type = element + # for adding additional JS file, user has to input name first: + if self.resource_type == "AdditionalJS": + self.window.show_input_panel("Please Input Additional JavaScript File Name: ", + "", self.on_input, None, None) + else: + self.create_resource() + + def on_input(self, js_file_name): + # Create component to local according to user input + if not re.match('^[a-z]+\\w*[A-Za-z0-9]$', js_file_name) or re.match('__+', js_file_name): + message = 'Invalid format, do you want to try again?' + if not sublime.ok_cancel_dialog(message): + return + self.window.show_input_panel("Please Input Lightning Web Component Name: ", + "", self.on_input, None, None) + return + + # Create new additional JS file + self.create_resource(js_file_name) + + def create_resource(self, js_file_name=None): + # Get template attribute, generate lwc resource file path templates = util.load_templates() - template = templates.get("LwcElement").get(element) + template = templates.get("LwcElement").get(self.resource_type) templates_path = os.path.join(self.settings["workspace"], - ".templates", template["directory"]) - with open(templates_path) as fp: - body = fp.read() + ".templates", template["directory"]) extension = template["extension"] - element_name = self.lwc_name + extension + element_name = (self.lwc_name if js_file_name is None else self.lwc_name + js_file_name) + extension # Combine lwc element component name element_file = os.path.join(self._dir, element_name) @@ -149,6 +167,12 @@ def run(self, dirs, element=""): if os.path.isfile(element_file): return self.window.open_file(element_file) + # Open template file and copy to the body, replace class name if necessary: + with open(templates_path) as fp: + body = fp.read() + if js_file_name is not None: + body = body.replace('{class_name}', js_file_name) + # Create lwc Element file with open(element_file, "w") as fp: fp.write(body) @@ -161,7 +185,7 @@ def run(self, dirs, element=""): self.window.run_command("deploy_lightning_to_server", { "dirs": [self._dir], "switch_project": False, - "element": element, + "element": self.resource_type, "update_meta": True }) @@ -169,6 +193,7 @@ def is_visible(self, dirs, element=""): if not dirs or len(dirs) != 1: return False self._dir = dirs[0] + self.settings = context.get_settings() # Check whether project is the active one if self.settings["default_project_name"] not in self._dir: From fc78179edc4404639dbed4f76974c6aab507e81e Mon Sep 17 00:00:00 2001 From: Lushang Date: Mon, 30 Mar 2020 23:32:17 +0800 Subject: [PATCH 40/46] Miscellaneous refinements --- aura.py | 5 +++-- completions.py | 3 ++- salesforce/api/metadata.py | 10 ++++++---- util.py | 17 ----------------- 4 files changed, 11 insertions(+), 24 deletions(-) diff --git a/aura.py b/aura.py index 66d35e7..f2e8a65 100644 --- a/aura.py +++ b/aura.py @@ -145,7 +145,6 @@ def is_visible(self): class RetrieveLightningFromServer(sublime_plugin.WindowCommand): def __init__(self, *args, **kwargs): super(RetrieveLightningFromServer, self).__init__(*args, **kwargs) - self.settings = context.get_settings() def run(self, dirs): message = "Are you sure you really want to continue refreshing" @@ -157,6 +156,7 @@ def run(self, dirs): ) def is_visible(self, dirs): + self.settings = context.get_settings() self.types = {} if len(dirs) == 0: return False @@ -196,7 +196,8 @@ def __init__(self, *args, **kwargs): super(DestructLightningFromServer, self).__init__(*args, **kwargs) def run(self, dirs): - if sublime.ok_cancel_dialog("Confirm to continue?"): + if sublime.ok_cancel_dialog("This will Delete the whole folder both from the server and local!" + + " Confirm to continue?"): processor.handle_destructive_files(dirs, ignore_folder=False) def is_visible(self, dirs): diff --git a/completions.py b/completions.py index 67e5c21..d16bed9 100644 --- a/completions.py +++ b/completions.py @@ -659,7 +659,8 @@ def on_query_completions(self, view, prefix, locations): meta_type = None else: is_lightning = True if file_name.split(".")[-1] in ["app", "cmp", "evt", "html", "js"] else False - meta_type = util.get_meta_type(file_name) + attributes = util.get_file_attributes(file_name) + meta_type = attributes["metadata_folder"] # Get tag definition of Visualforce page or Lightning aura component or Lightning Web component tag_defs = [] diff --git a/salesforce/api/metadata.py b/salesforce/api/metadata.py index a201f93..7363918 100644 --- a/salesforce/api/metadata.py +++ b/salesforce/api/metadata.py @@ -18,6 +18,7 @@ class MetadataApi: def __init__(self, settings, **kwargs): self.settings = settings self.api_version = settings["api_version"] + self.deploy_options = settings["deploy_options"] self.soap = SOAP(settings) self.session = None self.result = None @@ -550,14 +551,15 @@ def deploy(self, base64_zip, test_classes=[]): start_time = datetime.datetime.now() # Populate the soap_body with actual options - deploy_options = self.settings["deploy_options"] - + # move the deploy options in to class attributes from better manipulate + # deploy_options = self.settings["deploy_options"] + # If just checkOnly, output VALIDATE, otherwise, output DEPLOY - deploy_or_validate = "validate" if deploy_options["checkOnly"] else "deploy" + deploy_or_validate = "validate" if self.deploy_options["checkOnly"] else "deploy" # [sf:deploy] Printer.get('log').write_start().write("[sf:%s] Start request for a deploy..." % deploy_or_validate) - options = deploy_options + options = self.deploy_options options["zipfile"] = base64_zip # If testLevel is Run Specified Test, diff --git a/util.py b/util.py index dd09c0d..44cfd94 100644 --- a/util.py +++ b/util.py @@ -3751,20 +3751,3 @@ def convert_csv_to_json(csvfile, xmlNodes): os.remove(tempjson) return rjson - - -def get_meta_type(file_name): - """ - Get Metadata type from file name - return: aura/lwc/classes/objects etc. - """ - paths = [] - path, file_name = os.path.split(file_name) - while os.path.isdir(path): - path, crr_dir = os.path.split(path) - if crr_dir == 'src': - break - paths.append(crr_dir) - - # return the sub-directory of src, that is the meta type - return paths[-1] \ No newline at end of file From 29c29a502ed17297d9e77cc99c614361ad932ac4 Mon Sep 17 00:00:00 2001 From: Lushang Date: Mon, 30 Mar 2020 23:41:39 +0800 Subject: [PATCH 41/46] Build 3.6.0 --- HISTORY.rst | 18 ++++++++++++++++++ config/messages/3.5.9.md | 2 +- config/messages/3.6.0.md | 10 ++++++++++ config/settings/package.sublime-settings | 4 ++-- messages.json | 3 +-- 5 files changed, 32 insertions(+), 5 deletions(-) create mode 100644 config/messages/3.6.0.md diff --git a/HISTORY.rst b/HISTORY.rst index 16c99b7..2439222 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -3,6 +3,24 @@ Release History ----------------- +Release 3.6.0 (2020-03-30) +++++++++++++++++++++++++++++++++++++ +* Implemented Save lwc file to Server last one + - Now you can save ``lwc`` HTML markup, JavaScript code, CSS file, SVG resource and **Additional JS files** to Salesforce directly by ``HaoIDE`` +* Update component metadata after Creating Lightning Web Component or `lwc` resource like CSS, SVG, Additional JS files +* Updated related documentations. +* Miscellaneous bug fix and refinement. + + +Release 3.5.9 (2020-03-29) +++++++++++++++++++++++++++++++++++++ + +* Implemented Save lwc file to Server + - Now you can save ``lwc`` HTML markup, JavaScript code, CSS file, SVG resource and additional JS files to Salesforce separately +* Update documents + - updated documentations on auto completion, debug, lwc and etc. +* Miscellaneous bug fix and refinement + Release 3.5.8 (2020-03-28) ++++++++++++++++++++++++++++++++++++ diff --git a/config/messages/3.5.9.md b/config/messages/3.5.9.md index 8e17aae..432f0ca 100644 --- a/config/messages/3.5.9.md +++ b/config/messages/3.5.9.md @@ -2,7 +2,7 @@ Build 3.5.9 ----------- Release Date: 29 Mar 2020 -* Implemente Save lwc file to Server +* Implemented Save lwc file to Server - Now you can save `lwc` HTML markup, JavaScript code, CSS file, SVG resource and additional JS files to Salesforce separately * Update documents diff --git a/config/messages/3.6.0.md b/config/messages/3.6.0.md new file mode 100644 index 0000000..961a76e --- /dev/null +++ b/config/messages/3.6.0.md @@ -0,0 +1,10 @@ +Build 3.6.0 +----------- +Release Date: 30 Mar 2020 + +* Implemented Save lwc file to Server last one + - Now you can save `lwc` HTML markup, JavaScript code, CSS file, SVG resource and **Additional JS files** + to Salesforce directly by `HaoIDE` +* Update component metadata after Creating Lightning Web Component or `lwc` resource like CSS, SVG, Additional JS files +* Updated related documentations. +* Miscellaneous bug fix and refinement. \ No newline at end of file diff --git a/config/settings/package.sublime-settings b/config/settings/package.sublime-settings index ec4d9eb..23d2fd2 100644 --- a/config/settings/package.sublime-settings +++ b/config/settings/package.sublime-settings @@ -1,7 +1,7 @@ { "name": "haoide", - "version": "3.5.9", - "description": "haoide is a Sublime Text 3 plugin for Salesforce and used for swift development on Force.com", + "version": "3.6.0", + "description": "HaoIDE is a Sublime Text 3 plugin for Salesforce and used for swift development on Force.com", "author": "Hao Liu @ 2013-2019", "email": "mouse.mliu@gmail.com", "homepage": "https://github.com/xjsender/haoide", diff --git a/messages.json b/messages.json index 6ceafc0..b70b471 100644 --- a/messages.json +++ b/messages.json @@ -1,6 +1,5 @@ { - "3.5.7": "config/messages/3.5.7.md", - "3.5.8": "config/messages/3.5.8.md", "3.5.9": "config/messages/3.5.9.md", + "3.6.0": "config/messages/3.6.0.md", "install": "config/messages/install.txt" } \ No newline at end of file From 551e116b1fe0529bf8331df0aab8a6242319f8df Mon Sep 17 00:00:00 2001 From: Lushang Date: Thu, 2 Apr 2020 18:10:21 +0800 Subject: [PATCH 42/46] Remove component metadata cache after destructing --- processor.py | 86 ++++-- salesforce/api/tooling.py | 194 ++++++------- util.py | 577 +++++++++++++++++++++++--------------- 3 files changed, 512 insertions(+), 345 deletions(-) diff --git a/processor.py b/processor.py index 88972a4..dc63f2a 100644 --- a/processor.py +++ b/processor.py @@ -525,16 +525,27 @@ def handle_thread(api, thread, timeout=120): def handle_destructive_files(dirs_or_files, ignore_folder=True, timeout=120): - def handle_thread(thread, timeout=120): + """ + Destruct File(s) from Salesforce org and remove from local disk via Metadata API + @param dirs_or_files: lightning direcotry(bundle) or files + @param ignore_folder: ignore the folder itself + @param timeout: timeout in second + @return: None + """ + + def handle_destruct_thread(thread, timeout=120): if thread.is_alive(): - sublime.set_timeout(lambda: handle_thread(thread, timeout), timeout) + sublime.set_timeout(lambda: handle_destruct_thread(thread, timeout), timeout) return # After succeed, remove dirs_or_files and related *-meta.xml from local if "body" in api.result and api.result["body"]["status"] == "Succeeded": + # Remove Component metadata cache + util.delete_component_attribute(dirs_or_files) + + # Remove file from local disk and close the related view win = sublime.active_window() for _file_or_dir in dirs_or_files: - # Remove file from local disk and close the related view view = util.get_view_by_file_name(_file_or_dir) if view: win.focus_view(view) @@ -560,7 +571,7 @@ def handle_thread(thread, timeout=120): thread = threading.Thread(target=api.deploy, args=(base64_encoded_zip,)) thread.start() ThreadProgress(api, thread, "Destructing Files", "Destructing Files Succeed") - handle_thread(thread, timeout) + handle_destruct_thread(thread, timeout) def handle_destructive_package_xml(types, timeout=120): @@ -578,8 +589,18 @@ def handle_thread(thread, timeout=120): handle_thread(thread, timeout) -def handle_deploy_thread(base64_encoded_zip, - source_org=None, element=None, chosen_classes=[], timeout=120, update_meta=False): +def handle_deploy_thread(base64_encoded_zip, source_org=None, element=None, + chosen_classes=[], timeout=120, update_meta=False): + """ + Deploy code to specified Salesforce org via Metadata API + @param base64_encoded_zip: code content in base64 encoded + @param source_org: destination Salesforce org + @param element: aura element in [Application, Component, Event, Controller, Helper,etc.] + @param chosen_classes: + @param timeout: timeout in second + @param update_meta: whether update component metadata after deployed + @return: None + """ def handle_thread(thread, timeout=120): if thread.is_alive(): sublime.set_timeout(lambda: handle_thread(thread, timeout), timeout) @@ -608,9 +629,9 @@ def handle_thread(thread, timeout=120): def handle_update_lightning_meta(body, element, timeout=120): """ - + Update lightning aura/web component metadata via Tooling API after creation :param body: body data returned from SOAP API - :param element: Aura Bunlde type in `COMPONENT`, `CONTROLLER`, `HELPER`, `SVG`... + :param element: Aura bundle type in `COMPONENT`, `CONTROLLER`, `HELPER`, `SVG`... :param timeout: timeout in second :param cmp_type: type :return: @@ -640,8 +661,6 @@ def handle_thread(thread, full_name, timeout): "DefType": record["DefType"] } components_dict[bundle_type][full_name.lower()] = cmp_meta - s.set(username, components_dict) - sublime.save_settings(context.COMPONENT_METADATA_SETTINGS) elif bundle_type == "LightningComponentBundle": # save multiple Lightning Component Resource files for record in result["records"]: @@ -655,11 +674,13 @@ def handle_thread(thread, full_name, timeout): "type": bundle_type } components_dict[bundle_type][full_name.lower()] = cmp_meta + + # Save and reload component metadata + if result["totalSize"] >= 1: s.set(username, components_dict) sublime.save_settings(context.COMPONENT_METADATA_SETTINGS) - - # Refresh metadata settings - sublime.set_timeout(lambda: util.load_metadata_cache(True, settings["username"]), 5) + # Refresh metadata settings + sublime.set_timeout(lambda: util.load_metadata_cache(True, settings["username"]), 5) settings = context.get_settings() username = settings["username"] @@ -1604,6 +1625,15 @@ def handle_thread(thread, timeout): def handle_retrieve_package(types, extract_to, source_org=None, ignore_package_xml=False, timeout=120): + """ + Retrieve package via Metadata API + @param types: metadata type dict like {"AuraDefinitionBundle":["aura1", "aura2"]} + @param extract_to: target settings["workspace"] + @param source_org: source Salesforce org + @param ignore_package_xml: ignore package xml file + @param timeout: timeout in seconds + @return: None + """ def handle_thread(_thread, timeout): if _thread.is_alive(): sublime.set_timeout(lambda: handle_thread(_thread, timeout), timeout) @@ -1619,7 +1649,7 @@ def handle_thread(_thread, timeout): args=(api.result["zipFile"], extract_to, ignore_package_xml,)) _thread.start() - # Code Cache + # Code Cache in component metadata settings for saving file to server functionality # print("fileProperties:", api.result.get("fileProperties", None)) if isinstance(api.result.get("fileProperties", None), list): util.reload_file_attributes( @@ -1640,7 +1670,7 @@ def handle_thread(_thread, timeout): def handle_save_to_server(file_name, is_check_only=False, timeout=120): """ - Handle Save metadata to Salesforce + Handle Save metadata to Salesforce via Tooling API @param file_name: file name with path format @param is_check_only: only check the file from Salesforce, do not really save @param timeout: timeout in seconds @@ -1675,8 +1705,8 @@ def handle_thread(thread, timeout): # Backup current file time_stamp = time.strftime("%Y-%m-%d-%H-%M", time.localtime()) - outputdir = workspace + "/" + component_name + "-" + time_stamp + "-history" + extension - with open(outputdir, "wb") as fp: + output_dir = workspace + "/" + component_name + "-" + time_stamp + "-history" + extension + with open(output_dir, "wb") as fp: fp.write(body.encode("utf-8")) # Output succeed message in the console @@ -1709,6 +1739,7 @@ def handle_thread(thread, timeout): # If not succeed, just go to the error line # Because error line in page is always at the line 1, so just work in class or trigger elif "success" in result and not result["success"]: + print('error result', result) # Maybe network issue _message = "Unknown Problem!" if "problem" in result: @@ -1763,6 +1794,7 @@ def handle_thread(thread, timeout): component_id = component_attribute["id"] view.run_command("set_check_point", {"mark": component_id + "build_error"}) + # 1. Get component attribute and body content component_attribute, component_name = util.get_component_attribute(file_name) body = open(file_name, encoding="utf-8").read() @@ -1779,7 +1811,7 @@ def handle_thread(thread, timeout): if username + file_base_name in globals(): is_thread_alive = globals()[username + file_base_name] if is_thread_alive: - print('%s is in process' % file_base_name); + print('%s is in process' % file_base_name) return # Open panel @@ -1807,6 +1839,16 @@ def handle_thread(thread, timeout): def handle_create_component(data, component_name, component_type, markup_or_body, file_name, timeout=120): + """ + Handle create Apex Class/Trigger/Page/Component via Tooling API + @param data: component data to create, dict like {"name": "Aclass.cls", "body": content_body} + @param component_name: component name without extension + @param component_type: component type in [ApexClass, ApexPage, ApexTrigger, ApexComponent] + @param markup_or_body: content of the code + @param file_name: os file path + @param timeout: timeout in second + @return: None + """ def handle_thread(thread, timeout): if thread.is_alive(): sublime.set_timeout(lambda: handle_thread(thread, timeout), timeout) @@ -1850,7 +1892,7 @@ def handle_thread(thread, timeout): "type": component_type, "is_test": lower_name.startswith("test") or lower_name.endswith("test") } - components_dict[component_type][fullName.lower()] = attributes + components_dict[component_type][full_name.lower()] = attributes s.set(username, components_dict) # Save settings and show success message @@ -1886,9 +1928,9 @@ def handle_thread(thread, timeout): post_url = "/sobjects/" + component_type thread = threading.Thread(target=api.post, args=(post_url, data,)) thread.start() - fullName = os.path.basename(file_name) - ThreadProgress(api, thread, "Creating Component %s" % fullName, - "Creating Component %s Succeed" % fullName) + full_name = os.path.basename(file_name) + ThreadProgress(api, thread, "Creating Component %s" % full_name, + "Creating Component %s Succeed" % full_name) handle_thread(thread, timeout) diff --git a/salesforce/api/tooling.py b/salesforce/api/tooling.py index ff09e9a..864b627 100644 --- a/salesforce/api/tooling.py +++ b/salesforce/api/tooling.py @@ -13,6 +13,7 @@ from ..login import soap_login, rest_login from ..lib.panel import Printer + class ToolingApi(): def __init__(self, settings, **kwargs): self.settings = settings @@ -90,7 +91,7 @@ def parse_response(self, res): try: response_result = res.json() if isinstance(response_result, list): - response_result = response_result[0] + response_result = response_result[0] except: response_result = {"Error Message": res.text} response_result["success"] = False @@ -108,7 +109,7 @@ def parse_response(self, res): response_result["success"] = True return response_result - + def head(self, component_url, timeout=120): """ 'head' request @@ -124,11 +125,11 @@ def head(self, component_url, timeout=120): url = self.parse_url(component_url) try: - response = requests.head(url, verify=False, - headers=self.headers, timeout=timeout) + response = requests.head(url, verify=False, + headers=self.headers, timeout=timeout) except requests.exceptions.RequestException as e: self.result = { - "Error Message": "Network connection timeout when issue REST HEAD request", + "Error Message": "Network connection timeout when issue REST HEAD request", "success": False } return self.result @@ -140,7 +141,7 @@ def head(self, component_url, timeout=120): self.result = result return self.result return self.head(component_url) - + result = self.parse_response(response) self.result = result @@ -165,11 +166,11 @@ def get(self, component_url, timeout=120): headers["Accept-Encoding"] = 'identity, deflate, compress, gzip' try: - response = requests.get(url, data=None, verify=False, - headers=self.headers, timeout=timeout) + response = requests.get(url, data=None, verify=False, + headers=self.headers, timeout=timeout) except requests.exceptions.RequestException as e: self.result = { - "Error Message": "Network connection timeout when issuing REST GET request", + "Error Message": "Network connection timeout when issuing REST GET request", "success": False } return self.result @@ -181,7 +182,7 @@ def get(self, component_url, timeout=120): self.result = result return self.result return self.get(component_url) - + result = self.parse_response(response) self.result = result @@ -203,13 +204,13 @@ def put(self, put_url, data, timeout=120): return self.result url = self.parse_url(put_url) - + try: - response = requests.put(url, data=json.dumps(data), verify=False, - headers=self.headers, timeout=timeout) + response = requests.put(url, data=json.dumps(data), verify=False, + headers=self.headers, timeout=timeout) except requests.exceptions.RequestException as e: self.result = { - "Error Message": "Network Network connection timeout when issuing REST PUT request", + "Error Message": "Network Network connection timeout when issuing REST PUT request", "success": False } return self.result @@ -221,7 +222,7 @@ def put(self, put_url, data, timeout=120): self.result = result return self.result return self.put(put_url, data) - + result = self.parse_response(response) self.result = result @@ -243,13 +244,13 @@ def patch(self, patch_url, data, timeout=120): return self.result url = self.parse_url(patch_url) - + try: - response = requests.patch(url, data=json.dumps(data), verify=False, - headers=self.headers, timeout=timeout) + response = requests.patch(url, data=json.dumps(data), verify=False, + headers=self.headers, timeout=timeout) except requests.exceptions.RequestException as e: self.result = { - "Error Message": "Network connection timeout when issuing REST PATCH request", + "Error Message": "Network connection timeout when issuing REST PATCH request", "success": False } return self.result @@ -261,7 +262,7 @@ def patch(self, patch_url, data, timeout=120): self.result = result return self.result return self.patch(patch_url, data) - + result = self.parse_response(response) self.result = result @@ -283,13 +284,13 @@ def post(self, post_url, data, timeout=120): return self.result url = self.parse_url(post_url) - + try: - response = requests.post(url, data=json.dumps(data), verify=False, - headers=self.headers, timeout=timeout) + response = requests.post(url, data=json.dumps(data), verify=False, + headers=self.headers, timeout=timeout) except requests.exceptions.RequestException as e: self.result = { - "Error Message": "Network connection timeout when issuing REST POST request", + "Error Message": "Network connection timeout when issuing REST POST request", "success": False } return self.result @@ -301,7 +302,7 @@ def post(self, post_url, data, timeout=120): self.result = result return self.result return self.post(post_url, data) - + result = self.parse_response(response) self.result = result @@ -322,13 +323,13 @@ def delete(self, component_url, timeout=120): return self.result url = self.parse_url(component_url) - + try: - response = requests.delete(url, data=None, verify=False, - headers=self.headers, timeout=timeout) + response = requests.delete(url, data=None, verify=False, + headers=self.headers, timeout=timeout) except requests.exceptions.RequestException as e: self.result = { - "Error Message": "Network connection timeout when issuing REST DELETE request", + "Error Message": "Network connection timeout when issuing REST DELETE request", "success": False } return self.result @@ -364,13 +365,13 @@ def search(self, sosl, timeout=120): return self.result url = self.base_url + "/search" - params = {'q' : sosl} + params = {'q': sosl} try: - response = requests.get(url, headers=self.headers, verify=False, - params=params, timeout=timeout) + response = requests.get(url, headers=self.headers, verify=False, + params=params, timeout=timeout) except requests.exceptions.RequestException as e: self.result = { - "Error Message": "Network connection timeout when issuing REST SEARCH request", + "Error Message": "Network connection timeout when issuing REST SEARCH request", "success": False } return self.result @@ -402,11 +403,11 @@ def quick_search(self, sosl_string, timeout=120): # We need to escape this special character, # Don't know why ?, _ for ch in ["-", "?", "*"]: - sosl_string = sosl_string.replace(ch, "\\"+ch) + sosl_string = sosl_string.replace(ch, "\\" + ch) sosl_string = 'FIND {%s}' % sosl_string result = self.search(sosl_string) - + self.result = result return self.result @@ -439,14 +440,14 @@ def query(self, soql, is_toolingapi=False, timeout=120): # Just API 28 above support CustomField url = self.base_url + ("/tooling" if is_toolingapi else "") + "/query" - params = {'q' : soql} + params = {'q': soql} try: response = requests.get(url, data=None, verify=False, params=params, - headers=self.headers, timeout=timeout) + headers=self.headers, timeout=timeout) except requests.exceptions.RequestException as e: self.result = { - "Error Message": "Network connection timeout when issuing QUERY request", + "Error Message": "Network connection timeout when issuing QUERY request", "success": False } return self.result @@ -484,7 +485,7 @@ def get_all_result(previous_result): if not self.login(): return result = self.query(soql, is_toolingapi) - + # Database.com not support ApexComponent if not result["success"]: self.result = result @@ -513,27 +514,27 @@ def query_symbol_table(self, split=30): if not result["success"]: self.result = result return self.result - + offset = 0 result = {"totalSize": 0, "records": [], "success": result["success"]} describe_metadata = util.get_described_metadata(self.settings) namespacePrefix = describe_metadata.get("organizationNamespace", '') - soql = "SELECT NamespacePrefix, SymbolTable, Name FROM ApexClass " +\ - "WHERE NamespacePrefix = %s " % ( + soql = "SELECT NamespacePrefix, SymbolTable, Name FROM ApexClass " + \ + "WHERE NamespacePrefix = %s " % ( "'%s'" % namespacePrefix if namespacePrefix else 'null' - ) + ) while True: query = soql + "LIMIT %s OFFSET %s""" % (split, offset) previous_result = self.query(query, is_toolingapi=True) - if not previous_result["success"]: continue # Ignore exception - if previous_result["size"] == 0: break # No result + if not previous_result["success"]: continue # Ignore exception + if previous_result["size"] == 0: break # No result if self.settings["debug_mode"]: - print ('SOQL: %s, ' % query, 'totalSize: %s' % previous_result["size"]) + print('SOQL: %s, ' % query, 'totalSize: %s' % previous_result["size"]) result['totalSize'] += previous_result['totalSize'] previous_result['records'].extend(result['records']) result['records'] = previous_result['records'] offset += split - + # Invoke for thread self.result = result @@ -553,9 +554,9 @@ def query_logs(self, last_n_logs, user_id=None): if not user_id: user_id = self.session["user_id"] # Query self logs - soql = "SELECT Id,LogUserId,LogLength,Request,Operation,Application," +\ - "Status,DurationMilliseconds,StartTime,Location FROM ApexLog " +\ - "WHERE LogUserId='%s' ORDER BY StartTime DESC LIMIT %s" % (user_id, last_n_logs) + soql = "SELECT Id,LogUserId,LogLength,Request,Operation,Application," + \ + "Status,DurationMilliseconds,StartTime,Location FROM ApexLog " + \ + "WHERE LogUserId='%s' ORDER BY StartTime DESC LIMIT %s" % (user_id, last_n_logs) self.result = self.query(soql, is_toolingapi=True) return self.result @@ -572,12 +573,12 @@ def combine_soql(self, sobject, action=None, contains_compound=True): self.result = result return self.result - fields = sorted(result["fields"], key=lambda k : k['custom']) + fields = sorted(result["fields"], key=lambda k: k['custom']) field_list = [] for field in fields: # http://www.salesforce.com/us/developer/docs/api/Content/compound_fields_address.htm if not contains_compound and field.get("queryByDistance"): continue - if not action or field[action]: + if not action or field[action]: field_list.append(field.get("name")) # Id must be included in the field list @@ -721,7 +722,7 @@ def create_trace_flag(self, traced_entity_id=None): # Check whether traced user already has trace flag # If not, just create it for him/her - query = "SELECT Id, ExpirationDate FROM TraceFlag " +\ + query = "SELECT Id, ExpirationDate FROM TraceFlag " + \ "WHERE TracedEntityId = '%s'" % (traced_entity_id) result = self.query(query, True) @@ -734,7 +735,7 @@ def create_trace_flag(self, traced_entity_id=None): if result["totalSize"] > 0: self.delete("/tooling/sobjects/TraceFlag/" + result["records"][0]["Id"]) return self.create_trace_flag(traced_entity_id) - + # Start to create Trace Flag trace_flag = self.settings["trace_flag"] @@ -744,7 +745,7 @@ def create_trace_flag(self, traced_entity_id=None): if not debug_level["success"]: self.result = debug_level return self.result - + trace_flag["LogType"] = "USER_DEBUG" trace_flag["DebugLevelId"] = debug_level["id"] @@ -766,13 +767,13 @@ def create_trace_flag(self, traced_entity_id=None): def get_debug_level(self, name="haoide"): debug_levels = self.query( - "SELECT Id FROM DebugLevel WHERE DeveloperName = '%s'" % name, + "SELECT Id FROM DebugLevel WHERE DeveloperName = '%s'" % name, is_toolingapi=True ) if debug_levels["success"]: if debug_levels["totalSize"] > 0: debug_level = debug_levels["records"][0] - debug_level["id"] = debug_level["Id"] # Prevent keyError problem + debug_level["id"] = debug_level["Id"] # Prevent keyError problem debug_level["success"] = True return debug_level @@ -806,7 +807,7 @@ def retrieve_body(self, retrieve_url, timeout=120): response.encoding = "UTF-8" except requests.exceptions.RequestException as e: self.result = { - "Error Message": "Network connection timeout when issuing RETRIVING BODY request", + "Error Message": "Network connection timeout when issuing RETRIVING BODY request", "success": False } return self.result @@ -818,7 +819,7 @@ def retrieve_body(self, retrieve_url, timeout=120): result = self.parse_response(response) self.result = result - + return result def run_tests_asynchronous(self, class_ids): @@ -841,9 +842,9 @@ def run_tests_synchronous(self, class_name, test_names): * test_names -- Apex Test Method Name List """ if test_names and len(test_names) > 0: - data = {"tests":[{"className":class_name,"testMethods":test_names}]} + data = {"tests": [{"className": class_name, "testMethods": test_names}]} else: - data = {"tests":[{"className":class_name}]} + data = {"tests": [{"className": class_name}]} self.result = self.post("/tooling/runTestsSynchronous/", data) return self.result @@ -872,12 +873,12 @@ def run_test(self, class_id): time.sleep(2) data = {"ApexClassId": class_id} result = self.post("/sobjects/ApexTestQueueItem", data) - + # Exception Process if not result["success"]: self.result = result return self.result - + # Wait for the ApexTestQueueItem is over time.sleep(5) queue_item_id = result["id"] @@ -888,7 +889,7 @@ def run_test(self, class_id): if not result["success"]: self.result = result return self.result - + # If totalSize is Zero, it means we need to wait until test is finished while result["totalSize"] == 0 or result["records"][0]["Status"] in ["Queued", "Processing"]: time.sleep(2) @@ -898,7 +899,7 @@ def run_test(self, class_id): AsyncApexJobId,Id,Message,MethodName,Outcome,QueueItemId,StackTrace, TestTimestamp FROM ApexTestResult WHERE QueueItemId = '%s'""" % queue_item_id - # After Test is finished, get result + # After Test is finished, get result result = self.query(test_result_soql) # Exception Process @@ -907,7 +908,7 @@ def run_test(self, class_id): return self.result result = result["records"] - + # Combine these two result self.result = result @@ -927,9 +928,10 @@ def generate_workbook(self, sobjects): return result workspace = self.settings.get("workspace") - outputdir = util.generate_workbook(result, workspace, - self.settings.get("workbook_field_describe_columns"))+"/"+sobject+".csv" - print (sobject + " workbook outputdir: " + outputdir) + outputdir = util.generate_workbook(result, workspace, + self.settings.get( + "workbook_field_describe_columns")) + "/" + sobject + ".csv" + print(sobject + " workbook outputdir: " + outputdir) def save_to_server(self, component_attribute, body, is_check_only, check_save_conflict=True): """ This method contains 5 steps: @@ -962,8 +964,8 @@ def save_to_server(self, component_attribute, body, is_check_only, check_save_co if self.settings["check_save_conflict"] and not is_check_only and check_save_conflict: Printer.get('log').write("Start to check saving conflict") - query = "SELECT Id, LastModifiedById, LastModifiedBy.Id, " +\ - "LastModifiedBy.Name, LastModifiedDate, SystemModstamp " +\ + query = "SELECT Id, LastModifiedById, LastModifiedBy.Id, " + \ + "LastModifiedBy.Name, LastModifiedDate, SystemModstamp " + \ "FROM %s WHERE Id = '%s'" % (component_type, component_id) result = self.query(query, True) @@ -983,13 +985,13 @@ def save_to_server(self, component_attribute, body, is_check_only, check_save_co # If local date is different with server date or lastModifiedBy is not you, # it means there has conflict - lastModifiedByYou = class_attr["LastModifiedById"] == self.session["user_id"] - timeStampMatch = serverDateLiteral[:19] == localDateLiteral[:19] - if not lastModifiedByYou or not timeStampMatch: + last_modified_by_me = class_attr["LastModifiedById"] == self.session["user_id"] + time_stamp_match = serverDateLiteral[:19] == localDateLiteral[:19] + if not last_modified_by_me or not time_stamp_match: # Used for debug if self.settings["debug_mode"]: - print ("localDateLiteral: " + localDateLiteral) - print ("serverDateLiteral: " + serverDateLiteral) + print("localDateLiteral: " + localDateLiteral) + print("serverDateLiteral: " + serverDateLiteral) message = "Modified by %s at %s, continue?" % ( lastModifiedBy["Name"], serverLastModifiedDateZone @@ -1007,8 +1009,8 @@ def save_to_server(self, component_attribute, body, is_check_only, check_save_co # Get MetadataContainerId Printer.get('log').write("Start to fetch MetadataContainerId") - data = { - "name": "Save" + component_type[4 : len(component_type)] + component_id + data = { + "name": "Save" + component_type[4: len(component_type)] + component_id } container_url = "/tooling/sobjects/MetadataContainer" result = self.post(container_url, data) @@ -1024,11 +1026,11 @@ def save_to_server(self, component_attribute, body, is_check_only, check_save_co container_id = error_message[error_message.rindex("1dc"): len(error_message)] delete_result = self.delete(container_url + "/" + container_id) if delete_result["success"]: - sublime.set_timeout(lambda:sublime.status_message("container_id is deleted."), 10) + sublime.set_timeout(lambda: sublime.status_message("container_id is deleted."), 10) else: self.result = delete_result return delete_result - + # We can't reuse the container_id which caused error # Post Request to get MetadataContainerId return self.save_to_server(component_attribute, body, is_check_only, False) @@ -1036,7 +1038,7 @@ def save_to_server(self, component_attribute, body, is_check_only, check_save_co self.result = result return self.result - # Post ApexComponentMember + # Save the code to server by posting Apex[Class/Page/Component]Member data = { "ContentEntityId": component_id, "MetadataContainerId": container_id, @@ -1053,13 +1055,13 @@ def save_to_server(self, component_attribute, body, is_check_only, check_save_co } url = "/tooling/sobjects/" + component_type + "Member" member_result = self.post(url, data) - + # Check whether user has privilege of `Author Apex` if "errorCode" in member_result and member_result["errorCode"] == "NOT_FOUND": # Before return error to console, we need to delete the container_id # If delete failed, next saving operation will handle it sublime.set_timeout_async(self.delete(container_url + "/" + container_id), 100) - + self.result = { "success": False, "Error Message": "You don't have privilege on 'Author Apex'" @@ -1087,7 +1089,7 @@ def save_to_server(self, component_attribute, body, is_check_only, check_save_co Printer.get('log').write("ContainerAsyncRequest is in Queued, waiting...") result = self.get(sync_request_url + "/" + request_id) state = result["State"] - + return_result = { "lastModifiedDate": result["LastModifiedDate"] } @@ -1114,7 +1116,7 @@ def save_to_server(self, component_attribute, body, is_check_only, check_save_co else: compile_errors = unescape(result["CompilerErrors"]) compile_errors = json.loads(compile_errors) - + return_result = {} if len(compile_errors) > 0: return_result = compile_errors[0] @@ -1132,7 +1134,7 @@ def save_to_server(self, component_attribute, body, is_check_only, check_save_co problem = "\n".join(problem) return_result["problem"] = urllib.parse.unquote( unescape(problem, { - "'": "'", + "'": "'", """: '"' }) ) @@ -1148,8 +1150,8 @@ def save_to_server(self, component_attribute, body, is_check_only, check_save_co if "columnNumber" not in return_result: return_result["columnNumber"] = 0 - return_result["success"] = False - + return_result["success"] = False + if return_result["success"] and component_type == "ApexClass": sublime.set_timeout_async(self.write_symbol_table_cache(member_result["id"]), 5) @@ -1162,7 +1164,7 @@ def save_to_server(self, component_attribute, body, is_check_only, check_save_co def save_lightning_to_server(self, component_attribute, body, check_save_conflict=True): """ Save Lightning AuraDefinition or LightningComponentResource such as component makeup, controller and helper or - Lightning Web component teampl to Salesforce + Lightning Web component resource to Salesforce Arguments: @param component_attribute: attribute of component, e.g., component id, url @@ -1180,16 +1182,16 @@ def handle_error_message(result): try: if "\n" in result["message"]: error_messages = result["message"].split('\n') - if "CSS Parser" in error_messages[0] : + if "CSS Parser" in error_messages[0]: error_msg = error_messages[2] _result["problem"] = error_msg - error_line_info = error_msg[error_msg.find("(")+1: error_msg.find(")")] + error_line_info = error_msg[error_msg.find("(") + 1: error_msg.find(")")] _result["lineNumber"] = error_line_info.split(",")[0][5:] _result["columnNumber"] = error_line_info.split(",")[1][5:] else: error_base_info = error_messages[0].split(': ') error_line_info = error_base_info[1].split(':')[1] - error_line_info = error_line_info[1 : len(error_line_info) - 1] + error_line_info = error_line_info[1: len(error_line_info) - 1] _result['id'] = error_base_info[0] _result["lineNumber"] = error_line_info.split(',')[0] _result["columnNumber"] = error_line_info.split(',')[1] @@ -1200,7 +1202,7 @@ def handle_error_message(result): m = re.search(r'\[\d+,\s*\d+\]', result["message"]) if m: col_row = m.group(0) - col_row = col_row[1:len(col_row)-1] + col_row = col_row[1:len(col_row) - 1] _result["lineNumber"] = col_row.split(',')[0] _result["columnNumber"] = col_row.split(',')[1] except Exception as _ex: @@ -1291,7 +1293,7 @@ def handle_error_message(result): def write_symbol_table_cache(self, member_id): # Get the symbol table from ApexClassMember - query = "SELECT Id, SymbolTable " +\ + query = "SELECT Id, SymbolTable " + \ "FROM ApexClassMember WHERE Id ='%s'" % member_id member = self.query(query, True) @@ -1307,7 +1309,7 @@ def write_symbol_table_cache(self, member_id): outer = util.parse_symbol_table(symbol_table) symboltable_dict[symbol_table["name"].lower()] = { - "outer" : outer, + "outer": outer, "name": symbol_table["name"] } @@ -1319,4 +1321,4 @@ def write_symbol_table_cache(self, member_id): symboltable_dict[symbol_table["name"].lower()]["inners"] = inners symbol_table_cache.set(self.settings["username"], symboltable_dict) - sublime.save_settings("symbol_table.sublime-settings") \ No newline at end of file + sublime.save_settings("symbol_table.sublime-settings") diff --git a/util.py b/util.py index 44cfd94..fdb2d90 100644 --- a/util.py +++ b/util.py @@ -32,7 +32,7 @@ def load_templates(): """ settings = context.get_settings() target_dir = os.path.join(settings["workspace"], ".templates") - if not os.path.exists(target_dir): + if not os.path.exists(target_dir): os.makedirs(target_dir) templates_dir = os.path.join(target_dir, "templates.json") @@ -43,7 +43,7 @@ def load_templates(): if not os.path.isfile(templates_dir) or not os.path.exists(lwc_dir) or not os.path.exists(lwc_ele_dir): # get the installed haoide package directory source_dir = os.path.join( - sublime.installed_packages_path(), + sublime.installed_packages_path(), "haoide.sublime-package" ) @@ -87,19 +87,19 @@ def copy_files_in_folder(source_dir, target_dir): @target_dir -- Target Directory """ - for _file in os.listdir(source_dir): - sourceFile = os.path.join(source_dir, _file) - targetFile = os.path.join(target_dir, _file) + for _file in os.listdir(source_dir): + sourceFile = os.path.join(source_dir, _file) + targetFile = os.path.join(target_dir, _file) - if os.path.isfile(sourceFile): - if not os.path.exists(target_dir): - os.makedirs(target_dir) + if os.path.isfile(sourceFile): + if not os.path.exists(target_dir): + os.makedirs(target_dir) if not os.path.exists(targetFile) or ( os.path.exists(targetFile) and ( - os.path.getsize(targetFile) != os.path.getsize(sourceFile) - )): - open(targetFile, "wb").write(open(sourceFile, "rb").read()) - if os.path.isdir(sourceFile): + os.path.getsize(targetFile) != os.path.getsize(sourceFile) + )): + open(targetFile, "wb").write(open(sourceFile, "rb").read()) + if os.path.isdir(sourceFile): copy_files_in_folder(sourceFile, targetFile) @@ -130,7 +130,7 @@ def copy_files(attributes, target_dir): # Build target file target_file = os.path.join( - target_meta_folder, + target_meta_folder, attribute["fullName"] ) @@ -160,8 +160,8 @@ def copy_files(attributes, target_dir): def get_described_metadata(settings): cache_file = os.path.join( - settings["workspace"], - ".config", + settings["workspace"], + ".config", "metadata.json" ) @@ -222,6 +222,7 @@ def get_package_info(settings): return package + def get_completion_from_cache(settings, component_type, is_lightning=False): """ Get component completion list from .config/package.json @@ -238,7 +239,7 @@ def get_completion_from_cache(settings, component_type, is_lightning=False): members = package_cache.get(component_type, []) for member in members: completion_list.append(( - "%s%s\t%s" % (namespace, member.get("fullName"), component_type), + "%s%s\t%s" % (namespace, member.get("fullName"), component_type), "%s%s" % (namespace, member.get("fullName")) )) else: @@ -246,6 +247,7 @@ def get_completion_from_cache(settings, component_type, is_lightning=False): return completion_list + def view_coverage(file_name, record, body): """ View Apex Class/Trigger code coverage like developer console UI @@ -322,7 +324,7 @@ def local_datetime(server_datetime_str): * local_datetime -- local datetime with GMT offset """ - + offset = get_local_timezone_offset() local_datetime = datetime.datetime.strptime(server_datetime_str[:19], '%Y-%m-%dT%H:%M:%S') local_datetime += datetime.timedelta(hours=offset) @@ -365,7 +367,7 @@ def populate_all_components(): component_id = component_attributes[key]["id"] component_type = component_attributes[key]["type"] component_name = component_attributes[key]["name"] - return_component_attributes[component_type+"."+component_name] = component_id + return_component_attributes[component_type + "." + component_name] = component_id return return_component_attributes @@ -462,7 +464,7 @@ def set_component_attribute(attributes, lastModifiedDate): * attributes -- component attributes * lastModifiedDate -- LastModifiedDate of component """ - + # If sobjects is exist in local cache, just return it settings = context.get_settings() username = settings["username"] @@ -475,13 +477,14 @@ def set_component_attribute(attributes, lastModifiedDate): components_dict = s.get(username, {}) # Prevent exception if no component in org - if _type not in components_dict: - components_dict = {_type : {}} + if _type not in components_dict: + components_dict = {_type: {}} - # Build components dict - attr = components_dict[_type][fullName.lower()] + # update components dict lastModifiedDate atrribute + attr = components_dict[_type][fullName.lower()] attr["lastModifiedDate"] = lastModifiedDate - components_dict[_type][fullName.lower()] = attr + # Comment out unnecessary assignment + # components_dict[_type][fullName.lower()] = attr # Save settings and show success message s.set(username, components_dict) @@ -556,8 +559,8 @@ def get_symbol_tables(username): def get_sobject_completion_list( - sobject_describe, - prefix="", + sobject_describe, + prefix="", display_fields=True, display_parent_relationships=True, display_child_relationships=True): @@ -584,9 +587,9 @@ def get_sobject_completion_list( if display_parent_relationships: for key in sorted(sobject_describe["parentRelationships"]): parent_sobject = sobject_describe["parentRelationships"][key] - completion_list.append((prefix + key + "\t" + parent_sobject + "(c2p)", key)) + completion_list.append((prefix + key + "\t" + parent_sobject + "(c2p)", key)) - # Child Relationship Describe + # Child Relationship Describe if display_child_relationships: for key in sorted(sobject_describe["childRelationships"]): child_sobject = sobject_describe["childRelationships"][key] @@ -624,7 +627,7 @@ def get_component_completion(username, component_type, tag_has_ending=False): value = "c:%s%s" % (component_name, "" if tag_has_ending else "$1>") completion_list.append((display, value)) else: - completion_list.append((component_name+"\t"+component_type, component_name)) + completion_list.append((component_name + "\t" + component_type, component_name)) return completion_list @@ -634,7 +637,7 @@ def get_component_attributes(settings, component_name, is_lightning=False): "aura", component_name, component_name + ".cmp") else: component_dir = os.path.join(settings["workspace"], "src", - "components", component_name+".component") + "components", component_name + ".component") attributes = [] if os.path.isfile(component_dir): name, _type, description = "", "", "" @@ -671,12 +674,13 @@ def get_component_attributes(settings, component_name, is_lightning=False): return attributes + def get_attribute_completion(settings, component_name, is_lightning=False): completion_list = [] for attribute in get_component_attributes(settings, component_name, is_lightning): display = "%s\t%s(%s)" % ( - attribute["name"], - attribute["description"], + attribute["name"], + attribute["description"], attribute["type"].capitalize() ) value = '%s="$1"$0' % attribute["name"] @@ -684,6 +688,7 @@ def get_attribute_completion(settings, component_name, is_lightning=False): return completion_list + def convert_15_to_18(the15Id): """ Convert Salesforce 15 Id to 18 Id @@ -695,21 +700,21 @@ def convert_15_to_18(the15Id): * 18 Id - converted 18 Id """ - + if not the15Id or len(the15Id) != 15: return the15Id cmap = { "00000": "A", "00001": "B", "00010": "C", "00011": "D", "00100": "E", "00101": "F", "00110": "G", "00111": "H", "01000": "I", "01001": "J", - "01010": "K", "01011": "L", "01100": "M", "01101": "N", "01110": "O", - "01111": "P", "10000": "Q", "10001": "R", "10010": "S", "10011": "T", - "10100": "U", "10101": "V", "10110": "W", "10111": "X", "11000": "Y", - "11001": "Z", "11010": "0", "11011": "1", "11100": "2", "11101": "3", + "01010": "K", "01011": "L", "01100": "M", "01101": "N", "01110": "O", + "01111": "P", "10000": "Q", "10001": "R", "10010": "S", "10011": "T", + "10100": "U", "10101": "V", "10110": "W", "10111": "X", "11000": "Y", + "11001": "Z", "11010": "0", "11011": "1", "11100": "2", "11101": "3", "11110": "4", "11111": "5" } chars = [cmap["".join(["1" if c.isupper() else "0" for c in char[::-1]])] \ - for char in list_chunks(the15Id, 5)] + for char in list_chunks(the15Id, 5)] return the15Id + "".join(chars) @@ -723,7 +728,7 @@ def list_chunks(l, n): * n - split size """ for i in range(0, len(l), n): - yield l[i:i+n] + yield l[i:i + n] def dict_chunks(data, SIZE=10000): @@ -793,7 +798,7 @@ def get_variable_type(view, pt, pattern): # Get the matched variable type matched_regions = view.find_all(pattern, sublime.IGNORECASE) uncomment_regions = remove_comments(view, matched_regions) - + # Three scenarios: # 1. If no matched regions # 2. Only one matched region @@ -803,7 +808,7 @@ def get_variable_type(view, pt, pattern): elif len(uncomment_regions) == 1: matched_region = uncomment_regions[0] else: - row_region = {} # Row => Region + row_region = {} # Row => Region for mr in uncomment_regions: row, col = view.rowcol(mr.begin()) row_region[row] = mr @@ -823,7 +828,7 @@ def get_variable_type(view, pt, pattern): # Get the content of matched region matched_str = view.substr(matched_region).strip() - + # If list, map, set if "<" in matched_str and ">" in matched_str: variable_type = matched_str.split("<")[0].strip() @@ -860,7 +865,7 @@ def get_soql_match_region(view, pt): matched_region = m break - if not matched_region: + if not matched_region: return (matched_region, is_between_start_and_from, sobject_name) match_str = view.substr(matched_region) @@ -870,7 +875,7 @@ def get_soql_match_region(view, pt): if pt >= (select_pos + match_begin) and pt <= (from_pos + match_begin): is_between_start_and_from = True - sobject_name = match_str[from_pos+5:] + sobject_name = match_str[from_pos + 5:] sobject_name = sobject_name.strip() return (matched_region, is_between_start_and_from, sobject_name) @@ -885,7 +890,7 @@ def parse_symbol_table(symbol_table): """ completions = {} - if not symbol_table: + if not symbol_table: return completions; for c in symbol_table.get('constructors', []): @@ -896,37 +901,37 @@ def parse_symbol_table(symbol_table): params.append(p["type"].capitalize() + " " + p["name"]) paramStrings = [] for i, p in enumerate(params): - paramStrings.append("${"+str(i+1)+":"+params[i]+"}") + paramStrings.append("${" + str(i + 1) + ":" + params[i] + "}") paramString = ", ".join(paramStrings) - completions[modifiers+" "+c["name"]+"("+", ".join(params)+")"] =\ + completions[modifiers + " " + c["name"] + "(" + ", ".join(params) + ")"] = \ "%s(%s)" % (c["name"], paramString) else: - completions[modifiers+" "+c["name"]+"()"] = c["name"]+"()${1:}" + completions[modifiers + " " + c["name"] + "()"] = c["name"] + "()${1:}" for c in symbol_table.get('properties', []): modifiers = " ".join(c.get("modifiers", [])) property_type = c["type"].capitalize() if "type" in c and c["type"] else "" - completions[modifiers+" "+c["name"]+"\t"+property_type] = c["name"] + completions[modifiers + " " + c["name"] + "\t" + property_type] = c["name"] for c in symbol_table.get('methods', []): params = [] modifiers = " ".join(c.get("modifiers", [])) if 'parameters' in c and type(c['parameters']) is list and len(c['parameters']) > 0: for p in c['parameters']: - params.append(p["type"]+" "+p["name"]) + params.append(p["type"] + " " + p["name"]) if len(params) == 1: - completions[modifiers+" "+c["name"]+"("+", ".join(params)+") \t"+c['returnType']] =\ + completions[modifiers + " " + c["name"] + "(" + ", ".join(params) + ") \t" + c['returnType']] = \ "%s(${1:%s})" % (c["name"], ", ".join(params)) elif len(params) > 1: paramStrings = [] for i, p in enumerate(params): - paramStrings.append("${"+str(i+1)+":"+params[i]+"}") + paramStrings.append("${" + str(i + 1) + ":" + params[i] + "}") paramString = ", ".join(paramStrings) - completions[modifiers+" "+c["name"]+"("+", ".join(params)+") \t"+c['returnType']] =\ - c["name"]+"("+paramString+")" + completions[modifiers + " " + c["name"] + "(" + ", ".join(params) + ") \t" + c['returnType']] = \ + c["name"] + "(" + paramString + ")" else: - completions[modifiers+" "+c["name"]+"("+", ".join(params)+") \t"+c['returnType']] =\ - c["name"]+"()${1:}" + completions[modifiers + " " + c["name"] + "(" + ", ".join(params) + ") \t" + c['returnType']] = \ + c["name"] + "()${1:}" for c in symbol_table.get("innerClasses", []): tableDeclaration = c.get("tableDeclaration") @@ -943,16 +948,16 @@ def parse_symbol_table(symbol_table): params = [] if 'parameters' in con and type(con['parameters']) is list and len(con['parameters']) > 0: for p in con['parameters']: - params.append(p["type"].capitalize()+" "+p["name"]) + params.append(p["type"].capitalize() + " " + p["name"]) paramStrings = [] for i, p in enumerate(params): - paramStrings.append("${"+str(i+1)+":"+params[i]+"}") + paramStrings.append("${" + str(i + 1) + ":" + params[i] + "}") paramString = ", ".join(paramStrings) - completions[modifiers+" "+con["name"]+"("+", ".join(params)+")"] =\ - c["name"]+"("+paramString+")" + completions[modifiers + " " + con["name"] + "(" + ", ".join(params) + ")"] = \ + c["name"] + "(" + paramString + ")" else: - completions[modifiers+" "+con["name"]+"()"] =\ - c["name"]+"()${1:}" + completions[modifiers + " " + con["name"] + "()"] = \ + c["name"] + "()${1:}" return completions @@ -993,20 +998,20 @@ def add_config_history(operation, content, settings, ext="json"): * history_content -- the content needed to keep """ outputdir = os.path.join(settings["workspace"], ".config") - if not os.path.exists(outputdir): + if not os.path.exists(outputdir): os.makedirs(outputdir) with open(outputdir + "/%s.%s" % (operation, ext), "w") as fp: fp.write(json.dumps(content, indent=4)) # After write the file to local, refresh sidebar - sublime.set_timeout(lambda:sublime.active_window().run_command('refresh_folder_list'), 200); - sublime.set_timeout(lambda:sublime.active_window().run_command('refresh_folder_list'), 1300); + sublime.set_timeout(lambda: sublime.active_window().run_command('refresh_folder_list'), 200); + sublime.set_timeout(lambda: sublime.active_window().run_command('refresh_folder_list'), 1300); def export_report_api(rootdir): reports = [] - for parent,dirnames,filenames in os.walk(rootdir): + for parent, dirnames, filenames in os.walk(rootdir): for filename in filenames: if not filename.endswith(".report"): continue report_dir = parent + "/" + filename @@ -1152,7 +1157,7 @@ def parse_package_types(_types): # If no elements, don't keep it if not elements: continue - + # inFolder is false if attr["inFolder"] == "false": package_types[_type] = elements @@ -1162,7 +1167,7 @@ def parse_package_types(_types): for folder in [e for e in elements if "/" not in e]: folder_elements[folder] = [ e for e in elements if e.startswith(folder) \ - and "/" in e + and "/" in e ] package_types[_type] = folder_elements continue @@ -1206,7 +1211,7 @@ def build_package_types(package_xml_content): metadata_types = result["Package"]["types"] # If there is only one types in package - if isinstance(metadata_types, dict): + if isinstance(metadata_types, dict): metadata_types = [metadata_types] types = {} @@ -1235,7 +1240,7 @@ def build_folder_types(dirs): types = {} for _dir in dirs: base, folder = os.path.split(_dir) - + if folder not in settings: continue if dname not in _dir: continue @@ -1268,11 +1273,11 @@ def build_package_dict(files, ignore_folder=True): package_dict = {} for f in files: # Ignore folder - if ignore_folder and not os.path.isfile(f): + if ignore_folder and not os.path.isfile(f): continue # Replace meta file with source file - if f.endswith("-meta.xml"): + if f.endswith("-meta.xml"): f = f.replace("-meta.xml", "") # If ignore_folder is true and f is folder @@ -1344,10 +1349,11 @@ def build_package_xml(settings, package_dict): return package_xml_content + def build_destructive_package_by_files(files, ignore_folder=True): settings = context.get_settings() workspace = settings["workspace"] - if not os.path.exists(workspace): + if not os.path.exists(workspace): os.makedirs(workspace) # Constucture package dict @@ -1355,13 +1361,13 @@ def build_destructive_package_by_files(files, ignore_folder=True): # Build destructiveChanges.xml destructive_xml_content = build_package_xml(settings, package_dict) - destructive_xml_path = workspace+"/destructiveChanges.xml" + destructive_xml_path = workspace + "/destructiveChanges.xml" with open(destructive_xml_path, "wb") as fp: fp.write(destructive_xml_content.encode("utf-8")) # Build package.xml package_xml_content = build_package_xml(settings, {}) - package_xml_path = workspace+"/package.xml" + package_xml_path = workspace + "/package.xml" with open(package_xml_path, "wb") as fp: fp.write(package_xml_content.encode("utf-8")) @@ -1387,6 +1393,7 @@ def build_destructive_package_by_files(files, ignore_folder=True): return base64_package + def build_destructive_package_by_package_xml(types): """ Build destructive package, @@ -1408,13 +1415,13 @@ def build_destructive_package_by_package_xml(types): # Build destructiveChanges.xml destructive_xml_content = build_package_xml(settings, types) - destructive_xml_path = workspace+"/destructiveChanges.xml" + destructive_xml_path = workspace + "/destructiveChanges.xml" with open(destructive_xml_path, "wb") as fp: fp.write(destructive_xml_content.encode("utf-8")) # Build package.xml package_xml_content = build_package_xml(settings, {}) - package_xml_path = workspace+"/package.xml" + package_xml_path = workspace + "/package.xml" with open(package_xml_path, "wb") as fp: fp.write(package_xml_content.encode("utf-8")) @@ -1460,9 +1467,9 @@ def build_deploy_package(files): # Define write_to write_to = ( - metadata_folder, - ("/" + f["folder"]) if f["folder"] else "", - f["name"], + metadata_folder, + ("/" + f["folder"]) if f["folder"] else "", + f["name"], f["extension"] ) @@ -1488,7 +1495,7 @@ def build_deploy_package(files): package_xml_content = format_xml(package_xml_content) if settings["debug_mode"]: - print ("{seprate}\n[Package.xml for Deployment]: \n{seprate}\n{content}\n{seprate}".format( + print("{seprate}\n[Package.xml for Deployment]: \n{seprate}\n{content}\n{seprate}".format( seprate="~" * 100, content=package_xml_content.decode("UTF-8") )) @@ -1497,13 +1504,13 @@ def build_deploy_package(files): try: time_stamp = time.strftime("%Y%m%d%H%M", time.localtime(time.time())) xml_dir = os.path.join(settings["workspace"], ".deploy") - if not os.path.exists(xml_dir): + if not os.path.exists(xml_dir): os.mkdir(xml_dir) - + # http://stackoverflow.com/questions/1627198/python-mkdir-giving-me-wrong-permissions if not os.access(xml_dir, os.W_OK): os.chmod(xml_dir, 0o755) - + xml_dir = os.path.join(xml_dir, "package-%s.xml" % time_stamp) with open(xml_dir, "wb") as fp: fp.write(package_xml_content) @@ -1536,12 +1543,12 @@ def compress_resource_folder(resource_folder): static_resource_path, resource_name = os.path.split(resource_folder) # Create StaticResource File - static_resource_file = os.path.join(static_resource_path, resource_name+".resource") + static_resource_file = os.path.join(static_resource_path, resource_name + ".resource") zf = zipfile.ZipFile(static_resource_file, "w", zipfile.ZIP_DEFLATED) for dirpath, dirnames, filenames in os.walk(resource_folder): - basename = dirpath[len(resource_folder)+1:] + basename = dirpath[len(resource_folder) + 1:] for filename in filenames: - zf.write(os.path.join(dirpath, filename), basename+"/"+filename) + zf.write(os.path.join(dirpath, filename), basename + "/" + filename) zf.close() # Build package @@ -1574,7 +1581,7 @@ def build_lightning_package(files_or_dirs, meta_type=""): for dirpath, dirnames, filenames in os.walk(_file_or_dir): base, aura_name = os.path.split(dirpath) if not filenames: - zf.write(dirpath, meta_folder+"/"+aura_name) + zf.write(dirpath, meta_folder + "/" + aura_name) else: for filename in filenames: zf.write(os.path.join(dirpath, filename), "%s/%s/%s" % ( @@ -1599,7 +1606,7 @@ def build_lightning_package(files_or_dirs, meta_type=""): meta_type, settings["api_version"] ) - package_xml_path = settings["workspace"]+"/package.xml" + package_xml_path = settings["workspace"] + "/package.xml" open(package_xml_path, "wb").write(package_xml_content.encode("utf-8")) zf.write(package_xml_path, "package.xml") os.remove(package_xml_path) @@ -1625,12 +1632,12 @@ def base64_encode(zipfile): def compress_package(package_dir): - zipfile_path = package_dir+"/archive.zip" + zipfile_path = package_dir + "/archive.zip" zf = zipfile.ZipFile(zipfile_path, "w", zipfile.ZIP_DEFLATED) for dirpath, dirnames, filenames in os.walk(package_dir): - basename = dirpath[len(package_dir)+1:] + basename = dirpath[len(package_dir) + 1:] for filename in filenames: - zf.write(os.path.join(dirpath, filename), basename+"/"+filename) + zf.write(os.path.join(dirpath, filename), basename + "/" + filename) zf.close() base64_package = base64_encode(zipfile_path) @@ -1662,6 +1669,7 @@ def extract_encoded_zipfile(encoded_zip_file, extract_to, ignore_package_xml=Fal # we need to refresh the sublime workspace to show it sublime.active_window().run_command("refresh_folder_list") + def extract_zipfile(zipfile_path, extract_to): """ Extract Zip File to current folder """ @@ -1672,7 +1680,7 @@ def extract_zipfile(zipfile_path, extract_to): raise BaseException(str(ex)) return - if not os.path.exists(extract_to): + if not os.path.exists(extract_to): os.makedirs(extract_to) for filename in zfile.namelist(): @@ -1698,7 +1706,7 @@ def extract_file(zipfile_path, extract_to, ignore_package_xml=False): """ zip_file = zipfile.ZipFile(zipfile_path, 'r') for filename in zip_file.namelist(): - if filename.endswith('/'): + if filename.endswith('/'): continue if ignore_package_xml and filename == "unpackaged/package.xml": @@ -1717,6 +1725,7 @@ def extract_file(zipfile_path, extract_to, ignore_package_xml=False): zip_file.close() + def extract_zip(base64String, extract_to): """ 1. Decode base64String to zip @@ -1737,6 +1746,7 @@ def extract_zip(base64String, extract_to): return zipfile_path + def parse_package(package_content): """Parse package types to specified format @@ -1782,24 +1792,25 @@ def parse_package(package_content): members.append("%s" % t["members"]) elements.append("%s%s" % ( - "".join(members), + "".join(members), "%s" % t["name"] )) return "".join(elements) + "%s" % result["Package"]["version"] + def reload_file_attributes(file_properties, settings=None, append=False): - """ Keep the file attribute to local cache + """ Keep the file attribute to local cache for saving to server directly later Paramter: - * file_properties -- file attributes returned from server + * file_properties -- file attributes returned from server via Metadata API * settings -- whole plugin settings * append -- default is False, if append is false, it means local cache of default project are reloaded by file properties, otherwise, file properties will be appended to local cache """ # Get settings - if not settings: + if not settings: settings = context.get_settings() metadata_body_or_markup = { @@ -1813,7 +1824,7 @@ def reload_file_attributes(file_properties, settings=None, append=False): # print(file_properties) # If the package only contains `package.xml` - if isinstance(file_properties, dict): + if isinstance(file_properties, dict): file_properties = [file_properties] component_settings = sublime.load_settings(context.COMPONENT_METADATA_SETTINGS) @@ -1831,11 +1842,11 @@ def reload_file_attributes(file_properties, settings=None, append=False): if metdata_object in all_components_attr: components_attr = all_components_attr[metdata_object] - base_name = filep['fileName'][filep['fileName'].rfind("/")+1:] + base_name = filep['fileName'][filep['fileName'].rfind("/") + 1:] last_point = base_name.rfind(".") name = base_name[:last_point] - extension = ".%s" % base_name[last_point+1:] - + extension = ".%s" % base_name[last_point + 1:] + attrs = { "namespacePrefix": filep.get("namespacePrefix", None), "name": name, @@ -1867,7 +1878,8 @@ def reload_file_attributes(file_properties, settings=None, append=False): sublime.save_settings(context.COMPONENT_METADATA_SETTINGS) # Reload component metadata cache in globals() - sublime.set_timeout(lambda:load_metadata_cache(True, settings["username"]), 5) + sublime.set_timeout(lambda: load_metadata_cache(True, settings["username"]), 5) + def format_debug_logs(settings, records): if len(records) == 0: return "No available logs." @@ -1914,22 +1926,23 @@ def format_debug_logs(settings, records): # Headers headers = "" for header in debug_log_headers: - headers += "%-*s" % (debug_log_headers_properties[header]["width"], - debug_log_headers_properties[header]["label"]) + headers += "%-*s" % (debug_log_headers_properties[header]["width"], + debug_log_headers_properties[header]["label"]) # Content content = "" - records = sorted(records, key=lambda k : k['StartTime']) + records = sorted(records, key=lambda k: k['StartTime']) for record in records: for header in debug_log_headers: if header == "StartTime": content += "%-*s" % (debug_log_headers_properties[header]["width"], - local_datetime(record[header])) + local_datetime(record[header])) continue content += "%-*s" % (debug_log_headers_properties[header]["width"], record[header]) content += "\n" - return "\n" + headers + "\n" + (len(headers) * "-") + "\n" + content[:len(content)-1] + return "\n" + headers + "\n" + (len(headers) * "-") + "\n" + content[:len(content) - 1] + def format_error_message(result): """Format message as below format @@ -1946,17 +1959,21 @@ def format_error_message(result): error_message = "" for key, value in result.items(): - if isinstance(value, list): - if value: value = value[0] - else: continue - elif not value: continue - + if isinstance(value, list): + if value: + value = value[0] + else: + continue + elif not value: + continue + error_message += "% 30s\t" % "{0}: ".format(key) - value = urllib.parse.unquote(unescape(none_value(value), - {"'": "'", """: '"'})) + value = urllib.parse.unquote(unescape(none_value(value), + {"'": "'", """: '"'})) error_message += "%-30s\t" % value + "\n" - return error_message[:len(error_message)-1] + return error_message[:len(error_message) - 1] + def format_waiting_message(result, header=""): error_message = header + "\n" + "-" * 100 + "\n" @@ -1978,6 +1995,7 @@ def format_waiting_message(result, header=""): return error_message + def format_xml(xml_string, indent="4"): """Return formatted XML string @@ -1999,6 +2017,7 @@ def format_xml(xml_string, indent="4"): return content + def none_value(value): """ If value is None, return "", if not, return string format of value @@ -2009,7 +2028,8 @@ def none_value(value): if not value: return "" return "%s" % value - + + def is_python3x(): """ If python version is 3.x, return True @@ -2017,9 +2037,12 @@ def is_python3x(): return sys.version > '3' + """ Below three functions are used to parse completions out of box. """ + + def parse_namespace(publicDeclarations): """ from . import util @@ -2037,6 +2060,7 @@ def parse_namespace(publicDeclarations): return namespaces_dict + def parse_method(methods, is_method=True): if not methods: return {} @@ -2058,11 +2082,12 @@ def parse_method(methods, is_method=True): for i in range(len(display_parameters)): return_parameters.append("${%s:%s}" % (i + 1, display_parameters[i])) - methods_dict["%s(%s)\t%s" % (method["name"], ', '.join(display_parameters), returnType)] =\ + methods_dict["%s(%s)\t%s" % (method["name"], ', '.join(display_parameters), returnType)] = \ "%s(%s)$0" % (method["name"], ', '.join(return_parameters)) return methods_dict + def parse_properties(properties): if not properties: return {} properties_dict = {} @@ -2071,6 +2096,7 @@ def parse_properties(properties): return properties_dict + def parse_all(apex): """ Usage: @@ -2108,10 +2134,10 @@ def parse_all(apex): if class_name.lower() in apex_completions: apex_completions[class_name.lower()] = [apex_completions[class_name.lower()]] apex_completions[class_name.lower()].append({ - "constructors" : constructors_dict, - "methods" : methods_dict, - "properties" : properties_dict, - "namespace" : namespace, + "constructors": constructors_dict, + "methods": methods_dict, + "properties": properties_dict, + "namespace": namespace, "name": class_name }) else: @@ -2121,7 +2147,7 @@ def parse_all(apex): apex_completions[class_name.lower()]["properties"] = properties_dict apex_completions[class_name.lower()]["namespace"] = namespace apex_completions[class_name.lower()]["name"] = class_name - + return apex_completions @@ -2135,9 +2161,9 @@ def parse_code_coverage(result): "Coverage": _record.get("Coverage") } - code_coverage_desc =("Trigger Or Class Code Coverage:\n" + - "Select Apex trigger or class name and " + - "view code coverage by context menu\n") + code_coverage_desc = ("Trigger Or Class Code Coverage:\n" + + "Select Apex trigger or class name and " + + "view code coverage by context menu\n") # Keep the coverage to local cache, will overwrite the old one settings = context.get_settings() @@ -2167,8 +2193,9 @@ def parse_code_coverage(result): row += "%-*s" % (header_width["Lines"], "%s/%s" % (covered_lines, total_lines)) code_coverage += row + "\n" - return message.SEPRATE.format(code_coverage_desc + "-"*79 + "\n" + - columns + "\n"*2 + code_coverage) + return message.SEPRATE.format(code_coverage_desc + "-" * 79 + "\n" + + columns + "\n" * 2 + code_coverage) + def parse_sync_test_coverage(result): successes = result["successes"] @@ -2178,7 +2205,7 @@ def parse_sync_test_coverage(result): allrows = [] if result["failures"]: allrows.append("Failed Test Methods:") - for failure in sorted(result["failures"], key=lambda k : k["name"]): + for failure in sorted(result["failures"], key=lambda k: k["name"]): allrows.append("~" * 80) failure_row = [] failure_row.append("% 30s %-30s " % ("ClassName: ", failure["name"])) @@ -2193,7 +2220,7 @@ def parse_sync_test_coverage(result): if result["successes"]: allrows.append("~" * 80) allrows.append("Successful Test Methods:") - for success in sorted(result["successes"], key=lambda k : k["name"]): + for success in sorted(result["successes"], key=lambda k: k["name"]): allrows.append("~" * 80) success_row = [] success_row.append("% 30s %-30s " % ("ClassName: ", success["name"])) @@ -2220,7 +2247,8 @@ def parse_sync_test_coverage(result): coverageRows.append("".join(columns)) coverageRows.append("~" * 80) codeCoverage = sorted(result["codeCoverage"], reverse=True, - key=lambda k : 0 if k["numLocations"] == 0 else (k["numLocations"] - k['numLocationsNotCovered']) / k["numLocations"]) + key=lambda k: 0 if k["numLocations"] == 0 else (k["numLocations"] - k[ + 'numLocationsNotCovered']) / k["numLocations"]) for coverage in codeCoverage: coverageRow = [] coverageRow.append("%-*s" % (header_width["Type"], coverage["type"])) @@ -2232,12 +2260,12 @@ def parse_sync_test_coverage(result): numLocationsCovered = numLocations - numLocationsNotCovered percent = numLocationsCovered / numLocations * 100 if numLocations != 0 else 0 coverageRow.append("%-*s" % ( - header_width["Percent"], + header_width["Percent"], "%.2f%%" % percent )) coverageRow.append("%-*s" % ( header_width["Lines"], "%s/%s" % ( - numLocationsCovered, + numLocationsCovered, numLocations ) )) @@ -2248,6 +2276,7 @@ def parse_sync_test_coverage(result): return "\n".join(allrows) + def parse_test_result(test_result): """ format test result as specified format @@ -2279,8 +2308,8 @@ def parse_test_result(test_result): return_result = class_name + test_result_desc + test_result_content[:-1] # Parse Debug Log Part - info = "Select LogId and view log detail " +\ - "in Sublime or Salesforce by context menu" + info = "Select LogId and view log detail " + \ + "in Sublime or Salesforce by context menu" debug_log_content = "LogId: " if len(test_result) > 0 and test_result[0]["ApexLogId"] != None: debug_log_content += test_result[0]["ApexLogId"] @@ -2290,6 +2319,7 @@ def parse_test_result(test_result): return return_result + def parse_validation_rule(settings, sobjects): """ Parse the validation rule in Sobject.object to csv @@ -2306,8 +2336,8 @@ def parse_validation_rule(settings, sobjects): # Initiate CSV Writer and Write headers columns = settings["validation_rule_columns"] with open(outputdir + "/ValidationRules.csv", "wb") as fp: - fp.write(u'\ufeff'.encode('utf8')) # Write BOM Header - fp.write(",".join(columns).encode("utf-8") + b"\n") # Write Header + fp.write(u'\ufeff'.encode('utf8')) # Write BOM Header + fp.write(",".join(columns).encode("utf-8") + b"\n") # Write Header # Open workflow source file validation_rule_path = settings["workspace"] + "/src/objects" @@ -2330,6 +2360,7 @@ def parse_validation_rule(settings, sobjects): # If one sobject doesn't have vr, We don't need do anything pass + def parse_workflow_metadata(settings, sobjects): """Parse Sobject.workflow to csv, including rule, field update and alerts @@ -2377,8 +2408,8 @@ def parse_workflow_metadata(settings, sobjects): # Write Header with open(rule_outputdir, "wb") as fp: - fp.write(u'\ufeff'.encode('utf8')) # Write BOM Header - fp.write(",".join([(c[0].upper() + c[1:]) for c in columns]).encode("utf-8") + b"\n") # Write Header + fp.write(u'\ufeff'.encode('utf8')) # Write BOM Header + fp.write(",".join([(c[0].upper() + c[1:]) for c in columns]).encode("utf-8") + b"\n") # Write Header # Append Body rule_path = settings["workspace"] + "/src/workflows" @@ -2397,6 +2428,7 @@ def parse_workflow_metadata(settings, sobjects): # If one sobject doesn't have vr, We don't need do anything pass + def write_metadata_to_csv(fp, columns, metadata, sobject): """ This method is invoked by function in this module @@ -2447,7 +2479,7 @@ def write_metadata_to_csv(fp, columns, metadata, sobject): else: value = " ".join(cell_value) + "\n" - cell_value = value[ : -1] + cell_value = value[: -1] else: cell_value = "" elif not cell_value: @@ -2456,8 +2488,8 @@ def write_metadata_to_csv(fp, columns, metadata, sobject): cell_value = "%s" % cell_value # Unescape special code to normal - cell_value = urllib.parse.unquote(unescape(cell_value, - {"'": "'", """: '"'})) + cell_value = urllib.parse.unquote(unescape(cell_value, + {"'": "'", """: '"'})) # Append cell_value to list in order to write list to csv if '"' in cell_value: @@ -2470,9 +2502,10 @@ def write_metadata_to_csv(fp, columns, metadata, sobject): row_value_bin = ",".join(row_value) row_values += row_value_bin.encode("utf-8") + b"\n" - fp.write(row_values) # Write Body + fp.write(row_values) # Write Body fp.close() + def list2csv(file_path, records, NOT_INCLUDED_COLUMNS=["urls", "attributes"]): """convert simple dict in list to csv @@ -2496,6 +2529,7 @@ def list2csv(file_path, records, NOT_INCLUDED_COLUMNS=["urls", "attributes"]): values.append(('"%s"' % none_value(record[strk])).encode("utf-8")) fp.write(b",".join(values) + b"\n") + def json2csv(_list, NOT_INCLUDED_COLUMNS=["urls", "attributes"]): """convert simple dict in list to csv @@ -2520,6 +2554,7 @@ def json2csv(_list, NOT_INCLUDED_COLUMNS=["urls", "attributes"]): return csv_content + def parse_data_template_vertical(output_file_dir, result): """Parse the data template to csv by page layout @@ -2569,7 +2604,7 @@ def parse_data_template_vertical(output_file_dir, result): for picklist in details["picklistValues"]: picklist_labels.append(picklist["label"]) picklist_values.append(picklist["value"]) - + fields_picklist_labels.append('"%s"' % "\n".join(picklist_labels)) fields_picklist_values.append('"%s"' % "\n".join(picklist_values)) @@ -2584,6 +2619,7 @@ def parse_data_template_vertical(output_file_dir, result): fp.write(",".join(fields_picklist_labels).encode("utf-8") + b"\n") fp.write(",".join(fields_picklist_values).encode("utf-8") + b"\n") + def parse_data_template_horizontal(output_file_dir, result): """Parse the data template to csv by page layout @@ -2623,7 +2659,7 @@ def parse_data_template_horizontal(output_file_dir, result): for picklist in details["picklistValues"]: picklist_labels.append(picklist["label"]) picklist_values.append(picklist["value"]) - + row = [] row.append(details["label"]) row.append(details["name"]) @@ -2639,6 +2675,7 @@ def parse_data_template_horizontal(output_file_dir, result): fp.write(u'\ufeff'.encode('utf8')) fp.write("\n".join(rows).encode("utf-8")) + def get_soql_fields(soql): """ Get the field list of soql @@ -2653,10 +2690,10 @@ def get_soql_fields(soql): return [] fieldstr = match.group(0).strip()[6:-4].replace("\n", "").replace("\t", "") - print (fieldstr.split(',')) + print(fieldstr.split(',')) fields = [] - expr_fields = [] # Aggregate Fields + expr_fields = [] # Aggregate Fields for f in fieldstr.split(','): f = f.strip() if " " in f: @@ -2670,15 +2707,16 @@ def get_soql_fields(soql): for idx in range(0, len(expr_fields)): fields.append('expr%s' % idx) - print (fields) + print(fields) return fields + def query_to_csv(result, soql): records = result["records"] if not records: return b"No matched rows" - + # Get CSV headers, # If we use * to fetch all fields if re.compile("select\\s+\\*\\s+from[\\s\\t]+\\w+", re.I).match(soql): @@ -2710,7 +2748,8 @@ def query_to_csv(result, soql): rows += ",".join(row).encode("utf-8") + b"\n" return rows - + + def parse_execute_anonymous_xml(result): """Return the formatted anonymous execute result @@ -2730,14 +2769,15 @@ def parse_execute_anonymous_xml(result): line = result["line"] column = result["column"] compileProblem = result["compileProblem"] - view_result = compileProblem + " at line " + line +\ - " column " + column + view_result = compileProblem + " at line " + line + \ + " column " + column - view_result = urllib.parse.unquote(unescape(view_result, - {"'": "'", """: '"'})) + view_result = urllib.parse.unquote(unescape(view_result, + {"'": "'", """: '"'})) return view_result + def generate_workbook(result, workspace, workbook_field_describe_columns): """ generate workbook for sobject according to user customized columns you can change the workbook_field_describe_columns in default settings @@ -2763,21 +2803,21 @@ def generate_workbook(result, workspace, workbook_field_describe_columns): # Create new csv file for this workbook # fp = open(outputdir + "/" + sobject + ".csv", "wb", newline='') workbook_dir = outputdir + "/" + sobject + ".csv" - - #------------------------------------------------------------ + + # ------------------------------------------------------------ # Headers, all headers are capitalized - #------------------------------------------------------------ + # ------------------------------------------------------------ headers = [column.capitalize() for column in fields_key] # Write Header fp = open(workbook_dir, "wb") - fp.write(u'\ufeff'.encode('utf8')) # Write BOM Header - fp.write(",".join(headers).encode("utf-8") + b"\n") # Write Header + fp.write(u'\ufeff'.encode('utf8')) # Write BOM Header + fp.write(",".join(headers).encode("utf-8") + b"\n") # Write Header - #------------------------------------------------------------ + # ------------------------------------------------------------ # Fields Part (All rows are sorted by field label) - #------------------------------------------------------------ - fields = sorted(fields, key=lambda k : k['label']) + # ------------------------------------------------------------ + fields = sorted(fields, key=lambda k: k['label']) for field in fields: row_value_literal = b"" row_values = [] @@ -2789,7 +2829,7 @@ def generate_workbook(result, workspace, workbook_field_describe_columns): for key in fields_key: # Get field value by field API(key) row_value = field.get(key) - + if isinstance(row_value, list): if key == "picklistValues": value = '' @@ -2810,8 +2850,8 @@ def generate_workbook(result, workspace, workbook_field_describe_columns): row_value = field_type if key == "type" else "%s" % row_value # Unescape special code to normal - row_value = urllib.parse.unquote(unescape(row_value, - {"'": "'", """: '"'})) + row_value = urllib.parse.unquote(unescape(row_value, + {"'": "'", """: '"'})) # Append row_value to list in order to write list to csv if '"' in row_value: @@ -2828,16 +2868,17 @@ def generate_workbook(result, workspace, workbook_field_describe_columns): fp.close() # Display Success Message - sublime.set_timeout(lambda:sublime.status_message(sobject + " workbook is generated"), 10) + sublime.set_timeout(lambda: sublime.status_message(sobject + " workbook is generated"), 10) # Return outputdir return outputdir + record_keys = ["label", "name", "type", "length"] record_key_width = { - "label": 40, - "name": 40, - "type": 20, + "label": 40, + "name": 40, + "type": 20, "length": 7 } recordtype_key_width = { @@ -2854,6 +2895,8 @@ def generate_workbook(result, workspace, workbook_field_describe_columns): } seprate = 100 * "-" + "\n" + + def parse_sobject_field_result(result): """According to sobject describe result, display record type information, child sobjects information and the field information. @@ -2870,9 +2913,9 @@ def parse_sobject_field_result(result): # View Name or Header view_result = sobject + " Describe:\n" - #------------------------------------------------ + # ------------------------------------------------ # Fields Part - #------------------------------------------------ + # ------------------------------------------------ # Output totalSize Part fields = result.get("fields") view_result += seprate @@ -2889,15 +2932,15 @@ def parse_sobject_field_result(result): view_result += len(columns) * "-" + "\n" # Sort fields list by lable of every field - fields = sorted(fields, key=lambda k : k['label']) + fields = sorted(fields, key=lambda k: k['label']) # Output field values for record in fields: row = "" for key in record_keys: row_value = "Formula(%s)" % record.get(key) if key == "type" \ - and record["calculatedFormula"] else record.get(key) - + and record["calculatedFormula"] else record.get(key) + if not row_value: row_value = "" @@ -2908,9 +2951,9 @@ def parse_sobject_field_result(result): view_result += row + "\n" view_result += "\n" - #------------------------------------------------ + # ------------------------------------------------ # Record Type Part - #------------------------------------------------ + # ------------------------------------------------ recordtypes = result.get("recordTypeInfos") view_result += seprate view_result += "Record Type Info: \t" + str(len(recordtypes)) + "\n" @@ -2935,7 +2978,7 @@ def parse_sobject_field_result(result): row = "" for key in recordtype_keys: if key not in recordtype_key_width: continue - + # Get field value by field API # and convert it to str row_value = recordtype.get(key) @@ -2945,14 +2988,14 @@ def parse_sobject_field_result(result): key_width = recordtype_key_width[key] row_value = "%-*s" % (key_width, row_value) row += row_value - + view_result += row + "\n" view_result += "\n" - #------------------------------------------------ + # ------------------------------------------------ # Child Relationship - #------------------------------------------------ + # ------------------------------------------------ childRelationships = result.get("childRelationships") view_result += seprate view_result += "ChildRelationships Info: \t" + str(len(childRelationships)) + "\n" @@ -2978,13 +3021,14 @@ def parse_sobject_field_result(result): row_value = "%-*s" % (30, row_value) row += row_value - + view_result += row + "\n" view_result += "\n" return view_result + def getUniqueElementValueFromXmlString(xmlString, elementName): """ Extracts an element value from an XML string. @@ -2997,17 +3041,18 @@ def getUniqueElementValueFromXmlString(xmlString, elementName): elementsByName = xmlStringAsDom.getElementsByTagName(elementName) elementValue = None if len(elementsByName) > 0: - elementValue = elementsByName[0].toxml().replace('<' +\ - elementName + '>','').replace('','') + elementValue = elementsByName[0].toxml().replace('<' + \ + elementName + '>', '').replace('', '') else: elementValue = xmlString.decode("utf-8") return unescape(elementValue, {"'": "'", """: '"'}) + def get_response_error(response): # Debug Message settings = context.get_settings() if settings["debug_mode"]: - print (response.content) + print(response.content) content = response.content result = {"success": False} @@ -3020,6 +3065,7 @@ def get_response_error(response): result["Error Message"] = response.content return result + def get_path_attr(path_or_file): """Return project name and component folder attribute @@ -3046,18 +3092,29 @@ def get_path_attr(path_or_file): return project_name, metadata_folder + def get_file_attributes(file_name): + """ + get file attribute from the file_name (file path) + @param file_name: file path, usually from view.file_name() + @return: dict with following attributes: + name(file name without extension), + extension, + full name (name with extension), + metadata folder(metadata type folder, like aura/class/lwc/pages/triggers), + folder (Lightning bundle folder, usually is the Lightning Aura/Web Component name) + """ attributes = {} base, fullName = os.path.split(file_name) if "." in fullName: name = fullName[:fullName.rfind(".")] - extension = fullName[fullName.rfind(".")+1:] + extension = fullName[fullName.rfind(".") + 1:] else: name, extension = fullName, "" attributes["fullName"] = fullName attributes["name"] = name attributes["extension"] = extension - + base, folder = os.path.split(base) base, metafolder_or_src = os.path.split(base) @@ -3073,6 +3130,7 @@ def get_file_attributes(file_name): return attributes + def get_metadata_folder(file_name): """ Get the metadata_folder by file_name @@ -3088,6 +3146,7 @@ def get_metadata_folder(file_name): attributes = get_file_attributes(file_name) return attributes["metadata_folder"] + def load_metadata_cache(reload_cache=False, username=None): """ Reload component cache in globals() """ @@ -3099,6 +3158,7 @@ def load_metadata_cache(reload_cache=False, username=None): return globals()["components"] + def get_component_attribute(file_name, switch=True, reload_cache=False): """ get the component name by file_name, and then get the component_url and component_id @@ -3133,7 +3193,7 @@ def get_component_attribute(file_name, switch=True, reload_cache=False): # Check whether project of current file is active project default_project_name = settings["default_project_name"] - if switch and default_project_name.lower() not in file_name.lower(): + if switch and default_project_name.lower() not in file_name.lower(): return None, None xml_name = settings[metadata_folder]["xmlName"] @@ -3147,6 +3207,60 @@ def get_component_attribute(file_name, switch=True, reload_cache=False): # Return tuple return (component_attribute, name) + +def delete_component_attribute(dirs_or_files, switch=True): + """ + Delete component metadata cache for given files or directory(Lightning bundle) + @param dirs_or_files: lightning direcotry(bundle) or files + @param switch: + @return: + """ + + def remove_component_cache(file_path): + file_attr = get_file_attributes(file_path) + metadata_folder = file_attr["metadata_folder"] + full_name = file_attr["fullName"] + folder = file_attr.get("folder", None) + + xml_name = settings[metadata_folder]["xmlName"] + if xml_name in components_dict: + components_dict[xml_name].pop(full_name.lower(), None) + # Following code will be useful for future component attribute structure + if folder: + components_dict[xml_name].pop(folder.lower() + full_name.lower(), None) + + settings = context.get_settings() + username = settings["username"] + s = sublime.load_settings(context.COMPONENT_METADATA_SETTINGS) + if not s.has(username): + return + components_dict = s.get(username, {}) + + # Check whether project of current file is active project + for _path in dirs_or_files: + default_project_name = settings["default_project_name"] + if switch and default_project_name.lower() not in _path.lower(): + print('not all current project') + return + + # loop through the files and delete component cache + for _path in dirs_or_files: + # delete the component metadata for the file + if os.path.isfile(_path): + remove_component_cache(_path) + else: + files = [f for f in os.listdir(_path) if os.path.isfile(os.path.join(_path, f))] + for _file in files: + remove_component_cache(os.path.join(_path, _file)) + + # Update component metadata + s.set(username, components_dict) + sublime.save_settings(context.COMPONENT_METADATA_SETTINGS) + + # Reload component metadata cache in globals() + sublime.set_timeout(lambda: load_metadata_cache(True, settings["username"]), 5) + + def check_enabled(file_name, check_cache=True): """ Check whether file is ApexTrigger, ApexComponent, ApexPage or ApexClass @@ -3168,7 +3282,7 @@ def check_enabled(file_name, check_cache=True): # Check whether current file is subscribed component attributes = get_file_attributes(file_name) metadata_folder = attributes["metadata_folder"] - if metadata_folder not in settings["all_metadata_folders"]: + if metadata_folder not in settings["all_metadata_folders"]: sublime.status_message("Not valid SFDC component") return False @@ -3181,24 +3295,26 @@ def check_enabled(file_name, check_cache=True): # Check whether active component is in active project if check_cache: component_attribute, component_name = get_component_attribute(file_name) - if not component_attribute: + if not component_attribute: sublime.status_message("Not found the attribute of this component") return False - + return True + def display_active_project(view): """ Display the default project name in the sidebar """ settings = context.get_settings() - if not settings: return # Fix plugin loading issue + if not settings: return # Fix plugin loading issue display_message = "Default Project => %s (v%s.0)" % ( settings["default_project_name"], settings["api_version"] ) view.set_status('default_project', display_message) + def switch_project(target): """ Set the default project to the chosen one """ @@ -3236,10 +3352,11 @@ def switch_project(target): # Reload cache for completions from . import completions - sublime.set_timeout(lambda:completions.load_sobject_cache(True), 50) + sublime.set_timeout(lambda: completions.load_sobject_cache(True), 50) # Reload cache for component metadata - sublime.set_timeout(lambda:load_metadata_cache(True), 50) + sublime.set_timeout(lambda: load_metadata_cache(True), 50) + def add_project_to_workspace(settings): """Add new project folder to workspace @@ -3261,7 +3378,7 @@ def add_project_to_workspace(settings): if not os.path.exists(workspace): os.makedirs(workspace) project_file_path = os.path.join(workspace, "%s.sublime-project" % dpn) with open(project_file_path, "wb") as fp: - fp.write(json.dumps({"folders":[switch_to_folder]}, indent=4).encode("utf-8")) + fp.write(json.dumps({"folders": [switch_to_folder]}, indent=4).encode("utf-8")) project_data = sublime.active_window().project_data() if not project_data: project_data = {} @@ -3273,9 +3390,9 @@ def add_project_to_workspace(settings): folder_path = folder["path"] # Parse windows path to AS-UNIX - if "\\" in folder_path: + if "\\" in folder_path: folder_path = folder_path.replace("\\", "/") - if "\\" in workspace: + if "\\" in workspace: workspace = workspace.replace("\\", "/") if folder_path == workspace: @@ -3339,6 +3456,7 @@ def get_completion_list(meta_type, meta_folder): return completion_list + def get_metadata_elements(metadata_dir, suffix=None): """ Get the name list by specified metadataObject @@ -3364,11 +3482,12 @@ def get_metadata_elements(metadata_dir, suffix=None): return elements + def export_role_hierarchy(records): settings = context.get_settings() - top_roles = [] # Role hierarchy - rolemap = {} # Define roleId => role + top_roles = [] # Role hierarchy + rolemap = {} # Define roleId => role for r in records: # Build map rolemap[r["Id"]] = r @@ -3378,28 +3497,29 @@ def export_role_hierarchy(records): # Start to write role name to csv rows = [] - for role in sorted(top_roles, key=lambda k : k['Name']): + for role in sorted(top_roles, key=lambda k: k['Name']): rows.append(role["Name"]) - append_child_roles(rolemap, role["Id"], rows, 1, - settings["include_users_in_role_hierarchy"]) + append_child_roles(rolemap, role["Id"], rows, 1, + settings["include_users_in_role_hierarchy"]) - outputdir = settings["workspace"]+ "/.export/Role" + outputdir = settings["workspace"] + "/.export/Role" if not os.path.exists(outputdir): os.makedirs(outputdir) - outputfile = outputdir+"/hierarchy.csv" + outputfile = outputdir + "/hierarchy.csv" with open(outputfile, "wb") as fp: fp.write("\n".join(rows).encode("utf-8")) return outputfile + def append_child_roles(rolemap, role_id, rows, level, include_users): child_roles = [] for role in rolemap.values(): if role["ParentRoleId"] == role_id: child_roles.append(role) - for role in sorted(child_roles, key=lambda k : k['Name']): + for role in sorted(child_roles, key=lambda k: k['Name']): row = level * "," + role["Name"] # If include_users is true, Include active user list after role name @@ -3422,6 +3542,7 @@ def append_child_roles(rolemap, role_id, rows, level, include_users): append_child_roles(rolemap, role["Id"], rows, level + 1, include_users) + def export_profile_settings(): settings = context.get_settings() @@ -3443,9 +3564,9 @@ def export_profile_settings(): # Escape profile name, for example, # "Custom%3A Sales Profile" changed to "Custom: Sales Profile" unquoted_profile = urllib.parse.unquote(unescape(profile, {"'": "'", """: '"'})) - Printer.get("log").write("Parsing the profile security settings of "+unquoted_profile) + Printer.get("log").write("Parsing the profile security settings of " + unquoted_profile) - profile_file = os.path.join(profile_dir, profile+".profile") + profile_file = os.path.join(profile_dir, profile + ".profile") result = xmltodict.parse(open(profile_file, "rb").read()) result = result["Profile"] @@ -3458,7 +3579,7 @@ def export_profile_settings(): object_permissions = result["objectPermissions"] # Some profiles just only have one objectPermissions - if isinstance(result["objectPermissions"], dict): + if isinstance(result["objectPermissions"], dict): object_permissions = [object_permissions] for op in object_permissions: @@ -3525,23 +3646,23 @@ def export_profile_settings(): # Get the unescaped profiles profiles = sorted(list(profile_settings.keys())) - + ######################################### # 1. Export objectPermissions ######################################### # Define object CRUD cruds = [ - "allowRead", "allowCreate", "allowEdit", - "allowDelete", "modifyAllRecords", + "allowRead", "allowCreate", "allowEdit", + "allowDelete", "modifyAllRecords", "viewAllRecords" ] crud_literal = { - "allowCreate": "C", - "allowRead": "R", - "allowEdit": "U", - "allowDelete": "D", - "modifyAllRecords": "M", + "allowCreate": "C", + "allowRead": "R", + "allowEdit": "U", + "allowDelete": "D", + "modifyAllRecords": "M", "viewAllRecords": "V" } @@ -3615,12 +3736,12 @@ def export_profile_settings(): all_rows.append(",".join(rows)) - outputdir = settings["workspace"]+ "/.export/profile" + outputdir = settings["workspace"] + "/.export/profile" if not os.path.exists(outputdir): os.makedirs(outputdir) - Printer.get("log").write("Writing profile object security to "+outputdir) - with open(outputdir+"/ObjectPermissions.csv", "wb") as fp: + Printer.get("log").write("Writing profile object security to " + outputdir) + with open(outputdir + "/ObjectPermissions.csv", "wb") as fp: fp.write("\n".join(all_rows).encode("utf-8")) ######################################### @@ -3646,8 +3767,8 @@ def export_profile_settings(): all_rows.append(",".join(rows)) - Printer.get("log").write("Writing profile tab visibility to "+outputdir) - with open(outputdir+"/TabVisibilities.csv", "wb") as fp: + Printer.get("log").write("Writing profile tab visibility to " + outputdir) + with open(outputdir + "/TabVisibilities.csv", "wb") as fp: fp.write("\n".join(all_rows).encode("utf-8")) ######################################### @@ -3674,8 +3795,8 @@ def export_profile_settings(): all_rows.append(",".join(rows)) - Printer.get("log").write("Writing profile user permission to "+outputdir) - with open(outputdir+"/UserPermissions.csv", "wb") as fp: + Printer.get("log").write("Writing profile user permission to " + outputdir) + with open(outputdir + "/UserPermissions.csv", "wb") as fp: fp.write("\n".join(all_rows).encode("utf-8")) ######################################### @@ -3716,14 +3837,15 @@ def export_profile_settings(): # Every field is separated line all_rows.append(",".join(rows)) - outputdir = settings["workspace"]+ "/.export/profile" + outputdir = settings["workspace"] + "/.export/profile" if not os.path.exists(outputdir): os.makedirs(outputdir) - Printer.get("log").write("Writing profile object security to "+outputdir) - with open(outputdir+"/FieldLevelSecurity.csv", "wb") as fp: + Printer.get("log").write("Writing profile object security to " + outputdir) + with open(outputdir + "/FieldLevelSecurity.csv", "wb") as fp: fp.write("\n".join(all_rows).encode("utf-8")) + def build_metadata(csvfile, options): """ Convert JSON to custom labels metadata """ rjson = convert_csv_to_json(csvfile, options.get("xmlNodes")) @@ -3736,11 +3858,12 @@ def build_metadata(csvfile, options): return xmltodict.unparse(custom_labels_json) + def convert_csv_to_json(csvfile, xmlNodes): """ Convert CSV to JSON format""" - fp = open(csvfile, "rt", encoding="utf8"); # Open CSV file - next(fp) # Ignore header + fp = open(csvfile, "rt", encoding="utf8"); # Open CSV file + next(fp) # Ignore header csv_reader = csv.DictReader(fp, xmlNodes) tempjson = os.path.join(os.path.split(csvfile)[0], "temp.json") From 6384ac387eb339208c1539b8b39fb92f06bf9d38 Mon Sep 17 00:00:00 2001 From: Lushang Date: Thu, 2 Apr 2020 18:12:12 +0800 Subject: [PATCH 43/46] Miscellaneous refinement and bug fix --- aura.py | 17 +-- lwc.py | 3 +- main.py | 430 +++++++++++++++++++++++++++++++++----------------------- 3 files changed, 265 insertions(+), 185 deletions(-) diff --git a/aura.py b/aura.py index f2e8a65..13aed3e 100644 --- a/aura.py +++ b/aura.py @@ -196,12 +196,13 @@ def __init__(self, *args, **kwargs): super(DestructLightningFromServer, self).__init__(*args, **kwargs) def run(self, dirs): - if sublime.ok_cancel_dialog("This will Delete the whole folder both from the server and local!" + - " Confirm to continue?"): + _, bundle_name = os.path.split(dirs[0]) + if sublime.ok_cancel_dialog("This will Delete %s !" % bundle_name + " Confirm to continue?"): processor.handle_destructive_files(dirs, ignore_folder=False) def is_visible(self, dirs): - if len(dirs) == 0: return False + if len(dirs) == 0: + return False self.settings = context.get_settings() for _dir in dirs: attributes = util.get_file_attributes(_dir) @@ -226,7 +227,7 @@ def run(self, dirs, element=""): template = templates.get("AuraElement").get(element) settings = context.get_settings() templates_path = os.path.join(settings["workspace"], - ".templates", template["directory"]) + ".templates", template["directory"]) with open(templates_path) as fp: body = fp.read() @@ -297,7 +298,7 @@ def __init__(self, *args, **kwargs): def run(self, _type=""): self._type = _type self.window.show_input_panel("Please Input %s Name: " % _type, - "", self.on_input, None, None) + "", self.on_input, None, None) def on_input(self, lightning_name): # Create component to local according to user input @@ -305,7 +306,7 @@ def on_input(self, lightning_name): message = 'Invalid format, do you want to try again?' if not sublime.ok_cancel_dialog(message): return self.window.show_input_panel("Please Input %s Name: " % self._type, - "", self.on_input, None, None) + "", self.on_input, None, None) return # Get settings @@ -326,10 +327,10 @@ def on_input(self, lightning_name): message = "%s is already exist, do you want to try again?" % lightning_name if not sublime.ok_cancel_dialog(message, "Try Again?"): return self.window.show_input_panel("Please Input Lightning Name: ", - "", self.on_input, None, None) + "", self.on_input, None, None) return - lightning_file = os.path.join(component_dir, lightning_name+template["extension"]) + lightning_file = os.path.join(component_dir, lightning_name + template["extension"]) # Create Aura lightning file with open(lightning_file, "w") as fp: diff --git a/lwc.py b/lwc.py index 0d8e0a9..fce5131 100644 --- a/lwc.py +++ b/lwc.py @@ -158,7 +158,8 @@ def create_resource(self, js_file_name=None): ".templates", template["directory"]) extension = template["extension"] - element_name = (self.lwc_name if js_file_name is None else self.lwc_name + js_file_name) + extension + element_name = self.lwc_name if js_file_name is None else js_file_name + element_name += extension # Combine lwc element component name element_file = os.path.join(self._dir, element_name) diff --git a/main.py b/main.py index 800a6fc..af14e64 100644 --- a/main.py +++ b/main.py @@ -18,7 +18,6 @@ from . import context from . import util - from .salesforce.lib import xmlformatter from .salesforce.lib.jsontoapex import JSONConverter from .salesforce.lib.panel import Printer @@ -66,8 +65,8 @@ def is_enabled(self): self.choose_all = False if not self.selection: self.choose_all = True - self.selection = self.view.substr(sublime.Region(0, - self.view.size())) + self.selection = self.view.substr(sublime.Region(0, + self.view.size())) return True @@ -90,7 +89,7 @@ def run(self, edit): lables_metadata = formatter.format_string(lables_metadata) except ValueError as ve: return Printer.get('error').write(str(ve)) - + view = sublime.active_window().new_file() view.set_syntax_file("Packages/XML/XML.tmLanguage") view.run_command("new_view", { @@ -114,7 +113,7 @@ def run(self, edit): except ValueError as ve: raise ve return Printer.get('error').write(str(ve)) - + view = sublime.active_window().new_file() view.set_syntax_file("Packages/XML/XML.tmLanguage") view.run_command("new_view", { @@ -126,11 +125,11 @@ def run(self, edit): class JsonFormat(BaseSelection, sublime_plugin.TextCommand): def run(self, edit): try: - formatted_json = json.dumps(json.loads(self.selection), - ensure_ascii=False, indent=4) + formatted_json = json.dumps(json.loads(self.selection), + ensure_ascii=False, indent=4) except ValueError as ve: return Printer.get('error').write(str(ve)) - + if not self.choose_all: view = sublime.active_window().new_file() view.run_command("new_view", { @@ -177,9 +176,9 @@ def run(self, edit): except ValueError as ve: return Printer.get('error').write(str(ve)) - sublime.active_window().show_input_panel("Input Class Name: ", - "JSON2Apex", self.on_input_name, None, None) - + sublime.active_window().show_input_panel("Input Class Name: ", + "JSON2Apex", self.on_input_name, None, None) + def on_input_name(self, name): if not name: name = "JSON2Apex" @@ -278,18 +277,18 @@ class DiffWithServer(sublime_plugin.TextCommand): def run(self, edit, switch=True, source_org=None): if not source_org: source_org = self.settings["default_project_name"] - + if switch: return self.view.window().run_command("switch_project", { "callback_options": { - "callback_command": "diff_with_server", + "callback_command": "diff_with_server", "args": { "switch": False, "source_org": source_org } } }) - + file_name = self.view.file_name() attr = util.get_component_attribute(file_name, False, reload_cache=True)[0] @@ -302,7 +301,7 @@ def run(self, edit, switch=True, source_org=None): def is_enabled(self): self.file_name = self.view.file_name() - if not self.file_name: + if not self.file_name: return False self.settings = context.get_settings() @@ -394,8 +393,8 @@ def run(self, callback_options={}): # Add subscribed ones and unsubscribed ones to list self.items.extend(sorted(subscribed_items)) self.items.extend(sorted(unsubscripted_items)) - self.window.show_quick_panel(self.items, self.on_done, - sublime.MONOSPACE_FONT) + self.window.show_quick_panel(self.items, self.on_done, + sublime.MONOSPACE_FONT) def on_done(self, index): if index == -1: @@ -437,7 +436,7 @@ def on_done(self, index): s.set("projects", projects) sublime.save_settings(context.TOOLING_API_SETTINGS) - sublime.set_timeout(lambda:sublime.active_window().run_command("toggle_metadata_objects", { + sublime.set_timeout(lambda: sublime.active_window().run_command("toggle_metadata_objects", { "callback_options": self.callback_options }), 10) @@ -472,7 +471,7 @@ def run(self): if not sublime.ok_cancel_dialog(message, "Confirm Clear?"): return settings = context.get_settings() - session_path = settings["workspace"]+"/.config/session.json" + session_path = settings["workspace"] + "/.config/session.json" try: os.remove(session_path) sublime.status_message("Session cache is cleared") @@ -486,7 +485,7 @@ def __init__(self, *args, **kwargs): def run(self, cache_name): self.cache_name = cache_name - self.cache_settings = self.cache_name+".sublime-settings" + self.cache_settings = self.cache_name + ".sublime-settings" self.caches = util.get_sobject_caches(self.cache_settings) if not self.caches: Printer.get('error').write("No cache already") @@ -500,7 +499,7 @@ def on_done(self, index): if not sublime.ok_cancel_dialog(message, "Confirm Clear"): return util.clear_cache(self.caches[index][1], self.cache_settings) - sublime.set_timeout(lambda:sublime.active_window().run_command("clear_cache", { + sublime.set_timeout(lambda: sublime.active_window().run_command("clear_cache", { "cache_name": self.cache_name }), 10) @@ -510,8 +509,8 @@ def __init__(self, *args, **kwargs): super(Convert15Id218Id, self).__init__(*args, **kwargs) def run(self): - self.window.show_input_panel("Input 15 Id: ", - "", self.on_input, None, None) + self.window.show_input_panel("Input 15 Id: ", + "", self.on_input, None, None) def on_input(self, input): c18Id = util.convert_15_to_18(input) @@ -523,8 +522,8 @@ def __init__(self, *args, **kwargs): super(DecodeUrl, self).__init__(*args, **kwargs) def run(self): - self.window.show_input_panel("Input your URL to be decoded: ", - "", self.on_input, None, None) + self.window.show_input_panel("Input your URL to be decoded: ", + "", self.on_input, None, None) def on_input(self, input): decodedUrl = urllib.request.unquote(input) @@ -536,8 +535,8 @@ def __init__(self, *args, **kwargs): super(EncodeUrl, self).__init__(*args, **kwargs) def run(self): - self.window.show_input_panel("Input your URL to be encoded: ", - "", self.on_input, None, None) + self.window.show_input_panel("Input your URL to be encoded: ", + "", self.on_input, None, None) def on_input(self, input): encodedUrl = urllib.request.quote(input) @@ -559,32 +558,33 @@ def on_done(self, index): self.filters = ["all", "updateable", "createable", "custom"] self.display_filters = [a.capitalize() for a in self.filters] - sublime.set_timeout(lambda:self.window.show_quick_panel(self.display_filters, self.on_choose_action), 10) + sublime.set_timeout(lambda: self.window.show_quick_panel(self.display_filters, self.on_choose_action), 10) def on_choose_action(self, index): if index == -1: return processor.handle_generate_sobject_soql(self.sobject, self.filters[index]) + class ExportQueryToCsv(sublime_plugin.WindowCommand): def __init__(self, *args, **kwargs): super(ExportQueryToCsv, self).__init__(*args, **kwargs) def run(self, tooling=False): self.tooling = tooling - sublime.active_window().show_input_panel('Input Your %s SOQL:' % - ('Tooling' if tooling else ''), "", self.on_input_soql, None, None) + sublime.active_window().show_input_panel('Input Your %s SOQL:' % + ('Tooling' if tooling else ''), "", self.on_input_soql, None, None) def on_input_soql(self, soql): self.soql = soql.strip() # Check whether the soql is valid and not parent-to-child query - match = re.match("[\\n\\s]*SELECT\\s+[*\\w\\n,.:_\\s()]+?\\s+FROM\\s+[1-9_a-zA-Z]+", - self.soql, re.IGNORECASE) + match = re.match("[\\n\\s]*SELECT\\s+[*\\w\\n,.:_\\s()]+?\\s+FROM\\s+[1-9_a-zA-Z]+", + self.soql, re.IGNORECASE) if not match: Printer.get("error").write("Your input SOQL is not valid") if sublime.ok_cancel_dialog("Want to try again?"): - self.window.show_input_panel('Input Your SOQL:', - "", self.on_input_soql, None, None) + self.window.show_input_panel('Input Your SOQL:', + "", self.on_input_soql, None, None) return # This feature does not support parent to child query @@ -592,16 +592,16 @@ def on_input_soql(self, soql): if len(matchs) > 1: Printer.get("error").write("This feature does not support parent-to-child query") if sublime.ok_cancel_dialog("Want to try again?"): - self.window.show_input_panel('Input Your SOQL:', - "", self.on_input_soql, None, None) + self.window.show_input_panel('Input Your SOQL:', + "", self.on_input_soql, None, None) return # Parse the sObject Name for CSV name matchstr = match.group(0) - self.sobject = matchstr[matchstr.rfind(" ")+1:] + self.sobject = matchstr[matchstr.rfind(" ") + 1:] - sublime.active_window().show_input_panel('Input CSV Name:', - self.sobject, self.on_input_name, None, None) + sublime.active_window().show_input_panel('Input CSV Name:', + self.sobject, self.on_input_name, None, None) def on_input_name(self, name): if not name: return @@ -615,7 +615,7 @@ def __init__(self, *args, **kwargs): def run(self, vertical=True): self.vertical = vertical self.sobject_recordtypes_attr = processor.populate_sobject_recordtypes() - if not self.sobject_recordtypes_attr: return # Network Issue Cause + if not self.sobject_recordtypes_attr: return # Network Issue Cause self.sobject_recordtypes = sorted(list(self.sobject_recordtypes_attr.keys())) self.window.show_quick_panel(self.sobject_recordtypes, self.on_choose_recordtype) @@ -629,8 +629,8 @@ def on_choose_recordtype(self, index): recordtype_id = self.sobject_recordtypes_attr[sobject_recordtype] # handle this describe request - processor.handle_export_data_template_thread(sobject, - recordtype_name, recordtype_id, self.vertical) + processor.handle_export_data_template_thread(sobject, + recordtype_name, recordtype_id, self.vertical) def is_enabled(self): return util.check_action_enabled() @@ -639,7 +639,7 @@ def is_enabled(self): class ExecuteRestTest(sublime_plugin.TextCommand): def run(self, edit): self.items = ["Get", "Post", "Put", "Patch", "Delete", "Tooling Query", - "Query", "Query All", "Search", "Quick Search", + "Query", "Query All", "Search", "Quick Search", "Head", "Retrieve Body"] self.view.show_popup_menu(self.items, self.on_choose_action), @@ -657,8 +657,8 @@ def on_input(self, data): except ValueError as ve: Printer.get('error').write(str(ve)) if not sublime.ok_cancel_dialog("Do you want to try again?", "Yes?"): return - self.view.window().show_input_panel("Input JSON Body: ", - "", self.on_input, None, None) + self.view.window().show_input_panel("Input JSON Body: ", + "", self.on_input, None, None) return processor.handle_execute_rest_test(self.chosen_action, self.sel, data) @@ -679,13 +679,13 @@ def run(self, edit, is_background=False, allowed_folders=None): sel_text = self.view.substr(self.view.word(sel.begin())) settings = context.get_settings() for ct in settings["subscribed_metadata_objects"]: - if "suffix" not in settings[ct]: + if "suffix" not in settings[ct]: continue suffix = settings[ct]["suffix"] folder = settings[ct]["directoryName"] target_file = os.path.join(settings["workspace"] + \ - "/src/%s/%s.%s" % (folder, sel_text, suffix) - ) + "/src/%s/%s.%s" % (folder, sel_text, suffix) + ) if os.path.isfile(target_file): if allowed_folders: if folder in allowed_folders: @@ -702,7 +702,7 @@ class SetCheckPointCommand(sublime_plugin.TextCommand): def run(self, edit, mark): sel = [s for s in self.view.sel()] self.view.add_regions(mark, sel, "invalid", "dot", - sublime.DRAW_SOLID_UNDERLINE | sublime.DRAW_EMPTY_AS_OVERWRITE) + sublime.DRAW_SOLID_UNDERLINE | sublime.DRAW_EMPTY_AS_OVERWRITE) class RemoveCheckPointCommand(sublime_plugin.TextCommand): @@ -716,7 +716,7 @@ def run(self, edit): def is_enabled(self): # Must Be File - if not self.view.file_name(): + if not self.view.file_name(): return False self.file_name = self.view.file_name() @@ -726,16 +726,16 @@ def is_enabled(self): # Must be class or trigger self.attributes = util.get_file_attributes(self.file_name) - if not self.attributes["extension"]: + if not self.attributes["extension"]: return False - if self.attributes["metadata_folder"] not in ["classes", "triggers"]: + if self.attributes["metadata_folder"] not in ["classes", "triggers"]: return False # Can't be Test Class with open(self.file_name, encoding="utf-8") as fp: self.body = fp.read() - if "@istest" in self.body.lower(): + if "@istest" in self.body.lower(): return False return True @@ -774,6 +774,7 @@ def run(self, edit): # Move focus to the coverage view sublime.active_window().focus_view(coverage_view) + class NewViewCommand(sublime_plugin.TextCommand): """ Create a new view with specified input @@ -793,6 +794,7 @@ def run(self, edit, point=0, name="", input=""): view.set_name(name) view.insert(edit, point, input) + class NewDynamicViewCommand(sublime_plugin.TextCommand): """ Create a new view with specified input @@ -812,7 +814,7 @@ def run(self, edit, view_id=None, view_name="", input="", point=0, erase_all=Fal view = sublime.active_window().active_view() if view_id and not view.id() == view_id: for v in sublime.active_window().views(): - if v.id() == view_id: + if v.id() == view_id: view = v view.set_scratch(True) @@ -820,6 +822,7 @@ def run(self, edit, view_id=None, view_name="", input="", point=0, erase_all=Fal if erase_all: view.erase(edit, sublime.Region(0, view.size())) view.insert(edit, point, input) + class RefreshFolder(sublime_plugin.WindowCommand): def __init__(self, *args, **kwargs): super(RefreshFolder, self).__init__(*args, **kwargs) @@ -836,6 +839,7 @@ def is_visible(self, dirs): return True + class RetrieveMetadataCommand(sublime_plugin.WindowCommand): def __init__(self, *args, **kwargs): super(RetrieveMetadataCommand, self).__init__(*args, **kwargs) @@ -856,10 +860,11 @@ def run(self, retrieve_all=True): processor.handle_refresh_folder(types, not retrieve_all) + class RenameMetadata(sublime_plugin.TextCommand): def run(self, edit): - self.view.window().show_input_panel("Input New Name", - self.filename, self.on_input, None, None) + self.view.window().show_input_panel("Input New Name", + self.filename, self.on_input, None, None) def on_input(self, new_name): if not new_name or not re.match("\w+[a-zA-Z0-9]+", new_name): @@ -874,8 +879,8 @@ def is_enabled(self): self.file_name = self.view.file_name() base, filename = os.path.split(self.file_name) base, folder = os.path.split(base) - if folder not in self.settings["all_metadata_folders"]:return False - if not util.check_enabled(self.view.file_name(), check_cache=False): + if folder not in self.settings["all_metadata_folders"]: return False + if not util.check_enabled(self.view.file_name(), check_cache=False): return False self.filename = filename.split(".")[0] @@ -886,12 +891,13 @@ def is_enabled(self): class RetrieveFileFromServer(sublime_plugin.TextCommand): """ - Retrieve Single File From Salesforce + Retrieve Single File From Salesforce via Metadata API """ + def run(self, edit, switch=True): files = [self.view.file_name()] sublime.active_window().run_command("retrieve_files_from_server", { - "files": files, + "files": files, "switch": switch }) @@ -901,7 +907,7 @@ def is_enabled(self): attributes = util.get_file_attributes(self.view.file_name()) metadata_folder = attributes["metadata_folder"] if metadata_folder not in self.settings["all_metadata_folders"]: return False - if not util.check_enabled(self.view.file_name(), check_cache=False): + if not util.check_enabled(self.view.file_name(), check_cache=False): return False return True @@ -912,8 +918,9 @@ def is_visible(self): class RetrieveFilesFromServer(sublime_plugin.WindowCommand): """ - Retrieve List of files from Salesforce + Retrieve List of files from Salesforce via Metadata API """ + def __init__(self, *args, **kwargs): super(RetrieveFilesFromServer, self).__init__(*args, **kwargs) @@ -933,7 +940,7 @@ def run(self, files, switch=True, source_org=None, confirmed=False, extract_to=N if switch: return self.window.run_command("switch_project", { "callback_options": { - "callback_command": "retrieve_files_from_server", + "callback_command": "retrieve_files_from_server", "args": { "files": files, "switch": False, @@ -978,7 +985,7 @@ def is_visible(self, files): continue # Ignore folder metadata_folder = util.get_metadata_folder(_file) if metadata_folder not in settings["all_metadata_folders"]: return False - if not util.check_enabled(_file, check_cache=False): + if not util.check_enabled(_file, check_cache=False): return False return True @@ -997,6 +1004,10 @@ def is_enabled(self): class DestructFileFromServer(sublime_plugin.TextCommand): + """ + Destruct the selected code from Salesforce and delete from local folder + """ + def run(self, edit): files = [self.view.file_name()] sublime.active_window().run_command("destruct_files_from_server", { @@ -1007,8 +1018,8 @@ def is_enabled(self): if not self.view or not self.view.file_name(): return False self.settings = context.get_settings() metadata_folder = util.get_metadata_folder(self.view.file_name()) - if metadata_folder not in self.settings["all_metadata_folders"]:return False - if not util.check_enabled(self.view.file_name(), check_cache=False): + if metadata_folder not in self.settings["all_metadata_folders"]: return False + if not util.check_enabled(self.view.file_name(), check_cache=False): return False return True @@ -1016,29 +1027,36 @@ def is_enabled(self): def is_visible(self): return self.is_enabled() + class DestructFilesFromServer(sublime_plugin.WindowCommand): + """ + Destruct the selected code files from Salesforce and delete from local folder via Metadata API + """ + def __init__(self, *args, **kwargs): super(DestructFilesFromServer, self).__init__(*args, **kwargs) def run(self, files): - message = "Confirm destructing %s from server?" % ( + _message = "Confirm destructing %s from server?" % ( "these files" if len(files) > 1 else "this file" ) - if sublime.ok_cancel_dialog(message, "Confirm"): + if sublime.ok_cancel_dialog(_message, "Confirm"): processor.handle_destructive_files(files) def is_visible(self, files): if len(files) == 0: return False self.settings = context.get_settings() for _file in files: - if not os.path.isfile(_file): continue # Ignore folder + if not os.path.isfile(_file): + continue # Ignore folder _folder = util.get_metadata_folder(_file) if _folder not in self.settings["all_metadata_folders"]: return False - if not util.check_enabled(_file, check_cache=False): + if not util.check_enabled(_file, check_cache=False): return False return True + class DeployZip(sublime_plugin.WindowCommand): def __init__(self, *args, **kwargs): super(DeployZip, self).__init__(*args, **kwargs) @@ -1053,8 +1071,8 @@ def run(self, zipfile_path=None, chosen_classes=[]): path = sublime.get_clipboard() if not path or not os.path.isfile(path): path = "" if not path.endswith("zip"): path = "" - self.window.show_input_panel("Input Zip File Path:", - path, self.on_input, None, None) + self.window.show_input_panel("Input Zip File Path:", + path, self.on_input, None, None) def on_input(self, zipfile_path): if not zipfile_path.endswith('.zip'): @@ -1067,11 +1085,11 @@ def on_input(self, zipfile_path): def execute_deploy(self): settings = context.get_settings() deploy_options = settings["deploy_options"] - testLevel = deploy_options.get("testLevel", "NoTestRun") + testLevel = deploy_options.get("testLevel", "NoTestRun") if testLevel == "RunSpecifiedTests" and not self.chosen_classes: return self.window.run_command("choose_test_classes", { "callback_options": { - "callback_command": "deploy_zip", + "callback_command": "deploy_zip", "args": { "zipfile_path": self.zipfile_path, "chosen_classes": self.chosen_classes @@ -1079,9 +1097,9 @@ def execute_deploy(self): } }) + processor.handle_deploy_thread(util.base64_encode(self.zipfile_path), + chosen_classes=self.chosen_classes) - processor.handle_deploy_thread(util.base64_encode(self.zipfile_path), - chosen_classes=self.chosen_classes) class DeployOpenFilesToServer(sublime_plugin.WindowCommand): def __init__(self, *args, **kwargs): @@ -1090,9 +1108,9 @@ def __init__(self, *args, **kwargs): def run(self, select_all=True): # If deploy all open files if select_all: - return sublime.active_window().run_command("deploy_files_to_server", - {"files": list(self.file_attributes.values())}) - + return sublime.active_window().run_command("deploy_files_to_server", + {"files": list(self.file_attributes.values())}) + # If just deploy some files if not hasattr(self, "chosen_files"): self.chosen_files = [] @@ -1116,9 +1134,9 @@ def on_choose(self, index): chosen_files.append(self.file_attributes[item[4:]]) if chosen_files: - sublime.active_window().run_command("deploy_files_to_server", - {"files": chosen_files} - ) + sublime.active_window().run_command("deploy_files_to_server", + {"files": chosen_files} + ) return # Get chosen file name @@ -1133,8 +1151,8 @@ def on_choose(self, index): # Start next round self.populate_items() - sublime.set_timeout(lambda:self.window.show_quick_panel(self.items, - self.on_choose, sublime.MONOSPACE_FONT), 10) + sublime.set_timeout(lambda: self.window.show_quick_panel(self.items, + self.on_choose, sublime.MONOSPACE_FONT), 10) def is_enabled(self): """ @@ -1151,7 +1169,7 @@ def is_enabled(self): for _view in views: _file = _view.file_name() # Ignore folder - if not _file or not os.path.isfile(_file): + if not _file or not os.path.isfile(_file): continue attributes = util.get_file_attributes(_file) # Ignore non-sfdc files @@ -1161,11 +1179,12 @@ def is_enabled(self): self.file_attributes[attributes["fullName"]] = _file # If there is no sfdc code file, just disable this command - if not self.file_attributes: + if not self.file_attributes: return False return True + class DeployFileToServer(sublime_plugin.TextCommand): def run(self, edit, switch=True): files = [self.view.file_name()] @@ -1185,10 +1204,12 @@ def is_enabled(self): def is_visible(self): return self.is_enabled() + class DeployFileToThisServer(sublime_plugin.TextCommand): """ Deploy a opened file to current active Salesforce org """ + def run(self, edit): files = [self.view.file_name()] sublime.active_window().run_command("deploy_files_to_server", { @@ -1212,11 +1233,11 @@ def run(self, files, switch=True, source_org=None, chosen_classes=[]): source_org = settings["default_project_name"] deploy_options = settings["deploy_options"] - testLevel = deploy_options.get("testLevel", "NoTestRun") + testLevel = deploy_options.get("testLevel", "NoTestRun") if testLevel == "RunSpecifiedTests" and not chosen_classes: return self.window.run_command("choose_test_classes", { "callback_options": { - "callback_command": "deploy_files_to_server", + "callback_command": "deploy_files_to_server", "args": { "files": files, "switch": False, @@ -1228,7 +1249,7 @@ def run(self, files, switch=True, source_org=None, chosen_classes=[]): if switch: return self.window.run_command("switch_project", { "callback_options": { - "callback_command": "deploy_files_to_server", + "callback_command": "deploy_files_to_server", "args": { "files": files, "switch": False, @@ -1247,7 +1268,7 @@ def run(self, files, switch=True, source_org=None, chosen_classes=[]): # Keep the files to deploy base64_encoded_zip = util.build_deploy_package(files) processor.handle_deploy_thread( - base64_encoded_zip, + base64_encoded_zip, source_org=source_org, chosen_classes=chosen_classes ) @@ -1261,7 +1282,7 @@ def is_visible(self, files): if not files: return False self.settings = context.get_settings() for _file in files: - if not os.path.isfile(_file): continue # Ignore folder + if not os.path.isfile(_file): continue # Ignore folder attributes = util.get_file_attributes(_file) if attributes["metadata_folder"] not in self.settings["all_metadata_folders"]: return False @@ -1278,6 +1299,7 @@ def run(self, edit, switch=True, source_org=None): def is_enabled(self): return self.view.file_name() is not None + class CopyFilesToProject(sublime_plugin.WindowCommand): def __init__(self, *args, **kwargs): super(CopyFilesToProject, self).__init__(*args, **kwargs) @@ -1290,7 +1312,7 @@ def run(self, files, switch=True, source_org=None): if switch: return self.window.run_command("switch_project", { "callback_options": { - "callback_command": "copy_files_to_project", + "callback_command": "copy_files_to_project", "args": { "files": files, "switch": False, @@ -1314,8 +1336,8 @@ def is_enabled(self, files, **kwargs): self.settings = context.get_settings() self.attributes = [] for _file in files: - if not os.path.isfile(_file): continue # Ignore folder - if _file.endswith("-meta.xml"): continue # Ignore meta file + if not os.path.isfile(_file): continue # Ignore folder + if _file.endswith("-meta.xml"): continue # Ignore meta file attribute = util.get_file_attributes(_file) if attribute["metadata_folder"] not in self.settings["all_metadata_folders"]: continue @@ -1331,6 +1353,7 @@ def is_enabled(self, files, **kwargs): def is_visible(self, files, **kwargs): return self.is_enabled(files) + class ExportProfile(sublime_plugin.WindowCommand): def __init__(self, *args, **kwargs): super(ExportProfile, self).__init__(*args, **kwargs) @@ -1343,6 +1366,7 @@ def run(self): def is_enabled(self): return util.check_action_enabled() + class ExportValidationRulesCommand(sublime_plugin.WindowCommand): def __init__(self, *args, **kwargs): super(ExportValidationRulesCommand, self).__init__(*args, **kwargs) @@ -1359,6 +1383,7 @@ def run(self): def is_enabled(self): return util.check_action_enabled() + class ExportCustomLablesCommand(sublime_plugin.WindowCommand): def __init__(self, *args, **kwargs): super(ExportCustomLablesCommand, self).__init__(*args, **kwargs) @@ -1374,11 +1399,12 @@ def run(self): outputdir = settings["workspace"] + "/.export/labels" if not os.path.exists(outputdir): os.makedirs(outputdir) lables = xmltodict.parse(open(lable_path, "rb").read()) - util.list2csv(outputdir+"/Labels.csv", lables["CustomLabels"]["labels"]) + util.list2csv(outputdir + "/Labels.csv", lables["CustomLabels"]["labels"]) def is_enabled(self): return util.check_action_enabled() + class ExportWorkflowsCommand(sublime_plugin.WindowCommand): def __init__(self, *args, **kwargs): super(ExportWorkflowsCommand, self).__init__(*args, **kwargs) @@ -1396,26 +1422,29 @@ def run(self): def is_enabled(self): return util.check_action_enabled() + class ExportCustomFieldCommand(sublime_plugin.WindowCommand): def __init__(self, *args, **kwargs): super(ExportCustomFieldCommand, self).__init__(*args, **kwargs) def run(self): processor.handle_export_customfield() - + def is_enabled(self): return util.check_action_enabled() + class ExportRoleHierarchyCommand(sublime_plugin.WindowCommand): def __init__(self, *args, **kwargs): super(ExportRoleHierarchyCommand, self).__init__(*args, **kwargs) def run(self): processor.handle_export_role_hierarchy() - + def is_enabled(self): return util.check_action_enabled() + class DescribeSobjectCommand(sublime_plugin.WindowCommand): def __init__(self, *args, **kwargs): super(DescribeSobjectCommand, self).__init__(*args, **kwargs) @@ -1429,13 +1458,14 @@ def on_done(self, index): if index == -1: return processor.handle_describe_sobject(self.sobjects[index]) + class ExportWorkbookCommand(sublime_plugin.WindowCommand): def __init__(self, *args, **kwargs): super(ExportWorkbookCommand, self).__init__(*args, **kwargs) def run(self): - self.window.show_input_panel("Input Sobjects(* or sobjects separated with semi-colon), Case is Sensitive", - "*", self.on_input, None, None) + self.window.show_input_panel("Input Sobjects(* or sobjects separated with semi-colon), Case is Sensitive", + "*", self.on_input, None, None) def on_input(self, input): # Display the fields in a new view @@ -1455,8 +1485,8 @@ def on_input(self, input): if sobject not in sobjects_describe: message = '"%s" is not valid sobject, do you want to try again?' % sobject if not sublime.ok_cancel_dialog(message, "Continue?"): return - self.window.show_input_panel("Sobjects(* means all, or sobjects seprated with semi-colon)", - input, self.on_input, None, None) + self.window.show_input_panel("Sobjects(* means all, or sobjects seprated with semi-colon)", + input, self.on_input, None, None) return # After ensured input is valid, just start to generate workbooks @@ -1465,6 +1495,7 @@ def on_input(self, input): def is_enabled(self): return util.check_action_enabled() + class ViewComponentInSfdcCommand(sublime_plugin.WindowCommand): def __init__(self, *args, **kwargs): super(ViewComponentInSfdcCommand, self).__init__(*args, **kwargs) @@ -1484,6 +1515,7 @@ def on_done(self, index): startURL = "/" + class_id self.window.run_command("login_to_sfdc", {"startURL": startURL}) + class PreviewPageCommand(sublime_plugin.TextCommand): def run(self, view): startURL = "/apex/" + self.attributes["name"] @@ -1497,6 +1529,7 @@ def is_visible(self): return util.check_enabled(self.view.file_name()) + class RunOneTestCommand(sublime_plugin.WindowCommand): """ List the test classes from local cache, after any one is chosen, get the attribute of the chosen class and run test, @@ -1520,6 +1553,7 @@ class RunOneTestCommand(sublime_plugin.WindowCommand): ... } """ + def __init__(self, *args, **kwargs): super(RunOneTestCommand, self).__init__(*args, **kwargs) @@ -1545,6 +1579,7 @@ def on_done(self, index): class_id = self.classes_attr[key]["id"] processor.handle_run_test(class_name, class_id) + class FetchOrgWideCoverageCommand(sublime_plugin.WindowCommand): def __init__(self, *args, **kwargs): super(FetchOrgWideCoverageCommand, self).__init__(*args, **kwargs) @@ -1552,6 +1587,7 @@ def __init__(self, *args, **kwargs): def run(self): pass + class ChooseTestClasses(sublime_plugin.WindowCommand): def __init__(self, *args, **kwargs): super(ChooseTestClasses, self).__init__(*args, **kwargs) @@ -1566,7 +1602,8 @@ def run(self, callback_options={}): self.classes_attr = util.populate_components("ApexClass") self.classmap = {} - selected_items = []; unselected_items = [] + selected_items = []; + unselected_items = [] for key, item in self.classes_attr.items(): if not item["is_test"]: continue @@ -1578,8 +1615,8 @@ def run(self, callback_options={}): cname = item["name"] classItem = "%s[%s] %s" % ( - " " * 4, - "√" if cname in self.chosen_classes else "x", + " " * 4, + "√" if cname in self.chosen_classes else "x", cname ) if cname in self.chosen_classes: @@ -1595,7 +1632,7 @@ def run(self, callback_options={}): org_name=settings["default_project_name"] ) ); - + # Add `All` Item allItem = "[%s] All" % ( "√" if self.chosen_classes else "x" @@ -1612,8 +1649,8 @@ def run(self, callback_options={}): if hasattr(self, "index"): selected_index = self.index - self.window.show_quick_panel(self.items, self.on_done, - sublime.MONOSPACE_FONT, selected_index) + self.window.show_quick_panel(self.items, self.on_done, + sublime.MONOSPACE_FONT, selected_index) def on_done(self, index): if index == -1: @@ -1653,6 +1690,7 @@ def on_done(self, index): callback_options=self.callback_options ), 10) + class RunSyncTests(sublime_plugin.WindowCommand): def __init__(self, *args, **kwargs): super(RunSyncTests, self).__init__(*args, **kwargs) @@ -1666,6 +1704,7 @@ def run(self, chosen_classes=[]): }) processor.handle_run_sync_test(chosen_classes) + class RunSyncTest(sublime_plugin.TextCommand): def run(self, edit): tests = []; @@ -1679,9 +1718,9 @@ def run(self, edit): def is_enabled(self): # Get current file name and Read file content file_name = self.view.file_name() - if not file_name or not file_name.endswith(".cls"): + if not file_name or not file_name.endswith(".cls"): return False - if not util.check_enabled(file_name): + if not util.check_enabled(file_name): return False # Test class must be class firstly @@ -1699,12 +1738,12 @@ def is_enabled(self): component_attribute["namespacePrefix"], self.cname ) - + for region in self.view.sel(): sel = self.view.substr(self.view.word(region.begin())) if sel and not sel.isspace() and not re.compile(r'^[a-zA-Z0-9_]*$').match(sel.strip()): return False - + return True def is_visible(self): @@ -1715,6 +1754,7 @@ class RunAsyncTest(sublime_plugin.WindowCommand): """ @deprecated """ + def __init__(self, *args, **kwargs): super(RunAsyncTest, self).__init__(*args, **kwargs) @@ -1733,7 +1773,7 @@ def is_enabled(self, files): continue self.class_ids.append(component_attribute["id"]) - + return len(self.class_ids) > 0 def is_visible(self): @@ -1744,6 +1784,7 @@ class RunTestCommand(sublime_plugin.TextCommand): """ Run Async Test """ + def run(self, view): # Get component_attribute by file_name attributes = util.get_file_attributes(self.view.file_name()) @@ -1755,9 +1796,9 @@ def run(self, view): def is_enabled(self): # Get current file name and Read file content file_name = self.view.file_name() - if not file_name or not file_name.endswith(".cls"): + if not file_name or not file_name.endswith(".cls"): return False - if not util.check_enabled(file_name): + if not util.check_enabled(file_name): return False # Test class must be class firstly @@ -1773,6 +1814,7 @@ def is_enabled(self): def is_visible(self): return self.is_enabled() + class TrackAllDebugLogs(sublime_plugin.WindowCommand): def __init__(self, *args, **kwargs): super(TrackAllDebugLogs, self).__init__(*args, **kwargs) @@ -1783,6 +1825,7 @@ def run(self): if sublime.ok_cancel_dialog("Confirm to track logs for all users?", "Continue"): processor.handle_track_all_debug_logs_thread(users) + class TrackDebugLog(sublime_plugin.WindowCommand): def __init__(self, *args, **kwargs): super(TrackDebugLog, self).__init__(*args, **kwargs) @@ -1791,7 +1834,7 @@ def run(self, track_self=False): if track_self: processor.handle_create_debug_log('Me', None) return - + self.users = processor.handle_populate_users("track_debug_log") if not self.users: return self.users_name = sorted(self.users.keys(), reverse=False) @@ -1804,6 +1847,7 @@ def on_done(self, index): user_id = self.users[user_name] processor.handle_create_debug_log(user_name, user_id) + class FetchDebugLogCommand(sublime_plugin.WindowCommand): def __init__(self, *args, **kwargs): super(FetchDebugLogCommand, self).__init__(*args, **kwargs) @@ -1814,7 +1858,7 @@ def run(self, fetch_self=False): return self.users = processor.handle_populate_users("fetch_debug_log") - if not self.users: return # Network Issue Cause + if not self.users: return # Network Issue Cause self.users_name = sorted(self.users.keys(), reverse=False) self.window.show_quick_panel(self.users_name, self.on_done) @@ -1858,7 +1902,7 @@ def run(self, edit): # get file content, may be apex class or trigger class_path = os.path.join(work_dir, 'src', - 'classes', self.file_name+'.cls') + 'classes', self.file_name + '.cls') trigger_path = os.path.join(work_dir, 'src', 'triggers', self.file_name + '.trigger') _path = class_path if os.path.isfile(class_path) else trigger_path @@ -1888,6 +1932,7 @@ def is_enabled(self): def is_visible(self): return self.view.name() == 'Test Result' + class ViewDebugOnly(sublime_plugin.TextCommand): def run(self, view): whole_region = sublime.Region(0, self.view.size()) @@ -1908,6 +1953,7 @@ def run(self, view): def is_enabled(self): return self.view.settings().get("is_debug_log") is True + class ExecuteQuery(sublime_plugin.TextCommand): def run(self, view): sublime.active_window().run_command("haoku", { @@ -1923,6 +1969,7 @@ def is_enabled(self): return True + class ExecuteAnonymousCommand(sublime_plugin.TextCommand): def run(self, view): processor.handle_execute_anonymous(self.selection) @@ -1934,6 +1981,7 @@ def is_enabled(self): return True + class ViewIdInSfdcWebCommand(sublime_plugin.TextCommand): def run(self, view): startURL = "/" + self.record_id @@ -1942,7 +1990,7 @@ def run(self, view): if self.record_id.startswith("07L"): startURL = "/p/setup/layout/ApexDebugLogDetailEdit/d?apex_log_id=" + self.record_id - + self.view.window().run_command("login_to_sfdc", {"startURL": startURL}) def is_enabled(self): @@ -1951,7 +1999,7 @@ def is_enabled(self): self.record_id = self.view.substr(self.view.sel()[0]) else: self.record_id = self.view.substr(self.view.sel()[0]).encode("utf-8") - + if len(self.record_id) != 15 and len(self.record_id) != 18: return False @@ -1960,6 +2008,7 @@ def is_enabled(self): return True + class ShowInSfdcWebCommand(sublime_plugin.TextCommand): def run(self, view): # Get file_name and component_attribute @@ -1972,6 +2021,7 @@ def run(self, view): def is_enabled(self): return util.check_enabled(self.view.file_name()) + class LoginToSfdcCommand(sublime_plugin.WindowCommand): def __init__(self, *args, **kwargs): super(LoginToSfdcCommand, self).__init__(*args, **kwargs) @@ -1982,17 +2032,17 @@ def run(self, startURL="", copy_url=False): session = util.get_session_info(settings) # If .config/session.json is not exist, login firstly - if not session: - return self.window.run_command('login', - { - "callback_options": { - "callback_command": "login_to_sfdc", - "args": { - "startURL": startURL - } - } - } - ) + if not session: + return self.window.run_command('login', + { + "callback_options": { + "callback_command": "login_to_sfdc", + "args": { + "startURL": startURL + } + } + } + ) # If .config/session.json is exist, use frontdoor method show_url = "%s/secur/frontdoor.jsp?sid=%s&retURL=%s" % ( @@ -2004,6 +2054,7 @@ def run(self, startURL="", copy_url=False): sublime.set_clipboard(show_url) + class AboutCommand(sublime_plugin.ApplicationCommand): def run(command): package_info = sublime.load_settings("package.sublime-settings") @@ -2016,21 +2067,25 @@ def run(command): ) sublime.message_dialog(version_info) + class ReportIssueCommand(sublime_plugin.ApplicationCommand): def run(command): package_info = sublime.load_settings("package.sublime-settings") util.open_with_browser(package_info.get("issue_url")) + class HaoideHelp(sublime_plugin.ApplicationCommand): def run(command, url=""): package_info = sublime.load_settings("package.sublime-settings") util.open_with_browser(package_info.get("homepage") + url) + class ReleaseNotesCommand(sublime_plugin.ApplicationCommand): def run(command): package_info = sublime.load_settings("package.sublime-settings") util.open_with_browser(package_info.get("history_url")) + class DeleteFilesFromServer(sublime_plugin.WindowCommand): def __init__(self, *args, **kwargs): super(DeleteFilesFromServer, self).__init__(*args, **kwargs) @@ -2058,11 +2113,12 @@ def is_visible(self, files): return True + class DeleteFileFromServer(sublime_plugin.TextCommand): def run(self, view): files = [self.view.file_name()] self.view.window().run_command("delete_files_from_server", { - "files" : [self.view.file_name()] + "files": [self.view.file_name()] }) def is_enabled(self): @@ -2073,20 +2129,21 @@ def is_enabled(self): attr = util.get_component_attribute(self.file_name)[0] if not attr or "url" not in attr: return False - + return True def is_visible(self): return self.is_enabled() + class CreateApexTriggerCommand(sublime_plugin.WindowCommand): def __init__(self, *args, **kwargs): super(CreateApexTriggerCommand, self).__init__(*args, **kwargs) def run(self): sobjects_describe = util.populate_sobjects_describe() - self.sobjects = sorted([name for name in sobjects_describe\ - if "triggerable" in sobjects_describe[name] and sobjects_describe[name]["triggerable"]]) + self.sobjects = sorted([name for name in sobjects_describe \ + if "triggerable" in sobjects_describe[name] and sobjects_describe[name]["triggerable"]]) self.window.show_quick_panel(self.sobjects, self.on_done) def on_done(self, index): @@ -2100,6 +2157,7 @@ def on_done(self, index): def is_enabled(self): return util.check_action_enabled() + class CreateApexPageCommand(sublime_plugin.WindowCommand): def __init__(self, *args, **kwargs): super(CreateApexPageCommand, self).__init__(*args, **kwargs) @@ -2113,6 +2171,7 @@ def run(self): def is_enabled(self): return util.check_action_enabled() + class CreateApexComponentCommand(sublime_plugin.WindowCommand): def __init__(self, *args, **kwargs): super(CreateApexComponentCommand, self).__init__(*args, **kwargs) @@ -2126,6 +2185,7 @@ def run(self): def is_enabled(self): return util.check_action_enabled() + class CreateApexClassCommand(sublime_plugin.WindowCommand): def __init__(self, *args, **kwargs): super(CreateApexClassCommand, self).__init__(*args, **kwargs) @@ -2139,6 +2199,7 @@ def run(self): def is_enabled(self): return util.check_action_enabled() + class CreateStaticResource(sublime_plugin.WindowCommand): def __init__(self, *args, **kwargs): super(CreateStaticResource, self).__init__(*args, **kwargs) @@ -2152,36 +2213,36 @@ def on_choose(self, index): if index == -1: return self.content_type = self.content_types[index] - + self.input_name_message = "Please Input StaticResource Name: " - self.window.show_input_panel(self.input_name_message, - "", self.on_input_name, None, None) + self.window.show_input_panel(self.input_name_message, + "", self.on_input_name, None, None) def on_input_name(self, input): # Create component to local according to user input if not re.match('^[a-zA-Z]+\\w+$', input): message = 'Invalid name, do you want to try again?' if not sublime.ok_cancel_dialog(message, "Try Again?"): return - self.window.show_input_panel(self.input_name_message, - "", self.on_input_name, None, None) + self.window.show_input_panel(self.input_name_message, + "", self.on_input_name, None, None) return - + self.resource_name = input # Input file location self.input_location_message = "Please Input File or Path for StaticResource: " - self.window.show_input_panel(self.input_location_message, - "", self.on_input_location, None, None) + self.window.show_input_panel(self.input_location_message, + "", self.on_input_location, None, None) def on_input_location(self, location): # Get file or path from user input, allow trying agin if not os.path.exists(location) and not os.path.isfile(location): if not sublime.ok_cancel_dialog("Invalid file or path", "Try Again?"): return - self.window.show_input_panel(self.input_location_message, - "", self.on_input_location, None, None) + self.window.show_input_panel(self.input_location_message, + "", self.on_input_location, None, None) return - + if os.path.isfile(location): body = open(location, "r").read() @@ -2197,15 +2258,20 @@ def on_input_location(self, location): def is_enabled(self): return util.check_action_enabled() + class CreateComponentCommand(sublime_plugin.WindowCommand): + """ + Create Apex Class/Trigger/Page/Component via Tooling API + """ + def __init__(self, *args, **kwargs): super(CreateComponentCommand, self).__init__(*args, **kwargs) def run(self, template_name=None, - component_name=None, - component_type=None, - markup_or_body=None, - sobject_name=None): + component_name=None, + component_type=None, + markup_or_body=None, + sobject_name=None): self.template_name = template_name self.component_name = component_name self.component_type = component_type @@ -2219,7 +2285,7 @@ def run(self, template_name=None, # After input # in visualforce page, we can get # the component name and template name, no need to choose again - if self.component_name and self.template_name: + if self.component_name and self.template_name: self.template_attr = templates[self.template_name] self.create_component() else: @@ -2251,7 +2317,7 @@ def on_input(self, input): if not sublime.ok_cancel_dialog(message, "Try Again?"): return self.window.show_input_panel("Please Input Name: ", "", self.on_input, None, None) return - + self.component_name = input self.create_component() @@ -2276,8 +2342,8 @@ def create_component(self): file_name = "%s/%s" % (component_outputdir, self.component_name + extension) if os.path.isfile(file_name): - message = '"%s" is already exist, do you want to try again?' % self.component_name - if not sublime.ok_cancel_dialog(message, "Continue?"): + _message = '"%s" is already exist, do you want to try again?' % self.component_name + if not sublime.ok_cancel_dialog(_message, "Continue?"): self.window.open_file(file_name) return self.window.show_input_panel("Please Input Name: ", "", self.on_input, None, None) @@ -2292,7 +2358,7 @@ def create_component(self): # Build Post body data = { - "name": self.component_name, + "name": self.component_name, self.markup_or_body: body } @@ -2303,22 +2369,23 @@ def create_component(self): elif self.component_type in ["ApexPage", "ApexComponent"]: data["MasterLabel"] = self.component_name - processor.handle_create_component(data, self.component_name, - self.component_type, - self.markup_or_body, - file_name) + processor.handle_create_component(data, self.component_name, + self.component_type, + self.markup_or_body, + file_name) class SaveToServer(sublime_plugin.TextCommand): """ - Save Metadata to Server using Tooling API or Metadata API + Save Metadata to Server using Tooling API """ + def run(self, edit, is_check_only=False): # Check whether need confirm settings = context.get_settings() if settings["confirm_on_save"]: message = "Confirm to continue save operation?" - if not sublime.ok_cancel_dialog(message, "Save to Server?"): + if not sublime.ok_cancel_dialog(message, "Save to Server?"): return # Automatically save current file if dirty @@ -2334,12 +2401,13 @@ def is_enabled(self): attributes = util.get_file_attributes(self.view.file_name()) if attributes["metadata_folder"] not in ["classes", "components", "pages", "triggers", "aura", "lwc"]: return False - + return util.check_enabled(self.view.file_name()) def is_visible(self): return self.is_enabled() + class ViewFileAttributes(sublime_plugin.TextCommand): def run(self, edit): view = sublime.active_window().new_file() @@ -2355,9 +2423,10 @@ def is_enabled(self): self.component_attribute, self.cname = util.get_component_attribute(self.file_name) if not self.component_attribute: return False - + return True + class SwitchProjectCommand(sublime_plugin.WindowCommand): def __init__(self, *args, **kwargs): super(SwitchProjectCommand, self).__init__(*args, **kwargs) @@ -2369,8 +2438,8 @@ def run(self, callback_options={}): for k, v in settings["projects"].items(): if not v.get("hidden_in_project_list", False): projects[k] = v - self.projects = ["(" + ('Active' if projects[p]["default"] else - 'Inactive') + ") " + p for p in projects] + self.projects = ["(" + ('Active' if projects[p]["default"] else + 'Inactive') + ") " + p for p in projects] self.projects = sorted(self.projects, reverse=False) self.window.show_quick_panel(self.projects, self.on_done) @@ -2397,6 +2466,7 @@ def on_done(self, index): args = self.callback_options["args"] if "args" in self.callback_options else {} self.window.run_command(callback_command, args) + class Login(sublime_plugin.WindowCommand): def __init__(self, *args, **kwargs): super(Login, self).__init__(*args, **kwargs) @@ -2404,6 +2474,7 @@ def __init__(self, *args, **kwargs): def run(self, callback_options={}, force=False): processor.handle_login_thread(callback_options, force=force) + class UpdateUserLanguage(sublime_plugin.WindowCommand): def __init__(self, *args, **kwargs): super(UpdateUserLanguage, self).__init__(*args, **kwargs) @@ -2423,13 +2494,14 @@ def on_choose(self, index): def is_enabled(self): return util.check_action_enabled() + class EnableDevelopmentMode(sublime_plugin.WindowCommand): def __init__(self, *args, **kwargs): super(EnableDevelopmentMode, self).__init__(*args, **kwargs) def run(self): self.users = processor.handle_populate_users("enable_development_mode") - if not self.users: return # Network Issue Cause + if not self.users: return # Network Issue Cause self.users_name = sorted(self.users.keys(), reverse=False) self.window.show_quick_panel(self.users_name, self.on_done) @@ -2443,13 +2515,14 @@ def on_done(self, index): def is_enabled(self): return util.check_action_enabled() + class UpdateUserPassword(sublime_plugin.WindowCommand): def __init__(self, *args, **kwargs): super(UpdateUserPassword, self).__init__(*args, **kwargs) def run(self): self.users = processor.handle_populate_users("update_user_password") - if not self.users: return # Network Issue Cause + if not self.users: return # Network Issue Cause self.users_name = sorted(self.users.keys(), reverse=False) self.window.show_quick_panel(self.users_name, self.on_done) @@ -2459,15 +2532,15 @@ def on_done(self, index): user_name = self.users_name[index] self.user_id = self.users[user_name] - sublime.active_window().show_input_panel("Input New Password: ", - "", self.on_input, None, None) + sublime.active_window().show_input_panel("Input New Password: ", + "", self.on_input, None, None) def on_input(self, password): if not re.match('[\s\S]{5,22}', password): message = 'Invalid password, do you want to try again?' if not sublime.ok_cancel_dialog(message, "Try Again?"): return - return sublime.active_window().show_input_panel("Input New Password: ", - "", self.on_input, None, None) + return sublime.active_window().show_input_panel("Input New Password: ", + "", self.on_input, None, None) processor.handle_update_user_password(self.user_id, password) @@ -2523,14 +2596,15 @@ def run(self): "callback_command": "create_new_project" } }) - + dpn = settings["default_project"]["project_name"] message = "Are you sure you really want to create new project for %s?" % dpn if not sublime.ok_cancel_dialog(message, "Create New Project?"): return - + util.add_project_to_workspace(settings) processor.handle_new_project() + class DescribeMetadata(sublime_plugin.WindowCommand): def __init__(self, *args, **kwargs): super(DescribeMetadata, self).__init__(*args, **kwargs) @@ -2538,6 +2612,7 @@ def __init__(self, *args, **kwargs): def run(self, callback_options={}): processor.handle_describe_metadata(callback_options) + class ExtractToHere(sublime_plugin.WindowCommand): def __init__(self, *args, **kwargs): super(ExtractToHere, self).__init__(*args, **kwargs) @@ -2555,12 +2630,13 @@ def run(self, files): Printer.get("log").write_start().write("Extracted to " + extract_to) def is_visible(self, files): - if not files or len(files) > 1: + if not files or len(files) > 1: return False self._file = files[0] return zipfile.is_zipfile(self._file) + class UpdateStaticResource(sublime_plugin.WindowCommand): def __init__(self, *args, **kwargs): super(UpdateStaticResource, self).__init__(*args, **kwargs) @@ -2579,6 +2655,7 @@ def is_visible(self, dirs): return True + class RefreshFileFromServer(sublime_plugin.TextCommand): def run(self, view): self.view.window().run_command("refresh_files_from_server", { @@ -2589,7 +2666,7 @@ def is_enabled(self): file_name = self.view.file_name() if not file_name: return False attr = util.get_component_attribute(file_name)[0] - if not attr or "url" not in attr: + if not attr or "url" not in attr: return False return True @@ -2597,6 +2674,7 @@ def is_enabled(self): def is_visible(self): return self.is_enabled() + class RefreshFilesFromServer(sublime_plugin.WindowCommand): def __init__(self, *args, **kwargs): super(RefreshFilesFromServer, self).__init__(*args, **kwargs) @@ -2606,7 +2684,7 @@ def run(self, files): if not sublime.ok_cancel_dialog(message, "Refresh Files?"): return for file_name in files: - if file_name.endswith("-meta.xml"): continue # Ignore -meta.xml file + if file_name.endswith("-meta.xml"): continue # Ignore -meta.xml file attr = util.get_component_attribute(file_name)[0] # Handle Refresh Current Component @@ -2624,4 +2702,4 @@ def is_visible(self, files): if not attr or "url" not in attr: return False - return True \ No newline at end of file + return True From 8927b9ba2d59a89e3b612d9dca9274ca49f00ed9 Mon Sep 17 00:00:00 2001 From: Lushang Date: Thu, 2 Apr 2020 18:13:37 +0800 Subject: [PATCH 44/46] Update documentation, added Issue Report guidance --- README.md | 14 ++++++++++---- docs/issue.md | 30 ++++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+), 4 deletions(-) create mode 100644 docs/issue.md diff --git a/README.md b/README.md index 27b8a9a..e2048d5 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # Sublime IDE for Salesforce -This plugin supports [Sublime Text 3](http://www.sublimetext.com/3) for windows and OSX, not tested for Linux. +This plugin supports [Sublime Text 3](http://www.sublimetext.com/3) for windows and OSX, has not enough testing for Linux yet. -All of my motivation on this plugin come from your star, if you think this plugin is helpful in your daily work, please **star** this plugin. +All of our motivation on this plugin come from your star, if you think this plugin is helpful in your daily work, please **star** this plugin. # Installation @@ -14,7 +14,7 @@ Or, You can follow the step-by-step [instruction](https://meighanrockssf.wordpre # Project Configuration After you have installed this plugin successfully, you can follow Project Configuration to configure your own project. -If you don't want to keep your user credential information in the plugin , you just need to do it as below format, plugin will lanuch the browser to start OAuth2 Login process, +If you don't want to keep your user credential information in the plugin , you just need to do it as below format, plugin will launch the browser to start OAuth2 Login process, ```javascript "projects": { "pro-sublime": { @@ -64,6 +64,12 @@ If you don't want to keep your user credential information in the plugin , you j > - [Salesforce oAuth2](https://github.com/neworganizing/salesforce-oauth2) > - [SalesforceXyTools](https://github.com/exiahuang/SalesforceXyTools) +# Feedback & Contribution +Feel free to open issues, but you should refer to the Raise Issue before +reporting any bug. + +well welcome to any contribution, open an issue for discussion before draft you code. + # Q&A + ``Refresh Package`` vs ``Update Project`` * ``Refresh Package`` can update the project by the ``package.xml`` in the project folder or ``project/src`` folder @@ -78,7 +84,7 @@ If you don't want to keep your user credential information in the plugin , you j * ``Deploy to Server`` is achieved by ``Metadata API`` tech, which is usually used to develop none-apex in sandbox, deploy any components into different org or production + What's the usage of ``Update Project Pattern`` command? - * Everytime when you udpate the ``file_exclude_patterns`` or ``folder_exclude_patterns``, you must execute ``Update Project Pattern`` command to ensure it is working. + * Everytime when you update the ``file_exclude_patterns`` or ``folder_exclude_patterns``, you must execute ``Update Project Pattern`` command to ensure it is working. * Everytime when the default project doesn't appeared in the sidebar panel, you an use this command to show the default project. + If you failed to deploy package after release 3.3.7 diff --git a/docs/issue.md b/docs/issue.md new file mode 100644 index 0000000..c2c35bc --- /dev/null +++ b/docs/issue.md @@ -0,0 +1,30 @@ +# Raise Issue + +Create an [Issue][1] for following situations: +- Find a bug +- Have a good idea about any enhancement/new feature + +### Report a Bug ### + +For better investigation, you should include following message: + +1. Title: a concise summary about the bug +2. Description about the bug + - Details with text description, provide screenshot if necessary. + - Steps to recur the bug. + - Any workaround you have tried. +3. Context information + - Operation System and version. e.g *Windows 10, version 1903* + - Sublime Test 3 version. e.g *Version 3.2.2 Build 3211* + - Your HaoIDE version. e.g *Build 3.6.0* + - Sublime Text 3 console log. You can press `Ctrl+~` to open the console panel. + - Your user settings if necessary. + - Any other necessary information. + +### Propose an Enhancement or a New Feature + +Just open an issue to discuss it! + +If you want to contribute, also open an issue before draft the code! + +[1]: https://github.com/xjsender/haoide/issues \ No newline at end of file From 0e428ae4cfd8190897b6d132a46d1c2dae39f382 Mon Sep 17 00:00:00 2001 From: Lushang Date: Wed, 16 Dec 2020 15:22:39 +0800 Subject: [PATCH 45/46] Updated new Apex classes in release v50.0 --- completions.py | 6 +++- processor.py | 2 +- salesforce/lib/apex.py | 81 ++++++++++++++++++++++++++++++++++++------ 3 files changed, 77 insertions(+), 12 deletions(-) diff --git a/completions.py b/completions.py index d16bed9..b75dddc 100644 --- a/completions.py +++ b/completions.py @@ -31,13 +31,17 @@ def load_sobject_cache(reload_cache=False, username=None): class PackageCompletions(sublime_plugin.EventListener): + """ + Completions for Package.xml + """ def on_query_completions(self, view, prefix, locations): if not view.match_selector(locations[0], "text.xml"): return [] # Check whether current file is package file pattern = "[\\s.*<>\\-\\w/\\%1-9]+" - if not view.find_all(pattern): return + if not view.find_all(pattern): + return location = locations[0] pt = locations[0] - len(prefix) - 1 diff --git a/processor.py b/processor.py index dc63f2a..82f744d 100644 --- a/processor.py +++ b/processor.py @@ -1466,7 +1466,7 @@ def handle_thread(thread, timeout): # Makedir for subscribed meta types for metadata_folder in settings["subscribed_metadata_folders"]: - outputdir = os.path.join(extract_to, "src", metadata_folder); + outputdir = os.path.join(extract_to, "src", metadata_folder) if not os.path.exists(outputdir): os.makedirs(outputdir) # Extract the zipFile to extract_to diff --git a/salesforce/lib/apex.py b/salesforce/lib/apex.py index d51c883..aa09a4a 100644 --- a/salesforce/lib/apex.py +++ b/salesforce/lib/apex.py @@ -697,6 +697,7 @@ "Separator" ], "System": [ + "AccessType", "XmlException", "RequiredFeatureMissingException", "SearchException", @@ -737,7 +738,8 @@ "ApexPages", "Approval", "QuickAction", - "SObject", + "SObject", + "SObjectAccessDecision", "AssertException", "Date", "Messaging", @@ -829,7 +831,8 @@ "QueueableContextImpl", "Site", "UserManagement", - "Callable" + "Callable", + "Security", ], "Canvas": [ "CanvasRenderException", @@ -864,14 +867,15 @@ "EmailFileAttachment", "AttachmentRetrievalOption", "InboundEmailResult", - "InboundEmail", - "RenderEmailTemplateError", + "InboundEmail", "EmailToSalesforceHandler", "SingleEmailMessage", "TextAttachment", "PushNotification", - "PushNotificationPayload", - "RenderEmailTemplateBodyResult", + "PushNotificationPayload", + "CustomNotification", + "RenderEmailTemplateBodyResult", + "RenderEmailTemplateError", "MassEmailMessage" ], "DataProtection": [ @@ -3082,7 +3086,25 @@ }, "namespace": "Messaging", "properties": {} - }, + }, + "customnotification": { + "constructors": { + "CustomNotification()\t": "CustomNotification()$0", + "CustomNotification(String typeId, String sender, String title, String body, String targetId, String targetPageRef)\t": "CustomNotification(${1:String typeId}, ${2:String sender}, ${3:String title}, ${4:String body}, ${5:String targetId}, ${6:String targetPageRef})$0" + }, + "name": "CustomNotification", + "methods": { + "send(Set users)\tvoid": "send(${1:Set users})$0", + "setNotificationTypeId(String id)\tvoid": "setNotificationTypeId(${1:String id})$0", + "setTitle(String title)\tvoid": "setTitle(${1:String title})$0", + "setBody(String body)\tvoid": "setBody(${1:String body})$0", + "setSenderId(String id)\tvoid": "setSenderId(${1:String id})$0", + "setTargetId(String targetId)\tvoid": "setTargetId(${1:String targetId})$0", + "setTargetPageRef(String pageRef)\tvoid": "setTargetPageRef(${1:String pageRef})$0", + }, + "namespace": "Messaging", + "properties": {} + }, "sortorder": [ { "constructors": {}, @@ -9658,7 +9680,13 @@ "getLimitFieldsDescribes()\tInteger": "getLimitFieldsDescribes()$0", "getChildRelationshipsDescribes()\tInteger": "getChildRelationshipsDescribes()$0", "getHeapSize()\tInteger": "getHeapSize()$0", - "getPickListDescribes()\tInteger": "getPickListDescribes()$0" + "getPickListDescribes()\tInteger": "getPickListDescribes()$0", + "getMobilePushApexCalls()\tInteger": "getMobilePushApexCalls()$0", + "getLimitMobilePushApexCalls()\tInteger": "getLimitMobilePushApexCalls()$0", + "getPublishImmediateDML()\tInteger": "getPublishImmediateDML()$0", + "getLimitPublishImmediateDML()\tInteger": "getLimitPublishImmediateDML()$0", + "getQueueableJobs()\tInteger": "getQueueableJobs()$0", + "getLimitQueueableJobs()\tInteger": "getLimitQueueableJobs()$0", }, "namespace": "Limits", "name": "Limits" @@ -23310,5 +23338,38 @@ "properties": { "fileCount": "fileCount$0" } - } -} \ No newline at end of file + }, + "security": { + "constructors": {}, + "name": "Security", + "methods": { + "stripInaccessible(System.AccessType accessCheckType, List sourceRecords, Boolean enforceRootObjectCRUD)\tSystem.SObjectAccessDecision": "stripInaccessible(${1:System.AccessType accessCheckType}, ${2:List sourceRecords}, ${3:Boolean enforceRootObjectCRUD})$0", + "stripInaccessible(System.AccessType accessCheckType, List sourceRecords)\tSystem.SObjectAccessDecision": "stripInaccessible(${1:System.AccessType accessCheckType}, ${2:List sourceRecords})$0", + }, + "namespace": "System", + "properties": {} + }, + "accesstype": { + "constructors": {}, + "name": "AccessType", + "methods": {}, + "namespace": "System", + "properties": { + "CREATABLE": "CREATABLE$0", + "READABLE": "READABLE$0", + "UPDATABLE": "UPDATABLE$0", + "UPSERTABLE": "UPSERTABLE$0", + } + }, + "sobjectaccessdecision": { + "constructors": {}, + "name": "SObjectAccessDecision", + "methods": { + "getModifiedIndexes()\tSet": "getModifiedIndexes()$0", + "getRecords()\tList": "getRecords()$0", + "getRemovedFields()\tMap>": "getRemovedFields()$0", + }, + "namespace": "System", + "properties": {} + }, +} From 8d3d5ca81b1b141bb7c9669f001e7246aa228bad Mon Sep 17 00:00:00 2001 From: Lushang Date: Wed, 13 Jan 2021 21:25:33 +0800 Subject: [PATCH 46/46] Release 3.6.1 --- HISTORY.rst | 9 ++++++ config/messages/3.6.1.md | 8 +++++ config/messages/install.txt | 30 +++++++++---------- config/settings/package.sublime-settings | 4 +-- ...lass Header - class header.sublime-snippet | 2 +- messages.json | 2 +- 6 files changed, 36 insertions(+), 19 deletions(-) create mode 100644 config/messages/3.6.1.md diff --git a/HISTORY.rst b/HISTORY.rst index 2439222..20006a4 100644 --- a/HISTORY.rst +++ b/HISTORY.rst @@ -3,6 +3,15 @@ Release History ----------------- + +Build 3.6.1 (2021-01-13) +++++++++++++++++++++++++++++++++++++ +* Removed component metadata cache after destructing +* Updated new Apex classes in Salesforce release v50.0 +* Updated documentations, added Issue Report Guidance +* Miscellaneous bug fixings and refinements + + Release 3.6.0 (2020-03-30) ++++++++++++++++++++++++++++++++++++ * Implemented Save lwc file to Server last one diff --git a/config/messages/3.6.1.md b/config/messages/3.6.1.md new file mode 100644 index 0000000..a501788 --- /dev/null +++ b/config/messages/3.6.1.md @@ -0,0 +1,8 @@ +Build 3.6.1 +----------- +Release Date: 13 January 2021 + +* Removed component metadata cache after destructing +* Updated new Apex classes in Salesforce release v50.0 +* Updated documentations, added Issue Report Guidance +* Miscellaneous bug fixings and refinements \ No newline at end of file diff --git a/config/messages/install.txt b/config/messages/install.txt index 5965d2b..0400251 100644 --- a/config/messages/install.txt +++ b/config/messages/install.txt @@ -1,16 +1,16 @@ -# Sublime IDE for Salesforce -This plugin supports [Sublime Text 3](http://www.sublimetext.com/3) for windows and OSX, not tested for Linux. - -# Installation -You can install this plugin by searching ``haoide`` in package control, if you don't know how to use ``package control``, you can refer to [usage of package control](https://packagecontrol.io/docs/usage). - -This plugin is in improvement stage, many ideas are generated in daily work of mine or my friends, if you have any idea or find any issue, please log issue by clicking ``Report Issue`` in the main menu, thanks for you help on improving this plugin. - -All of my motivation on this plugin come from your star, if you think this plugin is helpful in your daily work, please **star** this plugin. - -# Change Logs -+ Change Logs - -# Quick Link -+ [Demos](https://github.com/xjsender/SublimeApexScreenshot) +# Sublime IDE for Salesforce +This plugin supports [Sublime Text 3](http://www.sublimetext.com/3) for windows and OSX, not tested for Linux. + +# Installation +You can install this plugin by searching ``haoide`` in package control, if you don't know how to use ``package control``, you can refer to [usage of package control](https://packagecontrol.io/docs/usage). + +This plugin is in improvement stage, many ideas are generated in daily work of mine or my friends, if you have any idea or find any issue, please log issue by clicking ``Report Issue`` in the main menu, thanks for you help on improving this plugin. + +All of our motivation on this plugin come from your star, if you think this plugin is helpful in your daily work, please **star** this plugin. + +# Change Logs ++ Change Logs + +# Quick Link ++ [Demos](https://github.com/xjsender/SublimeApexScreenshot) + [Document](https://github.com/xjsender/haoide) \ No newline at end of file diff --git a/config/settings/package.sublime-settings b/config/settings/package.sublime-settings index 23d2fd2..5fdae4f 100644 --- a/config/settings/package.sublime-settings +++ b/config/settings/package.sublime-settings @@ -1,8 +1,8 @@ { "name": "haoide", - "version": "3.6.0", + "version": "3.6.1", "description": "HaoIDE is a Sublime Text 3 plugin for Salesforce and used for swift development on Force.com", - "author": "Hao Liu @ 2013-2019", + "author": "Hao Liu @ 2013-2019, Lushang @ 2020-2021", "email": "mouse.mliu@gmail.com", "homepage": "https://github.com/xjsender/haoide", "issue_url": "https://github.com/xjsender/haoide/issues", diff --git a/config/snippets/Apex/Class Header - class header.sublime-snippet b/config/snippets/Apex/Class Header - class header.sublime-snippet index ac651ca..e01175a 100644 --- a/config/snippets/Apex/Class Header - class header.sublime-snippet +++ b/config/snippets/Apex/Class Header - class header.sublime-snippet @@ -7,7 +7,7 @@ * Author: $4 ($5) * Create Date: 2020-${6:03-27} * Modify History: - * 2020-${6:03-27} $4 ${7:Create this class} + * 2021-${6:01-13} $4 ${7:Create this class} **************************************************************************************************/ ]]> ch diff --git a/messages.json b/messages.json index b70b471..bf678cc 100644 --- a/messages.json +++ b/messages.json @@ -1,5 +1,5 @@ { - "3.5.9": "config/messages/3.5.9.md", "3.6.0": "config/messages/3.6.0.md", + "3.6.1": "config/messages/3.6.1.md", "install": "config/messages/install.txt" } \ No newline at end of file