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(
builder,
{
action: view.actionImpl.ValueSelector,
actionPopup: view.component.ValueSelector,
action: view.actionImpl.AttributeSelector,
actionPopup: tracker.component.SprintEditor,
actionProps: {
attribute: 'sprint',
_class: tracker.class.Sprint,
queryOptions: {
sort: {
startDate: -1,
targetDate: -1
}
},
query: {},
searchField: 'label',
placeholder: tracker.string.Sprint
isAction: true
},
label: tracker.string.Sprint,
icon: tracker.icon.Sprint,

View File

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

View File

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

View File

@ -359,6 +359,33 @@ function ValueSelector (
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 (
element?: PopupPosAlignment | Resource<(e?: Event) => PopupAlignment | undefined>,
evt?: Event
@ -398,5 +425,6 @@ export const actionImpl = {
ShowPanel,
ShowPopup,
ShowEditor,
ValueSelector
ValueSelector,
AttributeSelector
}

View File

@ -64,7 +64,11 @@
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> = {}

View File

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