Use Row Editors for grid editing

git-svn-id: svn://10.0.0.236/trunk@258490 18797224-902f-48f8-a5cc-f745e15eee43
This commit is contained in:
ghendricks%novell.com 2009-09-24 19:44:57 +00:00
parent 45f37e1f93
commit 959f5501d5
22 changed files with 288 additions and 320 deletions

View File

@ -37,7 +37,7 @@ Testopia.Attachment.Grid = function(object){
},
id: 'attach_id',
fields: [{
name: "id",
name: "attach_id",
mapping: "attachment_id"
}, {
name: "submitter",
@ -46,7 +46,7 @@ Testopia.Attachment.Grid = function(object){
name: "caserun_id",
mapping: "caserun_id"
}, {
name: "name",
name: "filename",
mapping: "filename"
}, //editable
{
@ -80,7 +80,7 @@ Testopia.Attachment.Grid = function(object){
header: "ID",
width: 20,
sortable: true,
dataIndex: 'id',
dataIndex: 'attach_id',
renderer: attachlink
}, {
header: "Created",
@ -98,7 +98,9 @@ Testopia.Attachment.Grid = function(object){
}, {
header: "Name",
width: 50,
editor: new Ext.grid.GridEditor(new Ext.form.TextField({})),
editor: {
xtype: 'textfield'
},
sortable: true,
dataIndex: 'name'
}, {
@ -109,15 +111,18 @@ Testopia.Attachment.Grid = function(object){
}, {
header: "Type",
width: 30,
editor: new Ext.grid.GridEditor(new Ext.form.TextField({})),
editor: {
xtype: 'textfield'
},
sortable: true,
dataIndex: 'mimetype'
}, {
header: "Description",
width: 120,
editor: new Ext.grid.GridEditor(new Ext.form.TextField({
editor: {
xtype: 'textfield',
value: 'description'
})),
},
sortable: true,
dataIndex: 'description'
}, {
@ -140,8 +145,12 @@ Testopia.Attachment.Grid = function(object){
},
autoExpandColumn: "Name",
autoScroll: true,
plugins: [new Ext.ux.grid.RowEditor({
id:'attachment_row_editor',
saveText: 'Update'
})],
enableColumnHide: true,
tbar: [new Ext.Toolbar.Fill(), {
tbar: ['->', {
xtype: 'button',
id: 'edit_attachment_btn',
icon: 'extensions/testopia/img/edit.png',
@ -192,16 +201,17 @@ Testopia.Attachment.Grid = function(object){
});
this.on('rowcontextmenu', this.onContextClick, this);
this.on('activate', this.onActivate, this);
this.on('afteredit', this.onGridEdit, this);
Ext.getCmp('attachment_row_editor').on('afteredit', this.onGridEdit, this);
};
Ext.extend(Testopia.Attachment.Grid, Ext.grid.EditorGridPanel, {
Ext.extend(Testopia.Attachment.Grid, Ext.grid.GridPanel, {
onContextClick: function(grid, index, e){
var sm = this.selectionModel;
var object = this.object;
if (!this.menu) { // create context menu on first right click
this.menu = new Ext.menu.Menu({
id: 'AttachGrid-ctx-menu',
enableScrolling: false,
items: [{
text: "Delete Selected Attachments",
id: 'attach_delete_mnu',
@ -229,25 +239,11 @@ Ext.extend(Testopia.Attachment.Grid, Ext.grid.EditorGridPanel, {
}
this.menu.showAt(e.getXY());
},
onGridEdit: function(gevent){
var myparams = {
action: "edit",
ctype: "json",
attach_id: this.store.getAt(gevent.row).get('id')
};
onGridEdit: function(e){
var myparams = e.record.data;
var ds = this.store;
switch (gevent.field) {
case 'name':
myparams.filename = gevent.value;
break;
case 'mime_type':
myparams.mime_type = gevent.value;
break;
case 'description':
myparams.description = gevent.value;
break;
}
myparams.ctype = 'json';
myparams.action = 'edit';
this.form.submit({
url: "tr_attachment.cgi",
params: myparams,

View File

@ -30,7 +30,7 @@ Testopia.Build.Store = function(params, auto){
id: 'build_id',
autoLoad: auto,
fields: [{
name: "id",
name: "build_id",
mapping: "build_id"
}, {
name: "name",
@ -62,7 +62,7 @@ Testopia.Build.Combo = function(cfg){
store: cfg.transform ? false : new Testopia.Build.Store(cfg.params, cfg.mode == 'local' ? true : false),
loadingText: 'Looking up builds...',
displayField: 'name',
valueField: 'id',
valueField: 'build_id',
typeAhead: true,
triggerAction: 'all',
minListWidth: 300,
@ -87,6 +87,15 @@ Testopia.Build.Grid = function(product_id){
mode: 'remote',
params: {
product_id: product_id
},
listeners: {
'startedit': function(){
var pid = Ext.getCmp('products_pane').getSelectionModel().getSelectedNode().id;
if (mbox.store.baseParams.product_id != pid) {
mbox.store.baseParams.product_id = pid;
mbox.store.load();
}
}
}
});
this.columns = [{
@ -94,49 +103,38 @@ Testopia.Build.Grid = function(product_id){
width: 80,
sortable: true,
dataIndex: 'name',
editor: new Ext.grid.GridEditor(new Ext.form.TextField({
editor: {
xtype: 'textfield',
value: 'name',
allowBlank: false
}), {
completeOnEnter: true,
listeners: {
'beforecomplete': function(e, v){
if (!e.getValue()) {
return false;
}
}
}
})
}
}, {
header: "Description",
width: 120,
editor: {
xtype: 'textfield'
},
sortable: true,
dataIndex: 'description'
}, {
header: "Milestone",
width: 120,
sortable: true,
dataIndex: 'milestone',
editor: new Ext.grid.GridEditor(mbox, {
listeners: {
'startedit': function(){
var pid = Ext.getCmp('products_pane').getSelectionModel().getSelectedNode().id;
if (mbox.store.baseParams.product_id != pid) {
mbox.store.baseParams.product_id = pid;
mbox.store.load();
}
}
}
})
editor: mbox
}, {
header: "Description",
width: 120,
editor: new Ext.grid.GridEditor(new Ext.form.TextField()),
sortable: true,
dataIndex: 'description'
}, new Ext.grid.CheckColumn({
header: 'Active',
dataIndex: 'isactive',
editor: new Ext.grid.GridEditor(new Ext.form.Checkbox({
trueText: 'Yes',
falseText: 'No',
sortable: true,
xtype: 'booleancolumn',
editor:{
xtype: 'checkbox',
value: 'isactive'
})),
},
width: 25
})];
}];
this.form = new Ext.form.BasicForm('testopia_helper_frm');
@ -148,6 +146,10 @@ Testopia.Build.Grid = function(product_id){
},
autoExpandColumn: "build_name",
autoScroll: true,
plugins: [new Ext.ux.grid.RowEditor({
id:'build_row_editor',
saveText: 'Update'
})],
sm: new Ext.grid.RowSelectionModel({
singleSelect: true
}),
@ -174,9 +176,9 @@ Testopia.Build.Grid = function(product_id){
});
this.on('rowcontextmenu', this.onContextClick, this);
this.on('activate', this.onActivate, this);
this.on('afteredit', this.onGridEdit, this);
Ext.getCmp('build_row_editor').on('afteredit', this.onGridEdit, this);
};
Ext.extend(Testopia.Build.Grid, Ext.grid.EditorGridPanel, {
Ext.extend(Testopia.Build.Grid, Ext.grid.GridPanel, {
newRecord: function(){
NewBuild = Ext.data.Record.create([{
name: 'name',
@ -198,15 +200,17 @@ Ext.extend(Testopia.Build.Grid, Ext.grid.EditorGridPanel, {
});
var g = Ext.getCmp('build_grid');
g.store.insert(0, b);
g.startEditing(0, 0);
Ext.getCmp('build_row_editor').startEditing(0);
},
onContextClick: function(grid, index, e){
grid.getSelectionModel().selectRow(index);
if (!this.menu) { // create context menu on first right click
this.menu = new Ext.menu.Menu({
id: 'build-ctx-menu',
enableScrolling: false,
items: [{
text: "Reports",
enableScrolling: false,
menu: {
items: [{
text: 'New Completion Report',
@ -255,42 +259,21 @@ Ext.extend(Testopia.Build.Grid, Ext.grid.EditorGridPanel, {
this.menu.showAt(e.getXY());
},
onGridEdit: function(e){
var bid = e.record.get('id');
var myparams = {
product_id: this.product_id,
build_id: bid
};
var myparams = e.record.data;
var ds = this.store;
if (bid) {
myparams.product_id = this.product_id;
if (myparams.build_id) {
myparams.action = "edit";
switch (e.field) {
case 'name':
myparams.name = e.value;
break;
case 'description':
myparams.description = e.value;
break;
case 'isactive':
myparams.isactive = e.value;
break;
case 'milestone':
myparams.milestone = e.value;
break;
}
}
else {
myparams.action = "add";
myparams.name = e.value;
myparams.milestone = Ext.getCmp('products_pane').getSelectionModel().getSelectedNode().attributes.attributes.defaultmilestone;
myparams.isactive = 1;
}
this.form.submit({
url: "tr_builds.cgi",
params: myparams,
success: function(f, a){
if (a.result.build_id) {
e.record.set('id', a.result.build_id);
e.record.set('build_id', a.result.build_id);
}
ds.commitChanges();
},

View File

@ -274,11 +274,23 @@ Testopia.TestCase.Grid = function(params, cfg){
params.limit = Ext.state.Manager.get('TESTOPIA_DEFAULT_PAGE_SIZE', 25);
params.current_tab = 'case';
this.params = params;
categoryCombo = new Testopia.Category.Combo({
var categoryCombo = new Testopia.Category.Combo({
id: 'case_grid_cateogy_chooser',
hiddenName: 'category',
mode: 'remote',
params: {}
params: {
product_id: params.product_id
},
listeners: {
'startedit': function(){
var pid = Ext.getCmp(cfg.id || 'case_grid').getSelectionModel().getSelected().get('product_id');
if (categoryCombo.store.baseParams.product_id != pid) {
categoryCombo.store.baseParams.product_id = pid;
categoryCombo.store.load();
}
}
}
});
this.store = new Ext.data.GroupingStore({
@ -379,11 +391,12 @@ Testopia.TestCase.Grid = function(params, cfg){
width: 50,
sortable: true,
dataIndex: 'sortkey',
editor: new Ext.grid.GridEditor(new Ext.form.NumberField({
editor: {
xtype: 'numberfield',
allowBlank: true,
allowDecimals: false,
allowNegative: false
})),
},
id: "sortkey"
}, {
header: "Summary",
@ -391,9 +404,10 @@ Testopia.TestCase.Grid = function(params, cfg){
dataIndex: 'summary',
id: "case_summary",
sortable: true,
editor: new Ext.grid.GridEditor(new Ext.form.TextField({
editor: {
xtype: 'textfield',
allowBlank: false
}))
}
}, {
header: "Author",
width: 150,
@ -405,9 +419,9 @@ Testopia.TestCase.Grid = function(params, cfg){
width: 150,
sortable: true,
dataIndex: 'tester',
editor: new Ext.grid.GridEditor(new Testopia.User.Lookup({
editor: new Testopia.User.Lookup({
hiddenName: 'tester'
})),
}),
renderer: Testopia.Util.ComboRenderer.createDelegate(this)
}, {
header: "Created",
@ -426,27 +440,17 @@ Testopia.TestCase.Grid = function(params, cfg){
width: 100,
sortable: true,
dataIndex: 'priority',
editor: new Ext.grid.GridEditor(new Testopia.TestCase.PriorityCombo({
editor: new Testopia.TestCase.PriorityCombo({
hiddenName: 'priority',
mode: 'remote'
})),
}),
renderer: Testopia.Util.ComboRenderer.createDelegate(this)
}, {
header: "Category",
width: 100,
sortable: true,
dataIndex: 'category',
editor: new Ext.grid.GridEditor(categoryCombo, {
listeners: {
'startedit': function(){
var pid = Ext.getCmp(cfg.id || 'case_grid').getSelectionModel().getSelected().get('product_id');
if (categoryCombo.store.baseParams.product_id != pid) {
categoryCombo.store.baseParams.product_id = pid;
categoryCombo.store.load();
}
}
}
}),
editor: categoryCombo,
renderer: Testopia.Util.ComboRenderer.createDelegate(this)
}, {
header: "Component",
@ -458,7 +462,7 @@ Testopia.TestCase.Grid = function(params, cfg){
width: 100,
sortable: true,
dataIndex: 'status',
editor: new Ext.grid.GridEditor(new Testopia.TestCase.StatusListCombo('status')),
editor: new Testopia.TestCase.StatusListCombo('status'),
renderer: Testopia.Util.ComboRenderer.createDelegate(this)
}, {
header: "Requirement",
@ -466,14 +470,18 @@ Testopia.TestCase.Grid = function(params, cfg){
sortable: true,
dataIndex: 'requirement',
hidden: true,
editor: new Ext.grid.GridEditor(new Ext.form.TextField({
editor: {
xtype: 'textfield',
name: 'requirement'
}))
}
}, {
header: "Estimated Time",
width: 60,
sortable: true,
dataIndex: 'estimated_time',
editor: {
xtype: 'textfield'
},
hidden: true
}, {
header: "Average Time",
@ -516,6 +524,10 @@ Testopia.TestCase.Grid = function(params, cfg){
region: 'center',
autoExpandColumn: "case_summary",
autoScroll: true,
plugins: [new Ext.ux.grid.RowEditor({
id:'case_row_editor',
saveText: 'Update'
})],
sm: new Ext.grid.RowSelectionModel({
singleSelect: false,
listeners: {
@ -615,10 +627,10 @@ Testopia.TestCase.Grid = function(params, cfg){
this.on('activate', this.onActivate, this);
this.on('rowcontextmenu', this.onContextClick, this);
this.on('afteredit', this.onGridEdit, this);
Ext.getCmp('case_row_editor').on('afteredit', this.onGridEdit, this);
};
Ext.extend(Testopia.TestCase.Grid, Ext.grid.EditorGridPanel, {
Ext.extend(Testopia.TestCase.Grid, Ext.grid.GridPanel, {
onContextClick: function(grid, index, e){
grid.selindex = index;
if (!this.menu) { // create context menu on first right click
@ -632,11 +644,13 @@ Ext.extend(Testopia.TestCase.Grid, Ext.grid.EditorGridPanel, {
this.menu = new Ext.menu.Menu({
id: 'case_list_ctx_menu',
enableScrolling: false,
items: [{
text: 'Modify Selected Test Cases',
icon: 'extensions/testopia/img/edit.png',
iconCls: 'img_button_16x',
menu: {
enableScrolling: false,
items: [{
text: 'Requirements',
handler: function(){
@ -965,44 +979,27 @@ Ext.extend(Testopia.TestCase.Grid, Ext.grid.EditorGridPanel, {
}
this.menu.showAt(e.getXY());
},
onGridEdit: function(gevent){
var myparams = {
action: "edit",
case_id: gevent.record.get('case_id')
};
onGridEdit: function(e){
var ds = this.store;
var display_value = '';
switch (gevent.field) {
case 'sortkey':
myparams.sortkey = gevent.value;
break;
case 'summary':
myparams.summary = gevent.value;
break;
case 'tester':
myparams.tester = gevent.value;
break;
case 'priority':
myparams.priority = gevent.value;
break;
case 'status':
myparams.status = gevent.value;
break;
case 'category':
myparams.category = gevent.value;
break;
case 'requirement':
myparams.requirement = gevent.value;
break;
var myparams = e.record.data;
myparams.action = 'edit';
var tester;
if (!myparams.tester.match('@')){
tester = myparams.tester;
delete myparams.tester;
}
this.form.submit({
url: "tr_process_case.cgi",
params: myparams,
success: function(f, a){
if (tester)
myparams.tester = tester;
ds.commitChanges();
},
failure: function(f, a){
Testopia.Util.error(f, a);
if (tester)
myparams.tester = tester;
ds.rejectChanges();
}
});
@ -1293,7 +1290,7 @@ Testopia.TestCase.NewCaseForm = function(plan_ids, product_id, run_id){
sm: new Ext.grid.RowSelectionModel({
singleSelect: false
}),
tbar: [new Ext.menu.TextItem('Product'), new Ext.Toolbar.Spacer(), new Testopia.Product.Combo({
tbar: ['Product', ' ', new Testopia.Product.Combo({
mode: 'local',
value: product_id,
id: 'comp_product_combo'
@ -1734,10 +1731,6 @@ Testopia.TestCase.clonePopup = function(product_id, cases){
});
win.show(this);
var items = pg.getTopToolbar().items.items;
for (var i = 0; i < items.length; i++) {
items[i].destroy();
}
var pchooser = new Testopia.Product.Combo({
id: 'case_clone_win_product_chooser',
mode: 'local',
@ -1757,7 +1750,8 @@ Testopia.TestCase.clonePopup = function(product_id, cases){
Ext.getCmp('case_clone_product_id').setValue(r.get('id'));
pg.store.load();
});
pg.getTopToolbar().add(new Ext.menu.TextItem('Product: '), pchooser);
pg.getTopToolbar().removeAll();
pg.getTopToolbar().add('Product: ', pchooser);
pg.getSelectionModel().un('rowselect', pg.getSelectionModel().events['rowselect'].listeners[0].fn);
pg.getSelectionModel().un('rowdeselect', pg.getSelectionModel().events['rowdeselect'].listeners[0].fn);
pg.store.load();

View File

@ -1691,7 +1691,7 @@ Testopia.TestCaseRun.Info = function(){
loadingText: 'Loading...',
tpl: new Ext.XTemplate('<tpl for=".">', '<div id="notesdiv" style="margin: 5px; padding: 5px; border: 1px solid black;"><pre>{notes}</pre></div>', '</tpl>', '<div class="x-clear"><input id="caserun_append_note_fld" ></div>')
}],
bbar: [new Ext.menu.TextItem('Add a Note: '), {
bbar: ['Add a Note: ', {
xtype: 'textfield',
id: 'caserun_append_note_fld',
width: 1000
@ -2063,7 +2063,7 @@ Testopia.TestCase.Bugs.Grid = function(id){
icon: 'extensions/testopia/img/delete.png',
iconCls: 'img_button_16x',
handler: removebug.createDelegate(this)
}, new Ext.Toolbar.Separator(), new Ext.menu.TextItem('This view includes all bugs attached to the selected test case regardless of run')],
}, '-', 'This view includes all bugs attached to the selected test case regardless of run'],
border: false,
title: 'Bugs',
id: 'case_bugs_panel',

View File

@ -77,26 +77,19 @@ Testopia.Category.Grid = function(product_id){
width: 120,
sortable: true,
dataIndex: 'name',
editor: new Ext.grid.GridEditor(new Ext.form.TextField({
editor: {
xtype: 'textfield',
value: 'name',
allowBlank: false
}), {
completeOnEnter: true,
listeners: {
'beforecomplete': function(e, v){
if (!e.getValue()) {
return false;
}
}
}
})
}
}, {
header: "Description",
width: 120,
id: 'category_desc_column',
editor: new Ext.grid.GridEditor(new Ext.form.TextField({
editor: {
xtype: 'textfield',
value: 'description'
})),
},
sortable: true,
dataIndex: 'description'
}];
@ -111,6 +104,10 @@ Testopia.Category.Grid = function(product_id){
},
autoExpandColumn: "category_desc_column",
autoScroll: true,
plugins: [new Ext.ux.grid.RowEditor({
id:'category_row_editor',
saveText: 'Update'
})],
enableColumnHide: true,
sm: new Ext.grid.RowSelectionModel({
singleSelect: true
@ -152,10 +149,10 @@ Testopia.Category.Grid = function(product_id){
});
this.on('rowcontextmenu', this.onContextClick, this);
this.on('activate', this.onActivate, this);
this.on('afteredit', this.onGridEdit, this);
Ext.getCmp('category_row_editor').on('afteredit', this.onGridEdit, this);
};
Ext.extend(Testopia.Category.Grid, Ext.grid.EditorGridPanel, {
Ext.extend(Testopia.Category.Grid, Ext.grid.GridPanel, {
newRecord: function(){
NewCategory = Ext.data.Record.create([{
name: 'name',
@ -170,13 +167,14 @@ Ext.extend(Testopia.Category.Grid, Ext.grid.EditorGridPanel, {
});
var g = Ext.getCmp('category_grid');
g.store.insert(0, b);
g.startEditing(0, 0);
Ext.getCmp('category_row_editor').startEditing(0);
},
onContextClick: function(grid, index, e){
grid.getSelectionModel().selectRow(index);
if (!this.menu) { // create context menu on first right click
this.menu = new Ext.menu.Menu({
id: 'category-ctx-menu',
enableScrolling: false,
items: [{
text: 'Add a Category',
icon: 'extensions/testopia/img/add.png',
@ -203,27 +201,14 @@ Ext.extend(Testopia.Category.Grid, Ext.grid.EditorGridPanel, {
this.menu.showAt(e.getXY());
},
onGridEdit: function(e){
var bid = e.record.get('category_id');
var myparams = {
product_id: this.product_id,
category_id: bid
};
var myparams = e.record.data;
var ds = this.store;
if (bid) {
myparams.product_id = this.product_id;
if (myparams.build_id) {
myparams.action = "edit";
switch (e.field) {
case 'name':
myparams.name = e.value;
break;
case 'description':
myparams.description = e.value;
break;
}
}
else {
myparams.action = "add";
myparams.name = e.value;
}
this.form.submit({
url: "tr_categories.cgi",

View File

@ -19,12 +19,13 @@
* Ryan Hamilton <rhamilton@novell.com>
* Daniel Parker <dparker1@novell.com>
*/
Testopia.Environment.Store = function(params, auto){
params.ctype = 'json';
Testopia.Environment.Store.superclass.constructor.call(this, {
url: 'tr_list_environments.cgi',
listeners: { 'exception': Testopia.Util.loadError },
listeners: {
'exception': Testopia.Util.loadError
},
root: 'Result',
baseParams: params,
totalProperty: 'totalResultsAvailable',
@ -142,6 +143,9 @@ Testopia.Environment.Grid = function(params, cfg){
},
autoExpandColumn: "env_name_col",
autoScroll: true,
plugins: [new Ext.ux.grid.RowEditor({
saveText: 'Update'
})],
sm: new Ext.grid.RowSelectionModel({
singleSelect: true,
listeners: {
@ -200,6 +204,7 @@ Ext.extend(Testopia.Environment.Grid, Ext.grid.EditorGridPanel, {
onContextClick: function(grid, index, e){
if (!this.menu) { // create context menu on first right click
this.menu = new Ext.menu.Menu({
enableScrolling: false,
id: 'run-ctx-menu',
items: [{
text: 'Create a new environment',

View File

@ -49,10 +49,10 @@ Testopia.TestPlan.Store = function(params, auto){
name: "product_id",
mapping: "product_id"
}, {
name: "default_product_version",
name: "prod_version",
mapping: "default_product_version"
}, {
name: "plan_type",
name: "type",
mapping: "plan_type"
}, {
name: "case_count",
@ -183,6 +183,15 @@ Testopia.TestPlan.Grid = function(params, cfg){
mode: 'remote',
params: {
product_id: params.product_id
},
listeners: {
'startedit': function(){
var pid = Ext.getCmp(cfg.id || 'plan_grid').getSelectionModel().getSelected().get('product_id');
if (versionbox.store.baseParams.product_id != pid) {
versionbox.store.baseParams.product_id = pid;
versionbox.store.load();
}
}
}
});
@ -202,9 +211,10 @@ Testopia.TestPlan.Grid = function(params, cfg){
dataIndex: 'name',
id: "plan_name",
sortable: true,
editor: new Ext.grid.GridEditor(new Ext.form.TextField({
editor: {
xtype: 'textfield',
allowBlank: false
}))
}
}, {
header: "Author",
width: 150,
@ -226,29 +236,19 @@ Testopia.TestPlan.Grid = function(params, cfg){
header: "Product Version",
width: 60,
sortable: true,
dataIndex: 'default_product_version',
editor: new Ext.grid.GridEditor(versionbox, {
listeners: {
'startedit': function(){
var pid = Ext.getCmp(cfg.id || 'plan_grid').getSelectionModel().getSelected().get('product_id');
if (versionbox.store.baseParams.product_id != pid) {
versionbox.store.baseParams.product_id = pid;
versionbox.store.load();
}
}
}
}),
dataIndex: 'prod_version',
editor: versionbox,
renderer: Testopia.Util.ComboRenderer.createDelegate(this)
}, {
header: "Type",
width: 60,
sortable: true,
dataIndex: 'plan_type',
editor: new Ext.grid.GridEditor(new Testopia.TestPlan.TypesCombo({
dataIndex: 'type',
editor: new Testopia.TestPlan.TypesCombo({
id: 'plan_grid_ types_chooser',
hiddenName: 'type',
mode: 'remote'
})),
}),
renderer: Testopia.Util.ComboRenderer.createDelegate(this)
}, {
header: "Cases",
@ -276,6 +276,10 @@ Testopia.TestPlan.Grid = function(params, cfg){
},
autoExpandColumn: "plan_name",
autoScroll: true,
plugins: [new Ext.ux.grid.RowEditor({
id:'plan_row_editor',
saveText: 'Update'
})],
sm: new Ext.grid.RowSelectionModel({
singleSelect: cfg.single || false,
listeners: {
@ -367,16 +371,17 @@ Testopia.TestPlan.Grid = function(params, cfg){
});
Ext.apply(this, cfg);
this.on('rowcontextmenu', this.onContextClick, this);
this.on('afteredit', this.onGridEdit, this);
this.on('activate', this.onActivate, this);
Ext.getCmp('plan_row_editor').on('afteredit', this.onGridEdit, this);
};
Ext.extend(Testopia.TestPlan.Grid, Ext.grid.EditorGridPanel, {
Ext.extend(Testopia.TestPlan.Grid, Ext.grid.GridPanel, {
onContextClick: function(grid, index, e){
grid.selindex = index;
if (!this.menu) { // create context menu on first right click
this.menu = new Ext.menu.Menu({
id: 'plan-ctx-menu',
enableScrolling: false,
items: [{
text: 'Create a New Test Plan',
id: 'plan_menu_new_plan',
@ -395,6 +400,7 @@ Ext.extend(Testopia.TestPlan.Grid, Ext.grid.EditorGridPanel, {
text: 'Edit',
id: 'plan_grid_edit_mnu',
menu: {
enableScrolling: false,
items: [{
text: 'Type',
handler: function(){
@ -444,6 +450,7 @@ Ext.extend(Testopia.TestPlan.Grid, Ext.grid.EditorGridPanel, {
}, {
text: "Reports",
menu: {
enableScrolling: false,
items: [{
text: 'New Status Report',
handler: function(){
@ -637,24 +644,10 @@ Ext.extend(Testopia.TestPlan.Grid, Ext.grid.EditorGridPanel, {
Testopia.TestCase.NewCasePopup(Testopia.Util.getSelectedObjects(this, 'plan_id'), this.getSelectionModel().getSelected().get('product_id'));
},
onGridEdit: function(gevent){
var myparams = {
action: "edit",
plan_id: gevent.record.get('plan_id')
};
onGridEdit: function(e){
var ds = this.store;
switch (gevent.field) {
case 'default_product_version':
myparams.prod_version = gevent.value;
break;
case 'plan_type':
myparams.type = gevent.value;
break;
case 'name':
myparams.name = gevent.value;
break;
}
var myparams = e.record.data;
myparams.action = 'edit';
this.form.submit({
url: "tr_process_plan.cgi",
params: myparams,

View File

@ -62,7 +62,7 @@ Testopia.TestRun.Grid = function(params, cfg){
name: "case_count",
mapping: "case_count"
}, {
name: "product_version",
name: "run_product_version",
mapping: "product_version"
}, {
name: "product_id",
@ -100,6 +100,15 @@ Testopia.TestRun.Grid = function(params, cfg){
params: {
product_id: params.product_id,
activeonly: 1
},
listeners: {
'startedit': function(){
var pid = Ext.getCmp(cfg.id || 'run_grid').getSelectionModel().getSelected().get('product_id');
if (bcombo.store.baseParams.product_id != pid) {
bcombo.store.baseParams.product_id = pid;
bcombo.store.load();
}
}
}
});
var ecombo = new Testopia.Environment.Combo({
@ -109,6 +118,15 @@ Testopia.TestRun.Grid = function(params, cfg){
params: {
product_id: params.product_id,
isactive: 1
},
listeners: {
'startedit': function(){
var pid = Ext.getCmp(cfg.id || 'run_grid').getSelectionModel().getSelected().get('product_id');
if (ecombo.store.baseParams.product_id != pid) {
ecombo.store.baseParams.product_id = pid;
ecombo.store.load();
}
}
}
});
var vcombo = new Testopia.Product.VersionCombo({
@ -117,6 +135,15 @@ Testopia.TestRun.Grid = function(params, cfg){
mode: 'remote',
params: {
product_id: params.product_id
},
listeners: {
'startedit': function(){
var pid = Ext.getCmp(cfg.id || 'run_grid').getSelectionModel().getSelected().get('product_id');
if (vcombo.store.baseParams.product_id != pid) {
vcombo.store.baseParams.product_id = pid;
vcombo.store.load();
}
}
}
});
@ -134,9 +161,10 @@ Testopia.TestRun.Grid = function(params, cfg){
dataIndex: "summary",
id: "run_name",
sortable: true,
editor: new Ext.grid.GridEditor(new Ext.form.TextField({
editor: {
xtype: 'textfield',
allowBlank: false
}))
}
}, {
header: "Manager Name",
width: 150,
@ -144,9 +172,9 @@ Testopia.TestRun.Grid = function(params, cfg){
id: "manager_name_col",
sortable: true,
hidden: true,
editor: new Ext.grid.GridEditor(new Testopia.User.Lookup({
editor: new Testopia.User.Lookup({
hiddenName: 'manager'
})),
}),
renderer: Testopia.Util.ComboRenderer.createDelegate(this)
}, {
header: "Start Date",
@ -166,17 +194,7 @@ Testopia.TestRun.Grid = function(params, cfg){
dataIndex: "build",
id: "build_col",
sortable: true,
editor: new Ext.grid.GridEditor(bcombo, {
listeners: {
'startedit': function(){
var pid = Ext.getCmp(cfg.id || 'run_grid').getSelectionModel().getSelected().get('product_id');
if (bcombo.store.baseParams.product_id != pid) {
bcombo.store.baseParams.product_id = pid;
bcombo.store.load();
}
}
}
}),
editor: bcombo,
renderer: Testopia.Util.ComboRenderer.createDelegate(this)
}, {
header: "Enviroment",
@ -184,17 +202,7 @@ Testopia.TestRun.Grid = function(params, cfg){
dataIndex: "environment",
id: "environment",
sortable: true,
editor: new Ext.grid.GridEditor(ecombo, {
listeners: {
'startedit': function(){
var pid = Ext.getCmp(cfg.id || 'run_grid').getSelectionModel().getSelected().get('product_id');
if (ecombo.store.baseParams.product_id != pid) {
ecombo.store.baseParams.product_id = pid;
ecombo.store.load();
}
}
}
}),
editor: ecombo,
renderer: Testopia.Util.ComboRenderer.createDelegate(this)
}, {
header: "Status",
@ -215,17 +223,7 @@ Testopia.TestRun.Grid = function(params, cfg){
id: "product_version",
sortable: true,
hidden: true,
editor: new Ext.grid.GridEditor(vcombo, {
listeners: {
'startedit': function(){
var pid = Ext.getCmp(cfg.id || 'run_grid').getSelectionModel().getSelected().get('product_id');
if (vcombo.store.baseParams.product_id != pid) {
vcombo.store.baseParams.product_id = pid;
vcombo.store.load();
}
}
}
}),
editor: vcombo,
renderer: Testopia.Util.ComboRenderer.createDelegate(this)
}, {
header: "Plan ID",
@ -270,6 +268,10 @@ Testopia.TestRun.Grid = function(params, cfg){
autoExpandColumn: "run_summary",
autoScroll: true,
stripeRows: true,
plugins: [new Ext.ux.grid.RowEditor({
id:'run_row_editor',
saveText: 'Update'
})],
sm: new Ext.grid.RowSelectionModel({
singleSelect: false,
listeners: {
@ -356,19 +358,21 @@ Testopia.TestRun.Grid = function(params, cfg){
Ext.apply(this, cfg);
this.on('rowcontextmenu', this.onContextClick, this);
this.on('afteredit', this.onGridEdit, this);
this.on('activate', this.onActivate, this);
Ext.getCmp('run_row_editor').on('afteredit', this.onGridEdit, this);
};
Ext.extend(Testopia.TestRun.Grid, Ext.grid.EditorGridPanel, {
Ext.extend(Testopia.TestRun.Grid, Ext.grid.GridPanel, {
onContextClick: function(grid, index, e){
grid.selindex = index;
if (!this.menu) { // create context menu on first right click
this.menu = new Ext.menu.Menu({
id: 'run-ctx-menu',
enableScrolling: false,
items: [{
text: "Reports",
menu: {
enableScrolling: false,
items: [{
text: 'New Run Status Report',
handler: function(){
@ -657,38 +661,25 @@ Ext.extend(Testopia.TestRun.Grid, Ext.grid.EditorGridPanel, {
}
this.menu.showAt(e.getXY());
},
onGridEdit: function(gevent){
var myparams = {
action: "edit",
run_id: gevent.record.get('run_id')
};
onGridEdit: function(e){
var ds = this.store;
switch (gevent.field) {
case 'product_version':
myparams.run_product_version = gevent.value;
break;
case 'manager':
myparams.manager = gevent.value;
break;
case 'build':
myparams.build = gevent.value;
break;
case 'environment':
myparams.environment = gevent.value;
break;
case 'summary':
myparams.summary = gevent.value;
break;
var myparams = e.record.data;
myparams.action = 'edit';
var manager;
if (!myparams.manager.match('@')){
manager = myparams.manager;
delete myparams.manager;
}
this.form.submit({
url: "tr_process_run.cgi",
params: myparams,
success: function(f, a){
myparams.manager = manager;
ds.commitChanges();
},
failure: function(f, a){
Testopia.Util.error(f, a);
myparams.manager = manager;
ds.rejectChanges();
}
});
@ -758,10 +749,10 @@ Testopia.TestRun.NewRunForm = function(plan){
handler: function(){
casegrid.getSelectionModel().selectAll();
}
}, new Ext.Toolbar.Fill(), {
}, '->', {
xtype: 'checkbox',
id: 'selectall'
}, new Ext.Toolbar.Spacer(), new Ext.menu.TextItem(' Include all CONFIRMED Cases in Plan ' + plan.id));
}, ' ', ' Include all CONFIRMED Cases in Plan ' + plan.id);
});
Testopia.TestRun.NewRunForm.superclass.constructor.call(this, {
@ -1232,10 +1223,6 @@ Testopia.TestRun.ClonePopup = function(product_id, runs, caselist){
});
win.show(this);
var items = pg.getTopToolbar().items.items;
for (var i = 0; i < items.length; i++) {
items[i].destroy();
}
var pchooser = new Testopia.Product.Combo({
id: 'run_clone_win_product_chooser',
mode: 'local',
@ -1273,7 +1260,8 @@ Testopia.TestRun.ClonePopup = function(product_id, runs, caselist){
Ext.getCmp('run_clone_product_id').setValue(r.get('id'));
pg.store.load();
});
pg.getTopToolbar().add(new Ext.menu.TextItem('Product: '), pchooser);
pg.getTopToolbar().removeAll();
pg.getTopToolbar().add('Product: ', pchooser);
pg.getSelectionModel().un('rowselect', pg.getSelectionModel().events['rowselect'].listeners[0].fn);
pg.getSelectionModel().un('rowdeselect', pg.getSelectionModel().events['rowdeselect'].listeners[0].fn);
pg.store.load();

View File

@ -684,6 +684,7 @@ Ext.extend(Testopia.Search.SavedReportsList, Ext.grid.GridPanel, {
}
this.menu = new Ext.menu.Menu({
id:'run-ctx-menu',
enableScrolling: false,
items: [{
text: 'Open in a new tab',
disabled: d ? false : true,

View File

@ -243,6 +243,7 @@ Ext.extend(Testopia.Tags.ObjectTags, Ext.grid.GridPanel, {
if (!this.menu) { // create context menu on first right click
this.menu = new Ext.menu.Menu({
id: 'tags-ctx-menu',
enableScrolling: false,
items: [{
text: 'Remove Selected Tags',
icon: 'extensions/testopia/img/delete.png',
@ -374,6 +375,7 @@ Ext.extend(Testopia.Tags.ProductTags, Ext.grid.GridPanel, {
if (!this.menu) { // create context menu on first right click
this.menu = new Ext.menu.Menu({
id: 'tags-ctx-menu',
enableScrolling: false,
items: [{
text: 'Refresh',
icon: 'extensions/testopia/img/refresh.png',

View File

@ -336,6 +336,7 @@ Ext.extend(Testopia.Util.HistoryList, Ext.grid.GridPanel, {
if (!this.menu) { // create context menu on first right click
this.menu = new Ext.menu.Menu({
id: 'history-ctx-menu',
enableScrolling: false,
items: [{
text: 'Refresh',
icon: 'extensions/testopia/img/refresh.png',
@ -690,18 +691,14 @@ Testopia.Util.getSelectedObjects = function(grid, field){
};
Testopia.Util.editFirstSelection = function(grid){
if (grid.getSelectionModel().getCount() === 0) {
if (grid.store.getCount() === 0) {
return;
}
var cols = grid.getColumnModel();
var count = grid.getColumnModel().getColumnCount();
var row = grid.store.indexOf(grid.getSelectionModel().getSelected());
for (var col = 0; col < count - 1; col++) {
if (cols.isCellEditable(col, row)) {
grid.startEditing(row, col);
return;
}
if (row == -1){
row = 0;
}
grid.plugins[0].startEditing(row);
};
Testopia.Util.urlQueryToJSON = function(url){
@ -831,7 +828,7 @@ Testopia.Util.PlanSelector = function(product_id, cfg){
for (var i = 0; i < items.length; i++) {
items[i].destroy();
}
pg.getTopToolbar().add(new Ext.menu.TextItem('Product: '), pchooser);
pg.getTopToolbar().add('Product: ', pchooser);
pg.getSelectionModel().un('rowselect', pg.getSelectionModel().events['rowselect'].listeners[0].fn);
pg.getSelectionModel().un('rowdeselect', pg.getSelectionModel().events['rowdeselect'].listeners[0].fn);
pg.store.load();

View File

@ -75,6 +75,11 @@ Ext.override(Ext.form.Field, {
}
});// End Override
Ext.override(Ext.menu.Menu, {
ignoreParentClicks: true,
enableScrolling: false
});
//check column widget
Ext.grid.CheckColumn = function(config){
Ext.apply(this, config);

View File

@ -189,11 +189,14 @@ sub create {
###############################
sub check_build {
my ($name, $product, $throw) = @_;
my $pid = ref $product ? $product->id : $product;
my $dbh = Bugzilla->dbh;
trick_taint($name);
trick_taint($pid);
my $is = $dbh->selectrow_array(
"SELECT build_id FROM test_builds
WHERE name = ? AND product_id = ?",
undef, $name, $product->id);
undef, $name, $pid);
if ($throw){
ThrowUserError('invalid-test-id-non-existent', {type => 'Build', id => $name}) unless $is;
return Testopia::Build->new($is);
@ -212,6 +215,7 @@ sub TO_JSON {
foreach my $field ($self->DB_COLUMNS){
$obj->{$field} = $self->{$field};
}
$obj->{isactive} = $self->{isactive} ? JSON::true : JSON::false;
return $json->encode($obj);
}

View File

@ -164,11 +164,14 @@ sub create {
###############################
sub check_case_category {
my ($name, $product) = @_;
my $pid = ref $product ? $product->id : $product;
my $dbh = Bugzilla->dbh;
trick_taint($pid);
trick_taint($name);
my $is = $dbh->selectrow_array(
"SELECT category_id FROM test_case_categories
WHERE name = ? AND product_id = ?",
undef, $name, $product->id);
undef, $name, $pid);
return $is;
}

View File

@ -575,6 +575,8 @@ sub check_environment{
my ($name, $product, $throw) = (@_);
my $pid = ref $product ? $product->id : $product;
my $dbh = Bugzilla->dbh;
trick_taint($name);
trick_taint($pid);
my ($used) = $dbh->selectrow_array(
"SELECT environment_id
FROM test_environments

View File

@ -111,10 +111,6 @@ use constant VALIDATORS => {
};
use constant UPDATE_VALIDATORS => {
category_id => \&_check_category,
};
use constant ALIAS_MAX_LENGTH => 255;
use constant REQUIREMENT_MAX_LENGTH => 255;
use constant SUMMARY_MAX_LENGTH => 255;
@ -447,7 +443,6 @@ sub _check_bugs {
#### Mutators ####
###############################
sub set_case_status { $_[0]->set('case_status_id', $_[1]); }
sub set_category { $_[0]->set('category_id', $_[1]); }
sub set_priority { $_[0]->set('priority_id', $_[1]); }
sub set_default_tester { $_[0]->set('default_tester_id', $_[1]); }
sub set_sortkey { $_[0]->set('sortkey', $_[1]); }
@ -461,6 +456,12 @@ sub set_estimated_time { $_[0]->set('estimated_time', $_[1]); }
sub set_dependson { $_[0]->set('dependson', $_[1]); }
sub set_blocks { $_[0]->set('blocks', $_[1]); }
sub set_category {
my ($self, $value) = @_;
$value = $self->_check_category($value, $self->plans->[0]->product);
$self->set('category_id', $value);
}
sub new {
my $invocant = shift;
my $class = ref($invocant) || $invocant;

View File

@ -101,11 +101,6 @@ use constant VALIDATORS => {
target_completion => \&_check_target,
};
use constant UPDATE_VALIDATORS => {
environment_id => \&_check_env,
build_id => \&_check_build,
};
###############################
#### Validators ####
###############################
@ -215,8 +210,6 @@ sub _check_target {
###############################
#### Mutators ####
###############################
sub set_environment { $_[0]->set('environment_id', $_[1]); }
sub set_build { $_[0]->set('build_id', $_[1]); }
sub set_summary { $_[0]->set('summary', $_[1]); }
sub set_manager { $_[0]->set('manager_id', $_[1]); }
sub set_plan_text_version { $_[0]->set('plan_text_version', $_[1]); }
@ -225,6 +218,18 @@ sub set_stop_date { $_[0]->set('stop_date', $_[1]); }
sub set_target_pass { $_[0]->set('target_pass', $_[1]); }
sub set_target_completion { $_[0]->set('target_completion', $_[1]); }
sub set_environment {
my ($self, $value) = @_;
$value = $self->_check_env($value, $self->plan->product);
$self->set('environment_id', $value);
}
sub set_build {
my ($self, $value) = @_;
$value = $self->_check_build($value, $self->plan->product);
$self->set('build_id', $value);
}
sub set_product_version {
my ($self, $value) = @_;
$value = $self->_check_product_version($value);

View File

@ -1,4 +1,5 @@
<link href="extensions/testopia/css/testopia.css" rel="stylesheet" type="text/css">
<link href="extensions/testopia/extjs/examples/ux/css/RowEditor.css" rel="stylesheet" type="text/css" />
<script type="text/javascript">
Testopia_user = {login: "[% user.login %]", id: [% user.id %]};
DEFAULT_CASE_STATUS = '[% Param('default-test-case-status') %]';

View File

@ -85,6 +85,7 @@
items: [{
text: "Archived",
id: 'plan_archive_mnu',
ignoreParentClicks: true,
checked: [% plan.isactive ? 'false' : 'true' %],
checkHandler: function(i,c){
testopia_form.submit({

View File

@ -30,13 +30,15 @@
? "extensions/testopia/testopia.all.js" : "extensions/testopia/testopia.all.ycomp.js"
style_urls = ["extensions/testopia/extjs/resources/css/ext-all.css",
"extensions/testopia/extjs/examples/ux/css/xtheme-gray-extend.css"]
"extensions/testopia/extjs/examples/ux/css/xtheme-gray-extend.css",
"extensions/testopia/extjs/examples/grid/grid-examples.css"]
%]
[% IF Param('testopia-debug') == 'Developer' %]
[% javascript_urls = [
"extensions/testopia/extjs/adapter/ext/ext-base-debug.js",
"extensions/testopia/extjs/ext-all-debug.js"
"extensions/testopia/extjs/ext-all-debug.js",
"extensions/testopia/extjs/examples/ux/RowEditor.js",
"extensions/testopia/js/strings.js",
"extensions/testopia/js/vars.js",
"extensions/testopia/js/util.js",
@ -56,5 +58,5 @@
%]
[% ELSE %]
[% javascript_urls = [debug_ext_base, debug_ext, debug_testopia] %]
[% javascript_urls = [debug_ext_base, debug_ext, debug_testopia, "extensions/testopia/extjs/examples/ux/RowEditor.js"] %]
[% END %]

View File

@ -60,7 +60,7 @@ if ($action eq 'add'){
name => $cgi->param('name') || '',
description => $cgi->param('desc') || $cgi->param('description') || '',
milestone => $cgi->param('milestone') || '---',
isactive => $cgi->param('isactive') ? 1 : 0,
isactive => $cgi->param('isactive') =~ /(1|true)/ ? 1 : 0,
});
print "{success: true, build_id: ". $build->id . "}";

View File

@ -56,7 +56,7 @@ if ($action eq 'add'){
my $category = Testopia::Category->create({
product_id => $product->id,
name => $cgi->param('name'),
description => $cgi->param('desc'),
description => $cgi->param('description'),
});
print "{success: true, category_id: ". $category->id . "}";