1
0
mirror of https://github.com/mattermost/focalboard.git synced 2025-03-23 20:52:42 +02:00

Added confirmation dialog for unlinking a channel (#3432)

* Added confirmation dialog for unlinking a channel

* Updated texts
This commit is contained in:
Harshil Sharma 2022-07-28 15:01:22 +05:30 committed by GitHub
parent 67608a833b
commit 4f7ce070bc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 489 additions and 2 deletions

View File

@ -361,6 +361,9 @@
"shareBoard.confirm-link-public-channel": "You're adding a public channel",
"shareBoard.confirm-link-public-channel-button": "Yes, add public channel",
"shareBoard.confirm-link-public-channel-subtext": "Anyone who joins that public channel will now get “Editor” access to the board, are you sure you want to proceed?",
"shareBoard.confirm-unlink.title": "Unlink channel from board",
"shareBoard.confirm-unlink.body": "When you unlink a channel from a board, all members of the channel (existing and new) will loose access to it unless they are given permission separately. {lineBreak} Are you sure you want to unlink it?",
"shareBoard.confirm-unlink.confirmBtnText": "Yes, unlink",
"shareBoard.lastAdmin": "Boards must have at least one Administrator",
"shareBoard.members-select-group": "Members",
"tutorial_tip.finish_tour": "Done",

View File

@ -1,5 +1,255 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`src/components/shareBoard/shareBoard confirm unlinking linked channel 1`] = `
<div>
<div
class="Dialog dialog-back ShareBoardDialog"
>
<div
class="backdrop"
/>
<div
class="wrapper"
>
<div
class="dialog"
role="dialog"
>
<div
class="toolbar"
>
<button
aria-label="Close dialog"
title="Close dialog"
type="button"
>
<i
class="CompassIcon icon-close CloseIcon"
/>
</button>
<div
class="toolbar--right"
>
<div>
<span
class="text-heading5"
>
Share Board
</span>
</div>
</div>
</div>
<div
class="share-input__container"
>
<div
class="share-input"
>
<i
class="CompassIcon icon-magnify MagnifyIcon"
/>
<div
class="userSearchInput css-b62m3t-container"
>
<span
class="css-1f43avz-a11yText-A11yText"
id="react-select-12-live-region"
/>
<span
aria-atomic="false"
aria-live="polite"
aria-relevant="additions text"
class="css-1f43avz-a11yText-A11yText"
/>
<div
class=" css-1wmrr75-Control"
>
<div
class=" css-30zlo3-ValueContainer"
>
<div
class=" css-14el2xx-placeholder"
id="react-select-12-placeholder"
>
Search for people
</div>
<div
class=" css-ox1y69-Input"
data-value=""
>
<input
aria-autocomplete="list"
aria-describedby="react-select-12-placeholder"
aria-expanded="false"
aria-haspopup="true"
autocapitalize="none"
autocomplete="off"
autocorrect="off"
class=""
id="react-select-12-input"
role="combobox"
spellcheck="false"
style="opacity: 1; width: 100%; grid-area: 1 / 2; min-width: 2px; border: 0px; margin: 0px; outline: 0; padding: 0px;"
tabindex="0"
type="text"
value=""
/>
</div>
</div>
<div
class=" css-1hb7zxy-IndicatorsContainer"
/>
</div>
</div>
</div>
</div>
<div
class="user-items"
>
<div
class="user-item"
>
<div
class="user-item__content"
>
<i
class="CompassIcon icon-mattermost user-item__img"
/>
<div
class="ml-3"
>
<strong>
Everyone at Test Team Team
</strong>
</div>
</div>
<div>
<div
aria-label="menuwrapper"
class="MenuWrapper"
role="button"
>
<button
class="user-item__button"
>
None
<i
class="CompassIcon icon-chevron-down CompassIcon"
/>
</button>
</div>
</div>
</div>
<div
class="user-item channel-item"
>
<div
class="user-item__content"
>
<span
class="user-item__img"
>
<i
class="CompassIcon icon-lock-outline LockOutlineIcon"
/>
</span>
<div
class="ml-3"
>
<strong>
Dunder Mifflin Party Planing Committee
</strong>
</div>
</div>
<div>
<div
aria-label="menuwrapper"
class="MenuWrapper"
role="button"
>
<button
class="user-item__button"
>
Editor
<i
class="CompassIcon icon-chevron-down CompassIcon"
/>
</button>
</div>
</div>
</div>
</div>
<div
class="tabs-container"
>
<button
class="tab-item tab-item--active"
>
Share
</button>
<button
class="tab-item false"
>
Publish
</button>
</div>
<div
class="tabs-content"
>
<div>
<div
class="d-flex justify-content-between"
>
<div
class="d-flex flex-column"
>
<div
class="text-heading2"
>
Share internally
</div>
<div
class="text-light"
>
Users who have permissions will be able to use this link.
</div>
</div>
</div>
</div>
<div
class="d-flex justify-content-between tabs-inputs"
>
<div
class="d-flex input-container"
>
<a
class="shareUrl"
href="http://localhost/1/1"
rel="noreferrer"
target="_blank"
>
http://localhost/1/1
</a>
</div>
<button
title="Copy internal link"
type="button"
>
<i
class="CompassIcon icon-content-copy CompassIcon"
/>
<span>
Copy link
</span>
</button>
</div>
</div>
</div>
</div>
</div>
</div>
`;
exports[`src/components/shareBoard/shareBoard return shareBoard and click Copy link 1`] = `
<div>
<div
@ -790,6 +1040,44 @@ exports[`src/components/shareBoard/shareBoard return shareBoard and click Select
</div>
</div>
</div>
<div
class="user-item channel-item"
>
<div
class="user-item__content"
>
<span
class="user-item__img"
>
<i
class="CompassIcon icon-lock-outline LockOutlineIcon"
/>
</span>
<div
class="ml-3"
>
<strong>
Dunder Mifflin Party Planing Committee
</strong>
</div>
</div>
<div>
<div
aria-label="menuwrapper"
class="MenuWrapper"
role="button"
>
<button
class="user-item__button"
>
Editor
<i
class="CompassIcon icon-chevron-down CompassIcon"
/>
</button>
</div>
</div>
</div>
</div>
<div
class="tabs-content"
@ -1220,6 +1508,44 @@ exports[`src/components/shareBoard/shareBoard return shareBoard and click Select
</div>
</div>
</div>
<div
class="user-item channel-item"
>
<div
class="user-item__content"
>
<span
class="user-item__img"
>
<i
class="CompassIcon icon-lock-outline LockOutlineIcon"
/>
</span>
<div
class="ml-3"
>
<strong>
Dunder Mifflin Party Planing Committee
</strong>
</div>
</div>
<div>
<div
aria-label="menuwrapper"
class="MenuWrapper"
role="button"
>
<button
class="user-item__button"
>
Editor
<i
class="CompassIcon icon-chevron-down CompassIcon"
/>
</button>
</div>
</div>
</div>
</div>
<div
class="tabs-content"
@ -1418,6 +1744,44 @@ exports[`src/components/shareBoard/shareBoard return shareBoard and click Select
</div>
</div>
</div>
<div
class="user-item channel-item"
>
<div
class="user-item__content"
>
<span
class="user-item__img"
>
<i
class="CompassIcon icon-lock-outline LockOutlineIcon"
/>
</span>
<div
class="ml-3"
>
<strong>
Dunder Mifflin Party Planing Committee
</strong>
</div>
</div>
<div>
<div
aria-label="menuwrapper"
class="MenuWrapper"
role="button"
>
<button
class="user-item__button"
>
Editor
<i
class="CompassIcon icon-chevron-down CompassIcon"
/>
</button>
</div>
</div>
</div>
</div>
<div
class="tabs-content"
@ -1848,6 +2212,44 @@ exports[`src/components/shareBoard/shareBoard return shareBoard and click Select
</div>
</div>
</div>
<div
class="user-item channel-item"
>
<div
class="user-item__content"
>
<span
class="user-item__img"
>
<i
class="CompassIcon icon-lock-outline LockOutlineIcon"
/>
</span>
<div
class="ml-3"
>
<strong>
Dunder Mifflin Party Planing Committee
</strong>
</div>
</div>
<div>
<div
aria-label="menuwrapper"
class="MenuWrapper"
role="button"
>
<button
class="user-item__button"
>
Editor
<i
class="CompassIcon icon-chevron-down CompassIcon"
/>
</button>
</div>
</div>
</div>
</div>
<div
class="tabs-content"

View File

@ -19,16 +19,19 @@ import PrivateIcon from '../../widgets/icons/lockOutline'
import PublicIcon from '../../widgets/icons/globe'
import DeleteIcon from '../../widgets/icons/delete'
import CompassIcon from '../../widgets/icons/compassIcon'
import ConfirmationDialogBox from "../confirmationDialogBox"
const ChannelPermissionsRow = (): JSX.Element => {
const intl = useIntl()
const board = useAppSelector(getCurrentBoard)
const [linkedChannel, setLinkedChannel] = useState<Channel|null>(null)
const [showUnlinkChannelConfirmation, setShowUnlinkChannelConfirmation] = useState<boolean>(false)
const onUnlinkBoard = async () => {
const newBoard = createBoard(board)
newBoard.channelId = ''
mutator.updateBoard(newBoard, board, 'unlinked channel')
setShowUnlinkChannelConfirmation(false)
}
useEffect(() => {
@ -43,8 +46,32 @@ const ChannelPermissionsRow = (): JSX.Element => {
return <></>
}
const confirmationDialog = (
<ConfirmationDialogBox
dialogBox={{
heading: intl.formatMessage({
id: 'shareBoard.confirm-unlink.title',
defaultMessage: 'Unlink channel from board',
}),
subText: intl.formatMessage({
id: 'shareBoard.confirm-unlink.body',
defaultMessage: 'When you unlink a channel from a board, all members of the channel (existing and new) will loose access to it unless they are given permission separately. {lineBreak} Are you sure you want to unlink it?',
}, {
lineBreak: <p/>
}),
confirmButtonText: intl.formatMessage({
id: 'shareBoard.confirm-unlink.confirmBtnText',
defaultMessage: 'Yes, unlink',
}),
onConfirm: onUnlinkBoard,
onClose: () => setShowUnlinkChannelConfirmation(false),
}}
/>
)
return (
<div className='user-item'>
<div className='user-item channel-item'>
{showUnlinkChannelConfirmation && confirmationDialog}
<div className='user-item__content'>
<span className='user-item__img'>
{linkedChannel.type === 'P' && <PrivateIcon/>}
@ -69,7 +96,7 @@ const ChannelPermissionsRow = (): JSX.Element => {
id='Unlink'
icon={<DeleteIcon/>}
name={intl.formatMessage({id: 'BoardMember.unlinkChannel', defaultMessage: 'Unlink'})}
onClick={onUnlinkBoard}
onClick={() => setShowUnlinkChannelConfirmation(true)}
/>
</Menu>
</MenuWrapper>

View File

@ -77,21 +77,27 @@ board.cardProperties = [
],
},
]
board.channelId = 'channel_1'
const activeView = TestBlockFactory.createBoardView(board)
activeView.id = 'view1'
activeView.fields.hiddenOptionIds = []
activeView.fields.visiblePropertyIds = ['property1']
activeView.fields.visibleOptionIds = ['value1']
const fakeBoard = {id: board.id}
activeView.boardId = fakeBoard.id
const card1 = TestBlockFactory.createCard(board)
card1.id = 'card1'
card1.title = 'card-1'
card1.boardId = fakeBoard.id
const card2 = TestBlockFactory.createCard(board)
card2.id = 'card2'
card2.title = 'card-2'
card2.boardId = fakeBoard.id
const card3 = TestBlockFactory.createCard(board)
card3.id = 'card3'
card3.title = 'card-3'
@ -187,6 +193,8 @@ describe('src/components/shareBoard/shareBoard', () => {
viewId,
workspaceId,
}
mockedOctoClient.getChannel.mockResolvedValue({type: 'P', display_name: 'Dunder Mifflin Party Planing Committee'} as Channel)
})
afterEach(() => {
@ -335,6 +343,7 @@ describe('src/components/shareBoard/shareBoard', () => {
expect(mockedOctoClient.setSharing).toBeCalledTimes(1)
expect(container).toMatchSnapshot()
})
test('return shareBoard, and click switch', async () => {
const sharing:ISharing = {
id: boardId,
@ -374,6 +383,7 @@ describe('src/components/shareBoard/shareBoard', () => {
expect(mockedOctoClient.getSharing).toBeCalledTimes(2)
expect(container).toMatchSnapshot()
})
test('return shareBoardComponent and click Switch without sharing', async () => {
const sharing:ISharing = {
id: '',
@ -425,6 +435,7 @@ describe('src/components/shareBoard/shareBoard', () => {
expect(mockedUtils.createGuid).toBeCalledTimes(1)
expect(container).toMatchSnapshot()
})
test('should match snapshot with sharing and without workspaceId and subpath', async () => {
w.baseURL = '/test-subpath/plugins/boards'
const sharing:ISharing = {
@ -575,4 +586,48 @@ describe('src/components/shareBoard/shareBoard', () => {
expect(container).toMatchSnapshot()
})
test('confirm unlinking linked channel', async () => {
const sharing:ISharing = {
id: '',
enabled: false,
token: '',
}
mockedOctoClient.getSharing.mockResolvedValue(sharing)
mockedUtils.isFocalboardPlugin.mockReturnValue(true)
let container: Element | DocumentFragment | null = null
await act(async () => {
const result = render(
wrapDNDIntl(
<ReduxProvider store={store}>
<ShareBoard
onClose={jest.fn()}
enableSharedBoards={true}
/>
</ReduxProvider>),
{wrapper: MemoryRouter},
)
container = result.container
})
expect(container).toMatchSnapshot()
const channelMenuBtn = container!.querySelector('.user-item.channel-item .MenuWrapper')
expect(channelMenuBtn).not.toBeNull()
userEvent.click(channelMenuBtn as Element)
const unlinkOption = screen.getByText('Unlink')
expect(unlinkOption).not.toBeNull()
userEvent.click(unlinkOption)
const unlinkConfirmationBtn = screen.getByText('Yes, unlink')
expect(unlinkConfirmationBtn).not.toBeNull()
userEvent.click(unlinkConfirmationBtn)
expect(mockedOctoClient.patchBoard).toBeCalled()
const closeButton = screen.getByRole('button', {name: 'Close dialog'})
expect(closeButton).toBeDefined()
})
})