diff --git a/src/components/IotHub/iot-hub-dynamic-search.ts b/src/components/IotHub/iot-hub-dynamic-search.ts
index a88fe63a76..90fe044c54 100644
--- a/src/components/IotHub/iot-hub-dynamic-search.ts
+++ b/src/components/IotHub/iot-hub-dynamic-search.ts
@@ -5,6 +5,7 @@ import {
SEARCH_PAGE_SIZE,
DEFAULT_IOT_HUB_SORT_ID,
getCardVariant,
+ getCategoryForItemType,
getIotHubSortOption,
type IotHubItemType,
type ListingView,
@@ -61,7 +62,6 @@ function updateResultsCount(countEl: HTMLElement, totalResults: number): void {
// (SearchFilterBar input, IotHubSort selection, Pagination per-page).
const DEBOUNCE_MS = 300;
-const ITEM_TYPE_BY_TYPE = new Map(IOT_HUB_CATEGORIES.map((c) => [c.itemType, c]));
// FilterPanel section keys are translated to API/URL params here.
// `type` resolves to one of three names depending on the page's itemType
@@ -194,7 +194,7 @@ export function setupDynamicSearch(): void {
lastTrackedQuery = null;
return;
}
- const key = `${term} ${activeFilters}`;
+ const key = `${term} ${activeFilters}`;
if (key === lastTrackedQuery) return;
lastTrackedQuery = key;
window.dataLayer?.push({
@@ -318,7 +318,7 @@ export function setupDynamicSearch(): void {
): Array<{ slug: string; label: string; items: ListingView[] }> {
const byType = new Map();
for (const it of items) {
- const cat = ITEM_TYPE_BY_TYPE.get(it.itemType as IotHubItemType);
+ const cat = getCategoryForItemType(it.itemType);
if (!cat) continue;
const list = byType.get(cat.itemType) ?? [];
list.push(it);
@@ -339,8 +339,11 @@ export function setupDynamicSearch(): void {
if (itemType) {
// Single-category context (category page) — emit a flat grid
// without a section header, matching the static SSR shape.
- const cat = ITEM_TYPE_BY_TYPE.get(itemType as IotHubItemType);
- const categorySlug = cat?.slug ?? '';
+ const cat = getCategoryForItemType(itemType);
+ // Unknown item type has no public category — skip rather than emit
+ // cards with a `/iot-hub//slug/` href (matches groupResults).
+ if (!cat) return;
+ const categorySlug = cat.slug;
const variant = getCardVariant(itemType);
const grid = document.createElement('div');
grid.className = `iot-hub-grid iot-hub-grid--${variant}`;
diff --git a/src/components/IotHub/iot-hub-listing-card-bind.ts b/src/components/IotHub/iot-hub-listing-card-bind.ts
index 6b1a325301..b7c27b96e2 100644
--- a/src/components/IotHub/iot-hub-listing-card-bind.ts
+++ b/src/components/IotHub/iot-hub-listing-card-bind.ts
@@ -18,6 +18,11 @@ import { bindIotHubIcon } from './iot-hub-icon-bind';
// Sync for everything except the compact thumb glyph, which delegates to
// bindIotHubIcon (async for MDI). Callers don't await — the icon wrapper
// stays in its reset state until the SVG arrives.
+//
+// Runtime caller: iot-hub-dynamic-search.ts buildCardNode() binds every cloned
+// result card on the search / category / creator listing pages. (The
+// commented-out line in ListingCardTemplate.astro is an illustrative example,
+// not the live call site.)
export function bindListingCard(
root: HTMLElement,
@@ -27,8 +32,10 @@ export function bindListingCard(
): void {
const variant = getCardVariant(item.itemType);
- // Root href.
- root.setAttribute('href', `/iot-hub/${categorySlug}/${item.slug}/`);
+ // Root href. An empty categorySlug (item type with no public category, e.g.
+ // a type the site doesn't surface) would yield `/iot-hub//slug/` — guard it
+ // to '#' instead, matching getListingHref.
+ root.setAttribute('href', categorySlug ? `/iot-hub/${categorySlug}/${item.slug}/` : '#');
// DEVICE cards get a white preview background (vs the light gray default).
root.classList.toggle('iot-hub-card--device', item.itemType === 'DEVICE');
diff --git a/src/components/IotHub/iot-hub-listing-link-bind.ts b/src/components/IotHub/iot-hub-listing-link-bind.ts
index 5fb5acb6fe..cccfbc1380 100644
--- a/src/components/IotHub/iot-hub-listing-link-bind.ts
+++ b/src/components/IotHub/iot-hub-listing-link-bind.ts
@@ -1,5 +1,5 @@
import {
- IOT_HUB_CATEGORIES,
+ getCategoryForItemType,
getCardVariant,
getPlaceholderIcon,
resolveImage,
@@ -19,11 +19,10 @@ export const TYPE_FALLBACK_ICON: Record = {
DEVICE: 'memory',
};
-// Build the `/iot-hub/{category}/{slug}/` href for a listing, falling back
-// to `#` when the itemType isn't in IOT_HUB_CATEGORIES (defensive — every
-// known item type is registered).
+// Build the `/iot-hub/{category}/{slug}/` href for a listing, falling back to
+// `#` when the itemType has no public category (see getCategoryForItemType).
export function getListingHref(item: ListingView): string {
- const cat = IOT_HUB_CATEGORIES.find((c) => c.itemType === item.itemType);
+ const cat = getCategoryForItemType(item.itemType);
return cat ? `/iot-hub/${cat.slug}/${item.slug}/` : '#';
}
diff --git a/src/content/_includes/docs/edge/user-guide/edge-proxy.mdx b/src/content/_includes/docs/edge/user-guide/edge-proxy.mdx
deleted file mode 100644
index bcc94b4fc5..0000000000
--- a/src/content/_includes/docs/edge/user-guide/edge-proxy.mdx
+++ /dev/null
@@ -1,185 +0,0 @@
-import DocLink from '@components/DocLink.astro';
-import Tabs from '@components/Tabs.astro';
-import TabItem from '@components/TabItem.astro';
-import { Aside } from '@astrojs/starlight/components';
-
-Running ThingsBoard Edge behind a proxy server means all outbound communication — specifically the gRPC connection to the ThingsBoard server on port 17100 — is routed through the proxy instead of going directly to the internet.
-
-This setup is common in restricted network environments where direct internet access is deliberately blocked. Proxies also add a security layer by filtering and monitoring outbound traffic, and can cache resources to reduce bandwidth usage.
-
-
-
-
-## Prerequisites
-
-- A proxy server (HTTP or HTTPS) with its host, port, and credentials if required.
-- A list of addresses that should bypass the proxy (e.g., internal resources). Note that the Debian configuration uses `|` as the separator, not commas.
-- Java 17 installed.
-- ThingsBoard Edge installed and running.
-
-## Step 1. Modify the configuration file
-
-Edit `/etc/tb-edge/conf/tb-edge.conf` to enable the proxy:
-
-```bash
-sudo tee -a /etc/tb-edge/conf/tb-edge.conf > /dev/null <http://localhost:8080 and log in with your tenant credentials. Go to **Edge → Status** and confirm the **Status** field shows **Connected** — this confirms Edge is reaching the server through the proxy.
-
-
-
-## Troubleshooting
-
-Check Edge logs for errors:
-
-```bash
-cat /var/log/tb-edge/tb-edge.log | grep ERROR
-```
-
-Test connectivity through the proxy:
-
-```bash
-curl -x http://proxy_host:proxy_port https://your_tb_cloud_url
-```
-
-Confirm the proxy host is reachable:
-
-```bash
-ping proxy_host
-traceroute proxy_host
-```
-
-
-
-
-## Prerequisites
-
-- A proxy server (HTTP or HTTPS) with its host, port, and credentials if required.
-- A list of addresses that should bypass the proxy, including internal resources, the database host (`postgres`), and the ThingsBoard server IP or hostname.
-- ThingsBoard Edge installed and running via Docker Compose.
-- Docker and Docker Compose installed.
-
-
-
-## Step 1. Stop the container
-
-```bash
-docker compose stop
-```
-
-## Step 2. Update docker-compose.yml
-
-Open the file:
-
-```bash
-sudo nano docker-compose.yml
-```
-
-Add the following lines to the `environment` block:
-
-```yaml
- HTTP_PROXY: http://proxy_user:proxy_password@proxy_host:proxy_port
- HTTPS_PROXY: http://proxy_user:proxy_password@proxy_host:proxy_port
- NO_PROXY: localhost,127.0.0.1,postgres,YOUR_TB_SERVER_IP
-```
-
-Replace `YOUR_TB_SERVER_IP` with the IP address or hostname of your ThingsBoard server. If your proxy does not require authentication, omit the `proxy_user:proxy_password@` part from the URL.
-
-- **`HTTP_PROXY` / `HTTPS_PROXY`** — proxy URL for HTTP and HTTPS traffic. Example: `http://user:password@proxy.example.com:8080`
-- **`NO_PROXY`** — comma-separated list of addresses that bypass the proxy. Example: `localhost,127.0.0.1,postgres,thingsboard.example.com`
-
-## Step 3. Restart the containers
-
-```bash
-docker compose up -d && docker compose logs -f mytbedge
-```
-
-`mytbedge` is the default Edge container name. If you renamed your container, replace it in the command.
-
-Once started, open the Edge UI at http://localhost:8080 and log in with your tenant credentials. Go to **Edge → Status** and confirm the **Status** field shows **Connected** — this confirms Edge is reaching the server through the proxy.
-
-
-
-## Troubleshooting
-
-Verify proxy environment variables are set:
-
-```bash
-echo $HTTP_PROXY
-echo $HTTPS_PROXY
-echo $NO_PROXY
-```
-
-If not set, check inside the running container:
-
-```bash
-docker exec -it container_name printenv | grep -i proxy
-```
-
-Test internet access through the proxy from inside the container:
-
-```bash
-docker exec -it container_name curl -I https://google.com
-```
-
-Test connectivity to ThingsBoard Cloud through the proxy:
-
-```bash
-curl -x http://proxy_host:proxy_port https://your_tb_cloud_url
-```
-
-Check container logs for proxy-related errors:
-
-```bash
-docker logs container_name
-```
-
-
-
diff --git a/src/content/_includes/docs/edge/user-guide/provision-customer.mdx b/src/content/_includes/docs/edge/user-guide/provision-customer.mdx
deleted file mode 100644
index e69de29bb2..0000000000
diff --git a/src/content/_includes/docs/edge/user-guide/provision-dashboard.mdx b/src/content/_includes/docs/edge/user-guide/provision-dashboard.mdx
deleted file mode 100644
index e69de29bb2..0000000000
diff --git a/src/content/_includes/docs/edge/user-guide/provision-user.mdx b/src/content/_includes/docs/edge/user-guide/provision-user.mdx
deleted file mode 100644
index e69de29bb2..0000000000
diff --git a/src/content/docs/docs/edge/pe/user-guide/edge-proxy.mdx b/src/content/docs/docs/edge/pe/user-guide/edge-proxy.mdx
deleted file mode 100644
index 58bc12730a..0000000000
--- a/src/content/docs/docs/edge/pe/user-guide/edge-proxy.mdx
+++ /dev/null
@@ -1,8 +0,0 @@
----
-title: Connect Edge through a proxy
-description: "Configure ThingsBoard Edge to connect to the server through a proxy."
----
-import PageComponent from '@includes/docs/edge/user-guide/edge-proxy.mdx'
-import { Products } from '~/models/site.models'
-
-
diff --git a/src/content/docs/docs/edge/pe/user-guide/provision-customer.mdx b/src/content/docs/docs/edge/pe/user-guide/provision-customer.mdx
deleted file mode 100644
index 1ce8ddb090..0000000000
--- a/src/content/docs/docs/edge/pe/user-guide/provision-customer.mdx
+++ /dev/null
@@ -1,8 +0,0 @@
----
-title: Provision customer
-description: "Provision a customer from the ThingsBoard server to Edge."
----
-import PageComponent from '@includes/docs/edge/user-guide/provision-customer.mdx'
-import { Products } from '~/models/site.models'
-
-
diff --git a/src/content/docs/docs/edge/pe/user-guide/provision-dashboard.mdx b/src/content/docs/docs/edge/pe/user-guide/provision-dashboard.mdx
deleted file mode 100644
index 12de26ae68..0000000000
--- a/src/content/docs/docs/edge/pe/user-guide/provision-dashboard.mdx
+++ /dev/null
@@ -1,8 +0,0 @@
----
-title: Provision dashboard
-description: "Provision a dashboard from the ThingsBoard server to Edge."
----
-import PageComponent from '@includes/docs/edge/user-guide/provision-dashboard.mdx'
-import { Products } from '~/models/site.models'
-
-
diff --git a/src/content/docs/docs/edge/pe/user-guide/provision-user.mdx b/src/content/docs/docs/edge/pe/user-guide/provision-user.mdx
deleted file mode 100644
index 19f2e4602b..0000000000
--- a/src/content/docs/docs/edge/pe/user-guide/provision-user.mdx
+++ /dev/null
@@ -1,8 +0,0 @@
----
-title: Provision user
-description: "Manage user access on ThingsBoard Edge."
----
-import PageComponent from '@includes/docs/edge/user-guide/provision-user.mdx'
-import { Products } from '~/models/site.models'
-
-
diff --git a/src/content/docs/docs/edge/user-guide/edge-proxy.mdx b/src/content/docs/docs/edge/user-guide/edge-proxy.mdx
deleted file mode 100644
index 1400f1284d..0000000000
--- a/src/content/docs/docs/edge/user-guide/edge-proxy.mdx
+++ /dev/null
@@ -1,8 +0,0 @@
----
-title: Connect Edge through a proxy
-description: "Configure ThingsBoard Edge to connect to the server through a proxy."
----
-import PageComponent from '@includes/docs/edge/user-guide/edge-proxy.mdx'
-import { Products } from '~/models/site.models'
-
-
diff --git a/src/content/docs/docs/edge/user-guide/provision-customer.mdx b/src/content/docs/docs/edge/user-guide/provision-customer.mdx
deleted file mode 100644
index c60b062805..0000000000
--- a/src/content/docs/docs/edge/user-guide/provision-customer.mdx
+++ /dev/null
@@ -1,8 +0,0 @@
----
-title: Provision customer
-description: "Provision a customer from the ThingsBoard server to Edge."
----
-import PageComponent from '@includes/docs/edge/user-guide/provision-customer.mdx'
-import { Products } from '~/models/site.models'
-
-
diff --git a/src/content/docs/docs/edge/user-guide/provision-dashboard.mdx b/src/content/docs/docs/edge/user-guide/provision-dashboard.mdx
deleted file mode 100644
index 81d306febc..0000000000
--- a/src/content/docs/docs/edge/user-guide/provision-dashboard.mdx
+++ /dev/null
@@ -1,8 +0,0 @@
----
-title: Provision dashboard
-description: "Provision a dashboard from the ThingsBoard server to Edge."
----
-import PageComponent from '@includes/docs/edge/user-guide/provision-dashboard.mdx'
-import { Products } from '~/models/site.models'
-
-
diff --git a/src/content/docs/docs/edge/user-guide/provision-user.mdx b/src/content/docs/docs/edge/user-guide/provision-user.mdx
deleted file mode 100644
index 26da81e513..0000000000
--- a/src/content/docs/docs/edge/user-guide/provision-user.mdx
+++ /dev/null
@@ -1,8 +0,0 @@
----
-title: Provision user
-description: "Manage user access on ThingsBoard Edge."
----
-import PageComponent from '@includes/docs/edge/user-guide/provision-user.mdx'
-import { Products } from '~/models/site.models'
-
-
diff --git a/src/content/docs/docs/pe/reference/configuration-reference.mdx b/src/content/docs/docs/pe/reference/configuration-reference.mdx
deleted file mode 100644
index 803f9cd057..0000000000
--- a/src/content/docs/docs/pe/reference/configuration-reference.mdx
+++ /dev/null
@@ -1,6 +0,0 @@
----
-title: Configuration Reference
-description: ThingsBoard Professional Edition configuration reference.
----
-
-TODO
diff --git a/src/data/redirects.ts b/src/data/redirects.ts
index 2712cb2440..3dc786fd16 100644
--- a/src/data/redirects.ts
+++ b/src/data/redirects.ts
@@ -292,6 +292,23 @@ export const SINGLE_REDIRECTS: SingleRedirect[] = [
{ oldPath: 'edge/config/provision-user', target: '/docs/edge/user-guide/provision-customers-and-users/' },
{ oldPath: 'edge/config/subscribe-to-attribute', target: '/docs/edge/user-guide/attribute-sync/' },
{ oldPath: 'pe/edge/config/subscribe-to-attribute', target: '/docs/edge/pe/user-guide/attribute-sync/' },
+ // Orphan Edge user-guide pages removed — redirect to their live replacements.
+ // PE entries carry both the canonical `edge/pe/` source (the deleted page's own
+ // URL) and the legacy `pe/edge/` alias, so old links resolve in one hop instead
+ // of chaining through the pe/edge → edge/pe catch-all.
+ { oldPath: 'edge/user-guide/provision-customer', target: '/docs/edge/user-guide/provision-customers-and-users/' },
+ { oldPath: 'edge/pe/user-guide/provision-customer', target: '/docs/edge/pe/user-guide/provision-customers-and-users/' },
+ { oldPath: 'pe/edge/user-guide/provision-customer', target: '/docs/edge/pe/user-guide/provision-customers-and-users/' },
+ { oldPath: 'edge/user-guide/provision-user', target: '/docs/edge/user-guide/provision-customers-and-users/' },
+ { oldPath: 'edge/pe/user-guide/provision-user', target: '/docs/edge/pe/user-guide/provision-customers-and-users/' },
+ { oldPath: 'pe/edge/user-guide/provision-user', target: '/docs/edge/pe/user-guide/provision-customers-and-users/' },
+ { oldPath: 'edge/user-guide/provision-dashboard', target: '/docs/edge/user-guide/dashboards/' },
+ { oldPath: 'edge/pe/user-guide/provision-dashboard', target: '/docs/edge/pe/user-guide/dashboards/' },
+ { oldPath: 'pe/edge/user-guide/provision-dashboard', target: '/docs/edge/pe/user-guide/dashboards/' },
+ { oldPath: 'edge/user-guide/edge-proxy', target: '/docs/edge/user-guide/edge-proxy/debian/' },
+ { oldPath: 'edge/pe/user-guide/edge-proxy', target: '/docs/edge/pe/user-guide/edge-proxy/debian/' },
+ { oldPath: 'pe/edge/user-guide/edge-proxy', target: '/docs/edge/pe/user-guide/edge-proxy/debian/' },
+ { oldPath: 'pe/reference/configuration-reference', target: '/docs/pe/reference/' },
{ oldPath: 'edge/edge-architecture', target: '/docs/edge/reference/architecture/' },
{ oldPath: 'pe/edge/edge-architecture', target: '/docs/edge/pe/reference/architecture/' },
{ oldPath: 'edge/faq', target: '/docs/edge/why-thingsboard-edge/' },
@@ -1265,6 +1282,9 @@ export const SINGLE_REDIRECTS: SingleRedirect[] = [
* literal `?query` strings (no placeholder substitution).
*/
export const NON_DOCS_REDIRECTS: Record = {
+ // Removed marketing page
+ '/community/': '/',
+
// Services
'/services/support/': '/services/',
diff --git a/src/models/iot-hub.ts b/src/models/iot-hub.ts
index 1ada3c94a2..c0c4b46093 100644
--- a/src/models/iot-hub.ts
+++ b/src/models/iot-hub.ts
@@ -164,6 +164,20 @@ export const getCardVariant = (itemType: string): IotHubCardVariant => {
return cat?.card ?? 'big';
};
+// Single source of truth for resolving a listing's itemType to its IoT Hub
+// category. Returns undefined when the type has no public category — a type the
+// site doesn't surface (e.g. DASHBOARD). Callers building a URL fall back to
+// '#'; callers rendering a grid/section skip the item. Map-backed so per-item
+// hot loops (grouping search results) stay O(1).
+const CATEGORY_BY_ITEM_TYPE = new Map(
+ IOT_HUB_CATEGORIES.map((c) => [c.itemType, c] as const)
+);
+
+export const getCategoryForItemType = (
+ itemType: string
+): (typeof IOT_HUB_CATEGORIES)[number] | undefined =>
+ CATEGORY_BY_ITEM_TYPE.get(itemType as IotHubItemType);
+
// Default `cfType` → Material icon name.
const CF_TYPE_ICONS: Record = {
SIMPLE: 'calculate',
diff --git a/src/pages/community/index.astro b/src/pages/community/index.astro
deleted file mode 100644
index 6a91754021..0000000000
--- a/src/pages/community/index.astro
+++ /dev/null
@@ -1,192 +0,0 @@
----
-import BaseLayout from '@layouts/BaseLayout.astro';
----
-
-
-
-
-
-
-
-
Community
-
Events
-
-
-
-
-
-
Talk to Us!
-
We would love to hear from you, how you are using ThingsBoard, and what we can do to make it better.