1
0
mirror of https://github.com/mattermost/focalboard.git synced 2024-12-24 13:43:12 +02:00

[GH-512] Feature #512 made confirmation dialog box. (#1546)

* Made confirmationDialogBox from existing dialog component

* Used ConfirmationDialogBox to raise warning before deletion of card property

* fixes as ci checks did not pass

* fixes to pass ci tests

* Flash Message now visible (changed its z-index)

* Confirmation Dialog shows the property name.

* fixes for eslint test failure

* fixes for eslint test fail

* fixes for eslint test failure

* fix for eslint test failure

* fixed a wrong subtext string

* fixed eslint issues in scss

* i18n en.json for localisation updated

* `en.json;`-wrong file generated by `npm run i18n-extract ` command removed

Co-authored-by: Prakhar <>
This commit is contained in:
prakharporwal 2021-10-15 00:12:36 +05:30 committed by GitHub
parent a756b7e1c6
commit 977bc1dafa
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 169 additions and 5 deletions

View File

@ -14,6 +14,9 @@
"CardDetail.addCardText": "add card text", "CardDetail.addCardText": "add card text",
"CardDetail.moveContent": "move card content", "CardDetail.moveContent": "move card content",
"CardDetail.new-comment-placeholder": "Add a comment...", "CardDetail.new-comment-placeholder": "Add a comment...",
"CardDetailProperty.confirm-delete": "Confirm Delete Property",
"CardDetailProperty.confirm-delete-subtext": "Are you sure you want to delete the property \"{propertyName}\"? Deleting it will delete the property from all cards in this board.",
"CardDetailProperty.property-deleted": "Deleted {propertyName} Successfully!",
"CardDialog.editing-template": "You're editing a template.", "CardDialog.editing-template": "You're editing a template.",
"CardDialog.nocard": "This card doesn't exist or is inaccessible.", "CardDialog.nocard": "This card doesn't exist or is inaccessible.",
"CardDialog.copiedLink": "Copied!", "CardDialog.copiedLink": "Copied!",

View File

@ -1,7 +1,8 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information. // See LICENSE.txt for license information.
import React from 'react'
import {FormattedMessage} from 'react-intl' import React, {useState} from 'react'
import {useIntl, FormattedMessage} from 'react-intl'
import {Board, PropertyType, IPropertyTemplate} from '../../blocks/board' import {Board, PropertyType, IPropertyTemplate} from '../../blocks/board'
import {Card} from '../../blocks/card' import {Card} from '../../blocks/card'
@ -14,6 +15,8 @@ import MenuWrapper from '../../widgets/menuWrapper'
import PropertyMenu from '../../widgets/propertyMenu' import PropertyMenu from '../../widgets/propertyMenu'
import PropertyValueElement from '../propertyValueElement' import PropertyValueElement from '../propertyValueElement'
import {ConfirmationDialogBox} from '../confirmationDialogBox'
import {sendFlashMessage} from '../flashMessages'
type Props = { type Props = {
board: Board board: Board
@ -27,8 +30,13 @@ type Props = {
} }
const CardDetailProperties = React.memo((props: Props) => { const CardDetailProperties = React.memo((props: Props) => {
const intl = useIntl()
const {board, card, cards, views, activeView, contents, comments} = props const {board, card, cards, views, activeView, contents, comments} = props
const [showConfirmationDialog, setShowConfirmationDialog] = useState<boolean>(false)
const [deletingPropId, setDeletingPropId] = useState<string>('')
const [deletingPropName, setDeletingPropName] = useState<string>('')
return ( return (
<div className='octo-propertylist CardDetailProperties'> <div className='octo-propertylist CardDetailProperties'>
{board.fields.cardProperties.map((propertyTemplate: IPropertyTemplate) => { {board.fields.cardProperties.map((propertyTemplate: IPropertyTemplate) => {
@ -47,7 +55,12 @@ const CardDetailProperties = React.memo((props: Props) => {
propertyName={propertyTemplate.name} propertyName={propertyTemplate.name}
propertyType={propertyTemplate.type} propertyType={propertyTemplate.type}
onTypeAndNameChanged={(newType: PropertyType, newName: string) => mutator.changePropertyTypeAndName(board, cards, propertyTemplate, newType, newName)} onTypeAndNameChanged={(newType: PropertyType, newName: string) => mutator.changePropertyTypeAndName(board, cards, propertyTemplate, newType, newName)}
onDelete={(id: string) => mutator.deleteProperty(board, views, cards, id)} onDelete={(id: string) => {
setDeletingPropId(id)
setDeletingPropName(propertyTemplate.name)
setShowConfirmationDialog(true)
}
}
/> />
</MenuWrapper> </MenuWrapper>
} }
@ -64,6 +77,26 @@ const CardDetailProperties = React.memo((props: Props) => {
) )
})} })}
{showConfirmationDialog && (
<ConfirmationDialogBox
propertyId={deletingPropId}
onClose={() => setShowConfirmationDialog(false)}
onConfirm={() => {
mutator.deleteProperty(board, views, cards, deletingPropId)
setShowConfirmationDialog(false)
sendFlashMessage({content: intl.formatMessage({id: 'CardDetailProperty.property-deleted', defaultMessage: 'Deleted {propertyName} Successfully!'}, {propertyName: deletingPropName}), severity: 'high'})
}}
heading={intl.formatMessage({id: 'CardDetailProperty.confirm-delete', defaultMessage: 'Confirm Delete Property'})}
subText={intl.formatMessage({
id: 'CardDetailProperty.confirm-delete-subtext',
defaultMessage: 'Are you sure you want to delete the property "{propertyName}"? Deleting it will delete the property from all cards in this board.',
},
{propertyName: deletingPropName})
}
/>
)}
{!props.readonly && {!props.readonly &&
<div className='octo-propertyname add-property'> <div className='octo-propertyname add-property'>
<Button <Button

View File

@ -0,0 +1,60 @@
.confirmation-dialog-box {
.dialog {
position: fixed;
top: 30%;
left: 50%;
transform: translate(-50%, -50%);
width: max-content;
height: max-content;
z-index: 300;
background-color: rgb(var(--center-channel-bg-rgb));
box-shadow: rgba(var(--center-channel-color-rgb), 0.1) 0 0 0 1px,
rgba(var(--center-channel-color-rgb), 0.1) 0 2px 4px;
border-radius: var(--modal-rad);
padding: 0;
-webkit-overflow-scrolling: touch;
overflow-x: hidden;
overflow-y: auto;
> .toolbar {
position: absolute;
top: 0;
right: 0;
padding: 16px;
}
}
}
.box-area {
display: grid;
place-items: center;
.heading {
margin-top: 2rem;
padding: 2px 4px;
}
.sub-text {
width: 26rem;
word-wrap: normal;
margin: 0.5rem 3rem;
padding: 2px;
@media screen and (max-width: 400px) {
width: 12rem;
}
}
}
.action-buttons {
display: flex;
margin: 1rem;
justify-content: space-between;
.Button {
margin: 2px 1rem;
}
}

View File

@ -0,0 +1,56 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import React from 'react'
import {FormattedMessage} from 'react-intl'
import Button from '../widgets/buttons/button'
import Dialog from './dialog'
import './confirmationDialogBox.scss'
type Props = {
propertyId: string;
onClose: () => void;
onConfirm: () => void;
heading: string;
subText?: string;
}
export const ConfirmationDialogBox = (props: Props) => {
return (
<Dialog
className='confirmation-dialog-box'
onClose={props.onClose}
>
<div className='box-area'>
<h3 className='heading'>{props.heading}</h3>
<p className='sub-text'>{props.subText}</p>
<div className='action-buttons'>
<Button
title='Cancel'
active={true}
onClick={props.onClose}
>
<FormattedMessage
id='ConfirmationDialog.cancel-action'
defaultMessage='Cancel'
/>
</Button>
<Button
title='Delete'
submit={true}
emphasis='danger'
onClick={props.onConfirm}
>
<FormattedMessage
id='ConfirmationDialog.delete-action'
defaultMessage='Delete'
/>
</Button>
</div>
</div>
</Dialog>
)
}

View File

@ -12,7 +12,7 @@ import './dialog.scss'
type Props = { type Props = {
children: React.ReactNode children: React.ReactNode
toolsMenu: React.ReactNode toolsMenu?: React.ReactNode // some dialogs may not require a toolmenu
hideCloseButton?: boolean hideCloseButton?: boolean
className?: string className?: string
onClose: () => void, onClose: () => void,

View File

@ -17,7 +17,7 @@
font-size: 18px; font-size: 18px;
vertical-align: middle; vertical-align: middle;
border-radius: 20px; border-radius: 20px;
z-index: 12; z-index: 999;
&.flashIn { &.flashIn {
visibility: visible; visibility: visible;

View File

@ -5,6 +5,8 @@
--sidebar-text-rgb: 255, 255, 255; --sidebar-text-rgb: 255, 255, 255;
--button-color-rgb: 255, 255, 255; --button-color-rgb: 255, 255, 255;
--button-bg-rgb: 28, 88, 217; --button-bg-rgb: 28, 88, 217;
--button-danger-color-rgb: 255, 255, 255;
--button-danger-bg-rgb: 210, 75, 78;
--link-color-rgb: 56, 111, 229; --link-color-rgb: 56, 111, 229;
--error-text-rgb: #d24b4e; --error-text-rgb: #d24b4e;
} }

View File

@ -58,6 +58,16 @@
} }
} }
&.emphasis--danger {
color: rgb(var(--button-danger-color-rgb));
background-color: rgb(var(--button-danger-bg-rgb));
&:hover {
background-color: rgb(var(--button-danger-bg-rgb), 0.8);
}
}
&.active { &.active {
background: rgba(var(--button-bg-rgb), 0.08); background: rgba(var(--button-bg-rgb), 0.08);
color: rgb(var(--button-bg-rgb)); color: rgb(var(--button-bg-rgb));