diff --git a/apps/teams-test-app/src/pages/TestApp.tsx b/apps/teams-test-app/src/pages/TestApp.tsx index 1789309187..f0c8ecb883 100644 --- a/apps/teams-test-app/src/pages/TestApp.tsx +++ b/apps/teams-test-app/src/pages/TestApp.tsx @@ -1,5 +1,5 @@ import { IAppWindow } from '@microsoft/teams-js'; -import React, { useRef, useState } from 'react'; +import React, { useEffect, useMemo, useRef, useState } from 'react'; import AppAPIs from '../components/AppAPIs'; import AppEntityAPIs from '../components/AppEntityAPIs'; @@ -68,12 +68,14 @@ import VisualMediaAPIs from '../components/VisualMediaAPIs'; import WebStorageAPIs from '../components/WebStorageAPIs'; export const appInitializationTestQueryParameter = 'appInitializationTest'; +export const groupedModeQueryParameter = 'groupedMode'; // Define query parameter name for grouped mode export const TestApp: React.FC = () => { const dialogWindowRef = useRef(null); const [iframeUrl, setIframeUrl] = useState(null); const [groupedMode, setGroupedMode] = useState(false); // Toggle between default and grouped mode const [visibleSections, setVisibleSections] = useState([]); // Track multiple open sections + const [hideButtons, setHideButtons] = useState(false); // New state to hide buttons const loadCurrentUrl = (): void => { setIframeUrl(new URL(window.location.href + `?${appInitializationTestQueryParameter}=true`)); @@ -90,75 +92,102 @@ export const TestApp: React.FC = () => { }; // List of sections dynamically created from React elements - const sections = [ - { name: 'AppAPIs', component: }, - { name: 'AppInitializationAPIs', component: }, - { name: 'AppInstallDialogAPIs', component: }, - { name: 'AuthenticationAPIs', component: }, - { name: 'AppEntityAPIs', component: }, - { name: 'BarCodeAPIs', component: }, - { name: 'CalendarAPIs', component: }, - { name: 'CallAPIs', component: }, - { name: 'ChatAPIs', component: }, - { name: 'ClipboardAPIs', component: }, - { name: 'CookieAccessComponent', component: }, - { name: 'CopilotAPIs', component: }, - { name: 'CustomAPIs', component: }, - { name: 'DialogAPIs', component: }, - { name: 'DialogCardAPIs', component: }, - { name: 'DialogCardBotAPIs', component: }, - { name: 'DialogUpdateAPIs', component: }, - { name: 'DialogUrlAPIs', component: }, - { name: 'DialogUrlBotAPIs', component: }, - { - name: 'DialogUrlParentCommunicationAPIs', - component: , - }, - { name: 'ExternalAppAuthenticationAPIs', component: }, - { name: 'ExternalAppCardActionsAPIs', component: }, - { name: 'ExternalAppCardActionsForCEAAPIs', component: }, - { name: 'ExternalAppCommandsAPIs', component: }, - { name: 'FilesAPIs', component: }, - { name: 'FullTrustAPIs', component: }, - { name: 'GeoLocationAPIs', component: }, - { name: 'HostEntityTabAPIs', component: }, - { name: 'Links', component: }, - { name: 'LocationAPIs', component: }, - { name: 'LogAPIs', component: }, - { name: 'MailAPIs', component: }, - { name: 'MarketplaceAPIs', component: }, - { name: 'MediaAPIs', component: }, - { name: 'MeetingAPIs', component: }, - { name: 'MeetingRoomAPIs', component: }, - { name: 'MenusAPIs', component: }, - { name: 'MessageChannelAPIs', component: }, - { name: 'MonetizationAPIs', component: }, - { name: 'NestedAppAuthAPIs', component: }, - { name: 'NotificationAPIs', component: }, - { name: 'OtherAppStateChangedAPIs', component: }, - { name: 'PagesAPIs', component: }, - { name: 'PagesAppButtonAPIs', component: }, - { name: 'PagesBackStackAPIs', component: }, - { name: 'PagesConfigAPIs', component: }, - { name: 'PagesCurrentAppAPIs', component: }, - { name: 'PagesTabsAPIs', component: }, - { name: 'PeopleAPIs', component: }, - { name: 'PrivateAPIs', component: }, - { name: 'ProfileAPIs', component: }, - { name: 'RemoteCameraAPIs', component: }, - { name: 'SearchAPIs', component: }, - { name: 'SecondaryBrowserAPIs', component: }, - { name: 'SharingAPIs', component: }, - { name: 'WebStorageAPIs', component: }, - { name: 'StageViewAPIs', component: }, - { name: 'StageViewSelfAPIs', component: }, - { name: 'TeamsCoreAPIs', component: }, - { name: 'TeamsAPIs', component: }, - { name: 'ThirdPartyCloudStorageAPIs', component: }, - { name: 'VideoAPIs', component: }, - { name: 'VideoExAPIs', component: }, - { name: 'VisualMediaAPIs', component: }, - ]; + const sections = useMemo( + () => [ + { name: 'AppAPIs', component: }, + { name: 'AppInitializationAPIs', component: }, + { name: 'AppInstallDialogAPIs', component: }, + { name: 'AuthenticationAPIs', component: }, + { name: 'AppEntityAPIs', component: }, + { name: 'BarCodeAPIs', component: }, + { name: 'CalendarAPIs', component: }, + { name: 'CallAPIs', component: }, + { name: 'ChatAPIs', component: }, + { name: 'ClipboardAPIs', component: }, + { name: 'CookieAccessComponent', component: }, + { name: 'CopilotAPIs', component: }, + { name: 'CustomAPIs', component: }, + { name: 'DialogAPIs', component: }, + { name: 'DialogCardAPIs', component: }, + { name: 'DialogCardBotAPIs', component: }, + { name: 'DialogUpdateAPIs', component: }, + { name: 'DialogUrlAPIs', component: }, + { name: 'DialogUrlBotAPIs', component: }, + { + name: 'DialogUrlParentCommunicationAPIs', + component: , + }, + { name: 'ExternalAppAuthenticationAPIs', component: }, + { name: 'ExternalAppCardActionsAPIs', component: }, + { name: 'ExternalAppCardActionsForCEAAPIs', component: }, + { name: 'ExternalAppCommandsAPIs', component: }, + { name: 'FilesAPIs', component: }, + { name: 'FullTrustAPIs', component: }, + { name: 'GeoLocationAPIs', component: }, + { name: 'HostEntityTabAPIs', component: }, + { name: 'Links', component: }, + { name: 'LocationAPIs', component: }, + { name: 'LogAPIs', component: }, + { name: 'MailAPIs', component: }, + { name: 'MarketplaceAPIs', component: }, + { name: 'MediaAPIs', component: }, + { name: 'MeetingAPIs', component: }, + { name: 'MeetingRoomAPIs', component: }, + { name: 'MenusAPIs', component: }, + { name: 'MessageChannelAPIs', component: }, + { name: 'MonetizationAPIs', component: }, + { name: 'NestedAppAuthAPIs', component: }, + { name: 'NotificationAPIs', component: }, + { name: 'OtherAppStateChangedAPIs', component: }, + { name: 'PagesAPIs', component: }, + { name: 'PagesAppButtonAPIs', component: }, + { name: 'PagesBackStackAPIs', component: }, + { name: 'PagesConfigAPIs', component: }, + { name: 'PagesCurrentAppAPIs', component: }, + { name: 'PagesTabsAPIs', component: }, + { name: 'PeopleAPIs', component: }, + { name: 'PrivateAPIs', component: }, + { name: 'ProfileAPIs', component: }, + { name: 'RemoteCameraAPIs', component: }, + { name: 'SearchAPIs', component: }, + { name: 'SecondaryBrowserAPIs', component: }, + { name: 'SharingAPIs', component: }, + { name: 'WebStorageAPIs', component: }, + { name: 'StageViewAPIs', component: }, + { name: 'StageViewSelfAPIs', component: }, + { name: 'TeamsCoreAPIs', component: }, + { name: 'TeamsAPIs', component: }, + { name: 'ThirdPartyCloudStorageAPIs', component: }, + { name: 'VideoAPIs', component: }, + { name: 'VideoExAPIs', component: }, + { name: 'VisualMediaAPIs', component: }, + ], + [], + ); + + // Check URL for groupedMode parameter on component mount + useEffect(() => { + const params = new URLSearchParams(window.location.search); + const groupedModeParam = params.get(groupedModeQueryParameter); + + if (groupedModeParam) { + setGroupedMode(true); // Automatically switch to grouped mode + + // Split the parameter by comma to support multiple sections + const sectionsToOpen = groupedModeParam.split(','); + + // Find matching sections + const matchingSections = sections + .filter((section) => sectionsToOpen.some((param) => param.toLowerCase() === section.name.toLowerCase())) + .map((section) => section.name); + + // If matching sections found, open them + if (matchingSections.length > 0) { + setVisibleSections(matchingSections); + setHideButtons(true); // Hide buttons if sections are specified in query + } + } + }, [sections]); // Include sections in the dependency array return ( <> @@ -192,14 +221,29 @@ export const TestApp: React.FC = () => { ) : ( <> {/* Grouped mode: Dynamically create buttons for each section */} - {sections.map((section) => ( -
- - {visibleSections.includes(section.name) && section.component} -
- ))} + {!hideButtons && ( + <> + {sections.map((section) => ( +
+ + {visibleSections.includes(section.name) && section.component} +
+ ))} + + )} + + {/* Only display visible sections if buttons are hidden */} + {hideButtons && ( + <> + {sections + .filter((section) => visibleSections.includes(section.name)) + .map((section) => ( +
{section.component}
+ ))} + + )} )}