feat(records): scheduled records empty-state hint
Fixes UX bug: пользователь создаёт запись с validFrom на будущую дату
(e.g. 18.05), открывает catalog 15.05 — пустая таблица, никаких хинтов
о том что запись существует.
Backend (read-api):
- New endpoint GET /api/v1/{dict}/records/scheduled-summary
- Returns {count, nearestValidFrom} для записей с validFrom > now AND
validTo > now в текущем scope view
- Single-aggregate JPA query (COUNT + MIN), respect scope filter same way
as listActive — INTERNAL scheduled не учитывается для PUBLIC consumer'а
Frontend:
- New useScheduledSummary hook + ScheduledRecordsSummary type
- Empty-state в dictionaries.$name now shows: "Запланировано N, ближайшая
на DD.MM [Перейти к этой дате]" с CTA который set'ает time-travel на
nearestValidFrom
- i18n keys для ru/en plural forms
Связан с MR !219 (TimeTravelPicker 30-day future window) — теперь slider
позволяет дойти до даты записи, и empty-state hint позволяет узнать что
запись существует.
This commit is contained in:
@@ -20,6 +20,7 @@ import {
|
||||
type RecordDependentsPage,
|
||||
type RecordResponse,
|
||||
type ReviewQueuePage,
|
||||
type ScheduledRecordsSummary,
|
||||
type SchemaDependent,
|
||||
type SearchResponse,
|
||||
type WebhookDeliveryPage,
|
||||
@@ -784,6 +785,37 @@ export const useRecords = (
|
||||
scopeCsv: string,
|
||||
filter?: RecordsFilter,
|
||||
) => useQuery(recordsQuery(dictionaryName, scopeCsv, filter))
|
||||
|
||||
/**
|
||||
* Scheduled records hint для empty-state. Fetch'ит count записей с
|
||||
* validFrom > now (но validTo > now — т.е. не сразу закрытые). Показывается
|
||||
* пользователю когда список пуст, но в будущем что-то запланировано.
|
||||
*
|
||||
* <p>Fixes UX bug: user создал запись с validFrom=18.05, открыл catalog 15.05 —
|
||||
* пустая таблица, никаких хинтов. Теперь UI показывает «Запланировано: 1
|
||||
* запись на 18.05 [перейти к дате]».
|
||||
*
|
||||
* <p>Stale 30s — scheduled state changes медленно. Refetch on focus = true
|
||||
* (default) — пользователь возвращается во вкладку → fresh count.
|
||||
*/
|
||||
export const scheduledSummaryQuery = (dictionaryName: string, scopeCsv: string) =>
|
||||
queryOptions({
|
||||
queryKey: ['scheduled-summary', dictionaryName, scopeCsv] as const,
|
||||
queryFn: async (): Promise<ScheduledRecordsSummary> => {
|
||||
const { data } = await apiClient.get<ScheduledRecordsSummary>(
|
||||
`/${dictionaryName}/records/scheduled-summary`,
|
||||
{ params: { as_scope: scopeCsv } },
|
||||
)
|
||||
return data
|
||||
},
|
||||
staleTime: 30_000,
|
||||
})
|
||||
|
||||
export const useScheduledSummary = (dictionaryName: string, scopeCsv: string) =>
|
||||
useQuery({
|
||||
...scheduledSummaryQuery(dictionaryName, scopeCsv),
|
||||
enabled: Boolean(dictionaryName),
|
||||
})
|
||||
export const useRecordRaw = (
|
||||
dictionaryName: string,
|
||||
businessKey: string | undefined,
|
||||
|
||||
Reference in New Issue
Block a user