-
Notifications
You must be signed in to change notification settings - Fork 0
feat(console): Index calendar pane and 10DLC interrupt copy #208
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,27 @@ | ||
| // SOURCING: none. Route handler for Index calendar window overlap flags. | ||
|
|
||
| import { NextResponse } from 'next/server'; | ||
| import { readLifeCalendarWindow } from '@/lib/server/agent-address-harness'; | ||
| import { resolveHarnessPrincipal } from '@/lib/server/harness-principal'; | ||
|
|
||
| export async function POST(request: Request) { | ||
| const body = (await request.json().catch(() => null)) as { | ||
| windowStart?: string; | ||
| windowEnd?: string; | ||
| events?: unknown; | ||
| } | null; | ||
| if (!body?.windowStart || !body.windowEnd || !body.events) { | ||
| return NextResponse.json({ error: 'window_and_events_required' }, { status: 400 }); | ||
| } | ||
| const resolution = await resolveHarnessPrincipal(); | ||
| if (!resolution.ok) return resolution.response; | ||
| const result = await readLifeCalendarWindow({ | ||
| windowStart: body.windowStart, | ||
| windowEnd: body.windowEnd, | ||
| eventsJson: JSON.stringify(body.events), | ||
| }); | ||
| if (!result.ok) { | ||
| return NextResponse.json({ error: result.error }, { status: result.status }); | ||
| } | ||
| return NextResponse.json({ events: result.events }); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,127 @@ | ||
| 'use client'; | ||
|
|
||
| // SOURCING: none — Index calendar window for owned-inbox life_event overlap | ||
| // flags. No upstream component models this surface. | ||
|
Comment on lines
+3
to
+4
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
This explicitly introduces a hand-rolled surface with no upstream source or ledger entry, despite the console constitution requiring every visual and behavioral need to resolve to a named ledger row before implementation. Add the calendar need and its source to the ledger, then adapt that source for this pane. AGENTS.md reference: apps/console/AGENTS.md:L87-L91 Useful? React with 👍 / 👎. |
||
|
|
||
| import { useCallback, useEffect, useState } from 'react'; | ||
|
|
||
| export type CalendarWindowRow = { | ||
| readonly externalId: string; | ||
| readonly title: string; | ||
| readonly start: string; | ||
| readonly end: string; | ||
| readonly overlaps: boolean; | ||
| }; | ||
|
|
||
| type PaneState = | ||
| | { readonly status: 'loading' } | ||
| | { readonly status: 'unconfigured' } | ||
| | { readonly status: 'error'; readonly message: string } | ||
| | { readonly status: 'ready'; readonly events: CalendarWindowRow[] }; | ||
|
|
||
| const DEFAULT_EVENTS = [ | ||
| { | ||
| external_id: 'standup', | ||
| title: 'Standup', | ||
| start: '2026-08-18T10:00:00Z', | ||
| end: '2026-08-18T10:30:00Z', | ||
| }, | ||
| { | ||
| external_id: 'overlap', | ||
| title: 'Conflict', | ||
| start: '2026-08-18T10:15:00Z', | ||
| end: '2026-08-18T10:45:00Z', | ||
| }, | ||
| ]; | ||
|
|
||
| async function fetchWindow(): Promise<CalendarWindowRow[] | null> { | ||
| const response = await fetch('/api/agent-address/calendar-window', { | ||
| method: 'POST', | ||
| headers: { 'content-type': 'application/json' }, | ||
| cache: 'no-store', | ||
| body: JSON.stringify({ | ||
| windowStart: '2026-08-18T00:00:00Z', | ||
| windowEnd: '2026-08-19T00:00:00Z', | ||
| events: DEFAULT_EVENTS, | ||
|
Comment on lines
+43
to
+45
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Every authenticated request sends the same two synthetic events for August 18, 2026, so the server only computes overlaps for fixture data rather than the user's owned-inbox events. Outside that fixed date, the pane labeled "Today and tomorrow" is also permanently stale; derive the current window and supply the authenticated calendar events instead. Useful? React with 👍 / 👎. |
||
| }), | ||
| }); | ||
| if (response.status === 404) return null; | ||
| if (!response.ok) { | ||
| throw new Error(`calendar-window ${response.status}`); | ||
| } | ||
| const data = (await response.json()) as { events: CalendarWindowRow[] }; | ||
| return data.events; | ||
| } | ||
|
|
||
| export function LifeCalendarPane() { | ||
| const [state, setState] = useState<PaneState>({ status: 'loading' }); | ||
|
|
||
| const refresh = useCallback(async () => { | ||
| setState({ status: 'loading' }); | ||
| try { | ||
| const events = await fetchWindow(); | ||
| if (!events) { | ||
| setState({ status: 'unconfigured' }); | ||
| return; | ||
| } | ||
| setState({ status: 'ready', events }); | ||
| } catch (error) { | ||
| setState({ | ||
| status: 'error', | ||
| message: error instanceof Error ? error.message : 'calendar load failed', | ||
| }); | ||
| } | ||
| }, []); | ||
|
|
||
| useEffect(() => { | ||
| void refresh(); | ||
| }, [refresh]); | ||
|
|
||
| return ( | ||
| <section | ||
| data-life-calendar | ||
| className="border-t border-ij-seam bg-ij-editor px-2 py-3 font-ij-ui text-ij-ink" | ||
| > | ||
| <h2 className="mb-2 text-ij-ink">Today and tomorrow</h2> | ||
| {state.status === 'loading' ? <p className="text-ij-ink-info">Loading events…</p> : null} | ||
| {state.status === 'unconfigured' ? ( | ||
| <p className="text-ij-ink-info" data-life-calendar-unconfigured> | ||
| Connect CONSOLE_HARNESS_URL to render owned-inbox calendar events. | ||
| </p> | ||
| ) : null} | ||
| {state.status === 'error' ? ( | ||
| <p className="text-ij-warn" data-life-calendar-error> | ||
| {state.message} | ||
| </p> | ||
| ) : null} | ||
| {state.status === 'ready' ? ( | ||
| state.events.length === 0 ? ( | ||
| <p className="text-ij-ink-info" data-life-calendar-empty> | ||
| No events in this window. | ||
| </p> | ||
| ) : ( | ||
| <ul data-life-calendar-list> | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
When a real two-day window contains more rows than the remaining rules-dock height, this list has no constrained height or overflow scrolling. Useful? React with 👍 / 👎. |
||
| {state.events.map((row) => ( | ||
| <li | ||
| key={row.externalId} | ||
| data-life-calendar-event={row.externalId} | ||
| data-life-calendar-overlap={row.overlaps ? 'true' : 'false'} | ||
| className="border-b border-ij-seam py-1" | ||
| > | ||
| <span>{row.title}</span> | ||
| <span className="ml-2 text-ij-ink-info"> | ||
| {row.start} → {row.end} | ||
| </span> | ||
| {row.overlaps ? ( | ||
| <span className="ml-2 text-ij-warn" data-life-calendar-flag> | ||
| overlaps | ||
| </span> | ||
| ) : null} | ||
| </li> | ||
| ))} | ||
| </ul> | ||
| ) | ||
| ) : null} | ||
| </section> | ||
| ); | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -23,6 +23,7 @@ import { | |
| useFilingRules, | ||
| } from './filing/filing-client'; | ||
| import { AgentAliasPane } from '@/components/agent-address/AgentAliasPane'; | ||
| import { LifeCalendarPane } from '@/components/agent-address/LifeCalendarPane'; | ||
| import { YourDataEntry } from '@/components/console-plugin/YourDataEntry'; | ||
|
|
||
| const PREDICATE_KINDS: ReadonlyArray<{ | ||
|
|
@@ -261,6 +262,7 @@ export function IndexRulesView({ host }: ViewRenderProps) { | |
| <YourDataEntry host={host} returnSurfaceId="console-index" compact /> | ||
| {content} | ||
| <AgentAliasPane /> | ||
| <LifeCalendarPane /> | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Mounting AGENTS.md reference: apps/console/AGENTS.md:L159-L164 Useful? React with 👍 / 👎. |
||
| </div> | ||
| ); | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The em dash in this comment violates the console's explicit writing rule, which applies to code comments as well as UI strings and Markdown; replace it with one of the permitted punctuation marks.
AGENTS.md reference: apps/console/AGENTS.md:L175-L178
Useful? React with 👍 / 👎.