Extend the IoT Hub install dialog so installing a rule chain can also set
it as the Default rule chain on a Device or Asset profile in one step.
The confirm step shows three actions: Cancel, Install (creates the chain
without targeting any profile), and Set for profile (opens a picker step).
The picker step has Cancel, Back, and Install — confirming with a profile
that already has a non-null defaultRuleChainId routes through a
confirm-overwrite step before replacing it. CALCULATED_FIELD keeps its
existing single-button flow unchanged.
Backend:
* RuleChainInstalledItemDescriptor gains a nullable EntityId
targetProfileId field, persisted in the existing descriptor JSON column
(no schema migration; @JsonIgnoreProperties(ignoreUnknown=true) handles
pre-existing rows).
* DefaultIotHubService.installRuleChain() now accepts SecurityUser and
JsonNode data; a new setAsDefaultRuleChain() helper applies the chain
as Default rule chain on the selected DEVICE_PROFILE or ASSET_PROFILE
via the existing tbDeviceProfileService / tbAssetProfileService save
paths (so the change shows up in the tenant audit log as a normal
profile update).
Frontend:
* iot-hub-install-dialog.component grows a per-ItemType selectEntityConfig
map, a 'confirm-overwrite' state, and the methods
installAsEntityProfileDefault, selectEntityBack, resolveOverwrite,
confirmOverwriteReplace, confirmOverwriteCancel.
* tb-entity-select gets a 512px min-width above the gt-sm breakpoint so
the picker renders at a consistent width regardless of the prompt text
length (mirrors the pattern in recipient-notification-dialog).
* New i18n keys: rule-chain-install-desc, rule-chain-install-as-default,
select-profile-for-rule-chain, rule-chain-overwrite-title,
rule-chain-overwrite-body, rule-chain-overwrite-replace.
- ${images.gallery(...)} accepts JS-style image objects
({src, alt?, caption?}) that may span multiple lines and contain
whitespace inside the gallery brackets. Captions go through a
whitelist sanitiser (b/strong/i/em/u/s/mark/small/sub/sup/br/code/
span with class+style only — style values containing
expression()/javascript:/url() are dropped) so authors can use
inline markup without exposing XSS.
- Promote escapeHtml / escapeHtmlAttr to exported helpers in
iot-hub-markdown.utils, add the new sanitizeInlineHtml. Drop the
duplicate copies (and the now-unused DocLinks helpers + buildDocLinkButton)
from shared/models/iot-hub/device-package.models.
- Move the PhotoSwipe wiring out of TbIotHubMarkdownComponent into a
reusable tbPhotoSwipeGallery shared directive, declared/exported
by SharedModule. The component now just renders the
data-attributed wrapper and the directive lazy-binds PhotoSwipe.
- Tighten the gallery layout: 200px-min auto-fill grid, 8px vertical
margins, hover border swapped to the shared #2a7dec accent token.
- Wire photoswipe (5.4.4) into ui-ngx and load its CSS via angular.json.
- Replace the in-place ".tb-gallery-img-expanded" toggle in
TbIotHubMarkdownComponent.onReady with a PhotoSwipe lightbox bound
to each ".tb-gallery-images" container, picking up
".tb-gallery-image" anchors. Items are sized from the underlying
image's naturalWidth/Height; the lightbox slide uses contained
rendering with a max viewport sized 90vw / 78vh and a 0-opacity
backdrop.
- Style the gallery: 240px-min auto-fill grid with 12px gap, 115px
thumbnail strip with object-fit contained images, hover lift
(border + translate + shadow) and a fade-in caption tooltip
bottom-pinned over the thumbnail.
- Move solution-install-dialog.component.{ts,html,scss} from
home/components/solution/ into home/components/iot-hub/, drop the
now-empty solution folder.
- Register SolutionInstallDialogComponent in IotHubComponentsModule
(declaration + export) and remove its declaration / export /
import from HomeComponentsModule. HomeComponentsModule already
imports IotHubComponentsModule, so consumers continue to resolve
the component without changes.
- Update import paths in iot-hub-install-dialog,
iot-hub-update-dialog, iot-hub-item-detail-dialog (and the
modified home-components module) to the new
@home/components/iot-hub/solution-install-dialog.component path.
- Pick up incidental work-in-progress edits in the iot-hub markdown
utils / template / dialogs touched alongside this move.
- Add TbIotHubMarkdownComponent (home/components/iot-hub) wrapping
tb-markdown with applyDefaultMarkdownStyle=false, the IoT Hub item
link compile module, and forwarded lineNumbers /
fallbackToPlainMarkdown coerced-boolean inputs.
- Carry the readme/description typography (h1..h6, p, ul/ol, li, a,
img, code, code-wrapper / clipboard-btn, pre[language] with Prism
tokens and line-numbers, tables) so callers don't have to override
the default markdown styles. Tunes ported from the design:
list margins, 6px heading bottom padding, table widths and
padding, clipboard offsets, etc.
- Replace tb-markdown with tb-iot-hub-markdown in the item detail
dialog (description + readme + changelog), the install / update
dialog error blocks, and the solution install dialog. Drop the
inline .dlg-readme markdown overrides and the
.dlg-description ::ng-deep block, leaving only the dlg-readme
layout tweak and a padding:0 reset for .dlg-description.
- Solution install dialog drops the now-redundant
itemLinkCompileModules field + IotHubItemLinkModule import and the
.table-wrapper ::ng-deep override; the iot-hub-markdown component
carries those styles itself.
- Selected card inverts the icon container: primary-coloured
background with the masked glyph painted white, on top of the
existing primary border + inset shadow.
- Default (idle, non-hovered) cards use a transparent border so the
outline appears only on hover or when selected — the 1px layout
space stays intact to avoid jitter.
Apply a tb-connectivity-cards-pair modifier to the card grid when
availableInstallMethods.length === 2 and switch its tracks to
repeat(auto-fill, minmax(300px, 1fr)) so the two cards spread to
sensible widths instead of squeezing into the 240px minimum.
- Add installMethodIcons map covering integrations (existing
assets/integration-icon files), direct-connect transports (new
assets/direct-connect-icon: http/mqtt/coap/lwm2m/snmp), and gateway
connectors (new assets/gateway-connect-icon: mqtt/modbus/opc-ua/
bacnet/ble/can/ftp/ocpp/odbc/request/rest/snmp/socket/xmpp).
Direct/gateway icons are exported from the design via the Figma
REST API. The PE-only illustration is also exported.
- Replace the row of stroked buttons in the device install
connectivity selector with a card grid that mirrors the design
(276x116, 6px radius, primary border on hover/select, mask-image
driven icon rendered in primary, primary-tinted 4% surface,
inner-shadowed 48x48 white icon container, "PE Only" pill).
- Restructure the wizard so that the connection method is the first
wizard step ("Connection method"). Three placeholder steps
(Prerequisites / Configuration / Provisioning) preview the rest of
the flow until a method is picked. On selection, placeholders are
swapped for the real install steps and the stepper auto-advances;
re-clicking the already selected card is a no-op.
- Replace the inline PE-only panel with a dedicated dialog
(TbPeConnectivityMethodPromptComponent) matching the design
(500x364 white card, 140 illustration, 24px title with primary
connector name, "Try Professional Edition" link to
https://thingsboard.io/installations/, Close, top-right X). PE-only
cards open this prompt instead of advancing the wizard.
* 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.
- 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.
Under `mvn -T<n>` with the three yarn-using modules (ui-ngx,
msa/web-ui, msa/js-executor), concurrent yarn 1.x processes contend
on the shared `~/.cache/yarn`. The `--mutex network` flag was applied
only to `yarn install`, so `yarn run pkg` could overlap with another
module's install. Intermittent failures observed on CI:
`/bin/sh: 1: tsc: not found` during `yarn run pkg`, caused by
incomplete typescript extraction into per-module node_modules.
Fix at two layers:
1. Maven reactor chain (primary): add reactor-only pom <dependency>
entries (type=pom, scope=provided, wildcard exclusions) to form
ui-ngx -> msa/web-ui -> msa/js-executor
so the MultiThreadedBuilder schedules them strictly serial,
regardless of -T thread count. msa/web-ui already had a real
dependency on ui-ngx; only one new fake link was needed.
2. Yarn-level mutex (defense in depth): add `--mutex network` to
`yarn run pkg` (msa/web-ui, msa/js-executor) and
`yarn run build:prod` (ui-ngx), so single-module builds outside the
reactor chain (`mvn -pl msa/<module>`) still serialize against any
other yarn process on the agent.
Comment in msa/pom.xml updated: the previous "Modules order is
important..." note was misleading - module order in the reactor does
not enforce serialization under -T; the dependency edges do.
- Replace per-type icon SVG sets with single composite cluster SVGs
exported from the updated design (devices, solutions, widgets,
calculated fields, alarm rules, rule chains).
- Add soft per-type colored glow blobs (Ellipse 399 / 400, opacity 0.16,
filter: blur(120px)) at the page level so the wash spans the whole
page background instead of being clipped by the hero.
- Fix hero icons transition: switch from vertical translate to a uniform
scale around the hero centre so icons burst from / collapse to the
centre on enter/exit, matching the design prototype.
- Drive blob fill via [style.color] + currentColor for smooth per-type
tint cross-fades.
Remove the no-longer-used ViewContainerRef injection and the commented-
out fallback branches now that initAngularComponent uses the
angularContainer view container exclusively.
- Group tomcat, commons-lang3 version properties under spring-boot.version
- Drop thymeleaf override (PE-only dependency, not present in CE)
- Drop lz4 plumbing: kafka-clients 3.9.2 and cassandra-all 5.0.7 now transitively ship at.yawk.lz4:lz4-java, making the Dec 2025 CVE hack obsolete
- Fill description and tags for the HTML Container widget type JSON.
- Add basic config component (plain HTML / Angular mode editor).
- Add advanced settings component and shared common settings.
New static widget that replaces the dashboard layout with configurable
HTML, CSS, and JavaScript and exposes the WidgetContext to the user
script. Use for custom complex visualizations or actions when system
widgets are not enough.
Moved NioEventLoopGroup allocations into the try block so that a
constructor failure for the second group no longer leaks the first.
Channel close failures during cleanup now attach via addSuppressed
instead of replacing the original BindException. Narrowed the outer
catch from Throwable to Exception, removing the brittle (Error) cast
that would have masked any direct Throwable subclass.
The base image thingsboard/openjdk17:bookworm-slim ships a customized
/etc/java-17-openjdk/security/java.security. When apt-get install pulls
in a newer openjdk-17-jre-headless to satisfy cassandra's java11-runtime
dependency, dpkg blocks on a non-interactive conffile prompt and the
build fails. The ensuing "cassandra depends on java11-runtime" error is
just the cascade from openjdk-17-jre-headless never finishing configure.
Pass --force-confdef --force-confold so dpkg silently keeps the base
image's customized conffile and the upgrade completes.