From e00d4dd6678253bbd74afe51ef2fd2a353ee3393 Mon Sep 17 00:00:00 2001 From: ayusht2810 Date: Tue, 12 Dec 2023 22:55:27 +0530 Subject: [PATCH 1/8] [MI-3835] Add logic to hide/show rhs on the presence of user in whitelist --- webapp/src/App.tsx | 41 +++++++++++++++++++++++++++++++++++++---- webapp/src/index.tsx | 28 ++++++---------------------- 2 files changed, 43 insertions(+), 26 deletions(-) diff --git a/webapp/src/App.tsx b/webapp/src/App.tsx index 4fbe1d38a..fa16fa1f9 100644 --- a/webapp/src/App.tsx +++ b/webapp/src/App.tsx @@ -1,23 +1,34 @@ import React, {useEffect} from 'react'; +import {Action, Store} from 'redux'; import {useDispatch} from 'react-redux'; -import usePluginApi from 'hooks/usePluginApi'; +// eslint-disable-next-line import/no-unresolved +import {PluginRegistry} from 'types/mattermost-webapp'; + +import {GlobalState} from 'mattermost-redux/types/store'; + +import {RhsTitle} from 'components'; -//global styles import {pluginApiServiceConfigs} from 'constants/apiService.constant'; +import {defaultPage, defaultPerPage, pluginTitle} from 'constants/common.constants'; +import {iconUrl} from 'constants/illustrations.constants'; + +import {Rhs} from 'containers'; + import useApiRequestCompletionState from 'hooks/useApiRequestCompletionState'; +import usePluginApi from 'hooks/usePluginApi'; import {setConnected} from 'reducers/connectedState'; -import {defaultPage, defaultPerPage} from 'constants/common.constants'; import {setIsRhsLoading} from 'reducers/spinner'; +// global styles import 'styles/main.scss'; /** * This is the main App component for the plugin * @returns {JSX.Element} */ -const App = (): JSX.Element => { +const App = ({registry, store}:{registry: PluginRegistry, store: Store>>}): JSX.Element => { const dispatch = useDispatch(); const {makeApiRequestWithCompletionStatus, getApiState} = usePluginApi(); @@ -35,6 +46,8 @@ const App = (): JSX.Element => { dispatch(setIsRhsLoading(isLoading)); }, [isLoading]); + const {data: whitelistUserData} = getApiState(pluginApiServiceConfigs.whitelistUser.apiServiceName); + useApiRequestCompletionState({ serviceName: pluginApiServiceConfigs.needsConnect.apiServiceName, handleSuccess: () => { @@ -43,6 +56,26 @@ const App = (): JSX.Element => { }, }); + useApiRequestCompletionState({ + serviceName: pluginApiServiceConfigs.whitelistUser.apiServiceName, + handleSuccess: () => { + const {presentInWhitelist} = whitelistUserData as WhitelistUserResponse; + if (presentInWhitelist) { + const {_, toggleRHSPlugin} = registry.registerRightHandSidebarComponent(Rhs, ); + registry.registerChannelHeaderButtonAction( + , () => store.dispatch(toggleRHSPlugin), null, pluginTitle); + if (registry.registerAppBarComponent) { + registry.registerAppBarComponent(iconUrl, () => store.dispatch(toggleRHSPlugin), pluginTitle); + } + } + }, + }); + return <>; }; diff --git a/webapp/src/index.tsx b/webapp/src/index.tsx index 229315380..60644fe32 100644 --- a/webapp/src/index.tsx +++ b/webapp/src/index.tsx @@ -9,14 +9,6 @@ import EnforceConnectedAccountModal from 'components/enforceConnectedAccountModa import MSTeamsAppManifestSetting from 'components/appManifestSetting'; import ListConnectedUsers from 'components/getConnectedUsersSetting'; -import {RhsTitle} from 'components'; - -import {Rhs} from 'containers'; - -import {pluginTitle} from 'constants/common.constants'; - -import {iconUrl} from 'constants/illustrations.constants'; - import {handleConnect, handleDisconnect} from 'websocket'; import manifest from './manifest'; @@ -30,26 +22,18 @@ export default class Plugin { // eslint-disable-next-line @typescript-eslint/no-unused-vars, @typescript-eslint/no-empty-function public async initialize(registry: PluginRegistry, store: Store>>) { registry.registerReducer(reducer); - registry.registerRootComponent(App); + registry.registerRootComponent(() => ( + + )); // @see https://developers.mattermost.com/extend/plugins/webapp/reference/ this.enforceConnectedAccountId = registry.registerRootComponent(EnforceConnectedAccountModal); registry.registerAdminConsoleCustomSetting('appManifestDownload', MSTeamsAppManifestSetting); registry.registerAdminConsoleCustomSetting('ConnectedUsersReportDownload', ListConnectedUsers); - const {_, toggleRHSPlugin} = registry.registerRightHandSidebarComponent(Rhs, ); - - // TODO: update icons later - registry.registerChannelHeaderButtonAction( - , () => store.dispatch(toggleRHSPlugin), null, pluginTitle); - - if (registry.registerAppBarComponent) { - registry.registerAppBarComponent(iconUrl, () => store.dispatch(toggleRHSPlugin), pluginTitle); - } registry.registerWebSocketEventHandler(`custom_${manifest.id}_connect`, handleConnect(store)); registry.registerWebSocketEventHandler(`custom_${manifest.id}_disconnect`, handleDisconnect(store)); From 81487003a2897f801827416827ecff375d7e616d Mon Sep 17 00:00:00 2001 From: ayusht2810 Date: Wed, 13 Dec 2023 12:04:32 +0530 Subject: [PATCH 2/8] [MI-3835] Add comments and remove extra imports --- webapp/src/App.tsx | 4 +--- webapp/src/index.tsx | 2 -- webapp/src/types/mattermost-webapp/index.d.ts | 2 +- 3 files changed, 2 insertions(+), 6 deletions(-) diff --git a/webapp/src/App.tsx b/webapp/src/App.tsx index fa16fa1f9..7eb481f67 100644 --- a/webapp/src/App.tsx +++ b/webapp/src/App.tsx @@ -2,9 +2,6 @@ import React, {useEffect} from 'react'; import {Action, Store} from 'redux'; import {useDispatch} from 'react-redux'; -// eslint-disable-next-line import/no-unresolved -import {PluginRegistry} from 'types/mattermost-webapp'; - import {GlobalState} from 'mattermost-redux/types/store'; import {RhsTitle} from 'components'; @@ -60,6 +57,7 @@ const App = ({registry, store}:{registry: PluginRegistry, store: Store { const {presentInWhitelist} = whitelistUserData as WhitelistUserResponse; + // Register the channel header button and app bar if the user is a whitelist user if (presentInWhitelist) { const {_, toggleRHSPlugin} = registry.registerRightHandSidebarComponent(Rhs, ); registry.registerChannelHeaderButtonAction( diff --git a/webapp/src/index.tsx b/webapp/src/index.tsx index 60644fe32..c68cb46e2 100644 --- a/webapp/src/index.tsx +++ b/webapp/src/index.tsx @@ -13,8 +13,6 @@ import {handleConnect, handleDisconnect} from 'websocket'; import manifest from './manifest'; -// eslint-disable-next-line import/no-unresolved -import {PluginRegistry} from './types/mattermost-webapp'; import App from './App'; export default class Plugin { diff --git a/webapp/src/types/mattermost-webapp/index.d.ts b/webapp/src/types/mattermost-webapp/index.d.ts index b87f23ba9..5af2c2143 100644 --- a/webapp/src/types/mattermost-webapp/index.d.ts +++ b/webapp/src/types/mattermost-webapp/index.d.ts @@ -1,4 +1,4 @@ -export interface PluginRegistry { +interface PluginRegistry { registerPostTypeComponent(typeName: string, component: React.ElementType) registerRootComponent(component: React.ElementType) registerAdminConsoleCustomSetting(key: string, component: React.ElementType) From bd45fc817d23f871c2a20fa9d468e54d1f2c662c Mon Sep 17 00:00:00 2001 From: ayusht2810 Date: Wed, 13 Dec 2023 12:07:04 +0530 Subject: [PATCH 3/8] [MI-3835] Fix lint error --- webapp/src/App.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/webapp/src/App.tsx b/webapp/src/App.tsx index 7eb481f67..64634d874 100644 --- a/webapp/src/App.tsx +++ b/webapp/src/App.tsx @@ -57,6 +57,7 @@ const App = ({registry, store}:{registry: PluginRegistry, store: Store { const {presentInWhitelist} = whitelistUserData as WhitelistUserResponse; + // Register the channel header button and app bar if the user is a whitelist user if (presentInWhitelist) { const {_, toggleRHSPlugin} = registry.registerRightHandSidebarComponent(Rhs, ); From 35cc5a0cafa43ed95c5b4c53295dbf9b7513861d Mon Sep 17 00:00:00 2001 From: ayusht2810 Date: Wed, 13 Dec 2023 16:01:19 +0530 Subject: [PATCH 4/8] [MI-3835] Minor line addition --- webapp/src/App.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/webapp/src/App.tsx b/webapp/src/App.tsx index 64634d874..62a9523c0 100644 --- a/webapp/src/App.tsx +++ b/webapp/src/App.tsx @@ -68,6 +68,7 @@ const App = ({registry, store}:{registry: PluginRegistry, store: Store, () => store.dispatch(toggleRHSPlugin), null, pluginTitle); + if (registry.registerAppBarComponent) { registry.registerAppBarComponent(iconUrl, () => store.dispatch(toggleRHSPlugin), pluginTitle); } From e3c7514a76558821d773cb1012ae58f9be65abd3 Mon Sep 17 00:00:00 2001 From: ayusht2810 Date: Thu, 14 Dec 2023 00:11:52 +0530 Subject: [PATCH 5/8] [MI-3835] Add logic to hide/show rhs on the basis of system console setting --- plugin.json | 6 + server/api.go | 14 +- server/api_test.go | 50 +-- server/configuration.go | 1 + webapp/src/App.tsx | 30 +- .../LinkedChannelCard.component.tsx | 30 +- .../RhsTitle/RhsTitle.component.tsx | 18 +- .../Snackbar/Snackbar.component.tsx | 40 +-- webapp/src/constants/apiService.constant.ts | 6 +- webapp/src/constants/common.constants.ts | 2 + webapp/src/containers/Rhs/Rhs.container.tsx | 14 +- .../ConnectAccount.container.tsx | 50 +-- .../ConnectedAccount.container.tsx | 72 ++-- .../LinkedChannels.container.tsx | 64 ++-- webapp/src/services/index.ts | 6 +- webapp/src/styles/_utils.scss | 318 +++++++++--------- webapp/src/types/common/index.d.ts | 4 +- webapp/src/types/common/service.d.ts | 2 +- webapp/src/types/common/store.d.ts | 4 + webapp/src/types/mattermost-webapp/index.d.ts | 1 + 20 files changed, 365 insertions(+), 367 deletions(-) diff --git a/plugin.json b/plugin.json index 539a1a67c..8c3c5eec5 100644 --- a/plugin.json +++ b/plugin.json @@ -171,6 +171,12 @@ "value": "UserPrincipalName" } ] + },{ + "key": "enableRhs", + "display_name": "Enable RHS", + "type": "bool", + "help_text": "When true, user will be able to view RHS (right hand sidebar).", + "default": false },{ "key": "appManifestDownload", "display_name": "Download Manifest", diff --git a/server/api.go b/server/api.go index 1876bd1b9..c34bafdf7 100644 --- a/server/api.go +++ b/server/api.go @@ -95,7 +95,7 @@ func NewAPI(p *Plugin, store store.Store) *API { router.HandleFunc("/oauth-redirect", api.oauthRedirectHandler).Methods(http.MethodGet) router.HandleFunc("/connected-users", api.getConnectedUsers).Methods(http.MethodGet) router.HandleFunc("/connected-users/download", api.getConnectedUsersFile).Methods(http.MethodGet) - router.HandleFunc("/whitelist-user", api.handleAuthRequired(api.whitelistUser)).Methods(http.MethodGet) + router.HandleFunc("/rhs-enabled", api.handleAuthRequired(api.rhsEnabled)).Methods(http.MethodGet) channelsRouter.HandleFunc("/link", api.handleAuthRequired(api.checkUserConnected(api.linkChannels))).Methods(http.MethodPost) channelsRouter.HandleFunc(fmt.Sprintf("/{%s}/unlink", PathParamChannelID), api.handleAuthRequired(api.unlinkChannels)).Methods(http.MethodDelete) @@ -892,17 +892,9 @@ func (a *API) getConnectedUsersFile(w http.ResponseWriter, r *http.Request) { } } -func (a *API) whitelistUser(w http.ResponseWriter, r *http.Request) { - userID := r.Header.Get(HeaderMattermostUserID) - presentInWhitelist, err := a.p.store.IsUserPresentInWhitelist(userID) - if err != nil { - a.p.API.LogError("Error in checking if a user is present in whitelist", "UserID", userID, "Error", err.Error()) - http.Error(w, "error in checking if a user is present in whitelist", http.StatusInternalServerError) - return - } - +func (a *API) rhsEnabled(w http.ResponseWriter, r *http.Request) { response := map[string]bool{ - "presentInWhitelist": presentInWhitelist, + "rhsEnabled": a.p.getConfiguration().EnableRHS, } w.Header().Set("Content-Type", "application/json") diff --git a/server/api_test.go b/server/api_test.go index e1d800698..5d55a95c8 100644 --- a/server/api_test.go +++ b/server/api_test.go @@ -1813,64 +1813,36 @@ func TestUnlinkChannels(t *testing.T) { } } -func TestWhitelistUser(t *testing.T) { +func TestRhsEnabled(t *testing.T) { for _, test := range []struct { Name string - SetupPlugin func(*plugintest.API) - SetupStore func(*storemocks.Store) - SetupMetrics func(*metricsmocks.Metrics) + SetupPlugin func(*Plugin) ExpectedResult string ExpectedStatusCode int }{ { - Name: "WhitelistUser: unable to check user in the whitelist", - SetupPlugin: func(api *plugintest.API) { - api.On("LogError", "Error in checking if a user is present in whitelist", "UserID", testutils.GetUserID(), "Error", "unable to check user in the whitelist").Times(1) - }, - SetupStore: func(store *storemocks.Store) { - store.On("IsUserPresentInWhitelist", testutils.GetUserID()).Return(false, errors.New("unable to check user in the whitelist")).Times(1) - }, - SetupMetrics: func(mockmetrics *metricsmocks.Metrics) { - mockmetrics.On("IncrementHTTPErrors").Times(1) + Name: "RhsEnabled: rhs is enabled", + SetupPlugin: func(p *Plugin) { + p.configuration.EnableRHS = true }, - ExpectedResult: "error in checking if a user is present in whitelist\n", - ExpectedStatusCode: http.StatusInternalServerError, - }, - { - Name: "WhitelistUser: user is not present in whitelist", - SetupPlugin: func(api *plugintest.API) {}, - SetupStore: func(store *storemocks.Store) { - store.On("IsUserPresentInWhitelist", testutils.GetUserID()).Return(false, nil).Times(1) - }, - SetupMetrics: func(mockmetrics *metricsmocks.Metrics) {}, - ExpectedResult: `{"presentInWhitelist":false}`, + ExpectedResult: `{"rhsEnabled":true}`, ExpectedStatusCode: http.StatusOK, }, { - Name: "WhitelistUser: user present in whitelist", - SetupPlugin: func(api *plugintest.API) {}, - SetupStore: func(store *storemocks.Store) { - store.On("IsUserPresentInWhitelist", testutils.GetUserID()).Return(true, nil).Times(1) - }, - SetupMetrics: func(mockmetrics *metricsmocks.Metrics) {}, - ExpectedResult: `{"presentInWhitelist":true}`, + Name: "RhsEnabled: rhs is not enabled", + SetupPlugin: func(p *Plugin) {}, + ExpectedResult: `{"rhsEnabled":false}`, ExpectedStatusCode: http.StatusOK, }, } { t.Run(test.Name, func(t *testing.T) { assert := assert.New(t) plugin := newTestPlugin(t) - mockAPI := &plugintest.API{} - plugin.SetAPI(mockAPI) - defer mockAPI.AssertExpectations(t) - - test.SetupPlugin(mockAPI) - test.SetupStore(plugin.store.(*storemocks.Store)) - test.SetupMetrics(plugin.metricsService.(*metricsmocks.Metrics)) + test.SetupPlugin(plugin) w := httptest.NewRecorder() - r := httptest.NewRequest(http.MethodGet, "/whitelist-user", nil) + r := httptest.NewRequest(http.MethodGet, "/rhs-enabled", nil) r.Header.Add(HeaderMattermostUserID, testutils.GetUserID()) plugin.ServeHTTP(nil, w, r) diff --git a/server/configuration.go b/server/configuration.go index 702775c51..1fb391bc2 100644 --- a/server/configuration.go +++ b/server/configuration.go @@ -41,6 +41,7 @@ type configuration struct { SyntheticUserAuthService string `json:"syntheticUserAuthService"` SyntheticUserAuthData string `json:"syntheticUserAuthData"` AutomaticallyPromoteSyntheticUsers bool `json:"automaticallyPromoteSyntheticUsers"` + EnableRHS bool `json:"enableRhs"` } func (c *configuration) ProcessConfiguration() { diff --git a/webapp/src/App.tsx b/webapp/src/App.tsx index 62a9523c0..12aa00b83 100644 --- a/webapp/src/App.tsx +++ b/webapp/src/App.tsx @@ -7,7 +7,7 @@ import {GlobalState} from 'mattermost-redux/types/store'; import {RhsTitle} from 'components'; import {pluginApiServiceConfigs} from 'constants/apiService.constant'; -import {defaultPage, defaultPerPage, pluginTitle} from 'constants/common.constants'; +import {defaultPage, defaultPerPage, pluginTitle, rhsButtonId} from 'constants/common.constants'; import {iconUrl} from 'constants/illustrations.constants'; import {Rhs} from 'containers'; @@ -28,11 +28,10 @@ import 'styles/main.scss'; const App = ({registry, store}:{registry: PluginRegistry, store: Store>>}): JSX.Element => { const dispatch = useDispatch(); const {makeApiRequestWithCompletionStatus, getApiState} = usePluginApi(); - useEffect(() => { const linkedChannelsParams: SearchLinkedChannelParams = {page: defaultPage, per_page: defaultPerPage}; - makeApiRequestWithCompletionStatus(pluginApiServiceConfigs.whitelistUser.apiServiceName); + makeApiRequestWithCompletionStatus(pluginApiServiceConfigs.rhsEnabled.apiServiceName); makeApiRequestWithCompletionStatus(pluginApiServiceConfigs.needsConnect.apiServiceName); makeApiRequestWithCompletionStatus(pluginApiServiceConfigs.getLinkedChannels.apiServiceName, linkedChannelsParams); }, []); @@ -43,7 +42,7 @@ const App = ({registry, store}:{registry: PluginRegistry, store: Store { - const {presentInWhitelist} = whitelistUserData as WhitelistUserResponse; + const {rhsEnabled} = rhsEnabledData as RhsEnabledResponse; + const rhsButtonData = localStorage.getItem(rhsButtonId); + if (rhsButtonData) { + const data = JSON.parse(rhsButtonData); + registry.unregisterComponent(data.headerId); + registry.unregisterComponent(data.appBarId); + localStorage.removeItem(rhsButtonId); + } - // Register the channel header button and app bar if the user is a whitelist user - if (presentInWhitelist) { + if (rhsEnabled) { + let appBarId; const {_, toggleRHSPlugin} = registry.registerRightHandSidebarComponent(Rhs, ); - registry.registerChannelHeaderButtonAction( + const headerId = registry.registerChannelHeaderButtonAction( , () => store.dispatch(toggleRHSPlugin), null, pluginTitle); if (registry.registerAppBarComponent) { - registry.registerAppBarComponent(iconUrl, () => store.dispatch(toggleRHSPlugin), pluginTitle); + appBarId = registry.registerAppBarComponent(iconUrl, () => store.dispatch(toggleRHSPlugin), pluginTitle); } + localStorage.setItem(rhsButtonId, JSON.stringify({ + headerId, + appBarId, + })); } }, }); diff --git a/webapp/src/components/LinkedChannelCard/LinkedChannelCard.component.tsx b/webapp/src/components/LinkedChannelCard/LinkedChannelCard.component.tsx index 5094c2661..1a2ae474c 100644 --- a/webapp/src/components/LinkedChannelCard/LinkedChannelCard.component.tsx +++ b/webapp/src/components/LinkedChannelCard/LinkedChannelCard.component.tsx @@ -7,21 +7,23 @@ import {LinkedChannelCardProps} from './LinkedChannelCard.types'; import './LinkedChannelCard.styles.scss'; export const LinkedChannelCard = ({msTeamsChannelName, msTeamsTeamName, mattermostChannelName, mattermostTeamName}: LinkedChannelCardProps) => ( -
-
- -
-
-
- {/* TODO: Update icon on basis of channel type */} - -
{mattermostChannelName}
-
{mattermostTeamName}
+
+
+
+
-
- -
{msTeamsChannelName}
-
{msTeamsTeamName}
+
+
+ {/* TODO: Update icon on basis of channel type */} + +
{mattermostChannelName}
+
{mattermostTeamName}
+
+
+ +
{msTeamsChannelName}
+
{msTeamsTeamName}
+
diff --git a/webapp/src/components/RhsTitle/RhsTitle.component.tsx b/webapp/src/components/RhsTitle/RhsTitle.component.tsx index 4901fb902..cfa6fffb8 100644 --- a/webapp/src/components/RhsTitle/RhsTitle.component.tsx +++ b/webapp/src/components/RhsTitle/RhsTitle.component.tsx @@ -4,12 +4,14 @@ import {iconUrl} from 'constants/illustrations.constants'; import {pluginTitle} from 'constants/common.constants'; export const RhsTitle = () => ( - - - {pluginTitle} - +
+ + + {pluginTitle} + +
); diff --git a/webapp/src/components/Snackbar/Snackbar.component.tsx b/webapp/src/components/Snackbar/Snackbar.component.tsx index a81ebc381..f4cf4a25e 100644 --- a/webapp/src/components/Snackbar/Snackbar.component.tsx +++ b/webapp/src/components/Snackbar/Snackbar.component.tsx @@ -47,26 +47,28 @@ export const Snackbar = () => { }; return ( -
-
- -
{message}
-
- +
+ +
{message}
+
+ +
); }; diff --git a/webapp/src/constants/apiService.constant.ts b/webapp/src/constants/apiService.constant.ts index e341b450f..7037676c0 100644 --- a/webapp/src/constants/apiService.constant.ts +++ b/webapp/src/constants/apiService.constant.ts @@ -10,10 +10,10 @@ export const pluginApiServiceConfigs: Record = { success: 'success', diff --git a/webapp/src/containers/Rhs/Rhs.container.tsx b/webapp/src/containers/Rhs/Rhs.container.tsx index 1f577d31c..c5b77bf91 100644 --- a/webapp/src/containers/Rhs/Rhs.container.tsx +++ b/webapp/src/containers/Rhs/Rhs.container.tsx @@ -22,11 +22,8 @@ export const Rhs = () => { const {isOpen} = getSnackbarState(state); - const {data} = getApiState(pluginApiServiceConfigs.whitelistUser.apiServiceName); const {data: linkedChannels} = getApiState(pluginApiServiceConfigs.getLinkedChannels.apiServiceName); - const {presentInWhitelist} = data as WhitelistUserResponse; - // NOTE: Commented out on purpose.This is part of Phase-II // const isAnyChannelLinked = useMemo(() => Boolean((linkedChannels as ChannelLinkData[])?.length), [linkedChannels]); const isAnyChannelLinked = false; @@ -34,8 +31,10 @@ export const Rhs = () => { const getRhsView = useCallback(() => { if (isRhsLoading) { return ( -
- +
+
+ +
); } @@ -57,10 +56,7 @@ export const Rhs = () => { return ( <> - { - presentInWhitelist ? - getRhsView() : 'MS Teams Sync plugin' - } + {getRhsView()} {isOpen && } ); diff --git a/webapp/src/containers/Rhs/views/ConnectAccount/ConnectAccount.container.tsx b/webapp/src/containers/Rhs/views/ConnectAccount/ConnectAccount.container.tsx index 8c56be765..1d097bc76 100644 --- a/webapp/src/containers/Rhs/views/ConnectAccount/ConnectAccount.container.tsx +++ b/webapp/src/containers/Rhs/views/ConnectAccount/ConnectAccount.container.tsx @@ -25,31 +25,33 @@ export const ConnectAccount = () => { }); return ( -
-
-
- -

{Constants.connectAccountMsg}

+
+
+
+
+ +

{Constants.connectAccountMsg}

+
+ +
+
+
+
{Constants.listTitle}
+
    + {Constants.connectAccountFeatures.map(({icon, text}) => ( +
  • + +
    {text}
    +
  • + )) } +
- -
-
-
-
{Constants.listTitle}
-
    - {Constants.connectAccountFeatures.map(({icon, text}) => ( -
  • - -
    {text}
    -
  • - )) } -
); diff --git a/webapp/src/containers/Rhs/views/ConnectedAccount/ConnectedAccount.container.tsx b/webapp/src/containers/Rhs/views/ConnectedAccount/ConnectedAccount.container.tsx index 99e9fb697..381fe3f18 100644 --- a/webapp/src/containers/Rhs/views/ConnectedAccount/ConnectedAccount.container.tsx +++ b/webapp/src/containers/Rhs/views/ConnectedAccount/ConnectedAccount.container.tsx @@ -57,47 +57,49 @@ export const ConnectedAccount = () => { }, [connected, isAlreadyConnected]); return ( -
-
- {/* TODO: Refactor user Avatar */} -
- +
+
+ {/* TODO: Refactor user Avatar */} +
+ > + +
+
+
{'Connected as '}{username}
+ +
-
-
{'Connected as '}{username}
- -
-
-
- {/* NOTE: Part of Phase-II */} - {/* +
+ {/* NOTE: Part of Phase-II */} + {/*

{'There are no linked channels yet'}

*/} +
+
-
); }; diff --git a/webapp/src/containers/Rhs/views/LinkedChannels/LinkedChannels.container.tsx b/webapp/src/containers/Rhs/views/LinkedChannels/LinkedChannels.container.tsx index 0e6b0e345..db1468f46 100644 --- a/webapp/src/containers/Rhs/views/LinkedChannels/LinkedChannels.container.tsx +++ b/webapp/src/containers/Rhs/views/LinkedChannels/LinkedChannels.container.tsx @@ -53,38 +53,40 @@ export const LinkedChannels = () => { ), [totalLinkedChannels]); return ( -
-
- -
-

{channelListTitle}

-
- } - endMessage={ -

- {noMoreChannelsText} -

- } - scrollableTarget='scrollableArea' +
+
+
+ +
+

{channelListTitle}

+
- {totalLinkedChannels.map(({msTeamsChannelID, ...rest}) => ( - - )) - } - + } + endMessage={ +

+ {noMoreChannelsText} +

+ } + scrollableTarget='scrollableArea' + > + {totalLinkedChannels.map(({msTeamsChannelID, ...rest}) => ( + + )) + } +
+
); diff --git a/webapp/src/services/index.ts b/webapp/src/services/index.ts index 47e2a0c9d..68530417d 100644 --- a/webapp/src/services/index.ts +++ b/webapp/src/services/index.ts @@ -30,10 +30,10 @@ export const msTeamsPluginApi = createApi({ method: pluginApiServiceConfigs.connect.method, }), }), - [pluginApiServiceConfigs.whitelistUser.apiServiceName]: builder.query({ + [pluginApiServiceConfigs.rhsEnabled.apiServiceName]: builder.query({ query: () => ({ - url: pluginApiServiceConfigs.whitelistUser.path, - method: pluginApiServiceConfigs.whitelistUser.method, + url: pluginApiServiceConfigs.rhsEnabled.path, + method: pluginApiServiceConfigs.rhsEnabled.method, }), }), [pluginApiServiceConfigs.getLinkedChannels.apiServiceName]: builder.query({ diff --git a/webapp/src/styles/_utils.scss b/webapp/src/styles/_utils.scss index a6dad31ca..1add83c65 100644 --- a/webapp/src/styles/_utils.scss +++ b/webapp/src/styles/_utils.scss @@ -1,217 +1,219 @@ -// display -@each $display in $display-styles { - .d-#{$display} { - display: $display !important; +.msteams-sync-utils { + // display + @each $display in $display-styles { + .d-#{$display} { + display: $display !important; + } } -} -// gap -@each $size in $sizes { - .gap-#{$size} { - gap: #{$size}px !important; + // gap + @each $size in $sizes { + .gap-#{$size} { + gap: #{$size}px !important; + } } -} -// font-weights -@each $font-weight in $font-weights { - .wt-#{$font-weight} { - font-weight: $font-weight !important; + // font-weights + @each $font-weight in $font-weights { + .wt-#{$font-weight} { + font-weight: $font-weight !important; + } } -} -// font sizes -@each $font-size in $font-sizes { - .font-#{$font-size} { - font-size: #{$font-size}px !important; + // font sizes + @each $font-size in $font-sizes { + .font-#{$font-size} { + font-size: #{$font-size}px !important; + } } -} -// border radius -@each $size in $sizes { - .rounded-#{$size} { - border-radius: #{$size}px !important; + // border radius + @each $size in $sizes { + .rounded-#{$size} { + border-radius: #{$size}px !important; + } } -} -// padding -@each $size in $sizes { - .p-#{$size} { - padding: #{$size}px !important; + // padding + @each $size in $sizes { + .p-#{$size} { + padding: #{$size}px !important; + } } -} -// margin -@each $size in $sizes { - .m-#{$size} { - margin: #{$size}px !important; + // margin + @each $size in $sizes { + .m-#{$size} { + margin: #{$size}px !important; + } } -} -// margin block -@each $size in $sizes { - .my-#{$size} { - margin-block: #{$size}px !important; + // margin block + @each $size in $sizes { + .my-#{$size} { + margin-block: #{$size}px !important; + } } -} -// padding block -@each $size in $sizes { - .py-#{$size} { - padding-block: #{$size}px !important; + // padding block + @each $size in $sizes { + .py-#{$size} { + padding-block: #{$size}px !important; + } } -} -// padding inline -@each $size in $sizes { - .px-#{$size} { - padding-inline: #{$size}px !important; + // padding inline + @each $size in $sizes { + .px-#{$size} { + padding-inline: #{$size}px !important; + } } -} -// line height -@each $line-height in $line-heights { - .lh-#{$line-height} { - line-height: #{$line-height}px !important; + // line height + @each $line-height in $line-heights { + .lh-#{$line-height} { + line-height: #{$line-height}px !important; + } } -} -// positions -@each $size in $sizes { - .top-#{$size} { - top: #{$size}px; - } + // positions + @each $size in $sizes { + .top-#{$size} { + top: #{$size}px; + } - .right-#{$size} { - right: #{$size}px; - } + .right-#{$size} { + right: #{$size}px; + } - .bottom-#{$size} { - bottom: #{$size}px; - } + .bottom-#{$size} { + bottom: #{$size}px; + } - .left-#{$size} { - left: #{$size}px; + .left-#{$size} { + left: #{$size}px; + } } -} -@each $position in $positions { - .#{$position} { - position: $position !important; + @each $position in $positions { + .#{$position} { + position: $position !important; + } } -} - -.mt-0 { - margin-top: 0; -} -.align-items-center { - align-items: center; -} + .mt-0 { + margin-top: 0; + } -.align-items-start { - align-items: flex-start; -} + .align-items-center { + align-items: center; + } -.align-items-end { - align-items: flex-end; -} + .align-items-start { + align-items: flex-start; + } -.justify-center { - justify-content: center; -} + .align-items-end { + align-items: flex-end; + } -.justify-start { - justify-content: flex-start; -} + .justify-center { + justify-content: center; + } -.justify-end { - justify-content: flex-end; -} + .justify-start { + justify-content: flex-start; + } -.justify-between { - justify-content: space-between; -} + .justify-end { + justify-content: flex-end; + } -.flex-1 { - flex: 1 -} + .justify-between { + justify-content: space-between; + } -.flex-2 { - flex: 2 -} + .flex-1 { + flex: 1 + } -.flex-1-0-0 { - flex: 1 0 0; -} + .flex-2 { + flex: 2 + } -.flex-column { - flex-direction: column; -} + .flex-1-0-0 { + flex: 1 0 0; + } -.w-full { - width: 100% -} + .flex-column { + flex-direction: column; + } -.h-full { - height: 100%; -} + .w-full { + width: 100% + } -.text-center { - text-align: center; -} + .h-full { + height: 100%; + } -.overflow-y-auto { - overflow-y: auto; -} + .text-center { + text-align: center; + } -.border-t-1 { - border-top-width: 1px; - border-top-style: solid; - border-top-color: rgba(var(--center-channel-color-rgb), 0.12); -} + .overflow-y-auto { + overflow-y: auto; + } -.border-y-1 { - border-block-width: 1px; - border-block-style: solid; - border-block-color: rgba(var(--center-channel-color-rgb), 0.12); -} + .border-t-1 { + border-top-width: 1px; + border-top-style: solid; + border-top-color: rgba(var(--center-channel-color-rgb), 0.12); + } -.opacity-6 { - opacity: 0.6; -} + .border-y-1 { + border-block-width: 1px; + border-block-style: solid; + border-block-color: rgba(var(--center-channel-color-rgb), 0.12); + } -.text-white { - color: var(--button-color) -} + .opacity-6 { + opacity: 0.6; + } -.icon-white { - & path, & rect, & circle { - fill: var(--button-color), + .text-white { + color: var(--button-color) } -} -.icon-16 { - height: 16px; - width: 16px; + .icon-white { + & path, & rect, & circle { + fill: var(--button-color), + } + } - svg { + .icon-16 { height: 16px; width: 16px; + + svg { + height: 16px; + width: 16px; + } } -} -.elevation-2 { - box-shadow: var(--elevation-2); -} + .elevation-2 { + box-shadow: var(--elevation-2); + } -.bg-success { - background-color: var(--online-indicator); -} + .bg-success { + background-color: var(--online-indicator); + } -.bg-default { - background-color: var(--center-channel-color); -} + .bg-default { + background-color: var(--center-channel-color); + } -.bg-error { - background-color: var(--error-text); + .bg-error { + background-color: var(--error-text); + } } diff --git a/webapp/src/types/common/index.d.ts b/webapp/src/types/common/index.d.ts index 6d62d3bb7..d7e200dcd 100644 --- a/webapp/src/types/common/index.d.ts +++ b/webapp/src/types/common/index.d.ts @@ -15,8 +15,8 @@ type WebsocketEventParams = { data: Record, } -type WhitelistUserResponse= { - presentInWhitelist: boolean +type RhsEnabledResponse= { + rhsEnabled: boolean } type ChannelLinkData = { diff --git a/webapp/src/types/common/service.d.ts b/webapp/src/types/common/service.d.ts index 50313008f..9c1db5846 100644 --- a/webapp/src/types/common/service.d.ts +++ b/webapp/src/types/common/service.d.ts @@ -1,6 +1,6 @@ type HttpMethod = 'GET' | 'POST' | 'PATCH' | 'DELETE'; -type PluginApiServiceName = 'needsConnect' | 'connect' | 'whitelistUser' | 'getLinkedChannels' | 'disconnectUser' ; +type PluginApiServiceName = 'needsConnect' | 'connect' | 'rhsEnabled' | 'getLinkedChannels' | 'disconnectUser' ; type PluginApiService = { path: string, diff --git a/webapp/src/types/common/store.d.ts b/webapp/src/types/common/store.d.ts index 624e752a2..7188c4854 100644 --- a/webapp/src/types/common/store.d.ts +++ b/webapp/src/types/common/store.d.ts @@ -24,6 +24,10 @@ type ConnectedState = { msteamsUserId: string; }; +type CanSeeRhsState = { + canSeeRhs: boolean; +} + type NeedsConnectState = { needsConnect: boolean; }; diff --git a/webapp/src/types/mattermost-webapp/index.d.ts b/webapp/src/types/mattermost-webapp/index.d.ts index 5af2c2143..7ff95ef58 100644 --- a/webapp/src/types/mattermost-webapp/index.d.ts +++ b/webapp/src/types/mattermost-webapp/index.d.ts @@ -7,6 +7,7 @@ interface PluginRegistry { registerAppBarComponent(iconUrl: string, action: () => void, tooltipText: string) registerReducer(reducer) registerWebSocketEventHandler(event: string, handler: (msg: WebsocketEventParams) => void) + unregisterComponent(id: string) // Add more if needed from https://developers.mattermost.com/extend/plugins/webapp/reference } From 4887646b817669a75a4e4f4d2482773a1fc59a81 Mon Sep 17 00:00:00 2001 From: ayusht2810 Date: Thu, 14 Dec 2023 00:28:05 +0530 Subject: [PATCH 6/8] [MI-3835] Fix ci --- server/api.go | 2 +- .../LinkedChannelCard.test.tsx.snap | 352 +++++++------- .../__snapshots__/RhsTitle.test.tsx.snap | 32 +- .../src/components/Snackbar/Snackbar.test.tsx | 2 +- .../__snapshots__/Snackbar.test.tsx.snap | 116 ++--- .../Rhs/__snapshots__/Rhs.test.tsx.snap | 292 ++++++------ .../ConnectAccount.test.tsx.snap | 446 +++++++++--------- .../ConnectedAccount.test.tsx.snap | 112 +++-- .../LinkedChannels.test.tsx.snap | 174 +++---- 9 files changed, 796 insertions(+), 732 deletions(-) diff --git a/server/api.go b/server/api.go index c34bafdf7..9cf229ccd 100644 --- a/server/api.go +++ b/server/api.go @@ -892,7 +892,7 @@ func (a *API) getConnectedUsersFile(w http.ResponseWriter, r *http.Request) { } } -func (a *API) rhsEnabled(w http.ResponseWriter, r *http.Request) { +func (a *API) rhsEnabled(w http.ResponseWriter, _ *http.Request) { response := map[string]bool{ "rhsEnabled": a.p.getConfiguration().EnableRHS, } diff --git a/webapp/src/components/LinkedChannelCard/__snapshots__/LinkedChannelCard.test.tsx.snap b/webapp/src/components/LinkedChannelCard/__snapshots__/LinkedChannelCard.test.tsx.snap index c6d510982..adee45fc5 100644 --- a/webapp/src/components/LinkedChannelCard/__snapshots__/LinkedChannelCard.test.tsx.snap +++ b/webapp/src/components/LinkedChannelCard/__snapshots__/LinkedChannelCard.test.tsx.snap @@ -5,6 +5,186 @@ exports[`Linked Channel Card component Should render correctly 1`] = ` "asFragment": [Function], "baseElement":
+
+
+ +
+
+ + + + + +
+ mockMattermostChannelName +
+
+ mockMattermostTeamName +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + +
+ mockMSTeamsChannelName +
+
+ mockMSTeamsTeamName +
+
+
+
+
+
+ , + "container":
+
@@ -176,178 +356,6 @@ exports[`Linked Channel Card component Should render correctly 1`] = `
- , - "container":
-
- -
-
- - - - - -
- mockMattermostChannelName -
-
- mockMattermostTeamName -
-
-
- - - - - - - - - - - - - - - - - - - - - - - -
- mockMSTeamsChannelName -
-
- mockMSTeamsTeamName -
-
-
-
, "debug": [Function], "findAllByAltText": [Function], diff --git a/webapp/src/components/RhsTitle/__snapshots__/RhsTitle.test.tsx.snap b/webapp/src/components/RhsTitle/__snapshots__/RhsTitle.test.tsx.snap index 2776cf02e..8886b0151 100644 --- a/webapp/src/components/RhsTitle/__snapshots__/RhsTitle.test.tsx.snap +++ b/webapp/src/components/RhsTitle/__snapshots__/RhsTitle.test.tsx.snap @@ -5,6 +5,26 @@ exports[`Rhs Title component Should render correctly 1`] = ` "asFragment": [Function], "baseElement":
+
+ + + Microsoft Teams Sync + +
+
+ , + "container":
+
@@ -16,18 +36,6 @@ exports[`Rhs Title component Should render correctly 1`] = ` Microsoft Teams Sync
- , - "container":
- - - Microsoft Teams Sync -
, "debug": [Function], "findAllByAltText": [Function], diff --git a/webapp/src/components/Snackbar/Snackbar.test.tsx b/webapp/src/components/Snackbar/Snackbar.test.tsx index 98dcbb958..a04e3a545 100644 --- a/webapp/src/components/Snackbar/Snackbar.test.tsx +++ b/webapp/src/components/Snackbar/Snackbar.test.tsx @@ -19,7 +19,7 @@ describe('Snackbar component', () => { }); it('Should show correct type', () => { - expect(tree.container.firstChild).toHaveClass('bg-error'); + expect(tree.container.firstChild?.firstChild).toHaveClass('bg-error'); }); it('Should show correct message', () => { diff --git a/webapp/src/components/Snackbar/__snapshots__/Snackbar.test.tsx.snap b/webapp/src/components/Snackbar/__snapshots__/Snackbar.test.tsx.snap index db02da2cf..63e0a3737 100644 --- a/webapp/src/components/Snackbar/__snapshots__/Snackbar.test.tsx.snap +++ b/webapp/src/components/Snackbar/__snapshots__/Snackbar.test.tsx.snap @@ -5,6 +5,68 @@ exports[`Snackbar component Should render correctly 1`] = ` "asFragment": [Function], "baseElement":
+
+
+
+ + + + + +
+ mockMessage +
+
+ +
+
+
+ , + "container":
+
@@ -58,60 +120,6 @@ exports[`Snackbar component Should render correctly 1`] = `
- , - "container":
-
-
- - - - - -
- mockMessage -
-
- -
, "debug": [Function], "findAllByAltText": [Function], diff --git a/webapp/src/containers/Rhs/__snapshots__/Rhs.test.tsx.snap b/webapp/src/containers/Rhs/__snapshots__/Rhs.test.tsx.snap index 12b3103d8..cf9e7c2ae 100644 --- a/webapp/src/containers/Rhs/__snapshots__/Rhs.test.tsx.snap +++ b/webapp/src/containers/Rhs/__snapshots__/Rhs.test.tsx.snap @@ -11,93 +11,101 @@ exports[`RHS view Should render correctly 1`] = ` aria-hidden="true" >
- -
-
-
- Connected as - +
+
+
- John Doe - -
- + Connected as + + John Doe + + + +
+
-
- - - - - -
- mockMessage -
-
-
+ + + + + + +
, "debug": [Function], diff --git a/webapp/src/containers/Rhs/views/ConnectAccount/__snapshots__/ConnectAccount.test.tsx.snap b/webapp/src/containers/Rhs/views/ConnectAccount/__snapshots__/ConnectAccount.test.tsx.snap index d279a8b83..69d96fcac 100644 --- a/webapp/src/containers/Rhs/views/ConnectAccount/__snapshots__/ConnectAccount.test.tsx.snap +++ b/webapp/src/containers/Rhs/views/ConnectAccount/__snapshots__/ConnectAccount.test.tsx.snap @@ -5,6 +5,233 @@ exports[`Connect Account View Should render correctly 1`] = ` "asFragment": [Function], "baseElement":
+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

+ Connect your Microsoft Teams account +

+
+ +
+
+
+
+ With your connected Microsoft Teams account, you will be able to: +
+
    +
  • + + + + + +
    + Send and receive direct and group messages with your colleagues on Microsoft Teams +
    +
  • +
  • + + + + + +
    + Send and receive messages in channels that are linked between the two platforms. +
    +
  • +
+
+
+
+
+ , + "container":
+
@@ -223,225 +450,6 @@ exports[`Connect Account View Should render correctly 1`] = `
- , - "container":
-
-
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

- Connect your Microsoft Teams account -

-
- -
-
-
-
- With your connected Microsoft Teams account, you will be able to: -
-
    -
  • - - - - - -
    - Send and receive direct and group messages with your colleagues on Microsoft Teams -
    -
  • -
  • - - - - - -
    - Send and receive messages in channels that are linked between the two platforms. -
    -
  • -
-
-
, "debug": [Function], "findAllByAltText": [Function], diff --git a/webapp/src/containers/Rhs/views/ConnectedAccount/__snapshots__/ConnectedAccount.test.tsx.snap b/webapp/src/containers/Rhs/views/ConnectedAccount/__snapshots__/ConnectedAccount.test.tsx.snap index 119814b5d..3412d0def 100644 --- a/webapp/src/containers/Rhs/views/ConnectedAccount/__snapshots__/ConnectedAccount.test.tsx.snap +++ b/webapp/src/containers/Rhs/views/ConnectedAccount/__snapshots__/ConnectedAccount.test.tsx.snap @@ -11,41 +11,45 @@ exports[`Connected Account View Should render correctly 1`] = ` aria-hidden="true" >
- -
-
-
- Connected as - +
+
+
- John Doe - -
- + Connected as + + John Doe + + + +
+
-