systemlink-cli 1.7.0__tar.gz → 1.8.0__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.
- {systemlink_cli-1.7.0 → systemlink_cli-1.8.0}/PKG-INFO +1 -1
- {systemlink_cli-1.7.0 → systemlink_cli-1.8.0}/pyproject.toml +1 -1
- {systemlink_cli-1.7.0 → systemlink_cli-1.8.0}/slcli/_version.py +1 -1
- {systemlink_cli-1.7.0 → systemlink_cli-1.8.0}/slcli/skill_click.py +3 -3
- {systemlink_cli-1.7.0 → systemlink_cli-1.8.0}/slcli/skills/slcli/SKILL.md +1 -1
- systemlink_cli-1.8.0/slcli/skills/systemlink-notebook/SKILL.md +310 -0
- systemlink_cli-1.8.0/slcli/skills/systemlink-notebook/references/interfaces.md +82 -0
- systemlink_cli-1.8.0/slcli/skills/systemlink-notebook/references/notebook-patterns.md +252 -0
- {systemlink_cli-1.7.0 → systemlink_cli-1.8.0}/LICENSE +0 -0
- {systemlink_cli-1.7.0 → systemlink_cli-1.8.0}/dff-editor/editor.js +0 -0
- {systemlink_cli-1.7.0 → systemlink_cli-1.8.0}/dff-editor/index.html +0 -0
- {systemlink_cli-1.7.0 → systemlink_cli-1.8.0}/slcli/__init__.py +0 -0
- {systemlink_cli-1.7.0 → systemlink_cli-1.8.0}/slcli/__main__.py +0 -0
- {systemlink_cli-1.7.0 → systemlink_cli-1.8.0}/slcli/asset_click.py +0 -0
- {systemlink_cli-1.7.0 → systemlink_cli-1.8.0}/slcli/cli_formatters.py +0 -0
- {systemlink_cli-1.7.0 → systemlink_cli-1.8.0}/slcli/cli_utils.py +0 -0
- {systemlink_cli-1.7.0 → systemlink_cli-1.8.0}/slcli/comment_click.py +0 -0
- {systemlink_cli-1.7.0 → systemlink_cli-1.8.0}/slcli/completion_click.py +0 -0
- {systemlink_cli-1.7.0 → systemlink_cli-1.8.0}/slcli/config.py +0 -0
- {systemlink_cli-1.7.0 → systemlink_cli-1.8.0}/slcli/config_click.py +0 -0
- {systemlink_cli-1.7.0 → systemlink_cli-1.8.0}/slcli/dff_click.py +0 -0
- {systemlink_cli-1.7.0 → systemlink_cli-1.8.0}/slcli/dff_decorators.py +0 -0
- {systemlink_cli-1.7.0 → systemlink_cli-1.8.0}/slcli/example_click.py +0 -0
- {systemlink_cli-1.7.0 → systemlink_cli-1.8.0}/slcli/example_loader.py +0 -0
- {systemlink_cli-1.7.0 → systemlink_cli-1.8.0}/slcli/example_provisioner.py +0 -0
- {systemlink_cli-1.7.0 → systemlink_cli-1.8.0}/slcli/examples/README.md +0 -0
- {systemlink_cli-1.7.0 → systemlink_cli-1.8.0}/slcli/examples/_schema/schema-v1.0.json +0 -0
- {systemlink_cli-1.7.0 → systemlink_cli-1.8.0}/slcli/examples/demo-complete-workflow/README.md +0 -0
- {systemlink_cli-1.7.0 → systemlink_cli-1.8.0}/slcli/examples/demo-complete-workflow/config.yaml +0 -0
- {systemlink_cli-1.7.0 → systemlink_cli-1.8.0}/slcli/examples/demo-test-plans/README.md +0 -0
- {systemlink_cli-1.7.0 → systemlink_cli-1.8.0}/slcli/examples/demo-test-plans/config.yaml +0 -0
- {systemlink_cli-1.7.0 → systemlink_cli-1.8.0}/slcli/examples/exercise-5-1-parametric-insights/README.md +0 -0
- {systemlink_cli-1.7.0 → systemlink_cli-1.8.0}/slcli/examples/exercise-5-1-parametric-insights/config.yaml +0 -0
- {systemlink_cli-1.7.0 → systemlink_cli-1.8.0}/slcli/examples/exercise-7-1-test-plans/README.md +0 -0
- {systemlink_cli-1.7.0 → systemlink_cli-1.8.0}/slcli/examples/exercise-7-1-test-plans/config.yaml +0 -0
- {systemlink_cli-1.7.0 → systemlink_cli-1.8.0}/slcli/examples/spec-compliance-notebooks/README.md +0 -0
- {systemlink_cli-1.7.0 → systemlink_cli-1.8.0}/slcli/examples/spec-compliance-notebooks/config.yaml +0 -0
- {systemlink_cli-1.7.0 → systemlink_cli-1.8.0}/slcli/examples/spec-compliance-notebooks/notebooks/SpecAnalysis_ComplianceCalculation.ipynb +0 -0
- {systemlink_cli-1.7.0 → systemlink_cli-1.8.0}/slcli/examples/spec-compliance-notebooks/notebooks/SpecComplianceCalculation.ipynb +0 -0
- {systemlink_cli-1.7.0 → systemlink_cli-1.8.0}/slcli/examples/spec-compliance-notebooks/notebooks/SpecfileExtractionAndIngestion.ipynb +0 -0
- {systemlink_cli-1.7.0 → systemlink_cli-1.8.0}/slcli/examples/spec-compliance-notebooks/spec_template.xlsx +0 -0
- {systemlink_cli-1.7.0 → systemlink_cli-1.8.0}/slcli/feed_click.py +0 -0
- {systemlink_cli-1.7.0 → systemlink_cli-1.8.0}/slcli/file_click.py +0 -0
- {systemlink_cli-1.7.0 → systemlink_cli-1.8.0}/slcli/function_click.py +0 -0
- {systemlink_cli-1.7.0 → systemlink_cli-1.8.0}/slcli/function_templates.py +0 -0
- {systemlink_cli-1.7.0 → systemlink_cli-1.8.0}/slcli/main.py +0 -0
- {systemlink_cli-1.7.0 → systemlink_cli-1.8.0}/slcli/mcp_click.py +0 -0
- {systemlink_cli-1.7.0 → systemlink_cli-1.8.0}/slcli/mcp_server.py +0 -0
- {systemlink_cli-1.7.0 → systemlink_cli-1.8.0}/slcli/notebook_click.py +0 -0
- {systemlink_cli-1.7.0 → systemlink_cli-1.8.0}/slcli/platform.py +0 -0
- {systemlink_cli-1.7.0 → systemlink_cli-1.8.0}/slcli/policy_click.py +0 -0
- {systemlink_cli-1.7.0 → systemlink_cli-1.8.0}/slcli/policy_utils.py +0 -0
- {systemlink_cli-1.7.0 → systemlink_cli-1.8.0}/slcli/profiles.py +0 -0
- {systemlink_cli-1.7.0 → systemlink_cli-1.8.0}/slcli/response_handlers.py +0 -0
- {systemlink_cli-1.7.0 → systemlink_cli-1.8.0}/slcli/rich_output.py +0 -0
- {systemlink_cli-1.7.0 → systemlink_cli-1.8.0}/slcli/routine_click.py +0 -0
- {systemlink_cli-1.7.0 → systemlink_cli-1.8.0}/slcli/skills/slcli/references/analysis-recipes.md +0 -0
- {systemlink_cli-1.7.0 → systemlink_cli-1.8.0}/slcli/skills/slcli/references/filtering.md +0 -0
- {systemlink_cli-1.7.0 → systemlink_cli-1.8.0}/slcli/skills/systemlink-webapp/SKILL.md +0 -0
- {systemlink_cli-1.7.0 → systemlink_cli-1.8.0}/slcli/skills/systemlink-webapp/references/deployment.md +0 -0
- {systemlink_cli-1.7.0 → systemlink_cli-1.8.0}/slcli/skills/systemlink-webapp/references/layout-patterns.md +0 -0
- {systemlink_cli-1.7.0 → systemlink_cli-1.8.0}/slcli/skills/systemlink-webapp/references/nimble-angular.md +0 -0
- {systemlink_cli-1.7.0 → systemlink_cli-1.8.0}/slcli/skills/systemlink-webapp/references/systemlink-services.md +0 -0
- {systemlink_cli-1.7.0 → systemlink_cli-1.8.0}/slcli/ssl_trust.py +0 -0
- {systemlink_cli-1.7.0 → systemlink_cli-1.8.0}/slcli/system_click.py +0 -0
- {systemlink_cli-1.7.0 → systemlink_cli-1.8.0}/slcli/table_utils.py +0 -0
- {systemlink_cli-1.7.0 → systemlink_cli-1.8.0}/slcli/tag_click.py +0 -0
- {systemlink_cli-1.7.0 → systemlink_cli-1.8.0}/slcli/templates_click.py +0 -0
- {systemlink_cli-1.7.0 → systemlink_cli-1.8.0}/slcli/testmonitor_click.py +0 -0
- {systemlink_cli-1.7.0 → systemlink_cli-1.8.0}/slcli/universal_handlers.py +0 -0
- {systemlink_cli-1.7.0 → systemlink_cli-1.8.0}/slcli/user_click.py +0 -0
- {systemlink_cli-1.7.0 → systemlink_cli-1.8.0}/slcli/utils.py +0 -0
- {systemlink_cli-1.7.0 → systemlink_cli-1.8.0}/slcli/web_editor.py +0 -0
- {systemlink_cli-1.7.0 → systemlink_cli-1.8.0}/slcli/webapp_click.py +0 -0
- {systemlink_cli-1.7.0 → systemlink_cli-1.8.0}/slcli/workflow_preview.py +0 -0
- {systemlink_cli-1.7.0 → systemlink_cli-1.8.0}/slcli/workflows_click.py +0 -0
- {systemlink_cli-1.7.0 → systemlink_cli-1.8.0}/slcli/workitem_click.py +0 -0
- {systemlink_cli-1.7.0 → systemlink_cli-1.8.0}/slcli/workspace_click.py +0 -0
- {systemlink_cli-1.7.0 → systemlink_cli-1.8.0}/slcli/workspace_utils.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[tool.poetry]
|
|
2
2
|
name = "systemlink-cli"
|
|
3
|
-
version = "1.
|
|
3
|
+
version = "1.8.0"
|
|
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" }]
|
|
@@ -11,7 +11,7 @@ import questionary
|
|
|
11
11
|
from .utils import ExitCodes
|
|
12
12
|
|
|
13
13
|
SKILL_NAME = "slcli"
|
|
14
|
-
SKILL_CHOICES = ["slcli", "systemlink-webapp"]
|
|
14
|
+
SKILL_CHOICES = ["slcli", "systemlink-webapp", "systemlink-notebook"]
|
|
15
15
|
|
|
16
16
|
# Mapping of client name -> (personal skills dir, project subdir relative to repo root)
|
|
17
17
|
# personal dir uses Path.home() so it's always resolved at call time via _personal_dir().
|
|
@@ -178,7 +178,7 @@ def register_skill_commands(cli: Any) -> None:
|
|
|
178
178
|
"-k",
|
|
179
179
|
type=click.Choice(SKILL_CHOICES + ["all"], case_sensitive=False),
|
|
180
180
|
default=None,
|
|
181
|
-
help="Skill to install (slcli, systemlink-webapp, or all).",
|
|
181
|
+
help="Skill to install (slcli, systemlink-webapp, systemlink-notebook, or all).",
|
|
182
182
|
)
|
|
183
183
|
@click.option(
|
|
184
184
|
"--client",
|
|
@@ -207,7 +207,7 @@ def register_skill_commands(cli: Any) -> None:
|
|
|
207
207
|
"""Install agent skills for AI coding assistants.
|
|
208
208
|
|
|
209
209
|
Copies bundled skills into the skills directory of one or more AI clients.
|
|
210
|
-
Available skills: slcli, systemlink-webapp.
|
|
210
|
+
Available skills: slcli, systemlink-webapp, systemlink-notebook.
|
|
211
211
|
Supported clients and their skill locations:
|
|
212
212
|
|
|
213
213
|
\b
|
|
@@ -703,7 +703,7 @@ generated `.nipkg`, and emits a thin `manifest.json` with `schemaVersion`, `nipk
|
|
|
703
703
|
Install bundled skills for supported AI clients.
|
|
704
704
|
|
|
705
705
|
```bash
|
|
706
|
-
slcli skill install --skill [slcli|systemlink-webapp|all] --client [agents|claude|all] --scope [personal|project|both]
|
|
706
|
+
slcli skill install --skill [slcli|systemlink-webapp|systemlink-notebook|all] --client [agents|claude|all] --scope [personal|project|both]
|
|
707
707
|
```
|
|
708
708
|
|
|
709
709
|
Client paths:
|
|
@@ -0,0 +1,310 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: systemlink-notebook
|
|
3
|
+
description: >-
|
|
4
|
+
Create, structure, and deploy Jupyter Notebooks for NI SystemLink.
|
|
5
|
+
Use when the user asks to create a notebook, report, or analysis that runs on
|
|
6
|
+
SystemLink — including Systems Grid reports, test data analysis notebooks,
|
|
7
|
+
asset reports, scheduled notebooks, or any notebook that uses scrapbook (sb.glue)
|
|
8
|
+
to return results. Covers parameter cells, systemlink metadata, output formats,
|
|
9
|
+
papermill integration, and deployment via slcli.
|
|
10
|
+
argument-hint: 'Describe the notebook purpose and what data it should report on'
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
# SystemLink Notebook Creation
|
|
14
|
+
|
|
15
|
+
## When to Use
|
|
16
|
+
|
|
17
|
+
- Creating a new Jupyter Notebook that will run on SystemLink
|
|
18
|
+
- Adding parameters or outputs to a notebook for the SystemLink Notebook Execution Service
|
|
19
|
+
- Building a Systems Grid column report
|
|
20
|
+
- Creating a test data analysis notebook
|
|
21
|
+
- Deploying a notebook to SystemLink via `slcli`
|
|
22
|
+
|
|
23
|
+
## Notebook Structure
|
|
24
|
+
|
|
25
|
+
Every SystemLink notebook follows this cell pattern:
|
|
26
|
+
|
|
27
|
+
1. **Imports (markdown)** — describe dependencies
|
|
28
|
+
2. **Imports (code)** — import modules
|
|
29
|
+
3. **Parameters (markdown)** — describe each parameter
|
|
30
|
+
4. **Parameters (code)** — declare parameter variables with defaults *(requires special metadata)*
|
|
31
|
+
5. **Logic (markdown + code)** — one or more pairs of markdown/code cells
|
|
32
|
+
6. **Output (markdown)** — describe the output format
|
|
33
|
+
7. **Output (code)** — format results and call `sb.glue('result', result)`
|
|
34
|
+
8. **Instructions (markdown)** — how to use the notebook in SystemLink UI
|
|
35
|
+
|
|
36
|
+
## Parameters Cell Metadata
|
|
37
|
+
|
|
38
|
+
The parameters cell is the most critical part. It **must** have this metadata structure
|
|
39
|
+
in the cell's `.metadata` field for SystemLink to recognize the parameters and outputs.
|
|
40
|
+
|
|
41
|
+
```json
|
|
42
|
+
{
|
|
43
|
+
"papermill": {
|
|
44
|
+
"parameters": {
|
|
45
|
+
"param_name": "default_value"
|
|
46
|
+
}
|
|
47
|
+
},
|
|
48
|
+
"systemlink": {
|
|
49
|
+
"namespaces": [],
|
|
50
|
+
"outputs": [
|
|
51
|
+
{
|
|
52
|
+
"display_name": "Human Readable Output Name",
|
|
53
|
+
"id": "output_snake_case_id",
|
|
54
|
+
"type": "data_frame"
|
|
55
|
+
}
|
|
56
|
+
],
|
|
57
|
+
"parameters": [
|
|
58
|
+
{
|
|
59
|
+
"display_name": "Human Readable Param Name",
|
|
60
|
+
"id": "param_name",
|
|
61
|
+
"type": "string"
|
|
62
|
+
}
|
|
63
|
+
],
|
|
64
|
+
"version": 2
|
|
65
|
+
},
|
|
66
|
+
"tags": ["parameters"]
|
|
67
|
+
}
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
### Key rules for parameter metadata
|
|
71
|
+
|
|
72
|
+
- `papermill.parameters` keys **must** match the variable names in the code cell
|
|
73
|
+
- `systemlink.parameters[].id` **must** match the variable names in the code cell
|
|
74
|
+
- `systemlink.outputs[].id` **must** match the key used in the result dict passed to `sb.glue`
|
|
75
|
+
- `tags: ["parameters"]` is **required** — this is how papermill identifies the cell
|
|
76
|
+
- `systemlink.version` must be `2` for most notebooks, or `1` for **Work Item Automations**
|
|
77
|
+
- Supported parameter types: `string`, `integer`, `float`, `boolean`, `string[]`
|
|
78
|
+
- Supported output types: `data_frame`, `scalar`, `string`, `string[]`
|
|
79
|
+
|
|
80
|
+
### Work Item Automations pattern
|
|
81
|
+
|
|
82
|
+
Notebooks with the **Work Item Automations** interface receive work item IDs as a
|
|
83
|
+
**list** (`string[]`), not a comma-separated string. Key differences from other notebooks:
|
|
84
|
+
|
|
85
|
+
- `systemlink.version` must be `1`
|
|
86
|
+
- `work_item_ids` parameter type is `"string[]"` and its default value in
|
|
87
|
+
`papermill.parameters` is `[]` (empty list)
|
|
88
|
+
- The Python variable must also default to a list: `work_item_ids = []`
|
|
89
|
+
- Do NOT split by comma — the parameter is already a list of strings
|
|
90
|
+
|
|
91
|
+
Example parameters cell metadata for Work Item Automations:
|
|
92
|
+
```json
|
|
93
|
+
{
|
|
94
|
+
"papermill": {
|
|
95
|
+
"parameters": {
|
|
96
|
+
"work_item_ids": []
|
|
97
|
+
}
|
|
98
|
+
},
|
|
99
|
+
"systemlink": {
|
|
100
|
+
"outputs": [...],
|
|
101
|
+
"parameters": [
|
|
102
|
+
{
|
|
103
|
+
"display_name": "Work item IDs",
|
|
104
|
+
"id": "work_item_ids",
|
|
105
|
+
"type": "string[]"
|
|
106
|
+
}
|
|
107
|
+
],
|
|
108
|
+
"version": 1
|
|
109
|
+
},
|
|
110
|
+
"tags": ["parameters"]
|
|
111
|
+
}
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
## Output Format (sb.glue)
|
|
115
|
+
|
|
116
|
+
All notebooks must use `scrapbook` to return results. The output cell should:
|
|
117
|
+
|
|
118
|
+
```python
|
|
119
|
+
import scrapbook as sb
|
|
120
|
+
|
|
121
|
+
# For data_frame outputs:
|
|
122
|
+
result = [{
|
|
123
|
+
"display_name": "Human Readable Name",
|
|
124
|
+
"id": "output_id", # Must match systemlink.outputs[].id
|
|
125
|
+
"type": "data_frame",
|
|
126
|
+
"data": {
|
|
127
|
+
"columns": ["column1", "column2"],
|
|
128
|
+
"values": df.reset_index().values.tolist()
|
|
129
|
+
}
|
|
130
|
+
}]
|
|
131
|
+
sb.glue('result', result)
|
|
132
|
+
|
|
133
|
+
# For scalar outputs:
|
|
134
|
+
result = [{
|
|
135
|
+
"display_name": "Count",
|
|
136
|
+
"id": "count_output",
|
|
137
|
+
"type": "scalar",
|
|
138
|
+
"data": 42
|
|
139
|
+
}]
|
|
140
|
+
sb.glue('result', result)
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
### Systems Grid reports
|
|
144
|
+
|
|
145
|
+
When the notebook is used as a Systems Grid column, the `data_frame` output
|
|
146
|
+
**must** include `minion id` as the first column. This maps rows to systems.
|
|
147
|
+
|
|
148
|
+
```python
|
|
149
|
+
df_dict = {
|
|
150
|
+
'columns': ['minion id', 'your column name'],
|
|
151
|
+
'values': df.reset_index().values.tolist() # index = system IDs
|
|
152
|
+
}
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
## Common Imports
|
|
156
|
+
|
|
157
|
+
```python
|
|
158
|
+
# Always needed
|
|
159
|
+
import pandas as pd
|
|
160
|
+
import scrapbook as sb
|
|
161
|
+
|
|
162
|
+
# Systems queries
|
|
163
|
+
from systemlink.clients.nisysmgmt.api.systems_api import SystemsApi
|
|
164
|
+
from systemlink.clients.nisysmgmt.models.query_systems_request import QuerySystemsRequest
|
|
165
|
+
|
|
166
|
+
# Test results
|
|
167
|
+
from nisystemlink.clients.testmonitor import TestMonitorClient
|
|
168
|
+
from nisystemlink.clients.core import HttpConfigurationManager
|
|
169
|
+
|
|
170
|
+
# Assets
|
|
171
|
+
from nisystemlink.clients.assetmanagement import AssetManagementClient
|
|
172
|
+
|
|
173
|
+
# Direct HTTP (when no typed client exists)
|
|
174
|
+
import requests
|
|
175
|
+
from nisystemlink.clients.core import HttpConfigurationManager
|
|
176
|
+
config = HttpConfigurationManager.get_configuration()
|
|
177
|
+
base_url = config.server_uri.rstrip("/")
|
|
178
|
+
headers = {"x-ni-api-key": config.api_keys[0]}
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
## Systems Query Pattern
|
|
182
|
+
|
|
183
|
+
The `SystemsApi` uses a projection/filter pattern for querying:
|
|
184
|
+
|
|
185
|
+
```python
|
|
186
|
+
api = SystemsApi()
|
|
187
|
+
|
|
188
|
+
# Projection selects which fields to return
|
|
189
|
+
projection = 'new(id, alias, state, packages.data["ni-daqmx"].displayversion)'
|
|
190
|
+
|
|
191
|
+
# Filter selects which systems to include
|
|
192
|
+
filter = '!string.IsNullOrEmpty(id) && packages.data.keys.Contains("ni-daqmx")'
|
|
193
|
+
|
|
194
|
+
query = QuerySystemsRequest(skip=0, projection=projection, filter=filter)
|
|
195
|
+
query_result = api.get_systems_by_query(query=query)
|
|
196
|
+
data = await query_result
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
### Common filter expressions
|
|
200
|
+
|
|
201
|
+
| Filter | Description |
|
|
202
|
+
|--------|-------------|
|
|
203
|
+
| `!string.IsNullOrEmpty(id)` | All systems (default/fallback) |
|
|
204
|
+
| `connected.data.state == "CONNECTED"` | Connected systems only |
|
|
205
|
+
| `packages.data.keys.Contains("pkg")` | Systems with a specific package |
|
|
206
|
+
| `grains.data.kernel == "Windows"` | Windows systems |
|
|
207
|
+
|
|
208
|
+
## Notebook Interfaces
|
|
209
|
+
|
|
210
|
+
When deploying, set the notebook interface to tell SystemLink how it will be used.
|
|
211
|
+
See [interfaces reference](./references/interfaces.md) for the full list.
|
|
212
|
+
|
|
213
|
+
Common interfaces:
|
|
214
|
+
- **Systems Grid** — report that adds a column to the Systems management grid
|
|
215
|
+
- **Test Data Analysis** — analysis of test monitor results
|
|
216
|
+
- **Periodic Execution** — scheduled recurring notebook
|
|
217
|
+
- **Work Item Automations** — triggered by work item state changes
|
|
218
|
+
|
|
219
|
+
## Setting Cell Metadata
|
|
220
|
+
|
|
221
|
+
The VS Code notebook editor tools do **not** persist custom cell metadata (like
|
|
222
|
+
`papermill`, `systemlink`, `tags`). You must write cell metadata directly into
|
|
223
|
+
the `.ipynb` JSON file using a Python script:
|
|
224
|
+
|
|
225
|
+
```python
|
|
226
|
+
import json
|
|
227
|
+
|
|
228
|
+
with open('notebook.ipynb') as f:
|
|
229
|
+
nb = json.load(f)
|
|
230
|
+
|
|
231
|
+
# Find the parameters cell and set its metadata
|
|
232
|
+
for cell in nb['cells']:
|
|
233
|
+
src = ''.join(cell.get('source', []))
|
|
234
|
+
if 'parameters' in src and cell['cell_type'] == 'code':
|
|
235
|
+
cell['metadata'] = {
|
|
236
|
+
"papermill": {
|
|
237
|
+
"parameters": {
|
|
238
|
+
"param_name": "default_value"
|
|
239
|
+
}
|
|
240
|
+
},
|
|
241
|
+
"systemlink": {
|
|
242
|
+
"namespaces": [],
|
|
243
|
+
"outputs": [...],
|
|
244
|
+
"parameters": [...],
|
|
245
|
+
"version": 2
|
|
246
|
+
},
|
|
247
|
+
"tags": ["parameters"],
|
|
248
|
+
"trusted": False,
|
|
249
|
+
"editable": True,
|
|
250
|
+
"slideshow": {"slide_type": ""}
|
|
251
|
+
}
|
|
252
|
+
break
|
|
253
|
+
|
|
254
|
+
with open('notebook.ipynb', 'w') as f:
|
|
255
|
+
json.dump(nb, f, indent=1)
|
|
256
|
+
f.write('\n')
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
**Critical:** Without this metadata, SystemLink will not display parameters or
|
|
260
|
+
outputs in the UI. Always verify metadata was written by inspecting the raw JSON.
|
|
261
|
+
|
|
262
|
+
Also ensure the notebook-level `kernelspec` metadata is set. Papermill requires
|
|
263
|
+
this to execute the notebook — without it you get
|
|
264
|
+
`ValueError: No kernel name found in notebook`. The VS Code notebook editor may
|
|
265
|
+
clear this when editing cells. Always verify and restore if needed:
|
|
266
|
+
|
|
267
|
+
```python
|
|
268
|
+
nb['metadata']['kernelspec'] = {
|
|
269
|
+
'display_name': 'Python 3',
|
|
270
|
+
'language': 'python',
|
|
271
|
+
'name': 'python3'
|
|
272
|
+
}
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
## Deployment
|
|
276
|
+
|
|
277
|
+
Deploy via `slcli`. **Always read the user's configured workspace** from `slcli info`
|
|
278
|
+
and pass it with `--workspace` so the notebook lands in the correct workspace:
|
|
279
|
+
|
|
280
|
+
```bash
|
|
281
|
+
# 1. Read the configured workspace name from the active slcli profile
|
|
282
|
+
# (look for the "Workspace" row in `slcli info` output)
|
|
283
|
+
|
|
284
|
+
# Create a new notebook with interface and workspace set at creation time (preferred)
|
|
285
|
+
slcli notebook manage create --file notebook.ipynb --name "My Notebook" --interface "Systems Grid" --workspace "<WORKSPACE_NAME>"
|
|
286
|
+
|
|
287
|
+
# Update content of an existing notebook
|
|
288
|
+
slcli notebook manage update --id <NOTEBOOK_ID> --content notebook.ipynb
|
|
289
|
+
|
|
290
|
+
# Update interface or metadata in place when needed
|
|
291
|
+
slcli notebook manage update --id <NOTEBOOK_ID> --interface "Systems Grid"
|
|
292
|
+
|
|
293
|
+
# Delete and re-create only as a fallback if the server rejects the update
|
|
294
|
+
slcli notebook manage delete --id <NOTEBOOK_ID> --yes
|
|
295
|
+
slcli notebook manage create --file notebook.ipynb --name "My Notebook" --interface "Systems Grid" --workspace "<WORKSPACE_NAME>"
|
|
296
|
+
```
|
|
297
|
+
|
|
298
|
+
**Important:** Prefer setting `--interface` at creation time, but use
|
|
299
|
+
`slcli notebook manage update --interface ...` for in-place interface changes when
|
|
300
|
+
you are updating an existing notebook. Delete and re-create only as a fallback if
|
|
301
|
+
the server rejects the update.
|
|
302
|
+
|
|
303
|
+
**Important:** Always determine the target workspace by running `slcli info` and
|
|
304
|
+
reading the `Workspace` field from the active profile. Do not assume "Default" or
|
|
305
|
+
prompt the user unless `slcli info` shows no workspace configured.
|
|
306
|
+
|
|
307
|
+
## Example
|
|
308
|
+
|
|
309
|
+
See [notebook-patterns.md](./references/notebook-patterns.md) for a complete
|
|
310
|
+
annotated example based on the NI PackageVersionExample pattern.
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
# Notebook Interfaces
|
|
2
|
+
|
|
3
|
+
When deploying a notebook to SystemLink, you can assign an **interface** that tells
|
|
4
|
+
SystemLink how the notebook will be used. This affects how parameters are presented
|
|
5
|
+
and how the notebook is triggered.
|
|
6
|
+
|
|
7
|
+
Set the interface during creation or update:
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
slcli notebook manage update --id <ID> --interface "Systems Grid"
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
Prefer `create --interface ...` when you are creating a new notebook. Use
|
|
14
|
+
`update --interface ...` for in-place interface changes on an existing notebook.
|
|
15
|
+
Delete and re-create only if the server rejects the update.
|
|
16
|
+
|
|
17
|
+
## Available Interfaces
|
|
18
|
+
|
|
19
|
+
| Interface | Use Case |
|
|
20
|
+
| ---------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
21
|
+
| **Assets Grid** | Report that adds a column to the Assets management grid |
|
|
22
|
+
| **Data Table Analysis** | Analysis of data table contents |
|
|
23
|
+
| **Data Space Analysis** | Analysis of data space contents |
|
|
24
|
+
| **File Analysis** | Analysis of uploaded files |
|
|
25
|
+
| **Periodic Execution** | Scheduled recurring notebook (e.g. daily/hourly reports) |
|
|
26
|
+
| **Resource Changed Routine** | Triggered when a resource changes (via v1 routines) |
|
|
27
|
+
| **Specification Analysis** | Analysis against specifications/limits |
|
|
28
|
+
| **Systems Grid** | Report that adds a column to the Systems management grid |
|
|
29
|
+
| **Test Data Analysis** | Analysis of test monitor results |
|
|
30
|
+
| **Test Data Extraction** | Extract and transform test data |
|
|
31
|
+
| **Work Item Automations** | Notebooks that can be manually executed on selected work items, or triggered by work item lifecycle events. **Use this for any notebook that acts on work items** (e.g. close, update status, assign). |
|
|
32
|
+
| **Work Item Operations** | Internal operations performed on work items by the system |
|
|
33
|
+
| **Work Item Scheduler** | Scheduling logic for work items |
|
|
34
|
+
|
|
35
|
+
## Common Interface Patterns
|
|
36
|
+
|
|
37
|
+
### Systems Grid
|
|
38
|
+
|
|
39
|
+
Parameters typically include:
|
|
40
|
+
|
|
41
|
+
- `group_by` (string) — always support "System"
|
|
42
|
+
- `systems_filter` (string) — filter expression for which systems
|
|
43
|
+
- Domain-specific params (e.g. `package` for package version)
|
|
44
|
+
|
|
45
|
+
Output must be `data_frame` with `minion id` as the first column.
|
|
46
|
+
|
|
47
|
+
### Test Data Analysis
|
|
48
|
+
|
|
49
|
+
Parameters typically include:
|
|
50
|
+
|
|
51
|
+
- `group_by` (string)
|
|
52
|
+
- `program_name` (string)
|
|
53
|
+
- `status_filter` (string)
|
|
54
|
+
- `systems_filter` (string)
|
|
55
|
+
|
|
56
|
+
### Periodic Execution
|
|
57
|
+
|
|
58
|
+
No special parameter requirements. Typically uses fixed configuration
|
|
59
|
+
or reads from tags/files. Can be scheduled via routines:
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
slcli routine create --api-version v1 \
|
|
63
|
+
--name "Daily Report" \
|
|
64
|
+
--type SCHEDULED \
|
|
65
|
+
--notebook-id <NOTEBOOK_ID> \
|
|
66
|
+
--schedule '{"startTime":"2026-01-01T00:00:00Z","repeat":"DAY"}'
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
### Work Item Automations
|
|
70
|
+
|
|
71
|
+
Use this interface for notebooks that act on selected work items (close, update,
|
|
72
|
+
assign, etc.). The notebook appears in the work items UI and can be manually
|
|
73
|
+
triggered on one or more selected work items.
|
|
74
|
+
|
|
75
|
+
Parameters are injected by the work item system:
|
|
76
|
+
|
|
77
|
+
- `work_item_ids` (string[]) — list of selected work item IDs. Default: `[]`
|
|
78
|
+
- `workspace` (string) — workspace context (optional)
|
|
79
|
+
|
|
80
|
+
**Critical:** `work_item_ids` must be typed as `"string[]"` (not `"string"`),
|
|
81
|
+
default to `[]` in both papermill and the code cell, and `systemlink.version`
|
|
82
|
+
must be `1`. See the systemlink-notebook skill for the full metadata example.
|
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
# Notebook Patterns
|
|
2
|
+
|
|
3
|
+
Annotated examples of common SystemLink notebook patterns.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Pattern 1: Systems Grid Column Report
|
|
8
|
+
|
|
9
|
+
This is the most common pattern. The notebook queries system data and returns
|
|
10
|
+
a `data_frame` output that the Systems Grid can display as a column.
|
|
11
|
+
|
|
12
|
+
### Full annotated example (Package Version)
|
|
13
|
+
|
|
14
|
+
**Cell 1 — Imports description (markdown)**
|
|
15
|
+
```markdown
|
|
16
|
+
### Imports
|
|
17
|
+
Import Python modules for executing the notebook.
|
|
18
|
+
- Pandas is used for building and handling dataframes.
|
|
19
|
+
- Scrapbook is used for recording data for the Notebook Execution Service.
|
|
20
|
+
- SystemsApi is an NI provided package for communicating with the SystemLink Systems service.
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
**Cell 2 — Imports (code)**
|
|
24
|
+
```python
|
|
25
|
+
import pandas as pd
|
|
26
|
+
import scrapbook as sb
|
|
27
|
+
|
|
28
|
+
from systemlink.clients.nisysmgmt.api.systems_api import SystemsApi
|
|
29
|
+
from systemlink.clients.nisysmgmt.models.query_systems_request import QuerySystemsRequest
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
**Cell 3 — Parameters description (markdown)**
|
|
33
|
+
```markdown
|
|
34
|
+
### Parameters
|
|
35
|
+
- `group_by`: The property by which data is grouped. For the data to appear
|
|
36
|
+
as a column in the Systems Grid, we must support 'System' here.
|
|
37
|
+
- `package`: The Package Name of the software to display the version of.
|
|
38
|
+
- `systems_filter`: A filter specifying which systems to query.
|
|
39
|
+
An empty filter matches all systems.
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
**Cell 4 — Parameters (code, with metadata)**
|
|
43
|
+
|
|
44
|
+
The code cell declares variables with defaults:
|
|
45
|
+
```python
|
|
46
|
+
group_by = "System"
|
|
47
|
+
package = "ni-daqmx"
|
|
48
|
+
systems_filter = ""
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
The cell metadata must include:
|
|
52
|
+
```json
|
|
53
|
+
{
|
|
54
|
+
"papermill": {
|
|
55
|
+
"parameters": {
|
|
56
|
+
"group_by": "System",
|
|
57
|
+
"package": "ni-daqmx",
|
|
58
|
+
"systems_filter": ""
|
|
59
|
+
}
|
|
60
|
+
},
|
|
61
|
+
"systemlink": {
|
|
62
|
+
"namespaces": [],
|
|
63
|
+
"outputs": [
|
|
64
|
+
{
|
|
65
|
+
"display_name": "Package Version",
|
|
66
|
+
"id": "package_version",
|
|
67
|
+
"type": "data_frame"
|
|
68
|
+
}
|
|
69
|
+
],
|
|
70
|
+
"parameters": [
|
|
71
|
+
{
|
|
72
|
+
"display_name": "Group by",
|
|
73
|
+
"id": "group_by",
|
|
74
|
+
"type": "string"
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
"display_name": "Package",
|
|
78
|
+
"id": "package",
|
|
79
|
+
"type": "string"
|
|
80
|
+
},
|
|
81
|
+
{
|
|
82
|
+
"display_name": "Systems Filter",
|
|
83
|
+
"id": "systems_filter",
|
|
84
|
+
"type": "string"
|
|
85
|
+
}
|
|
86
|
+
],
|
|
87
|
+
"version": 2
|
|
88
|
+
},
|
|
89
|
+
"tags": ["parameters"]
|
|
90
|
+
}
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
**Cell 5 — Query description (markdown)**
|
|
94
|
+
```markdown
|
|
95
|
+
### Query for Systems with the specified package and get the Package Version
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
**Cell 6 — Query (code)**
|
|
99
|
+
```python
|
|
100
|
+
api = SystemsApi()
|
|
101
|
+
|
|
102
|
+
projection = f'new(id, packages.data["{package}"].displayversion, packages.data["{package}"].version)'
|
|
103
|
+
filter = (systems_filter or "!string.IsNullOrEmpty(id)") + f' && packages.data.keys.Contains("{package}")'
|
|
104
|
+
|
|
105
|
+
query_sys_request = QuerySystemsRequest(skip=0, projection=projection, filter=filter)
|
|
106
|
+
query_result = api.get_systems_by_query(query=query_sys_request)
|
|
107
|
+
data = await query_result
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
**Cell 7 — Dataframe description (markdown)**
|
|
111
|
+
```markdown
|
|
112
|
+
### Extract Package data from query results and create pandas dataframe
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
**Cell 8 — Dataframe (code)**
|
|
116
|
+
```python
|
|
117
|
+
pkg_version = { item['id'] : item['displayversion'] for item in data.data }
|
|
118
|
+
df = pd.DataFrame.from_dict(pkg_version, orient='index', columns=['Package Version'])
|
|
119
|
+
df
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
**Cell 9 — Output description (markdown)**
|
|
123
|
+
```markdown
|
|
124
|
+
### Convert dataframe to result format that the Systems Grid can interpret
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
**Cell 10 — Output with sb.glue (code)**
|
|
128
|
+
```python
|
|
129
|
+
df_dict = {
|
|
130
|
+
'columns': ['minion id', 'package version'],
|
|
131
|
+
'values': df.reset_index().values.tolist()
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
result = [{
|
|
135
|
+
"display_name": "Package Version",
|
|
136
|
+
"id": "package_version",
|
|
137
|
+
"type": "data_frame",
|
|
138
|
+
"data": df_dict
|
|
139
|
+
}]
|
|
140
|
+
|
|
141
|
+
sb.glue('result', result)
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
**Cell 11 — Usage instructions (markdown)**
|
|
145
|
+
```markdown
|
|
146
|
+
### View the output of this report in the Systems Grid
|
|
147
|
+
1. Upload this notebook to the reports folder in SystemLink Jupyter
|
|
148
|
+
2. From the Systems page, press the edit grid button
|
|
149
|
+
3. Press '+ ADD' and select 'Notebook' as the data source
|
|
150
|
+
4. Select this report, choose 'Package Version' as the output
|
|
151
|
+
5. Enter the package name and update interval
|
|
152
|
+
6. Enter a column name and press Done
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
---
|
|
156
|
+
|
|
157
|
+
## Pattern 2: Test Data Analysis
|
|
158
|
+
|
|
159
|
+
Query test results and return a summary. Uses `nisystemlink.clients.testmonitor`.
|
|
160
|
+
|
|
161
|
+
**Parameters cell metadata:**
|
|
162
|
+
```json
|
|
163
|
+
{
|
|
164
|
+
"papermill": {
|
|
165
|
+
"parameters": {
|
|
166
|
+
"group_by": "System",
|
|
167
|
+
"program_name": "",
|
|
168
|
+
"status_filter": "",
|
|
169
|
+
"systems_filter": ""
|
|
170
|
+
}
|
|
171
|
+
},
|
|
172
|
+
"systemlink": {
|
|
173
|
+
"namespaces": [],
|
|
174
|
+
"outputs": [
|
|
175
|
+
{
|
|
176
|
+
"display_name": "Test Summary",
|
|
177
|
+
"id": "test_summary",
|
|
178
|
+
"type": "data_frame"
|
|
179
|
+
}
|
|
180
|
+
],
|
|
181
|
+
"parameters": [
|
|
182
|
+
{"display_name": "Group by", "id": "group_by", "type": "string"},
|
|
183
|
+
{"display_name": "Program Name", "id": "program_name", "type": "string"},
|
|
184
|
+
{"display_name": "Status Filter", "id": "status_filter", "type": "string"},
|
|
185
|
+
{"display_name": "Systems Filter", "id": "systems_filter", "type": "string"}
|
|
186
|
+
],
|
|
187
|
+
"version": 2
|
|
188
|
+
},
|
|
189
|
+
"tags": ["parameters"]
|
|
190
|
+
}
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
**Query pattern:**
|
|
194
|
+
```python
|
|
195
|
+
from nisystemlink.clients.testmonitor import TestMonitorClient
|
|
196
|
+
from nisystemlink.clients.core import HttpConfigurationManager
|
|
197
|
+
|
|
198
|
+
config = HttpConfigurationManager.get_configuration()
|
|
199
|
+
client = TestMonitorClient(config)
|
|
200
|
+
|
|
201
|
+
# Use the client to query results with filters
|
|
202
|
+
results = client.get_results(
|
|
203
|
+
filter=f'status.statusType == "{status_filter}"' if status_filter else None,
|
|
204
|
+
take=1000
|
|
205
|
+
)
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
**Output pattern (same as Pattern 1):**
|
|
209
|
+
```python
|
|
210
|
+
result = [{
|
|
211
|
+
"display_name": "Test Summary",
|
|
212
|
+
"id": "test_summary",
|
|
213
|
+
"type": "data_frame",
|
|
214
|
+
"data": {
|
|
215
|
+
"columns": ["minion id", "pass rate"],
|
|
216
|
+
"values": df.reset_index().values.tolist()
|
|
217
|
+
}
|
|
218
|
+
}]
|
|
219
|
+
sb.glue('result', result)
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
---
|
|
223
|
+
|
|
224
|
+
## Pattern 3: Scalar Output
|
|
225
|
+
|
|
226
|
+
When the notebook returns a single value instead of a table.
|
|
227
|
+
|
|
228
|
+
**Output metadata:**
|
|
229
|
+
```json
|
|
230
|
+
{
|
|
231
|
+
"systemlink": {
|
|
232
|
+
"outputs": [
|
|
233
|
+
{
|
|
234
|
+
"display_name": "Total Count",
|
|
235
|
+
"id": "total_count",
|
|
236
|
+
"type": "scalar"
|
|
237
|
+
}
|
|
238
|
+
]
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
**Output code:**
|
|
244
|
+
```python
|
|
245
|
+
result = [{
|
|
246
|
+
"display_name": "Total Count",
|
|
247
|
+
"id": "total_count",
|
|
248
|
+
"type": "scalar",
|
|
249
|
+
"data": len(df)
|
|
250
|
+
}]
|
|
251
|
+
sb.glue('result', result)
|
|
252
|
+
```
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{systemlink_cli-1.7.0 → systemlink_cli-1.8.0}/slcli/examples/demo-complete-workflow/README.md
RENAMED
|
File without changes
|
{systemlink_cli-1.7.0 → systemlink_cli-1.8.0}/slcli/examples/demo-complete-workflow/config.yaml
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{systemlink_cli-1.7.0 → systemlink_cli-1.8.0}/slcli/examples/exercise-7-1-test-plans/README.md
RENAMED
|
File without changes
|
{systemlink_cli-1.7.0 → systemlink_cli-1.8.0}/slcli/examples/exercise-7-1-test-plans/config.yaml
RENAMED
|
File without changes
|
{systemlink_cli-1.7.0 → systemlink_cli-1.8.0}/slcli/examples/spec-compliance-notebooks/README.md
RENAMED
|
File without changes
|
{systemlink_cli-1.7.0 → systemlink_cli-1.8.0}/slcli/examples/spec-compliance-notebooks/config.yaml
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{systemlink_cli-1.7.0 → systemlink_cli-1.8.0}/slcli/skills/slcli/references/analysis-recipes.md
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|