o365 calendar sync (#8044)
Implemented: * Account Connect * Calendar sync via delta ids then requesting single events I think I would split the messaging part into a second pr - that's a step more complex then the calendar :) --------- Co-authored-by: bosiraphael <raphael.bosi@gmail.com>
This commit is contained in:
@ -1,7 +1,7 @@
|
||||
import { InformationBanner } from '@/information-banner/components/InformationBanner';
|
||||
import { useAccountToReconnect } from '@/information-banner/hooks/useAccountToReconnect';
|
||||
import { InformationBannerKeys } from '@/information-banner/types/InformationBannerKeys';
|
||||
import { useTriggerGoogleApisOAuth } from '@/settings/accounts/hooks/useTriggerGoogleApisOAuth';
|
||||
import { useTriggerApisOAuth } from '@/settings/accounts/hooks/useTriggerApiOAuth';
|
||||
import { IconRefresh } from 'twenty-ui';
|
||||
|
||||
export const InformationBannerReconnectAccountEmailAliases = () => {
|
||||
@ -9,7 +9,7 @@ export const InformationBannerReconnectAccountEmailAliases = () => {
|
||||
InformationBannerKeys.ACCOUNTS_TO_RECONNECT_EMAIL_ALIASES,
|
||||
);
|
||||
|
||||
const { triggerGoogleApisOAuth } = useTriggerGoogleApisOAuth();
|
||||
const { triggerApisOAuth } = useTriggerApisOAuth();
|
||||
|
||||
if (!accountToReconnect) {
|
||||
return null;
|
||||
@ -20,7 +20,7 @@ export const InformationBannerReconnectAccountEmailAliases = () => {
|
||||
message={`Please reconnect your mailbox ${accountToReconnect?.handle} to update your email aliases:`}
|
||||
buttonTitle="Reconnect"
|
||||
buttonIcon={IconRefresh}
|
||||
buttonOnClick={() => triggerGoogleApisOAuth()}
|
||||
buttonOnClick={() => triggerApisOAuth(accountToReconnect.provider)}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import { InformationBanner } from '@/information-banner/components/InformationBanner';
|
||||
import { useAccountToReconnect } from '@/information-banner/hooks/useAccountToReconnect';
|
||||
import { InformationBannerKeys } from '@/information-banner/types/InformationBannerKeys';
|
||||
import { useTriggerGoogleApisOAuth } from '@/settings/accounts/hooks/useTriggerGoogleApisOAuth';
|
||||
import { useTriggerApisOAuth } from '@/settings/accounts/hooks/useTriggerApiOAuth';
|
||||
import { IconRefresh } from 'twenty-ui';
|
||||
|
||||
export const InformationBannerReconnectAccountInsufficientPermissions = () => {
|
||||
@ -9,7 +9,7 @@ export const InformationBannerReconnectAccountInsufficientPermissions = () => {
|
||||
InformationBannerKeys.ACCOUNTS_TO_RECONNECT_INSUFFICIENT_PERMISSIONS,
|
||||
);
|
||||
|
||||
const { triggerGoogleApisOAuth } = useTriggerGoogleApisOAuth();
|
||||
const { triggerApisOAuth } = useTriggerApisOAuth();
|
||||
|
||||
if (!accountToReconnect) {
|
||||
return null;
|
||||
@ -21,7 +21,7 @@ export const InformationBannerReconnectAccountInsufficientPermissions = () => {
|
||||
reconnect for updates:`}
|
||||
buttonTitle="Reconnect"
|
||||
buttonIcon={IconRefresh}
|
||||
buttonOnClick={() => triggerGoogleApisOAuth()}
|
||||
buttonOnClick={() => triggerApisOAuth(accountToReconnect.provider)}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { IconGoogle } from 'twenty-ui';
|
||||
import { IconComponent, IconGoogle, IconMicrosoft } from 'twenty-ui';
|
||||
|
||||
import { ConnectedAccount } from '@/accounts/types/ConnectedAccount';
|
||||
import { SettingsAccountsListEmptyStateCard } from '@/settings/accounts/components/SettingsAccountsListEmptyStateCard';
|
||||
@ -9,6 +9,11 @@ import { SettingsPath } from '@/types/SettingsPath';
|
||||
import { SettingsAccountsConnectedAccountsRowRightContainer } from '@/settings/accounts/components/SettingsAccountsConnectedAccountsRowRightContainer';
|
||||
import { SettingsListCard } from '../../components/SettingsListCard';
|
||||
|
||||
const ProviderIcons: { [k: string]: IconComponent } = {
|
||||
google: IconGoogle,
|
||||
microsoft: IconMicrosoft,
|
||||
};
|
||||
|
||||
export const SettingsAccountsConnectedAccountsListCard = ({
|
||||
accounts,
|
||||
loading,
|
||||
@ -27,7 +32,7 @@ export const SettingsAccountsConnectedAccountsListCard = ({
|
||||
items={accounts}
|
||||
getItemLabel={(account) => account.handle}
|
||||
isLoading={loading}
|
||||
RowIcon={IconGoogle}
|
||||
RowIconFn={(row) => ProviderIcons[row.provider]}
|
||||
RowRightComponent={({ item: account }) => (
|
||||
<SettingsAccountsConnectedAccountsRowRightContainer account={account} />
|
||||
)}
|
||||
|
||||
@ -1,7 +1,14 @@
|
||||
import { useTriggerApisOAuth } from '@/settings/accounts/hooks/useTriggerApiOAuth';
|
||||
import { useIsFeatureEnabled } from '@/workspace/hooks/useIsFeatureEnabled';
|
||||
import styled from '@emotion/styled';
|
||||
import { Button, Card, CardContent, CardHeader, IconGoogle } from 'twenty-ui';
|
||||
|
||||
import { useTriggerGoogleApisOAuth } from '@/settings/accounts/hooks/useTriggerGoogleApisOAuth';
|
||||
import {
|
||||
Button,
|
||||
Card,
|
||||
CardContent,
|
||||
CardHeader,
|
||||
IconGoogle,
|
||||
IconMicrosoft,
|
||||
} from 'twenty-ui';
|
||||
|
||||
const StyledHeader = styled(CardHeader)`
|
||||
align-items: center;
|
||||
@ -12,6 +19,7 @@ const StyledHeader = styled(CardHeader)`
|
||||
const StyledBody = styled(CardContent)`
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
gap: ${({ theme }) => theme.spacing(2)};
|
||||
`;
|
||||
|
||||
type SettingsAccountsListEmptyStateCardProps = {
|
||||
@ -21,11 +29,10 @@ type SettingsAccountsListEmptyStateCardProps = {
|
||||
export const SettingsAccountsListEmptyStateCard = ({
|
||||
label,
|
||||
}: SettingsAccountsListEmptyStateCardProps) => {
|
||||
const { triggerGoogleApisOAuth } = useTriggerGoogleApisOAuth();
|
||||
|
||||
const handleOnClick = async () => {
|
||||
await triggerGoogleApisOAuth();
|
||||
};
|
||||
const { triggerApisOAuth } = useTriggerApisOAuth();
|
||||
const isMicrosoftSyncEnabled = useIsFeatureEnabled(
|
||||
'IS_MICROSOFT_SYNC_ENABLED',
|
||||
);
|
||||
|
||||
return (
|
||||
<Card>
|
||||
@ -35,8 +42,16 @@ export const SettingsAccountsListEmptyStateCard = ({
|
||||
Icon={IconGoogle}
|
||||
title="Connect with Google"
|
||||
variant="secondary"
|
||||
onClick={handleOnClick}
|
||||
onClick={() => triggerApisOAuth('google')}
|
||||
/>
|
||||
{isMicrosoftSyncEnabled && (
|
||||
<Button
|
||||
Icon={IconMicrosoft}
|
||||
title="Connect with Microsoft"
|
||||
variant="secondary"
|
||||
onClick={() => triggerApisOAuth('microsoft')}
|
||||
/>
|
||||
)}
|
||||
</StyledBody>
|
||||
</Card>
|
||||
);
|
||||
|
||||
@ -12,7 +12,7 @@ import {
|
||||
import { ConnectedAccount } from '@/accounts/types/ConnectedAccount';
|
||||
import { CoreObjectNameSingular } from '@/object-metadata/types/CoreObjectNameSingular';
|
||||
import { useDestroyOneRecord } from '@/object-record/hooks/useDestroyOneRecord';
|
||||
import { useTriggerGoogleApisOAuth } from '@/settings/accounts/hooks/useTriggerGoogleApisOAuth';
|
||||
import { useTriggerApisOAuth } from '@/settings/accounts/hooks/useTriggerApiOAuth';
|
||||
import { Dropdown } from '@/ui/layout/dropdown/components/Dropdown';
|
||||
import { DropdownMenu } from '@/ui/layout/dropdown/components/DropdownMenu';
|
||||
import { DropdownMenuItemsContainer } from '@/ui/layout/dropdown/components/DropdownMenuItemsContainer';
|
||||
@ -35,8 +35,7 @@ export const SettingsAccountsRowDropdownMenu = ({
|
||||
const { destroyOneRecord } = useDestroyOneRecord({
|
||||
objectNameSingular: CoreObjectNameSingular.ConnectedAccount,
|
||||
});
|
||||
|
||||
const { triggerGoogleApisOAuth } = useTriggerGoogleApisOAuth();
|
||||
const { triggerApisOAuth } = useTriggerApisOAuth();
|
||||
|
||||
return (
|
||||
<Dropdown
|
||||
@ -71,7 +70,7 @@ export const SettingsAccountsRowDropdownMenu = ({
|
||||
LeftIcon={IconRefresh}
|
||||
text="Reconnect"
|
||||
onClick={() => {
|
||||
triggerGoogleApisOAuth();
|
||||
triggerApisOAuth(account.provider);
|
||||
closeDropdown();
|
||||
}}
|
||||
/>
|
||||
|
||||
@ -8,21 +8,35 @@ import {
|
||||
useGenerateTransientTokenMutation,
|
||||
} from '~/generated/graphql';
|
||||
|
||||
export const useTriggerGoogleApisOAuth = () => {
|
||||
const getProviderUrl = (provider: string) => {
|
||||
switch (provider) {
|
||||
case 'google':
|
||||
return 'google-apis';
|
||||
case 'microsoft':
|
||||
return 'microsoft-apis';
|
||||
default:
|
||||
throw new Error(`Provider ${provider} is not supported`);
|
||||
}
|
||||
};
|
||||
|
||||
export const useTriggerApisOAuth = () => {
|
||||
const [generateTransientToken] = useGenerateTransientTokenMutation();
|
||||
|
||||
const triggerGoogleApisOAuth = useCallback(
|
||||
async ({
|
||||
redirectLocation,
|
||||
messageVisibility,
|
||||
calendarVisibility,
|
||||
loginHint,
|
||||
}: {
|
||||
redirectLocation?: AppPath | string;
|
||||
messageVisibility?: MessageChannelVisibility;
|
||||
calendarVisibility?: CalendarChannelVisibility;
|
||||
loginHint?: string;
|
||||
} = {}) => {
|
||||
const triggerApisOAuth = useCallback(
|
||||
async (
|
||||
provider: string,
|
||||
{
|
||||
redirectLocation,
|
||||
messageVisibility,
|
||||
calendarVisibility,
|
||||
loginHint,
|
||||
}: {
|
||||
redirectLocation?: AppPath | string;
|
||||
messageVisibility?: MessageChannelVisibility;
|
||||
calendarVisibility?: CalendarChannelVisibility;
|
||||
loginHint?: string;
|
||||
} = {},
|
||||
) => {
|
||||
const authServerUrl = REACT_APP_SERVER_BASE_URL;
|
||||
|
||||
const transientToken = await generateTransientToken();
|
||||
@ -46,10 +60,10 @@ export const useTriggerGoogleApisOAuth = () => {
|
||||
|
||||
params += loginHint ? `&loginHint=${loginHint}` : '';
|
||||
|
||||
window.location.href = `${authServerUrl}/auth/google-apis?${params}`;
|
||||
window.location.href = `${authServerUrl}/auth/${getProviderUrl(provider)}?${params}`;
|
||||
},
|
||||
[generateTransientToken],
|
||||
);
|
||||
|
||||
return { triggerGoogleApisOAuth };
|
||||
return { triggerApisOAuth };
|
||||
};
|
||||
@ -2,7 +2,7 @@ import { GMAIL_SEND_SCOPE } from '@/accounts/constants/GmailSendScope';
|
||||
import { ConnectedAccount } from '@/accounts/types/ConnectedAccount';
|
||||
import { currentWorkspaceMemberState } from '@/auth/states/currentWorkspaceMemberState';
|
||||
import { useFindManyRecords } from '@/object-record/hooks/useFindManyRecords';
|
||||
import { useTriggerGoogleApisOAuth } from '@/settings/accounts/hooks/useTriggerGoogleApisOAuth';
|
||||
import { useTriggerApisOAuth } from '@/settings/accounts/hooks/useTriggerApiOAuth';
|
||||
import { Select, SelectOption } from '@/ui/input/components/Select';
|
||||
import { WorkflowEditGenericFormBase } from '@/workflow/components/WorkflowEditGenericFormBase';
|
||||
import { VariableTagInput } from '@/workflow/search-variables/components/VariableTagInput';
|
||||
@ -38,7 +38,8 @@ export const WorkflowEditActionFormSendEmail = (
|
||||
) => {
|
||||
const theme = useTheme();
|
||||
const currentWorkspaceMember = useRecoilValue(currentWorkspaceMemberState);
|
||||
const { triggerGoogleApisOAuth } = useTriggerGoogleApisOAuth();
|
||||
const { triggerApisOAuth } = useTriggerApisOAuth();
|
||||
|
||||
const workflowId = useRecoilValue(workflowIdState);
|
||||
const redirectUrl = `/object/workflow/${workflowId}`;
|
||||
|
||||
@ -66,7 +67,7 @@ export const WorkflowEditActionFormSendEmail = (
|
||||
!isDefined(scopes) ||
|
||||
!isDefined(scopes.find((scope) => scope === GMAIL_SEND_SCOPE))
|
||||
) {
|
||||
await triggerGoogleApisOAuth({
|
||||
await triggerApisOAuth('google', {
|
||||
redirectLocation: redirectUrl,
|
||||
loginHint: connectedAccount.handle,
|
||||
});
|
||||
@ -183,7 +184,7 @@ export const WorkflowEditActionFormSendEmail = (
|
||||
options={connectedAccountOptions}
|
||||
callToActionButton={{
|
||||
onClick: () =>
|
||||
triggerGoogleApisOAuth({ redirectLocation: redirectUrl }),
|
||||
triggerApisOAuth('google', { redirectLocation: redirectUrl }),
|
||||
Icon: IconPlus,
|
||||
text: 'Add account',
|
||||
}}
|
||||
|
||||
@ -16,4 +16,5 @@ export type FeatureFlagKey =
|
||||
| 'IS_SSO_ENABLED'
|
||||
| 'IS_UNIQUE_INDEXES_ENABLED'
|
||||
| 'IS_ARRAY_AND_JSON_FILTER_ENABLED'
|
||||
| 'IS_MICROSOFT_SYNC_ENABLED'
|
||||
| 'IS_ADVANCED_FILTERS_ENABLED';
|
||||
|
||||
Reference in New Issue
Block a user