mirror of
https://github.com/pgadmin-org/pgadmin4.git
synced 2025-02-25 18:55:31 -06:00
Fixed following issues for query tool after react porting:
1) Add New Server Connection > Server options keep loading(For empty Server group). 2) After clicking indent/Unindent(for all operations) for large query option left as it is till operation completes 3) Check sign beside options in Execute Option/Copy Header is little bit big 4) In explain > Analysis tab does not show ROWS column 5) In explain > Explain > analysis previous explain output is NOT cleared. New rows are appended. Same applies to the statistics tab. 6) Update new query tool connection tool tip. Fixes #7289 7) Explain-Analyze > Loops column is empty. 8) Explain-Analyze with Verbose & Costs > in ROW X columns upward arrows are missing. 9) Explain-Analyze with all option checked > background colors are missing for timing. 10) Explain-Analyze > Additional bullet is added before Hash Cond. 11) Browser Tree > Filtered rows icon is not working. 12) Create table with timestamp and default value as function now() > Add new row > Enter mandatory columns except column where default value is function(now()) > Click Save > New row added but column with default value has value [default]. not updated to actual value. / Default values are not considered for any column while adding a new entry. 13) Disable execute options in View/Edit data. 14) The Boolean column always shows null. 15) In Query history Remove & Remove all buttons are stuck to each other. 16) On Remove all, the right panel is empty. 17) Create a column with boolean[]/ text[], Try to add a new entry from data grid, enter “” quotes > Click Ok > Now try edit cell > You can not change value. 18) In query history - Select queries are suffixed by ’Save Data’ icon 19) Edit any table with PK > Try to insert duplicate PK > Error thrown > Correct pK value > Still old error shown > Not able to add new entry (This works when focus is moved from edited cell) 20) Clicking arrows after opening dropdown options, does not collapse dropdown. refs #6131
This commit is contained in:
committed by
Akshay Joshi
parent
74e3f976c1
commit
9c30d983bd
@@ -422,7 +422,7 @@ export default function QueryToolComponent({params, pgWindow, pgAdmin, selectedN
|
||||
eventBus.current.deregisterListener(e[0], e[1]);
|
||||
});
|
||||
};
|
||||
}, [qtState]);
|
||||
}, [qtState.params, qtState.current_file]);
|
||||
|
||||
useEffect(()=>{
|
||||
/* Fire query change so that title changes to latest */
|
||||
@@ -602,11 +602,12 @@ export default function QueryToolComponent({params, pgWindow, pgAdmin, selectedN
|
||||
onResetLayout={onResetLayout}
|
||||
docker={docker.current}
|
||||
/>
|
||||
<MainToolBar
|
||||
containerRef={containerRef}
|
||||
onManageMacros={onManageMacros}
|
||||
onFilterClick={onFilterClick}
|
||||
/>
|
||||
{React.useMemo(()=>(
|
||||
<MainToolBar
|
||||
containerRef={containerRef}
|
||||
onManageMacros={onManageMacros}
|
||||
onFilterClick={onFilterClick}
|
||||
/>), [containerRef.current, onManageMacros, onFilterClick])}
|
||||
<Layout
|
||||
getLayoutInstance={(obj)=>docker.current=obj}
|
||||
defaultLayout={defaultLayout}
|
||||
|
||||
@@ -170,8 +170,8 @@ export function TextEditor({row, column, onRowChange, onClose}) {
|
||||
}, []);
|
||||
|
||||
const onOK = ()=>{
|
||||
if(column.is_array && !isValidArray(value)) {
|
||||
console.error(gettext('Arrays must start with "{" and end with "}"'));
|
||||
if(column.is_array && !isValidArray(localVal)) {
|
||||
Notifier.error(gettext('Arrays must start with "{" and end with "}"'));
|
||||
} else {
|
||||
let columnVal = textColumnFinalVal(localVal, column);
|
||||
onRowChange({ ...row, [column.key]: columnVal}, true);
|
||||
@@ -205,14 +205,14 @@ TextEditor.propTypes = EditorPropTypes;
|
||||
export function NumberEditor({row, column, onRowChange, onClose}) {
|
||||
const classes = useStyles();
|
||||
const value = row[column.key] ?? '';
|
||||
const onBlur = ()=>{
|
||||
const isValidData = ()=>{
|
||||
if(!column.is_array && isNaN(value)){
|
||||
Notifier.error(gettext('Please enter a valid number'));
|
||||
return;
|
||||
return false;
|
||||
} else if(column.is_array) {
|
||||
if(!isValidArray(value)) {
|
||||
Notifier.error(gettext('Arrays must start with "{" and end with "}"'));
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
let checkVal = value.trim().slice(1, -1);
|
||||
if(checkVal == '') {
|
||||
@@ -223,16 +223,25 @@ export function NumberEditor({row, column, onRowChange, onClose}) {
|
||||
for (const val of checkVal) {
|
||||
if(isNaN(val)) {
|
||||
Notifier.error(gettext('Arrays must start with "{" and end with "}"'));
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
onClose(column.can_edit ? true : false);
|
||||
return true;
|
||||
};
|
||||
const onBlur = ()=>{
|
||||
if(isValidData()) {
|
||||
onClose(column.can_edit ? true : false);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
const onKeyDown = (e)=>{
|
||||
if(e.code == 'Tab') {
|
||||
e.preventDefault();
|
||||
onBlur();
|
||||
if(!onBlur()) {
|
||||
e.stopPropagation();
|
||||
}
|
||||
}
|
||||
};
|
||||
return (
|
||||
@@ -245,7 +254,7 @@ export function NumberEditor({row, column, onRowChange, onClose}) {
|
||||
onRowChange({ ...row, [column.key]: e.target.value });
|
||||
}
|
||||
}}
|
||||
// onBlur={onBlur}
|
||||
onBlur={onBlur}
|
||||
onKeyDown={onKeyDown}
|
||||
/>
|
||||
);
|
||||
@@ -269,7 +278,7 @@ export function CheckboxEditor({row, column, onRowChange, onClose}) {
|
||||
};
|
||||
const onBlur = ()=>{onClose(true);};
|
||||
let className = 'checked';
|
||||
if(!value) {
|
||||
if(!value && value != null) {
|
||||
className = 'unchecked';
|
||||
} else if(value == null){
|
||||
className = 'intermediate';
|
||||
@@ -323,7 +332,7 @@ export function JsonTextEditor({row, column, onRowChange, onClose}) {
|
||||
value={localVal}
|
||||
options={{
|
||||
onChange: onChange,
|
||||
onError: (error)=>console.error('Invalid Json: ' + error.message.split(':')[0]),
|
||||
onError: (error)=>Notifier.error('Invalid Json: ' + error.message.split(':')[0]),
|
||||
}}
|
||||
className={'jsoneditor-div'}
|
||||
/>
|
||||
|
||||
@@ -63,6 +63,9 @@ class NewConnectionSchema extends BaseUISchema {
|
||||
.then(({data: respData})=>{
|
||||
let groupedOptions = [];
|
||||
_.forIn(respData.data.result.server_list, (v, k)=>{
|
||||
if(v.length == 0) {
|
||||
return;
|
||||
}
|
||||
/* initial selection */
|
||||
_.find(v, (o)=>o.value==obj.params.sid).selected = true;
|
||||
groupedOptions.push({
|
||||
|
||||
@@ -106,15 +106,15 @@ export function ConnectionBar({connected, connecting, connectionStatus, connecti
|
||||
>
|
||||
<Tooltip title={queryToolCtx.params.is_query_tool ? '' : connTitle}>
|
||||
<Box display="flex" width="100%">
|
||||
<Box textOverflow="ellipsis" overflow="hidden" marginRight="auto">{connecting && '(Obtaining connection)'}{connTitle}</Box>
|
||||
<Box textOverflow="ellipsis" overflow="hidden" marginRight="auto">{connecting && gettext('(Obtaining connection)')}{connTitle}</Box>
|
||||
{queryToolCtx.params.is_query_tool && <Box><KeyboardArrowDownIcon /></Box>}
|
||||
</Box>
|
||||
</Tooltip>
|
||||
</DefaultButton>
|
||||
<PgIconButton title="New query tool" icon={<QueryToolIcon />} onClick={onNewQueryToolClick}/>
|
||||
<PgIconButton title={gettext('New query tool for current connection')} icon={<QueryToolIcon />} onClick={onNewQueryToolClick}/>
|
||||
</PgButtonGroup>
|
||||
<PgButtonGroup size="small" variant="text" style={{marginLeft: 'auto'}}>
|
||||
<PgIconButton title="Reset layout" icon={<RotateLeftRoundedIcon />} onClick={onResetLayout}/>
|
||||
<PgIconButton title={gettext('Reset layout')} icon={<RotateLeftRoundedIcon />} onClick={onResetLayout}/>
|
||||
</PgButtonGroup>
|
||||
</Box>
|
||||
<PgMenu
|
||||
|
||||
@@ -94,7 +94,7 @@ function parseEwkbData(rows, column) {
|
||||
|
||||
// generate map info content
|
||||
if (tooLargeDataSize || tooManyGeometries) {
|
||||
infoList.push(supportedGeometries.length + ' of ' + rows.length + ' geometries rendered.');
|
||||
infoList.push(gettext('%s of %s geometries rendered.', supportedGeometries.length, rows.length));
|
||||
}
|
||||
if (geometries3D.length > 0) {
|
||||
infoList.push(gettext('3D geometries not rendered.'));
|
||||
@@ -116,7 +116,7 @@ function parseData(rows, columns, column) {
|
||||
'geoJSONs': [],
|
||||
'selectedSRID': 0,
|
||||
'getPopupContent': undefined,
|
||||
'infoList': ['Empty row.'],
|
||||
'infoList': [gettext('Empty row.')],
|
||||
};
|
||||
}
|
||||
|
||||
@@ -294,19 +294,19 @@ function TheMap({data}) {
|
||||
<>
|
||||
{data.selectedSRID === 4326 &&
|
||||
<LayersControl position="topright">
|
||||
<LayersControl.BaseLayer checked name="Empty">
|
||||
<LayersControl.BaseLayer checked name={gettext('Empty')}>
|
||||
<TileLayer
|
||||
url=""
|
||||
/>
|
||||
</LayersControl.BaseLayer>
|
||||
<LayersControl.BaseLayer checked name="Street">
|
||||
<LayersControl.BaseLayer checked name={gettext('Street')}>
|
||||
<TileLayer
|
||||
url="https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png"
|
||||
maxZoom={19}
|
||||
attribution='© <a href="http://www.openstreetmap.org/copyright" target="_blank">OpenStreetMap</a>'
|
||||
/>
|
||||
</LayersControl.BaseLayer>
|
||||
<LayersControl.BaseLayer name="Topography">
|
||||
<LayersControl.BaseLayer name={gettext('Topography')}>
|
||||
<TileLayer
|
||||
url="https://{s}.tile.opentopomap.org/{z}/{x}/{y}.png"
|
||||
maxZoom={17}
|
||||
@@ -317,7 +317,7 @@ function TheMap({data}) {
|
||||
}
|
||||
/>
|
||||
</LayersControl.BaseLayer>
|
||||
<LayersControl.BaseLayer name="Gray Style">
|
||||
<LayersControl.BaseLayer name={gettext('Gray Style')}>
|
||||
<TileLayer
|
||||
url="https://cartodb-basemaps-{s}.global.ssl.fastly.net/light_all/{z}/{x}/{y}{r}.png"
|
||||
maxZoom={19}
|
||||
@@ -328,7 +328,7 @@ function TheMap({data}) {
|
||||
subdomains='abcd'
|
||||
/>
|
||||
</LayersControl.BaseLayer>
|
||||
<LayersControl.BaseLayer name="Light Color">
|
||||
<LayersControl.BaseLayer name={gettext('Light Color')}>
|
||||
<TileLayer
|
||||
url="https://cartodb-basemaps-{s}.global.ssl.fastly.net/rastertiles/voyager/{z}/{x}/{y}{r}.pn"
|
||||
maxZoom={19}
|
||||
@@ -339,7 +339,7 @@ function TheMap({data}) {
|
||||
subdomains='abcd'
|
||||
/>
|
||||
</LayersControl.BaseLayer>
|
||||
<LayersControl.BaseLayer name="Dark Matter">
|
||||
<LayersControl.BaseLayer name={gettext('Dark Matter')}>
|
||||
<TileLayer
|
||||
url="https://cartodb-basemaps-{s}.global.ssl.fastly.net/dark_all/{z}/{x}/{y}{r}.png"
|
||||
maxZoom={19}
|
||||
|
||||
@@ -23,7 +23,7 @@ import FormatListNumberedRoundedIcon from '@material-ui/icons/FormatListNumbered
|
||||
import HelpIcon from '@material-ui/icons/HelpRounded';
|
||||
import {QUERY_TOOL_EVENTS, CONNECTION_STATUS} from '../QueryToolConstants';
|
||||
import { QueryToolConnectionContext, QueryToolContext, QueryToolEventsContext } from '../QueryToolComponent';
|
||||
import { PgMenu, PgMenuDivider, PgMenuItem } from '../../../../../../static/js/components/Menu';
|
||||
import { PgMenu, PgMenuDivider, PgMenuItem, usePgMenuGroup } from '../../../../../../static/js/components/Menu';
|
||||
import gettext from 'sources/gettext';
|
||||
import { useKeyboardShortcuts } from '../../../../../../static/js/custom_hooks';
|
||||
import {shortcut_key} from 'sources/keyboard_shortcuts';
|
||||
@@ -150,7 +150,7 @@ export function MainToolBar({containerRef, onFilterClick, onManageMacros}) {
|
||||
'filter': true,
|
||||
'limit': false,
|
||||
});
|
||||
const [menuOpenId, setMenuOpenId] = React.useState(null);
|
||||
const {openMenuName, toggleMenu, onMenuClose} = usePgMenuGroup();
|
||||
const [checkedMenuItems, setCheckedMenuItems] = React.useState({});
|
||||
/* Menu button refs */
|
||||
const saveAsMenuRef = React.useRef(null);
|
||||
@@ -189,14 +189,6 @@ export function MainToolBar({containerRef, onFilterClick, onManageMacros}) {
|
||||
explain(true);
|
||||
}, [explain]);
|
||||
|
||||
const openMenu = useCallback((e)=>{
|
||||
setMenuOpenId(e.currentTarget.name);
|
||||
}, []);
|
||||
|
||||
const handleMenuClose = useCallback(()=>{
|
||||
setMenuOpenId(null);
|
||||
}, []);
|
||||
|
||||
const checkMenuClick = useCallback((e)=>{
|
||||
setCheckedMenuItems((prev)=>{
|
||||
let newVal = !prev[e.value];
|
||||
@@ -453,21 +445,21 @@ export function MainToolBar({containerRef, onFilterClick, onManageMacros}) {
|
||||
accesskey={shortcut_key(queryToolPref.btn_save_file)} disabled={buttonsDisabled['save'] || !queryToolCtx.params.is_query_tool}
|
||||
onClick={()=>{saveFile(false);}} />
|
||||
<PgIconButton title={gettext('File')} icon={<KeyboardArrowDownIcon />} splitButton disabled={!queryToolCtx.params.is_query_tool}
|
||||
name="menu-saveas" ref={saveAsMenuRef} onClick={openMenu}
|
||||
name="menu-saveas" ref={saveAsMenuRef} onClick={toggleMenu}
|
||||
/>
|
||||
</PgButtonGroup>
|
||||
<PgButtonGroup size="small">
|
||||
<PgIconButton title={gettext('Edit')} icon={
|
||||
<><EditRoundedIcon /><KeyboardArrowDownIcon style={{marginLeft: '-10px'}} /></>}
|
||||
disabled={!queryToolCtx.params.is_query_tool}
|
||||
name="menu-edit" ref={editMenuRef} onClick={openMenu} />
|
||||
name="menu-edit" ref={editMenuRef} onClick={toggleMenu} />
|
||||
</PgButtonGroup>
|
||||
<PgButtonGroup size="small" color={highlightFilter ? 'primary' : 'default'}>
|
||||
<PgIconButton title={gettext('Sort/Filter')} icon={<FilterIcon />}
|
||||
onClick={onFilterClick} disabled={buttonsDisabled['filter']} accesskey={shortcut_key(queryToolPref.btn_filter_dialog)}/>
|
||||
<PgIconButton title={gettext('Filter options')} icon={<KeyboardArrowDownIcon />} splitButton
|
||||
disabled={buttonsDisabled['filter']} name="menu-filter" ref={filterMenuRef} accesskey={shortcut_key(queryToolPref.btn_filter_options)}
|
||||
onClick={openMenu} />
|
||||
onClick={toggleMenu} />
|
||||
</PgButtonGroup>
|
||||
<InputSelectNonSearch options={[
|
||||
{label: gettext('No limit'), value: '-1'},
|
||||
@@ -482,7 +474,7 @@ export function MainToolBar({containerRef, onFilterClick, onManageMacros}) {
|
||||
onClick={executeQuery} disabled={buttonsDisabled['execute']} shortcut={queryToolPref.execute_query}/>
|
||||
<PgIconButton title={gettext('Execute options')} icon={<KeyboardArrowDownIcon />} splitButton
|
||||
name="menu-autocommit" ref={autoCommitMenuRef} accesskey={shortcut_key(queryToolPref.btn_delete_row)}
|
||||
onClick={openMenu} />
|
||||
onClick={toggleMenu} disabled={!queryToolCtx.params.is_query_tool}/>
|
||||
</PgButtonGroup>
|
||||
<PgButtonGroup size="small">
|
||||
<PgIconButton title={gettext('Explain')} icon={<ExplicitRoundedIcon />}
|
||||
@@ -491,7 +483,7 @@ export function MainToolBar({containerRef, onFilterClick, onManageMacros}) {
|
||||
onClick={()=>{explainAnalyse();}} disabled={buttonsDisabled['explain_analyse'] || !queryToolCtx.params.is_query_tool} shortcut={queryToolPref.explain_analyze_query}/>
|
||||
<PgIconButton title={gettext('Explain Settings')} icon={<KeyboardArrowDownIcon />} splitButton
|
||||
disabled={!queryToolCtx.params.is_query_tool}
|
||||
name="menu-explain" ref={explainMenuRef} onClick={openMenu} />
|
||||
name="menu-explain" ref={explainMenuRef} onClick={toggleMenu} />
|
||||
</PgButtonGroup>
|
||||
<PgButtonGroup size="small">
|
||||
<PgIconButton title={gettext('Commit')} icon={<CommitIcon />}
|
||||
@@ -502,7 +494,7 @@ export function MainToolBar({containerRef, onFilterClick, onManageMacros}) {
|
||||
<PgButtonGroup size="small">
|
||||
<PgIconButton title={gettext('Macros')} icon={
|
||||
<><FormatListNumberedRoundedIcon /><KeyboardArrowDownIcon style={{marginLeft: '-10px'}} /></>}
|
||||
disabled={!queryToolCtx.params.is_query_tool} name="menu-macros" ref={macrosMenuRef} onClick={openMenu} />
|
||||
disabled={!queryToolCtx.params.is_query_tool} name="menu-macros" ref={macrosMenuRef} onClick={toggleMenu} />
|
||||
</PgButtonGroup>
|
||||
<PgButtonGroup size="small">
|
||||
<PgIconButton title={gettext('Help')} icon={<HelpIcon />} onClick={onHelpClick} />
|
||||
@@ -510,15 +502,15 @@ export function MainToolBar({containerRef, onFilterClick, onManageMacros}) {
|
||||
</Box>
|
||||
<PgMenu
|
||||
anchorRef={saveAsMenuRef}
|
||||
open={menuOpenId=='menu-saveas'}
|
||||
onClose={handleMenuClose}
|
||||
open={openMenuName=='menu-saveas'}
|
||||
onClose={onMenuClose}
|
||||
>
|
||||
<PgMenuItem onClick={()=>{saveFile(true);}}>{gettext('Save as')}</PgMenuItem>
|
||||
</PgMenu>
|
||||
<PgMenu
|
||||
anchorRef={editMenuRef}
|
||||
open={menuOpenId=='menu-edit'}
|
||||
onClose={handleMenuClose}
|
||||
open={openMenuName=='menu-edit'}
|
||||
onClose={onMenuClose}
|
||||
>
|
||||
<PgMenuItem shortcut={FIXED_PREF.find}
|
||||
onClick={()=>{eventBus.fireEvent(QUERY_TOOL_EVENTS.EDITOR_FIND_REPLACE, false);}}>{gettext('Find')}</PgMenuItem>
|
||||
@@ -540,8 +532,8 @@ export function MainToolBar({containerRef, onFilterClick, onManageMacros}) {
|
||||
</PgMenu>
|
||||
<PgMenu
|
||||
anchorRef={filterMenuRef}
|
||||
open={menuOpenId=='menu-filter'}
|
||||
onClose={handleMenuClose}
|
||||
open={openMenuName=='menu-filter'}
|
||||
onClose={onMenuClose}
|
||||
>
|
||||
<PgMenuItem onClick={()=>{eventBus.fireEvent(QUERY_TOOL_EVENTS.TRIGGER_INCLUDE_EXCLUDE_FILTER, true);}}>{gettext('Filter by Selection')}</PgMenuItem>
|
||||
<PgMenuItem onClick={()=>{eventBus.fireEvent(QUERY_TOOL_EVENTS.TRIGGER_INCLUDE_EXCLUDE_FILTER, false);}}>{gettext('Exclude by Selection')}</PgMenuItem>
|
||||
@@ -549,8 +541,8 @@ export function MainToolBar({containerRef, onFilterClick, onManageMacros}) {
|
||||
</PgMenu>
|
||||
<PgMenu
|
||||
anchorRef={autoCommitMenuRef}
|
||||
open={menuOpenId=='menu-autocommit'}
|
||||
onClose={handleMenuClose}
|
||||
open={openMenuName=='menu-autocommit'}
|
||||
onClose={onMenuClose}
|
||||
>
|
||||
<PgMenuItem hasCheck value="auto_commit" checked={checkedMenuItems['auto_commit']}
|
||||
onClick={checkMenuClick}>{gettext('Auto commit?')}</PgMenuItem>
|
||||
@@ -559,8 +551,8 @@ export function MainToolBar({containerRef, onFilterClick, onManageMacros}) {
|
||||
</PgMenu>
|
||||
<PgMenu
|
||||
anchorRef={explainMenuRef}
|
||||
open={menuOpenId=='menu-explain'}
|
||||
onClose={handleMenuClose}
|
||||
open={openMenuName=='menu-explain'}
|
||||
onClose={onMenuClose}
|
||||
>
|
||||
<PgMenuItem hasCheck value="explain_verbose" checked={checkedMenuItems['explain_verbose']}
|
||||
onClick={checkMenuClick}>{gettext('Verbose')}</PgMenuItem>
|
||||
@@ -577,8 +569,8 @@ export function MainToolBar({containerRef, onFilterClick, onManageMacros}) {
|
||||
</PgMenu>
|
||||
<PgMenu
|
||||
anchorRef={macrosMenuRef}
|
||||
open={menuOpenId=='menu-macros'}
|
||||
onClose={handleMenuClose}
|
||||
open={openMenuName=='menu-macros'}
|
||||
onClose={onMenuClose}
|
||||
>
|
||||
<PgMenuItem onClick={onManageMacros}>{gettext('Manage macros')}</PgMenuItem>
|
||||
<PgMenuDivider />
|
||||
|
||||
@@ -19,7 +19,7 @@ import moment from 'moment';
|
||||
import PlayArrowRoundedIcon from '@material-ui/icons/PlayArrowRounded';
|
||||
import AssessmentRoundedIcon from '@material-ui/icons/AssessmentRounded';
|
||||
import ExplicitRoundedIcon from '@material-ui/icons/ExplicitRounded';
|
||||
import { SaveDataIcon, CommitIcon, RollbackIcon } from '../../../../../../static/js/components/ExternalIcon';
|
||||
import { SaveDataIcon, CommitIcon, RollbackIcon, ViewDataIcon } from '../../../../../../static/js/components/ExternalIcon';
|
||||
import { InputSwitch } from '../../../../../../static/js/components/FormComponents';
|
||||
import CodeMirror from '../../../../../../static/js/components/CodeMirror';
|
||||
import { DefaultButton } from '../../../../../../static/js/components/Buttons';
|
||||
@@ -30,6 +30,7 @@ import { LayoutEventsContext, LAYOUT_EVENTS } from '../../../../../../static/js/
|
||||
import PropTypes from 'prop-types';
|
||||
import { parseApiError } from '../../../../../../static/js/api_instance';
|
||||
import * as clipboard from '../../../../../../static/js/clipboard';
|
||||
import EmptyPanelMessage from '../../../../../../static/js/components/EmptyPanelMessage';
|
||||
|
||||
const useStyles = makeStyles((theme)=>({
|
||||
leftRoot: {
|
||||
@@ -145,9 +146,9 @@ class QueryHistoryUtils {
|
||||
getDatePrefix(date) {
|
||||
let prefix = '';
|
||||
if (this.isDaysBefore(date, 0)) {
|
||||
prefix = 'Today - ';
|
||||
prefix = gettext('Today - ');
|
||||
} else if (this.isDaysBefore(date, 1)) {
|
||||
prefix = 'Yesterday - ';
|
||||
prefix = gettext('Yesterday - ');
|
||||
}
|
||||
return prefix;
|
||||
}
|
||||
@@ -247,7 +248,7 @@ function QuerySourceIcon({source}) {
|
||||
case JSON.stringify(QuerySources.SAVE_DATA):
|
||||
return <SaveDataIcon style={{marginLeft: '-4px'}}/>;
|
||||
case JSON.stringify(QuerySources.VIEW_DATA):
|
||||
return <SaveDataIcon style={{marginLeft: '-4px'}}/>;
|
||||
return <ViewDataIcon style={{marginLeft: '-4px'}}/>;
|
||||
default:
|
||||
return <></>;
|
||||
}
|
||||
@@ -312,7 +313,9 @@ function QueryHistoryDetails({entry}) {
|
||||
}, [entry]);
|
||||
|
||||
if(!entry) {
|
||||
return <></>;
|
||||
return <Box display="flex" height="100%">
|
||||
<EmptyPanelMessage text={gettext('Select an history entry to see details.')} />
|
||||
</Box>;
|
||||
}
|
||||
|
||||
return (
|
||||
@@ -460,39 +463,45 @@ export function QueryHistory() {
|
||||
<Loader message={loaderText} />
|
||||
{React.useMemo(()=>(
|
||||
<Box display="flex" height="100%">
|
||||
<Box flexBasis="50%" maxWidth="50%" className={classes.leftRoot}>
|
||||
<Box padding="0.25rem" display="flex">
|
||||
{gettext('Show queries generated internally by pgAdmin?')}
|
||||
<InputSwitch value={showInternal} onChange={(e)=>{
|
||||
setShowInternal(e.target.checked);
|
||||
qhu.current.showInternal = e.target.checked;
|
||||
setSelectedItemKey(qhu.current.getNextItemKey());
|
||||
}} />
|
||||
<Box marginLeft="auto">
|
||||
<DefaultButton size="small" disabled={!selectedItemKey} onClick={onRemove}>Remove</DefaultButton>
|
||||
<DefaultButton size="small" disabled={!qhu.current?.getGroups()?.length}
|
||||
className={classes.removeBtnMargin} onClick={onRemoveAll}>Remove All</DefaultButton>
|
||||
{qhu.current.size() == 0 ?
|
||||
<EmptyPanelMessage text={gettext('No history found')} />:
|
||||
<>
|
||||
<Box flexBasis="50%" maxWidth="50%" className={classes.leftRoot}>
|
||||
<Box padding="0.25rem" display="flex" flexWrap="wrap">
|
||||
<Box marginRight="auto">
|
||||
{gettext('Show queries generated internally by pgAdmin?')}
|
||||
<InputSwitch value={showInternal} onChange={(e)=>{
|
||||
setShowInternal(e.target.checked);
|
||||
qhu.current.showInternal = e.target.checked;
|
||||
setSelectedItemKey(qhu.current.getNextItemKey());
|
||||
}} />
|
||||
</Box>
|
||||
<Box>
|
||||
<DefaultButton size="small" disabled={!selectedItemKey} onClick={onRemove}>{gettext('Remove')}</DefaultButton>
|
||||
<DefaultButton size="small" disabled={!qhu.current?.getGroups()?.length}
|
||||
className={classes.removeBtnMargin} onClick={onRemoveAll}>{gettext('Remove All')}</DefaultButton>
|
||||
</Box>
|
||||
</Box>
|
||||
<Box flexGrow="1" overflow="auto" className={classes.listRoot}>
|
||||
<List innerRef={listRef} className={classes.root} subheader={<li />} tabIndex="0" onKeyDown={onKeyPressed}>
|
||||
{qhu.current.getGroups().map(([groupKey, groupHeader]) => (
|
||||
<ListItem key={`section-${groupKey}`} className={classes.removePadding}>
|
||||
<List className={classes.removePadding}>
|
||||
<ListSubheader className={classes.listSubheader}>{groupHeader}</ListSubheader>
|
||||
{qhu.current.getGroupEntries(groupKey).map((entry) => (
|
||||
<HistoryEntry key={entry.itemKey} entry={entry} formatEntryDate={qhu.current.formatEntryDate}
|
||||
itemKey={entry.itemKey} selectedItemKey={selectedItemKey} onClick={()=>{setSelectedItemKey(entry.itemKey);}}/>
|
||||
))}
|
||||
</List>
|
||||
</ListItem>
|
||||
))}
|
||||
</List>
|
||||
</Box>
|
||||
</Box>
|
||||
</Box>
|
||||
<Box flexGrow="1" overflow="auto" className={classes.listRoot}>
|
||||
<List innerRef={listRef} className={classes.root} subheader={<li />} tabIndex="0" onKeyDown={onKeyPressed}>
|
||||
{qhu.current.getGroups().map(([groupKey, groupHeader]) => (
|
||||
<ListItem key={`section-${groupKey}`} className={classes.removePadding}>
|
||||
<List className={classes.removePadding}>
|
||||
<ListSubheader className={classes.listSubheader}>{groupHeader}</ListSubheader>
|
||||
{qhu.current.getGroupEntries(groupKey).map((entry) => (
|
||||
<HistoryEntry key={entry.itemKey} entry={entry} formatEntryDate={qhu.current.formatEntryDate}
|
||||
itemKey={entry.itemKey} selectedItemKey={selectedItemKey} onClick={()=>{setSelectedItemKey(entry.itemKey);}}/>
|
||||
))}
|
||||
</List>
|
||||
</ListItem>
|
||||
))}
|
||||
</List>
|
||||
</Box>
|
||||
</Box>
|
||||
<Box flexBasis="50%" maxWidth="50%" overflow="auto">
|
||||
<QueryHistoryDetails entry={selectedEntry}/>
|
||||
</Box>
|
||||
<Box flexBasis="50%" maxWidth="50%" overflow="auto">
|
||||
<QueryHistoryDetails entry={selectedEntry}/>
|
||||
</Box>
|
||||
</>}
|
||||
</Box>
|
||||
), [selectedItemKey, showInternal, qhu.current.size()])}
|
||||
</>
|
||||
|
||||
@@ -627,7 +627,7 @@ export class ResultSetUtils {
|
||||
data.primary_keys = (_.isEmpty(data.primary_keys) && data.has_oids) ? data.oids : data.primary_keys;
|
||||
data.can_edit = !_.isEmpty(data.primary_keys);
|
||||
let procColumns = this.processColumns(data);
|
||||
onResultsAvailable(data, procColumns, this.processRows(result, procColumns, this.processRows(result, procColumns)));
|
||||
onResultsAvailable(data, procColumns, this.processRows(result, procColumns));
|
||||
this.setStartData(null);
|
||||
let planJson = this.getPlanJson(result, data);
|
||||
if(planJson) {
|
||||
@@ -886,12 +886,14 @@ export function ResultSet() {
|
||||
};
|
||||
useEffect(()=>{
|
||||
eventBus.registerListener(QUERY_TOOL_EVENTS.FETCH_MORE_ROWS, fetchMoreRows);
|
||||
return ()=>eventBus.deregisterListener(QUERY_TOOL_EVENTS.FETCH_MORE_ROWS, fetchMoreRows);
|
||||
}, [queryData, columns]);
|
||||
return ()=>{
|
||||
eventBus.deregisterListener(QUERY_TOOL_EVENTS.FETCH_MORE_ROWS, fetchMoreRows);
|
||||
};
|
||||
}, [queryData?.has_more_rows, columns]);
|
||||
|
||||
useEffect(()=>{
|
||||
eventBus.fireEvent(QUERY_TOOL_EVENTS.ROWS_FETCHED, queryData?.rows_fetched_to, queryData?.rows_affected);
|
||||
}, [queryData]);
|
||||
}, [queryData?.rows_fetched_to, queryData?.rows_affected]);
|
||||
|
||||
const warnSaveDataClose = ()=>{
|
||||
// No changes.
|
||||
@@ -975,7 +977,7 @@ export function ResultSet() {
|
||||
}
|
||||
|
||||
eventBus.fireEvent(QUERY_TOOL_EVENTS.SAVE_DATA_DONE, true);
|
||||
if(!_.size(dataChangeStore.added)) {
|
||||
if(_.size(dataChangeStore.added)) {
|
||||
// Update the rows in a grid after addition
|
||||
respData.data.query_results.forEach((qr)=>{
|
||||
if(!_.isNull(qr.row_added)) {
|
||||
|
||||
@@ -158,7 +158,7 @@ export function ResultSetToolbar({containerRef, canEdit}) {
|
||||
open={menuOpenId=='menu-copyheader'}
|
||||
onClose={handleMenuClose}
|
||||
>
|
||||
<PgMenuItem hasCheck value="copy_with_headers" checked={checkedMenuItems['copy_with_headers']} onClick={checkMenuClick}>Copy with headers</PgMenuItem>
|
||||
<PgMenuItem hasCheck value="copy_with_headers" checked={checkedMenuItems['copy_with_headers']} onClick={checkMenuClick}>{gettext('Copy with headers')}</PgMenuItem>
|
||||
</PgMenu>
|
||||
</>
|
||||
);
|
||||
|
||||
@@ -15,6 +15,7 @@ import _ from 'lodash';
|
||||
import { QUERY_TOOL_EVENTS } from '../QueryToolConstants';
|
||||
import { useStopwatch } from '../../../../../../static/js/custom_hooks';
|
||||
import { QueryToolEventsContext } from '../QueryToolComponent';
|
||||
import gettext from 'sources/gettext';
|
||||
|
||||
|
||||
const useStyles = makeStyles((theme)=>({
|
||||
@@ -86,18 +87,18 @@ export function StatusBar() {
|
||||
|
||||
let stagedText = '';
|
||||
if(dataRowChangeCounts.added > 0) {
|
||||
stagedText += ` Added: ${dataRowChangeCounts.added};`;
|
||||
stagedText += ' ' + gettext('Added: %s', dataRowChangeCounts.added);
|
||||
}
|
||||
if(dataRowChangeCounts.updated > 0) {
|
||||
stagedText += ` Updated: ${dataRowChangeCounts.updated};`;
|
||||
stagedText += ' ' + gettext('Updated: %s', dataRowChangeCounts.updated);
|
||||
}
|
||||
if(dataRowChangeCounts.deleted > 0) {
|
||||
stagedText += ` Deleted: ${dataRowChangeCounts.deleted};`;
|
||||
stagedText += ' ' + gettext('Deleted: %s', dataRowChangeCounts.deleted);
|
||||
}
|
||||
|
||||
return (
|
||||
<Box className={classes.root}>
|
||||
<Box className={clsx(classes.padding, classes.divider)}>Total rows: {rowsCount[0]} of {rowsCount[1]}</Box>
|
||||
<Box className={clsx(classes.padding, classes.divider)}>{gettext('Total rows: %s of %s', rowsCount[0], rowsCount[1])}</Box>
|
||||
{lastTaskText &&
|
||||
<Box className={clsx(classes.padding, classes.divider)}>{lastTaskText} {hours.toString().padStart(2, '0')}:{minutes.toString().padStart(2, '0')}:{seconds.toString().padStart(2, '0')}.{msec.toString().padStart(3, '0')}</Box>
|
||||
}
|
||||
@@ -105,13 +106,13 @@ export function StatusBar() {
|
||||
<Box className={clsx(classes.padding, classes.divider)}>{lastTaskText} {hours.toString().padStart(2, '0')}:{minutes.toString().padStart(2, '0')}:{seconds.toString().padStart(2, '0')}.{msec.toString().padStart(3, '0')}</Box>
|
||||
}
|
||||
{Boolean(selectedRowsCount) &&
|
||||
<Box className={clsx(classes.padding, classes.divider)}>Rows selected: {selectedRowsCount}</Box>}
|
||||
<Box className={clsx(classes.padding, classes.divider)}>{gettext('Rows selected: %s',selectedRowsCount)}</Box>}
|
||||
{stagedText &&
|
||||
<Box className={clsx(classes.padding, classes.divider)}>
|
||||
<span>Changes staged: {stagedText}</span>
|
||||
<span>{gettext('Changes staged: %s', stagedText)}</span>
|
||||
</Box>
|
||||
}
|
||||
<Box className={clsx(classes.padding, classes.mlAuto)}>Ln {position[0]}, Col {position[1]}</Box>
|
||||
<Box className={clsx(classes.padding, classes.mlAuto)}>{gettext('Ln %s, Col %s', position[0], position[1])}</Box>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user