Merge to prod#394
Merged
Merged
Conversation
* Added all High-performance SCADA fluid system widgets docs * Added General high-performance SCADA symbols docs * Added all General high-performance SCADA symbols docs * Updated sidebar for SCADA widgets * Updated sidebar for SCADA widgets - Scales * Added High-performance SCADA oil & gas docs * Updated Get dashboard state object option for all widgets * Created Widgets Library navigation menu * Added a return button to the Widgets Library * Added Analogue gauges widgets docs * Updated Widgets doc * Updated links
* Updated variable * Updated variable
* Fix author bugs surfaced by external-link audit
- trendz-analytics: wrap `<code>http://thingsboard{...}:8080</code>` in a
JSX template literal so the remark-gfm autolinker no longer captures the
unevaluated expression and renders an `http://thingsboard%7Bprops.product`
anchor.
- device-library (68 files): replace `<a href="https://YOUR_TB_HOST">` and
the markdown-form variant with an inline-code placeholder
(`ThingsBoard account at \`YOUR_TB_HOST\``). The 2 `YOUR_TB_HOST/signup`
links in dsgw-210 now point at the real `https://thingsboard.cloud/signup`.
- partners/distributors: pre-render all 97 cards as static HTML with real
`<a href>` attributes so the link audit sees them, SEO indexes them, and
no-JS users get the list. Client-side filter toggles `hidden` on cards
instead of rebuilding the DOM. Country select is now pre-populated with
every country so filtering by country alone works; the reset button and
filter logic treat region/country as independent AND filters.
* Fix external 404s surfaced by link audit
- AgroSense data-converters (3 device pages, 12 URLs): the
raw.githubusercontent.com/thingsboard/data-converters paths used
`VENDORS/Makerfabs/...` but the public repo lays them out under
`VENDORS/AgroSense/...` (Makerfabs is the manufacturer, AgroSense is
the product line / folder name).
- gcp-marketplace.mdx: drop the broken
cloud.google.com/marketplace/docs/partners/integrated-saas/pricing
link wrapping "BYOL"; the page never existed, and the surrounding
sentence already explains the acronym in parentheses.
- edge-vs-cloud blog post: halosmartiot.com renamed `/news/` → `/blog/`.
- mqtt-broker/mqtt-over-ws: nodejs.org dropped
`/en/learn/getting-started/how-to-install-nodejs`; point at the
Download page since the link sits behind "Install Node.js".
- comfort-v2 leak sensor: replace the dead
`tektelic.com/wp-content/uploads/TEKTELIC_Comfort_Vivid_v2_UG.pdf`
with the official user guide on `knowledgehub.tektelic.com`.
- digital-ocean install guide: DigitalOcean migrated docs to a separate
subdomain — `www.digitalocean.com/docs/...` →
`docs.digitalocean.com/products/droplets/how-to/connect-with-ssh/`.
- azure-marketplace.mdx: bare `azure.microsoft.com` redirects to
`/en-us`; match the other 4 Azure references that already use the
locale-explicit URL.
* Resolve external link redirects to canonical targets
Replaces external URLs that were reachable only via a 3xx hop with
their final canonical destination. Removes the redirect roundtrip
and keeps the URL stable against further upstream restructuring.
Host/protocol moves:
- http://wiki.seeedstudio.com/, http://www.dragino.com/ → https
- chirpstack.io → www.chirpstack.io/
- angular.io → angular.dev/
- cloudflare.com → www.cloudflare.com/
- claude.ai/download → claude.com/download
- console.anthropic.com/settings/keys → platform.claude.com/...
- console.thethingsnetwork.org/ → console.cloud.thethings.network/
- docs.anthropic.com/.../claude-code/overview → code.claude.com/docs/en/overview
- cloud.google.com/<svc>/docs/... → docs.cloud.google.com/<svc>/docs/...
(16 specific URLs across compute, dns, k8s, memorystore, sql)
- cloud.google.com/sdk/downloads → docs.cloud.google.com/sdk/docs/install-sdk
Path renames:
- aws.amazon.com/marketplace/pp/B07V8S6JLG → /pp/prodview-wohnfuiqbf5w4
- aws.amazon.com/premiumsupport/.../route-53-create-alias-records/ → repost.aws/...
- docs.aws.amazon.com/cli/.../install-cliv2.html → getting-started-install.html
- developer.apple.com/app-store/submissions/ → /submitting/
- developer.apple.com/help/account/manage-keys/ → /help/account/keys/
- developer.apple.com/.../information_property_list/ → information-property-list/
- developer.mozilla.org/.../HTTP/Headers/ → HTTP/Reference/Headers/
- developers.cloudflare.com/fundamentals/get-started/reference/ → /reference/policies-compliances/
Trailing slash / canonical form:
- sixfab.com/alpon, /product/alpon-x4 (add /)
- lansitec.com/products/{lorawan-smart-badge-tracker,uwb-anchor} (add /)
- elastel.com/docs/ElastPro/{Getting_Started,intro} (add /)
- jetbrains.com/idea/download (add /)
- thethingsnetwork.org/docs/applications/mqtt/api (add /)
- namecheap.com KB article 9646 (add /; was the actual 4xx, the
bare-host one is bot-detection)
- docs.mistral.ai/getting-started/quickstart/ → quickstarts (plural;
canonical lives at /quickstarts without trailing slash)
* Address dead/problematic external domains from link audit
- Milesight (5 device pages): the manufacturer migrated from
milesight-iot.com to milesight.com and reorganized the path
(lorawan/<gateway|sensor>/<id> → iot/product/lorawan-<gateway|sensor>/<id>).
Updated UG56/UG65/UG67 gateway and WS101/WS202 sensor links to the
new canonical URLs.
- exp4j: trailing slash on objecthunter.net/exp4j → /exp4j/ to skip the
301. The underlying domain is fine for browsers; only the audit fails
on it because the server doesn't serve the intermediate certificate
and curl can't fetch it via AIA the way browsers do.
- Sensolyze: their domain (sensolyze.com) now serves the cyon.ch
"Domain nicht eingerichtet" placeholder — the hosting account is no
longer active and the company appears gone. Drop the `link` field
from the clients-feedback entry; FeedbackCard already renders the
logo without an anchor when link is absent.
* Update data.it-novum vol-6 video links; drop Voxney distributor
- thingsboard-user-meetup-2025 blog post: it-novum reorganized the
vol-6 meetup recordings under /mediathek/thingsboard/ — the old
/video/<slug>/ URLs 301 to the new path. Update all 9 links inline
to the canonical destination.
- Voxney PLSC, Inc. distributor: voxney.com returns a 500 from the
audit and looks defunct; remove the entry from the distributors
list (97 → 96 distributors).
* Fix geofencing example images on PE/PAAS and tooltip code background
- Pin Example 1 image sources to the existing -ce assets so the ImageGallery
resolver falls back to them on PE/PAAS instead of hitting a missing CDN URL
- Override --sl-color-bg-inline-code on .thumb-tooltip so inline <code> in
captions renders transparent against the dark tooltip background
* Address more external-link audit findings
- DockerComposeUpgradeSteps: handle deleted thingsboard-pe-docker-compose
release branches by rendering the manifests label as plain text, and fix
branch URL pattern (PE branches drop the trailing .0 for X.Y.0 releases).
- Update TPS company link to its new domain (tps.company → tps-factory.com).
- Replace dead TBMQ CE GitHub Discussions link with GitHub Issues.
- Drop obsolete ceGhTagOverride for Edge 4.0.1 (tag and package suffix now match).
…#391) * Pricing calculator: fix mobile overflow, sizing, and add-on row layout Four issues at 375-389px wide. The grid fix lives in `CalculatorInline.astro` (inline calculators only); the remaining rules live in `CalculatorModal.astro` and are inherited by every calculator that uses it — both the inline pricing calculators and the modal variants (TB and TBMQ × PAYG / Perpetual / Private Cloud). - `.calc-inline-body` grid used bare `1fr` / `3fr` for tracks, which resolves to `minmax(auto, …)` and lets each track grow to fit its children's min-content. The fixed-width 110px number input and non-wrapping button text in the summary panel pushed the inputs panel wider than the viewport; `.calc-inline`'s `overflow: hidden` then clipped the Reset button and summary values. Switched to explicit `minmax(0, …)` and added `min-width: 0` on `.calc-panel` so the panel can shrink inside the grid track. - `.calc-total-row` had no gap between the "Total" label and the amount, and the 26px amount + 20px label collided on a single line at 375px. Added `gap: $spacing-3` plus `media-down(sm)` overrides (label 20px → 16px, amount 26px → 18px) so the row stays one clean line on a phone. - `.calc-reset-btn` used `width: 25%`, which collapses to ~70px on a ~280px panel — the 8px/20px padding cramps the label and the button looks awkward. Added `media-down(sm)` rule to switch to `width: auto; min-width: 100px`. - `.calc-addon-result` used `height: 32px` (fixed) and the row default was 14px text on both sides. "Multi-AZ Deployment" + "Add to plan ($400.00)" overflowed the single-line cap and wrapped awkwardly mid-phrase. Switched to `min-height: 32px` so rows can grow, added `gap: $spacing-3` for breathing room, `white-space: nowrap` on the action button so "Add to plan ($X)" stays on one line, and a `media-down(sm)` rule that drops label + action + price to 12px so each add-on row stays as one horizontal pair (mirrors the desktop layout instead of stacking). * Landing: center feature-card icons on mobile The default `feature-card` variant's `.feature-card__inner` switches to `display: block; text-align: center` at `media-down(md)`, which should centre the inline-block `<img>` icon above the title. In practice the icons drifted noticeably left — `<img>` baseline alignment quirks plus the SVG's visual centroid sitting slightly off the geometric centre. Force `display: block; margin: 0 auto $spacing-4` on `.feature-card__icon` at the same breakpoint for guaranteed horizontal centring. Only the default variant is affected; `tbmq-card` and `pe` variants have their own icon rules. * Landing: fit rule-engine hover overlay to the video rectangle `<GifVideo>` renders `<video width="890" height="375">`. The scoped CSS only set `width: 100%`, so the height attribute kept the element 375px tall on narrow viewports while the video content scaled down to its intrinsic 890:375 aspect ratio inside that taller box — letterbox bands top and bottom. The absolutely-positioned `.overlay` (height: 100%) matched the element, not the visible content, so the dark hover overlay extended above and below the rule-engine diagram on mobile. Add `height: auto` so the element honours the intrinsic aspect ratio. The width/height HTML attributes still supply the ratio hint, so layout- shift is unchanged. * PE comparison table: align CE/PE columns and rework mobile layout Multiple issues on `/products/thingsboard-pe/` at mobile widths (≤500px) where the Features / CE / PE table layout was off: - `.comparison-header` had no horizontal padding while `.comparison-row` had `padding: 12px 20px`. The header was 40px wider in its flex distribution area than each body row, shifting every header column's centre ~13-18px right of the checkmarks beneath. Added matching `padding: 0 1.25rem` to the header and dropped the now-redundant `padding-left` on the header's `.col-feature`. - Standard IoT Protocols' label carried an unbreakable token `(MQTT/CoAP/HTTP/SNMP/LWM2M)`. With `overflow-wrap: normal`, `.col-feature`'s min-content was pinned to ~150px at 12px, blowing past its flex share and squeezing `.col-ce` / `.col-pe` narrower than the 20px icon — the icons rendered smaller and drifted right in that one row. Switched the slashes to commas + spaces so the label wraps naturally, and added `overflow-wrap: anywhere` on `.col-feature` as a defence against future labels with similar unbreakable tokens. - Added `flex-shrink: 0` on the CE/PE icon images so they never shrink with their parent flex cell, regardless of min-content pressure elsewhere in the row. - Tightened CE/PE columns at ≤500px (flex 0.4 → 0.18 in both header and body rows) so the icon columns sit close together near the right edge and the Features label gets the freed-up width. Header and body share the same flex, so the "CE" / "PE" letters sit directly above the checkmarks below. - The Support Model row contains text cells ("Community" / "Advanced + SLA") that overflow a 0.18-wide cell. Added a `:has(.cell-link)` override that widens those cells to flex 0.45 — icon rows stay tight, text rows breathe. * Pricing calculators: drop execCommand clipboard fallback The six pricing calculators' "Copy summary" buttons tried the modern `navigator.clipboard.writeText` first, then fell back through a hidden `<textarea>` + `document.execCommand('copy')` if the async API rejected. Drop the fallback: - thingsboard.io serves over HTTPS, so the primary path always succeeds for production users. - Modern Chrome/Firefox/Safari/Edge have shipped `Clipboard.writeText` for 5+ years (Chrome 66 Apr 2018, FF 63 Oct 2018, Safari 13.1 Mar 2020). - The fallback only fired in `pnpm dev --host` LAN previews (non-secure context) and inside iframes with `clipboard-write` denied by Permissions- Policy — neither relevant for real thingsboard.io traffic. - `document.execCommand` is `@deprecated` in lib.dom.d.ts, so the six call sites each produced a `ts(6387)` hint; dropping the block clears them and shaves ~17 lines per calculator (net -102). If the primary path rejects for some unusual user, the Copy button just won't flash "copied" — the rest of the calculator stays functional and the user can still hit Download (separate code path) or select the summary by hand. Affects all six calculators (TB and TBMQ × PAYG / Perpetual / Private Cloud). * Pricing background: hide rotated boundary cuts at wide viewports At >= ~2000px viewports, the pricing page's animated wave background showed faint diagonal cuts at the -28deg rotation angle — the SVG's internal element/path boundaries leaking through against the page background. Three sources, three fixes: - Wave paths (4×) were filled regions bounded vertically at y=0 and y=1800. The `<animateTransform>` translation by one period (-900, -600, or -450) brought those horizontal closures into the visible viewBox at certain animation phases, where rotation turned them into diagonal hairlines. Extended each path's body by one period above (M-point) and one period below (last L-line) — closures now sit at y=-period and y=1800+period, far outside any visible viewport position. Loop seamlessness is preserved because translation is still by exactly one period. - Radial-glow `<rect>` backdrops (2×) spanned only the original viewBox 0..900 range. After the wave-path extension, they were the only layer ending at y=0 / y=900, so the boundary became visible as a faint opacity step (gradient-glow + waves below vs. waves alone above). Stretched both rects to -900..3600 to match the wave coverage, and flipped the two radial gradients to `gradientUnits="userSpaceOnUse"` with absolute centres so the glows stay anchored to their original positions instead of stretching downward with the larger rect. - The SVG element's own rotated top/bottom edge (the rectangle of the <svg> element itself, 110% × 180% of viewport). With path + gradient extensions in place this is the only remaining hard edge. Added a CSS `mask-image: linear-gradient(...)` fade on the SVG element — applied in local coordinate space before transform, so the fade direction rotates with the SVG and tracks the boundary perfectly. Hard rectangle edge → smooth fade-to-transparent. Both -webkit- and unprefixed forms for breadth (Safari pre-15.4). Result: no visible diagonal artifacts at any tested viewport size; the existing `prefers-reduced-motion: reduce` rule and dark-theme tinting are untouched. * Pricing calculators: replace ∞ glyph with tabler:infinity icon Slider tail tick labels rendered the infinity symbol via the unicode `∞` (U+221E) glyph at 28px font-size. Cross-platform font metrics for this character vary a lot — on Android it renders noticeably taller than on desktop, and Chrome's mobile text autosizing can boost it further, making the ∞ look disproportionately huge next to the 12px numeric tick labels. Replaced the glyph with the tabler `infinity` SVG icon so the visual size is pinned to a CSS dimension (18px) and stays consistent across Android / iOS / desktop: - 5 static .astro templates (TbPayg, TbPerpetual, TbmqPayg, TbmqPerpetual, TbmqPrivateCloud) — `<span class="…infinity">∞</span>` becomes `<span class="…infinity"><Icon name="tabler:infinity" /></span>`. The `Icon` component was already imported in each file. - TbPrivateCloudCalculator builds its slider ticks in client-side JS (`buildTicks()` runs in the browser, can't call Astro's <Icon>) — added an `INFINITY_ICON` string constant that inlines the same SVG markup astro-icon emits (`width="1em"`, `currentColor` stroke), used when the tick label equals `'∞'`. - Shared `.calc-tick-label.infinity` rule in CalculatorModal.astro went from `font-size: 28px; font-weight: 300; line-height: 24px` (sizing a text glyph) to `font-size: 18px; line-height: 1` (sizing the 1em SVG). `currentColor` stroke picks up the existing tick-label hover state for free, so no extra interaction rules were needed. * Use-case diagrams: replace generic schema, resize to 1038px (PROD-8078) PROD-8078 flagged that the IoT-architecture diagram on most use-case pages was the wrong one (the LoRaWAN/Sigfox sensor-tree variant from the old environment-monitoring layout, mistakenly mounted as the generic `use-case.svg` for nine other pages) and that all schema diagrams should be 1038px wide instead of 720px. - Re-exported 14 schemas from Figma `FUX2Li59wxdYASam49kH05` via the REST API at scale=1.4417 → native 1038px width, then ran `svgo --multipass` (≈68% size reduction off the raw export). Final files are 220-260 KB SVG. - `use-case.svg` + `use-case-dark.svg` now hold the simple Modbus / OPC-UA / BACnet / Other-Protocols → IoT Gateway → ThingsBoard → Alarms/Dashboards/Notifications/Data Lakes diagram (Figma frame `1364:13291` / `1235:28448`). The nine pages still pointing at `use-case.svg` — smart-office, smart-retail, smart-farming, site-fleet-tracking, smart-metering, air-quality-monitoring, smart-irrigation, waste-management, tank-level-monitoring — pick up the new diagram automatically with no data-file edits. - Refreshed the other six per-page diagrams from their respective Figma frames at the same 1038 width: smart-energy, water-metering, health-care, swimming-pool, oil-and-gas, energy-management (each light+dark pair). - Added two new files: `environment-monitoring.svg` + `environment-monitoring-dark.svg` (Figma frames `1364:13314` / `1364:12915`) holding the LoRaWAN/Sigfox variant — what was previously inside `use-case.svg`. PROD-8078 marks env-monitoring as "ok", so its diagram is preserved verbatim, just relocated to a page-specific path and brought up to 1038px. - `src/data/use-cases/environment-monitoring.ts:56` — `schemeSrc` now points to the new env-monitoring-specific file. * ImageGallery: opt out of PhotoSwipe lightbox for use-case schemas The architecture schemas on use-case pages (rendered by `SolutionStructure.astro`) are already full content-width — there's no extra detail revealed by opening them in the lightbox. Click-to-zoom also reads as more awkward than helpful: PhotoSwipe v5's backdrop-filter blur on a mostly-white page produces a pale gray backdrop instead of the strongly dark feel the lightbox has on docs pages with their dark sidebars (same computed styles, different page colors behind the blur). - New `noLightbox?: boolean` prop on `<ImageGallery>`. When set on a single-image gallery (and not in `cardMode`), the figure renders the `<img>` (or interactive SVG) directly without the `<a class="gallery-thumb">` wrapper. The parent picks up an `image-gallery--no-lightbox` modifier class for any future styling hook. - PhotoSwipe's init uses `children: '.gallery-thumb'`. With no `.gallery-thumb` element inside a no-lightbox gallery, the binding is a no-op for that gallery — no JS branch needed. - CSS rule for `.image-gallery--no-lightbox .single-image > img` / `> :global(svg)` mirrors the sizing rules of `.single-thumb img` so the image fills the column the same way. - Light/dark variant swap (`.light-only` / `.dark-only`) continues to work — those rules target the `<img>` class directly, not the wrapper. - `SolutionStructure.astro` passes `noLightbox` to its single-image ImageGallery. Other ImageGallery usages are untouched. * Use-case schemas: render inline theme-aware (drop noLightbox path) Reverses commit 562c247 ("ImageGallery: opt out of PhotoSwipe lightbox for use-case schemas") and replaces the indirection with a direct inline render in `SolutionStructure.astro`. Why the change of approach: the ImageGallery `noLightbox` prop was a narrow opt-out used in exactly one place (use-case architecture schemas), and it still left the schema rendering coupled to the gallery's product-suffix resolution / PhotoSwipe scaffolding even though neither was being used. Rendering the schema inline keeps SolutionStructure self-contained and removes a special-case branch from a component that's shared across docs. - Revert all noLightbox additions in `ImageGallery.astro` (prop, Astro.props destructure, JSX branch, CSS rule, modifier class). - `SolutionStructure.astro` now resolves the schema asset via `import.meta.glob('/src/assets/schemas/*.svg', { eager: true })`, picks up an optional `-dark.svg` sibling, and renders a `<figure class="uc-scheme">` with two `<img>` children using `.uc-scheme-img--light` / `.uc-scheme-img--dark` modifier classes. - Theme swap is a plain `[data-theme='dark']` CSS rule pair (no JS, no PhotoSwipe binding); when a dark variant doesn't exist the light image stays visible in both themes. - Optional `schemeCaption` renders as a `<figcaption>` (was lightbox- only in the ImageGallery path, so this is a small UX bonus for schemas that supply one). * ImageGallery: clear inherited --color-bg on PhotoSwipe root Starlight defines `--color-bg` globally; PhotoSwipe v5's root element (`.pswp`) inherits it, which paints a tinted (non-transparent) layer behind the lightbox content on non-docs pages where the page bg differs from the Starlight default. Override with `--color-bg: transparent` so the `.pswp__bg` backdrop-filter blur is the only thing painted behind the image, regardless of which page hosts the gallery. * Pricing calculators: silently swallow clipboard rejections `navigator.clipboard.writeText(text).then(flashCopied)` without a `.catch` lets any rejection bubble as an unhandled promise rejection. The most common real-world trigger isn't the insecure-context case the old execCommand fallback covered — it's Safari/Firefox throwing `NotAllowedError: Document is not focused` when focus shifts to another window/iframe between the click and the promise settling. That path rejects on HTTPS too. Add a no-op `.catch(() => {})` to all six calculators so rejections fail silently (no `.copied` flash) without surfacing as console errors or hitting any error tracker. The insecure-context execCommand fallback is intentionally not restored. Addresses PR #391 inline review comment from vvlladd28.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
Type of change
src/content/docs/**)src/content/_includes/**)src/components/**,src/styles/**)src/pages/**,src/data/**)src/data/redirects.ts)releaseskill)Affected products
Related issues
Checklist
pnpm checkpasses (Astro / TypeScript)pnpm lint:eslintpassespnpm lint:slugcheckpasses (required if pages were added/renamed/moved across languages)pnpm lint:linkcheckpasses locally — required to merge; run it before requesting review (usepnpm lint:linkcheck:nobuildif you already ran a build)src/data/redirects.ts, andpnpm generate:redirectswas runsrc/data/versions.ts