Adding menu options in sidebar, and improving order (#3713)
* Adding category and board options at the top * Updating UI * Updating test * Updating test * Updating icon * Fixing bug and translation * Updating createCategory component * Removing unused vars * Removing unused vars * Updating UI * fixed tests * fixed tests * fixed tests * Updating test Co-authored-by: Mattermod <mattermod@users.noreply.github.com> Co-authored-by: Harshil Sharma <harshilsharma63@gmail.com>
This commit is contained in:
parent
61a8af8f34
commit
62ffa9c39a
24 changed files with 355 additions and 246 deletions
|
@ -23,7 +23,7 @@ exports[`components/boardSelector renders with no results 1`] = `
|
|||
>
|
||||
<button
|
||||
aria-label="Close dialog"
|
||||
class="IconButton size--medium"
|
||||
class="IconButton dialog__close size--medium"
|
||||
title="Close dialog"
|
||||
type="button"
|
||||
>
|
||||
|
@ -126,7 +126,7 @@ exports[`components/boardSelector renders with some results 1`] = `
|
|||
>
|
||||
<button
|
||||
aria-label="Close dialog"
|
||||
class="IconButton size--medium"
|
||||
class="IconButton dialog__close size--medium"
|
||||
title="Close dialog"
|
||||
type="button"
|
||||
>
|
||||
|
@ -327,7 +327,7 @@ exports[`components/boardSelector renders without start searching 1`] = `
|
|||
>
|
||||
<button
|
||||
aria-label="Close dialog"
|
||||
class="IconButton size--medium"
|
||||
class="IconButton dialog__close size--medium"
|
||||
title="Close dialog"
|
||||
type="button"
|
||||
>
|
||||
|
|
|
@ -23,15 +23,8 @@
|
|||
position: relative;
|
||||
width: 600px;
|
||||
height: 450px;
|
||||
|
||||
.toolbar {
|
||||
flex-direction: row-reverse;
|
||||
padding: 0;
|
||||
position: absolute;
|
||||
right: 18px;
|
||||
top: 18px;
|
||||
}
|
||||
}
|
||||
|
||||
.confirmation-dialog-box {
|
||||
.dialog {
|
||||
position: fixed;
|
||||
|
|
|
@ -242,6 +242,7 @@
|
|||
"Sidebar.untitled-view": "(Untitled View)",
|
||||
"SidebarCategories.BlocksMenu.Move": "Move To...",
|
||||
"SidebarCategories.CategoryMenu.CreateNew": "Create New Category",
|
||||
"SidebarCategories.CategoryMenu.CreateBoard": "Create New Board",
|
||||
"SidebarCategories.CategoryMenu.Delete": "Delete Category",
|
||||
"SidebarCategories.CategoryMenu.DeleteModal.Body": "Boards in <b>{categoryName}</b> will move back to the Boards categories. You're not removed from any boards.",
|
||||
"SidebarCategories.CategoryMenu.DeleteModal.Title": "Delete this category?",
|
||||
|
@ -400,4 +401,4 @@
|
|||
"tutorial_tip.ok": "Next",
|
||||
"tutorial_tip.out": "Opt out of these tips.",
|
||||
"tutorial_tip.seen": "Seen this before?"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,7 +20,7 @@ exports[`/components/confirmationDialogBox confirmDialog should match snapshot 1
|
|||
>
|
||||
<button
|
||||
aria-label="Close dialog"
|
||||
class="IconButton size--medium"
|
||||
class="IconButton dialog__close size--medium"
|
||||
title="Close dialog"
|
||||
type="button"
|
||||
>
|
||||
|
@ -95,7 +95,7 @@ exports[`/components/confirmationDialogBox confirmDialog with Confirm Button Tex
|
|||
>
|
||||
<button
|
||||
aria-label="Close dialog"
|
||||
class="IconButton size--medium"
|
||||
class="IconButton dialog__close size--medium"
|
||||
title="Close dialog"
|
||||
type="button"
|
||||
>
|
||||
|
|
|
@ -20,7 +20,7 @@ exports[`components/dialog should match snapshot 1`] = `
|
|||
>
|
||||
<button
|
||||
aria-label="Close dialog"
|
||||
class="IconButton size--medium"
|
||||
class="IconButton dialog__close size--medium"
|
||||
title="Close dialog"
|
||||
type="button"
|
||||
>
|
||||
|
@ -61,7 +61,7 @@ exports[`components/dialog should return dialog and click on cancel button 1`] =
|
|||
>
|
||||
<button
|
||||
aria-label="Close dialog"
|
||||
class="IconButton size--medium"
|
||||
class="IconButton dialog__close size--medium"
|
||||
title="Close dialog"
|
||||
type="button"
|
||||
>
|
||||
|
|
|
@ -9,8 +9,8 @@
|
|||
background-color: rgba(var(--sidebar-text-rgb), 0.08);
|
||||
color: rgba(var(--sidebar-text-rgb), 0.56);
|
||||
flex: 1;
|
||||
padding: 6px 8px;
|
||||
gap: 6px;
|
||||
padding: 6px 8px 6px 4px;
|
||||
gap: 4px;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
height: 28px;
|
||||
|
@ -28,9 +28,17 @@
|
|||
}
|
||||
|
||||
.add-board-icon {
|
||||
margin-left: 4px;
|
||||
border-radius: 28px;
|
||||
margin-left: 8px;
|
||||
width: 28px;
|
||||
height: 28px;
|
||||
flex: 0 0 28px;
|
||||
background-color: rgba(var(--sidebar-text-rgb), 0.08);
|
||||
color: rgba(var(--sidebar-text-rgb), 0.72);
|
||||
|
||||
&:hover {
|
||||
background-color: rgba(var(--sidebar-text-rgb), 0.16);
|
||||
color: var(--sidebar-text);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,17 +2,19 @@
|
|||
// See LICENSE.txt for license information.
|
||||
import React, {useEffect, useState} from 'react'
|
||||
|
||||
import {useIntl} from 'react-intl'
|
||||
import {FormattedMessage, useIntl} from 'react-intl'
|
||||
|
||||
import MenuWrapper from '../../widgets/menuWrapper'
|
||||
import CompassIcon from '../../widgets/icons/compassIcon'
|
||||
import Menu from '../../widgets/menu'
|
||||
import Search from '../../widgets/icons/search'
|
||||
|
||||
import CreateCategory from '../createCategory/createCategory'
|
||||
import {useAppSelector} from '../../store/hooks'
|
||||
|
||||
import {
|
||||
getOnboardingTourCategory,
|
||||
getOnboardingTourStep,
|
||||
} from '../../store/users'
|
||||
|
||||
import {getCurrentCard} from '../../store/cards'
|
||||
|
||||
import './boardsSwitcher.scss'
|
||||
|
@ -26,7 +28,7 @@ import IconButton from '../../widgets/buttons/iconButton'
|
|||
import SearchForBoardsTourStep from '../../components/onboardingTour/searchForBoards/searchForBoards'
|
||||
|
||||
type Props = {
|
||||
onBoardTemplateSelectorOpen?: () => void,
|
||||
onBoardTemplateSelectorOpen: () => void,
|
||||
userIsGuest?: boolean,
|
||||
}
|
||||
|
||||
|
@ -35,11 +37,11 @@ const BoardsSwitcher = (props: Props): JSX.Element => {
|
|||
|
||||
const [showSwitcher, setShowSwitcher] = useState<boolean>(false)
|
||||
const onboardingTourCategory = useAppSelector(getOnboardingTourCategory)
|
||||
const [showCreateCategoryModal, setShowCreateCategoryModal] = useState(false)
|
||||
const onboardingTourStep = useAppSelector(getOnboardingTourStep)
|
||||
const currentCard = useAppSelector(getCurrentCard)
|
||||
const noCardOpen = !currentCard
|
||||
|
||||
|
||||
const shouldViewSearchForBoardsTour = noCardOpen &&
|
||||
onboardingTourCategory === TOUR_SIDEBAR &&
|
||||
onboardingTourStep === SidebarTourSteps.SEARCH_FOR_BOARDS.toString()
|
||||
|
@ -68,6 +70,10 @@ const BoardsSwitcher = (props: Props): JSX.Element => {
|
|||
}
|
||||
}
|
||||
|
||||
const handleCreateNewCategory = () => {
|
||||
setShowCreateCategoryModal(true)
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
document.addEventListener('keydown', handleQuickSwitchKeyPress)
|
||||
document.addEventListener('keydown', handleEscKeyPress)
|
||||
|
@ -95,19 +101,53 @@ const BoardsSwitcher = (props: Props): JSX.Element => {
|
|||
{shouldViewSearchForBoardsTour && <div><SearchForBoardsTourStep/></div>}
|
||||
{
|
||||
Utils.isFocalboardPlugin() && !props.userIsGuest &&
|
||||
<IconButton
|
||||
size='small'
|
||||
inverted={true}
|
||||
className='add-board-icon'
|
||||
onClick={props.onBoardTemplateSelectorOpen}
|
||||
icon={<AddIcon/>}
|
||||
/>
|
||||
<MenuWrapper>
|
||||
<IconButton
|
||||
size='small'
|
||||
inverted={true}
|
||||
className='add-board-icon'
|
||||
icon={<AddIcon/>}
|
||||
/>
|
||||
<Menu>
|
||||
<Menu.Text
|
||||
id='create-new-board-option'
|
||||
icon={<CompassIcon icon='plus' />}
|
||||
onClick={props.onBoardTemplateSelectorOpen}
|
||||
name='Create new board'
|
||||
/>
|
||||
<Menu.Text
|
||||
id='createNewCategory'
|
||||
name={intl.formatMessage({id: 'SidebarCategories.CategoryMenu.CreateNew', defaultMessage: 'Create New Category'})}
|
||||
icon={
|
||||
<CompassIcon
|
||||
icon='folder-plus-outline'
|
||||
className='CreateNewFolderIcon'
|
||||
/>
|
||||
}
|
||||
onClick={handleCreateNewCategory}
|
||||
/>
|
||||
</Menu>
|
||||
</MenuWrapper>
|
||||
}
|
||||
|
||||
{
|
||||
showSwitcher &&
|
||||
<BoardSwitcherDialog onClose={() => setShowSwitcher(false)} />
|
||||
}
|
||||
|
||||
{
|
||||
showCreateCategoryModal && (
|
||||
<CreateCategory
|
||||
onClose={() => setShowCreateCategoryModal(false)}
|
||||
title={(
|
||||
<FormattedMessage
|
||||
id='SidebarCategories.CategoryMenu.CreateNew'
|
||||
defaultMessage='Create New Category'
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
)
|
||||
}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
|
|
@ -20,7 +20,7 @@ exports[`component/BoardSwitcherDialog base case 1`] = `
|
|||
>
|
||||
<button
|
||||
aria-label="Close dialog"
|
||||
class="IconButton size--medium"
|
||||
class="IconButton dialog__close size--medium"
|
||||
title="Close dialog"
|
||||
type="button"
|
||||
>
|
||||
|
|
|
@ -10,10 +10,6 @@
|
|||
color: rgba(var(--center-channel-color-rgb), 0.56);
|
||||
}
|
||||
|
||||
.toolbar {
|
||||
padding: 4px;
|
||||
}
|
||||
|
||||
span {
|
||||
display: inline-block;
|
||||
height: 100%;
|
||||
|
|
|
@ -20,7 +20,7 @@ exports[`components/createCategory/CreateCategory base case should match snapsho
|
|||
>
|
||||
<button
|
||||
aria-label="Close dialog"
|
||||
class="IconButton size--medium"
|
||||
class="IconButton dialog__close size--medium"
|
||||
title="Close dialog"
|
||||
type="button"
|
||||
>
|
||||
|
@ -35,7 +35,9 @@ exports[`components/createCategory/CreateCategory base case should match snapsho
|
|||
<div
|
||||
class="CreateCategory"
|
||||
>
|
||||
<h3>
|
||||
<h3
|
||||
class="dialog-title"
|
||||
>
|
||||
<span>
|
||||
title
|
||||
</span>
|
||||
|
|
|
@ -4,20 +4,14 @@
|
|||
.wrapper {
|
||||
.dialog {
|
||||
width: 600px;
|
||||
height: 260px;
|
||||
}
|
||||
|
||||
.toolbar {
|
||||
flex-direction: row-reverse;
|
||||
padding: 2px 6px;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
.CreateCategory {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding: 0 40px 30px;
|
||||
gap: 12px;
|
||||
flex: 1;
|
||||
padding: 0 32px 24px;
|
||||
gap: 24px;
|
||||
|
||||
.inputWrapper {
|
||||
position: relative;
|
||||
|
@ -38,18 +32,20 @@
|
|||
width: 100%;
|
||||
}
|
||||
|
||||
h3 {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
input {
|
||||
height: 48px;
|
||||
font-size: 16px;
|
||||
padding: 6px 12px;
|
||||
border-radius: 4px;
|
||||
border: 2px solid rgba(var(--center-channel-color-rgb), 0.16);
|
||||
border: 1px solid rgba(var(--center-channel-color-rgb), 0.16);
|
||||
background: var(--center-channel-bg);
|
||||
color: var(--center-channel-color);
|
||||
padding: 0 16px;
|
||||
flex: 1;
|
||||
transition: border 0.15s ease-in;
|
||||
|
||||
&:focus {
|
||||
border-color: var(--button-bg);
|
||||
box-shadow: inset 0 0 0 1px var(--button-bg);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -7,20 +7,59 @@ import {render} from "@testing-library/react"
|
|||
|
||||
import userEvent from "@testing-library/user-event"
|
||||
|
||||
import {wrapIntl} from "../../testUtils"
|
||||
import thunk from "redux-thunk"
|
||||
|
||||
import {Provider as ReduxProvider} from 'react-redux'
|
||||
|
||||
import {mocked} from "jest-mock"
|
||||
|
||||
import {mockStateStore, wrapIntl} from "../../testUtils"
|
||||
|
||||
import {IUser} from "../../user"
|
||||
|
||||
import mutator from "../../mutator"
|
||||
|
||||
import CreateCategory from "./createCategory"
|
||||
|
||||
jest.mock('../../mutator')
|
||||
const mockedMutator = mocked(mutator, true)
|
||||
|
||||
describe('components/createCategory/CreateCategory', () => {
|
||||
const me: IUser = {
|
||||
id: 'user-id-1',
|
||||
username: 'username_1',
|
||||
email: '',
|
||||
nickname: '',
|
||||
firstname: '',
|
||||
lastname: '',
|
||||
props: {},
|
||||
create_at: 0,
|
||||
update_at: 0,
|
||||
is_bot: false,
|
||||
roles: 'system_user',
|
||||
is_guest: false,
|
||||
}
|
||||
|
||||
const state = {
|
||||
teams: {
|
||||
current: {id: 'team-id', title: 'Test Team'},
|
||||
},
|
||||
users: {
|
||||
me,
|
||||
},
|
||||
}
|
||||
const store = mockStateStore([thunk], state)
|
||||
|
||||
it('base case should match snapshot', () => {
|
||||
const component = wrapIntl(
|
||||
<CreateCategory
|
||||
onClose={jest.fn()}
|
||||
onCreate={jest.fn()}
|
||||
title={
|
||||
<span>{'title'}</span>
|
||||
}
|
||||
/>
|
||||
<ReduxProvider store={store}>
|
||||
<CreateCategory
|
||||
onClose={jest.fn()}
|
||||
title={
|
||||
<span>{'title'}</span>
|
||||
}
|
||||
/>
|
||||
</ReduxProvider>
|
||||
)
|
||||
|
||||
const {container} = render(component)
|
||||
|
@ -30,13 +69,14 @@ describe('components/createCategory/CreateCategory', () => {
|
|||
it('should call onClose on being closed', () => {
|
||||
const onCloseHandler = jest.fn()
|
||||
const component = wrapIntl(
|
||||
<CreateCategory
|
||||
onClose={onCloseHandler}
|
||||
onCreate={jest.fn()}
|
||||
title={
|
||||
<span>{'title'}</span>
|
||||
}
|
||||
/>
|
||||
<ReduxProvider store={store}>
|
||||
<CreateCategory
|
||||
onClose={onCloseHandler}
|
||||
title={
|
||||
<span>{'title'}</span>
|
||||
}
|
||||
/>
|
||||
</ReduxProvider>
|
||||
)
|
||||
|
||||
const {container} = render(component)
|
||||
|
@ -52,35 +92,39 @@ describe('components/createCategory/CreateCategory', () => {
|
|||
})
|
||||
|
||||
it('should call onCreate on pressing enter', () => {
|
||||
const onCreateHandler = jest.fn()
|
||||
const component = wrapIntl(
|
||||
<CreateCategory
|
||||
onClose={jest.fn()}
|
||||
onCreate={onCreateHandler}
|
||||
title={
|
||||
<span>{'title'}</span>
|
||||
}
|
||||
/>
|
||||
<ReduxProvider store={store}>
|
||||
<CreateCategory
|
||||
onClose={jest.fn()}
|
||||
title={
|
||||
<span>{'title'}</span>
|
||||
}
|
||||
/>
|
||||
</ReduxProvider>
|
||||
)
|
||||
|
||||
const {container} = render(component)
|
||||
const inputField = container.querySelector('.categoryNameInput')
|
||||
expect(inputField).toBeTruthy()
|
||||
userEvent.type(inputField as Element, 'category name{enter}')
|
||||
expect(onCreateHandler).toBeCalledWith('category name')
|
||||
expect(mockedMutator.createCategory).toBeCalledWith({
|
||||
name: "category name",
|
||||
teamID: "team-id",
|
||||
userID: "user-id-1",
|
||||
})
|
||||
})
|
||||
|
||||
it('should show initial value', () => {
|
||||
const onCreateHandler = jest.fn()
|
||||
const component = wrapIntl(
|
||||
<CreateCategory
|
||||
initialValue='Dwight prank ideas'
|
||||
onClose={jest.fn()}
|
||||
onCreate={onCreateHandler}
|
||||
title={
|
||||
<span>{'title'}</span>
|
||||
}
|
||||
/>
|
||||
<ReduxProvider store={store}>
|
||||
<CreateCategory
|
||||
initialValue='Dwight prank ideas'
|
||||
onClose={jest.fn()}
|
||||
title={
|
||||
<span>{'title'}</span>
|
||||
}
|
||||
/>
|
||||
</ReduxProvider>
|
||||
)
|
||||
|
||||
const {container} = render(component)
|
||||
|
@ -90,16 +134,16 @@ describe('components/createCategory/CreateCategory', () => {
|
|||
})
|
||||
|
||||
it('should clear input field on clicking clear icon', () => {
|
||||
const onCreateHandler = jest.fn()
|
||||
const component = wrapIntl(
|
||||
<CreateCategory
|
||||
initialValue='Dunder Mifflin'
|
||||
onClose={jest.fn()}
|
||||
onCreate={onCreateHandler}
|
||||
title={
|
||||
<span>{'title'}</span>
|
||||
}
|
||||
/>
|
||||
<ReduxProvider store={store}>
|
||||
<CreateCategory
|
||||
initialValue='Dunder Mifflin'
|
||||
onClose={jest.fn()}
|
||||
title={
|
||||
<span>{'title'}</span>
|
||||
}
|
||||
/>
|
||||
</ReduxProvider>
|
||||
)
|
||||
|
||||
const {container} = render(component)
|
||||
|
|
|
@ -5,6 +5,17 @@ import React, {useState, KeyboardEvent} from 'react'
|
|||
|
||||
import {useIntl} from 'react-intl'
|
||||
|
||||
import {IUser} from '../../user'
|
||||
import {Category} from '../../store/sidebar'
|
||||
import {getCurrentTeam} from '../../store/teams'
|
||||
import mutator from '../../mutator'
|
||||
import {useAppSelector} from '../../store/hooks'
|
||||
import {
|
||||
getMe,
|
||||
} from '../../store/users'
|
||||
|
||||
import {Utils} from '../../utils'
|
||||
|
||||
import Dialog from '../dialog'
|
||||
import Button from '../../widgets/buttons/button'
|
||||
|
||||
|
@ -12,15 +23,18 @@ import './createCategory.scss'
|
|||
import CloseCircle from "../../widgets/icons/closeCircle"
|
||||
|
||||
type Props = {
|
||||
boardCategoryId?: string
|
||||
renameModal?: boolean
|
||||
initialValue?: string
|
||||
onClose: () => void
|
||||
onCreate: (name: string) => void
|
||||
title: JSX.Element
|
||||
}
|
||||
|
||||
const CreateCategory = (props: Props): JSX.Element => {
|
||||
const intl = useIntl()
|
||||
|
||||
const me = useAppSelector<IUser|null>(getMe)
|
||||
const team = useAppSelector(getCurrentTeam)
|
||||
const teamID = team?.id || ''
|
||||
const placeholder = intl.formatMessage({id: 'Categories.CreateCategoryDialog.Placeholder', defaultMessage: 'Name your category' })
|
||||
const cancelText = intl.formatMessage({id: 'Categories.CreateCategoryDialog.CancelText', defaultMessage: 'Cancel' })
|
||||
const createText = intl.formatMessage({id: 'Categories.CreateCategoryDialog.CreateText', defaultMessage: 'Create' })
|
||||
|
@ -30,17 +44,45 @@ const CreateCategory = (props: Props): JSX.Element => {
|
|||
|
||||
const handleKeypress = (e: KeyboardEvent) => {
|
||||
if (e.key === 'Enter') {
|
||||
props.onCreate(name)
|
||||
onCreate(name)
|
||||
}
|
||||
}
|
||||
|
||||
const onCreate = async (categoryName: string) => {
|
||||
if (!me) {
|
||||
Utils.logError('me not initialized')
|
||||
return
|
||||
}
|
||||
|
||||
if (props.renameModal) {
|
||||
const category: Category = {
|
||||
name: categoryName,
|
||||
id: props.boardCategoryId,
|
||||
userID: me.id,
|
||||
teamID,
|
||||
} as Category
|
||||
|
||||
await mutator.updateCategory(category)
|
||||
} else {
|
||||
const category: Category = {
|
||||
name: categoryName,
|
||||
userID: me.id,
|
||||
teamID,
|
||||
} as Category
|
||||
|
||||
await mutator.createCategory(category)
|
||||
}
|
||||
|
||||
props.onClose()
|
||||
}
|
||||
|
||||
return (
|
||||
<Dialog
|
||||
className='CreateCategoryModal'
|
||||
onClose={props.onClose}
|
||||
>
|
||||
<div className='CreateCategory'>
|
||||
<h3>{props.title}</h3>
|
||||
<h3 className='dialog-title'>{props.title}</h3>
|
||||
<div className='inputWrapper'>
|
||||
<input
|
||||
className='categoryNameInput'
|
||||
|
@ -70,7 +112,7 @@ const CreateCategory = (props: Props): JSX.Element => {
|
|||
<Button
|
||||
size={'medium'}
|
||||
filled={Boolean(name.trim())}
|
||||
onClick={() => props.onCreate(name.trim())}
|
||||
onClick={() => onCreate(name.trim())}
|
||||
disabled={!(name.trim())}
|
||||
>
|
||||
{props.initialValue ? updateText : createText}
|
||||
|
|
|
@ -10,6 +10,19 @@
|
|||
bottom: 0;
|
||||
}
|
||||
|
||||
.dialog-title {
|
||||
margin-top: 24px;
|
||||
font-weight: 600;
|
||||
font-size: 22px;
|
||||
line-height: 28px;
|
||||
}
|
||||
|
||||
.dialog__close {
|
||||
top: 18px;
|
||||
right: 18px;
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
.backdrop {
|
||||
@include z-index(dialog-backdrop);
|
||||
position: fixed;
|
||||
|
@ -26,14 +39,8 @@
|
|||
justify-content: center;
|
||||
}
|
||||
|
||||
.toolbar {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
padding: 16px;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.dialog {
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
background-color: rgb(var(--center-channel-bg-rgb));
|
||||
|
@ -55,6 +62,7 @@
|
|||
display: none !important;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (max-width: 975px) {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
|
@ -63,26 +71,33 @@
|
|||
bottom: 0;
|
||||
}
|
||||
|
||||
> * {
|
||||
>* {
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
> .banner {
|
||||
>.banner {
|
||||
background-color: rgba(230, 220, 192, 0.9);
|
||||
text-align: center;
|
||||
padding: 10px;
|
||||
color: #222;
|
||||
}
|
||||
|
||||
> .banner.error {
|
||||
>.banner.error {
|
||||
background-color: rgba(230, 192, 192, 0.9);
|
||||
}
|
||||
|
||||
> .toolbar {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
padding: 24px;
|
||||
justify-content: space-between;
|
||||
.IconButton {
|
||||
color: rgba(var(--center-channel-color-rgb), 0.56);
|
||||
|
||||
&:hover {
|
||||
color: rgba(var(--center-channel-color-rgb), 0.72);
|
||||
background-color: rgba(var(--center-channel-color-rgb), 0.08);
|
||||
}
|
||||
|
||||
&:active {
|
||||
background-color: rgba(var(--button-bg-rgb), 0.08);
|
||||
color: rgba(var(--button-bg-rgb), 1);
|
||||
}
|
||||
}
|
||||
|
||||
.toolbar--right {
|
||||
|
@ -90,7 +105,7 @@
|
|||
gap: 8px;
|
||||
}
|
||||
|
||||
> .content {
|
||||
>.content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
|
@ -98,12 +113,13 @@
|
|||
@media not screen and (max-width: 975px) {
|
||||
padding: 10px 126px;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 975px) {
|
||||
padding: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
> .content.fullwidth {
|
||||
>.content.fullwidth {
|
||||
padding-left: 78px;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -45,7 +45,7 @@ const Dialog = (props: Props) => {
|
|||
}
|
||||
isBackdropClickedRef.current = false
|
||||
props.onClose()
|
||||
|
||||
|
||||
}}
|
||||
onMouseDown={(e) => {
|
||||
if(e.target === e.currentTarget){
|
||||
|
@ -58,10 +58,11 @@ const Dialog = (props: Props) => {
|
|||
className='dialog'
|
||||
>
|
||||
<div className='toolbar'>
|
||||
{title && <h1 className='text-heading5 mt-2'>{title}</h1>}
|
||||
{title && <h1 className='dialog-title'>{title}</h1>}
|
||||
{
|
||||
!props.hideCloseButton &&
|
||||
<IconButton
|
||||
className='dialog__close'
|
||||
onClick={props.onClose}
|
||||
icon={<CloseIcon/>}
|
||||
title={closeDialogText}
|
||||
|
|
|
@ -8,18 +8,6 @@
|
|||
}
|
||||
}
|
||||
|
||||
.wrapper {
|
||||
.dialog {
|
||||
.toolbar {
|
||||
flex-direction: row-reverse;
|
||||
padding: 0;
|
||||
position: absolute;
|
||||
right: 18px;
|
||||
top: 18px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.wrapper {
|
||||
.dialog {
|
||||
position: relative;
|
||||
|
@ -58,7 +46,7 @@
|
|||
padding: 0 32px;
|
||||
cursor: pointer;
|
||||
overflow: hidden;
|
||||
|
||||
|
||||
&.freesize {
|
||||
height: unset;
|
||||
}
|
||||
|
|
|
@ -107,33 +107,6 @@ exports[`components/sidebarBoardItem sidebar board item 1`] = `
|
|||
<div
|
||||
class="menu-options"
|
||||
>
|
||||
<div>
|
||||
<div
|
||||
aria-label="Delete board"
|
||||
class="MenuOption TextOption menu-option"
|
||||
role="button"
|
||||
>
|
||||
<div
|
||||
class="d-flex"
|
||||
>
|
||||
<i
|
||||
class="CompassIcon icon-trash-can-outline DeleteIcon trash-can-outline"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
class="menu-option__content"
|
||||
>
|
||||
<div
|
||||
class="menu-name"
|
||||
>
|
||||
Delete board
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="noicon"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div
|
||||
class="MenuOption SubMenuOption menu-option boardMoveToCategorySubmenu"
|
||||
|
@ -239,6 +212,33 @@ exports[`components/sidebarBoardItem sidebar board item 1`] = `
|
|||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div
|
||||
aria-label="Delete board"
|
||||
class="MenuOption TextOption menu-option text-danger"
|
||||
role="button"
|
||||
>
|
||||
<div
|
||||
class="d-flex"
|
||||
>
|
||||
<i
|
||||
class="CompassIcon icon-trash-can-outline DeleteIcon trash-can-outline"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
class="menu-option__content"
|
||||
>
|
||||
<div
|
||||
class="menu-name"
|
||||
>
|
||||
Delete board
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="noicon"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="menu-spacer hideOnWidescreen"
|
||||
|
@ -349,33 +349,6 @@ exports[`components/sidebarBoardItem sidebar board item for guest 1`] = `
|
|||
<div
|
||||
class="menu-options"
|
||||
>
|
||||
<div>
|
||||
<div
|
||||
aria-label="Delete board"
|
||||
class="MenuOption TextOption menu-option"
|
||||
role="button"
|
||||
>
|
||||
<div
|
||||
class="d-flex"
|
||||
>
|
||||
<i
|
||||
class="CompassIcon icon-trash-can-outline DeleteIcon trash-can-outline"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
class="menu-option__content"
|
||||
>
|
||||
<div
|
||||
class="menu-name"
|
||||
>
|
||||
Delete board
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="noicon"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div
|
||||
class="MenuOption SubMenuOption menu-option boardMoveToCategorySubmenu"
|
||||
|
@ -429,6 +402,33 @@ exports[`components/sidebarBoardItem sidebar board item for guest 1`] = `
|
|||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div
|
||||
aria-label="Delete board"
|
||||
class="MenuOption TextOption menu-option text-danger"
|
||||
role="button"
|
||||
>
|
||||
<div
|
||||
class="d-flex"
|
||||
>
|
||||
<i
|
||||
class="CompassIcon icon-trash-can-outline DeleteIcon trash-can-outline"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
class="menu-option__content"
|
||||
>
|
||||
<div
|
||||
class="menu-name"
|
||||
>
|
||||
Delete board
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="noicon"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="menu-spacer hideOnWidescreen"
|
||||
|
|
|
@ -69,11 +69,12 @@ describe('components/sidebarSidebar', () => {
|
|||
})
|
||||
|
||||
const history = createMemoryHistory()
|
||||
const onBoardTemplateSelectorOpen = jest.fn()
|
||||
|
||||
const component = wrapIntl(
|
||||
<ReduxProvider store={store}>
|
||||
<Router history={history}>
|
||||
<Sidebar/>
|
||||
<Sidebar onBoardTemplateSelectorOpen={onBoardTemplateSelectorOpen}/>
|
||||
</Router>
|
||||
</ReduxProvider>,
|
||||
)
|
||||
|
@ -131,11 +132,12 @@ describe('components/sidebarSidebar', () => {
|
|||
})
|
||||
|
||||
const history = createMemoryHistory()
|
||||
const onBoardTemplateSelectorOpen = jest.fn()
|
||||
|
||||
const component = wrapIntl(
|
||||
<ReduxProvider store={store}>
|
||||
<Router history={history}>
|
||||
<Sidebar/>
|
||||
<Sidebar onBoardTemplateSelectorOpen={onBoardTemplateSelectorOpen}/>
|
||||
</Router>
|
||||
</ReduxProvider>,
|
||||
)
|
||||
|
@ -192,11 +194,12 @@ describe('components/sidebarSidebar', () => {
|
|||
})
|
||||
|
||||
const history = createMemoryHistory()
|
||||
const onBoardTemplateSelectorOpen = jest.fn()
|
||||
|
||||
const component = wrapIntl(
|
||||
<ReduxProvider store={store}>
|
||||
<Router history={history}>
|
||||
<Sidebar/>
|
||||
<Sidebar onBoardTemplateSelectorOpen={onBoardTemplateSelectorOpen}/>
|
||||
</Router>
|
||||
</ReduxProvider>,
|
||||
)
|
||||
|
@ -254,11 +257,12 @@ describe('components/sidebarSidebar', () => {
|
|||
})
|
||||
|
||||
const history = createMemoryHistory()
|
||||
const onBoardTemplateSelectorOpen = jest.fn()
|
||||
|
||||
const component = wrapIntl(
|
||||
<ReduxProvider store={store}>
|
||||
<Router history={history}>
|
||||
<Sidebar/>
|
||||
<Sidebar onBoardTemplateSelectorOpen={onBoardTemplateSelectorOpen}/>
|
||||
</Router>
|
||||
</ReduxProvider>,
|
||||
)
|
||||
|
@ -305,7 +309,7 @@ describe('components/sidebarSidebar', () => {
|
|||
// const component = wrapIntl(
|
||||
// <ReduxProvider store={store}>
|
||||
// <Router history={history}>
|
||||
// <Sidebar/>
|
||||
// <Sidebar onBoardTemplateSelectorOpen={onBoardTemplateSelectorOpen}/>
|
||||
// </Router>
|
||||
// </ReduxProvider>,
|
||||
// )
|
||||
|
|
|
@ -40,7 +40,7 @@ import {addMissingItems} from './utils'
|
|||
|
||||
type Props = {
|
||||
activeBoardId?: string
|
||||
onBoardTemplateSelectorOpen?: () => void
|
||||
onBoardTemplateSelectorOpen: () => void
|
||||
}
|
||||
|
||||
function getWindowDimensions() {
|
||||
|
|
|
@ -235,20 +235,6 @@ const SidebarBoardItem = (props: Props) => {
|
|||
position='auto'
|
||||
parentRef={boardItemRef}
|
||||
>
|
||||
<BoardPermissionGate
|
||||
boardId={board.id}
|
||||
permissions={[Permission.DeleteBoard]}
|
||||
>
|
||||
<Menu.Text
|
||||
key={`deleteBlock-${board.id}`}
|
||||
id='deleteBlock'
|
||||
name={intl.formatMessage({id: 'Sidebar.delete-board', defaultMessage: 'Delete board'})}
|
||||
icon={<DeleteIcon/>}
|
||||
onClick={() => {
|
||||
props.onDeleteRequest(board)
|
||||
}}
|
||||
/>
|
||||
</BoardPermissionGate>
|
||||
<Menu.SubMenu
|
||||
key={`moveBlock-${board.id}`}
|
||||
id='moveBlock'
|
||||
|
@ -279,6 +265,21 @@ const SidebarBoardItem = (props: Props) => {
|
|||
icon={<CloseIcon/>}
|
||||
onClick={() => handleHideBoard()}
|
||||
/>
|
||||
<BoardPermissionGate
|
||||
boardId={board.id}
|
||||
permissions={[Permission.DeleteBoard]}
|
||||
>
|
||||
<Menu.Text
|
||||
key={`deleteBlock-${board.id}`}
|
||||
id='deleteBlock'
|
||||
className='text-danger'
|
||||
name={intl.formatMessage({id: 'Sidebar.delete-board', defaultMessage: 'Delete board'})}
|
||||
icon={<DeleteIcon/>}
|
||||
onClick={() => {
|
||||
props.onDeleteRequest(board)
|
||||
}}
|
||||
/>
|
||||
</BoardPermissionGate>
|
||||
</Menu>
|
||||
</MenuWrapper>
|
||||
</div>
|
||||
|
|
|
@ -10,6 +10,7 @@ import {Board} from '../../blocks/board'
|
|||
import mutator from '../../mutator'
|
||||
import IconButton from '../../widgets/buttons/iconButton'
|
||||
import DeleteIcon from '../../widgets/icons/delete'
|
||||
import CompassIcon from '../../widgets/icons/compassIcon'
|
||||
import OptionsIcon from '../../widgets/icons/options'
|
||||
import Menu from '../../widgets/menu'
|
||||
import MenuWrapper from '../../widgets/menuWrapper'
|
||||
|
@ -30,7 +31,6 @@ import {
|
|||
|
||||
import {getCurrentCard} from '../../store/cards'
|
||||
import {Utils} from '../../utils'
|
||||
import Update from '../../widgets/icons/update'
|
||||
|
||||
import { TOUR_SIDEBAR, SidebarTourSteps, TOUR_BOARD, FINISHED } from '../../components/onboardingTour/index'
|
||||
import telemetryClient, {TelemetryActions, TelemetryCategory} from '../../telemetry/telemetryClient'
|
||||
|
@ -244,6 +244,12 @@ const SidebarCategory = (props: Props) => {
|
|||
{
|
||||
props.categoryBoards.id !== '' &&
|
||||
<React.Fragment>
|
||||
<Menu.Text
|
||||
id='updateCategory'
|
||||
name={intl.formatMessage({id: 'SidebarCategories.CategoryMenu.Update', defaultMessage: 'Rename Category'})}
|
||||
icon={<CompassIcon icon='pencil-outline'/>}
|
||||
onClick={handleUpdateCategory}
|
||||
/>
|
||||
<Menu.Text
|
||||
id='deleteCategory'
|
||||
className='text-danger'
|
||||
|
@ -251,11 +257,12 @@ const SidebarCategory = (props: Props) => {
|
|||
icon={<DeleteIcon/>}
|
||||
onClick={() => setShowDeleteCategoryDialog(true)}
|
||||
/>
|
||||
<Menu.Separator/>
|
||||
<Menu.Text
|
||||
id='updateCategory'
|
||||
name={intl.formatMessage({id: 'SidebarCategories.CategoryMenu.Update', defaultMessage: 'Rename Category'})}
|
||||
icon={<Update/>}
|
||||
onClick={handleUpdateCategory}
|
||||
id='createNewCategory'
|
||||
name={intl.formatMessage({id: 'SidebarCategories.CategoryMenu.CreateNew', defaultMessage: 'Create New Category'})}
|
||||
icon={<CreateNewFolder/>}
|
||||
onClick={handleCreateNewCategory}
|
||||
/>
|
||||
</React.Fragment>
|
||||
}
|
||||
|
@ -315,21 +322,6 @@ const SidebarCategory = (props: Props) => {
|
|||
defaultMessage='Create New Category'
|
||||
/>
|
||||
)}
|
||||
onCreate={async (name) => {
|
||||
if (!me) {
|
||||
Utils.logError('me not initialized')
|
||||
return
|
||||
}
|
||||
|
||||
const category: Category = {
|
||||
name,
|
||||
userID: me.id,
|
||||
teamID,
|
||||
} as Category
|
||||
|
||||
await mutator.createCategory(category)
|
||||
setShowCreateCategoryModal(false)
|
||||
}}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
@ -345,22 +337,6 @@ const SidebarCategory = (props: Props) => {
|
|||
/>
|
||||
)}
|
||||
onClose={() => setShowUpdateCategoryModal(false)}
|
||||
onCreate={async (name) => {
|
||||
if (!me) {
|
||||
Utils.logError('me not initialized')
|
||||
return
|
||||
}
|
||||
|
||||
const category: Category = {
|
||||
name,
|
||||
id: props.categoryBoards.id,
|
||||
userID: me.id,
|
||||
teamID,
|
||||
} as Category
|
||||
|
||||
await mutator.updateCategory(category)
|
||||
setShowUpdateCategoryModal(false)
|
||||
}}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
|
|
@ -20,7 +20,7 @@ exports[`components/viewLimitDialog/ViewLiimitDialog show notify upgrade button
|
|||
>
|
||||
<button
|
||||
aria-label="Close dialog"
|
||||
class="IconButton size--medium"
|
||||
class="IconButton dialog__close size--medium"
|
||||
title="Close dialog"
|
||||
type="button"
|
||||
>
|
||||
|
@ -96,7 +96,7 @@ exports[`components/viewLimitDialog/ViewLiimitDialog show upgrade button for sys
|
|||
>
|
||||
<button
|
||||
aria-label="Close dialog"
|
||||
class="IconButton size--medium"
|
||||
class="IconButton dialog__close size--medium"
|
||||
title="Close dialog"
|
||||
type="button"
|
||||
>
|
||||
|
|
|
@ -20,7 +20,7 @@ exports[`components/viewLimitDialog/ViewL]imitDialog show notify admin confirmat
|
|||
>
|
||||
<button
|
||||
aria-label="Close dialog"
|
||||
class="IconButton size--medium"
|
||||
class="IconButton dialog__close size--medium"
|
||||
title="Close dialog"
|
||||
type="button"
|
||||
>
|
||||
|
@ -130,7 +130,7 @@ exports[`components/viewLimitDialog/ViewL]imitDialog show view limit dialog 1`]
|
|||
>
|
||||
<button
|
||||
aria-label="Close dialog"
|
||||
class="IconButton size--medium"
|
||||
class="IconButton dialog__close size--medium"
|
||||
title="Close dialog"
|
||||
type="button"
|
||||
>
|
||||
|
|
|
@ -61,6 +61,7 @@
|
|||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: flex-start;
|
||||
position: relative;
|
||||
font-size: 14px;
|
||||
line-height: 24px;
|
||||
|
|
Loading…
Reference in a new issue