Add optional isNew flag on MenuSection; when set, menu-link and
menu-toggle components render a NEW badge next to the label. Marks
the IoT Hub entry as new.
Add CreatedRuleChainInfo extending CreatedEntityInfo that overrides
getEntityPageLink to produce /edgeManagement/ruleChains/<id> for EDGE
rule chains and /ruleChains/<id> otherwise. SolutionInstallContext now
registers rule chains with this type-aware info.
The IoT Hub backend sends the literal string 'Initial release' as the
changelog payload for every newly-published item. That text tells the
user nothing they don't already see from the v 1.0.0 chip in the meta
bar — just informational noise. Hide the Changelog heading + body when
the trimmed changelog equals 'Initial release'.
Both the inner section guard and the outer container guard use the new
shouldShowChangelog() helper so an item with empty readme + initial
release changelog doesn't leave an empty wrapper.
- Two-column widget showing top-3 solution templates and top-3 devices
fetched by totalInstallCount DESC, with installed-state fetching
(solution templates list + device counts)
- Section titles as .tb-title-link routerLinks to /iot-hub/solution-templates
and /iot-hub/devices
- Item cards open detail dialog via IotHubActionsService; solution template
cards show green check_circle badge in top-right when installed
- HomePageWidgetsModule now imports IotHubComponentsModule to resolve
IotHubActionsService
Device preview styling:
- Switch item card .tb-iot-hub-card-preview to white bg + bottom border
when item.type === DEVICE
- Switch detail dialog .dlg-preview to white bg + full border when DEVICE
Creates missing system images from application/src/main/data/resources/images
during LTS patch startup, mirroring the upgrade-path loadSystemResources logic.
Existing system images in the DB are left untouched.
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
Root pom.xml wired <skipAssembly>${pkg.skip.zip}</skipAssembly> at the
plugin-level <configuration> of maven-assembly-plugin inside the
always-active `packaging` profile's <pluginManagement>. Maven merges
plugin-level <configuration> into every execution of that plugin, so
-Dpkg.skip.zip=true (and the -Dpkg.skip=true alias that activates it)
suppressed any maven-assembly-plugin execution across the reactor -
not only the intended Windows ZIP execution.
In CE lts-4.2/4.3 this is latent (no CE module declares a non-ZIP
assembly execution), but it breaks downstream forks that do. PE's
rule-node-twilio-sms, for instance, declares a custom make-assembly
execution producing the classified -rule-node.jar consumed by
application's copy-pe-rule-nodes step; under -Dpkg.skip.zip=true that
assembly silently became a no-op and the downstream build failed to
resolve the classified artifact.
tools/pom.xml already sidesteps this via `combine.self="override"` on
its own <pluginManagement> - earlier evidence that the placement was
fragile.
Move <skipAssembly> into the `assembly` execution's own <configuration>
so it scopes only to the Windows ZIP execution.
Verified via mvn help:effective-pom on application/: with the fix,
<skipAssembly>true</skipAssembly> no longer appears at plugin-level
<configuration>, only inside the `assembly` <execution>.
Several testSaveProtoDeviceProfileWithInvalidRpcRequestSchema* tests
intermittently fail with:
org.thingsboard.server.dao.exception.TenantNotFoundException: Tenant
with id <fresh-tenant-uuid> not found
when the tenant created in @Before has not yet been populated in the
tenant profile cache by the time the request hits the partition-lookup
path (DefaultTenantRoutingInfoService -> TbTenantProfileCache ->
TenantService#findTenantById). The underlying request is idempotent
(the schema is invalid so it is rejected with 400 regardless of
retries), so wrap the doPost + status assertion in Awaitility with
Mockito.reset inside the retry block: only the last attempt's
invocations are visible to the subsequent verify* assertions.
Applies to all testSaveDeviceProfileWithInvalidRpcRequestProtoSchema
callers, including the currently-muted
testSaveProtoDeviceProfileWithInvalidRpcRequestSchemaRequestIdDateType.
The test asserts exactly 2 UserCredentialsUpdateMsg after creating a new
tenant-admin user, but the user activation flow can emit either 2 or 3
depending on timing:
- activateUserCredentials publishes CREDENTIALS_UPDATED (msg #1)
- setUserCredentialsEnabled publishes CREDENTIALS_UPDATED (msg #2)
- the initial USER ADDED edge event is processed asynchronously in
UserEdgeProcessor and bundles an extra UserCredentialsUpdateMsg when
it finds userCredentials.isEnabled() == true (i.e. activation
already raced past the ADDED event)
When the race goes the second way we end up with 1 UserUpdateMsg plus
3 UserCredentialsUpdateMsg, which currently fails the hard-coded
assertEquals(2, ...) assertion.
Accept both 2 and 3 UserCredentialsUpdateMsg instead of asserting an
exact count, matching the reality of the asynchronous edge event
pipeline.
Await cached resource data to become available after save eviction
before asserting, and await null after deletion. Prevents Mockito
verifyNoMoreInteractions(resourceService) failure caused by racing
background cache-load invocations.
Backport of 99334ba7fe from master.
- 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
Build hygiene for developers who rebuild lts-4.2 frequently: cleans the
pom.xml sources that generate noise without any code change.
- Pin maven-clean-plugin to 3.5.0 (latest stable) via a
<maven-clean-plugin.version> property, matching the convention already
used for surefire/install/deploy/jar plugins. Removes 55 "version is
missing" warnings plus the cascading "Some problems were encountered
while building the effective model" messages for every child module.
- Extend license-maven-plugin excludes for files that never carry a
license header: **/lombok.config, **/eslint.config.mjs,
**/config.monitoring, **/valkey-certs/**, **/data/certs/**, **/*.otf.
Directory-scoped patterns are used instead of broad extension globs
(**/*.crt, **/*.key, **/*.pem) so a stray cert dropped outside these
directories still raises a warning.
- Exclude sjk-jfr5 / sjk-jfr6 / sjk-nps transitive deps from cassandra-all
in tools/pom.xml. Their published POMs declare system-scope deps against
unresolved ${jmc5.path}, ${jmc6.path}, ${visualvm.path} properties,
producing 7 ERROR-level lines on every build. No ThingsBoard code imports
sjk, jmc, or netbeans profiler classes.
Net impact: 1040 -> 843 WARNING lines, 7 -> 0 ERROR lines. Build still
green. Full categorization of remaining warnings and Tier 2/3 migration
plan is tracked in issue #15481.
- postgres: 16.6 -> 18 (dao sql-test.properties / nosql-test.properties)
- timescaledb: latest-pg12 -> latest-pg18 (dao timescale-test.properties)
TimescaleDB pg15+ images crash on cgroup v2 CI hosts because
/docker-entrypoint-initdb.d/001_timescaledb_tune.sh evaluates
[ ${TS_TUNE_MEMORY} -gt ${FREE_BYTES} ] with an empty left operand
after the kernel reports the 64-bit max for /sys/fs/cgroup/memory.max.
Work around the upstream bug by setting NO_TS_TUNE=true.
The Testcontainers JDBC URL (jdbc:tc:timescaledb:...) does not support
docker env vars, so register a custom JdbcDatabaseContainerProvider
(TbTimescaleDBContainerProvider, activated via jdbc:tc:tbtimescaledb:...)
that starts a PostgreSQLContainer backed by timescale/timescaledb with
NO_TS_TUNE=true.
Production docker-compose files and tb-postgres image are untouched.
- 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