mirror of
https://github.com/ReCloudStudio/WebHooker.git
synced 2026-09-22 16:11:29 +00:00
fix(render): link title head to the event object URL
This commit is contained in:
parent
2f8a87048e
commit
7ac7bb7958
4 changed files with 13 additions and 31 deletions
11
AGENTS.md
11
AGENTS.md
|
|
@ -166,11 +166,12 @@ tests/__snapshots__/ # formatter snapshot golden files (toMatchSnapshot)
|
|||
`{repo}{#number}: {subject}` (e.g. `acme/widget#7: Add feature`). Repo comes from
|
||||
`payload.repository.full_name`; fall back to `t("common.repository")` when missing.
|
||||
- Only the repo head is hyperlinked (never the whole title). Drivers split the title via
|
||||
`splitMessageTitle`/`repoUrlFromMessage` (`server/lib/formatters/helpers.ts`): the Discord
|
||||
embed title is `{repo}{#number}` linked to the repository URL and `: {subject}` renders as
|
||||
the first description line; Telegram keeps the one-line title with an inline repo link and
|
||||
a plain subject. Messages without a colon separator (a `:` followed by a space) keep the
|
||||
legacy whole-title link — use colon-free wording for such titles.
|
||||
`splitMessageTitle` (`server/lib/formatters/helpers.ts`): the Discord embed title is
|
||||
`{repo}{#number}` linked to the event's object URL (`message.url`, e.g. the issue/PR/comment
|
||||
`html_url`) and `: {subject}` renders as the first description line; Telegram keeps the
|
||||
one-line title with an inline repo link and a plain subject. Messages without a colon
|
||||
separator (a `:` followed by a space) keep the legacy whole-title link — use colon-free
|
||||
wording for such titles.
|
||||
- Do NOT use `"Comment on org/repo"` / `"Review on org/repo"` prefixes. Comments, reviews
|
||||
and inline comments use the same `{repo}{#number}: {title}` title as their parent object.
|
||||
- All event-specific emoji live in `server/lib/formatters/` (via the `emojiPrefix` helper), never in
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@ import {
|
|||
MAX_FIELD_VALUE,
|
||||
MAX_FOOTER,
|
||||
MAX_TITLE,
|
||||
repoUrlFromMessage,
|
||||
splitMessageTitle,
|
||||
} from "../../formatters/helpers";
|
||||
|
||||
|
|
@ -27,10 +26,9 @@ export function renderNeutralMessage(message: NeutralMessage): FormattedMessage
|
|||
: undefined;
|
||||
|
||||
// Discord embed titles can only be linked as a whole, so only the repo head
|
||||
// goes into the title (linked to the repository); the `: subject` text is
|
||||
// rendered as the first line of the description, unlinked.
|
||||
// goes into the title (linked to the event's object URL); the `: subject`
|
||||
// text is rendered as the first line of the description, unlinked.
|
||||
const { head, subject } = splitMessageTitle(message.title);
|
||||
const repoUrl = repoUrlFromMessage(message.url);
|
||||
const rawDescription = subject
|
||||
? message.description
|
||||
? `${subject}\n${message.description}`
|
||||
|
|
@ -48,7 +46,7 @@ export function renderNeutralMessage(message: NeutralMessage): FormattedMessage
|
|||
embeds: [
|
||||
{
|
||||
title: cap(head, MAX_TITLE),
|
||||
url: subject ? repoUrl : message.url,
|
||||
url: message.url,
|
||||
color: message.color,
|
||||
description: cap(rawDescription, MAX_DESCRIPTION) || undefined,
|
||||
author: message.author
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import type { NeutralMessage } from "../../types";
|
||||
import { repoUrlFromMessage, splitMessageTitle } from "../../formatters/helpers";
|
||||
import { splitMessageTitle } from "../../formatters/helpers";
|
||||
|
||||
/** Telegram caps a single message at 4096 characters (HTML entities included). */
|
||||
const MAX_TEXT = 4096;
|
||||
|
|
@ -64,11 +64,11 @@ export function renderNeutralMessage(message: NeutralMessage): string {
|
|||
const parts: string[] = [];
|
||||
|
||||
// HTML allows partial links, so keep the `{repo}{#number}: {subject}` line
|
||||
// intact with only the repo head linked (the subject stays plain text).
|
||||
// intact with only the repo head linked to the event's object URL (the
|
||||
// subject stays plain text).
|
||||
const { head, subject } = splitMessageTitle(message.title);
|
||||
const repoUrl = repoUrlFromMessage(message.url);
|
||||
const title = subject
|
||||
? `<b>${repoUrl ? `<a href="${esc(repoUrl)}">${mdToHtml(head)}</a>` : mdToHtml(head)}: ${mdToHtml(subject)}</b>`
|
||||
? `<b>${message.url ? `<a href="${esc(message.url)}">${mdToHtml(head)}</a>` : mdToHtml(head)}: ${mdToHtml(subject)}</b>`
|
||||
: message.url
|
||||
? `<b><a href="${esc(message.url)}">${mdToHtml(message.title)}</a></b>`
|
||||
: `<b>${mdToHtml(message.title)}</b>`;
|
||||
|
|
|
|||
|
|
@ -31,23 +31,6 @@ export function splitMessageTitle(title: string): TitleParts {
|
|||
return { head: title.slice(0, idx), subject: title.slice(idx + 2) };
|
||||
}
|
||||
|
||||
/**
|
||||
* Repository URL derived from an event URL (origin + owner + repo). Returns
|
||||
* undefined when there is no URL to derive from — callers then render the
|
||||
* title without a link.
|
||||
*/
|
||||
export function repoUrlFromMessage(url: string | undefined): string | undefined {
|
||||
if (!url) return undefined;
|
||||
try {
|
||||
const parsed = new URL(url);
|
||||
const segments = parsed.pathname.split("/").filter(Boolean);
|
||||
if (segments.length >= 2) return `${parsed.origin}/${segments[0]}/${segments[1]}`;
|
||||
} catch {
|
||||
// not a parseable URL — no link
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
export function buildMessage(
|
||||
partial: Omit<Partial<NeutralMessage>, "title"> & { title: string },
|
||||
t: T,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue