このコミットが含まれているのは:
@@ -18,6 +18,7 @@ import { Button } from '@/components/ui/button'
|
||||
import { countsRequestParams, countsDefinitionParams, countsExportPayload, fieldsForCounts, fetchCounts,
|
||||
isCountsState, normaliseCountsParams, selectedCountColumns } from '@/lib/counts'
|
||||
import { countsExportLabels } from '@/lib/countsDisplay'
|
||||
import { isApiError } from '@/lib/api'
|
||||
import { CountsDefinitionContext, countsAxisFields, countsAxisLabel,
|
||||
visibleCountsResources, countsFieldLabel,
|
||||
fetchCountsDefinition }
|
||||
@@ -42,6 +43,16 @@ type PendingCountsRun = {
|
||||
target?: string }
|
||||
|
||||
|
||||
const tooManyColumns = (failure: unknown): number | null => {
|
||||
if (!isApiError (failure) || failure.response?.status !== 422) return null
|
||||
const body = (failure.response.data ?? { }) as {
|
||||
error?: unknown; maxColumns?: unknown; max_columns?: unknown }
|
||||
const maximum = body.maxColumns ?? body.max_columns
|
||||
return body.error === 'too_many_columns' && typeof maximum === 'number'
|
||||
? maximum : null
|
||||
}
|
||||
|
||||
|
||||
const CountsResourceContent = (
|
||||
{ resource, definition, definitionError }: {
|
||||
resource: CountsResource; definition?: CountsDefinition; definitionError: boolean },
|
||||
@@ -85,6 +96,7 @@ const CountsResourceContent = (
|
||||
cacheParams.set ('definition', state ? 'latest' : 'history')
|
||||
const [running, setRunning] = useState (false)
|
||||
const [runError, setRunError] = useState (false)
|
||||
const [runColumnLimit, setRunColumnLimit] = useState<number | null> (null)
|
||||
const pendingRun = useRef<PendingCountsRun | null> (null)
|
||||
const applied = useRef (params)
|
||||
const retainedParams = useRef (params)
|
||||
@@ -92,7 +104,8 @@ const CountsResourceContent = (
|
||||
const [exporting, setExporting] = useState (false)
|
||||
const exportInFlight = useRef (false)
|
||||
const [exportError, setExportError] = useState (false)
|
||||
const { data, dataUpdatedAt, isFetching: fetching, isPending: pending, isError: errorFlg,
|
||||
const { data, error: queryError, dataUpdatedAt, isFetching: fetching,
|
||||
isPending: pending, isError: errorFlg,
|
||||
isPlaceholderData: placeholder } = useQuery ({
|
||||
enabled: definition != null && params.has ('timezone') && !running,
|
||||
staleTime: params.has ('execution_at') ? 5 * 60 * 1000 : 0,
|
||||
@@ -124,6 +137,7 @@ const CountsResourceContent = (
|
||||
useEffect (() => {
|
||||
setRunning (false)
|
||||
setRunError (false)
|
||||
setRunColumnLimit (null)
|
||||
return () => {
|
||||
const pending = pendingRun.current
|
||||
pendingRun.current = null
|
||||
@@ -162,6 +176,7 @@ const CountsResourceContent = (
|
||||
const previous = new URLSearchParams (params)
|
||||
pendingRun.current = pending
|
||||
setRunError (false)
|
||||
setRunColumnLimit (null)
|
||||
setRunning (true)
|
||||
try
|
||||
{
|
||||
@@ -199,11 +214,12 @@ const CountsResourceContent = (
|
||||
}
|
||||
else setParams (committed, { preventScrollReset: true })
|
||||
}
|
||||
catch
|
||||
catch (failure)
|
||||
{
|
||||
if (pendingRun.current !== pending) return
|
||||
pendingRun.current = null
|
||||
setRunning (false)
|
||||
setRunColumnLimit (tooManyColumns (failure))
|
||||
setRunError (true)
|
||||
}
|
||||
}
|
||||
@@ -212,9 +228,11 @@ const CountsResourceContent = (
|
||||
const waiting = running || (!definitionError && (definition == null
|
||||
|| pending || fetching || placeholder
|
||||
|| (!params.has ('execution_at') && !errorFlg)))
|
||||
const columnLimit = runColumnLimit ?? tooManyColumns (queryError)
|
||||
|
||||
|
||||
const update = (key: string, value: string, extra?: Record<string, string>) => {
|
||||
setRunColumnLimit (null)
|
||||
const next = new URLSearchParams (params)
|
||||
if (value || ['sort', 'columns', 'children', 'conditions', 'drill'].includes (key))
|
||||
setCountState (next, key, value)
|
||||
@@ -275,7 +293,7 @@ const CountsResourceContent = (
|
||||
<CountsTableLayout>
|
||||
<div data-sidebar-container
|
||||
className="flex min-h-0 flex-1 flex-col overflow-hidden md:flex-row">
|
||||
<PageHead title={title} includeSiteName={false}/>
|
||||
<PageHead title={title}/>
|
||||
<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>
|
||||
@@ -347,7 +365,11 @@ const CountsResourceContent = (
|
||||
|
||||
{exportError && <p role="alert">{label ('common:fetchError')}</p>}
|
||||
</div>
|
||||
{(definitionError || errorFlg || runError) && <p role="alert">{label ('common:fetchError')}</p>}
|
||||
{columnLimit != null ? <div role="alert">
|
||||
<p>{label ('columnLimit.title')}</p>
|
||||
<p>{label ('columnLimit.message', { max: columnLimit })}</p>
|
||||
</div> : ((definitionError || errorFlg || runError)
|
||||
&& <p role="alert">{label ('common:fetchError')}</p>)}
|
||||
<div className="relative flex min-h-0 flex-1 flex-col overflow-hidden"
|
||||
aria-busy={waiting}>
|
||||
<div inert={waiting} className="flex min-h-0 flex-1 flex-col">
|
||||
|
||||
新しいイシューから参照
ユーザーをブロックする