2026-08-01 06:01:40 +00:00
|
|
|
|
import React, {
|
|
|
|
|
|
Suspense,
|
|
|
|
|
|
startTransition,
|
|
|
|
|
|
useCallback,
|
|
|
|
|
|
useEffect,
|
|
|
|
|
|
useMemo,
|
|
|
|
|
|
useRef,
|
|
|
|
|
|
useState,
|
|
|
|
|
|
} from 'react'
|
2026-07-11 20:35:32 +00:00
|
|
|
|
import '@/utils/registerDevExtremeEditors'
|
2026-02-24 20:44:16 +00:00
|
|
|
|
import { useParams, useSearchParams } from 'react-router-dom'
|
|
|
|
|
|
import classNames from 'classnames'
|
|
|
|
|
|
|
|
|
|
|
|
import Container from '@/components/shared/Container'
|
2026-08-28 13:44:14 +00:00
|
|
|
|
import { Badge, Button, Dialog } from '@/components/ui'
|
|
|
|
|
|
import RichText from '@/components/shared/RichText'
|
2026-02-24 20:44:16 +00:00
|
|
|
|
import { useLocalization } from '@/utils/hooks/useLocalization'
|
|
|
|
|
|
import { useCurrentMenuIcon } from '@/utils/hooks/useCurrentMenuIcon'
|
|
|
|
|
|
|
|
|
|
|
|
import { useStoreActions, useStoreState } from '@/store/store'
|
|
|
|
|
|
import { GridDto } from '@/proxy/form/models'
|
|
|
|
|
|
import { getList } from '@/services/form.service'
|
|
|
|
|
|
import { ListViewLayoutType } from '../admin/listForm/edit/types'
|
|
|
|
|
|
|
|
|
|
|
|
import {
|
|
|
|
|
|
FaChartArea,
|
2026-07-16 08:19:17 +00:00
|
|
|
|
FaThLarge,
|
2026-02-24 20:44:16 +00:00
|
|
|
|
FaList,
|
|
|
|
|
|
FaSitemap,
|
|
|
|
|
|
FaTable,
|
|
|
|
|
|
FaCalendarAlt,
|
|
|
|
|
|
FaProjectDiagram,
|
2026-07-16 14:01:18 +00:00
|
|
|
|
FaTasks,
|
2026-08-28 13:44:14 +00:00
|
|
|
|
FaInfoCircle,
|
2026-02-24 20:44:16 +00:00
|
|
|
|
} from 'react-icons/fa'
|
|
|
|
|
|
|
|
|
|
|
|
/* =======================
|
|
|
|
|
|
🔥 LAZY VIEW IMPORTS
|
|
|
|
|
|
======================= */
|
|
|
|
|
|
const Grid = React.lazy(() => import('./Grid'))
|
2026-07-16 08:19:17 +00:00
|
|
|
|
const CardView = React.lazy(() => import('./CardView'))
|
2026-02-24 20:44:16 +00:00
|
|
|
|
const Pivot = React.lazy(() => import('./Pivot'))
|
|
|
|
|
|
const Tree = React.lazy(() => import('./Tree'))
|
|
|
|
|
|
const Chart = React.lazy(() => import('./Chart'))
|
|
|
|
|
|
const GanttView = React.lazy(() => import('./GanttView'))
|
|
|
|
|
|
const SchedulerView = React.lazy(() => import('./SchedulerView'))
|
2026-07-16 14:01:18 +00:00
|
|
|
|
const TodoBoard = React.lazy(() => import('./TodoBoard'))
|
2026-02-24 20:44:16 +00:00
|
|
|
|
|
2026-05-03 09:52:22 +00:00
|
|
|
|
function isLayoutValid(dto: GridDto, layout: ListViewLayoutType | undefined): boolean {
|
|
|
|
|
|
if (!layout || layout === 'grid') return true
|
2026-07-16 08:19:17 +00:00
|
|
|
|
if (layout === 'card') return true
|
2026-05-03 09:52:22 +00:00
|
|
|
|
if (layout === 'pivot') return !!dto.gridOptions?.layoutDto?.pivot
|
|
|
|
|
|
if (layout === 'chart') return !!dto.gridOptions?.layoutDto?.chart
|
|
|
|
|
|
if (layout === 'tree')
|
2026-05-03 11:35:52 +00:00
|
|
|
|
return !!(
|
|
|
|
|
|
dto.gridOptions?.layoutDto?.tree &&
|
|
|
|
|
|
dto.gridOptions?.treeOptionDto?.keyExpr &&
|
|
|
|
|
|
dto.gridOptions?.treeOptionDto?.parentIdExpr
|
|
|
|
|
|
)
|
2026-05-03 09:52:22 +00:00
|
|
|
|
if (layout === 'gantt')
|
|
|
|
|
|
return !!(
|
|
|
|
|
|
dto.gridOptions?.layoutDto?.gantt &&
|
2026-05-03 11:35:52 +00:00
|
|
|
|
dto.gridOptions?.ganttOptionDto?.keyExpr &&
|
2026-05-03 09:52:22 +00:00
|
|
|
|
dto.gridOptions?.ganttOptionDto?.parentIdExpr &&
|
2026-05-03 11:35:52 +00:00
|
|
|
|
dto.gridOptions?.ganttOptionDto?.titleExpr &&
|
|
|
|
|
|
dto.gridOptions?.ganttOptionDto?.startExpr &&
|
|
|
|
|
|
dto.gridOptions?.ganttOptionDto?.endExpr &&
|
|
|
|
|
|
dto.gridOptions?.ganttOptionDto?.progressExpr
|
2026-05-03 09:52:22 +00:00
|
|
|
|
)
|
|
|
|
|
|
if (layout === 'scheduler')
|
|
|
|
|
|
return !!(
|
|
|
|
|
|
dto.gridOptions?.layoutDto?.scheduler &&
|
|
|
|
|
|
dto.gridOptions?.schedulerOptionDto?.textExpr &&
|
2026-05-03 11:35:52 +00:00
|
|
|
|
dto.gridOptions?.schedulerOptionDto?.startDateExpr &&
|
|
|
|
|
|
dto.gridOptions?.schedulerOptionDto?.endDateExpr
|
2026-05-03 09:52:22 +00:00
|
|
|
|
)
|
2026-07-16 14:01:18 +00:00
|
|
|
|
if (layout === 'todo')
|
|
|
|
|
|
return !!(
|
|
|
|
|
|
dto.gridOptions?.layoutDto?.todo &&
|
|
|
|
|
|
dto.gridOptions?.todoOptionDto?.titleExpr &&
|
|
|
|
|
|
dto.gridOptions?.todoOptionDto?.statusExpr
|
|
|
|
|
|
)
|
2026-05-03 09:52:22 +00:00
|
|
|
|
return false
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-08-05 20:51:43 +00:00
|
|
|
|
interface ListProps {
|
|
|
|
|
|
listFormCode?: string
|
|
|
|
|
|
gridDto?: GridDto
|
2026-08-06 13:17:59 +00:00
|
|
|
|
isSubForm?: boolean
|
2026-08-05 20:51:43 +00:00
|
|
|
|
onRefreshGridDto?: () => Promise<void> | void
|
2026-08-19 12:13:32 +00:00
|
|
|
|
/**
|
|
|
|
|
|
* Filter carrier of a list embedded in a page. A standalone list reads the
|
|
|
|
|
|
* page address, but an embedded one is filtered by its host — the designer
|
|
|
|
|
|
* builds these from static values, the URL or a Form record.
|
|
|
|
|
|
*/
|
|
|
|
|
|
searchParams?: URLSearchParams
|
2026-08-05 20:51:43 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const List: React.FC<ListProps> = ({
|
|
|
|
|
|
listFormCode: externalListFormCode,
|
|
|
|
|
|
gridDto: externalGridDto,
|
2026-08-06 13:17:59 +00:00
|
|
|
|
isSubForm = false,
|
2026-08-05 20:51:43 +00:00
|
|
|
|
onRefreshGridDto,
|
2026-08-19 12:13:32 +00:00
|
|
|
|
searchParams: externalSearchParams,
|
2026-08-05 20:51:43 +00:00
|
|
|
|
}) => {
|
|
|
|
|
|
const { listFormCode: routeListFormCode = '' } = useParams()
|
|
|
|
|
|
const listFormCode = externalListFormCode || routeListFormCode
|
2026-08-19 12:13:32 +00:00
|
|
|
|
const [routeSearchParams] = useSearchParams()
|
|
|
|
|
|
const searchParams = externalSearchParams ?? routeSearchParams
|
2026-02-24 20:44:16 +00:00
|
|
|
|
|
|
|
|
|
|
const { translate } = useLocalization()
|
|
|
|
|
|
const mode = useStoreState((state) => state.theme.mode)
|
|
|
|
|
|
const MenuIcon = useCurrentMenuIcon('w-5 h-5')
|
|
|
|
|
|
|
|
|
|
|
|
const { states } = useStoreState((state) => state.admin.lists)
|
|
|
|
|
|
const { setStates } = useStoreActions((a) => a.admin.lists)
|
|
|
|
|
|
|
2026-08-01 06:01:40 +00:00
|
|
|
|
const activeListFormCodeRef = useRef(listFormCode)
|
|
|
|
|
|
activeListFormCodeRef.current = listFormCode
|
|
|
|
|
|
|
|
|
|
|
|
const [gridDtoState, setGridDtoState] = useState<{
|
|
|
|
|
|
listFormCode: string
|
|
|
|
|
|
gridDto: GridDto | null
|
|
|
|
|
|
}>({ listFormCode: '', gridDto: null })
|
2026-08-05 20:51:43 +00:00
|
|
|
|
const gridDto =
|
|
|
|
|
|
externalGridDto ??
|
|
|
|
|
|
(gridDtoState.listFormCode === listFormCode ? gridDtoState.gridDto : null)
|
2026-08-01 06:01:40 +00:00
|
|
|
|
|
|
|
|
|
|
const [viewModeState, setViewModeState] = useState<{
|
|
|
|
|
|
listFormCode: string
|
|
|
|
|
|
layoutType?: ListViewLayoutType
|
|
|
|
|
|
}>({ listFormCode: '' })
|
|
|
|
|
|
const viewMode = viewModeState.listFormCode === listFormCode ? viewModeState.layoutType : undefined
|
2026-02-24 20:44:16 +00:00
|
|
|
|
|
|
|
|
|
|
/* =======================
|
|
|
|
|
|
🔹 GRID DTO FETCH
|
|
|
|
|
|
======================= */
|
|
|
|
|
|
const refreshGridDto = useCallback(async () => {
|
|
|
|
|
|
if (!listFormCode) return
|
2026-08-05 20:51:43 +00:00
|
|
|
|
|
|
|
|
|
|
if (onRefreshGridDto) {
|
|
|
|
|
|
await onRefreshGridDto()
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-08-01 06:01:40 +00:00
|
|
|
|
const requestedListFormCode = listFormCode
|
2026-02-24 20:44:16 +00:00
|
|
|
|
try {
|
2026-08-01 06:01:40 +00:00
|
|
|
|
const response = await getList({ listFormCode: requestedListFormCode })
|
|
|
|
|
|
if (activeListFormCodeRef.current !== requestedListFormCode) return
|
|
|
|
|
|
setGridDtoState({ listFormCode: requestedListFormCode, gridDto: response.data })
|
2026-02-24 20:44:16 +00:00
|
|
|
|
} catch (err) {
|
|
|
|
|
|
console.error('GridDto load error:', err)
|
|
|
|
|
|
}
|
2026-08-05 20:51:43 +00:00
|
|
|
|
}, [listFormCode, onRefreshGridDto])
|
2026-02-24 20:44:16 +00:00
|
|
|
|
|
|
|
|
|
|
useEffect(() => {
|
2026-08-05 20:51:43 +00:00
|
|
|
|
if (!externalGridDto) void refreshGridDto()
|
|
|
|
|
|
}, [externalGridDto, refreshGridDto])
|
2026-02-24 20:44:16 +00:00
|
|
|
|
|
|
|
|
|
|
/* =======================
|
|
|
|
|
|
🔹 INITIAL VIEW MODE
|
|
|
|
|
|
======================= */
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
|
|
if (!gridDto) return
|
|
|
|
|
|
|
|
|
|
|
|
const savedLayout = states.find((s) => s.listFormCode === listFormCode)?.layout
|
|
|
|
|
|
const defaultLayout = gridDto.gridOptions?.layoutDto?.defaultLayout
|
2026-05-03 09:52:22 +00:00
|
|
|
|
const candidate = savedLayout ?? defaultLayout
|
2026-05-03 11:35:52 +00:00
|
|
|
|
|
2026-08-01 06:01:40 +00:00
|
|
|
|
setViewModeState({
|
|
|
|
|
|
listFormCode,
|
|
|
|
|
|
layoutType: isLayoutValid(gridDto, candidate) ? candidate : 'grid',
|
|
|
|
|
|
})
|
2026-02-24 20:44:16 +00:00
|
|
|
|
}, [gridDto, states, listFormCode])
|
|
|
|
|
|
|
|
|
|
|
|
/* =======================
|
|
|
|
|
|
🔹 VIEW SWITCH HANDLER
|
|
|
|
|
|
======================= */
|
|
|
|
|
|
const setLayout = useCallback(
|
|
|
|
|
|
(layout: ListViewLayoutType) => {
|
|
|
|
|
|
startTransition(() => {
|
2026-08-01 06:01:40 +00:00
|
|
|
|
setViewModeState({ listFormCode, layoutType: layout })
|
2026-02-24 20:44:16 +00:00
|
|
|
|
})
|
|
|
|
|
|
setStates({ listFormCode, layout })
|
|
|
|
|
|
},
|
|
|
|
|
|
[listFormCode, setStates],
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
/* =======================
|
|
|
|
|
|
🔹 PRELOAD MAP (HOVER)
|
|
|
|
|
|
======================= */
|
|
|
|
|
|
const preload = useMemo(
|
|
|
|
|
|
() => ({
|
|
|
|
|
|
grid: () => import('./Grid'),
|
2026-07-16 08:19:17 +00:00
|
|
|
|
card: () => import('./CardView'),
|
2026-02-24 20:44:16 +00:00
|
|
|
|
pivot: () => import('./Pivot'),
|
|
|
|
|
|
tree: () => import('./Tree'),
|
|
|
|
|
|
chart: () => import('./Chart'),
|
|
|
|
|
|
gantt: () => import('./GanttView'),
|
|
|
|
|
|
scheduler: () => import('./SchedulerView'),
|
2026-07-16 14:01:18 +00:00
|
|
|
|
todo: () => import('./TodoBoard'),
|
2026-02-24 20:44:16 +00:00
|
|
|
|
}),
|
|
|
|
|
|
[],
|
|
|
|
|
|
)
|
|
|
|
|
|
|
2026-08-28 13:44:14 +00:00
|
|
|
|
/* =======================
|
|
|
|
|
|
🔹 HEADER DESCRIPTION (LISTFORM DESCRIPTION)
|
|
|
|
|
|
======================= */
|
|
|
|
|
|
// Description bir dil anahtarıdır; karşılığı yoksa translate anahtarı geri döndürür,
|
|
|
|
|
|
// o durumda kullanıcıya anahtar gösterilmez.
|
|
|
|
|
|
const [descriptionOpen, setDescriptionOpen] = useState(false)
|
|
|
|
|
|
const description = useMemo(() => {
|
|
|
|
|
|
const key = gridDto?.gridOptions?.description
|
|
|
|
|
|
if (!key) return null
|
|
|
|
|
|
const text = translate('::' + key)
|
|
|
|
|
|
return text && text !== key ? text : null
|
|
|
|
|
|
}, [gridDto?.gridOptions?.description, translate])
|
|
|
|
|
|
|
2026-02-24 20:44:16 +00:00
|
|
|
|
if (!listFormCode || !gridDto || !viewMode) {
|
|
|
|
|
|
return null
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
|
<Container>
|
|
|
|
|
|
{/* =======================
|
|
|
|
|
|
HEADER
|
|
|
|
|
|
======================= */}
|
|
|
|
|
|
<div
|
|
|
|
|
|
className={classNames(
|
|
|
|
|
|
'flex items-center gap-2 pb-1 border-b',
|
|
|
|
|
|
mode === 'light' ? 'border-gray-200' : 'border-neutral-700',
|
|
|
|
|
|
)}
|
|
|
|
|
|
>
|
|
|
|
|
|
{MenuIcon}
|
2026-08-28 13:44:14 +00:00
|
|
|
|
{description ? (
|
|
|
|
|
|
<button
|
|
|
|
|
|
className="flex items-center gap-1 text-sm font-medium hover:underline"
|
|
|
|
|
|
title={translate('::App.Platform.ShowDescription')}
|
|
|
|
|
|
type="button"
|
|
|
|
|
|
onClick={() => setDescriptionOpen(true)}
|
|
|
|
|
|
>
|
|
|
|
|
|
<h4 className="text-sm font-medium">{translate('::' + gridDto.gridOptions.title)}</h4>
|
|
|
|
|
|
<FaInfoCircle className="text-xs opacity-60" />
|
|
|
|
|
|
</button>
|
|
|
|
|
|
) : (
|
|
|
|
|
|
<h4 className="text-sm font-medium">{translate('::' + gridDto.gridOptions.title)}</h4>
|
|
|
|
|
|
)}
|
2026-02-24 20:44:16 +00:00
|
|
|
|
<Badge content={viewMode} />
|
|
|
|
|
|
|
|
|
|
|
|
{/* =======================
|
|
|
|
|
|
VIEW BUTTONS
|
|
|
|
|
|
======================= */}
|
|
|
|
|
|
<div className="flex gap-1 ml-auto">
|
2026-07-16 14:01:18 +00:00
|
|
|
|
{gridDto?.gridOptions?.layoutDto.todo &&
|
|
|
|
|
|
gridDto?.gridOptions?.todoOptionDto?.titleExpr &&
|
|
|
|
|
|
gridDto?.gridOptions?.todoOptionDto?.statusExpr && (
|
|
|
|
|
|
<Button
|
|
|
|
|
|
size="sm"
|
|
|
|
|
|
icon={<FaTasks />}
|
|
|
|
|
|
variant={viewMode === 'todo' ? 'solid' : 'default'}
|
|
|
|
|
|
onClick={() => setLayout('todo')}
|
|
|
|
|
|
onMouseEnter={() => preload.todo()}
|
2026-08-14 14:03:34 +00:00
|
|
|
|
title={translate('::App.Platform.TabTodo')}
|
2026-07-16 14:01:18 +00:00
|
|
|
|
/>
|
|
|
|
|
|
)}
|
2026-02-24 20:44:16 +00:00
|
|
|
|
{gridDto?.gridOptions?.layoutDto.scheduler &&
|
|
|
|
|
|
gridDto?.gridOptions?.schedulerOptionDto?.textExpr &&
|
|
|
|
|
|
gridDto?.gridOptions?.schedulerOptionDto?.startDateExpr && (
|
|
|
|
|
|
<Button
|
2026-05-05 17:59:30 +00:00
|
|
|
|
size="sm"
|
2026-05-12 12:32:40 +00:00
|
|
|
|
icon={<FaCalendarAlt />}
|
2026-02-24 20:44:16 +00:00
|
|
|
|
variant={viewMode === 'scheduler' ? 'solid' : 'default'}
|
|
|
|
|
|
onClick={() => setLayout('scheduler')}
|
|
|
|
|
|
onMouseEnter={() => preload.scheduler()}
|
2026-08-14 14:03:34 +00:00
|
|
|
|
title={translate('::App.Platform.TabScheduler')}
|
2026-07-10 08:18:20 +00:00
|
|
|
|
></Button>
|
2026-02-24 20:44:16 +00:00
|
|
|
|
)}
|
|
|
|
|
|
|
|
|
|
|
|
{gridDto?.gridOptions?.layoutDto.gantt &&
|
|
|
|
|
|
gridDto?.gridOptions?.ganttOptionDto?.parentIdExpr &&
|
|
|
|
|
|
gridDto?.gridOptions?.ganttOptionDto?.titleExpr && (
|
|
|
|
|
|
<Button
|
2026-05-05 17:59:30 +00:00
|
|
|
|
size="sm"
|
2026-05-12 12:32:40 +00:00
|
|
|
|
icon={<FaProjectDiagram />}
|
2026-02-24 20:44:16 +00:00
|
|
|
|
variant={viewMode === 'gantt' ? 'solid' : 'default'}
|
|
|
|
|
|
onClick={() => setLayout('gantt')}
|
|
|
|
|
|
onMouseEnter={() => preload.gantt()}
|
2026-08-14 14:03:34 +00:00
|
|
|
|
title={translate('::App.Platform.TabGantt')}
|
2026-07-10 08:18:20 +00:00
|
|
|
|
></Button>
|
2026-02-24 20:44:16 +00:00
|
|
|
|
)}
|
|
|
|
|
|
|
|
|
|
|
|
{gridDto?.gridOptions?.layoutDto.tree &&
|
|
|
|
|
|
gridDto?.gridOptions?.treeOptionDto?.parentIdExpr && (
|
|
|
|
|
|
<Button
|
2026-05-05 17:59:30 +00:00
|
|
|
|
size="sm"
|
2026-05-12 12:32:40 +00:00
|
|
|
|
icon={<FaSitemap />}
|
2026-02-24 20:44:16 +00:00
|
|
|
|
variant={viewMode === 'tree' ? 'solid' : 'default'}
|
|
|
|
|
|
onClick={() => setLayout('tree')}
|
|
|
|
|
|
onMouseEnter={() => preload.tree()}
|
2026-08-14 14:03:34 +00:00
|
|
|
|
title={translate('::App.Platform.TabTree')}
|
2026-07-10 08:18:20 +00:00
|
|
|
|
></Button>
|
2026-02-24 20:44:16 +00:00
|
|
|
|
)}
|
|
|
|
|
|
|
|
|
|
|
|
<Button
|
2026-05-05 17:59:30 +00:00
|
|
|
|
size="sm"
|
2026-05-12 12:32:40 +00:00
|
|
|
|
icon={<FaList />}
|
2026-02-24 20:44:16 +00:00
|
|
|
|
variant={viewMode === 'grid' ? 'solid' : 'default'}
|
|
|
|
|
|
onClick={() => setLayout('grid')}
|
|
|
|
|
|
onMouseEnter={() => preload.grid()}
|
2026-08-14 14:03:34 +00:00
|
|
|
|
title={translate('::App.ListFormEdit.TabGrid')}
|
2026-07-10 08:18:20 +00:00
|
|
|
|
></Button>
|
2026-02-24 20:44:16 +00:00
|
|
|
|
|
2026-07-16 08:19:17 +00:00
|
|
|
|
{gridDto.gridOptions.layoutDto.card && (
|
|
|
|
|
|
<Button
|
|
|
|
|
|
size="sm"
|
|
|
|
|
|
icon={<FaThLarge />}
|
|
|
|
|
|
variant={viewMode === 'card' ? 'solid' : 'default'}
|
|
|
|
|
|
onClick={() => setLayout('card')}
|
|
|
|
|
|
onMouseEnter={() => preload.card()}
|
2026-08-14 14:03:34 +00:00
|
|
|
|
title={translate('::App.ListFormEdit.TabCard')}
|
2026-07-16 08:19:17 +00:00
|
|
|
|
></Button>
|
|
|
|
|
|
)}
|
|
|
|
|
|
|
2026-02-24 20:44:16 +00:00
|
|
|
|
{gridDto.gridOptions.layoutDto.pivot && (
|
|
|
|
|
|
<Button
|
2026-05-05 17:59:30 +00:00
|
|
|
|
size="sm"
|
2026-05-12 12:32:40 +00:00
|
|
|
|
icon={<FaTable />}
|
2026-02-24 20:44:16 +00:00
|
|
|
|
variant={viewMode === 'pivot' ? 'solid' : 'default'}
|
|
|
|
|
|
onClick={() => setLayout('pivot')}
|
|
|
|
|
|
onMouseEnter={() => preload.pivot()}
|
2026-08-14 14:03:34 +00:00
|
|
|
|
title={translate('::App.Platform.TabPivot')}
|
2026-07-10 08:18:20 +00:00
|
|
|
|
></Button>
|
2026-02-24 20:44:16 +00:00
|
|
|
|
)}
|
|
|
|
|
|
|
|
|
|
|
|
{gridDto.gridOptions.layoutDto.chart && (
|
|
|
|
|
|
<Button
|
2026-05-05 17:59:30 +00:00
|
|
|
|
size="sm"
|
2026-05-12 12:32:40 +00:00
|
|
|
|
icon={<FaChartArea />}
|
2026-02-24 20:44:16 +00:00
|
|
|
|
variant={viewMode === 'chart' ? 'solid' : 'default'}
|
|
|
|
|
|
onClick={() => setLayout('chart')}
|
|
|
|
|
|
onMouseEnter={() => preload.chart()}
|
2026-08-14 14:03:34 +00:00
|
|
|
|
title={translate('::App.Platform.Chart')}
|
2026-07-10 08:18:20 +00:00
|
|
|
|
></Button>
|
2026-02-24 20:44:16 +00:00
|
|
|
|
)}
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
|
|
{/* =======================
|
|
|
|
|
|
VIEW RENDER
|
|
|
|
|
|
======================= */}
|
2026-08-14 14:03:34 +00:00
|
|
|
|
<Suspense fallback={<div className="p-4 text-sm">{translate('::App.Platform.LoadingWithThreeDot')}</div>}>
|
2026-02-24 20:44:16 +00:00
|
|
|
|
{viewMode === 'grid' && (
|
|
|
|
|
|
<Grid
|
|
|
|
|
|
listFormCode={listFormCode}
|
|
|
|
|
|
searchParams={searchParams}
|
2026-08-06 13:17:59 +00:00
|
|
|
|
isSubForm={isSubForm}
|
2026-02-24 20:44:16 +00:00
|
|
|
|
gridDto={gridDto}
|
|
|
|
|
|
/>
|
|
|
|
|
|
)}
|
|
|
|
|
|
|
2026-07-16 08:19:17 +00:00
|
|
|
|
{viewMode === 'card' && (
|
|
|
|
|
|
<CardView
|
|
|
|
|
|
listFormCode={listFormCode}
|
|
|
|
|
|
searchParams={searchParams}
|
2026-08-06 13:17:59 +00:00
|
|
|
|
isSubForm={isSubForm}
|
2026-07-16 08:19:17 +00:00
|
|
|
|
gridDto={gridDto}
|
|
|
|
|
|
/>
|
|
|
|
|
|
)}
|
|
|
|
|
|
|
2026-02-24 20:44:16 +00:00
|
|
|
|
{viewMode === 'pivot' && (
|
|
|
|
|
|
<Pivot
|
|
|
|
|
|
listFormCode={listFormCode}
|
|
|
|
|
|
searchParams={searchParams}
|
2026-08-06 13:17:59 +00:00
|
|
|
|
isSubForm={isSubForm}
|
2026-02-24 20:44:16 +00:00
|
|
|
|
gridDto={gridDto}
|
|
|
|
|
|
refreshGridDto={refreshGridDto}
|
|
|
|
|
|
/>
|
|
|
|
|
|
)}
|
|
|
|
|
|
|
|
|
|
|
|
{viewMode === 'tree' && (
|
|
|
|
|
|
<Tree
|
|
|
|
|
|
listFormCode={listFormCode}
|
|
|
|
|
|
searchParams={searchParams}
|
2026-08-06 13:17:59 +00:00
|
|
|
|
isSubForm={isSubForm}
|
2026-02-24 20:44:16 +00:00
|
|
|
|
gridDto={gridDto}
|
|
|
|
|
|
/>
|
|
|
|
|
|
)}
|
|
|
|
|
|
|
|
|
|
|
|
{viewMode === 'scheduler' && (
|
|
|
|
|
|
<SchedulerView
|
|
|
|
|
|
listFormCode={listFormCode}
|
|
|
|
|
|
searchParams={searchParams}
|
2026-08-06 13:17:59 +00:00
|
|
|
|
isSubForm={isSubForm}
|
2026-02-24 20:44:16 +00:00
|
|
|
|
gridDto={gridDto}
|
|
|
|
|
|
/>
|
|
|
|
|
|
)}
|
|
|
|
|
|
|
|
|
|
|
|
{viewMode === 'gantt' && (
|
|
|
|
|
|
<GanttView
|
|
|
|
|
|
listFormCode={listFormCode}
|
|
|
|
|
|
searchParams={searchParams}
|
2026-08-06 13:17:59 +00:00
|
|
|
|
isSubForm={isSubForm}
|
2026-02-24 20:44:16 +00:00
|
|
|
|
gridDto={gridDto}
|
|
|
|
|
|
/>
|
|
|
|
|
|
)}
|
|
|
|
|
|
|
2026-07-16 14:01:18 +00:00
|
|
|
|
{viewMode === 'todo' && (
|
|
|
|
|
|
<TodoBoard
|
|
|
|
|
|
listFormCode={listFormCode}
|
|
|
|
|
|
searchParams={searchParams}
|
2026-08-06 13:17:59 +00:00
|
|
|
|
isSubForm={isSubForm}
|
2026-07-16 14:01:18 +00:00
|
|
|
|
gridDto={gridDto}
|
|
|
|
|
|
/>
|
|
|
|
|
|
)}
|
|
|
|
|
|
|
2026-02-24 20:44:16 +00:00
|
|
|
|
{viewMode === 'chart' && (
|
|
|
|
|
|
<Chart
|
2026-07-06 09:44:26 +00:00
|
|
|
|
id={gridDto?.gridOptions.id as string}
|
2026-02-24 20:44:16 +00:00
|
|
|
|
listFormCode={listFormCode}
|
|
|
|
|
|
filter={searchParams.toString()}
|
|
|
|
|
|
isSubForm={true}
|
|
|
|
|
|
gridDto={gridDto}
|
|
|
|
|
|
refreshGridDto={refreshGridDto}
|
|
|
|
|
|
/>
|
|
|
|
|
|
)}
|
|
|
|
|
|
</Suspense>
|
2026-08-28 13:44:14 +00:00
|
|
|
|
|
|
|
|
|
|
{description && (
|
|
|
|
|
|
<Dialog
|
|
|
|
|
|
isOpen={descriptionOpen}
|
|
|
|
|
|
width={860}
|
|
|
|
|
|
onClose={() => setDescriptionOpen(false)}
|
|
|
|
|
|
onRequestClose={() => setDescriptionOpen(false)}
|
|
|
|
|
|
>
|
|
|
|
|
|
<Dialog.Header className="-mt-5 p-2 border-b border-gray-200 dark:border-gray-700">
|
|
|
|
|
|
<h2 className="text-lg font-semibold text-gray-800 dark:text-gray-100">
|
|
|
|
|
|
{translate('::' + gridDto.gridOptions.title)}
|
|
|
|
|
|
</h2>
|
|
|
|
|
|
</Dialog.Header>
|
|
|
|
|
|
<Dialog.Body className="mt-2 max-h-[70vh] select-text overflow-y-auto pr-1">
|
|
|
|
|
|
<RichText text={description} />
|
|
|
|
|
|
</Dialog.Body>
|
|
|
|
|
|
</Dialog>
|
|
|
|
|
|
)}
|
2026-02-24 20:44:16 +00:00
|
|
|
|
</Container>
|
|
|
|
|
|
)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
export default List
|