Skip to content

Dashboard: fix Channels schema errors, auto-load Usage, align Telegram health#31307

Closed
stakeswky wants to merge 2 commits intoopenclaw:mainfrom
stakeswky:fix/dashboard-31247
Closed

Dashboard: fix Channels schema errors, auto-load Usage, align Telegram health#31307
stakeswky wants to merge 2 commits intoopenclaw:mainfrom
stakeswky:fix/dashboard-31247

Conversation

@stakeswky
Copy link
Copy Markdown
Contributor

Fixes #31247\n\n### Summary\n- Dashboard Usage tab now loads data on first open (previously only loaded after manual refresh).\n- Config schema analysis now reports unsupported paths precisely for additionalProperties schemas (avoids marking whole parent objects as unsupported).\n- Config search respects tag filters when matching section names/labels (prevents false positives that hide the empty-results UI).\n- Debug health: align Telegram running/lastStartAt with Channels snapshot to avoid misleading mismatch in the dashboard.\n\n### Notes\n- The schema fix targets the form renderer's unsupported-path tracking so Telegram channel fields like accounts/capabilities no longer force Raw mode for the entire Channels section.\n\n

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 6aa7a5a1ec

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment on lines +27 to 31
const [status, health, channels, models, heartbeat] = await Promise.all([
state.client.request("status", {}),
state.client.request("health", {}),
state.client.request("channels.status", { probe: false, timeoutMs: 8000 }),
state.client.request("models.list", {}),
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Keep debug refresh resilient when channels.status fails

loadDebug now bundles channels.status into the main Promise.all, so any failure from that extra call (for example an older gateway without the method, a channel plugin error, or a denied method) rejects the whole batch and prevents status, health, models, and last-heartbeat from updating. This makes the debug tab lose all core snapshots in cases where it previously still worked; fetch channels.status as a best-effort side request instead of making it a hard dependency.

Useful? React with 👍 / 👎.

@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented Mar 2, 2026

Greptile Summary

This PR delivers four fixes: auto-loading the Usage tab on first open, precise unsupportedPaths tracking for additionalProperties schemas (so Telegram channel fields no longer force the entire Channels section into Raw mode), tag-aware search matching in the config form, and aligning Telegram running/lastStartAt in the Debug health view from the live channels.status snapshot.

Key observations:

  • The channels.status request in debug.ts is bundled into the same Promise.all as all other critical debug requests (status, health, models.list, last-heartbeat). A failure of this optional endpoint (unavailable server version, network timeout, no channels configured) will cause the entire Debug panel to fail to load rather than gracefully skipping the Telegram alignment.
  • The Telegram health reconciliation only applies to the telegram channel key; other channels with the same running/lastStartAt mismatch remain unaddressed.
  • The config-form.analyze.ts and config-form.render.ts changes are well-targeted and correct.
  • The app-settings.ts Usage tab auto-load follows the established pattern for other tabs and is straightforward.

Confidence Score: 3/5

  • Mostly safe to merge, but the channels.status addition to Promise.all in debug.ts introduces a reliability regression for the Debug panel that should be addressed.
  • Four of the five changes are clean and low-risk. The reliability concern in debug.ts — where a non-critical channels.status call can cause the entire Debug panel to fail — is a real regression risk that lowers confidence. It doesn't affect production data but it could degrade the developer/admin debug experience.
  • ui/src/ui/controllers/debug.ts — the channels.status request should be made independently of the critical debug requests to avoid a single point of failure.

Last reviewed commit: 6aa7a5a

Copy link
Copy Markdown
Contributor

@greptile-apps greptile-apps Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

5 files reviewed, 2 comments

Edit Code Review Agent Settings | Greptile

Comment on lines +27 to 33
const [status, health, channels, models, heartbeat] = await Promise.all([
state.client.request("status", {}),
state.client.request("health", {}),
state.client.request("channels.status", { probe: false, timeoutMs: 8000 }),
state.client.request("models.list", {}),
state.client.request("last-heartbeat", {}),
]);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

channels.status failure will break the entire Debug panel

channels.status is added to the same Promise.all as the other critical debug requests (status, health, models.list, last-heartbeat). If this endpoint is unavailable (e.g., no channel configured, older gateway version, or a network timeout), the whole Promise.all rejects and the catch block sets debugCallError — meaning users lose all debug information, not just the Telegram health alignment.

Since the channel reconciliation is purely cosmetic (aligning running/lastStartAt), it should be fetched independently so it cannot poison the other requests:

const [status, health, models, heartbeat] = await Promise.all([
  state.client.request("status", {}),
  state.client.request("health", {}),
  state.client.request("models.list", {}),
  state.client.request("last-heartbeat", {}),
]);

// Non-critical: align Telegram fields from channels snapshot
const channelsSnapshot = await state.client
  .request("channels.status", { probe: false, timeoutMs: 8000 })
  .catch(() => null);

Or alternatively, use Promise.allSettled and handle the settled result for channels separately.

Prompt To Fix With AI
This is a comment left during a code review.
Path: ui/src/ui/controllers/debug.ts
Line: 27-33

Comment:
**`channels.status` failure will break the entire Debug panel**

`channels.status` is added to the same `Promise.all` as the other critical debug requests (`status`, `health`, `models.list`, `last-heartbeat`). If this endpoint is unavailable (e.g., no channel configured, older gateway version, or a network timeout), the whole `Promise.all` rejects and the catch block sets `debugCallError` — meaning users lose all debug information, not just the Telegram health alignment.

Since the channel reconciliation is purely cosmetic (aligning `running`/`lastStartAt`), it should be fetched independently so it cannot poison the other requests:

```ts
const [status, health, models, heartbeat] = await Promise.all([
  state.client.request("status", {}),
  state.client.request("health", {}),
  state.client.request("models.list", {}),
  state.client.request("last-heartbeat", {}),
]);

// Non-critical: align Telegram fields from channels snapshot
const channelsSnapshot = await state.client
  .request("channels.status", { probe: false, timeoutMs: 8000 })
  .catch(() => null);
```

Or alternatively, use `Promise.allSettled` and handle the settled result for `channels` separately.

How can I resolve this? If you propose a fix, please make it concise.

Comment on lines +41 to +51
const telegramRuntime = channelsSnapshot?.channels?.telegram;
const telegramHealth = (debugHealth?.channels as Record<string, unknown> | undefined)
?.telegram as Record<string, unknown> | undefined;
if (telegramHealth && telegramRuntime) {
if (typeof telegramRuntime.running === "boolean") {
telegramHealth.running = telegramRuntime.running;
}
if (telegramRuntime.lastStartAt != null) {
telegramHealth.lastStartAt = telegramRuntime.lastStartAt;
}
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Telegram-only reconciliation is asymmetric

The reconciliation logic only applies to the telegram key inside channels. If the same running/lastStartAt mismatch exists for other channel types (WhatsApp, Discord, etc.), they will remain inconsistent. Consider iterating over all keys in channelsSnapshot.channels and applying the same alignment for any channel that has a corresponding entry in debugHealth.channels:

const channelsHealth = debugHealth?.channels as Record<string, Record<string, unknown>> | undefined;
if (channelsHealth && channelsSnapshot?.channels) {
  for (const [name, runtime] of Object.entries(channelsSnapshot.channels)) {
    const healthEntry = channelsHealth[name];
    if (healthEntry && runtime) {
      if (typeof runtime.running === "boolean") healthEntry.running = runtime.running;
      if (runtime.lastStartAt != null) healthEntry.lastStartAt = runtime.lastStartAt;
    }
  }
}
Prompt To Fix With AI
This is a comment left during a code review.
Path: ui/src/ui/controllers/debug.ts
Line: 41-51

Comment:
**Telegram-only reconciliation is asymmetric**

The reconciliation logic only applies to the `telegram` key inside `channels`. If the same `running`/`lastStartAt` mismatch exists for other channel types (WhatsApp, Discord, etc.), they will remain inconsistent. Consider iterating over all keys in `channelsSnapshot.channels` and applying the same alignment for any channel that has a corresponding entry in `debugHealth.channels`:

```ts
const channelsHealth = debugHealth?.channels as Record<string, Record<string, unknown>> | undefined;
if (channelsHealth && channelsSnapshot?.channels) {
  for (const [name, runtime] of Object.entries(channelsSnapshot.channels)) {
    const healthEntry = channelsHealth[name];
    if (healthEntry && runtime) {
      if (typeof runtime.running === "boolean") healthEntry.running = runtime.running;
      if (runtime.lastStartAt != null) healthEntry.lastStartAt = runtime.lastStartAt;
    }
  }
}
```

How can I resolve this? If you propose a fix, please make it concise.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Dashboard: Channels schema errors, Usage page empty, Telegram health mismatch

2 participants