このコミットが含まれているのは:
@@ -1,4 +1,4 @@
|
||||
import { useQuery } from '@tanstack/react-query'
|
||||
import { useQuery, useQueryClient } from '@tanstack/react-query'
|
||||
import { useEffect, useRef, useState } from 'react'
|
||||
import { useSearchParams } from 'react-router-dom'
|
||||
|
||||
@@ -38,15 +38,10 @@ import type { CountsResource } from '@/lib/counts'
|
||||
|
||||
const CountsResourceContent = ({ resource }: { resource: CountsResource }) => {
|
||||
const definition = useCountsDefinition ()
|
||||
const queryClient = useQueryClient ()
|
||||
const [source, setParams] = useSearchParams ()
|
||||
const params = normaliseCountsParams (resource, source, definition)
|
||||
const canonical = params.toString ()
|
||||
const controlParams = new URLSearchParams (params)
|
||||
controlParams.delete ('nested_json')
|
||||
controlParams.delete ('order')
|
||||
controlParams.delete ('row_numbers')
|
||||
controlParams.set ('columns', selectedCountColumns (resource, params, definition)
|
||||
.filter (column => column !== 'thumbnail').sort ().join (' '))
|
||||
const request = countsRequestParams (params)
|
||||
const [open, setOpen] = useState (false)
|
||||
const [sidebarOpen, setSidebarOpen] = useState (false)
|
||||
@@ -65,8 +60,10 @@ const CountsResourceContent = ({ resource }: { resource: CountsResource }) => {
|
||||
const [exporting, setExporting] = useState (false)
|
||||
const exportInFlight = useRef (false)
|
||||
const [exportError, setExportError] = useState (false)
|
||||
const { data, isPending, isError, isPlaceholderData, refetch } = useQuery ({
|
||||
const { data, dataUpdatedAt, isFetching, isPending, isError,
|
||||
isPlaceholderData, refetch } = useQuery ({
|
||||
enabled: params.has ('timezone'),
|
||||
staleTime: params.has ('execution_at') ? 5 * 60 * 1000 : 0,
|
||||
queryKey: countsKeys.index (resource, cacheParams.toString (), locale),
|
||||
queryFn: () => fetchCounts (resource, params, locale), retry: false,
|
||||
placeholderData: (previous, query) => {
|
||||
@@ -80,25 +77,22 @@ const CountsResourceContent = ({ resource }: { resource: CountsResource }) => {
|
||||
} })
|
||||
|
||||
useEffect (() => {
|
||||
if (source.toString () !== canonical)
|
||||
setParams (canonical, { replace: true })
|
||||
}, [canonical, source, setParams])
|
||||
|
||||
useEffect (() => {
|
||||
const timezone = Intl.DateTimeFormat ().resolvedOptions ().timeZone
|
||||
if (params.get ('timezone') !== timezone)
|
||||
const next = new URLSearchParams (canonical)
|
||||
if (!next.has ('timezone'))
|
||||
next.set ('timezone', Intl.DateTimeFormat ().resolvedOptions ().timeZone)
|
||||
if (data?.executionAt != null && !isPlaceholderData && !isFetching && !isError
|
||||
&& params.has ('timezone') && !params.has ('execution_at'))
|
||||
{
|
||||
const next = new URLSearchParams (canonical)
|
||||
next.set ('timezone', timezone)
|
||||
setParams (next, { replace: true })
|
||||
}
|
||||
else if (data?.executionAt != null && !isPlaceholderData && !params.has ('execution_at'))
|
||||
{
|
||||
const next = new URLSearchParams (canonical)
|
||||
next.set ('execution_at', data.executionAt)
|
||||
setParams (next, { replace: true })
|
||||
// Pin the response under its server-confirmed time before changing the URL.
|
||||
queryClient.setQueryData (
|
||||
countsKeys.index (resource, countsRequestParams (next).toString (), locale),
|
||||
data, { updatedAt: dataUpdatedAt })
|
||||
}
|
||||
}, [canonical, data, isPlaceholderData, params, setParams])
|
||||
if (source.toString () !== next.toString ())
|
||||
setParams (next, { replace: true })
|
||||
}, [canonical, data, dataUpdatedAt, isError, isFetching, isPlaceholderData,
|
||||
locale, params, queryClient, resource, setParams, source])
|
||||
|
||||
|
||||
const update = (key: string, value: string, extra?: Record<string, string>) => {
|
||||
@@ -166,8 +160,8 @@ const CountsResourceContent = ({ resource }: { resource: CountsResource }) => {
|
||||
<Button type="button" variant="ghost" size="sm" className="shrink-0 md:hidden"
|
||||
aria-expanded={sidebarOpen} aria-controls="counts-targets"
|
||||
onClick={() => setSidebarOpen (!sidebarOpen)}>{label ('target')}</Button>
|
||||
<SidebarComponent sidebarKey="counts" maxWidth={224}
|
||||
className={cn ('md:block md:max-w-56', !sidebarOpen && 'hidden')}>
|
||||
<SidebarComponent sidebarKey="counts" maxWidthRatio={.5}
|
||||
className={cn ('md:block', !sidebarOpen && 'hidden')}>
|
||||
<nav id="counts-targets" aria-label={message ('target').text}
|
||||
lang={message ('target').language}>
|
||||
<h2 className="mb-2 font-semibold">{label ('target')}</h2>
|
||||
@@ -212,7 +206,7 @@ const CountsResourceContent = ({ resource }: { resource: CountsResource }) => {
|
||||
<MainArea className="flex min-h-0 min-w-0 flex-col p-2">
|
||||
<PageTitle className="mb-1 text-base">{label (`titles.${resource}`)}</PageTitle>
|
||||
<div className="shrink-0">
|
||||
<CountsControls key={`${resource}:${controlParams}`}
|
||||
<CountsControls
|
||||
resource={resource} applied={params}
|
||||
open={open} setOpen={setOpen}
|
||||
reorder={value => update ('order', value)}
|
||||
|
||||
新しいイシューから参照
ユーザーをブロックする