fix bug
This commit is contained in:
@@ -13,7 +13,6 @@ export interface IManageRequestsPhaseTableProps {
|
|||||||
rows: ManagedApprovalRow[];
|
rows: ManagedApprovalRow[];
|
||||||
/** Заявка целиком только для просмотра (закрыта) — контролов нет вообще. */
|
/** Заявка целиком только для просмотра (закрыта) — контролов нет вообще. */
|
||||||
readOnly: boolean;
|
readOnly: boolean;
|
||||||
busy: boolean;
|
|
||||||
statusVariant: (status: string) => BadgeVariant;
|
statusVariant: (status: string) => BadgeVariant;
|
||||||
onReassign: (row: ManagedApprovalRow) => void;
|
onReassign: (row: ManagedApprovalRow) => void;
|
||||||
onRemove: (row: ManagedApprovalRow) => void;
|
onRemove: (row: ManagedApprovalRow) => void;
|
||||||
@@ -56,7 +55,6 @@ export const ManageRequestsPhaseTable: React.FC<IManageRequestsPhaseTableProps>
|
|||||||
title,
|
title,
|
||||||
rows,
|
rows,
|
||||||
readOnly,
|
readOnly,
|
||||||
busy,
|
|
||||||
statusVariant,
|
statusVariant,
|
||||||
onReassign,
|
onReassign,
|
||||||
onRemove,
|
onRemove,
|
||||||
@@ -181,14 +179,14 @@ export const ManageRequestsPhaseTable: React.FC<IManageRequestsPhaseTableProps>
|
|||||||
icon="chevron-down"
|
icon="chevron-down"
|
||||||
className={`${styles.iconBtnVisible} ${styles.flipY}`}
|
className={`${styles.iconBtnVisible} ${styles.flipY}`}
|
||||||
label={texts.manageRequests.moveUp}
|
label={texts.manageRequests.moveUp}
|
||||||
disabled={busy || isGhost || !movable || blockIndex <= lastLockedBlockIndex + 1}
|
disabled={isGhost || !movable || blockIndex <= lastLockedBlockIndex + 1}
|
||||||
onClick={() => moveBlockUp(blockIndex)}
|
onClick={() => moveBlockUp(blockIndex)}
|
||||||
/>
|
/>
|
||||||
<IconButton
|
<IconButton
|
||||||
icon="chevron-down"
|
icon="chevron-down"
|
||||||
className={styles.iconBtnVisible}
|
className={styles.iconBtnVisible}
|
||||||
label={texts.manageRequests.moveDown}
|
label={texts.manageRequests.moveDown}
|
||||||
disabled={busy || isGhost || !movable || blockIndex >= blocks.length - 1}
|
disabled={isGhost || !movable || blockIndex >= blocks.length - 1}
|
||||||
onClick={() => moveBlockDown(blockIndex)}
|
onClick={() => moveBlockDown(blockIndex)}
|
||||||
/>
|
/>
|
||||||
</ActionsCell>
|
</ActionsCell>
|
||||||
@@ -204,14 +202,13 @@ export const ManageRequestsPhaseTable: React.FC<IManageRequestsPhaseTableProps>
|
|||||||
icon="people"
|
icon="people"
|
||||||
className={r.parallelWithPrev ? styles.iconBtnActive : styles.iconBtnVisible}
|
className={r.parallelWithPrev ? styles.iconBtnActive : styles.iconBtnVisible}
|
||||||
label={r.parallelWithPrev ? texts.manageRequests.splitFromPrev : texts.manageRequests.mergeWithPrev}
|
label={r.parallelWithPrev ? texts.manageRequests.splitFromPrev : texts.manageRequests.mergeWithPrev}
|
||||||
disabled={busy || !canToggle}
|
disabled={!canToggle}
|
||||||
onClick={() => toggleParallel(i)}
|
onClick={() => toggleParallel(i)}
|
||||||
/>
|
/>
|
||||||
<IconButton
|
<IconButton
|
||||||
icon="edit"
|
icon="edit"
|
||||||
className={styles.iconBtnVisible}
|
className={styles.iconBtnVisible}
|
||||||
label={texts.manageRequests.reassign}
|
label={texts.manageRequests.reassign}
|
||||||
disabled={busy}
|
|
||||||
onClick={() => onReassign(r)}
|
onClick={() => onReassign(r)}
|
||||||
/>
|
/>
|
||||||
<IconButton
|
<IconButton
|
||||||
@@ -219,7 +216,6 @@ export const ManageRequestsPhaseTable: React.FC<IManageRequestsPhaseTableProps>
|
|||||||
className={styles.iconBtnVisible}
|
className={styles.iconBtnVisible}
|
||||||
label={texts.manageRequests.remove}
|
label={texts.manageRequests.remove}
|
||||||
danger
|
danger
|
||||||
disabled={busy}
|
|
||||||
onClick={() => onRemove(r)}
|
onClick={() => onRemove(r)}
|
||||||
/>
|
/>
|
||||||
</ActionsCell>
|
</ActionsCell>
|
||||||
@@ -254,7 +250,6 @@ export const ManageRequestsPhaseTable: React.FC<IManageRequestsPhaseTableProps>
|
|||||||
options={employees.map(toEmployeeOption)}
|
options={employees.map(toEmployeeOption)}
|
||||||
value=""
|
value=""
|
||||||
loading={employeesLoading}
|
loading={employeesLoading}
|
||||||
disabled={busy}
|
|
||||||
placeholder={addPlaceholder}
|
placeholder={addPlaceholder}
|
||||||
searchPlaceholder={texts.select.employeeSearchPlaceholder}
|
searchPlaceholder={texts.select.employeeSearchPlaceholder}
|
||||||
emptyMessage={texts.select.employeesEmpty}
|
emptyMessage={texts.select.employeesEmpty}
|
||||||
|
|||||||
@@ -84,6 +84,44 @@ function renumberPhase(phaseRows: ManagedApprovalRow[]): Array<{ id: number; ord
|
|||||||
.map(r => ({ id: r.id, order: r.order }));
|
.map(r => ({ id: r.id, order: r.order }));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Строки в одном из этих статусов ещё «в игре» — решение по ним не принято.
|
||||||
|
// approved/executed/rejected/returned сюда не входят: это уже принятые решения
|
||||||
|
// (в т.ч. «Возвращена на доработку» — согласующий своё слово сказал, просто мы
|
||||||
|
// разрешили его потом переназначить; в очереди на активацию он не участвует).
|
||||||
|
const PENDING_STATUSES: string[] = [REQUEST_STATUS.queued, REQUEST_STATUS.onApproval, REQUEST_STATUS.onExecution];
|
||||||
|
|
||||||
|
// Пересчитывает «чья сейчас очередь» в фазе — 1:1 activateNextQueued из
|
||||||
|
// request-portal (shared/approval/approvalList.service.ts): среди ещё не
|
||||||
|
// решённых строк у той, что с МИНИМАЛЬНЫМ order, выставляется активный статус
|
||||||
|
// фазы («На согласовании»/«На исполнении»), у всех остальных — «Ждёт очереди».
|
||||||
|
// Несколько строк с одинаковым order (параллельный шаг) активируются вместе —
|
||||||
|
// в этом и смысл параллельности. Вызывается после ЛЮБОГО изменения, которое
|
||||||
|
// могло поменять, кто в фазе «первый»: перестановка, удаление, добавление.
|
||||||
|
function computeActivationUpdates(phaseRows: ManagedApprovalRow[], phase: string): Array<{ id: number; status: string }> {
|
||||||
|
const activeStatus = phase === APPROVAL_PHASE.execution ? REQUEST_STATUS.onExecution : REQUEST_STATUS.onApproval;
|
||||||
|
const pending = phaseRows.filter(r => PENDING_STATUSES.indexOf(r.status) !== -1);
|
||||||
|
if (pending.length === 0) return [];
|
||||||
|
const minOrder = Math.min(...pending.map(r => r.order));
|
||||||
|
const updates: Array<{ id: number; status: string }> = [];
|
||||||
|
pending.forEach(r => {
|
||||||
|
const desired = r.order === minOrder ? activeStatus : REQUEST_STATUS.queued;
|
||||||
|
if (r.status !== desired) updates.push({ id: r.id, status: desired });
|
||||||
|
});
|
||||||
|
return updates;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Сливает изменения order и status по одному и тому же id в один объект — иначе
|
||||||
|
// пришлось бы отправлять на одну и ту же строку два отдельных PATCH-запроса.
|
||||||
|
function mergeRowUpdates(
|
||||||
|
orderUpdates: Array<{ id: number; order: number }>,
|
||||||
|
statusUpdates: Array<{ id: number; status: string }>
|
||||||
|
): Array<{ id: number; order?: number; status?: string }> {
|
||||||
|
const byId = new Map<number, { id: number; order?: number; status?: string }>();
|
||||||
|
orderUpdates.forEach(u => byId.set(u.id, { ...(byId.get(u.id) || { id: u.id }), order: u.order }));
|
||||||
|
statusUpdates.forEach(u => byId.set(u.id, { ...(byId.get(u.id) || { id: u.id }), status: u.status }));
|
||||||
|
return Array.from(byId.values());
|
||||||
|
}
|
||||||
|
|
||||||
// Что выбрано в комбобоксах «Тип заявки»/«Заявка» — переживает перезагрузку
|
// Что выбрано в комбобоксах «Тип заявки»/«Заявка» — переживает перезагрузку
|
||||||
// страницы (localStorage), чтобы не искать одну и ту же заявку заново после
|
// страницы (localStorage), чтобы не искать одну и ту же заявку заново после
|
||||||
// каждого F5. selectedRequest хранится целиком (не только id), чтобы сразу
|
// каждого F5. selectedRequest хранится целиком (не только id), чтобы сразу
|
||||||
@@ -144,12 +182,6 @@ export const ManageRequestsScreen: React.FC<IManageRequestsScreenProps> = ({ api
|
|||||||
// (и настоящий Id из SharePoint) ещё не долетел. Реальные Id списка всегда
|
// (и настоящий Id из SharePoint) ещё не долетел. Реальные Id списка всегда
|
||||||
// положительные, поэтому пересечься эти диапазоны не могут.
|
// положительные, поэтому пересечься эти диапазоны не могут.
|
||||||
const nextGhostId = React.useRef(-1);
|
const nextGhostId = React.useRef(-1);
|
||||||
// Идёт фоновая запись (перестановка/переключение параллельности) — блокирует
|
|
||||||
// ТОЛЬКО повторную перестановку, чтобы не отправить второй reorder поверх ещё
|
|
||||||
// не завершённого (порядок мог бы разъехаться при гонке двух запросов).
|
|
||||||
// Переназначение/удаление/добавление такой блокировки не требуют: они не
|
|
||||||
// трогают order соседних строк, поэтому гонок между собой не создают.
|
|
||||||
const [reordering, setReordering] = React.useState(false);
|
|
||||||
|
|
||||||
const requestType = requestTypes.items.filter(rt => rt.id === Number(requestTypeId))[0];
|
const requestType = requestTypes.items.filter(rt => rt.id === Number(requestTypeId))[0];
|
||||||
// Только типы с привязанным списком SharePoint — без list_id/site_url искать
|
// Только типы с привязанным списком SharePoint — без list_id/site_url искать
|
||||||
@@ -246,23 +278,36 @@ export const ManageRequestsScreen: React.FC<IManageRequestsScreenProps> = ({ api
|
|||||||
const remainingPhaseRows = matrix.rows.filter(r => r.phase === row.phase && r.id !== row.id);
|
const remainingPhaseRows = matrix.rows.filter(r => r.phase === row.phase && r.id !== row.id);
|
||||||
const renumberUpdates = renumberPhase(remainingPhaseRows);
|
const renumberUpdates = renumberPhase(remainingPhaseRows);
|
||||||
const orderById = new Map(renumberUpdates.map(u => [u.id, u.order]));
|
const orderById = new Map(renumberUpdates.map(u => [u.id, u.order]));
|
||||||
|
const renumberedPhaseRows = remainingPhaseRows.map(r => (orderById.has(r.id) ? { ...r, order: orderById.get(r.id)! } : r));
|
||||||
|
|
||||||
|
// Удалили как раз ту строку, что была активной («На согласовании» и т.п.) —
|
||||||
|
// очередь надо продвинуть на следующую по order, иначе фаза так и останется
|
||||||
|
// без единой активной строки.
|
||||||
|
const activationUpdates = computeActivationUpdates(renumberedPhaseRows, row.phase);
|
||||||
|
const statusById = new Map(activationUpdates.map(u => [u.id, u.status]));
|
||||||
|
const writeUpdates = mergeRowUpdates(renumberUpdates, activationUpdates);
|
||||||
|
|
||||||
setMatrix({
|
setMatrix({
|
||||||
...matrix,
|
...matrix,
|
||||||
rows: matrix.rows
|
rows: matrix.rows
|
||||||
.filter(r => r.id !== row.id)
|
.filter(r => r.id !== row.id)
|
||||||
.map(r => (orderById.has(r.id) ? { ...r, order: orderById.get(r.id)! } : r))
|
.map(r => {
|
||||||
|
const order = orderById.get(r.id);
|
||||||
|
const status = statusById.get(r.id);
|
||||||
|
return order !== undefined || status !== undefined ? { ...r, ...(order !== undefined && { order }), ...(status !== undefined && { status }) } : r;
|
||||||
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
requestManage
|
requestManage
|
||||||
.removeRow(matrix, row.id)
|
.removeRow(matrix, row.id)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
if (renumberUpdates.length === 0) return;
|
if (writeUpdates.length === 0) return;
|
||||||
// Удаление уже прошло — откатывать нечего, даже если это пересохранение
|
// Удаление уже прошло — откатывать нечего, даже если пересохранение
|
||||||
// номеров не удастся. Просто сообщаем об ошибке: строка гарантированно
|
// номеров/статусов не удастся. Просто сообщаем об ошибке: строка
|
||||||
// удалена, а нумерация в SharePoint в худшем случае останется с дыркой
|
// гарантированно удалена, а нумерация/активация в SharePoint в худшем
|
||||||
// (что чинится обычной перестановкой любого шага той же фазы).
|
// случае разойдётся с тем, что видно на экране (починится обычной
|
||||||
return requestManage.reorderRows(matrix, renumberUpdates).catch((e: Error) => setSaveError(e.message));
|
// перестановкой любого шага той же фазы).
|
||||||
|
return requestManage.reorderRows(matrix, writeUpdates).catch((e: Error) => setSaveError(e.message));
|
||||||
})
|
})
|
||||||
.catch((e: Error) => {
|
.catch((e: Error) => {
|
||||||
setMatrix(previous);
|
setMatrix(previous);
|
||||||
@@ -321,13 +366,16 @@ export const ManageRequestsScreen: React.FC<IManageRequestsScreenProps> = ({ api
|
|||||||
const order = nextOrder(phaseRows);
|
const order = nextOrder(phaseRows);
|
||||||
const ghostId = nextGhostId.current--;
|
const ghostId = nextGhostId.current--;
|
||||||
|
|
||||||
// Новая строка всегда «Ждёт очереди» — request-portal переводит её в «На
|
// Новая строка встаёт ПОСЛЕДНЕЙ по order (см. nextOrder) — значит, стать
|
||||||
// согласовании»/«На исполнении» через activateNextQueued при следующем
|
// активной сразу она может, только если во всей фазе вообще нет ни одной
|
||||||
// решении согласующего или повторной отправке формы (см.
|
// ожидающей строки (например, первый исполнитель, добавленный в заявку, где
|
||||||
// request-portal/shared/approval/approvalList.service.ts). Если это ПЕРВЫЙ
|
// до этого фазы исполнения не было вовсе): тогда «первый по order среди
|
||||||
// шаг фазы (например, добавили исполнителя в заявку, где фазы исполнения
|
// ожидающих» — она и есть. Если в фазе уже кто-то ждёт своей очереди, та
|
||||||
// раньше не было вовсе) — activateNextQueued не сработает сам по себе, пока
|
// строка всегда раньше по order — новая просто встаёт в конец «Ждёт очереди».
|
||||||
// кто-то не примет решение по заявке; шаг до этого момента просто ждёт.
|
const hasPending = phaseRows.some(r => PENDING_STATUSES.indexOf(r.status) !== -1);
|
||||||
|
const activeStatus = phase === APPROVAL_PHASE.execution ? REQUEST_STATUS.onExecution : REQUEST_STATUS.onApproval;
|
||||||
|
const initialStatus = hasPending ? REQUEST_STATUS.queued : activeStatus;
|
||||||
|
|
||||||
const ghostRow: ManagedApprovalRow = {
|
const ghostRow: ManagedApprovalRow = {
|
||||||
id: ghostId,
|
id: ghostId,
|
||||||
ticketId: matrix.request.id,
|
ticketId: matrix.request.id,
|
||||||
@@ -335,7 +383,7 @@ export const ManageRequestsScreen: React.FC<IManageRequestsScreenProps> = ({ api
|
|||||||
approverName: found?.fio || email,
|
approverName: found?.fio || email,
|
||||||
approverEmail: email,
|
approverEmail: email,
|
||||||
position,
|
position,
|
||||||
status: REQUEST_STATUS.queued,
|
status: initialStatus,
|
||||||
date: '',
|
date: '',
|
||||||
comment: '',
|
comment: '',
|
||||||
order,
|
order,
|
||||||
@@ -347,7 +395,7 @@ export const ManageRequestsScreen: React.FC<IManageRequestsScreenProps> = ({ api
|
|||||||
setMatrix({ ...matrix, rows: [...matrix.rows, ghostRow] });
|
setMatrix({ ...matrix, rows: [...matrix.rows, ghostRow] });
|
||||||
|
|
||||||
requestManage
|
requestManage
|
||||||
.addRow(matrix, matrix.request.id, phase, order, REQUEST_STATUS.queued, email, position, false)
|
.addRow(matrix, matrix.request.id, phase, order, initialStatus, email, position, false)
|
||||||
.then(() => reloadMatrix(true))
|
.then(() => reloadMatrix(true))
|
||||||
.catch((e: Error) => {
|
.catch((e: Error) => {
|
||||||
setMatrix(previous);
|
setMatrix(previous);
|
||||||
@@ -355,28 +403,38 @@ export const ManageRequestsScreen: React.FC<IManageRequestsScreenProps> = ({ api
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
// Перестановка/параллельность — оптимистично: order из ManageRequestsPhaseTable
|
// Перестановка/параллельность — оптимистично и БЕЗ блокировки: order из
|
||||||
// применяется к матрице СРАЗУ (клик по стрелке/значку виден мгновенно), запрос
|
// ManageRequestsPhaseTable применяется к матрице СРАЗУ (каждый клик по
|
||||||
// на запись уходит фоном. Если он упадёт — откатываем к состоянию до клика и
|
// стрелке/значку виден мгновенно, в т.ч. при быстрых повторных кликах —
|
||||||
// показываем ошибку; если пройдёт — тихо перечитываем матрицу (не меняя
|
// предыдущий фоновый запрос ничего не блокирует), запрос на запись уходит
|
||||||
// видимого состояния, если её никто больше не менял, но подхватит, если менял).
|
// фоном. При ошибке — не откатываем к «состоянию до клика»: если кликов было
|
||||||
|
// несколько подряд, такой откат затёр бы более поздние, ещё не сохранённые
|
||||||
|
// изменения. Вместо этого просто перечитываем матрицу с сервера — она сама
|
||||||
|
// покажет, что в итоге реально сохранилось.
|
||||||
const handleReorder = (updates: Array<{ id: number; order: number }>): void => {
|
const handleReorder = (updates: Array<{ id: number; order: number }>): void => {
|
||||||
if (!matrix || reordering) return;
|
if (!matrix || updates.length === 0) return;
|
||||||
setSaveError(undefined);
|
setSaveError(undefined);
|
||||||
|
|
||||||
const previous = matrix;
|
|
||||||
const orderById = new Map(updates.map(u => [u.id, u.order]));
|
const orderById = new Map(updates.map(u => [u.id, u.order]));
|
||||||
setMatrix({ ...matrix, rows: matrix.rows.map(r => (orderById.has(r.id) ? { ...r, order: orderById.get(r.id)! } : r)) });
|
const nextRows = matrix.rows.map(r => (orderById.has(r.id) ? { ...r, order: orderById.get(r.id)! } : r));
|
||||||
|
|
||||||
setReordering(true);
|
// order-обновления всегда относятся к ОДНОЙ фазе (перестановка идёт внутри
|
||||||
requestManage
|
// одной таблицы — см. ManageRequestsPhaseTable), поэтому фазу для пересчёта
|
||||||
.reorderRows(matrix, updates)
|
// активации достаточно взять у любой из задетых строк.
|
||||||
.then(() => reloadMatrix(true))
|
const changedPhase = nextRows.filter(r => orderById.has(r.id))[0].phase;
|
||||||
.catch((e: Error) => {
|
const activationUpdates = computeActivationUpdates(nextRows.filter(r => r.phase === changedPhase), changedPhase);
|
||||||
setMatrix(previous);
|
const statusById = new Map(activationUpdates.map(u => [u.id, u.status]));
|
||||||
setSaveError(e.message);
|
|
||||||
})
|
setMatrix({
|
||||||
.finally(() => setReordering(false));
|
...matrix,
|
||||||
|
rows: nextRows.map(r => (statusById.has(r.id) ? { ...r, status: statusById.get(r.id)! } : r))
|
||||||
|
});
|
||||||
|
|
||||||
|
const writeUpdates = mergeRowUpdates(updates, activationUpdates);
|
||||||
|
requestManage.reorderRows(matrix, writeUpdates).catch((e: Error) => {
|
||||||
|
setSaveError(e.message);
|
||||||
|
reloadMatrix(true);
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -439,7 +497,6 @@ export const ManageRequestsScreen: React.FC<IManageRequestsScreenProps> = ({ api
|
|||||||
title={texts.manageRequests.approvalPhaseTitle}
|
title={texts.manageRequests.approvalPhaseTitle}
|
||||||
rows={approvalRows}
|
rows={approvalRows}
|
||||||
readOnly={readOnly}
|
readOnly={readOnly}
|
||||||
busy={reordering}
|
|
||||||
statusVariant={statusVariant}
|
statusVariant={statusVariant}
|
||||||
onReassign={openReassign}
|
onReassign={openReassign}
|
||||||
onRemove={askDelete}
|
onRemove={askDelete}
|
||||||
@@ -453,7 +510,6 @@ export const ManageRequestsScreen: React.FC<IManageRequestsScreenProps> = ({ api
|
|||||||
title={texts.manageRequests.executionPhaseTitle}
|
title={texts.manageRequests.executionPhaseTitle}
|
||||||
rows={executionRows}
|
rows={executionRows}
|
||||||
readOnly={readOnly}
|
readOnly={readOnly}
|
||||||
busy={reordering}
|
|
||||||
statusVariant={statusVariant}
|
statusVariant={statusVariant}
|
||||||
onReassign={openReassign}
|
onReassign={openReassign}
|
||||||
onRemove={askDelete}
|
onRemove={askDelete}
|
||||||
|
|||||||
@@ -281,13 +281,28 @@ export class RequestManageService {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Переставить StepOrder нескольких строк разом (перестановка шагов местами). */
|
/**
|
||||||
|
* Переставить StepOrder нескольких строк разом (перестановка шагов местами) и,
|
||||||
|
* при необходимости, статус той же строки — см. ManageRequestsScreen/
|
||||||
|
* computeActivationUpdates: после любой перестановки строка, ставшая первой
|
||||||
|
* нерешённой в очереди фазы, должна получить «На согласовании»/«На
|
||||||
|
* исполнении» вместо «Ждёт очереди» (и наоборот — та, что раньше была первой,
|
||||||
|
* а теперь нет). Оба поля пишутся одним update, чтобы не плодить лишний
|
||||||
|
* запрос на строку.
|
||||||
|
*/
|
||||||
public async reorderRows(
|
public async reorderRows(
|
||||||
matrix: Pick<ManagedRequestMatrix, 'siteUrl' | 'approvalListTitle'>,
|
matrix: Pick<ManagedRequestMatrix, 'siteUrl' | 'approvalListTitle'>,
|
||||||
updates: Array<{ id: number; order: number }>
|
updates: Array<{ id: number; order?: number; status?: string }>
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
const sp = this.clientFor(matrix.siteUrl);
|
const sp = this.clientFor(matrix.siteUrl);
|
||||||
const list = sp.web.lists.getByTitle(matrix.approvalListTitle);
|
const list = sp.web.lists.getByTitle(matrix.approvalListTitle);
|
||||||
await Promise.all(updates.map(u => list.items.getById(u.id).update({ [FIELDS.order]: u.order })));
|
await Promise.all(
|
||||||
|
updates.map(u => {
|
||||||
|
const patch: Record<string, unknown> = {};
|
||||||
|
if (u.order !== undefined) patch[FIELDS.order] = u.order;
|
||||||
|
if (u.status !== undefined) patch[FIELDS.status] = u.status;
|
||||||
|
return list.items.getById(u.id).update(patch);
|
||||||
|
})
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user