mirror of
https://github.com/pgadmin-org/pgadmin4.git
synced 2024-11-25 18:20:20 -06:00
Port Schema & Catalog node to react. Fixes #6655
This commit is contained in:
parent
40879a5784
commit
08f2121544
@ -7,6 +7,8 @@
|
||||
//
|
||||
//////////////////////////////////////////////////////////////
|
||||
|
||||
import CatalogSchema from './catalog.ui';
|
||||
|
||||
define('pgadmin.node.catalog', [
|
||||
'sources/gettext', 'jquery', 'underscore', 'sources/pgadmin',
|
||||
'pgadmin.browser', 'pgadmin.browser.collection',
|
||||
@ -41,14 +43,6 @@ define('pgadmin.node.catalog', [
|
||||
|
||||
},
|
||||
model: pgBrowser.Node.Model.extend({
|
||||
defaults: {
|
||||
name: undefined,
|
||||
namespaceowner: undefined,
|
||||
nspacl: undefined,
|
||||
is_sys_obj: undefined,
|
||||
description: undefined,
|
||||
securitylabel: [],
|
||||
},
|
||||
initialize: function(attrs, args) {
|
||||
var isNew = (_.size(attrs) === 0);
|
||||
|
||||
@ -65,30 +59,15 @@ define('pgadmin.node.catalog', [
|
||||
},{
|
||||
id: 'oid', label: gettext('OID'), cell: 'string', mode: ['properties'],
|
||||
type: 'text',
|
||||
},{
|
||||
id: 'namespaceowner', label: gettext('Owner'), cell: 'string',
|
||||
type: 'text', readonly: true,
|
||||
},{
|
||||
id: 'acl', label: gettext('Privileges'), type: 'text',
|
||||
group: gettext('Security'), mode: ['properties'],
|
||||
},{
|
||||
id: 'is_sys_obj', label: gettext('System catalog?'),
|
||||
cell:'boolean', type: 'switch', mode: ['properties'],
|
||||
},{
|
||||
id: 'description', label: gettext('Comment'), cell: 'string',
|
||||
type: 'multiline',
|
||||
},{
|
||||
id: 'seclabels', label: gettext('Security labels'),
|
||||
model: pgBrowser.SecLabelModel, editable: false, type: 'collection',
|
||||
group: gettext('Security'), mode: ['edit', 'create'],
|
||||
min_version: 90200, canAdd: true,
|
||||
canEdit: false, canDelete: true, control: 'unique-col-collection',
|
||||
},
|
||||
],
|
||||
validate: function() {
|
||||
return null;
|
||||
},
|
||||
}]
|
||||
}),
|
||||
getSchema: function(treeNodeInfo) {
|
||||
return new CatalogSchema(
|
||||
{
|
||||
namespaceowner: pgBrowser.serverInfo[treeNodeInfo.server._id].user.name
|
||||
}
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,64 @@
|
||||
/////////////////////////////////////////////////////////////
|
||||
//
|
||||
// pgAdmin 4 - PostgreSQL Tools
|
||||
//
|
||||
// Copyright (C) 2013 - 2021, The pgAdmin Development Team
|
||||
// This software is released under the PostgreSQL Licence
|
||||
//
|
||||
//////////////////////////////////////////////////////////////
|
||||
|
||||
import gettext from 'sources/gettext';
|
||||
import BaseUISchema from 'sources/SchemaView/base_schema.ui';
|
||||
import SecLabelSchema from '../../../../static/js/sec_label.ui';
|
||||
|
||||
export default class CatalogSchema extends BaseUISchema {
|
||||
constructor(fieldOptions = {}, initValues) {
|
||||
super({
|
||||
name: undefined,
|
||||
namespaceowner: undefined,
|
||||
nspacl: undefined,
|
||||
is_sys_obj: undefined,
|
||||
description: undefined,
|
||||
securitylabel: [],
|
||||
...initValues
|
||||
});
|
||||
this.fieldOptions = {
|
||||
...fieldOptions,
|
||||
};
|
||||
}
|
||||
|
||||
get idAttribute() {
|
||||
return 'oid';
|
||||
}
|
||||
|
||||
get baseFields() {
|
||||
return [
|
||||
{
|
||||
id: 'name', label: gettext('Name'), cell: 'string',
|
||||
type: 'text', readonly: true,
|
||||
},{
|
||||
id: 'oid', label: gettext('OID'), cell: 'string', mode: ['properties'],
|
||||
type: 'text',
|
||||
},{
|
||||
id: 'namespaceowner', label: gettext('Owner'), cell: 'string',
|
||||
type: 'text', readonly: true,
|
||||
},{
|
||||
id: 'acl', label: gettext('Privileges'), type: 'text',
|
||||
group: gettext('Security'), mode: ['properties'],
|
||||
},{
|
||||
id: 'is_sys_obj', label: gettext('System catalog?'),
|
||||
cell:'boolean', type: 'switch', mode: ['properties'],
|
||||
},{
|
||||
id: 'description', label: gettext('Comment'), cell: 'string',
|
||||
type: 'multiline',
|
||||
},{
|
||||
id: 'seclabels', label: gettext('Security labels'),
|
||||
schema: new SecLabelSchema(),
|
||||
editable: false, type: 'collection',
|
||||
group: gettext('Security'), mode: ['edit', 'create'],
|
||||
min_version: 90200,
|
||||
canAdd: false, canEdit: false, canDelete: false,
|
||||
},
|
||||
];
|
||||
}
|
||||
}
|
@ -7,6 +7,10 @@
|
||||
//
|
||||
//////////////////////////////////////////////////////////////
|
||||
|
||||
import PGSchema from './schema.ui';
|
||||
import { getNodePrivilegeRoleSchema } from '../../../../static/js/privilege.ui';
|
||||
import { getNodeListByName } from '../../../../../../static/js/node_ajax';
|
||||
|
||||
define('pgadmin.node.schema', [
|
||||
'sources/gettext', 'sources/url_for', 'jquery', 'underscore',
|
||||
'sources/pgadmin', 'pgadmin.browser', 'pgadmin.backform', 'pgadmin.backgrid',
|
||||
@ -149,6 +153,8 @@ define('pgadmin.node.schema', [
|
||||
},
|
||||
});
|
||||
|
||||
/* As Backform.VacuumSettingsSchema is commonly used in table & partition, so keeping it as it is for now.
|
||||
this and other supporting model can be removed after their migration to react. */
|
||||
// Extend the browser's collection class for VacuumSettingsModel
|
||||
Backform.VacuumSettingsSchema = [{
|
||||
id: 'spacer_ctrl', group: gettext('Table'), mode: ['edit', 'create'], type: 'spacer',
|
||||
@ -357,12 +363,6 @@ define('pgadmin.node.schema', [
|
||||
},
|
||||
model: pgBrowser.Node.Model.extend({
|
||||
idAttribute: 'oid',
|
||||
defaults: {
|
||||
name: undefined,
|
||||
namespaceowner: undefined,
|
||||
description: undefined,
|
||||
is_system_obj: undefined,
|
||||
},
|
||||
initialize: function(attrs, args) {
|
||||
var isNew = (_.size(attrs) === 0);
|
||||
|
||||
@ -388,94 +388,24 @@ define('pgadmin.node.schema', [
|
||||
cell: 'switch', type: 'switch', mode: ['properties'],
|
||||
},{
|
||||
id: 'description', label: gettext('Comment'), cell: 'string',
|
||||
type: 'multiline',
|
||||
},{
|
||||
id: 'acl', label: gettext('Privileges'), type: 'text',
|
||||
group: gettext('Security'), mode: ['properties'],
|
||||
},{
|
||||
id: 'tblacl', label: gettext('Default TABLE privileges'), type: 'text',
|
||||
group: gettext('Security'), mode: ['properties'],
|
||||
},{
|
||||
id: 'seqacl', label: gettext('Default SEQUENCE privileges'), type: 'text',
|
||||
group: gettext('Security'), mode: ['properties'],
|
||||
},{
|
||||
id: 'funcacl', label: gettext('Default FUNCTION privileges'),
|
||||
group: gettext('Security'), type: 'text', mode: ['properties'],
|
||||
},{
|
||||
id: 'typeacl', label: gettext('Default TYPE privileges'), type: 'text',
|
||||
group: gettext('Security'), mode: ['properties'], min_version: 90200,
|
||||
visible: function() {
|
||||
return this.version_compatible;
|
||||
},
|
||||
},{
|
||||
id: 'nspacl', label: gettext('Privileges'),
|
||||
model: pgBrowser.Node.PrivilegeRoleModel.extend(
|
||||
{privileges: ['C', 'U']}), uniqueCol : ['grantee', 'grantor'],
|
||||
editable: false, type: 'collection', group: gettext('Security'),
|
||||
mode: ['edit', 'create'],
|
||||
canAdd: true, canDelete: true, control: 'unique-col-collection',
|
||||
},{
|
||||
id: 'seclabels', label: gettext('Security labels'),
|
||||
model: pgBrowser.SecLabelModel, editable: false, type: 'collection',
|
||||
group: gettext('Security'), mode: ['edit', 'create'],
|
||||
min_version: 90200, canAdd: true,
|
||||
canEdit: false, canDelete: true, control: 'unique-col-collection',
|
||||
},{
|
||||
type: 'nested', control: 'tab', group: gettext('Default privileges'),
|
||||
mode: ['create','edit'],
|
||||
schema:[{
|
||||
id: 'deftblacl', model: pgBrowser.Node.PrivilegeRoleModel.extend(
|
||||
{privileges: ['a', 'r', 'w', 'd', 'D', 'x', 't']}),
|
||||
label: '',
|
||||
editable: false, type: 'collection', group: gettext('Tables'),
|
||||
mode: ['edit', 'create'], control: 'unique-col-collection',
|
||||
canAdd: true, canDelete: true, uniqueCol : ['grantee', 'grantor'],
|
||||
},{
|
||||
id: 'defseqacl', model: pgBrowser.Node.PrivilegeRoleModel.extend(
|
||||
{privileges: ['r', 'w', 'U']}),
|
||||
label: '',
|
||||
editable: false, type: 'collection', group: gettext('Sequences'),
|
||||
mode: ['edit', 'create'], control: 'unique-col-collection',
|
||||
canAdd: true, canDelete: true, uniqueCol : ['grantee', 'grantor'],
|
||||
},{
|
||||
id: 'deffuncacl', model: pgBrowser.Node.PrivilegeRoleModel.extend(
|
||||
{privileges: ['X']}),
|
||||
label: '',
|
||||
editable: false, type: 'collection', group: gettext('Functions'),
|
||||
mode: ['edit', 'create'], control: 'unique-col-collection',
|
||||
canAdd: true, canDelete: true, uniqueCol : ['grantee', 'grantor'],
|
||||
},{
|
||||
id: 'deftypeacl', model: pgBrowser.Node.PrivilegeRoleModel.extend(
|
||||
{privileges: ['U']}),
|
||||
label: '',
|
||||
editable: false, type: 'collection', group: gettext('Types'),
|
||||
mode: ['edit', 'create'], control: 'unique-col-collection',
|
||||
canAdd: true, canDelete: true, uniqueCol : ['grantee', 'grantor'],
|
||||
min_version: 90200,
|
||||
}],
|
||||
},
|
||||
],
|
||||
validate: function() {
|
||||
var errmsg = null;
|
||||
|
||||
// Validation of mandatory fields
|
||||
this.errorModel.clear();
|
||||
if (_.isUndefined(this.get('name')) ||
|
||||
_.isNull(this.get('name')) ||
|
||||
String(this.get('name')).replace(/^\s+|\s+$/g, '') == '') {
|
||||
errmsg = gettext('Name cannot be empty.');
|
||||
this.errorModel.set('name', errmsg);
|
||||
return errmsg;
|
||||
} else if (_.isUndefined(this.get('namespaceowner')) ||
|
||||
_.isNull(this.get('namespaceowner')) ||
|
||||
String(this.get('namespaceowner')).replace(/^\s+|\s+$/g, '') == '') {
|
||||
errmsg = gettext('Owner cannot be empty.');
|
||||
this.errorModel.set('namespaceowner', errmsg);
|
||||
return errmsg;
|
||||
}
|
||||
return null;
|
||||
},
|
||||
type: 'multiline'
|
||||
}]
|
||||
}),
|
||||
getSchema: function(treeNodeInfo, itemNodeData) {
|
||||
var schemaObj = pgBrowser.Nodes['schema'];
|
||||
return new PGSchema(
|
||||
(privileges)=>getNodePrivilegeRoleSchema(schemaObj, treeNodeInfo, itemNodeData, privileges),
|
||||
{
|
||||
roles:() => getNodeListByName('role', treeNodeInfo, itemNodeData, {
|
||||
cacheLevel: 'database'
|
||||
}),
|
||||
server_info: pgBrowser.serverInfo[treeNodeInfo.server._id]
|
||||
},
|
||||
{
|
||||
namespaceowner: pgBrowser.serverInfo[treeNodeInfo.server._id].user.name
|
||||
}
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
pgBrowser.tableChildTreeNodeHierarchy = function(i) {
|
||||
@ -483,6 +413,8 @@ define('pgadmin.node.schema', [
|
||||
};
|
||||
}
|
||||
|
||||
/* As TableChildSwitchCell is commonly used in index, column & TableDialog, so keeping it as it is for now.
|
||||
this and other supporting model can be removed after their migration to react. */
|
||||
// Switch Cell with Deps (specifically for table children)
|
||||
Backgrid.Extension.TableChildSwitchCell = Backgrid.Extension.SwitchCell.extend({
|
||||
initialize: function() {
|
||||
|
@ -0,0 +1,112 @@
|
||||
/////////////////////////////////////////////////////////////
|
||||
//
|
||||
// pgAdmin 4 - PostgreSQL Tools
|
||||
//
|
||||
// Copyright (C) 2013 - 2021, The pgAdmin Development Team
|
||||
// This software is released under the PostgreSQL Licence
|
||||
//
|
||||
//////////////////////////////////////////////////////////////
|
||||
|
||||
import gettext from 'sources/gettext';
|
||||
import BaseUISchema from 'sources/SchemaView/base_schema.ui';
|
||||
import { DefaultPrivSchema } from '../../../static/js/database.ui';
|
||||
import SecLabelSchema from '../../../../static/js/sec_label.ui';
|
||||
import { isEmptyString } from 'sources/validators';
|
||||
|
||||
export default class PGSchema extends BaseUISchema {
|
||||
constructor(getPrivilegeRoleSchema, fieldOptions = {}, initValues) {
|
||||
super({
|
||||
name: undefined,
|
||||
namespaceowner: undefined,
|
||||
description: undefined,
|
||||
is_system_obj: undefined,
|
||||
...initValues
|
||||
});
|
||||
this.fieldOptions = {
|
||||
roles: [],
|
||||
server_info: [],
|
||||
...fieldOptions,
|
||||
};
|
||||
this.getPrivilegeRoleSchema = getPrivilegeRoleSchema;
|
||||
}
|
||||
|
||||
get idAttribute() {
|
||||
return 'oid';
|
||||
}
|
||||
|
||||
get baseFields() {
|
||||
let pgSchemaObj = this;
|
||||
return [
|
||||
{
|
||||
id: 'name', label: gettext('Name'), cell: 'string',
|
||||
type: 'text',
|
||||
},{
|
||||
id: 'oid', label: gettext('OID'), cell: 'string',
|
||||
type: 'text', mode: ['properties'],
|
||||
},{
|
||||
id: 'namespaceowner', label: gettext('Owner'), cell: 'string',
|
||||
type: 'select',
|
||||
options: pgSchemaObj.fieldOptions.roles,
|
||||
controlProps: { allowClear: false }
|
||||
},{
|
||||
id: 'is_sys_obj', label: gettext('System schema?'),
|
||||
cell: 'switch', type: 'switch', mode: ['properties'],
|
||||
},{
|
||||
id: 'description', label: gettext('Comment'), cell: 'string',
|
||||
type: 'multiline',
|
||||
},{
|
||||
id: 'acl', label: gettext('Privileges'), type: 'text',
|
||||
group: gettext('Security'), mode: ['properties'],
|
||||
},{
|
||||
id: 'tblacl', label: gettext('Default TABLE privileges'), type: 'text',
|
||||
group: gettext('Security'), mode: ['properties'],
|
||||
},{
|
||||
id: 'seqacl', label: gettext('Default SEQUENCE privileges'), type: 'text',
|
||||
group: gettext('Security'), mode: ['properties'],
|
||||
},{
|
||||
id: 'funcacl', label: gettext('Default FUNCTION privileges'),
|
||||
group: gettext('Security'), type: 'text', mode: ['properties'],
|
||||
},{
|
||||
id: 'typeacl', label: gettext('Default TYPE privileges'), type: 'text',
|
||||
group: gettext('Security'), mode: ['properties'], min_version: 90200
|
||||
},
|
||||
{
|
||||
id: 'nspacl', label: gettext('Privileges'), type: 'collection',
|
||||
schema: pgSchemaObj.getPrivilegeRoleSchema(['C', 'U']),
|
||||
uniqueCol : ['grantee', 'grantor'], editable: false,
|
||||
group: gettext('Security'), mode: ['edit', 'create'],
|
||||
canAdd: true, canDelete: true,
|
||||
},
|
||||
{
|
||||
id: 'seclabels', label: gettext('Security labels'),
|
||||
schema: new SecLabelSchema(), editable: false, type: 'collection',
|
||||
group: gettext('Security'), mode: ['edit', 'create'],
|
||||
min_version: 90200, canAdd: true,
|
||||
canEdit: false, canDelete: true,
|
||||
},
|
||||
{
|
||||
type: 'nested-tab',
|
||||
group: gettext('Default privileges'),
|
||||
mode: ['create','edit'],
|
||||
schema: new DefaultPrivSchema(pgSchemaObj.getPrivilegeRoleSchema)
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
validate(state, setError) {
|
||||
var errmsg = null;
|
||||
|
||||
// Validation of mandatory fields
|
||||
if (isEmptyString(state.name)) {
|
||||
errmsg = gettext('Name cannot be empty.');
|
||||
setError('name', errmsg);
|
||||
return true;
|
||||
}
|
||||
else if(isEmptyString(state.namespaceowner)) {
|
||||
errmsg = gettext('Owner cannot be empty.');
|
||||
setError('namespaceowner', errmsg);
|
||||
return true;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
@ -195,6 +195,7 @@ export function getNodeView(nodeType, treeNodeInfo, actionType, itemNodeData, fo
|
||||
hasSQL={nodeObj.hasSQL && (actionType === 'create' || actionType === 'edit')}
|
||||
getSQLValue={getSQLValue}
|
||||
disableSqlHelp={nodeObj.sqlAlterHelp == '' && nodeObj.sqlCreateHelp == ''}
|
||||
disableDialogHelp={nodeObj.dialogHelp == undefined || nodeObj.dialogHelp == ''}
|
||||
/>, container);
|
||||
}
|
||||
|
||||
|
@ -634,7 +634,8 @@ function SchemaDialogView({
|
||||
{useMemo(()=><Box>
|
||||
<PgIconButton data-test="sql-help" onClick={()=>props.onHelp(true, isNew)} icon={<InfoIcon />}
|
||||
disabled={props.disableSqlHelp} className={classes.buttonMargin} title="SQL help for this object type."/>
|
||||
<PgIconButton data-test="dialog-help" onClick={()=>props.onHelp(false, isNew)} icon={<HelpIcon />} title="Help for this dialog."/>
|
||||
<PgIconButton data-test="dialog-help" onClick={()=>props.onHelp(false, isNew)} icon={<HelpIcon />} title="Help for this dialog."
|
||||
disabled={props.disableDialogHelp}/>
|
||||
</Box>, [])}
|
||||
<Box marginLeft="auto">
|
||||
<DefaultButton data-test="Close" onClick={props.onClose} startIcon={<CloseIcon />} className={classes.buttonMargin}>
|
||||
@ -673,6 +674,7 @@ SchemaDialogView.propTypes = {
|
||||
hasSQL: PropTypes.bool,
|
||||
getSQLValue: PropTypes.func,
|
||||
disableSqlHelp: PropTypes.bool,
|
||||
disableDialogHelp: PropTypes.bool,
|
||||
};
|
||||
|
||||
const usePropsStyles = makeStyles((theme)=>({
|
||||
|
@ -60,6 +60,7 @@ describe('CastSchema', ()=>{
|
||||
confirmOnCloseReset={false}
|
||||
hasSQL={false}
|
||||
disableSqlHelp={false}
|
||||
disableDialogHelp={false}
|
||||
/>);
|
||||
});
|
||||
|
||||
@ -79,6 +80,7 @@ describe('CastSchema', ()=>{
|
||||
confirmOnCloseReset={false}
|
||||
hasSQL={false}
|
||||
disableSqlHelp={false}
|
||||
disableDialogHelp={false}
|
||||
/>);
|
||||
});
|
||||
|
||||
|
99
web/regression/javascript/schema_ui_files/catalog.ui.spec.js
Normal file
99
web/regression/javascript/schema_ui_files/catalog.ui.spec.js
Normal file
@ -0,0 +1,99 @@
|
||||
/////////////////////////////////////////////////////////////
|
||||
//
|
||||
// pgAdmin 4 - PostgreSQL Tools
|
||||
//
|
||||
// Copyright (C) 2013 - 2021, The pgAdmin Development Team
|
||||
// This software is released under the PostgreSQL Licence
|
||||
//
|
||||
//////////////////////////////////////////////////////////////
|
||||
|
||||
import jasmineEnzyme from 'jasmine-enzyme';
|
||||
import React from 'react';
|
||||
import '../helper/enzyme.helper';
|
||||
import { createMount } from '@material-ui/core/test-utils';
|
||||
import pgAdmin from 'sources/pgadmin';
|
||||
import {messages} from '../fake_messages';
|
||||
import SchemaView from '../../../pgadmin/static/js/SchemaView';
|
||||
import CatalogSchema from '../../../pgadmin/browser/server_groups/servers/databases/schemas/static/js/catalog.ui';
|
||||
|
||||
|
||||
describe('CatalogSchema', ()=>{
|
||||
let mount;
|
||||
let catalogObj = new CatalogSchema(
|
||||
{
|
||||
namespaceowner: '',
|
||||
}
|
||||
);
|
||||
let getInitData = ()=>Promise.resolve({});
|
||||
|
||||
/* Use createMount so that material ui components gets the required context */
|
||||
/* https://material-ui.com/guides/testing/#api */
|
||||
beforeAll(()=>{
|
||||
mount = createMount();
|
||||
});
|
||||
|
||||
afterAll(() => {
|
||||
mount.cleanUp();
|
||||
});
|
||||
|
||||
beforeEach(()=>{
|
||||
jasmineEnzyme();
|
||||
/* messages used by validators */
|
||||
pgAdmin.Browser = pgAdmin.Browser || {};
|
||||
pgAdmin.Browser.messages = pgAdmin.Browser.messages || messages;
|
||||
pgAdmin.Browser.utils = pgAdmin.Browser.utils || {};
|
||||
});
|
||||
|
||||
it('create', ()=>{
|
||||
mount(<SchemaView
|
||||
formType='dialog'
|
||||
schema={catalogObj}
|
||||
viewHelperProps={{
|
||||
mode: 'create',
|
||||
}}
|
||||
onSave={()=>{}}
|
||||
onClose={()=>{}}
|
||||
onHelp={()=>{}}
|
||||
onEdit={()=>{}}
|
||||
onDataChange={()=>{}}
|
||||
confirmOnCloseReset={false}
|
||||
hasSQL={false}
|
||||
disableSqlHelp={false}
|
||||
disableDialogHelp={true}
|
||||
/>);
|
||||
});
|
||||
|
||||
it('edit', ()=>{
|
||||
mount(<SchemaView
|
||||
formType='dialog'
|
||||
schema={catalogObj}
|
||||
getInitData={getInitData}
|
||||
viewHelperProps={{
|
||||
mode: 'create',
|
||||
}}
|
||||
onSave={()=>{}}
|
||||
onClose={()=>{}}
|
||||
onHelp={()=>{}}
|
||||
onEdit={()=>{}}
|
||||
onDataChange={()=>{}}
|
||||
confirmOnCloseReset={false}
|
||||
hasSQL={false}
|
||||
disableSqlHelp={false}
|
||||
disableDialogHelp={true}
|
||||
/>);
|
||||
});
|
||||
|
||||
it('properties', ()=>{
|
||||
mount(<SchemaView
|
||||
formType='tab'
|
||||
schema={catalogObj}
|
||||
getInitData={getInitData}
|
||||
viewHelperProps={{
|
||||
mode: 'properties',
|
||||
}}
|
||||
onHelp={()=>{}}
|
||||
onEdit={()=>{}}
|
||||
/>);
|
||||
});
|
||||
});
|
||||
|
@ -66,6 +66,7 @@ describe('CollationsSchema', () => {
|
||||
confirmOnCloseReset={false}
|
||||
hasSQL={false}
|
||||
disableSqlHelp={false}
|
||||
disableDialogHelp={false}
|
||||
/>);
|
||||
});
|
||||
|
||||
@ -85,6 +86,7 @@ describe('CollationsSchema', () => {
|
||||
confirmOnCloseReset={false}
|
||||
hasSQL={false}
|
||||
disableSqlHelp={false}
|
||||
disableDialogHelp={false}
|
||||
/>);
|
||||
});
|
||||
|
||||
|
@ -77,6 +77,7 @@ describe('DatabaseSchema', ()=>{
|
||||
confirmOnCloseReset={false}
|
||||
hasSQL={false}
|
||||
disableSqlHelp={false}
|
||||
disableDialogHelp={false}
|
||||
/>);
|
||||
});
|
||||
|
||||
@ -96,6 +97,7 @@ describe('DatabaseSchema', ()=>{
|
||||
confirmOnCloseReset={false}
|
||||
hasSQL={false}
|
||||
disableSqlHelp={false}
|
||||
disableDialogHelp={false}
|
||||
/>);
|
||||
});
|
||||
|
||||
|
@ -69,6 +69,7 @@ describe('DomainSchema', ()=>{
|
||||
confirmOnCloseReset={false}
|
||||
hasSQL={false}
|
||||
disableSqlHelp={false}
|
||||
disableDialogHelp={false}
|
||||
/>);
|
||||
});
|
||||
|
||||
@ -88,6 +89,7 @@ describe('DomainSchema', ()=>{
|
||||
confirmOnCloseReset={false}
|
||||
hasSQL={false}
|
||||
disableSqlHelp={false}
|
||||
disableDialogHelp={false}
|
||||
/>);
|
||||
});
|
||||
|
||||
@ -162,6 +164,7 @@ describe('DomainConstSchema', ()=>{
|
||||
confirmOnCloseReset={false}
|
||||
hasSQL={false}
|
||||
disableSqlHelp={false}
|
||||
disableDialogHelp={false}
|
||||
/>);
|
||||
|
||||
/* Make sure you hit every corner */
|
||||
@ -184,6 +187,7 @@ describe('DomainConstSchema', ()=>{
|
||||
confirmOnCloseReset={false}
|
||||
hasSQL={false}
|
||||
disableSqlHelp={false}
|
||||
disableDialogHelp={false}
|
||||
/>);
|
||||
});
|
||||
|
||||
|
@ -54,6 +54,7 @@ describe('DomainConstraintSchema', ()=>{
|
||||
confirmOnCloseReset={false}
|
||||
hasSQL={false}
|
||||
disableSqlHelp={false}
|
||||
disableDialogHelp={false}
|
||||
/>);
|
||||
});
|
||||
|
||||
@ -73,6 +74,7 @@ describe('DomainConstraintSchema', ()=>{
|
||||
confirmOnCloseReset={false}
|
||||
hasSQL={false}
|
||||
disableSqlHelp={false}
|
||||
disableDialogHelp={false}
|
||||
/>);
|
||||
});
|
||||
|
||||
|
@ -63,6 +63,7 @@ describe('EventTriggerSchema', ()=>{
|
||||
confirmOnCloseReset={false}
|
||||
hasSQL={false}
|
||||
disableSqlHelp={false}
|
||||
disableDialogHelp={false}
|
||||
/>);
|
||||
});
|
||||
|
||||
@ -82,6 +83,7 @@ describe('EventTriggerSchema', ()=>{
|
||||
confirmOnCloseReset={false}
|
||||
hasSQL={false}
|
||||
disableSqlHelp={false}
|
||||
disableDialogHelp={false}
|
||||
/>);
|
||||
});
|
||||
|
||||
|
@ -60,6 +60,7 @@ describe('ExtensionSchema', ()=>{
|
||||
confirmOnCloseReset={false}
|
||||
hasSQL={false}
|
||||
disableSqlHelp={false}
|
||||
disableDialogHelp={false}
|
||||
/>);
|
||||
});
|
||||
|
||||
@ -79,6 +80,7 @@ describe('ExtensionSchema', ()=>{
|
||||
confirmOnCloseReset={false}
|
||||
hasSQL={false}
|
||||
disableSqlHelp={false}
|
||||
disableDialogHelp={false}
|
||||
/>);
|
||||
});
|
||||
|
||||
|
@ -71,6 +71,7 @@ describe('ForeignDataWrapperSchema', ()=>{
|
||||
confirmOnCloseReset={false}
|
||||
hasSQL={false}
|
||||
disableSqlHelp={false}
|
||||
disableDialogHelp={false}
|
||||
/>);
|
||||
});
|
||||
|
||||
@ -90,6 +91,7 @@ describe('ForeignDataWrapperSchema', ()=>{
|
||||
confirmOnCloseReset={false}
|
||||
hasSQL={false}
|
||||
disableSqlHelp={false}
|
||||
disableDialogHelp={false}
|
||||
/>);
|
||||
});
|
||||
|
||||
|
@ -69,6 +69,7 @@ describe('ForeignServerSchema', ()=>{
|
||||
confirmOnCloseReset={false}
|
||||
hasSQL={false}
|
||||
disableSqlHelp={false}
|
||||
disableDialogHelp={false}
|
||||
/>);
|
||||
});
|
||||
|
||||
@ -88,6 +89,7 @@ describe('ForeignServerSchema', ()=>{
|
||||
confirmOnCloseReset={false}
|
||||
hasSQL={false}
|
||||
disableSqlHelp={false}
|
||||
disableDialogHelp={false}
|
||||
/>);
|
||||
});
|
||||
|
||||
|
@ -65,6 +65,7 @@ describe('FTSDictionarySchema', ()=>{
|
||||
confirmOnCloseReset={false}
|
||||
hasSQL={false}
|
||||
disableSqlHelp={false}
|
||||
disableDialogHelp={false}
|
||||
/>);
|
||||
});
|
||||
|
||||
@ -84,6 +85,7 @@ describe('FTSDictionarySchema', ()=>{
|
||||
confirmOnCloseReset={false}
|
||||
hasSQL={false}
|
||||
disableSqlHelp={false}
|
||||
disableDialogHelp={false}
|
||||
/>);
|
||||
});
|
||||
|
||||
|
@ -67,6 +67,7 @@ describe('FTSParserSchema', ()=>{
|
||||
confirmOnCloseReset={false}
|
||||
hasSQL={false}
|
||||
disableSqlHelp={false}
|
||||
disableDialogHelp={false}
|
||||
/>);
|
||||
});
|
||||
|
||||
@ -86,6 +87,7 @@ describe('FTSParserSchema', ()=>{
|
||||
confirmOnCloseReset={false}
|
||||
hasSQL={false}
|
||||
disableSqlHelp={false}
|
||||
disableDialogHelp={false}
|
||||
/>);
|
||||
});
|
||||
|
||||
|
@ -64,6 +64,7 @@ describe('FTSTemplateSchema', ()=>{
|
||||
confirmOnCloseReset={false}
|
||||
hasSQL={false}
|
||||
disableSqlHelp={false}
|
||||
disableDialogHelp={false}
|
||||
/>);
|
||||
});
|
||||
|
||||
@ -83,6 +84,7 @@ describe('FTSTemplateSchema', ()=>{
|
||||
confirmOnCloseReset={false}
|
||||
hasSQL={false}
|
||||
disableSqlHelp={false}
|
||||
disableDialogHelp={false}
|
||||
/>);
|
||||
});
|
||||
|
||||
|
@ -75,6 +75,7 @@ describe('LanguageSchema', ()=>{
|
||||
confirmOnCloseReset={false}
|
||||
hasSQL={false}
|
||||
disableSqlHelp={false}
|
||||
disableDialogHelp={false}
|
||||
/>);
|
||||
});
|
||||
|
||||
@ -94,6 +95,7 @@ describe('LanguageSchema', ()=>{
|
||||
confirmOnCloseReset={false}
|
||||
hasSQL={false}
|
||||
disableSqlHelp={false}
|
||||
disableDialogHelp={false}
|
||||
/>);
|
||||
});
|
||||
|
||||
|
@ -74,6 +74,7 @@ describe('MaterializedViewSchema', ()=>{
|
||||
confirmOnCloseReset={false}
|
||||
hasSQL={false}
|
||||
disableSqlHelp={false}
|
||||
disableDialogHelp={false}
|
||||
/>);
|
||||
});
|
||||
|
||||
@ -93,6 +94,7 @@ describe('MaterializedViewSchema', ()=>{
|
||||
confirmOnCloseReset={false}
|
||||
hasSQL={false}
|
||||
disableSqlHelp={false}
|
||||
disableDialogHelp={false}
|
||||
/>);
|
||||
});
|
||||
|
||||
|
@ -63,6 +63,7 @@ describe('PrivilegeSchema', ()=>{
|
||||
confirmOnCloseReset={false}
|
||||
hasSQL={false}
|
||||
disableSqlHelp={false}
|
||||
disableDialogHelp={false}
|
||||
/>);
|
||||
});
|
||||
|
||||
@ -82,6 +83,7 @@ describe('PrivilegeSchema', ()=>{
|
||||
confirmOnCloseReset={false}
|
||||
hasSQL={false}
|
||||
disableSqlHelp={false}
|
||||
disableDialogHelp={false}
|
||||
/>);
|
||||
});
|
||||
|
||||
@ -123,6 +125,7 @@ describe('PrivilegeSchema', ()=>{
|
||||
confirmOnCloseReset={false}
|
||||
hasSQL={false}
|
||||
disableSqlHelp={false}
|
||||
disableDialogHelp={false}
|
||||
/>);
|
||||
/* Make sure you hit every corner */
|
||||
ctrl.find('DataGridView').at(0).find('PgIconButton[data-test="add-row"]').find('button').simulate('click');
|
||||
|
@ -70,6 +70,7 @@ describe('PublicationSchema', ()=>{
|
||||
confirmOnCloseReset={false}
|
||||
hasSQL={false}
|
||||
disableSqlHelp={false}
|
||||
disableDialogHelp={false}
|
||||
/>);
|
||||
});
|
||||
|
||||
@ -89,6 +90,7 @@ describe('PublicationSchema', ()=>{
|
||||
confirmOnCloseReset={false}
|
||||
hasSQL={false}
|
||||
disableSqlHelp={false}
|
||||
disableDialogHelp={false}
|
||||
/>);
|
||||
});
|
||||
|
||||
|
@ -54,6 +54,7 @@ describe('ResourceGroupSchema', ()=>{
|
||||
confirmOnCloseReset={false}
|
||||
hasSQL={false}
|
||||
disableSqlHelp={false}
|
||||
disableDialogHelp={false}
|
||||
/>);
|
||||
});
|
||||
|
||||
@ -73,6 +74,7 @@ describe('ResourceGroupSchema', ()=>{
|
||||
confirmOnCloseReset={false}
|
||||
hasSQL={false}
|
||||
disableSqlHelp={false}
|
||||
disableDialogHelp={false}
|
||||
/>);
|
||||
});
|
||||
|
||||
|
114
web/regression/javascript/schema_ui_files/schema.ui.spec.js
Normal file
114
web/regression/javascript/schema_ui_files/schema.ui.spec.js
Normal file
@ -0,0 +1,114 @@
|
||||
/////////////////////////////////////////////////////////////
|
||||
//
|
||||
// pgAdmin 4 - PostgreSQL Tools
|
||||
//
|
||||
// Copyright (C) 2013 - 2021, The pgAdmin Development Team
|
||||
// This software is released under the PostgreSQL Licence
|
||||
//
|
||||
//////////////////////////////////////////////////////////////
|
||||
|
||||
import jasmineEnzyme from 'jasmine-enzyme';
|
||||
import React from 'react';
|
||||
import '../helper/enzyme.helper';
|
||||
import { createMount } from '@material-ui/core/test-utils';
|
||||
import pgAdmin from 'sources/pgadmin';
|
||||
import {messages} from '../fake_messages';
|
||||
import SchemaView from '../../../pgadmin/static/js/SchemaView';
|
||||
import {getNodePrivilegeRoleSchema} from '../../../pgadmin/browser/server_groups/servers/static/js/privilege.ui';
|
||||
import PGSchema from '../../../pgadmin/browser/server_groups/servers/databases/schemas/static/js/schema.ui';
|
||||
|
||||
|
||||
describe('PGSchema', ()=>{
|
||||
let mount;
|
||||
let schemaObj = new PGSchema(
|
||||
()=>getNodePrivilegeRoleSchema({}, {server: {user: {name: 'postgres'}}}, {}),
|
||||
{
|
||||
roles:() => [],
|
||||
namespaceowner: '',
|
||||
}
|
||||
);
|
||||
let getInitData = ()=>Promise.resolve({});
|
||||
|
||||
/* Use createMount so that material ui components gets the required context */
|
||||
/* https://material-ui.com/guides/testing/#api */
|
||||
beforeAll(()=>{
|
||||
mount = createMount();
|
||||
});
|
||||
|
||||
afterAll(() => {
|
||||
mount.cleanUp();
|
||||
});
|
||||
|
||||
beforeEach(()=>{
|
||||
jasmineEnzyme();
|
||||
/* messages used by validators */
|
||||
pgAdmin.Browser = pgAdmin.Browser || {};
|
||||
pgAdmin.Browser.messages = pgAdmin.Browser.messages || messages;
|
||||
pgAdmin.Browser.utils = pgAdmin.Browser.utils || {};
|
||||
});
|
||||
|
||||
it('create', ()=>{
|
||||
mount(<SchemaView
|
||||
formType='dialog'
|
||||
schema={schemaObj}
|
||||
viewHelperProps={{
|
||||
mode: 'create',
|
||||
}}
|
||||
onSave={()=>{}}
|
||||
onClose={()=>{}}
|
||||
onHelp={()=>{}}
|
||||
onEdit={()=>{}}
|
||||
onDataChange={()=>{}}
|
||||
confirmOnCloseReset={false}
|
||||
hasSQL={false}
|
||||
disableSqlHelp={false}
|
||||
disableDialogHelp={false}
|
||||
/>);
|
||||
});
|
||||
|
||||
it('schema validate', () => {
|
||||
let state = { name: 'abc' };
|
||||
let setError = jasmine.createSpy('setError');
|
||||
|
||||
schemaObj.validate(state, setError);
|
||||
expect(setError).toHaveBeenCalledWith('namespaceowner', 'Owner cannot be empty.');
|
||||
|
||||
state.namespaceowner = 'postgres';
|
||||
let validate = schemaObj.validate(state, setError);
|
||||
expect(validate).toBe(null);
|
||||
});
|
||||
|
||||
it('edit', ()=>{
|
||||
mount(<SchemaView
|
||||
formType='dialog'
|
||||
schema={schemaObj}
|
||||
getInitData={getInitData}
|
||||
viewHelperProps={{
|
||||
mode: 'create',
|
||||
}}
|
||||
onSave={()=>{}}
|
||||
onClose={()=>{}}
|
||||
onHelp={()=>{}}
|
||||
onEdit={()=>{}}
|
||||
onDataChange={()=>{}}
|
||||
confirmOnCloseReset={false}
|
||||
hasSQL={false}
|
||||
disableSqlHelp={false}
|
||||
disableDialogHelp={false}
|
||||
/>);
|
||||
});
|
||||
|
||||
it('properties', ()=>{
|
||||
mount(<SchemaView
|
||||
formType='tab'
|
||||
schema={schemaObj}
|
||||
getInitData={getInitData}
|
||||
viewHelperProps={{
|
||||
mode: 'properties',
|
||||
}}
|
||||
onHelp={()=>{}}
|
||||
onEdit={()=>{}}
|
||||
/>);
|
||||
});
|
||||
});
|
||||
|
@ -70,6 +70,7 @@ describe('SequenceSchema', ()=>{
|
||||
confirmOnCloseReset={false}
|
||||
hasSQL={false}
|
||||
disableSqlHelp={false}
|
||||
disableDialogHelp={false}
|
||||
/>);
|
||||
});
|
||||
|
||||
@ -89,6 +90,7 @@ describe('SequenceSchema', ()=>{
|
||||
confirmOnCloseReset={false}
|
||||
hasSQL={false}
|
||||
disableSqlHelp={false}
|
||||
disableDialogHelp={false}
|
||||
/>);
|
||||
});
|
||||
|
||||
|
@ -59,6 +59,7 @@ describe('ServerSchema', ()=>{
|
||||
confirmOnCloseReset={false}
|
||||
hasSQL={false}
|
||||
disableSqlHelp={false}
|
||||
disableDialogHelp={false}
|
||||
/>);
|
||||
});
|
||||
|
||||
@ -78,6 +79,7 @@ describe('ServerSchema', ()=>{
|
||||
confirmOnCloseReset={false}
|
||||
hasSQL={false}
|
||||
disableSqlHelp={false}
|
||||
disableDialogHelp={false}
|
||||
/>);
|
||||
});
|
||||
|
||||
|
@ -53,6 +53,7 @@ describe('ServerGroupSchema', ()=>{
|
||||
confirmOnCloseReset={false}
|
||||
hasSQL={false}
|
||||
disableSqlHelp={false}
|
||||
disableDialogHelp={false}
|
||||
/>);
|
||||
});
|
||||
|
||||
@ -72,6 +73,7 @@ describe('ServerGroupSchema', ()=>{
|
||||
confirmOnCloseReset={false}
|
||||
hasSQL={false}
|
||||
disableSqlHelp={false}
|
||||
disableDialogHelp={false}
|
||||
/>);
|
||||
});
|
||||
|
||||
|
@ -67,6 +67,7 @@ describe('SynonymSchema', ()=>{
|
||||
confirmOnCloseReset={false}
|
||||
hasSQL={false}
|
||||
disableSqlHelp={false}
|
||||
disableDialogHelp={false}
|
||||
/>);
|
||||
});
|
||||
|
||||
@ -86,6 +87,7 @@ describe('SynonymSchema', ()=>{
|
||||
confirmOnCloseReset={false}
|
||||
hasSQL={false}
|
||||
disableSqlHelp={false}
|
||||
disableDialogHelp={false}
|
||||
/>);
|
||||
});
|
||||
|
||||
|
@ -70,6 +70,7 @@ describe('TablespaceSchema', ()=>{
|
||||
confirmOnCloseReset={false}
|
||||
hasSQL={false}
|
||||
disableSqlHelp={false}
|
||||
disableDialogHelp={false}
|
||||
/>);
|
||||
});
|
||||
|
||||
@ -89,6 +90,7 @@ describe('TablespaceSchema', ()=>{
|
||||
confirmOnCloseReset={false}
|
||||
hasSQL={false}
|
||||
disableSqlHelp={false}
|
||||
disableDialogHelp={false}
|
||||
/>);
|
||||
});
|
||||
|
||||
|
@ -73,6 +73,7 @@ describe('TypeSchema', ()=>{
|
||||
confirmOnCloseReset={false}
|
||||
hasSQL={false}
|
||||
disableSqlHelp={false}
|
||||
disableDialogHelp={false}
|
||||
/>);
|
||||
|
||||
mount(<SchemaView
|
||||
@ -90,6 +91,7 @@ describe('TypeSchema', ()=>{
|
||||
confirmOnCloseReset={false}
|
||||
hasSQL={false}
|
||||
disableSqlHelp={false}
|
||||
disableDialogHelp={false}
|
||||
/>);
|
||||
});
|
||||
|
||||
@ -180,6 +182,7 @@ describe('TypeSchema', ()=>{
|
||||
confirmOnCloseReset={false}
|
||||
hasSQL={false}
|
||||
disableSqlHelp={false}
|
||||
disableDialogHelp={false}
|
||||
/>);
|
||||
|
||||
mount(<SchemaView
|
||||
@ -197,6 +200,7 @@ describe('TypeSchema', ()=>{
|
||||
confirmOnCloseReset={false}
|
||||
hasSQL={false}
|
||||
disableSqlHelp={false}
|
||||
disableDialogHelp={false}
|
||||
/>);
|
||||
});
|
||||
});
|
||||
@ -225,6 +229,7 @@ describe('TypeSchema', ()=>{
|
||||
confirmOnCloseReset={false}
|
||||
hasSQL={false}
|
||||
disableSqlHelp={false}
|
||||
disableDialogHelp={false}
|
||||
/>);
|
||||
|
||||
mount(<SchemaView
|
||||
@ -242,6 +247,7 @@ describe('TypeSchema', ()=>{
|
||||
confirmOnCloseReset={false}
|
||||
hasSQL={false}
|
||||
disableSqlHelp={false}
|
||||
disableDialogHelp={false}
|
||||
/>);
|
||||
});
|
||||
|
||||
@ -285,6 +291,7 @@ describe('TypeSchema', ()=>{
|
||||
confirmOnCloseReset={false}
|
||||
hasSQL={false}
|
||||
disableSqlHelp={false}
|
||||
disableDialogHelp={false}
|
||||
/>);
|
||||
|
||||
mount(<SchemaView
|
||||
@ -302,6 +309,7 @@ describe('TypeSchema', ()=>{
|
||||
confirmOnCloseReset={false}
|
||||
hasSQL={false}
|
||||
disableSqlHelp={false}
|
||||
disableDialogHelp={false}
|
||||
/>);
|
||||
});
|
||||
|
||||
@ -337,6 +345,7 @@ describe('TypeSchema', ()=>{
|
||||
confirmOnCloseReset={false}
|
||||
hasSQL={false}
|
||||
disableSqlHelp={false}
|
||||
disableDialogHelp={false}
|
||||
/>);
|
||||
|
||||
mount(<SchemaView
|
||||
@ -354,6 +363,7 @@ describe('TypeSchema', ()=>{
|
||||
confirmOnCloseReset={false}
|
||||
hasSQL={false}
|
||||
disableSqlHelp={false}
|
||||
disableDialogHelp={false}
|
||||
/>);
|
||||
});
|
||||
|
||||
@ -420,6 +430,7 @@ describe('TypeSchema', ()=>{
|
||||
confirmOnCloseReset={false}
|
||||
hasSQL={false}
|
||||
disableSqlHelp={false}
|
||||
disableDialogHelp={false}
|
||||
/>);
|
||||
});
|
||||
|
||||
@ -439,6 +450,7 @@ describe('TypeSchema', ()=>{
|
||||
confirmOnCloseReset={false}
|
||||
hasSQL={false}
|
||||
disableSqlHelp={false}
|
||||
disableDialogHelp={false}
|
||||
/>);
|
||||
});
|
||||
|
||||
|
@ -69,6 +69,7 @@ describe('UserMappingSchema', ()=>{
|
||||
confirmOnCloseReset={false}
|
||||
hasSQL={false}
|
||||
disableSqlHelp={false}
|
||||
disableDialogHelp={false}
|
||||
/>);
|
||||
});
|
||||
|
||||
@ -88,6 +89,7 @@ describe('UserMappingSchema', ()=>{
|
||||
confirmOnCloseReset={false}
|
||||
hasSQL={false}
|
||||
disableSqlHelp={false}
|
||||
disableDialogHelp={false}
|
||||
/>);
|
||||
});
|
||||
|
||||
|
@ -82,6 +82,7 @@ describe('VariableSchema', ()=>{
|
||||
confirmOnCloseReset={false}
|
||||
hasSQL={false}
|
||||
disableSqlHelp={false}
|
||||
disableDialogHelp={false}
|
||||
/>);
|
||||
});
|
||||
|
||||
@ -101,6 +102,7 @@ describe('VariableSchema', ()=>{
|
||||
confirmOnCloseReset={false}
|
||||
hasSQL={false}
|
||||
disableSqlHelp={false}
|
||||
disableDialogHelp={false}
|
||||
/>);
|
||||
});
|
||||
|
||||
@ -146,6 +148,7 @@ describe('VariableSchema', ()=>{
|
||||
confirmOnCloseReset={false}
|
||||
hasSQL={false}
|
||||
disableSqlHelp={false}
|
||||
disableDialogHelp={false}
|
||||
/>);
|
||||
/* Make sure you hit every corner */
|
||||
ctrl.find('DataGridView').at(0).find('PgIconButton[data-test="add-row"]').find('button').simulate('click');
|
||||
|
@ -73,6 +73,7 @@ describe('ViewSchema', ()=>{
|
||||
confirmOnCloseReset={false}
|
||||
hasSQL={false}
|
||||
disableSqlHelp={false}
|
||||
disableDialogHelp={false}
|
||||
/>);
|
||||
});
|
||||
|
||||
@ -92,6 +93,7 @@ describe('ViewSchema', ()=>{
|
||||
confirmOnCloseReset={false}
|
||||
hasSQL={false}
|
||||
disableSqlHelp={false}
|
||||
disableDialogHelp={false}
|
||||
/>);
|
||||
});
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user