Skip to content

feat(outlook-addin): calendar pane for rooms and desks, and Teams tab - #503

Open
MrYuion wants to merge 4 commits into
developfrom
feat/outlook-calendar-pane
Open

MrYuion wants to merge 4 commits into
developfrom
feat/outlook-calendar-pane

Conversation

@MrYuion

@MrYuion MrYuion commented Sep 30, 2026 •

Copy link
Copy Markdown
Collaborator

Problem

The Outlook add-in did not use the open calendar event. It asked for the title, date and time again, and booked rooms by creating a second event through PlaceOS. It had no map, and the workplace app could not open in Teams or the Outlook app bar. The PlaceOS Outlook and Teams development brief (goals G01–G09) asks for all of these.

Solution

Outlook calendar pane (apps/outlook-addin/src/app/calendar/)

  • Reads the subject, start, end, All day flag, recurrence and rooms from the Outlook item. It reads them again on Outlook change events, on focus, from a refresh button, and before it saves anything. It never infers All day from the duration. It uses the Office.js preview flag when the client has it. Otherwise it uses the saved event from PlaceOS when the saved times match Outlook.
  • Rooms: "Add to meeting" adds the room with enhancedLocation (type Room), so Exchange books it on Send. The pane shows each room as added, pending, confirmed or declined.
  • Desks: "Add to event" saves a new event (Outlook sends no invitation), reserves the desk through BookingFormService, and links the booking and the event in both directions. The pane flags the desk when the event time changes and offers Update and Remove. Recurring events and multi-day all-day events are blocked with a message until the policy is agreed.
  • List and map views for each tab. Filters apply in the pane, so a filter change does not start a new availability request. space-map and desk-map get an optional available input for the filtered list, and both are exported from their libraries.
  • The manifest has one "PlaceOS" button that opens #/calendar, and it requires Mailbox 1.8. The old forms stay in place for now.
  • Mock mode now registers the shared mocks in the add-in.

Workplace as a Teams / Microsoft 365 personal tab

  • @microsoft/teams-js loads only when the tab URL has ?host=teams. Sign in tries Teams SSO, then a sign-in window, then a Sign in button.
  • apps/workplace/teams/ has the manifest template, icons and a packaging script. See docs/teams-app.md.

Verification

  • Tests: outlook-addin 30, workplace 421, events 240, bookings 435, common 376. All pass.
  • Production builds of outlook-addin and workplace pass.
  • Checked in the browser in mock mode: room and desk search, filters, map selection, adding a room and reserving a desk.

Not verified yet

  • Nothing has been run in real Outlook (Classic or New) or in Teams. This needs a test tenant.
  • index.html loads the production Office.js (lib/1), which has no preview APIs. In production the All day flag comes only from the saved event.
  • Backend and infrastructure work: PlaceOS must accept the Entra token exchange (RFC 8693) for Teams and Outlook SSO. Without it, sign in falls back to the sign-in window. The host must also allow Microsoft 365 framing (CSP frame-ancestors). Desks whose event is deleted need a cleanup job.
  • The manifest has no pinning support yet and still points at microsoft.poc.placeos.com.

Changes made by Claude Opus 5.5 (1M context) in Claude Code.

🤖 Generated with Claude Code

Load teams-js only when the tab URL has `?host=teams`. Sign in through
Teams SSO, then a sign-in window, then a Sign in button, because the
Microsoft login page cannot load in the host frame. Add the app package
template, a packaging script and docs/teams-app.md.
Add a task pane that reads the title, time and All day setting from the
open Outlook event instead of asking for them again.

- Rooms are added to the event as Exchange room resources, so Exchange
  books them when the invitation is sent. This replaces the old flow
  that created a second event.
- Desks are reserved on "Add to event" and linked to the saved event in
  both directions. The pane flags a desk when the event time changes.
- Each tab has list and map views. Filters apply in the pane, so a
  filter change does not start a new availability request.
- space-map and desk-map accept an optional filtered list and are
  exported from their libraries.
- The manifest has one PlaceOS button that opens the pane.
@vercel

vercel Bot commented Sep 30, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated
frontend-templates Ignored Ignored Preview Sep 30, 2026 8:14am UTC

@greptile-apps greptile-apps Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Your trial has ended. Reactivate Greptile to resume code reviews.

Replace the legacy Office SSO (getAccessToken) with nested app
authentication through MSAL. The PlaceOS sign-in dialog stays as the
fallback when the manifest has no client ID or Outlook does not support
NestedAppAuth 1.1. The token scope is the same as the Teams app, so one
Entra app registration serves both.

- manifest.xml is now a template. manifest.ts makes the manifest for a
  PlaceOS host and adds the Entra client ID to the task pane URL.
- The base rule matches the appointment organizer button. Remove
  AppDomains, FunctionFile and WebApplicationInfo.
- Remove the Yeoman scaffold, the function file, ms-auth-login.html,
  the unused ms-auth route and the IE compatibility meta tag.
- Uploads now start when a stored token is used.
@vercel

vercel Bot commented Oct 1, 2026

Copy link
Copy Markdown

Deployment failed for project frontend-templates with the following error:

Resource is limited - try again in 24 hours (more than 100, code: "api-deployments-free-per-day").

Learn More: https://vercel.com/placeos?upgradeToPro=build-rate-limit

@greptile-apps greptile-apps Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Your trial has ended. Reactivate Greptile to resume code reviews.

Update ts-client to 6.8.0. The Outlook add-in and the Teams tab now
exchange the Microsoft Entra SSO token for PlaceOS tokens (RFC 8693)
instead of sending it as the bearer token. The exchange gives a refresh
token, so the PlaceOS token renews. When the exchange fails, sign in
falls back to the sign-in dialog or window.
@greptile-apps

greptile-apps Bot commented Oct 1, 2026 •

Copy link
Copy Markdown

RetriggerConfidence Score: 2/5

[Medium risk] Rebuilds Outlook add-in with new calendar booking UI and Teams app support.

The PR is not ready to merge because desk bookings can use old event times, lose their Outlook link, or act on the previous event.

Findings

  1. P1 Desk booked for old time ▶
  2. P1 Desk stays reserved after error ▶
  3. P1 Previous event’s desk persists ▶
  4. P2 Map offers outdated desk ▶

Summary

The Outlook add-in now uses the open appointment to find and add rooms or desks, while Workplace can open as a personal tab in Teams and Microsoft 365.

  • Rooms join the Outlook invitation; desks get a linked PlaceOS booking.
  • Both searches add filtered map views, and Teams sign-in can fall back to a sign-in window.
  • Outlook and Teams gain host-specific app packages and sign-in setup.
Diagram
%%{init: {'theme': 'neutral'}}%%
flowchart LR
  A[Outlook event] --> B[Calendar pane]
  B --> C[Add room to Outlook item]
  B --> D[Save event and reserve desk]
  D --> E[Write booking ID to Outlook item]
  T[Teams tab] --> S[Teams sign-in]
  S --> W[Workplace]
Loading

Reviews (1) · Last reviewed commit: "feat(auth): exchange Entra tokens for Pl..."

this._error.set(
errorMessage(error) || 'Unable to read the Outlook event.',
);
return this._event();

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Desk booked for old time

If Outlook fails to read an appointment after its time changes, refresh() returns the previous event. DeskLinkService._post() treats it as a fresh read and can reserve or update a desk for the old time. A failed read should stop the booking instead.

...(saved?.ical_uid ? { ical_uid: saved.ical_uid } : {}),
},
}).catch(() => booking);
await this._outlook.setProperty(DESK_BOOKING_PROPERTY, linked.id);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Desk stays reserved after error

add() creates the desk booking before saving its ID on the Outlook item. If that save fails, the pane reports an error but leaves the desk reserved. When reopened, it cannot find the booking through the missing link. Roll back the booking or make the link recoverable.


constructor() {
this._form.newForm('desk');
this.link.load();

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Previous event’s desk persists

When a pinned pane moves to another Outlook item, the event refreshes but the desk booking is not reloaded. The desk tab can show the previous appointment’s booking, and Remove or Update can act on it. Reload the desk link when the item changes.

[available]="map_desks()"
(onSelect)="selected_desk.set($event)"
/>
@if (selected_desk(); as desk) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Map offers outdated desk

When the event time or available desks change, the map keeps showing selected_desk even if it is no longer in map_desks(). Its card still says “Available” and offers Add. Clear the selection when that desk leaves the available list so users do not try to book an outdated result.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant