Polish GCal UI texting (#4244)
# What this PR does
Polish GCal UI texting
## Which issue(s) this PR closes
-
## Checklist
- [ ] Unit, integration, and e2e (if applicable) tests updated
- [ ] Documentation added (or `pr:no public docs` PR label added if not
required)
- [ ] Added the relevant release notes label (see labels prefixed w/
`release:`). These labels dictate how your PR will
show up in the autogenerated release notes.
---------
Co-authored-by: Joey Orlando <joey.orlando@grafana.com>
This commit is contained in:
parent
c8b37c7ad2
commit
baef4e2642
2 changed files with 132 additions and 102 deletions
|
|
@ -1,8 +1,9 @@
|
|||
import React, { useEffect, useState } from 'react';
|
||||
|
||||
import { css } from '@emotion/css';
|
||||
import { Button, HorizontalGroup, Icon, Switch, VerticalGroup, useStyles2 } from '@grafana/ui';
|
||||
import { Button, HorizontalGroup, Switch, VerticalGroup, useStyles2 } from '@grafana/ui';
|
||||
import { observer } from 'mobx-react';
|
||||
import { getUtilStyles } from 'styles/utils.styles';
|
||||
|
||||
import { Block } from 'components/GBlock/Block';
|
||||
import { Text } from 'components/Text/Text';
|
||||
|
|
@ -15,23 +16,20 @@ import { UserHelper } from 'models/user/user.helpers';
|
|||
import { ApiSchemas } from 'network/oncall-api/api.types';
|
||||
import { useStore } from 'state/useStore';
|
||||
import { UserActions } from 'utils/authorization/authorization';
|
||||
import { DOCS_ROOT } from 'utils/consts';
|
||||
|
||||
const GoogleCalendar: React.FC<{ id: ApiSchemas['User']['pk'] }> = observer(({ id }) => {
|
||||
const { userStore, scheduleStore } = useStore();
|
||||
|
||||
const styles = useStyles2(getStyles);
|
||||
const utils = useStyles2(getUtilStyles);
|
||||
|
||||
const [googleCalendarSettings, setGoogleCalendarSettings] =
|
||||
useState<ApiSchemas['User']['google_calendar_settings']>();
|
||||
const [showSchedulesDropdown, setShowSchedulesDropdown] = useState<boolean>();
|
||||
|
||||
const user = userStore.items[id];
|
||||
|
||||
useEffect(() => {
|
||||
(async () => {
|
||||
const user = await userStore.fetchItemById({ userPk: id });
|
||||
setGoogleCalendarSettings(user.google_calendar_settings);
|
||||
setShowSchedulesDropdown(user.google_calendar_settings.oncall_schedules_to_consider_for_shift_swaps?.length > 0);
|
||||
})();
|
||||
}, []);
|
||||
setShowSchedulesDropdown(user.google_calendar_settings?.oncall_schedules_to_consider_for_shift_swaps?.length > 0);
|
||||
}, [user]);
|
||||
|
||||
const handleShowSchedulesDropdownChange = (event: React.ChangeEvent<HTMLInputElement>) => {
|
||||
const value = event.target.checked;
|
||||
|
|
@ -43,111 +41,142 @@ const GoogleCalendar: React.FC<{ id: ApiSchemas['User']['pk'] }> = observer(({ i
|
|||
};
|
||||
|
||||
const handleSchedulesChange = (value) => {
|
||||
setGoogleCalendarSettings((v) => ({ ...v, oncall_schedules_to_consider_for_shift_swaps: value }));
|
||||
|
||||
userStore.updateCurrentUser({
|
||||
google_calendar_settings: { ...googleCalendarSettings, oncall_schedules_to_consider_for_shift_swaps: value },
|
||||
userStore.updateUser({
|
||||
pk: id,
|
||||
google_calendar_settings: {
|
||||
...user.google_calendar_settings,
|
||||
oncall_schedules_to_consider_for_shift_swaps: value,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
const user = userStore.items[id];
|
||||
|
||||
return (
|
||||
<VerticalGroup>
|
||||
<Block bordered className={styles.root}>
|
||||
<VerticalGroup spacing="lg">
|
||||
{user.has_google_oauth2_connected ? (
|
||||
<VerticalGroup>
|
||||
<HorizontalGroup justify="space-between">
|
||||
<HorizontalGroup>
|
||||
<GoogleCalendarLogo width={32} height={32} />
|
||||
<Text>Google calendar is connected</Text>
|
||||
</HorizontalGroup>
|
||||
<WithPermissionControlTooltip userAction={UserActions.UserSettingsWrite}>
|
||||
<WithConfirm title="Are you sure to disconnect your Google account?" confirmText="Disconnect">
|
||||
<Button variant="destructive" onClick={userStore.disconnectGoogle}>
|
||||
Disconnect
|
||||
</Button>
|
||||
</WithConfirm>
|
||||
</WithPermissionControlTooltip>
|
||||
</HorizontalGroup>
|
||||
</VerticalGroup>
|
||||
) : (
|
||||
<HorizontalGroup justify="space-between" spacing="lg">
|
||||
<HorizontalGroup spacing="md">
|
||||
<GoogleCalendarLogo width={32} height={32} />
|
||||
<div>
|
||||
<Text.Title level={5}>Connect your Google Calendar</Text.Title>
|
||||
<Text type="secondary">
|
||||
This connection allows Grafana OnCall to read your Out of Office events and autogenerate Shift Swap
|
||||
Requests
|
||||
</Text>
|
||||
</div>
|
||||
</HorizontalGroup>
|
||||
<Block bordered className={utils.width100}>
|
||||
<VerticalGroup spacing="lg">
|
||||
{user.has_google_oauth2_connected ? (
|
||||
<VerticalGroup>
|
||||
<HorizontalGroup justify="space-between" spacing="lg" align="flex-start">
|
||||
<Heading connected />
|
||||
<WithPermissionControlTooltip userAction={UserActions.UserSettingsWrite}>
|
||||
<Button variant="primary" onClick={UserHelper.handleConnectGoogle}>
|
||||
Connect
|
||||
</Button>
|
||||
<WithConfirm title="Are you sure to disconnect your Google account?" confirmText="Disconnect">
|
||||
<Button variant="destructive" onClick={userStore.disconnectGoogle}>
|
||||
Disconnect
|
||||
</Button>
|
||||
</WithConfirm>
|
||||
</WithPermissionControlTooltip>
|
||||
</HorizontalGroup>
|
||||
)}
|
||||
|
||||
{user.has_google_oauth2_connected && (
|
||||
<VerticalGroup>
|
||||
<WithPermissionControlTooltip userAction={UserActions.UserSettingsWrite}>
|
||||
<HorizontalGroup align="center">
|
||||
<Switch value={showSchedulesDropdown} onChange={handleShowSchedulesDropdownChange} />
|
||||
<Text type="secondary">Specify the schedules to sync with Google calendar</Text>
|
||||
</HorizontalGroup>
|
||||
</WithPermissionControlTooltip>
|
||||
{showSchedulesDropdown && (
|
||||
<div style={{ width: '100%' }}>
|
||||
<WithPermissionControlTooltip userAction={UserActions.UserSettingsWrite}>
|
||||
<GSelect<Schedule>
|
||||
isMulti
|
||||
showSearch
|
||||
allowClear
|
||||
disabled={false}
|
||||
items={scheduleStore.items}
|
||||
fetchItemsFn={scheduleStore.updateItems}
|
||||
fetchItemFn={scheduleStore.updateItem}
|
||||
getSearchResult={scheduleStore.getSearchResult}
|
||||
displayField="name"
|
||||
valueField="id"
|
||||
placeholder="Select Schedules"
|
||||
value={googleCalendarSettings?.oncall_schedules_to_consider_for_shift_swaps}
|
||||
onChange={handleSchedulesChange}
|
||||
/>
|
||||
</WithPermissionControlTooltip>
|
||||
</div>
|
||||
)}
|
||||
</VerticalGroup>
|
||||
)}
|
||||
|
||||
<HorizontalGroup spacing="sm">
|
||||
<Icon name="info-circle" />
|
||||
<Text type="secondary">
|
||||
Grafana OnCall's use and transfer to any other app of information received from Google APIs will adhere to{' '}
|
||||
<a
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
href="https://developers.google.com/terms/api-services-user-data-policy#additional_requirements_for_specific_api_scopes"
|
||||
>
|
||||
<Text type="link">Google API Services User Data Policy</Text>
|
||||
</a>
|
||||
, including the Limited Use requirements.
|
||||
</Text>
|
||||
</VerticalGroup>
|
||||
) : (
|
||||
<HorizontalGroup justify="space-between" spacing="lg" align="flex-start">
|
||||
<Heading connected={false} />
|
||||
<WithPermissionControlTooltip userAction={UserActions.UserSettingsWrite}>
|
||||
<Button variant="primary" onClick={UserHelper.handleConnectGoogle}>
|
||||
Connect
|
||||
</Button>
|
||||
</WithPermissionControlTooltip>
|
||||
</HorizontalGroup>
|
||||
</VerticalGroup>
|
||||
</Block>
|
||||
</VerticalGroup>
|
||||
)}
|
||||
|
||||
{user.has_google_oauth2_connected && (
|
||||
<VerticalGroup>
|
||||
<WithPermissionControlTooltip userAction={UserActions.UserSettingsWrite}>
|
||||
<HorizontalGroup spacing="md" align="center">
|
||||
<Switch value={showSchedulesDropdown} onChange={handleShowSchedulesDropdownChange} />
|
||||
<Text type="secondary">Specify the schedules to sync with Google calendar</Text>
|
||||
</HorizontalGroup>
|
||||
</WithPermissionControlTooltip>
|
||||
{showSchedulesDropdown && (
|
||||
<div className={utils.width100}>
|
||||
<WithPermissionControlTooltip userAction={UserActions.UserSettingsWrite}>
|
||||
<GSelect<Schedule>
|
||||
isMulti
|
||||
showSearch
|
||||
allowClear
|
||||
disabled={false}
|
||||
items={scheduleStore.items}
|
||||
fetchItemsFn={scheduleStore.updateItems}
|
||||
fetchItemFn={scheduleStore.updateItem}
|
||||
getSearchResult={scheduleStore.getSearchResult}
|
||||
displayField="name"
|
||||
valueField="id"
|
||||
placeholder="Select Schedules"
|
||||
value={user.google_calendar_settings.oncall_schedules_to_consider_for_shift_swaps}
|
||||
onChange={handleSchedulesChange}
|
||||
/>
|
||||
</WithPermissionControlTooltip>
|
||||
</div>
|
||||
)}
|
||||
</VerticalGroup>
|
||||
)}
|
||||
</VerticalGroup>
|
||||
</Block>
|
||||
);
|
||||
});
|
||||
|
||||
export const getStyles = () => ({
|
||||
root: css({
|
||||
width: '100%',
|
||||
icon: css({
|
||||
marginTop: '6px',
|
||||
}),
|
||||
});
|
||||
|
||||
const Heading: React.FC<{ connected: boolean }> = ({ connected }) => {
|
||||
const styles = useStyles2(getStyles);
|
||||
|
||||
return (
|
||||
<HorizontalGroup spacing="md" align="flex-start">
|
||||
<div className={styles.icon}>
|
||||
<GoogleCalendarLogo width={32} height={32} />
|
||||
</div>
|
||||
<VerticalGroup spacing="md">
|
||||
<VerticalGroup spacing="none">
|
||||
<Text.Title level={5}>
|
||||
{connected ? 'Google calendar is connected' : 'Connect your Google Calendar'}
|
||||
</Text.Title>
|
||||
{connected ? (
|
||||
<Text type="secondary">
|
||||
Add <Text type="primary">#grafana-oncall-ignore</Text> to an Out of Office event title to exclude it from
|
||||
Shift Swap Request creation.{' '}
|
||||
<a
|
||||
href={`${DOCS_ROOT}/manage/on-call-schedules/shift-swaps/#google-calendar-integration`}
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
>
|
||||
<Text type="link">Read more</Text>
|
||||
</a>
|
||||
</Text>
|
||||
) : (
|
||||
<Text type="secondary">
|
||||
This connection allows OnCall to read your Out of Office events and autogenerate Shift Swap Requests.{' '}
|
||||
<a
|
||||
href={`${DOCS_ROOT}/manage/on-call-schedules/shift-swaps/#google-calendar-integration`}
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
>
|
||||
<Text type="link">Read more</Text>
|
||||
</a>
|
||||
</Text>
|
||||
)}
|
||||
</VerticalGroup>
|
||||
{!connected && (
|
||||
<Text type="secondary">
|
||||
Grafana OnCall's use and transfer to any other app of information received from Google APIs will adhere
|
||||
<br />
|
||||
to{' '}
|
||||
<a
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
href="https://developers.google.com/terms/api-services-user-data-policy#additional_requirements_for_specific_api_scopes"
|
||||
>
|
||||
<Text type="secondary" underline>
|
||||
Google API Services User Data Policy
|
||||
</Text>
|
||||
</a>
|
||||
, including the Limited Use requirements.
|
||||
</Text>
|
||||
)}
|
||||
</VerticalGroup>
|
||||
</HorizontalGroup>
|
||||
);
|
||||
};
|
||||
|
||||
export { GoogleCalendar };
|
||||
|
|
|
|||
|
|
@ -52,6 +52,7 @@ export class UserStore {
|
|||
(acc: { [key: number]: ApiSchemas['User'] }, item: ApiSchemas['User']) => ({
|
||||
...acc,
|
||||
[item.pk]: {
|
||||
...this.items[item.pk],
|
||||
...item,
|
||||
timezone: UserHelper.getTimezone(item),
|
||||
},
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue