From f5315a4aca7996cbd072375f0e383ca433af40cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sedat=20=C3=96ZT=C3=9CRK?= <76204082+iamsedatozturk@users.noreply.github.com> Date: Tue, 2 Dec 2025 21:15:09 +0300 Subject: [PATCH] Scheduler --- .../GridOptionsDto/GridOptionsDto.cs | 13 + .../GridOptionsDto/SchedulerOptionDto.cs | 27 ++ .../ListForms/ListFormEditTabs.cs | 1 + .../Administration/ListFormsAppService.cs | 4 + .../Seeds/LanguagesData.json | 6 + .../Entities/Host/ListForm.cs | 1 + ui/src/proxy/admin/list-form/options.ts | 2 + ui/src/proxy/form/models.ts | 29 ++ ui/src/views/admin/listForm/edit/FormEdit.tsx | 7 + .../admin/listForm/edit/FormTabScheduler.tsx | 399 ++++++++++++++++++ ui/src/views/admin/listForm/edit/types.ts | 3 +- ui/src/views/list/List.tsx | 30 +- ui/src/views/list/SchedulerView.tsx | 264 ++++++++++++ .../views/list/useListFormCustomDataSource.ts | 2 + 14 files changed, 784 insertions(+), 4 deletions(-) create mode 100644 api/src/Erp.Platform.Application.Contracts/ListForms/GridOptionsDto/SchedulerOptionDto.cs create mode 100644 ui/src/views/admin/listForm/edit/FormTabScheduler.tsx create mode 100644 ui/src/views/list/SchedulerView.tsx diff --git a/api/src/Erp.Platform.Application.Contracts/ListForms/GridOptionsDto/GridOptionsDto.cs b/api/src/Erp.Platform.Application.Contracts/ListForms/GridOptionsDto/GridOptionsDto.cs index e58299c8..60b4ddd8 100644 --- a/api/src/Erp.Platform.Application.Contracts/ListForms/GridOptionsDto/GridOptionsDto.cs +++ b/api/src/Erp.Platform.Application.Contracts/ListForms/GridOptionsDto/GridOptionsDto.cs @@ -177,6 +177,19 @@ public class GridOptionsDto : AuditedEntityDto set { GanttOptionJson = JsonSerializer.Serialize(value); } } + [JsonIgnore] + public string SchedulerOptionJson { get; set; } + public SchedulerOptionDto SchedulerOptionDto + { + get + { + if (!string.IsNullOrEmpty(SchedulerOptionJson)) + return JsonSerializer.Deserialize(SchedulerOptionJson); + return new SchedulerOptionDto(); + } + set { SchedulerOptionJson = JsonSerializer.Serialize(value); } + } + [JsonIgnore] public string PagerOptionJson { get; set; } public GridPagerOptionDto PagerOptionDto diff --git a/api/src/Erp.Platform.Application.Contracts/ListForms/GridOptionsDto/SchedulerOptionDto.cs b/api/src/Erp.Platform.Application.Contracts/ListForms/GridOptionsDto/SchedulerOptionDto.cs new file mode 100644 index 00000000..581ef8eb --- /dev/null +++ b/api/src/Erp.Platform.Application.Contracts/ListForms/GridOptionsDto/SchedulerOptionDto.cs @@ -0,0 +1,27 @@ +namespace Erp.Platform.ListForms; + +/// +/// TreeList için özel ayarları içerir +/// +public class SchedulerOptionDto +{ + /// + /// Text olarak gösterilecek field adı (örn: "title") + /// + public string TextField { get; set; } + /// + /// Başlangıç tarihinin tutulduğu field adı (örn: "startDate") + /// + public string StartDateField { get; set; } + + /// + /// Bitiş tarihinin tutulduğu field adı (örn: "endDate") + /// + public string EndDateField { get; set; } + + /// + /// Tüm gün etkinlikler için kullanılan field adı (örn: "allDay") + /// + public string AllDayField { get; set; } +} + diff --git a/api/src/Erp.Platform.Application.Contracts/ListForms/ListFormEditTabs.cs b/api/src/Erp.Platform.Application.Contracts/ListForms/ListFormEditTabs.cs index d0407d0a..92f86984 100644 --- a/api/src/Erp.Platform.Application.Contracts/ListForms/ListFormEditTabs.cs +++ b/api/src/Erp.Platform.Application.Contracts/ListForms/ListFormEditTabs.cs @@ -48,6 +48,7 @@ public class ListFormEditTabs public const string PivotForm = "pivot"; public const string TreeForm = "tree"; public const string GanttForm = "gantt"; + public const string SchedulerForm = "scheduler"; public const string PagerForm = "pager"; public const string StateForm = "state"; public const string SubFormJsonRow = "subForm"; diff --git a/api/src/Erp.Platform.Application/ListForms/Administration/ListFormsAppService.cs b/api/src/Erp.Platform.Application/ListForms/Administration/ListFormsAppService.cs index 8d2ce695..50e082d7 100644 --- a/api/src/Erp.Platform.Application/ListForms/Administration/ListFormsAppService.cs +++ b/api/src/Erp.Platform.Application/ListForms/Administration/ListFormsAppService.cs @@ -154,6 +154,10 @@ public class ListFormsAppService : CrudAppService< else if (input.EditType == ListFormEditTabs.GanttForm) { item.GanttOptionJson = JsonSerializer.Serialize(input.GanttOptionDto); + } + else if (input.EditType == ListFormEditTabs.SchedulerForm) + { + item.SchedulerOptionJson = JsonSerializer.Serialize(input.SchedulerOptionDto); } else if (input.EditType == ListFormEditTabs.PagerForm) { diff --git a/api/src/Erp.Platform.DbMigrator/Seeds/LanguagesData.json b/api/src/Erp.Platform.DbMigrator/Seeds/LanguagesData.json index fb22c7b7..1411341f 100644 --- a/api/src/Erp.Platform.DbMigrator/Seeds/LanguagesData.json +++ b/api/src/Erp.Platform.DbMigrator/Seeds/LanguagesData.json @@ -3607,6 +3607,12 @@ "en": "Gantt", "tr": "Gantt" }, + { + "resourceName": "Platform", + "key": "ListForms.ListFormEdit.TabScheduler", + "en": "Scheduler", + "tr": "Zamanlayıcı" + }, { "resourceName": "Platform", "key": "ListForms.ListFormEdit.TabDetails", diff --git a/api/src/Erp.Platform.Domain/Entities/Host/ListForm.cs b/api/src/Erp.Platform.Domain/Entities/Host/ListForm.cs index 0859b8e4..88f5a2e1 100644 --- a/api/src/Erp.Platform.Domain/Entities/Host/ListForm.cs +++ b/api/src/Erp.Platform.Domain/Entities/Host/ListForm.cs @@ -35,6 +35,7 @@ public class ListForm : FullAuditedEntity public string PivotOptionJson { get; set; } public string TreeOptionJson { get; set; } // Tree yapisi ile ilgili ayarlar public string GanttOptionJson { get; set; } // Gantt yapisi ile ilgili ayarlar + public string SchedulerOptionJson { get; set; } // Scheduler yapisi ile ilgili ayarlar public string FilterRowJson { get; set; } // Filtre ayarlari, Json olarak tutulur, donus sinifi FilterRowDto public string RowJson { get; set; } // Row ayarları, Json olarak tutulur, donus sinifi FilterRowDto public string HeaderFilterJson { get; set; } // Header filtreleme ayarlari, Json olarak tutulur diff --git a/ui/src/proxy/admin/list-form/options.ts b/ui/src/proxy/admin/list-form/options.ts index 1c5e05f4..33ab54a8 100644 --- a/ui/src/proxy/admin/list-form/options.ts +++ b/ui/src/proxy/admin/list-form/options.ts @@ -43,6 +43,7 @@ export const ListFormEditTabs = { PivotForm: 'pivot', TreeForm: 'tree', GanttForm: 'gantt', + SchedulerForm: 'scheduler', PagerForm: 'pager', StateForm: 'state', SubForm: 'subForm', @@ -92,6 +93,7 @@ export const tabVisibilityConfig: Record = { 'pivots', 'tree', 'gantt', + 'scheduler', 'pager', 'state', 'extrafilter', diff --git a/ui/src/proxy/form/models.ts b/ui/src/proxy/form/models.ts index d23e034a..13a4b748 100644 --- a/ui/src/proxy/form/models.ts +++ b/ui/src/proxy/form/models.ts @@ -404,6 +404,32 @@ export interface GanttOptionDto { scaleType: GanttScaleType } +export interface SchedulerOptionDto { + textExpr?: string + startDateExpr?: string + endDateExpr?: string + allDayExpr?: string + recurrenceRuleExpr?: string + recurrenceExceptionExpr?: string + startDayHour?: number + endDayHour?: number + defaultView?: string + showAllDayPanel?: boolean + crossScrollingEnabled?: boolean + cellDuration?: number + firstDayOfWeek?: number + allowResizing?: boolean + allowDragging?: boolean + resources?: SchedulerResourceDto[] +} + +export interface SchedulerResourceDto { + fieldExpr?: string + dataSource?: any[] + label?: string + useColorAsDefault?: boolean +} + export interface GridEditingDto { mode?: GridsEditMode refreshMode?: GridsEditRefreshMode @@ -504,6 +530,8 @@ export interface GridOptionsDto extends AuditedEntityDto { treeOptionDto: TreeOptionDto ganttOptionJson?: string ganttOptionDto: GanttOptionDto + schedulerOptionJson?: string + schedulerOptionDto: SchedulerOptionDto pagerOptionJson?: string pagerOptionDto: GridPagerOptionDto editingOptionJson?: string @@ -851,6 +879,7 @@ export interface LayoutDto { tree: boolean chart: boolean gantt: boolean + scheduler: boolean defaultLayout: ListViewLayoutType cardLayoutColumn: number } diff --git a/ui/src/views/admin/listForm/edit/FormEdit.tsx b/ui/src/views/admin/listForm/edit/FormEdit.tsx index 76a8b427..3763b80e 100644 --- a/ui/src/views/admin/listForm/edit/FormEdit.tsx +++ b/ui/src/views/admin/listForm/edit/FormEdit.tsx @@ -51,6 +51,7 @@ import { tabVisibilityConfig } from '@/proxy/admin/list-form/options' import FormTabSorting from './FormTabSorting' import FormTabRow from './FormTabRow' import FormTabGantt from './FormTabGantt' +import FormTabScheduler from './FormTabScheduler' export interface FormEditProps { onSubmit: ( @@ -260,6 +261,9 @@ const FormEdit = () => { {visibleTabs.includes('gantt') && ( {translate('::ListForms.ListFormEdit.TabGantt')} )} + {visibleTabs.includes('scheduler') && ( + {translate('::ListForms.ListFormEdit.TabScheduler')} + )} {visibleTabs.includes('subForms') && ( {translate('::ListForms.ListFormEdit.SubForms')} )} @@ -367,6 +371,9 @@ const FormEdit = () => { + + + diff --git a/ui/src/views/admin/listForm/edit/FormTabScheduler.tsx b/ui/src/views/admin/listForm/edit/FormTabScheduler.tsx new file mode 100644 index 00000000..1d33c4ae --- /dev/null +++ b/ui/src/views/admin/listForm/edit/FormTabScheduler.tsx @@ -0,0 +1,399 @@ +import { + Button, + Notification, + Checkbox, + FormContainer, + FormItem, + Input, + Select, + toast, + Card, +} from '@/components/ui' +import { ListFormEditTabs } from '@/proxy/admin/list-form/options' +import { useStoreState } from '@/store' +import { useLocalization } from '@/utils/hooks/useLocalization' +import { Field, FieldProps, Form, Formik } from 'formik' +import * as Yup from 'yup' +import { FormEditProps } from './FormEdit' +import { SelectBoxOption } from '@/types/shared' +import { useEffect, useState } from 'react' +import { getListFormFields } from '@/services/admin/list-form-field.service' +import { groupBy } from 'lodash' +import { useParams } from 'react-router-dom' + +const validationSchema = Yup.object().shape({}) + +const schedulerViewOptions = [ + { value: 'day', label: 'Day' }, + { value: 'week', label: 'Week' }, + { value: 'workWeek', label: 'Work Week' }, + { value: 'month', label: 'Month' }, + { value: 'timelineDay', label: 'Timeline Day' }, + { value: 'timelineWeek', label: 'Timeline Week' }, + { value: 'timelineMonth', label: 'Timeline Month' }, + { value: 'agenda', label: 'Agenda' }, +] + +const firstDayOfWeekOptions = [ + { value: 0, label: 'Sunday' }, + { value: 1, label: 'Monday' }, + { value: 2, label: 'Tuesday' }, + { value: 3, label: 'Wednesday' }, + { value: 4, label: 'Thursday' }, + { value: 5, label: 'Friday' }, + { value: 6, label: 'Saturday' }, +] + +function FormTabScheduler(props: FormEditProps) { + const { listFormCode } = useParams() + const { translate } = useLocalization() + const [fieldList, setFieldList] = useState([]) + + const getFields = async () => { + if (!listFormCode) { + return + } + + try { + const resp = await getListFormFields({ + listFormCode, + sorting: 'ListOrderNo', + maxResultCount: 1000, + }) + if (resp.data?.items) { + const fieldNames = groupBy(resp?.data?.items, 'fieldName') + setFieldList( + Object.keys(fieldNames).map((a) => ({ + value: a, + label: a, + })), + ) + } + } catch (error: any) { + toast.push( + + Alanlar getirilemedi + {error.toString()} + , + { + placement: 'top-end', + }, + ) + } + } + + useEffect(() => { + getFields() + }, [listFormCode]) + + const listFormValues = useStoreState((s) => s.admin.lists.values) + if (!listFormValues) { + return null + } + + return ( + { + await props.onSubmit(ListFormEditTabs.SchedulerForm, values, formikHelpers) + }} + > + {({ touched, errors, isSubmitting, values }) => ( +
+ +
+ +
{translate('::SchedulerOptions.BasicSettings')}
+ + + + {({ field, form }: FieldProps) => ( + option.value === values.schedulerOptionDto?.startDateExpr, + )} + /> + )} + + + + + + {({ field, form }: FieldProps) => ( + option.value === values.schedulerOptionDto?.allDayExpr, + )} + /> + )} + + +
+ + +
{translate('::SchedulerOptions.RecurrenceSettings')}
+ + + + {({ field, form }: FieldProps) => ( + + option.value === values.schedulerOptionDto?.recurrenceExceptionExpr, + )} + /> + )} + + +
+ + +
{translate('::SchedulerOptions.ViewSettings')}
+ + + + {({ field, form }: FieldProps) => ( + option.value === values.schedulerOptionDto?.firstDayOfWeek, + )} + /> + )} + + + + + + {({ field, form }: FieldProps) => ( + + )} + + + + + + {({ field, form }: FieldProps) => ( + + )} + + + + + + {({ field, form }: FieldProps) => ( + + )} + + +
+ + +
{translate('::SchedulerOptions.InteractionSettings')}
+ + + + {({ field, form }: FieldProps) => ( + + {translate('::SchedulerOptions.ShowAllDayPanel')} + + )} + + + + + + {({ field, form }: FieldProps) => ( + + {translate('::SchedulerOptions.CrossScrollingEnabled')} + + )} + + + + + + {({ field, form }: FieldProps) => ( + + {translate('::SchedulerOptions.AllowResizing')} + + )} + + + + + + {({ field, form }: FieldProps) => ( + + {translate('::SchedulerOptions.AllowDragging')} + + )} + + +
+
+ + + +
+
+ )} +
+ ) +} + +export default FormTabScheduler diff --git a/ui/src/views/admin/listForm/edit/types.ts b/ui/src/views/admin/listForm/edit/types.ts index 895f7eda..9ff6a6a0 100644 --- a/ui/src/views/admin/listForm/edit/types.ts +++ b/ui/src/views/admin/listForm/edit/types.ts @@ -1,6 +1,6 @@ export type ChartOperation = '' | 'select' | 'insert' | 'update' | 'delete' export type ChartDialogType = '' | 'pane' | 'serie' | 'annotation' | 'axis' -export type ListViewLayoutType = 'grid' | 'card' | 'pivot' | 'tree' | 'chart' | 'gantt' +export type ListViewLayoutType = 'grid' | 'card' | 'pivot' | 'tree' | 'chart' | 'gantt' | 'scheduler' export const layoutTypes = { grid: 'Grid', @@ -9,4 +9,5 @@ export const layoutTypes = { tree: 'Tree', chart: 'Chart', gantt: 'Gantt', + scheduler: 'Scheduler', } diff --git a/ui/src/views/list/List.tsx b/ui/src/views/list/List.tsx index b11cfaa5..4e1c3d65 100644 --- a/ui/src/views/list/List.tsx +++ b/ui/src/views/list/List.tsx @@ -2,7 +2,7 @@ import { useParams, useSearchParams } from 'react-router-dom' import { useEffect, useState } from 'react' import Container from '@/components/shared/Container' import Grid from './Grid' -import { FaChartArea, FaList, FaSitemap, FaTable, FaTh, FaUser } from 'react-icons/fa' +import { FaChartArea, FaList, FaSitemap, FaTable, FaTh, FaUser, FaCalendarAlt } from 'react-icons/fa' import { useStoreActions, useStoreState } from '@/store/store' import classNames from 'classnames' import { useLocalization } from '@/utils/hooks/useLocalization' @@ -17,6 +17,7 @@ import Chart from './Chart' import Card from './Card' import { FaChartGantt } from 'react-icons/fa6' import GanttView from './GanttView' +import SchedulerView from './SchedulerView' const List = () => { const params = useParams() @@ -95,9 +96,25 @@ const List = () => { )}
+ {gridDto?.gridOptions?.layoutDto.scheduler && + gridDto?.gridOptions?.schedulerOptionDto?.textExpr && + gridDto?.gridOptions?.schedulerOptionDto?.startDateExpr && ( + + )} + {gridDto?.gridOptions?.layoutDto.gantt && - gridDto?.gridOptions?.treeOptionDto?.parentIdExpr && - gridDto?.gridOptions?.treeOptionDto?.titleExpr && ( + gridDto?.gridOptions?.ganttOptionDto?.parentIdExpr && + gridDto?.gridOptions?.ganttOptionDto?.titleExpr && (