Grid, Tree, Chart, Pivot Toolbar style
This commit is contained in:
parent
866d9f1e85
commit
76621b24d8
8 changed files with 349 additions and 206 deletions
134
ui/src/index.css
134
ui/src/index.css
|
|
@ -113,6 +113,140 @@ div.dialog-after-open > div.dialog-content.maximized {
|
|||
padding: 0 0 !important;
|
||||
}
|
||||
|
||||
.dx-datagrid-header-panel.pivot-toolbar-panel {
|
||||
min-height: 37px;
|
||||
background-color: transparent !important;
|
||||
}
|
||||
|
||||
.dark .dx-datagrid-header-panel.pivot-toolbar-panel {
|
||||
background-color: #202020 !important;
|
||||
}
|
||||
|
||||
.dx-datagrid-header-panel.pivot-toolbar-panel .button,
|
||||
.dx-datagrid-header-panel.pivot-toolbar-panel .dx-button,
|
||||
.dx-datagrid-header-panel.pivot-toolbar-panel button {
|
||||
background-color: transparent !important;
|
||||
border-color: transparent !important;
|
||||
border-radius: 0 !important;
|
||||
padding: 0 !important;
|
||||
}
|
||||
|
||||
.dx-datagrid-header-panel.pivot-toolbar-panel .relative.flex {
|
||||
gap: 4px !important;
|
||||
}
|
||||
|
||||
.dx-datagrid-header-panel.pivot-toolbar-panel > .dx-toolbar {
|
||||
width: 100% !important;
|
||||
background-color: transparent !important;
|
||||
}
|
||||
|
||||
.dx-datagrid-header-panel.pivot-toolbar-panel > .dx-toolbar .dx-toolbar-items-container {
|
||||
min-height: 28px !important;
|
||||
}
|
||||
|
||||
.dx-datagrid-header-panel.pivot-toolbar-panel > .dx-toolbar .dx-toolbar-before {
|
||||
width: auto !important;
|
||||
max-width: none !important;
|
||||
}
|
||||
|
||||
.dx-datagrid-header-panel.pivot-toolbar-panel > .dx-toolbar .dx-toolbar-after {
|
||||
width: auto !important;
|
||||
max-width: none !important;
|
||||
}
|
||||
|
||||
.dx-datagrid-header-panel.pivot-toolbar-panel > .dx-toolbar .dx-toolbar-after .dx-toolbar-item {
|
||||
padding-inline: 2px !important;
|
||||
}
|
||||
|
||||
.dx-datagrid-header-panel.pivot-toolbar-panel > .dx-toolbar .dx-button-content {
|
||||
padding-block: 4px !important;
|
||||
padding-inline: 6px !important;
|
||||
}
|
||||
|
||||
.dx-datagrid-header-panel.pivot-toolbar-panel .chart-toolbar-search {
|
||||
width: 160px;
|
||||
height: 32px;
|
||||
padding: 6px 12px 6px 34px;
|
||||
border: 0 !important;
|
||||
border-bottom: 1px solid #d1d5db !important;
|
||||
border-radius: 0 !important;
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
.dark .dx-datagrid-header-panel.pivot-toolbar-panel .chart-toolbar-search {
|
||||
background-color: #2d2d2d !important;
|
||||
border-bottom-color: #6b7280 !important;
|
||||
}
|
||||
|
||||
.dx-datagrid-header-panel.pivot-toolbar-panel > .dx-toolbar .dx-toolbar-menu-container .dx-button {
|
||||
border-radius: 50% !important;
|
||||
}
|
||||
|
||||
.dark
|
||||
.dx-datagrid-header-panel.pivot-toolbar-panel
|
||||
> .dx-toolbar
|
||||
.dx-toolbar-menu-container
|
||||
.dx-button {
|
||||
background-color: #343440 !important;
|
||||
border-color: #343440 !important;
|
||||
}
|
||||
|
||||
.dark
|
||||
.dx-datagrid-header-panel.pivot-toolbar-panel
|
||||
> .dx-toolbar
|
||||
.dx-toolbar-menu-container
|
||||
.dx-button:hover {
|
||||
background-color: #424250 !important;
|
||||
border-color: #424250 !important;
|
||||
}
|
||||
|
||||
.dx-datagrid-header-panel.pivot-toolbar-panel
|
||||
> .dx-toolbar
|
||||
.dx-toolbar-menu-container
|
||||
.dx-button-content {
|
||||
padding: 4px !important;
|
||||
}
|
||||
|
||||
.dark .dx-datagrid-header-panel.pivot-toolbar-panel .button,
|
||||
.dark .dx-datagrid-header-panel.pivot-toolbar-panel .dx-button,
|
||||
.dark .dx-datagrid-header-panel.pivot-toolbar-panel button {
|
||||
background-color: transparent !important;
|
||||
border-color: transparent !important;
|
||||
color: #fff !important;
|
||||
}
|
||||
|
||||
.dx-datagrid-header-panel.pivot-toolbar-panel .dx-button-text {
|
||||
text-transform: none !important;
|
||||
}
|
||||
|
||||
.dx-datagrid-header-panel.pivot-toolbar-panel .button:hover,
|
||||
.dx-datagrid-header-panel.pivot-toolbar-panel .dx-button:hover,
|
||||
.dx-datagrid-header-panel.pivot-toolbar-panel button:hover {
|
||||
background-color: #dedede !important;
|
||||
}
|
||||
|
||||
.dark .dx-datagrid-header-panel.pivot-toolbar-panel .button:hover,
|
||||
.dark .dx-datagrid-header-panel.pivot-toolbar-panel .dx-button:hover,
|
||||
.dark .dx-datagrid-header-panel.pivot-toolbar-panel button:hover {
|
||||
background-color: #2d2d2d !important;
|
||||
}
|
||||
|
||||
.dx-datagrid-header-panel.pivot-toolbar-panel,
|
||||
.dx-datagrid-header-panel.pivot-toolbar-panel .dx-button,
|
||||
.dx-datagrid-header-panel.pivot-toolbar-panel .dx-button-text,
|
||||
.dx-datagrid-header-panel.pivot-toolbar-panel svg {
|
||||
color: #000 !important;
|
||||
}
|
||||
|
||||
.dark .dx-datagrid-header-panel.pivot-toolbar-panel,
|
||||
.dark .dx-datagrid-header-panel.pivot-toolbar-panel .button,
|
||||
.dark .dx-datagrid-header-panel.pivot-toolbar-panel .dx-button,
|
||||
.dark .dx-datagrid-header-panel.pivot-toolbar-panel .dx-button-text,
|
||||
.dark .dx-datagrid-header-panel.pivot-toolbar-panel button,
|
||||
.dark .dx-datagrid-header-panel.pivot-toolbar-panel svg {
|
||||
color: #fff !important;
|
||||
}
|
||||
|
||||
.dx-datagrid-header-panel > .dx-toolbar .dx-toolbar-before,
|
||||
.dx-treelist-header-panel > .dx-toolbar .dx-toolbar-before {
|
||||
width: 50% !important;
|
||||
|
|
|
|||
|
|
@ -9,10 +9,10 @@ import { Helmet } from 'react-helmet'
|
|||
import { useParams, useSearchParams } from 'react-router-dom'
|
||||
import { GridDto } from '@/proxy/form/models'
|
||||
import { usePermission } from '@/utils/hooks/usePermission'
|
||||
import { Button, toast, Notification } from '@/components/ui'
|
||||
import { toast, Notification } from '@/components/ui'
|
||||
import { ROUTES_ENUM } from '@/routes/route.constant'
|
||||
import { usePWA } from '@/utils/hooks/usePWA'
|
||||
import { FaCog, FaCrosshairs, FaSearch, FaSyncAlt } from 'react-icons/fa'
|
||||
import { FaSearch } from 'react-icons/fa'
|
||||
import { buildSeriesDto } from './Utils'
|
||||
import { ChartSeriesDto } from '@/proxy/admin/charts/models'
|
||||
import { SelectBoxOption } from '@/types/shared'
|
||||
|
|
@ -29,6 +29,7 @@ import {
|
|||
} from '@/services/admin/list-form.service'
|
||||
import { layoutTypes } from '../admin/listForm/edit/types'
|
||||
import { useListFormCustomDataSource } from './useListFormCustomDataSource'
|
||||
import Toolbar, { Item } from 'devextreme-react/toolbar'
|
||||
|
||||
interface ChartProps extends CommonProps, Meta {
|
||||
id: string
|
||||
|
|
@ -327,82 +328,95 @@ const Chart = (props: ChartProps) => {
|
|||
></Helmet>
|
||||
)}
|
||||
{_listFormCode && chartOptions && (
|
||||
<div className="p-1 bg-white dark:bg-neutral-800 dark:border-neutral-700 h-full relative">
|
||||
<div className="flex justify-end items-center h-full">
|
||||
<div className="relative pb-1 flex gap-1 border-b-1">
|
||||
<FaSearch className="absolute left-2 top-1/2 -translate-y-1/2 text-gray-400 text-sm" />
|
||||
<input
|
||||
type="text"
|
||||
placeholder={translate('::App.Search')}
|
||||
value={searchText}
|
||||
onChange={(e) => setSearchText(e.target.value)}
|
||||
onKeyDown={(e) => {
|
||||
if (e.key === 'Enter') {
|
||||
onFilter(e.currentTarget.value)
|
||||
setPrevValue(e.currentTarget.value.trim()) // Enter ile tetiklenirse güncelle
|
||||
}
|
||||
}}
|
||||
onBlur={(e) => {
|
||||
const newValue = e.currentTarget.value.trim()
|
||||
<div className="p-1">
|
||||
<div className="dx-datagrid-header-panel pivot-toolbar-panel text-black dark:text-white">
|
||||
<Toolbar width="100%">
|
||||
<Item
|
||||
location="before"
|
||||
locateInMenu="never"
|
||||
render={() => (
|
||||
<div className="relative flex items-center">
|
||||
<FaSearch className="absolute left-3 top-1/2 -translate-y-1/2 text-gray-400 text-sm" />
|
||||
<input
|
||||
type="text"
|
||||
placeholder={translate('::App.Search')}
|
||||
value={searchText}
|
||||
onChange={(e) => setSearchText(e.target.value)}
|
||||
onKeyDown={(e) => {
|
||||
if (e.key === 'Enter') {
|
||||
onFilter(e.currentTarget.value)
|
||||
setPrevValue(e.currentTarget.value.trim()) // Enter ile tetiklenirse güncelle
|
||||
}
|
||||
}}
|
||||
onBlur={(e) => {
|
||||
const newValue = e.currentTarget.value.trim()
|
||||
|
||||
// 1. Değer değişmemişse => hiçbir şey yapma
|
||||
if (newValue === prevValue) return
|
||||
// 1. Değer değişmemişse => hiçbir şey yapma
|
||||
if (newValue === prevValue) return
|
||||
|
||||
// 2. Yeni değer boş, ama eskiden değer vardı => filtre temizle
|
||||
// 3. Yeni değer dolu ve eskisinden farklı => filtre uygula
|
||||
onFilter(newValue)
|
||||
setPrevValue(newValue)
|
||||
}}
|
||||
className="p-1 pl-6 pr-2 border border-1 outline-none text-xs text-gray-700 dark:text-gray-200 placeholder-gray-400 rounded"
|
||||
// 2. Yeni değer boş, ama eskiden değer vardı => filtre temizle
|
||||
// 3. Yeni değer dolu ve eskisinden farklı => filtre uygula
|
||||
onFilter(newValue)
|
||||
setPrevValue(newValue)
|
||||
}}
|
||||
className="chart-toolbar-search outline-none text-xs text-gray-700 placeholder-gray-400 dark:text-gray-200 dark:placeholder-gray-400"
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
/>
|
||||
<Button
|
||||
size="sm"
|
||||
variant={'default'}
|
||||
icon={<FaSyncAlt className="w-3 h-3" />}
|
||||
className="text-sm flex items-center gap-1"
|
||||
onClick={async () => {
|
||||
setInitialized(false)
|
||||
await refreshGridDto?.()
|
||||
<Item
|
||||
location="after"
|
||||
widget="dxButton"
|
||||
locateInMenu="auto"
|
||||
showText="always"
|
||||
options={{
|
||||
icon: 'refresh',
|
||||
text: translate('::App.Platform.Refresh'),
|
||||
hint: translate('::App.Platform.Refresh'),
|
||||
onClick: async () => {
|
||||
setInitialized(false)
|
||||
await refreshGridDto?.()
|
||||
},
|
||||
}}
|
||||
title={translate('::App.Platform.Refresh')}
|
||||
>
|
||||
{translate('::App.Platform.Refresh')}
|
||||
</Button>
|
||||
<Button
|
||||
size="sm"
|
||||
icon={<FaCrosshairs className="w-3 h-3" />}
|
||||
variant="default"
|
||||
className="text-sm flex items-center gap-1"
|
||||
onClick={() => setOpenDrawer(true)}
|
||||
title={translate('::ListForms.ListFormEdit.TabChartSeries')}
|
||||
>
|
||||
{translate('::ListForms.ListFormEdit.TabChartSeries')}
|
||||
</Button>
|
||||
/>
|
||||
<Item
|
||||
location="after"
|
||||
widget="dxButton"
|
||||
locateInMenu="auto"
|
||||
showText="always"
|
||||
options={{
|
||||
icon: 'chart',
|
||||
text: translate('::ListForms.ListFormEdit.TabChartSeries'),
|
||||
hint: translate('::ListForms.ListFormEdit.TabChartSeries'),
|
||||
onClick: () => setOpenDrawer(true),
|
||||
}}
|
||||
/>
|
||||
|
||||
{checkPermission(gridDto?.gridOptions.permissionDto.u) && (
|
||||
<Button
|
||||
size="sm"
|
||||
icon={<FaCog className="w-3 h-3" />}
|
||||
variant={'default'}
|
||||
className="text-sm"
|
||||
onClick={() => {
|
||||
window.open(
|
||||
ROUTES_ENUM.protected.saas.listFormManagement.edit.replace(
|
||||
':listFormCode',
|
||||
listFormCode,
|
||||
),
|
||||
isPwaMode ? '_self' : '_blank',
|
||||
)
|
||||
<Item
|
||||
location="after"
|
||||
widget="dxButton"
|
||||
locateInMenu="auto"
|
||||
showText="always"
|
||||
options={{
|
||||
icon: 'preferences',
|
||||
text: translate('::ListForms.ListForm.Manage'),
|
||||
hint: translate('::ListForms.ListForm.Manage'),
|
||||
onClick: () => {
|
||||
window.open(
|
||||
ROUTES_ENUM.protected.saas.listFormManagement.edit.replace(
|
||||
':listFormCode',
|
||||
listFormCode,
|
||||
),
|
||||
isPwaMode ? '_self' : '_blank',
|
||||
)
|
||||
},
|
||||
}}
|
||||
title={translate('::ListForms.ListForm.Manage')}
|
||||
></Button>
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</Toolbar>
|
||||
</div>
|
||||
<div
|
||||
className={`transition-all duration-300 ${openDrawer ? 'mr-[500px]' : 'mr-0'}`}
|
||||
style={{ width: openDrawer ? 'calc(100% - 500px)' : '100%' }}
|
||||
>
|
||||
<div className="border border-gray-200 dark:border-gray-600">
|
||||
<DxChart key={'DxChart' + _listFormCode} {...chartOptions}></DxChart>
|
||||
</div>
|
||||
|
||||
|
|
|
|||
|
|
@ -90,7 +90,7 @@ const ChartDrawer = ({
|
|||
<>
|
||||
{/* Drawer */}
|
||||
<div
|
||||
className={`fixed right-0 top-0 h-full w-[500px] bg-white shadow-2xl z-50 transform transition-transform duration-300 border-l-2 border-gray-300 ${
|
||||
className={`fixed right-0 top-0 h-full w-[500px] bg-white text-gray-900 shadow-2xl z-50 transform transition-transform duration-300 border-l-2 border-gray-300 dark:bg-gray-900 dark:text-gray-100 dark:border-gray-700 ${
|
||||
open ? 'translate-x-0' : 'translate-x-full'
|
||||
}`}
|
||||
>
|
||||
|
|
@ -139,8 +139,8 @@ const ChartDrawer = ({
|
|||
return (
|
||||
<Form className="flex flex-col h-full">
|
||||
{/* Header */}
|
||||
<div className="flex items-center justify-between p-4 border-b bg-gray-50">
|
||||
<h2 className="text-lg font-semibold flex items-center gap-2">
|
||||
<div className="flex items-center justify-between p-4 border-b border-gray-200 bg-gray-50 dark:border-gray-700 dark:bg-gray-800">
|
||||
<h2 className="text-lg font-semibold flex items-center gap-2 text-gray-900 dark:text-gray-100">
|
||||
<span>📊</span>
|
||||
{translate('::App.Platform.ChartDrawer.ChartSeries')}
|
||||
</h2>
|
||||
|
|
@ -155,7 +155,7 @@ const ChartDrawer = ({
|
|||
|
||||
<FormContainer size="sm" className="flex flex-col flex-1 overflow-hidden">
|
||||
{/* Add Series Button */}
|
||||
<div className="p-3 border-b">
|
||||
<div className="p-3 border-b border-gray-200 dark:border-gray-700">
|
||||
<Button
|
||||
size="sm"
|
||||
block
|
||||
|
|
@ -180,11 +180,11 @@ const ChartDrawer = ({
|
|||
{values.series.map((series, index) => (
|
||||
<div
|
||||
key={index}
|
||||
className="border rounded-lg p-3 bg-gray-50 hover:bg-gray-100 transition-colors"
|
||||
className="border border-gray-200 rounded-lg p-3 bg-gray-50 hover:bg-gray-100 transition-colors dark:border-gray-700 dark:bg-gray-800 dark:hover:bg-gray-700"
|
||||
>
|
||||
{/* Header */}
|
||||
<div className="flex items-center justify-between mb-3">
|
||||
<span className="font-semibold text-sm">
|
||||
<span className="font-semibold text-sm text-gray-900 dark:text-gray-100">
|
||||
{translate('::App.Platform.ChartDrawer.Series')} #{index + 1}
|
||||
</span>
|
||||
<Button
|
||||
|
|
@ -192,7 +192,7 @@ const ChartDrawer = ({
|
|||
size="xs"
|
||||
variant="plain"
|
||||
icon={<FaMinus />}
|
||||
className="border-0 text-red-500 hover:bg-red-100"
|
||||
className="border-0 text-red-500 hover:bg-red-100 dark:text-red-400 dark:hover:bg-red-900/30"
|
||||
onClick={() => {
|
||||
remove(index)
|
||||
}}
|
||||
|
|
@ -201,7 +201,7 @@ const ChartDrawer = ({
|
|||
|
||||
{/* Chart Type Selector */}
|
||||
<div className="mb-3">
|
||||
<label className="text-xs font-medium mb-1 block">
|
||||
<label className="text-xs font-medium mb-1 block text-gray-700 dark:text-gray-300">
|
||||
{translate('::App.Platform.ChartDrawer.ChartType')}
|
||||
</label>
|
||||
<Field name={`series[${index}].type`}>
|
||||
|
|
@ -214,7 +214,7 @@ const ChartDrawer = ({
|
|||
selectedSeriesIndex === index ? -1 : index,
|
||||
)
|
||||
}
|
||||
className="w-full px-3 py-2 text-left border rounded hover:bg-white flex items-center gap-2 transition-colors"
|
||||
className="w-full px-3 py-2 text-left border border-gray-300 rounded bg-white hover:bg-gray-50 flex items-center gap-2 transition-colors dark:border-gray-600 dark:bg-gray-900 dark:hover:bg-gray-800"
|
||||
>
|
||||
<span className="text-xl">
|
||||
{chartSeriesTypeOptions.find(
|
||||
|
|
@ -228,7 +228,7 @@ const ChartDrawer = ({
|
|||
</span>
|
||||
</Button>
|
||||
{selectedSeriesIndex === index && (
|
||||
<div className="absolute z-50 mt-1 w-full bg-white border rounded-lg shadow-xl p-2">
|
||||
<div className="absolute z-50 mt-1 w-full bg-white border border-gray-200 rounded-lg shadow-xl p-2 dark:bg-gray-900 dark:border-gray-700">
|
||||
<div className="grid grid-cols-2 gap-2">
|
||||
{chartSeriesTypeOptions.map((chartType) => (
|
||||
<Button
|
||||
|
|
@ -238,10 +238,10 @@ const ChartDrawer = ({
|
|||
form.setFieldValue(field.name, chartType.label)
|
||||
setSelectedSeriesIndex(-1)
|
||||
}}
|
||||
className={`p-2 rounded-lg hover:bg-blue-50 flex items-center gap-2 transition-all ${
|
||||
className={`p-2 rounded-lg hover:bg-blue-50 flex items-center gap-2 transition-all dark:hover:bg-blue-900/30 ${
|
||||
field.value === chartType.label
|
||||
? 'bg-blue-100 ring-2 ring-blue-400'
|
||||
: 'bg-gray-50'
|
||||
? 'bg-blue-100 ring-2 ring-blue-400 dark:bg-blue-900/40 dark:ring-blue-500'
|
||||
: 'bg-gray-50 dark:bg-gray-800'
|
||||
}`}
|
||||
>
|
||||
<span className="text-xl">{chartType.icon}</span>
|
||||
|
|
@ -260,7 +260,7 @@ const ChartDrawer = ({
|
|||
|
||||
{/* Name */}
|
||||
<div className="mb-3">
|
||||
<label className="text-xs font-medium mb-1 block">
|
||||
<label className="text-xs font-medium mb-1 block text-gray-700 dark:text-gray-300">
|
||||
{translate('::App.Listform.ListformField.Name')}
|
||||
</label>
|
||||
<Field
|
||||
|
|
@ -274,7 +274,7 @@ const ChartDrawer = ({
|
|||
|
||||
{/* Argument Field */}
|
||||
<div className="mb-3">
|
||||
<label className="text-xs font-medium mb-1 block">
|
||||
<label className="text-xs font-medium mb-1 block text-gray-700 dark:text-gray-300">
|
||||
{translate('::App.Platform.ChartDrawer.ArgumentField')}
|
||||
</label>
|
||||
<Field name={`series[${index}].argumentField`}>
|
||||
|
|
@ -300,7 +300,7 @@ const ChartDrawer = ({
|
|||
|
||||
{/* Value Field */}
|
||||
<div className="mb-3">
|
||||
<label className="text-xs font-medium mb-1 block">
|
||||
<label className="text-xs font-medium mb-1 block text-gray-700 dark:text-gray-300">
|
||||
{translate('::App.Platform.ChartDrawer.ValueField')}
|
||||
</label>
|
||||
<Field name={`series[${index}].valueField`}>
|
||||
|
|
@ -326,7 +326,7 @@ const ChartDrawer = ({
|
|||
|
||||
{/* Summary Type */}
|
||||
<div className="mb-3">
|
||||
<label className="text-xs font-medium mb-1 block">
|
||||
<label className="text-xs font-medium mb-1 block text-gray-700 dark:text-gray-300">
|
||||
{translate('::App.Platform.ChartDrawer.SummaryType')}
|
||||
</label>
|
||||
<Field name={`series[${index}].summaryType`}>
|
||||
|
|
@ -354,7 +354,7 @@ const ChartDrawer = ({
|
|||
</div>
|
||||
|
||||
{/* Footer */}
|
||||
<div className="p-4 border-t bg-gray-50 flex gap-2">
|
||||
<div className="p-4 border-t border-gray-200 bg-gray-50 flex gap-2 dark:border-gray-700 dark:bg-gray-800">
|
||||
<Button type="button" variant="plain" onClick={onClose} className="flex-1">
|
||||
{translate('::Cancel')}
|
||||
</Button>
|
||||
|
|
|
|||
|
|
@ -187,7 +187,7 @@ const GanttView = (props: GanttViewProps) => {
|
|||
|
||||
return (
|
||||
<>
|
||||
<div ref={widgetGroupRef}>
|
||||
<div ref={widgetGroupRef} className={(gridDto?.widgets?.length ?? 0) > 0 ? 'mt-2' : ''}>
|
||||
<WidgetGroup widgetGroups={gridDto?.widgets ?? []} />
|
||||
</div>
|
||||
|
||||
|
|
|
|||
|
|
@ -1402,7 +1402,7 @@ const Grid = (props: GridProps) => {
|
|||
|
||||
return (
|
||||
<>
|
||||
<div ref={widgetGroupRef} className="mt-2">
|
||||
<div ref={widgetGroupRef} className={(gridDto?.widgets?.length ?? 0) > 0 ? 'mt-2' : ''}>
|
||||
<WidgetGroup widgetGroups={gridDto?.widgets ?? []} />
|
||||
</div>
|
||||
|
||||
|
|
@ -1556,9 +1556,7 @@ const Grid = (props: GridProps) => {
|
|||
popup={{
|
||||
deferRendering: true,
|
||||
animation: {},
|
||||
wrapperAttr: useMobileEditPopup
|
||||
? { class: 'mobile-edit-popup' }
|
||||
: undefined,
|
||||
wrapperAttr: useMobileEditPopup ? { class: 'mobile-edit-popup' } : undefined,
|
||||
title:
|
||||
(mode === 'new' ? '✚ ' : '🖊️ ') +
|
||||
translate('::' + gridDto.gridOptions.editingOptionDto?.popup?.title),
|
||||
|
|
@ -1568,9 +1566,10 @@ const Grid = (props: GridProps) => {
|
|||
width: useMobileEditPopup
|
||||
? '100%'
|
||||
: gridDto.gridOptions.editingOptionDto?.popup?.width,
|
||||
height: useMobileEditPopup && isPopupFullScreen
|
||||
? '100%'
|
||||
: gridDto.gridOptions.editingOptionDto?.popup?.height,
|
||||
height:
|
||||
useMobileEditPopup && isPopupFullScreen
|
||||
? '100%'
|
||||
: gridDto.gridOptions.editingOptionDto?.popup?.height,
|
||||
position: useMobileEditPopup
|
||||
? {
|
||||
my: 'top center',
|
||||
|
|
|
|||
|
|
@ -32,8 +32,7 @@ import {
|
|||
} from './Utils'
|
||||
import { useFilters } from './useFilters'
|
||||
import WidgetGroup from '@/components/common/WidgetGroup'
|
||||
import { Button, Dropdown, Notification, toast } from '@/components/ui'
|
||||
import { FaCaretDown, FaCog, FaSave, FaTimes, FaUndo } from 'react-icons/fa'
|
||||
import { Notification, toast } from '@/components/ui'
|
||||
import { usePermission } from '@/utils/hooks/usePermission'
|
||||
import { ROUTES_ENUM } from '@/routes/route.constant'
|
||||
import { usePWA } from '@/utils/hooks/usePWA'
|
||||
|
|
@ -42,6 +41,7 @@ import { useListFormCustomDataSource } from './useListFormCustomDataSource'
|
|||
import { useListFormColumns } from './useListFormColumns'
|
||||
import { useStoreState } from '@/store'
|
||||
import Checkbox from '@/components/ui/Checkbox'
|
||||
import Toolbar, { Item } from 'devextreme-react/toolbar'
|
||||
|
||||
interface PivotProps {
|
||||
listFormCode: string
|
||||
|
|
@ -263,6 +263,44 @@ const Pivot = (props: PivotProps) => {
|
|||
})
|
||||
}, [listFormCode, storageKey])
|
||||
|
||||
const savePivotGridState = useCallback(() => {
|
||||
const instance = gridRef.current?.instance()
|
||||
if (!instance) {
|
||||
return
|
||||
}
|
||||
|
||||
const ds = instance.getDataSource()
|
||||
if (!ds || typeof ds.state !== 'function') {
|
||||
return
|
||||
}
|
||||
|
||||
const currentState = ds.state()
|
||||
customSaveState(currentState)
|
||||
.then(() => {
|
||||
toast.push(
|
||||
<Notification type="success" duration={2000}>
|
||||
{translate('::ListForms.ListForm.GridStateSaved')}
|
||||
</Notification>,
|
||||
{ placement: 'top-end' },
|
||||
)
|
||||
})
|
||||
.catch(() => {
|
||||
toast.push(
|
||||
<Notification type="danger" duration={2500}>
|
||||
{translate('::ListForms.ListForm.GridStateSaveError')}
|
||||
</Notification>,
|
||||
{ placement: 'top-end' },
|
||||
)
|
||||
})
|
||||
}, [customSaveState, translate])
|
||||
|
||||
const openFormManager = useCallback(() => {
|
||||
window.open(
|
||||
ROUTES_ENUM.protected.saas.listFormManagement.edit.replace(':listFormCode', listFormCode),
|
||||
isPwaMode ? '_self' : '_blank',
|
||||
)
|
||||
}, [isPwaMode, listFormCode])
|
||||
|
||||
useEffect(() => {
|
||||
refListFormCode.current = listFormCode
|
||||
}, [listFormCode])
|
||||
|
|
@ -420,112 +458,72 @@ const Pivot = (props: PivotProps) => {
|
|||
></Helmet>
|
||||
)}
|
||||
{gridDto && columnData && (
|
||||
<div className="p-1 bg-white dark:bg-neutral-800 dark:border-neutral-700 ">
|
||||
<div className="flex justify-end items-center text-black">
|
||||
<div className="relative flex gap-1">
|
||||
<label className="flex items-center gap-1 text-xs cursor-pointer dark:text-white">
|
||||
<span>{translate('::ListForms.ListFormEdit.ShowChart')}</span>
|
||||
<Checkbox checked={showChart} onChange={(checked) => setShowChart(checked)} />
|
||||
</label>
|
||||
<div className="dx-menu">
|
||||
<Dropdown
|
||||
placement="bottom-end"
|
||||
renderTitle={
|
||||
<Button
|
||||
size="sm"
|
||||
variant={'plain'}
|
||||
icon={<FaCaretDown className="ml-2 w-2 h-3" />}
|
||||
className="text-sm flex items-center gap-1 border-0"
|
||||
title="Menu"
|
||||
>
|
||||
<i className="dx-icon dx-icon-overflow" style={{ fontSize: '17px' }}></i>
|
||||
<span className="text-black dark:text-white" style={{ fontSize: '13px' }}>
|
||||
{translate('::ListForms.ListForm.GridMenu')}
|
||||
</span>
|
||||
</Button>
|
||||
}
|
||||
>
|
||||
<Dropdown.Item
|
||||
eventKey="removeFilter"
|
||||
onClick={clearPivotFilters}
|
||||
className="px-2"
|
||||
>
|
||||
<span className="flex items-center gap-2">
|
||||
<FaTimes className="w-3 h-3" />
|
||||
<span>{translate('::ListForms.ListForm.RemoveFilter')}</span>
|
||||
<div className="p-1">
|
||||
<div className="dx-datagrid-header-panel pivot-toolbar-panel text-black">
|
||||
<Toolbar width="100%">
|
||||
<Item
|
||||
location="before"
|
||||
locateInMenu="never"
|
||||
render={() => (
|
||||
<label className="flex items-center gap-1 text-xs cursor-pointer">
|
||||
<span className="font-medium">
|
||||
{translate('::ListForms.ListFormEdit.ShowChart')}
|
||||
</span>
|
||||
</Dropdown.Item>
|
||||
|
||||
<Dropdown.Item
|
||||
eventKey="saveGridState"
|
||||
onClick={() => {
|
||||
const instance = gridRef.current?.instance()
|
||||
if (instance) {
|
||||
const ds = instance.getDataSource()
|
||||
if (ds && typeof ds.state === 'function') {
|
||||
const currentState = ds.state()
|
||||
customSaveState(currentState)
|
||||
.then(() => {
|
||||
toast.push(
|
||||
<Notification type="success" duration={2000}>
|
||||
{translate('::ListForms.ListForm.GridStateSaved')}
|
||||
</Notification>,
|
||||
{ placement: 'top-end' },
|
||||
)
|
||||
})
|
||||
.catch(() => {
|
||||
toast.push(
|
||||
<Notification type="danger" duration={2500}>
|
||||
{translate('::ListForms.ListForm.GridStateSaveError')}
|
||||
</Notification>,
|
||||
{ placement: 'top-end' },
|
||||
)
|
||||
})
|
||||
}
|
||||
}
|
||||
}}
|
||||
className="px-2"
|
||||
>
|
||||
<span className="flex items-center gap-2">
|
||||
<FaSave className="w-3 h-3" />
|
||||
<span>{translate('::ListForms.ListForm.SaveGridState')}</span>
|
||||
</span>
|
||||
</Dropdown.Item>
|
||||
|
||||
<Dropdown.Item
|
||||
eventKey="resetGridState"
|
||||
onClick={resetPivotGridState}
|
||||
className="px-2"
|
||||
>
|
||||
<span className="flex items-center gap-2">
|
||||
<FaUndo className="w-3 h-3" />
|
||||
<span>{translate('::ListForms.ListForm.ResetGridState')}</span>
|
||||
</span>
|
||||
</Dropdown.Item>
|
||||
|
||||
{checkPermission(gridDto?.gridOptions.permissionDto.u) && (
|
||||
<Dropdown.Item
|
||||
eventKey="formManager"
|
||||
onClick={() => {
|
||||
window.open(
|
||||
ROUTES_ENUM.protected.saas.listFormManagement.edit.replace(
|
||||
':listFormCode',
|
||||
listFormCode,
|
||||
),
|
||||
isPwaMode ? '_self' : '_blank',
|
||||
)
|
||||
}}
|
||||
className="px-2"
|
||||
>
|
||||
<span className="flex items-center gap-2">
|
||||
<FaCog className="w-3 h-3" />
|
||||
<span>{translate('::ListForms.ListForm.Manage')}</span>
|
||||
</span>
|
||||
</Dropdown.Item>
|
||||
)}
|
||||
</Dropdown>
|
||||
</div>
|
||||
</div>
|
||||
<Checkbox checked={showChart} onChange={(checked) => setShowChart(checked)} />
|
||||
</label>
|
||||
)}
|
||||
/>
|
||||
<Item
|
||||
location="after"
|
||||
widget="dxButton"
|
||||
locateInMenu="auto"
|
||||
showText="always"
|
||||
options={{
|
||||
icon: 'clear',
|
||||
text: translate('::ListForms.ListForm.RemoveFilter'),
|
||||
hint: translate('::ListForms.ListForm.RemoveFilter'),
|
||||
onClick: clearPivotFilters,
|
||||
}}
|
||||
/>
|
||||
<Item
|
||||
location="after"
|
||||
widget="dxButton"
|
||||
locateInMenu="auto"
|
||||
showText="always"
|
||||
options={{
|
||||
icon: 'save',
|
||||
text: translate('::ListForms.ListForm.SaveGridState'),
|
||||
hint: translate('::ListForms.ListForm.SaveGridState'),
|
||||
onClick: savePivotGridState,
|
||||
}}
|
||||
/>
|
||||
<Item
|
||||
location="after"
|
||||
widget="dxButton"
|
||||
locateInMenu="auto"
|
||||
showText="always"
|
||||
options={{
|
||||
icon: 'undo',
|
||||
text: translate('::ListForms.ListForm.ResetGridState'),
|
||||
hint: translate('::ListForms.ListForm.ResetGridState'),
|
||||
onClick: resetPivotGridState,
|
||||
}}
|
||||
/>
|
||||
{checkPermission(gridDto?.gridOptions.permissionDto.u) && (
|
||||
<Item
|
||||
location="after"
|
||||
widget="dxButton"
|
||||
locateInMenu="auto"
|
||||
showText="always"
|
||||
options={{
|
||||
icon: 'preferences',
|
||||
text: translate('::ListForms.ListForm.Manage'),
|
||||
hint: translate('::ListForms.ListForm.Manage'),
|
||||
onClick: openFormManager,
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</Toolbar>
|
||||
</div>
|
||||
{showChart && (
|
||||
<Chart ref={chartRef as any}>
|
||||
|
|
@ -537,8 +535,6 @@ const Pivot = (props: PivotProps) => {
|
|||
</Chart>
|
||||
)}
|
||||
|
||||
<div className="dx-datagrid-header-panel h-1"></div>
|
||||
|
||||
<PivotGrid
|
||||
ref={gridRef as any}
|
||||
id={'Pivot-' + listFormCode}
|
||||
|
|
|
|||
|
|
@ -523,7 +523,7 @@ const SchedulerView = (props: SchedulerViewProps) => {
|
|||
|
||||
return (
|
||||
<>
|
||||
<div ref={widgetGroupRef}>
|
||||
<div ref={widgetGroupRef} className={(gridDto?.widgets?.length ?? 0) > 0 ? 'mt-2' : ''}>
|
||||
<WidgetGroup widgetGroups={gridDto?.widgets ?? []} />
|
||||
</div>
|
||||
|
||||
|
|
|
|||
|
|
@ -1060,7 +1060,7 @@ const Tree = (props: TreeProps) => {
|
|||
|
||||
return (
|
||||
<>
|
||||
<div ref={widgetGroupRef}>
|
||||
<div ref={widgetGroupRef} className={(gridDto?.widgets?.length ?? 0) > 0 ? 'mt-2' : ''}>
|
||||
<WidgetGroup widgetGroups={gridDto?.widgets ?? []} />
|
||||
</div>
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue