-
Notifications
You must be signed in to change notification settings - Fork 852
Add Smart Context sample #1607
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
Add Smart Context sample #1607
Conversation
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.
Pull request overview
This PR adds a new SPFx Application Customizer sample, “Smart Context”, which calls the Microsoft Graph Copilot API to generate structured, page-level insights and presents them in a rich, Copilot-inspired panel UI in SharePoint Online.
Changes:
- Introduces a Copilot service layer (
CopilotService, typed contracts, error classes, JSON parsing/validation helpers, and system prompt) to call the Microsoft Graph Copilot APIs and normalize responses. - Adds a complete React UI for the Smart Context panel (floating trigger button, loader, header/footer, section components, styling) that renders role, actions, decisions, people, timeline, and attribution references.
- Sets up the SPFx 1.22.1 project scaffolding, configuration, build tooling (Heft), permissions, documentation, and static assets for this sample.
Reviewed changes
Copilot reviewed 51 out of 61 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| samples/react-application-smart-context/tsconfig.json | Extends the SPFx web build rig base TypeScript configuration for the sample. |
| samples/react-application-smart-context/src/extensions/smartContextApp/services/serviceUtils.ts | Adds utility to strip inline citation markdown from Copilot responses. |
| samples/react-application-smart-context/src/extensions/smartContextApp/services/jsonUtils.ts | Implements JSON extraction from Copilot text responses and validation/normalization for the Smart Context data model. |
| samples/react-application-smart-context/src/extensions/smartContextApp/services/index.ts | Barrel exports for Copilot-related services, interfaces, errors, and JSON utilities. |
| samples/react-application-smart-context/src/extensions/smartContextApp/services/errors.ts | Defines custom error types and a helper to map errors to user-friendly messages. |
| samples/react-application-smart-context/src/extensions/smartContextApp/services/ICopilotService.ts | Declares Copilot conversation/chat contracts and the Smart Context schema interfaces. |
| samples/react-application-smart-context/src/extensions/smartContextApp/services/CopilotService.ts | Implements MS Graph Copilot conversation creation, chat sending, and Smart Context retrieval, including basic response processing. |
| samples/react-application-smart-context/src/extensions/smartContextApp/loc/myStrings.d.ts | Declares localized string typings for the application customizer. |
| samples/react-application-smart-context/src/extensions/smartContextApp/loc/en-us.js | Provides the English localization resource for the customizer title. |
| samples/react-application-smart-context/src/extensions/smartContextApp/constants/systemPrompt.ts | Defines the structured system prompt instructing Copilot to return a specific JSON schema. |
| samples/react-application-smart-context/src/extensions/smartContextApp/components/sections/index.ts | Barrel exports for Smart Context section components and icon utilities. |
| samples/react-application-smart-context/src/extensions/smartContextApp/components/sections/iconUtils.ts | Adds icon selection helpers and role definitions for use across the UI. |
| samples/react-application-smart-context/src/extensions/smartContextApp/components/sections/TldrItem.tsx | Renders individual TL;DR bullet items with animation. |
| samples/react-application-smart-context/src/extensions/smartContextApp/components/sections/TimelineItem.tsx | Renders timeline events with source iconography and vertical timeline styling. |
| samples/react-application-smart-context/src/extensions/smartContextApp/components/sections/SmartContextHeader.tsx | Defines the Smart Context panel header, including AI badge and title/subtitle. |
| samples/react-application-smart-context/src/extensions/smartContextApp/components/sections/SmartContextFooter.tsx | Defines the Smart Context panel footer with a data source disclosure message. |
| samples/react-application-smart-context/src/extensions/smartContextApp/components/sections/Section.tsx | Generic section wrapper for titles, icons, content lists, empty state, and “show more” behavior. |
| samples/react-application-smart-context/src/extensions/smartContextApp/components/sections/PersonItem.tsx | Displays a person card with Persona and optional profile link/details. |
| samples/react-application-smart-context/src/extensions/smartContextApp/components/sections/PendingActionItem.tsx | Displays pending action cards with urgency styling and due date display. |
| samples/react-application-smart-context/src/extensions/smartContextApp/components/sections/MyRoleCard.tsx | Renders the “My Role” card with markdown-bold parsing and a role legend. |
| samples/react-application-smart-context/src/extensions/smartContextApp/components/sections/KeyDecisionItem.tsx | Renders individual key decision items with icon and text. |
| samples/react-application-smart-context/src/extensions/smartContextApp/components/sections/AttributionItem.tsx | Renders content attribution links with icons derived from URL types. |
| samples/react-application-smart-context/src/extensions/smartContextApp/components/scss.d.ts | Provides TypeScript typings for SCSS modules used by React components. |
| samples/react-application-smart-context/src/extensions/smartContextApp/components/SmartContextPanel.tsx | Hosts the Fluent UI Panel, orchestrates Copilot calls, JSON extraction/validation, error handling, and passes data into the content component. |
| samples/react-application-smart-context/src/extensions/smartContextApp/components/SmartContextPanel.module.scss | Styles for the Smart Context panel container, loading state, and attribution list. |
| samples/react-application-smart-context/src/extensions/smartContextApp/components/SmartContextContent.tsx | Composes all Smart Context sections, groups attributions, and controls show-more behavior and entry animations. |
| samples/react-application-smart-context/src/extensions/smartContextApp/components/SmartContextContent.module.scss | Main styling for Smart Context content, including header, sections, cards, timeline, and animations. |
| samples/react-application-smart-context/src/extensions/smartContextApp/components/SmartContextContainer.tsx | Controls the floating button + panel lifecycle and passes necessary props. |
| samples/react-application-smart-context/src/extensions/smartContextApp/components/ISmartContextPanelProps.ts | Defines props for the Smart Context panel component. |
| samples/react-application-smart-context/src/extensions/smartContextApp/components/ISmartContextContainerProps.ts | Defines props for the Smart Context container component. |
| samples/react-application-smart-context/src/extensions/smartContextApp/components/IFloatingButtonProps.ts | Defines props for the floating trigger button. |
| samples/react-application-smart-context/src/extensions/smartContextApp/components/FloatingButton.tsx | Implements the fixed-position Fluent side tab button to open the Smart Context panel. |
| samples/react-application-smart-context/src/extensions/smartContextApp/components/FloatingButton.module.scss | Styles the floating side tab, including focus behavior and hover transitions. |
| samples/react-application-smart-context/src/extensions/smartContextApp/components/AiLoader.tsx | Implements an animated AI “solar system” loader with rotating status messages. |
| samples/react-application-smart-context/src/extensions/smartContextApp/components/AiLoader.module.scss | Styles and animations for the AI loader visual and progress bar. |
| samples/react-application-smart-context/src/extensions/smartContextApp/SmartContextAppApplicationCustomizer.ts | SPFx application customizer entry point that injects and renders the Smart Context container into the page. |
| samples/react-application-smart-context/src/extensions/smartContextApp/SmartContextAppApplicationCustomizer.manifest.json | Defines the SPFx extension manifest, including IDs and metadata for the customizer. |
| samples/react-application-smart-context/package.json | Declares dependencies, devDependencies, scripts, engines, and toolchain configuration for the sample. |
| samples/react-application-smart-context/docs/architecture.md | Documents the overall architecture, API flow, prompt design, and design rationale of the Smart Context sample. |
| samples/react-application-smart-context/config/write-manifests.json | Configures SPFx manifest writing behavior for the sample. |
| samples/react-application-smart-context/config/typescript.json | Extends the SPFx rig TypeScript config and static assets copying settings. |
| samples/react-application-smart-context/config/serve.json | Sets up SPFx serve configurations and debug custom action for the Smart Context customizer. |
| samples/react-application-smart-context/config/sass.json | Extends the SPFx rig SASS configuration. |
| samples/react-application-smart-context/config/rig.json | Points to the @microsoft/spfx-web-build-rig rig package for shared config. |
| samples/react-application-smart-context/config/package-solution.json | Defines the SPFx solution package, features, and required Microsoft Graph permissions. |
| samples/react-application-smart-context/config/deploy-azure-storage.json | Provides configuration for deploying built assets to Azure Storage. |
| samples/react-application-smart-context/config/config.json | Configures SPFx bundling, including the application customizer entrypoint and localized resources. |
| samples/react-application-smart-context/assets/smart-context-preview-5.png | Adds a Smart Context UI preview image used by the README. |
| samples/react-application-smart-context/assets/smart-context-preview-3.png | Adds another Smart Context UI preview image used by the README. |
| samples/react-application-smart-context/README.md | Documents the Smart Context sample, setup instructions, prerequisites, and references. |
| samples/react-application-smart-context/.yo-rc.json | Yeoman generator metadata for the SPFx solution, including versioning and environment info. |
| samples/react-application-smart-context/.nvmrc | Pins the Node.js version for development environments. |
| samples/react-application-smart-context/.npmignore | Defines which build artifacts are published to npm if the package is ever published. |
| samples/react-application-smart-context/.gitignore | Excludes build outputs, dependencies, and other non-source artifacts from version control. |
| samples/react-application-smart-context/.eslintrc.js | Configures ESLint rules for the SPFx project using the SPFx and RushStack configs. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
|
|
||
| React.useEffect(() => { | ||
| const interval = setInterval(() => { | ||
| setIsVisible(false); | ||
|
|
||
| setTimeout(() => { | ||
| setCurrentMessageIndex((prev) => (prev + 1) % messages.length); | ||
| setIsVisible(true); | ||
| }, 300); | ||
| }, 3000); | ||
|
|
||
| return () => clearInterval(interval); |
Copilot
AI
Feb 1, 2026
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.
This useEffect sets up an interval that in turn schedules setTimeout callbacks, but only the interval is cleared on unmount; pending timeouts can still fire and attempt to update state on an unmounted component. To avoid potential memory leaks and React warnings, also clear the timeout(s) (or refactor to use a single interval without nested timeouts) when the component unmounts or when messages changes.
| React.useEffect(() => { | |
| const interval = setInterval(() => { | |
| setIsVisible(false); | |
| setTimeout(() => { | |
| setCurrentMessageIndex((prev) => (prev + 1) % messages.length); | |
| setIsVisible(true); | |
| }, 300); | |
| }, 3000); | |
| return () => clearInterval(interval); | |
| const timeoutRef = React.useRef<number | null>(null); | |
| React.useEffect(() => { | |
| const interval = setInterval(() => { | |
| setIsVisible(false); | |
| if (timeoutRef.current !== null) { | |
| clearTimeout(timeoutRef.current); | |
| } | |
| timeoutRef.current = window.setTimeout(() => { | |
| setCurrentMessageIndex((prev) => (prev + 1) % messages.length); | |
| setIsVisible(true); | |
| }, 300); | |
| }, 3000); | |
| return () => { | |
| clearInterval(interval); | |
| if (timeoutRef.current !== null) { | |
| clearTimeout(timeoutRef.current); | |
| } | |
| }; |
| // DEBUG: Log full API response | ||
| console.log('[CopilotService] Chat API Response:', JSON.stringify(response, null, 2)); |
Copilot
AI
Feb 1, 2026
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.
Leaving this console.log of the full Copilot chat API response in the production service can leak verbose data to the browser console and clutter logs in real environments. Consider removing it or wrapping it in a conditional debug/logging utility so it is disabled in production builds.
| const jsonMatch = text.match(/\{[\s\S]*\}/); | ||
|
|
||
| if (!jsonMatch) { | ||
| throw new NoJsonFoundError(); | ||
| } | ||
|
|
||
| try { | ||
| return JSON.parse(jsonMatch[0]) as Record<string, unknown>; | ||
| } catch (error) { | ||
| throw new JsonParseError(error); |
Copilot
AI
Feb 1, 2026
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 JSON extraction regex here is greedy (/\{[\s\S]*\}/), so if the Copilot response contains more than one JSON fragment or additional braces after the JSON object, jsonMatch[0] can include extra trailing content and cause JSON.parse to throw. Consider using a non‑greedy pattern or more robust JSON block detection (e.g., tracking brace depth) so you reliably isolate just the JSON payload before parsing.
| const validatedData: ISmartContextData = { | ||
| myRole: data.myRole as ISmartContextData['myRole'], | ||
| pendingActions: Array.isArray(data.pendingActions) ? data.pendingActions : [], | ||
| keyDecisions: Array.isArray(data.keyDecisions) ? data.keyDecisions : [], | ||
| timeline: Array.isArray(data.timeline) ? data.timeline : [], | ||
| tldr: Array.isArray(data.tldr) ? data.tldr : [], | ||
| people: Array.isArray(data.people) ? data.people : [], | ||
| attributions: Array.isArray(data.attributions) ? data.attributions : [] |
Copilot
AI
Feb 1, 2026
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.
validateSmartContextData asserts that data.myRole is an IMyRole, but it does not provide a fallback when myRole is missing or malformed, so callers that rely on the non‑optional ISmartContextData.myRole may receive undefined at runtime. Either validate and provide a default myRole object here or make myRole optional in the interface so the type system reflects the actual behavior.
f8b1e35 to
3127b9b
Compare
|
Thank you @fredupstair for your sample! Highly appreciated! We'd love to have your sample featured in one of our future community calls. If haven't done so yet, and you'd be interested on showing this great sample in a public community call, please fill in following form and we'll get you scheduled - aka.ms/community/request/demo Thank you for sharing your sample with others - you rock! 👏🥇👩💻 |
What's in this Pull Request?
This PR adds a new sample to the PnP Extensions repository that shows how to consume the Microsoft Graph Copilot APIs to generate page-level insights. The sample demonstrates how an Application Customizer can analyze SharePoint page content in combination with your emails, chats, meetings, and files to provide instant, personalized insights, surfacing key people, pending actions, decisions, and relevant context that matter to you.