Optimizasyon değişimleri

This commit is contained in:
Sedat ÖZTÜRK 2026-07-06 12:44:26 +03:00
parent e96498645a
commit bab639ce63
184 changed files with 1470 additions and 3008 deletions

View file

@ -44,7 +44,7 @@
"code": "App.SiteManagement.Theme.Style",
"nameKey": "App.SiteManagement.Theme.Style",
"descriptionKey": "App.SiteManagement.Theme.Style.Description",
"defaultValue": "dx.material.blue.light.compact",
"defaultValue": "dx.material.blue.dark.compact",
"isVisibleToClients": true,
"providers": "U|G|D",
"isInherited": false,

View file

@ -10254,6 +10254,12 @@
"en": "Active",
"tr": "Aktif"
},
{
"resourceName": "Platform",
"key": "App.Status.Inactive",
"en": "Inactive",
"tr": "Pasif"
},
{
"resourceName": "Platform",
"key": "App.DeveloperKit.ComponentEditor.Save",

View file

@ -13,9 +13,7 @@ interface ComponentCodeEditorProps {
onResetCodeChanges: () => void
language?: string
theme?: 'vs-dark' | 'light'
parseError?: string | null
onCursorChange?: (componentId: string | null) => void
onDrop?: (componentDef: ComponentDefinition, position: { line: number; column: number }) => void
onComponentAdded?: (componentDef: ComponentDefinition) => void
onComponentSave: () => void
}
@ -24,6 +22,7 @@ export const ComponentCodeEditor: React.FC<ComponentCodeEditorProps> = ({
code,
onChange,
onApplyCodeChanges,
onResetCodeChanges,
language = 'typescript',
theme = 'vs-dark',
onCursorChange,
@ -48,7 +47,6 @@ export const ComponentCodeEditor: React.FC<ComponentCodeEditorProps> = ({
const editorRef = useRef<any>(null)
const containerRef = useRef<HTMLDivElement>(null)
const cursorChangeTimeout = useRef<number | null>(null)
// Refs to keep latest values accessible inside native DOM listeners
const localCodeRef = useRef(localCode)
const dropCallbacksRef = useRef({ onChange, onComponentAdded, onApplyCodeChanges })
@ -66,14 +64,6 @@ export const ComponentCodeEditor: React.FC<ComponentCodeEditorProps> = ({
dropCallbacksRef.current = { onChange, onComponentAdded, onApplyCodeChanges }
}, [onChange, onComponentAdded, onApplyCodeChanges])
useEffect(() => {
return () => {
if (cursorChangeTimeout.current) {
clearTimeout(cursorChangeTimeout.current)
}
}
}, [])
const findComponentIdAtPosition = (
code: string,
position: { lineNumber: number; column: number },
@ -169,7 +159,10 @@ export const ComponentCodeEditor: React.FC<ComponentCodeEditorProps> = ({
if (ch === '(') parenDepth++
else if (ch === ')') {
parenDepth--
if (parenDepth <= 0) { insideReturn = false; break }
if (parenDepth <= 0) {
insideReturn = false
break
}
}
}
}
@ -178,7 +171,10 @@ export const ComponentCodeEditor: React.FC<ComponentCodeEditorProps> = ({
if (ch === '(') parenDepth++
else if (ch === ')') {
parenDepth--
if (parenDepth <= 0) { insideReturn = false; break }
if (parenDepth <= 0) {
insideReturn = false
break
}
}
}
}
@ -186,15 +182,11 @@ export const ComponentCodeEditor: React.FC<ComponentCodeEditorProps> = ({
return insideReturn
}
const handleEditorCursorChange = (_event: any) => {
const handleEditorCursorChange = () => {
if (!editorRef.current) return
const position = editorRef.current.getPosition()
if (!position) return
// Throttle the cursor change to avoid too many calls
if (cursorChangeTimeout.current) {
clearTimeout(cursorChangeTimeout.current)
}
const id = findComponentIdAtPosition(localCode, position)
if (onCursorChange) onCursorChange(id)
}
@ -242,12 +234,19 @@ export const ComponentCodeEditor: React.FC<ComponentCodeEditorProps> = ({
let componentDefData: string | undefined
for (const fmt of ['application/json', 'text/plain']) {
const d = nativeEvent.dataTransfer.getData(fmt)
if (d) { componentDefData = d; break }
if (d) {
componentDefData = d
break
}
}
if (!componentDefData) return
let componentDef: any
try { componentDef = JSON.parse(componentDefData) } catch { return }
try {
componentDef = JSON.parse(componentDefData)
} catch {
return
}
if (!componentDef?.name) return
// Resolve the drop position inside Monaco
@ -300,8 +299,11 @@ export const ComponentCodeEditor: React.FC<ComponentCodeEditorProps> = ({
const newCode = newLines.join('\n')
setLocalCode(newCode)
const { onChange: onChg, onComponentAdded: onAdded, onApplyCodeChanges: onApply } =
dropCallbacksRef.current
const {
onChange: onChg,
onComponentAdded: onAdded,
onApplyCodeChanges: onApply,
} = dropCallbacksRef.current
onChg(newCode)
if (onAdded) onAdded(componentDefWithId)
setTimeout(() => onApply(newCode), 100)
@ -346,6 +348,7 @@ export const ComponentCodeEditor: React.FC<ComponentCodeEditorProps> = ({
const handleResetChanges = () => {
setLocalCode(code)
setHasChanges(false)
onResetCodeChanges()
}
// Drag & Drop handlers for Code Editor
@ -561,53 +564,53 @@ export const ComponentCodeEditor: React.FC<ComponentCodeEditorProps> = ({
<div className="bg-gray-800 border-b border-gray-700 p-4 flex items-end justify-between shrink-0">
<div className="flex items-center gap-2">
<Button
onClick={handleFormatCode}
loading={isFormatting}
icon={<FaCode className="w-4 h-4" />}
variant="default"
size="sm"
onClick={handleFormatCode}
>
Formatla
</Button>
<Button
onClick={() => setShowSettings(!showSettings)}
icon={<FaCog className="w-4 h-4" />}
variant={showSettings ? 'solid' : 'default'}
color="blue-600"
size="sm"
onClick={() => setShowSettings(!showSettings)}
>
Ayarlar
</Button>
<Button
onClick={handleResetChanges}
icon={<FaTimes className="w-4 h-4" />}
variant="solid"
color="red-600"
size="sm"
onClick={handleResetChanges}
>
Sıfırla
</Button>
<Button
onClick={handleApplyChanges}
icon={<FaCheck className="w-4 h-4" />}
variant="solid"
color="green-600"
size="sm"
onClick={handleApplyChanges}
>
Uygula
</Button>
</div>
<div className="col-span-2 flex items-center justify-end">
<Button
onClick={onComponentSave}
icon={<FaSave className="w-4 h-4" />}
variant="solid"
color="yellow-600"
size="sm"
className="shadow-sm"
onClick={onComponentSave}
>
Kaydet
</Button>
@ -622,8 +625,8 @@ export const ComponentCodeEditor: React.FC<ComponentCodeEditorProps> = ({
<label className="block text-sm font-medium text-gray-300 mb-2">Tema</label>
<select
value={editorTheme}
onChange={(e) => setEditorTheme(e.target.value as 'vs-dark' | 'light')}
className="w-full px-3 py-2 bg-gray-700 border border-gray-600 rounded-md text-white text-sm focus:outline-none focus:ring-2 focus:ring-blue-500"
onChange={(e) => setEditorTheme(e.target.value as 'vs-dark' | 'light')}
>
<option value="vs-dark">Koyu</option>
<option value="light">ık</option>
@ -637,8 +640,8 @@ export const ComponentCodeEditor: React.FC<ComponentCodeEditorProps> = ({
min="10"
max="24"
value={fontSize}
onChange={(e) => setFontSize(parseInt(e.target.value))}
className="w-full px-3 py-2 bg-gray-700 border border-gray-600 rounded-md text-white text-sm focus:outline-none focus:ring-2 focus:ring-blue-500"
onChange={(e) => setFontSize(parseInt(e.target.value))}
/>
</div>
@ -648,8 +651,8 @@ export const ComponentCodeEditor: React.FC<ComponentCodeEditorProps> = ({
</label>
<select
value={wordWrap}
onChange={(e) => setWordWrap(e.target.value as 'on' | 'off')}
className="w-full px-3 py-2 bg-gray-700 border border-gray-600 rounded-md text-white text-sm focus:outline-none focus:ring-2 focus:ring-blue-500"
onChange={(e) => setWordWrap(e.target.value as 'on' | 'off')}
>
<option value="on">ık</option>
<option value="off">Kapalı</option>
@ -659,11 +662,11 @@ export const ComponentCodeEditor: React.FC<ComponentCodeEditorProps> = ({
<div>
<label className="block text-sm font-medium text-gray-300 mb-2">Mini Harita</label>
<Button
onClick={() => setMinimap(!minimap)}
block
variant={minimap ? 'solid' : 'default'}
color="blue-600"
size="sm"
onClick={() => setMinimap(!minimap)}
>
{minimap ? 'Etkin' : 'Devre Dışı'}
</Button>
@ -680,8 +683,6 @@ export const ComponentCodeEditor: React.FC<ComponentCodeEditorProps> = ({
language={language}
theme={editorTheme}
value={localCode}
onChange={handleCodeChange}
onMount={handleEditorDidMount}
options={{
fontSize: fontSize,
wordWrap: wordWrap,
@ -748,6 +749,8 @@ export const ComponentCodeEditor: React.FC<ComponentCodeEditorProps> = ({
formatOnPaste: true,
formatOnType: true,
}}
onChange={handleCodeChange}
onMount={handleEditorDidMount}
/>
</div>

View file

@ -1,4 +1,4 @@
import { useState, useEffect } from "react";
import React, { useState, useEffect } from "react";
import TailwindModal from "./TailwindModal";
import { ComponentInfo, HookInfo, PropertyInfo } from "../../proxy/developerKit/componentInfo";
import { getComponentDefinition } from "./data/componentDefinitions";
@ -113,15 +113,6 @@ const PropertyPanel: React.FC<PropertyPanelProps> = ({
setHasHookChanges(true);
};
// Handle local event changes
const handleLocalEventChange = (eventName: string, value: string) => {
setPendingEvents((prev) => ({
...prev,
[eventName]: value,
}));
setHasChanges(true);
};
// Apply only property/event changes
const handleApplyPropChanges = () => {
if (!selectedComponent) return;
@ -222,7 +213,7 @@ const PropertyPanel: React.FC<PropertyPanelProps> = ({
if (property.type === "array") {
try {
arrayInputValue = JSON.stringify(value, null, 2);
} catch (e) {
} catch {
arrayInputValue = "";
arrayError = "Array verisi gösterilemiyor.";
}
@ -365,7 +356,7 @@ const PropertyPanel: React.FC<PropertyPanelProps> = ({
const parsed = JSON.parse(e.target.value);
handleLocalPropertyChange(property.name, parsed);
arrayError = "";
} catch (err) {
} catch {
arrayError = "Geçersiz JSON formatı";
}
}}

View file

@ -1,4 +1,4 @@
import { useState, useEffect } from 'react';
import React, { useState, useEffect } from 'react';
import { searchTailwindClasses, TAILWIND_CLASSES } from './data/tailwindClasses';
import { Button } from '../ui';
import { FaTimes } from 'react-icons/fa';
@ -40,12 +40,6 @@ const TailwindModal: React.FC<TailwindModalProps> = ({
// Don't close modal - let user select multiple classes
};
const handleAddToCurrentValue = (className: string) => {
const newValue = currentValue ? `${currentValue} ${className}` : className;
onSelectClass(newValue);
// Don't close modal - let user continue selecting
};
if (!isOpen) return null;
return (

View file

@ -1,3 +1,5 @@
import React from 'react';
declare interface Window {
ReactDOM?: {
render: (element: React.ReactNode, container: Element) => void;

View file

@ -1,3 +1,4 @@
import React from "react";
import classNames from "classnames";
interface InfoSectionProps {

View file

@ -1,4 +1,4 @@
import { useEffect, useState } from "react";
import React, { useEffect, useState } from "react";
import classNames from "classnames";
import { iconList } from "./iconList";

View file

@ -1,6 +1,5 @@
import classNames from "classnames";
import Widget, { type colorType } from "./Widget";
import { useNavigate } from "react-router-dom";
import { WidgetEditDto, WidgetGroupDto } from "../../types/common";
export default function WidgetGroup({
@ -8,8 +7,6 @@ export default function WidgetGroup({
}: {
widgetGroups: WidgetGroupDto[];
}) {
const navigate = useNavigate();
return (
<div>
{widgetGroups.map((group, gIdx) => (

View file

@ -1,4 +1,4 @@
import { cloneElement } from 'react'
import React, { cloneElement } from 'react'
import Avatar from '@/components/ui/Avatar'
import Logo from '@/components/template/Logo'
import { APP_NAME } from '@/constants/app.constant'

View file

@ -1,44 +1,10 @@
import React from 'react'
import { FaTachometerAlt, FaDatabase, FaBolt, FaServer, FaPuzzlePiece } from 'react-icons/fa'
import { useLocalization } from '@/utils/hooks/useLocalization'
import { useLocation, useNavigate } from 'react-router-dom'
import { ROUTES_ENUM } from '@/routes/route.constant'
import type { PropsWithChildren } from 'react'
import { Container } from '../shared'
interface DeveloperLayoutProps {
children: React.ReactNode
}
const DeveloperLayout: React.FC<DeveloperLayoutProps> = ({ children }) => {
const { translate } = useLocalization()
const location = useLocation()
const navigate = useNavigate()
const navigation = [
{
id: 'entities',
label: translate('::App.DeveloperKit.Entity'),
icon: FaDatabase,
path: ROUTES_ENUM.protected.saas.developerKit.entities,
},
{
id: 'endpoints',
label: translate('::App.DeveloperKit.CrudEndpoints'),
icon: FaServer,
path: ROUTES_ENUM.protected.saas.developerKit.endpoints,
},
{
id: 'components',
label: translate('::App.DeveloperKit.Components'),
icon: FaPuzzlePiece,
path: ROUTES_ENUM.protected.saas.developerKit.components,
},
]
const DeveloperLayout = ({ children }: PropsWithChildren) => {
return (
<Container>
<div className="flex flex-col lg:flex-row gap-8">
{/* Main Content */}
<div className="flex-1">{children}</div>
</div>
</Container>

View file

@ -23,7 +23,6 @@ export const BillingControls: React.FC<BillingControlsProps> = ({
setGlobalBillingCycle,
setGlobalPeriod,
onCartClick,
onNavigate,
cartItemsCount,
cartState,
}) => {

View file

@ -10,7 +10,7 @@ interface OrderSuccessProps {
onBackToShop: () => void
}
export const OrderSuccess: React.FC<OrderSuccessProps> = ({ orderId, onBackToShop }) => {
export const OrderSuccess: React.FC<OrderSuccessProps> = ({ orderId }) => {
const navigate = useNavigate()
const { translate } = useLocalization()

View file

@ -1,6 +1,6 @@
import React, { useState } from 'react'
import { FaPlus, FaMinus } from 'react-icons/fa'
import { BillingCycle, Product, ProductDto } from '@/proxy/order/models'
import { BillingCycle, ProductDto } from '@/proxy/order/models'
import { CartState } from '@/utils/cartUtils'
import { useLocalization } from '@/utils/hooks/useLocalization'
import { Button } from '@/components/ui'

View file

@ -4,14 +4,14 @@ import { Link } from 'react-router-dom'
import type { CommonProps } from '@/proxy/common'
import type { ComponentPropsWithoutRef } from 'react'
interface ActionLink extends CommonProps, ComponentPropsWithoutRef<'a'> {
interface ActionLinkProps extends CommonProps, ComponentPropsWithoutRef<'a'> {
themeColor?: boolean
to?: string
href?: string
reloadDocument?: boolean
}
const ActionLink = (props: ActionLink) => {
const ActionLink = (props: ActionLinkProps) => {
const {
children,
className,

View file

@ -1,5 +1,4 @@
import { MigrateLogEntry } from '@/proxy/setup/models'
import { useLocalization } from '@/utils/hooks/useLocalization'
import { useEffect, useRef, useState } from 'react'
import { createRoot } from 'react-dom/client'
import { Button } from '@/components/ui'

View file

@ -1,4 +1,4 @@
import { forwardRef } from 'react'
import React, { forwardRef } from 'react'
import classNames from 'classnames'
import useThemeClass from '@/utils/hooks/useThemeClass'
import { FaCheckCircle } from 'react-icons/fa'

View file

@ -179,34 +179,58 @@ export const ComponentProvider: React.FC<{ children: React.ReactNode }> = ({ chi
useEffect(() => {
// Example components for testing
const HelloWorldComponent: React.ComponentType<unknown> = () => {
return React.createElement('div', {
className: 'p-6 bg-blue-50 rounded-lg'
}, [
React.createElement('h1', {
className: 'text-2xl font-bold text-blue-900 mb-4'
}, 'Hello World!'),
React.createElement('p', {
className: 'text-blue-700'
}, 'Bu manuel kayıtlı bir komponent!')
])
return React.createElement(
'div',
{
className: 'p-6 bg-blue-50 rounded-lg',
},
[
React.createElement(
'h1',
{
className: 'text-2xl font-bold text-blue-900 mb-4',
},
'Hello World!',
),
React.createElement(
'p',
{
className: 'text-blue-700',
},
'Bu manuel kayıtlı bir komponent!',
),
],
)
}
const TestListComponent: React.ComponentType<unknown> = () => {
return React.createElement('div', {
className: 'p-6 bg-green-50 rounded-lg'
}, [
React.createElement('h1', {
className: 'text-2xl font-bold text-green-900 mb-4'
}, 'Test List'),
React.createElement('p', {
className: 'text-green-700'
}, 'Bu da test için kayıtlı komponent!')
])
return React.createElement(
'div',
{
className: 'p-6 bg-green-50 rounded-lg',
},
[
React.createElement(
'h1',
{
className: 'text-2xl font-bold text-green-900 mb-4',
},
'Test List',
),
React.createElement(
'p',
{
className: 'text-green-700',
},
'Bu da test için kayıtlı komponent!',
),
],
)
}
registerComponent('HelloWorld', HelloWorldComponent)
registerComponent('TestList', TestListComponent)
}, []) // Empty dependency array - only run once
}, []) // Empty dependency array - only run once
// Component compilation functions (moved from ComponentRegistryProvider)
const extractComponentInfo = useCallback((code: string, defaultName = '') => {
@ -269,8 +293,8 @@ export const ComponentProvider: React.FC<{ children: React.ReactNode }> = ({ chi
const componentDefinitions = componentInfos
.map((info) => {
const componentVariables = componentInfos
.filter(other => other.name !== info.name)
.map(other => `const ${other.name} = ${other.name}_Component;`)
.filter((other) => other.name !== info.name)
.map((other) => `const ${other.name} = ${other.name}_Component;`)
.join('\n ')
return `
@ -314,12 +338,90 @@ export const ComponentProvider: React.FC<{ children: React.ReactNode }> = ({ chi
}
const componentsFactory = new Function(
'React', 'Alert', 'Avatar', 'Badge', 'Button', 'Calendar', 'Card', 'Checkbox', 'ConfigProvider', 'DatePicker', 'Dialog', 'Drawer', 'Dropdown', 'FormItem', 'FormContainer', 'Input', 'InputGroup', 'Menu', 'MenuItem', 'Notification', 'Pagination', 'Progress', 'Radio', 'RangeCalendar', 'ScrollBar', 'Segment', 'Select', 'Skeleton', 'Spinner', 'Steps', 'Switcher', 'Table', 'Tabs', 'Tag', 'TimeInput', 'Timeline', 'toast', 'Tooltip', 'Upload', 'axios',
'React',
'Alert',
'Avatar',
'Badge',
'Button',
'Calendar',
'Card',
'Checkbox',
'ConfigProvider',
'DatePicker',
'Dialog',
'Drawer',
'Dropdown',
'FormItem',
'FormContainer',
'Input',
'InputGroup',
'Menu',
'MenuItem',
'Notification',
'Pagination',
'Progress',
'Radio',
'RangeCalendar',
'ScrollBar',
'Segment',
'Select',
'Skeleton',
'Spinner',
'Steps',
'Switcher',
'Table',
'Tabs',
'Tag',
'TimeInput',
'Timeline',
'toast',
'Tooltip',
'Upload',
'axios',
`return ${compiledBundle}`,
)
const compiledComponentsRegistry = componentsFactory(
React, Alert, Avatar, Badge, Button, Calendar, Card, Checkbox, ConfigProvider, DatePicker, Dialog, Drawer, Dropdown, FormItem, FormContainer, Input, InputGroup, Menu, MenuItem, Notification, Pagination, Progress, Radio, RangeCalendar, ScrollBar, Segment, Select, Skeleton, Spinner, Steps, Switcher, Table, Tabs, Tag, TimeInput, Timeline, toast, Tooltip, Upload, axios,
React,
Alert,
Avatar,
Badge,
Button,
Calendar,
Card,
Checkbox,
ConfigProvider,
DatePicker,
Dialog,
Drawer,
Dropdown,
FormItem,
FormContainer,
Input,
InputGroup,
Menu,
MenuItem,
Notification,
Pagination,
Progress,
Radio,
RangeCalendar,
ScrollBar,
Segment,
Select,
Skeleton,
Spinner,
Steps,
Switcher,
Table,
Tabs,
Tag,
TimeInput,
Timeline,
toast,
Tooltip,
Upload,
axios,
)
setCompiledComponents(compiledComponentsRegistry)
@ -352,14 +454,11 @@ export const ComponentProvider: React.FC<{ children: React.ReactNode }> = ({ chi
[components, compiledComponents],
)
const compileAndRender = useCallback(
(code: string, props: ComponentProps = {}) => {
if (!code?.trim()) return null
// Simplified version - can be extended later
return <div>Code compilation not implemented yet</div>
},
[],
)
const compileAndRender = useCallback((code: string) => {
if (!code?.trim()) return null
// Simplified version - can be extended later
return <div>Code compilation not implemented yet</div>
}, [])
const isComponentRegistered = useCallback(
(name: string) => {

View file

@ -1,4 +1,4 @@
import React, { createContext, useContext } from 'react'
import { createContext, useContext } from 'react'
interface DemoContextValue {
openDemo: () => void

View file

@ -1,5 +1,5 @@
// ScrollContext.tsx
import React, { createContext, useContext } from 'react'
import { createContext, useContext } from 'react'
export const ScrollContext = createContext<boolean>(false)

View file

@ -1,5 +1,5 @@
import React, { lazy } from 'react'
import { RouteDto } from '@/proxy/routes/models'
import { lazy } from 'react'
// Tüm view bileşenlerini import et (vite özel)
// shared klasörü hariç, çünkü bu bileşenler genellikle başka yerlerde statik import ediliyor

View file

@ -50,7 +50,7 @@ export const deleteListFormJsonRow = (id: string, field: string, index: number)
url: `/api/admin/list-form-json-row/${id}?field=${field}&index=${index}`,
})
export const getListFormSelectQueryByCode = (listFormCode?: string, op: number = -1) =>
export const getListFormSelectQueryByCode = (listFormCode?: string) =>
apiService.fetchData<string>({
method: 'GET',
url: `/api/admin/list-form-query-preview/form-select-query`,

View file

@ -56,7 +56,7 @@ class NoteService {
})
}
async downloadFile(savedFileName: string, fileName: string, fileType: string) {
async downloadFile(savedFileName: string, fileName: string) {
const response = await apiService.fetchData<NoteFileDto>({
url: `/api/app/note/download?savedFileName=${savedFileName}`,
method: 'GET',

View file

@ -1,5 +1,5 @@
import { InstallmentOptionDto, OrderDto, PaymentMethodDto, ProductDto } from '@/proxy/order/models'
import apiService, { Config } from '@/services/api.service'
import apiService from '@/services/api.service'
import axios from 'axios'
export class OrderService {

View file

@ -111,7 +111,7 @@ platformApiService.interceptors.response.use(
signOut()
error.silent = true
}
} catch (error2) {
} catch {
await revokeTokens({
token: auth.session.token,
refreshToken: auth.session.refreshToken,

View file

@ -1,663 +0,0 @@
import { DepartmentDto, EmployeeDto } from '@/proxy/intranet/models'
export interface Address {
// Adres
country: string
state: string
city: string
street: string
postalCode: string
}
export interface HrCostCenter {
// İnsan Kaynakları Masraf Merkezi
id: string
code: string
name: string
description?: string
parentCostCenterId?: string
parentCostCenter?: HrCostCenter
subCostCenters: HrCostCenter[]
responsibleEmployeeId?: string
responsibleEmployee?: EmployeeDto
departmentId?: string
department?: DepartmentDto
costCenterType: CostCenterType
budgetedAmount: number
actualAmount: number
currency: string
fiscalYear: string
isActive: boolean
creationTime: Date
lastModificationTime: Date
}
export interface HrPerformanceEvaluation {
// İnsan Kaynakları Performans Değerlendirmesi
id: string
employeeId: string
employee?: EmployeeDto
evaluatorId: string
evaluator?: EmployeeDto
evaluationPeriod: string
evaluationType: EvaluationTypeEnum
overallRating: number
goals: HrPerformanceGoal[]
competencies: HrCompetencyRating[]
strengths: string[]
areasForImprovement: string[]
developmentPlan: string[]
comments?: string
status: EvaluationStatusEnum
dueDate: Date
completedDate?: Date
creationTime: Date
lastModificationTime: Date
}
export interface HrPerformanceGoal {
// İnsan Kaynakları Performans Hedefi
id: string
evaluationId: string
goalDescription: string
targetValue?: string
actualValue?: string
weight: number
rating: number
comments?: string
}
export interface HrCompetencyRating {
// İnsan Kaynakları Yeterlilik Değerlendirmesi
id: string
evaluationId: string
competencyName: string
expectedLevel: number
actualLevel: number
rating: number
comments?: string
}
export interface HrTraining {
// İnsan Kaynakları Eğitimi
id: string
trainingCode: string
title: string
description?: string
trainingType: TrainingTypeEnum
provider: string
startDate: Date
endDate: Date
duration: number
location?: string
isOnline: boolean
maxParticipants?: number
cost: number
currency: string
status: TrainingStatusEnum
participants: HrTrainingParticipant[]
materials: string[]
creationTime: Date
lastModificationTime: Date
}
export interface HrTrainingParticipant {
// İnsan Kaynakları Eğitim Katılımcısı
id: string
trainingId: string
employeeId: string
employee?: EmployeeDto
enrollmentDate: Date
completionDate?: Date
status: ParticipationStatusEnum
score?: number
feedback?: string
certificateIssued: boolean
}
export interface HrWorkSchedule {
// İnsan Kaynakları Çalışma Programı
id: string
scheduleCode: string
name: string
description?: string
workingDays: HrWorkingDay[]
totalHoursPerWeek: number
isFlexible: boolean
isActive: boolean
}
export interface HrWorkingDay {
// İnsan Kaynakları Çalışma Günü
dayOfWeek: number // 0-6 (Sunday-Saturday)
isWorkingDay: boolean
startTime?: string
endTime?: string
breakDuration?: number // minutes
}
export interface HrDisciplinaryAction {
// İnsan Kaynakları Disiplin Cezası
id: string
employeeId: string
employee?: EmployeeDto
actionType: DisciplinaryActionTypeEnum
reason: string
description: string
actionDate: Date
issuedBy: string
severity: DisciplinarySeverityEnum
status: DisciplinaryStatusEnum
expiryDate?: Date
attachments: string[]
creationTime: Date
lastModificationTime: Date
}
export interface HrEmergencyContact {
// İnsan Kaynakları Acil Durum İletişim
name: string
relationship: string
phoneNumber: string
email?: string
address?: Address
}
export interface HrEmploymentType {
// İnsan Kaynakları İstihdam Türü
id: string
name: string
count?: number
creationTime: Date
lastModificationTime: Date
}
export interface HrPayroll {
// İnsan Kaynakları Maaş Bordrosu
id: string
employeeId: string
employee?: EmployeeDto
period: string
baseSalary: number
allowances: HrPayrollAllowance[] // İnsan Kaynakları Maaş Ek Ödemeleri
deductions: HrPayrollDeduction[] // İnsan Kaynakları Maaş Kesintileri
overtime: number
bonus: number
grossSalary: number
netSalary: number
tax: number
socialSecurity: number
status: PayrollStatusEnum
paymentDate?: Date
creationTime: Date
lastModificationTime: Date
}
export interface HrPayrollAllowance {
// İnsan Kaynakları Maaş Ek Ödemesi
id: string
name: string
amount: number
taxable: boolean
}
export interface HrPayrollDeduction {
// İnsan Kaynakları Maaş Kesintisi
id: string
name: string
amount: number
mandatory: boolean
}
export interface HrBadge {
// İnsan Kaynakları Rozeti
id: string
code: string
name: string
description: string
icon: string
color: string
backgroundColor: string
category: BadgeCategoryEnum
criteria: string
points: number
rarity: BadgeRarityEnum
isActive: boolean
creationTime: Date
lastModificationTime: Date
}
export interface HrOrganizationChart {
// İnsan Kaynakları Organizasyon Şeması
id: string
employeeId: string
employee?: EmployeeDto
parentId?: string
parent?: HrOrganizationChart
children?: HrOrganizationChart[]
level: number
position: string
isActive: boolean
}
export interface HrEmployeeBadge {
// İnsan Kaynakları Çalışan Rozeti
id: string
employeeId: string
employee?: EmployeeDto
badgeId: string
badge?: HrBadge
earnedDate: Date
expiryDate?: Date
reason?: string
notes?: string
isActive: boolean
creationTime: Date
lastModificationTime: Date
}
export interface HrEvaluation360Template {
// İnsan Kaynakları 360 Derece Değerlendirme Şablonu
id: string
name: string
description: string
isActive: boolean
questionGroups: HrQuestionGroup[]
applicablePositions: string[] // JobPosition ID'leri
applicableDepartments: string[] // Department ID'leri
assessorTypes: AssessorTypeEnum[] // Değerlendiriciler
creationTime: Date
lastModificationTime: Date
}
export interface HrQuestionGroup {
// İnsan Kaynakları Soru Grubu
id: string
templateId: string
groupName: string
description?: string
weight: number // Bu grubun toplam puandaki ağırlığı (%)
order: number
questions: HrEvaluationQuestion[]
}
export interface HrEvaluationQuestion {
// İnsan Kaynakları Değerlendirme Sorusu
id: string
groupId: string
questionText: string
questionType: QuestionTypeEnum
isRequired: boolean
weight: number // Bu sorunun grup içindeki ağırlığı (%)
order: number
options?: HrQuestionOption[] // Çoktan seçmeli sorular için
minRating?: number
maxRating?: number
ratingLabels?: string[] // Rating için etiketler (örn: ["Zayıf", "Orta", "İyi", "Mükemmel"])
}
export interface HrQuestionOption {
// İnsan Kaynakları Soru Seçeneği
id: string
questionId: string
optionText: string
value: number
order: number
}
export interface HrEvaluation360 {
// İnsan Kaynakları 360 Derece Değerlendirme Kampanyası
id: string
name: string
description: string
templateId: string
template?: HrEvaluation360Template
evaluationPeriod: string
startDate: Date
endDate: Date
status: CampaignStatusEnum
departmentId?: string // Hedef departman
targetEmployees: string[] // Değerlendirilecek Employee ID'leri
settings: HrEvaluation360Settings
creationTime: Date
lastModificationTime: Date
}
export interface HrEvaluation360Settings {
// İnsan Kaynakları 360 Derece Değerlendirme Ayarları
allowSelfEvaluation: boolean
requireManagerEvaluation: boolean
minPeerEvaluations: number
minSubordinateEvaluations: number
allowAnonymousFeedback: boolean
sendReminderEmails: boolean
reminderIntervalDays: number
}
export interface HrEvaluation360Participant {
// İnsan Kaynakları 360 Derece Değerlendirme Katılımcısı
id: string
campaignId: string
evaluatedEmployeeId: string // Değerlendirilen kişi
evaluatedEmployee?: EmployeeDto
evaluatorId: string // Değerlendiren kişi
evaluator?: EmployeeDto
evaluatorType: AssessorTypeEnum
status: ParticipantStatusEnum
invitedDate: Date
startedDate?: Date
completedDate?: Date
responses: HrEvaluation360Response[]
overallScore?: number
notes?: string
}
export interface HrEvaluation360Response {
// İnsan Kaynakları 360 Derece Değerlendirme Cevabı
id: string
participantId: string
questionId: string
question?: HrEvaluationQuestion
responseValue: string | number // Cevap değeri
responseText?: string // Metin cevaplar için
score: number // Hesaplanan puan
submittedDate: Date
}
export interface HrEvaluation360Result {
// İnsan Kaynakları 360 Derece Değerlendirme Sonucu
id: string
campaignId: string
employeeId: string
employee?: EmployeeDto
participants: HrEvaluation360Participant[] // Bu sonuca katkıda bulunan değerlendiriciler
overallScore: number
maxPossibleScore: number
scorePercentage: number
groupScores: HrGroupScore[]
assessorTypeScores: HrAssessorTypeScore[]
strengths: string[]
developmentAreas: string[]
actionPlan: string[]
managerComments?: string
hrComments?: string
status: ResultStatusEnum
generatedDate: Date
approvedBy?: string
approvedDate?: Date
}
export interface HrGroupScore {
// İnsan Kaynakları Grup Puanı
groupId: string
groupName: string
score: number
maxScore: number
percentage: number
responseCount: number
}
export interface HrAssessorTypeScore {
// İnsan Kaynakları Değerlendirici Türü Puanı
assessorType: AssessorTypeEnum
assessorCount: number
averageScore: number
maxScore: number
percentage: number
}
export enum PayrollStatusEnum {
// Maaş Durumu
Draft = 'DRAFT', // Taslak
Calculated = 'CALCULATED', // Hesaplandı
Approved = 'APPROVED', // Onaylandı
Paid = 'PAID', // Ödendi
Cancelled = 'CANCELLED', // İptal edildi
}
export enum GoalStatusEnum {
// Hedef Durumu
NotStarted = 'NOT_STARTED', // Başlanmadı
InProgress = 'IN_PROGRESS', // Devam Ediyor
Completed = 'COMPLETED', // Tamamlandı
Overdue = 'OVERDUE', // Geçmiş
Cancelled = 'CANCELLED', // İptal edildi
}
export enum BadgeCategoryEnum {
// Rozet Kategorisi
Performance = 'PERFORMANCE', // Performans
Leadership = 'LEADERSHIP', // Liderlik
Innovation = 'INNOVATION', // Yenilik
Teamwork = 'TEAMWORK', // Takım Çalışması
Customer = 'CUSTOMER', // Müşteri
Safety = 'SAFETY', // Güvenlik
Attendance = 'ATTENDANCE', // Devamsızlık
Training = 'TRAINING', // Eğitim
Project = 'PROJECT', // Proje
Special = 'SPECIAL', // Özel
}
export enum BadgeRarityEnum {
// Rozet Nadirliği
Common = 'COMMON', // Orta
Uncommon = 'UNCOMMON', // Yaygın olmayan
Rare = 'RARE', // Nadir
Epic = 'EPIC', // Epik
Legendary = 'LEGENDARY', // Efsanevi
}
export enum ResultStatusEnum {
// Sonuç Durumu
Pending = 'PENDING', // Beklemede
InReview = 'IN_REVIEW', // İnceleniyor
Approved = 'APPROVED', // Onaylandı
Published = 'PUBLISHED', // Yayınlandı
}
export enum GenderEnum {
// Cinsiyet
Male = 'MALE', // Erkek
Female = 'FEMALE', // Kadın
Other = 'OTHER', // Diğer
}
export enum MaritalStatusEnum {
// Medeni Durum
Single = 'SINGLE', // Bekar
Married = 'MARRIED', // Evli
Divorced = 'DIVORCED', // Boşanmış
Widowed = 'WIDOWED', // Dul
}
export enum CostCenterType {
// Masraf Merkezi Türü
Revenue = 'REVENUE', // Gelir
Standard = 'STANDARD', // Standart
Discretionary = 'DISCRETIONARY', // İsteğe bağlı
Investment = 'INVESTMENT', // Yatırım
Service = 'SERVICE', // Hizmet
Production = 'PRODUCTION', // Üretim
Support = 'SUPPORT', // Destek
Administrative = 'ADMINISTRATIVE', // İdari
}
export enum EmploymentTypeEnum {
// İstihdam Türü
FullTime = 'FULL_TIME', // Tam Zamanlı
PartTime = 'PART_TIME', // Yarı Zamanlı
Contract = 'CONTRACT', // Sözleşmeli
Intern = 'INTERN', // Stajyer
Temporary = 'TEMPORARY', // Geçici
Consultant = 'CONSULTANT', // Danışman
}
export enum EmployeeStatusEnum {
// Çalışan Durumu
Active = 'ACTIVE', // Aktif
Inactive = 'INACTIVE', // Pasif
OnLeave = 'ON_LEAVE', // İzinli
Suspended = 'SUSPENDED', // Askıya Alındı
Terminated = 'TERMINATED', // İşten Ayrıldı
}
export enum JobLevelEnum {
// İş Seviyesi
Entry = 'ENTRY', // Giriş
Junior = 'JUNIOR', // Junior
Mid = 'MID', // Orta
Senior = 'SENIOR', // Kıdemli
Lead = 'LEAD', // Lider
Manager = 'MANAGER', // Yönetici
Director = 'DIRECTOR', // Direktör
Executive = 'EXECUTIVE', // İcra
}
export enum LeaveTypeEnum {
// İzin Türü
Annual = 'Annual', // Yıllık
Sick = 'Sick', // Hastalık
Maternity = 'Maternity', // Doğum
Paternity = 'Paternity', // Babalık
Personal = 'Personal', // Kişisel
Emergency = 'Emergency', // Acil
Study = 'Study', // Eğitim
Unpaid = 'Unpaid', // Ücretsiz
}
export enum LeaveStatusEnum {
// İzin Durumu
Pending = 'Pending', // Beklemede
Approved = 'Approved', // Onaylandı
Rejected = 'Rejected', // Reddedildi
Cancelled = 'Cancelled', // İptal edildi
}
export enum EvaluationStatusEnum {
// Değerlendirme Durumu
NotStarted = 'NOT_STARTED', // Başlanmadı
InProgress = 'IN_PROGRESS', // Devam Ediyor
PendingReview = 'PENDING_REVIEW', // İnceleme Bekliyor
Completed = 'COMPLETED', // Tamamlandı
Overdue = 'OVERDUE', // Geçmiş
}
export enum TrainingTypeEnum {
// Eğitim Türü
Technical = 'TECHNICAL', // Teknik
Soft_Skills = 'SOFT_SKILLS', // Yumuşak Beceriler
Leadership = 'LEADERSHIP', // Liderlik
Compliance = 'COMPLIANCE', // Uyum
Safety = 'SAFETY', // Güvenlik
Product = 'PRODUCT', // Ürün
Process = 'PROCESS', // Süreç
}
export enum TrainingStatusEnum {
// Eğitim Durumu
Planned = 'PLANNED', // Planlandı
Open = 'OPEN', // Açık
InProgress = 'IN_PROGRESS', // Devam Ediyor
Completed = 'COMPLETED', // Tamamlandı
Cancelled = 'CANCELLED', // İptal Edildi
}
export enum ParticipationStatusEnum {
// Katılım Durumu
Enrolled = 'ENROLLED', // Kayıtlı
InProgress = 'IN_PROGRESS', // Devam Ediyor
Completed = 'COMPLETED', // Tamamlandı
Failed = 'FAILED', // Başarısız
Withdrawn = 'WITHDRAWN', // Çekildi
}
export enum DisciplinaryActionTypeEnum {
// Disiplin Cezası Türü
Verbal_Warning = 'VERBAL_WARNING', // Sözlü Uyarı
Written_Warning = 'WRITTEN_WARNING', // Yazılı Uyarı
Final_Warning = 'FINAL_WARNING', // Son Uyarı
Suspension = 'SUSPENSION', // Askıya Alma
Termination = 'TERMINATION', // İşten Çıkarma
Demotion = 'DEMOTION', // Aşağı Alma
}
export enum DisciplinarySeverityEnum {
// Disiplin Cezası Şiddeti
Minor = 'MINOR', // Hafif
Major = 'MAJOR', // Ağır
Severe = 'SEVERE', // Ciddi
}
export enum DisciplinaryStatusEnum {
// Disiplin Cezası Durumu
Active = 'ACTIVE', // Aktif
Resolved = 'RESOLVED', // Çözüldü
Expired = 'EXPIRED', // Süresi Dolmuş
Appealed = 'APPEALED', // İtiraz Edilmiş
}
export enum AssessorTypeEnum {
// Değerlendirici Türü
Self = 'SELF', // Kendi
Manager = 'MANAGER', // Yönetici
Peer = 'PEER', // Meslektaş
Subordinate = 'SUBORDINATE', // Ast
Customer = 'CUSTOMER', // Müşteri
OtherDepartment = 'OTHER_DEPARTMENT', // Diğer Departman
HRUpperManagement = 'HR_UPPER_MANAGEMENT', // İK/Üst Yönetim
External = 'EXTERNAL', // Dış paydaş değerlendirmesi (mevcut)
}
export enum EvaluationTypeEnum {
// Değerlendirme Türü
Annual = 'ANNUAL', // Yıllık
Quarterly = 'QUARTERLY', // Çeyrek
Probation = 'PROBATION', // Deneme Süresi
Project = 'PROJECT', // Proje
Competency = 'COMPETENCY', // Yeterlilik
Leadership = 'LEADERSHIP', // Liderlik
Degree360 = 'DEGREE_360', // 360° Derece değerlendirme
}
export enum CampaignStatusEnum {
// Kampanya Durumu
Draft = 'DRAFT', // Taslak
Active = 'ACTIVE', // Aktif
Completed = 'COMPLETED', // Tamamlandı
Cancelled = 'CANCELLED', // İptal Edildi
}
export enum ParticipantStatusEnum {
// Katılımcı Durumu
Invited = 'INVITED', // Davet Edildi
Started = 'STARTED', // Başladı
Completed = 'COMPLETED', // Tamamlandı
Expired = 'EXPIRED', // Süresi Dolmuş
Declined = 'DECLINED', // Reddedildi
}
export enum QuestionTypeEnum {
// Soru Türü
Rating = 'RATING', // 1-5 puan verme
MultipleChoice = 'MULTIPLE_CHOICE', // Çoktan seçmeli
Text = 'TEXT', // Metin cevap
YesNo = 'YES_NO', // Evet/Hayır
Scale = 'SCALE', // Ölçek (1-10 gibi)
}
export const getQuestionTypeText = (type: QuestionTypeEnum) => {
switch (type) {
case QuestionTypeEnum.Rating:
return 'Puanlama'
case QuestionTypeEnum.MultipleChoice:
return 'Çoktan Seçmeli'
case QuestionTypeEnum.Text:
return 'Metin'
case QuestionTypeEnum.YesNo:
return 'Evet/Hayır'
case QuestionTypeEnum.Scale:
return 'Ölçek'
default:
return 'Bilinmeyen'
}
}

View file

@ -11,7 +11,7 @@ function deepParseJson(jsonString: Json): Json {
}
try {
return deepParseJson(JSON.parse(jsonString))
} catch (err) {
} catch {
return jsonString
}
} else if (Array.isArray(jsonString)) {

View file

@ -7,12 +7,8 @@ import { NotificationDto } from '@/proxy/notification/models'
import { getList } from '@/services/notification.service'
import { useLocalization } from '@/utils/hooks/useLocalization'
import dayjs from 'dayjs'
import { Dictionary } from 'lodash'
import forOwn from 'lodash/forOwn'
import groupBy from 'lodash/groupBy'
import has from 'lodash/has'
import merge from 'lodash/merge'
import { useEffect, useState } from 'react'
import { useCallback, useEffect, useState } from 'react'
import Log from './components/Log'
import LogFilter from './components/LogFilter'
import { Helmet } from 'react-helmet'
@ -21,12 +17,13 @@ import { DIR_RTL } from '@/constants/theme.constant'
import { useStoreState } from '@/store'
const itemsPerPage = 10
type NotificationGroups = Record<string, NotificationDto[]>
const ActivityLog = () => {
const { translate } = useLocalization()
const [loading, setLoading] = useState(false)
const [notifications, setNotifications] = useState<Dictionary<NotificationDto[]>>({})
const [notifications, setNotifications] = useState<NotificationGroups>({})
const [page, setPage] = useState(0)
const [hasMore, setHasMore] = useState(false)
const [isFilterDrawerOpen, setIsFilterDrawerOpen] = useState(false)
@ -41,38 +38,43 @@ const ActivityLog = () => {
NotificationChannels.WhatsApp,
])
const fetchData = async (isLoadmore: boolean = false) => {
const fetchData = useCallback(async (isLoadmore: boolean = false) => {
setLoading(true)
const response = await getList({
maxResultCount: itemsPerPage,
skipCount: page * itemsPerPage,
sorting: 'CreationTime DESC',
channels: filter,
isListRequest: true,
})
const items = response.data?.items ?? []
const currentItemCount = page * itemsPerPage + items.length
setHasMore((response.data?.totalCount ?? 0) > currentItemCount)
const logs = groupBy(items, (a) => dayjs(a.creationTime).format('YYYY-MM-DD'))
if (isLoadmore) {
forOwn(notifications, function (value, key) {
if (has(logs, key)) {
notifications[key] = [...notifications[key], ...logs[key]]
delete logs[key]
}
try {
const response = await getList({
maxResultCount: itemsPerPage,
skipCount: page * itemsPerPage,
sorting: 'CreationTime DESC',
channels: filter,
isListRequest: true,
})
setNotifications(merge(notifications, logs))
} else {
setNotifications(logs)
const items = response.data?.items ?? []
const currentItemCount = page * itemsPerPage + items.length
setHasMore((response.data?.totalCount ?? 0) > currentItemCount)
const logs = groupBy(items, (a) => dayjs(a.creationTime).format('YYYY-MM-DD'))
if (isLoadmore) {
setNotifications((prev) => {
const next: NotificationGroups = { ...prev }
for (const [key, value] of Object.entries(logs)) {
next[key] = [...(next[key] ?? []), ...value]
}
return next
})
} else {
setNotifications(logs)
}
} finally {
setLoading(false)
}
setLoading(false)
}
}, [filter, page])
useEffect(() => {
fetchData(page > 0)
}, [page, filter])
}, [fetchData, page])
const handleFilterChange = (value: string[]) => {
setPage(0)
@ -111,13 +113,13 @@ const ActivityLog = () => {
<Log
notifications={notifications}
isLoading={loading}
onLoadMore={() => setPage((prev) => prev + 1)}
loadable={hasMore}
onLoadMore={() => setPage((prev) => prev + 1)}
></Log>
</div>
<div className="hidden lg:block">
<LogFilter filter={filter} onFilterChange={handleFilterChange} useAffix className="dark:bg-gray-800" />
<LogFilter useAffix filter={filter} className="dark:bg-gray-800" onFilterChange={handleFilterChange} />
</div>
</div>
</div>
@ -132,9 +134,9 @@ const ActivityLog = () => {
>
<LogFilter
filter={filter}
onFilterChange={handleFilterChange}
useAffix={false}
className="border-none p-0 dark:bg-gray-800"
onFilterChange={handleFilterChange}
/>
</Drawer>
</AdaptableCard>

View file

@ -5,7 +5,6 @@ import { AVATAR_URL } from '@/constants/app.constant'
import { NotificationDto } from '@/proxy/notification/models'
import { useLocalization } from '@/utils/hooks/useLocalization'
import dayjs from 'dayjs'
import { Dictionary } from 'lodash'
import isEmpty from 'lodash/isEmpty'
import keys from 'lodash/keys'
import Event from './Event'
@ -18,7 +17,7 @@ const Log = ({
isLoading,
loadable,
}: {
notifications: Dictionary<NotificationDto[]>
notifications: Record<string, NotificationDto[]>
onLoadMore: () => void
isLoading: boolean
loadable: boolean
@ -38,7 +37,7 @@ const Log = ({
{isEmpty(notifications[group]) ? (
<Timeline.Item className="dark:text-gray-400">Bildirim yok</Timeline.Item>
) : (
notifications[group].map((notification, i) => (
notifications[group].map((notification) => (
<Timeline.Item
key={notification.id}
media={
@ -57,7 +56,7 @@ const Log = ({
))}
<div className="text-center">
{loadable ? (
<Button size="sm" loading={isLoading} onClick={onLoadMore} variant='solid'>
<Button size="sm" loading={isLoading} variant='solid' onClick={onLoadMore}>
{translate('::Abp.Identity.ActivityLogs.LoadMore')}
</Button>
) : (

View file

@ -1,4 +1,4 @@
import { useState, useEffect, useCallback, useRef } from 'react'
import { useState, useEffect, useCallback, useRef, type MouseEvent } from 'react'
import { Helmet } from 'react-helmet'
import { Button, Input, Select, toast, Notification, Spinner } from '@/components/ui'
import { useStoreState } from '@/store'
@ -251,7 +251,7 @@ const FileManager = () => {
})
}
const handleItemDoubleClick = (item: FileItemType, event?: React.MouseEvent) => {
const handleItemDoubleClick = (item: FileItemType, event?: MouseEvent) => {
// Prevent text selection and other default behaviors
if (event) {
event.preventDefault()
@ -409,7 +409,7 @@ const FileManager = () => {
if (hasFiles) {
toast.push(
<Notification title="Security Warning" type="warning">
Folder '{item.name}' contains files and cannot be deleted for security reasons.
Folder {item.name} contains files and cannot be deleted for security reasons.
</Notification>,
)
return
@ -491,6 +491,8 @@ const FileManager = () => {
return () => {
document.removeEventListener('keydown', handleKeyDown)
}
// Keyboard shortcuts should bind once per selection/list state snapshot.
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [selectedItems, filteredItems])
// Bulk operations
@ -710,7 +712,7 @@ const FileManager = () => {
setLoading(false)
}
}
} catch (error) {
} catch {
toast.push(
<Notification title="Error" type="danger">
Invalid clipboard data
@ -738,18 +740,18 @@ const FileManager = () => {
<Button
variant="plain"
icon={<FaArrowUp />}
onClick={goUpOneLevel}
size="sm"
disabled={breadcrumbItems.length <= 1}
className="text-gray-600 hover:text-blue-600 flex-shrink-0"
title="Go up one level"
onClick={goUpOneLevel}
/>
<Button
variant="solid"
icon={<FaCloudUploadAlt />}
onClick={() => setUploadModalOpen(true)}
size="sm"
className="flex-shrink-0"
onClick={() => setUploadModalOpen(true)}
>
<span className="hidden sm:inline">{translate('::FileManager.UploadFiles')}</span>
<span className="sm:hidden">{translate('::FileManager.Upload')}</span>
@ -757,9 +759,9 @@ const FileManager = () => {
<Button
variant="default"
icon={<FaFolder />}
onClick={() => setCreateFolderModalOpen(true)}
size="sm"
className="flex-shrink-0"
onClick={() => setCreateFolderModalOpen(true)}
>
<span className="hidden sm:inline">{translate('::FileManager.CreateFolder')}</span>
<span className="sm:hidden">{translate('::FileManager.Create')}</span>
@ -769,33 +771,37 @@ const FileManager = () => {
<Button
variant="plain"
icon={<FaCopy />}
onClick={copySelectedItems}
disabled={selectedItems.length === 0}
size="sm"
className="text-gray-600 hover:text-blue-600 disabled:opacity-50 flex-shrink-0"
title={translate('::FileManager.CopySelectedItems')}
onClick={copySelectedItems}
/>
<Button
variant="plain"
icon={<FaCut />}
onClick={cutSelectedItems}
disabled={selectedItems.length === 0}
size="sm"
className="text-gray-600 hover:text-orange-600 disabled:opacity-50 flex-shrink-0"
title={translate('::FileManager.CutSelectedItems')}
onClick={cutSelectedItems}
/>
<Button
variant="plain"
icon={<FaPaste />}
onClick={pasteItems}
disabled={!hasClipboardData}
size="sm"
className="text-gray-600 hover:text-green-600 disabled:opacity-50 flex-shrink-0"
title={translate('::FileManager.PasteSelectedItems')}
onClick={pasteItems}
/>
<Button
variant="plain"
icon={<FaEdit />}
size="sm"
disabled={selectedItems.length !== 1}
className="text-gray-600 hover:text-blue-600 flex-shrink-0"
title={translate('::FileManager.RenameSelectedItem')}
onClick={() => {
if (selectedItems.length === 1) {
const itemToRename = filteredItems.find((item) => item.id === selectedItems[0])
@ -810,15 +816,21 @@ const FileManager = () => {
}
}
}}
size="sm"
disabled={selectedItems.length !== 1}
className="text-gray-600 hover:text-blue-600 flex-shrink-0"
title={translate('::FileManager.RenameSelectedItem')}
></Button>
<Button
variant="plain"
icon={<FaDownload />}
size="sm"
disabled={
selectedItems.length !== 1 ||
(() => {
const selectedItem = filteredItems.find((item) => item.id === selectedItems[0])
return selectedItem?.type !== 'file'
})()
}
className="text-gray-600 hover:text-green-600 flex-shrink-0"
title={translate('::FileManager.DownloadSelectedFile')}
onClick={() => {
if (selectedItems.length === 1) {
const itemToDownload = filteredItems.find((item) => item.id === selectedItems[0])
@ -833,26 +845,16 @@ const FileManager = () => {
}
}
}}
size="sm"
disabled={
selectedItems.length !== 1 ||
(() => {
const selectedItem = filteredItems.find((item) => item.id === selectedItems[0])
return selectedItem?.type !== 'file'
})()
}
className="text-gray-600 hover:text-green-600 flex-shrink-0"
title={translate('::FileManager.DownloadSelectedFile')}
></Button>
<Button
variant="plain"
icon={<FaTrash />}
onClick={deleteSelectedItems}
size="sm"
disabled={selectedItems.length === 0}
className="text-gray-600 hover:text-red-600 flex-shrink-0"
title={translate('::FileManager.DeleteSelectedItems')}
onClick={deleteSelectedItems}
>
<span>{translate('::Delete')}</span> {selectedItems.length > 0 && `(${selectedItems.length})`}
</Button>
@ -869,11 +871,6 @@ const FileManager = () => {
<FaSquare />
)
}
onClick={
selectedItems.length === filteredItems.filter((item) => !item.isReadOnly).length
? deselectAllItems
: selectAllItems
}
size="sm"
className="text-gray-600 hover:text-blue-600 flex-shrink-0"
title={
@ -881,6 +878,11 @@ const FileManager = () => {
? 'Deselect all selectable items'
: 'Select all selectable items'
}
onClick={
selectedItems.length === filteredItems.filter((item) => !item.isReadOnly).length
? deselectAllItems
: selectAllItems
}
>
<span className="hidden lg:inline">
{selectedItems.length === filteredItems.filter((item) => !item.isReadOnly).length
@ -904,9 +906,9 @@ const FileManager = () => {
size="sm"
placeholder={translate('::FileManager.SearchFiles')}
value={filters.searchTerm}
onChange={(e) => setFilters((prev) => ({ ...prev, searchTerm: e.target.value }))}
prefix={<FaSearch className="text-gray-400" />}
className="w-full sm:w-36 md:w-48"
onChange={(e) => setFilters((prev) => ({ ...prev, searchTerm: e.target.value }))}
/>
</div>
@ -954,15 +956,15 @@ const FileManager = () => {
size="sm"
icon={<FaTh />}
variant={viewMode === 'grid' ? 'solid' : 'default'}
onClick={() => setViewMode('grid')}
title="Grid view"
onClick={() => setViewMode('grid')}
/>
<Button
size="sm"
icon={<FaList />}
variant={viewMode === 'list' ? 'solid' : 'default'}
onClick={() => setViewMode('list')}
title="List view"
onClick={() => setViewMode('list')}
/>
</div>
</div>
@ -1131,40 +1133,40 @@ const FileManager = () => {
{/* Modals */}
<FileUploadModal
isOpen={uploadModalOpen}
onClose={() => setUploadModalOpen(false)}
onUpload={handleUploadFiles}
currentFolderId={currentFolderId}
loading={uploading}
onClose={() => setUploadModalOpen(false)}
onUpload={handleUploadFiles}
/>
<CreateFolderModal
isOpen={createFolderModalOpen}
onClose={() => setCreateFolderModalOpen(false)}
onCreate={handleCreateFolder}
loading={creating}
currentFolderId={currentFolderId}
onClose={() => setCreateFolderModalOpen(false)}
onCreate={handleCreateFolder}
/>
<RenameItemModal
isOpen={renameModalOpen}
item={itemToRename}
loading={renaming}
onClose={() => {
setRenameModalOpen(false)
setItemToRename(undefined)
}}
onRename={handleRenameItem}
item={itemToRename}
loading={renaming}
/>
<DeleteConfirmModal
isOpen={deleteModalOpen}
items={itemsToDelete}
loading={deleting}
onClose={() => {
setDeleteModalOpen(false)
setItemsToDelete([])
}}
onDelete={handleDeleteItems}
items={itemsToDelete}
loading={deleting}
/>
</Container>
)

View file

@ -27,7 +27,6 @@ const Breadcrumb = forwardRef<HTMLDivElement, BreadcrumbProps>((props, ref) => {
<FaFolder className="h-4 w-4 mr-1" />
)
}
onClick={() => onNavigate(item)}
className={classNames(
'flex items-center px-2 py-1 rounded hover:bg-gray-100 dark:hover:bg-gray-700 transition-colors',
index === items.length - 1
@ -35,6 +34,7 @@ const Breadcrumb = forwardRef<HTMLDivElement, BreadcrumbProps>((props, ref) => {
: 'text-gray-600 dark:text-gray-400 hover:text-gray-900 dark:hover:text-gray-100',
)}
disabled={index === items.length - 1}
onClick={() => onNavigate(item)}
>
<span className="truncate max-w-32">{item.name}</span>
</Button>

View file

@ -1,4 +1,4 @@
import { forwardRef, useState, useEffect } from 'react'
import { forwardRef, useState, useEffect, type ChangeEvent, type MouseEvent } from 'react'
import classNames from 'classnames'
import {
FaFolder,
@ -16,7 +16,6 @@ import {
FaLink,
} from 'react-icons/fa'
import { toast, Notification } from '@/components/ui'
// import { Dropdown } from '@/components/ui' // Artık kullanmıyoruz
import type { FileItem as FileItemType, FileActionMenuItem } from '@/types/fileManagement'
import { FILE_URL } from '@/constants/app.constant'
import { useLocalization } from '@/utils/hooks/useLocalization'
@ -26,7 +25,7 @@ export interface FileItemProps {
selected?: boolean
viewMode?: 'grid' | 'list'
onSelect?: (item: FileItemType) => void
onDoubleClick?: (item: FileItemType, event?: React.MouseEvent) => void
onDoubleClick?: (item: FileItemType, event?: MouseEvent) => void
onCreateFolder?: (parentItem: FileItemType) => void
onRename?: (item: FileItemType) => void
onMove?: (item: FileItemType) => void
@ -141,11 +140,11 @@ const FileItem = forwardRef<HTMLDivElement, FileItemProps>((props, ref) => {
onSelect?.(item)
}
const handleDoubleClick = (e: React.MouseEvent) => {
const handleDoubleClick = (e: MouseEvent) => {
onDoubleClick?.(item, e)
}
const handleContextMenu = (e: React.MouseEvent) => {
const handleContextMenu = (e: MouseEvent) => {
e.preventDefault()
e.stopPropagation()
@ -171,12 +170,12 @@ const FileItem = forwardRef<HTMLDivElement, FileItemProps>((props, ref) => {
}
}, [dropdownOpen])
const handleCheckboxChange = (e: React.ChangeEvent<HTMLInputElement>) => {
const handleCheckboxChange = (e: ChangeEvent<HTMLInputElement>) => {
e.stopPropagation() // Prevent item selection when clicking checkbox
onToggleSelect?.(item)
}
const handleCheckboxClick = (e: React.MouseEvent) => {
const handleCheckboxClick = (e: MouseEvent) => {
e.stopPropagation() // Prevent item selection when clicking checkbox
}
@ -216,7 +215,7 @@ const FileItem = forwardRef<HTMLDivElement, FileItemProps>((props, ref) => {
() => {
toast.push(
<Notification type="success" title="Başarılı">
Dosya URL'si panoya kopyalandı
Dosya URL&apos;si panoya kopyalandı
</Notification>,
)
},
@ -367,9 +366,9 @@ const FileItem = forwardRef<HTMLDivElement, FileItemProps>((props, ref) => {
<input
type="checkbox"
checked={selected}
className="w-4 h-4 text-blue-600 bg-gray-100 border-gray-300 rounded focus:ring-blue-500 dark:focus:ring-blue-600 dark:ring-offset-gray-800 focus:ring-2 dark:bg-gray-700 dark:border-gray-600"
onChange={handleCheckboxChange}
onClick={handleCheckboxClick}
className="w-4 h-4 text-blue-600 bg-gray-100 border-gray-300 rounded focus:ring-blue-500 dark:focus:ring-blue-600 dark:ring-offset-gray-800 focus:ring-2 dark:bg-gray-700 dark:border-gray-600"
/>
) : (
<div className="w-4 h-4" /> // Boş alan bırak
@ -464,9 +463,9 @@ const FileItem = forwardRef<HTMLDivElement, FileItemProps>((props, ref) => {
<input
type="checkbox"
checked={selected}
className="w-4 h-4 text-blue-600 bg-white border-gray-300 rounded focus:ring-blue-500 dark:focus:ring-blue-600 dark:ring-offset-gray-800 focus:ring-2 dark:bg-gray-700 dark:border-gray-600 shadow-sm"
onChange={handleCheckboxChange}
onClick={handleCheckboxClick}
className="w-4 h-4 text-blue-600 bg-white border-gray-300 rounded focus:ring-blue-500 dark:focus:ring-blue-600 dark:ring-offset-gray-800 focus:ring-2 dark:bg-gray-700 dark:border-gray-600 shadow-sm"
/>
</div>
)}

View file

@ -1,6 +1,5 @@
import { forwardRef, useState, useEffect } from 'react'
import { forwardRef, useState, useEffect, type FormEvent } from 'react'
import { Dialog, Button, Input, FormItem } from '@/components/ui'
import { FaTimes } from 'react-icons/fa'
import type { FileItem } from '@/types/fileManagement'
import { useLocalization } from '@/utils/hooks/useLocalization'
@ -20,7 +19,7 @@ export const CreateFolderModal = forwardRef<HTMLDivElement, CreateFolderModalPro
const [error, setError] = useState('')
const { translate } = useLocalization()
const handleSubmit = async (e: React.FormEvent) => {
const handleSubmit = async (e: FormEvent) => {
e.preventDefault()
if (!folderName.trim()) {
@ -33,7 +32,7 @@ export const CreateFolderModal = forwardRef<HTMLDivElement, CreateFolderModalPro
setFolderName('')
setError('')
onClose()
} catch (err) {
} catch {
setError('Failed to create folder')
}
}
@ -47,27 +46,27 @@ export const CreateFolderModal = forwardRef<HTMLDivElement, CreateFolderModalPro
return (
<Dialog isOpen={isOpen} onClose={handleClose}>
<div ref={ref}>
<form onSubmit={handleSubmit} className="py-6">
<form className="py-6" onSubmit={handleSubmit}>
<FormItem label={translate('::FileManager.FolderName')} invalid={!!error} errorMessage={error}>
<Input
value={folderName}
onChange={(e) => setFolderName(e.target.value)}
autoFocus
value={folderName}
className="mt-2"
onChange={(e) => setFolderName(e.target.value)}
/>
</FormItem>
</form>
<div className="flex justify-end space-x-2 pt-4 border-t">
<Button size='sm' variant="default" onClick={handleClose} disabled={loading}>
<Button size='sm' variant="default" disabled={loading} onClick={handleClose}>
{translate('::Cancel')}
</Button>
<Button
size='sm'
variant="solid"
onClick={handleSubmit}
loading={loading}
disabled={!folderName.trim()}
onClick={handleSubmit}
>
{translate('::FileManager.CreateFolder')}
</Button>
@ -102,7 +101,7 @@ export const RenameItemModal = forwardRef<HTMLDivElement, RenameItemModalProps>(
}
}, [item])
const handleSubmit = async (e: React.FormEvent) => {
const handleSubmit = async (e: FormEvent) => {
e.preventDefault()
if (!newName.trim()) {
@ -119,7 +118,7 @@ export const RenameItemModal = forwardRef<HTMLDivElement, RenameItemModalProps>(
await onRename(newName.trim())
setError('')
onClose()
} catch (err) {
} catch {
setError(`Failed to rename ${item?.type}`)
}
}
@ -141,31 +140,31 @@ export const RenameItemModal = forwardRef<HTMLDivElement, RenameItemModalProps>(
</h3>
</div>
<form onSubmit={handleSubmit} className="py-6">
<form className="py-6" onSubmit={handleSubmit}>
<FormItem
label={translate(`::FileManager.${item.type === 'folder' ? 'FolderName' : 'FileName'}`)}
invalid={!!error}
errorMessage={error}
>
<Input
value={newName}
onChange={(e) => setNewName(e.target.value)}
placeholder={`Enter ${translate(`::FileManager.${item.type === 'folder' ? 'FolderName' : 'FileName'}`)}`}
autoFocus
value={newName}
placeholder={`Enter ${translate(`::FileManager.${item.type === 'folder' ? 'FolderName' : 'FileName'}`)}`}
onChange={(e) => setNewName(e.target.value)}
/>
</FormItem>
</form>
<div className="flex justify-end space-x-2 pt-4 border-t">
<Button size='sm' variant="default" onClick={handleClose} disabled={loading}>
<Button size='sm' variant="default" disabled={loading} onClick={handleClose}>
{translate('::Cancel')}
</Button>
<Button
size='sm'
variant="solid"
onClick={handleSubmit}
loading={loading}
disabled={!newName.trim()}
onClick={handleSubmit}
>
{translate('::App.Listform.ListformField.Rename')}
</Button>
@ -195,7 +194,7 @@ export const DeleteConfirmModal = forwardRef<HTMLDivElement, DeleteConfirmModalP
try {
await onDelete()
onClose()
} catch (err) {
} catch {
// Error handling is done in parent component
}
}
@ -240,14 +239,14 @@ export const DeleteConfirmModal = forwardRef<HTMLDivElement, DeleteConfirmModalP
</div>
<div className="flex justify-end space-x-2 pt-4 border-t">
<Button size='sm' variant="default" onClick={onClose} disabled={loading}>
<Button size='sm' variant="default" disabled={loading} onClick={onClose}>
{translate('::Cancel')}
</Button>
<Button
size='sm'
variant="solid"
onClick={handleDelete}
loading={loading}
onClick={handleDelete}
>
{translate('::Delete')}
</Button>

View file

@ -1,4 +1,11 @@
import { forwardRef, useState, useCallback, useRef } from 'react'
import {
forwardRef,
useState,
useCallback,
useRef,
type ChangeEvent,
type DragEvent,
} from 'react'
import { Dialog, Button, Progress } from '@/components/ui'
import { FaCloudUploadAlt, FaTimes } from 'react-icons/fa'
import classNames from 'classnames'
@ -22,7 +29,7 @@ interface UploadFileWithProgress {
}
const FileUploadModal = forwardRef<HTMLDivElement, FileUploadModalProps>((props, ref) => {
const { isOpen, onClose, onUpload, currentFolderId, loading = false, className } = props
const { isOpen, onClose, onUpload, className } = props
const [uploadFiles, setUploadFiles] = useState<UploadFileWithProgress[]>([])
const [isDragOver, setIsDragOver] = useState(false)
@ -53,24 +60,24 @@ const FileUploadModal = forwardRef<HTMLDivElement, FileUploadModalProps>((props,
setUploadFiles((prev) => [...prev, ...newFiles])
}, [])
const handleFileInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
const handleFileInputChange = (e: ChangeEvent<HTMLInputElement>) => {
if (e.target.files) {
handleFilesSelect(e.target.files)
}
}
const handleDragOver = useCallback((e: React.DragEvent) => {
const handleDragOver = useCallback((e: DragEvent) => {
e.preventDefault()
setIsDragOver(true)
}, [])
const handleDragLeave = useCallback((e: React.DragEvent) => {
const handleDragLeave = useCallback((e: DragEvent) => {
e.preventDefault()
setIsDragOver(false)
}, [])
const handleDrop = useCallback(
(e: React.DragEvent) => {
(e: DragEvent) => {
e.preventDefault()
setIsDragOver(false)
@ -216,10 +223,6 @@ const FileUploadModal = forwardRef<HTMLDivElement, FileUploadModalProps>((props,
}
}
const clearCompletedFiles = () => {
setUploadFiles((prev) => prev.filter((f) => f.status !== 'completed'))
}
const clearErrorFiles = () => {
setUploadFiles((prev) => prev.filter((f) => f.status !== 'error'))
}
@ -231,7 +234,7 @@ const FileUploadModal = forwardRef<HTMLDivElement, FileUploadModalProps>((props,
const hasError = errorFiles > 0
return (
<Dialog isOpen={isOpen} onClose={handleClose} className={className}>
<Dialog isOpen={isOpen} className={className} onClose={handleClose}>
<div ref={ref}>
<div className="flex items-center justify-between pb-2 border-b">
<h3 className="text-lg font-semibold">Upload Files</h3>
@ -251,11 +254,11 @@ const FileUploadModal = forwardRef<HTMLDivElement, FileUploadModalProps>((props,
>
<input
ref={fileInputRef}
type="file"
multiple
type="file"
className="absolute inset-0 w-full h-full opacity-0 cursor-pointer"
onChange={handleFileInputChange}
disabled={uploading}
onChange={handleFileInputChange}
/>
<FaCloudUploadAlt className="mx-auto h-12 w-12 text-gray-400 mb-4" />
@ -318,9 +321,9 @@ const FileUploadModal = forwardRef<HTMLDivElement, FileUploadModalProps>((props,
variant="plain"
size="sm"
icon={<FaTimes />}
onClick={() => removeFile(file.id)}
disabled={uploading}
className="ml-2 flex-shrink-0"
onClick={() => removeFile(file.id)}
/>
)}
</div>
@ -349,21 +352,21 @@ const FileUploadModal = forwardRef<HTMLDivElement, FileUploadModalProps>((props,
{hasError && !uploading && (
<Button
variant="plain"
onClick={clearErrorFiles}
className="text-red-600 hover:text-red-700"
onClick={clearErrorFiles}
>
Clear Errors
</Button>
)}
<Button size="sm" variant="default" onClick={handleClose} disabled={uploading}>
<Button size="sm" variant="default" disabled={uploading} onClick={handleClose}>
{uploading ? 'Uploading...' : 'Close'}
</Button>
<Button
size="sm"
variant="solid"
onClick={handleUpload}
disabled={pendingFiles === 0 || uploading}
loading={uploading}
onClick={handleUpload}
>
{uploading ? 'Uploading...' : `Upload ${pendingFiles} File(s)`}
</Button>

View file

@ -1,4 +1,15 @@
import { useCallback, useEffect, useMemo, useRef, useState } from 'react'
import {
type Dispatch,
type MutableRefObject,
type SetStateAction,
type WheelEvent,
type MouseEvent as ReactMouseEvent,
useCallback,
useEffect,
useMemo,
useRef,
useState,
} from 'react'
import {
FaSitemap,
FaBriefcase,
@ -19,11 +30,10 @@ import {
OrgChartUserDto,
} from '@/services/orgChart.service'
import { useLocalization } from '@/utils/hooks/useLocalization'
import { APP_NAME } from '@/constants/app.constant'
import { AVATAR_URL, APP_NAME } from '@/constants/app.constant'
import Loading from '@/components/shared/Loading'
import { useCurrentMenuIcon } from '@/utils/hooks/useCurrentMenuIcon'
import { Avatar, Button } from '@/components/ui'
import { AVATAR_URL } from '@/constants/app.constant'
import { useStoreState } from '@/store'
import UserProfileCard from '@/views/intranet/SocialWall/UserProfileCard'
@ -436,9 +446,9 @@ function OrgChartNode({
tenantId?: string
zoom: number
positions: PositionMap
setPositions: React.Dispatch<React.SetStateAction<PositionMap>>
nodeRefs: React.MutableRefObject<NodeRefMap>
cardRefs: React.MutableRefObject<CardRefMap>
setPositions: Dispatch<SetStateAction<PositionMap>>
nodeRefs: MutableRefObject<NodeRefMap>
cardRefs: MutableRefObject<CardRefMap>
requestRepaint: () => void
applySelfTransform?: boolean
}) {
@ -451,9 +461,8 @@ function OrgChartNode({
const levelColor = LEVEL_COLORS[depth % LEVEL_COLORS.length]
const borderColor = levelColor.border
const headerBg = levelColor.header
const badgeBg = levelColor.badge
const handleDragStart = (e: React.MouseEvent<HTMLDivElement>) => {
const handleDragStart = (e: ReactMouseEvent<HTMLDivElement>) => {
const target = e.target as HTMLElement
if (target.closest('[data-stop-drag="true"]')) {
return
@ -508,12 +517,12 @@ function OrgChartNode({
ref={(el) => {
cardRefs.current[node.id] = el
}}
onMouseDown={handleDragStart}
data-card=""
data-depth={depth}
data-users-visible={showUsers ? 'true' : 'false'}
className={`relative bg-white border ${borderColor} rounded-xl shadow-sm w-36 sm:w-44 md:w-52 hover:shadow-md transition-shadow`}
style={{ cursor: dragging ? 'grabbing' : 'grab' }}
onMouseDown={handleDragStart}
>
{/* Header bar */}
<div
@ -534,10 +543,6 @@ function OrgChartNode({
{hasChildren && (
<Button
data-stop-drag="true"
onClick={() => {
setCollapsed((c) => !c)
requestRepaint()
}}
variant="plain"
shape="circle"
icon={
@ -548,6 +553,10 @@ function OrgChartNode({
)
}
className="ml-1 !h-5 !w-5 flex-shrink-0 !px-0 text-white opacity-70 transition-opacity hover:opacity-100"
onClick={() => {
setCollapsed((c) => !c)
requestRepaint()
}}
></Button>
)}
</div>
@ -590,7 +599,7 @@ function OrgChartNode({
{/* Children */}
{hasChildren && !collapsed && (
<div className="mt-6 sm:mt-8 md:mt-10 flex items-start gap-4 sm:gap-6 md:gap-10">
{node.children.map((child, idx) => {
{node.children.map((child) => {
const childPosition = positions[child.id] ?? { x: 0, y: 0 }
return (
@ -639,7 +648,7 @@ function OrgChartTree({
tenantId?: string
zoom: number
positions: PositionMap
setPositions: React.Dispatch<React.SetStateAction<PositionMap>>
setPositions: Dispatch<SetStateAction<PositionMap>>
edges: EdgeLink[]
}) {
const containerRef = useRef<HTMLDivElement>(null)
@ -836,7 +845,7 @@ const OrgChart = () => {
setPositions({})
}, [mode])
const handleWheelZoom = (e: React.WheelEvent<HTMLDivElement>) => {
const handleWheelZoom = (e: WheelEvent<HTMLDivElement>) => {
if (!e.ctrlKey) {
return
}
@ -882,7 +891,6 @@ const OrgChart = () => {
<div className="flex flex-wrap items-center gap-2">
<div className="flex items-center bg-slate-100 dark:bg-gray-800 rounded-lg p-1 gap-1">
<Button
onClick={() => setMode('department')}
variant="plain"
shape="none"
icon={<FaBuilding className="h-3.5 w-3.5 flex-shrink-0" />}
@ -892,13 +900,13 @@ const OrgChart = () => {
? '!bg-blue-600 !text-white shadow-sm ring-1 ring-blue-300/70 dark:ring-blue-400/70'
: '!bg-transparent text-slate-600 hover:!bg-white hover:text-slate-800 dark:text-gray-300 dark:hover:!bg-gray-700 dark:hover:text-white'
}`}
onClick={() => setMode('department')}
>
<span className="hidden sm:inline">
{translate('::App.Hr.Department') || 'Departman'}
</span>
</Button>
<Button
onClick={() => setMode('jobPosition')}
variant="plain"
shape="none"
icon={<FaBriefcase className="h-3.5 w-3.5 flex-shrink-0" />}
@ -908,6 +916,7 @@ const OrgChart = () => {
? '!bg-purple-600 !text-white shadow-sm ring-1 ring-purple-300/70 dark:ring-purple-400/70'
: '!bg-transparent text-slate-600 hover:!bg-white hover:text-slate-800 dark:text-gray-300 dark:hover:!bg-gray-700 dark:hover:text-white'
}`}
onClick={() => setMode('jobPosition')}
>
<span className="hidden sm:inline">
{translate('::App.Hr.JobPosition') || 'Pozisyon'}
@ -920,8 +929,8 @@ const OrgChart = () => {
<input
type="checkbox"
checked={showUsers}
onChange={(e) => setShowUsers(e.target.checked)}
className="h-4 w-4 rounded border-slate-300 dark:border-gray-600 text-blue-600 focus:ring-blue-500"
onChange={(e) => setShowUsers(e.target.checked)}
/>
<span className="hidden sm:inline">
{translate('::App.Definitions.OrgChart.ShowUsers') || 'Kullanıcılar'}
@ -931,42 +940,42 @@ const OrgChart = () => {
<div className="flex items-center bg-slate-100 dark:bg-gray-800 rounded-lg p-1 gap-1">
<Button
onClick={handleZoomOut}
variant="plain"
shape="none"
icon={<FaSearchMinus className="h-3.5 w-3.5" />}
className="!h-7 !w-7 !rounded-md !px-0 text-slate-600 hover:!bg-white hover:text-slate-800 dark:text-gray-300 dark:hover:!bg-gray-700 dark:hover:text-white sm:!h-8 sm:!w-8"
title="Zoom Out"
onClick={handleZoomOut}
/>
<span className="text-xs font-medium text-slate-600 dark:text-gray-300 px-1 min-w-[36px] sm:min-w-[46px] text-center">
{Math.round(zoom * 100)}%
</span>
<Button
onClick={handleZoomIn}
variant="plain"
shape="none"
icon={<FaSearchPlus className="h-3.5 w-3.5" />}
className="!h-7 !w-7 !rounded-md !px-0 text-slate-600 hover:!bg-white hover:text-slate-800 dark:text-gray-300 dark:hover:!bg-gray-700 dark:hover:text-white sm:!h-8 sm:!w-8"
title="Zoom In"
onClick={handleZoomIn}
/>
<Button
onClick={handleZoomReset}
variant="plain"
shape="none"
icon={<FaUndo className="h-3.5 w-3.5" />}
className="!h-7 !w-7 !rounded-md !px-0 text-slate-600 hover:!bg-white hover:text-slate-800 dark:text-gray-300 dark:hover:!bg-gray-700 dark:hover:text-white sm:!h-8 sm:!w-8"
title="Reset Zoom"
onClick={handleZoomReset}
/>
</div>
<Button
onClick={handleExportJpg}
disabled={exporting || loading}
variant="plain"
shape="none"
icon={<FaFileImage className="h-3.5 w-3.5 flex-shrink-0" />}
className="!inline-flex !h-auto !items-center !justify-center gap-1.5 !rounded-lg bg-slate-100 !p-1.5 text-xs font-medium text-slate-600 transition-colors hover:!bg-slate-200 disabled:opacity-50 dark:bg-gray-800 dark:text-gray-300 dark:hover:!bg-gray-700 sm:!p-2 sm:text-sm"
title="JPG olarak indir"
onClick={handleExportJpg}
>
<span className="hidden sm:inline">{exporting ? 'İşleniyor…' : 'Export'}</span>
</Button>

View file

@ -1,4 +1,4 @@
import { Card, Checkbox, FormContainer, FormItem, Input, Select, Button } from '@/components/ui'
import { Checkbox, FormContainer, FormItem, Input, Select, Button } from '@/components/ui'
import { SelectBoxOption } from '@/types/shared'
import { Field, FieldProps, Form, Formik } from 'formik'
import { object } from 'yup'
@ -26,7 +26,7 @@ function ChartTabAnimation(props: FormEditProps) {
await props.onSubmit(ListFormEditTabs.ChartAnimationForm, values, formikHelpers)
}}
>
{({ touched, errors, resetForm, isSubmitting, values }) => (
{({ touched, errors, isSubmitting, values }) => (
<Form>
<FormContainer size="sm">
<FormItem
@ -79,7 +79,7 @@ function ChartTabAnimation(props: FormEditProps) {
<Field type="number" name="animationDto.maxPointCountSupported" component={Input} />
</FormItem>
<div className="mt-4">
<Button size="sm" block variant="solid" loading={isSubmitting} type="submit">
<Button block size="sm" variant="solid" loading={isSubmitting} type="submit">
{isSubmitting ? translate('::Saving') : translate('::Save')}
</Button>
</div>

View file

@ -68,7 +68,7 @@ function ChartTabAnnotations(props: FormEditProps) {
)
}}
>
{({ touched, errors, resetForm, isSubmitting, values }) => (
{({ touched, errors, isSubmitting, values }) => (
<Form>
<FormContainer size="sm">
<Tabs defaultValue="annotations_general">
@ -121,7 +121,7 @@ function ChartTabAnnotations(props: FormEditProps) {
size="sm"
title="Edit"
icon={<FaEdit />}
onClick={async (e) => {
onClick={async () => {
setJsonRowOpModalData({
tabName: ListFormEditTabs.ChartAnnotations.GeneralJsonRow,
operation: 'update',
@ -660,7 +660,7 @@ function ChartTabAnnotations(props: FormEditProps) {
</TabContent>
</Tabs>
<div className="mt-4">
<Button size="sm" block variant="solid" loading={isSubmitting} type="submit">
<Button block size="sm" variant="solid" loading={isSubmitting} type="submit">
{isSubmitting ? translate('::Saving') : translate('::Save')}
</Button>
</div>

View file

@ -60,7 +60,7 @@ function ChartTabAxis(props: FormEditProps) {
await props.onSubmit(ListFormEditTabs.ChartAxis.CommonAxisForm, values, formikHelpers)
}}
>
{({ touched, errors, resetForm, isSubmitting, values }) => (
{({ touched, errors, isSubmitting, values }) => (
<Form>
<FormContainer size="sm">
<Tabs defaultValue="axis_value">
@ -114,7 +114,7 @@ function ChartTabAxis(props: FormEditProps) {
size="sm"
title="Edit"
icon={<FaEdit />}
onClick={async (e) => {
onClick={async () => {
setJsonRowOpModalData({
tabName: ListFormEditTabs.ChartAxis.ValueAxisJsonRow,
operation: 'update',
@ -541,7 +541,7 @@ function ChartTabAxis(props: FormEditProps) {
</TabContent>
</Tabs>
<div className="mt-4">
<Button size="sm" block variant="solid" loading={isSubmitting} type="submit">
<Button block size="sm" variant="solid" loading={isSubmitting} type="submit">
{isSubmitting ? translate('::Saving') : translate('::Save')}
</Button>
</div>

View file

@ -13,7 +13,7 @@ import TabList from '@/components/ui/Tabs/TabList'
import TabNav from '@/components/ui/Tabs/TabNav'
import { IdentityRoleDto } from '@/proxy/admin/models'
import { SelectBoxOption } from '@/types/shared'
import { Field, FieldProps, Form, Formik, FormikErrors, FormikTouched } from 'formik'
import { Field, FieldProps, Form, Formik } from 'formik'
import { FormEditProps } from '../../listForm/edit/FormEdit'
import { useLocalization } from '@/utils/hooks/useLocalization'
import { useStoreState } from '@/store/store'
@ -53,7 +53,7 @@ function ChartTabCommonSettings(props: FormEditProps) {
await props.onSubmit(ListFormEditTabs.ChartCommon, values, formikHelpers)
}}
>
{({ touched, errors, resetForm, isSubmitting, values }) => (
{({ touched, errors, isSubmitting, values }) => (
<Form>
<FormContainer size="sm">
<Tabs defaultValue="commonSettings_general">
@ -716,7 +716,7 @@ function ChartTabCommonSettings(props: FormEditProps) {
</TabContent>
</Tabs>
<div className="mt-4">
<Button size="sm" block variant="solid" loading={isSubmitting} type="submit">
<Button block size="sm" variant="solid" loading={isSubmitting} type="submit">
{isSubmitting ? translate('::Saving') : translate('::Save')}
</Button>
</div>

View file

@ -26,7 +26,7 @@ function ChartTabCrosshair(props: FormEditProps) {
await props.onSubmit(ListFormEditTabs.ChartCrosshairForm, values, formikHelpers)
}}
>
{({ touched, errors, resetForm, isSubmitting, values }) => (
{({ touched, errors, isSubmitting, values }) => (
<Form>
<FormContainer size="sm">
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-5 gap-3">
@ -336,7 +336,7 @@ function ChartTabCrosshair(props: FormEditProps) {
</Card>
</div>
<div className="mt-4">
<Button size="sm" block variant="solid" loading={isSubmitting} type="submit">
<Button block size="sm" variant="solid" loading={isSubmitting} type="submit">
{isSubmitting ? translate('::Saving') : translate('::Save')}
</Button>
</div>

View file

@ -1,4 +1,4 @@
import { Button, Card, Checkbox, FormContainer, FormItem, Input } from '@/components/ui'
import { Button, Checkbox, FormContainer, FormItem, Input } from '@/components/ui'
import { Field, FieldProps, Form, Formik } from 'formik'
import { FormEditProps } from '../../listForm/edit/FormEdit'
import { useLocalization } from '@/utils/hooks/useLocalization'
@ -24,7 +24,7 @@ function ChartTabExport(props: FormEditProps) {
await props.onSubmit(ListFormEditTabs.ChartExportForm, values, formikHelpers)
}}
>
{({ touched, errors, resetForm, isSubmitting, values }) => (
{({ touched, errors, isSubmitting }) => (
<Form>
<FormContainer size="sm">
<FormItem label="Enabled">
@ -65,7 +65,7 @@ function ChartTabExport(props: FormEditProps) {
</FormItem>
<div className="mt-4">
<Button size="sm" block variant="solid" loading={isSubmitting} type="submit">
<Button block size="sm" variant="solid" loading={isSubmitting} type="submit">
{isSubmitting ? translate('::Saving') : translate('::Save')}
</Button>
</div>

View file

@ -5,12 +5,8 @@ import {
FormContainer,
FormItem,
Input,
Select,
Tabs,
Select
} from '@/components/ui'
import TabContent from '@/components/ui/Tabs/TabContent'
import TabList from '@/components/ui/Tabs/TabList'
import TabNav from '@/components/ui/Tabs/TabNav'
import { SelectBoxOption } from '@/types/shared'
import { Field, FieldProps, Form, Formik } from 'formik'
import { FormEditProps } from '../../listForm/edit/FormEdit'
@ -42,7 +38,7 @@ function ChartTabLegend(props: FormEditProps) {
await props.onSubmit(ListFormEditTabs.ChartLegendForm, values, formikHelpers)
}}
>
{({ touched, errors, resetForm, isSubmitting, values }) => (
{({ touched, errors, isSubmitting, values }) => (
<Form>
<FormContainer size="sm">
<div className="grid grid-cols-1 md:grid-cols-2 gap-3">
@ -216,7 +212,7 @@ function ChartTabLegend(props: FormEditProps) {
</Card>
</div>
<div className="mt-4">
<Button size="sm" block variant="solid" loading={isSubmitting} type="submit">
<Button block size="sm" variant="solid" loading={isSubmitting} type="submit">
{isSubmitting ? translate('::Saving') : translate('::Save')}
</Button>
</div>

View file

@ -43,7 +43,7 @@ function ChartTabPanes(props: FormEditProps) {
)
}}
>
{({ touched, errors, resetForm, isSubmitting, values }) => (
{({ touched, errors, isSubmitting }) => (
<Form>
<FormContainer size="sm">
<Card className="my-2">
@ -110,7 +110,7 @@ function ChartTabPanes(props: FormEditProps) {
size="sm"
title="Edit"
icon={<FaEdit />}
onClick={async (e) => {
onClick={async () => {
setJsonRowOpModalData({
tabName: ListFormEditTabs.ChartPanes.PanesJsonRow,
operation: 'update',
@ -155,7 +155,7 @@ function ChartTabPanes(props: FormEditProps) {
setData={setJsonRowOpModalData}
/>
<div className="mt-4">
<Button size="sm" block variant="solid" loading={isSubmitting} type="submit">
<Button block size="sm" variant="solid" loading={isSubmitting} type="submit">
{isSubmitting ? translate('::Saving') : translate('::Save')}
</Button>
</div>

View file

@ -34,7 +34,7 @@ import {
chartSeriesSelectionModeOptions,
chartSeriesDashStyleOptions,
} from './options'
import { useEffect, useState } from 'react'
import { useCallback, useEffect, useMemo, useState } from 'react'
import { JsonRowDialogData } from './json-row-operations/types'
import JsonRowOpDialogSeries from './json-row-operations/JsonRowOpDialogSeries'
import CreatableSelect from 'react-select/creatable'
@ -52,25 +52,22 @@ function ChartTabSeries(props: FormEditProps & { listFormCode: string }) {
const [fieldList, setFieldList] = useState<SelectBoxOption[]>([])
const listFormValues = useStoreState((s) => s.admin.lists.values)
if (!listFormValues) {
return null
}
const valueAxisList = () => {
return listFormValues?.valueAxisDto.map((key: ChartValueAxisDto) => ({
const valueAxisList = useMemo(() => {
return (listFormValues?.valueAxisDto ?? []).map((key: ChartValueAxisDto) => ({
value: key.name,
label: key.name,
}))
}
}, [listFormValues?.valueAxisDto])
const valuePaneList = () => {
return listFormValues?.panesDto.map((key: ChartPanesDto) => ({
const valuePaneList = useMemo(() => {
return (listFormValues?.panesDto ?? []).map((key: ChartPanesDto) => ({
value: key.name,
label: key.name,
}))
}
}, [listFormValues?.panesDto])
const getFields = async () => {
const getFields = useCallback(async () => {
if (!props.listFormCode) {
return
}
@ -101,13 +98,17 @@ function ChartTabSeries(props: FormEditProps & { listFormCode: string }) {
},
)
}
}
}, [props.listFormCode])
useEffect(() => {
if (props.listFormCode) {
getFields()
}
}, [props.listFormCode])
}, [getFields, props.listFormCode])
if (!listFormValues) {
return null
}
return (
<Formik
@ -121,7 +122,7 @@ function ChartTabSeries(props: FormEditProps & { listFormCode: string }) {
)
}}
>
{({ touched, errors, resetForm, isSubmitting, values }) => (
{({ touched, errors, isSubmitting, values }) => (
<Form>
<FormContainer size="sm">
<Tabs defaultValue="series_general">
@ -176,7 +177,7 @@ function ChartTabSeries(props: FormEditProps & { listFormCode: string }) {
size="sm"
title="Edit"
icon={<FaEdit />}
onClick={async (e) => {
onClick={async () => {
setJsonRowOpModalData({
tabName: ListFormEditTabs.ChartSeries.GeneralJsonRow,
operation: 'update',
@ -346,9 +347,9 @@ function ChartTabSeries(props: FormEditProps & { listFormCode: string }) {
(option) =>
option.value === values.commonSeriesSettingsDto.argumentField,
)}
onChange={(option) => form.setFieldValue(field.name, option?.value)}
menuPlacement="auto"
maxMenuHeight={150}
onChange={(option) => form.setFieldValue(field.name, option?.value)}
/>
)}
</Field>
@ -362,7 +363,7 @@ function ChartTabSeries(props: FormEditProps & { listFormCode: string }) {
}
errorMessage={errors.commonSeriesSettingsDto?.valueField}
>
<Field type="text" name="valueField">
<Field type="text" name="commonSeriesSettingsDto.valueField">
{({ field, form }: FieldProps<SelectBoxOption>) => (
<Select
componentAs={CreatableSelect}
@ -374,9 +375,9 @@ function ChartTabSeries(props: FormEditProps & { listFormCode: string }) {
(option) =>
option.value === values.commonSeriesSettingsDto.valueField,
)}
onChange={(option) => form.setFieldValue(field.name, option?.value)}
menuPlacement="auto"
maxMenuHeight={150}
onChange={(option) => form.setFieldValue(field.name, option?.value)}
/>
)}
</Field>
@ -398,9 +399,9 @@ function ChartTabSeries(props: FormEditProps & { listFormCode: string }) {
<Select
field={field}
form={form}
options={valueAxisList()}
options={valueAxisList}
isClearable={true}
value={valueAxisList()?.find(
value={valueAxisList.find(
(option) => option.value === values.commonSeriesSettingsDto.axis,
)}
onChange={(option) => form.setFieldValue(field.name, option?.value)}
@ -424,9 +425,9 @@ function ChartTabSeries(props: FormEditProps & { listFormCode: string }) {
<Select
field={field}
form={form}
options={valuePaneList()}
options={valuePaneList}
isClearable={true}
value={valuePaneList()?.find(
value={valuePaneList.find(
(option) => option.value === values.commonSeriesSettingsDto.pane,
)}
onChange={(option) => form.setFieldValue(field.name, option?.value)}
@ -523,7 +524,7 @@ function ChartTabSeries(props: FormEditProps & { listFormCode: string }) {
</TabContent>
</Tabs>
<div className="mt-4">
<Button size="sm" block variant="solid" loading={isSubmitting} type="submit">
<Button block size="sm" variant="solid" loading={isSubmitting} type="submit">
{isSubmitting ? translate('::Saving') : translate('::Save')}
</Button>
</div>

View file

@ -26,7 +26,7 @@ const ChartTabZoomAndPan = (props: FormEditProps) => {
await props.onSubmit(ListFormEditTabs.ChartZoomForm, values, formikHelpers)
}}
>
{({ touched, errors, resetForm, isSubmitting, values }) => (
{({ touched, errors, isSubmitting, values }) => (
<Form>
<FormContainer size="sm">
<div className="grid grid-cols-1 md:grid-cols-2 gap-3">
@ -176,7 +176,7 @@ const ChartTabZoomAndPan = (props: FormEditProps) => {
</Card>
</div>
<div className="mt-4">
<Button size="sm" block variant="solid" loading={isSubmitting} type="submit">
<Button block size="sm" variant="solid" loading={isSubmitting} type="submit">
{isSubmitting ? translate('::Saving') : translate('::Save')}
</Button>
</div>

View file

@ -294,7 +294,7 @@ function FormCustomization({
/>
</FormItem>
<Button size="sm" block variant="solid" loading={isSubmitting} type="submit">
<Button block size="sm" variant="solid" loading={isSubmitting} type="submit">
{isSubmitting ? translate('::Saving') : translate('::Save')}
</Button>
</FormContainer>

View file

@ -1,4 +1,4 @@
import { Alert, Badge, Notification, Tabs, toast } from '@/components/ui'
import { Badge, Notification, Tabs, toast } from '@/components/ui'
import TabContent from '@/components/ui/Tabs/TabContent'
import TabList from '@/components/ui/Tabs/TabList'
import TabNav from '@/components/ui/Tabs/TabNav'
@ -7,7 +7,7 @@ import { SelectBoxOption } from '@/types/shared'
import { useStoreActions, useStoreState } from '@/store'
import { useLocalization } from '@/utils/hooks/useLocalization'
import { FormikHelpers } from 'formik'
import { useEffect, useState } from 'react'
import { useCallback, useEffect, useState } from 'react'
import { Helmet } from 'react-helmet'
import { Link, useParams } from 'react-router-dom'
import FormCustomization from './FormCustomization'
@ -27,8 +27,7 @@ import FormTabSubForm from './FormTabSubForm'
import FormFields from './form-fields/FormFields'
import { putListForms } from '@/services/admin/list-form.service'
import { getRoles, getUsers } from '@/services/identity.service'
import { GridOptionsEditDto, ListFormCustomizationDto } from '@/proxy/form/models'
import { SelectCommandTypeEnum } from '@/proxy/form/models'
import { SelectCommandTypeEnum, GridOptionsEditDto, ListFormCustomizationDto } from '@/proxy/form/models'
import { IdentityRoleDto, IdentityUserDto } from '@/proxy/admin/models'
import { getListFormCustomizations } from '@/services/admin/list-form-customization.service'
import { sqlObjectManagerService } from '@/services/sql-query-manager.service'
@ -95,7 +94,7 @@ const FormEdit = () => {
}
}, [languages])
const getRoleList = async () => {
const getRoleList = useCallback(async () => {
const response = await getRoles()
if (response.data?.items) {
setRoleList(
@ -105,9 +104,9 @@ const FormEdit = () => {
})),
)
}
}
}, [])
const getUserList = async () => {
const getUserList = useCallback(async () => {
const response = await getUsers(0, 1000)
if (response.data?.items) {
setUserList(
@ -117,17 +116,17 @@ const FormEdit = () => {
})),
)
}
}
}, [])
const getCustomizations = async () => {
const getCustomizations = useCallback(async () => {
if (!listFormCode) {
return
}
const resp = await getListFormCustomizations({ listFormCode, maxResultCount: 1000 })
setCustomizations(resp?.data?.items)
}
}, [listFormCode])
const refreshData = async () => {
const refreshData = useCallback(async () => {
if (!listFormCode) {
return
}
@ -135,7 +134,7 @@ const FormEdit = () => {
await getCustomizations()
await getRoleList()
await getUserList()
}
}, [getCustomizations, getListFormValues, getRoleList, getUserList, listFormCode])
const listFormType = listFormValues?.listFormType || 'List'
const [activeFormType, setActiveFormType] = useState<string>(listFormType)
@ -144,7 +143,7 @@ const FormEdit = () => {
//LİST FORM ve LİST FORM FİELDS AİT BİLGİLER
useEffect(() => {
refreshData()
}, [listFormCode])
}, [refreshData])
useEffect(() => {
const loadWorkflowColumns = async () => {
@ -378,9 +377,9 @@ const FormEdit = () => {
<TabContent value="details" className="px-2">
<FormTabDetails
onSubmit={onSubmit}
roleList={roleList}
userList={userList}
onSubmit={onSubmit}
onFormTypeChange={setActiveFormType}
/>
</TabContent>
@ -442,7 +441,7 @@ const FormEdit = () => {
<FormTabSubForm />
</TabContent>
<TabContent value="widget" className="px-2">
<FormTabWidgets listFormCode={listFormCode} />
<FormTabWidgets />
</TabContent>
<TabContent value="workflow" className="px-2">
<FormTabWorkflow
@ -478,7 +477,7 @@ const FormEdit = () => {
<ChartTabCommonSettings onSubmit={onSubmit} />
</TabContent>
<TabContent value="series" className="px-2">
<ChartTabSeries onSubmit={onSubmit} listFormCode={listFormCode} />
<ChartTabSeries listFormCode={listFormCode} onSubmit={onSubmit} />
</TabContent>
<TabContent value="panes" className="px-2">
<ChartTabPanes onSubmit={onSubmit} />

View file

@ -1,13 +1,10 @@
import { Container } from '@/components/shared'
import {
Button,
Card,
Checkbox,
FormContainer,
FormItem,
Input,
Select,
Tabs,
} from '@/components/ui'
import { ListFormEditTabs } from '@/proxy/admin/list-form/options'
import { useStoreState } from '@/store'
@ -310,7 +307,7 @@ function FormTabColumns(props: FormEditProps) {
</div>
</div>
<Button size="sm" block variant="solid" loading={isSubmitting} type="submit" className="my-2">
<Button block size="sm" variant="solid" loading={isSubmitting} type="submit" className="my-2">
{isSubmitting ? translate('::Saving') : translate('::Save')}
</Button>
</FormContainer>

View file

@ -78,7 +78,7 @@ function FormTabCommands() {
size="sm"
title="Edit"
icon={<FaEdit />}
onClick={async (e) => {
onClick={async () => {
setJsonRowOpModalData({
tabName: ListFormEditTabs.CommandColumnsJsonRow,
operation: 'update',

View file

@ -263,10 +263,10 @@ function FormTabDatabaseDataSource(props: FormEditProps) {
: []
return (
<Select
isClearable
componentAs={CreatableSelect}
field={field}
form={form}
isClearable
isLoading={isLoadingDbObjects}
options={grouped}
placeholder={
@ -346,10 +346,10 @@ function FormTabDatabaseDataSource(props: FormEditProps) {
<Field type="text" autoComplete="off" name="keyFieldName">
{({ field, form }: FieldProps<string>) => (
<Select
isClearable
componentAs={CreatableSelect}
field={field}
form={form}
isClearable
isLoading={isLoadingColumns}
placeholder={
isLoadingColumns
@ -387,7 +387,7 @@ function FormTabDatabaseDataSource(props: FormEditProps) {
</FormItem>
</Card>
<Button size="sm" block variant="solid" loading={isSubmitting}>
<Button block size="sm" variant="solid" loading={isSubmitting}>
{isSubmitting ? translate('::Saving') : translate('::Save')}
</Button>
</FormContainer>

View file

@ -48,7 +48,7 @@ function FormTabDatabaseDelete({
await onSubmit(ListFormEditTabs.Database.Delete.DeleteForm, values, formikHelpers)
}}
>
{({ touched, errors, values, isSubmitting }) => (
{({ touched, errors, isSubmitting }) => (
<Form>
<FormContainer size="sm">
<Card className="my-2">
@ -116,7 +116,7 @@ function FormTabDatabaseDelete({
</FormItem>
</div>
<Button size="sm" block variant="solid" loading={isSubmitting}>
<Button block size="sm" variant="solid" loading={isSubmitting}>
{isSubmitting ? translate('::Saving') : translate('::Save')}
</Button>
</Card>

View file

@ -48,7 +48,7 @@ function FormTabDatabaseInsert({
await onSubmit(ListFormEditTabs.Database.Insert.InsertForm, values, formikHelpers)
}}
>
{({ touched, errors, values, isSubmitting }) => (
{({ touched, errors, isSubmitting }) => (
<Form>
<FormContainer size="sm">
<Card className="my-2">
@ -114,7 +114,7 @@ function FormTabDatabaseInsert({
/>
</FormItem>
</div>
<Button size="sm" block variant="solid" loading={isSubmitting}>
<Button block size="sm" variant="solid" loading={isSubmitting}>
{isSubmitting ? translate('::Saving') : translate('::Save')}
</Button>
</Card>

View file

@ -48,7 +48,7 @@ function FormTabDatabaseSelect({
await onSubmit(ListFormEditTabs.Database.Select.SelectForm, values, formikHelpers)
}}
>
{({ touched, errors, values, isSubmitting }) => (
{({ touched, errors, isSubmitting }) => (
<Form>
<FormContainer size="sm">
<Card className="my-2">
@ -65,7 +65,7 @@ function FormTabDatabaseSelect({
component={Input}
/>
</FormItem>
<Button size="sm" block variant="solid" loading={isSubmitting}>
<Button block size="sm" variant="solid" loading={isSubmitting}>
{isSubmitting ? translate('::Saving') : translate('::Save')}
</Button>
</Card>

View file

@ -48,7 +48,7 @@ function FormTabDatabaseUpdate({
await onSubmit(ListFormEditTabs.Database.Update.UpdateForm, values, formikHelpers)
}}
>
{({ touched, errors, values, isSubmitting }) => (
{({ touched, errors, isSubmitting }) => (
<Form>
<FormContainer size="sm">
<Card className="my-2">
@ -114,7 +114,7 @@ function FormTabDatabaseUpdate({
/>
</FormItem>
</div>
<Button size="sm" block variant="solid" loading={isSubmitting}>
<Button block size="sm" variant="solid" loading={isSubmitting}>
{isSubmitting ? translate('::Saving') : translate('::Save')}
</Button>
</Card>

View file

@ -1,4 +1,3 @@
import { Container } from '@/components/shared'
import { Button, Card, Checkbox, FormContainer, FormItem, Input, Select } from '@/components/ui'
import { ListFormEditTabs } from '@/proxy/admin/list-form/options'
import { LanguageInfo } from '@/proxy/config/models'
@ -47,9 +46,6 @@ function FormTabDetails(
const languages = useStoreState((state) => state.abpConfig.config?.localization.languages)
const listFormValues = useStoreState((s) => s.admin.lists.values)
if (!listFormValues) {
return null
}
useEffect(() => {
if (languages) {
@ -62,6 +58,10 @@ function FormTabDetails(
}
}, [languages])
if (!listFormValues) {
return null
}
return (
<Formik
initialValues={listFormValues}
@ -437,7 +437,7 @@ function FormTabDetails(
</Card>
</div>
<Button size="sm" block variant="solid" loading={isSubmitting} type="submit">
<Button block size="sm" variant="solid" loading={isSubmitting} type="submit">
{isSubmitting ? translate('::Saving') : translate('::Save')}
</Button>
</FormContainer>

View file

@ -454,7 +454,7 @@ function FormTabEdit(props: FormEditProps & { listFormCode: string }) {
)}
</Card>
</div>
<Button size="sm" block variant="solid" loading={isSubmitting}>
<Button block size="sm" variant="solid" loading={isSubmitting}>
{isSubmitting ? translate('::Saving') : translate('::Save')}
</Button>
</FormContainer>

View file

@ -1,7 +1,6 @@
import { Container } from '@/components/shared'
import {
Button,
Card,
Checkbox,
FormContainer,
FormItem,
@ -18,15 +17,10 @@ import * as Yup from 'yup'
import { FormEditProps } from './FormEdit'
import {
applyFilterOptions,
overflowWrapOptions,
sortModeOptions,
whiteSpaceOptions,
} from './options'
import TabList from '@/components/ui/Tabs/TabList'
import TabNav from '@/components/ui/Tabs/TabNav'
import TabContent from '@/components/ui/Tabs/TabContent'
import { GridOptionsSortModeEnum } from '@/proxy/form/models'
import { SelectBoxOption } from '@/types/shared'
const validationSchema = Yup.object().shape({})
@ -304,7 +298,7 @@ function FormTabFilters(props: FormEditProps) {
</TabContent>
</Tabs>
<Button size="sm" block variant="solid" loading={isSubmitting} type="submit">
<Button block size="sm" variant="solid" loading={isSubmitting} type="submit">
{isSubmitting ? translate('::Saving') : translate('::Save')}
</Button>
</FormContainer>

View file

@ -16,9 +16,9 @@ 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 { useCallback, useEffect, useState } from 'react'
import { getListFormFields } from '@/services/admin/list-form-field.service'
import { groupBy } from 'lodash'
import groupBy from 'lodash/groupBy'
import { useParams } from 'react-router-dom'
import { GanttScaleType } from 'devextreme/ui/gantt'
import { gantScaleOptions } from './options'
@ -30,7 +30,7 @@ function FormTabGantt(props: FormEditProps) {
const { translate } = useLocalization()
const [fieldList, setFieldList] = useState<SelectBoxOption[]>([])
const getFields = async () => {
const getFields = useCallback(async () => {
if (!listFormCode) {
return
}
@ -61,11 +61,11 @@ function FormTabGantt(props: FormEditProps) {
},
)
}
}
}, [listFormCode])
useEffect(() => {
getFields()
}, [listFormCode])
}, [getFields])
const listFormValues = useStoreState((s) => s.admin.lists.values)
if (!listFormValues) {
@ -471,7 +471,7 @@ function FormTabGantt(props: FormEditProps) {
</Card>
</div>
<Button size="sm" block variant="solid" loading={isSubmitting} type="submit" className="my-2">
<Button block size="sm" variant="solid" loading={isSubmitting} type="submit" className="my-2">
{isSubmitting ? translate('::Saving') : translate('::Save')}
</Button>
</FormContainer>

View file

@ -26,7 +26,7 @@ function FormTabGroup(props: FormEditProps) {
await props.onSubmit(ListFormEditTabs.GroupForm, values, formikHelpers)
}}
>
{({ touched, errors, isSubmitting, values }) => (
{({ touched, errors, isSubmitting }) => (
<Form>
<FormContainer size="sm">
<FormItem
@ -54,7 +54,7 @@ function FormTabGroup(props: FormEditProps) {
/>
</FormItem>
<Button size="sm" block variant="solid" loading={isSubmitting} type="submit">
<Button block size="sm" variant="solid" loading={isSubmitting} type="submit">
{isSubmitting ? translate('::Saving') : translate('::Save')}
</Button>
</FormContainer>

View file

@ -235,7 +235,7 @@ function FormTabPager(props: FormEditProps) {
</div>
</div>
<Button size="sm" block variant="solid" loading={isSubmitting} type="submit">
<Button block size="sm" variant="solid" loading={isSubmitting} type="submit">
{isSubmitting ? translate('::Saving') : translate('::Save')}
</Button>
</FormContainer>

View file

@ -26,28 +26,27 @@ function FormTabPermissions(props: FormEditProps) {
const { translate } = useLocalization()
const listFormValues = useStoreState((s) => s.admin.lists.values)
useEffect(() => {
const loadPermissions = async () => {
const response = await getPermissionsList()
if (response.data) {
setPermissions(
response.data.map((permission: PermissionDefinitionRecord) => ({
value: permission.name,
label: permission.name,
})),
)
}
}
loadPermissions()
}, [])
if (!listFormValues) {
return null
}
const getPermissionList = async () => {
const response = await getPermissionsList()
if (response.data) {
setPermissions(
response.data.map((permission: PermissionDefinitionRecord) => ({
value: permission.name,
label: permission.name,
})),
)
}
}
useEffect(() => {
if (permissions) {
getPermissionList()
}
}, [permissions])
return (
<Container className="grid xl:grid-cols-2">
<Formik
@ -239,7 +238,7 @@ function FormTabPermissions(props: FormEditProps) {
</FormItem>
)}
<Button size="sm" block variant="solid" loading={isSubmitting} type="submit">
<Button block size="sm" variant="solid" loading={isSubmitting} type="submit">
{isSubmitting ? translate('::Saving') : translate('::Save')}
</Button>
</FormContainer>

View file

@ -186,7 +186,7 @@ function FormTabColumns(props: FormEditProps) {
</div>
</div>
<Button size="sm" block variant="solid" loading={isSubmitting} type="submit" className="my-2">
<Button block size="sm" variant="solid" loading={isSubmitting} type="submit" className="my-2">
{isSubmitting ? translate('::Saving') : translate('::Save')}
</Button>
</FormContainer>

View file

@ -98,7 +98,7 @@ function FormTabRow(props: FormEditProps) {
</Field>
</FormItem>
<Button size="sm" block variant="solid" loading={isSubmitting} type="submit">
<Button block size="sm" variant="solid" loading={isSubmitting} type="submit">
{isSubmitting ? translate('::Saving') : translate('::Save')}
</Button>
</FormContainer>

View file

@ -16,9 +16,9 @@ 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 { useCallback, useEffect, useState } from 'react'
import { getListFormFields } from '@/services/admin/list-form-field.service'
import { groupBy } from 'lodash'
import groupBy from 'lodash/groupBy'
import { useParams } from 'react-router-dom'
import { firstDayOfWeekOptions, schedulerViewOptions } from './options'
@ -29,7 +29,7 @@ function FormTabScheduler(props: FormEditProps) {
const { translate } = useLocalization()
const [fieldList, setFieldList] = useState<SelectBoxOption[]>([])
const getFields = async () => {
const getFields = useCallback(async () => {
if (!listFormCode) {
return
}
@ -60,11 +60,11 @@ function FormTabScheduler(props: FormEditProps) {
},
)
}
}
}, [listFormCode])
useEffect(() => {
getFields()
}, [listFormCode])
}, [getFields])
const listFormValues = useStoreState((s) => s.admin.lists.values)
if (!listFormValues) {
@ -363,7 +363,7 @@ function FormTabScheduler(props: FormEditProps) {
</FormItem>
</Card>
</div>
<Button size="sm" block variant="solid" loading={isSubmitting} type="submit" className="my-2">
<Button block size="sm" variant="solid" loading={isSubmitting} type="submit" className="my-2">
{isSubmitting ? translate('::Saving') : translate('::Save')}
</Button>{' '}
</FormContainer>

View file

@ -26,7 +26,7 @@ function FormTabSearch(props: FormEditProps) {
await props.onSubmit(ListFormEditTabs.SearchForm, values, formikHelpers)
}}
>
{({ touched, errors, isSubmitting, values }) => (
{({ touched, errors, isSubmitting }) => (
<Form>
<FormContainer size="sm">
<FormItem
@ -55,7 +55,7 @@ function FormTabSearch(props: FormEditProps) {
/>
</FormItem>
<Button size="sm" block variant="solid" loading={isSubmitting} type="submit">
<Button block size="sm" variant="solid" loading={isSubmitting} type="submit">
{isSubmitting ? translate('::Saving') : translate('::Save')}
</Button>
</FormContainer>

View file

@ -128,7 +128,7 @@ function FormTabSelect(props: FormEditProps) {
/>
</FormItem>
<Button size="sm" block variant="solid" loading={isSubmitting} type="submit">
<Button block size="sm" variant="solid" loading={isSubmitting} type="submit">
{isSubmitting ? translate('::Saving') : translate('::Save')}
</Button>
</FormContainer>

View file

@ -1,32 +1,20 @@
import { Container } from '@/components/shared'
import {
Button,
Card,
Checkbox,
FormContainer,
FormItem,
Input,
Select,
Tabs,
} from '@/components/ui'
import { ListFormEditTabs } from '@/proxy/admin/list-form/options'
import { useStoreState } from '@/store'
import { useLocalization } from '@/utils/hooks/useLocalization'
import { ApplyFilterMode } from 'devextreme/common/grids'
import { Field, FieldProps, Form, Formik } from 'formik'
import * as Yup from 'yup'
import { FormEditProps } from './FormEdit'
import {
applyFilterOptions,
overflowWrapOptions,
sortModeOptions,
whiteSpaceOptions,
} from './options'
import TabList from '@/components/ui/Tabs/TabList'
import TabNav from '@/components/ui/Tabs/TabNav'
import TabContent from '@/components/ui/Tabs/TabContent'
import { GridOptionsSortModeEnum } from '@/proxy/form/models'
import { SelectBoxOption } from '@/types/shared'
const validationSchema = Yup.object().shape({})
@ -74,7 +62,7 @@ function FormTabSorting(props: FormEditProps) {
</Field>
</FormItem>
<Button size="sm" block variant="solid" loading={isSubmitting} type="submit">
<Button block size="sm" variant="solid" loading={isSubmitting} type="submit">
{isSubmitting ? translate('::Saving') : translate('::Save')}
</Button>
</FormContainer>

View file

@ -97,7 +97,7 @@ function FormTabState(props: FormEditProps) {
/>
</FormItem>
<Button size="sm" block variant="solid" loading={isSubmitting} type="submit">
<Button block size="sm" variant="solid" loading={isSubmitting} type="submit">
{isSubmitting ? translate('::Saving') : translate('::Save')}
</Button>
</FormContainer>

View file

@ -7,7 +7,6 @@ import {
Input,
Select,
toast,
Card,
} from '@/components/ui'
import { ListFormEditTabs } from '@/proxy/admin/list-form/options'
import { useStoreState } from '@/store'
@ -16,9 +15,9 @@ 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 { useCallback, useEffect, useState } from 'react'
import { getListFormFields } from '@/services/admin/list-form-field.service'
import { groupBy } from 'lodash'
import groupBy from 'lodash/groupBy'
import { useParams } from 'react-router-dom'
const validationSchema = Yup.object().shape({})
@ -28,7 +27,7 @@ function FormTabTree(props: FormEditProps) {
const { translate } = useLocalization()
const [fieldList, setFieldList] = useState<SelectBoxOption[]>([])
const getFields = async () => {
const getFields = useCallback(async () => {
if (!listFormCode) {
return
}
@ -59,11 +58,11 @@ function FormTabTree(props: FormEditProps) {
},
)
}
}
}, [listFormCode])
useEffect(() => {
getFields()
}, [listFormCode])
}, [getFields])
const listFormValues = useStoreState((s) => s.admin.lists.values)
if (!listFormValues) {
@ -185,7 +184,7 @@ function FormTabTree(props: FormEditProps) {
component={Checkbox}
/>
</FormItem>
<Button size="sm" block variant="solid" loading={isSubmitting} type="submit" className="my-2">
<Button block size="sm" variant="solid" loading={isSubmitting} type="submit" className="my-2">
{isSubmitting ? translate('::Saving') : translate('::Save')}
</Button>
</FormContainer>

View file

@ -13,7 +13,7 @@ import { FaEdit, FaFileMedical, FaTrash } from 'react-icons/fa'
import { JsonRowDialogData } from './json-row-operations/types'
import JsonRowOpDialogWidget from './json-row-operations/JsonRowOpDialogWidget'
function FormTabWidgets(props: { listFormCode: string }) {
function FormTabWidgets() {
const [isJsonRowOpDialogOpen, setIsJsonRowOpDialogOpen] = useState(false)
const [jsonRowOpModalData, setJsonRowOpModalData] = useState<JsonRowDialogData>()
const { translate } = useLocalization()

View file

@ -12,7 +12,7 @@ import { workflowService, type WorkflowCriteriaDto } from '@/services/workflow.s
import { WorkflowDesigner } from '../workflow/WorkflowDesigner'
import { SelectBoxOption } from '@/types/shared'
import { Field, FieldProps, Form, Formik } from 'formik'
import { Button, Card, Checkbox, FormContainer, FormItem, Input, Select } from '@/components/ui'
import { Button, Card, Checkbox, FormContainer, FormItem, Select } from '@/components/ui'
import { ListFormEditTabs } from '@/proxy/admin/list-form/options'
import { bool, object, string } from 'yup'
import { useStoreState } from '@/store/store'
@ -450,7 +450,7 @@ export function FormTabWorkflow(
</FormItem>
</div>
<Button size="sm" block variant="solid" type="submit" loading={isSubmitting}>
<Button block size="sm" variant="solid" type="submit" loading={isSubmitting}>
{isSubmitting ? translate('::Saving') : translate('::Save')}
</Button>
</Card>

View file

@ -22,12 +22,10 @@ import { FormFieldEditProps } from './FormFields'
import FormFieldTabPivotSetting from './FormFieldTabPivotSetting'
function FormFieldEdit({
listFormCode,
item,
onSubmit,
fields
fields,
}: {
listFormCode: string
item: ColumnFormatEditDto | null
fields: ColumnFormatEditDto[]
} & FormFieldEditProps) {
@ -74,114 +72,60 @@ function FormFieldEdit({
<TabNav value="pivotSetting">
{translate('::ListForms.ListFormFieldEdit.TabPivotSettings')}
</TabNav>
</TabList>
</TabList>
<div className="pt-4">
<TabContent value="details">
<FormFieldTabDetails
listFormCode={listFormCode}
initialValues={item}
onSubmit={onSubmit}
/>
<FormFieldTabDetails initialValues={item} onSubmit={onSubmit} />
</TabContent>
<TabContent value="options">
<FormFieldTabOptions
listFormCode={listFormCode}
initialValues={item}
onSubmit={onSubmit}
/>
<FormFieldTabOptions initialValues={item} onSubmit={onSubmit} />
</TabContent>
<TabContent value="permissions">
<FormFieldTabPermissions
listFormCode={listFormCode}
initialValues={item}
onSubmit={onSubmit}
/>
<FormFieldTabPermissions initialValues={item} onSubmit={onSubmit} />
</TabContent>
<TabContent value="customization">
<FormFieldTabCustomization
listFormCode={listFormCode}
initialValues={item}
onSubmit={onSubmit}
/>
<FormFieldTabCustomization initialValues={item} onSubmit={onSubmit} />
</TabContent>
<TabContent value="filtering">
<FormFieldTabFiltering
listFormCode={listFormCode}
initialValues={item}
onSubmit={onSubmit}
/>
<FormFieldTabFiltering initialValues={item} onSubmit={onSubmit} />
</TabContent>
<TabContent value="headering">
<FormFieldTabHeadering
listFormCode={listFormCode}
initialValues={item}
onSubmit={onSubmit}
/>
<FormFieldTabHeadering initialValues={item} onSubmit={onSubmit} />
</TabContent>
<TabContent value="grouping">
<FormFieldTabGrouping
listFormCode={listFormCode}
initialValues={item}
onSubmit={onSubmit}
/>
<FormFieldTabGrouping initialValues={item} onSubmit={onSubmit} />
</TabContent>
<TabContent value="groupSummary">
<FormFieldTabGroupSummary
listFormCode={listFormCode}
initialValues={item}
onSubmit={onSubmit}
fields={fields}
onSubmit={onSubmit}
/>
</TabContent>
<TabContent value="totalSummary">
<FormFieldTabTotalSummary
listFormCode={listFormCode}
initialValues={item}
onSubmit={onSubmit}
fields={fields}
onSubmit={onSubmit}
/>
</TabContent>
<TabContent value="joinOptions">
<FormFieldTabJoinOptions
listFormCode={listFormCode}
initialValues={item}
onSubmit={onSubmit}
/>
<FormFieldTabJoinOptions initialValues={item} onSubmit={onSubmit} />
</TabContent>
<TabContent value="lookup">
<FormFieldTabLookup
listFormCode={listFormCode}
initialValues={item}
onSubmit={onSubmit}
/>
<FormFieldTabLookup initialValues={item} onSubmit={onSubmit} />
</TabContent>
<TabContent value="cssOptions">
<FormFieldTabCssOptions
listFormCode={listFormCode}
initialValues={item}
onSubmit={onSubmit}
/>
<FormFieldTabCssOptions initialValues={item} onSubmit={onSubmit} />
</TabContent>
<TabContent value="validationRules">
<FormFieldTabValidationRules
listFormCode={listFormCode}
initialValues={item}
onSubmit={onSubmit}
/>
<FormFieldTabValidationRules initialValues={item} onSubmit={onSubmit} />
</TabContent>
<TabContent value="conditionalFormatting">
<FormFieldTabConditionalFormatting
listFormCode={listFormCode}
initialValues={item}
onSubmit={onSubmit}
/>
<FormFieldTabConditionalFormatting initialValues={item} onSubmit={onSubmit} />
</TabContent>
<TabContent value="pivotSetting">
<FormFieldTabPivotSetting
listFormCode={listFormCode}
initialValues={item}
onSubmit={onSubmit}
/>
<FormFieldTabPivotSetting initialValues={item} onSubmit={onSubmit} />
</TabContent>
</div>
</Tabs>

View file

@ -46,11 +46,9 @@ const schema = object().shape({
})
function FormFieldTabConditionalFormatting({
listFormCode,
initialValues,
onSubmit,
}: {
listFormCode: string
initialValues: ColumnFormatEditDto
} & FormFieldEditProps) {
const { translate } = useLocalization()
@ -219,7 +217,7 @@ function FormFieldTabConditionalFormatting({
}
}}
>
{({ touched, errors, resetForm, values }) => (
{({ touched, errors, values }) => (
<Form>
<FormContainer size="sm">
<FormItem
@ -316,7 +314,7 @@ function FormFieldTabConditionalFormatting({
/>
</FormItem>
<Button size="sm" block variant="solid" loading={isLoading} type="submit">
<Button block size="sm" variant="solid" loading={isLoading} type="submit">
{isLoading ? translate('::Saving') : translate('::Save')}
</Button>
</FormContainer>

View file

@ -12,11 +12,9 @@ const schema = object().shape({
})
function FormFieldTabCssOptions({
listFormCode,
initialValues,
onSubmit,
}: {
listFormCode: string
initialValues: ColumnFormatEditDto
} & FormFieldEditProps) {
const { translate } = useLocalization()
@ -31,7 +29,7 @@ function FormFieldTabCssOptions({
await onSubmit(ListFormFieldEditTabs.CssOptionsForm, values, formikHelpers)
}}
>
{({ touched, errors, isSubmitting, values }) => (
{({ touched, errors, isSubmitting }) => (
<Form>
<FormContainer size="sm">
<FormItem
@ -63,7 +61,7 @@ function FormFieldTabCssOptions({
/>
</FormItem>
<Button size="sm" className="mt-1" block variant="solid" loading={isSubmitting} type="submit">
<Button block size="sm" className="mt-1" variant="solid" loading={isSubmitting} type="submit">
{isSubmitting ? translate('::Saving') : translate('::Save')}
</Button>
</FormContainer>

View file

@ -20,11 +20,9 @@ const schema = object().shape({
})
function FormFieldTabCustomization({
listFormCode,
initialValues,
onSubmit,
}: {
listFormCode: string
initialValues: ColumnFormatEditDto
} & FormFieldEditProps) {
const { translate } = useLocalization()
@ -39,7 +37,7 @@ function FormFieldTabCustomization({
await onSubmit(ListFormFieldEditTabs.CustomizationForm, values, formikHelpers)
}}
>
{({ touched, errors, isSubmitting, values }) => (
{({ isSubmitting, values }) => (
<Form>
<FormContainer size="sm">
<FormItem label={translate('::ListForms.ListFormFieldEdit.CustomizationFixed')}>
@ -70,7 +68,7 @@ function FormFieldTabCustomization({
</Field>
</FormItem>
<Button size="sm" className="mt-1" block variant="solid" loading={isSubmitting} type="submit">
<Button block size="sm" className="mt-1" variant="solid" loading={isSubmitting} type="submit">
{isSubmitting ? translate('::Saving') : translate('::Save')}
</Button>
</FormContainer>

View file

@ -23,11 +23,9 @@ const schema = object().shape({
})
function FormFieldTabDetails({
listFormCode,
initialValues,
onSubmit,
}: {
listFormCode: string
initialValues: ColumnFormatEditDto
} & FormFieldEditProps) {
const { translate } = useLocalization()
@ -156,7 +154,7 @@ function FormFieldTabDetails({
onClose={() => setIsEditorOptionsDialogOpen(false)}
onApply={(val) => setFieldValue('editorOptions', val)}
/>
<Button size="sm" className="mt-1" block variant="solid" loading={isSubmitting} type="submit">
<Button block size="sm" className="mt-1" variant="solid" loading={isSubmitting} type="submit">
{isSubmitting ? translate('::Saving') : translate('::Save')}
</Button>
</Form>

View file

@ -17,11 +17,9 @@ const schema = object().shape({
})
function FormFieldTabFiltering({
listFormCode,
initialValues,
onSubmit,
}: {
listFormCode: string
initialValues: ColumnFormatEditDto
} & FormFieldEditProps) {
const { translate } = useLocalization()
@ -36,7 +34,7 @@ function FormFieldTabFiltering({
await onSubmit(ListFormFieldEditTabs.FilteringForm, values, formikHelpers)
}}
>
{({ touched, errors, isSubmitting, values }) => (
{({ touched, errors, isSubmitting }) => (
<Form>
<FormContainer size="sm">
<FormItem
@ -84,7 +82,7 @@ function FormFieldTabFiltering({
/>
</FormItem>
<Button size="sm" className="mt-1" block variant="solid" loading={isSubmitting} type="submit">
<Button block size="sm" className="mt-1" variant="solid" loading={isSubmitting} type="submit">
{isSubmitting ? translate('::Saving') : translate('::Save')}
</Button>
</FormContainer>

View file

@ -23,12 +23,10 @@ const schema = object().shape({
})
function FormFieldTabGroupSummary({
listFormCode,
initialValues,
onSubmit,
fields,
}: {
listFormCode: string
initialValues: ColumnFormatEditDto
fields: ColumnFormatEditDto[]
} & FormFieldEditProps) {
@ -176,7 +174,7 @@ function FormFieldTabGroupSummary({
/>
</FormItem>
<Button size="sm" block variant="solid" loading={isSubmitting} type="submit">
<Button block size="sm" variant="solid" loading={isSubmitting} type="submit">
{isSubmitting ? translate('::Saving') : translate('::Save')}
</Button>
</FormContainer>

View file

@ -17,11 +17,9 @@ const schema = object().shape({
})
function FormFieldTabGrouping({
listFormCode,
initialValues,
onSubmit,
}: {
listFormCode: string
initialValues: ColumnFormatEditDto
} & FormFieldEditProps) {
const { translate } = useLocalization()
@ -36,7 +34,7 @@ function FormFieldTabGrouping({
await onSubmit(ListFormFieldEditTabs.GroupingForm, values, formikHelpers)
}}
>
{({ touched, errors, isSubmitting, values }) => (
{({ touched, errors, isSubmitting }) => (
<Form>
<FormContainer size="sm">
<FormItem label={translate('::ListForms.ListFormFieldEdit.GroupingAllowGrouping')}>
@ -61,7 +59,7 @@ function FormFieldTabGrouping({
/>
</FormItem>
<Button size="sm" className="mt-1" block variant="solid" loading={isSubmitting} type="submit">
<Button block size="sm" className="mt-1" variant="solid" loading={isSubmitting} type="submit">
{isSubmitting ? translate('::Saving') : translate('::Save')}
</Button>
</FormContainer>

View file

@ -17,11 +17,9 @@ const schema = object().shape({
})
function FormFieldTabHeadering({
listFormCode,
initialValues,
onSubmit,
}: {
listFormCode: string
initialValues: ColumnFormatEditDto
} & FormFieldEditProps) {
const { translate } = useLocalization()
@ -36,7 +34,7 @@ function FormFieldTabHeadering({
await onSubmit(ListFormFieldEditTabs.HeaderingForm, values, formikHelpers)
}}
>
{({ touched, errors, isSubmitting, values }) => (
{({ touched, errors, isSubmitting }) => (
<Form>
<FormContainer size="sm">
<FormItem
@ -65,7 +63,7 @@ function FormFieldTabHeadering({
/>
</FormItem>
<Button size="sm" className="mt-1" block variant="solid" loading={isSubmitting} type="submit">
<Button block size="sm" className="mt-1" variant="solid" loading={isSubmitting} type="submit">
{isSubmitting ? translate('::Saving') : translate('::Save')}
</Button>
</FormContainer>

View file

@ -1,5 +1,4 @@
import { Container } from '@/components/shared'
import { Button, Card, FormContainer, FormItem, Input, Select } from '@/components/ui'
import { Button, Card, FormItem, Input, Select } from '@/components/ui'
import {
ColumnFormatEditDto,
GridColumnJoinConditionEnum,
@ -29,11 +28,9 @@ const schema = object().shape({
})
function FormFieldTabJoinOptions({
listFormCode,
initialValues,
onSubmit,
}: {
listFormCode: string
initialValues: ColumnFormatEditDto
} & FormFieldEditProps) {
const { translate } = useLocalization()
@ -234,7 +231,7 @@ function FormFieldTabJoinOptions({
</FormItem>
</Card>
</div>
<Button size="sm" className="mt-1" block variant="solid" loading={isSubmitting} type="submit">
<Button block size="sm" className="mt-1" variant="solid" loading={isSubmitting} type="submit">
{isSubmitting ? translate('::Saving') : translate('::Save')}
</Button>
</Form>

View file

@ -1,5 +1,4 @@
import { Container } from '@/components/shared'
import { Button, Card, Checkbox, FormContainer, FormItem, Input, Select } from '@/components/ui'
import { Button, Card, FormItem, Input, Select } from '@/components/ui'
import { ColumnFormatEditDto, ListFormFieldEditTabs } from '@/proxy/admin/list-form-field/models'
import type { DatabaseColumnDto, SqlObjectExplorerDto } from '@/proxy/sql-query-manager/models'
import { sqlObjectManagerService } from '@/services/sql-query-manager.service'
@ -70,11 +69,11 @@ function TablePickerModal({
{step === 'columns' && (
<Button
type="button"
onClick={() => setStep('table')}
variant="plain"
shape="circle"
icon={<FaArrowLeft className="text-xs" />}
className="!h-6 !w-6 !px-0 text-gray-400 transition-colors hover:!bg-transparent hover:text-indigo-500"
onClick={() => setStep('table')}
/>
)}
<span className="text-sm font-semibold text-gray-700 dark:text-gray-200">
@ -85,11 +84,11 @@ function TablePickerModal({
</div>
<Button
type="button"
onClick={onClose}
variant="plain"
shape="circle"
icon={<FaTimes />}
className="!h-7 !w-7 !px-0 text-gray-400 hover:!bg-transparent hover:text-gray-600 dark:hover:text-gray-200"
onClick={onClose}
/>
</div>
@ -100,9 +99,9 @@ function TablePickerModal({
<input
autoFocus
value={tableSearch}
onChange={(e) => setTableSearch(e.target.value)}
placeholder={translate('::Search') || 'Ara...'}
className="w-full text-xs px-2 py-1.5 rounded border border-gray-200 dark:border-gray-600 bg-gray-50 dark:bg-gray-800 text-gray-700 dark:text-gray-200 focus:outline-none focus:border-indigo-400"
onChange={(e) => setTableSearch(e.target.value)}
/>
</div>
<div className="overflow-y-auto flex-1 p-2">
@ -117,6 +116,9 @@ function TablePickerModal({
<Button
key={t.fullName}
type="button"
variant="plain"
shape="none"
className="w-full !h-auto !justify-start !rounded !px-3 !py-2 text-left font-mono text-xs text-gray-700 transition-colors hover:!bg-indigo-50 dark:text-gray-200 dark:hover:!bg-indigo-900/30"
onClick={async () => {
setPickerTable(t)
setStep('columns')
@ -137,9 +139,6 @@ function TablePickerModal({
setIsLoadingColumns(false)
}
}}
variant="plain"
shape="none"
className="w-full !h-auto !justify-start !rounded !px-3 !py-2 text-left font-mono text-xs text-gray-700 transition-colors hover:!bg-indigo-50 dark:text-gray-200 dark:hover:!bg-indigo-900/30"
>
<span className="text-gray-400 mr-1">{t.schemaName}.</span>
{t.tableName}
@ -165,8 +164,8 @@ function TablePickerModal({
</label>
<select
value={keyCol}
onChange={(e) => setKeyCol(e.target.value)}
className="w-full text-xs h-8 px-2 rounded border border-gray-200 dark:border-gray-600 bg-gray-50 dark:bg-gray-700 text-gray-700 dark:text-gray-200 focus:outline-none focus:border-indigo-400"
onChange={(e) => setKeyCol(e.target.value)}
>
<option value="">-- Seçiniz --</option>
{pickerColumns.map((c) => (
@ -182,8 +181,8 @@ function TablePickerModal({
</label>
<select
value={nameCol}
onChange={(e) => setNameCol(e.target.value)}
className="w-full text-xs h-8 px-2 rounded border border-gray-200 dark:border-gray-600 bg-gray-50 dark:bg-gray-700 text-gray-700 dark:text-gray-200 focus:outline-none focus:border-indigo-400"
onChange={(e) => setNameCol(e.target.value)}
>
<option value="">-- Seçiniz --</option>
{pickerColumns.map((c) => (
@ -204,8 +203,10 @@ function TablePickerModal({
</div>
)}
<Button
block
type="button"
disabled={!keyCol || !nameCol}
variant="solid"
onClick={() => {
onSelect(
buildLookupQuery({
@ -216,8 +217,6 @@ function TablePickerModal({
}),
)
}}
block
variant="solid"
>
{translate('::OK')}
</Button>
@ -248,11 +247,9 @@ function getNormalizedInitialValues(initialValues: ColumnFormatEditDto) {
}
function FormFieldTabLookup({
listFormCode,
initialValues,
onSubmit,
}: {
listFormCode: string
initialValues: ColumnFormatEditDto
} & FormFieldEditProps) {
const { translate } = useLocalization()
@ -317,11 +314,11 @@ function FormFieldTabLookup({
extra={
<Button
type="button"
onClick={openTablePicker}
variant="plain"
shape="none"
icon={<FaPlus className="text-[8px]" />}
className="ml-2 !h-auto !items-center gap-1 !rounded border border-indigo-200 bg-indigo-50 !px-1.5 !py-0.5 text-[10px] font-medium text-indigo-600 transition-colors hover:!bg-indigo-100 dark:border-indigo-700 dark:bg-indigo-900/20 dark:text-indigo-400 dark:hover:!bg-indigo-800/40"
onClick={openTablePicker}
>
{translate('::ListForms.Wizard.Step3.GenerateFromTable') || 'Tablodan Oluştur'}
</Button>
@ -465,7 +462,7 @@ function FormFieldTabLookup({
</FormItem>
</Card>
</div>
<Button size="sm" className="mt-1" block variant="solid" loading={isSubmitting} type="submit">
<Button block size="sm" className="mt-1" variant="solid" loading={isSubmitting} type="submit">
{isSubmitting ? translate('::Saving') : translate('::Save')}
</Button>
</Form>

View file

@ -1,5 +1,4 @@
import { Container } from '@/components/shared'
import { Button, Card, Checkbox, FormContainer, FormItem, Input, Select } from '@/components/ui'
import { Button, Card, Checkbox, FormItem, Input, Select } from '@/components/ui'
import { ColumnFormatEditDto, ListFormFieldEditTabs } from '@/proxy/admin/list-form-field/models'
import { SelectBoxOption } from '@/types/shared'
import { useLocalization } from '@/utils/hooks/useLocalization'
@ -22,11 +21,9 @@ const schema = object().shape({
})
function FormFieldTabOptions({
listFormCode,
initialValues,
onSubmit,
}: {
listFormCode: string
initialValues: ColumnFormatEditDto
} & FormFieldEditProps) {
const { translate } = useLocalization()
@ -113,7 +110,7 @@ function FormFieldTabOptions({
</Card>
</div>
<Button size="sm" className="mt-1" block variant="solid" loading={isSubmitting} type="submit">
<Button block size="sm" className="mt-1" variant="solid" loading={isSubmitting} type="submit">
{isSubmitting ? translate('::Saving') : translate('::Save')}
</Button>
</Form>

View file

@ -21,11 +21,9 @@ const schema = object().shape({
})
function FormFieldTabPermissions({
listFormCode,
initialValues,
onSubmit,
}: {
listFormCode: string
initialValues: ColumnFormatEditDto
} & FormFieldEditProps) {
const { translate } = useLocalization()
@ -159,7 +157,7 @@ function FormFieldTabPermissions({
<Field name="permissionDto.i" component={Checkbox} />
</FormItem>
<Button size="sm" className="mt-1" block variant="solid" loading={isSubmitting} type="submit">
<Button block size="sm" className="mt-1" variant="solid" loading={isSubmitting} type="submit">
{isSubmitting ? translate('::Saving') : translate('::Save')}
</Button>
</FormContainer>

View file

@ -1,5 +1,4 @@
import { Container } from '@/components/shared'
import { Button, Card, Checkbox, FormContainer, FormItem, Input, Select } from '@/components/ui'
import { Button, Card, Checkbox, FormItem, Select } from '@/components/ui'
import { ColumnFormatEditDto, ListFormFieldEditTabs } from '@/proxy/admin/list-form-field/models'
import { useLocalization } from '@/utils/hooks/useLocalization'
import { Field, FieldProps, Form, Formik } from 'formik'
@ -28,11 +27,9 @@ const schema = object().shape({
})
function FormFieldTabPivotSetting({
listFormCode,
initialValues,
onSubmit,
}: {
listFormCode: string
initialValues: ColumnFormatEditDto
} & FormFieldEditProps) {
const { translate } = useLocalization()
@ -214,7 +211,7 @@ function FormFieldTabPivotSetting({
</FormItem>
</Card>
</div>
<Button size="sm" className="mt-1" block variant="solid" loading={isSubmitting} type="submit">
<Button block size="sm" className="mt-1" variant="solid" loading={isSubmitting} type="submit">
{isSubmitting ? translate('::Saving') : translate('::Save')}
</Button>
</Form>

View file

@ -8,7 +8,6 @@ import { columnSummaryTypeListOptions } from '../options'
import { FormFieldEditProps } from './FormFields'
import { tooltipFormatListOptions } from '@/proxy/admin/list-form/options'
import { SelectBoxOption } from '@/types/shared'
import { useState } from 'react'
const schema = object().shape({
columnTotalSummaryDto: object()
@ -24,12 +23,10 @@ const schema = object().shape({
})
function FormFieldTabTotalSummary({
listFormCode,
initialValues,
onSubmit,
fields,
}: {
listFormCode: string
initialValues: ColumnFormatEditDto
fields: ColumnFormatEditDto[]
} & FormFieldEditProps) {
@ -177,7 +174,7 @@ function FormFieldTabTotalSummary({
/>
</FormItem>
<Button size="sm" className="mt-1" block variant="solid" loading={isSubmitting} type="submit">
<Button block size="sm" className="mt-1" variant="solid" loading={isSubmitting} type="submit">
{isSubmitting ? translate('::Saving') : translate('::Save')}
</Button>
</FormContainer>

View file

@ -60,11 +60,9 @@ const schema = object().shape({
})
function FormFieldTabValidationRules({
listFormCode,
initialValues,
onSubmit,
}: {
listFormCode: string
initialValues: ColumnFormatEditDto
} & FormFieldEditProps) {
const { translate } = useLocalization()
@ -229,7 +227,7 @@ function FormFieldTabValidationRules({
}
}}
>
{({ touched, errors, resetForm, values }) => (
{({ touched, errors, values }) => (
<Form>
<FormContainer size="sm">
<FormItem
@ -355,7 +353,7 @@ function FormFieldTabValidationRules({
<Field name="trim" placeholder="Trim" component={Checkbox} />
</FormItem>
<Button size="sm" className="mt-1" block variant="solid" loading={isLoading} type="submit">
<Button block size="sm" className="mt-1" variant="solid" loading={isLoading} type="submit">
{isLoading ? translate('::Saving') : translate('::Save')}
</Button>
</FormContainer>

View file

@ -35,7 +35,7 @@ import { useLocalization } from '@/utils/hooks/useLocalization'
import setNull from '@/utils/setNull'
import classNames from 'classnames'
import { Field, FieldProps, Form, Formik, FormikHelpers } from 'formik'
import { useEffect, useState } from 'react'
import { useCallback, useEffect, useState } from 'react'
import { FaFileMedical, FaCopy, FaEyeSlash, FaMinus, FaTimes, FaTable } from 'react-icons/fa'
import { number, object, string } from 'yup'
import FormFieldEdit from './FormFieldEdit'
@ -219,7 +219,7 @@ function FormFields({
await getFields()
}
const getFields = async (cultureName?: string, roleId?: string, userId?: string) => {
const getFields = useCallback(async (cultureName?: string, roleId?: string, userId?: string) => {
if (!listFormCode) {
return
}
@ -254,11 +254,11 @@ function FormFields({
},
)
}
}
}, [listFormCode])
useEffect(() => {
getFields()
}, [listFormCode])
}, [getFields])
useEffect(() => {
if (!fields || !row) {
@ -266,10 +266,10 @@ function FormFields({
}
const newRow = fields.find((f) => f.id === row.id)
if (newRow) {
if (newRow && newRow !== row) {
setRow(newRow)
}
}, [fields])
}, [fields, row])
const onSubmit = async (
editType: string,
@ -390,7 +390,7 @@ function FormFields({
</Field>
</FormItem>
<Button size="sm" block variant="solid" loading={isSubmitting} type="submit">
<Button block size="sm" variant="solid" loading={isSubmitting} type="submit">
{isSubmitting ? '...' : translate('::ListForms.ListFormField.Filter')}
</Button>
</FormContainer>
@ -454,14 +454,14 @@ function FormFields({
<TBody>
{fields.map((field) => (
<Tr
key={field.id}
className={classNames(
'cursor-pointer',
field.id === row?.id ? 'bg-sozsoft-active dark:bg-gray-600' : '',
)}
onClick={(e: any) => {
onClick={() => {
setRow(field)
}}
key={field.id}
>
<Td className="flex items-center !p-0">
<Button
@ -505,7 +505,7 @@ function FormFields({
</Table>
</div>
<div className="2xl:col-span-3 lg:col-span-3 xl:col-span-2">
<FormFieldEdit listFormCode={listFormCode} item={row} onSubmit={onSubmit} fields={fields} />
<FormFieldEdit item={row} fields={fields} onSubmit={onSubmit} />
</div>
</div>
</AdaptableCard>
@ -684,7 +684,7 @@ function FormFields({
</Field>
</FormItem>
<Button size="sm" block variant="solid" loading={isSubmitting} type="submit">
<Button block size="sm" variant="solid" loading={isSubmitting} type="submit">
{isSubmitting ? translate('::Saving') : translate('::Save')}
</Button>
</FormContainer>
@ -793,7 +793,7 @@ function FormFields({
}
}}
>
{({ touched, errors, resetForm, isSubmitting, values }) => (
{({ touched, errors, isSubmitting, values }) => (
<Form>
<FormContainer size="sm">
<FormItem
@ -1023,7 +1023,7 @@ function FormFields({
<Field name="copiedFields.pivotSetting" component={Checkbox} className="mr-1" />
</FormItem>
</div>
<Button size="sm" block variant="solid" loading={isSubmitting} type="submit">
<Button block size="sm" variant="solid" loading={isSubmitting} type="submit">
{isSubmitting ? translate('::Saving') : translate('::Save')}
</Button>
</FormContainer>

View file

@ -1,7 +1,7 @@
import { Button, Dialog } from '@/components/ui'
import { useLocalization } from '@/utils/hooks/useLocalization'
import { useEffect, useMemo, useState } from 'react'
import { FaCheck, FaCode, FaPlus, FaSlidersH, FaTimes, FaTrash } from 'react-icons/fa'
import { FaCheck, FaCode, FaPlus, FaTimes, FaTrash } from 'react-icons/fa'
type CustomOption = {
id: string
@ -295,51 +295,52 @@ function EditorOptionsBuilderDialog({
<Button
type="button"
size="sm"
onClick={clearOptions}
title="editorOptions alanını boşaltır. Backend'e boş string kaydedilir."
onClick={clearOptions}
>
NULL / Empty
</Button>
<Button
type="button"
size="sm"
onClick={() => addPreset({ disabled: true })}
title='{"disabled": true} ekler.'
onClick={() => addPreset({ disabled: true })}
>
disabled
</Button>
<Button
type="button"
size="sm"
onClick={() => addPreset({ tooltip: { enabled: true } })}
title='{"tooltip": {"enabled": true}} ekler.'
onClick={() => addPreset({ tooltip: { enabled: true } })}
>
Tooltip
</Button>
<Button
type="button"
size="sm"
onClick={() => addPreset({ format: { type: 'fixedPoint', precision: 2 } })}
title="Ondalık format precision 2 ekler."
onClick={() => addPreset({ format: { type: 'fixedPoint', precision: 2 } })}
>
fixedPoint precision 2
</Button>
<Button
type="button"
size="sm"
title="Pasif ve precision 2 fixedPoint formatını birlikte ekler."
onClick={() =>
addPreset({
disabled: true,
format: { type: 'fixedPoint', precision: 2 },
})
}
title="Pasif ve precision 2 fixedPoint formatını birlikte ekler."
>
disabled fixedPoint 2
</Button>
<Button
type="button"
size="sm"
title="Precision 1, mask behavior, spin buttons ve pasif ayarını ekler."
onClick={() =>
addPreset({
format: { type: 'fixedPoint', precision: 1 },
@ -348,13 +349,13 @@ function EditorOptionsBuilderDialog({
disabled: true,
})
}
title="Precision 1, mask behavior, spin buttons ve pasif ayarını ekler."
>
disabled fixedPoint 1
</Button>
<Button
type="button"
size="sm"
title="NumberBox için precision 2, mask behavior ve spin buttons ekler."
onClick={() =>
addPreset({
format: { type: 'fixedPoint', precision: 2 },
@ -362,34 +363,34 @@ function EditorOptionsBuilderDialog({
showSpinButtons: true,
})
}
title="NumberBox için precision 2, mask behavior ve spin buttons ekler."
>
numberSpin precision 2
</Button>
<Button
type="button"
size="sm"
onClick={() => addPreset({ format: 'dd/MM/yyyy', displayFormat: 'dd/MM/yyyy' })}
title="DateBox için gün/ay/yıl formatını ekler."
onClick={() => addPreset({ format: 'dd/MM/yyyy', displayFormat: 'dd/MM/yyyy' })}
>
date dd/MM/yyyy
</Button>
<Button
type="button"
size="sm"
title="DateBox için gün/ay/yıl saat:dakika formatını ekler."
onClick={() =>
addPreset({
format: 'dd/MM/yyyy HH:mm',
displayFormat: 'dd/MM/yyyy HH:mm',
})
}
title="DateBox için gün/ay/yıl saat:dakika formatını ekler."
>
dateTime dd/MM/yyyy HH:mm
</Button>
<Button
type="button"
size="sm"
title="Telefon maskesi, yer tutucu ve Türkçe hata mesajı ekler."
onClick={() =>
addPreset({
format: 'phoneGlobal',
@ -400,13 +401,13 @@ function EditorOptionsBuilderDialog({
placeholder: '(555) 123-4567',
})
}
title="Telefon maskesi, yer tutucu ve Türkçe hata mesajı ekler."
>
phoneGlobal mask
</Button>
<Button
type="button"
size="sm"
title="Saat seçimi için dxDateBox time picker ayarları ekler."
onClick={() =>
addPreset({
type: 'time',
@ -417,32 +418,31 @@ function EditorOptionsBuilderDialog({
width: '100%',
})
}
title="Saat seçimi için dxDateBox time picker ayarları ekler."
>
time picker
</Button>
<Button
type="button"
size="sm"
onClick={() => addPreset({ width: 80, height: 80, multiple: true })}
title="ImageUpload için 80x80 ve multiple ayarlarını ekler."
onClick={() => addPreset({ width: 80, height: 80, multiple: true })}
>
multi image
</Button>
<Button type="button" size="sm" onClick={() => addPreset({ height: 60 })} title='{"height": 60} ekler.'>
<Button type="button" size="sm" title='{"height": 60} ekler.' onClick={() => addPreset({ height: 60 })}>
Height 60
</Button>
<Button type="button" size="sm" onClick={() => addPreset({ height: 100 })} title='{"height": 100} ekler.'>
<Button type="button" size="sm" title='{"height": 100} ekler.' onClick={() => addPreset({ height: 100 })}>
Height 100
</Button>
<Button type="button" size="sm" onClick={() => addPreset({ height: 200 })} title='{"height": 200} ekler.'>
<Button type="button" size="sm" title='{"height": 200} ekler.' onClick={() => addPreset({ height: 200 })}>
Height 200
</Button>
<Button
type="button"
size="sm"
onClick={() => addPreset(buildHtmlEditorOptions())}
title="HtmlEditor toolbar, image upload ve media resizing ayarlarını ekler."
onClick={() => addPreset(buildHtmlEditorOptions())}
>
htmlEditor toolbar
</Button>
@ -451,12 +451,12 @@ function EditorOptionsBuilderDialog({
return (
<Dialog
preventScroll
isOpen={isOpen}
width={1320}
height="88vh"
contentClassName="flex flex-col"
style={{ overlay: { zIndex: 1300 } }}
preventScroll
onClose={onClose}
onRequestClose={onClose}
>
@ -545,9 +545,9 @@ function EditorOptionsBuilderDialog({
<input
className={baseInputClass}
value={toInputValue(options.width)}
onChange={(event) => setOptionValue('width', event.target.value)}
placeholder="100% veya 240"
title="Örnek: 100%, 240, 80"
onChange={(event) => setOptionValue('width', event.target.value)}
/>
</label>
<label className="text-xs text-gray-500">
@ -555,15 +555,15 @@ function EditorOptionsBuilderDialog({
<input
className={baseInputClass}
value={toInputValue(options.height)}
placeholder="200"
type="number"
title="Editor yüksekliği. Örnek: 60, 100, 200"
onChange={(event) =>
setOptionValue(
'height',
event.target.value ? Number(event.target.value) : undefined,
)
}
placeholder="200"
type="number"
title="Editor yüksekliği. Örnek: 60, 100, 200"
/>
</label>
<label className="text-xs text-gray-500">
@ -571,9 +571,9 @@ function EditorOptionsBuilderDialog({
<input
className={baseInputClass}
value={toInputValue(options.placeholder)}
onChange={(event) => setOptionValue('placeholder', event.target.value)}
placeholder="Placeholder"
title="Editor boşken görünecek metin."
onChange={(event) => setOptionValue('placeholder', event.target.value)}
/>
</label>
</div>
@ -592,9 +592,9 @@ function EditorOptionsBuilderDialog({
<input
className={baseInputClass}
value={toInputValue(options.label)}
onChange={(event) => setOptionValue('label', event.target.value)}
placeholder="Alan etiketi"
title="Editor içi label metni."
onChange={(event) => setOptionValue('label', event.target.value)}
/>
</label>
<label className="text-xs text-gray-500">
@ -602,8 +602,8 @@ function EditorOptionsBuilderDialog({
<select
className={baseInputClass}
value={toSelectValue(options.labelMode)}
onChange={(event) => setOptionValue('labelMode', event.target.value)}
title="Label gösterim modu."
onChange={(event) => setOptionValue('labelMode', event.target.value)}
>
<option value="">Seç</option>
<option value="static">static</option>
@ -617,8 +617,8 @@ function EditorOptionsBuilderDialog({
<select
className={baseInputClass}
value={toSelectValue(options.stylingMode)}
onChange={(event) => setOptionValue('stylingMode', event.target.value)}
title="DevExtreme editor görünüm stili."
onChange={(event) => setOptionValue('stylingMode', event.target.value)}
>
<option value="">Seç</option>
<option value="outlined">outlined</option>
@ -631,9 +631,9 @@ function EditorOptionsBuilderDialog({
<input
className={baseInputClass}
value={toInputValue(options.hint)}
onChange={(event) => setOptionValue('hint', event.target.value)}
placeholder="Tooltip/hint metni"
title="Editor üzerine gelince gösterilecek hint."
onChange={(event) => setOptionValue('hint', event.target.value)}
/>
</label>
<label className="text-xs text-gray-500">
@ -641,9 +641,9 @@ function EditorOptionsBuilderDialog({
<input
className={baseInputClass}
value={toInputValue(options.valueChangeEvent)}
onChange={(event) => setOptionValue('valueChangeEvent', event.target.value)}
placeholder="change veya input"
title="Değer değişimini tetikleyecek DOM event adı. Örnek: change, input, keyup."
onChange={(event) => setOptionValue('valueChangeEvent', event.target.value)}
/>
</label>
<label className="text-xs text-gray-500">
@ -651,11 +651,11 @@ function EditorOptionsBuilderDialog({
<input
className={baseInputClass}
value={toInputValue(getByPath(options, 'inputAttr.aria-label'))}
placeholder="Erişilebilir ad"
title="Input için aria-label."
onChange={(event) =>
setOptionPathValue('inputAttr.aria-label', event.target.value)
}
placeholder="Erişilebilir ad"
title="Input için aria-label."
/>
</label>
</div>
@ -674,8 +674,8 @@ function EditorOptionsBuilderDialog({
<select
className={baseInputClass}
value={toSelectValue(options.mode)}
onChange={(event) => setOptionValue('mode', event.target.value)}
title="Input mode. TextBox/NumberBox için kullanılabilir."
onChange={(event) => setOptionValue('mode', event.target.value)}
>
<option value="">Seç</option>
<option value="text">text</option>
@ -692,15 +692,15 @@ function EditorOptionsBuilderDialog({
<input
className={baseInputClass}
value={toInputValue(options.maxLength)}
placeholder="50"
type="number"
title="Maksimum karakter sayısı."
onChange={(event) =>
setOptionValue(
'maxLength',
event.target.value ? Number(event.target.value) : undefined,
)
}
placeholder="50"
type="number"
title="Maksimum karakter sayısı."
/>
</label>
<label className="text-xs text-gray-500">
@ -708,9 +708,9 @@ function EditorOptionsBuilderDialog({
<input
className={baseInputClass}
value={toInputValue(options.mask)}
onChange={(event) => setOptionValue('mask', event.target.value)}
placeholder="(000) 000-0000"
title="TextBox mask değeri."
onChange={(event) => setOptionValue('mask', event.target.value)}
/>
</label>
<label className="text-xs text-gray-500">
@ -718,9 +718,9 @@ function EditorOptionsBuilderDialog({
<input
className={baseInputClass}
value={toInputValue(options.maskInvalidMessage)}
onChange={(event) => setOptionValue('maskInvalidMessage', event.target.value)}
placeholder="Geçerli değer girin"
title="Mask geçersiz olduğunda gösterilecek mesaj."
onChange={(event) => setOptionValue('maskInvalidMessage', event.target.value)}
/>
</label>
<label className="text-xs text-gray-500">
@ -728,8 +728,8 @@ function EditorOptionsBuilderDialog({
<select
className={baseInputClass}
value={toSelectValue(options.showMaskMode)}
onChange={(event) => setOptionValue('showMaskMode', event.target.value)}
title="Mask ne zaman gösterilsin?"
onChange={(event) => setOptionValue('showMaskMode', event.target.value)}
>
<option value="">Seç</option>
<option value="always">always</option>
@ -741,9 +741,9 @@ function EditorOptionsBuilderDialog({
<input
className={baseInputClass}
value={toInputValue(getByPath(options, 'maskRules.X'))}
onChange={(event) => setOptionPathValue('maskRules.X', event.target.value)}
placeholder="[0-9]"
title="Custom mask rule. Örnek: X -> [0-9]"
onChange={(event) => setOptionPathValue('maskRules.X', event.target.value)}
/>
</label>
</div>
@ -763,15 +763,15 @@ function EditorOptionsBuilderDialog({
<input
className={baseInputClass}
value={toInputValue(options[key])}
placeholder={key === 'step' ? '1' : '0'}
type="number"
title={`${key} numeric option.`}
onChange={(event) =>
setOptionValue(
key,
event.target.value ? Number(event.target.value) : undefined,
)
}
placeholder={key === 'step' ? '1' : '0'}
type="number"
title={`${key} numeric option.`}
/>
</label>
))}
@ -780,8 +780,8 @@ function EditorOptionsBuilderDialog({
<select
className={baseInputClass}
value={toSelectValue(getByPath(options, 'format.type'))}
onChange={(event) => setOptionPathValue('format.type', event.target.value)}
title="NumberBox format type."
onChange={(event) => setOptionPathValue('format.type', event.target.value)}
>
<option value="">Seç</option>
<option value="fixedPoint">fixedPoint</option>
@ -795,15 +795,15 @@ function EditorOptionsBuilderDialog({
<input
className={baseInputClass}
value={toInputValue(getByPath(options, 'format.precision'))}
placeholder="2"
type="number"
title="Ondalık hassasiyeti."
onChange={(event) =>
setOptionPathValue(
'format.precision',
event.target.value ? Number(event.target.value) : undefined,
)
}
placeholder="2"
type="number"
title="Ondalık hassasiyeti."
/>
</label>
</div>
@ -822,8 +822,8 @@ function EditorOptionsBuilderDialog({
<select
className={baseInputClass}
value={toSelectValue(options.type)}
onChange={(event) => setOptionValue('type', event.target.value)}
title="DateBox type."
onChange={(event) => setOptionValue('type', event.target.value)}
>
<option value="">Seç</option>
<option value="date">date</option>
@ -836,8 +836,8 @@ function EditorOptionsBuilderDialog({
<select
className={baseInputClass}
value={toSelectValue(options.pickerType)}
onChange={(event) => setOptionValue('pickerType', event.target.value)}
title="DateBox picker type."
onChange={(event) => setOptionValue('pickerType', event.target.value)}
>
<option value="">Seç</option>
<option value="calendar">calendar</option>
@ -851,9 +851,9 @@ function EditorOptionsBuilderDialog({
<input
className={baseInputClass}
value={toInputValue(options.displayFormat)}
onChange={(event) => setOptionValue('displayFormat', event.target.value)}
placeholder="dd/MM/yyyy veya HH:mm"
title="DateBox display format."
onChange={(event) => setOptionValue('displayFormat', event.target.value)}
/>
</label>
<label className="text-xs text-gray-500">
@ -861,11 +861,11 @@ function EditorOptionsBuilderDialog({
<input
className={baseInputClass}
value={toInputValue(options.dateSerializationFormat)}
placeholder="yyyy-MM-ddTHH:mm:ss"
title="Kaydedilecek date serialization format."
onChange={(event) =>
setOptionValue('dateSerializationFormat', event.target.value)
}
placeholder="yyyy-MM-ddTHH:mm:ss"
title="Kaydedilecek date serialization format."
/>
</label>
<label className="text-xs text-gray-500">
@ -873,15 +873,15 @@ function EditorOptionsBuilderDialog({
<input
className={baseInputClass}
value={toInputValue(options.interval)}
placeholder="5"
type="number"
title="Time list aralığı dakika cinsinden."
onChange={(event) =>
setOptionValue(
'interval',
event.target.value ? Number(event.target.value) : undefined,
)
}
placeholder="5"
type="number"
title="Time list aralığı dakika cinsinden."
/>
</label>
<label className="text-xs text-gray-500">
@ -889,9 +889,9 @@ function EditorOptionsBuilderDialog({
<input
className={baseInputClass}
value={toInputValue(options.invalidDateMessage)}
onChange={(event) => setOptionValue('invalidDateMessage', event.target.value)}
placeholder="Geçerli tarih/saat girin"
title="Geçersiz tarih mesajı."
onChange={(event) => setOptionValue('invalidDateMessage', event.target.value)}
/>
</label>
</div>
@ -932,6 +932,8 @@ function EditorOptionsBuilderDialog({
<input
className={`${baseInputClass} col-span-4`}
value={option.path}
placeholder="path.to.option"
title="Nokta ile nested path yaz. Örnek: toolbar.multiline"
onChange={(event) =>
setCustomOptions((current) =>
current.map((item) =>
@ -939,8 +941,6 @@ function EditorOptionsBuilderDialog({
),
)
}
placeholder="path.to.option"
title="Nokta ile nested path yaz. Örnek: toolbar.multiline"
/>
<select
className={`${baseInputClass} col-span-2`}
@ -963,6 +963,8 @@ function EditorOptionsBuilderDialog({
<input
className={`${baseInputClass} col-span-5`}
value={option.value}
placeholder={option.type === 'boolean' ? 'true / false' : 'value'}
title="Tip JSON ise object/array yazabilirsin. Tip boolean ise true veya false yaz."
onChange={(event) =>
setCustomOptions((current) =>
current.map((item) =>
@ -970,8 +972,6 @@ function EditorOptionsBuilderDialog({
),
)
}
placeholder={option.type === 'boolean' ? 'true / false' : 'value'}
title="Tip JSON ise object/array yazabilirsin. Tip boolean ise true veya false yaz."
/>
<Button
type="button"

View file

@ -3,7 +3,7 @@ import { SelectBoxOption } from '@/types/shared'
import { useLocalization } from '@/utils/hooks/useLocalization'
import Editor from '@monaco-editor/react'
import { useEffect, useMemo, useState } from 'react'
import { FaBolt, FaCheck, FaCode, FaMagic, FaPlus, FaTimes, FaTrash } from 'react-icons/fa'
import { FaCheck, FaCode, FaMagic, FaPlus, FaTimes, FaTrash } from 'react-icons/fa'
type CopyMapping = {
id: string
@ -597,12 +597,6 @@ function EditorScriptBuilderDialog({
setAmountTotalField((current) => current || findField('TotalAmount'))
}
const fillTimeDefaults = () => {
setTimeStartField((current) => current || findField('StartTime'))
setTimeEndField((current) => current || findField('EndTime'))
setTimeTargetField((current) => current || findField('TotalHours'))
}
const resetBuilderSelections = () => {
setCopyMappings([])
setDaysStartField('')
@ -834,12 +828,12 @@ function EditorScriptBuilderDialog({
return (
<Dialog
preventScroll
isOpen={isOpen}
width={1100}
height="82vh"
contentClassName="flex flex-col"
style={{ overlay: { zIndex: 1300 } }}
preventScroll
onClose={onClose}
onRequestClose={onClose}
>
@ -898,6 +892,8 @@ function EditorScriptBuilderDialog({
<input
className={baseInputClass}
value={mapping.source}
placeholder="Örn: unitPrice veya Customer.Name"
title="Seçilen kayıttaki kolon/path. Örnek: Quantity, UnitPrice, Customer.Name"
onChange={(event) =>
setCopyMappings((current) =>
current.map((item) =>
@ -907,8 +903,6 @@ function EditorScriptBuilderDialog({
),
)
}
placeholder="Örn: unitPrice veya Customer.Name"
title="Seçilen kayıttaki kolon/path. Örnek: Quantity, UnitPrice, Customer.Name"
/>
</label>
<div className="col-span-12 md:col-span-5">
@ -1012,11 +1006,11 @@ function EditorScriptBuilderDialog({
action.operator === 'empty' ||
action.operator === 'notEmpty'
}
placeholder="Örn: Aktif, 1000"
title="Koşulda kullanılacak sabit değer. Örnek: Aktif, 0, True"
onChange={(event) =>
updateConditionalAction(action.id, { value: event.target.value })
}
placeholder="Örn: Aktif, 1000"
title="Koşulda kullanılacak sabit değer. Örnek: Aktif, 0, True"
/>
</label>
<div className={actionIconCellClass}>
@ -1054,7 +1048,7 @@ function EditorScriptBuilderDialog({
<option value="confirm">Onay iste</option>
<option value="calculate">Formül hesapla</option>
<option value="setReadOnly">ReadOnly ayarla</option>
<option value="apiToField">API sonucunu field'a yaz</option>
<option value="apiToField">API sonucunu field&apos;a yaz</option>
</select>
</label>
@ -1077,11 +1071,11 @@ function EditorScriptBuilderDialog({
<input
className={baseInputClass}
value={action.textValue}
placeholder="text, {Field} or {selected.Name}"
title="Sabit metin veya token yaz. Örnek: {Name}, {value}, {selected.DisplayName}"
onChange={(event) =>
updateConditionalAction(action.id, { textValue: event.target.value })
}
placeholder="text, {Field} or {selected.Name}"
title="Sabit metin veya token yaz. Örnek: {Name}, {value}, {selected.DisplayName}"
/>
</label>
)}
@ -1129,11 +1123,11 @@ function EditorScriptBuilderDialog({
<input
className={baseInputClass}
value={action.apiUrl}
placeholder="/api/path/{Id}"
title="Token kullanabilirsin: /api/orders/{OrderId}, /api/x/{selected.Id}, /api/y/{value}"
onChange={(event) =>
updateConditionalAction(action.id, { apiUrl: event.target.value })
}
placeholder="/api/path/{Id}"
title="Token kullanabilirsin: /api/orders/{OrderId}, /api/x/{selected.Id}, /api/y/{value}"
/>
</label>
<label className={`${fieldLabelClass} col-span-12 md:col-span-3`}>
@ -1141,13 +1135,13 @@ function EditorScriptBuilderDialog({
<input
className={baseInputClass}
value={action.responsePath}
placeholder="data.value"
title="API JSON cevabından okunacak path. Boş bırakırsan tüm JSON hedef field'a yazılır."
onChange={(event) =>
updateConditionalAction(action.id, {
responsePath: event.target.value,
})
}
placeholder="data.value"
title="API JSON cevabından okunacak path. Boş bırakırsan tüm JSON hedef field'a yazılır."
/>
</label>
</>
@ -1160,13 +1154,13 @@ function EditorScriptBuilderDialog({
<input
className={baseInputClass}
value={action.textValue}
placeholder="/report?id={Id}&type={selected.Type}"
title="Açılacak URL. Token destekler: {Id}, {value}, {selected.Type}"
onChange={(event) =>
updateConditionalAction(action.id, {
textValue: event.target.value,
})
}
placeholder="/report?id={Id}&type={selected.Type}"
title="Açılacak URL. Token destekler: {Id}, {value}, {selected.Type}"
/>
</label>
<label className={`${fieldLabelClass} col-span-12 md:col-span-2`}>
@ -1194,11 +1188,11 @@ function EditorScriptBuilderDialog({
<input
className={baseInputClass}
value={action.message}
placeholder="{Field} tokenları ile mesaj"
title="Alert/confirm mesajı. Token destekler: {Name}, {value}, {selected.Name}"
onChange={(event) =>
updateConditionalAction(action.id, { message: event.target.value })
}
placeholder="{Field} tokenları ile mesaj"
title="Alert/confirm mesajı. Token destekler: {Name}, {value}, {selected.Name}"
/>
</label>
)}
@ -1209,11 +1203,11 @@ function EditorScriptBuilderDialog({
<input
className={baseInputClass}
value={action.formula}
placeholder="Number(data.Quantity || 0) * Number(data.UnitPrice || 0)"
title="JavaScript expression yaz. data=formData, selected=selectedItem, value=e.value olarak kullanılır."
onChange={(event) =>
updateConditionalAction(action.id, { formula: event.target.value })
}
placeholder="Number(data.Quantity || 0) * Number(data.UnitPrice || 0)"
title="JavaScript expression yaz. data=formData, selected=selectedItem, value=e.value olarak kullanılır."
/>
</label>
)}
@ -1292,9 +1286,9 @@ function EditorScriptBuilderDialog({
<input
className={baseInputClass}
value={serviceCall}
onChange={(event) => setServiceCall(event.target.value)}
placeholder="UiEvalService.ApiGenerateBackgroundWorkers();"
title="Global servis çağrısı. Örnek: UiEvalService.ApiGenerateBackgroundWorkers();"
onChange={(event) => setServiceCall(event.target.value)}
/>
</div>
</section>
@ -1340,7 +1334,6 @@ function EditorScriptBuilderDialog({
language="typescript"
theme="vs-dark"
value={scriptEditorValue}
onChange={(nextValue) => setScriptEditorValue(nextValue || '')}
options={{
automaticLayout: true,
fontSize: 12,
@ -1349,6 +1342,7 @@ function EditorScriptBuilderDialog({
tabSize: 2,
wordWrap: 'on',
}}
onChange={(nextValue) => setScriptEditorValue(nextValue || '')}
/>
</div>
</section>

View file

@ -88,10 +88,10 @@ function JsonRowOpDialogAnnotation({
id="annotationOperation"
isOpen={isOpen}
preventScroll={true}
onClose={handleClose}
onRequestClose={handleClose}
width={900}
height="90vh"
onClose={handleClose}
onRequestClose={handleClose}
>
{(data.operation === 'create' || data.operation === 'update') && (
<Formik

View file

@ -16,7 +16,7 @@ import { useStoreActions } from '@/store'
import { useLocalization } from '@/utils/hooks/useLocalization'
import { Field, FieldArray, FieldProps, Form, Formik } from 'formik'
import groupBy from 'lodash/groupBy'
import { Dispatch, SetStateAction, useEffect, useState } from 'react'
import { Dispatch, SetStateAction, useCallback, useEffect, useState } from 'react'
import { FaBolt, FaCalendarMinus, FaCalendarPlus, FaSlidersH, FaTag } from 'react-icons/fa'
import { number, object, string } from 'yup'
import {
@ -82,7 +82,7 @@ function JsonRowOpDialogEditForm({
const [scriptBuilderIndex, setScriptBuilderIndex] = useState<number | null>(null)
const [isHelperOpen, setIsHelperOpen] = useState(false)
const getFields = async () => {
const getFields = useCallback(async () => {
if (!listFormCode) {
return
}
@ -113,7 +113,7 @@ function JsonRowOpDialogEditForm({
},
)
}
}
}, [listFormCode])
const handleClose = async (e?: any) => {
if (e) {
@ -133,7 +133,7 @@ function JsonRowOpDialogEditForm({
if (isOpen && data) {
getFields()
}
}, [isOpen, data])
}, [isOpen, data, getFields])
if (!data || !fieldList?.length) {
return null
@ -279,10 +279,10 @@ function JsonRowOpDialogEditForm({
<Dialog
isOpen={isHelperOpen}
onClose={() => setIsHelperOpen(false)}
onRequestClose={() => setIsHelperOpen(false)}
preventScroll={true}
width={1000}
onClose={() => setIsHelperOpen(false)}
onRequestClose={() => setIsHelperOpen(false)}
>
<h5 className="mb-4">Helper</h5>
@ -396,11 +396,11 @@ function JsonRowOpDialogEditForm({
)
: null
}
menuPlacement="auto"
maxMenuHeight={150}
onChange={(option) =>
form.setFieldValue(field.name, option?.value)
}
menuPlacement="auto"
maxMenuHeight={150}
/>
)}
</Field>
@ -422,12 +422,12 @@ function JsonRowOpDialogEditForm({
(option) =>
option.value === values.items?.at(index)?.editorType2,
)}
onChange={(option) =>
form.setFieldValue(field.name, option?.value)
}
className="flex-1"
menuPlacement="auto"
maxMenuHeight={150}
onChange={(option) =>
form.setFieldValue(field.name, option?.value)
}
/>
)}
</Field>

View file

@ -10,10 +10,10 @@ import {
} from '@/components/ui'
import { ListFormJsonRowDto } from '@/proxy/admin/list-form/models'
import { SelectBoxOption } from '@/types/shared'
import { useStoreActions, useStoreState } from '@/store'
import { useStoreActions } from '@/store'
import { useLocalization } from '@/utils/hooks/useLocalization'
import { Field, FieldProps, Form, Formik } from 'formik'
import { Dispatch, SetStateAction, useEffect, useState } from 'react'
import { Dispatch, SetStateAction, useCallback, useEffect, useState } from 'react'
import { object, string } from 'yup'
import { JsonRowDialogData } from './types'
import {
@ -22,10 +22,10 @@ import {
postListFormJsonRow,
putListFormJsonRow,
} from '@/services/admin/list-form.service'
import { cascadeFilterOperator, colSpanOptions } from '../options'
import { cascadeFilterOperator } from '../options'
import CreatableSelect from 'react-select/creatable'
import { getListFormFields } from '@/services/admin/list-form-field.service'
import { groupBy } from 'lodash'
import groupBy from 'lodash/groupBy'
import { extraFilterControlTypeOptions } from '@/proxy/admin/list-form/options'
const schema = object().shape({
@ -73,7 +73,7 @@ function JsonRowOpDialogExtraFilter({
setIsOpen(false)
}
const getFields = async () => {
const getFields = useCallback(async () => {
if (!listFormCode) {
return
}
@ -104,13 +104,13 @@ function JsonRowOpDialogExtraFilter({
},
)
}
}
}, [listFormCode])
useEffect(() => {
if (isOpen && data) {
getFields()
}
}, [isOpen, data])
}, [isOpen, data, getFields])
if (!data || !fieldList?.length) {
return null
@ -121,9 +121,9 @@ function JsonRowOpDialogExtraFilter({
id="extraFilterOperation"
isOpen={isOpen}
preventScroll={true}
width={data.operation === 'create' || data.operation === 'update' ? 'sm' : '450px'}
onClose={handleClose}
onRequestClose={handleClose}
width={data.operation === 'create' || data.operation === 'update' ? 'sm' : '450px'}
>
{(data.operation === 'create' || data.operation === 'update') && (
<>

View file

@ -5,15 +5,13 @@ import {
FormItem,
Input,
Notification,
Select,
Tabs,
toast,
} from '@/components/ui'
import { ListFormJsonRowDto } from '@/proxy/admin/list-form/models'
import { useStoreActions } from '@/store'
import { useLocalization } from '@/utils/hooks/useLocalization'
import { Field, FieldProps, Form, Formik } from 'formik'
import { Dispatch, SetStateAction, useEffect, useState } from 'react'
import { Dispatch, SetStateAction } from 'react'
import { number, object, string } from 'yup'
import { JsonRowDialogData } from './types'
import {
@ -114,7 +112,7 @@ function JsonRowOpDialogPane({
}
}}
>
{({ touched, errors, values, isSubmitting }) => (
{({ touched, errors, isSubmitting }) => (
<Form>
<FormContainer size="sm">
<div className="h-full overflow-y-auto p-2">

View file

@ -14,7 +14,7 @@ import { SelectBoxOption } from '@/types/shared'
import { useStoreActions, useStoreState } from '@/store'
import { useLocalization } from '@/utils/hooks/useLocalization'
import { Field, FieldProps, Form, Formik } from 'formik'
import { Dispatch, SetStateAction, useEffect, useState } from 'react'
import { Dispatch, SetStateAction } from 'react'
import { boolean, number, object, string } from 'yup'
import { JsonRowDialogData } from './types'
import {
@ -30,7 +30,6 @@ import {
columnSummaryTypeListOptions,
} from '../options'
import { ChartPanesDto, ChartValueAxisDto } from '@/proxy/admin/charts/models'
import CreatableSelect from 'react-select/creatable'
import { tooltipFormatListOptions } from '@/proxy/admin/list-form/options'
const schema = object().shape({
@ -129,10 +128,10 @@ function JsonRowOpDialogSeries({
id="paneOperation"
isOpen={isOpen}
preventScroll={true}
onClose={handleClose}
onRequestClose={handleClose}
width={900}
height="90vh"
onClose={handleClose}
onRequestClose={handleClose}
>
{(data.operation === 'create' || data.operation === 'update') && (
<Formik
@ -282,9 +281,9 @@ function JsonRowOpDialogSeries({
value={fieldList?.find(
(option) => option.value === values.argumentField,
)}
onChange={(option) => form.setFieldValue(field.name, option?.value)}
menuPlacement="auto"
maxMenuHeight={150}
onChange={(option) => form.setFieldValue(field.name, option?.value)}
/>
)}
</Field>
@ -303,9 +302,9 @@ function JsonRowOpDialogSeries({
isClearable={true}
options={fieldList}
value={fieldList?.find((option) => option.value === values.valueField)}
onChange={(option) => form.setFieldValue(field.name, option?.value)}
menuPlacement="auto"
maxMenuHeight={150}
onChange={(option) => form.setFieldValue(field.name, option?.value)}
/>
)}
</Field>

View file

@ -122,7 +122,7 @@ function JsonRowOpDialogSubForm({
}
loadData()
}, [isOpen, listFormValues?.listFormCode])
}, [isOpen, listFormValues?.listFormCode, translate])
useEffect(() => {
if (isOpen) {

View file

@ -12,10 +12,10 @@ import {
import SqlEditor from '@/views/developerKit/SqlEditor'
import { ListFormJsonRowDto } from '@/proxy/admin/list-form/models'
import { SelectBoxOption } from '@/types/shared'
import { useStoreActions, useStoreState } from '@/store'
import { useStoreActions } from '@/store'
import { useLocalization } from '@/utils/hooks/useLocalization'
import { Field, FieldProps, Form, Formik } from 'formik'
import { Dispatch, SetStateAction, useEffect, useState } from 'react'
import { Dispatch, SetStateAction } from 'react'
import { number, object, string } from 'yup'
import { JsonRowDialogData } from './types'
import {
@ -77,10 +77,10 @@ function JsonRowOpDialogWidget({
id="widgetOperation"
isOpen={isOpen}
preventScroll={true}
onClose={handleClose}
onRequestClose={handleClose}
width={data.operation === 'create' || data.operation === 'update' ? 900 : 450}
height="90vh"
onClose={handleClose}
onRequestClose={handleClose}
>
{(data.operation === 'create' || data.operation === 'update') && (
<Formik
@ -243,13 +243,9 @@ function JsonRowOpDialogWidget({
<div className="space-y-3">
<div>
<code className="text-xs bg-gray-800 p-1 rounded block mt-1">
SELECT 'Aktif' as title, COUNT(Id) as value,
<br />
&nbsp;&nbsp;'blue' as color, 'FaChartBar' as icon,
<br />
&nbsp;&nbsp;'Aktif kayıtlar' as subTitle
<br />
FROM YourTable WHERE IsActive = 1
{
"SELECT 'Aktif' as title, COUNT(Id) as value, 'blue' as color, 'FaChartBar' as icon, 'Aktif kayıtlar' as subTitle FROM YourTable WHERE IsActive = 1"
}
</code>
</div>
</div>
@ -269,8 +265,8 @@ function JsonRowOpDialogWidget({
>
<SqlEditor
value={values.sqlQuery || ''}
onChange={(value) => setFieldValue('sqlQuery', value || '')}
height="35vh"
onChange={(value) => setFieldValue('sqlQuery', value || '')}
/>
</div>
</FormItem>

View file

@ -10,7 +10,6 @@ import { useLocation, useNavigate } from 'react-router-dom'
import * as Yup from 'yup'
import { getMenus } from '@/services/menu.service'
import { getPermissions } from '@/services/identity.service'
import { DbTypeEnum, SelectCommandTypeEnum } from '@/proxy/form/models'
import { getDataSources } from '@/services/data-source.service'
import { sqlObjectManagerService } from '@/services/sql-query-manager.service'
import type { SqlObjectExplorerDto, DatabaseColumnDto } from '@/proxy/sql-query-manager/models'
@ -32,13 +31,15 @@ import { Container } from '@/components/shared'
import { sqlDataTypeToDbType } from '../edit/options'
import { useStoreActions } from '@/store/store'
import { deleteWizardFile, getWizardFile, postListFormWizard } from '@/services/wizard.service'
import { UiLookupDataSourceTypeEnum } from '@/proxy/form/models'
import { ListFormWizardDto } from '@/proxy/admin/wizard/models'
import {
ListFormWorkflowCriteriaDto,
SubFormDto,
WidgetEditDto,
WorkflowDto,
UiLookupDataSourceTypeEnum,
DbTypeEnum,
SelectCommandTypeEnum,
} from '@/proxy/form/models'
// ─── Formik initial values & validation ──────────────────────────────────────
@ -271,7 +272,9 @@ const Wizard = () => {
setSelectCommandColumns(cols)
const colNames = new Set(cols.map((c) => c.columnName.toLowerCase()))
const hasTenantColumn = colNames.has('tenantid')
const selectableColumns = cols.filter((c) => isAutoSelectedColumn(c.columnName, hasTenantColumn))
const selectableColumns = cols.filter((c) =>
isAutoSelectedColumn(c.columnName, hasTenantColumn),
)
setSelectedColumns(new Set(selectableColumns.map((c) => c.columnName)))
setEditingGroups([])
// Auto-check isTenant / isBranch based on column presence
@ -297,7 +300,11 @@ const Wizard = () => {
const toggleColumn = (col: string) =>
setSelectedColumns((prev) => {
const next = new Set(prev)
next.has(col) ? next.delete(col) : next.add(col)
if (next.has(col)) {
next.delete(col)
} else {
next.add(col)
}
return next
})
@ -548,15 +555,17 @@ const Wizard = () => {
const previousSpacedLabel = toSpacedLabel(formik?.values.wizardName ?? '')
const derived = deriveListFormCode(name)
const setAutoText = (field: keyof Pick<
ListFormWizardDto,
| 'languageTextMenuEn'
| 'languageTextMenuTr'
| 'languageTextTitleEn'
| 'languageTextTitleTr'
| 'languageTextDescEn'
| 'languageTextDescTr'
>) => {
const setAutoText = (
field: keyof Pick<
ListFormWizardDto,
| 'languageTextMenuEn'
| 'languageTextMenuTr'
| 'languageTextTitleEn'
| 'languageTextTitleTr'
| 'languageTextDescEn'
| 'languageTextDescTr'
>,
) => {
const current = formik?.values[field]
if (!current || current === previousSpacedLabel) {
formik?.setFieldValue(field, spacedLabel)
@ -789,7 +798,7 @@ const Wizard = () => {
setSubmitting(false)
}}
>
{({ touched, errors, isSubmitting, values }) => (
{({ touched, errors, values }) => (
<Form onKeyDown={preventEnterSubmit}>
<FormContainer size={currentStep >= 2 ? undefined : 'sm'}>
{/* ─── Step 1: Basic Info ─────────────────────────────── */}
@ -856,7 +865,6 @@ const Wizard = () => {
groups={editingGroups}
onGroupsChange={setEditingGroups}
dbObjects={dbObjects}
isLoadingDbObjects={isLoadingDbObjects}
dsCode={currentDataSource}
translate={translate}
onBack={() => setCurrentStep(1)}

View file

@ -321,7 +321,8 @@ function MenuTreeInline({
const toggle = (code: string) =>
setExpanded((prev) => {
const n = new Set(prev)
n.has(code) ? n.delete(code) : n.add(code)
if (n.has(code)) n.delete(code)
else n.add(code)
return n
})

View file

@ -64,7 +64,6 @@ export interface WizardStep3Props {
groups: WizardGroup[]
onGroupsChange: (groups: WizardGroup[]) => void
dbObjects: SqlObjectExplorerDto | null
isLoadingDbObjects: boolean
dsCode: string
translate: (key: string) => string
onBack: () => void
@ -794,7 +793,6 @@ const WizardStep3 = ({
groups,
onGroupsChange,
dbObjects,
isLoadingDbObjects: _isLoadingDbObjects,
dsCode,
translate,
onBack,

Some files were not shown because too many files have changed in this diff Show more