From 2a7a2e3a2fdbc1ec21bff4f68c797645067b84d7 Mon Sep 17 00:00:00 2001 From: Musale Martin Date: Tue, 29 Oct 2024 17:13:53 +0300 Subject: [PATCH 01/24] WIP: set basics for the Notification banner --- src/app/views/App.tsx | 2 ++ src/app/views/classnames.ts | 5 +++-- .../views/common/banners/Notification.styles.ts | 10 ++++++++++ src/app/views/common/banners/Notification.tsx | 16 ++++++++++++++++ src/app/views/common/banners/index.ts | 5 +++++ 5 files changed, 36 insertions(+), 2 deletions(-) create mode 100644 src/app/views/common/banners/Notification.styles.ts create mode 100644 src/app/views/common/banners/Notification.tsx create mode 100644 src/app/views/common/banners/index.ts diff --git a/src/app/views/App.tsx b/src/app/views/App.tsx index 51cbdaddf7..fff0943d82 100644 --- a/src/app/views/App.tsx +++ b/src/app/views/App.tsx @@ -39,6 +39,7 @@ 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; @@ -472,6 +473,7 @@ class App extends Component { display: 'flex', flexDirection: 'column', alignItems: 'stretch', flex: 1 }} > +
diff --git a/src/app/views/classnames.ts b/src/app/views/classnames.ts index 16766feb70..a3be427587 100644 --- a/src/app/views/classnames.ts +++ b/src/app/views/classnames.ts @@ -1,4 +1,5 @@ -import { classNamesFunction, ITheme } from '@fluentui/react'; +import { classNamesFunction, IProcessedStyleSet, ITheme} from '@fluentui/react'; +import {IStyleSetBase} from '@fluentui/merge-styles' interface IClassNames { [prop: string]: unknown; @@ -6,7 +7,7 @@ interface IClassNames { styles?: object; } -export function classNames({ styles, theme }: IClassNames): any { +export function classNames({ styles, theme }: IClassNames): IProcessedStyleSet { const getClassNames = classNamesFunction(); return getClassNames(styles, theme); } diff --git a/src/app/views/common/banners/Notification.styles.ts b/src/app/views/common/banners/Notification.styles.ts new file mode 100644 index 0000000000..f0ff22f48e --- /dev/null +++ b/src/app/views/common/banners/Notification.styles.ts @@ -0,0 +1,10 @@ +import { ITheme } from '@fluentui/react'; + +export const NotificationStyles = (theme: ITheme) => { + return { + container: { + backgroundColor: 'blue', + textColor: '#ffffff' + } + } +} \ No newline at end of file diff --git a/src/app/views/common/banners/Notification.tsx b/src/app/views/common/banners/Notification.tsx new file mode 100644 index 0000000000..b46f39fe65 --- /dev/null +++ b/src/app/views/common/banners/Notification.tsx @@ -0,0 +1,16 @@ +import { classNames } from '../../classnames' + +interface NotificationProps { + header: string + content: string +} + + +export const Notification: React.FunctionComponent = (props: NotificationProps)=>{ + const notificationClassNames = classNames(props) + + return
+

{props.header}

+

{props.content}

+
+} \ No newline at end of file diff --git a/src/app/views/common/banners/index.ts b/src/app/views/common/banners/index.ts new file mode 100644 index 0000000000..96c3f6514b --- /dev/null +++ b/src/app/views/common/banners/index.ts @@ -0,0 +1,5 @@ +import { Notification } from './Notification' + +export default { + Notification +} \ No newline at end of file From bd5a32104e4abad7b6f5b7e98115b67b3030f056 Mon Sep 17 00:00:00 2001 From: Musale Martin Date: Wed, 30 Oct 2024 18:01:51 +0300 Subject: [PATCH 02/24] Revert to previous functionality --- src/app/views/classnames.ts | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/app/views/classnames.ts b/src/app/views/classnames.ts index a3be427587..49d8c49f55 100644 --- a/src/app/views/classnames.ts +++ b/src/app/views/classnames.ts @@ -1,5 +1,4 @@ -import { classNamesFunction, IProcessedStyleSet, ITheme} from '@fluentui/react'; -import {IStyleSetBase} from '@fluentui/merge-styles' +import { classNamesFunction, ITheme } from '@fluentui/react'; interface IClassNames { [prop: string]: unknown; @@ -7,7 +6,7 @@ interface IClassNames { styles?: object; } -export function classNames({ styles, theme }: IClassNames): IProcessedStyleSet { +export function classNames({ styles, theme }: IClassNames): any { const getClassNames = classNamesFunction(); return getClassNames(styles, theme); -} +} \ No newline at end of file From f26b351dae93861c0f5a10855ad5b999e1549a54 Mon Sep 17 00:00:00 2001 From: Musale Martin Date: Wed, 30 Oct 2024 18:02:24 +0300 Subject: [PATCH 03/24] Use v8 styling construct and a MessageBar --- .../common/banners/Notification.styles.ts | 9 +++-- src/app/views/common/banners/Notification.tsx | 40 ++++++++++++++----- 2 files changed, 35 insertions(+), 14 deletions(-) diff --git a/src/app/views/common/banners/Notification.styles.ts b/src/app/views/common/banners/Notification.styles.ts index f0ff22f48e..0b38f2383b 100644 --- a/src/app/views/common/banners/Notification.styles.ts +++ b/src/app/views/common/banners/Notification.styles.ts @@ -1,10 +1,11 @@ -import { ITheme } from '@fluentui/react'; +import { mergeStyleSets } from '@fluentui/react'; -export const NotificationStyles = (theme: ITheme) => { - return { +export const useNotificationStyles = ()=>{ + return mergeStyleSets({ container: { + borderRadius: '8px', backgroundColor: 'blue', textColor: '#ffffff' } - } + }) } \ No newline at end of file diff --git a/src/app/views/common/banners/Notification.tsx b/src/app/views/common/banners/Notification.tsx index b46f39fe65..fd1b20d97d 100644 --- a/src/app/views/common/banners/Notification.tsx +++ b/src/app/views/common/banners/Notification.tsx @@ -1,16 +1,36 @@ -import { classNames } from '../../classnames' +import { MessageBar, MessageBarType } from '@fluentui/react'; +import { useNotificationStyles } from './Notification.styles'; +import { useState } from 'react'; interface NotificationProps { - header: string - content: string + header: string; + content: string; + messageType?: MessageBarType; } +export const Notification: React.FunctionComponent = (props: NotificationProps) => { + const styles = useNotificationStyles(); + const [isVisible, setIsVisible] = useState(true); -export const Notification: React.FunctionComponent = (props: NotificationProps)=>{ - const notificationClassNames = classNames(props) + const handleDismiss = () => { + // TODO: track as dismissed in telemetry + // TODO: don't show again. Persist choice to state + setIsVisible(false); + }; - return
-

{props.header}

-

{props.content}

-
-} \ No newline at end of file + if (!isVisible) { + return null; + } + + return ( + +

{props.header}

+ {/* TODO: Track content when link is clicked in telemetry */} +

{props.content}

+
+ ); +}; From 377f689097c262304237b220ce08258c71b7e34e Mon Sep 17 00:00:00 2001 From: Musale Martin Date: Thu, 31 Oct 2024 14:52:01 +0300 Subject: [PATCH 04/24] Use fluent v9 and get messages for notification from GE.json --- src/app/views/App.tsx | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/app/views/App.tsx b/src/app/views/App.tsx index fff0943d82..e8a8cc4e33 100644 --- a/src/app/views/App.tsx +++ b/src/app/views/App.tsx @@ -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, webDarkTheme } from '@fluentui/react-components'; import { removeSpinners } from '../..'; import { authenticationWrapper } from '../../modules/authentication'; @@ -44,6 +45,7 @@ export interface IAppProps { theme?: ITheme; styles?: object; profile: object; + appTheme: string; graphExplorerMode: Mode; sidebarProperties: ISidebarProps; sampleQuery: IQuery; @@ -407,6 +409,7 @@ class App extends Component { return ( // @ts-ignore +
@@ -473,7 +476,13 @@ class App extends Component { display: 'flex', flexDirection: 'column', alignItems: 'stretch', flex: 1 }} > - +
+ +
@@ -497,6 +506,7 @@ class App extends Component { + ); } } From 06c88b316600005596dacd547345f3f7f6c57c5b Mon Sep 17 00:00:00 2001 From: Musale Martin Date: Thu, 31 Oct 2024 14:52:25 +0300 Subject: [PATCH 05/24] Add fluent v9 components dependencies --- package-lock.json | 1569 ++++++++++++++++++++++++++++++++++++++++++++- package.json | 1 + 2 files changed, 1559 insertions(+), 11 deletions(-) diff --git a/package-lock.json b/package-lock.json index d337ea68cb..0548b8bda7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14,6 +14,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", @@ -2921,6 +2922,11 @@ "postcss": "^8.4" } }, + "node_modules/@emotion/hash": { + "version": "0.9.2", + "resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.9.2.tgz", + "integrity": "sha512-MyqliTZGuOm3+5ZRSaaBGP3USLw6+EGykkwZns2EPC5g8jJ4z9OrdZY9apkl3+UP9+sdz76YYkwCKP5gh8iY3g==" + }, "node_modules/@eslint-community/eslint-utils": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", @@ -3045,6 +3051,36 @@ "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, + "node_modules/@floating-ui/core": { + "version": "1.6.8", + "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.6.8.tgz", + "integrity": "sha512-7XJ9cPU+yI2QeLS+FCSlqNFZJq8arvswefkZrYI1yQBbftw6FyrZOxYSh+9S7z7TpeWlRt9zJ5IhM1WIL334jA==", + "dependencies": { + "@floating-ui/utils": "^0.2.8" + } + }, + "node_modules/@floating-ui/devtools": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/@floating-ui/devtools/-/devtools-0.2.1.tgz", + "integrity": "sha512-8PHJLbD6VhBh+LJ1uty/Bz30qs02NXCE5u8WpOhSewlYXUWl03GNXknr9AS2yaAWJEQaY27x7eByJs44gODBcw==", + "peerDependencies": { + "@floating-ui/dom": ">=1.5.4" + } + }, + "node_modules/@floating-ui/dom": { + "version": "1.6.12", + "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.6.12.tgz", + "integrity": "sha512-NP83c0HjokcGVEMeoStg317VD9W7eDlGK7457dMBANbKA6GJZdc7rjujdgqzTaz93jkGgc5P/jeWbaCHnMNc+w==", + "dependencies": { + "@floating-ui/core": "^1.6.0", + "@floating-ui/utils": "^0.2.8" + } + }, + "node_modules/@floating-ui/utils": { + "version": "0.2.8", + "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.8.tgz", + "integrity": "sha512-kym7SodPp8/wloecOpcmSnWJsK7M0E5Wg8UcFA+uO4B9s5d0ywXOEro/8HM9x0rW+TljRzul/14UYz3TleT3ig==" + }, "node_modules/@fluentui/date-time-utilities": { "version": "8.6.9", "resolved": "https://registry.npmjs.org/@fluentui/date-time-utilities/-/date-time-utilities-8.6.9.tgz", @@ -3098,6 +3134,14 @@ "tslib": "^2.1.0" } }, + "node_modules/@fluentui/keyboard-keys": { + "version": "9.0.7", + "resolved": "https://registry.npmjs.org/@fluentui/keyboard-keys/-/keyboard-keys-9.0.7.tgz", + "integrity": "sha512-vaQ+lOveQTdoXJYqDQXWb30udSfTVcIuKk1rV0X0eGAgcHeSDeP1HxMy+OgHOQZH3OiBH4ZYeWxb+tmfiDiygQ==", + "dependencies": { + "@swc/helpers": "^0.5.1" + } + }, "node_modules/@fluentui/merge-styles": { "version": "8.6.13", "resolved": "https://registry.npmjs.org/@fluentui/merge-styles/-/merge-styles-8.6.13.tgz", @@ -3107,6 +3151,14 @@ "tslib": "^2.1.0" } }, + "node_modules/@fluentui/priority-overflow": { + "version": "9.1.13", + "resolved": "https://registry.npmjs.org/@fluentui/priority-overflow/-/priority-overflow-9.1.13.tgz", + "integrity": "sha512-yDojVpkhBZTXOYExrCgW1GXbw3x9pYIS617xlNJIc2t06Cd3H32y2p51QXFt94sBmlVyAvPu7UKBHaq1Yw7u+w==", + "dependencies": { + "@swc/helpers": "^0.5.1" + } + }, "node_modules/@fluentui/react": { "version": "8.120.7", "resolved": "https://registry.npmjs.org/@fluentui/react/-/react-8.120.7.tgz", @@ -3134,6 +3186,438 @@ "react-dom": ">=16.8.0 <19.0.0" } }, + "node_modules/@fluentui/react-accordion": { + "version": "9.5.7", + "resolved": "https://registry.npmjs.org/@fluentui/react-accordion/-/react-accordion-9.5.7.tgz", + "integrity": "sha512-/pSBQE+5MCwo8Pme9MdHn279RUn66gtb16JrTgTL6HLsIJuWmx6+wcejSyTUjt+E6+SpVc97aSDsM88U9SS/zw==", + "dependencies": { + "@fluentui/react-aria": "^9.13.8", + "@fluentui/react-context-selector": "^9.1.68", + "@fluentui/react-icons": "^2.0.245", + "@fluentui/react-jsx-runtime": "^9.0.45", + "@fluentui/react-motion": "^9.6.0", + "@fluentui/react-motion-components-preview": "^0.2.0", + "@fluentui/react-shared-contexts": "^9.20.2", + "@fluentui/react-tabster": "^9.22.9", + "@fluentui/react-theme": "^9.1.21", + "@fluentui/react-utilities": "^9.18.16", + "@griffel/react": "^1.5.22", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-alert": { + "version": "9.0.0-beta.124", + "resolved": "https://registry.npmjs.org/@fluentui/react-alert/-/react-alert-9.0.0-beta.124.tgz", + "integrity": "sha512-yFBo3B5H9hnoaXxlkuz8wRz04DEyQ+ElYA/p5p+Vojf19Zuta8DmFZZ6JtWdtxcdnnQ4LvAfC5OYYlzdReozPA==", + "dependencies": { + "@fluentui/react-avatar": "^9.6.29", + "@fluentui/react-button": "^9.3.83", + "@fluentui/react-icons": "^2.0.239", + "@fluentui/react-jsx-runtime": "^9.0.39", + "@fluentui/react-tabster": "^9.21.5", + "@fluentui/react-theme": "^9.1.19", + "@fluentui/react-utilities": "^9.18.10", + "@griffel/react": "^1.5.22", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-aria": { + "version": "9.13.8", + "resolved": "https://registry.npmjs.org/@fluentui/react-aria/-/react-aria-9.13.8.tgz", + "integrity": "sha512-OGd4LLW1LrdbCp+GkYLTRVX2IHZ/wnlOwHBX9VmQkY/FgeevDDGRH7HoXZRebmzDWHXzmjbyFxTO2QiJoF9zTQ==", + "dependencies": { + "@fluentui/keyboard-keys": "^9.0.7", + "@fluentui/react-jsx-runtime": "^9.0.45", + "@fluentui/react-shared-contexts": "^9.20.2", + "@fluentui/react-tabster": "^9.22.9", + "@fluentui/react-utilities": "^9.18.16", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-avatar": { + "version": "9.6.41", + "resolved": "https://registry.npmjs.org/@fluentui/react-avatar/-/react-avatar-9.6.41.tgz", + "integrity": "sha512-FB9P/TJLfeZTOrRMFDbrVR6jgdOI4ueGFZea/BeEHOdXKzqSAmXhGlAKl7Mkev4mKhjeT5uEjuNEs7tqGVUs6A==", + "dependencies": { + "@fluentui/react-badge": "^9.2.44", + "@fluentui/react-context-selector": "^9.1.68", + "@fluentui/react-icons": "^2.0.245", + "@fluentui/react-jsx-runtime": "^9.0.45", + "@fluentui/react-popover": "^9.9.23", + "@fluentui/react-shared-contexts": "^9.20.2", + "@fluentui/react-tabster": "^9.22.9", + "@fluentui/react-theme": "^9.1.21", + "@fluentui/react-tooltip": "^9.4.41", + "@fluentui/react-utilities": "^9.18.16", + "@griffel/react": "^1.5.22", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-badge": { + "version": "9.2.44", + "resolved": "https://registry.npmjs.org/@fluentui/react-badge/-/react-badge-9.2.44.tgz", + "integrity": "sha512-c/CF17QDAZ2/+atCxNgqpqUKvbqTLViNwro8FP9LsLfSVN9dNcAknLhPi8VMHjcdCUNTItm3gv4/ZFqnrQbURQ==", + "dependencies": { + "@fluentui/react-icons": "^2.0.245", + "@fluentui/react-jsx-runtime": "^9.0.45", + "@fluentui/react-shared-contexts": "^9.20.2", + "@fluentui/react-theme": "^9.1.21", + "@fluentui/react-utilities": "^9.18.16", + "@griffel/react": "^1.5.22", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-breadcrumb": { + "version": "9.0.41", + "resolved": "https://registry.npmjs.org/@fluentui/react-breadcrumb/-/react-breadcrumb-9.0.41.tgz", + "integrity": "sha512-JQBMUMFb5xsNuKR4bQCum6ad2D3RZ75dFxEEfufp133zFr6bt/2a96Xmc3IxZ8KFDQaJj9zLA0tvaeWNOhliqQ==", + "dependencies": { + "@fluentui/react-aria": "^9.13.8", + "@fluentui/react-button": "^9.3.94", + "@fluentui/react-icons": "^2.0.245", + "@fluentui/react-jsx-runtime": "^9.0.45", + "@fluentui/react-link": "^9.3.1", + "@fluentui/react-shared-contexts": "^9.20.2", + "@fluentui/react-tabster": "^9.22.9", + "@fluentui/react-theme": "^9.1.21", + "@fluentui/react-utilities": "^9.18.16", + "@griffel/react": "^1.5.22", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-button": { + "version": "9.3.94", + "resolved": "https://registry.npmjs.org/@fluentui/react-button/-/react-button-9.3.94.tgz", + "integrity": "sha512-8FepyrHjD0c9JQmvFP+N0zMyFW6jmLlwwtg8ThPCQJlInLZA4NrwEDmCl1cshyHBuTaSOBxuPGvTQHQetprMug==", + "dependencies": { + "@fluentui/keyboard-keys": "^9.0.7", + "@fluentui/react-aria": "^9.13.8", + "@fluentui/react-icons": "^2.0.245", + "@fluentui/react-jsx-runtime": "^9.0.45", + "@fluentui/react-shared-contexts": "^9.20.2", + "@fluentui/react-tabster": "^9.22.9", + "@fluentui/react-theme": "^9.1.21", + "@fluentui/react-utilities": "^9.18.16", + "@griffel/react": "^1.5.22", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-card": { + "version": "9.0.96", + "resolved": "https://registry.npmjs.org/@fluentui/react-card/-/react-card-9.0.96.tgz", + "integrity": "sha512-Tj26e6n4aETiuGQsKDCp4aVMlx76mplFRH6cvmtttBM7Ej/gjBB3a8fBjW4rhbX5x28NwJyeLiXgKmU6O1pvrg==", + "dependencies": { + "@fluentui/keyboard-keys": "^9.0.7", + "@fluentui/react-jsx-runtime": "^9.0.45", + "@fluentui/react-tabster": "^9.22.9", + "@fluentui/react-text": "^9.4.26", + "@fluentui/react-theme": "^9.1.21", + "@fluentui/react-utilities": "^9.18.16", + "@griffel/react": "^1.5.22", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-carousel": { + "version": "9.2.0", + "resolved": "https://registry.npmjs.org/@fluentui/react-carousel/-/react-carousel-9.2.0.tgz", + "integrity": "sha512-WcPQpOmcUWeFIScb0Y/yN+dkVyNCuKQ8CMHLM7UPp/OuoUfESO1kr6pnJtYtDjCMRUIB9lKw1wy5hDSLQAQ/vA==", + "dependencies": { + "@fluentui/react-aria": "^9.13.8", + "@fluentui/react-button": "^9.3.94", + "@fluentui/react-context-selector": "^9.1.68", + "@fluentui/react-icons": "^2.0.245", + "@fluentui/react-jsx-runtime": "^9.0.45", + "@fluentui/react-shared-contexts": "^9.20.2", + "@fluentui/react-tabster": "^9.22.9", + "@fluentui/react-theme": "^9.1.21", + "@fluentui/react-utilities": "^9.18.16", + "@griffel/react": "^1.5.22", + "@swc/helpers": "^0.5.1", + "embla-carousel": "^8.3.0", + "embla-carousel-autoplay": "^8.3.0", + "embla-carousel-fade": "^8.3.0" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-checkbox": { + "version": "9.2.39", + "resolved": "https://registry.npmjs.org/@fluentui/react-checkbox/-/react-checkbox-9.2.39.tgz", + "integrity": "sha512-6KFC7q9WvpPtMDKAowAfVsjhmQ1mUYeeKS2M/3N34hyZz5AbeFIHpczxxn7O0Q95bAeqy1+09lWbwwlJXRpwYw==", + "dependencies": { + "@fluentui/react-field": "^9.1.78", + "@fluentui/react-icons": "^2.0.245", + "@fluentui/react-jsx-runtime": "^9.0.45", + "@fluentui/react-label": "^9.1.77", + "@fluentui/react-shared-contexts": "^9.20.2", + "@fluentui/react-tabster": "^9.22.9", + "@fluentui/react-theme": "^9.1.21", + "@fluentui/react-utilities": "^9.18.16", + "@griffel/react": "^1.5.22", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-combobox": { + "version": "9.13.10", + "resolved": "https://registry.npmjs.org/@fluentui/react-combobox/-/react-combobox-9.13.10.tgz", + "integrity": "sha512-c3/UmhqbCZg8TySVT/utBovX2QDhR/ljZ3r8+wbKmkiaGU1JD0DL2nOJm9pX6guSQCnFNovKwwojykOBnpkv4Q==", + "dependencies": { + "@fluentui/keyboard-keys": "^9.0.7", + "@fluentui/react-aria": "^9.13.8", + "@fluentui/react-context-selector": "^9.1.68", + "@fluentui/react-field": "^9.1.78", + "@fluentui/react-icons": "^2.0.245", + "@fluentui/react-jsx-runtime": "^9.0.45", + "@fluentui/react-portal": "^9.4.37", + "@fluentui/react-positioning": "^9.15.10", + "@fluentui/react-shared-contexts": "^9.20.2", + "@fluentui/react-tabster": "^9.22.9", + "@fluentui/react-theme": "^9.1.21", + "@fluentui/react-utilities": "^9.18.16", + "@griffel/react": "^1.5.22", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-components": { + "version": "9.55.1", + "resolved": "https://registry.npmjs.org/@fluentui/react-components/-/react-components-9.55.1.tgz", + "integrity": "sha512-OuAQoNOAZerAk54DHnUqrSqauOn941oKbEp1PRqkFGjLCa8C78JRujTlLvoKo8osMSB8so6jyGTsfHJtLkpceA==", + "dependencies": { + "@fluentui/react-accordion": "^9.5.7", + "@fluentui/react-alert": "9.0.0-beta.124", + "@fluentui/react-aria": "^9.13.8", + "@fluentui/react-avatar": "^9.6.41", + "@fluentui/react-badge": "^9.2.44", + "@fluentui/react-breadcrumb": "^9.0.41", + "@fluentui/react-button": "^9.3.94", + "@fluentui/react-card": "^9.0.96", + "@fluentui/react-carousel": "^9.2.0", + "@fluentui/react-checkbox": "^9.2.39", + "@fluentui/react-combobox": "^9.13.10", + "@fluentui/react-dialog": "^9.11.18", + "@fluentui/react-divider": "^9.2.76", + "@fluentui/react-drawer": "^9.5.18", + "@fluentui/react-field": "^9.1.78", + "@fluentui/react-image": "^9.1.74", + "@fluentui/react-infobutton": "9.0.0-beta.102", + "@fluentui/react-infolabel": "^9.0.48", + "@fluentui/react-input": "^9.4.91", + "@fluentui/react-label": "^9.1.77", + "@fluentui/react-link": "^9.3.1", + "@fluentui/react-menu": "^9.14.18", + "@fluentui/react-message-bar": "^9.2.14", + "@fluentui/react-motion": "^9.6.0", + "@fluentui/react-overflow": "^9.1.32", + "@fluentui/react-persona": "^9.2.100", + "@fluentui/react-popover": "^9.9.23", + "@fluentui/react-portal": "^9.4.37", + "@fluentui/react-positioning": "^9.15.10", + "@fluentui/react-progress": "^9.1.89", + "@fluentui/react-provider": "^9.17.6", + "@fluentui/react-radio": "^9.2.34", + "@fluentui/react-rating": "^9.0.21", + "@fluentui/react-search": "^9.0.20", + "@fluentui/react-select": "^9.1.89", + "@fluentui/react-shared-contexts": "^9.20.2", + "@fluentui/react-skeleton": "^9.1.18", + "@fluentui/react-slider": "^9.1.96", + "@fluentui/react-spinbutton": "^9.2.90", + "@fluentui/react-spinner": "^9.5.1", + "@fluentui/react-swatch-picker": "^9.1.12", + "@fluentui/react-switch": "^9.1.96", + "@fluentui/react-table": "^9.15.20", + "@fluentui/react-tabs": "^9.6.0", + "@fluentui/react-tabster": "^9.22.9", + "@fluentui/react-tag-picker": "^9.3.6", + "@fluentui/react-tags": "^9.3.20", + "@fluentui/react-teaching-popover": "^9.1.20", + "@fluentui/react-text": "^9.4.26", + "@fluentui/react-textarea": "^9.3.90", + "@fluentui/react-theme": "^9.1.21", + "@fluentui/react-toast": "^9.3.58", + "@fluentui/react-toolbar": "^9.2.8", + "@fluentui/react-tooltip": "^9.4.41", + "@fluentui/react-tree": "^9.8.4", + "@fluentui/react-utilities": "^9.18.16", + "@fluentui/react-virtualizer": "9.0.0-alpha.86", + "@griffel/react": "^1.5.22", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-context-selector": { + "version": "9.1.68", + "resolved": "https://registry.npmjs.org/@fluentui/react-context-selector/-/react-context-selector-9.1.68.tgz", + "integrity": "sha512-PJwmvRevT/oyk/Gs0bnCb9UsQX/pXhM7lAHWq4ssnQLSmrdxJY/cwqAadQydJsA/itUy+FhgiEbPYGiEeB1GGA==", + "dependencies": { + "@fluentui/react-utilities": "^9.18.16", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0", + "scheduler": ">=0.19.0 <=0.23.0" + } + }, + "node_modules/@fluentui/react-dialog": { + "version": "9.11.18", + "resolved": "https://registry.npmjs.org/@fluentui/react-dialog/-/react-dialog-9.11.18.tgz", + "integrity": "sha512-wTH3xfcnSZmUVQV5L0oM1MJqgT4uA/EN8Enf9lRZx+aeyjX7IYywxm9YcIkgn4nZtj66gHFFlcAaR8aJgGUTfw==", + "dependencies": { + "@fluentui/keyboard-keys": "^9.0.7", + "@fluentui/react-aria": "^9.13.8", + "@fluentui/react-context-selector": "^9.1.68", + "@fluentui/react-icons": "^2.0.245", + "@fluentui/react-jsx-runtime": "^9.0.45", + "@fluentui/react-motion": "^9.6.0", + "@fluentui/react-portal": "^9.4.37", + "@fluentui/react-shared-contexts": "^9.20.2", + "@fluentui/react-tabster": "^9.22.9", + "@fluentui/react-theme": "^9.1.21", + "@fluentui/react-utilities": "^9.18.16", + "@griffel/react": "^1.5.22", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-divider": { + "version": "9.2.76", + "resolved": "https://registry.npmjs.org/@fluentui/react-divider/-/react-divider-9.2.76.tgz", + "integrity": "sha512-r8+637gYDtffENjEUtGu4l9LTceOHF4oV7X8Wf9Cw1ZVHExDVXCnQ2QpNxDrR+tFW0oOHWNfvn6gJ0A/43acmw==", + "dependencies": { + "@fluentui/react-jsx-runtime": "^9.0.45", + "@fluentui/react-shared-contexts": "^9.20.2", + "@fluentui/react-theme": "^9.1.21", + "@fluentui/react-utilities": "^9.18.16", + "@griffel/react": "^1.5.22", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-drawer": { + "version": "9.5.18", + "resolved": "https://registry.npmjs.org/@fluentui/react-drawer/-/react-drawer-9.5.18.tgz", + "integrity": "sha512-umNPJcCBGEBXt6MKPaBKHIejjjR/zPbgme3gF3gxHVmelKdbPuLvjnaL0F83e4pSmV/f655/SIYdQ6Lve3ShrQ==", + "dependencies": { + "@fluentui/react-dialog": "^9.11.18", + "@fluentui/react-jsx-runtime": "^9.0.45", + "@fluentui/react-motion": "^9.6.0", + "@fluentui/react-shared-contexts": "^9.20.2", + "@fluentui/react-tabster": "^9.22.9", + "@fluentui/react-theme": "^9.1.21", + "@fluentui/react-utilities": "^9.18.16", + "@griffel/react": "^1.5.22", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-field": { + "version": "9.1.78", + "resolved": "https://registry.npmjs.org/@fluentui/react-field/-/react-field-9.1.78.tgz", + "integrity": "sha512-uYJ9rmSOtbaLZU4QYWsTjrvuqP631iynt7XZZEBIvyRcuwnzWvXEG3ohYbc3+vY06SQI7L/iWjkSc+ESwWyo/Q==", + "dependencies": { + "@fluentui/react-context-selector": "^9.1.68", + "@fluentui/react-icons": "^2.0.245", + "@fluentui/react-jsx-runtime": "^9.0.45", + "@fluentui/react-label": "^9.1.77", + "@fluentui/react-theme": "^9.1.21", + "@fluentui/react-utilities": "^9.18.16", + "@griffel/react": "^1.5.22", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, "node_modules/@fluentui/react-focus": { "version": "8.9.13", "resolved": "https://registry.npmjs.org/@fluentui/react-focus/-/react-focus-8.9.13.tgz", @@ -3166,6 +3650,18 @@ "react": ">=16.8.0 <19.0.0" } }, + "node_modules/@fluentui/react-icons": { + "version": "2.0.264", + "resolved": "https://registry.npmjs.org/@fluentui/react-icons/-/react-icons-2.0.264.tgz", + "integrity": "sha512-Rhjx5vYmTzbe6q/50qBy9G4jpFwJQuBA4oAaluG2Pw9Cb50cz8O3ZQVRopNIi65xdAwuR0jTWPf869Iy1G6/sA==", + "dependencies": { + "@griffel/react": "^1.0.0", + "tslib": "^2.1.0" + }, + "peerDependencies": { + "react": ">=16.8.0 <19.0.0" + } + }, "node_modules/@fluentui/react-icons-mdl2": { "version": "1.3.63", "resolved": "https://registry.npmjs.org/@fluentui/react-icons-mdl2/-/react-icons-mdl2-1.3.63.tgz", @@ -3197,6 +3693,318 @@ "react-dom": ">=16.8.0 <19.0.0" } }, + "node_modules/@fluentui/react-image": { + "version": "9.1.74", + "resolved": "https://registry.npmjs.org/@fluentui/react-image/-/react-image-9.1.74.tgz", + "integrity": "sha512-O8Yl7NkIvqi878uGEBvyOCxmkEIBREqI5X2iEXLl0HsAnS72tE0UfWXO1jUwqqHImG415XN9HKyvYmCFQpnUPQ==", + "dependencies": { + "@fluentui/react-jsx-runtime": "^9.0.45", + "@fluentui/react-shared-contexts": "^9.20.2", + "@fluentui/react-theme": "^9.1.21", + "@fluentui/react-utilities": "^9.18.16", + "@griffel/react": "^1.5.22", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-infobutton": { + "version": "9.0.0-beta.102", + "resolved": "https://registry.npmjs.org/@fluentui/react-infobutton/-/react-infobutton-9.0.0-beta.102.tgz", + "integrity": "sha512-3kA4F0Vga8Ds6JGlBajLCCDOo/LmPuS786Wg7ui4ZTDYVIMzy1yp2XuVcZniifBFvEp0HQCUoDPWUV0VI3FfzQ==", + "dependencies": { + "@fluentui/react-icons": "^2.0.237", + "@fluentui/react-jsx-runtime": "^9.0.36", + "@fluentui/react-label": "^9.1.68", + "@fluentui/react-popover": "^9.9.6", + "@fluentui/react-tabster": "^9.21.0", + "@fluentui/react-theme": "^9.1.19", + "@fluentui/react-utilities": "^9.18.7", + "@griffel/react": "^1.5.14", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-infolabel": { + "version": "9.0.48", + "resolved": "https://registry.npmjs.org/@fluentui/react-infolabel/-/react-infolabel-9.0.48.tgz", + "integrity": "sha512-LsdFBfu9aBZ8GRZm4Q6jTrrnpG0p3KIpivB7bsp7lp4Mbea3gODJzBsklE4pMCMWd2Fug/4MTgv9ZlS1cj1y1A==", + "dependencies": { + "@fluentui/react-icons": "^2.0.245", + "@fluentui/react-jsx-runtime": "^9.0.45", + "@fluentui/react-label": "^9.1.77", + "@fluentui/react-popover": "^9.9.23", + "@fluentui/react-tabster": "^9.22.9", + "@fluentui/react-theme": "^9.1.21", + "@fluentui/react-utilities": "^9.18.16", + "@griffel/react": "^1.5.22", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.8.0 <19.0.0", + "@types/react-dom": ">=16.8.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.8.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-input": { + "version": "9.4.91", + "resolved": "https://registry.npmjs.org/@fluentui/react-input/-/react-input-9.4.91.tgz", + "integrity": "sha512-fZOftICkuT+efuw1c6qfqWK5O9UCE86ERCNli3GiQRxxEj/lOZkBx1QUoKoJZkXHXvy+lLIIAT5cyLBKPsmgOQ==", + "dependencies": { + "@fluentui/react-field": "^9.1.78", + "@fluentui/react-jsx-runtime": "^9.0.45", + "@fluentui/react-shared-contexts": "^9.20.2", + "@fluentui/react-theme": "^9.1.21", + "@fluentui/react-utilities": "^9.18.16", + "@griffel/react": "^1.5.22", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-jsx-runtime": { + "version": "9.0.45", + "resolved": "https://registry.npmjs.org/@fluentui/react-jsx-runtime/-/react-jsx-runtime-9.0.45.tgz", + "integrity": "sha512-MJg+Hdkdy8pXn+7nsLYQGSET4ypf+azQIHoFanhm2ZWOSjAcCKcOTsE33Z6KFxZ7dSUyH9njn7qK2Gt4YeW2MA==", + "dependencies": { + "@fluentui/react-utilities": "^9.18.16", + "@swc/helpers": "^0.5.1", + "react-is": "^17.0.2" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "react": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-jsx-runtime/node_modules/react-is": { + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", + "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==" + }, + "node_modules/@fluentui/react-label": { + "version": "9.1.77", + "resolved": "https://registry.npmjs.org/@fluentui/react-label/-/react-label-9.1.77.tgz", + "integrity": "sha512-XdjdieXDnvc4oL4o35Zc0RaebcEbyXZ5NUMRZSRSTe/2Q4gvEbtY2DL5+kTERtUiYHZF96zdtuJy0zWSnkyFYg==", + "dependencies": { + "@fluentui/react-jsx-runtime": "^9.0.45", + "@fluentui/react-shared-contexts": "^9.20.2", + "@fluentui/react-theme": "^9.1.21", + "@fluentui/react-utilities": "^9.18.16", + "@griffel/react": "^1.5.22", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-link": { + "version": "9.3.1", + "resolved": "https://registry.npmjs.org/@fluentui/react-link/-/react-link-9.3.1.tgz", + "integrity": "sha512-wvy8Hluvho/TiA6OE+24yUejQ8qAGqsj88E56wT0wqYFrnUIN3sGZmyjiKVkhH1xzce7YrTAv4KJKhug1sWsuQ==", + "dependencies": { + "@fluentui/keyboard-keys": "^9.0.7", + "@fluentui/react-jsx-runtime": "^9.0.45", + "@fluentui/react-shared-contexts": "^9.20.2", + "@fluentui/react-tabster": "^9.22.9", + "@fluentui/react-theme": "^9.1.21", + "@fluentui/react-utilities": "^9.18.16", + "@griffel/react": "^1.5.22", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-menu": { + "version": "9.14.18", + "resolved": "https://registry.npmjs.org/@fluentui/react-menu/-/react-menu-9.14.18.tgz", + "integrity": "sha512-rpVTAliTYjkDyzPIVdlGaBj7o/0SQfU+Vhrr9A1kdSJNWMzjbL4VcT3jJzOCwZ9c7ib9hHUAbmI3nVVJm/l24g==", + "dependencies": { + "@fluentui/keyboard-keys": "^9.0.7", + "@fluentui/react-aria": "^9.13.8", + "@fluentui/react-context-selector": "^9.1.68", + "@fluentui/react-icons": "^2.0.245", + "@fluentui/react-jsx-runtime": "^9.0.45", + "@fluentui/react-portal": "^9.4.37", + "@fluentui/react-positioning": "^9.15.10", + "@fluentui/react-shared-contexts": "^9.20.2", + "@fluentui/react-tabster": "^9.22.9", + "@fluentui/react-theme": "^9.1.21", + "@fluentui/react-utilities": "^9.18.16", + "@griffel/react": "^1.5.22", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-message-bar": { + "version": "9.2.14", + "resolved": "https://registry.npmjs.org/@fluentui/react-message-bar/-/react-message-bar-9.2.14.tgz", + "integrity": "sha512-ev2CCjau6lZ4R9Fd2O+DqMmk+g98kY4FDliD5MocCpVCL+oM6wjhWsRJ1O2joIyQgFKwufxj1fxZkk/YhZJBRA==", + "dependencies": { + "@fluentui/react-button": "^9.3.94", + "@fluentui/react-icons": "^2.0.245", + "@fluentui/react-jsx-runtime": "^9.0.45", + "@fluentui/react-link": "^9.3.1", + "@fluentui/react-shared-contexts": "^9.20.2", + "@fluentui/react-theme": "^9.1.21", + "@fluentui/react-utilities": "^9.18.16", + "@griffel/react": "^1.5.22", + "@swc/helpers": "^0.5.1", + "react-transition-group": "^4.4.1" + }, + "peerDependencies": { + "@types/react": ">=16.8.0 <19.0.0", + "@types/react-dom": ">=16.8.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.8.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-motion": { + "version": "9.6.0", + "resolved": "https://registry.npmjs.org/@fluentui/react-motion/-/react-motion-9.6.0.tgz", + "integrity": "sha512-Jxiz1EXernadWbQ2oMBEzjmKqDeHZXuyeC8GO8ReXo+utupI/pWC1xtn3tQRcIs+2RnI812ertWULcl7n8adqA==", + "dependencies": { + "@fluentui/react-shared-contexts": "^9.20.2", + "@fluentui/react-utilities": "^9.18.16", + "@swc/helpers": "^0.5.1", + "react-is": "^17.0.2" + }, + "peerDependencies": { + "@types/react": ">=16.8.0 <19.0.0", + "@types/react-dom": ">=16.8.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.8.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-motion-components-preview": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/@fluentui/react-motion-components-preview/-/react-motion-components-preview-0.2.0.tgz", + "integrity": "sha512-VSGts+QsJl5hO/Zl7gk6KTXeYx9uFMnDx6Y1OOeIwf1HpQS4YlhCmrTOUpV/89z8W3sXgJZvFyTUxV5pf87UCg==", + "dependencies": { + "@fluentui/react-motion": "*", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-motion/node_modules/react-is": { + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", + "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==" + }, + "node_modules/@fluentui/react-overflow": { + "version": "9.1.32", + "resolved": "https://registry.npmjs.org/@fluentui/react-overflow/-/react-overflow-9.1.32.tgz", + "integrity": "sha512-MG15Z4XZatJ/df+5wgsunBlZkdNKdOae5ZGWO98FH6YkmWqDCq0MTKMJu5ugEfHf9j5UUTgwKyMrJ/vHztXKUA==", + "dependencies": { + "@fluentui/priority-overflow": "^9.1.13", + "@fluentui/react-context-selector": "^9.1.68", + "@fluentui/react-theme": "^9.1.21", + "@fluentui/react-utilities": "^9.18.16", + "@griffel/react": "^1.5.22", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-persona": { + "version": "9.2.100", + "resolved": "https://registry.npmjs.org/@fluentui/react-persona/-/react-persona-9.2.100.tgz", + "integrity": "sha512-UkEa47KKFGDHHqFVaPilSNLPmPBweP6TjkpnMm94dsl8TiCaJpSaiPDVQ6iVbWMK92wjRdBv3OlbZmJroVqkDQ==", + "dependencies": { + "@fluentui/react-avatar": "^9.6.41", + "@fluentui/react-badge": "^9.2.44", + "@fluentui/react-jsx-runtime": "^9.0.45", + "@fluentui/react-shared-contexts": "^9.20.2", + "@fluentui/react-theme": "^9.1.21", + "@fluentui/react-utilities": "^9.18.16", + "@griffel/react": "^1.5.22", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-popover": { + "version": "9.9.23", + "resolved": "https://registry.npmjs.org/@fluentui/react-popover/-/react-popover-9.9.23.tgz", + "integrity": "sha512-1AOYiefOwqJ8+ctGvfOE4RjLHZGs8y2jlY3Liei0u7vVKiVIUaYP/cck7sCSbx4HCiqb1Prl60CTsJemmhuRkw==", + "dependencies": { + "@fluentui/keyboard-keys": "^9.0.7", + "@fluentui/react-aria": "^9.13.8", + "@fluentui/react-context-selector": "^9.1.68", + "@fluentui/react-jsx-runtime": "^9.0.45", + "@fluentui/react-portal": "^9.4.37", + "@fluentui/react-positioning": "^9.15.10", + "@fluentui/react-shared-contexts": "^9.20.2", + "@fluentui/react-tabster": "^9.22.9", + "@fluentui/react-theme": "^9.1.21", + "@fluentui/react-utilities": "^9.18.16", + "@griffel/react": "^1.5.22", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-portal": { + "version": "9.4.37", + "resolved": "https://registry.npmjs.org/@fluentui/react-portal/-/react-portal-9.4.37.tgz", + "integrity": "sha512-wWjuCP/PAHvHFCyjONYyHE5CRh94WMLtVIAAGlN9GQRo3U2nbvG2V422Vlro1e4zYb2T8Kf2wJ9VFkffD1j7bQ==", + "dependencies": { + "@fluentui/react-shared-contexts": "^9.20.2", + "@fluentui/react-tabster": "^9.22.9", + "@fluentui/react-utilities": "^9.18.16", + "@griffel/react": "^1.5.22", + "@swc/helpers": "^0.5.1", + "use-disposable": "^1.0.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, "node_modules/@fluentui/react-portal-compat-context": { "version": "9.0.12", "resolved": "https://registry.npmjs.org/@fluentui/react-portal-compat-context/-/react-portal-compat-context-9.0.12.tgz", @@ -3209,6 +4017,621 @@ "react": ">=16.14.0 <19.0.0" } }, + "node_modules/@fluentui/react-positioning": { + "version": "9.15.10", + "resolved": "https://registry.npmjs.org/@fluentui/react-positioning/-/react-positioning-9.15.10.tgz", + "integrity": "sha512-5vWtRO4AEWz9lw5KK191arOWjXzGYffSU6lMtvWsprqwFhYeVcu/OCGNElZote7RFz1t9Pjsx8sVbbp7TlVbJA==", + "dependencies": { + "@floating-ui/devtools": "0.2.1", + "@floating-ui/dom": "^1.2.0", + "@fluentui/react-shared-contexts": "^9.20.2", + "@fluentui/react-theme": "^9.1.21", + "@fluentui/react-utilities": "^9.18.16", + "@griffel/react": "^1.5.22", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-progress": { + "version": "9.1.89", + "resolved": "https://registry.npmjs.org/@fluentui/react-progress/-/react-progress-9.1.89.tgz", + "integrity": "sha512-t31AJ1Z5rCiaFzgqRbZGYwW8IQ1W1AJBPkMQ8sO390GYrJyPXaBL3g3qW8fFFgp69sEQjoWENGjU5su6ovS5Xw==", + "dependencies": { + "@fluentui/react-field": "^9.1.78", + "@fluentui/react-jsx-runtime": "^9.0.45", + "@fluentui/react-shared-contexts": "^9.20.2", + "@fluentui/react-theme": "^9.1.21", + "@fluentui/react-utilities": "^9.18.16", + "@griffel/react": "^1.5.22", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-provider": { + "version": "9.17.6", + "resolved": "https://registry.npmjs.org/@fluentui/react-provider/-/react-provider-9.17.6.tgz", + "integrity": "sha512-4+mUgtIenOoP3DAEvnhF9Ga6UxDxUSFsW8xtkFeavKWk8QznDU5b88qd3pLhMQzemSF3REgnNbQknzgbOyXMwg==", + "dependencies": { + "@fluentui/react-icons": "^2.0.245", + "@fluentui/react-jsx-runtime": "^9.0.45", + "@fluentui/react-shared-contexts": "^9.20.2", + "@fluentui/react-tabster": "^9.22.9", + "@fluentui/react-theme": "^9.1.21", + "@fluentui/react-utilities": "^9.18.16", + "@griffel/core": "^1.16.0", + "@griffel/react": "^1.5.22", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-radio": { + "version": "9.2.34", + "resolved": "https://registry.npmjs.org/@fluentui/react-radio/-/react-radio-9.2.34.tgz", + "integrity": "sha512-ZVlsEwNXjGA4vny8MjwA1/bGjAS1CI+svzfeeOCIN3SxVpr4R3Nme4bnOesi/fk7XBFWO2QGMOa1ycSawQ0x9Q==", + "dependencies": { + "@fluentui/react-field": "^9.1.78", + "@fluentui/react-jsx-runtime": "^9.0.45", + "@fluentui/react-label": "^9.1.77", + "@fluentui/react-shared-contexts": "^9.20.2", + "@fluentui/react-tabster": "^9.22.9", + "@fluentui/react-theme": "^9.1.21", + "@fluentui/react-utilities": "^9.18.16", + "@griffel/react": "^1.5.22", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-rating": { + "version": "9.0.21", + "resolved": "https://registry.npmjs.org/@fluentui/react-rating/-/react-rating-9.0.21.tgz", + "integrity": "sha512-ijzxAbsXXcLy58+q/z8vf5pDEv1Atfen/PGkr+3XdwA132M2bVIyrIagXIvNh1t2WY1fbhs/vivVKyKcLbmJgQ==", + "dependencies": { + "@fluentui/react-icons": "^2.0.245", + "@fluentui/react-jsx-runtime": "^9.0.45", + "@fluentui/react-tabster": "^9.22.9", + "@fluentui/react-theme": "^9.1.21", + "@fluentui/react-utilities": "^9.18.16", + "@griffel/react": "^1.5.22", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.8.0 <19.0.0", + "@types/react-dom": ">=16.8.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.8.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-search": { + "version": "9.0.20", + "resolved": "https://registry.npmjs.org/@fluentui/react-search/-/react-search-9.0.20.tgz", + "integrity": "sha512-Alz3xUJNuOTl3ViCtSeQUisLpDhhVF0rUvfqn1+q691N8SQamBOOXEffnyIHrDIwnlCQm/wOIuC8PFmZqthv1w==", + "dependencies": { + "@fluentui/react-icons": "^2.0.245", + "@fluentui/react-input": "^9.4.91", + "@fluentui/react-jsx-runtime": "^9.0.45", + "@fluentui/react-theme": "^9.1.21", + "@fluentui/react-utilities": "^9.18.16", + "@griffel/react": "^1.5.22", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-select": { + "version": "9.1.89", + "resolved": "https://registry.npmjs.org/@fluentui/react-select/-/react-select-9.1.89.tgz", + "integrity": "sha512-s/qhd56XIsC9nqstGDI3Fcnx1UMFlYktJn2lciPUbdNe2EkYSkYCZZqKUlECQH456dl/dJBdWF0oqwvCPxlGKA==", + "dependencies": { + "@fluentui/react-field": "^9.1.78", + "@fluentui/react-icons": "^2.0.245", + "@fluentui/react-jsx-runtime": "^9.0.45", + "@fluentui/react-shared-contexts": "^9.20.2", + "@fluentui/react-theme": "^9.1.21", + "@fluentui/react-utilities": "^9.18.16", + "@griffel/react": "^1.5.22", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-shared-contexts": { + "version": "9.20.2", + "resolved": "https://registry.npmjs.org/@fluentui/react-shared-contexts/-/react-shared-contexts-9.20.2.tgz", + "integrity": "sha512-vNsPDpjhZjkBBTjWOB7ddG/US89lsqAYvOi1ITb7YT5CLMVLzexewcAdSFmF8yrnc1bEOEW1BEH8aJoT0NAHnA==", + "dependencies": { + "@fluentui/react-theme": "^9.1.21", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "react": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-skeleton": { + "version": "9.1.18", + "resolved": "https://registry.npmjs.org/@fluentui/react-skeleton/-/react-skeleton-9.1.18.tgz", + "integrity": "sha512-FgNJBCdGg2kudn2Og1qXp6fkMd5rVAdKKiTe2yBiaHRPBc3sGJ81DgeXHnfIXlzBoCjbc68DWV90HuK18ElrXQ==", + "dependencies": { + "@fluentui/react-field": "^9.1.78", + "@fluentui/react-jsx-runtime": "^9.0.45", + "@fluentui/react-shared-contexts": "^9.20.2", + "@fluentui/react-theme": "^9.1.21", + "@fluentui/react-utilities": "^9.18.16", + "@griffel/react": "^1.5.22", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-slider": { + "version": "9.1.96", + "resolved": "https://registry.npmjs.org/@fluentui/react-slider/-/react-slider-9.1.96.tgz", + "integrity": "sha512-tg442xuE2CS44ezz8oTodLUC9yc+F4L59vQcLZ5OqEQGw+x/Vj+e/x0WDzHaEB4aomLeX5K0G+5gXTeq71pv8w==", + "dependencies": { + "@fluentui/react-field": "^9.1.78", + "@fluentui/react-jsx-runtime": "^9.0.45", + "@fluentui/react-shared-contexts": "^9.20.2", + "@fluentui/react-tabster": "^9.22.9", + "@fluentui/react-theme": "^9.1.21", + "@fluentui/react-utilities": "^9.18.16", + "@griffel/react": "^1.5.22", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-spinbutton": { + "version": "9.2.90", + "resolved": "https://registry.npmjs.org/@fluentui/react-spinbutton/-/react-spinbutton-9.2.90.tgz", + "integrity": "sha512-kNoWf7FtkiPawwB5FUXqDp7eTVg3AqTi5yBLs5x5IQDPkdoiVRa6q/NpR+B+DZcg2FN2L2Iz87RHvwuJZ8/hpA==", + "dependencies": { + "@fluentui/keyboard-keys": "^9.0.7", + "@fluentui/react-field": "^9.1.78", + "@fluentui/react-icons": "^2.0.245", + "@fluentui/react-jsx-runtime": "^9.0.45", + "@fluentui/react-shared-contexts": "^9.20.2", + "@fluentui/react-theme": "^9.1.21", + "@fluentui/react-utilities": "^9.18.16", + "@griffel/react": "^1.5.22", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-spinner": { + "version": "9.5.1", + "resolved": "https://registry.npmjs.org/@fluentui/react-spinner/-/react-spinner-9.5.1.tgz", + "integrity": "sha512-8C7SFwyg72VocnlbAarWu6xT+1QmeCAVe17lUFjQzmDTmPrh3a06HIkvDuuKEYtpyAY3h4m3vXP5azIbnEqjiw==", + "dependencies": { + "@fluentui/react-jsx-runtime": "^9.0.45", + "@fluentui/react-label": "^9.1.77", + "@fluentui/react-shared-contexts": "^9.20.2", + "@fluentui/react-theme": "^9.1.21", + "@fluentui/react-utilities": "^9.18.16", + "@griffel/react": "^1.5.22", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-swatch-picker": { + "version": "9.1.12", + "resolved": "https://registry.npmjs.org/@fluentui/react-swatch-picker/-/react-swatch-picker-9.1.12.tgz", + "integrity": "sha512-BMUmGW15OyqEKWPdT8Vy/WodqAKpPCGGbMWSNjFvwYPTVwSKLiIRYkC5UsX236CaN0M4z1kI+UKl447+urJH2A==", + "dependencies": { + "@fluentui/react-context-selector": "^9.1.68", + "@fluentui/react-icons": "^2.0.245", + "@fluentui/react-jsx-runtime": "^9.0.45", + "@fluentui/react-shared-contexts": "^9.20.2", + "@fluentui/react-tabster": "^9.22.9", + "@fluentui/react-theme": "^9.1.21", + "@fluentui/react-utilities": "^9.18.16", + "@griffel/react": "^1.5.22", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.8.0 <19.0.0", + "@types/react-dom": ">=16.8.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.8.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-switch": { + "version": "9.1.96", + "resolved": "https://registry.npmjs.org/@fluentui/react-switch/-/react-switch-9.1.96.tgz", + "integrity": "sha512-x2MZ5Bqm/XOTq9Ce8i2Be8ZZIcAlxJBq66ZFONwFxA3eyZ1Eq1wxg84BCUFogLL/CbzsgW3WQrRvQhIV9OymLQ==", + "dependencies": { + "@fluentui/react-field": "^9.1.78", + "@fluentui/react-icons": "^2.0.245", + "@fluentui/react-jsx-runtime": "^9.0.45", + "@fluentui/react-label": "^9.1.77", + "@fluentui/react-shared-contexts": "^9.20.2", + "@fluentui/react-tabster": "^9.22.9", + "@fluentui/react-theme": "^9.1.21", + "@fluentui/react-utilities": "^9.18.16", + "@griffel/react": "^1.5.22", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-table": { + "version": "9.15.20", + "resolved": "https://registry.npmjs.org/@fluentui/react-table/-/react-table-9.15.20.tgz", + "integrity": "sha512-9knCGNU69PlUCy5WDRa4S50HsoFklI8pgTLtui4IwnXCcsmXl57wv8EjzH89qSsp8ZSgKBWaRyyPG3GQUOsCpg==", + "dependencies": { + "@fluentui/keyboard-keys": "^9.0.7", + "@fluentui/react-aria": "^9.13.8", + "@fluentui/react-avatar": "^9.6.41", + "@fluentui/react-checkbox": "^9.2.39", + "@fluentui/react-context-selector": "^9.1.68", + "@fluentui/react-icons": "^2.0.245", + "@fluentui/react-jsx-runtime": "^9.0.45", + "@fluentui/react-radio": "^9.2.34", + "@fluentui/react-shared-contexts": "^9.20.2", + "@fluentui/react-tabster": "^9.22.9", + "@fluentui/react-theme": "^9.1.21", + "@fluentui/react-utilities": "^9.18.16", + "@griffel/react": "^1.5.22", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-tabs": { + "version": "9.6.0", + "resolved": "https://registry.npmjs.org/@fluentui/react-tabs/-/react-tabs-9.6.0.tgz", + "integrity": "sha512-VGBJ5vPAJB2YO6p1tjIgB4KLdPZyXAJSv2NzjGzr7q/sQuO7IJVWo19RpJGkJfkWbupuCwwqEd41A5gpt/Kscg==", + "dependencies": { + "@fluentui/react-context-selector": "^9.1.68", + "@fluentui/react-jsx-runtime": "^9.0.45", + "@fluentui/react-shared-contexts": "^9.20.2", + "@fluentui/react-tabster": "^9.22.9", + "@fluentui/react-theme": "^9.1.21", + "@fluentui/react-utilities": "^9.18.16", + "@griffel/react": "^1.5.22", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-tabster": { + "version": "9.22.9", + "resolved": "https://registry.npmjs.org/@fluentui/react-tabster/-/react-tabster-9.22.9.tgz", + "integrity": "sha512-Mnndzbo3SKbdSkn6LmtZpQvM0sFNW3ryo5ZXcCBjkQPPk2P1kAxGDxSYbFuWDCI2oWa/daJmDJr0IWxr0sQZuA==", + "dependencies": { + "@fluentui/react-shared-contexts": "^9.20.2", + "@fluentui/react-theme": "^9.1.21", + "@fluentui/react-utilities": "^9.18.16", + "@griffel/react": "^1.5.22", + "@swc/helpers": "^0.5.1", + "keyborg": "^2.6.0", + "tabster": "^8.2.0" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-tag-picker": { + "version": "9.3.6", + "resolved": "https://registry.npmjs.org/@fluentui/react-tag-picker/-/react-tag-picker-9.3.6.tgz", + "integrity": "sha512-dnqu+BzWTDq7PmItoZoDDMoH4TQtALf60vOUn4x9R7wtqd6yRQaBuY3dFuHEpBBLL/+qPH1rKNfl4NreQqJSKQ==", + "dependencies": { + "@fluentui/keyboard-keys": "^9.0.7", + "@fluentui/react-aria": "^9.13.8", + "@fluentui/react-combobox": "^9.13.10", + "@fluentui/react-context-selector": "^9.1.68", + "@fluentui/react-field": "^9.1.78", + "@fluentui/react-icons": "^2.0.245", + "@fluentui/react-jsx-runtime": "^9.0.45", + "@fluentui/react-portal": "^9.4.37", + "@fluentui/react-positioning": "^9.15.10", + "@fluentui/react-shared-contexts": "^9.20.2", + "@fluentui/react-tabster": "^9.22.9", + "@fluentui/react-tags": "^9.3.20", + "@fluentui/react-theme": "^9.1.21", + "@fluentui/react-utilities": "^9.18.16", + "@griffel/react": "^1.5.22", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-tags": { + "version": "9.3.20", + "resolved": "https://registry.npmjs.org/@fluentui/react-tags/-/react-tags-9.3.20.tgz", + "integrity": "sha512-NH5VnmyQXiIcZUctdft00xgvYqcqufogetknM37cEhOg6ERXKSnhT0iMxuznRYHTGZnP2hWbizrSagzHepG9Fw==", + "dependencies": { + "@fluentui/keyboard-keys": "^9.0.7", + "@fluentui/react-aria": "^9.13.8", + "@fluentui/react-avatar": "^9.6.41", + "@fluentui/react-icons": "^2.0.245", + "@fluentui/react-jsx-runtime": "^9.0.45", + "@fluentui/react-shared-contexts": "^9.20.2", + "@fluentui/react-tabster": "^9.22.9", + "@fluentui/react-theme": "^9.1.21", + "@fluentui/react-utilities": "^9.18.16", + "@griffel/react": "^1.5.22", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-teaching-popover": { + "version": "9.1.20", + "resolved": "https://registry.npmjs.org/@fluentui/react-teaching-popover/-/react-teaching-popover-9.1.20.tgz", + "integrity": "sha512-aiAxMmTvYgDleCG+JUzm0wqN5+bFqFj5MPj/TGx5fL3htmFWC9t0EYvuf1A9JOzp5K9erecJuQvu4mYs1aBK7g==", + "dependencies": { + "@fluentui/react-aria": "^9.13.8", + "@fluentui/react-button": "^9.3.94", + "@fluentui/react-context-selector": "^9.1.68", + "@fluentui/react-icons": "^2.0.245", + "@fluentui/react-jsx-runtime": "^9.0.45", + "@fluentui/react-popover": "^9.9.23", + "@fluentui/react-shared-contexts": "^9.20.2", + "@fluentui/react-tabster": "^9.22.9", + "@fluentui/react-theme": "^9.1.21", + "@fluentui/react-utilities": "^9.18.16", + "@griffel/react": "^1.5.22", + "@swc/helpers": "^0.5.1", + "use-sync-external-store": "^1.2.0" + }, + "peerDependencies": { + "@types/react": ">=16.8.0 <19.0.0", + "@types/react-dom": ">=16.8.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.8.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-text": { + "version": "9.4.26", + "resolved": "https://registry.npmjs.org/@fluentui/react-text/-/react-text-9.4.26.tgz", + "integrity": "sha512-RRHlT8jwMhncf+EKGACl0ZF3bI5B4OLBIHfB5aoNUjREmqHeX64om8le1+ICk7gQx654eEx8v0PnAplnS1Dnlw==", + "dependencies": { + "@fluentui/react-jsx-runtime": "^9.0.45", + "@fluentui/react-shared-contexts": "^9.20.2", + "@fluentui/react-theme": "^9.1.21", + "@fluentui/react-utilities": "^9.18.16", + "@griffel/react": "^1.5.22", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-textarea": { + "version": "9.3.90", + "resolved": "https://registry.npmjs.org/@fluentui/react-textarea/-/react-textarea-9.3.90.tgz", + "integrity": "sha512-PNNmKUxjZ+pmjnn4TZ7P9xmTXIVvE1KTEIKG7fXRpybfv9RmWizKUdzKMN1yYYEvEFLlKLaGW4gmiWFMVyeC7Q==", + "dependencies": { + "@fluentui/react-field": "^9.1.78", + "@fluentui/react-jsx-runtime": "^9.0.45", + "@fluentui/react-shared-contexts": "^9.20.2", + "@fluentui/react-theme": "^9.1.21", + "@fluentui/react-utilities": "^9.18.16", + "@griffel/react": "^1.5.22", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-theme": { + "version": "9.1.21", + "resolved": "https://registry.npmjs.org/@fluentui/react-theme/-/react-theme-9.1.21.tgz", + "integrity": "sha512-xiENKBT1ttcGiOKW0Dv2YEKYg92r1hYd6O/VGCvlX/j5ecclZ7RJO/O94LWQ8YJ22EzEYHeSp4y//uJQV9iU1g==", + "dependencies": { + "@fluentui/tokens": "1.0.0-alpha.18", + "@swc/helpers": "^0.5.1" + } + }, + "node_modules/@fluentui/react-toast": { + "version": "9.3.58", + "resolved": "https://registry.npmjs.org/@fluentui/react-toast/-/react-toast-9.3.58.tgz", + "integrity": "sha512-ELc0u3zZJcQXgfyGLhxKu4U9Y2OaE6uwWtw6+c1yPlh9meTnqlTJepfHsveJaD86aVSIWhHj5TzSeuSYWaQQdA==", + "dependencies": { + "@fluentui/keyboard-keys": "^9.0.7", + "@fluentui/react-aria": "^9.13.8", + "@fluentui/react-icons": "^2.0.245", + "@fluentui/react-jsx-runtime": "^9.0.45", + "@fluentui/react-motion": "^9.6.0", + "@fluentui/react-portal": "^9.4.37", + "@fluentui/react-shared-contexts": "^9.20.2", + "@fluentui/react-tabster": "^9.22.9", + "@fluentui/react-theme": "^9.1.21", + "@fluentui/react-utilities": "^9.18.16", + "@griffel/react": "^1.5.22", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-toolbar": { + "version": "9.2.8", + "resolved": "https://registry.npmjs.org/@fluentui/react-toolbar/-/react-toolbar-9.2.8.tgz", + "integrity": "sha512-PmtIFyajVhvoEHoQfE5kgjREhIv/UhSe9PDPOWG6Xf4mF0LrpN1pQDRLbBTR/00G4GTUv41i7hRazpRsngaluQ==", + "dependencies": { + "@fluentui/react-button": "^9.3.94", + "@fluentui/react-context-selector": "^9.1.68", + "@fluentui/react-divider": "^9.2.76", + "@fluentui/react-jsx-runtime": "^9.0.45", + "@fluentui/react-radio": "^9.2.34", + "@fluentui/react-shared-contexts": "^9.20.2", + "@fluentui/react-tabster": "^9.22.9", + "@fluentui/react-theme": "^9.1.21", + "@fluentui/react-utilities": "^9.18.16", + "@griffel/react": "^1.5.22", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-tooltip": { + "version": "9.4.41", + "resolved": "https://registry.npmjs.org/@fluentui/react-tooltip/-/react-tooltip-9.4.41.tgz", + "integrity": "sha512-KHfCp8uNFSqMVw/7eZ1rqLpTm9eeypmHODh8v0ght7o1Aom/KvMQwiYa21lWnga383bMMSit5+WJtIyaHjpgdg==", + "dependencies": { + "@fluentui/keyboard-keys": "^9.0.7", + "@fluentui/react-jsx-runtime": "^9.0.45", + "@fluentui/react-portal": "^9.4.37", + "@fluentui/react-positioning": "^9.15.10", + "@fluentui/react-shared-contexts": "^9.20.2", + "@fluentui/react-tabster": "^9.22.9", + "@fluentui/react-theme": "^9.1.21", + "@fluentui/react-utilities": "^9.18.16", + "@griffel/react": "^1.5.22", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-tree": { + "version": "9.8.4", + "resolved": "https://registry.npmjs.org/@fluentui/react-tree/-/react-tree-9.8.4.tgz", + "integrity": "sha512-v4vNkOdOWKg37WsDVPkj9YVHUMPL7lKJR9E3q8d32V7bBQgWQ4jkapWUxFTIEacYvHW0+24ajFj8XvEbFjISzQ==", + "dependencies": { + "@fluentui/keyboard-keys": "^9.0.7", + "@fluentui/react-aria": "^9.13.8", + "@fluentui/react-avatar": "^9.6.41", + "@fluentui/react-button": "^9.3.94", + "@fluentui/react-checkbox": "^9.2.39", + "@fluentui/react-context-selector": "^9.1.68", + "@fluentui/react-icons": "^2.0.245", + "@fluentui/react-jsx-runtime": "^9.0.45", + "@fluentui/react-motion": "^9.6.0", + "@fluentui/react-motion-components-preview": "^0.2.0", + "@fluentui/react-radio": "^9.2.34", + "@fluentui/react-shared-contexts": "^9.20.2", + "@fluentui/react-tabster": "^9.22.9", + "@fluentui/react-theme": "^9.1.21", + "@fluentui/react-utilities": "^9.18.16", + "@griffel/react": "^1.5.22", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-utilities": { + "version": "9.18.16", + "resolved": "https://registry.npmjs.org/@fluentui/react-utilities/-/react-utilities-9.18.16.tgz", + "integrity": "sha512-IXPD/TMsCcA5PVM4AvLT3Wgck/te7OaMj4OqDcVGciob+73MliScmXYz8ZwSIP1fxlo6CBPZo8mPZK8C6nkKQQ==", + "dependencies": { + "@fluentui/keyboard-keys": "^9.0.7", + "@fluentui/react-shared-contexts": "^9.20.2", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "react": ">=16.14.0 <19.0.0" + } + }, + "node_modules/@fluentui/react-virtualizer": { + "version": "9.0.0-alpha.86", + "resolved": "https://registry.npmjs.org/@fluentui/react-virtualizer/-/react-virtualizer-9.0.0-alpha.86.tgz", + "integrity": "sha512-Ap+FC0+TdMek/oK3HJDnoiF4DZ4/eiMJRiCqWeBpOjUK6dM3nkplBQzgcJRTkHEYUo7PR0G82PxHr0n07lu2qQ==", + "dependencies": { + "@fluentui/react-jsx-runtime": "^9.0.45", + "@fluentui/react-shared-contexts": "^9.20.2", + "@fluentui/react-utilities": "^9.18.16", + "@griffel/react": "^1.5.22", + "@swc/helpers": "^0.5.1" + }, + "peerDependencies": { + "@types/react": ">=16.14.0 <19.0.0", + "@types/react-dom": ">=16.9.0 <19.0.0", + "react": ">=16.14.0 <19.0.0", + "react-dom": ">=16.14.0 <19.0.0" + } + }, "node_modules/@fluentui/react-window-provider": { "version": "2.2.28", "resolved": "https://registry.npmjs.org/@fluentui/react-window-provider/-/react-window-provider-2.2.28.tgz", @@ -3258,6 +4681,14 @@ "react": ">=16.8.0 <19.0.0" } }, + "node_modules/@fluentui/tokens": { + "version": "1.0.0-alpha.18", + "resolved": "https://registry.npmjs.org/@fluentui/tokens/-/tokens-1.0.0-alpha.18.tgz", + "integrity": "sha512-d7CpB7RJhPlv8r6OjKRsL4mu8dvSiwrGdQuZyRhDjhCa/5u0xSdCxLmwGu4HOTlr9sg9Gf7LbQe2shAlq2J21w==", + "dependencies": { + "@swc/helpers": "^0.5.1" + } + }, "node_modules/@fluentui/utilities": { "version": "8.15.15", "resolved": "https://registry.npmjs.org/@fluentui/utilities/-/utilities-8.15.15.tgz", @@ -3274,6 +4705,39 @@ "react": ">=16.8.0 <19.0.0" } }, + "node_modules/@griffel/core": { + "version": "1.18.0", + "resolved": "https://registry.npmjs.org/@griffel/core/-/core-1.18.0.tgz", + "integrity": "sha512-3Dkn6f7ULeSzJ1wLyLfN1vc+v3q5shuEejeMe4XymBozQo0l35WIfH8FWcwB+Xrgip4fLLOy1p3sYN85gFGZxw==", + "dependencies": { + "@emotion/hash": "^0.9.0", + "@griffel/style-types": "^1.2.0", + "csstype": "^3.1.3", + "rtl-css-js": "^1.16.1", + "stylis": "^4.2.0", + "tslib": "^2.1.0" + } + }, + "node_modules/@griffel/react": { + "version": "1.5.25", + "resolved": "https://registry.npmjs.org/@griffel/react/-/react-1.5.25.tgz", + "integrity": "sha512-ZGiCdn71VIX56fd3AxM7ouCxgClPvunOFIpXxFKebGJ94/rdj4sIbahuI1QBUFuU4/bqUyD6QonjDEpFBl9ORw==", + "dependencies": { + "@griffel/core": "^1.18.0", + "tslib": "^2.1.0" + }, + "peerDependencies": { + "react": ">=16.8.0 <19.0.0" + } + }, + "node_modules/@griffel/style-types": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@griffel/style-types/-/style-types-1.2.0.tgz", + "integrity": "sha512-x166MNw0vWe5l5qhinfNT4eyWOaP48iFzPyFOfIB0/BVidKTWsEe5PmqRJDDtrJFS3VHhd/tE0oM6tkEMh2tsg==", + "dependencies": { + "csstype": "^3.1.3" + } + }, "node_modules/@hapi/hoek": { "version": "9.3.0", "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-9.3.0.tgz", @@ -7824,9 +9288,9 @@ "dev": true }, "node_modules/csstype": { - "version": "3.0.11", - "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.0.11.tgz", - "integrity": "sha512-sa6P2wJ+CAbgyy4KFssIb/JNMLxFvKF1pCYCSXS8ZMuqZnMsrxqI2E5sPyoTpxoPU/gVZMzr2zjOfg8GIZOMsw==" + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", + "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==" }, "node_modules/d3-format": { "version": "1.4.5", @@ -8170,6 +9634,15 @@ "utila": "~0.4" } }, + "node_modules/dom-helpers": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.2.1.tgz", + "integrity": "sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==", + "dependencies": { + "@babel/runtime": "^7.8.7", + "csstype": "^3.0.2" + } + }, "node_modules/dom-serializer": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.4.1.tgz", @@ -8325,6 +9798,27 @@ "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.13.tgz", "integrity": "sha512-lbBcvtIJ4J6sS4tb5TLp1b4LyfCdMkwStzXPyAgVgTRAsep4bvrAGaBOP7ZJtQMNJpSQ9SqG4brWOroNaQtm7Q==" }, + "node_modules/embla-carousel": { + "version": "8.3.1", + "resolved": "https://registry.npmjs.org/embla-carousel/-/embla-carousel-8.3.1.tgz", + "integrity": "sha512-DutFjtEO586XptDn4cwvBJwsR/8fMa4jUk5Jk2g+/elKgu8mdn0Z2sx33g4JskvbLc1/6P8Xg4QlfELGJFcP5A==" + }, + "node_modules/embla-carousel-autoplay": { + "version": "8.3.1", + "resolved": "https://registry.npmjs.org/embla-carousel-autoplay/-/embla-carousel-autoplay-8.3.1.tgz", + "integrity": "sha512-L8THF1AJJSQtlNa1wZ6lEKh/CiZssE3TsVFtabQNsS+pc1O1O/YTIYCC3khdQAztGMOBf3WfVDIY/4AIfQj3JQ==", + "peerDependencies": { + "embla-carousel": "8.3.1" + } + }, + "node_modules/embla-carousel-fade": { + "version": "8.3.1", + "resolved": "https://registry.npmjs.org/embla-carousel-fade/-/embla-carousel-fade-8.3.1.tgz", + "integrity": "sha512-YUnb222xjkdRDtyC09X59GapaYB6P8baAEHy1rn2UQ0yqixa80kXhG74SoJ6wxLYsZOaw5fZQ2V25p04ltHE/w==", + "peerDependencies": { + "embla-carousel": "8.3.1" + } + }, "node_modules/emittery": { "version": "0.13.1", "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.13.1.tgz", @@ -14170,6 +15664,11 @@ "util-deprecate": "~1.0.1" } }, + "node_modules/keyborg": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/keyborg/-/keyborg-2.6.0.tgz", + "integrity": "sha512-o5kvLbuTF+o326CMVYpjlaykxqYP9DphFQZ2ZpgrvBouyvOxyEB7oqe8nOLFpiV5VCtz0D3pt8gXQYWpLpBnmA==" + }, "node_modules/kind-of": { "version": "6.0.3", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", @@ -16870,14 +18369,6 @@ "react": "^18.2.0" } }, - "node_modules/react-dom/node_modules/scheduler": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz", - "integrity": "sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==", - "dependencies": { - "loose-envify": "^1.1.0" - } - }, "node_modules/react-error-overlay": { "version": "6.0.11", "resolved": "https://registry.npmjs.org/react-error-overlay/-/react-error-overlay-6.0.11.tgz", @@ -16932,6 +18423,21 @@ "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==" }, + "node_modules/react-transition-group": { + "version": "4.4.5", + "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.5.tgz", + "integrity": "sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==", + "dependencies": { + "@babel/runtime": "^7.5.5", + "dom-helpers": "^5.0.1", + "loose-envify": "^1.4.0", + "prop-types": "^15.6.2" + }, + "peerDependencies": { + "react": ">=16.6.0", + "react-dom": ">=16.6.0" + } + }, "node_modules/readable-stream": { "version": "3.6.2", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", @@ -17302,6 +18808,14 @@ "node": ">=8" } }, + "node_modules/rtl-css-js": { + "version": "1.16.1", + "resolved": "https://registry.npmjs.org/rtl-css-js/-/rtl-css-js-1.16.1.tgz", + "integrity": "sha512-lRQgou1mu19e+Ya0LsTvKrVJ5TYUbqCVPAiImX3UfLTenarvPUl1QFdvu5Z3PYmHT9RCcwIfbjRQBntExyj3Zg==", + "dependencies": { + "@babel/runtime": "^7.1.2" + } + }, "node_modules/run-applescript": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/run-applescript/-/run-applescript-7.0.0.tgz", @@ -17456,6 +18970,14 @@ "node": ">=v12.22.7" } }, + "node_modules/scheduler": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz", + "integrity": "sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==", + "dependencies": { + "loose-envify": "^1.1.0" + } + }, "node_modules/schema-utils": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.2.0.tgz", @@ -18241,6 +19763,11 @@ "webpack": "^5.27.0" } }, + "node_modules/stylis": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.3.4.tgz", + "integrity": "sha512-osIBl6BGUmSfDkyH2mB7EFvCJntXDrLhKjHTRj/rK6xLH0yuPrHULDRQzKokSOD4VoorhtKpfcfW1GAntu8now==" + }, "node_modules/supports-color": { "version": "5.5.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", @@ -18293,6 +19820,15 @@ "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", "dev": true }, + "node_modules/tabster": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/tabster/-/tabster-8.2.0.tgz", + "integrity": "sha512-Gvplk/Yl/12aVFA6FPOqGcq31Qv8hbPfYO0N+6IxrRgRT6eSLsipT6gkZBYjyOwGsp6BD5XlZAuJgupfG/GHoA==", + "dependencies": { + "keyborg": "2.6.0", + "tslib": "^2.3.1" + } + }, "node_modules/tapable": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", @@ -19042,6 +20578,17 @@ "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", "integrity": "sha512-jmYNElW7yvO7TV33CjSmvSiE2yco3bV2czu/OzDKdMNVZQWfxCblURLhf+47syQRBntjfLdd/H0egrzIG+oaFQ==" }, + "node_modules/use-disposable": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/use-disposable/-/use-disposable-1.0.4.tgz", + "integrity": "sha512-j83t6AMLWUyb5zwlTDqf6dP9LezM9R0yTbI/b6olmdaGtCKQUe9pgJWV6dRaaQLcozypjIEp4EmZr2DkZGKLSg==", + "peerDependencies": { + "@types/react": ">=16.8.0 <19.0.0", + "@types/react-dom": ">=16.8.0 <19.0.0", + "react": ">=16.8.0 <19.0.0", + "react-dom": ">=16.8.0 <19.0.0" + } + }, "node_modules/use-sync-external-store": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz", diff --git a/package.json b/package.json index fc9c2e8e10..864f83881d 100644 --- a/package.json +++ b/package.json @@ -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", From daf6010eabe6dfdb5f07cf72101794f5135272e5 Mon Sep 17 00:00:00 2001 From: Musale Martin Date: Thu, 31 Oct 2024 14:52:47 +0300 Subject: [PATCH 06/24] Update styles and components for Notification --- .../common/banners/Notification.styles.ts | 5 +-- src/app/views/common/banners/Notification.tsx | 37 ++++++++++++++----- 2 files changed, 29 insertions(+), 13 deletions(-) diff --git a/src/app/views/common/banners/Notification.styles.ts b/src/app/views/common/banners/Notification.styles.ts index 0b38f2383b..a30265581c 100644 --- a/src/app/views/common/banners/Notification.styles.ts +++ b/src/app/views/common/banners/Notification.styles.ts @@ -3,9 +3,8 @@ import { mergeStyleSets } from '@fluentui/react'; export const useNotificationStyles = ()=>{ return mergeStyleSets({ container: { - borderRadius: '8px', - backgroundColor: 'blue', - textColor: '#ffffff' + padding: '8px', + marginBottom: '8px' } }) } \ No newline at end of file diff --git a/src/app/views/common/banners/Notification.tsx b/src/app/views/common/banners/Notification.tsx index fd1b20d97d..e58c33a163 100644 --- a/src/app/views/common/banners/Notification.tsx +++ b/src/app/views/common/banners/Notification.tsx @@ -1,11 +1,20 @@ -import { MessageBar, MessageBarType } from '@fluentui/react'; +import { DismissRegular, OpenRegular } from '@fluentui/react-icons'; +import { + MessageBar, + MessageBarActions, + MessageBarTitle, + MessageBarBody, + Button, + Link + } from '@fluentui/react-components'; import { useNotificationStyles } from './Notification.styles'; import { useState } from 'react'; interface NotificationProps { header: string; content: string; - messageType?: MessageBarType; + link: string; + linkText: string; } export const Notification: React.FunctionComponent = (props: NotificationProps) => { @@ -23,14 +32,22 @@ export const Notification: React.FunctionComponent = (props: } return ( - -

{props.header}

- {/* TODO: Track content when link is clicked in telemetry */} -

{props.content}

+ + + {props.header}

+ {props.content}{' '} + {props.linkText} +
+ } + /> + } + />
); }; From 31949f86a397a23190dcccdc3dc3b5a78cb56d4a Mon Sep 17 00:00:00 2001 From: Musale Martin Date: Thu, 31 Oct 2024 14:53:04 +0300 Subject: [PATCH 07/24] Add text for notification --- src/messages/GE.json | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/messages/GE.json b/src/messages/GE.json index 71fa217dbe..5407a02ca9 100644 --- a/src/messages/GE.json +++ b/src/messages/GE.json @@ -498,5 +498,9 @@ "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" } \ No newline at end of file From bda0a9164c0a588057484d178bc1f4edccbf9576 Mon Sep 17 00:00:00 2001 From: Musale Martin Date: Thu, 31 Oct 2024 15:22:55 +0300 Subject: [PATCH 08/24] Hook theming of v9 provider to prop value --- src/app/views/App.tsx | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/app/views/App.tsx b/src/app/views/App.tsx index e8a8cc4e33..1a88bd10d8 100644 --- a/src/app/views/App.tsx +++ b/src/app/views/App.tsx @@ -3,7 +3,7 @@ import { bindActionCreators, Dispatch } from '@reduxjs/toolkit'; import { Resizable } from 're-resizable'; import { Component } from 'react'; import { connect } from 'react-redux'; -import { FluentProvider, webDarkTheme } from '@fluentui/react-components'; +import { FluentProvider, teamsHighContrastTheme, Theme, webDarkTheme, webLightTheme } from '@fluentui/react-components'; import { removeSpinners } from '../..'; import { authenticationWrapper } from '../../modules/authentication'; @@ -407,9 +407,14 @@ class App extends Component { this.removeFlexBasisProperty(); this.removeSidebarHeightProperty(); + const fluentV9Themes: Record= { + 'light': webLightTheme, + 'dark': webDarkTheme, + 'high-contrast': teamsHighContrastTheme + } return ( // @ts-ignore - +
From e248e4a7aaadd7fbe3f713f81509727673c9825c Mon Sep 17 00:00:00 2001 From: Musale Martin Date: Tue, 5 Nov 2024 14:31:44 +0300 Subject: [PATCH 09/24] Track the tutorial link with telemetry --- src/app/views/common/banners/Notification.tsx | 15 ++++++++++++--- src/messages/GE.json | 3 ++- src/telemetry/component-names.ts | 1 + 3 files changed, 15 insertions(+), 4 deletions(-) diff --git a/src/app/views/common/banners/Notification.tsx b/src/app/views/common/banners/Notification.tsx index e58c33a163..88c7cf9e26 100644 --- a/src/app/views/common/banners/Notification.tsx +++ b/src/app/views/common/banners/Notification.tsx @@ -9,6 +9,8 @@ import { } from '@fluentui/react-components'; import { useNotificationStyles } from './Notification.styles'; import { useState } from 'react'; +import { translateMessage } from '../../../utils/translate-messages'; +import { componentNames, telemetry } from '../../../../telemetry'; interface NotificationProps { header: string; @@ -17,12 +19,16 @@ interface NotificationProps { linkText: string; } +const handleOnClickLink = (e: React.MouseEvent)=>{ + telemetry.trackLinkClickEvent( + (e.currentTarget as HTMLAnchorElement).href, componentNames.GRAPH_EXPLORER_TUTORIAL_LINK) +} + export const Notification: React.FunctionComponent = (props: NotificationProps) => { const styles = useNotificationStyles(); const [isVisible, setIsVisible] = useState(true); const handleDismiss = () => { - // TODO: track as dismissed in telemetry // TODO: don't show again. Persist choice to state setIsVisible(false); }; @@ -36,13 +42,16 @@ export const Notification: React.FunctionComponent = (props: {props.header}

{props.content}{' '} - {props.linkText} + {props.linkText}
} /> diff --git a/src/messages/GE.json b/src/messages/GE.json index 5407a02ca9..f39e3d6e5f 100644 --- a/src/messages/GE.json +++ b/src/messages/GE.json @@ -502,5 +502,6 @@ "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" + "Banner notification 1 link": "https://aka.ms/ge", + "Dismiss banner": "Dismiss banner" } \ No newline at end of file diff --git a/src/telemetry/component-names.ts b/src/telemetry/component-names.ts index d00395d4c1..6e94626cd7 100644 --- a/src/telemetry/component-names.ts +++ b/src/telemetry/component-names.ts @@ -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' From 2ef65a5d42bdac380104f33657ccc1cb46454c70 Mon Sep 17 00:00:00 2001 From: Musale Martin Date: Tue, 5 Nov 2024 14:53:43 +0300 Subject: [PATCH 10/24] Add slice banner --- .../autocomplete-action-creators.spec.ts | 3 +- .../permissions-action-creator.spec.ts | 3 +- .../resource-explorer-action-creators.spec.ts | 3 +- src/app/services/reducers/index.ts | 4 ++- src/app/services/slices/banner.slice.ts | 32 +++++++++++++++++++ src/store/index.ts | 3 +- src/types/banner.ts | 3 ++ 7 files changed, 46 insertions(+), 5 deletions(-) create mode 100644 src/app/services/slices/banner.slice.ts create mode 100644 src/types/banner.ts diff --git a/src/app/services/actions/autocomplete-action-creators.spec.ts b/src/app/services/actions/autocomplete-action-creators.spec.ts index e9b932fafa..3dab2718b3 100644 --- a/src/app/services/actions/autocomplete-action-creators.spec.ts +++ b/src/app/services/actions/autocomplete-action-creators.spec.ts @@ -104,7 +104,8 @@ const mockState: ApplicationState = { error: null }, collections: [], - proxyUrl: '' + proxyUrl: '', + banner: {isVisible: false} } store.getState = () => ({ diff --git a/src/app/services/actions/permissions-action-creator.spec.ts b/src/app/services/actions/permissions-action-creator.spec.ts index 999336a6b6..48a4ae8b3f 100644 --- a/src/app/services/actions/permissions-action-creator.spec.ts +++ b/src/app/services/actions/permissions-action-creator.spec.ts @@ -125,7 +125,8 @@ const mockState: ApplicationState = { error: null }, collections: [], - proxyUrl: '' + proxyUrl: '', + banner: {isVisible: false} } const currentState = store.getState(); store.getState = () => { diff --git a/src/app/services/actions/resource-explorer-action-creators.spec.ts b/src/app/services/actions/resource-explorer-action-creators.spec.ts index edba19e182..8e9b397da6 100644 --- a/src/app/services/actions/resource-explorer-action-creators.spec.ts +++ b/src/app/services/actions/resource-explorer-action-creators.spec.ts @@ -100,7 +100,8 @@ const mockState: ApplicationState = { error: null }, collections: [], - proxyUrl: '' + proxyUrl: '', + banner: {isVisible: false} } const paths = [ diff --git a/src/app/services/reducers/index.ts b/src/app/services/reducers/index.ts index 02beeb2b20..9f7b77f1be 100644 --- a/src/app/services/reducers/index.ts +++ b/src/app/services/reducers/index.ts @@ -20,6 +20,7 @@ import snippets from '../slices/snippet.slice'; import themeChange from '../slices/theme.slice'; import termsOfUse from '../slices/terms-of-use.slice'; import sidebarProperties from '../slices/sidebar-properties.slice'; +import banner from '../slices/banner.slice'; const reducers = { auth, @@ -42,7 +43,8 @@ const reducers = { sidebarProperties, snippets, termsOfUse, - theme: themeChange + theme: themeChange, + banner }; export { diff --git a/src/app/services/slices/banner.slice.ts b/src/app/services/slices/banner.slice.ts new file mode 100644 index 0000000000..bc1003ae79 --- /dev/null +++ b/src/app/services/slices/banner.slice.ts @@ -0,0 +1,32 @@ +import { createSlice, PayloadAction } from '@reduxjs/toolkit'; +import { useAppSelector } from '../../../store'; +import { useEffect } from 'react'; +import { Banner } from '../../../types/banner'; + +const initialState: Banner = { + isVisible: false +}; + +const bannerSlice = createSlice({ + name: 'banner', + initialState, + reducers: { + showBanner(state) { + state.isVisible = true; + }, + hideBanner(state) { + state.isVisible = false; + } + } +}); + +export const { showBanner, hideBanner } = bannerSlice.actions; + +export default bannerSlice.reducer; +// Subscribe to store updates and save the banner state to localStorage +export const saveBannerState = () => { + const banner = useAppSelector(state=>state.banner) + useEffect(()=>{ + console.log('setting banner state', banner) + }, [banner]) +}; \ No newline at end of file diff --git a/src/store/index.ts b/src/store/index.ts index e25f01967e..13ffd03e13 100644 --- a/src/store/index.ts +++ b/src/store/index.ts @@ -49,7 +49,8 @@ const initialState = { body: undefined, headers: undefined } - } + }, + banner: {isVisible: false} } export const store = configureStore({ diff --git a/src/types/banner.ts b/src/types/banner.ts new file mode 100644 index 0000000000..c4657fa5fd --- /dev/null +++ b/src/types/banner.ts @@ -0,0 +1,3 @@ +export interface Banner { + isVisible: boolean +} \ No newline at end of file From 39814b6c75605c4cd86cdedf5b77b1d6e1554115 Mon Sep 17 00:00:00 2001 From: Musale Martin Date: Tue, 5 Nov 2024 16:17:26 +0300 Subject: [PATCH 11/24] Persist banner state to localstorage --- src/app/middleware/localStorageMiddleware.ts | 8 +++++++- src/app/services/graph-constants.ts | 3 ++- src/app/services/redux-constants.ts | 1 + src/modules/cache/banner.cache.ts | 20 ++++++++++++++++++++ 4 files changed, 30 insertions(+), 2 deletions(-) create mode 100644 src/modules/cache/banner.cache.ts diff --git a/src/app/middleware/localStorageMiddleware.ts b/src/app/middleware/localStorageMiddleware.ts index a12673fe1a..0fcc4bed0a 100644 --- a/src/app/middleware/localStorageMiddleware.ts +++ b/src/app/middleware/localStorageMiddleware.ts @@ -7,9 +7,11 @@ 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, SET_BANNER_STATE } from '../services/redux-constants'; import { saveToLocalStorage } from '../utils/local-storage'; +import { bannerCache } from '../../modules/cache/banner.cache'; const localStorageMiddleware: Middleware<{}, any, Dispatch> = () => (next) => async (value) => { const action = value as AppAction; @@ -49,6 +51,10 @@ const localStorageMiddleware: Middleware<{}, any, Dispatch> = () break; } + case SET_BANNER_STATE: + await bannerCache.update(action.payload as Boolean) + break; + default: break; } diff --git a/src/app/services/graph-constants.ts b/src/app/services/graph-constants.ts index bdc5315221..137f7dd2ca 100644 --- a/src/app/services/graph-constants.ts +++ b/src/app/services/graph-constants.ts @@ -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' \ No newline at end of file +export const EXP_URL='https://default.exp-tas.com/exptas76/9b835cbf-9742-40db-84a7-7a323a77f3eb-gedev/api/v1/tas' +export const BANNER_IS_VISIBLE = 'isVisible'; \ No newline at end of file diff --git a/src/app/services/redux-constants.ts b/src/app/services/redux-constants.ts index b0c0cb6246..bc4978e6a6 100644 --- a/src/app/services/redux-constants.ts +++ b/src/app/services/redux-constants.ts @@ -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'; diff --git a/src/modules/cache/banner.cache.ts b/src/modules/cache/banner.cache.ts new file mode 100644 index 0000000000..173ba02082 --- /dev/null +++ b/src/modules/cache/banner.cache.ts @@ -0,0 +1,20 @@ +import localforage from 'localforage'; +import { BANNER_IS_VISIBLE } from '../../app/services/graph-constants'; + +const bannerStorage = localforage.createInstance({ + storeName: 'banner', + name: 'GE_V4' +}); + +export const bannerCache = (function () { + const get = async (): Promise =>{ + return await bannerStorage.getItem(BANNER_IS_VISIBLE) as Boolean + } + const read = async (): Promise =>{ + return await bannerStorage.getItem(BANNER_IS_VISIBLE) + } + const update = async (value: Boolean) =>{ + await bannerStorage.setItem(BANNER_IS_VISIBLE, value.toString()) + } + return { get,read, update} +})(); From 24fa9793037d69d27ae923019a3626139dfc25d8 Mon Sep 17 00:00:00 2001 From: Musale Martin Date: Tue, 5 Nov 2024 16:17:52 +0300 Subject: [PATCH 12/24] Update state usage of banner state --- .../autocomplete-action-creators.spec.ts | 2 +- .../permissions-action-creator.spec.ts | 2 +- .../resource-explorer-action-creators.spec.ts | 2 +- src/app/services/slices/banner.slice.ts | 20 ++++--------------- src/app/views/common/banners/Notification.tsx | 12 ++++++----- src/index.tsx | 13 +++++++++++- src/store/index.ts | 2 +- 7 files changed, 27 insertions(+), 26 deletions(-) diff --git a/src/app/services/actions/autocomplete-action-creators.spec.ts b/src/app/services/actions/autocomplete-action-creators.spec.ts index 3dab2718b3..d8e97819bd 100644 --- a/src/app/services/actions/autocomplete-action-creators.spec.ts +++ b/src/app/services/actions/autocomplete-action-creators.spec.ts @@ -105,7 +105,7 @@ const mockState: ApplicationState = { }, collections: [], proxyUrl: '', - banner: {isVisible: false} + banner: {isVisible: true} } store.getState = () => ({ diff --git a/src/app/services/actions/permissions-action-creator.spec.ts b/src/app/services/actions/permissions-action-creator.spec.ts index 48a4ae8b3f..f6bcb1b140 100644 --- a/src/app/services/actions/permissions-action-creator.spec.ts +++ b/src/app/services/actions/permissions-action-creator.spec.ts @@ -126,7 +126,7 @@ const mockState: ApplicationState = { }, collections: [], proxyUrl: '', - banner: {isVisible: false} + banner: {isVisible: true} } const currentState = store.getState(); store.getState = () => { diff --git a/src/app/services/actions/resource-explorer-action-creators.spec.ts b/src/app/services/actions/resource-explorer-action-creators.spec.ts index 8e9b397da6..c03eeaa96e 100644 --- a/src/app/services/actions/resource-explorer-action-creators.spec.ts +++ b/src/app/services/actions/resource-explorer-action-creators.spec.ts @@ -101,7 +101,7 @@ const mockState: ApplicationState = { }, collections: [], proxyUrl: '', - banner: {isVisible: false} + banner: {isVisible: true} } const paths = [ diff --git a/src/app/services/slices/banner.slice.ts b/src/app/services/slices/banner.slice.ts index bc1003ae79..150843a69e 100644 --- a/src/app/services/slices/banner.slice.ts +++ b/src/app/services/slices/banner.slice.ts @@ -1,32 +1,20 @@ import { createSlice, PayloadAction } from '@reduxjs/toolkit'; -import { useAppSelector } from '../../../store'; -import { useEffect } from 'react'; import { Banner } from '../../../types/banner'; const initialState: Banner = { - isVisible: false + isVisible: true }; const bannerSlice = createSlice({ name: 'banner', initialState, reducers: { - showBanner(state) { - state.isVisible = true; - }, - hideBanner(state) { - state.isVisible = false; + setBannerState: (state, action: PayloadAction) => { + state.isVisible = action.payload; } } }); -export const { showBanner, hideBanner } = bannerSlice.actions; +export const { setBannerState } = bannerSlice.actions; export default bannerSlice.reducer; -// Subscribe to store updates and save the banner state to localStorage -export const saveBannerState = () => { - const banner = useAppSelector(state=>state.banner) - useEffect(()=>{ - console.log('setting banner state', banner) - }, [banner]) -}; \ No newline at end of file diff --git a/src/app/views/common/banners/Notification.tsx b/src/app/views/common/banners/Notification.tsx index 88c7cf9e26..ed1b25966d 100644 --- a/src/app/views/common/banners/Notification.tsx +++ b/src/app/views/common/banners/Notification.tsx @@ -8,9 +8,10 @@ import { Link } from '@fluentui/react-components'; import { useNotificationStyles } from './Notification.styles'; -import { useState } from 'react'; import { translateMessage } from '../../../utils/translate-messages'; import { componentNames, telemetry } from '../../../../telemetry'; +import { useAppDispatch, useAppSelector } from '../../../../store'; +import { setBannerState } from '../../../services/slices/banner.slice'; interface NotificationProps { header: string; @@ -26,14 +27,15 @@ const handleOnClickLink = (e: React.MouseEvent)=>{ export const Notification: React.FunctionComponent = (props: NotificationProps) => { const styles = useNotificationStyles(); - const [isVisible, setIsVisible] = useState(true); + const banner = useAppSelector(state=> state.banner); + console.log({banner}) + const dispatch = useAppDispatch() const handleDismiss = () => { - // TODO: don't show again. Persist choice to state - setIsVisible(false); + dispatch(setBannerState(false)) }; - if (!isVisible) { + if (!banner.isVisible) { return null; } diff --git a/src/index.tsx b/src/index.tsx index db0ba7aca1..7b8ac9a70e 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -7,7 +7,7 @@ import { Provider } from 'react-redux'; import App from './app/views/App'; -import { CURRENT_THEME } from './app/services/graph-constants'; +import { BANNER_IS_VISIBLE, CURRENT_THEME } from './app/services/graph-constants'; import { getAuthTokenSuccess, getConsentedScopesSuccess } from './app/services/slices/auth.slice'; import { createCollection } from './app/services/slices/collections.slice'; import { setDevxApiUrl } from './app/services/slices/devxapi.slice'; @@ -33,6 +33,8 @@ import { IDevxAPI } from './types/devx-api'; import { Mode } from './types/enums'; import { IHistoryItem } from './types/history'; import { Collection } from './types/resources'; +import { setBannerState } from './app/services/slices/banner.slice'; +import { bannerCache } from './modules/cache/banner.cache'; const appRoot: HTMLElement = document.getElementById('root')!; @@ -230,6 +232,15 @@ window.onerror = (message, url, lineNumber, columnNumber, error) => { }); } +(async () => { + const bannerState = await bannerCache.read(); + console.log({bannerState}) + if(bannerState === null) { + appStore.dispatch(setBannerState(true)) + } +})() + + const Root = () => { return ( diff --git a/src/store/index.ts b/src/store/index.ts index 13ffd03e13..d5a32129e9 100644 --- a/src/store/index.ts +++ b/src/store/index.ts @@ -50,7 +50,7 @@ const initialState = { headers: undefined } }, - banner: {isVisible: false} + banner: {isVisible: true} } export const store = configureStore({ From 1d80997812f5464deb6973104ccbc2f3d23b3adf Mon Sep 17 00:00:00 2001 From: Musale Martin Date: Tue, 5 Nov 2024 18:39:47 +0300 Subject: [PATCH 13/24] Use local storage to track banner visibility --- src/app/middleware/localStorageMiddleware.ts | 7 +------ .../autocomplete-action-creators.spec.ts | 3 +-- .../permissions-action-creator.spec.ts | 3 +-- .../resource-explorer-action-creators.spec.ts | 3 +-- src/app/services/graph-constants.ts | 2 +- src/app/services/reducers/index.ts | 4 +--- src/app/services/slices/banner.slice.ts | 20 ------------------- src/app/views/common/banners/Notification.tsx | 11 ++++------ src/index.tsx | 13 +----------- src/modules/cache/banner.cache.ts | 20 ------------------- src/store/index.ts | 3 +-- src/types/banner.ts | 3 --- 12 files changed, 12 insertions(+), 80 deletions(-) delete mode 100644 src/app/services/slices/banner.slice.ts delete mode 100644 src/modules/cache/banner.cache.ts delete mode 100644 src/types/banner.ts diff --git a/src/app/middleware/localStorageMiddleware.ts b/src/app/middleware/localStorageMiddleware.ts index 0fcc4bed0a..48aeff9ddc 100644 --- a/src/app/middleware/localStorageMiddleware.ts +++ b/src/app/middleware/localStorageMiddleware.ts @@ -8,10 +8,9 @@ import { getUniquePaths } from '../services/reducers/collections-reducer.util'; import { CHANGE_THEME_SUCCESS, COLLECTION_CREATE_SUCCESS, RESOURCEPATHS_ADD_SUCCESS, RESOURCEPATHS_DELETE_SUCCESS, - SAMPLES_FETCH_SUCCESS, SET_BANNER_STATE + SAMPLES_FETCH_SUCCESS } from '../services/redux-constants'; import { saveToLocalStorage } from '../utils/local-storage'; -import { bannerCache } from '../../modules/cache/banner.cache'; const localStorageMiddleware: Middleware<{}, any, Dispatch> = () => (next) => async (value) => { const action = value as AppAction; @@ -51,10 +50,6 @@ const localStorageMiddleware: Middleware<{}, any, Dispatch> = () break; } - case SET_BANNER_STATE: - await bannerCache.update(action.payload as Boolean) - break; - default: break; } diff --git a/src/app/services/actions/autocomplete-action-creators.spec.ts b/src/app/services/actions/autocomplete-action-creators.spec.ts index d8e97819bd..e9b932fafa 100644 --- a/src/app/services/actions/autocomplete-action-creators.spec.ts +++ b/src/app/services/actions/autocomplete-action-creators.spec.ts @@ -104,8 +104,7 @@ const mockState: ApplicationState = { error: null }, collections: [], - proxyUrl: '', - banner: {isVisible: true} + proxyUrl: '' } store.getState = () => ({ diff --git a/src/app/services/actions/permissions-action-creator.spec.ts b/src/app/services/actions/permissions-action-creator.spec.ts index f6bcb1b140..999336a6b6 100644 --- a/src/app/services/actions/permissions-action-creator.spec.ts +++ b/src/app/services/actions/permissions-action-creator.spec.ts @@ -125,8 +125,7 @@ const mockState: ApplicationState = { error: null }, collections: [], - proxyUrl: '', - banner: {isVisible: true} + proxyUrl: '' } const currentState = store.getState(); store.getState = () => { diff --git a/src/app/services/actions/resource-explorer-action-creators.spec.ts b/src/app/services/actions/resource-explorer-action-creators.spec.ts index c03eeaa96e..edba19e182 100644 --- a/src/app/services/actions/resource-explorer-action-creators.spec.ts +++ b/src/app/services/actions/resource-explorer-action-creators.spec.ts @@ -100,8 +100,7 @@ const mockState: ApplicationState = { error: null }, collections: [], - proxyUrl: '', - banner: {isVisible: true} + proxyUrl: '' } const paths = [ diff --git a/src/app/services/graph-constants.ts b/src/app/services/graph-constants.ts index 137f7dd2ca..fe6a94d699 100644 --- a/src/app/services/graph-constants.ts +++ b/src/app/services/graph-constants.ts @@ -33,4 +33,4 @@ export const ADMIN_CONSENT_DOC_LINK = 'https://learn.microsoft.com/en-us/graph/s 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 BANNER_IS_VISIBLE = 'isVisible'; \ No newline at end of file +export const BANNER_IS_VISIBLE = 'bannerIsVisible'; \ No newline at end of file diff --git a/src/app/services/reducers/index.ts b/src/app/services/reducers/index.ts index 9f7b77f1be..02beeb2b20 100644 --- a/src/app/services/reducers/index.ts +++ b/src/app/services/reducers/index.ts @@ -20,7 +20,6 @@ import snippets from '../slices/snippet.slice'; import themeChange from '../slices/theme.slice'; import termsOfUse from '../slices/terms-of-use.slice'; import sidebarProperties from '../slices/sidebar-properties.slice'; -import banner from '../slices/banner.slice'; const reducers = { auth, @@ -43,8 +42,7 @@ const reducers = { sidebarProperties, snippets, termsOfUse, - theme: themeChange, - banner + theme: themeChange }; export { diff --git a/src/app/services/slices/banner.slice.ts b/src/app/services/slices/banner.slice.ts deleted file mode 100644 index 150843a69e..0000000000 --- a/src/app/services/slices/banner.slice.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { createSlice, PayloadAction } from '@reduxjs/toolkit'; -import { Banner } from '../../../types/banner'; - -const initialState: Banner = { - isVisible: true -}; - -const bannerSlice = createSlice({ - name: 'banner', - initialState, - reducers: { - setBannerState: (state, action: PayloadAction) => { - state.isVisible = action.payload; - } - } -}); - -export const { setBannerState } = bannerSlice.actions; - -export default bannerSlice.reducer; diff --git a/src/app/views/common/banners/Notification.tsx b/src/app/views/common/banners/Notification.tsx index ed1b25966d..51715bc095 100644 --- a/src/app/views/common/banners/Notification.tsx +++ b/src/app/views/common/banners/Notification.tsx @@ -10,8 +10,7 @@ import { import { useNotificationStyles } from './Notification.styles'; import { translateMessage } from '../../../utils/translate-messages'; import { componentNames, telemetry } from '../../../../telemetry'; -import { useAppDispatch, useAppSelector } from '../../../../store'; -import { setBannerState } from '../../../services/slices/banner.slice'; +import { BANNER_IS_VISIBLE } from '../../../services/graph-constants'; interface NotificationProps { header: string; @@ -27,15 +26,13 @@ const handleOnClickLink = (e: React.MouseEvent)=>{ export const Notification: React.FunctionComponent = (props: NotificationProps) => { const styles = useNotificationStyles(); - const banner = useAppSelector(state=> state.banner); - console.log({banner}) - const dispatch = useAppDispatch() + const storageBanner = localStorage.getItem(BANNER_IS_VISIBLE); const handleDismiss = () => { - dispatch(setBannerState(false)) + localStorage.setItem(BANNER_IS_VISIBLE, 'false'); }; - if (!banner.isVisible) { + if (storageBanner === 'false') { return null; } diff --git a/src/index.tsx b/src/index.tsx index 7b8ac9a70e..db0ba7aca1 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -7,7 +7,7 @@ import { Provider } from 'react-redux'; import App from './app/views/App'; -import { BANNER_IS_VISIBLE, CURRENT_THEME } from './app/services/graph-constants'; +import { CURRENT_THEME } from './app/services/graph-constants'; import { getAuthTokenSuccess, getConsentedScopesSuccess } from './app/services/slices/auth.slice'; import { createCollection } from './app/services/slices/collections.slice'; import { setDevxApiUrl } from './app/services/slices/devxapi.slice'; @@ -33,8 +33,6 @@ import { IDevxAPI } from './types/devx-api'; import { Mode } from './types/enums'; import { IHistoryItem } from './types/history'; import { Collection } from './types/resources'; -import { setBannerState } from './app/services/slices/banner.slice'; -import { bannerCache } from './modules/cache/banner.cache'; const appRoot: HTMLElement = document.getElementById('root')!; @@ -232,15 +230,6 @@ window.onerror = (message, url, lineNumber, columnNumber, error) => { }); } -(async () => { - const bannerState = await bannerCache.read(); - console.log({bannerState}) - if(bannerState === null) { - appStore.dispatch(setBannerState(true)) - } -})() - - const Root = () => { return ( diff --git a/src/modules/cache/banner.cache.ts b/src/modules/cache/banner.cache.ts deleted file mode 100644 index 173ba02082..0000000000 --- a/src/modules/cache/banner.cache.ts +++ /dev/null @@ -1,20 +0,0 @@ -import localforage from 'localforage'; -import { BANNER_IS_VISIBLE } from '../../app/services/graph-constants'; - -const bannerStorage = localforage.createInstance({ - storeName: 'banner', - name: 'GE_V4' -}); - -export const bannerCache = (function () { - const get = async (): Promise =>{ - return await bannerStorage.getItem(BANNER_IS_VISIBLE) as Boolean - } - const read = async (): Promise =>{ - return await bannerStorage.getItem(BANNER_IS_VISIBLE) - } - const update = async (value: Boolean) =>{ - await bannerStorage.setItem(BANNER_IS_VISIBLE, value.toString()) - } - return { get,read, update} -})(); diff --git a/src/store/index.ts b/src/store/index.ts index d5a32129e9..e25f01967e 100644 --- a/src/store/index.ts +++ b/src/store/index.ts @@ -49,8 +49,7 @@ const initialState = { body: undefined, headers: undefined } - }, - banner: {isVisible: true} + } } export const store = configureStore({ diff --git a/src/types/banner.ts b/src/types/banner.ts deleted file mode 100644 index c4657fa5fd..0000000000 --- a/src/types/banner.ts +++ /dev/null @@ -1,3 +0,0 @@ -export interface Banner { - isVisible: boolean -} \ No newline at end of file From 0ec982343e2162ddf0c992e10660185f3b57c31a Mon Sep 17 00:00:00 2001 From: Musale Martin Date: Tue, 5 Nov 2024 19:31:49 +0300 Subject: [PATCH 14/24] Add the background and custom types --- .../common/banners/Notification.styles.ts | 23 ++++++---- src/app/views/common/banners/Notification.tsx | 4 +- src/app/views/common/banners/bgPolygons.svg | 46 +++++++++++++++++++ src/custom.d.ts | 5 ++ 4 files changed, 68 insertions(+), 10 deletions(-) create mode 100644 src/app/views/common/banners/bgPolygons.svg create mode 100644 src/custom.d.ts diff --git a/src/app/views/common/banners/Notification.styles.ts b/src/app/views/common/banners/Notification.styles.ts index a30265581c..4a919adc34 100644 --- a/src/app/views/common/banners/Notification.styles.ts +++ b/src/app/views/common/banners/Notification.styles.ts @@ -1,10 +1,15 @@ -import { mergeStyleSets } from '@fluentui/react'; +import { makeStyles } from '@fluentui/react-components'; +import polygons from './bgPolygons.svg' -export const useNotificationStyles = ()=>{ - return mergeStyleSets({ - container: { - padding: '8px', - marginBottom: '8px' - } - }) -} \ No newline at end of file +export const useNotificationStyles = makeStyles({ + container: { + padding: '8px', + marginBottom: '8px', + backgroundImage: `url(${polygons})`, + backgroundRepeat: 'no-repeat', + backgroundSize: 'contain', + backgroundPosition: 'right', + backgroundColor: '#E8EFFF' + } +} +) diff --git a/src/app/views/common/banners/Notification.tsx b/src/app/views/common/banners/Notification.tsx index 51715bc095..a4df4de442 100644 --- a/src/app/views/common/banners/Notification.tsx +++ b/src/app/views/common/banners/Notification.tsx @@ -10,7 +10,7 @@ import { import { useNotificationStyles } from './Notification.styles'; import { translateMessage } from '../../../utils/translate-messages'; import { componentNames, telemetry } from '../../../../telemetry'; -import { BANNER_IS_VISIBLE } from '../../../services/graph-constants'; +import { BANNER_IS_VISIBLE, CURRENT_THEME } from '../../../services/graph-constants'; interface NotificationProps { header: string; @@ -27,6 +27,8 @@ const handleOnClickLink = (e: React.MouseEvent)=>{ export const Notification: React.FunctionComponent = (props: NotificationProps) => { const styles = useNotificationStyles(); const storageBanner = localStorage.getItem(BANNER_IS_VISIBLE); + const theme = localStorage.getItem(CURRENT_THEME); + console.log(theme) const handleDismiss = () => { localStorage.setItem(BANNER_IS_VISIBLE, 'false'); diff --git a/src/app/views/common/banners/bgPolygons.svg b/src/app/views/common/banners/bgPolygons.svg new file mode 100644 index 0000000000..46b0df8819 --- /dev/null +++ b/src/app/views/common/banners/bgPolygons.svg @@ -0,0 +1,46 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/custom.d.ts b/src/custom.d.ts new file mode 100644 index 0000000000..eed6a3df67 --- /dev/null +++ b/src/custom.d.ts @@ -0,0 +1,5 @@ +// custom.d.ts +declare module '*.svg' { + const content: any; + export default content; +} From f630d655595a4d10aea2ab0214c02c24259ada5d Mon Sep 17 00:00:00 2001 From: Musale Martin Date: Wed, 6 Nov 2024 11:55:43 +0300 Subject: [PATCH 15/24] Fix theming and sizing of text in the body --- .../common/banners/Notification.styles.ts | 38 +++++++++++++------ src/app/views/common/banners/Notification.tsx | 10 ++--- 2 files changed, 32 insertions(+), 16 deletions(-) diff --git a/src/app/views/common/banners/Notification.styles.ts b/src/app/views/common/banners/Notification.styles.ts index 4a919adc34..08709d734c 100644 --- a/src/app/views/common/banners/Notification.styles.ts +++ b/src/app/views/common/banners/Notification.styles.ts @@ -1,15 +1,31 @@ import { makeStyles } from '@fluentui/react-components'; -import polygons from './bgPolygons.svg' +import polygons from './bgPolygons.svg'; export const useNotificationStyles = makeStyles({ - container: { - padding: '8px', - marginBottom: '8px', - backgroundImage: `url(${polygons})`, - backgroundRepeat: 'no-repeat', - backgroundSize: 'contain', - backgroundPosition: 'right', - backgroundColor: '#E8EFFF' + 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%' + } + } +}); diff --git a/src/app/views/common/banners/Notification.tsx b/src/app/views/common/banners/Notification.tsx index a4df4de442..70340d7698 100644 --- a/src/app/views/common/banners/Notification.tsx +++ b/src/app/views/common/banners/Notification.tsx @@ -10,7 +10,8 @@ import { import { useNotificationStyles } from './Notification.styles'; import { translateMessage } from '../../../utils/translate-messages'; import { componentNames, telemetry } from '../../../../telemetry'; -import { BANNER_IS_VISIBLE, CURRENT_THEME } from '../../../services/graph-constants'; +import { BANNER_IS_VISIBLE } from '../../../services/graph-constants'; +import { useAppSelector } from '../../../../store'; interface NotificationProps { header: string; @@ -27,8 +28,7 @@ const handleOnClickLink = (e: React.MouseEvent)=>{ export const Notification: React.FunctionComponent = (props: NotificationProps) => { const styles = useNotificationStyles(); const storageBanner = localStorage.getItem(BANNER_IS_VISIBLE); - const theme = localStorage.getItem(CURRENT_THEME); - console.log(theme) + const theme = useAppSelector(s => s.theme) const handleDismiss = () => { localStorage.setItem(BANNER_IS_VISIBLE, 'false'); @@ -39,8 +39,8 @@ export const Notification: React.FunctionComponent = (props: } return ( - - + + {props.header}

{props.content}{' '} Date: Wed, 6 Nov 2024 12:17:49 +0300 Subject: [PATCH 16/24] Handle dismissing of the banner --- src/app/views/common/banners/Notification.tsx | 23 +++++++++++-------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/src/app/views/common/banners/Notification.tsx b/src/app/views/common/banners/Notification.tsx index 70340d7698..1b4025d779 100644 --- a/src/app/views/common/banners/Notification.tsx +++ b/src/app/views/common/banners/Notification.tsx @@ -1,17 +1,18 @@ -import { DismissRegular, OpenRegular } from '@fluentui/react-icons'; import { + Button, + Link, MessageBar, MessageBarActions, - MessageBarTitle, MessageBarBody, - Button, - Link - } from '@fluentui/react-components'; -import { useNotificationStyles } from './Notification.styles'; -import { translateMessage } from '../../../utils/translate-messages'; + 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 { useAppSelector } from '../../../../store'; +import { translateMessage } from '../../../utils/translate-messages'; +import { useNotificationStyles } from './Notification.styles'; interface NotificationProps { header: string; @@ -28,13 +29,15 @@ const handleOnClickLink = (e: React.MouseEvent)=>{ export const Notification: React.FunctionComponent = (props: NotificationProps) => { const styles = useNotificationStyles(); const storageBanner = localStorage.getItem(BANNER_IS_VISIBLE); - const theme = useAppSelector(s => s.theme) + 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 (storageBanner === 'false') { + if (!isVisible) { return null; } From 460aacdce18a2a56a3615a5b6ec3e57dc9ea854d Mon Sep 17 00:00:00 2001 From: Musale Martin Date: Wed, 6 Nov 2024 12:20:25 +0300 Subject: [PATCH 17/24] Lock the v9 packages version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 864f83881d..4ed0723437 100644 --- a/package.json +++ b/package.json @@ -9,7 +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-components": "9.55.1", "@fluentui/react-icons-mdl2": "1.3.63", "@microsoft/applicationinsights-react-js": "17.3.1", "@microsoft/applicationinsights-web": "3.3.1", From b90a2aa60ae75a758b41752a6626e9113d2039c8 Mon Sep 17 00:00:00 2001 From: Musale Martin Date: Mon, 18 Nov 2024 12:49:35 +0300 Subject: [PATCH 18/24] Update the banner notification link --- src/messages/GE.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/messages/GE.json b/src/messages/GE.json index f39e3d6e5f..4571412964 100644 --- a/src/messages/GE.json +++ b/src/messages/GE.json @@ -502,6 +502,6 @@ "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", + "Banner notification 1 link": "https://learn.microsoft.com/graph/graph-explorer/graph-explorer-overview?view=graph-rest-1.0", "Dismiss banner": "Dismiss banner" } \ No newline at end of file From 8e4824f1bb6292f692ef25c660bde2936fe9c6a7 Mon Sep 17 00:00:00 2001 From: Musale Martin Date: Mon, 18 Nov 2024 15:58:37 +0300 Subject: [PATCH 19/24] Enhance type safety for trackReactComponent method --- src/telemetry/telemetry.ts | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/src/telemetry/telemetry.ts b/src/telemetry/telemetry.ts index 454bb615f5..cad0cd7cc7 100644 --- a/src/telemetry/telemetry.ts +++ b/src/telemetry/telemetry.ts @@ -9,9 +9,15 @@ import { } from '@microsoft/applicationinsights-web'; import { ComponentType } from 'react'; -import '../app/utils/string-operations'; +import variantService from '../app/services/variant-service'; +import { + getBrowserScreenSize, + getDeviceScreenScale +} from '../app/utils/device-characteristics-telemetry'; import { validateExternalLink } from '../app/utils/external-link-validation'; import { sanitizeQueryUrl } from '../app/utils/query-url-sanitization'; +import '../app/utils/string-operations'; +import { getVersion } from '../app/utils/version'; import { IQuery } from '../types/query-runner'; import { BUTTON_CLICK_EVENT, @@ -22,22 +28,16 @@ import { import { addCommonTelemetryItemProperties, filterRemoteDependencyData, + filterResizeObserverExceptions, filterTelemetryTypes, - sanitizeTelemetryItemUriProperty, - filterResizeObserverExceptions + sanitizeTelemetryItemUriProperty } from './filters'; import ITelemetry from './ITelemetry'; -import { getVersion } from '../app/utils/version'; -import { - getBrowserScreenSize, - getDeviceScreenScale -} from '../app/utils/device-characteristics-telemetry'; -import variantService from '../app/services/variant-service'; class Telemetry implements ITelemetry { private appInsights: ApplicationInsights; private config: any; - private reactPlugin: any; + private reactPlugin: ReactPlugin; constructor() { this.reactPlugin = new ReactPlugin(); @@ -81,10 +81,10 @@ class Telemetry implements ITelemetry { this.appInsights.trackException({ error, severityLevel, properties }); } - public trackReactComponent( - ComponentToTrack: ComponentType, + public trackReactComponent( + ComponentToTrack: ComponentType, componentName?: string - ): ComponentType { + ): ComponentType { return withAITracking(this.reactPlugin, ComponentToTrack, componentName); } From 7244c754adc7bdd0f607c556b6cdaccdccb03a11 Mon Sep 17 00:00:00 2001 From: Musale Martin Date: Mon, 18 Nov 2024 15:59:10 +0300 Subject: [PATCH 20/24] Add telemetry tracking for Notification component --- src/app/views/common/banners/Notification.tsx | 86 ++++++++++--------- src/telemetry/component-names.ts | 3 + 2 files changed, 47 insertions(+), 42 deletions(-) diff --git a/src/app/views/common/banners/Notification.tsx b/src/app/views/common/banners/Notification.tsx index 1b4025d779..58ecd54803 100644 --- a/src/app/views/common/banners/Notification.tsx +++ b/src/app/views/common/banners/Notification.tsx @@ -1,10 +1,10 @@ import { - Button, - Link, - MessageBar, - MessageBarActions, - MessageBarBody, - MessageBarTitle + Button, + Link, + MessageBar, + MessageBarActions, + MessageBarBody, + MessageBarTitle } from '@fluentui/react-components'; import { DismissRegular, OpenRegular } from '@fluentui/react-icons'; import { useState } from 'react'; @@ -22,45 +22,47 @@ interface NotificationProps { } const handleOnClickLink = (e: React.MouseEvent)=>{ - telemetry.trackLinkClickEvent( - (e.currentTarget as HTMLAnchorElement).href, componentNames.GRAPH_EXPLORER_TUTORIAL_LINK) + telemetry.trackLinkClickEvent( + (e.currentTarget as HTMLAnchorElement).href, componentNames.GRAPH_EXPLORER_TUTORIAL_LINK) } -export const Notification: React.FunctionComponent = (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 Notification: React.FunctionComponent = (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); - }; + const handleDismiss = () => { + localStorage.setItem(BANNER_IS_VISIBLE, 'false'); + setIsVisible(false); + }; - if (!isVisible) { - return null; - } + if (!isVisible) { + return null; + } - return ( - - - {props.header}

- {props.content}{' '} - {props.linkText} -
- } - /> - } - /> -
- ); + return ( + + + {props.header}

+ {props.content}{' '} + {props.linkText} +
+ } + /> + } + /> +
+ ); }; + +export default telemetry.trackReactComponent(Notification, componentNames.NOTIFICATION_COMPONENT) \ No newline at end of file diff --git a/src/telemetry/component-names.ts b/src/telemetry/component-names.ts index 6e94626cd7..34a44e36e5 100644 --- a/src/telemetry/component-names.ts +++ b/src/telemetry/component-names.ts @@ -109,3 +109,6 @@ export const GET_ADAPTIVE_CARD_ACTION = 'Get adaptive card action'; export const FETCH_PERMISSIONS_ACTION = 'Fetch permissions action'; export const MONACO_EDITOR_FORMAT_JSON_ACTION = 'Monaco editor format JSON action'; export const LAUNCH_FEEDBACK_POPUP_ACTION = 'Launch feedback popup action'; + +// Component names +export const NOTIFICATION_COMPONENT = 'Notification' \ No newline at end of file From fa8fd1ca2f6ef292d2a147e1c5961c11e401b7a1 Mon Sep 17 00:00:00 2001 From: Musale Martin Date: Mon, 18 Nov 2024 15:59:17 +0300 Subject: [PATCH 21/24] Refactor Notification import and update App component structure --- src/app/views/App.tsx | 186 +++++++++++++------------- src/app/views/common/banners/index.ts | 4 +- 2 files changed, 95 insertions(+), 95 deletions(-) diff --git a/src/app/views/App.tsx b/src/app/views/App.tsx index d0341e10d0..91ca490b72 100644 --- a/src/app/views/App.tsx +++ b/src/app/views/App.tsx @@ -1,9 +1,9 @@ import { Announced, getTheme, ITheme, styled } from '@fluentui/react'; +import { FluentProvider, teamsHighContrastTheme, Theme, webDarkTheme, webLightTheme } from '@fluentui/react-components'; 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'; @@ -31,6 +31,7 @@ import { TermsOfUseMessage } from './app-sections'; import { headerMessaging } from './app-sections/HeaderMessaging'; import { appStyles } from './App.styles'; import { classNames } from './classnames'; +import Notification from './common/banners/Notification'; import { KeyboardCopyEvent } from './common/copy-button/KeyboardCopyEvent'; import { StatusMessages } from './common/lazy-loader/component-registry'; import PopupsWrapper from './common/popups/PopupsWrapper'; @@ -40,7 +41,6 @@ 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; @@ -415,102 +415,102 @@ class App extends Component { return ( // @ts-ignore - - -
- - -
- {graphExplorerMode === Mode.Complete && ( - { - if (ref?.style?.width) { - this.resizeSideBar(ref.style.width); - } - }} - className={`ms-Grid-col ms-sm12 ms-md4 ms-lg4 ${sidebarWidth} resizable-sidebar`} - minWidth={'71'} - maxWidth={maxWidth} - enable={{ - right: true - }} - handleClasses={{ - right: classes.vResizeHandle - }} - bounds={'parent'} - size={{ - width: sideWidth, - height: '' - }} - > - - - )} - {graphExplorerMode === Mode.TryIt && + + +
+ + +
+ {graphExplorerMode === Mode.Complete && ( + { + if (ref?.style?.width) { + this.resizeSideBar(ref.style.width); + } + }} + className={`ms-Grid-col ms-sm12 ms-md4 ms-lg4 ${sidebarWidth} resizable-sidebar`} + minWidth={'71'} + maxWidth={maxWidth} + enable={{ + right: true + }} + handleClasses={{ + right: classes.vResizeHandle + }} + bounds={'parent'} + size={{ + width: sideWidth, + height: '' + }} + > + + + )} + {graphExplorerMode === Mode.TryIt && headerMessaging(query)} - {displayContent && ( - -
- -
- -
- -
-
-
- -
- + }} + > +
+
- - - )} -
-
- + +
+ +
+
+
+ +
+ +
+
+ + )} +
+
+ +
-
- -
-
+ + + ); } diff --git a/src/app/views/common/banners/index.ts b/src/app/views/common/banners/index.ts index 96c3f6514b..d28e098539 100644 --- a/src/app/views/common/banners/index.ts +++ b/src/app/views/common/banners/index.ts @@ -1,5 +1,5 @@ -import { Notification } from './Notification' +import Notification from './Notification' export default { - Notification + Notification } \ No newline at end of file From 03eae389aa62864cc7562a5af3147e58a40d6a96 Mon Sep 17 00:00:00 2001 From: Musale Martin Date: Mon, 18 Nov 2024 16:05:13 +0300 Subject: [PATCH 22/24] Add telemetry tracking for notification dismiss button --- src/app/views/common/banners/Notification.tsx | 5 ++++- src/telemetry/component-names.ts | 1 + src/telemetry/telemetry.ts | 2 +- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/app/views/common/banners/Notification.tsx b/src/app/views/common/banners/Notification.tsx index 58ecd54803..5f031ed8c5 100644 --- a/src/app/views/common/banners/Notification.tsx +++ b/src/app/views/common/banners/Notification.tsx @@ -9,7 +9,7 @@ import { import { DismissRegular, OpenRegular } from '@fluentui/react-icons'; import { useState } from 'react'; import { useAppSelector } from '../../../../store'; -import { componentNames, telemetry } from '../../../../telemetry'; +import { componentNames, eventTypes, telemetry } from '../../../../telemetry'; import { BANNER_IS_VISIBLE } from '../../../services/graph-constants'; import { translateMessage } from '../../../utils/translate-messages'; import { useNotificationStyles } from './Notification.styles'; @@ -33,6 +33,9 @@ const Notification: React.FunctionComponent = (props: Notific const theme = useAppSelector(s => s.theme); const handleDismiss = () => { + telemetry.trackEvent(eventTypes.BUTTON_CLICK_EVENT, { + ComponentName: componentNames.NOTIFICATION_BANNER_DISMISS_BUTTON + }); localStorage.setItem(BANNER_IS_VISIBLE, 'false'); setIsVisible(false); }; diff --git a/src/telemetry/component-names.ts b/src/telemetry/component-names.ts index 34a44e36e5..679c9b32fa 100644 --- a/src/telemetry/component-names.ts +++ b/src/telemetry/component-names.ts @@ -26,6 +26,7 @@ export const SIGN_IN_BUTTON = 'Sign in button'; export const SIGN_IN_WITH_OTHER_ACCOUNT_BUTTON = 'Sign in with other account button'; export const REVOKE_PERMISSION_CONSENT_BUTTON = 'Revoke consent to permissions button' export const FILTER_PERMISSIONS_BUTTON = 'Filter permissions button'; +export const NOTIFICATION_BANNER_DISMISS_BUTTON = 'Notification banner dismiss button' // List items export const HISTORY_LIST_ITEM = 'History list item'; diff --git a/src/telemetry/telemetry.ts b/src/telemetry/telemetry.ts index cad0cd7cc7..1fb1eac832 100644 --- a/src/telemetry/telemetry.ts +++ b/src/telemetry/telemetry.ts @@ -136,7 +136,7 @@ class Telemetry implements ITelemetry { }; } - private getInstrumentationKey() { + private getInstrumentationKey(): string { return ( (window as any).InstrumentationKey || process.env.REACT_APP_INSTRUMENTATION_KEY || From a5c5af4e3a506e4e43084b88b9a3d98129cb4f2a Mon Sep 17 00:00:00 2001 From: Musale Martin Date: Mon, 2 Dec 2024 15:31:46 +0300 Subject: [PATCH 23/24] fix: correct typo in notification link text --- src/app/views/App.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/views/App.tsx b/src/app/views/App.tsx index abff26745b..ba1757a673 100644 --- a/src/app/views/App.tsx +++ b/src/app/views/App.tsx @@ -485,7 +485,7 @@ class App extends Component {
From 565004d4032db7535ce1d11693275bbc45084d2f Mon Sep 17 00:00:00 2001 From: Musale Martin Date: Mon, 2 Dec 2024 16:12:28 +0300 Subject: [PATCH 24/24] fix: type in notification message --- src/messages/GE.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/messages/GE.json b/src/messages/GE.json index 8298c6ab8f..a2587b5c0c 100644 --- a/src/messages/GE.json +++ b/src/messages/GE.json @@ -510,7 +510,7 @@ "More request area items": "More request 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 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 tenant to explore capabilities.", "Banner notification 1 link text": "Follow a step-by-step tutorial", "Banner notification 1 link": "https://learn.microsoft.com/graph/graph-explorer/graph-explorer-overview?view=graph-rest-1.0", "Dismiss banner": "Dismiss banner",