Chart komponenti düzenlemesi

This commit is contained in:
Sedat ÖZTÜRK 2025-09-30 16:11:23 +03:00
parent ae9ce38478
commit e3a8165499
21 changed files with 823 additions and 247 deletions

View file

@ -91,11 +91,6 @@ public class ChartSeriesDto
/// FullStackedBarSeries,BubbleSeries,
/// </summary>
public string ValueField { get; set; }
/// <summary> Değer özetleme işlevini belirtir.
/// Accepted Values: 'avg' | 'count' | 'custom' | 'max' | 'min' | 'sum'
/// Default Value: 'sum'
/// </summary>
public string SummaryType { get; set; } = "sum";
/// <summary> Serinin görünür olup olmayacağını belirtir.
/// </summary>
public bool Visible { get; set; } = true;
@ -126,4 +121,12 @@ public class ChartSeriesDto
// valueErrorBar
public ChartLabelDto Label { get; set; }
/// <summary> Değer özetleme işlevini belirtir.
/// Accepted Values: 'avg' | 'count' | 'custom' | 'max' | 'min' | 'sum'
/// Default Value: 'sum'
/// </summary>
public string SummaryType { get; set; } = "sum";
/// <example>'Kullanıcı Adı'</example>
public string UserId { get; set; }
}

View file

@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.Json;
using System.Threading.Tasks;
using Kurs.Platform.Entities;
@ -8,6 +9,7 @@ using Kurs.Platform.Queries;
using Microsoft.AspNetCore.Authorization;
using Volo.Abp;
using Volo.Abp.Domain.Repositories;
using Volo.Abp.Users;
using static Kurs.Platform.PlatformConsts;
namespace Kurs.Platform.ListForms.Administration;
@ -19,37 +21,121 @@ namespace Kurs.Platform.ListForms.Administration;
public class ListFormJsonRowAppService : PlatformAppService
{
private readonly IRepository<ListForm, Guid> repository;
private readonly ICurrentUser currentUser;
private readonly string userId;
public ListFormJsonRowAppService(
IRepository<ListForm, Guid> _repository) : base()
IRepository<ListForm, Guid> _repository,
ICurrentUser _currentUser
) : base()
{
repository = _repository;
currentUser = _currentUser;
userId = currentUser.Name;
}
public async Task<dynamic> GetAllAsync(Guid id, string field)
{
var listForm = await GetAsync(id);
return field switch
switch (field)
{
ListFormEditTabs.Database.Select.SelectFieldsDefaultValuesJsonRow => listForm.SelectFieldsDefaultValueJson.IsNullOrWhiteSpace() ? [] : JsonSerializer.Deserialize<List<FieldsDefaultValueDto>>(listForm.SelectFieldsDefaultValueJson),
ListFormEditTabs.Database.Insert.InsertFieldsDefaultValuesJsonRow => listForm.InsertFieldsDefaultValueJson.IsNullOrWhiteSpace() ? [] : JsonSerializer.Deserialize<List<FieldsDefaultValueDto>>(listForm.InsertFieldsDefaultValueJson),
ListFormEditTabs.Database.Update.UpdateFieldsDefaultValuesJsonRow => listForm.UpdateFieldsDefaultValueJson.IsNullOrWhiteSpace() ? [] : JsonSerializer.Deserialize<List<FieldsDefaultValueDto>>(listForm.UpdateFieldsDefaultValueJson),
ListFormEditTabs.Database.Delete.DeleteFieldsDefaultValuesJsonRow => listForm.DeleteFieldsDefaultValueJson.IsNullOrWhiteSpace() ? [] : JsonSerializer.Deserialize<List<FieldsDefaultValueDto>>(listForm.DeleteFieldsDefaultValueJson),
ListFormEditTabs.Database.Insert.FormFieldsDefaultValuesJsonRow => listForm.FormFieldsDefaultValueJson.IsNullOrWhiteSpace() ? [] : JsonSerializer.Deserialize<List<FieldsDefaultValueDto>>(listForm.FormFieldsDefaultValueJson),
ListFormEditTabs.Edit.EditingFormFieldsJsonRow => listForm.EditingFormJson.IsNullOrWhiteSpace() ? [] : JsonSerializer.Deserialize<List<EditingFormDto>>(listForm.EditingFormJson),
ListFormEditTabs.CommandColumnsJsonRow => listForm.CommandColumnJson.IsNullOrWhiteSpace() ? [] : JsonSerializer.Deserialize<List<CommandColumnDto>>(listForm.CommandColumnJson),
ListFormEditTabs.SubFormJsonRow => listForm.SubFormsJson.IsNullOrWhiteSpace() ? [] : JsonSerializer.Deserialize<List<SubFormDto>>(listForm.SubFormsJson),
ListFormEditTabs.WidgetForm => listForm.WidgetsJson.IsNullOrWhiteSpace() ? [] : JsonSerializer.Deserialize<List<WidgetEditDto>>(listForm.WidgetsJson),
ListFormEditTabs.ExtraFilterForm => listForm.ExtraFilterJson.IsNullOrWhiteSpace() ? [] : JsonSerializer.Deserialize<List<ExtraFilterEditDto>>(listForm.ExtraFilterJson),
case ListFormEditTabs.Database.Select.SelectFieldsDefaultValuesJsonRow:
return listForm.SelectFieldsDefaultValueJson.IsNullOrWhiteSpace()
? []
: JsonSerializer.Deserialize<List<FieldsDefaultValueDto>>(listForm.SelectFieldsDefaultValueJson) ?? [];
ListFormEditTabs.ChartSeries.GeneralJsonRow => listForm.SeriesJson.IsNullOrWhiteSpace() ? [] : JsonSerializer.Deserialize<List<ChartSeriesDto>>(listForm.SeriesJson),
ListFormEditTabs.ChartAxis.ValueAxisJsonRow => listForm.ValueAxisJson.IsNullOrWhiteSpace() ? [] : JsonSerializer.Deserialize<List<ChartValueAxisDto>>(listForm.ValueAxisJson),
ListFormEditTabs.ChartPanes.PanesJsonRow => listForm.PanesJson.IsNullOrWhiteSpace() ? [] : JsonSerializer.Deserialize<List<ChartPanesDto>>(listForm.PanesJson),
ListFormEditTabs.ChartAnnotations.GeneralJsonRow => listForm.AnnotationsJson.IsNullOrWhiteSpace() ? [] : JsonSerializer.Deserialize<List<ChartAnnotationDto>>(listForm.AnnotationsJson),
case ListFormEditTabs.Database.Insert.InsertFieldsDefaultValuesJsonRow:
return listForm.InsertFieldsDefaultValueJson.IsNullOrWhiteSpace()
? []
: JsonSerializer.Deserialize<List<FieldsDefaultValueDto>>(listForm.InsertFieldsDefaultValueJson) ?? [];
_ => throw new UserFriendlyException(L[AppErrorCodes.ParameterNotValid]),
};
case ListFormEditTabs.Database.Update.UpdateFieldsDefaultValuesJsonRow:
return listForm.UpdateFieldsDefaultValueJson.IsNullOrWhiteSpace()
? []
: JsonSerializer.Deserialize<List<FieldsDefaultValueDto>>(listForm.UpdateFieldsDefaultValueJson) ?? [];
case ListFormEditTabs.Database.Delete.DeleteFieldsDefaultValuesJsonRow:
return listForm.DeleteFieldsDefaultValueJson.IsNullOrWhiteSpace()
? []
: JsonSerializer.Deserialize<List<FieldsDefaultValueDto>>(listForm.DeleteFieldsDefaultValueJson) ?? [];
case ListFormEditTabs.Database.Insert.FormFieldsDefaultValuesJsonRow:
return listForm.FormFieldsDefaultValueJson.IsNullOrWhiteSpace()
? []
: JsonSerializer.Deserialize<List<FieldsDefaultValueDto>>(listForm.FormFieldsDefaultValueJson) ?? [];
case ListFormEditTabs.Edit.EditingFormFieldsJsonRow:
return listForm.EditingFormJson.IsNullOrWhiteSpace()
? []
: JsonSerializer.Deserialize<List<EditingFormDto>>(listForm.EditingFormJson) ?? [];
case ListFormEditTabs.CommandColumnsJsonRow:
return listForm.CommandColumnJson.IsNullOrWhiteSpace()
? []
: JsonSerializer.Deserialize<List<CommandColumnDto>>(listForm.CommandColumnJson) ?? [];
case ListFormEditTabs.SubFormJsonRow:
return listForm.SubFormsJson.IsNullOrWhiteSpace()
? []
: JsonSerializer.Deserialize<List<SubFormDto>>(listForm.SubFormsJson) ?? [];
case ListFormEditTabs.WidgetForm:
return listForm.WidgetsJson.IsNullOrWhiteSpace()
? []
: JsonSerializer.Deserialize<List<WidgetEditDto>>(listForm.WidgetsJson) ?? [];
case ListFormEditTabs.ExtraFilterForm:
return listForm.ExtraFilterJson.IsNullOrWhiteSpace()
? []
: JsonSerializer.Deserialize<List<ExtraFilterEditDto>>(listForm.ExtraFilterJson) ?? [];
case ListFormEditTabs.ChartSeries.GeneralJsonRow:
return listForm.SeriesJson.IsNullOrWhiteSpace()
? []
: JsonSerializer.Deserialize<List<ChartSeriesDto>>(listForm.SeriesJson) ?? [];
case ListFormEditTabs.ChartAxis.ValueAxisJsonRow:
return listForm.ValueAxisJson.IsNullOrWhiteSpace()
? []
: JsonSerializer.Deserialize<List<ChartValueAxisDto>>(listForm.ValueAxisJson) ?? [];
case ListFormEditTabs.ChartPanes.PanesJsonRow:
return listForm.PanesJson.IsNullOrWhiteSpace()
? []
: JsonSerializer.Deserialize<List<ChartPanesDto>>(listForm.PanesJson) ?? [];
case ListFormEditTabs.ChartAnnotations.GeneralJsonRow:
return listForm.AnnotationsJson.IsNullOrWhiteSpace()
? []
: JsonSerializer.Deserialize<List<ChartAnnotationDto>>(listForm.AnnotationsJson) ?? [];
default:
throw new UserFriendlyException(L[AppErrorCodes.ParameterNotValid]);
}
// return field switch
// {
// ListFormEditTabs.Database.Select.SelectFieldsDefaultValuesJsonRow => listForm.SelectFieldsDefaultValueJson.IsNullOrWhiteSpace() ? [] : JsonSerializer.Deserialize<List<FieldsDefaultValueDto>>(listForm.SelectFieldsDefaultValueJson),
// ListFormEditTabs.Database.Insert.InsertFieldsDefaultValuesJsonRow => listForm.InsertFieldsDefaultValueJson.IsNullOrWhiteSpace() ? [] : JsonSerializer.Deserialize<List<FieldsDefaultValueDto>>(listForm.InsertFieldsDefaultValueJson),
// ListFormEditTabs.Database.Update.UpdateFieldsDefaultValuesJsonRow => listForm.UpdateFieldsDefaultValueJson.IsNullOrWhiteSpace() ? [] : JsonSerializer.Deserialize<List<FieldsDefaultValueDto>>(listForm.UpdateFieldsDefaultValueJson),
// ListFormEditTabs.Database.Delete.DeleteFieldsDefaultValuesJsonRow => listForm.DeleteFieldsDefaultValueJson.IsNullOrWhiteSpace() ? [] : JsonSerializer.Deserialize<List<FieldsDefaultValueDto>>(listForm.DeleteFieldsDefaultValueJson),
// ListFormEditTabs.Database.Insert.FormFieldsDefaultValuesJsonRow => listForm.FormFieldsDefaultValueJson.IsNullOrWhiteSpace() ? [] : JsonSerializer.Deserialize<List<FieldsDefaultValueDto>>(listForm.FormFieldsDefaultValueJson),
// ListFormEditTabs.Edit.EditingFormFieldsJsonRow => listForm.EditingFormJson.IsNullOrWhiteSpace() ? [] : JsonSerializer.Deserialize<List<EditingFormDto>>(listForm.EditingFormJson),
// ListFormEditTabs.CommandColumnsJsonRow => listForm.CommandColumnJson.IsNullOrWhiteSpace() ? [] : JsonSerializer.Deserialize<List<CommandColumnDto>>(listForm.CommandColumnJson),
// ListFormEditTabs.SubFormJsonRow => listForm.SubFormsJson.IsNullOrWhiteSpace() ? [] : JsonSerializer.Deserialize<List<SubFormDto>>(listForm.SubFormsJson),
// ListFormEditTabs.WidgetForm => listForm.WidgetsJson.IsNullOrWhiteSpace() ? [] : JsonSerializer.Deserialize<List<WidgetEditDto>>(listForm.WidgetsJson),
// ListFormEditTabs.ExtraFilterForm => listForm.ExtraFilterJson.IsNullOrWhiteSpace() ? [] : JsonSerializer.Deserialize<List<ExtraFilterEditDto>>(listForm.ExtraFilterJson),
// ListFormEditTabs.ChartSeries.GeneralJsonRow => listForm.SeriesJson.IsNullOrWhiteSpace() ? [] : JsonSerializer.Deserialize<List<ChartSeriesDto>>(listForm.SeriesJson),
// ListFormEditTabs.ChartAxis.ValueAxisJsonRow => listForm.ValueAxisJson.IsNullOrWhiteSpace() ? [] : JsonSerializer.Deserialize<List<ChartValueAxisDto>>(listForm.ValueAxisJson),
// ListFormEditTabs.ChartPanes.PanesJsonRow => listForm.PanesJson.IsNullOrWhiteSpace() ? [] : JsonSerializer.Deserialize<List<ChartPanesDto>>(listForm.PanesJson),
// ListFormEditTabs.ChartAnnotations.GeneralJsonRow => listForm.AnnotationsJson.IsNullOrWhiteSpace() ? [] : JsonSerializer.Deserialize<List<ChartAnnotationDto>>(listForm.AnnotationsJson),
// _ => throw new UserFriendlyException(L[AppErrorCodes.ParameterNotValid]),
// };
}
public async Task CreateAsync(Guid id, CrudFieldsDefaultValueJsonItemDto model)

View file

@ -90,6 +90,10 @@ public class ChartSeries : ValueObject
[JsonPropertyName("Label")]
public ChartLabel Label { get; private set; } = new();
[JsonInclude]
[JsonPropertyName("UserId")]
public string UserId { get; private set; }
// JSON + EF Core için parametresiz public ctor
public ChartSeries() { }
@ -116,5 +120,6 @@ public class ChartSeries : ValueObject
yield return Visible;
yield return Width;
yield return Label;
yield return UserId;
}
}

View file

@ -766,8 +766,8 @@ public class SelectQueryManager : PlatformDomainService, ISelectQueryManager
var seriesList = JsonSerializer.Deserialize<List<ChartSeries>>(listform.SeriesJson);
if (seriesList == null || !seriesList.Any())
throw new ArgumentException("Series list is empty!");
if (seriesList == null || seriesList.Count == 0)
return null;
// ArgumentField listesi
var argumentFields = seriesList.Select(s => s.ArgumentField).Distinct().ToList();

View file

@ -1,5 +1,5 @@
import { AuditedEntityDto } from '@/proxy/abp'
import { PermissionCrudDto } from '@/proxy/form/models'
import { PermissionCrudDto, SummaryTypeEnum } from '@/proxy/form/models'
export interface BreakDto {
endValue: number
@ -299,6 +299,7 @@ export interface ChartScrollBarDto {
}
export interface ChartSeriesDto {
index: number
argumentField?: string
axis?: string
barOverlapGroup?: string
@ -316,10 +317,11 @@ export interface ChartSeriesDto {
showInLegend: boolean
type?: string
valueField?: string
summaryType?: string
summaryType?: SummaryTypeEnum
visible: boolean
width: number
label: ChartLabelDto
userId?: string
}
export interface ChartSizeDto {

View file

@ -44,6 +44,7 @@ import {
ChartZoomAndPanDto,
} from '../admin/charts/models'
import { ListViewLayoutType } from '@/views/admin/listForm/edit/types'
import { SeriesType } from 'devextreme/common/charts'
//1
export interface SelectListItem {
@ -367,30 +368,7 @@ export interface GridPivotOptionDto {
showFilterFields: boolean
showChart: boolean
chartHeight: number
chartCommonSeriesType:
| 'area'
| 'bar'
| 'bubble'
| 'candlestick'
| 'fullstackedarea'
| 'fullstackedbar'
| 'fullstackedline'
| 'fullstackedspline'
| 'fullstackedsplinearea'
| 'line'
| 'rangearea'
| 'rangebar'
| 'scatter'
| 'spline'
| 'splinearea'
| 'stackedarea'
| 'stackedbar'
| 'stackedline'
| 'stackedspline'
| 'stackedsplinearea'
| 'steparea'
| 'stepline'
| 'stock'
chartCommonSeriesType: SeriesType
}
export interface GridEditingDto {

View file

@ -10,6 +10,7 @@ import {
Tabs,
Notification,
toast,
Badge,
} from '@/components/ui'
import TBody from '@/components/ui/Table/TBody'
import THead from '@/components/ui/Table/THead'
@ -153,6 +154,7 @@ function ChartTabSeries(props: FormEditProps & { listFormCode: string }) {
}}
/>
</Th>
<Th></Th>
<Th>Type</Th>
<Th>Name</Th>
<Th>Argument Field</Th>
@ -204,6 +206,7 @@ function ChartTabSeries(props: FormEditProps & { listFormCode: string }) {
/>
</div>
</Td>
<Td>{row.userId && <Badge content={row.userId} />}</Td>
<Td>{row.type}</Td>
<Td>{row.name}</Td>
<Td>{row.argumentField}</Td>
@ -320,7 +323,10 @@ function ChartTabSeries(props: FormEditProps & { listFormCode: string }) {
<FormItem
label="Argument Field"
invalid={errors.commonSeriesSettingsDto?.argumentField && touched.commonSeriesSettingsDto?.argumentField}
invalid={
errors.commonSeriesSettingsDto?.argumentField &&
touched.commonSeriesSettingsDto?.argumentField
}
errorMessage={errors.commonSeriesSettingsDto?.argumentField}
>
<Field type="text" name="commonSeriesSettingsDto.argumentField">
@ -331,7 +337,10 @@ function ChartTabSeries(props: FormEditProps & { listFormCode: string }) {
form={form}
isClearable={true}
options={fieldList}
value={fieldList.find((option) => option.value === values.commonSeriesSettingsDto.argumentField)}
value={fieldList.find(
(option) =>
option.value === values.commonSeriesSettingsDto.argumentField,
)}
onChange={(option) => form.setFieldValue(field.name, option?.value)}
menuPlacement="auto"
maxMenuHeight={150}
@ -342,7 +351,10 @@ function ChartTabSeries(props: FormEditProps & { listFormCode: string }) {
<FormItem
label="Value Field"
invalid={errors.commonSeriesSettingsDto?.valueField && touched.commonSeriesSettingsDto?.valueField}
invalid={
errors.commonSeriesSettingsDto?.valueField &&
touched.commonSeriesSettingsDto?.valueField
}
errorMessage={errors.commonSeriesSettingsDto?.valueField}
>
<Field type="text" name="valueField">
@ -353,7 +365,9 @@ function ChartTabSeries(props: FormEditProps & { listFormCode: string }) {
form={form}
isClearable={true}
options={fieldList}
value={fieldList.find((option) => option.value === values.commonSeriesSettingsDto.valueField)}
value={fieldList.find(
(option) => option.value === values.commonSeriesSettingsDto.valueField,
)}
onChange={(option) => form.setFieldValue(field.name, option?.value)}
menuPlacement="auto"
maxMenuHeight={150}

View file

@ -169,7 +169,7 @@ function JsonRowOpDialogAnnotation({
{({ touched, errors, values, isSubmitting }) => (
<Form>
<FormContainer size="sm">
<div className="max-h-96 overflow-y-auto p-2">
<div className="h-full overflow-y-auto p-2">
<Tabs defaultValue="annotations_general">
<TabList>
<TabNav value="annotations_general">General</TabNav>

View file

@ -185,7 +185,7 @@ function JsonRowOpDialogAxis({
return (
<Form>
<FormContainer size="sm">
<div className="max-h-96 overflow-y-auto p-2">
<div className="h-full overflow-y-auto p-2">
<FormItem
label="Visible"
invalid={errors.visible && touched.visible}

View file

@ -156,7 +156,7 @@ function JsonRowOpDialogCommand({
{({ touched, errors, values, isSubmitting }) => (
<Form>
<FormContainer size="sm">
<div className="max-h-96 overflow-y-auto p-2">
<div className="h-full overflow-y-auto p-2">
<FormItem
label="Button Position"
invalid={errors.buttonPosition && touched.buttonPosition}

View file

@ -142,7 +142,7 @@ function JsonRowOpDialogDatabase({
{({ touched, errors, values, isSubmitting }) => (
<Form>
<FormContainer size="sm">
<div className="max-h-96 overflow-y-auto p-2">
<div className="h-full overflow-y-auto p-2">
<FormItem
label="Field Name"
invalid={errors.fieldName && touched.fieldName}

View file

@ -197,7 +197,7 @@ function JsonRowOpDialogEditForm({
{({ touched, errors, values, isSubmitting }) => (
<Form>
<FormContainer size="sm">
<div className="max-h-[90vh] overflow-y-auto p-2">
<div className="h-full overflow-y-auto p-2">
<div className="grid grid-cols-5 gap-4 w-full">
<FormItem
label="Order"

View file

@ -8,7 +8,7 @@ import {
Select,
toast,
} from '@/components/ui'
import { ListFormJsonRowDto } from '@/proxy/admin/list-form/models'
import { ListFormJsonRowDto } from '@/proxy/admin/list-form/models'
import { SelectBoxOption } from '@/shared/types'
import { useStoreActions, useStoreState } from '@/store'
import { useLocalization } from '@/utils/hooks/useLocalization'
@ -177,7 +177,7 @@ function JsonRowOpDialogExtraFilter({
{({ touched, errors, values, isSubmitting }) => (
<Form>
<FormContainer size="sm">
<div className="max-h-full overflow-y-auto p-2">
<div className="h-full overflow-y-auto p-2">
<FormItem
label="Field Name"
invalid={errors.fieldName && touched.fieldName}

View file

@ -117,7 +117,7 @@ function JsonRowOpDialogPane({
{({ touched, errors, values, isSubmitting }) => (
<Form>
<FormContainer size="sm">
<div className="max-h-96 overflow-y-auto p-2">
<div className="h-full overflow-y-auto p-2">
<FormItem
label="Name"
invalid={errors.name && touched.name}

View file

@ -31,7 +31,7 @@ import {
chartSeriesTypeOptions,
columnSummaryTypeListOptions,
} from '../options'
import { ChartPanesDto, ChartSeriesDto, ChartValueAxisDto } from '@/proxy/admin/charts/models'
import { ChartPanesDto, ChartValueAxisDto } from '@/proxy/admin/charts/models'
import CreatableSelect from 'react-select/creatable'
const schema = object().shape({
@ -134,6 +134,7 @@ function JsonRowOpDialogSeries({
<Formik
initialValues={
data.chartSeriesValues ?? {
index: -1,
argumentField: '',
axis: '',
barOverlapGroup: '',
@ -204,7 +205,7 @@ function JsonRowOpDialogSeries({
{({ touched, errors, values, isSubmitting }) => (
<Form>
<FormContainer size="sm">
<div className="max-h-96 overflow-y-auto p-2">
<div className="h-full overflow-y-auto p-2">
<FormItem
label="Visible"
invalid={errors.visible && touched.visible}
@ -266,7 +267,6 @@ function JsonRowOpDialogSeries({
<Field type="text" name="argumentField">
{({ field, form }: FieldProps<SelectBoxOption>) => (
<Select
componentAs={CreatableSelect}
field={field}
form={form}
isClearable={true}
@ -290,7 +290,6 @@ function JsonRowOpDialogSeries({
<Field type="text" name="valueField">
{({ field, form }: FieldProps<SelectBoxOption>) => (
<Select
componentAs={CreatableSelect}
field={field}
form={form}
isClearable={true}
@ -306,10 +305,7 @@ function JsonRowOpDialogSeries({
<FormItem
label={translate('::ListForms.ListFormFieldEdit.PivotSettingSummaryType')}
invalid={
errors.summaryType &&
touched.summaryType
}
invalid={errors.summaryType && touched.summaryType}
errorMessage={errors.summaryType}
>
<Field
@ -327,8 +323,7 @@ function JsonRowOpDialogSeries({
isClearable={true}
options={columnSummaryTypeListOptions}
value={columnSummaryTypeListOptions.filter(
(option: any) =>
option.value === values.summaryType,
(option: any) => option.value === values.summaryType,
)}
onChange={(option) => form.setFieldValue(field.name, option?.value)}
/>

View file

@ -123,7 +123,7 @@ function JsonRowOpDialogSubForm({
{({ touched, errors, values, isSubmitting }) => (
<Form>
<FormContainer size="sm">
<div className="max-h-96 overflow-y-auto p-2">
<div className="h-full overflow-y-auto p-2">
<FormItem
label="Tab Title"
invalid={errors.tabTitle && touched.tabTitle}

View file

@ -135,7 +135,7 @@ function JsonRowOpDialogWidget({
{({ touched, errors, values, isSubmitting }) => (
<Form>
<FormContainer size="sm">
<div className="max-h-full overflow-y-auto p-2">
<div className="h-full overflow-y-auto p-2">
<FormItem
label="Column Gap (Sütun Boşluğu)"
invalid={errors.colGap && touched.colGap}

View file

@ -10,16 +10,27 @@ import { useParams, useSearchParams } from 'react-router-dom'
import { useListFormCustomDataSource } from '@/shared/useListFormCustomDataSource'
import { GridDto } from '@/proxy/form/models'
import { usePermission } from '@/utils/hooks/usePermission'
import { Button, FormContainer, FormItem, Input, toast, Notification, Dialog } from '@/components/ui'
import { Button, toast, Notification } from '@/components/ui'
import { ROUTES_ENUM } from '@/routes/route.constant'
import { usePWA } from '@/utils/hooks/usePWA'
import { FaCog, FaCrosshairs, FaMinus, FaPlus, FaSearch, FaSyncAlt } from 'react-icons/fa'
import { buildSeriesDto } from './Utils'
import { ChartSeriesDto } from '@/proxy/admin/charts/models'
import { Formik, Form, Field, FieldArray, useFormikContext } from 'formik' // sadece buradan Form
import { object, string, array } from 'yup'
import { SelectBoxOption } from '@/shared/types'
import { useStoreState } from '@/store/store'
import ChartSeriesDialog from './ChartSeriesDialog'
import { getListFormFields } from '@/services/admin/list-form-field.service'
import { groupBy } from 'lodash'
import { ListFormJsonRowDto } from '@/proxy/admin/list-form/models'
import { ListFormEditTabs } from '@/proxy/admin/list-form/options'
import {
deleteListFormJsonRow,
postListFormJsonRow,
putListFormJsonRow,
} from '@/services/admin/list-form.service'
interface ChartProps extends CommonProps, Meta {
id: string
listFormCode: string
filter?: string
isSubForm?: boolean
@ -30,11 +41,12 @@ interface ChartProps extends CommonProps, Meta {
}
const Chart = (props: ChartProps) => {
const { listFormCode, filter, isSubForm, level, gridDto } = props
// State UserId güncellemesi için
const { userName } = useStoreState((s) => s.auth.user)
const { id, listFormCode, filter, isSubForm, level, gridDto, refreshGridDto } = props
const { translate } = useLocalization()
const { checkPermission } = usePermission()
const isPwaMode = usePWA()
const [series, setSeries] = useState<ChartSeriesDto[]>([])
const initialized = useRef(false)
const [searchParams] = useSearchParams()
@ -44,38 +56,45 @@ const Chart = (props: ChartProps) => {
const params = useParams()
const _listFormCode = props?.listFormCode ?? params?.listFormCode ?? ''
const [openDialog, setOpenDialog] = useState(false)
const [fieldList, setFieldList] = useState<SelectBoxOption[]>([])
const [searchText, setSearchText] = useState('')
const [prevValue, setPrevValue] = useState('')
const [urlSearchParams, setUrlSearchParams] = useState<URLSearchParams>(
searchParams ? new URLSearchParams(searchParams) : new URLSearchParams(),
)
const schema = object().shape({
series: array().of(
object().shape({
name: string().required('Name Required'),
argumentField: string().required('Argument Field Required'),
valueField: string().required('Value Field Required'),
summaryType: string().required('Summary Type Required'),
}),
),
})
const [allSeries, setAllSeries] = useState<ChartSeriesDto[]>([])
const [userSeries, setUserSeries] = useState<ChartSeriesDto[]>([])
const [oldSeries, setOldSeries] = useState<ChartSeriesDto[]>([])
useEffect(() => {
if (gridDto && !initialized.current) {
const initialSeries = gridDto.gridOptions.seriesDto.map((s, index) => ({ ...s, index }))
setAllSeries(initialSeries)
setUserSeries(initialSeries.filter((s) => s.userId === userName))
setOldSeries(initialSeries.filter((s) => s.userId === userName))
initialized.current = true
}
}, [gridDto])
useEffect(() => {
if (!gridDto) return
if (!allSeries) return
if (!initialized.current) return
const seriesDto = userSeries.length > 0 ? userSeries : allSeries.length > 0 ? allSeries : []
const gridOptions = {
...gridDto.gridOptions,
seriesDto: series ?? gridDto.gridOptions.seriesDto,
seriesDto,
}
const dataSource = createSelectDataSource(
gridOptions,
listFormCode,
urlSearchParams,
[],
true,
)
const dataSource = createSelectDataSource(gridOptions, listFormCode, urlSearchParams, [], true)
const options = {
dataSource: dataSource,
@ -106,7 +125,7 @@ const Chart = (props: ChartProps) => {
valueAxis: gridDto.gridOptions.valueAxisDto,
tooltip: gridDto.gridOptions.tooltipDto,
series: buildSeriesDto(series ?? gridDto.gridOptions.seriesDto),
series: buildSeriesDto(seriesDto),
panes: gridDto.gridOptions.panesDto?.length > 0 ? gridDto.gridOptions.panesDto : undefined,
commonSeriesSettings: gridDto.gridOptions.commonSeriesSettingsDto,
@ -121,7 +140,7 @@ const Chart = (props: ChartProps) => {
}
setChartOptions(options)
}, [gridDto, series, searchParams, urlSearchParams])
}, [gridDto, allSeries, initialized.current, searchParams, urlSearchParams])
const onFilter = useCallback(
(value?: string) => {
@ -169,50 +188,64 @@ const Chart = (props: ChartProps) => {
[gridDto, urlSearchParams, searchText],
)
const newSeriesValue = () => {
return {
argumentField: '',
axis: '',
barOverlapGroup: '',
barPadding: 0,
barWidth: 0,
color: '',
cornerRadius: 0,
dashStyle: 'solid',
ignoreEmptyPoints: false,
name: '',
pane: '',
rangeValue1Field: '',
rangeValue2Field: '',
selectionMode: 'none',
showInLegend: true,
type: 'line',
valueField: '',
visible: true,
width: 2,
label: {
visible: true,
backgroundColor: '#f05b41',
customizeText: '',
format: 'decimal',
font: {
color: '#FFFFFF',
family: '"Segoe UI", "Helvetica Neue", "Trebuchet MS", Verdana, sans-serif',
size: 12,
weight: 400,
},
},
const getFields = async () => {
if (!props.listFormCode) return
try {
const resp = await getListFormFields({
listFormCode: props.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(
<Notification type="danger" duration={2000}>
Alanlar getirilemedi {error.toString()}
</Notification>,
{ placement: 'top-end' },
)
}
}
useEffect(() => {
if (gridDto && !initialized.current) {
setSeries(gridDto.gridOptions.seriesDto)
initialized.current = true
}
}, [gridDto])
if (props.listFormCode) getFields()
}, [props.listFormCode])
const [openDialog, setOpenDialog] = useState(false)
const onSave = async (newSeries: ChartSeriesDto[]) => {
// 1. Silinecek serileri bul (oldSeries var ama newSeries yok)
const toDelete = oldSeries.filter((old) => !newSeries.some((s) => s.index === old.index))
// Index kaymasını önlemek için büyükten küçüğe sırala
toDelete.sort((a, b) => b.index - a.index)
for (const old of toDelete) {
await deleteListFormJsonRow(id, ListFormEditTabs.ChartSeries.GeneralJsonRow, old.index)
}
// 2. Yeni veya güncellenen serileri kaydet
for (const series of newSeries) {
const input: ListFormJsonRowDto = {
index: series.index,
fieldName: ListFormEditTabs.ChartSeries.GeneralJsonRow,
itemChartSeries: series,
}
if (series.index === -1) {
await postListFormJsonRow(id, input)
} else {
await putListFormJsonRow(id, input)
}
}
// 3. Yeniden yükle
if (props.refreshGridDto) {
initialized.current = false
await props.refreshGridDto()
}
}
return (
<Container className={DX_CLASSNAMES}>
@ -252,26 +285,24 @@ const Chart = (props: ChartProps) => {
}}
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
size="xs"
variant={'default'}
className="text-sm"
onClick={async () => {
setSeries(gridDto?.gridOptions?.seriesDto ?? [])
await props.refreshGridDto()
initialized.current = false
await refreshGridDto()
}}
title="Refresh Data"
>
<FaSyncAlt className="w-3 h-3" />
</Button>
<Button
size="xs"
variant="default"
className="text-sm"
onClick={() => setOpenDialog(true)}
title="Edit Series"
title="Series Özelleştir"
>
<FaCrosshairs className="w-3 h-3" />
</Button>
@ -299,109 +330,13 @@ const Chart = (props: ChartProps) => {
</div>
<DxChart key={'DxChart' + _listFormCode} {...chartOptions}></DxChart>
<Dialog isOpen={openDialog} onClose={() => setOpenDialog(false)} width={600}>
<Formik
enableReinitialize
initialValues={{
series: series && series.length > 0 ? series : [newSeriesValue()],
}}
validationSchema={schema}
onSubmit={(values, { setSubmitting }) => {
setSeries(values.series)
setSubmitting(true)
try {
toast.push(<Notification type="success">{'Chart güncellendi'}</Notification>, {
placement: 'top-end',
})
setOpenDialog(false) // kaydettikten sonra dialogu kapat
} catch (error: any) {
toast.push(
<Notification type="danger">
Hata
<code>{error}</code>
</Notification>,
{ placement: 'top-end' },
)
} finally {
setSubmitting(false)
}
}}
>
{({ setFieldValue, values, isSubmitting }) => (
<Form className="flex flex-col h-full">
<FormContainer size="sm" className="flex flex-col h-full">
{/* Kaydırılabilir içerik */}
<div className="flex-1 overflow-y-auto p-2">
<FieldArray name="series">
{({ remove }) => (
<div>
{values.series.map((_, index) => (
<div key={index} className="mb-2 border-b pb-2">
<FormItem label="Name">
<Field
name={`series[${index}].name`}
type="text"
component={Input}
/>
</FormItem>
<FormItem label="Argument Field">
<Field
name={`series[${index}].argumentField`}
type="text"
component={Input}
/>
</FormItem>
<FormItem label="Value Field">
<Field
name={`series[${index}].valueField`}
type="text"
component={Input}
/>
</FormItem>
<FormItem label="Summary Type">
<Field
name={`series[${index}].summaryType`}
type="text"
component={Input}
/>
</FormItem>
<Button
shape="circle"
type="button"
className="mt-2"
size="xs"
icon={<FaMinus />}
onClick={() => remove(index)}
/>
</div>
))}
</div>
)}
</FieldArray>
</div>
{/* Footer */}
<div className="flex gap-2 mt-auto pt-2 border-t text-right">
<Button
variant="default"
type="button"
onClick={() =>
setFieldValue('series', [...values.series, newSeriesValue()])
}
>
<FaPlus />
</Button>
<Button block variant="solid" loading={isSubmitting} type="submit">
{isSubmitting ? translate('::SavingWithThreeDot') : translate('::Save')}
</Button>
</div>
</FormContainer>
</Form>
)}
</Formik>
</Dialog>
<ChartSeriesDialog
open={openDialog}
onClose={() => setOpenDialog(false)}
initialSeries={allSeries.filter((s) => s.userId === userName)}
fieldList={fieldList}
onSave={onSave}
/>
</div>
)}
</Container>

View file

@ -0,0 +1,279 @@
import { Button, FormContainer, Input, Notification, Select, Dialog, toast } from '@/components/ui'
import { Field, FieldArray, Form, Formik, FieldProps } from 'formik'
import { FaMinus, FaPlus } from 'react-icons/fa'
import { SelectBoxOption } from '@/shared/types'
import {
chartSeriesTypeOptions,
columnSummaryTypeListOptions,
} from '../admin/listForm/edit/options'
import { ChartSeriesDto } from '@/proxy/admin/charts/models'
import { useLocalization } from '@/utils/hooks/useLocalization'
import { useStoreState } from '@/store/store'
import { object, array, string } from 'yup'
import { SummaryTypeEnum } from '@/proxy/form/models'
interface ChartSeriesDialogProps {
open: boolean
onClose: () => void
initialSeries: ChartSeriesDto[]
fieldList: SelectBoxOption[]
onSave: (series: ChartSeriesDto[]) => void
}
const schema = object().shape({
series: array().of(
object().shape({
name: string().required('Name Required'),
argumentField: string().required('Argument Field Required'),
valueField: string().required('Value Field Required'),
summaryType: string().required('Summary Type Required'),
}),
),
})
const ChartSeriesDialog = ({
open,
onClose,
initialSeries,
fieldList,
onSave,
}: ChartSeriesDialogProps) => {
const { translate } = useLocalization()
// State UserId güncellemesi için
const { userName } = useStoreState((s) => s.auth.user)
const newSeriesValue = () => {
return {
index: -1,
type: 'line',
name: '',
argumentField: '',
valueField: '',
summaryType: SummaryTypeEnum.Sum,
axis: '',
barOverlapGroup: '',
barPadding: 0,
barWidth: 0,
color: '',
cornerRadius: 0,
dashStyle: 'solid',
ignoreEmptyPoints: false,
pane: '',
rangeValue1Field: '',
rangeValue2Field: '',
selectionMode: 'none',
showInLegend: true,
visible: true,
width: 2,
label: {
visible: true,
backgroundColor: '#f05b41',
customizeText: '',
format: 'decimal',
font: {
color: '#FFFFFF',
family: '"Segoe UI", "Helvetica Neue", "Trebuchet MS", Verdana, sans-serif',
size: 12,
weight: 400,
},
},
userId: userName ?? '',
}
}
return (
<Dialog isOpen={open} onClose={onClose} width={1200}>
<div className="flex flex-col bg-white p-4 h-[600px]">
<Formik
enableReinitialize
initialValues={{
series: initialSeries && initialSeries.length > 0 ? initialSeries : [newSeriesValue()],
}}
validationSchema={schema}
onSubmit={(values, { setSubmitting }) => {
try {
onSave(values.series)
toast.push(<Notification type="success">{'Chart güncellendi'}</Notification>, {
placement: 'top-end',
})
onClose()
} catch (error: any) {
toast.push(
<Notification type="danger">
Hata
<code>{error}</code>
</Notification>,
{ placement: 'top-end' },
)
} finally {
setSubmitting(false)
}
}}
>
{({ setFieldValue, values, isSubmitting }) => (
<Form className="flex flex-col h-full">
<FormContainer size="sm" className="flex flex-col h-full">
{/* Header */}
<div className="mb-2 pb-2 border-b flex items-center justify-between">
<Button
variant="default"
shape="circle"
type="button"
size="xs"
onClick={() => setFieldValue('series', [...values.series, newSeriesValue()])}
>
<div className="flex items-center gap-1">
<FaPlus /> Seri Ekle
</div>
</Button>
</div>
{/* Kaydırılabilir içerik */}
<div className="flex-1 overflow-y-auto p-1">
<FieldArray name="series">
{({ remove }) => (
<div>
<div className="grid grid-cols-12 gap-2 font-semibold text-xs py-2">
<div className="text-center col-span-1">#</div>
<div className="text-center col-span-2">Type</div>
<div className="text-center col-span-2">Name</div>
<div className="text-center col-span-2">Argument Field</div>
<div className="text-center col-span-2">Value Field</div>
<div className="text-center col-span-2">Summary Type</div>
<div className="text-center col-span-1">#</div>
</div>
{values.series.map((_, index) => (
<div key={index} className="border-b py-1">
<div className="grid grid-cols-12 gap-1 items-center">
<div className="text-center text-xs col-span-1">
{values.series[index].index}
</div>
<div className="text-xs col-span-2">
<Field name={`series[${index}].type`}>
{({ field, form }: FieldProps<SelectBoxOption>) => (
<Select
field={field}
form={form}
options={chartSeriesTypeOptions}
isClearable
value={chartSeriesTypeOptions.find(
(option) => option.value === field.value,
)}
onChange={(option) =>
form.setFieldValue(field.name, option?.value)
}
/>
)}
</Field>
</div>
<div className="text-xs col-span-2">
<Field
size="sm"
name={`series[${index}].name`}
type="text"
component={Input}
className="text-xs px-1 py-0 grid-cols-2"
/>
</div>
<div className="text-xs col-span-2">
<Field type="text" name={`series[${index}].argumentField`}>
{({ field, form }: FieldProps<SelectBoxOption>) => (
<Select
field={field}
form={form}
isClearable={true}
options={fieldList}
value={fieldList?.find(
(option) => option.value === field.value,
)}
onChange={(option) =>
form.setFieldValue(field.name, option?.value)
}
menuPlacement="auto"
maxMenuHeight={150}
/>
)}
</Field>
</div>
<div className="text-xs col-span-2">
<Field type="text" name={`series[${index}].valueField`}>
{({ field, form }: FieldProps<SelectBoxOption>) => (
<Select
field={field}
form={form}
isClearable={true}
options={fieldList}
value={fieldList?.find(
(option) => option.value === field.value,
)}
onChange={(option) =>
form.setFieldValue(field.name, option?.value)
}
menuPlacement="auto"
maxMenuHeight={150}
/>
)}
</Field>
</div>
<div className="text-xs col-span-2">
<Field type="text" name={`series[${index}].summaryType`}>
{({ field, form }: FieldProps<SelectBoxOption>) => (
<Select
field={field}
form={form}
isClearable={true}
options={columnSummaryTypeListOptions}
value={columnSummaryTypeListOptions.find(
(option) => option.value === field.value,
)}
onChange={(option) =>
form.setFieldValue(field.name, option?.value)
}
/>
)}
</Field>
</div>
<div className="flex items-center justify-center gap-1 col-span-1">
<Button
shape="circle"
type="button"
size="xs"
icon={<FaMinus />}
className="bg-slate-100 hover:bg-red-100"
onClick={() => remove(index)}
/>
</div>
</div>
</div>
))}
</div>
)}
</FieldArray>
</div>
{/* Footer */}
<div className="flex gap-2 mt-auto pt-2 border-t text-right justify-end">
<Button
variant="solid"
loading={isSubmitting}
type="submit"
className="ml-auto px-4 py-1 text-sm rounded"
>
{isSubmitting ? translate('::SavingWithThreeDot') : translate('::Save')}
</Button>
</div>
</FormContainer>
</Form>
)}
</Formik>
</div>
</Dialog>
)
}
export default ChartSeriesDialog

View file

@ -0,0 +1,278 @@
import { Button, FormContainer, Input, Notification, Select, Dialog, toast } from '@/components/ui'
import { Field, FieldArray, Form, Formik, FieldProps } from 'formik'
import { FaMinus, FaPlus } from 'react-icons/fa'
import { SelectBoxOption } from '@/shared/types'
import {
chartSeriesTypeOptions,
columnSummaryTypeListOptions,
} from '../admin/listForm/edit/options'
import { ChartSeriesDto } from '@/proxy/admin/charts/models'
import { useLocalization } from '@/utils/hooks/useLocalization'
import { useStoreState } from '@/store/store'
import { object, array, string } from 'yup'
interface ChartSeriesDialog1 {
open: boolean
onClose: () => void
initialSeries: ChartSeriesDto[]
fieldList: SelectBoxOption[]
onSave: (series: ChartSeriesDto[]) => void
}
const schema = object().shape({
series: array().of(
object().shape({
name: string().required('Name Required'),
argumentField: string().required('Argument Field Required'),
valueField: string().required('Value Field Required'),
summaryType: string().required('Summary Type Required'),
}),
),
})
const ChartSeriesDialog1 = ({
open,
onClose,
initialSeries,
fieldList,
onSave,
}: ChartSeriesDialog1) => {
const { translate } = useLocalization()
// State UserId güncellemesi için
const { userName } = useStoreState((s) => s.auth.user)
const newSeriesValue = () => {
return {
index: -1,
type: 'line',
name: '',
argumentField: '',
valueField: '',
summaryType: 'sum',
axis: '',
barOverlapGroup: '',
barPadding: 0,
barWidth: 0,
color: '',
cornerRadius: 0,
dashStyle: 'solid',
ignoreEmptyPoints: false,
pane: '',
rangeValue1Field: '',
rangeValue2Field: '',
selectionMode: 'none',
showInLegend: true,
visible: true,
width: 2,
label: {
visible: true,
backgroundColor: '#f05b41',
customizeText: '',
format: 'decimal',
font: {
color: '#FFFFFF',
family: '"Segoe UI", "Helvetica Neue", "Trebuchet MS", Verdana, sans-serif',
size: 12,
weight: 400,
},
},
userId: userName ?? '',
}
}
return (
<Dialog isOpen={open} onClose={onClose} width={1200}>
<div className="flex flex-col bg-white p-4 h-[600px]">
<Formik
enableReinitialize
initialValues={{
series: initialSeries && initialSeries.length > 0 ? initialSeries : [newSeriesValue()],
}}
validationSchema={schema}
onSubmit={(values, { setSubmitting }) => {
try {
onSave(values.series)
toast.push(<Notification type="success">{'Chart güncellendi'}</Notification>, {
placement: 'top-end',
})
onClose()
} catch (error: any) {
toast.push(
<Notification type="danger">
Hata
<code>{error}</code>
</Notification>,
{ placement: 'top-end' },
)
} finally {
setSubmitting(false)
}
}}
>
{({ setFieldValue, values, isSubmitting }) => (
<Form className="flex flex-col h-full">
<FormContainer size="sm" className="flex flex-col h-full">
{/* Header */}
<div className="mb-2 pb-2 border-b flex items-center justify-between">
<Button
variant="default"
shape="circle"
type="button"
size="xs"
onClick={() => setFieldValue('series', [...values.series, newSeriesValue()])}
>
<div className="flex items-center gap-1">
<FaPlus /> Seri Ekle
</div>
</Button>
</div>
{/* Kaydırılabilir içerik */}
<div className="flex-1 overflow-y-auto p-1">
<FieldArray name="series">
{({ remove }) => (
<div>
<div className="grid grid-cols-12 gap-2 font-semibold text-xs py-2">
<div className="text-center col-span-1">#</div>
<div className="text-center col-span-2">Type</div>
<div className="text-center col-span-2">Name</div>
<div className="text-center col-span-2">Argument Field</div>
<div className="text-center col-span-2">Value Field</div>
<div className="text-center col-span-2">Summary Type</div>
<div className="text-center col-span-1">#</div>
</div>
{values.series.map((_, index) => (
<div key={index} className="border-b py-1">
<div className="grid grid-cols-12 gap-1 items-center">
<div className="text-center text-xs col-span-1">
{values.series[index].index}
</div>
<div className="text-xs col-span-2">
<Field name={`series[${index}].type`}>
{({ field, form }: FieldProps<SelectBoxOption>) => (
<Select
field={field}
form={form}
options={chartSeriesTypeOptions}
isClearable
value={chartSeriesTypeOptions.find(
(option) => option.value === field.value,
)}
onChange={(option) =>
form.setFieldValue(field.name, option?.value)
}
/>
)}
</Field>
</div>
<div className="text-xs col-span-2">
<Field
size="sm"
name={`series[${index}].name`}
type="text"
component={Input}
className="text-xs px-1 py-0 grid-cols-2"
/>
</div>
<div className="text-xs col-span-2">
<Field type="text" name={`series[${index}].argumentField`}>
{({ field, form }: FieldProps<SelectBoxOption>) => (
<Select
field={field}
form={form}
isClearable={true}
options={fieldList}
value={fieldList?.find(
(option) => option.value === field.value,
)}
onChange={(option) =>
form.setFieldValue(field.name, option?.value)
}
menuPlacement="auto"
maxMenuHeight={150}
/>
)}
</Field>
</div>
<div className="text-xs col-span-2">
<Field type="text" name={`series[${index}].valueField`}>
{({ field, form }: FieldProps<SelectBoxOption>) => (
<Select
field={field}
form={form}
isClearable={true}
options={fieldList}
value={fieldList?.find(
(option) => option.value === field.value,
)}
onChange={(option) =>
form.setFieldValue(field.name, option?.value)
}
menuPlacement="auto"
maxMenuHeight={150}
/>
)}
</Field>
</div>
<div className="text-xs col-span-2">
<Field type="text" name={`series[${index}].summaryType`}>
{({ field, form }: FieldProps<SelectBoxOption>) => (
<Select
field={field}
form={form}
isClearable={true}
options={columnSummaryTypeListOptions}
value={columnSummaryTypeListOptions.find(
(option) => option.value === field.value,
)}
onChange={(option) =>
form.setFieldValue(field.name, option?.value)
}
/>
)}
</Field>
</div>
<div className="flex items-center justify-center gap-1 col-span-1">
<Button
shape="circle"
type="button"
size="xs"
icon={<FaMinus />}
className="bg-slate-100 hover:bg-red-100"
onClick={() => remove(index)}
/>
</div>
</div>
</div>
))}
</div>
)}
</FieldArray>
</div>
{/* Footer */}
<div className="flex gap-2 mt-auto pt-2 border-t text-right justify-end">
<Button
variant="solid"
loading={isSubmitting}
type="submit"
className="ml-auto px-4 py-1 text-sm rounded"
>
{isSubmitting ? translate('::SavingWithThreeDot') : translate('::Save')}
</Button>
</div>
</FormContainer>
</Form>
)}
</Formik>
</div>
</Dialog>
)
}
export default ChartSeriesDialog1

View file

@ -168,6 +168,7 @@ const List = () => {
/>
) : viewMode === 'chart' ? (
<Chart
id={gridDto?.gridOptions.id!}
listFormCode={listFormCode}
filter={searchParams.toString()}
isSubForm={true}