Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[MI-3837]: Integrate webhooks and enhancements #47

Merged
merged 3 commits into from
Dec 15, 2023
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import {getCurrentTeam, getLinkModalState} from 'selectors';

import {pluginApiServiceConfigs} from 'constants/apiService.constant';
import useApiRequestCompletionState from 'hooks/useApiRequestCompletionState';
import {setLinkModalLoading, showLinkModal} from 'reducers/linkModal';
import {hideLinkModal, preserveState, resetState, setLinkModalLoading, showLinkModal} from 'reducers/linkModal';
import useAlert from 'hooks/useAlert';

import {refetch} from 'reducers/refetchState';
Expand All @@ -23,7 +23,7 @@ import {SearchMSChannels} from './SearchMSChannels';
import {SearchMSTeams} from './SearchMSTeams';
import {SearchMMChannels} from './SearchMMChannels';

export const LinkChannelModal = ({onClose}: {onClose: () => void}) => {
export const LinkChannelModal = () => {
const dispatch = useDispatch();
const showAlert = useAlert();
const {state, makeApiRequestWithCompletionStatus} = usePluginApi();
Expand All @@ -35,13 +35,16 @@ export const LinkChannelModal = ({onClose}: {onClose: () => void}) => {
const [msChannel, setMSChannel] = useState<MSTeamOrChannel | null>(null);
const [linkChannelsPayload, setLinkChannelsPayload] = useState<LinkChannelsPayload | null>(null);

const handleModalClose = (preserveFields?: boolean) => {
if (!preserveFields) {
// console.log(mMChannel, mSChannel, mSTeam);

const handleModalClose = (preserve?: boolean) => {
if (!preserve) {
setMMChannel(null);
setMSTeam(null);
setMSChannel(null);
}
onClose();
dispatch(resetState());
dispatch(hideLinkModal());
};

const handleChannelLinking = () => {
Expand Down Expand Up @@ -91,10 +94,11 @@ export const LinkChannelModal = ({onClose}: {onClose: () => void}) => {
subtitle='Link a channel in Mattermost with a channel in Microsoft Teams'
primaryActionText='Link Channels'
secondaryActionText='Cancel'
onFooterCloseHandler={() => handleModalClose(true)}
onHeaderCloseHandler={() => handleModalClose(true)}
onFooterCloseHandler={handleModalClose}
onHeaderCloseHandler={handleModalClose}
isPrimaryButtonDisabled={!mmChannel || !msChannel || !msTeam}
onSubmitHandler={handleChannelLinking}
backdrop={true}
>
{isLoading && <LinearProgress className='fixed w-full left-0 top-100'/>}
<SearchMMChannels
Expand All @@ -110,11 +114,17 @@ export const LinkChannelModal = ({onClose}: {onClose: () => void}) => {
</Modal>
<DialogComponent
onSubmitHandler={() => {
dispatch(preserveState({
mmChannel: mmChannel?.displayName ?? '',
msChannel: msChannel?.DisplayName ?? '',
msTeam: msTeam?.DisplayName ?? '',
}));
dispatch(showLinkModal());
hideDialog();
}}
onCloseHandler={() => {
hideDialog();
dispatch(resetState());
}}
/>
</>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import {debounceFunctionTimeLimit} from 'constants/common.constants';
import {setLinkModalLoading} from 'reducers/linkModal';

import usePluginApi from 'hooks/usePluginApi';
import {getCurrentTeam} from 'selectors';
import {getCurrentTeam, getLinkModalState} from 'selectors';

import {SearchMMChannelProps} from './SearchMMChannels.types';

Expand All @@ -29,12 +29,16 @@ export const SearchMMChannels = ({
const {state} = usePluginApi();
const [searchTerm, setSearchTerm] = useState<string>('');
const {teams} = getCurrentTeam(state);
const {mmChannel} = getLinkModalState(state);

const [searchSuggestions, setSearchSuggestions] = useState<ListItemType[]>([]);
const [suggestionsLoading, setSuggestionsLoading] = useState<boolean>(false);

useEffect(() => {
handleClearInput();
if (!mmChannel) {
handleClearInput();
}
setSearchTerm(mmChannel);
}, [teamId]);

const searchChannels = ({searchFor}: {searchFor?: string}) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,17 +12,25 @@ import useApiRequestCompletionState from 'hooks/useApiRequestCompletionState';

import {setLinkModalLoading} from 'reducers/linkModal';

import {Icon} from 'components/Icon';

import {getLinkModalState} from 'selectors';

import {SearchMSChannelProps} from './SearchMSChannels.types';

export const SearchMSChannels = ({setChannel, teamId}: SearchMSChannelProps) => {
const dispatch = useDispatch();
const {makeApiRequestWithCompletionStatus, getApiState} = usePluginApi();
const {makeApiRequestWithCompletionStatus, getApiState, state} = usePluginApi();
const {msChannel} = getLinkModalState(state);
const [searchTerm, setSearchTerm] = useState<string>('');
const [searchChannelsPayload, setSearchChannelsPayload] = useState<SearchMSChannelsParams | null>(null);
const [searchSuggestions, setSearchSuggestions] = useState<ListItemType[]>([]);

useEffect(() => {
handleClearInput();
if (!msChannel || !teamId) {
handleClearInput();
}
setSearchTerm(msChannel);
}, [teamId]);

const searchChannels = ({searchFor}: {searchFor?: string}) => {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, {useCallback, useState} from 'react';
import React, {useCallback, useEffect, useState} from 'react';

import {ListItemType, MMSearch} from '@brightscout/mattermost-ui-library';

Expand All @@ -11,14 +11,20 @@ import useApiRequestCompletionState from 'hooks/useApiRequestCompletionState';
import usePluginApi from 'hooks/usePluginApi';
import utils from 'utils';
import {setLinkModalLoading} from 'reducers/linkModal';
import {getLinkModalState} from 'selectors';

export const SearchMSTeams = ({setMSTeam}: {setMSTeam: React.Dispatch<React.SetStateAction<MSTeamOrChannel | null>>}) => {
const dispatch = useDispatch();
const {makeApiRequestWithCompletionStatus, getApiState} = usePluginApi();
const {makeApiRequestWithCompletionStatus, getApiState, state} = usePluginApi();
const [searchTerm, setSearchTerm] = useState<string>('');
const {msTeam} = getLinkModalState(state);
const [searchTeamsPayload, setSearchTeamsPayload] = useState<SearchParams | null>(null);
const [searchSuggestions, setSearchSuggestions] = useState<ListItemType[]>([]);

useEffect(() => {
setSearchTerm(msTeam);
}, []);

const searchTeams = ({searchFor}: {searchFor?: string}) => {
if (searchFor) {
const payload = {
Expand Down
23 changes: 4 additions & 19 deletions webapp/src/containers/Rhs/Rhs.container.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,12 @@ import {setConnected} from 'reducers/connectedState';
import utils from 'utils';

import './Rhs.styles.scss';
import {hideLinkModal, showLinkModal} from 'reducers/linkModal';
import {showLinkModal} from 'reducers/linkModal';
import {resetRefetch} from 'reducers/refetchState';

export const Rhs = () => {
const {makeApiRequestWithCompletionStatus, getApiState, state} = usePluginApi();
const {Avatar} = window.Components;

// state variables
const [totalLinkedChannels, setTotalLinkedChannels] = useState<ChannelLinkData[]>([]);
Expand Down Expand Up @@ -209,23 +210,7 @@ export const Rhs = () => {
<div className='msteams-sync-rhs flex-1 d-flex flex-column'>
{connected ? (
<div className='py-12 px-20 border-y-1 d-flex gap-8'>
{/* TODO: Refactor user Avatar */}
<div
style={{
height: '32px',
width: '32px',
borderRadius: '50%',
backgroundColor: 'rgba(var(--center-channel-color-rgb), 0.12)',
}}
>
<img
style={{
borderRadius: '50%',
}}
src={utils.getAvatarUrl(msteamsUserId)}
/>
</div>

<Avatar url={utils.getAvatarUrl(msteamsUserId)}/>
<div>
<h5 className='my-0 font-12 lh-16'>{'Connected as '}<span className='wt-600'>{username}</span></h5>
<Button
Expand Down Expand Up @@ -343,7 +328,7 @@ export const Rhs = () => {
getRhsView() : 'MS Teams Sync plugin'
}
{isOpen && <Snackbar/>}
{<LinkChannelModal onClose={() => dispatch(hideLinkModal())}/>}
{<LinkChannelModal/>}
</>
);
};
10 changes: 7 additions & 3 deletions webapp/src/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,15 @@ import EnforceConnectedAccountModal from 'components/enforceConnectedAccountModa
import MSTeamsAppManifestSetting from 'components/appManifestSetting';
import ListConnectedUsers from 'components/getConnectedUsersSetting';

import {RhsTitle} from 'components';
import {LinkChannelModal, 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 {handleConnect, handleDisconnect, handleLink, handleModalLink} from 'websocket';

import manifest from './manifest';

Expand All @@ -31,6 +31,7 @@ export default class Plugin {
public async initialize(registry: PluginRegistry, store: Store<GlobalState, Action<Record<string, unknown>>>) {
registry.registerReducer(reducer);
registry.registerRootComponent(App);
registry.registerRootComponent(LinkChannelModal);

// @see https://developers.mattermost.com/extend/plugins/webapp/reference/
this.enforceConnectedAccountId = registry.registerRootComponent(EnforceConnectedAccountModal);
Expand All @@ -53,12 +54,15 @@ export default class Plugin {

registry.registerWebSocketEventHandler(`custom_${manifest.id}_connect`, handleConnect(store));
registry.registerWebSocketEventHandler(`custom_${manifest.id}_disconnect`, handleDisconnect(store));
registry.registerWebSocketEventHandler(`custom_${manifest.id}_link_channels`, handleModalLink(store));
registry.registerWebSocketEventHandler(`custom_${manifest.id}_link`, handleLink(store));
}
}

declare global {
interface Window {
registerPlugin(id: string, plugin: Plugin): void,
registerPlugin(id: string, plugin: Plugin): void;
Components: any;
}
}

Expand Down
19 changes: 17 additions & 2 deletions webapp/src/reducers/linkModal/index.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
import {PayloadAction, createSlice} from '@reduxjs/toolkit';

import {DialogState, ModalState} from 'types/common/store.d';
import {ModalState} from 'types/common/store.d';

const initialState: ModalState = {
show: false,
isLoading: false,
mmChannel: '',
msChannel: '',
msTeam: '',
};

export const linkModalSlice = createSlice({
Expand All @@ -20,9 +23,21 @@ export const linkModalSlice = createSlice({
setLinkModalLoading: (state, {payload}: PayloadAction<boolean>) => {
state.isLoading = payload;
},
preserveState: (state, {payload}: PayloadAction<Pick<ModalState, 'mmChannel' | 'msChannel' | 'msTeam'>>) => {
state.mmChannel = payload.mmChannel;
state.msChannel = payload.msChannel;
state.msTeam = payload.msTeam;
},
resetState: (state) => {
state.show = false;
state.isLoading = false;
state.mmChannel = '';
state.msChannel = '';
state.msTeam = '';
},
},
});

export const {showLinkModal, hideLinkModal, setLinkModalLoading} = linkModalSlice.actions;
export const {showLinkModal, hideLinkModal, setLinkModalLoading, preserveState, resetState} = linkModalSlice.actions;

export default linkModalSlice.reducer;
6 changes: 4 additions & 2 deletions webapp/src/types/common/store.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@ import {BaseQueryFn, FetchArgs, FetchBaseQueryError, FetchBaseQueryMeta} from '@

import {GlobalState} from 'mattermost-redux/types/store';

import {DialogProps} from '@brightscout/mattermost-ui-library';

import {DialogProps, ListItemType} from '@brightscout/mattermost-ui-library';
import {ModalProps} from '@brightscout/mattermost-ui-library/build/components/Modal';

import {SnackbarColor} from 'components/Snackbar/Snackbar.types';
Expand Down Expand Up @@ -50,6 +49,9 @@ type AppDialogs = {
type ModalState = {
show?: boolean;
isLoading?: boolean;
mmChannel: string;
msTeam: string;
msChannel: string;
}

type RefetchState = {
Expand Down
14 changes: 14 additions & 0 deletions webapp/src/websocket/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ import {Action, Store} from 'redux';
import {GlobalState} from 'mattermost-redux/types/store';

import {setConnected} from 'reducers/connectedState';
import {showLinkModal} from 'reducers/linkModal';
import {refetch} from 'reducers/refetchState';

export function handleConnect(store: Store<GlobalState, Action<Record<string, unknown>>>) {
return (msg: WebsocketEventParams) => {
Expand All @@ -17,3 +19,15 @@ export function handleDisconnect(store: Store<GlobalState, Action<Record<string,
store.dispatch(setConnected({connected: false, username: '', msteamsUserId: '', isAlreadyConnected: false}) as Action);
};
}

export function handleModalLink(store: Store<GlobalState, Action<Record<string, unknown>>>) {
return (_: WebsocketEventParams) => {
store.dispatch(showLinkModal() as Action);
};
}

export function handleLink(store: Store<GlobalState, Action<Record<string, unknown>>>) {
return (_: WebsocketEventParams) => {
store.dispatch(refetch() as Action);
};
}
4 changes: 4 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
# yarn lockfile v1