Skip to content

Commit

Permalink
Stablize Notifications Feature (#4860)
Browse files Browse the repository at this point in the history
* move to stable

* Change files

* move to stable

* Update packages/react-composites CallComposite browser test snapshots

* fix lint

---------

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
  • Loading branch information
carocao-msft and github-actions[bot] authored Jul 12, 2024
1 parent a763e2b commit 463abe1
Show file tree
Hide file tree
Showing 47 changed files with 168 additions and 40 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"type": "prerelease",
"area": "feature",
"workstream": "Notifications",
"comment": "Azure Communication Services UI Library is adding support for improved in-call notifications. In call notifications are essential for providing users with timely and relevant information about their calling experience. Whether it is an error message, a mute status, or a network quality indicator, notifications can help users troubleshoot issues and improve their communication. The new feature of ACS UI Library simplifies the display and management of multiple notifications in a consistent and user-friendly way. The in-call notification feature introduces a streamlined UI experience for displaying errors and notifications in the calling environment.",
"packageName": "@azure/communication-react",
"email": "96077406+carocao-msft@users.noreply.github.com",
"dependentChangeType": "patch"
}
6 changes: 3 additions & 3 deletions common/config/babel/features.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,6 @@ module.exports = {
"rich-text-editor-composite-support",
// Feature for Rich Text Editor (RTE) image upload support
"rich-text-editor-image-upload",
// Feature for showing notifications
"notifications",
// feature for adding JS helpers to the UI library API
"composite-js-helpers",
],
Expand Down Expand Up @@ -99,6 +97,8 @@ module.exports = {
// Feature to support file sharing in Teams interoperability chats
"file-sharing-teams-interop",
// Get join conference information
'teams-meeting-conference'
'teams-meeting-conference',
// Feature for showing notifications
"notifications"
]
}
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,7 @@ const findSelector = (component: (props: any) => JSX.Element | undefined): any =
return undefined;
};

/* @conditional-compile-remove(PSTN-calls) */
/* @conditional-compile-remove(PSTN-calls) */ /* @conditional-compile-remove(notifications) */
const findConditionalCompiledSelector = (component: (props: any) => JSX.Element | undefined): any => {
switch (component) {
/* @conditional-compile-remove(PSTN-calls) */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import { DiagnosticQuality } from '@azure/communication-calling';
/**
* Selector type for {@link Notification} component.
*
* @beta
* @public
*/
export type NotificationStackSelector = (
state: CallClientState,
Expand All @@ -39,7 +39,7 @@ export type NotificationStackSelector = (
* - `ErrorType` is never repeated in the returned errors.
* - Errors are returned in a fixed order by `ErrorType`.
*
* @beta
* @public
*/
export const notificationStackSelector: NotificationStackSelector = createSelector(
[
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ export interface ActiveErrorMessage {
type: ErrorType;
}

// @beta
// @public
export interface ActiveNotification {
autoDismiss?: boolean;
onClickPrimaryButton?: () => void;
Expand Down Expand Up @@ -3659,11 +3659,11 @@ export interface NetworkDiagnosticsState {
latest: LatestNetworkDiagnostics;
}

// @beta
// @public
const Notification_2: (props: NotificationProps) => JSX.Element;
export { Notification_2 as Notification }

// @beta
// @public
export interface NotificationProps {
autoDismiss?: boolean;
notificationIconProps?: IIconProps;
Expand All @@ -3674,10 +3674,10 @@ export interface NotificationProps {
showStackedEffect?: boolean;
}

// @beta
// @public
export const NotificationStack: (props: NotificationStackProps) => JSX.Element;

// @beta
// @public
export interface NotificationStackProps {
activeNotifications: ActiveNotification[];
ignorePremountNotifications?: boolean;
Expand All @@ -3686,13 +3686,13 @@ export interface NotificationStackProps {
strings?: NotificationStackStrings;
}

// @beta
// @public
export type NotificationStackSelector = (state: CallClientState, props: CallingBaseSelectorProps) => {
activeErrorMessages: ActiveNotification[];
activeNotifications: ActiveNotification[];
};

// @beta
// @public
export interface NotificationStackStrings {
callCameraAccessDenied?: NotificationStrings;
callCameraAccessDeniedSafari?: NotificationStrings;
Expand Down Expand Up @@ -3735,7 +3735,7 @@ export interface NotificationStackStrings {
unmuteGeneric?: NotificationStrings;
}

// @beta
// @public
export interface NotificationStrings {
dismissButtonAriaLabel: string;
message?: string;
Expand All @@ -3744,7 +3744,7 @@ export interface NotificationStrings {
title: string;
}

// @beta
// @public
export type NotificationType = keyof NotificationStackStrings;

// @public
Expand Down
103 changes: 102 additions & 1 deletion packages/communication-react/review/stable/communication-react.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ import { IContextualMenuItem } from '@fluentui/react';
import { IContextualMenuItemStyles } from '@fluentui/react';
import { IContextualMenuProps } from '@fluentui/react';
import { IContextualMenuStyles } from '@fluentui/react';
import { IIconProps } from '@fluentui/react';
import { IMessageBarProps } from '@fluentui/react';
import { IPersonaStyleProps } from '@fluentui/react';
import { IPersonaStyles } from '@fluentui/react';
Expand Down Expand Up @@ -108,6 +109,16 @@ export interface ActiveErrorMessage {
type: ErrorType;
}

// @public
export interface ActiveNotification {
autoDismiss?: boolean;
onClickPrimaryButton?: () => void;
onClickSecondaryButton?: () => void;
onDismiss?: () => void;
timestamp?: Date;
type: NotificationType;
}

// @public
export interface AdapterError extends Error {
innerError: Error;
Expand Down Expand Up @@ -1872,6 +1883,7 @@ export interface ComponentStrings {
messageStatusIndicator: MessageStatusIndicatorStrings;
messageThread: MessageThreadStrings;
microphoneButton: MicrophoneButtonStrings;
notificationStack: NotificationStackStrings;
participantItem: ParticipantItemStrings;
participantsButton: ParticipantsButtonStrings;
raiseHandButton: RaiseHandButtonStrings;
Expand Down Expand Up @@ -2179,6 +2191,7 @@ export const DEFAULT_COMPONENT_ICONS: {
ErrorBarClear: React_2.JSX.Element;
ErrorBarCallVideoRecoveredBySystem: React_2.JSX.Element;
ErrorBarCallVideoStoppedBySystem: React_2.JSX.Element;
NotificationBarRecording: React_2.JSX.Element;
HorizontalGalleryLeftButton: React_2.JSX.Element;
HorizontalGalleryRightButton: React_2.JSX.Element;
MessageDelivered: React_2.JSX.Element;
Expand Down Expand Up @@ -2333,6 +2346,7 @@ export const DEFAULT_COMPOSITE_ICONS: {
OpenAttachment: React_2.JSX.Element;
ErrorBarCallVideoRecoveredBySystem: React_2.JSX.Element;
ErrorBarCallVideoStoppedBySystem: React_2.JSX.Element;
NotificationBarRecording: React_2.JSX.Element;
MessageResend: React_2.JSX.Element;
ParticipantItemSpotlighted: React_2.JSX.Element;
DialpadBackspace: React_2.JSX.Element;
Expand Down Expand Up @@ -2588,7 +2602,7 @@ export interface FluentThemeProviderProps {
export const fromFlatCommunicationIdentifier: (id: string) => CommunicationIdentifier;

// @public
export type GetCallingSelector<Component extends (props: any) => JSX.Element | undefined> = AreEqual<Component, typeof VideoGallery> extends true ? VideoGallerySelector : AreEqual<Component, typeof DevicesButton> extends true ? DevicesButtonSelector : AreEqual<Component, typeof MicrophoneButton> extends true ? MicrophoneButtonSelector : AreEqual<Component, typeof CameraButton> extends true ? CameraButtonSelector : AreEqual<Component, typeof ScreenShareButton> extends true ? ScreenShareButtonSelector : AreEqual<Component, typeof ParticipantList> extends true ? ParticipantListSelector : AreEqual<Component, typeof ParticipantsButton> extends true ? ParticipantsButtonSelector : AreEqual<Component, typeof EndCallButton> extends true ? EmptySelector : AreEqual<Component, typeof ErrorBar> extends true ? CallErrorBarSelector : AreEqual<Component, typeof Dialpad> extends true ? EmptySelector : undefined;
export type GetCallingSelector<Component extends (props: any) => JSX.Element | undefined> = AreEqual<Component, typeof VideoGallery> extends true ? VideoGallerySelector : AreEqual<Component, typeof DevicesButton> extends true ? DevicesButtonSelector : AreEqual<Component, typeof MicrophoneButton> extends true ? MicrophoneButtonSelector : AreEqual<Component, typeof CameraButton> extends true ? CameraButtonSelector : AreEqual<Component, typeof ScreenShareButton> extends true ? ScreenShareButtonSelector : AreEqual<Component, typeof ParticipantList> extends true ? ParticipantListSelector : AreEqual<Component, typeof ParticipantsButton> extends true ? ParticipantsButtonSelector : AreEqual<Component, typeof EndCallButton> extends true ? EmptySelector : AreEqual<Component, typeof ErrorBar> extends true ? CallErrorBarSelector : AreEqual<Component, typeof Dialpad> extends true ? EmptySelector : AreEqual<Component, typeof NotificationStack> extends true ? NotificationStackSelector : undefined;

// @public
export const getCallingSelector: <Component extends (props: any) => JSX.Element | undefined>(component: Component) => GetCallingSelector<Component>;
Expand Down Expand Up @@ -3044,6 +3058,93 @@ export interface NetworkDiagnosticsState {
latest: LatestNetworkDiagnostics;
}

// @public
const Notification_2: (props: NotificationProps) => JSX.Element;
export { Notification_2 as Notification }

// @public
export interface NotificationProps {
autoDismiss?: boolean;
notificationIconProps?: IIconProps;
notificationStrings?: NotificationStrings;
onClickPrimaryButton?: () => void;
onClickSecondaryButton?: () => void;
onDismiss?: () => void;
showStackedEffect?: boolean;
}

// @public
export const NotificationStack: (props: NotificationStackProps) => JSX.Element;

// @public
export interface NotificationStackProps {
activeNotifications: ActiveNotification[];
ignorePremountNotifications?: boolean;
maxNotificationsToShow?: number;
onDismissNotification?: (dismissedNotification: ActiveNotification) => void;
strings?: NotificationStackStrings;
}

// @public
export type NotificationStackSelector = (state: CallClientState, props: CallingBaseSelectorProps) => {
activeErrorMessages: ActiveNotification[];
activeNotifications: ActiveNotification[];
};

// @public
export interface NotificationStackStrings {
callCameraAccessDenied?: NotificationStrings;
callCameraAccessDeniedSafari?: NotificationStrings;
callCameraAlreadyInUse?: NotificationStrings;
callLocalVideoFreeze?: NotificationStrings;
callMacOsCameraAccessDenied?: NotificationStrings;
callMacOsMicrophoneAccessDenied?: NotificationStrings;
callMacOsScreenShareAccessDenied?: NotificationStrings;
callMicrophoneAccessDenied?: NotificationStrings;
callMicrophoneAccessDeniedSafari?: NotificationStrings;
callMicrophoneMutedBySystem?: NotificationStrings;
callMicrophoneUnmutedBySystem?: NotificationStrings;
callNetworkQualityLow?: NotificationStrings;
callNoMicrophoneFound?: NotificationStrings;
callNoSpeakerFound?: NotificationStrings;
callVideoRecoveredBySystem?: NotificationStrings;
callVideoStoppedBySystem?: NotificationStrings;
cameraFrozenForRemoteParticipants?: NotificationStrings;
dismissButtonAriaLabel?: NotificationStrings;
failedToJoinCallGeneric?: NotificationStrings;
failedToJoinCallInvalidMeetingLink?: NotificationStrings;
muteGeneric?: NotificationStrings;
recordingAndTranscriptionStarted?: NotificationStrings;
recordingAndTranscriptionStopped?: NotificationStrings;
recordingStarted?: NotificationStrings;
recordingStopped?: NotificationStrings;
recordingStoppedStillTranscribing?: NotificationStrings;
speakingWhileMuted?: NotificationStrings;
startScreenShareGeneric?: NotificationStrings;
startSpotlightWhileMaxParticipantsAreSpotlighted?: NotificationStrings;
startVideoGeneric?: NotificationStrings;
stopScreenShareGeneric?: NotificationStrings;
stopVideoGeneric?: NotificationStrings;
teamsMeetingCallNetworkQualityLow?: NotificationStrings;
transcriptionStarted?: NotificationStrings;
transcriptionStopped?: NotificationStrings;
transcriptionStoppedStillRecording?: NotificationStrings;
unableToStartVideoEffect?: NotificationStrings;
unmuteGeneric?: NotificationStrings;
}

// @public
export interface NotificationStrings {
dismissButtonAriaLabel: string;
message?: string;
primaryButtonLabel?: string;
secondaryButtonLabel?: string;
title: string;
}

// @public
export type NotificationType = keyof NotificationStackStrings;

// @public
export type OnFetchProfileCallback = (userId: string, defaultProfile?: Profile) => Promise<Profile | undefined>;

Expand Down
6 changes: 3 additions & 3 deletions packages/react-components/src/components/Notification.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import {
/**
* Props for {@link Notification}.
*
* @beta
* @public
*/
export interface NotificationProps {
/**
Expand Down Expand Up @@ -59,7 +59,7 @@ export interface NotificationProps {
/**
* All strings that may be shown on the UI in the {@link Notification}.
*
* @beta
* @public
*/
export interface NotificationStrings {
/**
Expand Down Expand Up @@ -87,7 +87,7 @@ export interface NotificationStrings {
/**
* A component to show notification messages on the UI.
*
* @beta
* @public
*/
export const Notification = (props: NotificationProps): JSX.Element => {
const strings = props.notificationStrings;
Expand Down
10 changes: 5 additions & 5 deletions packages/react-components/src/components/NotificationStack.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import { Notification, NotificationStrings } from './Notification';

/**
* Props for {@link NotificationStack}.
* @beta
* @public
*/
export interface NotificationStackProps {
/**
Expand Down Expand Up @@ -57,7 +57,7 @@ export interface NotificationStackProps {
/**
* All strings that may be shown on the UI in the {@link NotificationStack}.
*
* @beta
* @public
*/
export interface NotificationStackStrings {
/**
Expand Down Expand Up @@ -251,14 +251,14 @@ export interface NotificationStackStrings {
/**
* All notifications that can be shown in the {@link NotificationStack}.
*
* @beta
* @public
*/
export type NotificationType = keyof NotificationStackStrings;

/**
* Active notifications to be shown via {@link NotificationStack}.
*
* @beta
* @public
*/
export interface ActiveNotification {
/**
Expand Down Expand Up @@ -305,7 +305,7 @@ export interface ActiveNotification {
* If the notification recurs, it is shown in the UI.
*
*
* @beta
* @public
*/
export const NotificationStack = (props: NotificationStackProps): JSX.Element => {
/* @conditional-compile-remove(notifications) */
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@ import { Stack } from '@fluentui/react';
import { Canvas, Description, Heading, Props, Title } from '@storybook/addon-docs';
import { Meta } from '@storybook/react/types-6-0';
import React from 'react';
import { Notification as NotificationComponent } from '../../../../react-components/src/components';
import { COMPONENT_FOLDER_PREFIX } from '../../constants';
import { controlsToAdd, hiddenControl } from '../../controlsUtils';
import { Notification as NotificationComponent } from '../../../react-components/src/components';
import { COMPONENT_FOLDER_PREFIX } from '../constants';
import { controlsToAdd, hiddenControl } from '../controlsUtils';
import { ExampleNotification } from './snippets/ExampleNotification.snippet';

const ExampleNotificationText = require('!!raw-loader!./snippets/ExampleNotification.snippet.tsx').default;
Expand Down Expand Up @@ -68,8 +68,8 @@ const NotificationStory = (args): JSX.Element => {
export const Notification = NotificationStory.bind({});

export default {
id: `${COMPONENT_FOLDER_PREFIX}-internal-Notification`,
title: `${COMPONENT_FOLDER_PREFIX}/Internal/Notifications/Notification`,
id: `${COMPONENT_FOLDER_PREFIX}-Notification`,
title: `${COMPONENT_FOLDER_PREFIX}/Notifications/Notification`,
component: NotificationComponent,
argTypes: {
notificationStrings: hiddenControl,
Expand Down
Loading

0 comments on commit 463abe1

Please sign in to comment.