CardView komponenti
This commit is contained in:
parent
d38e4f851a
commit
412ad236cc
20 changed files with 1446 additions and 83 deletions
|
|
@ -3,6 +3,7 @@
|
||||||
public class LayoutDto
|
public class LayoutDto
|
||||||
{
|
{
|
||||||
public bool Grid { get; set; } = true;
|
public bool Grid { get; set; } = true;
|
||||||
|
public bool Card { get; set; } = true;
|
||||||
public bool Pivot { get; set; } = true;
|
public bool Pivot { get; set; } = true;
|
||||||
public bool Chart { get; set; } = true;
|
public bool Chart { get; set; } = true;
|
||||||
public bool Tree { get; set; } = true;
|
public bool Tree { get; set; } = true;
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,7 @@ public class ListFormWizardDto
|
||||||
|
|
||||||
public string DefaultLayout { get; set; }
|
public string DefaultLayout { get; set; }
|
||||||
public bool Grid { get; set; }
|
public bool Grid { get; set; }
|
||||||
|
public bool Card { get; set; }
|
||||||
public bool Pivot { get; set; }
|
public bool Pivot { get; set; }
|
||||||
public bool Tree { get; set; }
|
public bool Tree { get; set; }
|
||||||
public bool Chart { get; set; }
|
public bool Chart { get; set; }
|
||||||
|
|
|
||||||
|
|
@ -281,7 +281,7 @@ public class ListFormWizardAppService(
|
||||||
ExportJson = WizardConsts.DefaultExportJson,
|
ExportJson = WizardConsts.DefaultExportJson,
|
||||||
IsSubForm = false,
|
IsSubForm = false,
|
||||||
ShowNote = input.SubForms.Count > 0 || input.WorkflowCriteria.Count > 0,
|
ShowNote = input.SubForms.Count > 0 || input.WorkflowCriteria.Count > 0,
|
||||||
LayoutJson = WizardConsts.DefaultLayoutJson(input.DefaultLayout, input.Grid, input.Pivot, input.Tree, input.Chart, input.Gantt, input.Scheduler),
|
LayoutJson = WizardConsts.DefaultLayoutJson(input.DefaultLayout, input.Grid, input.Card, input.Pivot, input.Tree, input.Chart, input.Gantt, input.Scheduler),
|
||||||
CultureName = LanguageCodes.En,
|
CultureName = LanguageCodes.En,
|
||||||
ListFormCode = input.ListFormCode,
|
ListFormCode = input.ListFormCode,
|
||||||
Name = nameLangKey,
|
Name = nameLangKey,
|
||||||
|
|
|
||||||
|
|
@ -4680,6 +4680,12 @@
|
||||||
"en": "Grid Layout",
|
"en": "Grid Layout",
|
||||||
"tr": "Liste Düzeni"
|
"tr": "Liste Düzeni"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"resourceName": "Platform",
|
||||||
|
"key": "ListForms.ListFormEdit.DetailsLayoutDto.CardLayout",
|
||||||
|
"en": "Card Layout",
|
||||||
|
"tr": "Kart Düzeni"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"resourceName": "Platform",
|
"resourceName": "Platform",
|
||||||
"key": "ListForms.ListFormEdit.DetailsLayoutDto.PivotLayout",
|
"key": "ListForms.ListFormEdit.DetailsLayoutDto.PivotLayout",
|
||||||
|
|
|
||||||
|
|
@ -67,6 +67,7 @@ public static class ListFormSeeder_DefaultJsons
|
||||||
public static string DefaultLayoutJson(string DefaultLayout = "grid") => JsonSerializer.Serialize(new LayoutDto()
|
public static string DefaultLayoutJson(string DefaultLayout = "grid") => JsonSerializer.Serialize(new LayoutDto()
|
||||||
{
|
{
|
||||||
Grid = true,
|
Grid = true,
|
||||||
|
Card = true,
|
||||||
Pivot = true,
|
Pivot = true,
|
||||||
Chart = true,
|
Chart = true,
|
||||||
Tree = true,
|
Tree = true,
|
||||||
|
|
|
||||||
|
|
@ -393,7 +393,7 @@ public class WizardDataSeeder : IDataSeedContributor, ITransientDependency
|
||||||
ExportJson = WizardConsts.DefaultExportJson,
|
ExportJson = WizardConsts.DefaultExportJson,
|
||||||
IsSubForm = false,
|
IsSubForm = false,
|
||||||
ShowNote = input.SubForms.Count > 0 || input.WorkflowCriteria.Count > 0,
|
ShowNote = input.SubForms.Count > 0 || input.WorkflowCriteria.Count > 0,
|
||||||
LayoutJson = WizardConsts.DefaultLayoutJson(input.DefaultLayout, input.Grid, input.Pivot, input.Tree, input.Chart, input.Gantt, input.Scheduler),
|
LayoutJson = WizardConsts.DefaultLayoutJson(input.DefaultLayout, input.Grid, input.Card, input.Pivot, input.Tree, input.Chart, input.Gantt, input.Scheduler),
|
||||||
CultureName = LanguageCodes.En,
|
CultureName = LanguageCodes.En,
|
||||||
ListFormCode = input.ListFormCode,
|
ListFormCode = input.ListFormCode,
|
||||||
Name = nameLangKey,
|
Name = nameLangKey,
|
||||||
|
|
|
||||||
|
|
@ -84,9 +84,10 @@ public static class WizardConsts
|
||||||
Margin = 10
|
Margin = 10
|
||||||
});
|
});
|
||||||
|
|
||||||
public static string DefaultLayoutJson(string DefaultLayout = "grid", bool Grid = true, bool Pivot = true, bool Chart = true, bool Tree = true, bool Gantt = true, bool Scheduler = true) => JsonSerializer.Serialize(new
|
public static string DefaultLayoutJson(string DefaultLayout = "grid", bool Grid = true, bool Card = true, bool Pivot = true, bool Chart = true, bool Tree = true, bool Gantt = true, bool Scheduler = true) => JsonSerializer.Serialize(new
|
||||||
{
|
{
|
||||||
Grid = Grid,
|
Grid = Grid,
|
||||||
|
Card = Card,
|
||||||
Pivot = Pivot,
|
Pivot = Pivot,
|
||||||
Chart = Chart,
|
Chart = Chart,
|
||||||
Tree = Tree,
|
Tree = Tree,
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,22 @@ body {
|
||||||
font-size: 14px; /* body’ye font-size uygulanmaz */
|
font-size: 14px; /* body’ye font-size uygulanmaz */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.list-card-view.dx-cardview {
|
||||||
|
padding: 0;
|
||||||
|
border-radius: 0;
|
||||||
|
background-color: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
.list-card-view .dx-cardview-card,
|
||||||
|
.list-card-view .dx-cardview-card-header .dx-toolbar,
|
||||||
|
.list-card-view .dx-cardview-card-footer {
|
||||||
|
border-radius: 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.list-card-view .dx-toolbar .dx-button-text {
|
||||||
|
text-transform: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
.dx-form-group-with-caption > .dx-form-group-content {
|
.dx-form-group-with-caption > .dx-form-group-content {
|
||||||
padding-top: 2px !important;
|
padding-top: 2px !important;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
import { SelectCommandTypeEnum } from '@/proxy/form/models'
|
|
||||||
import {
|
import {
|
||||||
ListFormWorkflowCriteriaDto,
|
ListFormWorkflowCriteriaDto,
|
||||||
SubFormDto,
|
SubFormDto,
|
||||||
WidgetEditDto,
|
WidgetEditDto,
|
||||||
WorkflowDto,
|
WorkflowDto,
|
||||||
|
SelectCommandTypeEnum
|
||||||
} from '@/proxy/form/models'
|
} from '@/proxy/form/models'
|
||||||
import { ListViewLayoutType } from '@/views/admin/listForm/edit/types'
|
import { ListViewLayoutType } from '@/views/admin/listForm/edit/types'
|
||||||
|
|
||||||
|
|
@ -39,6 +39,7 @@ export interface ListFormWizardDto {
|
||||||
|
|
||||||
defaultLayout: ListViewLayoutType
|
defaultLayout: ListViewLayoutType
|
||||||
grid: boolean
|
grid: boolean
|
||||||
|
card: boolean
|
||||||
pivot: boolean
|
pivot: boolean
|
||||||
tree: boolean
|
tree: boolean
|
||||||
chart: boolean
|
chart: boolean
|
||||||
|
|
|
||||||
|
|
@ -951,6 +951,7 @@ export interface ListFormWorkflowCriteriaDto {
|
||||||
|
|
||||||
export interface LayoutDto {
|
export interface LayoutDto {
|
||||||
grid: boolean
|
grid: boolean
|
||||||
|
card: boolean
|
||||||
pivot: boolean
|
pivot: boolean
|
||||||
tree: boolean
|
tree: boolean
|
||||||
chart: boolean
|
chart: boolean
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,7 @@ const schema = Yup.object().shape({
|
||||||
defaultLayout: Yup.string(),
|
defaultLayout: Yup.string(),
|
||||||
layoutDto: Yup.object().shape({
|
layoutDto: Yup.object().shape({
|
||||||
grid: Yup.boolean(),
|
grid: Yup.boolean(),
|
||||||
|
card: Yup.boolean(),
|
||||||
pivot: Yup.boolean(),
|
pivot: Yup.boolean(),
|
||||||
chart: Yup.boolean(),
|
chart: Yup.boolean(),
|
||||||
tree: Yup.boolean(),
|
tree: Yup.boolean(),
|
||||||
|
|
@ -312,6 +313,22 @@ function FormTabDetails(
|
||||||
/>
|
/>
|
||||||
</FormItem>
|
</FormItem>
|
||||||
|
|
||||||
|
<FormItem
|
||||||
|
label={translate('::ListForms.ListFormEdit.DetailsLayoutDto.CardLayout')}
|
||||||
|
invalid={errors.layoutDto?.card && touched.layoutDto?.card}
|
||||||
|
errorMessage={errors.layoutDto?.card}
|
||||||
|
>
|
||||||
|
<Field
|
||||||
|
className="w-20"
|
||||||
|
autoComplete="off"
|
||||||
|
name="layoutDto.card"
|
||||||
|
placeholder={translate(
|
||||||
|
'::ListForms.ListFormEdit.DetailsLayoutDto.CardLayout',
|
||||||
|
)}
|
||||||
|
component={Checkbox}
|
||||||
|
/>
|
||||||
|
</FormItem>
|
||||||
|
|
||||||
<FormItem
|
<FormItem
|
||||||
label={translate('::ListForms.ListFormEdit.DetailsLayoutDto.PivotLayout')}
|
label={translate('::ListForms.ListFormEdit.DetailsLayoutDto.PivotLayout')}
|
||||||
invalid={errors.layoutDto?.pivot && touched.layoutDto?.pivot}
|
invalid={errors.layoutDto?.pivot && touched.layoutDto?.pivot}
|
||||||
|
|
|
||||||
|
|
@ -224,6 +224,7 @@ export const listFormTypeOptions = [
|
||||||
|
|
||||||
export const listFormDefaultLayoutOptions = [
|
export const listFormDefaultLayoutOptions = [
|
||||||
{ value: 'grid', label: 'Grid' },
|
{ value: 'grid', label: 'Grid' },
|
||||||
|
{ value: 'card', label: 'Card' },
|
||||||
{ value: 'pivot', label: 'Pivot' },
|
{ value: 'pivot', label: 'Pivot' },
|
||||||
{ value: 'chart', label: 'Chart' },
|
{ value: 'chart', label: 'Chart' },
|
||||||
{ value: 'tree', label: 'Tree' },
|
{ value: 'tree', label: 'Tree' },
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,17 @@
|
||||||
export type ChartOperation = '' | 'select' | 'insert' | 'update' | 'delete'
|
export type ChartOperation = '' | 'select' | 'insert' | 'update' | 'delete'
|
||||||
export type ChartDialogType = '' | 'pane' | 'serie' | 'annotation' | 'axis'
|
export type ChartDialogType = '' | 'pane' | 'serie' | 'annotation' | 'axis'
|
||||||
export type ListViewLayoutType = 'grid' | 'pivot' | 'tree' | 'chart' | 'gantt' | 'scheduler'
|
export type ListViewLayoutType =
|
||||||
|
| 'grid'
|
||||||
|
| 'card'
|
||||||
|
| 'pivot'
|
||||||
|
| 'tree'
|
||||||
|
| 'chart'
|
||||||
|
| 'gantt'
|
||||||
|
| 'scheduler'
|
||||||
|
|
||||||
export const layoutTypes = {
|
export const layoutTypes = {
|
||||||
grid: 'Grid',
|
grid: 'Grid',
|
||||||
|
card: 'Card',
|
||||||
pivot: 'Pivot',
|
pivot: 'Pivot',
|
||||||
tree: 'Tree',
|
tree: 'Tree',
|
||||||
chart: 'Chart',
|
chart: 'Chart',
|
||||||
|
|
|
||||||
|
|
@ -516,6 +516,20 @@ const WizardStep2 = ({
|
||||||
/>
|
/>
|
||||||
</FormItem>
|
</FormItem>
|
||||||
|
|
||||||
|
<FormItem
|
||||||
|
label={translate('::ListForms.ListFormEdit.DetailsLayoutDto.CardLayout')}
|
||||||
|
invalid={errors?.card && touched?.card}
|
||||||
|
errorMessage={errors?.card}
|
||||||
|
>
|
||||||
|
<Field
|
||||||
|
className="w-20"
|
||||||
|
autoComplete="off"
|
||||||
|
name="card"
|
||||||
|
placeholder={translate('::ListForms.ListFormEdit.DetailsLayoutDto.CardLayout')}
|
||||||
|
component={Checkbox}
|
||||||
|
/>
|
||||||
|
</FormItem>
|
||||||
|
|
||||||
<FormItem
|
<FormItem
|
||||||
label={translate('::ListForms.ListFormEdit.DetailsLayoutDto.PivotLayout')}
|
label={translate('::ListForms.ListFormEdit.DetailsLayoutDto.PivotLayout')}
|
||||||
invalid={errors?.pivot && touched?.pivot}
|
invalid={errors?.pivot && touched?.pivot}
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,40 @@ import React from 'react'
|
||||||
const NO_IMAGE = '/img/others/no-image.png'
|
const NO_IMAGE = '/img/others/no-image.png'
|
||||||
|
|
||||||
let previewElement: HTMLDivElement | null = null
|
let previewElement: HTMLDivElement | null = null
|
||||||
|
let previewTarget: HTMLElement | null = null
|
||||||
|
let previewListenersBound = false
|
||||||
|
|
||||||
|
const hidePreviewElement = () => {
|
||||||
|
previewTarget = null
|
||||||
|
if (previewElement) {
|
||||||
|
previewElement.style.opacity = '0'
|
||||||
|
previewElement.style.display = 'none'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const bindPreviewDismissListeners = () => {
|
||||||
|
if (previewListenersBound) return
|
||||||
|
previewListenersBound = true
|
||||||
|
|
||||||
|
document.addEventListener(
|
||||||
|
'pointermove',
|
||||||
|
(event) => {
|
||||||
|
const target = event.target as Node | null
|
||||||
|
if (
|
||||||
|
previewTarget &&
|
||||||
|
(!previewTarget.isConnected || !target || !previewTarget.contains(target))
|
||||||
|
) {
|
||||||
|
hidePreviewElement()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{ passive: true },
|
||||||
|
)
|
||||||
|
document.addEventListener('scroll', hidePreviewElement, true)
|
||||||
|
window.addEventListener('blur', hidePreviewElement)
|
||||||
|
document.addEventListener('visibilitychange', () => {
|
||||||
|
if (document.hidden) hidePreviewElement()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
const getPreviewElement = () => {
|
const getPreviewElement = () => {
|
||||||
if (!previewElement) {
|
if (!previewElement) {
|
||||||
|
|
@ -31,6 +65,7 @@ const getPreviewElement = () => {
|
||||||
element.appendChild(image)
|
element.appendChild(image)
|
||||||
document.body.appendChild(element)
|
document.body.appendChild(element)
|
||||||
previewElement = element
|
previewElement = element
|
||||||
|
bindPreviewDismissListeners()
|
||||||
}
|
}
|
||||||
|
|
||||||
return previewElement
|
return previewElement
|
||||||
|
|
@ -38,6 +73,7 @@ const getPreviewElement = () => {
|
||||||
|
|
||||||
export const showImageHoverPreview = (src: string, event: React.MouseEvent<HTMLElement>) => {
|
export const showImageHoverPreview = (src: string, event: React.MouseEvent<HTMLElement>) => {
|
||||||
const element = getPreviewElement()
|
const element = getPreviewElement()
|
||||||
|
previewTarget = event.currentTarget
|
||||||
const image = element.querySelector('img') as HTMLImageElement
|
const image = element.querySelector('img') as HTMLImageElement
|
||||||
image.onerror = () => {
|
image.onerror = () => {
|
||||||
image.onerror = null
|
image.onerror = null
|
||||||
|
|
@ -65,13 +101,11 @@ export const showImageHoverPreview = (src: string, event: React.MouseEvent<HTMLE
|
||||||
}
|
}
|
||||||
|
|
||||||
export const hideImageHoverPreview = () => {
|
export const hideImageHoverPreview = () => {
|
||||||
if (previewElement) {
|
hidePreviewElement()
|
||||||
previewElement.style.opacity = '0'
|
|
||||||
previewElement.style.display = 'none'
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export const openImageInNewTab = (url: string) => {
|
export const openImageInNewTab = (url: string) => {
|
||||||
|
hidePreviewElement()
|
||||||
if (!url.startsWith('data:image/')) {
|
if (!url.startsWith('data:image/')) {
|
||||||
window.open(url, '_blank', 'noopener,noreferrer')
|
window.open(url, '_blank', 'noopener,noreferrer')
|
||||||
return
|
return
|
||||||
|
|
|
||||||
1234
ui/src/views/list/CardView.tsx
Normal file
1234
ui/src/views/list/CardView.tsx
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -15,6 +15,7 @@ import { ListViewLayoutType } from '../admin/listForm/edit/types'
|
||||||
|
|
||||||
import {
|
import {
|
||||||
FaChartArea,
|
FaChartArea,
|
||||||
|
FaThLarge,
|
||||||
FaList,
|
FaList,
|
||||||
FaSitemap,
|
FaSitemap,
|
||||||
FaTable,
|
FaTable,
|
||||||
|
|
@ -26,6 +27,7 @@ import {
|
||||||
🔥 LAZY VIEW IMPORTS
|
🔥 LAZY VIEW IMPORTS
|
||||||
======================= */
|
======================= */
|
||||||
const Grid = React.lazy(() => import('./Grid'))
|
const Grid = React.lazy(() => import('./Grid'))
|
||||||
|
const CardView = React.lazy(() => import('./CardView'))
|
||||||
const Pivot = React.lazy(() => import('./Pivot'))
|
const Pivot = React.lazy(() => import('./Pivot'))
|
||||||
const Tree = React.lazy(() => import('./Tree'))
|
const Tree = React.lazy(() => import('./Tree'))
|
||||||
const Chart = React.lazy(() => import('./Chart'))
|
const Chart = React.lazy(() => import('./Chart'))
|
||||||
|
|
@ -34,6 +36,7 @@ const SchedulerView = React.lazy(() => import('./SchedulerView'))
|
||||||
|
|
||||||
function isLayoutValid(dto: GridDto, layout: ListViewLayoutType | undefined): boolean {
|
function isLayoutValid(dto: GridDto, layout: ListViewLayoutType | undefined): boolean {
|
||||||
if (!layout || layout === 'grid') return true
|
if (!layout || layout === 'grid') return true
|
||||||
|
if (layout === 'card') return true
|
||||||
if (layout === 'pivot') return !!dto.gridOptions?.layoutDto?.pivot
|
if (layout === 'pivot') return !!dto.gridOptions?.layoutDto?.pivot
|
||||||
if (layout === 'chart') return !!dto.gridOptions?.layoutDto?.chart
|
if (layout === 'chart') return !!dto.gridOptions?.layoutDto?.chart
|
||||||
if (layout === 'tree')
|
if (layout === 'tree')
|
||||||
|
|
@ -125,6 +128,7 @@ const List: React.FC = () => {
|
||||||
const preload = useMemo(
|
const preload = useMemo(
|
||||||
() => ({
|
() => ({
|
||||||
grid: () => import('./Grid'),
|
grid: () => import('./Grid'),
|
||||||
|
card: () => import('./CardView'),
|
||||||
pivot: () => import('./Pivot'),
|
pivot: () => import('./Pivot'),
|
||||||
tree: () => import('./Tree'),
|
tree: () => import('./Tree'),
|
||||||
chart: () => import('./Chart'),
|
chart: () => import('./Chart'),
|
||||||
|
|
@ -200,6 +204,16 @@ const List: React.FC = () => {
|
||||||
onMouseEnter={() => preload.grid()}
|
onMouseEnter={() => preload.grid()}
|
||||||
></Button>
|
></Button>
|
||||||
|
|
||||||
|
{gridDto.gridOptions.layoutDto.card && (
|
||||||
|
<Button
|
||||||
|
size="sm"
|
||||||
|
icon={<FaThLarge />}
|
||||||
|
variant={viewMode === 'card' ? 'solid' : 'default'}
|
||||||
|
onClick={() => setLayout('card')}
|
||||||
|
onMouseEnter={() => preload.card()}
|
||||||
|
></Button>
|
||||||
|
)}
|
||||||
|
|
||||||
{gridDto.gridOptions.layoutDto.pivot && (
|
{gridDto.gridOptions.layoutDto.pivot && (
|
||||||
<Button
|
<Button
|
||||||
size="sm"
|
size="sm"
|
||||||
|
|
@ -235,6 +249,15 @@ const List: React.FC = () => {
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
{viewMode === 'card' && (
|
||||||
|
<CardView
|
||||||
|
listFormCode={listFormCode}
|
||||||
|
searchParams={searchParams}
|
||||||
|
isSubForm={false}
|
||||||
|
gridDto={gridDto}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
|
||||||
{viewMode === 'pivot' && (
|
{viewMode === 'pivot' && (
|
||||||
<Pivot
|
<Pivot
|
||||||
listFormCode={listFormCode}
|
listFormCode={listFormCode}
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ import {
|
||||||
GridDto,
|
GridDto,
|
||||||
PlatformEditorTypes,
|
PlatformEditorTypes,
|
||||||
UiLookupDataSourceTypeEnum,
|
UiLookupDataSourceTypeEnum,
|
||||||
EditingFormItemDto
|
EditingFormItemDto,
|
||||||
} from '@/proxy/form/models'
|
} from '@/proxy/form/models'
|
||||||
import { useLocalization } from '@/utils/hooks/useLocalization'
|
import { useLocalization } from '@/utils/hooks/useLocalization'
|
||||||
import Scheduler, {
|
import Scheduler, {
|
||||||
|
|
@ -307,7 +307,9 @@ const SchedulerView = (props: SchedulerViewProps) => {
|
||||||
if (i.editorOptions) {
|
if (i.editorOptions) {
|
||||||
editorOptions = JSON.parse(i.editorOptions)
|
editorOptions = JSON.parse(i.editorOptions)
|
||||||
}
|
}
|
||||||
} catch {}
|
} catch (err) {
|
||||||
|
console.log(err)
|
||||||
|
}
|
||||||
|
|
||||||
const fieldName = i.dataField.split(':')[0]
|
const fieldName = i.dataField.split(':')[0]
|
||||||
const listFormField = gridDto.columnFormats.find((x: any) => x.fieldName === fieldName)
|
const listFormField = gridDto.columnFormats.find((x: any) => x.fieldName === fieldName)
|
||||||
|
|
|
||||||
|
|
@ -14,12 +14,14 @@ import dxDataGrid from 'devextreme/ui/data_grid'
|
||||||
import dxPivotGrid from 'devextreme/ui/pivot_grid'
|
import dxPivotGrid from 'devextreme/ui/pivot_grid'
|
||||||
import dxTreeList from 'devextreme/ui/tree_list'
|
import dxTreeList from 'devextreme/ui/tree_list'
|
||||||
import dxGantt from 'devextreme/ui/gantt'
|
import dxGantt from 'devextreme/ui/gantt'
|
||||||
|
import dxCardView from 'devextreme/ui/card_view'
|
||||||
import { Dispatch, MutableRefObject, SetStateAction, useEffect, useState } from 'react'
|
import { Dispatch, MutableRefObject, SetStateAction, useEffect, useState } from 'react'
|
||||||
import { setGridPanelColor } from './Utils'
|
import { setGridPanelColor } from './Utils'
|
||||||
import { usePermission } from '@/utils/hooks/usePermission'
|
import { usePermission } from '@/utils/hooks/usePermission'
|
||||||
import { usePWA } from '@/utils/hooks/usePWA'
|
import { usePWA } from '@/utils/hooks/usePWA'
|
||||||
import { ROUTES_ENUM } from '@/routes/route.constant'
|
import { ROUTES_ENUM } from '@/routes/route.constant'
|
||||||
import type { GanttRef } from 'devextreme-react/cjs/gantt'
|
import type { GanttRef } from 'devextreme-react/cjs/gantt'
|
||||||
|
import type { CardViewRef } from 'devextreme-react/card-view'
|
||||||
import { useStoreState } from '@/store'
|
import { useStoreState } from '@/store'
|
||||||
import { MULTIVALUE_DELIMITER } from '@/constants/app.constant'
|
import { MULTIVALUE_DELIMITER } from '@/constants/app.constant'
|
||||||
import { createReportQueryString } from '../report/reportRouteParams'
|
import { createReportQueryString } from '../report/reportRouteParams'
|
||||||
|
|
@ -29,7 +31,7 @@ export interface ISelectBoxData {
|
||||||
label?: string
|
label?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
type GridInstance = dxDataGrid | dxPivotGrid | dxTreeList | dxGantt
|
type GridInstance = dxDataGrid | dxPivotGrid | dxTreeList | dxGantt | dxCardView
|
||||||
type FilterToolbarActionId =
|
type FilterToolbarActionId =
|
||||||
| 'openDynamicGridReport'
|
| 'openDynamicGridReport'
|
||||||
| 'saveActiveFilter'
|
| 'saveActiveFilter'
|
||||||
|
|
@ -50,68 +52,46 @@ type FilterToolbarAction = {
|
||||||
|
|
||||||
// Grid tipini kontrol eden yardımcı fonksiyonlar
|
// Grid tipini kontrol eden yardımcı fonksiyonlar
|
||||||
const isDataGrid = (grid: GridInstance): grid is dxDataGrid => {
|
const isDataGrid = (grid: GridInstance): grid is dxDataGrid => {
|
||||||
return 'clearFilter' in grid
|
return 'state' in grid && 'getVisibleColumns' in grid && !('getRootNode' in grid)
|
||||||
}
|
}
|
||||||
|
|
||||||
const isTreeList = (grid: GridInstance): grid is dxTreeList => {
|
const isTreeList = (grid: GridInstance): grid is dxTreeList => {
|
||||||
return 'getRootNode' in grid
|
return 'getRootNode' in grid
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const isCardView = (grid: GridInstance): grid is dxCardView => {
|
||||||
|
return 'getSelectedCardKeys' in grid
|
||||||
|
}
|
||||||
|
|
||||||
const supportsState = (grid: GridInstance): grid is dxDataGrid | dxTreeList => {
|
const supportsState = (grid: GridInstance): grid is dxDataGrid | dxTreeList => {
|
||||||
return 'state' in grid && typeof (grid as any).state === 'function'
|
return 'state' in grid && typeof (grid as any).state === 'function'
|
||||||
}
|
}
|
||||||
|
|
||||||
const setToolbarItemValue = (grid: GridInstance, itemName: string, value: any) => {
|
const setToolbarItemValue = (grid: GridInstance, itemName: string, value: any) => {
|
||||||
if (isDataGrid(grid)) {
|
const component = grid as any
|
||||||
const toolbarOptions = grid.option('toolbar')
|
const toolbarOptions = component.option('toolbar')
|
||||||
if (toolbarOptions?.items) {
|
if (toolbarOptions?.items) {
|
||||||
const index = toolbarOptions.items.findIndex((item: any) => item.name === itemName)
|
const index = toolbarOptions.items.findIndex((item: any) => item.name === itemName)
|
||||||
if (index > -1 && toolbarOptions.items[index]) {
|
if (index > -1 && toolbarOptions.items[index]) {
|
||||||
const item = toolbarOptions.items[index] as any
|
const item = toolbarOptions.items[index] as any
|
||||||
if (item.options) {
|
if (item.options) {
|
||||||
item.options.value = value
|
item.options.value = value
|
||||||
grid.option('toolbar', toolbarOptions)
|
component.option('toolbar', toolbarOptions)
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if (isTreeList(grid)) {
|
|
||||||
const toolbarOptions = grid.option('toolbar')
|
|
||||||
if (toolbarOptions?.items) {
|
|
||||||
const index = toolbarOptions.items.findIndex((item: any) => item.name === itemName)
|
|
||||||
if (index > -1 && toolbarOptions.items[index]) {
|
|
||||||
const item = toolbarOptions.items[index] as any
|
|
||||||
if (item.options) {
|
|
||||||
item.options.value = value
|
|
||||||
grid.option('toolbar', toolbarOptions)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const setToolbarItemItems = (grid: GridInstance, itemName: string, items: any[]) => {
|
const setToolbarItemItems = (grid: GridInstance, itemName: string, items: any[]) => {
|
||||||
if (isDataGrid(grid)) {
|
const component = grid as any
|
||||||
const toolbarOptions = grid.option('toolbar')
|
const toolbarOptions = component.option('toolbar')
|
||||||
if (toolbarOptions?.items) {
|
if (toolbarOptions?.items) {
|
||||||
const index = toolbarOptions.items.findIndex((item: any) => item.name === itemName)
|
const index = toolbarOptions.items.findIndex((item: any) => item.name === itemName)
|
||||||
if (index > -1 && toolbarOptions.items[index]) {
|
if (index > -1 && toolbarOptions.items[index]) {
|
||||||
const item = toolbarOptions.items[index] as any
|
const item = toolbarOptions.items[index] as any
|
||||||
if (item.options) {
|
if (item.options) {
|
||||||
item.options.items = items
|
item.options.items = items
|
||||||
grid.option('toolbar', toolbarOptions)
|
component.option('toolbar', toolbarOptions)
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if (isTreeList(grid)) {
|
|
||||||
const toolbarOptions = grid.option('toolbar')
|
|
||||||
if (toolbarOptions?.items) {
|
|
||||||
const index = toolbarOptions.items.findIndex((item: any) => item.name === itemName)
|
|
||||||
if (index > -1 && toolbarOptions.items[index]) {
|
|
||||||
const item = toolbarOptions.items[index] as any
|
|
||||||
if (item.options) {
|
|
||||||
item.options.items = items
|
|
||||||
grid.option('toolbar', toolbarOptions)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -140,34 +120,23 @@ const fitColumns = (grid: GridInstance) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
const clearGridFilter = (grid: GridInstance) => {
|
const clearGridFilter = (grid: GridInstance) => {
|
||||||
if (isDataGrid(grid)) {
|
;(grid as any).clearFilter?.()
|
||||||
grid.clearFilter()
|
|
||||||
} else if (isTreeList(grid)) {
|
|
||||||
grid.clearFilter()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const setFilterPanelVisible = (grid: GridInstance, visible: boolean) => {
|
const setFilterPanelVisible = (grid: GridInstance, visible: boolean) => {
|
||||||
if (isDataGrid(grid)) {
|
;(grid as any).option('filterPanel', { visible })
|
||||||
grid.option('filterPanel', { visible })
|
|
||||||
} else if (isTreeList(grid)) {
|
|
||||||
grid.option('filterPanel', { visible })
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const setFilterValue = (grid: GridInstance, value: any) => {
|
const setFilterValue = (grid: GridInstance, value: any) => {
|
||||||
if (isDataGrid(grid)) {
|
;(grid as any).option('filterValue', value)
|
||||||
grid.option('filterValue', value)
|
|
||||||
} else if (isTreeList(grid)) {
|
|
||||||
grid.option('filterValue', value)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const resetGridState = (grid: GridInstance) => {
|
const resetGridState = (grid: GridInstance) => {
|
||||||
if (isDataGrid(grid)) {
|
if (supportsState(grid)) {
|
||||||
grid.state(null)
|
|
||||||
} else if (isTreeList(grid)) {
|
|
||||||
grid.state(null)
|
grid.state(null)
|
||||||
|
} else if (isCardView(grid)) {
|
||||||
|
grid.option('filterValue', undefined)
|
||||||
|
grid.option('selectedCardKeys', [])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -305,6 +274,7 @@ const useFilters = ({
|
||||||
| MutableRefObject<PivotGridRef | undefined>
|
| MutableRefObject<PivotGridRef | undefined>
|
||||||
| MutableRefObject<TreeListRef<any, any> | undefined>
|
| MutableRefObject<TreeListRef<any, any> | undefined>
|
||||||
| MutableRefObject<GanttRef | undefined>
|
| MutableRefObject<GanttRef | undefined>
|
||||||
|
| MutableRefObject<CardViewRef | undefined>
|
||||||
listFormCode: string
|
listFormCode: string
|
||||||
saveGridState?: (state: any) => Promise<void>
|
saveGridState?: (state: any) => Promise<void>
|
||||||
}): {
|
}): {
|
||||||
|
|
|
||||||
|
|
@ -68,6 +68,40 @@ const cellTemplateMultiValue = (
|
||||||
|
|
||||||
// Hover preview overlay — singleton, tüm grid hücreleri tarafından paylaşılır
|
// Hover preview overlay — singleton, tüm grid hücreleri tarafından paylaşılır
|
||||||
let __imgPreviewEl: HTMLDivElement | null = null
|
let __imgPreviewEl: HTMLDivElement | null = null
|
||||||
|
let __imgPreviewTarget: HTMLElement | null = null
|
||||||
|
let __imgPreviewListenersBound = false
|
||||||
|
|
||||||
|
function hideImgPreview() {
|
||||||
|
__imgPreviewTarget = null
|
||||||
|
if (__imgPreviewEl) {
|
||||||
|
__imgPreviewEl.style.opacity = '0'
|
||||||
|
__imgPreviewEl.style.display = 'none'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function bindImgPreviewDismissListeners() {
|
||||||
|
if (__imgPreviewListenersBound) return
|
||||||
|
__imgPreviewListenersBound = true
|
||||||
|
|
||||||
|
document.addEventListener(
|
||||||
|
'pointermove',
|
||||||
|
(event) => {
|
||||||
|
const target = event.target as Node | null
|
||||||
|
if (
|
||||||
|
__imgPreviewTarget &&
|
||||||
|
(!__imgPreviewTarget.isConnected || !target || !__imgPreviewTarget.contains(target))
|
||||||
|
) {
|
||||||
|
hideImgPreview()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{ passive: true },
|
||||||
|
)
|
||||||
|
document.addEventListener('scroll', hideImgPreview, true)
|
||||||
|
window.addEventListener('blur', hideImgPreview)
|
||||||
|
document.addEventListener('visibilitychange', () => {
|
||||||
|
if (document.hidden) hideImgPreview()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
function getImgPreview(): HTMLDivElement {
|
function getImgPreview(): HTMLDivElement {
|
||||||
if (!__imgPreviewEl) {
|
if (!__imgPreviewEl) {
|
||||||
|
|
@ -97,12 +131,14 @@ function getImgPreview(): HTMLDivElement {
|
||||||
el.appendChild(img)
|
el.appendChild(img)
|
||||||
document.body.appendChild(el)
|
document.body.appendChild(el)
|
||||||
__imgPreviewEl = el
|
__imgPreviewEl = el
|
||||||
|
bindImgPreviewDismissListeners()
|
||||||
}
|
}
|
||||||
return __imgPreviewEl
|
return __imgPreviewEl
|
||||||
}
|
}
|
||||||
|
|
||||||
function showImgPreview(src: string, e: MouseEvent) {
|
function showImgPreview(src: string, e: MouseEvent) {
|
||||||
const el = getImgPreview()
|
const el = getImgPreview()
|
||||||
|
__imgPreviewTarget = e.currentTarget instanceof HTMLElement ? e.currentTarget : null
|
||||||
const imgEl = el.querySelector('img') as HTMLImageElement
|
const imgEl = el.querySelector('img') as HTMLImageElement
|
||||||
imgEl.onerror = () => {
|
imgEl.onerror = () => {
|
||||||
imgEl.onerror = null
|
imgEl.onerror = null
|
||||||
|
|
@ -132,13 +168,6 @@ function showImgPreview(src: string, e: MouseEvent) {
|
||||||
el.style.opacity = '1'
|
el.style.opacity = '1'
|
||||||
}
|
}
|
||||||
|
|
||||||
function hideImgPreview() {
|
|
||||||
if (__imgPreviewEl) {
|
|
||||||
__imgPreviewEl.style.opacity = '0'
|
|
||||||
__imgPreviewEl.style.display = 'none'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const cellTemplateImage = (
|
const cellTemplateImage = (
|
||||||
cellElement: HTMLElement,
|
cellElement: HTMLElement,
|
||||||
cellInfo: DataGridTypes.ColumnCellTemplateData<any, any>,
|
cellInfo: DataGridTypes.ColumnCellTemplateData<any, any>,
|
||||||
|
|
@ -166,7 +195,10 @@ const cellTemplateImage = (
|
||||||
img.addEventListener('mouseenter', (e) => showImgPreview(url, e as MouseEvent))
|
img.addEventListener('mouseenter', (e) => showImgPreview(url, e as MouseEvent))
|
||||||
img.addEventListener('mousemove', (e) => showImgPreview(url, e as MouseEvent))
|
img.addEventListener('mousemove', (e) => showImgPreview(url, e as MouseEvent))
|
||||||
img.addEventListener('mouseleave', hideImgPreview)
|
img.addEventListener('mouseleave', hideImgPreview)
|
||||||
img.addEventListener('click', () => openImageSource(url))
|
img.addEventListener('click', () => {
|
||||||
|
hideImgPreview()
|
||||||
|
openImageSource(url)
|
||||||
|
})
|
||||||
|
|
||||||
cellElement.appendChild(img)
|
cellElement.appendChild(img)
|
||||||
})
|
})
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue