diff --git a/grafana-plugin/src/components/RotationForm/RotationForm.tsx b/grafana-plugin/src/components/RotationForm/RotationForm.tsx index 76619aef..7018f81e 100644 --- a/grafana-plugin/src/components/RotationForm/RotationForm.tsx +++ b/grafana-plugin/src/components/RotationForm/RotationForm.tsx @@ -1,12 +1,14 @@ import React, { FC } from 'react'; -import { IconButton, VerticalGroup, HorizontalGroup } from '@grafana/ui'; +import { IconButton, VerticalGroup, HorizontalGroup, Field, Input, Button } from '@grafana/ui'; import cn from 'classnames/bind'; +import dayjs from 'dayjs'; import Draggable from 'react-draggable'; import Modal from 'components/Modal/Modal'; import Text from 'components/Text/Text'; import UserGroups from 'components/UserGroups/UserGroups'; +import { getTzOffsetString } from 'models/timezone/timezone.helpers'; import styles from './RotationForm.module.css'; @@ -21,6 +23,8 @@ const cx = cn.bind(styles); const RotationForm: FC = (props) => { const { onHide } = props; + const moment = dayjs(); + return ( = (props) => { )} > -
+ Rotation 1 -
- -
-
+ + + + + + + - {/* - - */} +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + Timezone: {getTzOffsetString(moment)} + + + + +
); diff --git a/grafana-plugin/src/components/UserGroups/UserGroups.helpers.ts b/grafana-plugin/src/components/UserGroups/UserGroups.helpers.ts index 5f6348a5..11fb41a7 100644 --- a/grafana-plugin/src/components/UserGroups/UserGroups.helpers.ts +++ b/grafana-plugin/src/components/UserGroups/UserGroups.helpers.ts @@ -1,4 +1,4 @@ -import { getRandomTimezone } from '../UsersTimezones/UsersTimezones.helpers'; +import { getRandomTimezone } from 'components/UsersTimezones/UsersTimezones.helpers'; export const getRandomGroups = () => { return [ @@ -44,21 +44,14 @@ export const toPlainArray = (groups) => { return items; }; -export const fromPlainArray = ( - items, - createNewGroup = false, - deleteEmptyGroups = true, -) => { +export const fromPlainArray = (items, createNewGroup = false, deleteEmptyGroups = true) => { const groups = []; return items .reduce((memo, item, currentIndex) => { if (item.type === 'item') { let lastGroup = memo[memo.length - 1]; - if ( - !lastGroup || - (createNewGroup && currentIndex === items.length - 1) - ) { + if (!lastGroup || (createNewGroup && currentIndex === items.length - 1)) { lastGroup = []; memo.push(lastGroup); } diff --git a/grafana-plugin/src/components/UserGroups/UserGroups.module.css b/grafana-plugin/src/components/UserGroups/UserGroups.module.css index 43b142d9..38886248 100644 --- a/grafana-plugin/src/components/UserGroups/UserGroups.module.css +++ b/grafana-plugin/src/components/UserGroups/UserGroups.module.css @@ -82,3 +82,7 @@ cursor: pointer; } + +.select{ + width: 100%; +} diff --git a/grafana-plugin/src/components/UserGroups/UserGroups.tsx b/grafana-plugin/src/components/UserGroups/UserGroups.tsx index 9c1821ca..bb03be3f 100644 --- a/grafana-plugin/src/components/UserGroups/UserGroups.tsx +++ b/grafana-plugin/src/components/UserGroups/UserGroups.tsx @@ -1,11 +1,16 @@ import React, { FC, useCallback, useEffect, useMemo, useState } from 'react'; -import { VerticalGroup, HorizontalGroup, IconButton } from '@grafana/ui'; +import { SelectableValue } from '@grafana/data'; +import { VerticalGroup, HorizontalGroup, IconButton, Field, Input } from '@grafana/ui'; import { arrayMoveImmutable } from 'array-move'; import cn from 'classnames/bind'; import { SortableContainer, SortableElement, SortableHandle } from 'react-sortable-hoc'; import Text from 'components/Text/Text'; +import GSelect from 'containers/GSelect/GSelect'; +import UserTooltip from 'containers/UserTooltip/UserTooltip'; +import { User } from 'models/user/user.types'; +import { getRandomTimezone } from 'pages/schedule/Schedule.helpers'; import { fromPlainArray, getRandomGroups, toPlainArray } from './UserGroups.helpers'; @@ -54,12 +59,38 @@ const SortableList = SortableContainer(({ items, onAddUserGroup }) => { }); const UserGroups = () => { - const [groups, setGroups] = useState(getRandomGroups()); + const [groups, setGroups] = useState([[]]); const handleAddUserGroup = useCallback(() => { setGroups((oldGroups) => [...oldGroups, []]); }, [groups]); + const handleUserAdd = useCallback((pk: User['pk'], user: User) => { + if (!pk) { + return; + } + + setGroups((groups) => { + const newGroups = [...groups]; + const lastGroup = newGroups[groups.length - 1]; + + lastGroup.push({ pk, name: user.username, tz: getRandomTimezone() }); + + return newGroups; + }); + }, []); + + const filterUsers = useCallback( + ({ value }) => { + const userAlreadyExist = groups.some((group) => group.some((user) => user.pk === value)); + + console.log('userAlreadyExist', userAlreadyExist); + + return !userAlreadyExist; + }, + [groups] + ); + const items = useMemo(() => toPlainArray(groups), [groups]); const onSortEnd = useCallback( @@ -83,9 +114,19 @@ const UserGroups = () => { onAddUserGroup={handleAddUserGroup} //useDragHandle /> - {/*
- Add user group + -
*/} + } + filterOptions={filterUsers} + /> ); diff --git a/grafana-plugin/src/containers/GSelect/GSelect.tsx b/grafana-plugin/src/containers/GSelect/GSelect.tsx index 35e0a085..ae7ae736 100644 --- a/grafana-plugin/src/containers/GSelect/GSelect.tsx +++ b/grafana-plugin/src/containers/GSelect/GSelect.tsx @@ -35,6 +35,7 @@ interface GSelectProps { dropdownRender?: (menu: ReactElement) => ReactElement; getOptionLabel?: (item: SelectableValue) => React.ReactNode; getDescription?: (item: any) => React.ReactNode; + filterOptions?: () => boolean; } const GSelect = observer((props: GSelectProps) => { @@ -59,6 +60,7 @@ const GSelect = observer((props: GSelectProps) => { getOptionLabel, showWarningIfEmptyValue = false, getDescription, + filterOptions = () => true, } = props; const store = useStore(); @@ -91,12 +93,14 @@ const GSelect = observer((props: GSelectProps) => { const searchResult = model.getSearchResult(query); const items = Array.isArray(searchResult.results) ? searchResult.results : searchResult; - const options = items.map((item: any) => ({ - value: item[valueField], - label: get(item, displayField), - imgUrl: item.avatar_url, - description: getDescription && getDescription(item), - })); + const options = items + .map((item: any) => ({ + value: item[valueField], + label: get(item, displayField), + imgUrl: item.avatar_url, + description: getDescription && getDescription(item), + })) + .filter(filterOptions); return options; }); };