>({
);
})}
- {isExpanded && groupRows.map((row, rowIndex) => {
+ {isExpanded && groupRows.map((row) => {
const globalIndex = displayData.indexOf(row);
- const dataAttributes = getRowDataAttributes ? getRowDataAttributes(row, globalIndex) : {};
- return (
-
onRowClick?.(row, globalIndex)}
- draggable={rowDraggable}
- onDragStart={rowDraggable && onRowDragStart ? (e) => onRowDragStart(e, row) : undefined}
- {...Object.fromEntries(
- Object.entries(dataAttributes).map(([key, value]) => [`data-${key}`, value])
- )}
- >
- {selectable && (
- |
- handleRowSelect(row)}
- onClick={(e) => e.stopPropagation()}
- disabled={isRowSelectable && !isRowSelectable(row)}
- title={
- isRowSelectable && !isRowSelectable(row)
- ? t('Dieses Element kann nicht ausgewählt werden')
- : t('Dieses Element auswählen')
- }
- style={{
- opacity: isRowSelectable && !isRowSelectable(row) ? 0.4 : 1,
- cursor: isRowSelectable && !isRowSelectable(row) ? 'not-allowed' : 'pointer'
- }}
- />
- |
- )}
- {hasActionColumn && (
-
- {
- if (el) {
- actionButtonsRefs.current.set(globalIndex, el);
- } else {
- actionButtonsRefs.current.delete(globalIndex);
- }
- }}
- className={`${styles.actionButtons} ${shouldWrapActionButtons ? styles.actionButtonsWrap : ''}`}
- >
- {actionButtons.map((actionButton, actionIndex) => {
- if (actionButton.visible && !actionButton.visible(row, hookData)) return null;
- const actionTitle = typeof actionButton.title === 'function'
- ? actionButton.title(row)
- : actionButton.title;
- let disabledResult: boolean | { disabled: boolean; message?: string } = false;
- if (actionButton.disabled) {
- disabledResult = actionButton.disabled(row, hookData);
- } else if (row._permissions) {
- if (actionButton.type === 'edit' && row._permissions.canUpdate === false) {
- disabledResult = true;
- } else if (actionButton.type === 'delete' && row._permissions.canDelete === false) {
- disabledResult = true;
- }
- }
- const isLoading = actionButton.loading ? actionButton.loading(row) : false;
- const isProcessing = actionButton.isProcessing ? actionButton.isProcessing(row) : false;
- const baseProps = {
- row, disabled: disabledResult, loading: isLoading,
- className: [compact ? actionBtnStyles.compact : '', actionButton.className ?? ''].filter(Boolean).join(' '),
- title: actionTitle,
- idField: actionButton.idField ?? 'id', nameField: actionButton.nameField ?? 'name',
- typeField: actionButton.typeField ?? 'type', contentField: actionButton.contentField ?? 'content',
- operationName: actionButton.operationName, loadingStateName: actionButton.loadingStateName
- };
- switch (actionButton.type) {
- case 'edit':
- return ;
- case 'delete':
- return ;
- case 'view':
- return {})} isViewing={isProcessing} hookData={hookData} />;
- case 'copy':
- return ;
- default:
- return null;
- }
- })}
- {customActions.map((customAction) => (
-
- ))}
-
- |
- )}
- {detectedColumns.map(column => {
- const cellValue = row[column.key];
- const customClassName = column.cellClassName ? column.cellClassName(cellValue, row) : '';
- const combinedClassName = `${styles.td} ${customClassName}`.trim();
- const alignStyle = _columnAlignStyle(column);
- return (
-
- {formatCellValue(cellValue, column, row)}
- |
- );
- })}
-
- );
+ return _renderDataRow(row, globalIndex);
})}
);
@@ -3276,97 +3244,6 @@ export function FormGeneratorTable
>({
// Total colspan for group/breadcrumb/ungrouped rows
const _totalColSpan = (selectable ? 1 : 0) + (hasActionColumn ? 1 : 0) + detectedColumns.length;
- // ── Helper: render a single data row ──────────────────
- const _renderDataRow = (row: T, index: number) => {
- const dataAttributes = getRowDataAttributes ? getRowDataAttributes(row, index) : {};
- const rowId = _getRowId(row);
-
- return (
- onRowClick?.(row, index)}
- draggable={rowDraggable}
- onDragStart={(e) => {
- if (rowDraggable && onRowDragStart) onRowDragStart(e, row);
- }}
- onDragEnd={() => {}}
- {...Object.fromEntries(Object.entries(dataAttributes).map(([k, v]) => [`data-${k}`, v]))}
- >
- {selectable && (
- |
- handleRowSelect(row)}
- onClick={(e) => e.stopPropagation()}
- disabled={isRowSelectable && !isRowSelectable(row)}
- title={isRowSelectable && !isRowSelectable(row) ? t('Dieses Element kann nicht ausgewählt werden') : t('Dieses Element auswählen')}
- style={{ opacity: isRowSelectable && !isRowSelectable(row) ? 0.4 : 1, cursor: isRowSelectable && !isRowSelectable(row) ? 'not-allowed' : 'pointer' }}
- />
- |
- )}
- {hasActionColumn && (
-
- { if (el) actionButtonsRefs.current.set(index, el); else actionButtonsRefs.current.delete(index); }}
- className={`${styles.actionButtons} ${shouldWrapActionButtons ? styles.actionButtonsWrap : ''}`}>
- {actionButtons.map((ab, ai) => {
- if (ab.visible && !ab.visible(row, hookData)) return null;
- const abTitle = typeof ab.title === 'function' ? ab.title(row) : ab.title;
- let dis: boolean | { disabled: boolean; message?: string } = false;
- if (ab.disabled) { dis = ab.disabled(row, hookData); }
- else if (row._permissions) {
- if (ab.type === 'edit' && row._permissions.canUpdate === false) dis = true;
- else if (ab.type === 'delete' && row._permissions.canDelete === false) dis = true;
- }
- const isLd = ab.loading ? ab.loading(row) : false;
- const isProc = ab.isProcessing ? ab.isProcessing(row) : false;
- const bp = { row, disabled: dis, loading: isLd, className: [compact ? actionBtnStyles.compact : '', ab.className ?? ''].filter(Boolean).join(' '), title: abTitle, idField: ab.idField ?? 'id', nameField: ab.nameField ?? 'name', typeField: ab.typeField ?? 'type', contentField: ab.contentField ?? 'content', operationName: ab.operationName, loadingStateName: ab.loadingStateName };
- switch (ab.type) {
- case 'edit': return ;
- case 'delete': return ;
- case 'view': return {})} isViewing={isProc} hookData={hookData} />;
- case 'copy': return ;
- default: return null;
- }
- })}
- {customActions.map((ca) => (
-
- ))}
-
- |
- )}
- {detectedColumns.map((col) => {
- const cv = row[col.key];
- const cCls = col.cellClassName ? col.cellClassName(cv, row) : '';
- const aStyle = _columnAlignStyle(col);
- return (
-
- {formatCellValue(cv, col, row)}
- |
- );
- })}
-
- );
- };
-
// ── Strategy B view grouping: insert collapsible group headers ──
if (effectiveGroupLayout && effectiveGroupLayout.bands.length > 0) {
const rows: React.ReactNode[] = [];
diff --git a/src/components/FormGenerator/FormGeneratorTree/FormGeneratorTree.tsx b/src/components/FormGenerator/FormGeneratorTree/FormGeneratorTree.tsx
index 8e31414..fa1087c 100644
--- a/src/components/FormGenerator/FormGeneratorTree/FormGeneratorTree.tsx
+++ b/src/components/FormGenerator/FormGeneratorTree/FormGeneratorTree.tsx
@@ -405,10 +405,12 @@ export function FormGeneratorTree({
onSelectionChange,
onRefresh,
onSendToChat,
+ allowCreateFolder = true,
className,
}: FormGeneratorTreeProps) {
const { t } = useLanguage();
- const { confirm, ConfirmDialog } = useConfirm();
+ const { confirm } = useConfirm();
+ const { prompt, PromptDialog } = usePrompt();
const [nodes, setNodes] = useState[]>([]);
const [expandedIds, setExpandedIds] = useState>(new Set());
const [selectedIds, setSelectedIds] = useState>(new Set());
@@ -695,6 +697,7 @@ export function FormGeneratorTree({
if (ownership === 'shared') return;
if (draggingIds.size === 0) return;
if (draggingIds.has(node.id)) return;
+ if (node.type !== 'folder') return;
e.preventDefault();
e.dataTransfer.dropEffect = 'move';
setDragOverId(node.id);