diff --git a/ui/src/components/codeLayout/StyleModal.tsx b/ui/src/components/codeLayout/StyleModal.tsx index cb1c8276..bedb823c 100644 --- a/ui/src/components/codeLayout/StyleModal.tsx +++ b/ui/src/components/codeLayout/StyleModal.tsx @@ -1,6 +1,6 @@ import { useMemo, useState } from 'react' import { FaPlus, FaSearch, FaTimes } from 'react-icons/fa' -import { Button } from '@/components/ui' +import { Button, Select } from '@/components/ui' import { useLocalization } from '@/utils/hooks/useLocalization' import Input from '@/components/ui/Input' @@ -352,6 +352,11 @@ const StyleModal = ({ const [search, setSearch] = useState('') const [customClass, setCustomClass] = useState('') const [category, setCategory] = useState('__all__') + + const categoryOptions = [ + { value: '__all__', label: translate('::App.StyleModal.AllCategories') }, + ...Object.keys(STYLE_GROUPS).map((name) => ({ value: name, label: name })), + ] const selected = useMemo(() => new Set(splitClasses(value)), [value]) const classes = useMemo(() => { const source = @@ -409,18 +414,15 @@ const StyleModal = ({ onChange={(event) => setSearch(event.target.value)} /> - + onChange(event.target.value)} - > - - {options.map((option) => ( - - ))} - + { - const next = event.target.value + + /> ) @@ -357,17 +356,21 @@ function ScriptBuilderDialog({ param.placeholder || translate('::App.ScriptBuilder.Choose'), )} {param.type === 'select' && ( - + ({ + value: item.value, + label: item.label.startsWith('App.') ? translate('::' + item.label) : item.label, + })) + + const conditionKindOptions = dialect.conditionKinds.map((item) => ({ + value: item.value, + label: item.label, + })) + + const triggerOptions = (dialect.triggers ?? []).map((item) => ({ + value: item.value, + label: item.label, + })) + const renderCondition = (rule: ScriptRule, condition: ScriptRuleCondition, index: number) => { const operator = dialect.operators.find((item) => item.value === condition.operator) const kind = @@ -401,16 +424,16 @@ function ScriptBuilderDialog({ {translate('::App.ScriptBuilder.Conjunction')} - option.value === (rule.join ?? 'and'))} + onChange={(option) => + option && updateRule(rule.id, { join: option.value as ScriptRule['join'] }) } - > - - - + /> ) : (
@@ -427,17 +450,16 @@ function ScriptBuilderDialog({ {translate('::App.ScriptBuilder.Comparison')} - + - updateCondition(rule, index, { kind: event.target.value, source: '' }) + + /> )} @@ -602,17 +624,18 @@ function ScriptBuilderDialog({ {dialect.triggers && ( )}
diff --git a/ui/src/views/admin/listForm/edit/form-fields/FormFieldTabLookup.tsx b/ui/src/views/admin/listForm/edit/form-fields/FormFieldTabLookup.tsx index d98ec080..6f775523 100644 --- a/ui/src/views/admin/listForm/edit/form-fields/FormFieldTabLookup.tsx +++ b/ui/src/views/admin/listForm/edit/form-fields/FormFieldTabLookup.tsx @@ -1,4 +1,4 @@ -import { Button, Card, FormItem, Input } 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' @@ -50,6 +50,10 @@ function TablePickerModal({ null, ) const [pickerColumns, setPickerColumns] = useState([]) + const pickerColumnOptions = pickerColumns.map((c) => ({ + value: c.columnName ?? '', + label: c.columnName ?? '', + })) const [isLoadingColumns, setIsLoadingColumns] = useState(false) const [keyCol, setKeyCol] = useState('') const [nameCol, setNameCol] = useState('') @@ -163,35 +167,31 @@ function TablePickerModal({ - + setNameCol(e.target.value)} - > - - {pickerColumns.map((c) => ( - - ))} - + + + /> setNewPath(event.target.value)} /> - + { - if (!event.target.value) return onChange(undefined) - onChange(event.target.value === 'true') + + /> ) } @@ -93,29 +99,36 @@ const SelectControl = ({ const current = value === undefined || value === null ? '' : String(value) const known = spec.choices?.some((choice) => String(choice.value) === current) + const choiceOptions = [ + ...(spec.choices ?? []).map((choice) => ({ + value: String(choice.value), + label: String(choice.label), + })), + ...(current && !known + ? [ + { + value: current, + label: `${current} (${translate('::App.ListFormEditorOptions.CurrentValue')})`, + }, + ] + : []), + ] + return ( - option.value === current)} + onChange={(option) => { + const raw = option?.value if (!raw) return onChange(undefined) const choice = spec.choices?.find((item) => String(item.value) === raw) onChange(choice ? choice.value : raw) }} - > - - {spec.choices?.map((choice) => ( - - ))} - {current && !known && ( - - )} - + /> ) } diff --git a/ui/src/views/admin/listForm/edit/json-row-operations/editor-script/scriptRecipes.ts b/ui/src/views/admin/listForm/edit/json-row-operations/editor-script/scriptRecipes.ts index a7ce4825..5ee2d241 100644 --- a/ui/src/views/admin/listForm/edit/json-row-operations/editor-script/scriptRecipes.ts +++ b/ui/src/views/admin/listForm/edit/json-row-operations/editor-script/scriptRecipes.ts @@ -44,7 +44,7 @@ export const triggerLabels: { value: RuleTrigger; label: string; help: string }[ label: 'App.ScriptBuilderOpen.OpenLabel', help: 'App.ScriptBuilderOpen.Help', }, - { value: 'both', label: 'Her ikisi', help: 'App.ScriptBuilderBoth.Help' }, + { value: 'both', label: 'App.StaticLookup.Both', help: 'App.ScriptBuilderBoth.Help' }, ] /** Ek koşullar nasıl birleşecek. */ diff --git a/ui/src/views/admin/listForm/wizard/WizardStepFields.tsx b/ui/src/views/admin/listForm/wizard/WizardStepFields.tsx index 484be74a..2043c8e2 100644 --- a/ui/src/views/admin/listForm/wizard/WizardStepFields.tsx +++ b/ui/src/views/admin/listForm/wizard/WizardStepFields.tsx @@ -1,4 +1,4 @@ -import { Button, Dialog } from '@/components/ui' +import { Button, Dialog, Select } from '@/components/ui' import type { SelectBoxOption } from '@/types/shared' import { useLocalization } from '@/utils/hooks/useLocalization' import { @@ -230,6 +230,10 @@ function SortableItem({ null, ) const [pickerColumns, setPickerColumns] = useState([]) + const pickerColumnOptions = pickerColumns.map((c) => ({ + value: c.columnName ?? '', + label: c.columnName ?? '', + })) const [isLoadingPickerColumns, setIsLoadingPickerColumns] = useState(false) const [pickerKeyCol, setPickerKeyCol] = useState('') const [pickerNameCol, setPickerNameCol] = useState('') @@ -321,17 +325,17 @@ function SortableItem({ {translate('::App.WizardStep3.EditorType')} - + - onLookupDataSourceTypeChange(e.target.value as unknown as UiLookupDataSourceTypeEnum) + + />
@@ -514,35 +520,35 @@ function SortableItem({ - + setPickerNameCol(e.target.value)} - className="w-full text-xs h-7 px-1.5 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" - > - - {pickerColumns.map((c) => ( - - ))} - + onColSpanChange(Number(e.target.value))} - className="text-xs h-5 w-9 px-0.5 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" - > - {Array.from({ length: groupColCount }, (_, i) => i + 1).map((n) => ( - - ))} - + setCopyDialogRole(e.target.value)} - > - - {roleList - .filter((role) => role !== name) - .map((role) => ( - - ))} - + { - const recipient = availableRecipients.find((p) => p.id === e.target.value) + + /> )}
diff --git a/ui/src/views/admin/videoroom/RoomList.tsx b/ui/src/views/admin/videoroom/RoomList.tsx index 0ed4f833..cbbb8756 100644 --- a/ui/src/views/admin/videoroom/RoomList.tsx +++ b/ui/src/views/admin/videoroom/RoomList.tsx @@ -29,7 +29,7 @@ import PageTitle from '@/components/shared/PageTitle' import { useLocalization } from '@/utils/hooks/useLocalization' import { VideoroomDto } from '@/proxy/videoroom/models' import classNames from 'classnames' -import { Button, Dialog, Input } from '@/components/ui' +import { Button, Dialog, Input, Select } from '@/components/ui' import { FcVideoCall } from 'react-icons/fc' export interface RoomProps { @@ -45,6 +45,21 @@ const RoomList = () => { const { user } = useStoreState((state) => state.auth) const { translate } = useLocalization() + const microphoneStateOptions = [ + { value: 'muted' as const, label: translate('::App.VideoRoom.MicrophoneMuted') }, + { value: 'unmuted' as const, label: translate('::App.VideoRoom.MicrophoneUnmuted') }, + ] + const cameraStateOptions = [ + { value: 'on' as const, label: translate('::App.VideoRoom.CameraOn') }, + { value: 'off' as const, label: translate('::App.VideoRoom.CameraOff') }, + ] + const layoutOptions = [ + { value: 'grid', label: translate('::App.VideoRoom.LayoutGridView') }, + { value: 'teacher-focus', label: translate('::App.VideoRoom.LayoutTeacherFocus') }, + { value: 'presentation', label: translate('::App.VideoRoom.LayoutPresentation') }, + { value: 'sidebar', label: translate('::App.VideoRoom.LayoutSidebar') }, + ] + const newClassEntity: VideoroomDto = { id: crypto.randomUUID(), name: '', @@ -733,80 +748,70 @@ const RoomList = () => { - + option.value === videoroom.settingsDto?.defaultMicrophoneState, + )} + onChange={(option) => setVideoroom({ ...videoroom, settingsDto: { ...videoroom.settingsDto!, - defaultMicrophoneState: e.target.value as 'muted' | 'unmuted', + defaultMicrophoneState: option?.value ?? 'muted', }, }) } - className="border border-gray-300 dark:border-gray-700 rounded-lg bg-white dark:bg-gray-800 text-gray-900 dark:text-white focus:ring-2 focus:ring-blue-500 focus:border-transparent" - > - - - + />
- option.value === videoroom.settingsDto?.defaultCameraState, + )} + onChange={(option) => setVideoroom({ ...videoroom, settingsDto: { ...videoroom.settingsDto!, - defaultCameraState: e.target.value as 'on' | 'off', + defaultCameraState: option?.value ?? 'on', }, }) } - className="border border-gray-300 dark:border-gray-700 rounded-lg bg-white dark:bg-gray-800 text-gray-900 dark:text-white focus:ring-2 focus:ring-blue-500 focus:border-transparent" - > - - - + />
- option.value === videoroom.settingsDto?.defaultLayout, + )} + onChange={(option) => setVideoroom({ ...videoroom, settingsDto: { ...videoroom.settingsDto!, - defaultLayout: e.target.value, + defaultLayout: option?.value ?? 'grid', }, }) } - className="border border-gray-300 dark:border-gray-700 rounded-lg bg-white dark:bg-gray-800 text-gray-900 dark:text-white focus:ring-2 focus:ring-blue-500 focus:border-transparent" - > - - - - - + />
{selectCollectionSample && (
@@ -3549,28 +3551,34 @@ const VisualComponentDesigner = () => { {translate('::' + label)} - ({ + value: field.path, + label: field.path, + }))} + value={ + selectOptionsBinding[key] + ? { + value: selectOptionsBinding[key] as string, + label: selectOptionsBinding[key] as string, + } + : null + } + onChange={(option) => updateSelectedBindingDetails(optionDataProperty, { - [key]: event.target.value, + [key]: option?.value ?? '', }) } - > - - {selectColumnFields.map((field) => ( - - ))} - + /> ))}
@@ -3609,28 +3617,25 @@ const VisualComponentDesigner = () => { ))} - !selectOptionColumns.includes(field.path)) + .map((field) => ({ value: field.path, label: field.path }))} + value={null} + onChange={(option) => { + const next = option?.value if (!next || selectOptionColumns.includes(next)) return updateSelectedBindingDetails(optionDataProperty, { columns: [...selectOptionColumns, next], }) }} - > - - {selectColumnFields - .filter((field) => !selectOptionColumns.includes(field.path)) - .map((field) => ( - - ))} - + />

{translate('::App.DeveloperKitComponentDesigner.ExtraColumnsHint')}{' '} @@ -3764,42 +3769,54 @@ const VisualComponentDesigner = () => { {lookup && (

- + + + /> )} {lookup.sourceId && (
@@ -3813,26 +3830,29 @@ const VisualComponentDesigner = () => { {translate(label)} - - {rowFields.map((path) => ( - - ))} - + ) + } + menuPortalTarget={window.document.body} + options={rowFields.map((path) => ({ value: path, label: path }))} + value={ + lookup[field] + ? { value: lookup[field], label: lookup[field] } + : null + } + onChange={(option) => + writeColumnLookup(column, { [field]: option?.value ?? '' }) + } + /> ))}
@@ -3987,6 +4007,15 @@ const VisualComponentDesigner = () => { const patchFilter = (id: string, updates: Partial) => writeFilters(filters.map((filter) => (filter.id === id ? { ...filter, ...updates } : filter))) + const filterSourceOptions = DESIGNER_FILTER_SOURCES.map((item) => ({ + value: item, + label: translate( + `::App.DeveloperKitComponentDesigner.FilterSource${ + item.charAt(0).toUpperCase() + item.slice(1) + }`, + ), + })) + return (
@@ -4038,25 +4067,28 @@ const VisualComponentDesigner = () => { >
{strictColumns ? ( - ( - - ))} - + ).map((column) => ({ value: column, label: column }))} + value={ + filter.field + ? { value: filter.field, label: filter.field } + : null + } + onChange={(option) => + patchFilter(filter.id, { field: option?.value ?? '' }) + } + /> ) : ( { onChange={(event) => patchFilter(filter.id, { field: event.target.value })} /> )} - ({ + value: operator, + label: FILTER_OPERATOR_LABELS[operator], + }))} + value={{ + value: filter.operator, + label: FILTER_OPERATOR_LABELS[filter.operator], + }} + onChange={(option) => + option && patchFilter(filter.id, { - operator: event.target.value as DesignerFilterOperator, + operator: option.value as DesignerFilterOperator, }) } - > - {DESIGNER_FILTER_OPERATORS.map((operator) => ( - - ))} - + />
{!valueless && (
- option.value === filter.source, + )} + onChange={(option) => + option && patchFilter(filter.id, { - source: event.target.value as DesignerFilterSource, + source: option.value as DesignerFilterSource, value: '', }) } - > - {DESIGNER_FILTER_SOURCES.map((item) => ( - - ))} - + /> {filter.source !== 'record' && ( { next to the source selector left neither of them usable. */} {!valueless && filter.source === 'record' && (
- ({ + value: item.ref, + label: item.ref, + }))} + value={masterRef ? { value: masterRef, label: masterRef } : null} + onChange={(option) => patchFilter(filter.id, { - value: masterColumn ? `${event.target.value}.${masterColumn}` : event.target.value, + value: masterColumn + ? `${option?.value ?? ''}.${masterColumn}` + : (option?.value ?? ''), }) } - > - - {sqlContainerRefs.map((item) => ( - - ))} - + /> {

{translate('::' + slot.description)}

- ({ + value: source.id, + label: `${source.name} · ${source.url}`, + }))} + value={options + .filter((source) => source.id === currentValue) + .map((source) => ({ + value: source.id, + label: `${source.name} · ${source.url}`, + }))} + onChange={(option) => { + const sourceId = option?.value ?? '' updateSelectedProp(slot.property, sourceId) const source = document.dataSources.find((item) => item.id === sourceId) if ( @@ -4279,16 +4331,7 @@ const VisualComponentDesigner = () => { void testDataSource(source) } }} - > - - {options.map((source) => ( - - ))} - + /> {!options.length && (

{translate('::App.DeveloperKitComponentDesigner.NoEndpointForMethod', { @@ -4316,17 +4359,26 @@ const VisualComponentDesigner = () => { Koleksiyon - + updateSelectedProp('keySource', event.target.value)} - > - {SQL_DATA_SOURCE_KEY_SOURCES.map((item) => ( - - ))} - + { const column = binding?.sourceId === sqlScopeNode.id ? binding.path : '' const rawDefault = selectedNode.props?.[SQL_DEFAULT_VALUE_PROP] const currentDefault = rawDefault === undefined || rawDefault === null ? '' : String(rawDefault) + const sqlDefaultValueOptions = [ + { value: 'true', label: translate('::App.Platform.Yes') }, + { value: 'false', label: translate('::App.Platform.No') }, + ] const columnListId = `sql-columns-${sqlScopeNode.id}` // A picker gets a real date editor, unless it holds a token — `@today` is not // a date the browser can render, and typing it needs a plain text field. @@ -4552,18 +4608,24 @@ const VisualComponentDesigner = () => { })}

{sqlRecordProperty === 'checked' ? ( - + { {sqlScopeSource?.name}
) : ( - ({ + value: source.id, + label: source.name, + }))} + value={inspectorDataSources + .filter((source) => source.id === (activeDataSource?.id || '')) + .map((source) => ({ value: source.id, label: source.name }))} + onChange={(option) => { + const sourceId = option?.value ?? '' setDataPanelSourceId(sourceId) if ( (isOptionDataComponent(selectedNode?.type) || @@ -4703,20 +4778,7 @@ const VisualComponentDesigner = () => { void testDataSource(source) } }} - > - {/* Without this a browser paints the first option while the - value is still empty, which reads as a made choice. */} - {!activeDataSource && ( - - )} - {inspectorDataSources.map((source) => ( - - ))} - + /> )}
@@ -4733,24 +4795,30 @@ const VisualComponentDesigner = () => { Koleksiyon - ( - - ))} - + menuPortalTarget={window.document.body} + options={tabularCollectionPaths.map((path) => ({ + value: path, + label: + path || + translate('::App.DeveloperKitComponentDesigner.WholeResponseArray'), + }))} + value={{ + value: tabularItemsBinding.path, + label: + tabularItemsBinding.path || + translate('::App.DeveloperKitComponentDesigner.WholeResponseArray'), + }} + onChange={(option) => + updateSelectedBindingDetails('items', { path: option?.value ?? '' }) + } + />
)} @@ -4871,6 +4939,29 @@ const VisualComponentDesigner = () => { choice === '__root__' || selectableFields.some((field) => field.path === choice) + const bindingChoiceOptions = [ + ...(activeBindingSample !== undefined && + (collection || !Array.isArray(activeBindingSample) || isActiveRepeatedSource) + ? [ + { + value: '__root__', + label: translate( + isActiveRepeatedSource + ? '::App.DeveloperKitComponentDesigner.CurrentGridRow' + : collection + ? '::App.DeveloperKitComponentDesigner.WholeCollection' + : '::App.DeveloperKitComponentDesigner.WholeResponse', + ), + }, + ] + : []), + ...(!knownChoice ? [{ value: choice, label: `${choice} (mevcut path)` }] : []), + ...selectableFields.map((field) => ({ + value: field.path, + label: `${field.path} · ${field.type}`, + })), + ] + return (