mirror of
https://github.com/hcengineering/platform.git
synced 2025-04-14 04:08:19 +00:00
[UBER-426] Add milestone status editor (#3391)
Signed-off-by: Sergei Ogorelkov <sergei.ogorelkov@icloud.com>
This commit is contained in:
parent
5eaaa3f8a6
commit
7536a8f51e
@ -1488,6 +1488,10 @@ export function createModel (builder: Builder): void {
|
||||
presenter: tracker.component.MilestoneStatusPresenter
|
||||
})
|
||||
|
||||
builder.mixin(tracker.class.TypeMilestoneStatus, core.class.Class, view.mixin.AttributeEditor, {
|
||||
inlineEditor: tracker.component.MilestoneStatusEditor
|
||||
})
|
||||
|
||||
builder.mixin(tracker.class.TypeMilestoneStatus, core.class.Class, view.mixin.AttributeFilter, {
|
||||
component: view.component.ValueFilter
|
||||
})
|
||||
|
@ -0,0 +1,87 @@
|
||||
<!--
|
||||
// Copyright © 2023 Hardcore Engineering Inc.
|
||||
//
|
||||
// Licensed under the Eclipse Public License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License. You may
|
||||
// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
//
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
-->
|
||||
<script lang="ts">
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
import { Data } from '@hcengineering/core'
|
||||
import { Milestone } from '@hcengineering/tracker'
|
||||
import { getClient } from '@hcengineering/presentation'
|
||||
import { Button, ButtonKind, ButtonSize, Icon, SelectPopup, eventToHTMLElement, showPopup } from '@hcengineering/ui'
|
||||
import { defaultMilestoneStatuses, milestoneStatusAssets } from '../../utils'
|
||||
import tracker from '../../plugin'
|
||||
|
||||
export let value: Milestone['status'] | undefined
|
||||
export let object: Milestone | Data<Milestone>
|
||||
export let kind: ButtonKind = 'link'
|
||||
export let size: ButtonSize = 'large'
|
||||
export let justify: 'left' | 'center' = 'left'
|
||||
export let width: string | undefined = undefined
|
||||
export let disabled = false
|
||||
|
||||
const dispatch = createEventDispatcher()
|
||||
const client = getClient()
|
||||
|
||||
function handlePopupOpen (event: MouseEvent) {
|
||||
showPopup(
|
||||
SelectPopup,
|
||||
{ value: itemsInfo, placeholder: tracker.string.SetStatus },
|
||||
eventToHTMLElement(event),
|
||||
changeStatus
|
||||
)
|
||||
}
|
||||
|
||||
async function changeStatus (newStatus: Milestone['status'] | null | undefined) {
|
||||
if (disabled || newStatus == null || value === newStatus) {
|
||||
return
|
||||
}
|
||||
|
||||
value = newStatus
|
||||
dispatch('change', value)
|
||||
|
||||
if ('_id' in object) {
|
||||
await client.update(object, { status: newStatus })
|
||||
}
|
||||
}
|
||||
|
||||
$: itemsInfo = defaultMilestoneStatuses.map((status) => ({
|
||||
id: status,
|
||||
isSelected: value === status,
|
||||
...milestoneStatusAssets[status]
|
||||
}))
|
||||
|
||||
$: icon = value === undefined ? tracker.icon.MilestoneStatusPlanned : milestoneStatusAssets[value].icon
|
||||
$: label = value === undefined ? tracker.string.Planned : milestoneStatusAssets[value].label
|
||||
</script>
|
||||
|
||||
{#if kind === 'list'}
|
||||
<button
|
||||
class="flex-no-shrink clear-mins cursor-pointer content-pointer-events-none"
|
||||
{disabled}
|
||||
on:click={handlePopupOpen}
|
||||
>
|
||||
<Icon {icon} {size} />
|
||||
</button>
|
||||
{:else}
|
||||
<Button
|
||||
{label}
|
||||
{kind}
|
||||
{icon}
|
||||
{justify}
|
||||
{size}
|
||||
{width}
|
||||
{disabled}
|
||||
showTooltip={{ label: tracker.string.SetStatus }}
|
||||
on:click={handlePopupOpen}
|
||||
/>
|
||||
{/if}
|
@ -13,37 +13,28 @@
|
||||
// limitations under the License.
|
||||
-->
|
||||
<script lang="ts">
|
||||
import { MilestoneStatus } from '@hcengineering/tracker'
|
||||
import { Milestone, MilestoneStatus } from '@hcengineering/tracker'
|
||||
import type { ButtonKind, ButtonSize } from '@hcengineering/ui'
|
||||
import tracker from '../../plugin'
|
||||
|
||||
import MilestoneStatusSelector from './MilestoneStatusSelector.svelte'
|
||||
import MilestoneStatusEditor from './MilestoneStatusEditor.svelte'
|
||||
|
||||
export let value: MilestoneStatus
|
||||
export let object: Milestone
|
||||
export let onChange: ((value: MilestoneStatus) => void) | undefined = undefined
|
||||
export let kind: ButtonKind = 'link'
|
||||
export let size: ButtonSize = 'large'
|
||||
export let justify: 'left' | 'center' = 'left'
|
||||
export let width: string | undefined = '100%'
|
||||
|
||||
function handleComponentStatusChange (newMilestoneStatus: MilestoneStatus | undefined) {
|
||||
if (newMilestoneStatus === undefined || onChange === undefined) {
|
||||
return
|
||||
}
|
||||
|
||||
onChange(newMilestoneStatus)
|
||||
}
|
||||
|
||||
$: isEditable = onChange !== undefined
|
||||
$: disabled = onChange === undefined
|
||||
</script>
|
||||
|
||||
<MilestoneStatusSelector
|
||||
<MilestoneStatusEditor
|
||||
{value}
|
||||
{object}
|
||||
{kind}
|
||||
{size}
|
||||
{width}
|
||||
{justify}
|
||||
{isEditable}
|
||||
showTooltip={isEditable ? { label: tracker.string.SetStatus } : undefined}
|
||||
selectedMilestoneStatus={value}
|
||||
onMilestoneStatusChange={handleComponentStatusChange}
|
||||
{disabled}
|
||||
on:change={({ detail }) => onChange?.(detail)}
|
||||
/>
|
||||
|
@ -1,83 +0,0 @@
|
||||
<!--
|
||||
// Copyright © 2022 Hardcore Engineering Inc.
|
||||
//
|
||||
// Licensed under the Eclipse Public License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License. You may
|
||||
// obtain a copy of the License at https://www.eclipse.org/legal/epl-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
//
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
-->
|
||||
<script lang="ts">
|
||||
import { MilestoneStatus } from '@hcengineering/tracker'
|
||||
import { Button, showPopup, SelectPopup, eventToHTMLElement, Icon } from '@hcengineering/ui'
|
||||
import type { ButtonKind, ButtonSize, LabelAndProps } from '@hcengineering/ui'
|
||||
import tracker from '../../plugin'
|
||||
import { defaultMilestoneStatuses, milestoneStatusAssets } from '../../utils'
|
||||
|
||||
export let selectedMilestoneStatus: MilestoneStatus | undefined
|
||||
export let shouldShowLabel: boolean = true
|
||||
export let onMilestoneStatusChange: ((newMilestoneStatus: MilestoneStatus | undefined) => void) | undefined =
|
||||
undefined
|
||||
export let isEditable: boolean = true
|
||||
|
||||
export let kind: ButtonKind = 'no-border'
|
||||
export let size: ButtonSize = 'small'
|
||||
export let justify: 'left' | 'center' = 'center'
|
||||
export let width: string | undefined = 'min-content'
|
||||
export let showTooltip: LabelAndProps | undefined = undefined
|
||||
|
||||
$: selectedStatusIcon = selectedMilestoneStatus
|
||||
? milestoneStatusAssets[selectedMilestoneStatus].icon
|
||||
: tracker.icon.MilestoneStatusPlanned
|
||||
|
||||
$: selectedStatusLabel = shouldShowLabel
|
||||
? selectedMilestoneStatus
|
||||
? milestoneStatusAssets[selectedMilestoneStatus].label
|
||||
: tracker.string.Planned
|
||||
: undefined
|
||||
|
||||
$: statusesInfo = defaultMilestoneStatuses.map((s) => ({
|
||||
id: s,
|
||||
isSelected: milestoneStatusAssets[s].label === selectedStatusLabel,
|
||||
...milestoneStatusAssets[s]
|
||||
}))
|
||||
|
||||
const handleMilestoneStatusEditorOpened = (event: MouseEvent) => {
|
||||
if (!isEditable) {
|
||||
return
|
||||
}
|
||||
showPopup(
|
||||
SelectPopup,
|
||||
{ value: statusesInfo, placeholder: tracker.string.SetStatus, searchable: true },
|
||||
eventToHTMLElement(event),
|
||||
onMilestoneStatusChange
|
||||
)
|
||||
}
|
||||
</script>
|
||||
|
||||
{#if kind === 'list'}
|
||||
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
||||
<div
|
||||
class="flex-no-shrink clear-mins cursor-pointer content-pointer-events-none"
|
||||
on:click={handleMilestoneStatusEditorOpened}
|
||||
>
|
||||
<Icon icon={selectedStatusIcon} {size} />
|
||||
</div>
|
||||
{:else}
|
||||
<Button
|
||||
{kind}
|
||||
{size}
|
||||
{width}
|
||||
{justify}
|
||||
disabled={!isEditable}
|
||||
icon={selectedStatusIcon}
|
||||
label={selectedStatusLabel}
|
||||
{showTooltip}
|
||||
on:click={handleMilestoneStatusEditorOpened}
|
||||
/>
|
||||
{/if}
|
@ -21,7 +21,7 @@
|
||||
import { StyledTextArea } from '@hcengineering/text-editor'
|
||||
import { createEventDispatcher } from 'svelte'
|
||||
import tracker from '../../plugin'
|
||||
import MilestoneStatusSelector from './MilestoneStatusSelector.svelte'
|
||||
import MilestoneStatusEditor from './MilestoneStatusEditor.svelte'
|
||||
import { createBacklinks } from '@hcengineering/chunter-resources'
|
||||
|
||||
export let space: Ref<Project>
|
||||
@ -42,14 +42,6 @@
|
||||
// Create an backlink to document
|
||||
await createBacklinks(client, _id, tracker.class.Milestone, _id, object.description ?? '')
|
||||
}
|
||||
|
||||
const handleComponentStatusChanged = (newMilestoneStatus: MilestoneStatus | undefined) => {
|
||||
if (newMilestoneStatus === undefined) {
|
||||
return
|
||||
}
|
||||
|
||||
object.status = newMilestoneStatus
|
||||
}
|
||||
</script>
|
||||
|
||||
<Card
|
||||
@ -83,12 +75,7 @@
|
||||
showButtons={false}
|
||||
/>
|
||||
<svelte:fragment slot="pool">
|
||||
<MilestoneStatusSelector
|
||||
selectedMilestoneStatus={object.status}
|
||||
onMilestoneStatusChange={handleComponentStatusChanged}
|
||||
kind={'secondary'}
|
||||
size={'large'}
|
||||
/>
|
||||
<MilestoneStatusEditor bind:value={object.status} {object} kind="secondary" />
|
||||
<DatePresenter
|
||||
bind:value={object.targetDate}
|
||||
editable
|
||||
|
@ -87,6 +87,7 @@ import MilestonePresenter from './components/milestones/MilestonePresenter.svelt
|
||||
import Milestones from './components/milestones/Milestones.svelte'
|
||||
import MilestoneSelector from './components/milestones/MilestoneSelector.svelte'
|
||||
import MilestoneStatusPresenter from './components/milestones/MilestoneStatusPresenter.svelte'
|
||||
import MilestoneStatusEditor from './components/milestones/MilestoneStatusEditor.svelte'
|
||||
import MilestoneTitlePresenter from './components/milestones/MilestoneTitlePresenter.svelte'
|
||||
|
||||
import ScrumRecordPanel from './components/scrums/ScrumRecordPanel.svelte'
|
||||
@ -456,6 +457,7 @@ export default async (): Promise<Resources> => ({
|
||||
Scrums,
|
||||
ScrumRecordPanel,
|
||||
MilestoneStatusPresenter,
|
||||
MilestoneStatusEditor,
|
||||
MilestoneTitlePresenter,
|
||||
MilestoneSelector,
|
||||
MilestoneEditor,
|
||||
|
@ -359,6 +359,7 @@ export default mergeIds(trackerId, tracker, {
|
||||
Milestones: '' as AnyComponent,
|
||||
MilestonePresenter: '' as AnyComponent,
|
||||
MilestoneStatusPresenter: '' as AnyComponent,
|
||||
MilestoneStatusEditor: '' as AnyComponent,
|
||||
MilestoneTitlePresenter: '' as AnyComponent,
|
||||
MilestoneDatePresenter: '' as AnyComponent,
|
||||
EditMilestone: '' as AnyComponent,
|
||||
|
Loading…
Reference in New Issue
Block a user