Fixed review comments:

1. Split the restore options/backup options into 2 tabs
2. Restore icon changes
3. feature tests issues
4. restore help link broken
5. Comment section not visible

refs #7018
This commit is contained in:
Rahul Shirsat 2022-01-06 16:46:44 +05:30 committed by Akshay Joshi
parent f56b4030f1
commit 6528d086ba
9 changed files with 64 additions and 32 deletions

View File

@ -509,7 +509,7 @@ define('pgadmin.browser.node', [
w: (!_.isUndefined(width) && !_.isNull(width)) ? width : w: (!_.isUndefined(width) && !_.isNull(width)) ? width :
(screen.width < 700 ? screen.width * 0.95 : screen.width * 0.5), (screen.width < 700 ? screen.width * 0.95 : screen.width * 0.5),
h: (!_.isUndefined(height) && !_.isNull(height)) ? height : h: (!_.isUndefined(height) && !_.isNull(height)) ? height :
(screen.height < 500 ? screen.height * 0.95 : screen.height * 0.35), (screen.height < 500 ? screen.height * 0.95 : screen.height * 0.4),
x: (screen.width < 700 ? '2%' : '25%'), x: (screen.width < 700 ? '2%' : '25%'),
y: (screen.height < 500 ? '2%' : '25%'), y: (screen.height < 500 ? '2%' : '25%'),
} }

View File

@ -26,6 +26,9 @@ export function getUtilityView(schema, treeNodeInfo, actionType, formType, conta
}; };
const confirmOnReset = pgAdmin.Browser.get_preferences_for_module('browser').confirm_on_properties_close; const confirmOnReset = pgAdmin.Browser.get_preferences_for_module('browser').confirm_on_properties_close;
/* button icons */
const saveBtnIcon = extraData.save_btn_icon;
/* on save button callback, promise required */ /* on save button callback, promise required */
const onSaveClick = (isNew, data)=>new Promise((resolve, reject)=>{ const onSaveClick = (isNew, data)=>new Promise((resolve, reject)=>{
return api({ return api({
@ -90,6 +93,7 @@ export function getUtilityView(schema, treeNodeInfo, actionType, formType, conta
schema={_schema} schema={_schema}
viewHelperProps={viewHelperProps} viewHelperProps={viewHelperProps}
customSaveBtnName={saveBtnName} customSaveBtnName={saveBtnName}
customSaveBtnIconType={saveBtnIcon}
onSave={onSaveClick} onSave={onSaveClick}
onClose={()=>containerPanel.close()} onClose={()=>containerPanel.close()}
onHelp={onHelp} onHelp={onHelp}

View File

@ -240,16 +240,24 @@ class PGUtilitiesBackupFeatureTest(BaseFeatureTest):
self.page.fill_input_by_field_name( self.page.fill_input_by_field_name(
NavMenuLocators.restore_file_name_txt_box_name, NavMenuLocators.restore_file_name_txt_box_name,
"test_backup", loose_focus=True) "test_backup", input_keys=True, loose_focus=True)
# Click on the Restore button
restore_btn = self.page.find_by_xpath( restore_btn = self.page.find_by_xpath(
NavMenuLocators.restore_button_xpath) NavMenuLocators.restore_button_xpath)
click = True
retry = 3
while click and retry > 0:
try:
restore_btn.click() restore_btn.click()
if self.page.wait_for_element_to_disappear(
self.page.wait_for_element_to_disappear(
lambda driver: driver.find_element( lambda driver: driver.find_element(
By.CSS_SELECTOR, By.NAME,
NavMenuLocators.restore_file_name_txt_box_name)) NavMenuLocators.restore_file_name_txt_box_name)):
click = False
except Exception:
retry -= 1
pass
def _check_escaped_characters(self, source_code, string_to_find, source): def _check_escaped_characters(self, source_code, string_to_find, source):
# For XSS we need to search against element's html code # For XSS we need to search against element's html code

View File

@ -12,6 +12,7 @@ import { Box, makeStyles } from '@material-ui/core';
import {Accordion, AccordionSummary, AccordionDetails} from '@material-ui/core'; import {Accordion, AccordionSummary, AccordionDetails} from '@material-ui/core';
import ExpandMoreIcon from '@material-ui/icons/ExpandMore'; import ExpandMoreIcon from '@material-ui/icons/ExpandMore';
import SaveIcon from '@material-ui/icons/Save'; import SaveIcon from '@material-ui/icons/Save';
import PublishIcon from '@material-ui/icons/Publish';
import SettingsBackupRestoreIcon from '@material-ui/icons/SettingsBackupRestore'; import SettingsBackupRestoreIcon from '@material-ui/icons/SettingsBackupRestore';
import CloseIcon from '@material-ui/icons/Close'; import CloseIcon from '@material-ui/icons/Close';
import InfoIcon from '@material-ui/icons/InfoRounded'; import InfoIcon from '@material-ui/icons/InfoRounded';
@ -683,6 +684,15 @@ function SchemaDialogView({
formErr: formErr, formErr: formErr,
}), [formResetKey, formErr]); }), [formResetKey, formErr]);
const getButtonIcon = () => {
if(props.customSaveBtnIconType == 'upload') {
return <PublishIcon />;
}
return <SaveIcon />;
};
let ButtonIcon = getButtonIcon();
/* I am Groot */ /* I am Groot */
return ( return (
<StateUtilsContext.Provider value={stateUtils}> <StateUtilsContext.Provider value={stateUtils}>
@ -710,7 +720,7 @@ function SchemaDialogView({
<DefaultButton data-test="Reset" onClick={onResetClick} startIcon={<SettingsBackupRestoreIcon />} disabled={!dirty || saving} className={classes.buttonMargin}> <DefaultButton data-test="Reset" onClick={onResetClick} startIcon={<SettingsBackupRestoreIcon />} disabled={!dirty || saving} className={classes.buttonMargin}>
{gettext('Reset')} {gettext('Reset')}
</DefaultButton> </DefaultButton>
<PrimaryButton data-test="Save" onClick={onSaveClick} startIcon={<SaveIcon />} disabled={!dirty || saving || Boolean(formErr.name) || !formReady}> <PrimaryButton data-test="Save" onClick={onSaveClick} startIcon={ButtonIcon} disabled={!dirty || saving || Boolean(formErr.name) || !formReady}>
{props.customSaveBtnName ? gettext(props.customSaveBtnName) : gettext('Save')} {props.customSaveBtnName ? gettext(props.customSaveBtnName) : gettext('Save')}
</PrimaryButton> </PrimaryButton>
</Box> </Box>
@ -745,6 +755,7 @@ SchemaDialogView.propTypes = {
showFooter: PropTypes.bool, showFooter: PropTypes.bool,
resetKey: PropTypes.any, resetKey: PropTypes.any,
customSaveBtnName: PropTypes.string, customSaveBtnName: PropTypes.string,
customSaveBtnIconType: PropTypes.string,
}; };
const usePropsStyles = makeStyles((theme)=>({ const usePropsStyles = makeStyles((theme)=>({

View File

@ -142,7 +142,7 @@ define([
}, },
startBackupGlobal: function(action, treeItem) { startBackupGlobal: function(action, treeItem) {
pgBrowser.Node.registerUtilityPanel(); pgBrowser.Node.registerUtilityPanel();
var panel = pgBrowser.Node.addUtilityPanel(); var panel = pgBrowser.Node.addUtilityPanel(pgBrowser.stdW.md);
var tree = pgBrowser.tree, var tree = pgBrowser.tree,
i = treeItem || tree.selected(), i = treeItem || tree.selected(),
data = i ? tree.itemData(i) : undefined, data = i ? tree.itemData(i) : undefined,
@ -159,7 +159,7 @@ define([
}, },
startBackupServer: function(action, treeItem) { startBackupServer: function(action, treeItem) {
pgBrowser.Node.registerUtilityPanel(); pgBrowser.Node.registerUtilityPanel();
var panel = pgBrowser.Node.addUtilityPanel(); var panel = pgBrowser.Node.addUtilityPanel(pgBrowser.stdW.md);
var tree = pgBrowser.tree, var tree = pgBrowser.tree,
i = treeItem || tree.selected(), i = treeItem || tree.selected(),
data = i ? tree.itemData(i) : undefined, data = i ? tree.itemData(i) : undefined,
@ -235,7 +235,7 @@ define([
} }
pgBrowser.Node.registerUtilityPanel(); pgBrowser.Node.registerUtilityPanel();
var panel = pgBrowser.Node.addUtilityPanel(), var panel = pgBrowser.Node.addUtilityPanel(pgBrowser.stdW.md, pgBrowser.stdH.lg),
j = panel.$container.find('.obj_properties').first(); j = panel.$container.find('.obj_properties').first();
var schema = that.getUISchema(treeItem, 'backup_objects'); var schema = that.getUISchema(treeItem, 'backup_objects');

View File

@ -515,7 +515,7 @@ export default class BackupSchema extends BaseUISchema {
}, { }, {
type: 'nested-fieldset', type: 'nested-fieldset',
label: gettext('Sections'), label: gettext('Sections'),
group: gettext('Dump options'), group: gettext('Data/Objects'),
schema:new getSectionSchema(), schema:new getSectionSchema(),
visible: function() { visible: function() {
if (!_.isUndefined(obj.backupType) && obj.backupType === 'server') if (!_.isUndefined(obj.backupType) && obj.backupType === 'server')
@ -525,27 +525,27 @@ export default class BackupSchema extends BaseUISchema {
}, { }, {
type: 'nested-fieldset', type: 'nested-fieldset',
label: gettext('Type of objects'), label: gettext('Type of objects'),
group: gettext('Dump options'), group: gettext('Data/Objects'),
schema: obj.getTypeObjSchema() schema: obj.getTypeObjSchema()
}, { }, {
type: 'nested-fieldset', type: 'nested-fieldset',
label: gettext('Do not save'), label: gettext('Do not save'),
group: gettext('Dump options'), group: gettext('Data/Objects'),
schema: obj.getSaveOptSchema(), schema: obj.getSaveOptSchema(),
}, { }, {
type: 'nested-fieldset', type: 'nested-fieldset',
label: gettext('Queries'), label: gettext('Queries'),
group: gettext('Dump options'), group: gettext('Options'),
schema: obj.getQueryOptionSchema(), schema: obj.getQueryOptionSchema(),
}, { }, {
type: 'nested-fieldset', type: 'nested-fieldset',
label: gettext('Disable'), label: gettext('Disable'),
group: gettext('Dump options'), group: gettext('Options'),
schema: obj.getDisabledOptionSchema(), schema: obj.getDisabledOptionSchema(),
}, { }, {
type: 'nested-fieldset', type: 'nested-fieldset',
label: gettext('Miscellaneous'), label: gettext('Miscellaneous'),
group: gettext('Dump options'), group: gettext('Options'),
schema: obj.getMiscellaneousSchema(), schema: obj.getMiscellaneousSchema(),
}]; }];
} }

View File

@ -80,7 +80,7 @@ define('tools.restore', [
()=>getRestoreSectionSchema({selectedNodeType: itemNodeData._type}), ()=>getRestoreSectionSchema({selectedNodeType: itemNodeData._type}),
()=>getRestoreTypeObjSchema({selectedNodeType: itemNodeData._type}), ()=>getRestoreTypeObjSchema({selectedNodeType: itemNodeData._type}),
()=>getRestoreSaveOptSchema({nodeInfo: treeNodeInfo}), ()=>getRestoreSaveOptSchema({nodeInfo: treeNodeInfo}),
()=>getRestoreQueryOptionSchema({nodeInfo: treeNodeInfo}), ()=>getRestoreQueryOptionSchema({selectedNodeType: itemNodeData._type, nodeInfo: treeNodeInfo}),
()=>getRestoreDisableOptionSchema({nodeInfo: treeNodeInfo}), ()=>getRestoreDisableOptionSchema({nodeInfo: treeNodeInfo}),
()=>getRestoreMiscellaneousSchema({nodeInfo: treeNodeInfo}), ()=>getRestoreMiscellaneousSchema({nodeInfo: treeNodeInfo}),
{ {
@ -115,6 +115,7 @@ define('tools.restore', [
if('function' in treeInfo) { if('function' in treeInfo) {
extraData['functions'] = [nodeData._label]; extraData['functions'] = [nodeData._label];
} }
extraData['save_btn_icon'] = 'upload';
return extraData; return extraData;
}, },
url_for_utility_exists: function(id){ url_for_utility_exists: function(id){
@ -146,7 +147,7 @@ define('tools.restore', [
return; return;
} }
pgBrowser.Node.registerUtilityPanel(); pgBrowser.Node.registerUtilityPanel();
var panel = pgBrowser.Node.addUtilityPanel(), var panel = pgBrowser.Node.addUtilityPanel(pgBrowser.stdW.md),
j = panel.$container.find('.obj_properties').first(); j = panel.$container.find('.obj_properties').first();
var schema = that.getUISchema(treeItem); var schema = that.getUISchema(treeItem);
@ -159,7 +160,7 @@ define('tools.restore', [
}), }),
extraData = that.setExtraParameters(treeNodeInfo, data); extraData = that.setExtraParameters(treeNodeInfo, data);
var sqlHelpUrl = 'restore.html', var sqlHelpUrl = 'backup.html',
helpUrl = url_for('help.static', { helpUrl = url_for('help.static', {
'filename': 'restore_dialog.html', 'filename': 'restore_dialog.html',
}); });

View File

@ -100,6 +100,9 @@ export class RestoreTypeObjSchema extends BaseUISchema {
group: gettext('Type of objects'), group: gettext('Type of objects'),
deps: ['pre_data', 'data', 'post_data', 'only_schema'], deps: ['pre_data', 'data', 'post_data', 'only_schema'],
disabled: function(state) { disabled: function(state) {
if(obj.selectedNodeType == 'table') {
state.only_data = true;
}
return (obj.selectedNodeType !== 'database' && obj.selectedNodeType !== 'schema') || return (obj.selectedNodeType !== 'database' && obj.selectedNodeType !== 'schema') ||
(state.pre_data || (state.pre_data ||
state.data || state.data ||
@ -114,6 +117,9 @@ export class RestoreTypeObjSchema extends BaseUISchema {
group: gettext('Type of objects'), group: gettext('Type of objects'),
deps: ['pre_data', 'data', 'post_data', 'only_data'], deps: ['pre_data', 'data', 'post_data', 'only_data'],
disabled: function(state) { disabled: function(state) {
if(obj.selectedNodeType == 'index' || obj.selectedNodeType == 'function') {
state.only_schema = true;
}
return (obj.selectedNodeType !== 'database' && obj.selectedNodeType !== 'schema') || return (obj.selectedNodeType !== 'database' && obj.selectedNodeType !== 'schema') ||
(state.pre_data || (state.pre_data ||
state.data || state.data ||
@ -174,7 +180,7 @@ export class RestoreSaveOptSchema extends BaseUISchema {
disabled: false, disabled: false,
group: gettext('Do not save'), group: gettext('Do not save'),
visible: function() { visible: function() {
var serverInfo = obj.fieldOptions.nodeInfo; var serverInfo = obj.fieldOptions.nodeInfo.server;
return !_.isUndefined(serverInfo) && serverInfo.version >= 110000 ? true : false; return !_.isUndefined(serverInfo) && serverInfo.version >= 110000 ? true : false;
}, },
}]; }];
@ -218,9 +224,11 @@ export class RestoreQueryOptionSchema extends BaseUISchema {
label: gettext('Clean before restore'), label: gettext('Clean before restore'),
type: 'switch', type: 'switch',
group: gettext('Queries'), group: gettext('Queries'),
disabled: function() { disabled: function(state) {
return obj.selectedNodeType === 'function' if(obj.selectedNodeType === 'function' || obj.selectedNodeType === 'trigger_function') {
|| obj.selectedNodeType === 'trigger_function'; state.clean = true;
return true;
}
}, },
}, { }, {
id: 'single_transaction', id: 'single_transaction',
@ -407,37 +415,37 @@ export default class RestoreSchema extends BaseUISchema {
}, { }, {
type: 'nested-fieldset', type: 'nested-fieldset',
label: gettext('Sections'), label: gettext('Sections'),
group: gettext('Restore options'), group: gettext('Data/Objects'),
schema:obj.getSectionSchema(), schema:obj.getSectionSchema(),
visible: true visible: true
}, { }, {
type: 'nested-fieldset', type: 'nested-fieldset',
label: gettext('Type of objects'), label: gettext('Type of objects'),
group: gettext('Restore options'), group: gettext('Data/Objects'),
schema:obj.getRestoreTypeObjSchema(), schema:obj.getRestoreTypeObjSchema(),
visible: true visible: true
}, { }, {
type: 'nested-fieldset', type: 'nested-fieldset',
label: gettext('Do not save'), label: gettext('Do not save'),
group: gettext('Restore options'), group: gettext('Data/Objects'),
schema:obj.getRestoreSaveOptSchema(), schema:obj.getRestoreSaveOptSchema(),
visible: true visible: true
}, { }, {
type: 'nested-fieldset', type: 'nested-fieldset',
label: gettext('Queries'), label: gettext('Queries'),
group: gettext('Restore options'), group: gettext('Options'),
schema:obj.getRestoreQueryOptionSchema(), schema:obj.getRestoreQueryOptionSchema(),
visible: true visible: true
}, { }, {
type: 'nested-fieldset', type: 'nested-fieldset',
label: gettext('Disable'), label: gettext('Disable'),
group: gettext('Restore options'), group: gettext('Options'),
schema:obj.getRestoreDisableOptionSchema(), schema:obj.getRestoreDisableOptionSchema(),
visible: true visible: true
}, { }, {
type: 'nested-fieldset', type: 'nested-fieldset',
label: gettext('Miscellaneous / Behavior'), label: gettext('Miscellaneous / Behavior'),
group: gettext('Restore options'), group: gettext('Options'),
schema:obj.getRestoreMiscellaneousSchema(), schema:obj.getRestoreMiscellaneousSchema(),
visible: true visible: true
}]; }];

View File

@ -100,7 +100,7 @@ class NavMenuLocators:
"//following::input[@name='file']" "//following::input[@name='file']"
restore_button_xpath = \ restore_button_xpath = \
"//button[contains(@class,'fa-upload') and contains(.,'Restore')]" "//button[ contains(.,'Restore')]"
maintenance_operation = "//label[text()='Maintenance operation']" maintenance_operation = "//label[text()='Maintenance operation']"