TSK-1166: sprint editor action (#3110)

Signed-off-by: Vyacheslav Tumanov <me@slavatumanov.me>
This commit is contained in:
Vyacheslav Tumanov 2023-04-29 20:43:01 +05:00 committed by GitHub
parent 9412db643e
commit 9b04d366e3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 83 additions and 24 deletions

View File

@ -1511,20 +1511,11 @@ export function createModel (builder: Builder): void {
createAction( createAction(
builder, builder,
{ {
action: view.actionImpl.ValueSelector, action: view.actionImpl.AttributeSelector,
actionPopup: view.component.ValueSelector, actionPopup: tracker.component.SprintEditor,
actionProps: { actionProps: {
attribute: 'sprint', attribute: 'sprint',
_class: tracker.class.Sprint, isAction: true
queryOptions: {
sort: {
startDate: -1,
targetDate: -1
}
},
query: {},
searchField: 'label',
placeholder: tracker.string.Sprint
}, },
label: tracker.string.Sprint, label: tracker.string.Sprint,
icon: tracker.icon.Sprint, icon: tracker.icon.Sprint,

View File

@ -29,6 +29,7 @@
import { getDayOfSprint } from '../../utils' import { getDayOfSprint } from '../../utils'
import TimePresenter from '../issues/timereport/TimePresenter.svelte' import TimePresenter from '../issues/timereport/TimePresenter.svelte'
import SprintSelector from './SprintSelector.svelte' import SprintSelector from './SprintSelector.svelte'
import { createEventDispatcher } from 'svelte'
export let value: Issue | IssueTemplate export let value: Issue | IssueTemplate
export let isEditable: boolean = true export let isEditable: boolean = true
@ -41,19 +42,29 @@
export let justify: 'left' | 'center' = 'left' export let justify: 'left' | 'center' = 'left'
export let width: string | undefined = '100%' export let width: string | undefined = '100%'
export let onlyIcon: boolean = false export let onlyIcon: boolean = false
export let isAction: boolean = false
export let groupBy: string | undefined = undefined export let groupBy: string | undefined = undefined
export let enlargedText: boolean = false export let enlargedText: boolean = false
export let compression: boolean = false export let compression: boolean = false
const client = getClient() const client = getClient()
const dispatch = createEventDispatcher()
const handleSprintIdChanged = async (newSprintId: Ref<Sprint> | null | undefined) => { const handleSprintIdChanged = async (newSprintId: Ref<Sprint> | null | undefined) => {
if (!isEditable || newSprintId === undefined || value.sprint === newSprintId) { if (!isEditable || newSprintId === undefined || value.sprint === newSprintId) {
return return
} }
if (Array.isArray(value)) {
await client.update(value, { sprint: newSprintId }) await Promise.all(
value.map(async (p) => {
await client.update(p, { sprint: newSprintId })
})
)
} else {
await client.update(value, { sprint: newSprintId })
}
if (isAction) dispatch('close')
} }
const sprintQuery = createQuery() const sprintQuery = createQuery()
@ -85,6 +96,7 @@
showTooltip={{ label: value.sprint ? tracker.string.MoveToSprint : tracker.string.AddToSprint }} showTooltip={{ label: value.sprint ? tracker.string.MoveToSprint : tracker.string.AddToSprint }}
value={value.sprint} value={value.sprint}
onChange={handleSprintIdChanged} onChange={handleSprintIdChanged}
{isAction}
/> />
</div> </div>
{/if} {/if}
@ -111,6 +123,7 @@
showTooltip={{ label: value.sprint ? tracker.string.MoveToSprint : tracker.string.AddToSprint }} showTooltip={{ label: value.sprint ? tracker.string.MoveToSprint : tracker.string.AddToSprint }}
value={value.sprint} value={value.sprint}
onChange={handleSprintIdChanged} onChange={handleSprintIdChanged}
{isAction}
/> />
</div> </div>
{/if} {/if}

View File

@ -36,6 +36,7 @@
export let enlargedText: boolean = false export let enlargedText: boolean = false
export let short: boolean = false export let short: boolean = false
export let focusIndex: number | undefined = undefined export let focusIndex: number | undefined = undefined
export let isAction: boolean = false
export let useComponent: Ref<Component> | undefined = undefined export let useComponent: Ref<Component> | undefined = undefined
export let showTooltip: LabelAndProps | undefined = undefined export let showTooltip: LabelAndProps | undefined = undefined
@ -72,13 +73,8 @@
selectedSprint = sprints.find((it) => it._id === newSprintId) selectedSprint = sprints.find((it) => it._id === newSprintId)
} }
const handleSprintEditorOpened = async (event: MouseEvent): Promise<void> => { const getSprintInfo = (rawSprints: Sprint[]) => {
event.stopPropagation() return [
if (!isEditable) {
return
}
const sprintInfo = [
{ id: null, icon: tracker.icon.Sprint, label: tracker.string.NoSprint }, { id: null, icon: tracker.icon.Sprint, label: tracker.string.NoSprint },
...rawSprints.map((p) => ({ ...rawSprints.map((p) => ({
id: p._id, id: p._id,
@ -87,6 +83,17 @@
category: sprintStatusAssets[p.status] category: sprintStatusAssets[p.status]
})) }))
] ]
}
$: sprints = getSprintInfo(rawSprints)
const handleSprintEditorOpened = async (event: MouseEvent): Promise<void> => {
event.stopPropagation()
if (!isEditable) {
return
}
const sprintInfo = sprints
showPopup( showPopup(
SelectPopup, SelectPopup,
@ -97,7 +104,16 @@
} }
</script> </script>
{#if onlyIcon || sprintText === undefined} {#if isAction}
<SelectPopup
value={sprints}
placeholder={popupPlaceholder}
searchable
on:close={(evt) => {
if (onChange !== undefined) onChange(evt.detail)
}}
/>
{:else if onlyIcon || sprintText === undefined}
<Button <Button
{focusIndex} {focusIndex}
{kind} {kind}

View File

@ -359,6 +359,33 @@ function ValueSelector (
showPopup(view.component.ValueSelector, { ...props, value: doc, width: 'large' }, 'top') showPopup(view.component.ValueSelector, { ...props, value: doc, width: 'large' }, 'top')
} }
function AttributeSelector (
doc: Doc | Doc[],
evt: Event,
props: {
actionPopup: AnyComponent
attribute: string
values?: Array<{ icon?: Asset, label: IntlString, id: number | string }>
isAction?: boolean
}
): void {
const client = getClient()
const hierarchy = client.getHierarchy()
const docArray = Array.isArray(doc) ? doc : [doc]
const attribute = hierarchy.getAttribute(docArray[0]._class, props.attribute)
showPopup(props.actionPopup, { ...props, value: docArray, width: 'large' }, 'top', (result) => {
console.log(result)
if (result != null) {
for (const docEl of docArray) {
void updateAttribute(client, docEl, docEl._class, { key: props.attribute, attr: attribute }, result)
}
}
})
}
async function getPopupAlignment ( async function getPopupAlignment (
element?: PopupPosAlignment | Resource<(e?: Event) => PopupAlignment | undefined>, element?: PopupPosAlignment | Resource<(e?: Event) => PopupAlignment | undefined>,
evt?: Event evt?: Event
@ -398,5 +425,6 @@ export const actionImpl = {
ShowPanel, ShowPanel,
ShowPopup, ShowPopup,
ShowEditor, ShowEditor,
ValueSelector ValueSelector,
AttributeSelector
} }

View File

@ -64,7 +64,11 @@
dispatch('close', newStatus) dispatch('close', newStatus)
} }
$: current = (value as any)[attribute] $: current = Array.isArray(value)
? value.every((v) => (v as any)[attribute] === (value as Array<any>)[0][attribute])
? (value as Array<any>)[0][attribute]
: value
: (value as any)[attribute]
let finalQuery: DocumentQuery<Doc> = {} let finalQuery: DocumentQuery<Doc> = {}

View File

@ -790,6 +790,13 @@ const view = plugin(viewId, {
values?: { icon?: Asset, label: IntlString, id: number | string }[] values?: { icon?: Asset, label: IntlString, id: number | string }[]
placeholder?: IntlString placeholder?: IntlString
}>,
AttributeSelector: '' as ViewAction<{
attribute: string
isAction?: boolean
// Or list of values to select from
values?: { icon?: Asset, label: IntlString, id: number | string }[]
}> }>
} }
}) })