diff --git a/scm-webapp/src/main/webapp/index.html b/scm-webapp/src/main/webapp/index.html
index 6c2a60234f..6fcc131a77 100644
--- a/scm-webapp/src/main/webapp/index.html
+++ b/scm-webapp/src/main/webapp/index.html
@@ -51,6 +51,8 @@
+
+
SCM-WebAPP
diff --git a/scm-webapp/src/main/webapp/resources/js/sonia.login.js b/scm-webapp/src/main/webapp/resources/js/sonia.login.js
index 0d8665af20..3817d2e2a7 100644
--- a/scm-webapp/src/main/webapp/resources/js/sonia.login.js
+++ b/scm-webapp/src/main/webapp/resources/js/sonia.login.js
@@ -146,4 +146,4 @@ Sonia.login.Window = Ext.extend(Ext.Window,{
Sonia.login.Window.superclass.initComponent.apply(this, arguments);
}
-});
\ No newline at end of file
+});
diff --git a/scm-webapp/src/main/webapp/resources/js/sonia.repository.js b/scm-webapp/src/main/webapp/resources/js/sonia.repository.js
new file mode 100644
index 0000000000..6d0a61e814
--- /dev/null
+++ b/scm-webapp/src/main/webapp/resources/js/sonia.repository.js
@@ -0,0 +1,310 @@
+/**
+ * Copyright (c) 2010, Sebastian Sdorra
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of SCM-Manager; nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * http://bitbucket.org/sdorra/scm-manager
+ *
+ */
+
+var repositoryTypeStore = new Ext.data.JsonStore({
+ id: 1,
+ fields: [ 'displayName', 'name' ]
+});
+
+function loadRepositoryTypes(state){
+ repositoryTypeStore.loadData( state.repositoryTypes );
+}
+
+// register login callback
+loginCallbacks.push( loadRepositoryTypes );
+
+// register namespace
+Ext.ns('Sonia.repository');
+
+
+// RepositoryGrid
+Sonia.repository.Grid = Ext.extend(Ext.grid.GridPanel, {
+
+ urlTemplate: '{0}',
+ mailtoTemplate: '{0}',
+
+ initComponent: function(){
+
+ var selectionModel = new Ext.grid.RowSelectionModel({
+ singleSelect: true
+ });
+
+ selectionModel.on({
+ selectionchange: {
+ scope: this,
+ fn: this.selectionChanged
+ }
+ });
+
+ var repositoryStore = new Sonia.rest.JsonStore({
+ url: restUrl + 'repositories.json',
+ root: 'repositories',
+ fields: [ 'id', 'name', 'type', 'contact', 'description', 'creationDate', 'url' ],
+ sortInfo: {
+ field: 'name'
+ }
+ });
+
+ var repositoryColModel = new Ext.grid.ColumnModel({
+ columns: [
+ {header: 'Name', sortable: true, dataIndex: 'name'},
+ {header: 'Type', sortable: true, dataIndex: 'type', renderer: this.renderRepositoryType},
+ {header: 'Contact', sortable: true, dataIndex: 'contact', scope: this, renderer: this.renderMailto},
+ {header: 'Description', sortable: true, dataIndex: 'description'},
+ {header: 'Creation date', sortable: true, dataIndex: 'creationDate'},
+ {header: 'Url', sortable: true, dataIndex: 'url', scope: this, renderer: this.renderUrl}
+ ]
+ });
+
+ var config = {
+ store: repositoryStore,
+ colModel: repositoryColModel,
+ sm: selectionModel
+ };
+
+ Ext.apply(this, Ext.apply(this.initialConfig, config));
+ Sonia.repository.Grid.superclass.initComponent.apply(this, arguments);
+
+ // load data
+ if ( debug ){
+ console.debug( 'load repository list' );
+ }
+ repositoryStore.load();
+ },
+
+ reload: function(){
+ if ( debug ){
+ console.debug('reload store');
+ }
+
+ console.debug( this );
+
+ this.store.load();
+ },
+
+ selectionChanged: function(sm){
+ var selected = sm.getSelected();
+ if ( selected ){
+ if ( debug ){
+ console.debug( selected.data.name + ' selected' );
+ }
+ var editPanel = Ext.getCmp('repositoryEditPanel');
+ editPanel.removeAll();
+ var panel = new Sonia.repository.FormPanel({
+ item: selected.data,
+ region: 'south',
+ title: 'Repository Form',
+ padding: 5,
+ onUpdate: {
+ fn: this.reload,
+ scope: this
+ },
+ onCreate: {
+ fn: this.reload,
+ scope: this
+ }
+ });
+ editPanel.add(panel);
+ editPanel.doLayout();
+ }
+ },
+
+ renderRepositoryType: function(repositoryType){
+ return repositoryTypeStore.queryBy(function(rec){
+ return rec.data.name == repositoryType;
+ }).itemAt(0).data.displayName;
+ },
+
+ renderUrl: function(url){
+ return String.format( this.urlTemplate, url );
+ },
+
+ renderMailto: function(mail){
+ return String.format( this.mailtoTemplate, mail );
+ }
+
+
+});
+
+// register xtype
+Ext.reg('repositoryGrid', Sonia.repository.Grid);
+
+// RepositoryFormPanel
+Sonia.repository.FormPanel = Ext.extend(Ext.FormPanel,{
+
+ item: null,
+ onUpdate: null,
+ onCreate: null,
+
+ initComponent: function(){
+
+ update = this.item != null;
+
+ var config = {
+ padding: 5,
+ labelWidth: 100,
+ defaults: {width: 240},
+ autoScroll: true,
+ defaultType: 'textfield',
+ items:[
+ {id: 'repositoryName', fieldLabel: 'Name', name: 'name', readOnly: update, allowBlank: false},
+ {
+ fieldLabel: 'Type',
+ name: 'type',
+ xtype: 'combo',
+ readOnly: update,
+ hiddenName : 'type',
+ typeAhead: true,
+ triggerAction: 'all',
+ lazyRender: true,
+ mode: 'local',
+ editable: false,
+ store: repositoryTypeStore,
+ valueField: 'name',
+ displayField: 'displayName',
+ allowBlank: false
+ },
+
+ {fieldLabel: 'Contact', name: 'contact'},
+ {fieldLabel: 'Description', name: 'description', xtype: 'textarea'}
+ ],
+ buttonAlign: 'center',
+ buttons: [
+ {text: 'Ok', scope: this, handler: this.submit},
+ {text: 'Cancel', scope: this, handler: this.reset}
+ ]
+ };
+
+ Ext.apply(this, Ext.apply(this.initialConfig, config));
+ Sonia.repository.FormPanel.superclass.initComponent.apply(this, arguments);
+
+ if ( update ){
+ this.loadData( this.item );
+ }
+ },
+
+ loadData: function(item){
+ this.item = item;
+ var data = {success: true, data: item};
+ this.getForm().loadRecord(data);
+ },
+
+ submit: function(){
+ if ( debug ){
+ console.debug( 'repository form submitted' );
+ }
+ var item = this.getForm().getFieldValues();
+ item = Ext.apply( this.item, item );
+
+ if ( debug ){
+ console.debug( 'update repository: ' + item.name );
+ }
+ var url = restUrl + 'repositories/' + item.id + ".json";
+ Ext.Ajax.request({
+ url: url,
+ jsonData: item,
+ method: 'PUT',
+ scope: this,
+ success: function(){
+ if ( debug ){
+ console.debug('update success');
+ }
+ this.execCallback(this.onUpdate, item);
+ },
+ failure: function(){
+ alert( 'failure' );
+ }
+ });
+ },
+
+ create: function(item){
+
+ },
+
+ reset: function(){
+ this.getForm().reset();
+ },
+
+ execCallback: function(obj, item){
+ if ( Ext.isFunction( obj ) ){
+ obj(item);
+ } else if ( Ext.isObject( obj )){
+ obj.fn.call( obj.scope, item );
+ }
+ }
+
+});
+
+// register xtype
+Ext.reg('repositoryForm', Sonia.repository.FormPanel);
+
+// RepositoryPanel
+Sonia.repository.Panel = Ext.extend(Ext.Panel, {
+
+ initComponent: function(){
+
+ var config = {
+ layout: 'border',
+ hideMode: 'offsets',
+ bodyCssClass: 'x-panel-mc',
+ enableTabScroll: true,
+ region:'center',
+ autoScroll: true,
+ items: [{
+ xtype: 'repositoryGrid',
+ region: 'center'
+ }, {
+ id: 'repositoryEditPanel',
+ layout: 'fit',
+ items: [{
+ //xtype: 'repositoryForm',
+ region: 'south',
+ title: 'Repository Form',
+ xtype: 'panel',
+ padding: 5,
+ html: 'Add or select an Repository'
+ }],
+ height: 250,
+ split: true,
+ border: false,
+ region: 'south'
+ }
+ ]
+ }
+
+ Ext.apply(this, Ext.apply(this.initialConfig, config));
+ Sonia.repository.Panel.superclass.initComponent.apply(this, arguments);
+ }
+
+});
+
+// register xtype
+Ext.reg('repositoryPanel', Sonia.repository.Panel);
diff --git a/scm-webapp/src/main/webapp/resources/js/sonia.rest.js b/scm-webapp/src/main/webapp/resources/js/sonia.rest.js
new file mode 100644
index 0000000000..6eba193d3a
--- /dev/null
+++ b/scm-webapp/src/main/webapp/resources/js/sonia.rest.js
@@ -0,0 +1,60 @@
+/**
+ * Copyright (c) 2010, Sebastian Sdorra
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of SCM-Manager; nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * http://bitbucket.org/sdorra/scm-manager
+ *
+ */
+
+Ext.ns("Sonia.rest");
+
+Sonia.rest.JsonStore = Ext.extend( Ext.data.JsonStore, {
+
+ constructor: function(config) {
+ var baseConfig = {
+ autoLoad: false,
+ listeners: {
+ // fix jersey empty array problem
+ exception: {
+ fn: function(proxy, type, action, options, response, arg){
+ var status = response.status;
+ if ( status == 200 && action == 'read' && response.responseText == 'null' ){
+ if ( debug ){
+ console.debug( 'empty array, clear whole store' );
+ }
+ this.removeAll();
+ } else {
+ alert( action + "(" + status + "): " + response.responseText );
+ }
+ },
+ scope: this
+ }
+ }
+ };
+ Sonia.rest.JsonStore.superclass.constructor.call(this, Ext.apply(config, baseConfig));
+ }
+
+});
diff --git a/scm-webapp/src/main/webapp/resources/js/sonia.scm.js b/scm-webapp/src/main/webapp/resources/js/sonia.scm.js
index 6aac89b606..81465c3c89 100644
--- a/scm-webapp/src/main/webapp/resources/js/sonia.scm.js
+++ b/scm-webapp/src/main/webapp/resources/js/sonia.scm.js
@@ -113,7 +113,9 @@ Ext.onReady(function(){
title: 'Main',
items: [{
label: 'Repositories',
- fn: function(){console.debug( 'Repositories' );}
+ fn: function(){
+ addTabPanel('repositories', 'repositoryPanel', 'Repositories');
+ }
}]
},{
title: 'Config',