You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
docs(iot-hub): correct related items against the scanner implementation
Address review on #637. The section described a mechanism that differed
from solution-template-scan.service.ts on four points, all verified
against the iot-hub sources:
- the scan reads every .json entry in the archive, not only dashboards/
- the key collected is typeFullFqn, not fqn
- system widgets are dropped by a `system.` prefix test before any
lookup, not compared against widget bundles; note that this makes the
test a spelling test a hand-edited export can defeat
- the blocking guarantee holds only for the create / add-version wizard;
replacing the package on an existing version is deliberately
non-blocking, and a failed scan leaves the step valid
Also:
- drop the claim that the public listing page shows related widgets and
the related-widgets-first provisioning order — neither is backed by
this repo or the creator portal
- note that the wizard labels the step "Required items"
- settle on "system widget" / "IoT Hub widget" throughout
- record that a suspended creator's widget stops resolving
- rename the blocking subsection to a noun phrase, bold the in-page link
- make the checklist item actionable by naming typeFullFqn
- reconcile ${item-link} guidance: widgets are derived automatically, so
reserve the card for dependencies the platform cannot detect
Copy file name to clipboardExpand all lines: src/content/docs/docs/iot-hub/contribution-guides/solution-template.mdx
+41-26Lines changed: 41 additions & 26 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -23,15 +23,16 @@ Create a free **Creator account** on the <a href="https://iot-hub.thingsboard.io
23
23
24
24
When a user clicks **Install** on your solution template in IoT Hub:
25
25
26
-
1. They review the **description** (from `description.md`), the preview gallery (from `imageUrls` in `solution.json`), and the list of **[related items](#related-items)** the template pulls in.
26
+
1. They review the **description** (from `description.md`) and preview gallery (from `imageUrls` in `solution.json`).
27
27
2. They confirm installation — the platform atomically provisions every entity in your template:
28
-
- Related IoT Hub widgets used by your dashboards (first, so the dashboards render)
- Devices, assets, customers, dashboards (next, referencing the profiles)
31
30
- Device emulators (last, seeded with telemetry)
32
31
3. They are redirected to the **main dashboard** with live data already flowing.
33
32
4. The **post-install instructions** (from `instructions.md`) are shown alongside the dashboard — telling them how to inspect the setup, connect real hardware, customize widgets, and so on.
34
33
34
+
Any IoT Hub widget your dashboards use is installed along with the template — see **[Related items](#related-items)**.
35
+
35
36
Your job as a creator is to describe the complete solution declaratively in the archive so that a single installation produces a working end-to-end demo.
36
37
37
38
## Quick Start
@@ -430,42 +431,54 @@ The `entityNameFilter` must exactly match a device `name` from `entities/devices
430
431
431
432
## Related Items
432
433
433
-
Solution template dashboards often use widgets that are not part of ThingsBoard's built-in widget bundles — widgets published to IoT Hub by you or by other contributors. IoT Hub tracks those dependencies for you as **related items**.
434
+
Dashboards in a solution template often use widgets that do not ship with ThingsBoard — **IoT Hub widgets** published by you or by another contributor. IoT Hub derives those dependencies from your package and stores them on the version as **related items**, so they install together with the template.
435
+
436
+
In the upload wizard and in the version drawer, this step (and the corresponding tab) is called **Required items**.
434
437
435
438
### How the Check Works
436
439
437
-
When you upload the ZIP, IoT Hub parses every dashboard in `dashboards/`, collects the widget `fqn` of every widget placed on it, and compares each one against the list of ThingsBoard system widget bundles:
440
+
When you upload the ZIP, IoT Hub scans the archive:
438
441
439
-
| FQN resolves to | What IoT Hub does |
440
-
|---|---|
441
-
| A **system** widget bundle | Nothing — the widget ships with ThingsBoard and is available on every instance |
442
-
| A **published IoT Hub widget**| Records a relation between this solution template version and that widget |
443
-
|**Nothing**| Reports a validation error — see [Unknown FQNs Block the Upload](#unknown-fqns-block-the-upload)|
442
+
<Steps>
443
+
1. It collects every `typeFullFqn` value found in **any**`.json` file in the package — not only the files under `dashboards/`. `typeFullFqn` is the key a ThingsBoard export writes a widget type reference under, so a reference sitting in a rule chain export or in `entities/dashboards.json` is picked up the same way.
444
+
2. It drops every FQN starting with `system.` — those widgets ship with ThingsBoard, exist on every instance, and are never a marketplace dependency.
445
+
3. It looks the remaining FQNs up in the IoT Hub catalog in a single request. A dashboard export scopes a widget type by its owner (`tenant.john_doe.air_quality_card`) while IoT Hub stores the bare FQN (`john_doe.air_quality_card`), so both readings are tried.
446
+
</Steps>
447
+
448
+
Every FQN that resolves to a published IoT Hub widget is recorded as a related item of this template version. Every FQN that does not resolve is reported as a missing widget.
444
449
445
450
<Asidetype="note">
446
-
You never declare related items yourself. There is no field for them in `solution.json` or `entities/*.json` — every relation is derived from the dashboard exports and created automatically on upload.
451
+
You never declare related items yourself. There is no field for them in `solution.json` or `entities/*.json` — the list is derived from the archive and recomputed every time the package is replaced.
447
452
</Aside>
448
453
449
-
### Unknown FQNs Block the Upload
454
+
<Asidetype="caution">
455
+
The system-widget test is a spelling test on the FQN, not a lookup against the widget bundles. An FQN hand-edited to start with `system.` is accepted silently and installs as a broken widget.
456
+
</Aside>
450
457
451
-
If a dashboard uses a widget FQN that is neither a system widget nor a published IoT Hub widget, the upload wizard reports an error listing the unresolved FQNs and keeps the remaining steps disabled. A package in that state cannot be saved or submitted, so a template whose dashboards would render broken widgets never reaches the catalog.
458
+
### If an FQN Does Not Resolve
452
459
453
-
There are three ways to resolve it:
460
+
The **Required items** step lists the unresolved FQNs and explains that the dashboards use custom widgets that are not published in IoT Hub, so anyone installing the solution would get broken widgets. Whether that blocks you depends on where you hit it:
461
+
462
+
| Where | Behavior |
463
+
|---|---|
464
+
| Create item / add version wizard | The step is invalid: the stepper will not advance and the version cannot be created until every FQN resolves |
465
+
| Replacing the package on an existing version | The new package is saved with the dependencies actually detected and the missing widgets show up as a warning — **submitting for review is not blocked**|
466
+
467
+
Treat the wizard as a guard rather than a guarantee: a version whose package was replaced can reach review with unresolved widgets, so fix them before you submit. A scan that fails outright — an unreadable archive, or the catalog not answering — does not block anything either; IoT Hub says which of the two happened and keeps the previous dependency list instead of replacing it with an empty one.
468
+
469
+
There are three ways to resolve a missing widget:
454
470
455
471
-**Publish the widget to IoT Hub first.** Upload it as a separate IoT Hub item and wait for its version to be **approved** — a version still pending review does not resolve the FQN. See the <ahref="/docs/iot-hub/contribution-guides/widget/"target="_blank"rel="noopener noreferrer"><strong>IoT Widget Contribution Guide</strong></a>. Then re-upload the template ZIP.
456
-
-**Swap it for a system widget.** Rebuild that part of the dashboard with a built-in ThingsBoard widget and re-export the dashboard.
472
+
-**Swap it for a system widget.** Rebuild that part of the dashboard with a widget bundled with ThingsBoard and re-export the dashboard.
457
473
-**Remove the widget from the dashboard** and re-export the dashboard.
458
474
459
-
Any approved IoT Hub widget resolves — it does not have to be one of your own.
460
-
461
-
### What Users Get
475
+
Any published IoT Hub widget resolves — it does not have to be one of your own. The one exception is a widget whose creator has since been suspended: it stops resolving even though its version is still approved.
462
476
463
-
Related items make the dependency both visible and self-installing:
477
+
### What Gets Installed
464
478
465
-
- The public solution template page lists the related widgets, so users see what the template pulls in **before** they install it.
466
-
- On install, IoT Hub installs those widgets together with the template. Users never have to track down a missing widget or repair a dashboard afterwards.
479
+
Installing the template installs its related items too, so users never have to track down a missing widget or repair a dashboard afterwards.
467
480
468
-
A relation points at the widget item rather than at a pinned widget version, so every installation gets the latest approved version of each related widget. Keep your own published widgets backward compatible: a breaking change to a widget also changes how it behaves inside every solution template that references it.
481
+
A related item points at the widget **item**, not at a specific widget version, so your template never pins a widget version — each installation picks up whatever version IoT Hub serves for that widget at the time. Keep your published widgets backward compatible: a breaking change to a widget also changes how it behaves inside every solution template that references it.
469
482
470
483
## Device Profiles and Asset Profiles
471
484
@@ -639,7 +652,7 @@ These placeholders are resolved at install time:
639
652
|`${MAIN_DASHBOARD_URL}`| Deep link to the solution's main dashboard |
640
653
|`${DOCKER_CONFIG}`| Full `docker-compose.yml` content for the gateway, pre-filled with host, port, and token. Usually wrapped in a `bash` code block |
641
654
|`${DOCS_BASE_URL}`| Base URL of the ThingsBoard documentation — use for links that should work on both ThingsBoard Cloud and on-prem |
642
-
|`${item-link:<item-uuid>}`| Renders a link card pointing at another IoT Hub item (widget, dashboard, rule chain, etc.) the user can install in one click. Use for dependencies your template relies on|
655
+
|`${item-link:<item-uuid>}`| Renders a link card pointing at another IoT Hub item the user can install in one click. Use for dependencies the platform cannot derive from your package — widgets are handled automatically, see **[Related items](#related-items)**|
2.**Prerequisites** — what the user needs (Docker, network access, accounts). If your solution template depends on another IoT Hub item you have published (e.g. a custom widget, dashboard, or rule chain), reference it here with `${item-link:<item-uuid>}`. The platform replaces the placeholder with a link card pointing at that IoT Hub item so users can install the dependency in one click. Example:
674
+
2.**Prerequisites** — what the user needs (Docker, network access, accounts). If your solution template depends on another IoT Hub item you have published, reference it here with `${item-link:<item-uuid>}`. The platform replaces the placeholder with a link card pointing at that IoT Hub item so users can install the dependency in one click. Example:
662
675
663
676
```markdown
664
-
This solution uses our custom Air Quality widget. Install it first:
677
+
This solution pairs with our Predictive Maintenance rule chain. Install it first:
665
678
666
679
${item-link:d93b9a1a-1c07-408c-bb86-743bbcb36832}
667
680
```
668
681
682
+
Widgets are the exception: the widgets your dashboards use are detected and installed automatically as **[related items](#related-items)**, so they need no `${item-link}` card.
683
+
669
684
3.**Launch the emulator** — copy-paste Docker commands.
670
685
4.**Launch the gateway** — use `${DOCKER_CONFIG}` to give them a ready-to-run config.
671
686
5.**Interacting with the dashboard** — link to the main dashboard via `${MAIN_DASHBOARD_URL}`.
@@ -753,7 +768,7 @@ Every upload creates a new version of your template. Bump the version in the upl
753
768
-[ ] No hardcoded UUIDs remain in any `singleEntity.id` or similar references
754
769
-[ ] Dashboard titles match the names in `entities/dashboards.json`
755
770
-[ ] Every widget displays data from a telemetry key that an emulator actually produces — nothing should be empty after installation
756
-
-[ ] Every non-system widget used on a dashboard is already published to IoT Hub with an **approved** version, so its FQN resolves as a **[related item](#related-items)**
771
+
-[ ] Every widget that does not ship with ThingsBoard is already published to IoT Hub with an **approved** version, so its `typeFullFqn` resolves as a **[related item](#related-items)** — search the dashboard export for `typeFullFqn` to enumerate them
0 commit comments