Skip to content

Commit b0eae4c

Browse files
committed
Implemented Save lwc's resource file to Salesforce
1 parent 1c2e99c commit b0eae4c

File tree

5 files changed

+114
-71
lines changed

5 files changed

+114
-71
lines changed

main.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2294,7 +2294,11 @@ def create_component(self):
22942294
self.markup_or_body,
22952295
file_name)
22962296

2297+
22972298
class SaveToServer(sublime_plugin.TextCommand):
2299+
"""
2300+
Save Metadata to Server using Tooling API or Metadata API
2301+
"""
22982302
def run(self, edit, is_check_only=False):
22992303
# Check whether need confirm
23002304
settings = context.get_settings()
@@ -2311,9 +2315,10 @@ def run(self, edit, is_check_only=False):
23112315
processor.handle_save_to_server(self.view.file_name(), is_check_only)
23122316

23132317
def is_enabled(self):
2314-
if not self.view or not self.view.file_name(): return False
2318+
if not self.view or not self.view.file_name():
2319+
return False
23152320
attributes = util.get_file_attributes(self.view.file_name())
2316-
if attributes["metadata_folder"] not in ["classes", "components", "pages", "triggers", "aura"]:
2321+
if attributes["metadata_folder"] not in ["classes", "components", "pages", "triggers", "aura", "lwc"]:
23172322
return False
23182323

23192324
return util.check_enabled(self.view.file_name())

processor.py

Lines changed: 31 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1582,9 +1582,9 @@ def handle_thread(thread, timeout):
15821582

15831583

15841584
def handle_retrieve_package(types, extract_to, source_org=None, ignore_package_xml=False, timeout=120):
1585-
def handle_thread(thread, timeout):
1586-
if thread.is_alive():
1587-
sublime.set_timeout(lambda: handle_thread(thread, timeout), timeout)
1585+
def handle_thread(_thread, timeout):
1586+
if _thread.is_alive():
1587+
sublime.set_timeout(lambda: handle_thread(_thread, timeout), timeout)
15881588
return
15891589

15901590
# If source_org is not None, we need to switch project back
@@ -1593,11 +1593,11 @@ def handle_thread(thread, timeout):
15931593

15941594
# Extract the zipFile to extract_to
15951595
if api.result and api.result["success"]:
1596-
thread = threading.Thread(target=util.extract_encoded_zipfile,
1597-
args=(api.result["zipFile"], extract_to, ignore_package_xml,))
1598-
thread.start()
1596+
_thread = threading.Thread(target=util.extract_encoded_zipfile,
1597+
args=(api.result["zipFile"], extract_to, ignore_package_xml,))
1598+
_thread.start()
15991599

1600-
# Apex Code Cache
1600+
# Code Cache
16011601
if isinstance(api.result.get("fileProperties", None), list):
16021602
util.reload_file_attributes(
16031603
api.result["fileProperties"],
@@ -1610,11 +1610,19 @@ def handle_thread(thread, timeout):
16101610
thread = threading.Thread(target=api.retrieve, args=({"types": types},))
16111611
thread.start()
16121612
handle_thread(thread, timeout)
1613-
ThreadProgress(api, thread, "Retrieve File From Server",
1613+
ThreadProgress(api, thread,
1614+
"Retrieve File From Server",
16141615
"Retrieve File From Server Succeed")
16151616

16161617

16171618
def handle_save_to_server(file_name, is_check_only=False, timeout=120):
1619+
"""
1620+
Handle Save metadata to Salesforce
1621+
@param file_name: file name with path format
1622+
@param is_check_only: only check the file from Salesforce, do not really save
1623+
@param timeout: timeout in seconds
1624+
@return: None
1625+
"""
16181626
def handle_thread(thread, timeout):
16191627
if thread.is_alive():
16201628
sublime.set_timeout(lambda: handle_thread(thread, timeout), timeout)
@@ -1679,15 +1687,18 @@ def handle_thread(thread, timeout):
16791687
# Because error line in page is always at the line 1, so just work in class or trigger
16801688
elif "success" in result and not result["success"]:
16811689
# Maybe network issue
1682-
if "problem" not in result: return
1690+
_message = "Unknown Problem!"
1691+
if "problem" in result:
1692+
_message = "Compile Error for %s: %s at line %s column %s" % (
1693+
file_base_name,
1694+
result["problem"],
1695+
result["lineNumber"],
1696+
result["columnNumber"]
1697+
)
1698+
elif "message" in result:
1699+
_message = result["message"]
16831700

1684-
message = "Compile Error for %s: %s at line %s column %s" % (
1685-
file_base_name,
1686-
result["problem"],
1687-
result["lineNumber"],
1688-
result["columnNumber"]
1689-
)
1690-
Printer.get('log').write(message)
1701+
Printer.get('log').write(_message)
16911702

16921703
# Get the active view
16931704
view = util.get_view_by_file_name(file_name)
@@ -1753,8 +1764,10 @@ def handle_thread(thread, timeout):
17531764
Printer.get('log').write_start().write("Start to %s %s" % (compile_or_save, file_base_name))
17541765

17551766
api = ToolingApi(settings)
1756-
if component_attribute["type"] in ["AuraDefinitionBundle", "AuraDefinition"]:
1757-
target = api.save_aura_to_server
1767+
lngt_meta_type = ["AuraDefinitionBundle", "AuraDefinition",
1768+
"LightningComponentBundle", "LightningComponentResource"]
1769+
if component_attribute["type"] in lngt_meta_type:
1770+
target = api.save_lightning_to_server
17581771
else:
17591772
target = api.save_to_server
17601773
thread = threading.Thread(target=target,

salesforce/api/metadata.py

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -179,7 +179,7 @@ def retrieve(self, options, timeout=120):
179179
180180
Arguments:
181181
182-
* options -- {"types" : types, "package_names": package_names}
182+
* options -- {"types" : types_dict, "package_names": package_names}
183183
"""
184184
result = self.login()
185185
if not result or not result["success"]:
@@ -223,8 +223,8 @@ def retrieve(self, options, timeout=120):
223223

224224
# Post retrieve request
225225
try:
226-
response = requests.post(self.metadata_url, soap_body, verify=False,
227-
headers=self.headers, timeout=120)
226+
response = requests.post(self.metadata_url, soap_body, verify=False,
227+
headers=self.headers, timeout=120)
228228
except requests.exceptions.RequestException as e:
229229
self.result = {
230230
"Error Message": "Network connection timeout when issuing retrieve request",
@@ -322,11 +322,13 @@ def retrieve(self, options, timeout=120):
322322
# Total time
323323
total_seconds = (datetime.datetime.now() - start_time).seconds
324324
Printer.get('log').write("Total time: %s seconds" % total_seconds, False)
325+
# print('meta retrive result', result)
325326

326327
self.result = result
327328

328329
def prepare_members(self, _types, list_package_for_all=False):
329-
if not self.login(): return
330+
if not self.login():
331+
return
330332

331333
if list_package_for_all:
332334
Printer.get("log").write_start()
@@ -335,7 +337,8 @@ def prepare_members(self, _types, list_package_for_all=False):
335337
# EmailFolder, DocumentFolder, DashboardFolder and ReportFolder
336338
records = []
337339
for _type in _types:
338-
if "*" not in _types[_type]: continue
340+
if "*" not in _types[_type]:
341+
continue
339342
if _type in self.settings["metadata_objects_in_folder"]:
340343
# List package for ``suffix.capitalize() + 'Folder'``
341344
metadata_object = _type + "Folder" if _type != "EmailTemplate" else "EmailFolder"
@@ -377,19 +380,20 @@ def prepare_members(self, _types, list_package_for_all=False):
377380

378381
# In order to speed up retrieve request, we will not list package for them
379382
# just when we want to get full copy or build package.xml, we will list_package for all
380-
# Note: CustomObject must be retrieved by ``list_package`` request
383+
# Note: CustomObject must be retrieved by ``list_package`` request
381384
# list package for metadata object which supports wildcard retrieve
382385
_types_list = []
386+
# print("retrieve types: ", _types)
383387
if not list_package_for_all:
384388
if "CustomObject" in _types and "*" in _types["CustomObject"]:
385389
_types_list.append("CustomObject")
386390

387-
print(_types)
388391
if "InstalledPackage" in _types and "*" in _types["InstalledPackage"]:
389392
_types_list.append("InstalledPackage")
390393
else:
391394
for _type in _types:
392-
if "*" not in _types[_type]: continue
395+
if "*" not in _types[_type]:
396+
continue
393397
if _type not in self.settings["metadata_objects_in_folder"]:
394398
_types_list.append(_type)
395399

salesforce/api/tooling.py

Lines changed: 43 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -958,7 +958,7 @@ def save_to_server(self, component_attribute, body, is_check_only, check_save_co
958958
# Component Attribute
959959
component_type = component_attribute["type"]
960960
component_id = component_attribute["id"]
961-
component_body = component_attribute["body"]
961+
# component_body = component_attribute["body"]
962962

963963
if self.settings["check_save_conflict"] and not is_check_only and check_save_conflict:
964964
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
11591159
# Result used in thread invoke
11601160
self.result = return_result
11611161

1162-
def save_aura_to_server(self, component_attribute, body, check_save_conflict=True):
1163-
""" Save AuraDefinition such as Lightning component makeup, controller and helper
1162+
def save_lightning_to_server(self, component_attribute, body, check_save_conflict=True):
1163+
"""
1164+
Save Lightning AuraDefinition or LightningComponentResource such as component makeup, controller and helper or
1165+
Lightning Web component teampl to Salesforce
11641166
11651167
Arguments:
1166-
1167-
* component_attribute - attribute of component, e.g., component id, url
1168-
* body -- Code content
1169-
* check_save_conflict -- indicate whether to check saving conflict
1168+
@param component_attribute: attribute of component, e.g., component id, url
1169+
@param body: Code content
1170+
@param check_save_conflict: indicate whether to check saving conflict
1171+
@return: saving result
11701172
"""
11711173

11721174
def handle_error_message(result):
1175+
if self.settings["debug_mode"]:
1176+
print('Error: ', result)
11731177
_result = dict()
11741178
_result["success"] = False
11751179
_result["errorCode"] = result["errorCode"]
1176-
if "\n" in result["message"]:
1177-
error_messages = result["message"].split('\n')
1178-
if "CSS Parser" in error_messages[0] :
1179-
error_msg = error_messages[2]
1180-
_result["problem"] = error_msg
1181-
error_line_info = error_msg[error_msg.find("(")+1: error_msg.find(")")]
1182-
_result["lineNumber"] = error_line_info.split(",")[0][5:]
1183-
_result["columnNumber"] = error_line_info.split(",")[1][5:]
1180+
try:
1181+
if "\n" in result["message"]:
1182+
error_messages = result["message"].split('\n')
1183+
if "CSS Parser" in error_messages[0] :
1184+
error_msg = error_messages[2]
1185+
_result["problem"] = error_msg
1186+
error_line_info = error_msg[error_msg.find("(")+1: error_msg.find(")")]
1187+
_result["lineNumber"] = error_line_info.split(",")[0][5:]
1188+
_result["columnNumber"] = error_line_info.split(",")[1][5:]
1189+
else:
1190+
error_base_info = error_messages[0].split(': ')
1191+
error_line_info = error_base_info[1].split(':')[1]
1192+
error_line_info = error_line_info[1 : len(error_line_info) - 1]
1193+
_result['id'] = error_base_info[0]
1194+
_result["lineNumber"] = error_line_info.split(',')[0]
1195+
_result["columnNumber"] = error_line_info.split(',')[1]
1196+
_result["problem"] = error_messages[1]
11841197
else:
1185-
error_base_info = error_messages[0].split(': ')
1186-
error_line_info = error_base_info[1].split(':')[1]
1187-
error_line_info = error_line_info[1 : len(error_line_info) - 1]
1188-
_result['id'] = error_base_info[0]
1189-
_result["lineNumber"] = error_line_info.split(',')[0]
1190-
_result["columnNumber"] = error_line_info.split(',')[1]
1191-
_result["problem"] = error_messages[1]
1192-
else:
1193-
_result["problem"] = result["message"]
1194-
_result['id'] = result["message"].split(':')[0]
1195-
m = re.search(r'\[\d+,\s*\d+\]', result["message"])
1196-
if m:
1197-
col_row = m.group(0)
1198-
col_row = col_row[1:len(col_row)-1]
1199-
_result["lineNumber"] = col_row.split(',')[0]
1200-
_result["columnNumber"] = col_row.split(',')[1]
1198+
_result["problem"] = result["message"]
1199+
_result['id'] = result["message"].split(':')[0]
1200+
m = re.search(r'\[\d+,\s*\d+\]', result["message"])
1201+
if m:
1202+
col_row = m.group(0)
1203+
col_row = col_row[1:len(col_row)-1]
1204+
_result["lineNumber"] = col_row.split(',')[0]
1205+
_result["columnNumber"] = col_row.split(',')[1]
1206+
except Exception as _ex:
1207+
if self.settings["debug_mode"]:
1208+
print('Error parsing error result: ', _ex)
1209+
_result["message"] = result["message"]
12011210
return _result
12021211

12031212
# 1. Firstly Login
@@ -1207,10 +1216,10 @@ def handle_error_message(result):
12071216
return self.result
12081217

12091218
# Component Attribute
1210-
# component_type = component_attribute["type"]
1211-
component_type = 'AuraDefinition'
1219+
bundle_type = component_attribute["type"]
1220+
component_type = 'AuraDefinition' if bundle_type == "AuraDefinitionBundle" else 'LightningComponentResource'
12121221
component_id = component_attribute["id"]
1213-
component_url = self.base_url + '/tooling/sobjects/AuraDefinition/' + component_id
1222+
component_url = self.base_url + '/tooling/sobjects/' + component_type + '/' + component_id
12141223

12151224
# 2. Check conflict
12161225
if self.settings["check_save_conflict"] and check_save_conflict:

util.py

Lines changed: 21 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1687,13 +1687,21 @@ def extract_zipfile(zipfile_path, extract_to):
16871687

16881688
zfile.close()
16891689

1690+
16901691
def extract_file(zipfile_path, extract_to, ignore_package_xml=False):
1691-
zfile = zipfile.ZipFile(zipfile_path, 'r')
1692-
for filename in zfile.namelist():
1692+
"""
1693+
extract packaged Zip file from metadata API
1694+
@param zipfile_path:
1695+
@param extract_to:
1696+
@param ignore_package_xml:
1697+
@return:
1698+
"""
1699+
zip_file = zipfile.ZipFile(zipfile_path, 'r')
1700+
for filename in zip_file.namelist():
16931701
if filename.endswith('/'):
16941702
continue
16951703

1696-
if ignore_package_xml and filename == "unpackaged/package.xml":
1704+
if ignore_package_xml and filename == "unpackaged/package.xml":
16971705
continue
16981706

16991707
if filename.startswith("unpackaged"):
@@ -1705,9 +1713,9 @@ def extract_file(zipfile_path, extract_to, ignore_package_xml=False):
17051713
os.makedirs(os.path.dirname(f))
17061714

17071715
with open(f, "wb") as fp:
1708-
fp.write(zfile.read(filename))
1716+
fp.write(zip_file.read(filename))
17091717

1710-
zfile.close()
1718+
zip_file.close()
17111719

17121720
def extract_zip(base64String, extract_to):
17131721
"""
@@ -1802,6 +1810,8 @@ def reload_file_attributes(file_properties, settings=None, append=False):
18021810
"ApexComponent": "Markup"
18031811
}
18041812

1813+
# print(file_properties)
1814+
18051815
# If the package only contains `package.xml`
18061816
if isinstance(file_properties, dict):
18071817
file_properties = [file_properties]
@@ -2194,8 +2204,9 @@ def parse_sync_test_coverage(result):
21942204
allrows.append("\n".join(success_row))
21952205

21962206
allrows.append("~" * 80)
2197-
allrows.append("Follow the instruction as below, you can quickly view code coverage,")
2198-
allrows.append(" * Put focus on code name, hold down 'alt' and Dblclick the 'Left Mouse'")
2207+
allrows.append("Apex Class Or Trigger Code Coverage Statistics:")
2208+
# allrows.append("Follow the instruction as below, you can quickly view code coverage,")
2209+
# allrows.append(" * Put focus on code name, hold down 'alt' and Dblclick the 'Left Mouse'")
21992210

22002211
header_width = {
22012212
"Type": 15, "Name": 50, "Percent": 10, "Lines": 10
@@ -3148,7 +3159,8 @@ def check_enabled(file_name, check_cache=True):
31483159
31493160
* Bool -- check whether current file is apex code file and has local cache
31503161
"""
3151-
if not file_name: return False
3162+
if not file_name:
3163+
return False
31523164

31533165
# Get toolingapi settings
31543166
settings = context.get_settings()
@@ -3593,7 +3605,7 @@ def export_profile_settings():
35933605
if sobject in profile_settings[profile]["objectPermissions"]:
35943606
object_permission = profile_settings[profile]["objectPermissions"][sobject]
35953607
for crud in cruds:
3596-
rows.append("" if object_permission[crud] == "true" else "")
3608+
rows.append("True" if object_permission[crud] == "true" else "")
35973609
else:
35983610
for crud in cruds:
35993611
rows.append("")

0 commit comments

Comments
 (0)