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

feat: add a notification banner to display for first time users #3396

Open
wants to merge 24 commits into
base: dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 18 commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
2a7a2e3
WIP: set basics for the Notification banner
musale Oct 29, 2024
bd5a321
Revert to previous functionality
musale Oct 30, 2024
f26b351
Use v8 styling construct and a MessageBar
musale Oct 30, 2024
fb0096e
Merge branch 'dev' into feat/notification-banner
musale Oct 31, 2024
377f689
Use fluent v9 and get messages for notification from GE.json
musale Oct 31, 2024
06c88b3
Add fluent v9 components dependencies
musale Oct 31, 2024
daf6010
Update styles and components for Notification
musale Oct 31, 2024
31949f8
Add text for notification
musale Oct 31, 2024
bda0a91
Hook theming of v9 provider to prop value
musale Oct 31, 2024
e248e4a
Track the tutorial link with telemetry
musale Nov 5, 2024
2ef65a5
Add slice banner
musale Nov 5, 2024
39814b6
Persist banner state to localstorage
musale Nov 5, 2024
24fa979
Update state usage of banner state
musale Nov 5, 2024
1d80997
Use local storage to track banner visibility
musale Nov 5, 2024
0ec9823
Add the background and custom types
musale Nov 5, 2024
f630d65
Fix theming and sizing of text in the body
musale Nov 6, 2024
8891992
Handle dismissing of the banner
musale Nov 6, 2024
460aacd
Lock the v9 packages version
musale Nov 6, 2024
b90a2aa
Update the banner notification link
musale Nov 18, 2024
ad6b7da
Merge remote-tracking branch 'origin' into feat/notification-banner
musale Nov 18, 2024
8e4824f
Enhance type safety for trackReactComponent method
musale Nov 18, 2024
7244c75
Add telemetry tracking for Notification component
musale Nov 18, 2024
fa8fd1c
Refactor Notification import and update App component structure
musale Nov 18, 2024
03eae38
Add telemetry tracking for notification dismiss button
musale Nov 18, 2024
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
1,569 changes: 1,558 additions & 11 deletions package-lock.json

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
"@babel/core": "7.25.2",
"@babel/runtime": "7.25.6",
"@fluentui/react": "8.120.7",
"@fluentui/react-components": "9.55.1",
"@fluentui/react-icons-mdl2": "1.3.63",
"@microsoft/applicationinsights-react-js": "17.3.1",
"@microsoft/applicationinsights-web": "3.3.1",
Expand Down
3 changes: 2 additions & 1 deletion src/app/middleware/localStorageMiddleware.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ import { CURRENT_THEME } from '../services/graph-constants';
import { getUniquePaths } from '../services/reducers/collections-reducer.util';
import {
CHANGE_THEME_SUCCESS, COLLECTION_CREATE_SUCCESS,
RESOURCEPATHS_ADD_SUCCESS, RESOURCEPATHS_DELETE_SUCCESS, SAMPLES_FETCH_SUCCESS
RESOURCEPATHS_ADD_SUCCESS, RESOURCEPATHS_DELETE_SUCCESS,
SAMPLES_FETCH_SUCCESS
} from '../services/redux-constants';
import { saveToLocalStorage } from '../utils/local-storage';

Expand Down
3 changes: 2 additions & 1 deletion src/app/services/graph-constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,4 +32,5 @@ export const ADMIN_CONSENT_DOC_LINK = 'https://learn.microsoft.com/en-us/graph/s
// eslint-disable-next-line max-len
export const CONSENT_TYPE_DOC_LINK = 'https://learn.microsoft.com/en-us/graph/api/resources/oauth2permissiongrant?view=graph-rest-1.0#:~:text=(eq%20only).-,consentType,-String'
export const CURRENT_THEME='CURRENT_THEME';
export const EXP_URL='https://default.exp-tas.com/exptas76/9b835cbf-9742-40db-84a7-7a323a77f3eb-gedev/api/v1/tas'
export const EXP_URL='https://default.exp-tas.com/exptas76/9b835cbf-9742-40db-84a7-7a323a77f3eb-gedev/api/v1/tas'
musale marked this conversation as resolved.
Show resolved Hide resolved
export const BANNER_IS_VISIBLE = 'bannerIsVisible';
1 change: 1 addition & 0 deletions src/app/services/redux-constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,3 +56,4 @@ export const REVOKE_SCOPES_PENDING = 'auth/revokeScopes/pending';
export const REVOKE_SCOPES_SUCCESS = 'auth/revokeScopes/fulfilled';
export const REVOKE_SCOPES_ERROR = 'auth/revokeScopes/rejected';
export const COLLECTION_CREATE_SUCCESS = 'collections/createCollection';
export const SET_BANNER_STATE = 'banner/setBannerState';
17 changes: 17 additions & 0 deletions src/app/views/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { bindActionCreators, Dispatch } from '@reduxjs/toolkit';
import { Resizable } from 're-resizable';
import { Component } from 'react';
import { connect } from 'react-redux';
import { FluentProvider, teamsHighContrastTheme, Theme, webDarkTheme, webLightTheme } from '@fluentui/react-components';

import { removeSpinners } from '../..';
import { authenticationWrapper } from '../../modules/authentication';
Expand Down Expand Up @@ -39,10 +40,12 @@ import { QueryResponse } from './query-response';
import { QueryRunner } from './query-runner';
import { parse } from './query-runner/util/iframe-message-parser';
import { Sidebar } from './sidebar/Sidebar';
import { Notification } from './common/banners/Notification';
export interface IAppProps {
theme?: ITheme;
styles?: object;
profile: object;
appTheme: string;
graphExplorerMode: Mode;
sidebarProperties: ISidebarProps;
sampleQuery: IQuery;
Expand Down Expand Up @@ -404,8 +407,14 @@ class App extends Component<IAppProps, IAppState> {
this.removeFlexBasisProperty();
this.removeSidebarHeightProperty();

const fluentV9Themes: Record<string, Theme>= {
'light': webLightTheme,
'dark': webDarkTheme,
'high-contrast': teamsHighContrastTheme
}
return (
// @ts-ignore
<FluentProvider theme={fluentV9Themes[this.props.appTheme]}>
<ThemeContext.Provider value={this.props.appTheme}>
<PopupsProvider>
<div className={`ms-Grid ${classes.app}`} style={{ paddingLeft: mobileScreen && '15px' }}>
Expand Down Expand Up @@ -472,6 +481,13 @@ class App extends Component<IAppProps, IAppState> {
display: 'flex', flexDirection: 'column', alignItems: 'stretch', flex: 1
}}
>
<div className='ms-Grid-row'>
<Notification
header={translateMessage('Banner notification 1 header')}
content={translateMessage('Banner notification 1 content')}
link={translateMessage('Banner notificatication 1 link')}
linkText={translateMessage('Banner notification 1 link text')}/>
</div>
<ValidationProvider>
<div style={{ marginBottom: 2 }} >
<QueryRunner onSelectVerb={this.handleSelectVerb} />
Expand All @@ -495,6 +511,7 @@ class App extends Component<IAppProps, IAppState> {
<PopupsWrapper />
</PopupsProvider>
</ThemeContext.Provider>
</FluentProvider>
);
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/app/views/classnames.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,4 @@ interface IClassNames {
export function classNames({ styles, theme }: IClassNames): any {
const getClassNames = classNamesFunction();
return getClassNames(styles, theme);
}
}
31 changes: 31 additions & 0 deletions src/app/views/common/banners/Notification.styles.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { makeStyles } from '@fluentui/react-components';
import polygons from './bgPolygons.svg';

export const useNotificationStyles = makeStyles({
container: {
padding: '8px',
marginBottom: '8px',
backgroundImage: `url(${polygons})`,
backgroundRepeat: 'no-repeat',
backgroundSize: 'contain',
backgroundPosition: 'right',
'&light': {
backgroundColor: '#E8EFFF',
color: '#000000'
},
'&.dark': {
backgroundColor: '#1D202A',
color: '#ffffff'
},
'&.highContrast': {
backgroundColor: '#0C3B5E',
color: '#ffffff'
}
},
body: {
width: '100%',
'@media (min-width: 720px)': {
width: '70%'
}
}
});
66 changes: 66 additions & 0 deletions src/app/views/common/banners/Notification.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import {
Button,
Link,
MessageBar,
MessageBarActions,
MessageBarBody,
MessageBarTitle
} from '@fluentui/react-components';
import { DismissRegular, OpenRegular } from '@fluentui/react-icons';
import { useState } from 'react';
import { useAppSelector } from '../../../../store';
import { componentNames, telemetry } from '../../../../telemetry';
import { BANNER_IS_VISIBLE } from '../../../services/graph-constants';
import { translateMessage } from '../../../utils/translate-messages';
import { useNotificationStyles } from './Notification.styles';

interface NotificationProps {
header: string;
content: string;
link: string;
linkText: string;
}

const handleOnClickLink = (e: React.MouseEvent<HTMLAnchorElement>)=>{
telemetry.trackLinkClickEvent(
(e.currentTarget as HTMLAnchorElement).href, componentNames.GRAPH_EXPLORER_TUTORIAL_LINK)
}

export const Notification: React.FunctionComponent<NotificationProps> = (props: NotificationProps) => {
const styles = useNotificationStyles();
const storageBanner = localStorage.getItem(BANNER_IS_VISIBLE);
const [isVisible, setIsVisible] = useState(storageBanner === null || storageBanner === 'true');
const theme = useAppSelector(s => s.theme);

const handleDismiss = () => {
localStorage.setItem(BANNER_IS_VISIBLE, 'false');
setIsVisible(false);
};

if (!isVisible) {
return null;
}

return (
<MessageBar className={`${styles.container} ${theme}`} icon={''}>
<MessageBarBody className={styles.body}>
<MessageBarTitle>{props.header}</MessageBarTitle><br></br>
{props.content}{' '}
<Link
onClick={handleOnClickLink}
href={props.link}
target='_blank'>{props.linkText} <OpenRegular /></Link>
</MessageBarBody>
<MessageBarActions
containerAction={
<Button
onClick={handleDismiss}
aria-label={translateMessage('Dismiss banner')}
appearance="transparent"
icon={<DismissRegular />}
/>
}
/>
</MessageBar>
);
};
46 changes: 46 additions & 0 deletions src/app/views/common/banners/bgPolygons.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
5 changes: 5 additions & 0 deletions src/app/views/common/banners/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { Notification } from './Notification'

export default {
Notification
}
5 changes: 5 additions & 0 deletions src/custom.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
// custom.d.ts
declare module '*.svg' {
const content: any;
export default content;
}
7 changes: 6 additions & 1 deletion src/messages/GE.json
Original file line number Diff line number Diff line change
Expand Up @@ -498,5 +498,10 @@
"Revoking admin granted scopes": "Revoking admin granted scopes",
"Revoking default scopes": "Revoking default scopes",
"More request area items": "More request area items",
"More response items": "More response area items"
"More response items": "More response area items",
"Banner notification 1 header": "New to Graph Explorer?",
"Banner notification 1 content": "Graph Explorer is a developer tool that let's you learn about Microsoft Graph APIs. Use Graph Explorer to try the APIs on the default sample tenat to explore capabilities.",
"Banner notification 1 link text": "Follow a step-by-step tutorial",
"Banner notification 1 link": "https://aka.ms/ge",
musale marked this conversation as resolved.
Show resolved Hide resolved
"Dismiss banner": "Dismiss banner"
}
1 change: 1 addition & 0 deletions src/telemetry/component-names.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ export const GRAPH_TOOLKIT_PLAYGROUND_LINK = 'Graph toolkit playground link';
export const MICROSOFT_APIS_TERMS_OF_USE_LINK = 'Microsoft APIs terms of use link';
export const MICROSOFT_PRIVACY_STATEMENT_LINK = 'Microsoft privacy statement link';
export const MICROSOFT_GRAPH_API_REFERENCE_DOCS_LINK = 'Microsoft graph API reference docs link';
export const GRAPH_EXPLORER_TUTORIAL_LINK = 'Graph Explorer Tutorial Link';
export const CODE_SNIPPET_LANGUAGES = {
CSharp: {
sdk: 'C# SDK link', doc: 'C# snippet docs link'
Expand Down
Loading