{rowLabel}} content={digestStr} />
+ );
+ return (
+
+ {!params.row.___weave?.isNew ? (
+ onClick(rowId)}>{rowSpan}
+ ) : null}
+
+ );
+ },
+ },
+ ...(isEditing
+ ? [
+ {
+ field: 'controls',
+ headerName: '',
+ width: columnWidths.controls ?? 48,
+ sortable: false,
+ filterable: false,
+ editable: false,
+ renderCell: (params: GridRenderCellParams) => (
+
+ ),
+ },
+ ]
+ : []),
+ ];
+
+ const fieldColumns: GridColDef[] = Array.from(allFields).map(field => ({
+ field: field as string,
+ headerName: field as string,
+ width: columnWidths[field as string] ?? undefined,
+ flex: columnWidths[field as string] ? undefined : 1,
+ minWidth: 100,
+ editable: isEditing,
+ sortable: !isEditing,
+ filterable: false,
+ renderCell: (params: GridRenderCellParams) => {
+ if (!isEditing) {
+ return (
+
+
+
+ );
+ }
+ const rowIndex = params.row.___weave?.index;
+
+ const editedFields =
+ rowIndex != null && !params.row.___weave?.isNew
+ ? getEditedFields(rowIndex)
+ : {};
+ return (
+
+ );
+ },
+ renderEditCell: (params: GridRenderEditCellParams) => {
+ const rowIndex = params.row.___weave?.index;
+ const serverValue =
+ rowIndex != null && !params.row.___weave?.isNew
+ ? get(loadedRows[rowIndex - offset]?.val ?? {}, params.field)
+ : '';
+ return (
+
+ );
+ },
+ }));
+
+ return [...baseColumns, ...fieldColumns];
+ }, [
+ combinedRows,
+ getEditedFields,
+ deleteRow,
+ restoreRow,
+ deletedRows,
+ deleteAddedRow,
+ initialFields,
+ isEditing,
+ onClick,
+ offset,
+ loadedRows,
+ columnWidths,
+ preserveFieldOrder,
+ ]);
+
+ const handleColumnWidthChange = useCallback((params: any) => {
+ setColumnWidths(prev => ({
+ ...prev,
+ [params.colDef.field]: params.width,
+ }));
+ }, []);
+
+ const CustomFooter = useCallback(() => {
+ return (
+
+ {isEditing && (
+
+
+
+ )}
+
+
+
+
+ );
+ }, [isEditing, handleAddRowsClick]);
+
+ return (
+
+ col.field),
+ },
+ }}
+ onColumnWidthChange={handleColumnWidthChange}
+ columnBufferPx={50}
+ autoHeight={false}
+ disableColumnMenu={true}
+ density="compact"
+ rows={combinedRows}
+ columns={columns}
+ sortingMode="server"
+ sortModel={sortModel}
+ onSortModelChange={onSortModelChange}
+ editMode="cell"
+ pagination
+ paginationMode="server"
+ paginationModel={paginationModel}
+ onPaginationModelChange={setPaginationModel}
+ rowCount={
+ (numRowsQuery.result?.count ?? 0) + (isEditing ? numAddedRows : 0)
+ }
+ disableMultipleColumnsSorting
+ loading={!fetchQueryLoaded}
+ disableRowSelectionOnClick
+ keepBorders={false}
+ pageSizeOptions={[50]}
+ slots={{
+ footer: isEditing ? CustomFooter : undefined,
+ }}
+ sx={{
+ border: 'none',
+ flex: 1,
+ height: '100%',
+ '& .MuiDataGrid-cell': {
+ padding: '0',
+ },
+ '& .MuiDataGrid-columnHeaders': {
+ borderBottom: '1px solid rgba(224, 224, 224, 1)',
+ marginBottom: '-1px', // offset the border
+ },
+ '& .MuiDataGrid-cell[data-field="controls"]': {
+ borderLeft: 'none',
+ boxShadow: 'none',
+ '&:focus, &:focus-within': {
+ outline: 'none',
+ },
+ '&:hover': {
+ backgroundColor: 'transparent',
+ },
+ '&.MuiDataGrid-cell--editing': {
+ backgroundColor: 'transparent',
+ boxShadow: 'none',
+ },
+ '&.Mui-selected, &.Mui-selected:hover, &.Mui-selected:focus': {
+ backgroundColor: 'transparent',
+ boxShadow: 'none',
+ },
+ },
+ '& .MuiDataGrid-columnHeader[data-field="controls"]': {
+ borderLeft: 'none',
+ boxShadow: 'none',
+ border: 'none',
+ '&:focus, &:focus-within': {
+ outline: 'none',
+ },
+ },
+ '& .MuiDataGrid-footerContainer': {
+ backgroundColor: 'white',
+ border: 'none',
+ borderTop: '1px solid rgba(224, 224, 224, 1)',
+ },
+ '& .MuiDataGrid-columnSeparator': {
+ visibility: 'visible',
+ },
+ '& .MuiDataGrid-filler--pinnedRight': {
+ borderLeft: 'none',
+ },
+ }}
+ getRowId={(row: GridRowModel) => row.___weave?.id ?? row.id}
+ />
+
+ );
+};
diff --git a/weave-js/src/components/PagePanelComponents/Home/Browse3/datasets/editors/CodeEditor.tsx b/weave-js/src/components/PagePanelComponents/Home/Browse3/datasets/editors/CodeEditor.tsx
new file mode 100644
index 000000000000..df4776ae0180
--- /dev/null
+++ b/weave-js/src/components/PagePanelComponents/Home/Browse3/datasets/editors/CodeEditor.tsx
@@ -0,0 +1,85 @@
+import {Editor} from '@monaco-editor/react';
+import {Box} from '@mui/material';
+import React from 'react';
+
+interface CodeEditorProps {
+ value: string;
+ onChange: (value: string) => void;
+ onClose: () => void;
+}
+
+export const CodeEditor: React.FC = ({
+ value,
+ onChange,
+ onClose,
+}) => {
+ return (
+
+ onChange(newValue ?? '')}
+ onMount={(editor, monacoInstance) => {
+ editor.addAction({
+ id: 'closeEditor',
+ label: 'Close Editor',
+ keybindings: [
+ monacoInstance.KeyMod.CtrlCmd + monacoInstance.KeyCode.Enter,
+ ],
+ run: () => {
+ onClose();
+ },
+ });
+ const disposable = editor.onKeyDown(e => {
+ if (e.browserEvent.key === 'Enter' && !e.browserEvent.metaKey) {
+ e.browserEvent.preventDefault();
+ e.browserEvent.stopPropagation();
+ editor.trigger('keyboard', 'type', {text: '\n'});
+ }
+ });
+
+ editor.onDidDispose(() => {
+ disposable.dispose();
+ });
+ }}
+ options={{
+ minimap: {enabled: false},
+ scrollBeyondLastLine: true,
+ fontSize: 12,
+ fontFamily: 'monospace',
+ lineNumbers: 'on',
+ folding: false,
+ automaticLayout: true,
+ padding: {top: 12, bottom: 12},
+ fixedOverflowWidgets: true,
+ wordWrap: 'off',
+ scrollbar: {
+ horizontal: 'auto',
+ useShadows: false,
+ verticalScrollbarSize: 10,
+ horizontalScrollbarSize: 10,
+ },
+ }}
+ />
+
+ );
+};
diff --git a/weave-js/src/components/PagePanelComponents/Home/Browse3/datasets/editors/DiffEditor.tsx b/weave-js/src/components/PagePanelComponents/Home/Browse3/datasets/editors/DiffEditor.tsx
new file mode 100644
index 000000000000..559754b5308d
--- /dev/null
+++ b/weave-js/src/components/PagePanelComponents/Home/Browse3/datasets/editors/DiffEditor.tsx
@@ -0,0 +1,97 @@
+import {DiffEditor as MonacoDiffEditor} from '@monaco-editor/react';
+import {Box} from '@mui/material';
+import type {editor as monacoEditor} from 'monaco-editor';
+import React from 'react';
+
+interface DiffEditorProps {
+ value: string;
+ originalValue: string;
+ onChange: (value: string) => void;
+ onClose: () => void;
+}
+
+export const DiffEditor: React.FC = ({
+ value,
+ originalValue,
+ onChange,
+ onClose,
+}) => {
+ return (
+
+ {
+ const modifiedEditor = editor.getModifiedEditor();
+ modifiedEditor.addAction({
+ id: 'closeEditor',
+ label: 'Close Editor',
+ keybindings: [monaco.KeyMod.CtrlCmd + monaco.KeyCode.Enter],
+ run: () => {
+ onClose();
+ },
+ });
+
+ const keyDisposable = modifiedEditor.onKeyDown(e => {
+ if (e.browserEvent.key === 'Enter' && !e.browserEvent.metaKey) {
+ e.browserEvent.preventDefault();
+ e.browserEvent.stopPropagation();
+ modifiedEditor.trigger('keyboard', 'type', {text: '\n'});
+ }
+ });
+
+ const changeDisposable = modifiedEditor.onDidChangeModelContent(
+ () => {
+ const model = modifiedEditor.getModel();
+ if (model) {
+ onChange(model.getValue());
+ }
+ }
+ );
+
+ modifiedEditor.onDidDispose(() => {
+ keyDisposable.dispose();
+ changeDisposable.dispose();
+ });
+ }}
+ options={{
+ minimap: {enabled: false},
+ scrollBeyondLastLine: true,
+ fontSize: 12,
+ fontFamily: 'monospace',
+ lineNumbers: 'on',
+ folding: false,
+ automaticLayout: true,
+ padding: {top: 12, bottom: 12},
+ fixedOverflowWidgets: true,
+ wordWrap: 'off',
+ scrollbar: {
+ horizontal: 'auto',
+ useShadows: false,
+ verticalScrollbarSize: 10,
+ horizontalScrollbarSize: 10,
+ },
+ }}
+ />
+
+ );
+};
diff --git a/weave-js/src/components/PagePanelComponents/Home/Browse3/datasets/editors/TextEditor.tsx b/weave-js/src/components/PagePanelComponents/Home/Browse3/datasets/editors/TextEditor.tsx
new file mode 100644
index 000000000000..8b2aaa76f3fd
--- /dev/null
+++ b/weave-js/src/components/PagePanelComponents/Home/Browse3/datasets/editors/TextEditor.tsx
@@ -0,0 +1,59 @@
+import {TextField} from '@mui/material';
+import React from 'react';
+
+interface TextEditorProps {
+ value: string;
+ onChange: (value: string) => void;
+ onClose: () => void;
+ inputRef?: React.RefObject;
+}
+
+export const TextEditor: React.FC = ({
+ value,
+ onChange,
+ onClose,
+ inputRef,
+}) => {
+ const handleKeyDown = (event: React.KeyboardEvent) => {
+ if (event.key === 'Enter' && !event.metaKey) {
+ event.stopPropagation();
+ } else if (event.key === 'Enter' && event.metaKey) {
+ onClose();
+ }
+ };
+
+ return (
+ onChange(e.target.value)}
+ onKeyDown={handleKeyDown}
+ onFocus={e => {
+ const target = e.target as HTMLTextAreaElement;
+ target.setSelectionRange(0, target.value.length);
+ }}
+ fullWidth
+ multiline
+ autoFocus
+ sx={{
+ width: '100%',
+ '& .MuiInputBase-root': {
+ fontFamily: '"Source Sans Pro", sans-serif',
+ fontSize: '14px',
+ border: 'none',
+ backgroundColor: 'white',
+ },
+ '& .MuiInputBase-input': {
+ padding: '0px',
+ },
+ '& .MuiOutlinedInput-notchedOutline': {
+ border: 'none',
+ },
+ '& textarea': {
+ overflow: 'hidden !important',
+ resize: 'none',
+ },
+ }}
+ />
+ );
+};
diff --git a/weave-js/src/components/PagePanelComponents/Home/Browse3/pages/CallPage/DataTableView.tsx b/weave-js/src/components/PagePanelComponents/Home/Browse3/pages/CallPage/DataTableView.tsx
index 800b6a0fdf2b..ac8f56a05c46 100644
--- a/weave-js/src/components/PagePanelComponents/Home/Browse3/pages/CallPage/DataTableView.tsx
+++ b/weave-js/src/components/PagePanelComponents/Home/Browse3/pages/CallPage/DataTableView.tsx
@@ -48,7 +48,7 @@ import {TABLE_ID_EDGE_NAME} from '../wfReactInterface/constants';
import {useWFHooks} from '../wfReactInterface/context';
import {SortBy} from '../wfReactInterface/traceServerClientTypes';
-const RowId = styled.span`
+export const RowId = styled.span`
font-family: 'Inconsolata', monospace;
`;
RowId.displayName = 'S.RowId';
@@ -238,7 +238,7 @@ export const WeaveCHTable: FC<{
);
};
-type DataTableServerSidePaginationControls = {
+export type DataTableServerSidePaginationControls = {
paginationModel: GridPaginationModel;
onPaginationModelChange: (model: GridPaginationModel) => void;
totalRows: number;
diff --git a/weave-js/src/components/PagePanelComponents/Home/Browse3/pages/ObjectsPage/ObjectVersionPage.tsx b/weave-js/src/components/PagePanelComponents/Home/Browse3/pages/ObjectsPage/ObjectVersionPage.tsx
index be9cc8e69e77..eddb23998aa9 100644
--- a/weave-js/src/components/PagePanelComponents/Home/Browse3/pages/ObjectsPage/ObjectVersionPage.tsx
+++ b/weave-js/src/components/PagePanelComponents/Home/Browse3/pages/ObjectsPage/ObjectVersionPage.tsx
@@ -9,6 +9,7 @@ import {LoadingDots} from '../../../../../LoadingDots';
import {Tailwind} from '../../../../../Tailwind';
import {Timestamp} from '../../../../../Timestamp';
import {Tooltip} from '../../../../../Tooltip';
+import {DatasetEditProvider} from '../../datasets/DatasetEditorContext';
import {DatasetVersionPage} from '../../datasets/DatasetVersionPage';
import {NotFoundPanel} from '../../NotFoundPanel';
import {CustomWeaveTypeProjectContext} from '../../typeViews/CustomWeaveTypeDispatcher';
@@ -211,10 +212,12 @@ const ObjectVersionPageInner: React.FC<{
if (isDataset) {
return (
-
+
+
+
);
}