Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import { Flex, Text } from '@nvidia/foundations-react-core';
import { ColumnConfigPanel } from '@studio/components/ColumnConfigPanel';
import { ModelConfigPanel } from '@studio/components/ModelConfigPanel';
import type { FC } from 'react';
import { type FC, memo } from 'react';

export interface BuilderConfigPaneProps {
selectedColumnId: string | null;
Expand All @@ -16,35 +16,37 @@ export interface BuilderConfigPaneProps {
onModelClose: () => void;
}

export const BuilderConfigPane: FC<BuilderConfigPaneProps> = ({
export const BuilderConfigPane: FC<BuilderConfigPaneProps> = memo(function BuilderConfigPane({
selectedColumnId,
selectedModelId,
workspace,
onColumnRemove,
onColumnClose,
onModelRemove,
onModelClose,
}) => (
<div className="w-[240px] shrink-0 border-l border-base bg-surface-base">
{selectedColumnId ? (
<ColumnConfigPanel
columnId={selectedColumnId}
onRemove={onColumnRemove}
onClose={onColumnClose}
/>
) : selectedModelId ? (
<ModelConfigPanel
modelId={selectedModelId}
workspace={workspace}
onRemove={onModelRemove}
onClose={onModelClose}
/>
) : (
<Flex align="center" justify="center" className="h-full p-density-lg">
<Text kind="body/regular/sm" className="text-secondary text-center">
Select a column or model to configure it, or add one from the left.
</Text>
</Flex>
)}
</div>
);
}) {
return (
<div className="w-[240px] shrink-0 border-l border-base bg-surface-base">
{selectedColumnId ? (
<ColumnConfigPanel
columnId={selectedColumnId}
onRemove={onColumnRemove}
onClose={onColumnClose}
/>
) : selectedModelId ? (
<ModelConfigPanel
modelId={selectedModelId}
workspace={workspace}
onRemove={onModelRemove}
onClose={onModelClose}
/>
) : (
<Flex align="center" justify="center" className="h-full p-density-lg">
<Text kind="body/regular/sm" className="text-secondary text-center">
Select a column or model to configure it, or add one from the left.
</Text>
</Flex>
)}
</div>
);
});
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { useStickToBottom } from '@nemo/common/src/hooks/useStickToBottom';
import { Banner, Button, CodeSnippet, Flex, Stack } from '@nvidia/foundations-react-core';
import { formatPreviewLogsForDisplay } from '@studio/components/NewDataDesignerJobForm/previewApi';
import { ChevronDown, ChevronRight } from 'lucide-react';
import type { FC } from 'react';
import { type FC, memo } from 'react';

export interface BuilderDetailsPanelProps {
validationErrors: string[];
Expand All @@ -14,13 +14,13 @@ export interface BuilderDetailsPanelProps {
isOpen: boolean;
onToggle: () => void;
}
export const BuilderDetailsPanel: FC<BuilderDetailsPanelProps> = ({
export const BuilderDetailsPanel: FC<BuilderDetailsPanelProps> = memo(function BuilderDetailsPanel({
validationErrors,
submitError,
previewLogs,
isOpen,
onToggle,
}) => {
}) {
const { ref: logsScrollRef } = useStickToBottom<HTMLDivElement>({
enabled: isOpen && !!previewLogs,
});
Expand Down Expand Up @@ -80,4 +80,4 @@ export const BuilderDetailsPanel: FC<BuilderDetailsPanelProps> = ({
)}
</div>
);
};
});
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import type {
JobBuilderFormValues,
PaletteTab,
} from '@studio/routes/DataDesignerJobBuildRoute/useJobBuilder';
import type { FC } from 'react';
import { type FC, memo } from 'react';
import { useFormContext, useWatch } from 'react-hook-form';

export interface BuilderPaletteProps {
Expand All @@ -24,15 +24,15 @@ export interface BuilderPaletteProps {
}

// Tabs only swap what you're adding — column and model configs both open in the right pane.
export const BuilderPalette: FC<BuilderPaletteProps> = ({
export const BuilderPalette: FC<BuilderPaletteProps> = memo(function BuilderPalette({
tab,
onTabChange,
selectedModelId,
workspace,
onAddColumn,
onAddModel,
onSelectModel,
}) => {
}) {
const { control, getValues } = useFormContext<JobBuilderFormValues>();
const models = useWatch({ control, name: 'models' });
const hasSeedColumn = getValues('columns').some(
Expand Down Expand Up @@ -69,4 +69,4 @@ export const BuilderPalette: FC<BuilderPaletteProps> = ({
</div>
</aside>
);
};
});
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { Button, Flex, SegmentedControl, Tag, Text } from '@nvidia/foundations-r
import type { StartOptionTag } from '@studio/components/CreateFilesetStart/types';
import type { JobBuilderFormValues } from '@studio/routes/DataDesignerJobBuildRoute/useJobBuilder';
import { FileJson, ListTree, Pencil, SplinePointer } from 'lucide-react';
import { type FC, useState } from 'react';
import { type FC, memo, useState } from 'react';
import { useFormContext, useWatch } from 'react-hook-form';

/** Which renderer the center pane shows: the flat schema list or the DAG canvas. */
Expand All @@ -26,7 +26,7 @@ export interface BuilderToolbarProps {
isSubmitting: boolean;
}

export const BuilderToolbar: FC<BuilderToolbarProps> = ({
export const BuilderToolbar: FC<BuilderToolbarProps> = memo(function BuilderToolbar({
templateTag,
columnCount,
viewMode,
Expand All @@ -35,7 +35,7 @@ export const BuilderToolbar: FC<BuilderToolbarProps> = ({
isPreviewing,
onSubmit,
isSubmitting,
}) => {
}) {
const [isEditingName, setIsEditingName] = useState(false);
const { control } = useFormContext<JobBuilderFormValues>();
const name = useWatch({ control, name: 'name' }) ?? '';
Expand Down Expand Up @@ -126,4 +126,4 @@ export const BuilderToolbar: FC<BuilderToolbarProps> = ({
</Flex>
</Flex>
);
};
});
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import { useFormContext, useWatch } from 'react-hook-form';

export interface SchemaListProps {
selectedId: string | null;
onSelect: (id: string | null) => void;
onSelect: (id: string) => void;
onDelete: (id: string) => void;
}

Expand Down Expand Up @@ -63,8 +63,8 @@ export const SchemaList: FC<SchemaListProps> = ({ selectedId, onSelect, onDelete
column={column}
references={referencesById.get(column.id) ?? []}
selected={column.id === selectedId}
onSelect={() => onSelect(column.id)}
onDelete={() => onDelete(column.id)}
onSelect={onSelect}
onDelete={onDelete}
/>
))}
</Stack>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { CardIconBadge } from '@studio/components/common/SelectableCard';
import type { BuilderColumn } from '@studio/routes/DataDesignerJobBuildRoute/columns';
import { describeColumn } from '@studio/routes/DataDesignerJobBuildRoute/describeColumn';
import { Box, Trash2 } from 'lucide-react';
import type { FC } from 'react';
import { type FC, memo } from 'react';

/** Accent color → NVIDIA Foundations text token, matching the DAG node icon styling. */
const ACCENT_ICON_CLASS: Record<string, string> = {
Expand All @@ -24,22 +24,22 @@ export interface SchemaRowProps {
/** Names of columns this one references, shown inline as `{{ name }}` relationship tags. */
references: string[];
selected: boolean;
onSelect: () => void;
onDelete: () => void;
onSelect: (id: string) => void;
onDelete: (id: string) => void;
}

/**
* One column rendered as a row in the schema list: a generation-step number, an icon badge,
* the column name, a type badge, a one-line summary, and its relationship tags. Selecting the
* row opens the same config pane the DAG canvas uses; the trailing button deletes the column.
*/
export const SchemaRow: FC<SchemaRowProps> = ({
export const SchemaRow: FC<SchemaRowProps> = memo(function SchemaRow({
column,
references,
selected,
onSelect,
onDelete,
}) => {
}) {
const { option } = column;
const { typeLabel, detail } = describeColumn(column);
const Icon = option.icon ?? Box;
Expand All @@ -54,7 +54,7 @@ export const SchemaRow: FC<SchemaRowProps> = ({
<button
type="button"
data-select=""
onClick={onSelect}
onClick={() => onSelect(column.id)}
aria-pressed={selected}
className="flex min-w-0 flex-1 items-center gap-density-md px-density-lg py-density-md text-left focus-visible:outline-none cursor-pointer"
>
Expand Down Expand Up @@ -93,7 +93,7 @@ export const SchemaRow: FC<SchemaRowProps> = ({
kind="tertiary"
color="danger"
size="tiny"
onClick={onDelete}
onClick={() => onDelete(column.id)}
aria-label={`Delete ${column.name || option.label}`}
className="h-full rounded-none opacity-0 transition-opacity focus-visible:opacity-100 group-hover:opacity-100"
>
Expand All @@ -102,4 +102,4 @@ export const SchemaRow: FC<SchemaRowProps> = ({
</Flex>
</Flex>
);
};
});
Original file line number Diff line number Diff line change
Expand Up @@ -140,16 +140,16 @@ export const DataDesignerJobBuildRoute: FC = () => {
getCurrentConfig,
});

const handlePreview = () => {
const handlePreview = useCallback(() => {
if (validateAndCollectErrors().length > 0) return;
setIsDetailsOpen(true);
void runPreview();
};
}, [validateAndCollectErrors, runPreview]);

const createJob = useDataDesignerCreateJob();
const submitError = createJob.error ? getErrorMessage(createJob.error) : null;

const handleSubmit = async () => {
const handleSubmit = useCallback(async () => {
if (validateAndCollectErrors().length > 0) return;
const { columns, models, name, rows } = builder.getBuilderValues();

Expand All @@ -173,7 +173,17 @@ export const DataDesignerJobBuildRoute: FC = () => {
setIsDetailsOpen(true);
// Error surfaced via createJob.error / submitError below.
}
};
}, [validateAndCollectErrors, builder, createJob, workspace, servedModelNames, navigate]);

const toggleDetails = useCallback(() => setIsDetailsOpen((open) => !open), []);
const onColumnRemove = useCallback(() => {
if (builder.selectedColumnId) builder.removeColumn(builder.selectedColumnId);
}, [builder]);
const onColumnClose = useCallback(() => builder.selectColumn(null), [builder]);
const onModelRemove = useCallback(() => {
if (builder.selectedModelId) builder.removeModel(builder.selectedModelId);
}, [builder]);
const onModelClose = useCallback(() => builder.selectModel(null), [builder]);

return (
<AccessibleTitle title={heading}>
Expand All @@ -195,7 +205,7 @@ export const DataDesignerJobBuildRoute: FC = () => {
submitError={submitError}
previewLogs={previewLogs}
isOpen={isDetailsOpen}
onToggle={() => setIsDetailsOpen((open) => !open)}
onToggle={toggleDetails}
/>

<Flex className="min-h-0 border-t border-base h-full">
Expand Down Expand Up @@ -229,14 +239,10 @@ export const DataDesignerJobBuildRoute: FC = () => {
selectedColumnId={builder.selectedColumnId}
selectedModelId={builder.selectedModelId}
workspace={workspace}
onColumnRemove={() =>
builder.selectedColumnId && builder.removeColumn(builder.selectedColumnId)
}
onColumnClose={() => builder.selectColumn(null)}
onModelRemove={() =>
builder.selectedModelId && builder.removeModel(builder.selectedModelId)
}
onModelClose={() => builder.selectModel(null)}
onColumnRemove={onColumnRemove}
onColumnClose={onColumnClose}
onModelRemove={onModelRemove}
onModelClose={onModelClose}
/>
</Flex>
</Stack>
Expand Down
Loading