このコミットが含まれているのは:
@@ -4,6 +4,7 @@ import { useSearchParams } from 'react-router-dom'
|
||||
|
||||
import PrefetchLink from '@/components/PrefetchLink'
|
||||
import CountsControls from '@/components/counts/CountsControls'
|
||||
import CountsStateResults from '@/components/counts/CountsStateResults'
|
||||
import CountsResults from '@/components/counts/CountsResults'
|
||||
import CountsTableLayout from '@/components/counts/CountsTableLayout'
|
||||
import PageHead from '@/components/common/PageHead'
|
||||
@@ -13,8 +14,9 @@ import MainArea from '@/components/layout/MainArea'
|
||||
import SidebarComponent from '@/components/layout/SidebarComponent'
|
||||
import { Button } from '@/components/ui/button'
|
||||
import { countsCSV, countsRequestParams, fieldsForCounts, fetchCounts,
|
||||
normaliseCountsParams, selectedCountColumns } from '@/lib/counts'
|
||||
isCountsState, normaliseCountsParams, selectedCountColumns } from '@/lib/counts'
|
||||
import { countsCSVCell } from '@/lib/countsDisplay'
|
||||
import { countsStateCell, countsStateDrill, countsStateFields } from '@/lib/countsState'
|
||||
import { countsKeys } from '@/lib/queryKeys'
|
||||
import { cn } from '@/lib/utils'
|
||||
import { useLocale } from '@/lib/useLocale'
|
||||
@@ -35,14 +37,16 @@ const CountsResourcePage = ({ resource }: { resource: CountsResource }) => {
|
||||
const [sidebarOpen, setSidebarOpen] = useState (false)
|
||||
const locale = useLocale ()
|
||||
const { label, message } = useUITranslation ('counts')
|
||||
const mode = params.get ('mode') ?? 'summary'
|
||||
const mode = params.get ('mode') ?? 'state'
|
||||
const state = isCountsState (params)
|
||||
const stateTable = mode === 'state' || mode === 'trend'
|
||||
const axis = params.get ('axis') ?? 'month'
|
||||
const { data, isPending, isError, isPlaceholderData, refetch } = useQuery ({
|
||||
queryKey: countsKeys.index (resource, request.toString (), locale),
|
||||
queryFn: () => fetchCounts (resource, request, locale), retry: false,
|
||||
placeholderData: (previous, query) => {
|
||||
const previousMode = new URLSearchParams (String (query?.queryKey[3] ?? ''))
|
||||
.get ('mode') ?? 'summary'
|
||||
.get ('mode') ?? 'state'
|
||||
return (query?.queryKey[1] === resource && query?.queryKey[2] === locale
|
||||
&& previousMode === mode) ? previous : undefined
|
||||
} })
|
||||
@@ -52,6 +56,18 @@ const CountsResourcePage = ({ resource }: { resource: CountsResource }) => {
|
||||
setParams (canonical, { replace: true })
|
||||
}, [canonical, source, setParams])
|
||||
|
||||
useEffect (() => {
|
||||
if (!state || data?.at == null || isPlaceholderData) return
|
||||
const next = new URLSearchParams (canonical)
|
||||
if (!next.get ('at')) next.set ('at', data.at)
|
||||
if (mode === 'trend')
|
||||
{
|
||||
if (!next.get ('from') && data.from) next.set ('from', data.from)
|
||||
if (!next.get ('before') && data.before) next.set ('before', data.before)
|
||||
}
|
||||
if (next.toString () !== canonical) setParams (next, { replace: true })
|
||||
}, [canonical, data, isPlaceholderData, mode, setParams, state])
|
||||
|
||||
const update = (key: string, value: string) => {
|
||||
const next = new URLSearchParams (params)
|
||||
if (value || key === 'sort') next.set (key, value)
|
||||
@@ -61,7 +77,12 @@ const CountsResourcePage = ({ resource }: { resource: CountsResource }) => {
|
||||
}
|
||||
const exportCSV = () => {
|
||||
const columns = selectedCountColumns (resource, params)
|
||||
const rows = mode === 'summary'
|
||||
const stateFields = countsStateFields (mode === 'trend')
|
||||
const rows = stateTable
|
||||
? [stateFields.map (field => message (field.label).text),
|
||||
...(data?.stateRows ?? []).map (row => stateFields.map (
|
||||
field => countsStateCell (row, field.key, locale)))]
|
||||
: (mode === 'summary'
|
||||
? [[message (`axes.${axis}`).text, message ('metric').text],
|
||||
...(data?.groups ?? []).map (group => [
|
||||
group.key == null ? message ('history:bot').text : group.name ?? String (group.key),
|
||||
@@ -69,7 +90,7 @@ const CountsResourcePage = ({ resource }: { resource: CountsResource }) => {
|
||||
: [columns.map (column => message (
|
||||
fieldsForCounts (resource).find (field => field.key === column)!.label).text),
|
||||
...(data?.versions ?? []).map (row => columns.map (
|
||||
column => countsCSVCell (row, column, resource, params, locale)))]
|
||||
column => countsCSVCell (row, column, resource, params, locale)))])
|
||||
const url = URL.createObjectURL (new Blob ([countsCSV (rows)], {
|
||||
type: 'text/csv;charset=utf-8' }))
|
||||
const link = document.createElement ('a')
|
||||
@@ -123,11 +144,23 @@ const CountsResourcePage = ({ resource }: { resource: CountsResource }) => {
|
||||
{isPending && <p>{label ('shared:messages.loadingEllipsis')}</p>}
|
||||
{isError && <p role="alert">{label ('common:fetchError')}</p>}
|
||||
{data != null && <>
|
||||
<p className="my-1 text-xs">{label ('total', { count: data.count })}</p>
|
||||
<CountsResults resource={resource} data={data} params={params}
|
||||
pending={isPlaceholderData} update={update}/>
|
||||
{state && data.at && <div className="my-1 flex flex-wrap gap-x-4 gap-y-1 text-xs">
|
||||
<span>{label ('state.boundary')}:{data.at.replace ('T', ' ')}</span>
|
||||
{data.totals && (['posts', 'tags', 'assignments'] as const).map (key => (
|
||||
<span key={key}>{label (`state.totals.${key}`)}:
|
||||
{key !== 'assignments' && data.totals![key] != null
|
||||
? <PrefetchLink to={countsStateDrill (params, data.at!, key)}>
|
||||
{data.totals![key]}</PrefetchLink>
|
||||
: data.totals![key] ?? '—'}
|
||||
</span>))}
|
||||
</div>}
|
||||
{!state && <p className="my-1 text-xs">{label ('total', { count: data.count })}</p>}
|
||||
{stateTable ? <CountsStateResults data={data} params={params}
|
||||
pending={isPlaceholderData} update={update}/> : (
|
||||
<CountsResults resource={resource} data={data} params={params}
|
||||
pending={isPlaceholderData} update={update}/>)}
|
||||
<Pagination page={data.page} totalPages={Math.ceil (
|
||||
(mode === 'summary' ? data.groupCount ?? 0 : data.count) / data.limit)}/>
|
||||
((stateTable || mode === 'summary') ? data.groupCount ?? 0 : data.count) / data.limit)}/>
|
||||
</>}
|
||||
</MainArea>
|
||||
</div>
|
||||
|
||||
新しいイシューから参照
ユーザーをブロックする