Enhance TrainingUnitSectionsEditor with new drag-and-drop functionality for parallel phases
All checks were successful
Deploy Development / deploy (push) Successful in 39s
Test Suite / pytest-backend (push) Successful in 36s
Test Suite / lint-backend (push) Successful in 0s
Test Suite / build-frontend (push) Successful in 11s
Test Suite / k6 /health Baseline (push) Successful in 33s
Test Suite / playwright-tests (push) Successful in 1m8s
All checks were successful
Deploy Development / deploy (push) Successful in 39s
Test Suite / pytest-backend (push) Successful in 36s
Test Suite / lint-backend (push) Successful in 0s
Test Suite / build-frontend (push) Successful in 11s
Test Suite / k6 /health Baseline (push) Successful in 33s
Test Suite / playwright-tests (push) Successful in 1m8s
- Added new event handlers for drag-and-drop operations to manage sections above and below split headers in parallel phases. - Implemented utility functions to reorder sections as whole groups or as the first entry in parallel phases, improving section management. - Updated CSS styles to visually represent new drop zones for sections, enhancing user experience during reordering. - Refactored existing logic to accommodate new features and ensure proper handling of section placements within parallel streams.
This commit is contained in:
parent
73975d3402
commit
72e8f31cff
|
|
@ -5990,6 +5990,23 @@ a.analysis-split__nav-item {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Parallele Phase: feste Einfügebänder oberhalb/unterhalb des Split-Headers */
|
||||||
|
.tu-phase-drop--above-split,
|
||||||
|
.tu-phase-drop--below-split {
|
||||||
|
margin: 6px 2px 8px;
|
||||||
|
min-height: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tu-section-dropband--phase-parallel-slot {
|
||||||
|
height: 14px;
|
||||||
|
background: linear-gradient(
|
||||||
|
180deg,
|
||||||
|
color-mix(in srgb, var(--accent) 12%, var(--surface2)) 0%,
|
||||||
|
hsl(200 30% 94%) 100%
|
||||||
|
);
|
||||||
|
border: 1px dashed color-mix(in srgb, var(--accent) 38%, transparent);
|
||||||
|
}
|
||||||
|
|
||||||
.tu-sec-drag-grip {
|
.tu-sec-drag-grip {
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
display: inline-flex;
|
display: inline-flex;
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,8 @@ import {
|
||||||
phaseRunsFromSections,
|
phaseRunsFromSections,
|
||||||
swapAdjacentPhaseRuns,
|
swapAdjacentPhaseRuns,
|
||||||
reorderBlocksImmutableWithPlanLoc,
|
reorderBlocksImmutableWithPlanLoc,
|
||||||
|
reorderSectionBeforeParallelRunAsWholeGroup,
|
||||||
|
reorderSectionAsFirstInParallelPhase,
|
||||||
reorderBlockIntoParallelStreamEnd,
|
reorderBlockIntoParallelStreamEnd,
|
||||||
globalInsertBeforeIndexForParallelStreamEnd,
|
globalInsertBeforeIndexForParallelStreamEnd,
|
||||||
movePhaseRunUpByPhaseOrder,
|
movePhaseRunUpByPhaseOrder,
|
||||||
|
|
@ -729,6 +731,145 @@ export default function TrainingUnitSectionsEditor({
|
||||||
setDropSectionBand({ slot: sectionToSlot, beforeIdx })
|
setDropSectionBand({ slot: sectionToSlot, beforeIdx })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const onPhaseAboveSplitDragOver = (e, po) => {
|
||||||
|
if (!enableSectionDragReorder || !enableParallelPhaseControls) return
|
||||||
|
if (!dtHasType(e, DND_TU_SECTION)) return
|
||||||
|
e.preventDefault()
|
||||||
|
e.stopPropagation()
|
||||||
|
try {
|
||||||
|
e.dataTransfer.dropEffect = 'move'
|
||||||
|
} catch {
|
||||||
|
/* ignore */
|
||||||
|
}
|
||||||
|
setDropSectionBand({ slot: sectionToSlot, phaseAboveSplitPo: Number(po) || 0 })
|
||||||
|
}
|
||||||
|
|
||||||
|
const onPhaseBelowSplitDragOver = (e, po) => {
|
||||||
|
if (!enableSectionDragReorder || !enableParallelPhaseControls) return
|
||||||
|
if (!dtHasType(e, DND_TU_SECTION)) return
|
||||||
|
e.preventDefault()
|
||||||
|
e.stopPropagation()
|
||||||
|
try {
|
||||||
|
e.dataTransfer.dropEffect = 'move'
|
||||||
|
} catch {
|
||||||
|
/* ignore */
|
||||||
|
}
|
||||||
|
setDropSectionBand({ slot: sectionToSlot, phaseBelowSplitPo: Number(po) || 0 })
|
||||||
|
}
|
||||||
|
|
||||||
|
const applyParsedSectionDrop = (data) => {
|
||||||
|
const phaseRunMove = data.phaseRunMove
|
||||||
|
const fromSi = data.fromSectionIdx
|
||||||
|
const fromSlot = typeof data.fromSlot === 'number' ? data.fromSlot : -1
|
||||||
|
|
||||||
|
if (phaseRunMove != null && phaseRunMove.phaseOrderIndex != null) {
|
||||||
|
return { kind: 'phaseRun', phaseRunMove, fromSlot }
|
||||||
|
}
|
||||||
|
if (typeof fromSi !== 'number') return null
|
||||||
|
|
||||||
|
if (
|
||||||
|
typeof onMoveSectionsAcrossSlots === 'function' &&
|
||||||
|
sectionToSlot >= 0 &&
|
||||||
|
fromSlot >= 0
|
||||||
|
) {
|
||||||
|
return { kind: 'crossSlot', fromSi, fromSlot }
|
||||||
|
}
|
||||||
|
|
||||||
|
return { kind: 'local', fromSi }
|
||||||
|
}
|
||||||
|
|
||||||
|
const onPhaseAboveSplitDrop = (e, po) => {
|
||||||
|
if (!enableSectionDragReorder || !enableParallelPhaseControls) return
|
||||||
|
e.preventDefault()
|
||||||
|
e.stopPropagation()
|
||||||
|
clearSectionDnD()
|
||||||
|
let raw = ''
|
||||||
|
try {
|
||||||
|
raw = e.dataTransfer.getData(DND_TU_SECTION)
|
||||||
|
} catch {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (!raw) return
|
||||||
|
let data
|
||||||
|
try {
|
||||||
|
data = JSON.parse(raw)
|
||||||
|
} catch {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const targetPo = Number(po) || 0
|
||||||
|
const parsed = applyParsedSectionDrop(data)
|
||||||
|
if (!parsed) return
|
||||||
|
|
||||||
|
if (parsed.kind === 'phaseRun') {
|
||||||
|
const dragPo = Number(parsed.phaseRunMove.phaseOrderIndex) || 0
|
||||||
|
if (dragPo === targetPo) return
|
||||||
|
patch((prev) => {
|
||||||
|
const idxs = indicesOfParallelPhase(prev, targetPo)
|
||||||
|
const fg = idxs.length ? idxs[0] : -1
|
||||||
|
if (fg < 0) return prev
|
||||||
|
let next = moveParallelPhaseRunToInsertBefore(prev, dragPo, fg)
|
||||||
|
if (enableParallelPhaseControls) next = afterSectionReorderParallelGuard(prev, next)
|
||||||
|
return next
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (parsed.kind === 'crossSlot') return
|
||||||
|
|
||||||
|
const { fromSi } = parsed
|
||||||
|
patch((prev) => {
|
||||||
|
let next = reorderSectionBeforeParallelRunAsWholeGroup(prev, fromSi, targetPo)
|
||||||
|
if (enableParallelPhaseControls) next = afterSectionReorderParallelGuard(prev, next)
|
||||||
|
return next
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const onPhaseBelowSplitDrop = (e, po) => {
|
||||||
|
if (!enableSectionDragReorder || !enableParallelPhaseControls) return
|
||||||
|
e.preventDefault()
|
||||||
|
e.stopPropagation()
|
||||||
|
clearSectionDnD()
|
||||||
|
let raw = ''
|
||||||
|
try {
|
||||||
|
raw = e.dataTransfer.getData(DND_TU_SECTION)
|
||||||
|
} catch {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (!raw) return
|
||||||
|
let data
|
||||||
|
try {
|
||||||
|
data = JSON.parse(raw)
|
||||||
|
} catch {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
const targetPo = Number(po) || 0
|
||||||
|
const parsed = applyParsedSectionDrop(data)
|
||||||
|
if (!parsed) return
|
||||||
|
|
||||||
|
if (parsed.kind === 'phaseRun') {
|
||||||
|
const dragPo = Number(parsed.phaseRunMove.phaseOrderIndex) || 0
|
||||||
|
if (dragPo === targetPo) return
|
||||||
|
patch((prev) => {
|
||||||
|
const idxs = indicesOfParallelPhase(prev, targetPo)
|
||||||
|
const fg = idxs.length ? idxs[0] : -1
|
||||||
|
if (fg < 0) return prev
|
||||||
|
let next = moveParallelPhaseRunToInsertBefore(prev, dragPo, fg)
|
||||||
|
if (enableParallelPhaseControls) next = afterSectionReorderParallelGuard(prev, next)
|
||||||
|
return next
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (parsed.kind === 'crossSlot') return
|
||||||
|
|
||||||
|
const { fromSi } = parsed
|
||||||
|
patch((prev) => {
|
||||||
|
let next = reorderSectionAsFirstInParallelPhase(prev, fromSi, targetPo)
|
||||||
|
if (enableParallelPhaseControls) next = afterSectionReorderParallelGuard(prev, next)
|
||||||
|
return next
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
const onSectionBandDrop = (e, insertBeforeIdx) => {
|
const onSectionBandDrop = (e, insertBeforeIdx) => {
|
||||||
if (!enableSectionDragReorder) return
|
if (!enableSectionDragReorder) return
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
|
|
@ -763,6 +904,32 @@ export default function TrainingUnitSectionsEditor({
|
||||||
|
|
||||||
if (typeof fromSi !== 'number') return
|
if (typeof fromSi !== 'number') return
|
||||||
|
|
||||||
|
if (enableParallelPhaseControls) {
|
||||||
|
const fromPl = list[fromSi]?.planLoc
|
||||||
|
if (fromPl?.phaseKind === 'parallel' && insertBeforeIdx >= 0 && insertBeforeIdx < list.length) {
|
||||||
|
const po = fromPl.phaseOrderIndex ?? 0
|
||||||
|
const fromSo = fromPl.parallelStreamOrderIndex ?? 0
|
||||||
|
const tabSo =
|
||||||
|
parallelStreamTabByPhase[po] ?? streamsForParallelPhaseOrders(list, po)[0] ?? 0
|
||||||
|
const targetPl = list[insertBeforeIdx]?.planLoc
|
||||||
|
if (
|
||||||
|
targetPl?.phaseKind === 'parallel' &&
|
||||||
|
(targetPl.phaseOrderIndex ?? 0) === po &&
|
||||||
|
(targetPl.parallelStreamOrderIndex ?? 0) !== fromSo &&
|
||||||
|
tabSo === fromSo
|
||||||
|
) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
enableParallelPhaseControls &&
|
||||||
|
(insertBeforeIdx === fromSi || insertBeforeIdx === fromSi + 1)
|
||||||
|
) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if (
|
if (
|
||||||
typeof onMoveSectionsAcrossSlots === 'function' &&
|
typeof onMoveSectionsAcrossSlots === 'function' &&
|
||||||
sectionToSlot >= 0 &&
|
sectionToSlot >= 0 &&
|
||||||
|
|
@ -1182,12 +1349,6 @@ export default function TrainingUnitSectionsEditor({
|
||||||
parallelPhaseOrder != null
|
parallelPhaseOrder != null
|
||||||
? firstSectionIndexByParallelPhase.get(parallelPhaseOrder)
|
? firstSectionIndexByParallelPhase.get(parallelPhaseOrder)
|
||||||
: null
|
: null
|
||||||
const phaseIndicesAll =
|
|
||||||
parallelPhaseOrder != null ? indicesOfParallelPhase(list, parallelPhaseOrder) : []
|
|
||||||
const isLastGlobalRowOfParallelPhase =
|
|
||||||
pl?.phaseKind === 'parallel' &&
|
|
||||||
phaseIndicesAll.length > 0 &&
|
|
||||||
sIdx === phaseIndicesAll[phaseIndicesAll.length - 1]
|
|
||||||
const firstVisibleIdxActiveStream =
|
const firstVisibleIdxActiveStream =
|
||||||
parallelPhaseOrder != null && streamOrdersForParallelPhase.length
|
parallelPhaseOrder != null && streamOrdersForParallelPhase.length
|
||||||
? sectionIndicesForParallelStream(
|
? sectionIndicesForParallelStream(
|
||||||
|
|
@ -1203,18 +1364,26 @@ export default function TrainingUnitSectionsEditor({
|
||||||
firstGlobalIdxThisPhase != null &&
|
firstGlobalIdxThisPhase != null &&
|
||||||
sIdx !== firstGlobalIdxThisPhase
|
sIdx !== firstGlobalIdxThisPhase
|
||||||
|
|
||||||
|
const isFirstSectionOfParallelPhase =
|
||||||
|
parallelPhaseOrder != null &&
|
||||||
|
firstSectionIndexByParallelPhase.get(parallelPhaseOrder) === sIdx
|
||||||
|
const hideDropBeforeFirstParallelBecauseDedicatedSlot =
|
||||||
|
enableParallelPhaseControls &&
|
||||||
|
isFirstSectionOfParallelPhase &&
|
||||||
|
pl?.phaseKind === 'parallel'
|
||||||
const showSectionDropBandBefore =
|
const showSectionDropBandBefore =
|
||||||
(pl?.phaseKind !== 'parallel' ||
|
(pl?.phaseKind !== 'parallel' || !hideParallelSection) &&
|
||||||
!hideParallelSection ||
|
!hideDropBandBeforeOrphanFirstVisible &&
|
||||||
isLastGlobalRowOfParallelPhase) &&
|
!hideDropBeforeFirstParallelBecauseDedicatedSlot
|
||||||
!hideDropBandBeforeOrphanFirstVisible
|
|
||||||
|
|
||||||
const bandActiveBefore = (bx) =>
|
const bandActiveBefore = (bx) =>
|
||||||
enableSectionDragReorder &&
|
enableSectionDragReorder &&
|
||||||
dropSectionBand &&
|
dropSectionBand &&
|
||||||
dropSectionBand.slot === sectionToSlot &&
|
dropSectionBand.slot === sectionToSlot &&
|
||||||
dropSectionBand.beforeIdx === bx &&
|
dropSectionBand.beforeIdx === bx &&
|
||||||
!dropSectionBand.streamDrop
|
!dropSectionBand.streamDrop &&
|
||||||
|
dropSectionBand.phaseAboveSplitPo == null &&
|
||||||
|
dropSectionBand.phaseBelowSplitPo == null
|
||||||
|
|
||||||
const streamChipDropActive = (po, so) =>
|
const streamChipDropActive = (po, so) =>
|
||||||
useStreamTagDropUx &&
|
useStreamTagDropUx &&
|
||||||
|
|
@ -1222,9 +1391,15 @@ export default function TrainingUnitSectionsEditor({
|
||||||
dropSectionBand?.streamDrop?.po === po &&
|
dropSectionBand?.streamDrop?.po === po &&
|
||||||
dropSectionBand?.streamDrop?.so === so
|
dropSectionBand?.streamDrop?.so === so
|
||||||
|
|
||||||
const isFirstSectionOfParallelPhase =
|
const phaseAboveSplitDnd =
|
||||||
parallelPhaseOrder != null &&
|
parallelPhaseOrder != null &&
|
||||||
firstSectionIndexByParallelPhase.get(parallelPhaseOrder) === sIdx
|
dropSectionBand?.slot === sectionToSlot &&
|
||||||
|
dropSectionBand?.phaseAboveSplitPo === parallelPhaseOrder
|
||||||
|
const phaseBelowSplitDnd =
|
||||||
|
parallelPhaseOrder != null &&
|
||||||
|
dropSectionBand?.slot === sectionToSlot &&
|
||||||
|
dropSectionBand?.phaseBelowSplitPo === parallelPhaseOrder
|
||||||
|
|
||||||
const streamVisual =
|
const streamVisual =
|
||||||
enableParallelPhaseControls && pl?.phaseKind === 'parallel'
|
enableParallelPhaseControls && pl?.phaseKind === 'parallel'
|
||||||
? parallelStreamVisual(pl.parallelStreamOrderIndex ?? 0)
|
? parallelStreamVisual(pl.parallelStreamOrderIndex ?? 0)
|
||||||
|
|
@ -1256,6 +1431,28 @@ export default function TrainingUnitSectionsEditor({
|
||||||
{isFirstSectionOfParallelPhase &&
|
{isFirstSectionOfParallelPhase &&
|
||||||
enableParallelPhaseControls &&
|
enableParallelPhaseControls &&
|
||||||
streamOrdersForParallelPhase.length ? (
|
streamOrdersForParallelPhase.length ? (
|
||||||
|
<Fragment key={`phase-edge-${parallelPhaseOrder}`}>
|
||||||
|
{enableSectionDragReorder ? (
|
||||||
|
<div
|
||||||
|
className={
|
||||||
|
'tu-section-dropband tu-phase-drop--above-split tu-section-dropband--phase-parallel-slot' +
|
||||||
|
sectionDropBandRegionClass(
|
||||||
|
list,
|
||||||
|
firstGlobalIdxThisPhase ?? sIdx,
|
||||||
|
enableParallelPhaseControls
|
||||||
|
) +
|
||||||
|
(phaseAboveSplitDnd ? ' tu-section-dropband--active' : '')
|
||||||
|
}
|
||||||
|
title="Oberhalb der Split-Phase: Abschnitt in die Ganzgruppe ziehen"
|
||||||
|
aria-label="Dropzone Ganzgruppe oberhalb der Split-Phase"
|
||||||
|
onDragOver={(e) => onPhaseAboveSplitDragOver(e, parallelPhaseOrder)}
|
||||||
|
onDragLeave={(e) => {
|
||||||
|
if (e.currentTarget.contains(e.relatedTarget)) return
|
||||||
|
clearSectionDnD()
|
||||||
|
}}
|
||||||
|
onDrop={(e) => onPhaseAboveSplitDrop(e, parallelPhaseOrder)}
|
||||||
|
/>
|
||||||
|
) : null}
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
marginBottom: '12px',
|
marginBottom: '12px',
|
||||||
|
|
@ -1425,6 +1622,22 @@ export default function TrainingUnitSectionsEditor({
|
||||||
+ Abschnitt in diesem Stream
|
+ Abschnitt in diesem Stream
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
{enableSectionDragReorder ? (
|
||||||
|
<div
|
||||||
|
className={
|
||||||
|
'tu-section-dropband tu-phase-drop--below-split tu-section-dropband--phase-parallel-slot' +
|
||||||
|
(phaseBelowSplitDnd ? ' tu-section-dropband--active' : '')
|
||||||
|
}
|
||||||
|
title="Erster Abschnitt dieser Split-Phase (vorne einfügen)"
|
||||||
|
aria-label="Dropzone erster Abschnitt unter dem Split-Kopf"
|
||||||
|
onDragOver={(e) => onPhaseBelowSplitDragOver(e, parallelPhaseOrder)}
|
||||||
|
onDragLeave={(e) => {
|
||||||
|
if (e.currentTarget.contains(e.relatedTarget)) return
|
||||||
|
clearSectionDnD()
|
||||||
|
}}
|
||||||
|
onDrop={(e) => onPhaseBelowSplitDrop(e, parallelPhaseOrder)}
|
||||||
|
/>
|
||||||
|
) : null}
|
||||||
<div
|
<div
|
||||||
role="tablist"
|
role="tablist"
|
||||||
aria-label={`Streams · Phase ${parallelPhaseOrder}`}
|
aria-label={`Streams · Phase ${parallelPhaseOrder}`}
|
||||||
|
|
@ -1584,6 +1797,7 @@ export default function TrainingUnitSectionsEditor({
|
||||||
})}
|
})}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</Fragment>
|
||||||
) : null}
|
) : null}
|
||||||
{!hideParallelSection ? (
|
{!hideParallelSection ? (
|
||||||
<>
|
<>
|
||||||
|
|
|
||||||
|
|
@ -863,6 +863,48 @@ export function reorderBlocksImmutableWithPlanLoc(prev, fromI, toBeforeIdx) {
|
||||||
return arr
|
return arr
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Abschnitt direkt vor den Parallel-Lauf setzen (immer Ganzgruppe oberhalb der Split-Phase).
|
||||||
|
*/
|
||||||
|
export function reorderSectionBeforeParallelRunAsWholeGroup(prev, fromI, phaseOrderIndex) {
|
||||||
|
const po = Number(phaseOrderIndex) || 0
|
||||||
|
const idxs = indicesOfParallelPhase(prev, po)
|
||||||
|
if (!idxs.length || fromI < 0 || fromI >= (prev?.length ?? 0)) return prev
|
||||||
|
const fg = idxs[0]
|
||||||
|
const arr = [...prev]
|
||||||
|
const [moved] = arr.splice(fromI, 1)
|
||||||
|
let insertAt = fg
|
||||||
|
if (fromI < insertAt) insertAt -= 1
|
||||||
|
insertAt = Math.max(0, Math.min(insertAt, arr.length))
|
||||||
|
const above = insertAt > 0 ? arr[insertAt - 1] : undefined
|
||||||
|
let planLocNext
|
||||||
|
if (above?.planLoc?.phaseKind === 'whole_group') {
|
||||||
|
planLocNext = { ...above.planLoc }
|
||||||
|
} else if (!above) {
|
||||||
|
planLocNext = defaultPlanLocWholeGroup(0)
|
||||||
|
} else {
|
||||||
|
const mx = maxPhaseOrderIndexFromSections(arr)
|
||||||
|
planLocNext = defaultPlanLocWholeGroup(mx + 1)
|
||||||
|
}
|
||||||
|
arr.splice(insertAt, 0, { ...moved, planLoc: planLocNext })
|
||||||
|
return arr
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Abschnitt als neuen ersten Eintrag der Parallel-Phase (gleiche Phasen-/Stream-Metadaten wie bisheriger Kopf). */
|
||||||
|
export function reorderSectionAsFirstInParallelPhase(prev, fromI, phaseOrderIndex) {
|
||||||
|
const po = Number(phaseOrderIndex) || 0
|
||||||
|
const idxs = indicesOfParallelPhase(prev, po)
|
||||||
|
if (!idxs.length || fromI < 0 || fromI >= (prev?.length ?? 0)) return prev
|
||||||
|
let fg = idxs[0]
|
||||||
|
const arr = [...prev]
|
||||||
|
const headTpl = { ...arr[fg].planLoc }
|
||||||
|
const [moved] = arr.splice(fromI, 1)
|
||||||
|
if (fromI < fg) fg -= 1
|
||||||
|
fg = Math.max(0, Math.min(fg, arr.length))
|
||||||
|
arr.splice(fg, 0, { ...moved, planLoc: { ...headTpl } })
|
||||||
|
return arr
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Abschnitt ans Ende eines parallelen Streams setzen (planLoc wie dieser Stream).
|
* Abschnitt ans Ende eines parallelen Streams setzen (planLoc wie dieser Stream).
|
||||||
* Leerer Stream: Einfügen hinter den letzten Abschnitt der zugehörigen parallelen Phase, planLoc vom Referenz-Abschnitt mit angepasstem streamIndex.
|
* Leerer Stream: Einfügen hinter den letzten Abschnitt der zugehörigen parallelen Phase, planLoc vom Referenz-Abschnitt mit angepasstem streamIndex.
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user