DND in progress

This commit is contained in:
Harshil Sharma 2023-01-24 13:57:47 +05:30
parent 4112db4626
commit d009f80d7c
4 changed files with 149 additions and 85 deletions

View file

@ -24,12 +24,74 @@ import BlackCheckboxOutline from '../../widgets/icons/blackCheckboxOutline'
import ShareBoardDialog from './shareBoard'
const valueCategoriesInitialValue: StatusCategory[] = [
{
id: 'category_id_1',
title: 'Not Started',
options: [
{id: 'status_id_1', value: 'Pending Design', color: 'propColorPurple'},
{id: 'status_id_2', value: 'TODO', color: 'propColorYellow'},
{id: 'status_id_3', value: 'Pending Specs', color: 'propColorGray'},
],
emptyState: {
icon: (<BlackCheckboxOutline/>),
color: '--sys-dnd-indicator-rgb',
text: (
<FormattedMessage
id='statusProperty.configDialog.todo.emptyText'
defaultMessage='Drag statuses here to consider tasks with these statuses “Not Started”'
/>
),
},
},
{
id: 'category_id_2',
title: 'In progress',
options: [
{id: 'status_id_4', value: 'In Progress', color: 'propColorBrown'},
{id: 'status_id_5', value: 'In Review', color: 'propColorRed'},
{id: 'status_id_6', value: 'In QA', color: 'propColorPink'},
{id: 'status_id_7', value: 'Awaiting Cherrypick', color: 'propColorOrange'},
],
emptyState: {
icon: (<ClockOutline/>),
color: '--away-indicator-rgb',
text: (
<FormattedMessage
id='statusProperty.configDialog.inProgress.emptyText'
defaultMessage='Drag statuses here to consider tasks with these statuses “in progress”'
/>
),
},
},
{
id: 'category_id_3',
title: 'Completed',
options: [
{id: 'status_id_20', value: 'Done', color: 'propColorPink'},
{id: 'status_id_21', value: 'Branch Cut', color: 'propColorGreen'},
{id: 'status_id_22', value: 'Released', color: 'propColorDefault'},
],
emptyState: {
icon: (<CheckIcon/>),
color: '--online-indicator-rgb',
text: (
<FormattedMessage
id='statusProperty.configDialog.complete.emptyText'
defaultMessage='Drag statuses here to consider tasks with these statuses ”Done”'
/>
),
},
},
]
type Props = {
enableSharedBoards: boolean
}
const ShareBoardButton = (props: Props) => {
const [showShareDialog, setShowShareDialog] = useState(false)
const board = useAppSelector(getCurrentBoard)
const [valueCategories, setValueCategories] = useState<StatusCategory[]>(valueCategoriesInitialValue)
const iconForBoardType = () => {
if (board.type === BoardTypeOpen) {
@ -38,67 +100,6 @@ const ShareBoardButton = (props: Props) => {
return <LockOutline/>
}
const valueCategories: StatusCategory[] = [
{
id: 'category_id_1',
title: 'Not Started',
options: [
{id: 'status_id_1', value: 'Pending Design', color: 'propColorPurple'},
{id: 'status_id_2', value: 'TODO', color: 'propColorYellow'},
{id: 'status_id_3', value: 'Pending Specs', color: 'propColorGray'},
],
emptyState: {
icon: (<BlackCheckboxOutline/>),
color: '--sys-dnd-indicator-rgb',
text: (
<FormattedMessage
id='statusProperty.configDialog.todo.emptyText'
defaultMessage='Drag statuses here to consider tasks with these statuses “Not Started”'
/>
),
},
},
{
id: 'category_id_2',
title: 'In progress',
options: [
{id: 'status_id_4', value: 'In Progress', color: 'propColorBrown'},
{id: 'status_id_5', value: 'In Review', color: 'propColorRed'},
{id: 'status_id_6', value: 'In QA', color: 'propColorPink'},
{id: 'status_id_7', value: 'Awaiting Cherrypick', color: 'propColorOrange'},
],
emptyState: {
icon: (<ClockOutline/>),
color: '--away-indicator-rgb',
text: (
<FormattedMessage
id='statusProperty.configDialog.inProgress.emptyText'
defaultMessage='Drag statuses here to consider tasks with these statuses “in progress”'
/>
),
},
},
{
id: 'category_id_3',
title: 'Completed',
options: [
{id: 'status_id_20', value: 'Done', color: 'propColorPink'},
{id: 'status_id_21', value: 'Branch Cut', color: 'propColorGreen'},
{id: 'status_id_22', value: 'Released', color: 'propColorDefault'},
],
emptyState: {
icon: (<CheckIcon/>),
color: '--online-indicator-rgb',
text: (
<FormattedMessage
id='statusProperty.configDialog.complete.emptyText'
defaultMessage='Drag statuses here to consider tasks with these statuses ”Done”'
/>
),
},
},
]
return (
<div className='ShareBoardButton'>
<Button
@ -127,7 +128,7 @@ const ShareBoardButton = (props: Props) => {
<EditStatusPropertyDialog
valueCategories={valueCategories}
onClose={() => setShowShareDialog(false)}
onUpdate={(updatedValue) => console.log(updatedValue)}
onUpdate={(updatedValue) => setValueCategories(updatedValue)}
/>
}
</div>

View file

@ -1,12 +1,10 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import React, {useEffect, useState} from 'react'
import React, {useCallback, useEffect, useState} from 'react'
import {FormattedMessage} from 'react-intl'
import {useCallback} from 'preact/hooks'
import {DragDropContext, Droppable, Draggable} from 'react-beautiful-dnd'
import {DragDropContext, Droppable, Draggable, DropReason, DropResult} from 'react-beautiful-dnd'
import PlusIcon from '../../../widgets/icons/plus'
@ -14,11 +12,12 @@ import InfoIcon from '../../../widgets/icons/info'
import './editStatusDialog.scss'
import ActionDialog from '../../actionDialog/actionDialog'
import Label from '../../../widgets/label'
import {IPropertyOption} from '../../../blocks/board'
import DragHandle from '../../../widgets/icons/dragHandle'
import EditIcon from '../../../widgets/icons/edit'
import {IDType, Utils} from '../../../utils'
import EditableLabel from './editableLabel/editableLabel'
export type StatusCategoryEmptyState = {
@ -29,6 +28,7 @@ export type StatusCategoryEmptyState = {
export type EditablePropertyOption = IPropertyOption & {
editing?: boolean
focused?: boolean
}
export type StatusCategory = {
@ -46,9 +46,9 @@ type Props = {
const EditStatusPropertyDialog = (props: Props): JSX.Element => {
const [valueCategories, setValueCategories] = useState<StatusCategory[]>([])
const [focusedValueID, setFocusedValueID] = useState<string>()
useEffect(() => {
console.log('setting: ' + props.valueCategories.length)
setValueCategories(props.valueCategories)
}, [props.valueCategories])
@ -59,11 +59,33 @@ const EditStatusPropertyDialog = (props: Props): JSX.Element => {
/>
)
const generateValueRow = (option: EditablePropertyOption, index: number): JSX.Element => {
const handleAddNewValue = (statusCategoryID: string, newOptionValue: IPropertyOption): void => {
const categoryIndex = valueCategories.findIndex((valueCategory) => valueCategory.id === statusCategoryID)
if (categoryIndex < 0) {
Utils.logError(`category with ID: ${statusCategoryID} not found`)
return
}
const valueIndex = valueCategories[categoryIndex].options.findIndex((option) => option.id === newOptionValue.id)
if (valueIndex < 0) {
Utils.logError(`Value with ID ${newOptionValue.id} not found`)
return
}
const updatedValueCategories = [...valueCategories]
updatedValueCategories[categoryIndex].options[valueIndex] = newOptionValue
setFocusedValueID('')
setValueCategories(updatedValueCategories)
props.onUpdate(updatedValueCategories)
}
const generateValueRow = (categoryID: string, option: EditablePropertyOption, index: number): JSX.Element => {
return (
<Draggable
draggableId={option.id}
index={index}
key={index}
>
{(provided) => (
<div
@ -80,7 +102,9 @@ const EditStatusPropertyDialog = (props: Props): JSX.Element => {
</div>
<EditableLabel
option={option}
editing={option.editing}
editing={option.id === focusedValueID}
focus={option.id === focusedValueID}
onBlur={(newOptionValue: IPropertyOption) => handleAddNewValue(categoryID, newOptionValue)}
/>
<div className={`colorEditor ${option.color} withBorder`}/>
<EditIcon/>
@ -110,27 +134,45 @@ const EditStatusPropertyDialog = (props: Props): JSX.Element => {
}
const handleAddCategoryValue = (categoryID: string) => {
console.log('asdasd')
const categoryIndex = valueCategories.findIndex((valueCategory) => valueCategory.id === categoryID)
if (categoryIndex < 0) {
return
}
const newOption: EditablePropertyOption = {
id: '',
id: Utils.createGuid(IDType.None),
value: '',
color: 'propColorOrange',
editing: true,
}
const updatedValueCategories = [...valueCategories]
updatedValueCategories[categoryIndex].options.unshift(newOption)
setFocusedValueID(newOption.id)
setValueCategories(updatedValueCategories)
}
const onDragEndHandler = () => {}
const onDragEndHandler = useCallback(async (result: DropResult) => {
const {destination, source, type} = result
console.log(valueCategories)
if (type !== 'statusCategory' || !destination) {
return
}
console.log(`destination: ${destination} source: ${source} type: ${type}`)
const updatedValues = Array.from(valueCategories)
const sourceCategoryIndex = updatedValues.findIndex((valueCategory) => valueCategory.id === source.droppableId)
const destinationCategoryIndex = updatedValues.findIndex((valueCategory) => valueCategory.id === destination.droppableId)
const draggedObject = valueCategories[sourceCategoryIndex].options[source.index]
updatedValues[sourceCategoryIndex].options.splice(source.index, 1)
updatedValues[destinationCategoryIndex].options.splice(destination.index, 0, draggedObject)
setValueCategories(updatedValues)
}, [valueCategories])
return (
<ActionDialog
@ -165,7 +207,10 @@ const EditStatusPropertyDialog = (props: Props): JSX.Element => {
<PlusIcon/>
</div>
</div>
<Droppable droppableId={`categorySwimlane_${valueCategory.id}`}>
<Droppable
type='statusCategory'
droppableId={valueCategory.id}
>
{(provided) => (
<div
ref={provided.innerRef}
@ -179,7 +224,7 @@ const EditStatusPropertyDialog = (props: Props): JSX.Element => {
}
{
valueCategory.options.length > 0 &&
valueCategory.options.map((option, index) => generateValueRow(option, index))
valueCategory.options.map((option, index) => generateValueRow(valueCategory.id, option, index))
}
</div>
{provided.placeholder}

View file

@ -1,9 +1,10 @@
.Label {
.EditableLabel {
input {
border: none;
background: none;
border-bottom: 1px solid;
border-radius: 0;
max-width: 100%;
}
text-transform: uppercase;
}
}

View file

@ -1,6 +1,6 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import React from 'react'
import React, {useState} from 'react'
import Label from '../../../../widgets/label'
@ -11,23 +11,40 @@ import './editableLabel.scss'
type Props = {
option: IPropertyOption
editing?: boolean
focus?: boolean
onBlur?: (newOptionValue: IPropertyOption) => void
}
const EditableLabel = (props: Props): JSX.Element => {
const {option} = props
const [value, setValue] = useState<string>(props.option.value)
const displayValue = (<span>{option.value}</span>)
const handleOnBlur = () => {
const newOptionValue = {
...props.option,
value,
}
if (props.onBlur) {
props.onBlur(newOptionValue)
}
}
const displayValue = (<span>{props.option.value}</span>)
const editValue = (
<input
defaultValue={props.option.value}
autoFocus={props.focus}
onChange={(e) => setValue(e.target.value)}
onBlur={handleOnBlur}
/>
)
return (
<Label
key={option.id}
color={option.color}
title={option.value}
key={props.option.id}
className='EditableLabel'
color={props.option.color}
title={props.option.value}
>
{ props.editing ? editValue : displayValue }
</Label>