* docs(iot-hub): spec for ${item-link:uuid} markdown component
Design for a new markdown placeholder that renders an item card
(thumbnail + name + creator) inline in IoT Hub readmes and install
instructions, opening the linked item in a new tab.
* docs(iot-hub): correct branch name in item-link spec
* docs(iot-hub): implementation plan for ${item-link:uuid} markdown component
Step-by-step task plan covering the placeholder utility, the link card
component, module wiring, three integration sites (item readme, device
install instructions, solution install instructions), translations, and
manual visual QA.
* feat(iot-hub): add item-link placeholder utility for markdown
* feat(iot-hub): add TbIotHubItemLinkCardComponent for markdown item links
* refactor(iot-hub): remove impossible-state guards in item-link card
* feat(iot-hub): wrap item-link card in IotHubItemLinkModule
* feat(iot-hub): add item-link-unavailable translation key
* feat(iot-hub): render ${item-link} cards in item readme
* feat(iot-hub): render ${item-link} cards in device install instructions
* feat(iot-hub): render ${item-link} cards in solution install instructions
* fix(iot-hub): match item-link card thumbnail to search popup (99x56, contain)
- Split the settings dialog into a resizable two-pane layout (left:
resources/HTML/CSS/JS tabs; right: live preview) using split.js,
with a fullscreen toggle that resets the tab animation duration to
avoid jank during expand.
- Split ContainerFunctionEditorCompleter into HTML- and Angular-mode
variants so the autocomplete suggests `container` only in HTML
mode (Angular mode has no container argument).
- Mark the widget with previewWidth/previewHeight 100% and
overflowVisible: true in its controllerScript typeParameters so
the basic config preview fills its slot.
ImageService.replaceBase64WithImageUrl rewrites base64 data URIs into
system-image URLs at save time. After install, the DB image is a
'tb-image;...' URL while the JSON file still carries a base64 data URI —
naive string compare always reported a diff and caused every system
bundle to be re-saved on every patch run.
SystemPatchApplier now creates widget types missing from the DB
instead of throwing, and merges new fqns into existing system bundles.
Bundle creation and inline widgetTypes in bundle JSONs are explicitly
rejected as out-of-scope for patch upgrades.
- Add a clearFilters output + hasActiveFilters() helper to
TbIotHubInstalledItemsTableComponent and render a primary
"Clear all filters" button in the empty state when search or
type filters are active. The parent installed-items page binds
the output to its clearAllFilters() and now also resets
textSearch / appliedTextSearch alongside the type filters.
- Restore the 24px bottom margin on the empty-state body paragraph
so the button has the same breathing room as in the browse
component empty state.
- Update the installed-items page filter panel: remove DASHBOARD,
add ALARM_RULE, and reorder to the canonical
DEVICE → SOLUTION_TEMPLATE → WIDGET → CALCULATED_FIELD →
ALARM_RULE → RULE_CHAIN order shared with home and search.
- Replace the plain text empty placeholder with the same illustration +
title + subtitle layout used by tb-iot-hub-empty-state in the browse
component (no-data illustration, 18/500 title, 14/0.54 body).
- Add a no-installed-items-text locale key ("Try adjusting your search
or filters.").
- Make the table wrapper a flex column and place the empty state and
loading spinner inside it as flex-1 children so both vertically
centre below the sticky header instead of pinning to the top.
- Add a dedicated alarm-rules hero SVG (560×276) and point the
ALARM_RULE PAGE_CONFIG to it instead of the stale dashboards image.
- Replace the calculated-fields and devices hero SVGs with the
updated illustrations exported from the design.
The Installed / IoT Hub toggle now carries icon templates that don't
collapse cleanly into a mat-select on xs viewports — keep the toggle
buttons at every breakpoint instead.
- Add a `template?: TemplateRef<any>` slot to ToggleHeaderOption +
ToggleOption so callers can render arbitrary content inside a
toggle (the existing string label / error icon path stays the
default).
- Use it in the dashboard widget-select header to render a tb-icon
next to each label: now_widgets for Installed, hub for IoT Hub.
- Style the top-level toggle with a 42px pill (8px radius, white-15
border, 40px buttons, 36px line-height, 500 weight) so the icon +
label sit comfortably and contrast against the primary toolbar.
- Apply the same DEVICE → SOLUTION_TEMPLATE → WIDGET → CALCULATED_FIELD →
ALARM_RULE → RULE_CHAIN ordering to the home search popup and the
search component, so all entry points group results consistently.
- Drop DASHBOARD entirely from the search component (route, installed
counts, type order) and filter it out of the home search popup
groups.
- Add ALARM_RULE to the search component (compact-card layout, route
alarm-rules, installed-count handling).
- Remove the "Add from IoT Hub" header action and addDashboardFromIotHub
handler from the dashboards page, plus the now-unused
IotHubActionsService / ItemType imports and constructor injection.
- Reorder category cards to match the design: Devices → Solutions →
Widgets → Calculated Fields → Alarm Rules → Rule Chains.
- Replace gradient card backgrounds with the design's flat per-card
colors and swap stale SVG illustrations for fresh PNG renders
exported from the design.
- Implement the design's hover interaction (200ms ease-out): the card
image scales up by 5.4 % (matching the 387×148 → 408×156 frame
growth) and a chevron slides in next to the title.
- Add the "Most popular in IoT Hub" h2 plus a full-width bleed divider
between the category cards and the popular sections.
- Drop the "Popular " prefix from popular section headers and use
item.type-*-plural translations directly. Remove the now-unused
iot-hub.popular-* locale keys.
- Reorder popular sections to match the design's order.
- Switch the IoT Hub menu and breadcrumb icons from `store` to `hub`.
Spring Boot 3.5.14 ships an ImportsContextCustomizer change that
double-registers legacy @SpyBean fields, causing "Duplicate spy definition"
failures during ApplicationContext load in tests that mix @SpyBean and
@MockitoSpyBean across the test class hierarchy. Pin the test artifacts
to 3.5.13 until 3.5.15+ is released with a fix; runtime stays on 3.5.14
so the CVE fixes remain in effect.
- Restructure HTML Container settings into a mat-tab-group (Resources /
HTML / CSS / JavaScript) instead of a single resources expansion panel
followed by stacked editor blocks. Each editor tab uses [fillHeight]
so the editors fill the panel.
- Wire fill-height plumbing: tb-widget-settings host h-full, basic and
advanced settings @HostBinding('style.height')='100%', advanced panel
switched from inline height:100% to flex-1, mat-content height:100%.
- Register html_container in widget_bundles/html_widgets.json so the
widget appears in the HTML Widgets bundle.
- Replace the placeholder html-card image reference with a dedicated
html-container.png asset and embedded data.
- Add 'JavaScript' translation key for the new tab label.