Rally 将SSO用户链接到项目';s详细信息页

Rally 将SSO用户链接到项目';s详细信息页,rally,appsdk2,Rally,Appsdk2,我正在一个rallygrid组件中显示快照存储记录,并希望使其可以单击ID字段,并打开该工作项的详细信息页面。由于快照记录包含一个“_unformatedId”而不是“formatedId”,因此我尝试使用一个列渲染器来实现这一点,该渲染器将文本添加为链接: renderer: function(val, meta, record) { return '<a href="https://rally1.rallydev.com/#/detail/userstory/' + recor

我正在一个rallygrid组件中显示快照存储记录,并希望使其可以单击ID字段,并打开该工作项的详细信息页面。由于快照记录包含一个“_unformatedId”而不是“formatedId”,因此我尝试使用一个列渲染器来实现这一点,该渲染器将文本添加为链接:

renderer: function(val, meta, record) {
    return '<a href="https://rally1.rallydev.com/#/detail/userstory/' + record.get('ObjectID') + '" target="_blank">US' + record.get('_UnformattedID') + '</a>';
}
渲染器:函数(val、meta、record){
返回“”;
}
作为非SSO用户,这非常适合我,但我们工作区中使用SSO的用户报告说,链接只会将他们带到默认的起始页。不是他们期望的详细页面


有没有更好的方法可以让所有用户都能使用这些功能?

SSO的实现在整个组织中是不同的,但这个技巧对我来说很有效。 我检测到主机:

this._host = window.location.hostname;
然后我在构建
渲染器的返回值时使用host,因为在我的环境中,SSO和非SSO场景中生成的URL只在主机部分不同

{
   text: 'Formatted ID', dataIndex: 'UnformattedID', 
        renderer: function(val, meta, record) {
            return '<a href="https://' + that._host + '/#/detail/userstory/' + record.get('ObjectID') + '" target="_blank">US' + record.get('UnformattedID') + '</a>';
    }
}
{
文本:“格式化ID”,数据索引:“未格式化”,
渲染器:函数(val、meta、record){
返回“”;
}
}

Ext.define('CustomApp'{
扩展:“Rally.app.app”,
组件CLS:“应用程序”,
启动:函数(){
这是。_host=window.location.hostname;
console.log('host',this.\u host);
var iterationComboBox=Ext.create('Rally.ui.combobox.iterationComboBox'{
听众:{
就绪:函数(组合框){
这是。_iterationId=combobox.getRecord().get('ObjectID');
this.\u加载故事(this.\u迭代ID);
},
选择:函数(组合框){
这是。_iterationId=combobox.getRecord().get('ObjectID');
this.\u加载故事(this.\u迭代ID);
},
范围:本
}
});
this.add(迭代组合框);
},
_loadStories:函数(迭代ID){
log('loading stories for',iterationOid);
var myStore=Ext.create('Rally.data.lookback.SnapshotStore'{
自动加载:对,
获取:['Name','u unformatted','ScheduleState','u TypeHierarchy'],
过滤器:[{
属性:''uu'At',
值:“当前”
},
{
属性:“\u TypeHierarchy”,
值:“HierarchycalRequirement”
},
{
属性:“迭代”,
值:迭代ID
}
],
水合物:[“类型层次结构”],
听众:{
加载:函数(存储、记录、成功){
console.log(“加载的%i条记录”,记录.length);
这个._onDataLoaded(myStore,records);
},
范围:本
}
});         
},
_onDataLoaded:函数(存储、数据){
log('count',store.getCount());
var=这个;
var记录=[];
Ext.Array.each(数据、函数(记录){
记录。推送({
Name:record.get('Name'),
ObjectID:record.get('ObjectID'),
未格式化:记录。获取(“U未格式化”)
});
});
var myStore=Ext.create('Rally.data.custom.Store'{
数据:记录
});
如果(!this.down('#grid')){
这个。添加({
xtype:“rallygrid”,
id:'网格',
商店:myStore,
专栏CFGS:[
{
文本:“名称”,数据索引:“名称”,flex:1
},
{
文本:“格式化ID”,数据索引:“未格式化”,
渲染器:函数(val、meta、record){
返回“”;
}
}
]
});
}
否则{
控制台日志(存储);
this.down(“#grid”).reconforme(myStore);
}
}
});
Ext.define('CustomApp', {
    extend: 'Rally.app.App',
    componentCls: 'app',
    launch: function() {
    this._host = window.location.hostname;
    console.log('host', this._host);
        var iterationComboBox = Ext.create('Rally.ui.combobox.IterationComboBox',{
                   listeners:{
                           ready: function(combobox){
                                this._iterationOid = combobox.getRecord().get('ObjectID');
                                this._loadStories(this._iterationOid);
                           },
                           select: function(combobox){
                                this._iterationOid = combobox.getRecord().get('ObjectID'); 
                                this._loadStories(this._iterationOid);
                           },
                           scope: this  
                   }
           });
        this.add(iterationComboBox);
    },


     _loadStories:function(iterationOid){
        console.log('loading stories for ', iterationOid);
        var myStore = Ext.create('Rally.data.lookback.SnapshotStore', {
                autoLoad:true,
                fetch    : ['Name','_UnformattedID','ScheduleState','_TypeHierarchy'],

                filters  : [{
                    property : '__At',
                    value    : 'current'
                },
                {
                    property : '_TypeHierarchy',
                    value    : 'HierarchicalRequirement'
                },
                {
                    property : 'Iteration',
                    value    : iterationOid
                }
                ],
        hydrate: ['_TypeHierarchy'],
                listeners: {
                           load: function(store,records,success){
                                   console.log("loaded %i records", records.length);
                                this._onDataLoaded(myStore, records);
                           },
                           scope:this
                   }
        });         
    },

     _onDataLoaded: function(store,data){
                console.log('count',store.getCount());
        var that = this;
        var records = [];
                    Ext.Array.each(data, function(record) {
                        records.push({
                            Name: record.get('Name'),
                            ObjectID: record.get('ObjectID'),
                UnformattedID: record.get('_UnformattedID')
                        });
                    });
            var myStore = Ext.create('Rally.data.custom.Store', {
                data: records
            });
                    if (!this.down('#grid')) {
            this.add({
                xtype: 'rallygrid',
                id: 'grid',
                store: myStore,
                columnCfgs: [
                {
                    text: 'Name', dataIndex: 'Name', flex: 1
                },
                {
                    text: 'Formatted ID', dataIndex: 'UnformattedID', 
                    renderer: function(val, meta, record) {
                        return '<a href="https://' + that._host + '/#/detail/userstory/' + record.get('ObjectID') + '" target="_blank">US' + record.get('UnformattedID') + '</a>';
                    }
                }
                ]
            });
            }
            else{
            console.log(store);
            this.down('#grid').reconfigure(myStore);
             }
     }
});