Архивация списков #9
@@ -2,7 +2,7 @@ import * as React from 'react';
|
||||
import type { WebPartContext } from '@microsoft/sp-webpart-base';
|
||||
import styles from './ApproveFeature.module.scss';
|
||||
import { getViewComponent } from '../../forms/viewRegistry';
|
||||
import { partitionForPageUrlAndListId } from '../../shared/approval';
|
||||
import { isConfirmedStaleListId } from '../../shared/approval';
|
||||
|
||||
export interface IApproveFeatureProps {
|
||||
context: WebPartContext;
|
||||
@@ -19,9 +19,10 @@ export interface IApproveFeatureProps {
|
||||
const ApproveFeature: React.FC<IApproveFeatureProps> = ({ context, formKey, itemId, listId }) => {
|
||||
const ViewComponent = getViewComponent(formKey);
|
||||
|
||||
// Партиция указана, но её нет в реестре — см. тот же комментарий в EditFeature.
|
||||
// Партиция указана и реестр ТОЧНО знает, что её там нет — см. тот же
|
||||
// комментарий в EditFeature (isConfirmedStaleListId).
|
||||
const partitionError =
|
||||
listId && !partitionForPageUrlAndListId(formKey, listId)
|
||||
listId && isConfirmedStaleListId(formKey, listId)
|
||||
? `Не удалось открыть заявку: список «${listId}» не найден в реестре партиций. Ссылка могла устареть — попробуйте открыть заявку заново из списка.`
|
||||
: undefined;
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ import styles from '../approve/ApproveFeature.module.scss';
|
||||
import { getFormComponent } from '../../forms/registry';
|
||||
import { REQUEST_TYPES } from '../../data/requests';
|
||||
import { emitRequestsChanged } from '../../shared/requestEvents';
|
||||
import { partitionForPageUrlAndListId } from '../../shared/approval';
|
||||
import { isConfirmedStaleListId } from '../../shared/approval';
|
||||
|
||||
export interface IEditFeatureProps {
|
||||
context: WebPartContext;
|
||||
@@ -33,12 +33,16 @@ const EditFeature: React.FC<IEditFeatureProps> = ({ context, formKey, itemId, li
|
||||
return <div className={styles.state}>Для формы «{formKey}» редактирование не настроено.</div>;
|
||||
}
|
||||
|
||||
// Партиция указана (заявки нумерованные, см. shared/approval/listPartitions.ts),
|
||||
// но её нет в реестре — устаревшая/битая ссылка. Проверяем ЗДЕСЬ, ДО монтирования
|
||||
// формы: внутри формы имя списка резолвится синхронно (useMemo) и там уже негде
|
||||
// красиво показать ошибку без риска уронить рендер всей панели — см.
|
||||
// vacationApprovalService и аналоги в остальных формах.
|
||||
if (listId && !partitionForPageUrlAndListId(formKey, listId)) {
|
||||
// Партиция указана (заявки нумерованные, см. shared/approval/listPartitions.ts)
|
||||
// и реестр ТОЧНО знает, что такого listId в серии типа нет (см.
|
||||
// isConfirmedStaleListId) — устаревшая/битая ссылка. Если реестр про серию
|
||||
// просто ничего не знает (approval-route не ответил при старте) — это НЕ
|
||||
// повод отказывать: listId доверяем как есть, ровно как listTargetsForType в
|
||||
// myRequests.service.ts. Проверяем ЗДЕСЬ, ДО монтирования формы: внутри неё
|
||||
// имя списка резолвится синхронно (useMemo) и там уже негде красиво показать
|
||||
// ошибку без риска уронить рендер всей панели — см. vacationApprovalService и
|
||||
// аналоги в остальных формах.
|
||||
if (listId && isConfirmedStaleListId(formKey, listId)) {
|
||||
return (
|
||||
<div className={styles.state}>
|
||||
Не удалось открыть заявку: список «{listId}» не найден в реестре партиций. Ссылка могла устареть —
|
||||
|
||||
@@ -29,6 +29,7 @@ export {
|
||||
currentPartitionForTypeId,
|
||||
currentPartitionForPageUrl,
|
||||
partitionForPageUrlAndListId,
|
||||
isConfirmedStaleListId,
|
||||
} from './listPartitions';
|
||||
export { useRequestTypeId } from './useRequestTypeId';
|
||||
export type { IRequestTypeIdState } from './useRequestTypeId';
|
||||
|
||||
@@ -97,10 +97,9 @@ export function currentPartitionForPageUrl(pageUrl: string): IListPartition | un
|
||||
* реестре, чтобы узнать имя списка (для парного списка согласования — см.
|
||||
* shared/listTitles.ts, approvalListTitleForListId).
|
||||
*
|
||||
* undefined — партиции с таким listId в реестре нет (устарела ссылка, реестр ещё
|
||||
* не загрузился). Вызывающая сторона в этом случае должна показать ошибку, а не
|
||||
* молча откатываться на текущую партицию — иначе данные архивной заявки
|
||||
* читались/писались бы не в тот список.
|
||||
* undefined — либо реестр про тип вообще ничего не знает (серия пуста), либо
|
||||
* partitions есть, но именно такого listId среди них нет. Эти два случая —
|
||||
* РАЗНЫЕ по смыслу: см. isConfirmedStaleListId ниже, только он умеет их различать.
|
||||
*/
|
||||
export function partitionForPageUrlAndListId(pageUrl: string, listId: string): IListPartition | undefined {
|
||||
const id = typeIdByPageUrl.get(pageUrl);
|
||||
@@ -108,3 +107,24 @@ export function partitionForPageUrlAndListId(pageUrl: string, listId: string): I
|
||||
const lower = listId.toLowerCase();
|
||||
return partitionsForTypeId(id).filter((p) => p.listId.toLowerCase() === lower)[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* true — ТОЛЬКО когда реестр про серию этого типа реально что-то знает (она не
|
||||
* пуста) и listId в неё не входит. Тогда ссылка гарантированно битая/устаревшая
|
||||
* (например, партицию удалили из реестра руками) — вот здесь уместна ошибка.
|
||||
*
|
||||
* Если же серия пуста — approval-route не ответил при старте, тип только что
|
||||
* появился, реестр ещё не успел зарегистрировать эту серию — мы просто НЕ ЗНАЕМ,
|
||||
* валиден ли listId, и вины на нём нет. В этом случае false: тот же приём
|
||||
* «доверять RequestType.listId без реестра», что и у listTargetsForType в
|
||||
* myRequests.service.ts — иначе временная недоступность approval-route выглядела
|
||||
* бы как «эта заявка вообще не открывается», хотя ссылка совершенно рабочая.
|
||||
*/
|
||||
export function isConfirmedStaleListId(pageUrl: string, listId: string): boolean {
|
||||
const id = typeIdByPageUrl.get(pageUrl);
|
||||
if (id === undefined) return false;
|
||||
const series = partitionsForTypeId(id);
|
||||
if (series.length === 0) return false;
|
||||
const lower = listId.toLowerCase();
|
||||
return !series.some((p) => p.listId.toLowerCase() === lower);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
import { RequestTypeId } from '../models/types';
|
||||
import { currentPartitionForPageUrl, partitionForPageUrlAndListId } from './approval/listPartitions';
|
||||
import {
|
||||
currentPartitionForPageUrl,
|
||||
isConfirmedStaleListId,
|
||||
partitionForPageUrlAndListId
|
||||
} from './approval/listPartitions';
|
||||
|
||||
/**
|
||||
* ЕДИНЫЙ источник имён списков SharePoint.
|
||||
@@ -98,22 +102,30 @@ export function approvalListTitle(id: RequestTypeId): string {
|
||||
* Имя списка данных КОНКРЕТНОЙ партиции по её listId — для открытия/сохранения
|
||||
* заявки, которая не обязательно лежит в текущей партиции (архив).
|
||||
*
|
||||
* В отличие от dataListTitle() НИЧЕГО не подставляет по умолчанию: если listId
|
||||
* не нашёлся в реестре (устаревшая ссылка, партиция удалена из реестра), это
|
||||
* означает, что мы рискуем прочитать/записать не тот список — правильный ответ
|
||||
* тут явная ошибка, а не молчаливый откат на текущую партицию.
|
||||
* Бросает ТОЛЬКО когда реестр ТОЧНО знает, что такого listId в серии нет
|
||||
* (isConfirmedStaleListId) — тогда мы рискуем прочитать/записать не тот список,
|
||||
* и правильный ответ — явная ошибка, а не молчаливый откат.
|
||||
*
|
||||
* Если же реестр про серию просто ничего не знает (approval-route не ответил
|
||||
* при старте) — это НЕ повод бросать: откатываемся на ту же конвенцию по номеру,
|
||||
* что и dataListTitle() для текущей партиции без реестра. Сам listId при этом не
|
||||
* используется как источник данных (данные читаются им напрямую, см. load.ts
|
||||
* каждой формы) — здесь он нужен только чтобы вывести ИМЯ списка согласования
|
||||
* по конвенции, а на неё влияет лишь номер партиции, не сам url.
|
||||
*/
|
||||
export function dataListTitleForListId(id: RequestTypeId, listId: string): string {
|
||||
const partition = partitionForPageUrlAndListId(id, listId);
|
||||
if (!partition) {
|
||||
if (partition?.title) return partition.title;
|
||||
|
||||
if (isConfirmedStaleListId(id, listId)) {
|
||||
throw new Error(
|
||||
`Список «${listId}» не найден в реестре партиций типа заявки «${id}» — возможно, ссылка устарела.`
|
||||
);
|
||||
}
|
||||
// Title кешируется в реестре на момент создания партиции — то же ограничение,
|
||||
// что и у dataListTitle() для текущей партиции (см. её комментарий), поэтому
|
||||
// фолбэк на конвенцию по номеру здесь абсолютно тот же приём.
|
||||
return partition.title || `${listTitleBase(id)} ${partition.number} — данные`;
|
||||
|
||||
// Партиция нашлась, но Title не закеширован (см. dataListTitle), либо реестр
|
||||
// про серию вообще ничего не знает — оба случая закрываются одним фолбэком.
|
||||
return `${listTitleBase(id)} ${partition?.number ?? FALLBACK_LIST_NUMBER} — данные`;
|
||||
}
|
||||
|
||||
/** Имя парного списка согласования конкретной партиции — см. dataListTitleForListId. */
|
||||
|
||||
Reference in New Issue
Block a user