refactor: centralize channel ui metadata

This commit is contained in:
Peter Steinberger
2026-01-20 13:10:26 +00:00
parent 6f9861bb9b
commit fdb171cb15
19 changed files with 240 additions and 68 deletions

View File

@@ -272,8 +272,11 @@ export function renderApp(state: AppViewState) {
error: state.cronError,
busy: state.cronBusy,
form: state.cronForm,
channels: state.channelsSnapshot?.channelOrder ?? [],
channels: state.channelsSnapshot?.channelMeta?.length
? state.channelsSnapshot.channelMeta.map((entry) => entry.id)
: state.channelsSnapshot?.channelOrder ?? [],
channelLabels: state.channelsSnapshot?.channelLabels ?? {},
channelMeta: state.channelsSnapshot?.channelMeta ?? [],
runsJobId: state.cronRunsJobId,
runs: state.cronRuns,
onFormChange: (patch) => (state.cronForm = { ...state.cronForm, ...patch }),

View File

@@ -4,11 +4,19 @@ export type ChannelsStatusSnapshot = {
channelLabels: Record<string, string>;
channelDetailLabels?: Record<string, string>;
channelSystemImages?: Record<string, string>;
channelMeta?: ChannelUiMetaEntry[];
channels: Record<string, unknown>;
channelAccounts: Record<string, ChannelAccountSnapshot[]>;
channelDefaultAccountId: Record<string, string>;
};
export type ChannelUiMetaEntry = {
id: string;
label: string;
detailLabel: string;
systemImage?: string;
};
export const CRON_CHANNEL_LAST = "last";
export type ChannelAccountSnapshot = {

View File

@@ -3,6 +3,7 @@ import { html, nothing } from "lit";
import { formatAgo } from "../format";
import type {
ChannelAccountSnapshot,
ChannelUiMetaEntry,
ChannelsStatusSnapshot,
DiscordStatus,
IMessageStatus,
@@ -85,6 +86,9 @@ ${props.snapshot ? JSON.stringify(props.snapshot, null, 2) : "No snapshot yet."}
}
function resolveChannelOrder(snapshot: ChannelsStatusSnapshot | null): ChannelKey[] {
if (snapshot?.channelMeta?.length) {
return snapshot.channelMeta.map((entry) => entry.id) as ChannelKey[];
}
if (snapshot?.channelOrder?.length) {
return snapshot.channelOrder;
}
@@ -148,7 +152,7 @@ function renderGenericChannelCard(
props: ChannelsProps,
channelAccounts: Record<string, ChannelAccountSnapshot[]>,
) {
const label = props.snapshot?.channelLabels?.[key] ?? key;
const label = resolveChannelLabel(props.snapshot, key);
const status = props.snapshot?.channels?.[key] as Record<string, unknown> | undefined;
const configured = typeof status?.configured === "boolean" ? status.configured : undefined;
const running = typeof status?.running === "boolean" ? status.running : undefined;
@@ -197,6 +201,21 @@ function renderGenericChannelCard(
`;
}
function resolveChannelMetaMap(
snapshot: ChannelsStatusSnapshot | null,
): Record<string, ChannelUiMetaEntry> {
if (!snapshot?.channelMeta?.length) return {};
return Object.fromEntries(snapshot.channelMeta.map((entry) => [entry.id, entry]));
}
function resolveChannelLabel(
snapshot: ChannelsStatusSnapshot | null,
key: string,
): string {
const meta = resolveChannelMetaMap(snapshot)[key];
return meta?.label ?? snapshot?.channelLabels?.[key] ?? key;
}
const RECENT_ACTIVITY_THRESHOLD_MS = 10 * 60 * 1000; // 10 minutes
function hasRecentActivity(account: ChannelAccountSnapshot): boolean {

View File

@@ -7,7 +7,7 @@ import {
formatCronState,
formatNextRun,
} from "../presenter";
import type { CronJob, CronRunLogEntry, CronStatus } from "../types";
import type { ChannelUiMetaEntry, CronJob, CronRunLogEntry, CronStatus } from "../types";
import type { CronFormState } from "../ui-types";
export type CronProps = {
@@ -19,6 +19,7 @@ export type CronProps = {
form: CronFormState;
channels: string[];
channelLabels?: Record<string, string>;
channelMeta?: ChannelUiMetaEntry[];
runsJobId: string | null;
runs: CronRunLogEntry[];
onFormChange: (patch: Partial<CronFormState>) => void;
@@ -46,6 +47,8 @@ function buildChannelOptions(props: CronProps): string[] {
function resolveChannelLabel(props: CronProps, channel: string): string {
if (channel === "last") return "last";
const meta = props.channelMeta?.find((entry) => entry.id === channel);
if (meta?.label) return meta.label;
return props.channelLabels?.[channel] ?? channel;
}