Listeleri mükemmelleştirme ikon vs.
This commit is contained in:
parent
9ea283712e
commit
1d36fc8225
7 changed files with 151 additions and 27 deletions
|
|
@ -22763,7 +22763,7 @@
|
||||||
"accountHolder": "Özlem Öztürk",
|
"accountHolder": "Özlem Öztürk",
|
||||||
"branch": "03663 / Enpara",
|
"branch": "03663 / Enpara",
|
||||||
"accountNumber": "73941177",
|
"accountNumber": "73941177",
|
||||||
"iban": "TR65 0011 1000 0000 0073 9411 77"
|
"iban": "TR11 0015 7000 0000 0073 9411 77"
|
||||||
},
|
},
|
||||||
"workHour": {
|
"workHour": {
|
||||||
"weekday": "Public.contact.workHours.weekday",
|
"weekday": "Public.contact.workHours.weekday",
|
||||||
|
|
|
||||||
|
|
@ -806,6 +806,7 @@ public class SelectQueryManager : PlatformDomainService, ISelectQueryManager
|
||||||
var sql = $@"
|
var sql = $@"
|
||||||
SELECT {string.Join(", ", selectParts)}
|
SELECT {string.Join(", ", selectParts)}
|
||||||
FROM [{listform.SelectCommand}]
|
FROM [{listform.SelectCommand}]
|
||||||
|
{GetWhereString()}
|
||||||
GROUP BY {argumentExpression}";
|
GROUP BY {argumentExpression}";
|
||||||
|
|
||||||
return sql;
|
return sql;
|
||||||
|
|
|
||||||
|
|
@ -288,11 +288,23 @@ const useListFormColumns = ({
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hasUpdate) {
|
if (hasUpdate) {
|
||||||
column.buttons.push('edit')
|
// column.buttons.push('edit')
|
||||||
|
column.buttons.push({
|
||||||
|
icon: 'edit',
|
||||||
|
hint: translate('::Edit'),
|
||||||
|
name: 'edit',
|
||||||
|
text: translate('::Edit'),
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hasDelete) {
|
if (hasDelete) {
|
||||||
column.buttons.push('delete')
|
// column.buttons.push('delete')
|
||||||
|
column.buttons.push({
|
||||||
|
icon: 'trash',
|
||||||
|
hint: translate('::Delete'),
|
||||||
|
name: 'delete',
|
||||||
|
text: translate('::Delete'),
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
gridDto.gridOptions.commandColumnDto.forEach((action) => {
|
gridDto.gridOptions.commandColumnDto.forEach((action) => {
|
||||||
|
|
|
||||||
|
|
@ -4,12 +4,12 @@ import { captionize } from 'devextreme/core/utils/inflector'
|
||||||
import { useListFormCustomDataSource } from '@/shared/useListFormCustomDataSource'
|
import { useListFormCustomDataSource } from '@/shared/useListFormCustomDataSource'
|
||||||
import { Button, Pagination, Select } from '@/components/ui'
|
import { Button, Pagination, Select } from '@/components/ui'
|
||||||
import classNames from 'classnames'
|
import classNames from 'classnames'
|
||||||
import { FaSearch } from 'react-icons/fa'
|
import { FaCog, FaSearch } from 'react-icons/fa'
|
||||||
import FormDevExpress from '../form/FormDevExpress'
|
import FormDevExpress from '../form/FormDevExpress'
|
||||||
import { GroupItem } from 'devextreme/ui/form'
|
import { GroupItem } from 'devextreme/ui/form'
|
||||||
import { Form as FormDx } from 'devextreme-react/form'
|
import { Form as FormDx } from 'devextreme-react/form'
|
||||||
import FormButtons from '../form/FormButtons'
|
import FormButtons from '../form/FormButtons'
|
||||||
import { Link, useNavigate } from 'react-router-dom'
|
import { useNavigate } from 'react-router-dom'
|
||||||
import { ROUTES_ENUM } from '@/routes/route.constant'
|
import { ROUTES_ENUM } from '@/routes/route.constant'
|
||||||
import CustomStore from 'devextreme/data/custom_store'
|
import CustomStore from 'devextreme/data/custom_store'
|
||||||
import { PermissionResults, SimpleItemWithColData } from '../form/types'
|
import { PermissionResults, SimpleItemWithColData } from '../form/types'
|
||||||
|
|
@ -20,6 +20,7 @@ import { Container, Loading } from '@/components/shared'
|
||||||
import WidgetGroup from '@/components/common/WidgetGroup'
|
import WidgetGroup from '@/components/common/WidgetGroup'
|
||||||
import { GridExtraFilterState } from './Utils'
|
import { GridExtraFilterState } from './Utils'
|
||||||
import { useStoreActions, useStoreState } from '@/store/store'
|
import { useStoreActions, useStoreState } from '@/store/store'
|
||||||
|
import { usePWA } from '@/utils/hooks/usePWA'
|
||||||
|
|
||||||
const CardItem = ({
|
const CardItem = ({
|
||||||
isSubForm,
|
isSubForm,
|
||||||
|
|
@ -41,8 +42,9 @@ const CardItem = ({
|
||||||
const [formData, setFormData] = useState(row)
|
const [formData, setFormData] = useState(row)
|
||||||
const refForm = useRef<FormDx>(null)
|
const refForm = useRef<FormDx>(null)
|
||||||
const navigate = useNavigate()
|
const navigate = useNavigate()
|
||||||
const { checkPermission } = usePermission()
|
|
||||||
const { translate } = useLocalization()
|
const { translate } = useLocalization()
|
||||||
|
const { checkPermission } = usePermission()
|
||||||
|
const isPwaMode = usePWA()
|
||||||
|
|
||||||
const keyField = gridDto.gridOptions.keyFieldName
|
const keyField = gridDto.gridOptions.keyFieldName
|
||||||
const rowId = row[keyField!]
|
const rowId = row[keyField!]
|
||||||
|
|
@ -204,6 +206,8 @@ const Card = (props: CardProps) => {
|
||||||
const [searchText, setSearchText] = useState('')
|
const [searchText, setSearchText] = useState('')
|
||||||
const [prevValue, setPrevValue] = useState('')
|
const [prevValue, setPrevValue] = useState('')
|
||||||
const [loading, setLoading] = useState(false)
|
const [loading, setLoading] = useState(false)
|
||||||
|
const { checkPermission } = usePermission()
|
||||||
|
const isPwaMode = usePWA()
|
||||||
const [extraFilters, setExtraFilters] = useState<GridExtraFilterState[]>([])
|
const [extraFilters, setExtraFilters] = useState<GridExtraFilterState[]>([])
|
||||||
|
|
||||||
const { states } = useStoreState((state) => state.base.lists)
|
const { states } = useStoreState((state) => state.base.lists)
|
||||||
|
|
@ -355,7 +359,7 @@ const Card = (props: CardProps) => {
|
||||||
<WidgetGroup widgetGroups={gridDto.widgets || []} />
|
<WidgetGroup widgetGroups={gridDto.widgets || []} />
|
||||||
|
|
||||||
<Container>
|
<Container>
|
||||||
<div className="p-1 bg-white dark:bg-neutral-800 dark:border-neutral-700 ">
|
<div className="bg-white dark:bg-neutral-800 dark:border-neutral-700 ">
|
||||||
<div className="flex justify-end items-center">
|
<div className="flex justify-end items-center">
|
||||||
<div className="relative py-1 flex gap-1 border-b-1">
|
<div className="relative py-1 flex gap-1 border-b-1">
|
||||||
<FaSearch className="absolute left-2 top-1/2 -translate-y-1/2 text-gray-400 text-sm" />
|
<FaSearch className="absolute left-2 top-1/2 -translate-y-1/2 text-gray-400 text-sm" />
|
||||||
|
|
@ -444,6 +448,26 @@ const Card = (props: CardProps) => {
|
||||||
>
|
>
|
||||||
5
|
5
|
||||||
</Button>
|
</Button>
|
||||||
|
|
||||||
|
{checkPermission(gridDto?.gridOptions.permissionDto.u) && (
|
||||||
|
<Button
|
||||||
|
size="xs"
|
||||||
|
variant={'default'}
|
||||||
|
className="text-sm"
|
||||||
|
onClick={() => {
|
||||||
|
window.open(
|
||||||
|
ROUTES_ENUM.protected.saas.listFormManagement.edit.replace(
|
||||||
|
':listFormCode',
|
||||||
|
listFormCode,
|
||||||
|
),
|
||||||
|
isPwaMode ? '_self' : '_blank',
|
||||||
|
)
|
||||||
|
}}
|
||||||
|
title="Form Manager"
|
||||||
|
>
|
||||||
|
<FaCog className="w-3 h-3" />
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ import { Container } from '@/components/shared'
|
||||||
import { DX_CLASSNAMES } from '@/constants/app.constant'
|
import { DX_CLASSNAMES } from '@/constants/app.constant'
|
||||||
import { useLocalization } from '@/utils/hooks/useLocalization'
|
import { useLocalization } from '@/utils/hooks/useLocalization'
|
||||||
import DxChart from 'devextreme-react/chart'
|
import DxChart from 'devextreme-react/chart'
|
||||||
import { useEffect, useState } from 'react'
|
import { useCallback, useEffect, useState } from 'react'
|
||||||
import { Helmet } from 'react-helmet'
|
import { Helmet } from 'react-helmet'
|
||||||
import { useParams, useSearchParams } from 'react-router-dom'
|
import { useParams, useSearchParams } from 'react-router-dom'
|
||||||
import { useListFormCustomDataSource } from '@/shared/useListFormCustomDataSource'
|
import { useListFormCustomDataSource } from '@/shared/useListFormCustomDataSource'
|
||||||
|
|
@ -13,7 +13,7 @@ import { usePermission } from '@/utils/hooks/usePermission'
|
||||||
import { Button } from '@/components/ui'
|
import { Button } from '@/components/ui'
|
||||||
import { ROUTES_ENUM } from '@/routes/route.constant'
|
import { ROUTES_ENUM } from '@/routes/route.constant'
|
||||||
import { usePWA } from '@/utils/hooks/usePWA'
|
import { usePWA } from '@/utils/hooks/usePWA'
|
||||||
import { FaInfoCircle, FaSyncAlt } from 'react-icons/fa'
|
import { FaCog, FaSearch, FaSyncAlt } from 'react-icons/fa'
|
||||||
import { buildSeriesDto } from './Utils'
|
import { buildSeriesDto } from './Utils'
|
||||||
|
|
||||||
interface ChartProps extends CommonProps, Meta {
|
interface ChartProps extends CommonProps, Meta {
|
||||||
|
|
@ -39,13 +39,19 @@ const Chart = (props: ChartProps) => {
|
||||||
const params = useParams()
|
const params = useParams()
|
||||||
const _listFormCode = props?.listFormCode ?? params?.listFormCode ?? ''
|
const _listFormCode = props?.listFormCode ?? params?.listFormCode ?? ''
|
||||||
|
|
||||||
|
const [searchText, setSearchText] = useState('')
|
||||||
|
const [prevValue, setPrevValue] = useState('')
|
||||||
|
const [urlSearchParams, setUrlSearchParams] = useState<URLSearchParams>(
|
||||||
|
searchParams ? new URLSearchParams(searchParams) : new URLSearchParams(),
|
||||||
|
)
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!gridDto) return
|
if (!gridDto) return
|
||||||
|
|
||||||
const dataSource = createSelectDataSource(
|
const dataSource = createSelectDataSource(
|
||||||
gridDto.gridOptions,
|
gridDto.gridOptions,
|
||||||
listFormCode,
|
listFormCode,
|
||||||
searchParams,
|
urlSearchParams,
|
||||||
[],
|
[],
|
||||||
true,
|
true,
|
||||||
)
|
)
|
||||||
|
|
@ -94,7 +100,53 @@ const Chart = (props: ChartProps) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
setChartOptions(options)
|
setChartOptions(options)
|
||||||
}, [gridDto, searchParams])
|
}, [gridDto, searchParams, urlSearchParams])
|
||||||
|
|
||||||
|
const onFilter = useCallback(
|
||||||
|
(value?: string) => {
|
||||||
|
const text = value !== undefined ? value.trim() : searchText.trim()
|
||||||
|
|
||||||
|
if (!gridDto?.columnFormats) return
|
||||||
|
|
||||||
|
const newParams = new URLSearchParams(urlSearchParams.toString())
|
||||||
|
|
||||||
|
if (!text) {
|
||||||
|
newParams.delete('filter')
|
||||||
|
setUrlSearchParams(newParams)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const merged = gridDto.columnFormats
|
||||||
|
.filter(
|
||||||
|
(col) =>
|
||||||
|
col.dataType === 'string' &&
|
||||||
|
col.visible &&
|
||||||
|
col.width &&
|
||||||
|
col.allowSearch &&
|
||||||
|
col.width > 0,
|
||||||
|
)
|
||||||
|
.map((col) => [col.fieldName, 'contains', text])
|
||||||
|
|
||||||
|
let filter: any = null
|
||||||
|
if (merged.length === 1) {
|
||||||
|
filter = merged[0]
|
||||||
|
} else if (merged.length > 1) {
|
||||||
|
filter = merged.reduce((acc, f, idx) => {
|
||||||
|
if (idx === 0) return f
|
||||||
|
return [acc, 'or', f]
|
||||||
|
}, null as any)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (filter) {
|
||||||
|
newParams.set('filter', JSON.stringify(filter))
|
||||||
|
} else {
|
||||||
|
newParams.delete('filter')
|
||||||
|
}
|
||||||
|
|
||||||
|
setUrlSearchParams(newParams)
|
||||||
|
},
|
||||||
|
[gridDto, urlSearchParams, searchText],
|
||||||
|
)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Container className={DX_CLASSNAMES}>
|
<Container className={DX_CLASSNAMES}>
|
||||||
|
|
@ -109,6 +161,32 @@ const Chart = (props: ChartProps) => {
|
||||||
<div className="p-1 bg-white dark:bg-neutral-800 dark:border-neutral-700 h-full">
|
<div className="p-1 bg-white dark:bg-neutral-800 dark:border-neutral-700 h-full">
|
||||||
<div className="flex justify-end items-center h-full">
|
<div className="flex justify-end items-center h-full">
|
||||||
<div className="relative pb-1 flex gap-1 border-b-1">
|
<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="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
|
||||||
|
|
||||||
|
// 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"
|
||||||
|
/>
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
size="xs"
|
size="xs"
|
||||||
variant={'default'}
|
variant={'default'}
|
||||||
|
|
@ -116,7 +194,7 @@ const Chart = (props: ChartProps) => {
|
||||||
onClick={async () => {
|
onClick={async () => {
|
||||||
await props.refreshGridDto()
|
await props.refreshGridDto()
|
||||||
}}
|
}}
|
||||||
title="Reset Grid State"
|
title="Refresh Data"
|
||||||
>
|
>
|
||||||
<FaSyncAlt className="w-3 h-3" />
|
<FaSyncAlt className="w-3 h-3" />
|
||||||
</Button>
|
</Button>
|
||||||
|
|
@ -136,7 +214,7 @@ const Chart = (props: ChartProps) => {
|
||||||
}}
|
}}
|
||||||
title="Form Manager"
|
title="Form Manager"
|
||||||
>
|
>
|
||||||
<FaInfoCircle className="w-3 h-3" />
|
<FaCog className="w-3 h-3" />
|
||||||
</Button>
|
</Button>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -34,7 +34,15 @@ import {
|
||||||
import { useFilters } from './useFilters'
|
import { useFilters } from './useFilters'
|
||||||
import WidgetGroup from '@/components/common/WidgetGroup'
|
import WidgetGroup from '@/components/common/WidgetGroup'
|
||||||
import { Button } from '@/components/ui'
|
import { Button } from '@/components/ui'
|
||||||
import { FaInfoCircle, FaSyncAlt, FaTrash, FaTrashAlt } from 'react-icons/fa'
|
import {
|
||||||
|
FaCog,
|
||||||
|
FaInfoCircle,
|
||||||
|
FaSyncAlt,
|
||||||
|
FaTimes,
|
||||||
|
FaTrash,
|
||||||
|
FaTrashAlt,
|
||||||
|
FaUndo,
|
||||||
|
} from 'react-icons/fa'
|
||||||
import { usePermission } from '@/utils/hooks/usePermission'
|
import { usePermission } from '@/utils/hooks/usePermission'
|
||||||
import { ROUTES_ENUM } from '@/routes/route.constant'
|
import { ROUTES_ENUM } from '@/routes/route.constant'
|
||||||
import { usePWA } from '@/utils/hooks/usePWA'
|
import { usePWA } from '@/utils/hooks/usePWA'
|
||||||
|
|
@ -317,7 +325,7 @@ const Pivot = (props: PivotProps) => {
|
||||||
onClick={clearPivotFilters}
|
onClick={clearPivotFilters}
|
||||||
title="Remove Filter"
|
title="Remove Filter"
|
||||||
>
|
>
|
||||||
<FaTrash className="w-3 h-3" />
|
<FaTimes className="w-3 h-3" />
|
||||||
</Button>
|
</Button>
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
|
|
@ -327,7 +335,7 @@ const Pivot = (props: PivotProps) => {
|
||||||
onClick={resetPivotGridState}
|
onClick={resetPivotGridState}
|
||||||
title="Reset Grid State"
|
title="Reset Grid State"
|
||||||
>
|
>
|
||||||
<FaSyncAlt className="w-3 h-3" />
|
<FaUndo className="w-3 h-3" />
|
||||||
</Button>
|
</Button>
|
||||||
|
|
||||||
{checkPermission(gridDto?.gridOptions.permissionDto.u) && (
|
{checkPermission(gridDto?.gridOptions.permissionDto.u) && (
|
||||||
|
|
@ -346,7 +354,7 @@ const Pivot = (props: PivotProps) => {
|
||||||
}}
|
}}
|
||||||
title="Form Manager"
|
title="Form Manager"
|
||||||
>
|
>
|
||||||
<FaInfoCircle className="w-3 h-3" />
|
<FaCog className="w-3 h-3" />
|
||||||
</Button>
|
</Button>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -129,15 +129,7 @@ const useFilters = ({
|
||||||
menus.push({
|
menus.push({
|
||||||
text: translate('::ListForms.ListForm.ResetGridState'),
|
text: translate('::ListForms.ListForm.ResetGridState'),
|
||||||
id: 'resetGridState',
|
id: 'resetGridState',
|
||||||
icon: 'refresh',
|
icon: 'revert',
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
if (checkPermission(gridDto?.gridOptions.permissionDto.u)) {
|
|
||||||
menus.push({
|
|
||||||
text: translate('::ListForms.ListForm.Manage'),
|
|
||||||
id: 'openManage',
|
|
||||||
icon: 'preferences',
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -149,6 +141,14 @@ const useFilters = ({
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (checkPermission(gridDto?.gridOptions.permissionDto.u)) {
|
||||||
|
menus.push({
|
||||||
|
text: translate('::ListForms.ListForm.Manage'),
|
||||||
|
id: 'openManage',
|
||||||
|
icon: 'preferences',
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
if (checkPermission(gridDto?.gridOptions.permissionDto.e)) {
|
if (checkPermission(gridDto?.gridOptions.permissionDto.e)) {
|
||||||
items.push({
|
items.push({
|
||||||
locateInMenu: 'auto',
|
locateInMenu: 'auto',
|
||||||
|
|
@ -228,6 +228,7 @@ const useFilters = ({
|
||||||
{
|
{
|
||||||
text: translate('::ListForms.ListForm.GridMenu'),
|
text: translate('::ListForms.ListForm.GridMenu'),
|
||||||
items: menus,
|
items: menus,
|
||||||
|
icon: 'overflow',
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue