Skip to content

Commit 95b2387

Browse files
Show auto-complete column names in filtered rows dialog of table and filter options of view/edit data tool. #3751
Allow setting NULL ordering for columns in view/edit data filter dialog. #3317
1 parent da53082 commit 95b2387

File tree

12 files changed

+597
-556
lines changed

12 files changed

+597
-556
lines changed

docs/en_US/editgrid.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,7 @@ To add new column(s) in data sorting grid, click on the [+] icon.
212212

213213
* Use the drop-down *Column* to select the column you want to sort.
214214
* Use the drop-down *Order* to select the sort order for the column.
215+
* Use the drop-down *NULLs* to select the NULL values order for the column.
215216

216217
To delete a row from the grid, click the trash icon.
217218

20.7 KB
Loading

docs/en_US/release_notes_8_14.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,12 @@ Bundled PostgreSQL Utilities
2020
New features
2121
************
2222

23+
| `Issue #3317 <https://github.com/pgadmin-org/pgadmin4/issues/3317>`_ - Allow setting NULL ordering for columns in view/edit data filter dialog.
24+
| `Issue #3751 <https://github.com/pgadmin-org/pgadmin4/issues/3751>`_ - Show auto-complete column names in filtered rows dialog of table and filter options of view/edit data tool.
2325
| `Issue #5786 <https://github.com/pgadmin-org/pgadmin4/issues/5786>`_ - Allow the use of a pgpass file in the pgAdmin container via Docker secrets.
2426
| `Issue #6592 <https://github.com/pgadmin-org/pgadmin4/issues/6592>`_ - Fixed multiple issues and improved ERD auto-layout.
2527
| `Issue #8095 <https://github.com/pgadmin-org/pgadmin4/issues/8095>`_ - Added support for a builtin locale provider in the Database dialog.
28+
| `Issue #8134 <https://github.com/pgadmin-org/pgadmin4/issues/8134>`_ - Add a user preference to enable/disable alternating row background colors in the data output of query tool.
2629
2730
Housekeeping
2831
************

web/pgadmin/static/js/SchemaView/FormView.jsx

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -260,7 +260,8 @@ export default function FormView({
260260
let contentClassName = [
261261
isSingleCollection() ? 'FormView-singleCollectionPanelContent' :
262262
'FormView-nonTabPanelContent',
263-
(schemaState.errors?.message ? 'FormView-errorMargin' : null)
263+
(schemaState.errors?.message ? 'FormView-errorMargin' : null),
264+
(finalGroups.some((g)=>g.isFullTab) ? 'FormView-fullControl' : ''),
264265
];
265266
return (
266267
<>
@@ -275,7 +276,8 @@ export default function FormView({
275276
classNameRoot={[
276277
isSingleCollection() ?
277278
'FormView-singleCollectionPanel' : 'FormView-nonTabPanel',
278-
className
279+
className,
280+
(finalGroups.some((g)=>g.isFullTab) ? 'FormView-fullSpace' : ''),
279281
].join(' ')}
280282
className={contentClassName.join(' ')}>
281283
{

web/pgadmin/static/js/SchemaView/StyledComponents.jsx

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -144,15 +144,17 @@ export const FormContentBox = styled(Box)(({theme}) => ({
144144
'& .FormView-fullControl': {
145145
display: 'flex',
146146
flexDirection: 'column',
147-
'& .FormView-sqlTabInput': {
147+
'& .FormView-sqlTabInput, & .Form-sql': {
148148
border: 0,
149149
},
150150
}
151151
},
152152
'& .FormView-nonTabPanel': {
153153
...theme.mixins.tabPanel,
154154
'& .FormView-nonTabPanelContent': {
155-
height: 'unset',
155+
'&:not(.FormView-fullControl)': {
156+
height: 'unset',
157+
},
156158
'& .FormView-controlRow': {
157159
marginBottom: theme.spacing(1),
158160
},

web/pgadmin/static/js/UtilityView.jsx

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ export default function UtilityView({dockerObj}) {
4141
<UtilityViewContent
4242
docker={docker.current}
4343
panelId={panelId}
44-
schema={dialogProps.schema}
44+
{...dialogProps}
4545
treeNodeInfo={treeNodeInfo}
4646
actionType={dialogProps.actionType??'create'}
4747
formType='dialog'
@@ -60,10 +60,6 @@ export default function UtilityView({dockerObj}) {
6060
onClose();
6161
})}
6262
extraData={dialogProps.extraData??{}}
63-
saveBtnName={dialogProps.saveBtnName}
64-
urlBase={dialogProps.urlBase}
65-
sqlHelpUrl={dialogProps.sqlHelpUrl}
66-
helpUrl={dialogProps.helpUrl}
6763
/>
6864
</ErrorBoundary>
6965
)

web/pgadmin/static/js/components/FormComponents.jsx

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -189,23 +189,29 @@ FormInput.propTypes = {
189189
labelTooltip: PropTypes.string
190190
};
191191

192-
export function InputSQL({ value, options, onChange, className, controlProps, inputRef, ...props }) {
192+
export function InputSQL({ value, options={}, onChange, className, controlProps, inputRef, ...props }) {
193193

194194
const editor = useRef();
195+
const { autocompleteProvider, autocompleteOnKeyPress } = options;
195196

196197
return (
197198
<Root style={{height: '100%'}}>
198199
<CodeMirror
199200
currEditor={(obj) => {
200201
editor.current = obj;
201202
inputRef?.(obj);
203+
if(autocompleteProvider) {
204+
editor.current.registerAutocomplete(autocompleteProvider);
205+
}
202206
}}
203207
value={value || ''}
204208
options={{
205-
...options,
209+
..._.omit(options, ['autocompleteProvider', 'autocompleteOnKeyPress']),
206210
}}
207211
className={'Form-sql ' + className}
208212
onChange={onChange}
213+
autocomplete={true}
214+
autocompleteOnKeyPress={autocompleteOnKeyPress}
209215
{...controlProps}
210216
{...props}
211217
/>

web/pgadmin/static/js/components/ReactCodeMirror/components/Editor.jsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -165,7 +165,7 @@ const defaultExtensions = [
165165

166166
export default function Editor({
167167
currEditor, name, value, options, onCursorActivity, onChange, readonly,
168-
disabled, autocomplete = false, breakpoint = false, onBreakPointChange,
168+
disabled, autocomplete = false, autocompleteOnKeyPress, breakpoint = false, onBreakPointChange,
169169
showActiveLine=false, keepHistory = true, cid, helpid, labelledBy,
170170
customKeyMap, language='pgsql'
171171
}) {
@@ -331,7 +331,7 @@ export default function Editor({
331331
}],
332332
};
333333
if (autocomplete) {
334-
if (pref.autocomplete_on_key_press) {
334+
if (pref.autocomplete_on_key_press || autocompleteOnKeyPress) {
335335
newConfigExtn.push(autocompletion({
336336
...autoCompOptions,
337337
activateOnTyping: true,

web/pgadmin/tools/sqleditor/static/js/components/dialogs/FilterDialog.jsx

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,15 +27,26 @@ class SortingCollection extends BaseUISchema {
2727
{
2828
id: 'name', label: gettext('Column'), cell: 'select', controlProps: {
2929
allowClear: false,
30-
}, noEmpty: true, options: this.columnOptions, optionsReloadBasis: this.reloadColOptions
30+
}, noEmpty: true, options: this.columnOptions, optionsReloadBasis: this.reloadColOptions,
31+
width: 300,
3132
},
3233
{
3334
id: 'order', label: gettext('Order'), cell: 'select', controlProps: {
3435
allowClear: false,
3536
}, options: [
3637
{label: gettext('ASC'), value: 'asc'},
3738
{label: gettext('DESC'), value: 'desc'},
38-
]
39+
],
40+
width: 150,
41+
},
42+
{
43+
id: 'order_null', label: gettext('NULLs'), cell: 'select', controlProps: {
44+
allowClear: true,
45+
}, options: [
46+
{label: gettext('FIRST'), value: 'nulls first'},
47+
{label: gettext('LAST'), value: 'nulls last'},
48+
],
49+
width: 150,
3950
},
4051
];
4152
}
@@ -62,6 +73,23 @@ class FilterSchema extends BaseUISchema {
6273
options: {
6374
lineWrapping: true,
6475
},
76+
autocompleteOnKeyPress: true,
77+
autocompleteProvider: (context, onAvailable)=>{
78+
return new Promise((resolve)=>{
79+
const word = context.matchBefore(/\w*/);
80+
const fullSql = context.state.doc.toString();
81+
onAvailable();
82+
resolve({
83+
from: word.from,
84+
options: (this.sortingCollObj.columnOptions??[]).map((col)=>({
85+
label: col.label, type: 'property',
86+
})),
87+
validFor: (text, from)=>{
88+
return text.startsWith(fullSql.slice(from));
89+
}
90+
});
91+
});
92+
}
6593
}
6694
},
6795
{

web/pgadmin/tools/sqleditor/static/js/show_view_data.js

Lines changed: 35 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -14,23 +14,47 @@ import _ from 'lodash';
1414
import { isEmptyString } from 'sources/validators';
1515
import usePreferences from '../../../../preferences/static/js/store';
1616
import pgAdmin from 'sources/pgadmin';
17+
import { getNodeListByName } from '../../../../browser/static/js/node_ajax';
1718

1819
export default class DataFilterSchema extends BaseUISchema {
19-
constructor(fieldOptions = {}) {
20+
constructor(getColumns) {
2021
super({
2122
filter_sql: ''
2223
});
2324

24-
this.fieldOptions = {
25-
...fieldOptions,
26-
};
25+
this.getColumns = getColumns;
2726
}
2827

2928
get baseFields() {
3029
return [{
3130
id: 'filter_sql',
3231
label: gettext('Data Filter'),
3332
type: 'sql', isFullTab: true, cell: 'text',
33+
controlProps: {
34+
autocompleteOnKeyPress: true,
35+
autocompleteProvider: (context, onAvailable)=>{
36+
return new Promise((resolve, reject)=>{
37+
const word = context.matchBefore(/\w*/);
38+
const fullSql = context.state.doc.toString();
39+
this.getColumns().then((columns) => {
40+
onAvailable();
41+
resolve({
42+
from: word.from,
43+
options: (columns??[]).map((col)=>({
44+
label: col.label, type: 'property',
45+
})),
46+
validFor: (text, from)=>{
47+
return text.startsWith(fullSql.slice(from));
48+
}
49+
});
50+
})
51+
.catch((err) => {
52+
onAvailable();
53+
reject(err instanceof Error ? err : Error(gettext('Something went wrong')));
54+
});
55+
});
56+
}
57+
}
3458
}];
3559
}
3660

@@ -64,8 +88,7 @@ export function showViewData(
6488
return;
6589
}
6690

67-
const parentData = pgBrowser.tree.getTreeNodeHierarchy( treeIdentifier
68-
);
91+
const parentData = pgBrowser.tree.getTreeNodeHierarchy(treeIdentifier);
6992

7093
if (hasServerOrDatabaseConfiguration(parentData)
7194
|| !hasSchemaOrCatalogOrViewInformation(parentData)) {
@@ -157,7 +180,11 @@ function generateFilterValidateUrl(nodeData, parentData) {
157180
function showFilterDialog(pgBrowser, item, queryToolMod, transId,
158181
gridUrl, queryToolTitle, validateUrl) {
159182

160-
let schema = new DataFilterSchema();
183+
const treeNodeInfo = pgBrowser.tree.getTreeNodeHierarchy(item);
184+
const itemNodeData = pgBrowser.tree.findNodeByDomElement(item).getData();
185+
let schema = new DataFilterSchema(
186+
()=>getNodeListByName('column', treeNodeInfo, itemNodeData),
187+
);
161188
let helpUrl = url_for('help.static', {'filename': 'viewdata_filter.html'});
162189

163190
let okCallback = function() {
@@ -168,7 +195,7 @@ function showFilterDialog(pgBrowser, item, queryToolMod, transId,
168195
gettext('Data Filter - %s', queryToolTitle),{
169196
schema, urlBase: validateUrl, helpUrl, saveBtnName: gettext('OK'), isTabView: false,
170197
onSave: okCallback,
171-
}, pgBrowser.stdW.md, pgBrowser.stdH.sm
198+
}, pgBrowser.stdW.md, pgBrowser.stdH.md
172199
);
173200
}
174201

0 commit comments

Comments
 (0)