mirror of
https://github.com/mauriceboe/TREK.git
synced 2026-10-23 07:26:30 +00:00
fix(ci): collection lookups typed as partial, card formatting, two unused exports, and the format check says when Prettier gave up
This commit is contained in:
@@ -31,11 +31,16 @@ export async function isFormatted(path) {
|
||||
if (!options) throw new RatchetError(`no Prettier config applies to ${path}`);
|
||||
try {
|
||||
return await prettier.check(readText(path), { ...options, filepath: path });
|
||||
} catch {
|
||||
} catch (err) {
|
||||
stopped.set(path, String(err instanceof Error ? err.message : err).split('
|
||||
')[0]);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/** Why Prettier gave up on a file, by its path, so the failure line can say it was not about style. */
|
||||
const stopped = new Map();
|
||||
|
||||
/** The files under root that Prettier would rewrite, keyed by their path from root. */
|
||||
export async function unformatted(root) {
|
||||
const found = [];
|
||||
@@ -74,6 +79,8 @@ export async function check({
|
||||
if (list) for (const key of found) log(`${allowed.has(key) ? 'listed' : 'new '} ${key}`);
|
||||
for (const key of fresh) {
|
||||
error(`FAIL ${key} is not formatted. Run: npx prettier --write ${key}`);
|
||||
const why = stopped.get(join(root, key));
|
||||
if (why) error(` Prettier could not format it: ${why}`);
|
||||
}
|
||||
for (const key of stale) {
|
||||
error(`FAIL ${key} is listed in scripts/format-baseline.json but is formatted now or gone.`);
|
||||
|
||||
@@ -33,10 +33,7 @@ const passport: AtlasPassportCard = {
|
||||
kind: 'atlasPassport',
|
||||
countries: { visited: 23, planned: 4, idea: 0 },
|
||||
totals: { trips: 48, days: 410, places: 990, cities: 312, flownKm: 182_300 },
|
||||
flags: [
|
||||
...CODES.map((code) => ({ code, status: 'visited' as const })),
|
||||
{ code: 'MA', status: 'planned' as const },
|
||||
],
|
||||
flags: [...CODES.map((code) => ({ code, status: 'visited' as const })), { code: 'MA', status: 'planned' as const }],
|
||||
moreFlags: 4,
|
||||
continents: [
|
||||
{ name: 'Europe', visited: 14, planned: 2 },
|
||||
|
||||
@@ -19,14 +19,13 @@ import type { ChangeItem } from '../../assistantParts';
|
||||
*/
|
||||
|
||||
/** How a country's or a region's standing reads. A table, so each word is named where it is read. */
|
||||
export const STATUS_LOOK: Readonly<Record<AtlasStatusAfter, { Icon: LucideIcon; tone: PillTone; labelKey: string }>> =
|
||||
{
|
||||
visited: { Icon: Check, tone: 'success', labelKey: 'assistant.card.atlas.status.visited' },
|
||||
planned: { Icon: CalendarClock, tone: 'info', labelKey: 'assistant.card.atlas.status.planned' },
|
||||
idea: { Icon: Lightbulb, tone: 'neutral', labelKey: 'assistant.card.atlas.status.idea' },
|
||||
none: { Icon: CircleDashed, tone: 'neutral', labelKey: 'assistant.card.atlas.status.none' },
|
||||
unknown: { Icon: Briefcase, tone: 'info', labelKey: 'assistant.card.atlas.status.unknown' },
|
||||
};
|
||||
export const STATUS_LOOK: Readonly<Record<AtlasStatusAfter, { Icon: LucideIcon; tone: PillTone; labelKey: string }>> = {
|
||||
visited: { Icon: Check, tone: 'success', labelKey: 'assistant.card.atlas.status.visited' },
|
||||
planned: { Icon: CalendarClock, tone: 'info', labelKey: 'assistant.card.atlas.status.planned' },
|
||||
idea: { Icon: Lightbulb, tone: 'neutral', labelKey: 'assistant.card.atlas.status.idea' },
|
||||
none: { Icon: CircleDashed, tone: 'neutral', labelKey: 'assistant.card.atlas.status.none' },
|
||||
unknown: { Icon: Briefcase, tone: 'info', labelKey: 'assistant.card.atlas.status.unknown' },
|
||||
};
|
||||
|
||||
/** The continents in the Atlas page's own words. */
|
||||
export const CONTINENT_LABEL: Readonly<Record<AtlasCardContinent, { labelKey: string }>> = {
|
||||
|
||||
@@ -126,7 +126,9 @@ export default function ExpensesCard({ cards }: { cards: readonly CardEntry[] })
|
||||
actions={<CardOpenButton target={costsTarget()} labelKey="assistant.card.budget.open" />}
|
||||
/>
|
||||
<CardRows>
|
||||
{card.rows.map((row, i) => <ExpenseRow key={row.id ?? `new-${i}`} row={row} />)}
|
||||
{card.rows.map((row, i) => (
|
||||
<ExpenseRow key={row.id ?? `new-${i}`} row={row} />
|
||||
))}
|
||||
</CardRows>
|
||||
<ExpensesFoot card={card} />
|
||||
</CardFrame>
|
||||
|
||||
@@ -65,7 +65,9 @@ export default function PaymentsCard({ cards }: { cards: readonly CardEntry[] })
|
||||
actions={<CardOpenButton target={costsTarget()} labelKey="assistant.card.budget.open" />}
|
||||
/>
|
||||
<CardRows>
|
||||
{card.rows.map((row, i) => <PaymentRow key={row.id ?? `new-${i}`} row={row} />)}
|
||||
{card.rows.map((row, i) => (
|
||||
<PaymentRow key={row.id ?? `new-${i}`} row={row} />
|
||||
))}
|
||||
</CardRows>
|
||||
<CardMore count={card.more} target={costsTarget()} />
|
||||
</CardFrame>
|
||||
|
||||
@@ -118,6 +118,3 @@ export interface CardView<K extends TrekCardKind> {
|
||||
runnable?(card: TrekCardOf<K>): boolean;
|
||||
startsExcluded?(card: TrekCardOf<K>): boolean;
|
||||
}
|
||||
|
||||
/** The view of a kind not drawn yet: it renders nothing, so its cards are left out until a package fills it. */
|
||||
export const PENDING_VIEW = {} satisfies CardView<TrekCardKind>;
|
||||
|
||||
@@ -181,7 +181,9 @@ function Words({ bubble, spot, own }: Pick<BubbleProps, 'bubble' | 'spot' | 'own
|
||||
reply={bubble.reply}
|
||||
text={<MessageText text={bubble.text} plain />}
|
||||
>
|
||||
{bubble.files.map((file) => <ChatFile key={file.fileId} file={file} tripId={tripId} />)}
|
||||
{bubble.files.map((file) => (
|
||||
<ChatFile key={file.fileId} file={file} tripId={tripId} />
|
||||
))}
|
||||
</ChatBubble>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -146,7 +146,9 @@ export default function CollabNotesBlock({ cards }: { cards: readonly CardEntry[
|
||||
actions={<CardOpenButton target={NOTES_TARGET} labelKey="assistant.card.collab.openNotes" />}
|
||||
/>
|
||||
<div className={`mt-2 gap-2 ${density === 'roomy' ? 'grid grid-cols-2' : 'flex flex-col'}`}>
|
||||
{notes.map((note, index) => <NoteView key={note.noteId ?? `new-${index}`} note={note} state={null} />)}
|
||||
{notes.map((note, index) => (
|
||||
<NoteView key={note.noteId ?? `new-${index}`} note={note} state={null} />
|
||||
))}
|
||||
</div>
|
||||
<CardMore count={more} labelKey="assistant.card.collab.moreNotes" target={NOTES_TARGET} />
|
||||
</CardFrame>
|
||||
@@ -157,7 +159,9 @@ export default function CollabNotesBlock({ cards }: { cards: readonly CardEntry[
|
||||
export function CollabNotesBody({ card, item }: { card: NotesCard; item: ChangeItem }) {
|
||||
return (
|
||||
<div className="flex flex-col gap-2">
|
||||
{card.notes.map((note, index) => <NoteView key={note.noteId ?? `new-${index}`} note={note} state={item.state} />)}
|
||||
{card.notes.map((note, index) => (
|
||||
<NoteView key={note.noteId ?? `new-${index}`} note={note} state={item.state} />
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -133,7 +133,9 @@ export default function CollabPollsBlock({ cards }: { cards: readonly CardEntry[
|
||||
actions={<CardOpenButton target={POLLS_TARGET} labelKey="assistant.card.collab.openPolls" />}
|
||||
/>
|
||||
<div className="mt-2 flex flex-col gap-2">
|
||||
{polls.map((poll, index) => <PollView key={poll.pollId ?? `new-${index}`} poll={poll} state={null} />)}
|
||||
{polls.map((poll, index) => (
|
||||
<PollView key={poll.pollId ?? `new-${index}`} poll={poll} state={null} />
|
||||
))}
|
||||
</div>
|
||||
<CardMore count={more} labelKey="assistant.card.collab.morePolls" target={POLLS_TARGET} />
|
||||
</CardFrame>
|
||||
@@ -144,7 +146,9 @@ export default function CollabPollsBlock({ cards }: { cards: readonly CardEntry[
|
||||
export function CollabPollsBody({ card, item }: { card: PollsCard; item: ChangeItem }) {
|
||||
return (
|
||||
<div className="flex flex-col gap-2">
|
||||
{card.polls.map((poll, index) => <PollView key={poll.pollId ?? `new-${index}`} poll={poll} state={item.state} />)}
|
||||
{card.polls.map((poll, index) => (
|
||||
<PollView key={poll.pollId ?? `new-${index}`} poll={poll} state={item.state} />
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -40,7 +40,7 @@ function placesCardOf(card: TrekCard | null): CollectionPlacesCard | null {
|
||||
}
|
||||
|
||||
/** The saved place a change card is about: its only one. */
|
||||
export function firstPlace(card: TrekCard | null): CollectionCardPlace | null {
|
||||
function firstPlace(card: TrekCard | null): CollectionCardPlace | null {
|
||||
const places = placesCardOf(card)?.places ?? [];
|
||||
return places.length === 1 ? (places[0] ?? null) : null;
|
||||
}
|
||||
|
||||
@@ -91,7 +91,9 @@ export function JourneyEntryFacts({ item }: { card: JourneyEntriesCard; item: Ch
|
||||
tone="info"
|
||||
/>
|
||||
))}
|
||||
{states.map((row) => <StateChange key={row.field ?? row.labelKey} row={row} />)}
|
||||
{states.map((row) => (
|
||||
<StateChange key={row.field ?? row.labelKey} row={row} />
|
||||
))}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -37,10 +37,7 @@ const row = (id: number | null, name: string, over: Partial<PackingCardItem> = {
|
||||
...over,
|
||||
});
|
||||
|
||||
const packing = (
|
||||
groups: Array<[string, PackingCardItem[]]>,
|
||||
over: Partial<PackingListCard> = {}
|
||||
): PackingListCard => ({
|
||||
const packing = (groups: Array<[string, PackingCardItem[]]>, over: Partial<PackingListCard> = {}): PackingListCard => ({
|
||||
kind: 'packingList',
|
||||
source: { type: 'trip' },
|
||||
groupBy: 'category',
|
||||
|
||||
@@ -139,15 +139,7 @@ export interface RunEntry {
|
||||
}
|
||||
|
||||
/** A change in a run: the round include choice, the tile of what it does, and the row. */
|
||||
function RunRow({
|
||||
entry,
|
||||
excluded,
|
||||
onToggle,
|
||||
}: {
|
||||
entry: RunEntry;
|
||||
excluded: boolean;
|
||||
onToggle: (id: string) => void;
|
||||
}) {
|
||||
function RunRow({ entry, excluded, onToggle }: { entry: RunEntry; excluded: boolean; onToggle: (id: string) => void }) {
|
||||
const { t } = useTranslation();
|
||||
const { variant } = useAssistantView();
|
||||
const glyph = ROW_GLYPH[entry.change];
|
||||
|
||||
@@ -305,9 +305,7 @@ export function PackingGroup({
|
||||
))}
|
||||
</ul>
|
||||
)}
|
||||
{group.items.length > 0 && (
|
||||
<MoreLine label={hidden > 0 ? t('tours.packing.more', { count: hidden }) : null} />
|
||||
)}
|
||||
{group.items.length > 0 && <MoreLine label={hidden > 0 ? t('tours.packing.more', { count: hidden }) : null} />}
|
||||
</section>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -20,15 +20,7 @@ import { settingLabel } from './roadtripSettings';
|
||||
*/
|
||||
|
||||
/** One way of driving it, as a row to pick: saved or tried, how far and how long, how much to look at. */
|
||||
function VariantRow({
|
||||
card,
|
||||
picked,
|
||||
onPick,
|
||||
}: {
|
||||
card: RoadtripCard;
|
||||
picked: boolean;
|
||||
onPick: () => void;
|
||||
}) {
|
||||
function VariantRow({ card, picked, onPick }: { card: RoadtripCard; picked: boolean; onPick: () => void }) {
|
||||
const { t } = useTranslation();
|
||||
const format = useCardFormat();
|
||||
const warnings = card.days.filter(dayHasWarning).length;
|
||||
@@ -55,9 +47,7 @@ function VariantRow({
|
||||
})}
|
||||
</span>
|
||||
{warnings > 0 && (
|
||||
<span className="flex-none text-warning">
|
||||
{t('assistant.card.roadtrip.warnings', { count: warnings })}
|
||||
</span>
|
||||
<span className="flex-none text-warning">{t('assistant.card.roadtrip.warnings', { count: warnings })}</span>
|
||||
)}
|
||||
</button>
|
||||
</li>
|
||||
|
||||
@@ -76,7 +76,9 @@ export default function TourRouteActions({
|
||||
)}
|
||||
</div>
|
||||
{take.visible && caption && (
|
||||
<p className="m-0 text-end text-caption text-content-muted" role="status">{caption}</p>
|
||||
<p className="m-0 text-end text-caption text-content-muted" role="status">
|
||||
{caption}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -70,7 +70,11 @@ export default function VacayChangeGroup({
|
||||
/>
|
||||
)}
|
||||
{placed.length > 0 && (
|
||||
<ul className="sr-only">{placed.map((entry) => <li key={entry.toolCallId}>{labelOf(entry)}</li>)}</ul>
|
||||
<ul className="sr-only">
|
||||
{placed.map((entry) => (
|
||||
<li key={entry.toolCallId}>{labelOf(entry)}</li>
|
||||
))}
|
||||
</ul>
|
||||
)}
|
||||
{twice && (
|
||||
<div className={PILLS}>
|
||||
|
||||
@@ -96,7 +96,13 @@ function Cell({
|
||||
{marks}
|
||||
</span>
|
||||
);
|
||||
return cell.holiday ? <Tooltip label={cell.holiday.name} placement="top">{body}</Tooltip> : body;
|
||||
return cell.holiday ? (
|
||||
<Tooltip label={cell.holiday.name} placement="top">
|
||||
{body}
|
||||
</Tooltip>
|
||||
) : (
|
||||
body
|
||||
);
|
||||
}
|
||||
|
||||
export default function VacayMiniMonth({ view, month, placed, today, size, onToggle, labelOf }: MonthProps) {
|
||||
@@ -109,7 +115,9 @@ export default function VacayMiniMonth({ view, month, placed, today, size, onTog
|
||||
<p className={TITLE}>{title}</p>
|
||||
<div className={GRID[size]}>
|
||||
{weekdays.map((name, column) => (
|
||||
<span key={`weekday-${column}`} aria-hidden="true" className={WEEKDAY}>{name}</span>
|
||||
<span key={`weekday-${column}`} aria-hidden="true" className={WEEKDAY}>
|
||||
{name}
|
||||
</span>
|
||||
))}
|
||||
{cells.map((cell, index) =>
|
||||
cell ? (
|
||||
|
||||
@@ -70,7 +70,9 @@ export default function VacayRowFacts({ card }: { card: VacayCard; item: ChangeI
|
||||
</SoftPill>
|
||||
)}
|
||||
{proposal.notes.map((note) => (
|
||||
<SoftPill key={note} tone={NOTE_LOOK[note].tone}>{t(NOTE_LOOK[note].labelKey)}</SoftPill>
|
||||
<SoftPill key={note} tone={NOTE_LOOK[note].tone}>
|
||||
{t(NOTE_LOOK[note].labelKey)}
|
||||
</SoftPill>
|
||||
))}
|
||||
</>
|
||||
);
|
||||
|
||||
@@ -33,7 +33,7 @@ export function NoteHeadBand({
|
||||
}) {
|
||||
return (
|
||||
<div
|
||||
className={`flex items-center gap-2 py-1.5 ps-3 pe-1.5 ${bordered ? 'border-b border-edge-faint' : ''}`}
|
||||
className={`flex items-center gap-2 py-1.5 pe-1.5 ps-3 ${bordered ? 'border-b border-edge-faint' : ''}`}
|
||||
style={{ background: tintOf(color) }}
|
||||
>
|
||||
{/* The category is only its colour here; the name is in the tooltip and the filter above. */}
|
||||
|
||||
@@ -122,7 +122,7 @@ function labelApplied({ result, preview }: AppliedInput): CollectionPlacesCard |
|
||||
return { ...card, labels: [{ ...shown, id: positiveId(label.id), name, color }] };
|
||||
}
|
||||
|
||||
export const COLLECTION_APPLIED: Readonly<Record<string, (input: AppliedInput) => TrekCard | null>> = {
|
||||
export const COLLECTION_APPLIED: Readonly<Partial<Record<string, (input: AppliedInput) => TrekCard | null>>> = {
|
||||
save_place_to_collection: savedApplied,
|
||||
update_collection_place: placeApplied,
|
||||
set_collection_place_status: placeApplied,
|
||||
@@ -137,22 +137,23 @@ export const COLLECTION_APPLIED: Readonly<Record<string, (input: AppliedInput) =
|
||||
};
|
||||
|
||||
/** The ids a receipt names where the answer does not name them under the usual keys. */
|
||||
export const COLLECTION_APPLIED_IDS: Readonly<Record<string, (args: ToolArgs, result: unknown) => number[]>> = {
|
||||
create_collection: (_args, result) => idsOf(positiveId(recordOf(recordOf(result).collection).id)),
|
||||
update_collection: (args) => idsOf(argId(args, 'collectionId')),
|
||||
delete_collection: (args) => idsOf(argId(args, 'collectionId')),
|
||||
save_trip_places_to_collection: (args) => idsOf(argId(args, 'collectionId')),
|
||||
accept_collection_invite: (args) => idsOf(argId(args, 'collectionId')),
|
||||
decline_collection_invite: (args) => idsOf(argId(args, 'collectionId')),
|
||||
cancel_collection_invite: (args) => idsOf(argId(args, 'collectionId')),
|
||||
create_collection_label: (args) => idsOf(argId(args, 'collection_id')),
|
||||
update_collection_label: (_args, result) => idsOf(positiveId(recordOf(recordOf(result).label).collection_id)),
|
||||
// The new trip places, so "Show on map" opens the first of them.
|
||||
copy_collection_places_to_trip: (_args, result) =>
|
||||
rowsOf(recordOf(result).created)
|
||||
.map((row) => positiveId(row.id))
|
||||
.filter((id): id is number => id !== null),
|
||||
};
|
||||
export const COLLECTION_APPLIED_IDS: Readonly<Partial<Record<string, (args: ToolArgs, result: unknown) => number[]>>> =
|
||||
{
|
||||
create_collection: (_args, result) => idsOf(positiveId(recordOf(recordOf(result).collection).id)),
|
||||
update_collection: (args) => idsOf(argId(args, 'collectionId')),
|
||||
delete_collection: (args) => idsOf(argId(args, 'collectionId')),
|
||||
save_trip_places_to_collection: (args) => idsOf(argId(args, 'collectionId')),
|
||||
accept_collection_invite: (args) => idsOf(argId(args, 'collectionId')),
|
||||
decline_collection_invite: (args) => idsOf(argId(args, 'collectionId')),
|
||||
cancel_collection_invite: (args) => idsOf(argId(args, 'collectionId')),
|
||||
create_collection_label: (args) => idsOf(argId(args, 'collection_id')),
|
||||
update_collection_label: (_args, result) => idsOf(positiveId(recordOf(recordOf(result).label).collection_id)),
|
||||
// The new trip places, so "Show on map" opens the first of them.
|
||||
copy_collection_places_to_trip: (_args, result) =>
|
||||
rowsOf(recordOf(result).created)
|
||||
.map((row) => positiveId(row.id))
|
||||
.filter((id): id is number => id !== null),
|
||||
};
|
||||
|
||||
function idsOf(id: number | null): number[] {
|
||||
return id === null ? [] : [id];
|
||||
|
||||
@@ -80,7 +80,7 @@ const oneLabel: Loader = async (args, read) => {
|
||||
return { ...NO_LOOKUP, items, collection: await collectionOf(read, positiveId(recordOf(label).collection_id)) };
|
||||
};
|
||||
|
||||
export const COLLECTION_LOADS: Readonly<Record<string, Loader>> = {
|
||||
export const COLLECTION_LOADS: Readonly<Partial<Record<string, Loader>>> = {
|
||||
save_place_to_collection: async (args, read) => {
|
||||
const query = membershipQuery(args);
|
||||
const [collection, membership] = await Promise.all([
|
||||
|
||||
Reference in New Issue
Block a user