openclaw/ui/src/ui/views/channels.telegram.ts

134 lines
4.6 KiB
TypeScript

import { html, nothing } from "lit";
import { formatAgo } from "../format";
import type { ChannelAccountSnapshot, TelegramStatus } from "../types";
import type { ChannelsProps } from "./channels.types";
import { renderChannelConfigSection } from "./channels.config";
export function renderTelegramCard(params: {
props: ChannelsProps;
telegram?: TelegramStatus;
telegramAccounts: ChannelAccountSnapshot[];
accountCountLabel: unknown;
}) {
const { props, telegram, telegramAccounts, accountCountLabel } = params;
const hasMultipleAccounts = telegramAccounts.length > 1;
const configDisabled = props.configSaving || props.configSchemaLoading;
const renderAccountCard = (account: ChannelAccountSnapshot) => {
const probe = account.probe as { bot?: { username?: string } } | undefined;
const botUsername = probe?.bot?.username;
const label = account.name || account.accountId;
return html`
<div class="account-card">
<div class="account-card-header">
<div class="account-card-title">
${botUsername ? `@${botUsername}` : label}
</div>
<div class="account-card-id">${account.accountId}</div>
</div>
<div class="status-list account-card-status">
<div>
<span class="label">Running</span>
<span>${account.running ? "Yes" : "No"}</span>
</div>
<div>
<span class="label">Configured</span>
<span>${account.configured ? "Yes" : "No"}</span>
</div>
<div>
<span class="label">Last inbound</span>
<span>${account.lastInboundAt ? formatAgo(account.lastInboundAt) : "n/a"}</span>
</div>
${account.lastError
? html`
<div class="account-card-error">
${account.lastError}
</div>
`
: nothing}
</div>
</div>
`;
};
return html`
<div class="card card--channel">
<div class="card-content">
<div class="card-title">Telegram</div>
<div class="card-sub">Bot status and channel configuration.</div>
${accountCountLabel}
${hasMultipleAccounts
? html`
<div class="account-card-list">
${telegramAccounts.map((account) => renderAccountCard(account))}
</div>
`
: html`
<div class="status-list" style="margin-top: 16px;">
<div>
<span class="label">Configured</span>
<span>${telegram?.configured ? "Yes" : "No"}</span>
</div>
<div>
<span class="label">Running</span>
<span>${telegram?.running ? "Yes" : "No"}</span>
</div>
<div>
<span class="label">Mode</span>
<span>${telegram?.mode ?? "n/a"}</span>
</div>
<div>
<span class="label">Last start</span>
<span>${telegram?.lastStartAt ? formatAgo(telegram.lastStartAt) : "n/a"}</span>
</div>
<div>
<span class="label">Last probe</span>
<span>${telegram?.lastProbeAt ? formatAgo(telegram.lastProbeAt) : "n/a"}</span>
</div>
</div>
`}
${telegram?.probe
? html`<div class="callout" style="margin-top: 12px;">
Probe ${telegram.probe.ok ? "ok" : "failed"} ·
${telegram.probe.status ?? ""} ${telegram.probe.error ?? ""}
</div>`
: nothing}
${renderChannelConfigSection({ channelId: "telegram", props })}
</div>
<div class="card-footer">
${telegram?.lastError
? html`<div class="callout danger" style="margin-bottom: 12px;">
${telegram.lastError}
</div>`
: nothing}
<div class="row" style="gap: 8px; align-items: center; flex-wrap: wrap;">
<ui-button @click=${() => props.onRefresh(true)}>
Probe
</ui-button>
<div style="margin-left: auto; display: flex; gap: 8px;">
<ui-button
variant="primary"
?disabled=${configDisabled || !props.configFormDirty}
@click=${() => props.onConfigSave()}
>
${props.configSaving ? "Saving…" : "Save Config"}
</ui-button>
<ui-button
?disabled=${configDisabled}
@click=${() => props.onConfigReload()}
>
Reload
</ui-button>
</div>
</div>
</div>
</div>
`;
}