feat: add tooltips for icon buttons
This commit is contained in:
@@ -9,6 +9,7 @@ import classNames from 'classnames';
|
||||
import { useDispatch, useSelector } from 'react-redux';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { Button, Icon, Label, Loader } from 'semantic-ui-react';
|
||||
import { Tooltip } from '../../../lib/custom-ui';
|
||||
|
||||
import selectors from '../../../selectors';
|
||||
import entryActions from '../../../entry-actions';
|
||||
@@ -161,9 +162,11 @@ const ItemContent = React.forwardRef(({ id, onOpen }, ref) => {
|
||||
</div>
|
||||
{canEdit && (
|
||||
<EditPopup attachmentId={id}>
|
||||
<Button className={styles.editButton}>
|
||||
<Icon fitted name="pencil" size="small" />
|
||||
</Button>
|
||||
<Tooltip content={t('action.editAttachment', { context: 'title' })}>
|
||||
<Button className={styles.editButton}>
|
||||
<Icon fitted name="pencil" size="small" />
|
||||
</Button>
|
||||
</Tooltip>
|
||||
</EditPopup>
|
||||
)}
|
||||
</div>
|
||||
|
||||
+13
-8
@@ -8,7 +8,9 @@ import ReactDOM from 'react-dom';
|
||||
import PropTypes from 'prop-types';
|
||||
import { useSelector } from 'react-redux';
|
||||
import { Draggable } from 'react-beautiful-dnd';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { Button, Icon } from 'semantic-ui-react';
|
||||
import { Tooltip } from '../../../lib/custom-ui';
|
||||
|
||||
import selectors from '../../../selectors';
|
||||
|
||||
@@ -18,6 +20,7 @@ const CustomField = React.memo(({ id, index, onEdit }) => {
|
||||
const selectCustomFieldById = useMemo(() => selectors.makeSelectCustomFieldById(), []);
|
||||
|
||||
const customField = useSelector((state) => selectCustomFieldById(state, id));
|
||||
const [t] = useTranslation();
|
||||
|
||||
const handleEditClick = useCallback(() => {
|
||||
onEdit(id);
|
||||
@@ -36,14 +39,16 @@ const CustomField = React.memo(({ id, index, onEdit }) => {
|
||||
{customField.showOnFrontOfCard && <Icon name="pin" className={styles.nameIcon} />}
|
||||
{customField.name}
|
||||
</span>
|
||||
<Button
|
||||
icon="pencil"
|
||||
size="small"
|
||||
floated="right"
|
||||
disabled={!customField.isPersisted}
|
||||
className={styles.editButton}
|
||||
onClick={handleEditClick}
|
||||
/>
|
||||
<Tooltip content={t('action.edit', { context: 'title' })}>
|
||||
<Button
|
||||
icon="pencil"
|
||||
size="small"
|
||||
floated="right"
|
||||
disabled={!customField.isPersisted}
|
||||
className={styles.editButton}
|
||||
onClick={handleEditClick}
|
||||
/>
|
||||
</Tooltip>
|
||||
</div>
|
||||
);
|
||||
|
||||
|
||||
@@ -7,7 +7,9 @@ import groupBy from 'lodash/groupBy';
|
||||
import React, { useMemo } from 'react';
|
||||
import classNames from 'classnames';
|
||||
import { useSelector } from 'react-redux';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { Button } from 'semantic-ui-react';
|
||||
import { Tooltip } from '../../../lib/custom-ui';
|
||||
import { usePopup } from '../../../lib/popup';
|
||||
|
||||
import selectors from '../../../selectors';
|
||||
@@ -20,6 +22,7 @@ import styles from './BoardMemberships.module.scss';
|
||||
|
||||
const BoardMemberships = React.memo(() => {
|
||||
const boardMemberships = useSelector(selectors.selectMembershipsForCurrentBoard);
|
||||
const [t] = useTranslation();
|
||||
|
||||
const canAdd = useSelector((state) => {
|
||||
const user = selectors.selectCurrentUser(state);
|
||||
@@ -57,7 +60,9 @@ const BoardMemberships = React.memo(() => {
|
||||
)}
|
||||
{canAdd && (
|
||||
<AddPopup>
|
||||
<Button icon="add user" className={classNames(styles.segment, styles.addButton)} />
|
||||
<Tooltip content={t('action.addMember')}>
|
||||
<Button icon="add user" className={classNames(styles.segment, styles.addButton)} />
|
||||
</Tooltip>
|
||||
</AddPopup>
|
||||
)}
|
||||
</>
|
||||
|
||||
@@ -11,7 +11,7 @@ import { useInView } from 'react-intersection-observer';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { Button, Icon, Loader } from 'semantic-ui-react';
|
||||
import { useWindowWidth } from '../../../lib/hooks';
|
||||
import { Masonry } from '../../../lib/custom-ui';
|
||||
import { Masonry, Tooltip } from '../../../lib/custom-ui';
|
||||
|
||||
import selectors from '../../../selectors';
|
||||
import { BoardMembershipRoles } from '../../../constants/Enums';
|
||||
@@ -81,14 +81,16 @@ const GridView = React.memo(
|
||||
</span>
|
||||
</Button>
|
||||
{onCardPaste && clipboard && canPasteCard && (
|
||||
<Button
|
||||
type="button"
|
||||
disabled={!onCardCreate}
|
||||
className={classNames(styles.addCardButton, styles.paste)}
|
||||
onClick={onCardPaste}
|
||||
>
|
||||
<Icon fitted name="paste" />
|
||||
</Button>
|
||||
<Tooltip content={t('action.paste')}>
|
||||
<Button
|
||||
type="button"
|
||||
disabled={!onCardCreate}
|
||||
className={classNames(styles.addCardButton, styles.paste)}
|
||||
onClick={onCardPaste}
|
||||
>
|
||||
<Icon fitted name="paste" />
|
||||
</Button>
|
||||
</Tooltip>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -10,6 +10,7 @@ import { shallowEqual, useSelector } from 'react-redux';
|
||||
import { useInView } from 'react-intersection-observer';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { Button, Icon, Loader } from 'semantic-ui-react';
|
||||
import { Tooltip } from '../../../lib/custom-ui';
|
||||
|
||||
import selectors from '../../../selectors';
|
||||
import { BoardMembershipRoles } from '../../../constants/Enums';
|
||||
@@ -74,14 +75,16 @@ const ListView = React.memo(
|
||||
</span>
|
||||
</Button>
|
||||
{onCardPaste && clipboard && canPasteCard && (
|
||||
<Button
|
||||
type="button"
|
||||
disabled={!onCardCreate}
|
||||
className={classNames(styles.addCardButton, styles.paste)}
|
||||
onClick={onCardPaste}
|
||||
>
|
||||
<Icon fitted name="paste" />
|
||||
</Button>
|
||||
<Tooltip content={t('action.paste')}>
|
||||
<Button
|
||||
type="button"
|
||||
disabled={!onCardCreate}
|
||||
className={classNames(styles.addCardButton, styles.paste)}
|
||||
onClick={onCardPaste}
|
||||
>
|
||||
<Icon fitted name="paste" />
|
||||
</Button>
|
||||
</Tooltip>
|
||||
)}
|
||||
</div>
|
||||
))}
|
||||
|
||||
@@ -11,7 +11,7 @@ import { useTranslation } from 'react-i18next';
|
||||
import { Icon } from 'semantic-ui-react';
|
||||
import { useDidUpdate } from '../../../lib/hooks';
|
||||
import { usePopup } from '../../../lib/popup';
|
||||
import { Input } from '../../../lib/custom-ui';
|
||||
import { Input, Tooltip } from '../../../lib/custom-ui';
|
||||
|
||||
import selectors from '../../../selectors';
|
||||
import entryActions from '../../../entry-actions';
|
||||
@@ -162,11 +162,13 @@ const Filters = React.memo(() => {
|
||||
</button>
|
||||
</BoardMembershipsPopup>
|
||||
{userIds.length === 0 && withCurrentUserSelector && (
|
||||
<button type="button" className={styles.filterButton} onClick={handleCurrentUserSelect}>
|
||||
<span className={styles.filterLabel}>
|
||||
<Icon fitted name="target" className={styles.filterLabelIcon} />
|
||||
</span>
|
||||
</button>
|
||||
<Tooltip content={t('action.filterByCurrentUser')}>
|
||||
<button type="button" className={styles.filterButton} onClick={handleCurrentUserSelect}>
|
||||
<span className={styles.filterLabel}>
|
||||
<Icon fitted name="target" className={styles.filterLabelIcon} />
|
||||
</span>
|
||||
</button>
|
||||
</Tooltip>
|
||||
)}
|
||||
{userIds.map((userId) => (
|
||||
<span key={userId} className={styles.filterItem}>
|
||||
|
||||
@@ -5,7 +5,9 @@
|
||||
|
||||
import React, { useCallback } from 'react';
|
||||
import { useDispatch, useSelector } from 'react-redux';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { Icon } from 'semantic-ui-react';
|
||||
import { Tooltip } from '../../../../lib/custom-ui';
|
||||
import { usePopup } from '../../../../lib/popup';
|
||||
|
||||
import selectors from '../../../../selectors';
|
||||
@@ -20,6 +22,7 @@ const RightSide = React.memo(() => {
|
||||
const board = useSelector(selectors.selectCurrentBoard);
|
||||
|
||||
const dispatch = useDispatch();
|
||||
const [t] = useTranslation();
|
||||
|
||||
const handleSelectViewClick = useCallback(
|
||||
({ currentTarget: { value: view } }) => {
|
||||
@@ -40,24 +43,33 @@ const RightSide = React.memo(() => {
|
||||
<div className={styles.action}>
|
||||
<div className={styles.buttonGroup}>
|
||||
{views.map((view) => (
|
||||
<button
|
||||
<Tooltip
|
||||
key={view}
|
||||
type="button"
|
||||
value={view}
|
||||
content={t('action.switchToView', {
|
||||
view: t(`common.${view}`).toLowerCase(),
|
||||
})}
|
||||
disabled={view === board.view}
|
||||
className={styles.button}
|
||||
onClick={handleSelectViewClick}
|
||||
>
|
||||
<Icon fitted name={BoardViewIcons[view]} />
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
value={view}
|
||||
disabled={view === board.view}
|
||||
className={styles.button}
|
||||
onClick={handleSelectViewClick}
|
||||
>
|
||||
<Icon fitted name={BoardViewIcons[view]} />
|
||||
</button>
|
||||
</Tooltip>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
<div className={styles.action}>
|
||||
<ActionsPopup>
|
||||
<button type="button" className={styles.button}>
|
||||
<Icon fitted name="ellipsis vertical" />
|
||||
</button>
|
||||
<Tooltip content={t('common.openBoardActions')}>
|
||||
<button type="button" className={styles.button}>
|
||||
<Icon fitted name="ellipsis vertical" />
|
||||
</button>
|
||||
</Tooltip>
|
||||
</ActionsPopup>
|
||||
</div>
|
||||
</>
|
||||
|
||||
@@ -6,7 +6,9 @@
|
||||
import React, { useCallback, useRef } from 'react';
|
||||
import { useDispatch, useSelector } from 'react-redux';
|
||||
import { DragDropContext, Droppable } from 'react-beautiful-dnd';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { Button } from 'semantic-ui-react';
|
||||
import { Tooltip } from '../../../lib/custom-ui';
|
||||
import { closePopup, usePopup } from '../../../lib/popup';
|
||||
|
||||
import selectors from '../../../selectors';
|
||||
@@ -32,6 +34,7 @@ const Boards = React.memo(() => {
|
||||
});
|
||||
|
||||
const dispatch = useDispatch();
|
||||
const [t] = useTranslation();
|
||||
|
||||
const tabsWrapperRef = useRef(null);
|
||||
|
||||
@@ -75,7 +78,9 @@ const Boards = React.memo(() => {
|
||||
{placeholder}
|
||||
{canAdd && (
|
||||
<AddBoardPopup>
|
||||
<Button icon="plus" className={styles.addButton} />
|
||||
<Tooltip content={t('action.createBoard')}>
|
||||
<Button icon="plus" className={styles.addButton} />
|
||||
</Tooltip>
|
||||
</AddBoardPopup>
|
||||
)}
|
||||
</div>
|
||||
|
||||
@@ -9,7 +9,9 @@ import classNames from 'classnames';
|
||||
import { useDispatch, useSelector } from 'react-redux';
|
||||
import { Link } from 'react-router';
|
||||
import { Draggable } from 'react-beautiful-dnd';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { Button, Icon } from 'semantic-ui-react';
|
||||
import { Tooltip } from '../../../lib/custom-ui';
|
||||
|
||||
import selectors from '../../../selectors';
|
||||
import entryActions from '../../../entry-actions';
|
||||
@@ -40,6 +42,7 @@ const Item = React.memo(({ id, index }) => {
|
||||
});
|
||||
|
||||
const dispatch = useDispatch();
|
||||
const [t] = useTranslation();
|
||||
|
||||
const handleEditClick = useCallback(() => {
|
||||
dispatch(entryActions.openBoardSettingsModal(id));
|
||||
@@ -64,9 +67,11 @@ const Item = React.memo(({ id, index }) => {
|
||||
<span className={styles.name}>{board.name}</span>
|
||||
</Link>
|
||||
{canEdit && (
|
||||
<Button className={styles.editButton} onClick={handleEditClick}>
|
||||
<Icon fitted name="pencil" size="small" />
|
||||
</Button>
|
||||
<Tooltip content={t('action.edit', { context: 'title' })}>
|
||||
<Button className={styles.editButton} onClick={handleEditClick}>
|
||||
<Icon fitted name="pencil" size="small" />
|
||||
</Button>
|
||||
</Tooltip>
|
||||
)}
|
||||
</>
|
||||
) : (
|
||||
|
||||
@@ -7,7 +7,9 @@ import React, { useCallback, useContext, useMemo, useRef, useState } from 'react
|
||||
import PropTypes from 'prop-types';
|
||||
import classNames from 'classnames';
|
||||
import { useDispatch, useSelector } from 'react-redux';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { Button, Icon } from 'semantic-ui-react';
|
||||
import { Tooltip } from '../../../lib/custom-ui';
|
||||
import { push } from '../../../lib/redux-router';
|
||||
import { closePopup, usePopup } from '../../../lib/popup';
|
||||
|
||||
@@ -57,6 +59,7 @@ const Card = React.memo(({ id, isInline }) => {
|
||||
});
|
||||
|
||||
const dispatch = useDispatch();
|
||||
const [t] = useTranslation();
|
||||
const [isEditNameOpened, setIsEditNameOpened] = useState(false);
|
||||
const [, , handleCardMouseEnter, handleCardMouseLeave] = useContext(BoardShortcutsContext);
|
||||
|
||||
@@ -151,9 +154,11 @@ const Card = React.memo(({ id, isInline }) => {
|
||||
</div>
|
||||
{canUseActions && (
|
||||
<CardActionsPopup ref={actionsPopupRef} cardId={id} onNameEdit={handleNameEdit}>
|
||||
<Button className={styles.actionsButton}>
|
||||
<Icon fitted name="pencil" size="small" />
|
||||
</Button>
|
||||
<Tooltip content={t('common.openCardActions')}>
|
||||
<Button className={styles.actionsButton}>
|
||||
<Icon fitted name="pencil" size="small" />
|
||||
</Button>
|
||||
</Tooltip>
|
||||
</CardActionsPopup>
|
||||
)}
|
||||
</>
|
||||
|
||||
@@ -6,7 +6,9 @@
|
||||
import React, { useCallback, useEffect, useMemo } from 'react';
|
||||
import classNames from 'classnames';
|
||||
import { useDispatch, useSelector } from 'react-redux';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { Icon } from 'semantic-ui-react';
|
||||
import { Tooltip } from '../../../lib/custom-ui';
|
||||
import { push } from '../../../lib/redux-router';
|
||||
|
||||
import selectors from '../../../selectors';
|
||||
@@ -45,6 +47,7 @@ const CardModal = React.memo(() => {
|
||||
});
|
||||
|
||||
const dispatch = useDispatch();
|
||||
const [t] = useTranslation();
|
||||
|
||||
const handleClose = useCallback(() => {
|
||||
dispatch(push(Paths.BOARDS.replace(':id', card.boardId)));
|
||||
@@ -102,9 +105,11 @@ const CardModal = React.memo(() => {
|
||||
onClose={handleClose}
|
||||
>
|
||||
{prevCardId && (
|
||||
<button type="button" className={styles.prevButton} onClick={handlePrevClick}>
|
||||
<Icon fitted name="arrow left" size="large" className={styles.prevButtonIcon} />
|
||||
</button>
|
||||
<Tooltip content={t('action.goBack')} position="right center">
|
||||
<button type="button" className={styles.prevButton} onClick={handlePrevClick}>
|
||||
<Icon fitted name="arrow left" size="large" className={styles.prevButtonIcon} />
|
||||
</button>
|
||||
</Tooltip>
|
||||
)}
|
||||
{canEdit ? (
|
||||
<AddAttachmentZone>
|
||||
|
||||
@@ -7,7 +7,9 @@ import React, { useMemo } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import classNames from 'classnames';
|
||||
import { useSelector } from 'react-redux';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { Button, Icon } from 'semantic-ui-react';
|
||||
import { Tooltip } from '../../../../lib/custom-ui';
|
||||
|
||||
import selectors from '../../../../selectors';
|
||||
import { usePopupInClosableContext } from '../../../../hooks';
|
||||
@@ -23,6 +25,7 @@ const Item = React.memo(({ id, dragHandleProps }) => {
|
||||
const selectListById = useMemo(() => selectors.makeSelectListById(), []);
|
||||
|
||||
const customFieldGroup = useSelector((state) => selectCustomFieldGroupById(state, id));
|
||||
const [t] = useTranslation();
|
||||
|
||||
const canEdit = useSelector((state) => {
|
||||
if (customFieldGroup.boardId) {
|
||||
@@ -51,9 +54,11 @@ const Item = React.memo(({ id, dragHandleProps }) => {
|
||||
<div className={classNames(styles.moduleHeader, canEdit && styles.moduleHeaderEditable)}>
|
||||
{customFieldGroup.isPersisted && canEdit && (
|
||||
<CustomFieldGroupPopup id={customFieldGroup.id}>
|
||||
<Button className={styles.editButton}>
|
||||
<Icon fitted name="pencil" size="small" />
|
||||
</Button>
|
||||
<Tooltip content={t('action.editGroup')}>
|
||||
<Button className={styles.editButton}>
|
||||
<Icon fitted name="pencil" size="small" />
|
||||
</Button>
|
||||
</Tooltip>
|
||||
</CustomFieldGroupPopup>
|
||||
)}
|
||||
<span className={styles.moduleHeaderTitle}>{customFieldGroup.name}</span>
|
||||
|
||||
@@ -9,6 +9,7 @@ import { shallowEqual, useDispatch, useSelector } from 'react-redux';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { Button, Checkbox, Grid, Icon } from 'semantic-ui-react';
|
||||
import { useDidUpdate } from '../../../lib/hooks';
|
||||
import { Tooltip } from '../../../lib/custom-ui';
|
||||
|
||||
import selectors from '../../../selectors';
|
||||
import entryActions from '../../../entry-actions';
|
||||
@@ -361,12 +362,14 @@ const ProjectContent = React.memo(() => {
|
||||
onUserSelect={handleUserSelect}
|
||||
onUserDeselect={handleUserDeselect}
|
||||
>
|
||||
<button
|
||||
type="button"
|
||||
className={classNames(styles.attachment, styles.dueDate)}
|
||||
>
|
||||
<Icon name="add" size="small" className={styles.addAttachment} />
|
||||
</button>
|
||||
<Tooltip content={t('action.addMember')}>
|
||||
<button
|
||||
type="button"
|
||||
className={classNames(styles.attachment, styles.dueDate)}
|
||||
>
|
||||
<Icon name="add" size="small" className={styles.addAttachment} />
|
||||
</button>
|
||||
</Tooltip>
|
||||
</BoardMembershipsPopup>
|
||||
)}
|
||||
</div>
|
||||
@@ -401,12 +404,14 @@ const ProjectContent = React.memo(() => {
|
||||
onSelect={handleLabelSelect}
|
||||
onDeselect={handleLabelDeselect}
|
||||
>
|
||||
<button
|
||||
type="button"
|
||||
className={classNames(styles.attachment, styles.dueDate)}
|
||||
>
|
||||
<Icon name="add" size="small" className={styles.addAttachment} />
|
||||
</button>
|
||||
<Tooltip content={t('action.addLabel')}>
|
||||
<button
|
||||
type="button"
|
||||
className={classNames(styles.attachment, styles.dueDate)}
|
||||
>
|
||||
<Icon name="add" size="small" className={styles.addAttachment} />
|
||||
</button>
|
||||
</Tooltip>
|
||||
</LabelsPopup>
|
||||
)}
|
||||
</div>
|
||||
@@ -465,17 +470,19 @@ const ProjectContent = React.memo(() => {
|
||||
)}
|
||||
</span>
|
||||
{canEditStopwatch && (
|
||||
<button
|
||||
type="button"
|
||||
className={classNames(styles.attachment, styles.dueDate)}
|
||||
onClick={handleToggleStopwatchClick}
|
||||
>
|
||||
<Icon
|
||||
name={card.stopwatch.startedAt ? 'pause' : 'play'}
|
||||
size="small"
|
||||
className={styles.addAttachment}
|
||||
/>
|
||||
</button>
|
||||
<Tooltip content={t(card.stopwatch.startedAt ? 'action.stop' : 'action.start')}>
|
||||
<button
|
||||
type="button"
|
||||
className={classNames(styles.attachment, styles.dueDate)}
|
||||
onClick={handleToggleStopwatchClick}
|
||||
>
|
||||
<Icon
|
||||
name={card.stopwatch.startedAt ? 'pause' : 'play'}
|
||||
size="small"
|
||||
className={styles.addAttachment}
|
||||
/>
|
||||
</button>
|
||||
</Tooltip>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
@@ -507,9 +514,11 @@ const ProjectContent = React.memo(() => {
|
||||
/* eslint-disable-next-line jsx-a11y/click-events-have-key-events,
|
||||
jsx-a11y/no-static-element-interactions */
|
||||
<div className={styles.cursorPointer} onClick={handleEditDescriptionClick}>
|
||||
<Button className={styles.editButton}>
|
||||
<Icon fitted name="pencil" size="small" />
|
||||
</Button>
|
||||
<Tooltip content={t('action.editDescription', { context: 'title' })}>
|
||||
<Button className={styles.editButton}>
|
||||
<Icon fitted name="pencil" size="small" />
|
||||
</Button>
|
||||
</Tooltip>
|
||||
<ExpandableMarkdown>{card.description}</ExpandableMarkdown>
|
||||
</div>
|
||||
) : (
|
||||
@@ -554,14 +563,16 @@ const ProjectContent = React.memo(() => {
|
||||
<div className={classNames(styles.text, styles.textList)}>{t('common.list')}</div>
|
||||
{canUseLists ? (
|
||||
<ListsPopup currentId={list.id} onSelect={handleListSelect}>
|
||||
<button type="button" className={styles.listButton}>
|
||||
<span className={classNames(styles.list, styles.listHoverable)}>
|
||||
<Icon name="columns" size="small" className={styles.listIcon} />
|
||||
<span className={styles.hidable}>
|
||||
{list.name || t(`common.${list.type}`)}
|
||||
<Tooltip content={t('common.selectList')}>
|
||||
<button type="button" className={styles.listButton}>
|
||||
<span className={classNames(styles.list, styles.listHoverable)}>
|
||||
<Icon name="columns" size="small" className={styles.listIcon} />
|
||||
<span className={styles.hidable}>
|
||||
{list.name || t(`common.${list.type}`)}
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
</button>
|
||||
</button>
|
||||
</Tooltip>
|
||||
</ListsPopup>
|
||||
) : (
|
||||
<span className={styles.list}>
|
||||
|
||||
@@ -10,6 +10,7 @@ import { useTranslation } from 'react-i18next';
|
||||
import { Gallery, Item as GalleryItem } from 'react-photoswipe-gallery';
|
||||
import { Button, Grid, Icon } from 'semantic-ui-react';
|
||||
import { useDidUpdate } from '../../../lib/hooks';
|
||||
import { Tooltip } from '../../../lib/custom-ui';
|
||||
|
||||
import selectors from '../../../selectors';
|
||||
import entryActions from '../../../entry-actions';
|
||||
@@ -383,12 +384,14 @@ const StoryContent = React.memo(() => {
|
||||
onSelect={handleLabelSelect}
|
||||
onDeselect={handleLabelDeselect}
|
||||
>
|
||||
<button
|
||||
type="button"
|
||||
className={classNames(styles.attachment, styles.dueDate)}
|
||||
>
|
||||
<Icon name="add" size="small" className={styles.addAttachment} />
|
||||
</button>
|
||||
<Tooltip content={t('action.addLabel')}>
|
||||
<button
|
||||
type="button"
|
||||
className={classNames(styles.attachment, styles.dueDate)}
|
||||
>
|
||||
<Icon name="add" size="small" className={styles.addAttachment} />
|
||||
</button>
|
||||
</Tooltip>
|
||||
</LabelsPopup>
|
||||
)}
|
||||
</div>
|
||||
@@ -419,9 +422,11 @@ const StoryContent = React.memo(() => {
|
||||
className={classNames(styles.descriptionText, styles.cursorPointer)}
|
||||
onClick={handleEditDescriptionClick}
|
||||
>
|
||||
<Button className={styles.editButton}>
|
||||
<Icon fitted name="pencil" size="small" />
|
||||
</Button>
|
||||
<Tooltip content={t('action.editDescription', { context: 'title' })}>
|
||||
<Button className={styles.editButton}>
|
||||
<Icon fitted name="pencil" size="small" />
|
||||
</Button>
|
||||
</Tooltip>
|
||||
<Markdown>{card.description}</Markdown>
|
||||
</div>
|
||||
) : (
|
||||
@@ -477,14 +482,16 @@ const StoryContent = React.memo(() => {
|
||||
<div className={classNames(styles.text, styles.textList)}>{t('common.list')}</div>
|
||||
{canUseLists ? (
|
||||
<ListsPopup currentId={list.id} onSelect={handleListSelect}>
|
||||
<button type="button" className={styles.listButton}>
|
||||
<span className={classNames(styles.list, styles.listHoverable)}>
|
||||
<Icon name="columns" size="small" className={styles.listIcon} />
|
||||
<span className={styles.hidable}>
|
||||
{list.name || t(`common.${list.type}`)}
|
||||
<Tooltip content={t('common.selectList')}>
|
||||
<button type="button" className={styles.listButton}>
|
||||
<span className={classNames(styles.list, styles.listHoverable)}>
|
||||
<Icon name="columns" size="small" className={styles.listIcon} />
|
||||
<span className={styles.hidable}>
|
||||
{list.name || t(`common.${list.type}`)}
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
</button>
|
||||
</button>
|
||||
</Tooltip>
|
||||
</ListsPopup>
|
||||
) : (
|
||||
<span className={styles.list}>
|
||||
|
||||
@@ -9,8 +9,10 @@ import PropTypes from 'prop-types';
|
||||
import classNames from 'classnames';
|
||||
import { useSelector } from 'react-redux';
|
||||
import { Draggable } from 'react-beautiful-dnd';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { Button, Icon } from 'semantic-ui-react';
|
||||
import { useToggle } from '../../../../lib/hooks';
|
||||
import { Tooltip } from '../../../../lib/custom-ui';
|
||||
|
||||
import selectors from '../../../../selectors';
|
||||
import { usePopupInClosableContext } from '../../../../hooks';
|
||||
@@ -24,6 +26,7 @@ const Item = React.memo(({ id, index }) => {
|
||||
const selectTaskListById = useMemo(() => selectors.makeSelectTaskListById(), []);
|
||||
|
||||
const taskList = useSelector((state) => selectTaskListById(state, id));
|
||||
const [t] = useTranslation();
|
||||
|
||||
const canEdit = useSelector((state) => {
|
||||
const boardMembership = selectors.selectCurrentUserMembershipForCurrentBoard(state);
|
||||
@@ -67,22 +70,30 @@ const Item = React.memo(({ id, index }) => {
|
||||
{taskList.isPersisted && withActions && (
|
||||
<div className={classNames(styles.actions)}>
|
||||
{taskList.hideCompletedTasks && (
|
||||
<Button
|
||||
className={styles.button}
|
||||
onClick={handleToggleCompletedVisibleClick}
|
||||
<Tooltip
|
||||
content={t(
|
||||
isCompletedVisible ? 'common.hideCompletedTasks' : 'action.showActive',
|
||||
)}
|
||||
>
|
||||
<Icon
|
||||
fitted
|
||||
name={isCompletedVisible ? 'eye slash' : 'eye'}
|
||||
size="small"
|
||||
/>
|
||||
</Button>
|
||||
<Button
|
||||
className={styles.button}
|
||||
onClick={handleToggleCompletedVisibleClick}
|
||||
>
|
||||
<Icon
|
||||
fitted
|
||||
name={isCompletedVisible ? 'eye slash' : 'eye'}
|
||||
size="small"
|
||||
/>
|
||||
</Button>
|
||||
</Tooltip>
|
||||
)}
|
||||
{canEdit && (
|
||||
<EditPopup taskListId={taskList.id}>
|
||||
<Button className={styles.button}>
|
||||
<Icon fitted name="pencil" size="small" />
|
||||
</Button>
|
||||
<Tooltip content={t('action.edit', { context: 'title' })}>
|
||||
<Button className={styles.button}>
|
||||
<Icon fitted name="pencil" size="small" />
|
||||
</Button>
|
||||
</Tooltip>
|
||||
</EditPopup>
|
||||
)}
|
||||
</div>
|
||||
|
||||
@@ -8,7 +8,7 @@ import PropTypes from 'prop-types';
|
||||
import { useDispatch, useSelector } from 'react-redux';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { Button, Icon, Input, Message } from 'semantic-ui-react';
|
||||
import { Popup } from '../../../../lib/custom-ui';
|
||||
import { Popup, Tooltip } from '../../../../lib/custom-ui';
|
||||
|
||||
import selectors from '../../../../selectors';
|
||||
import entryActions from '../../../../entry-actions';
|
||||
@@ -115,9 +115,11 @@ const ApiKeyStep = React.memo(({ userId, onBack, onClose }) => {
|
||||
/>
|
||||
<div className={styles.valueWrapper}>
|
||||
<Input fluid readOnly value={user.apiKeyState.value} className={styles.value} />
|
||||
<Button className={styles.copyButton} onClick={handleCopyClick}>
|
||||
<Icon fitted name={isCopied ? 'check' : 'copy'} />
|
||||
</Button>
|
||||
<Tooltip content={t('action.copy')}>
|
||||
<Button className={styles.copyButton} onClick={handleCopyClick}>
|
||||
<Icon fitted name={isCopied ? 'check' : 'copy'} />
|
||||
</Button>
|
||||
</Tooltip>
|
||||
</div>
|
||||
</>
|
||||
) : (
|
||||
|
||||
@@ -10,6 +10,7 @@ import { useDispatch, useSelector } from 'react-redux';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { Button, Icon, Table } from 'semantic-ui-react';
|
||||
import { useEventCallback } from '../../../../lib/hooks';
|
||||
import { Tooltip } from '../../../../lib/custom-ui';
|
||||
|
||||
import selectors from '../../../../selectors';
|
||||
import entryActions from '../../../../entry-actions';
|
||||
@@ -84,9 +85,11 @@ const Item = React.memo(({ id }) => {
|
||||
</Table.Cell>
|
||||
<Table.Cell textAlign="right">
|
||||
<ActionsPopup userId={id}>
|
||||
<Button className={styles.button}>
|
||||
<Icon fitted name="pencil" />
|
||||
</Button>
|
||||
<Tooltip content={t('common.userActions', { context: 'title' })}>
|
||||
<Button className={styles.button}>
|
||||
<Icon fitted name="pencil" />
|
||||
</Button>
|
||||
</Tooltip>
|
||||
</ActionsPopup>
|
||||
</Table.Cell>
|
||||
</Table.Row>
|
||||
|
||||
@@ -7,7 +7,9 @@ import React, { useCallback } from 'react';
|
||||
import classNames from 'classnames';
|
||||
import { shallowEqual, useDispatch, useSelector } from 'react-redux';
|
||||
import { Link } from 'react-router';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { Button, Icon, Menu } from 'semantic-ui-react';
|
||||
import { Tooltip } from '../../../lib/custom-ui';
|
||||
import { usePopup } from '../../../lib/popup';
|
||||
|
||||
import selectors from '../../../selectors';
|
||||
@@ -72,6 +74,7 @@ const Header = React.memo(() => {
|
||||
}, shallowEqual);
|
||||
|
||||
const dispatch = useDispatch();
|
||||
const [t] = useTranslation();
|
||||
|
||||
const handleToggleFavoritesClick = useCallback(() => {
|
||||
dispatch(entryActions.toggleFavorites(!isFavoritesEnabled));
|
||||
@@ -102,55 +105,69 @@ const Header = React.memo(() => {
|
||||
<Menu inverted size="large" className={styles.menu}>
|
||||
{project && (
|
||||
<Menu.Menu position="left">
|
||||
<Menu.Item
|
||||
as={Link}
|
||||
to={Paths.ROOT}
|
||||
className={classNames(styles.item, styles.itemHoverable)}
|
||||
>
|
||||
<Icon fitted name="arrow left" />
|
||||
</Menu.Item>
|
||||
<Tooltip content={t('action.returnToProjects')}>
|
||||
<Menu.Item
|
||||
as={Link}
|
||||
to={Paths.ROOT}
|
||||
className={classNames(styles.item, styles.itemHoverable)}
|
||||
>
|
||||
<Icon fitted name="arrow left" />
|
||||
</Menu.Item>
|
||||
</Tooltip>
|
||||
<Menu.Item className={classNames(styles.item, styles.title)}>
|
||||
{project.name}
|
||||
{canEditProject && (
|
||||
<Button className={styles.editButton} onClick={handleProjectSettingsClick}>
|
||||
<Icon fitted name="pencil" size="small" />
|
||||
</Button>
|
||||
<Tooltip content={t('common.openProjectSettings')}>
|
||||
<Button className={styles.editButton} onClick={handleProjectSettingsClick}>
|
||||
<Icon fitted name="pencil" size="small" />
|
||||
</Button>
|
||||
</Tooltip>
|
||||
)}
|
||||
</Menu.Item>
|
||||
</Menu.Menu>
|
||||
)}
|
||||
<Menu.Menu position="right">
|
||||
{withFavoritesToggler && (
|
||||
<Menu.Item
|
||||
className={classNames(styles.item, styles.itemHoverable)}
|
||||
onClick={handleToggleFavoritesClick}
|
||||
<Tooltip
|
||||
content={t(isFavoritesEnabled ? 'action.hideProjectList' : 'action.showProjectList')}
|
||||
>
|
||||
<Icon
|
||||
fitted
|
||||
name={isFavoritesEnabled ? 'star' : 'star outline'}
|
||||
className={classNames(isFavoritesEnabled && styles.itemIconEnabled)}
|
||||
/>
|
||||
</Menu.Item>
|
||||
<Menu.Item
|
||||
className={classNames(styles.item, styles.itemHoverable)}
|
||||
onClick={handleToggleFavoritesClick}
|
||||
>
|
||||
<Icon
|
||||
fitted
|
||||
name={isFavoritesEnabled ? 'star' : 'star outline'}
|
||||
className={classNames(isFavoritesEnabled && styles.itemIconEnabled)}
|
||||
/>
|
||||
</Menu.Item>
|
||||
</Tooltip>
|
||||
)}
|
||||
{withEditModeToggler && (
|
||||
<Menu.Item
|
||||
className={classNames(styles.item, styles.itemHoverable)}
|
||||
onClick={handleToggleEditModeClick}
|
||||
<Tooltip
|
||||
content={t(isEditModeEnabled ? 'action.disableEditMode' : 'action.enableEditMode')}
|
||||
>
|
||||
<Icon
|
||||
fitted
|
||||
name={isEditModeEnabled ? 'unlock' : 'lock'}
|
||||
className={classNames(isEditModeEnabled && styles.itemIconEnabled)}
|
||||
/>
|
||||
</Menu.Item>
|
||||
<Menu.Item
|
||||
className={classNames(styles.item, styles.itemHoverable)}
|
||||
onClick={handleToggleEditModeClick}
|
||||
>
|
||||
<Icon
|
||||
fitted
|
||||
name={isEditModeEnabled ? 'unlock' : 'lock'}
|
||||
className={classNames(isEditModeEnabled && styles.itemIconEnabled)}
|
||||
/>
|
||||
</Menu.Item>
|
||||
</Tooltip>
|
||||
)}
|
||||
<NotificationsPopup>
|
||||
<Menu.Item className={classNames(styles.item, styles.itemHoverable)}>
|
||||
<Icon fitted name="bell" />
|
||||
{notificationIds.length > 0 && (
|
||||
<span className={styles.notification}>{notificationIds.length}</span>
|
||||
)}
|
||||
</Menu.Item>
|
||||
<Tooltip content={t('common.openNotifications')}>
|
||||
<Menu.Item className={classNames(styles.item, styles.itemHoverable)}>
|
||||
<Icon fitted name="bell" />
|
||||
{notificationIds.length > 0 && (
|
||||
<span className={styles.notification}>{notificationIds.length}</span>
|
||||
)}
|
||||
</Menu.Item>
|
||||
</Tooltip>
|
||||
</NotificationsPopup>
|
||||
<UserActionsPopup>
|
||||
<Menu.Item className={classNames(styles.item, styles.itemHoverable)}>
|
||||
|
||||
@@ -6,7 +6,9 @@
|
||||
import React, { useCallback } from 'react';
|
||||
import classNames from 'classnames';
|
||||
import { useDispatch, useSelector } from 'react-redux';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { Icon } from 'semantic-ui-react';
|
||||
import { Tooltip } from '../../../../lib/custom-ui';
|
||||
import { usePopup } from '../../../../lib/popup';
|
||||
|
||||
import selectors from '../../../../selectors';
|
||||
@@ -17,12 +19,18 @@ import SelectOrderStep from './SelectOrderStep';
|
||||
|
||||
import styles from './RightSide.module.scss';
|
||||
|
||||
const LABEL_BY_VIEW = {
|
||||
[HomeViews.GRID_PROJECTS]: 'common.gridProjects',
|
||||
[HomeViews.GROUPED_PROJECTS]: 'common.groupedProjects',
|
||||
};
|
||||
|
||||
const RightSide = React.memo(() => {
|
||||
const currentView = useSelector(selectors.selectHomeView); // TODO: rename?
|
||||
const currentOrder = useSelector(selectors.selectProjectsOrder); // TODO: rename?
|
||||
const isHiddenVisible = useSelector(selectors.selectIsHiddenProjectsVisible);
|
||||
|
||||
const dispatch = useDispatch();
|
||||
const [t] = useTranslation();
|
||||
|
||||
const handleSelectViewClick = useCallback(
|
||||
({ currentTarget: { value: view } }) => {
|
||||
@@ -47,34 +55,47 @@ const RightSide = React.memo(() => {
|
||||
return (
|
||||
<>
|
||||
<div className={styles.action}>
|
||||
<button
|
||||
type="button"
|
||||
className={classNames(styles.button)}
|
||||
onClick={handleToggleHiddenClick}
|
||||
<Tooltip
|
||||
content={t(isHiddenVisible ? 'action.hideHiddenProjects' : 'common.showHiddenProjects')}
|
||||
>
|
||||
<Icon fitted name={isHiddenVisible ? 'eye slash' : 'eye'} />
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
className={classNames(styles.button)}
|
||||
onClick={handleToggleHiddenClick}
|
||||
>
|
||||
<Icon fitted name={isHiddenVisible ? 'eye slash' : 'eye'} />
|
||||
</button>
|
||||
</Tooltip>
|
||||
</div>
|
||||
<div className={styles.action}>
|
||||
<SelectOrderPopup value={currentOrder} onSelect={handleOrderSelect}>
|
||||
<button type="button" className={styles.button}>
|
||||
<Icon fitted name={ProjectOrderIcons[currentOrder]} />
|
||||
</button>
|
||||
<Tooltip content={t('common.selectOrder', { context: 'title' })}>
|
||||
<button type="button" className={styles.button}>
|
||||
<Icon fitted name={ProjectOrderIcons[currentOrder]} />
|
||||
</button>
|
||||
</Tooltip>
|
||||
</SelectOrderPopup>
|
||||
</div>
|
||||
<div className={styles.action}>
|
||||
<div className={styles.buttonGroup}>
|
||||
{[HomeViews.GRID_PROJECTS, HomeViews.GROUPED_PROJECTS].map((view) => (
|
||||
<button
|
||||
<Tooltip
|
||||
key={view}
|
||||
type="button"
|
||||
value={view}
|
||||
content={t('action.switchToView', {
|
||||
view: t(LABEL_BY_VIEW[view]),
|
||||
})}
|
||||
disabled={view === currentView}
|
||||
className={styles.button}
|
||||
onClick={handleSelectViewClick}
|
||||
>
|
||||
<Icon fitted name={HomeViewIcons[view]} />
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
value={view}
|
||||
disabled={view === currentView}
|
||||
className={styles.button}
|
||||
onClick={handleSelectViewClick}
|
||||
>
|
||||
<Icon fitted name={HomeViewIcons[view]} />
|
||||
</button>
|
||||
</Tooltip>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -8,7 +8,9 @@ import ReactDOM from 'react-dom';
|
||||
import PropTypes from 'prop-types';
|
||||
import { useSelector } from 'react-redux';
|
||||
import { Draggable } from 'react-beautiful-dnd';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { Button, Icon } from 'semantic-ui-react';
|
||||
import { Tooltip } from '../../../lib/custom-ui';
|
||||
|
||||
import selectors from '../../../selectors';
|
||||
|
||||
@@ -18,6 +20,7 @@ const CustomField = React.memo(({ id, index, onEdit }) => {
|
||||
const selectCustomFieldById = useMemo(() => selectors.makeSelectCustomFieldById(), []);
|
||||
|
||||
const customField = useSelector((state) => selectCustomFieldById(state, id));
|
||||
const [t] = useTranslation();
|
||||
|
||||
const handleEditClick = useCallback(() => {
|
||||
onEdit(id);
|
||||
@@ -36,14 +39,16 @@ const CustomField = React.memo(({ id, index, onEdit }) => {
|
||||
{customField.showOnFrontOfCard && <Icon name="pin" className={styles.nameIcon} />}
|
||||
{customField.name}
|
||||
</span>
|
||||
<Button
|
||||
icon="pencil"
|
||||
size="small"
|
||||
floated="right"
|
||||
disabled={!customField.isPersisted}
|
||||
className={styles.editButton}
|
||||
onClick={handleEditClick}
|
||||
/>
|
||||
<Tooltip content={t('action.edit', { context: 'title' })}>
|
||||
<Button
|
||||
icon="pencil"
|
||||
size="small"
|
||||
floated="right"
|
||||
disabled={!customField.isPersisted}
|
||||
className={styles.editButton}
|
||||
onClick={handleEditClick}
|
||||
/>
|
||||
</Tooltip>
|
||||
</div>
|
||||
);
|
||||
|
||||
|
||||
@@ -8,7 +8,9 @@ import ReactDOM from 'react-dom';
|
||||
import PropTypes from 'prop-types';
|
||||
import { useSelector } from 'react-redux';
|
||||
import { Draggable } from 'react-beautiful-dnd';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { Button } from 'semantic-ui-react';
|
||||
import { Tooltip } from '../../../lib/custom-ui';
|
||||
|
||||
import selectors from '../../../selectors';
|
||||
|
||||
@@ -18,6 +20,7 @@ const Item = React.memo(({ id, index, onEdit }) => {
|
||||
const selectCustomFieldGroupById = useMemo(() => selectors.makeSelectCustomFieldGroupById(), []);
|
||||
|
||||
const customFieldGroup = useSelector((state) => selectCustomFieldGroupById(state, id));
|
||||
const [t] = useTranslation();
|
||||
|
||||
const handleEditClick = useCallback(() => {
|
||||
onEdit(id);
|
||||
@@ -35,14 +38,16 @@ const Item = React.memo(({ id, index, onEdit }) => {
|
||||
>
|
||||
{customFieldGroup.name}
|
||||
</span>
|
||||
<Button
|
||||
icon="pencil"
|
||||
size="small"
|
||||
floated="right"
|
||||
disabled={!customFieldGroup.isPersisted}
|
||||
className={styles.editButton}
|
||||
onClick={handleEditClick}
|
||||
/>
|
||||
<Tooltip content={t('action.editGroup')}>
|
||||
<Button
|
||||
icon="pencil"
|
||||
size="small"
|
||||
floated="right"
|
||||
disabled={!customFieldGroup.isPersisted}
|
||||
className={styles.editButton}
|
||||
onClick={handleEditClick}
|
||||
/>
|
||||
</Tooltip>
|
||||
</div>
|
||||
);
|
||||
|
||||
|
||||
@@ -6,7 +6,9 @@
|
||||
import React, { useCallback, useMemo, useState } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { useDispatch, useSelector } from 'react-redux';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { Button, Icon } from 'semantic-ui-react';
|
||||
import { Tooltip } from '../../../lib/custom-ui';
|
||||
|
||||
import selectors from '../../../selectors';
|
||||
import entryActions from '../../../entry-actions';
|
||||
@@ -49,6 +51,7 @@ const CustomField = React.memo(({ id, customFieldGroupId }) => {
|
||||
});
|
||||
|
||||
const dispatch = useDispatch();
|
||||
const [t] = useTranslation();
|
||||
const [isCopied, setIsCopied] = useState(false);
|
||||
|
||||
const handleValueUpdate = useCallback(
|
||||
@@ -95,9 +98,11 @@ const CustomField = React.memo(({ id, customFieldGroupId }) => {
|
||||
</div>
|
||||
)}
|
||||
{customFieldValue && customFieldValue.content && (
|
||||
<Button className={styles.copyButton} onClick={handleCopyClick}>
|
||||
<Icon fitted name={isCopied ? 'check' : 'copy'} />
|
||||
</Button>
|
||||
<Tooltip content={t('action.copy')}>
|
||||
<Button className={styles.copyButton} onClick={handleCopyClick}>
|
||||
<Icon fitted name={isCopied ? 'check' : 'copy'} />
|
||||
</Button>
|
||||
</Tooltip>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -11,7 +11,9 @@ import PropTypes from 'prop-types';
|
||||
import classNames from 'classnames';
|
||||
import { useSelector } from 'react-redux';
|
||||
import { Draggable } from 'react-beautiful-dnd';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { Button } from 'semantic-ui-react';
|
||||
import { Tooltip } from '../../../lib/custom-ui';
|
||||
|
||||
import selectors from '../../../selectors';
|
||||
import { BoardMembershipRoles } from '../../../constants/Enums';
|
||||
@@ -23,6 +25,7 @@ const Item = React.memo(({ id, index, isActive, onSelect, onDeselect, onEdit })
|
||||
const selectLabelById = useMemo(() => selectors.makeSelectLabelById(), []);
|
||||
|
||||
const label = useSelector((state) => selectLabelById(state, id));
|
||||
const [t] = useTranslation();
|
||||
|
||||
const canEdit = useSelector((state) => {
|
||||
const boardMembership = selectors.selectCurrentUserMembershipForCurrentBoard(state);
|
||||
@@ -63,14 +66,16 @@ const Item = React.memo(({ id, index, isActive, onSelect, onDeselect, onEdit })
|
||||
{label.name}
|
||||
</span>
|
||||
{canEdit && (
|
||||
<Button
|
||||
icon="pencil"
|
||||
size="small"
|
||||
floated="right"
|
||||
disabled={!label.isPersisted}
|
||||
className={styles.editButton}
|
||||
onClick={handleEditClick}
|
||||
/>
|
||||
<Tooltip content={t('action.edit', { context: 'title' })}>
|
||||
<Button
|
||||
icon="pencil"
|
||||
size="small"
|
||||
floated="right"
|
||||
disabled={!label.isPersisted}
|
||||
className={styles.editButton}
|
||||
onClick={handleEditClick}
|
||||
/>
|
||||
</Tooltip>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -13,6 +13,7 @@ import { useTranslation } from 'react-i18next';
|
||||
import { Draggable, Droppable } from 'react-beautiful-dnd';
|
||||
import { Button, Icon } from 'semantic-ui-react';
|
||||
import { useDidUpdate, useToggle, useTransitioning } from '../../../lib/hooks';
|
||||
import { Tooltip } from '../../../lib/custom-ui';
|
||||
import { usePopup } from '../../../lib/popup';
|
||||
|
||||
import selectors from '../../../selectors';
|
||||
@@ -240,16 +241,20 @@ const List = React.memo(({ id, index }) => {
|
||||
{list.isPersisted &&
|
||||
(canEdit ? (
|
||||
<ActionsPopup listId={id} onNameEdit={handleNameEdit} onCardAdd={handleCardAdd}>
|
||||
<Button className={styles.headerButton}>
|
||||
<Icon fitted name="pencil" size="small" />
|
||||
</Button>
|
||||
<Tooltip content={t('common.openListActions')}>
|
||||
<Button className={styles.headerButton}>
|
||||
<Icon fitted name="pencil" size="small" />
|
||||
</Button>
|
||||
</Tooltip>
|
||||
</ActionsPopup>
|
||||
) : (
|
||||
canArchiveCards && (
|
||||
<ArchiveCardsPopup listId={id}>
|
||||
<Button className={styles.headerButton}>
|
||||
<Icon fitted name="archive" size="small" />
|
||||
</Button>
|
||||
<Tooltip content={t('action.archiveCards')}>
|
||||
<Button className={styles.headerButton}>
|
||||
<Icon fitted name="archive" size="small" />
|
||||
</Button>
|
||||
</Tooltip>
|
||||
</ArchiveCardsPopup>
|
||||
)
|
||||
))}
|
||||
@@ -275,14 +280,16 @@ const List = React.memo(({ id, index }) => {
|
||||
</span>
|
||||
</button>
|
||||
{clipboard && canPasteCard && (
|
||||
<button
|
||||
type="button"
|
||||
disabled={!list.isPersisted}
|
||||
className={classNames(styles.addCardButton, styles.paste)}
|
||||
onClick={handlePasteCardClick}
|
||||
>
|
||||
<Icon name="paste" />
|
||||
</button>
|
||||
<Tooltip content={t('action.paste')}>
|
||||
<button
|
||||
type="button"
|
||||
disabled={!list.isPersisted}
|
||||
className={classNames(styles.addCardButton, styles.paste)}
|
||||
onClick={handlePasteCardClick}
|
||||
>
|
||||
<Icon name="paste" />
|
||||
</button>
|
||||
</Tooltip>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
|
||||
@@ -6,8 +6,10 @@
|
||||
import React, { useCallback, useMemo, useRef } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { useDispatch, useSelector } from 'react-redux';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { Button, Dropdown, Form, Icon, Input } from 'semantic-ui-react';
|
||||
import { useDidUpdate, usePrevious, useToggle } from '../../../lib/hooks';
|
||||
import { Tooltip } from '../../../lib/custom-ui';
|
||||
|
||||
import selectors from '../../../selectors';
|
||||
import entryActions from '../../../entry-actions';
|
||||
@@ -31,6 +33,7 @@ const Item = React.memo(({ id }) => {
|
||||
const notificationService = useSelector((state) => selectNotificationServiceById(state, id));
|
||||
|
||||
const dispatch = useDispatch();
|
||||
const [t] = useTranslation();
|
||||
|
||||
const defaultData = useMemo(
|
||||
() => ({
|
||||
@@ -183,24 +186,32 @@ const Item = React.memo(({ id }) => {
|
||||
onChange={handleFieldChange}
|
||||
onBlur={handleUrlBlur}
|
||||
/>
|
||||
<Button
|
||||
type="button"
|
||||
loading={notificationService.isTesting}
|
||||
disabled={!notificationService.isPersisted || notificationService.isTesting}
|
||||
className={styles.button}
|
||||
onClick={handleTestClick}
|
||||
>
|
||||
<Icon fitted name="paper plane outline" />
|
||||
</Button>
|
||||
<Tooltip content={t('action.sendTestEmail')}>
|
||||
<Button
|
||||
type="button"
|
||||
loading={notificationService.isTesting}
|
||||
disabled={!notificationService.isPersisted || notificationService.isTesting}
|
||||
className={styles.button}
|
||||
onClick={handleTestClick}
|
||||
>
|
||||
<Icon fitted name="paper plane outline" />
|
||||
</Button>
|
||||
</Tooltip>
|
||||
<ConfirmationPopup
|
||||
title="common.deleteNotificationService"
|
||||
content="common.areYouSureYouWantToDeleteThisNotificationService"
|
||||
buttonContent="action.deleteNotificationService"
|
||||
onConfirm={handleDeleteConfirm}
|
||||
>
|
||||
<Button type="button" disabled={!notificationService.isPersisted} className={styles.button}>
|
||||
<Icon fitted name="trash alternate outline" />
|
||||
</Button>
|
||||
<Tooltip content={t('action.deleteNotificationService')}>
|
||||
<Button
|
||||
type="button"
|
||||
disabled={!notificationService.isPersisted}
|
||||
className={styles.button}
|
||||
>
|
||||
<Icon fitted name="trash alternate outline" />
|
||||
</Button>
|
||||
</Tooltip>
|
||||
</ConfirmationPopup>
|
||||
</Form>
|
||||
);
|
||||
|
||||
+9
-4
@@ -6,9 +6,10 @@
|
||||
import React, { useCallback, useEffect } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import classNames from 'classnames';
|
||||
import { Trans } from 'react-i18next';
|
||||
import { Trans, useTranslation } from 'react-i18next';
|
||||
import { Button, Dropdown, Form, Icon, Input, Message } from 'semantic-ui-react';
|
||||
import { useDidUpdate, useToggle } from '../../../lib/hooks';
|
||||
import { Tooltip } from '../../../lib/custom-ui';
|
||||
|
||||
import { useEscapeInterceptor, useForm, useNestedRef } from '../../../hooks';
|
||||
import { NotificationServiceFormats } from '../../../constants/Enums';
|
||||
@@ -22,6 +23,8 @@ const DEFAULT_DATA = {
|
||||
};
|
||||
|
||||
const NotificationServices = React.memo(({ ids, onCreate }) => {
|
||||
const [t] = useTranslation();
|
||||
|
||||
const [data, handleFieldChange, setData] = useForm(DEFAULT_DATA);
|
||||
const [focusUrlFieldState, focusUrlField] = useToggle();
|
||||
|
||||
@@ -117,9 +120,11 @@ const NotificationServices = React.memo(({ ids, onCreate }) => {
|
||||
onChange={handleFieldChange}
|
||||
onBlur={handleUrlBlur}
|
||||
/>
|
||||
<Button positive className={styles.button}>
|
||||
<Icon fitted name="plus" />
|
||||
</Button>
|
||||
<Tooltip content={t('common.addNotificationService', { context: 'title' })}>
|
||||
<Button positive className={styles.button}>
|
||||
<Icon fitted name="plus" />
|
||||
</Button>
|
||||
</Tooltip>
|
||||
</Form>
|
||||
)}
|
||||
</>
|
||||
|
||||
@@ -5,7 +5,9 @@
|
||||
|
||||
import React from 'react';
|
||||
import { useSelector } from 'react-redux';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { Button } from 'semantic-ui-react';
|
||||
import { Tooltip } from '../../../lib/custom-ui';
|
||||
|
||||
import selectors from '../../../selectors';
|
||||
import { usePopupInClosableContext } from '../../../hooks';
|
||||
@@ -18,6 +20,7 @@ import styles from './ProjectManagers.module.scss';
|
||||
|
||||
const ProjectManagers = React.memo(() => {
|
||||
const projectManagers = useSelector(selectors.selectManagersForCurrentProject);
|
||||
const [t] = useTranslation();
|
||||
|
||||
const canAdd = useSelector((state) => {
|
||||
const user = selectors.selectCurrentUser(state);
|
||||
@@ -47,7 +50,9 @@ const ProjectManagers = React.memo(() => {
|
||||
))}
|
||||
{canAdd && (
|
||||
<AddPopup>
|
||||
<Button icon="add user" className={styles.addButton} />
|
||||
<Tooltip content={t('action.addMember')}>
|
||||
<Button icon="add user" className={styles.addButton} />
|
||||
</Tooltip>
|
||||
</AddPopup>
|
||||
)}
|
||||
</div>
|
||||
|
||||
@@ -5,7 +5,9 @@
|
||||
|
||||
import React, { useCallback } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { Button, Icon, Label } from 'semantic-ui-react';
|
||||
import { Tooltip } from '../../../../lib/custom-ui';
|
||||
|
||||
import { usePopupInClosableContext } from '../../../../hooks';
|
||||
import ConfirmationStep from '../../../common/ConfirmationStep';
|
||||
@@ -13,6 +15,8 @@ import ConfirmationStep from '../../../common/ConfirmationStep';
|
||||
import styles from './Image.module.scss';
|
||||
|
||||
const Image = React.memo(({ url, isActive, onSelect, onDeselect, onDelete }) => {
|
||||
const [t] = useTranslation();
|
||||
|
||||
const handleClick = useCallback(() => {
|
||||
if (isActive) {
|
||||
onDeselect();
|
||||
@@ -52,9 +56,11 @@ const Image = React.memo(({ url, isActive, onSelect, onDeselect, onDelete }) =>
|
||||
buttonContent="action.deleteBackgroundImage"
|
||||
onConfirm={onDelete}
|
||||
>
|
||||
<Button className={styles.deleteButton}>
|
||||
<Icon fitted name="trash alternate" size="small" />
|
||||
</Button>
|
||||
<Tooltip content={t('action.deleteBackgroundImage')}>
|
||||
<Button className={styles.deleteButton}>
|
||||
<Icon fitted name="trash alternate" size="small" />
|
||||
</Button>
|
||||
</Tooltip>
|
||||
</ConfirmationPopup>
|
||||
)}
|
||||
</div>
|
||||
|
||||
@@ -10,8 +10,10 @@ import classNames from 'classnames';
|
||||
import { shallowEqual, useDispatch, useSelector } from 'react-redux';
|
||||
import { Link } from 'react-router';
|
||||
import { Draggable } from 'react-beautiful-dnd';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { Button, Checkbox, Icon } from 'semantic-ui-react';
|
||||
import { useDidUpdate } from '../../../../lib/hooks';
|
||||
import { Tooltip } from '../../../../lib/custom-ui';
|
||||
|
||||
import selectors from '../../../../selectors';
|
||||
import entryActions from '../../../../entry-actions';
|
||||
@@ -60,6 +62,7 @@ const Task = React.memo(({ id, index }) => {
|
||||
}, shallowEqual);
|
||||
|
||||
const dispatch = useDispatch();
|
||||
const [t] = useTranslation();
|
||||
const [isEditNameOpened, setIsEditNameOpened] = useState(false);
|
||||
const [, , setIsClosableActive] = useContext(ClosableContext);
|
||||
|
||||
@@ -203,16 +206,20 @@ const Task = React.memo(({ id, index }) => {
|
||||
className={styles.assigneeUserAvatar}
|
||||
/>
|
||||
) : (
|
||||
<Button className={styles.button}>
|
||||
<Icon fitted name="add user" size="small" />
|
||||
</Button>
|
||||
<Tooltip content={t('common.selectAssignee', { context: 'title' })}>
|
||||
<Button className={styles.button}>
|
||||
<Icon fitted name="add user" size="small" />
|
||||
</Button>
|
||||
</Tooltip>
|
||||
)}
|
||||
</SelectAssigneePopup>
|
||||
)}
|
||||
<ActionsPopup taskId={id} onNameEdit={handleNameEdit}>
|
||||
<Button className={styles.button}>
|
||||
<Icon fitted name="pencil" size="small" />
|
||||
</Button>
|
||||
<Tooltip content={t('common.taskActions', { context: 'title' })}>
|
||||
<Button className={styles.button}>
|
||||
<Icon fitted name="pencil" size="small" />
|
||||
</Button>
|
||||
</Tooltip>
|
||||
</ActionsPopup>
|
||||
</>
|
||||
) : (
|
||||
|
||||
Reference in New Issue
Block a user