Form komponentinin column sayısı eklendi

This commit is contained in:
Sedat ÖZTÜRK 2026-08-20 08:57:55 +03:00
parent 690da79b87
commit 61234dec3f
6 changed files with 60 additions and 7 deletions

View file

@ -25014,6 +25014,12 @@
"en": "Header text of the card wrapping the container; leave empty to hide the header. A value starting with :: is resolved as a localization key.", "en": "Header text of the card wrapping the container; leave empty to hide the header. A value starting with :: is resolved as a localization key.",
"tr": "Kabı saran kartın başlık metni; boş bırakılırsa başlık gizlenir. :: ile başlayan değer dil anahtarı olarak çözümlenir." "tr": "Kabı saran kartın başlık metni; boş bırakılırsa başlık gizlenir. :: ile başlayan değer dil anahtarı olarak çözümlenir."
}, },
{
"resourceName": "Platform",
"key": "App.CatalogSqlDataSource.SqlDataSourceColumnCountDescription",
"en": "How many components are placed side by side inside the form. 1 keeps every component on its own row; 2 places two components per row and wraps to the next one.",
"tr": "Form içindeki bileşenlerin yan yana kaç sütun halinde dizileceği. 1 seçilirse her bileşen alt alta durur; 2 seçilirse her satıra iki bileşen yerleşir ve sonraki satıra geçer."
},
{ {
"resourceName": "Platform", "resourceName": "Platform",
"key": "App.CatalogSqlDataSource.SqlDataSourceTitle", "key": "App.CatalogSqlDataSource.SqlDataSourceTitle",

File diff suppressed because one or more lines are too long

View file

@ -18,6 +18,7 @@ import {
getDesignerTabSlot, getDesignerTabSlot,
getDesignerValueByPath, getDesignerValueByPath,
getSqlDataSourceEndpointId, getSqlDataSourceEndpointId,
getSqlDataSourceColumnCount,
getSqlDataSourceKeyField, getSqlDataSourceKeyField,
getSqlFormValueProperty, getSqlFormValueProperty,
isDesignerDateComponent, isDesignerDateComponent,
@ -844,6 +845,7 @@ const SqlDataSourceView = ({
const selectId = getSqlDataSourceEndpointId(node, 'selectEndpoint') const selectId = getSqlDataSourceEndpointId(node, 'selectEndpoint')
const keyField = getSqlDataSourceKeyField(node) const keyField = getSqlDataSourceKeyField(node)
const collectionPath = String(node.props.collectionPath ?? '') const collectionPath = String(node.props.collectionPath ?? '')
const columnCount = getSqlDataSourceColumnCount(node)
const rows = React.useMemo( const rows = React.useMemo(
() => (selectId ? resolveSqlDataSourceRows(dataValues[selectId], collectionPath) : []), () => (selectId ? resolveSqlDataSourceRows(dataValues[selectId], collectionPath) : []),
[collectionPath, dataValues, selectId], [collectionPath, dataValues, selectId],
@ -972,7 +974,22 @@ const SqlDataSourceView = ({
)} )}
</div> </div>
)} )}
{renderChildren(childDataValues, formScope)} {columnCount > 1 ? (
// Grid only once more than one column is asked for, so a single column
// form keeps the exact flex layout it had before the setting existed.
<div
style={{
display: 'grid',
gridTemplateColumns: `repeat(${columnCount}, minmax(0, 1fr))`,
gap: Number(node.props.gap) || 0,
alignItems: 'start',
}}
>
{renderChildren(childDataValues, formScope)}
</div>
) : (
renderChildren(childDataValues, formScope)
)}
{/* The drop zone belongs with the content, above the command toolbar. */} {/* The drop zone belongs with the content, above the command toolbar. */}
{interactive && !node.children.length && ( {interactive && !node.children.length && (
<div className="rounded border border-dashed border-slate-300 px-3 py-4 text-center text-xs text-slate-400 dark:border-slate-700"> <div className="rounded border border-dashed border-slate-300 px-3 py-4 text-center text-xs text-slate-400 dark:border-slate-700">

View file

@ -849,6 +849,16 @@ export const SQL_DATA_SOURCE_DEFINITION: DesignerComponentDefinition = {
category: 'properties', category: 'properties',
description: 'App.CatalogBoolean.BooleanDescription2', description: 'App.CatalogBoolean.BooleanDescription2',
}, },
// Number of columns the fields inside the container are laid out in. 1 —
// the default — keeps every child on its own row; a higher value places
// that many components side by side before wrapping to the next row.
{
name: 'columnCount',
type: 'number',
value: 1,
category: 'styling',
description: 'App.CatalogSqlDataSource.SqlDataSourceColumnCountDescription',
},
{ {
name: 'gap', name: 'gap',
type: 'number', type: 'number',

View file

@ -5,6 +5,7 @@ import {
getDesignerTabSlotValue, getDesignerTabSlotValue,
getDesignerDataSourceFilters, getDesignerDataSourceFilters,
getDesignerNodeFilters, getDesignerNodeFilters,
getSqlDataSourceColumnCount,
getSqlDataSourceEndpointId, getSqlDataSourceEndpointId,
getSqlDataSourceKeyField, getSqlDataSourceKeyField,
getSqlDataSourceKeyParam, getSqlDataSourceKeyParam,
@ -723,11 +724,22 @@ const SQL_TOOLBAR_BUTTON_CLASS =
const sqlDataSourceToCode = (node: DesignerNode, level: number, itemVariable?: string) => { const sqlDataSourceToCode = (node: DesignerNode, level: number, itemVariable?: string) => {
const names = sqlIdentifiers(node) const names = sqlIdentifiers(node)
const formScope: FormScope = { sourceId: node.id, setterName: names.setField } const formScope: FormScope = { sourceId: node.id, setterName: names.setField }
const columnCount = getSqlDataSourceColumnCount(node)
const gap = Number(node.props.gap) || 0
// Children sit one level deeper once they are wrapped in the column grid.
const children = node.children const children = node.children
.map((child) => nodeToCode(child, level + 2, itemVariable, formScope)) .map((child) => nodeToCode(child, level + (columnCount > 1 ? 3 : 2), itemVariable, formScope))
.join('\n') .join('\n')
const className = JSON.stringify(String(node.props.className || '')) const className = JSON.stringify(String(node.props.className || ''))
const style = `{ display: "flex", flexDirection: "column", gap: ${Number(node.props.gap) || 0} }` const style = `{ display: "flex", flexDirection: "column", gap: ${gap} }`
// The toolbar and the error line stay in the outer column, so only the fields
// are laid out side by side. A single column emits no wrapper at all, which
// keeps the markup of every page saved before the setting existed unchanged.
const gridStyle = `{ display: "grid", gridTemplateColumns: "repeat(${columnCount}, minmax(0, 1fr))", gap: ${gap}, alignItems: "start" }`
const content =
columnCount > 1
? `${indent(`<div style={${gridStyle}}>`, level + 2)}\n${children}\n${indent('</div>', level + 2)}`
: children
const plainButtonClass = `${SQL_TOOLBAR_BUTTON_CLASS} border border-slate-300 text-slate-600 hover:border-sky-400 hover:text-sky-700 dark:border-slate-700 dark:text-slate-300` const plainButtonClass = `${SQL_TOOLBAR_BUTTON_CLASS} border border-slate-300 text-slate-600 hover:border-sky-400 hover:text-sky-700 dark:border-slate-700 dark:text-slate-300`
// Navigation appears on its own whenever there is more than one record to walk. // Navigation appears on its own whenever there is more than one record to walk.
const navigation = ` const navigation = `
@ -764,7 +776,7 @@ ${indent(`{${names.error} ? <div className="rounded-md bg-red-50 px-3 py-2 text-
return `${indent(cardStart, level)} return `${indent(cardStart, level)}
${indent(`<div ref={${names.host}} className=${className} style={${style}}>`, level + 1)} ${indent(`<div ref={${names.host}} className=${className} style={${style}}>`, level + 1)}
${children}${toolbar}${error} ${content}${toolbar}${error}
${indent('</div>', level + 1)} ${indent('</div>', level + 1)}
${indent('</UiKit.Card>', level)}` ${indent('</UiKit.Card>', level)}`
} }

View file

@ -847,6 +847,14 @@ export const getSqlDataSourceEndpointId = (node: DesignerNode, property: string)
export const getSqlDataSourceKeyField = (node: DesignerNode) => export const getSqlDataSourceKeyField = (node: DesignerNode) =>
String(node.props?.keyFieldName ?? '').trim() || 'id' String(node.props?.keyFieldName ?? '').trim() || 'id'
/**
* How many components the container places side by side. Documents saved before
* the setting existed carry no value at all, so the fallback is 1 every child
* on its own row, which is exactly how those pages already look.
*/
export const getSqlDataSourceColumnCount = (node: DesignerNode) =>
Math.min(12, Math.max(1, Math.floor(Number(node.props?.columnCount) || 1)))
/** /**
* Where the key in the page URL is read from. It fills `/api/app/orders/{id}`, * Where the key in the page URL is read from. It fills `/api/app/orders/{id}`,
* is appended as `?id=…` when the endpoint has no placeholder, and narrows a list * is appended as `?id=…` when the endpoint has no placeholder, and narrows a list