← Back to team overview

dhis2-devs team mailing list archive

[Branch ~dhis2-devs-core/dhis2/trunk] Rev 21478: support attributes in optionSets

 

------------------------------------------------------------
revno: 21478
committer: Morten Olav Hansen <mortenoh@xxxxxxxxx>
branch nick: dhis2
timestamp: Thu 2015-12-17 14:36:30 +0100
message:
  support attributes in optionSets
added:
  dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-dataadmin/src/main/java/org/hisp/dhis/dataadmin/action/option/ShowAddOptionAction.java
  dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-dataadmin/src/main/java/org/hisp/dhis/dataadmin/action/option/ShowAddOptionSetAction.java
modified:
  dhis-2/dhis-api/src/main/java/org/hisp/dhis/attribute/Attribute.java
  dhis-2/dhis-api/src/main/java/org/hisp/dhis/attribute/AttributeStore.java
  dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/startup/TableAlteror.java
  dhis-2/dhis-services/dhis-service-core/src/main/resources/org/hisp/dhis/attribute/hibernate/Attribute.hbm.xml
  dhis-2/dhis-services/dhis-service-core/src/main/resources/org/hisp/dhis/option/hibernate/OptionSet.hbm.xml
  dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-dataadmin/src/main/java/org/hisp/dhis/dataadmin/action/attribute/AddAttributeAction.java
  dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-dataadmin/src/main/java/org/hisp/dhis/dataadmin/action/attribute/UpdateAttributeAction.java
  dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-dataadmin/src/main/java/org/hisp/dhis/dataadmin/action/option/AddOptionSetAction.java
  dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-dataadmin/src/main/java/org/hisp/dhis/dataadmin/action/option/GetOptionSetAction.java
  dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-dataadmin/src/main/java/org/hisp/dhis/dataadmin/action/option/UpdateOptionSetAction.java
  dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-dataadmin/src/main/resources/META-INF/dhis/beans.xml
  dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-dataadmin/src/main/resources/struts.xml
  dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-dataadmin/src/main/webapp/dhis-web-maintenance-dataadmin/addAttributeForm.vm
  dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-dataadmin/src/main/webapp/dhis-web-maintenance-dataadmin/addOptionSetForm.vm
  dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-dataadmin/src/main/webapp/dhis-web-maintenance-dataadmin/updateAttributeForm.vm
  dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-dataadmin/src/main/webapp/dhis-web-maintenance-dataadmin/updateOptionSetForm.vm


--
lp:dhis2
https://code.launchpad.net/~dhis2-devs-core/dhis2/trunk

Your team DHIS 2 developers is subscribed to branch lp:dhis2.
To unsubscribe from this branch go to https://code.launchpad.net/~dhis2-devs-core/dhis2/trunk/+edit-subscription
=== modified file 'dhis-2/dhis-api/src/main/java/org/hisp/dhis/attribute/Attribute.java'
--- dhis-2/dhis-api/src/main/java/org/hisp/dhis/attribute/Attribute.java	2015-12-17 12:56:47 +0000
+++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/attribute/Attribute.java	2015-12-17 13:36:30 +0000
@@ -109,6 +109,8 @@
 
     private boolean optionAttribute;
 
+    private boolean optionSetAttribute;
+
     private boolean mandatory;
 
     private boolean unique;
@@ -452,6 +454,19 @@
     @JsonProperty
     @JsonView( { DetailedView.class, ExportView.class } )
     @JacksonXmlProperty( namespace = DxfNamespaces.DXF_2_0 )
+    public boolean isOptionSetAttribute()
+    {
+        return optionSetAttribute;
+    }
+
+    public void setOptionSetAttribute( boolean optionSetAttribute )
+    {
+        this.optionSetAttribute = optionSetAttribute;
+    }
+
+    @JsonProperty
+    @JsonView( { DetailedView.class, ExportView.class } )
+    @JacksonXmlProperty( namespace = DxfNamespaces.DXF_2_0 )
     public OptionSet getOptionSet()
     {
         return optionSet;
@@ -497,6 +512,7 @@
         if ( trackedEntityAttributeAttribute ) klasses.add( TrackedEntityAttribute.class );
         if ( documentAttribute ) klasses.add( Document.class );
         if ( optionAttribute ) klasses.add( Option.class );
+        if ( optionSetAttribute ) klasses.add( OptionSet.class );
 
         return klasses;
     }
@@ -527,6 +543,9 @@
             trackedEntityAttributeAttribute = attribute.isTrackedEntityAttributeAttribute();
             categoryOptionAttribute = attribute.isCategoryOptionAttribute();
             categoryOptionGroupAttribute = attribute.isCategoryOptionGroupAttribute();
+            documentAttribute = attribute.isDocumentAttribute();
+            optionAttribute = attribute.isOptionAttribute();
+            optionSetAttribute = attribute.isOptionSetAttribute();
             mandatory = attribute.isMandatory();
 
             if ( strategy.isReplace() )

=== modified file 'dhis-2/dhis-api/src/main/java/org/hisp/dhis/attribute/AttributeStore.java'
--- dhis-2/dhis-api/src/main/java/org/hisp/dhis/attribute/AttributeStore.java	2015-12-17 11:44:56 +0000
+++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/attribute/AttributeStore.java	2015-12-17 13:36:30 +0000
@@ -39,6 +39,7 @@
 import org.hisp.dhis.indicator.Indicator;
 import org.hisp.dhis.indicator.IndicatorGroup;
 import org.hisp.dhis.option.Option;
+import org.hisp.dhis.option.OptionSet;
 import org.hisp.dhis.organisationunit.OrganisationUnit;
 import org.hisp.dhis.organisationunit.OrganisationUnitGroup;
 import org.hisp.dhis.organisationunit.OrganisationUnitGroupSet;
@@ -78,6 +79,7 @@
         .put( CategoryOptionGroup.class, "categoryOptionGroupAttribute" )
         .put( Document.class, "documentAttribute" )
         .put( Option.class, "optionAttribute" )
+        .put( OptionSet.class, "optionSetAttribute" )
         .build();
 
     /**

=== modified file 'dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/startup/TableAlteror.java'
--- dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/startup/TableAlteror.java	2015-12-17 11:44:56 +0000
+++ dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/startup/TableAlteror.java	2015-12-17 13:36:30 +0000
@@ -767,6 +767,7 @@
         executeSql( "UPDATE attribute SET categoryoptiongroupattribute=false WHERE categoryoptiongroupattribute IS NULL" );
         executeSql( "UPDATE attribute SET documentattribute=false WHERE documentattribute IS NULL" );
         executeSql( "UPDATE attribute SET optionattribute=false WHERE optionattribute IS NULL" );
+        executeSql( "UPDATE attribute SET optionsetattribute=false WHERE optionsetattribute IS NULL" );
 
         executeSql( "ALTER TABLE trackedentityattributedimension DROP COLUMN operator" );
         executeSql( "ALTER TABLE trackedentitydataelementdimension DROP COLUMN operator" );

=== modified file 'dhis-2/dhis-services/dhis-service-core/src/main/resources/org/hisp/dhis/attribute/hibernate/Attribute.hbm.xml'
--- dhis-2/dhis-services/dhis-service-core/src/main/resources/org/hisp/dhis/attribute/hibernate/Attribute.hbm.xml	2015-12-17 11:44:56 +0000
+++ dhis-2/dhis-services/dhis-service-core/src/main/resources/org/hisp/dhis/attribute/hibernate/Attribute.hbm.xml	2015-12-17 13:36:30 +0000
@@ -65,6 +65,8 @@
 
     <property name="optionAttribute" not-null="false" />
 
+    <property name="optionSetAttribute" not-null="false" />
+
     <property name="sortOrder" />
 
     <set name="attributeValues" inverse="true" lazy="true">

=== modified file 'dhis-2/dhis-services/dhis-service-core/src/main/resources/org/hisp/dhis/option/hibernate/OptionSet.hbm.xml'
--- dhis-2/dhis-services/dhis-service-core/src/main/resources/org/hisp/dhis/option/hibernate/OptionSet.hbm.xml	2015-09-09 09:01:21 +0000
+++ dhis-2/dhis-services/dhis-service-core/src/main/resources/org/hisp/dhis/option/hibernate/OptionSet.hbm.xml	2015-12-17 13:36:30 +0000
@@ -34,6 +34,13 @@
       <one-to-many class="org.hisp.dhis.option.Option" />
     </list>
 
+    <!-- Dynamic attribute values -->
+    <set name="attributeValues" table="optionsetattributevalues" cascade="delete-orphan">
+      <cache usage="read-write" />
+      <key column="optionsetid" />
+      <many-to-many class="org.hisp.dhis.attribute.AttributeValue" column="attributevalueid" unique="true" />
+    </set>
+
     <!-- Access properties -->
     <many-to-one name="user" class="org.hisp.dhis.user.User" column="userid" foreign-key="fk_optionset_userid" />
 

=== modified file 'dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-dataadmin/src/main/java/org/hisp/dhis/dataadmin/action/attribute/AddAttributeAction.java'
--- dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-dataadmin/src/main/java/org/hisp/dhis/dataadmin/action/attribute/AddAttributeAction.java	2015-12-17 11:44:56 +0000
+++ dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-dataadmin/src/main/java/org/hisp/dhis/dataadmin/action/attribute/AddAttributeAction.java	2015-12-17 13:36:30 +0000
@@ -218,6 +218,13 @@
         this.optionAttribute = optionAttribute;
     }
 
+    private boolean optionSetAttribute;
+
+    public void setOptionSetAttribute( boolean optionSetAttribute )
+    {
+        this.optionSetAttribute = optionSetAttribute;
+    }
+
     private String optionSetUid;
 
     public void setOptionSetUid( String optionSetUid )
@@ -258,6 +265,7 @@
         attribute.setCategoryOptionGroupAttribute( categoryOptionGroupAttribute );
         attribute.setDocumentAttribute( documentAttribute );
         attribute.setOptionAttribute( optionAttribute );
+        attribute.setOptionSetAttribute( optionSetAttribute );
 
         attributeService.addAttribute( attribute );
 

=== modified file 'dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-dataadmin/src/main/java/org/hisp/dhis/dataadmin/action/attribute/UpdateAttributeAction.java'
--- dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-dataadmin/src/main/java/org/hisp/dhis/dataadmin/action/attribute/UpdateAttributeAction.java	2015-12-17 11:44:56 +0000
+++ dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-dataadmin/src/main/java/org/hisp/dhis/dataadmin/action/attribute/UpdateAttributeAction.java	2015-12-17 13:36:30 +0000
@@ -225,6 +225,13 @@
         this.optionAttribute = optionAttribute;
     }
 
+    private boolean optionSetAttribute;
+
+    public void setOptionSetAttribute( boolean optionSetAttribute )
+    {
+        this.optionSetAttribute = optionSetAttribute;
+    }
+
     private String optionSetUid;
 
     public void setOptionSetUid( String optionSetUid )
@@ -270,6 +277,7 @@
             attribute.setCategoryOptionGroupAttribute( categoryOptionGroupAttribute );
             attribute.setDocumentAttribute( documentAttribute );
             attribute.setOptionAttribute( optionAttribute );
+            attribute.setOptionSetAttribute( optionSetAttribute );
 
             attributeService.updateAttribute( attribute );
 

=== modified file 'dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-dataadmin/src/main/java/org/hisp/dhis/dataadmin/action/option/AddOptionSetAction.java'
--- dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-dataadmin/src/main/java/org/hisp/dhis/dataadmin/action/option/AddOptionSetAction.java	2015-09-09 09:01:21 +0000
+++ dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-dataadmin/src/main/java/org/hisp/dhis/dataadmin/action/option/AddOptionSetAction.java	2015-12-17 13:36:30 +0000
@@ -30,9 +30,13 @@
 
 import com.opensymphony.xwork2.Action;
 import org.apache.commons.lang3.StringUtils;
+import org.hisp.dhis.attribute.AttributeService;
 import org.hisp.dhis.common.ValueType;
 import org.hisp.dhis.option.OptionService;
 import org.hisp.dhis.option.OptionSet;
+import org.springframework.beans.factory.annotation.Autowired;
+
+import java.util.List;
 
 /**
  * @author Chau Thu Tran
@@ -51,6 +55,9 @@
         this.optionService = optionService;
     }
 
+    @Autowired
+    private AttributeService attributeService;
+
     // -------------------------------------------------------------------------------------------------
     // Input
     // -------------------------------------------------------------------------------------------------
@@ -76,6 +83,13 @@
         this.valueType = valueType;
     }
 
+    private List<String> jsonAttributeValues;
+
+    public void setJsonAttributeValues( List<String> jsonAttributeValues )
+    {
+        this.jsonAttributeValues = jsonAttributeValues;
+    }
+
     // -------------------------------------------------------------------------------------------------
     // Action implementation
     // -------------------------------------------------------------------------------------------------
@@ -89,6 +103,11 @@
         optionSet.setValueType( ValueType.valueOf( valueType ) );
         optionSet.setVersion( 1 );
 
+        if ( jsonAttributeValues != null )
+        {
+            attributeService.updateAttributeValues( optionSet, jsonAttributeValues );
+        }
+
         optionService.saveOptionSet( optionSet );
 
         return SUCCESS;

=== modified file 'dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-dataadmin/src/main/java/org/hisp/dhis/dataadmin/action/option/GetOptionSetAction.java'
--- dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-dataadmin/src/main/java/org/hisp/dhis/dataadmin/action/option/GetOptionSetAction.java	2015-12-17 12:56:47 +0000
+++ dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-dataadmin/src/main/java/org/hisp/dhis/dataadmin/action/option/GetOptionSetAction.java	2015-12-17 13:36:30 +0000
@@ -32,9 +32,9 @@
 import org.hisp.dhis.attribute.Attribute;
 import org.hisp.dhis.attribute.AttributeService;
 import org.hisp.dhis.attribute.comparator.AttributeSortOrderComparator;
-import org.hisp.dhis.option.Option;
 import org.hisp.dhis.option.OptionService;
 import org.hisp.dhis.option.OptionSet;
+import org.hisp.dhis.system.util.AttributeUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 
 import java.util.ArrayList;
@@ -109,7 +109,9 @@
     {
         optionSet = optionService.getOptionSet( id );
 
-        attributes = new ArrayList<>( attributeService.getAttributes( Option.class ) );
+        attributeValues = AttributeUtils.getAttributeValueMap( optionSet.getAttributeValues() );
+
+        attributes = new ArrayList<>( attributeService.getAttributes( OptionSet.class ) );
         Collections.sort( attributes, AttributeSortOrderComparator.INSTANCE );
 
         return SUCCESS;

=== added file 'dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-dataadmin/src/main/java/org/hisp/dhis/dataadmin/action/option/ShowAddOptionAction.java'
--- dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-dataadmin/src/main/java/org/hisp/dhis/dataadmin/action/option/ShowAddOptionAction.java	1970-01-01 00:00:00 +0000
+++ dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-dataadmin/src/main/java/org/hisp/dhis/dataadmin/action/option/ShowAddOptionAction.java	2015-12-17 13:36:30 +0000
@@ -0,0 +1,112 @@
+package org.hisp.dhis.dataadmin.action.option;
+
+/*
+ * Copyright (c) 2004-2015, University of Oslo
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 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.
+ * Neither the name of the HISP project 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 COPYRIGHT OWNER 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.
+ */
+
+import com.opensymphony.xwork2.Action;
+import org.hisp.dhis.attribute.Attribute;
+import org.hisp.dhis.attribute.AttributeService;
+import org.hisp.dhis.attribute.comparator.AttributeSortOrderComparator;
+import org.hisp.dhis.option.Option;
+import org.hisp.dhis.option.OptionService;
+import org.hisp.dhis.option.OptionSet;
+import org.springframework.beans.factory.annotation.Autowired;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @author Morten Olav Hansen <mortenoh@xxxxxxxxx>
+ */
+public class ShowAddOptionAction
+    implements Action
+{
+    // -------------------------------------------------------------------------------------------------
+    // Dependencies
+    // -------------------------------------------------------------------------------------------------
+
+    private OptionService optionService;
+
+    @Autowired
+    private AttributeService attributeService;
+
+    // -------------------------------------------------------------------------------------------------
+    // Input/Output
+    // -------------------------------------------------------------------------------------------------
+
+    private Integer id;
+
+    private OptionSet optionSet;
+
+    private List<Attribute> attributes;
+
+    private Map<Integer, String> attributeValues = new HashMap<>();
+
+    // -------------------------------------------------------------------------------------------------
+    // Getters && Setters
+    // -------------------------------------------------------------------------------------------------
+
+    public void setOptionService( OptionService optionService )
+    {
+        this.optionService = optionService;
+    }
+
+    public OptionSet getOptionSet()
+    {
+        return optionSet;
+    }
+
+    public void setId( Integer id )
+    {
+        this.id = id;
+    }
+
+    public List<Attribute> getAttributes()
+    {
+        return attributes;
+    }
+
+    // -------------------------------------------------------------------------------------------------
+    // Action implementation
+    // -------------------------------------------------------------------------------------------------
+
+    @Override
+    public String execute()
+        throws Exception
+    {
+        optionSet = optionService.getOptionSet( id );
+
+        attributes = new ArrayList<>( attributeService.getAttributes( Option.class ) );
+        Collections.sort( attributes, AttributeSortOrderComparator.INSTANCE );
+
+        return SUCCESS;
+    }
+}

=== added file 'dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-dataadmin/src/main/java/org/hisp/dhis/dataadmin/action/option/ShowAddOptionSetAction.java'
--- dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-dataadmin/src/main/java/org/hisp/dhis/dataadmin/action/option/ShowAddOptionSetAction.java	1970-01-01 00:00:00 +0000
+++ dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-dataadmin/src/main/java/org/hisp/dhis/dataadmin/action/option/ShowAddOptionSetAction.java	2015-12-17 13:36:30 +0000
@@ -0,0 +1,79 @@
+package org.hisp.dhis.dataadmin.action.option;
+
+/*
+ * Copyright (c) 2004-2015, University of Oslo
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * 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.
+ * Neither the name of the HISP project 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 COPYRIGHT OWNER 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.
+ */
+
+import com.opensymphony.xwork2.Action;
+import org.hisp.dhis.attribute.Attribute;
+import org.hisp.dhis.attribute.AttributeService;
+import org.hisp.dhis.attribute.comparator.AttributeSortOrderComparator;
+import org.hisp.dhis.option.OptionSet;
+import org.springframework.beans.factory.annotation.Autowired;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * @author Morten Olav Hansen <mortenoh@xxxxxxxxx>
+ */
+public class ShowAddOptionSetAction
+    implements Action
+{
+    // -------------------------------------------------------------------------------------------------
+    // Dependencies
+    // -------------------------------------------------------------------------------------------------
+
+    @Autowired
+    private AttributeService attributeService;
+
+    // -------------------------------------------------------------------------------------------------
+    // Input/Output
+    // -------------------------------------------------------------------------------------------------
+
+    private List<Attribute> attributes;
+
+    public List<Attribute> getAttributes()
+    {
+        return attributes;
+    }
+
+    // -------------------------------------------------------------------------------------------------
+    // Action implementation
+    // -------------------------------------------------------------------------------------------------
+
+    @Override
+    public String execute()
+        throws Exception
+    {
+        attributes = new ArrayList<>( attributeService.getAttributes( OptionSet.class ) );
+        Collections.sort( attributes, AttributeSortOrderComparator.INSTANCE );
+
+        return SUCCESS;
+    }
+}

=== modified file 'dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-dataadmin/src/main/java/org/hisp/dhis/dataadmin/action/option/UpdateOptionSetAction.java'
--- dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-dataadmin/src/main/java/org/hisp/dhis/dataadmin/action/option/UpdateOptionSetAction.java	2015-09-10 07:57:00 +0000
+++ dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-dataadmin/src/main/java/org/hisp/dhis/dataadmin/action/option/UpdateOptionSetAction.java	2015-12-17 13:36:30 +0000
@@ -30,8 +30,12 @@
 
 import com.opensymphony.xwork2.Action;
 import org.apache.commons.lang3.StringUtils;
+import org.hisp.dhis.attribute.AttributeService;
 import org.hisp.dhis.option.OptionService;
 import org.hisp.dhis.option.OptionSet;
+import org.springframework.beans.factory.annotation.Autowired;
+
+import java.util.List;
 
 /**
  * @author Chau Thu Tran
@@ -51,6 +55,9 @@
         this.optionService = optionService;
     }
 
+    @Autowired
+    private AttributeService attributeService;
+
     // -------------------------------------------------------------------------------------------------
     // Input
     // -------------------------------------------------------------------------------------------------
@@ -76,6 +83,13 @@
         this.code = code;
     }
 
+    private List<String> jsonAttributeValues;
+
+    public void setJsonAttributeValues( List<String> jsonAttributeValues )
+    {
+        this.jsonAttributeValues = jsonAttributeValues;
+    }
+
     // -------------------------------------------------------------------------------------------------
     // Action implementation
     // -------------------------------------------------------------------------------------------------
@@ -88,6 +102,11 @@
         optionSet.setName( StringUtils.trimToNull( name ) );
         optionSet.setCode( StringUtils.trimToNull( code ) );
 
+        if ( jsonAttributeValues != null )
+        {
+            attributeService.updateAttributeValues( optionSet, jsonAttributeValues );
+        }
+
         optionService.updateOptionSet( optionSet );
 
         return SUCCESS;

=== modified file 'dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-dataadmin/src/main/resources/META-INF/dhis/beans.xml'
--- dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-dataadmin/src/main/resources/META-INF/dhis/beans.xml	2015-10-03 11:12:19 +0000
+++ dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-dataadmin/src/main/resources/META-INF/dhis/beans.xml	2015-12-17 13:36:30 +0000
@@ -315,6 +315,9 @@
 
   <!-- OptionSet -->
 
+  <bean id="org.hisp.dhis.dataadmin.action.option.ShowAddOptionSetAction"
+    class="org.hisp.dhis.dataadmin.action.option.ShowAddOptionSetAction" />
+
   <bean id="org.hisp.dhis.dataadmin.action.option.GetOptionSetListAction"
     class="org.hisp.dhis.dataadmin.action.option.GetOptionSetListAction"
     scope="prototype">
@@ -353,6 +356,10 @@
 
   <!-- Option -->
 
+  <bean id="org.hisp.dhis.dataadmin.action.option.ShowAddOptionAction" class="org.hisp.dhis.dataadmin.action.option.ShowAddOptionAction">
+    <property name="optionService" ref="org.hisp.dhis.option.OptionService" />
+  </bean>
+
   <bean id="org.hisp.dhis.dataadmin.action.option.AddOptionAction"
     class="org.hisp.dhis.dataadmin.action.option.AddOptionAction"
     scope="prototype">

=== modified file 'dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-dataadmin/src/main/resources/struts.xml'
--- dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-dataadmin/src/main/resources/struts.xml	2015-09-24 07:35:03 +0000
+++ dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-dataadmin/src/main/resources/struts.xml	2015-12-17 13:36:30 +0000
@@ -522,7 +522,7 @@
       <param name="requiredAuthorities">F_OPTIONSET_MANAGEMENT</param>
     </action>
 
-    <action name="showAddOptionSetForm" class="org.hisp.dhis.dataadmin.action.NoAction">
+    <action name="showAddOptionSetForm" class="org.hisp.dhis.dataadmin.action.option.ShowAddOptionSetAction">
       <result name="success" type="velocity">/main.vm</result>
       <param name="page">/dhis-web-maintenance-dataadmin/addOptionSetForm.vm</param>
       <param name="javascripts">javascript/optionSet.js</param>
@@ -573,7 +573,7 @@
 		<param name="requiredAuthorities">F_OPTIONSET_MANAGEMENT</param>
 	</action>
 
-	<action name="showAddOptionForm" class="org.hisp.dhis.dataadmin.action.option.GetOptionSetAction">
+	<action name="showAddOptionForm" class="org.hisp.dhis.dataadmin.action.option.ShowAddOptionAction">
 		<result name="success" type="velocity">/main.vm</result>
 		<param name="page">/dhis-web-maintenance-dataadmin/addOptionForm.vm</param>
 		<param name="javascripts">javascript/option.js</param>

=== modified file 'dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-dataadmin/src/main/webapp/dhis-web-maintenance-dataadmin/addAttributeForm.vm'
--- dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-dataadmin/src/main/webapp/dhis-web-maintenance-dataadmin/addAttributeForm.vm	2015-12-17 11:44:56 +0000
+++ dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-dataadmin/src/main/webapp/dhis-web-maintenance-dataadmin/addAttributeForm.vm	2015-12-17 13:36:30 +0000
@@ -72,6 +72,7 @@
 			<input type="checkbox" id="categoryOptionGroupAttribute" name="categoryOptionGroupAttribute" value="true" /><label for="categoryOptionGroupAttribute">$i18n.getString( 'category_option_group' )</label> <br />
 			<input type="checkbox" id="documentAttribute" name="documentAttribute" value="true" /><label for="documentAttribute">$i18n.getString( 'document' )</label> <br />
 			<input type="checkbox" id="optionAttribute" name="optionAttribute" value="true" /><label for="optionAttribute">$i18n.getString( 'option' )</label> <br />
+			<input type="checkbox" id="optionSetAttribute" name="optionSetAttribute" value="true" /><label for="optionSetAttribute">$i18n.getString( 'option_set' )</label> <br />
 		</td>
 	</tr>
 

=== modified file 'dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-dataadmin/src/main/webapp/dhis-web-maintenance-dataadmin/addOptionSetForm.vm'
--- dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-dataadmin/src/main/webapp/dhis-web-maintenance-dataadmin/addOptionSetForm.vm	2015-09-14 11:09:56 +0000
+++ dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-dataadmin/src/main/webapp/dhis-web-maintenance-dataadmin/addOptionSetForm.vm	2015-12-17 13:36:30 +0000
@@ -1,14 +1,15 @@
 <script type="text/javascript">
-	jQuery(document).ready(	function() {
-		validation( 'addOptionSetForm', function(form){
-			form.submit();
-		});
-		checkValueIsExist( "name", "validateOptionSet.action");	
-	});
+  jQuery(document).ready(function() {
+    validation('addOptionSetForm', function(form) {
+      #tblDynamicAttributesJavascript()
+      form.submit();
+    });
+    checkValueIsExist("name", "validateOptionSet.action");
+  });
 
-    var i18n_specify_option_name = '$encoder.jsEscape( $i18n.getString( "specify_option_name" ) , "'")';
-    var i18n_option_name_already_exists = '$encoder.jsEscape( $i18n.getString( "option_name_already_exists" ) , "'")';
-    var i18n_must_include_option = '$encoder.jsEscape( $i18n.getString( "must_include_option" ) , "'")';
+  var i18n_specify_option_name = '$encoder.jsEscape( $i18n.getString( "specify_option_name" ) , "'")';
+  var i18n_option_name_already_exists = '$encoder.jsEscape( $i18n.getString( "option_name_already_exists" ) , "'")';
+  var i18n_must_include_option = '$encoder.jsEscape( $i18n.getString( "must_include_option" ) , "'")';
 </script>
 
 <h3>$i18n.getString( "add_option_set" )</h3>
@@ -17,14 +18,14 @@
 
 <form id="addOptionSetForm" name="addOptionSetForm" action="addOptionSet.action" method="post" class="inputForm">
   <table>
-      <colgroup>
-          <col width="50px" />
-          <col width="150px"/>
-          <col width="50px"/>
-      </colgroup>
+    <colgroup>
+      <col width="50px"/>
+      <col width="150px"/>
+      <col width="50px"/>
+    </colgroup>
 
     <tr>
-      <th colspan="4">$i18n.getString( "details" )</th>      
+      <th colspan="4">$i18n.getString( "details" )</th>
     </tr>
     <tr>
       <td><label>$i18n.getString( "name" ) <em title="$i18n.getString( 'required' )" class="required">*</em></label></td>
@@ -35,32 +36,37 @@
       <td colspan="3"><input type="text" id="code" name="code" class="{validate:{minlength:2}}"></td>
     </tr>
     <tr>
-   		<td><label for="valueType">$i18n.getString( "value_type" ) <em title="$i18n.getString( 'required' )" class="required">*</em></label></td>
-   		<td>
-         <select id="valueType" name="valueType">
-           <option value="INTEGER">$i18n.getString( "int" )</option>
-           <option value="INTEGER_POSITIVE">$i18n.getString( "positive_integer" )</option>
-           <option value="INTEGER_NEGATIVE">$i18n.getString( "negative_integer" )</option>
-           <option value="INTEGER_ZERO_OR_POSITIVE">$i18n.getString( "zero_positive_int" )</option>
-           <option value="COORDINATE">$i18n.getString( "coordinate" )</option>
-           <option value="NUMBER">$i18n.getString( "number" )</option>
-           <option value="UNIT_INTERVAL">$i18n.getString( "unit_interval" )</option>
-           <option value="PERCENTAGE">$i18n.getString( "percentage" )</option>
-           <option value="TEXT">$i18n.getString( "text" )</option>
-           <option value="LONG_TEXT">$i18n.getString( "long_text" )</option>
-           <option value="DATE">$i18n.getString( "date" )</option>
-           <option value="USERNAME">$i18n.getString( "user_name" )</option>
-           <option value="BOOLEAN">$i18n.getString( "yes_no" )</option>
-           <option value="TRUE_ONLY">$i18n.getString( "yes_only" )</option>
-         </select>
-   		</td>
-   	</tr>
-	<tr>
-	  <td></td>
-	  <td colspan="3">
-		<input type="submit"  value="$i18n.getString( 'add' )" style="width:10em">
-		<input type="button" onclick="window.location.href='optionSet.action'" value="$i18n.getString( 'cancel' )" style="width:10em"/></p>
-      </td>
-	</tr>
+      <td><label for="valueType">$i18n.getString( "value_type" ) <em title="$i18n.getString( 'required' )" class="required">*</em></label></td>
+      <td>
+        <select id="valueType" name="valueType">
+          <option value="INTEGER">$i18n.getString( "int" )</option>
+          <option value="INTEGER_POSITIVE">$i18n.getString( "positive_integer" )</option>
+          <option value="INTEGER_NEGATIVE">$i18n.getString( "negative_integer" )</option>
+          <option value="INTEGER_ZERO_OR_POSITIVE">$i18n.getString( "zero_positive_int" )</option>
+          <option value="COORDINATE">$i18n.getString( "coordinate" )</option>
+          <option value="NUMBER">$i18n.getString( "number" )</option>
+          <option value="UNIT_INTERVAL">$i18n.getString( "unit_interval" )</option>
+          <option value="PERCENTAGE">$i18n.getString( "percentage" )</option>
+          <option value="TEXT">$i18n.getString( "text" )</option>
+          <option value="LONG_TEXT">$i18n.getString( "long_text" )</option>
+          <option value="DATE">$i18n.getString( "date" )</option>
+          <option value="USERNAME">$i18n.getString( "user_name" )</option>
+          <option value="BOOLEAN">$i18n.getString( "yes_no" )</option>
+          <option value="TRUE_ONLY">$i18n.getString( "yes_only" )</option>
+        </select>
+      </td>
+    </tr>
+  </table>
+
+  #tblDynamicAttributes( { "attributes": $attributes, "attributeValues": $attributeValues } )
+
+  <table>
+    <tr>
+      <td></td>
+      <td colspan="3">
+        <input type="submit" value="$i18n.getString( 'add' )" style="width:10em">
+        <input type="button" onclick="window.location.href='optionSet.action'" value="$i18n.getString( 'cancel' )" style="width:10em"/></p>
+      </td>
+    </tr>
   </table>
 </form>

=== modified file 'dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-dataadmin/src/main/webapp/dhis-web-maintenance-dataadmin/updateAttributeForm.vm'
--- dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-dataadmin/src/main/webapp/dhis-web-maintenance-dataadmin/updateAttributeForm.vm	2015-12-17 11:44:56 +0000
+++ dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-dataadmin/src/main/webapp/dhis-web-maintenance-dataadmin/updateAttributeForm.vm	2015-12-17 13:36:30 +0000
@@ -73,6 +73,7 @@
       <input type="checkbox" id="categoryOptionGroupAttribute" name="categoryOptionGroupAttribute" value="true" #if( $attribute.categoryOptionGroupAttribute ) checked="checked" #end /><label for="categoryOptionGroupAttribute">$i18n.getString( 'category_option_group' ) <br />
       <input type="checkbox" id="documentAttribute" name="documentAttribute" value="true" #if( $attribute.documentAttribute ) checked="checked" #end /><label for="documentAttribute">$i18n.getString( 'document' ) <br />
       <input type="checkbox" id="optionAttribute" name="optionAttribute" value="true" #if( $attribute.optionAttribute ) checked="checked" #end /><label for="optionAttribute">$i18n.getString( 'option' ) <br />
+      <input type="checkbox" id="optionSetAttribute" name="optionSetAttribute" value="true" #if( $attribute.optionSetAttribute ) checked="checked" #end /><label for="optionSetAttribute">$i18n.getString( 'option_set' ) <br />
 		</label> <br />
 		</td>
 	</tr>

=== modified file 'dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-dataadmin/src/main/webapp/dhis-web-maintenance-dataadmin/updateOptionSetForm.vm'
--- dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-dataadmin/src/main/webapp/dhis-web-maintenance-dataadmin/updateOptionSetForm.vm	2015-09-14 11:09:56 +0000
+++ dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-dataadmin/src/main/webapp/dhis-web-maintenance-dataadmin/updateOptionSetForm.vm	2015-12-17 13:36:30 +0000
@@ -1,10 +1,16 @@
 <script type="text/javascript">
-	jQuery(document).ready(	function() {
-		validation2( 'updateOptionSetForm', function( form ){ form.submit() }, {
-			'beforeValidateHandler': function() { listValidator( 'memberValidator', 'options' ); }		});
+  jQuery(document).ready(function() {
+    validation2('updateOptionSetForm', function(form) {
+      #tblDynamicAttributesJavascript()
+      form.submit()
+    }, {
+      'beforeValidateHandler': function() {
+        listValidator('memberValidator', 'options');
+      }
+    });
 
-		checkValueIsExist( "name", "validateOptionSet.action",{id:getFieldValue('id')});	
-	});
+    checkValueIsExist("name", "validateOptionSet.action", { id: getFieldValue('id') });
+  });
 
 </script>
 
@@ -14,48 +20,53 @@
   <input id='id' name='id' value='$optionSet.id' type='hidden'>
   <table>
     <colgroup>
-        <col width="50px" />
-        <col width="150px"/>
-        <col width="50px"/>
+      <col width="50px"/>
+      <col width="150px"/>
+      <col width="50px"/>
     </colgroup>
     <tr>
-      <th colspan='3'>$i18n.getString( "details" )</th>      
+      <th colspan='3'>$i18n.getString( "details" )</th>
     </tr>
     <tr>
       <td><label>$i18n.getString( "name" ) <em title="$i18n.getString( 'required' )" class="required">*</em></label></td>
-      <td ><input type="text" id="name" name="name" value='$optionSet.name' class="{validate:{required:true,minlength:2}}" /></td>
+      <td><input type="text" id="name" name="name" value='$optionSet.name' class="{validate:{required:true,minlength:2}}"/></td>
     </tr>
     <tr>
       <td><label>$i18n.getString( "code" )</label></td>
-      <td ><input type="text" id="code" name="code" value='$!optionSet.code' class="{validate:{minlength:2}}" /></td>
+      <td><input type="text" id="code" name="code" value='$!optionSet.code' class="{validate:{minlength:2}}"/></td>
     </tr>
     <tr>
-   		<td><label for="valueType">$i18n.getString( "value_type" ) <em title="$i18n.getString( 'required' )" class="required">*</em></label></td>
-   		<td>
-         <select id="valueType" name="valueType" disabled style="background-color: lightgrey;">
-           <option value="INTEGER" #if( $!optionSet.valueType == 'INTEGER' ) selected="selected" #end >$i18n.getString( "int" )</option>
-           <option value="INTEGER_POSITIVE" #if( $!optionSet.valueType == 'INTEGER_POSITIVE' ) selected="selected" #end >$i18n.getString( "positive_integer" )</option>
-           <option value="INTEGER_NEGATIVE" #if( $!optionSet.valueType == 'INTEGER_NEGATIVE' ) selected="selected" #end >$i18n.getString( "negative_integer" )</option>
-           <option value="INTEGER_ZERO_OR_POSITIVE" #if( $!optionSet.valueType == 'INTEGER_ZERO_OR_POSITIVE' ) selected="selected" #end >$i18n.getString( "zero_positive_int" )</option>
-           <option value="COORDINATE" #if( $!optionSet.valueType == 'COORDINATE' ) selected="selected" #end >$i18n.getString( "coordinate" )</option>
-           <option value="NUMBER" #if( $!optionSet.valueType == 'NUMBER' ) selected="selected" #end >$i18n.getString( "number" )</option>
-           <option value="UNIT_INTERVAL" #if( $!optionSet.valueType == 'UNIT_INTERVAL' ) selected="selected" #end >$i18n.getString( "unit_interval" )</option>
-           <option value="PERCENTAGE" #if( $!optionSet.valueType == 'PERCENTAGE' ) selected="selected" #end >$i18n.getString( "percentage" )</option>
-           <option value="TEXT" #if( $!optionSet.valueType == 'TEXT' ) selected="selected" #end >$i18n.getString( "text" )</option>
-           <option value="LONG_TEXT" #if( $!optionSet.valueType == 'LONG_TEXT' ) selected="selected" #end >$i18n.getString( "long_text" )</option>
-           <option value="DATE" #if( $!optionSet.valueType == 'DATE' ) selected="selected" #end >$i18n.getString( "date" )</option>
-           <option value="USERNAME" #if( $!optionSet.valueType == 'USERNAME' ) selected="selected" #end >$i18n.getString( "user_name" )</option>
-           <option value="BOOLEAN" #if( $!optionSet.valueType == 'BOOLEAN' ) selected="selected" #end >$i18n.getString( "yes_no" )</option>
-           <option value="TRUE_ONLY" #if( $!optionSet.valueType == 'TRUE_ONLY' ) selected="selected" #end >$i18n.getString( "yes_only" )</option>
-         </select>
-   		</td>
-   	</tr>
-	<tr>
-	  <td></td>
-	  <td colspan="2">
-		<input type="submit"  value="$i18n.getString( 'update' )" style="width:10em">
-		<input type="button" onclick="window.location.href='optionSet.action'" value="$i18n.getString( 'cancel' )" style="width:10em"/></p>
+      <td><label for="valueType">$i18n.getString( "value_type" ) <em title="$i18n.getString( 'required' )" class="required">*</em></label></td>
+      <td>
+        <select id="valueType" name="valueType" disabled style="background-color: lightgrey;">
+          <option value="INTEGER" #if( $!optionSet.valueType == 'INTEGER' ) selected="selected" #end >$i18n.getString( "int" )</option>
+          <option value="INTEGER_POSITIVE" #if( $!optionSet.valueType == 'INTEGER_POSITIVE' ) selected="selected" #end >$i18n.getString( "positive_integer" )</option>
+          <option value="INTEGER_NEGATIVE" #if( $!optionSet.valueType == 'INTEGER_NEGATIVE' ) selected="selected" #end >$i18n.getString( "negative_integer" )</option>
+          <option value="INTEGER_ZERO_OR_POSITIVE" #if( $!optionSet.valueType == 'INTEGER_ZERO_OR_POSITIVE' ) selected="selected" #end >$i18n.getString( "zero_positive_int" )</option>
+          <option value="COORDINATE" #if( $!optionSet.valueType == 'COORDINATE' ) selected="selected" #end >$i18n.getString( "coordinate" )</option>
+          <option value="NUMBER" #if( $!optionSet.valueType == 'NUMBER' ) selected="selected" #end >$i18n.getString( "number" )</option>
+          <option value="UNIT_INTERVAL" #if( $!optionSet.valueType == 'UNIT_INTERVAL' ) selected="selected" #end >$i18n.getString( "unit_interval" )</option>
+          <option value="PERCENTAGE" #if( $!optionSet.valueType == 'PERCENTAGE' ) selected="selected" #end >$i18n.getString( "percentage" )</option>
+          <option value="TEXT" #if( $!optionSet.valueType == 'TEXT' ) selected="selected" #end >$i18n.getString( "text" )</option>
+          <option value="LONG_TEXT" #if( $!optionSet.valueType == 'LONG_TEXT' ) selected="selected" #end >$i18n.getString( "long_text" )</option>
+          <option value="DATE" #if( $!optionSet.valueType == 'DATE' ) selected="selected" #end >$i18n.getString( "date" )</option>
+          <option value="USERNAME" #if( $!optionSet.valueType == 'USERNAME' ) selected="selected" #end >$i18n.getString( "user_name" )</option>
+          <option value="BOOLEAN" #if( $!optionSet.valueType == 'BOOLEAN' ) selected="selected" #end >$i18n.getString( "yes_no" )</option>
+          <option value="TRUE_ONLY" #if( $!optionSet.valueType == 'TRUE_ONLY' ) selected="selected" #end >$i18n.getString( "yes_only" )</option>
+        </select>
       </td>
-	</tr>
+    </tr>
+  </table>
+
+  #tblDynamicAttributes( { "attributes": $attributes, "attributeValues": $attributeValues } )
+
+  <table>
+  <tr>
+    <td></td>
+    <td colspan="2">
+      <input type="submit" value="$i18n.getString( 'update' )" style="width:10em">
+      <input type="button" onclick="window.location.href='optionSet.action'" value="$i18n.getString( 'cancel' )" style="width:10em"/></p>
+    </td>
+  </tr>
   </table>
 </form>