Skip to content
Open
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
46 changes: 46 additions & 0 deletions web/pgadmin/static/js/Dialogs/ConfirmFileDropContent.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/////////////////////////////////////////////////////////////
//
// pgAdmin 4 - PostgreSQL Tools
//
// Copyright (C) 2013 - 2026, The pgAdmin Development Team
// This software is released under the PostgreSQL Licence
//
//////////////////////////////////////////////////////////////

import { ModalContent, ModalFooter } from '../components/ModalContent';
import gettext from 'sources/gettext';
import { Box } from '@mui/material';
import { DefaultButton, PrimaryButton } from '../components/Buttons';
import CloseIcon from '@mui/icons-material/CloseRounded';
import MergeTypeRoundedIcon from '@mui/icons-material/MergeTypeRounded';
import FindReplaceRoundedIcon from '@mui/icons-material/FindReplaceRounded';
import PropTypes from 'prop-types';

export default function ConfirmFileDropContent({closeModal, onMerge, onReplace}) {
return (
<ModalContent>
<Box flexGrow="1" p={2}>
{gettext('The editor already has content. Do you want to replace it with the dropped file, or merge the file content at the current cursor position?')}
</Box>
<ModalFooter>
<DefaultButton data-test="close" startIcon={<CloseIcon />} onClick={()=>{
closeModal();
}} >{gettext('Cancel')}</DefaultButton>
<DefaultButton data-test="merge" startIcon={<MergeTypeRoundedIcon />} onClick={()=>{
onMerge?.();
closeModal();
}} >{gettext('Merge')}</DefaultButton>
<PrimaryButton data-test="replace" startIcon={<FindReplaceRoundedIcon />} onClick={()=>{
onReplace?.();
closeModal();
}} autoFocus={true} >{gettext('Replace')}</PrimaryButton>
</ModalFooter>
</ModalContent>
);
}

ConfirmFileDropContent.propTypes = {
closeModal: PropTypes.func,
onMerge: PropTypes.func,
onReplace: PropTypes.func,
};
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,14 @@ import { checkTrojanSource } from 'sources/utils';
import usePreferences from '../../../../../preferences/static/js/store';
import KeyboardArrowRightRoundedIcon from '@mui/icons-material/KeyboardArrowRightRounded';
import ExpandMoreRoundedIcon from '@mui/icons-material/ExpandMoreRounded';
import {
handleOsFileDrop,
handleOsFileDragOver,
handleEditorBlur,
handleEditorMouseUp,
handleEditorKeyUp,
rememberCaretPos,
} from '../sqlFileDrop';

// Codemirror packages
import {
Expand All @@ -29,7 +37,7 @@ import {
EditorView,
keymap,
} from '@codemirror/view';
import { EditorState, Compartment } from '@codemirror/state';
import { EditorState, Compartment, Prec } from '@codemirror/state';
import { history, defaultKeymap, historyKeymap, indentLess, indentMore, deleteCharBackwardStrict, copyLineDown } from '@codemirror/commands';
import { closeBrackets, autocompletion, closeBracketsKeymap, completionKeymap, acceptCompletion } from '@codemirror/autocomplete';
import {
Expand Down Expand Up @@ -58,13 +66,30 @@ import plpgsqlFoldService from '../extensions/plpgsqlFoldService';
const arrowRightHtml = ReactDOMServer.renderToString(<KeyboardArrowRightRoundedIcon style={{width: '16px', fill: 'currentcolor'}} />);
const arrowDownHtml = ReactDOMServer.renderToString(<ExpandMoreRoundedIcon style={{width: '16px', fill: 'currentcolor'}} />);

function handleDrop(e, editor) {
/** Resolve drop insert position from mouse coords (fallback: document end). */
function getDropPos(editor, event) {
const x = event?.clientX ?? event?.x;
const y = event?.clientY ?? event?.y;
if (typeof x === 'number' && typeof y === 'number') {
const pos = editor.posAtCoords({ x, y }, false);
if (typeof pos === 'number') {
return pos;
}
}
return editor.state.doc.length;
}

/** Handle OS file drops or tree/object-explorer text drops on the editor. */
export function handleDrop(e, editor) {
if (handleOsFileDrop(e, editor)) {
return true;
}

let dropDetails = null;
try {
dropDetails = JSON.parse(e.dataTransfer.getData('text'));

/* Stop firefox from redirecting */

if (e.preventDefault) {
e.preventDefault();
}
Expand All @@ -76,13 +101,20 @@ function handleDrop(e, editor) {
return false;
}

const dropPos = editor.posAtCoords({ x: e.x, y: e.y });
const dropPos = getDropPos(editor, e);
const insert = dropDetails.text || '';
const changes = editor.state.changes({ from: dropPos, to: dropPos, insert });
const insertAt = changes.mapPos(dropPos, -1);
const anchor = Math.min(insertAt + (dropDetails.cur?.from ?? 0), changes.newLength);
const head = Math.min(insertAt + (dropDetails.cur?.to ?? 0), changes.newLength);
editor.dispatch({
changes: { from: dropPos, to: dropPos, insert: dropDetails.text || '' },
selection: { anchor: dropPos + dropDetails.cur.from, head: dropPos + dropDetails.cur.to }
changes,
selection: { anchor, head },
scrollIntoView: true,
});

editor.focus();
return true;
}

function calcFontSize(fontSize) {
Expand Down Expand Up @@ -150,10 +182,14 @@ const defaultExtensions = [
PgSQL.language.data.of({
autocomplete: false,
}),
EditorView.domEventHandlers({
Prec.highest(EditorView.domEventHandlers({
drop: handleDrop,
paste: handlePaste,
}),
dragover: handleOsFileDragOver,
blur: handleEditorBlur,
mouseup: handleEditorMouseUp,
keyup: handleEditorKeyUp,
})),
errorMarkerExtn(),
indentService.of((context, pos) => {
if(context.state.facet(indentNewLine)) {
Expand Down Expand Up @@ -215,9 +251,11 @@ export default function Editor({
].concat(keepHistory ? [history()] : [])),
[EditorView.updateListener.of(function(update) {
if(update.selectionSet) {
rememberCaretPos(update.view);
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Resolved
onCursorActivity?.(update.view.getCursor(), update.view);
}
if(update.docChanged) {
rememberCaretPos(update.view);
onChange?.(update.view.getValue(), update.view);
}
if(breakpoint) {
Expand Down
Loading