Skip to content
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

Fix macOS UI issue by introducing grouped mode to load specific section in test app #2521

Merged
merged 7 commits into from
Oct 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions apps/teams-test-app/src/App.css
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,31 @@
.App-container {
display: grid;
}

/* ==============================================================
* Grouped Mode - Button, Section Button, and Section Content Styles
* ============================================================== */

/* Style for individual section buttons */
.section-button-in-grouped-mode {
background-color: #0f6cbd; /* Blue background for buttons */
color: white; /* White text */
border: none; /* Remove default border */
border-radius: 4px; /* Rounded corners */
padding: 8px 15px; /* Padding inside the button */
cursor: pointer; /* Pointer cursor on hover */
font-size: 14px; /* Font size of the button text */
}

/* Style for section button hover effect */
.section-button-in-grouped-mode:hover {
background-color: #0056b3; /* Darker blue on hover */
}

/* Style for the section content */
.section-content-in-grouped-mode {
margin-top: 2px; /* Space above each section's content */
border: 1px solid #ddd; /* Light grey border around the section */
padding: 4px; /* Padding inside the section */
border-radius: 4px; /* Rounded corners */
}
225 changes: 157 additions & 68 deletions apps/teams-test-app/src/pages/TestApp.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { IAppWindow } from '@microsoft/teams-js';
import React from 'react';
import React, { useEffect, useMemo, useRef, useState } from 'react';

import AppAPIs from '../components/AppAPIs';
import AppEntityAPIs from '../components/AppEntityAPIs';
Expand Down Expand Up @@ -69,15 +69,128 @@ 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 = React.useRef<IAppWindow | null>(null);
const [iframeUrl, setIframeUrl] = React.useState<URL | null>(null);
const dialogWindowRef = useRef<IAppWindow | null>(null);
const [iframeUrl, setIframeUrl] = useState<URL | null>(null);
const [groupedMode, setGroupedMode] = useState(false); // Toggle between default and grouped mode
const [visibleSections, setVisibleSections] = useState<string[]>([]); // 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`));
};

// Function to toggle the visibility of a specific section
const toggleSection = (sectionName: string): void => {
setVisibleSections(
(prev) =>
prev.includes(sectionName)
? prev.filter((section) => section !== sectionName) // Hide section if already open
: [...prev, sectionName], // Show section if not open
);
};

// List of sections dynamically created from React elements
const sections = useMemo(
() => [
{ name: 'AppAPIs', component: <AppAPIs /> },
{ name: 'AppInitializationAPIs', component: <AppInitializationAPIs /> },
{ name: 'AppInstallDialogAPIs', component: <AppInstallDialogAPIs /> },
{ name: 'AuthenticationAPIs', component: <AuthenticationAPIs /> },
{ name: 'AppEntityAPIs', component: <AppEntityAPIs /> },
{ name: 'BarCodeAPIs', component: <BarCodeAPIs /> },
{ name: 'CalendarAPIs', component: <CalendarAPIs /> },
{ name: 'CallAPIs', component: <CallAPIs /> },
{ name: 'ChatAPIs', component: <ChatAPIs /> },
{ name: 'ClipboardAPIs', component: <ClipboardAPIs /> },
{ name: 'CookieAccessComponent', component: <CookieAccessComponent /> },
{ name: 'CopilotAPIs', component: <CopilotAPIs /> },
{ name: 'CustomAPIs', component: <CustomAPIs /> },
{ name: 'DialogAPIs', component: <DialogAPIs /> },
{ name: 'DialogCardAPIs', component: <DialogCardAPIs /> },
{ name: 'DialogCardBotAPIs', component: <DialogCardBotAPIs /> },
{ name: 'DialogUpdateAPIs', component: <DialogUpdateAPIs /> },
{ name: 'DialogUrlAPIs', component: <DialogUrlAPIs childWindowRef={dialogWindowRef} /> },
{ name: 'DialogUrlBotAPIs', component: <DialogUrlBotAPIs /> },
{
name: 'DialogUrlParentCommunicationAPIs',
component: <DialogUrlParentCommunicationAPIs childWindowRef={dialogWindowRef} />,
},
{ name: 'ExternalAppAuthenticationAPIs', component: <ExternalAppAuthenticationAPIs /> },
{ name: 'ExternalAppAuthenticationForCEAAPIs', component: <ExternalAppAuthenticationForCEAAPIs /> },
{ name: 'ExternalAppCardActionsAPIs', component: <ExternalAppCardActionsAPIs /> },
{ name: 'ExternalAppCardActionsForCEAAPIs', component: <ExternalAppCardActionsForCEAAPIs /> },
{ name: 'ExternalAppCommandsAPIs', component: <ExternalAppCommandsAPIs /> },
{ name: 'FilesAPIs', component: <FilesAPIs /> },
{ name: 'FullTrustAPIs', component: <FullTrustAPIs /> },
{ name: 'GeoLocationAPIs', component: <GeoLocationAPIs /> },
{ name: 'HostEntityTabAPIs', component: <HostEntityTabAPIs /> },
{ name: 'Links', component: <Links /> },
{ name: 'LocationAPIs', component: <LocationAPIs /> },
{ name: 'LogAPIs', component: <LogAPIs /> },
{ name: 'MailAPIs', component: <MailAPIs /> },
{ name: 'MarketplaceAPIs', component: <MarketplaceAPIs /> },
{ name: 'MediaAPIs', component: <MediaAPIs /> },
{ name: 'MeetingAPIs', component: <MeetingAPIs /> },
{ name: 'MeetingRoomAPIs', component: <MeetingRoomAPIs /> },
{ name: 'MenusAPIs', component: <MenusAPIs /> },
{ name: 'MessageChannelAPIs', component: <MessageChannelAPIs /> },
{ name: 'MonetizationAPIs', component: <MonetizationAPIs /> },
{ name: 'NestedAppAuthAPIs', component: <NestedAppAuthAPIs /> },
{ name: 'NotificationAPIs', component: <NotificationAPIs /> },
{ name: 'OtherAppStateChangedAPIs', component: <OtherAppStateChangedAPIs /> },
{ name: 'PagesAPIs', component: <PagesAPIs /> },
{ name: 'PagesAppButtonAPIs', component: <PagesAppButtonAPIs /> },
{ name: 'PagesBackStackAPIs', component: <PagesBackStackAPIs /> },
{ name: 'PagesConfigAPIs', component: <PagesConfigAPIs /> },
{ name: 'PagesCurrentAppAPIs', component: <PagesCurrentAppAPIs /> },
{ name: 'PagesTabsAPIs', component: <PagesTabsAPIs /> },
{ name: 'PeopleAPIs', component: <PeopleAPIs /> },
{ name: 'PrivateAPIs', component: <PrivateAPIs /> },
{ name: 'ProfileAPIs', component: <ProfileAPIs /> },
{ name: 'RemoteCameraAPIs', component: <RemoteCameraAPIs /> },
{ name: 'SearchAPIs', component: <SearchAPIs /> },
{ name: 'SecondaryBrowserAPIs', component: <SecondaryBrowserAPIs /> },
{ name: 'SharingAPIs', component: <SharingAPIs /> },
{ name: 'WebStorageAPIs', component: <WebStorageAPIs /> },
{ name: 'StageViewAPIs', component: <StageViewAPIs /> },
{ name: 'StageViewSelfAPIs', component: <StageViewSelfAPIs /> },
{ name: 'TeamsCoreAPIs', component: <TeamsCoreAPIs /> },
{ name: 'TeamsAPIs', component: <TeamsAPIs /> },
{ name: 'ThirdPartyCloudStorageAPIs', component: <ThirdPartyCloudStorageAPIs /> },
{ name: 'VideoAPIs', component: <VideoAPIs /> },
{ name: 'VideoExAPIs', component: <VideoExAPIs /> },
{ name: 'VisualMediaAPIs', component: <VisualMediaAPIs /> },
],
[],
);

// 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 (
<>
<button id="button_reload" onClick={() => window.location.reload()}>
Expand All @@ -86,6 +199,12 @@ export const TestApp: React.FC = () => {
<button id="button_iframe" onClick={loadCurrentUrl}>
Load Current URL in child Iframe for initialization testing
</button>

{/* Toggle between default and grouped mode */}
<button onClick={() => setGroupedMode(!groupedMode)}>
{groupedMode ? 'Show All Sections' : 'Switch to Grouped Mode'}
</button>

<div className="App-container">
{iframeUrl !== null && (
<div>
Expand All @@ -94,71 +213,41 @@ export const TestApp: React.FC = () => {
<iframe src={iframeUrl.toString()} width="100%" height="500px" />
</div>
)}
<AppAPIs />
<AppInitializationAPIs />
<AppInstallDialogAPIs />
<AuthenticationAPIs />
<AppEntityAPIs />
<BarCodeAPIs />
<CalendarAPIs />
<CallAPIs />
<ChatAPIs />
<ClipboardAPIs />
<CookieAccessComponent />
<CopilotAPIs />
<CustomAPIs />
<DialogAPIs />
<DialogCardAPIs />
<DialogCardBotAPIs />
<DialogUpdateAPIs />
<DialogUrlAPIs childWindowRef={dialogWindowRef} />
<DialogUrlBotAPIs />
<DialogUrlParentCommunicationAPIs childWindowRef={dialogWindowRef} />
<ExternalAppAuthenticationAPIs />
<ExternalAppAuthenticationForCEAAPIs />
<ExternalAppCardActionsAPIs />
<ExternalAppCardActionsForCEAAPIs />
<ExternalAppCommandsAPIs />
<FilesAPIs />
<FullTrustAPIs />
<GeoLocationAPIs />
<HostEntityTabAPIs />
<Links />
<LocationAPIs />
<LogAPIs />
<MailAPIs />
<MarketplaceAPIs />
<MediaAPIs />
<MeetingAPIs />
<MeetingRoomAPIs />
<MenusAPIs />
<MessageChannelAPIs />
<MonetizationAPIs />
<NestedAppAuthAPIs />
<NotificationAPIs />
<OtherAppStateChangedAPIs />
<PagesAPIs />
<PagesAppButtonAPIs />
<PagesBackStackAPIs />
<PagesConfigAPIs />
<PagesCurrentAppAPIs />
<PagesTabsAPIs />
<PeopleAPIs />
<PrivateAPIs />
<ProfileAPIs />
<RemoteCameraAPIs />
<SearchAPIs />
<SecondaryBrowserAPIs />
<SharingAPIs />
<WebStorageAPIs />
<StageViewAPIs />
<StageViewSelfAPIs />
<TeamsCoreAPIs />
<TeamsAPIs />
<ThirdPartyCloudStorageAPIs />
<VideoAPIs />
<VideoExAPIs />
<VisualMediaAPIs />
{/* Default mode: Show all sections */}
{!groupedMode ? (
<>
{sections.map((section) => (
<React.Fragment key={section.name}>{section.component}</React.Fragment>
))}
</>
) : (
<>
{/* Grouped mode: Dynamically create buttons for each section */}
{!hideButtons && (
<>
{sections.map((section) => (
<div key={section.name} className="section-content-in-grouped-mode">
<button className="section-button-in-grouped-mode" onClick={() => toggleSection(section.name)}>
{section.name}
</button>
{visibleSections.includes(section.name) && section.component}
</div>
))}
</>
)}

{/* Only display visible sections if buttons are hidden */}
{hideButtons && (
<>
{sections
.filter((section) => visibleSections.includes(section.name))
.map((section) => (
<div key={section.name}>{section.component}</div>
))}
</>
)}
</>
)}
</div>
<Version />
</>
Expand Down
Loading