add user groups user selector

This commit is contained in:
Maxim 2022-06-24 18:08:45 +03:00
parent 2ce1ff2e65
commit a195e09689
5 changed files with 110 additions and 30 deletions

View file

@ -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<RotationFormProps> = (props) => {
const { onHide } = props;
const moment = dayjs();
return (
<Modal
width="400px"
@ -33,16 +37,50 @@ const RotationForm: FC<RotationFormProps> = (props) => {
)}
>
<VerticalGroup>
<div className={cx('header')}>
<HorizontalGroup justify="space-between">
<Text size="medium">Rotation 1</Text>
<div className={cx('header-buttons')}>
<IconButton className={cx('handle', 'drag-handler')} name="draggabledots" />
</div>
</div>
<HorizontalGroup>
<IconButton variant="secondary" tooltip="Copy" name="copy" />
<IconButton variant="secondary" tooltip="Code" name="brackets-curly" />
<IconButton variant="secondary" tooltip="Delete" name="trash-alt" />
<IconButton variant="secondary" className={cx('drag-handler')} name="draggabledots" />
</HorizontalGroup>
</HorizontalGroup>
<UserGroups />
{/*<HorizontalGroup justify="end">
<Button variant="primary">Create</Button>
</HorizontalGroup>*/}
<hr />
<VerticalGroup>
<HorizontalGroup>
<Field label="Repeat shifts every">
<Input value="1" />
</Field>
<Field label="">
<Input value="days" />
</Field>
</HorizontalGroup>
<HorizontalGroup>
<Field label="Shift start">
<Input value="12 May, 22 10:00" />
</Field>
<Field label="Shift end">
<Input value="12 May, 22 10:00" />
</Field>
</HorizontalGroup>
<HorizontalGroup>
<Field label="Rotation start">
<Input value="12 May, 22 10:00" />
</Field>
<Field label="Rotation end">
<Input value="endless" />
</Field>
</HorizontalGroup>
</VerticalGroup>
<HorizontalGroup justify="space-between">
<Text type="secondary">Timezone: {getTzOffsetString(moment)}</Text>
<HorizontalGroup>
<Button variant="secondary">+ Override</Button>
<Button variant="primary">Create</Button>
</HorizontalGroup>
</HorizontalGroup>
</VerticalGroup>
</Modal>
);

View file

@ -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);
}

View file

@ -82,3 +82,7 @@
cursor: pointer;
}
.select{
width: 100%;
}

View file

@ -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
/>
{/* <div className={cx('add-user-group')} onClick={handleAddUserGroup}>
Add user group +
</div>*/}
<GSelect
showSearch
allowClear
modelName="userStore"
displayField="username"
valueField="pk"
placeholder="Add user"
className={cx('select')}
value={null}
onChange={handleUserAdd}
getOptionLabel={({ label, value }: SelectableValue) => <UserTooltip id={value} />}
filterOptions={filterUsers}
/>
</VerticalGroup>
</div>
);

View file

@ -35,6 +35,7 @@ interface GSelectProps {
dropdownRender?: (menu: ReactElement) => ReactElement;
getOptionLabel?: <T>(item: SelectableValue<T>) => 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;
});
};