PROD-8423: .tb-main-content (the scroll container holding the router-outlet in home.component.html) keeps its scrollTop across route changes, so navigating from a scrolled-down IoT Hub home to a child page (e.g. Calculated Fields) opened the new page already scrolled. Angular's scrollPositionRestoration only handles window scroll, not arbitrary containers. Add a #mainContent ref, capture the ElementRef, and reset its scroll position in the existing (activate) handler so every route navigation lands at the top.
PROD-8420: .tb-iot-hub-sort-row was locked to height: 32px, so when many use-case filters were selected the chip-set wrapped to multiple lines but the row stayed one line tall and the card grid below rendered on top of the wrapped chips. Switch to min-height: 32px so the row keeps its baseline single-line height when empty but grows naturally with wrapped chips.
IotHubActionsService.deleteItem now returns true/false (no cancel-as-EMPTY) and updateItem returns string|boolean; callers no longer early-return on a null installed item and instead let the service produce a false, so the subscriber consistently fires. Installed-items table shows a translucent loading overlay during update/delete via isLoading + relative-positioned container. Replace mr-2 inline-block align-middle hacks on dialog button spinners with matButtonIcon, and use matButtonIcon for the check-for-updates button icon/spinner too.
Detail dialog non-CF/RC layout stacks the preview and description on lt-md instead of overflowing horizontally. Hero cluster moves up to 15% and title drops to 28px on the smallest viewport. getInstalledItemUrl for DEVICE descriptors now falls back to the first DEVICE entry in createdEntityIds when dashboardId is missing, so single-device packages still resolve to an entity URL.
* Fixed Advanced Widget Style Editor rendering
(cherry picked from commit 32ddf4336b)
* Moved styles to class for styles consistency
(cherry picked from commit 0b306159ba)
Wrap the creator description and social-link block in a flex column that takes the remaining height with overflow-y:auto, so long bios scroll inside the left rail instead of pushing the avatar off-screen. Lock the avatar's min-height to keep its circle from collapsing.
Unvalidated sortProperty on GET /api/iot-hub/installedItems was passed straight into Spring Data's Sort.by, so a client could trigger a 500 PropertyReferenceException by naming an unknown entity field. Add ALLOWED_SORT_PROPERTIES on IotHubInstalledItemEntity (createdTime, itemName, itemType, version) and call validatePageLink in the service so the failure is a 400 with a clear message.
If iotHubInstalledItemService.save throws after the local entity was already created, the entity was orphaned — visible in the tenant but invisible to IoT Hub update/delete. Extracted the per-type entity-deletion dispatch from deleteInstalledItem into a deleteEntityForDescriptor helper and call it from doInstallVersion and registerDeviceInstall on tracking-save failure. registerDeviceInstall now also wraps reportVersionInstalled best-effort to match doInstallVersion.
The post-install Thread.sleep was driven by installTimeoutMs from the uploaded solution.json with no upper bound — a malicious or misconfigured template could pin an HTTP worker thread indefinitely. Cap it at a configurable max (default 60s) exposed as iot-hub.max-install-timeout-ms with an IOT_HUB_MAX_INSTALL_TIMEOUT_MS env override.
Stream entries through a fixed buffer and abort with IOException when the archive crosses any of three configurable thresholds: total uncompressed bytes, per-entry uncompressed bytes, or entry count. Defaults — 200 MiB total, 50 MiB per entry, 10 000 entries — and env-var overrides IOT_HUB_MAX_UNCOMPRESSED_ARCHIVE_BYTES / IOT_HUB_MAX_UNCOMPRESSED_ENTRY_BYTES / IOT_HUB_MAX_ARCHIVE_ENTRY_COUNT are exposed under iot-hub in thingsboard.yml.
Add youtubeUrl to CreatorView and render it alongside the other creator social links. Reindents the link block so it nests correctly inside the surrounding flex column.