systemlink-cli 1.9.2__tar.gz → 1.9.3__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (79) hide show
  1. {systemlink_cli-1.9.2 → systemlink_cli-1.9.3}/PKG-INFO +1 -1
  2. {systemlink_cli-1.9.2 → systemlink_cli-1.9.3}/pyproject.toml +1 -1
  3. {systemlink_cli-1.9.2 → systemlink_cli-1.9.3}/slcli/_version.py +1 -1
  4. {systemlink_cli-1.9.2 → systemlink_cli-1.9.3}/slcli/webapp_click.py +107 -38
  5. {systemlink_cli-1.9.2 → systemlink_cli-1.9.3}/LICENSE +0 -0
  6. {systemlink_cli-1.9.2 → systemlink_cli-1.9.3}/dff-editor/editor.js +0 -0
  7. {systemlink_cli-1.9.2 → systemlink_cli-1.9.3}/dff-editor/index.html +0 -0
  8. {systemlink_cli-1.9.2 → systemlink_cli-1.9.3}/slcli/__init__.py +0 -0
  9. {systemlink_cli-1.9.2 → systemlink_cli-1.9.3}/slcli/__main__.py +0 -0
  10. {systemlink_cli-1.9.2 → systemlink_cli-1.9.3}/slcli/asset_click.py +0 -0
  11. {systemlink_cli-1.9.2 → systemlink_cli-1.9.3}/slcli/cli_formatters.py +0 -0
  12. {systemlink_cli-1.9.2 → systemlink_cli-1.9.3}/slcli/cli_utils.py +0 -0
  13. {systemlink_cli-1.9.2 → systemlink_cli-1.9.3}/slcli/comment_click.py +0 -0
  14. {systemlink_cli-1.9.2 → systemlink_cli-1.9.3}/slcli/completion_click.py +0 -0
  15. {systemlink_cli-1.9.2 → systemlink_cli-1.9.3}/slcli/config.py +0 -0
  16. {systemlink_cli-1.9.2 → systemlink_cli-1.9.3}/slcli/config_click.py +0 -0
  17. {systemlink_cli-1.9.2 → systemlink_cli-1.9.3}/slcli/dff_click.py +0 -0
  18. {systemlink_cli-1.9.2 → systemlink_cli-1.9.3}/slcli/dff_decorators.py +0 -0
  19. {systemlink_cli-1.9.2 → systemlink_cli-1.9.3}/slcli/example_click.py +0 -0
  20. {systemlink_cli-1.9.2 → systemlink_cli-1.9.3}/slcli/example_loader.py +0 -0
  21. {systemlink_cli-1.9.2 → systemlink_cli-1.9.3}/slcli/example_provisioner.py +0 -0
  22. {systemlink_cli-1.9.2 → systemlink_cli-1.9.3}/slcli/examples/README.md +0 -0
  23. {systemlink_cli-1.9.2 → systemlink_cli-1.9.3}/slcli/examples/_schema/schema-v1.0.json +0 -0
  24. {systemlink_cli-1.9.2 → systemlink_cli-1.9.3}/slcli/examples/demo-complete-workflow/README.md +0 -0
  25. {systemlink_cli-1.9.2 → systemlink_cli-1.9.3}/slcli/examples/demo-complete-workflow/config.yaml +0 -0
  26. {systemlink_cli-1.9.2 → systemlink_cli-1.9.3}/slcli/examples/demo-test-plans/README.md +0 -0
  27. {systemlink_cli-1.9.2 → systemlink_cli-1.9.3}/slcli/examples/demo-test-plans/config.yaml +0 -0
  28. {systemlink_cli-1.9.2 → systemlink_cli-1.9.3}/slcli/examples/exercise-5-1-parametric-insights/README.md +0 -0
  29. {systemlink_cli-1.9.2 → systemlink_cli-1.9.3}/slcli/examples/exercise-5-1-parametric-insights/config.yaml +0 -0
  30. {systemlink_cli-1.9.2 → systemlink_cli-1.9.3}/slcli/examples/exercise-7-1-test-plans/README.md +0 -0
  31. {systemlink_cli-1.9.2 → systemlink_cli-1.9.3}/slcli/examples/exercise-7-1-test-plans/config.yaml +0 -0
  32. {systemlink_cli-1.9.2 → systemlink_cli-1.9.3}/slcli/examples/spec-compliance-notebooks/README.md +0 -0
  33. {systemlink_cli-1.9.2 → systemlink_cli-1.9.3}/slcli/examples/spec-compliance-notebooks/config.yaml +0 -0
  34. {systemlink_cli-1.9.2 → systemlink_cli-1.9.3}/slcli/examples/spec-compliance-notebooks/notebooks/SpecAnalysis_ComplianceCalculation.ipynb +0 -0
  35. {systemlink_cli-1.9.2 → systemlink_cli-1.9.3}/slcli/examples/spec-compliance-notebooks/notebooks/SpecComplianceCalculation.ipynb +0 -0
  36. {systemlink_cli-1.9.2 → systemlink_cli-1.9.3}/slcli/examples/spec-compliance-notebooks/notebooks/SpecfileExtractionAndIngestion.ipynb +0 -0
  37. {systemlink_cli-1.9.2 → systemlink_cli-1.9.3}/slcli/examples/spec-compliance-notebooks/spec_template.xlsx +0 -0
  38. {systemlink_cli-1.9.2 → systemlink_cli-1.9.3}/slcli/feed_click.py +0 -0
  39. {systemlink_cli-1.9.2 → systemlink_cli-1.9.3}/slcli/file_click.py +0 -0
  40. {systemlink_cli-1.9.2 → systemlink_cli-1.9.3}/slcli/function_click.py +0 -0
  41. {systemlink_cli-1.9.2 → systemlink_cli-1.9.3}/slcli/function_templates.py +0 -0
  42. {systemlink_cli-1.9.2 → systemlink_cli-1.9.3}/slcli/main.py +0 -0
  43. {systemlink_cli-1.9.2 → systemlink_cli-1.9.3}/slcli/mcp_click.py +0 -0
  44. {systemlink_cli-1.9.2 → systemlink_cli-1.9.3}/slcli/mcp_server.py +0 -0
  45. {systemlink_cli-1.9.2 → systemlink_cli-1.9.3}/slcli/notebook_click.py +0 -0
  46. {systemlink_cli-1.9.2 → systemlink_cli-1.9.3}/slcli/platform.py +0 -0
  47. {systemlink_cli-1.9.2 → systemlink_cli-1.9.3}/slcli/policy_click.py +0 -0
  48. {systemlink_cli-1.9.2 → systemlink_cli-1.9.3}/slcli/policy_utils.py +0 -0
  49. {systemlink_cli-1.9.2 → systemlink_cli-1.9.3}/slcli/profiles.py +0 -0
  50. {systemlink_cli-1.9.2 → systemlink_cli-1.9.3}/slcli/response_handlers.py +0 -0
  51. {systemlink_cli-1.9.2 → systemlink_cli-1.9.3}/slcli/rich_output.py +0 -0
  52. {systemlink_cli-1.9.2 → systemlink_cli-1.9.3}/slcli/routine_click.py +0 -0
  53. {systemlink_cli-1.9.2 → systemlink_cli-1.9.3}/slcli/skill_click.py +0 -0
  54. {systemlink_cli-1.9.2 → systemlink_cli-1.9.3}/slcli/skills/slcli/SKILL.md +0 -0
  55. {systemlink_cli-1.9.2 → systemlink_cli-1.9.3}/slcli/skills/slcli/references/analysis-recipes.md +0 -0
  56. {systemlink_cli-1.9.2 → systemlink_cli-1.9.3}/slcli/skills/slcli/references/filtering.md +0 -0
  57. {systemlink_cli-1.9.2 → systemlink_cli-1.9.3}/slcli/skills/systemlink-notebook/SKILL.md +0 -0
  58. {systemlink_cli-1.9.2 → systemlink_cli-1.9.3}/slcli/skills/systemlink-notebook/references/interfaces.md +0 -0
  59. {systemlink_cli-1.9.2 → systemlink_cli-1.9.3}/slcli/skills/systemlink-notebook/references/notebook-patterns.md +0 -0
  60. {systemlink_cli-1.9.2 → systemlink_cli-1.9.3}/slcli/skills/systemlink-webapp/SKILL.md +0 -0
  61. {systemlink_cli-1.9.2 → systemlink_cli-1.9.3}/slcli/skills/systemlink-webapp/references/deployment.md +0 -0
  62. {systemlink_cli-1.9.2 → systemlink_cli-1.9.3}/slcli/skills/systemlink-webapp/references/layout-patterns.md +0 -0
  63. {systemlink_cli-1.9.2 → systemlink_cli-1.9.3}/slcli/skills/systemlink-webapp/references/nimble-angular.md +0 -0
  64. {systemlink_cli-1.9.2 → systemlink_cli-1.9.3}/slcli/skills/systemlink-webapp/references/systemlink-services.md +0 -0
  65. {systemlink_cli-1.9.2 → systemlink_cli-1.9.3}/slcli/ssl_trust.py +0 -0
  66. {systemlink_cli-1.9.2 → systemlink_cli-1.9.3}/slcli/system_click.py +0 -0
  67. {systemlink_cli-1.9.2 → systemlink_cli-1.9.3}/slcli/table_utils.py +0 -0
  68. {systemlink_cli-1.9.2 → systemlink_cli-1.9.3}/slcli/tag_click.py +0 -0
  69. {systemlink_cli-1.9.2 → systemlink_cli-1.9.3}/slcli/templates_click.py +0 -0
  70. {systemlink_cli-1.9.2 → systemlink_cli-1.9.3}/slcli/testmonitor_click.py +0 -0
  71. {systemlink_cli-1.9.2 → systemlink_cli-1.9.3}/slcli/universal_handlers.py +0 -0
  72. {systemlink_cli-1.9.2 → systemlink_cli-1.9.3}/slcli/user_click.py +0 -0
  73. {systemlink_cli-1.9.2 → systemlink_cli-1.9.3}/slcli/utils.py +0 -0
  74. {systemlink_cli-1.9.2 → systemlink_cli-1.9.3}/slcli/web_editor.py +0 -0
  75. {systemlink_cli-1.9.2 → systemlink_cli-1.9.3}/slcli/workflow_preview.py +0 -0
  76. {systemlink_cli-1.9.2 → systemlink_cli-1.9.3}/slcli/workflows_click.py +0 -0
  77. {systemlink_cli-1.9.2 → systemlink_cli-1.9.3}/slcli/workitem_click.py +0 -0
  78. {systemlink_cli-1.9.2 → systemlink_cli-1.9.3}/slcli/workspace_click.py +0 -0
  79. {systemlink_cli-1.9.2 → systemlink_cli-1.9.3}/slcli/workspace_utils.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: systemlink-cli
3
- Version: 1.9.2
3
+ Version: 1.9.3
4
4
  Summary: SystemLink Integrator CLI - cross-platform CLI for SystemLink workflows and templates.
5
5
  License-File: LICENSE
6
6
  Author: Fred Visser
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "systemlink-cli"
3
- version = "1.9.2"
3
+ version = "1.9.3"
4
4
  description = "SystemLink Integrator CLI - cross-platform CLI for SystemLink workflows and templates."
5
5
  authors = ["Fred Visser <fred.visser@emerson.com>"]
6
6
  packages = [{ include = "slcli" }]
@@ -1,4 +1,4 @@
1
1
  """Version information for slcli."""
2
2
 
3
3
  # This file is auto-generated. Do not edit manually.
4
- __version__ = "1.9.2"
4
+ __version__ = "1.9.3"
@@ -85,6 +85,70 @@ def _get_webapp_base_url() -> str:
85
85
  return f"{get_base_url()}/niapp/v1"
86
86
 
87
87
 
88
+ def _build_published_webapp_url(
89
+ webapp_id: str,
90
+ webapp_name: str = "",
91
+ workspace_id: str = "",
92
+ workspace_name_hint: str = "",
93
+ properties: Optional[Dict[str, Any]] = None,
94
+ ) -> str:
95
+ """Return the best available published URL for a webapp.
96
+
97
+ Prefers the friendly SystemLink web UI URL and falls back to any explicit
98
+ URL-like property returned by the service, then the raw content endpoint.
99
+ """
100
+ from urllib.parse import quote
101
+
102
+ resolved_name = webapp_name
103
+ resolved_workspace_id = workspace_id
104
+ resolved_properties = properties or {}
105
+
106
+ if webapp_id and (not resolved_name or not resolved_workspace_id):
107
+ try:
108
+ resp = requests.get(
109
+ f"{_get_webapp_base_url()}/webapps/{webapp_id}",
110
+ headers=get_headers("application/json"),
111
+ verify=get_ssl_verify(),
112
+ )
113
+ resp.raise_for_status()
114
+ data = resp.json()
115
+ resolved_name = resolved_name or str(data.get("name", ""))
116
+ resolved_workspace_id = resolved_workspace_id or str(data.get("workspace", ""))
117
+ maybe_properties = data.get("properties", {})
118
+ if not resolved_properties and isinstance(maybe_properties, dict):
119
+ resolved_properties = maybe_properties
120
+ except Exception:
121
+ pass
122
+
123
+ workspace_name = workspace_name_hint.strip()
124
+ if resolved_workspace_id:
125
+ try:
126
+ workspace_map = get_workspace_map()
127
+ except Exception:
128
+ workspace_map = {}
129
+
130
+ mapped_workspace_name = str(workspace_map.get(resolved_workspace_id, "") or "").strip()
131
+ if mapped_workspace_name:
132
+ workspace_name = mapped_workspace_name
133
+
134
+ if resolved_name and workspace_name:
135
+ web_base = get_web_url().rstrip("/")
136
+ return f"{web_base}/webapps/app/{quote(workspace_name)}/{quote(resolved_name)}"
137
+
138
+ fallback_url = (
139
+ resolved_properties.get("embedLocation")
140
+ or resolved_properties.get("url")
141
+ or resolved_properties.get("interface")
142
+ )
143
+ if fallback_url:
144
+ return str(fallback_url)
145
+
146
+ if webapp_id:
147
+ return f"{_get_webapp_base_url()}/webapps/{webapp_id}/content"
148
+
149
+ return ""
150
+
151
+
88
152
  def _query_webapps_http(filter_str: str, max_items: int = 1000) -> List[Dict[str, Any]]:
89
153
  """Query webapps using continuation token pagination.
90
154
 
@@ -1343,7 +1407,6 @@ def register_webapp_commands(cli: Any) -> None:
1343
1407
  def open_webapp(webapp_id: str) -> None:
1344
1408
  """Open a webapp in the browser."""
1345
1409
  import webbrowser
1346
- from urllib.parse import quote
1347
1410
 
1348
1411
  try:
1349
1412
  base = _get_webapp_base_url()
@@ -1354,44 +1417,16 @@ def register_webapp_commands(cli: Any) -> None:
1354
1417
  )
1355
1418
  resp.raise_for_status()
1356
1419
  data = resp.json()
1357
- # Try to construct the public webapps URL which looks like:
1358
- # https://<host>/webapps/app/<WorkspaceName>/<Name>
1359
- name = data.get("name")
1360
- workspace_id = data.get("workspace")
1361
-
1362
- # Resolve workspace display name
1363
- try:
1364
- workspace_map = get_workspace_map()
1365
- except Exception:
1366
- workspace_map = {}
1367
-
1368
- workspace_name = get_workspace_display_name(workspace_id or "", workspace_map)
1369
-
1370
- # If we have both a workspace name and webapp name, build the friendly URL
1371
- if workspace_name and name:
1372
- # Prefer explicit web UI URL, otherwise derive from API URL
1373
- web_base = get_web_url()
1374
- # Ensure no trailing slash on base
1375
- web_base = web_base.rstrip("/")
1376
-
1377
- app_path = f"/webapps/app/{quote(workspace_name)}/{quote(name)}"
1378
- app_url = f"{web_base}{app_path}"
1420
+ app_url = _build_published_webapp_url(
1421
+ webapp_id,
1422
+ webapp_name=str(data.get("name", "")),
1423
+ workspace_id=str(data.get("workspace", "")),
1424
+ properties=data.get("properties", {}),
1425
+ )
1426
+ if app_url:
1379
1427
  webbrowser.open(app_url)
1380
1428
  click.echo(f"✓ Opening: {app_url}")
1381
1429
  return
1382
-
1383
- # Fallback: try any embed/url/interface property
1384
- props = data.get("properties", {}) or {}
1385
- url = props.get("embedLocation") or props.get("url") or props.get("interface")
1386
- if url:
1387
- webbrowser.open(url)
1388
- click.echo(f"✓ Opening: {url}")
1389
- return
1390
-
1391
- # Last-resort fallback: open content endpoint (may require auth)
1392
- content_url = f"{base}/webapps/{webapp_id}/content"
1393
- webbrowser.open(content_url)
1394
- click.echo("✓ Opening content endpoint (may require authentication in browser)")
1395
1430
  except Exception as exc:
1396
1431
  handle_api_error(exc)
1397
1432
 
@@ -1444,6 +1479,7 @@ def register_webapp_commands(cli: Any) -> None:
1444
1479
  suggested = tmp_dir / (sanitize_filename(source.name) + ".nipkg")
1445
1480
  packaged = _pack_folder_to_nipkg(source, suggested)
1446
1481
  tmp_file = packaged
1482
+ created_workspace_id = ""
1447
1483
 
1448
1484
  # If no webapp id provided create webapp metadata using name
1449
1485
  base = _get_webapp_base_url()
@@ -1454,6 +1490,7 @@ def register_webapp_commands(cli: Any) -> None:
1454
1490
  ws_id = get_workspace_id_with_fallback(
1455
1491
  get_effective_workspace(workspace) or workspace
1456
1492
  )
1493
+ created_workspace_id = ws_id
1457
1494
  payload = {
1458
1495
  "name": name,
1459
1496
  "type": "WebVI",
@@ -1485,9 +1522,24 @@ def register_webapp_commands(cli: Any) -> None:
1485
1522
  url, headers=upload_headers, data=data, verify=get_ssl_verify()
1486
1523
  )
1487
1524
  if resp.status_code in (200, 201, 204):
1525
+ workspace_name_hint = (
1526
+ get_effective_workspace(workspace) or workspace
1527
+ if created_workspace_id
1528
+ else ""
1529
+ )
1530
+ published_url = _build_published_webapp_url(
1531
+ webapp_id,
1532
+ webapp_name=name,
1533
+ workspace_id=created_workspace_id,
1534
+ workspace_name_hint=workspace_name_hint,
1535
+ )
1488
1536
  format_success(
1489
1537
  "Published webapp content",
1490
- {"Webapp ID": webapp_id, "Source": str(packaged)},
1538
+ {
1539
+ "Webapp ID": webapp_id,
1540
+ "Source": str(packaged),
1541
+ "Published URL": published_url,
1542
+ },
1491
1543
  )
1492
1544
  else:
1493
1545
  # Try to show body message
@@ -1499,6 +1551,7 @@ def register_webapp_commands(cli: Any) -> None:
1499
1551
  sys.exit(ExitCodes.GENERAL_ERROR)
1500
1552
  else:
1501
1553
  packaged = source
1554
+ created_workspace_id = ""
1502
1555
 
1503
1556
  # If no webapp id provided create webapp metadata using name
1504
1557
  base = _get_webapp_base_url()
@@ -1509,6 +1562,7 @@ def register_webapp_commands(cli: Any) -> None:
1509
1562
  ws_id = get_workspace_id_with_fallback(
1510
1563
  get_effective_workspace(workspace) or workspace
1511
1564
  )
1565
+ created_workspace_id = ws_id
1512
1566
  payload = {
1513
1567
  "name": name,
1514
1568
  "type": "WebVI",
@@ -1538,9 +1592,24 @@ def register_webapp_commands(cli: Any) -> None:
1538
1592
  url = f"{base}/webapps/{webapp_id}/content"
1539
1593
  resp = requests.put(url, headers=upload_headers, data=data, verify=get_ssl_verify())
1540
1594
  if resp.status_code in (200, 201, 204):
1595
+ workspace_name_hint = (
1596
+ (get_effective_workspace(workspace) or workspace)
1597
+ if created_workspace_id
1598
+ else ""
1599
+ )
1600
+ published_url = _build_published_webapp_url(
1601
+ webapp_id,
1602
+ webapp_name=name,
1603
+ workspace_id=created_workspace_id,
1604
+ workspace_name_hint=workspace_name_hint,
1605
+ )
1541
1606
  format_success(
1542
1607
  "Published webapp content",
1543
- {"Webapp ID": webapp_id, "Source": str(packaged)},
1608
+ {
1609
+ "Webapp ID": webapp_id,
1610
+ "Source": str(packaged),
1611
+ "Published URL": published_url,
1612
+ },
1544
1613
  )
1545
1614
  else:
1546
1615
  # Try to show body message
File without changes