Reintroduces the canonical item link (/iot-hub/{itemId}) that resolves
to the latest published version. The preview shape (/iot-hub/{itemId}/preview)
stays removed — if a creator wants to preview a specific draft, they
share the /iot-hub/version/{itemVersionId} link with that exact
versionId.
Final URL shapes:
- /iot-hub/{itemId} → latest published version
- /iot-hub/version/{itemVersionId} → specific version, warning if unpublished
Resolver branches on which route param is present — no extra data flag.
Restores getPublishedVersion API method. IoT Hub ask adds back one new
endpoint: GET /api/items/{itemId}/published.
Consolidates to a single deep-link shape: /iot-hub/version/{itemVersionId}.
A specific version snapshot is a more useful sharable link than
"latest of item" — stable, unambiguous, and fits creator review
workflows ("please look at exactly this draft").
Removes /iot-hub/{itemId} and /iot-hub/{itemId}/preview routes, the
getPublishedVersion and getLatestVersion API methods (now unused), the
byVersion and preview route-data flags, and the iot-hub.item-preview
i18n key. Simplifies the resolver to a single getVersionInfo call with
the same warning-if-unpublished gate.
Big win for the IoT Hub backend contract: no new endpoints needed, only
a behavior guarantee on existing /api/versions/{versionId}.
Third URL shape for deep links, pointing at a specific version snapshot
rather than "latest of item". Stable link — useful for creators sharing
"review exactly this draft" references. Routes through the same
resolver component with a new byVersion flag on route data; reuses the
existing getVersionInfo API and the same warning-if-unpublished gate as
the preview flow.
Spec + plan updated to document the new shape and the expanded IoT Hub
backend contract.
Nine bite-sized tasks (i18n, utils, API methods, warning dialog, detail
dialog badge, resolver component, routing, type-page handoff, smoke
test) each verified by build + manual walkthrough. No frontend unit
tests because ui-ngx has no test runner configured.
Adds design for /iot-hub/{itemId} and /iot-hub/{itemId}/preview deep
links, covering router resolver component, warning dialog for
unpublished content, detail dialog preview badge, type-page handoff,
and the IoT Hub-side API endpoints required to support it.
- getFilterInfo and getWidgetCategories now append peOnly=false and tbVersion=<computed> to the URL, matching getPublishedVersions behavior
- add-item dialog content: scope max-height: 70vh to mat-gt-sm
- MpItemVersionQuery switched to options-object pattern (no more positional undefined params)
- Remove widgets-bundle-search and widget-types-panel components (inlined / merged into filter popover)
- Widget select empty state: shared #noData template with tb-no-data-bg illustration + 'Clear all filters' button (clears both search and filters); Installed->All widgets adds 'Browse IoT Hub' banner that navigates to IoT Hub->All widgets
- Filter popover: immediate-apply (no Apply/Cancel), Clear all + close in header, tbPopoverPlacement=bottomRight, tbPopoverShowCloseButton=false; installed mode uses same expansion-panel style as iot hub with widget type badge and Include Deprecated (shown for bundle and allWidgets)
- Sort mat-menu (Most installed / Newest / Name) with iconPositionEnd; client-side sort for installed widgets, scada items first when scadaFirst=true
- Replace all-widgets/installed-from-iot-hub placeholder SVGs with high-fidelity PNG@2x assets (incl. separate all-iot-hub-widgets.png for IoT Hub mode)
- IoT Hub browse: merge add-mode styles into embedded class, embedded always uses mobile filter drawer; compact grid 1 col default / 2 cols gt-md; regular 3 cols gt-sm; empty state uses tb-no-data-bg
- iot-hub-search: empty state uses tb-no-data-bg; add-item-dialog: tb-fullscreen-dialog-lt-md panel class, content 70vh with widths 80vw/1000px/1200px at gt-sm/gt-md/gt-xmd
- New TbIotHubInstalledItemsDialogComponent opened from detail dialog Manage section
- Extract TbIotHubInstalledItemsTableComponent with itemVersion mode for single-item view
- Add installed item counts API (GET /installedItems/counts) and itemId filter to installed items list
- Wire installed counts into home, browse, search, and detail dialog (replaces installedDevices list)
- Propagate ChipOverflowDirective with minChips input; use on detail dialog meta chips
- openEntity opens in new tab; "View item details" swaps to "Review device instructions" for DEVICE items
Redesign item detail dialog: move install/add/update/open buttons to footer,
move creator to sticky meta bar with avatar and verified badge, add manage
section with solution instructions, remove, and installed items count buttons,
update subtitle with grouped icon+text pairs matching design.
Add getInstalledItemCounts API (backend + frontend) returning item counts
by itemId per type. Replace installedDevices list with count-based tracking
in home, browse, and search components. Add installedItemsCount to item card
and detail dialog data flow.
Add verified field to CreatorView and creatorVerified to MpItemVersionView.
Show verified badge (32px teal icon + tooltip) on creator profile page.
Show 16px teal verified icon on item cards when creator is verified.
Make dlg-meta-bar always rendered and sticky in item detail dialog.
Add inline search inputs for filter panels with >= 10 items, "Most popular"
grouping for use cases with >= 11 items, scrollable filter items containers
with hover-visible scrollbar, and totalItems filtering. Convert *ngFor/*ngIf
to new Angular @for/@if flow syntax in the filter panel.
Replace hardcoded category/use-case/subtype enums and translation maps
with dynamic FilterParamInfo data from /api/item-listing/filterInfo/{itemType}.
Add inline search input for filter panels with >= 10 items, "Most popular"
grouping for use cases and vendors with >= 11 items, scrollable filter
items container with hover-visible scrollbar, and multi-vendor support
in MpItemVersionQuery. Remove redundant enums, maps, and locale translations.
Update dashboard widget select filter panel to use dynamic data.
When a device is already installed, show an "Install one more" button
next to the Remove button. Clicking it opens the install wizard to
provision another instance of the same device package.
Always fetch ZIP and open the device install review dialog (tabs with
instructions, forms, provisioning) — never fall back to the generic
detail dialog. The review dialog handles missing installState gracefully
(shows empty forms but instructions still render from ZIP).
Show the guide icon on device cards for ALL installed items, not just
those with installState. If installState is available, opens the
read-only review dialog. If not (items installed before the feature),
falls back to the item detail dialog — same pattern as the installed
items page info button.
When the browse component is used on /iot-hub/devices (via items page
component), the parent sets config in its own ngOnInit, so the child's
@Input setter fires AFTER the child's ngOnInit. The DEVICE-specific
loading (vendors + installed items) in ngOnInit never executed because
activeType was still the default WIDGET at that point.
Fix: trigger loading directly in the activeType setter when the value
changes to DEVICE.
The device card's "Installed" chip, guide button, and delete/update
buttons need the installed item data. Added installedDevices loading
when DEVICE tab is active, included in getInstalledItem() lookup
and reloadInstalledItems() refresh.
Without this, getInstalledItem() returned undefined for DEVICE type,
so cards showed "Install" instead of "Installed" and the guide button
was never visible.
Show a document icon button (📄) next to the "Installed" chip on
device cards that have stored install state. Clicking opens the
read-only review dialog with tabs (same as from Installed Items).
Visible in both "same version" and "update available" card states.
Tooltip: "View setup guide". Only shown for DEVICE items with
installState in their descriptor.
Hardware Types: update to 15 values (was 19):
Actuator, AI Accelerator, Analyzer, Camera, Controller, Data Logger,
Development Board, Display, Gateway, Meter, PLC, Relay, Sensor,
Single Board Computer, Tracker
Use Cases: flatten to 22 values (was 27 grouped into 8 industries):
Air Quality Monitoring, Asset Tracking, Cold Chain, Drones, ...
No more group headers — simple flat checkbox list.
Fetch distinct vendor list from IoT Hub API (GET /versions/published/vendors)
when DEVICE tab is activated. Render as checkboxes (same pattern as
Hardware Type filter). Vendor is the first filter section for devices.
Replaces the debounced text input approach with dynamic checkbox list.
Add Vendor as the first filter for DEVICE type in browse page:
- Text input with debounced search (400ms)
- Clear button when filter is active
- Passes vendor param to IoT Hub API query
- Included in filter count and clearAllFilters
- Positioned above Hardware Type and Connectivity filters
- Use Cases: add 27 grouped values (8 industry groups) with sub-headers
in the filter panel. Applied to all item types.
- Device filters: replace Category with Connectivity (55 values, 3 groups)
and Hardware Type (19 values) filters. Category hidden for DEVICE type.
- Query model: add hardwareTypes, connectivity, vendor params to
MpItemVersionQuery (IoT Hub API already supports these).
- Detail dialog: DEVICE type shows Hardware Type + Connectivity + Use Cases
instead of Category + Use Cases.
- Filter chips updated for new filter types.
Replace mat-stepper with mat-tab-group in review mode for a cleaner
read-only experience. All tabs are freely clickable without linear
progression.
- Extract step content into shared ng-template (used by both stepper
and tabs to avoid duplication)
- Pre-activate all step content on init in review mode (tabs render
lazily)
- Add onTabChanged handler for tab selection
- Footer shows Close + Open Dashboard buttons
- Install mode stepper unchanged
The provisioning step content (entity list) was empty because
onStepActivated() was only called for the initial step. When the
user clicked on the Provisioning step directly, nothing triggered
the content initialization.
Fix: listen to mat-stepper selectionChange event to call
onStepActivated() whenever the user navigates between steps.
Also disable linear mode in review mode so all steps are freely
clickable.
The review mode check ran after the single-connectivity auto-start,
so the wizard was already built with empty state before review mode
could restore form values and entity outputs.
Fix: move connectivity selection logic after the review mode check.
Review mode sets its own connectivity from stored state; normal mode
falls through to the existing single/multi connectivity logic.
- Remove stale iotHubApiService from dialog data (now directly injected)
- Fall back to regular detail dialog for items without installState
(installed before the review mode feature)