diff --git a/CMake/LofarPackageList.cmake b/CMake/LofarPackageList.cmake
index a54966e0ffb3587a9b9410d65317abe283462504..f151e9395a89417b77f596cc5105a4f0ef8ef335 100644
--- a/CMake/LofarPackageList.cmake
+++ b/CMake/LofarPackageList.cmake
@@ -1,7 +1,7 @@
 # - Create for each LOFAR package a variable containing the absolute path to
 # its source directory. 
 #
-# Generated by gen_LofarPackageList_cmake.sh at do 21 jan 2021 13:07:07 CET
+# Generated by gen_LofarPackageList_cmake.sh at di  9 feb 2021 14:22:29 CET
 #
 #                      ---- DO NOT EDIT ----
 #
@@ -96,6 +96,7 @@ if(NOT DEFINED LOFAR_PACKAGE_LIST_INCLUDED)
   set(LTAIngest_SOURCE_DIR ${CMAKE_SOURCE_DIR}/LTA/LTAIngest)
   set(ltastorageoverview_SOURCE_DIR ${CMAKE_SOURCE_DIR}/LTA/ltastorageoverview)
   set(sip_SOURCE_DIR ${CMAKE_SOURCE_DIR}/LTA/sip)
+  set(LTACatalogue_SOURCE_DIR ${CMAKE_SOURCE_DIR}/LTA/LTACatalogue)
   set(LTAIngestCommon_SOURCE_DIR ${CMAKE_SOURCE_DIR}/LTA/LTAIngest/LTAIngestCommon)
   set(LTAIngestServer_SOURCE_DIR ${CMAKE_SOURCE_DIR}/LTA/LTAIngest/LTAIngestServer)
   set(LTAIngestClient_SOURCE_DIR ${CMAKE_SOURCE_DIR}/LTA/LTAIngest/LTAIngestClient)
diff --git a/CMake/variants/variants.cbm206 b/CMake/variants/variants.cbm206
index 75b51fb5fec037c6b10f57bd67b226075ea31122..13b95d875c4f57fbd9cf1b52aaa133b9e04fa076 100644
--- a/CMake/variants/variants.cbm206
+++ b/CMake/variants/variants.cbm206
@@ -11,7 +11,7 @@ option(USE_LOG4CPLUS "Use Log4Cplus" ON)
 option(USE_MPI       "Use MPI"       ON)
 
 set(CASACORE_ROOT_DIR /opt/casacore/3.0.0)
-set(DAL_ROOT_DIR      /opt/DAL/3.3.1)
+set(DAL_ROOT_DIR      /opt/DAL/3.3.2)
 set(BLITZ_ROOT_DIR    /opt/blitz/1.0.1)
 
 # MPI_ROOT_DIR does not need to be specified, because it can just be found thanks to the usage of mpi-selector
diff --git a/CMake/variants/variants.head01 b/CMake/variants/variants.head01
index 891fc9269fc6156b6b67d2063c5e66d7ecd0e23f..8e14b09865dafd8b7f1b3cc0510e54ff84e25c3f 100644
--- a/CMake/variants/variants.head01
+++ b/CMake/variants/variants.head01
@@ -1,2 +1,2 @@
 set(CASACORE_ROOT_DIR /opt/casacore-v3.0.0)
-set(DAL_ROOT_DIR      /opt/DAL-v3.3.1)
+set(DAL_ROOT_DIR      /opt/DAL-v3.3.2)
diff --git a/Docker/lofar-ci/Dockerfile_ci_base b/Docker/lofar-ci/Dockerfile_ci_base
index 1afd6427e70ff6bc4c5937f5986241e418751e0c..35016a984fb0dd38b48cef912ed12cfa5d1caec4 100644
--- a/Docker/lofar-ci/Dockerfile_ci_base
+++ b/Docker/lofar-ci/Dockerfile_ci_base
@@ -8,6 +8,7 @@ FROM centos:centos7.6.1810
 RUN yum -y groupinstall 'Development Tools' && \
     yum -y install epel-release && \
     yum -y install cmake cmake3 gcc git log4cplus-devel python3 python3-devel python3-pip which wget curl atop valgrind && \
+    python3 -m pip install -U pip && \
     pip3 install kombu==4.6.8 requests coverage python-qpid-proton && \
     adduser lofarsys && \
     mkdir -p /opt/lofar && chown -R lofarsys:lofarsys /opt
diff --git a/LCS/Messaging/python/messaging/config.py b/LCS/Messaging/python/messaging/config.py
index c8ea8f0763e0d97779fc78a78caa9abbf0e5e63c..7373d04e9077f0be5f188f7be8c6236909cbd64a 100644
--- a/LCS/Messaging/python/messaging/config.py
+++ b/LCS/Messaging/python/messaging/config.py
@@ -5,6 +5,8 @@ logger = logging.getLogger(__name__)
 import kombu
 # make default kombu/amqp logger less spammy
 logging.getLogger("amqp").setLevel(logging.INFO)
+# we're logging when this file is loaded, so format must be correct
+logging.basicConfig(format = '%(asctime)s %(levelname)s %(message)s', level = logging.INFO)
 
 from lofar.messaging import adaptNameToEnvironment
 from lofar.common import isProductionEnvironment, isTestEnvironment
@@ -59,6 +61,8 @@ for port in possible_ports:
     except Exception as e:
         logger.debug("cannot connect to broker: hostname=%s port=%s userid=%s password=*** error=%s",
                      DEFAULT_BROKER, port, DEFAULT_USER, e)
+else:
+    logger.error("Cannot connect to rabbitmq broker with hostname=%s userid=%s password=***. I tried ports %s.", DEFAULT_BROKER, DEFAULT_USER, possible_ports)
 
 # default exchange to use for publishing messages
 DEFAULT_BUSNAME = adaptNameToEnvironment(os.environ.get('LOFAR_DEFAULT_EXCHANGE', 'lofar'))
diff --git a/LCS/PyCommon/CMakeLists.txt b/LCS/PyCommon/CMakeLists.txt
index 2ab093021552dc5a10dcd660e127dd67f0be96b4..8e03082eebc95c9b2150c9d8589e84bb450615b2 100644
--- a/LCS/PyCommon/CMakeLists.txt
+++ b/LCS/PyCommon/CMakeLists.txt
@@ -8,6 +8,7 @@ include(PythonInstall)
 include(FindPythonModule)
 find_python_module(jsonschema)
 find_python_module(psycopg2)
+find_python_module(cx_Oracle)
 
 set(_py_files
   __init__.py
@@ -22,6 +23,8 @@ set(_py_files
   math.py
   methodtrigger.py
   util.py
+  database.py
+  oracle.py
   postgres.py
   datetimeutils.py
   flask_utils.py
diff --git a/LCS/PyCommon/database.py b/LCS/PyCommon/database.py
new file mode 100644
index 0000000000000000000000000000000000000000..77951c94f88a89e508c0df2f8653516cc67f0ab7
--- /dev/null
+++ b/LCS/PyCommon/database.py
@@ -0,0 +1,203 @@
+#!/usr/bin/env python3
+
+# Copyright (C) 2012-2015  ASTRON (Netherlands Institute for Radio Astronomy)
+# P.O. Box 2, 7990 AA Dwingeloo, The Netherlands
+#
+# This file is part of the LOFAR software suite.
+# The LOFAR software suite is free software: you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as published
+# by the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# The LOFAR software suite is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with the LOFAR software suite. If not, see <http://www.gnu.org/licenses/>.
+
+# $Id$
+
+'''
+common abstract database connection class
+'''
+
+import logging
+from datetime import  datetime, timedelta
+import collections
+import time
+import re
+from lofar.common.util import single_line_with_single_spaces
+from lofar.common.dbcredentials import DBCredentials
+
+logger = logging.getLogger(__name__)
+
+FETCH_NONE=0
+FETCH_ONE=1
+FETCH_ALL=2
+
+class DatabaseError(Exception):
+    pass
+
+class DatabaseConnectionError(DatabaseError):
+    pass
+
+class DatabaseExecutionError(DatabaseError):
+    pass
+
+class AbstractDatabaseConnection:
+    '''Abstract DatabaseConnection class defining a uniform class API for lofar database connections.'''
+    def __init__(self,
+                 dbcreds: DBCredentials,
+                 auto_commit_selects: bool=False,
+                 num_connect_retries: int=5,
+                 connect_retry_interval: float=1.0,
+                 query_timeout: float=3600):
+        self._dbcreds = dbcreds
+        self._connection = None
+        self._cursor = None
+        self.__auto_commit_selects = auto_commit_selects
+        self.__num_connect_retries = num_connect_retries
+        self.__connect_retry_interval = connect_retry_interval
+        self.__query_timeout = query_timeout
+
+    def connect_if_needed(self):
+        if not self.is_connected:
+            self.connect()
+
+    def connect(self):
+        if self.is_connected:
+            logger.debug("already connected to database: %s", self)
+            return
+
+        for retry_cntr in range(self.__num_connect_retries+1):
+            try:
+                logger.debug("connecting to database: %s", self)
+
+                # let the subclass create the connection and cursor.
+                # handle connection errors here.
+                self._connection, self._cursor = self._do_create_connection_and_cursor()
+                logger.info("connected to database: %s", self)
+                # we have a proper connection, so return
+                return
+            except Exception as error:
+                error_string = single_line_with_single_spaces(error)
+                logger.error(error_string)
+
+                if self._is_recoverable_connection_error(error):
+                    # try to reconnect on connection-like-errors
+                    if retry_cntr == self.__num_connect_retries:
+                        raise DatabaseConnectionError("Error while connecting to %s. error=%s" % (self, error_string))
+
+                    logger.info('retrying to connect to %s in %s seconds', self.database, self.__connect_retry_interval)
+                    time.sleep(self.__connect_retry_interval)
+                else:
+                    # non-connection-error, raise generic DatabaseError
+                    raise DatabaseError(error_string)
+
+    def disconnect(self):
+        if self._connection is not None or self._cursor is not None:
+            logger.debug("disconnecting from database: %s", self)
+
+            if self._cursor is not None:
+                self._cursor.close()
+                self._cursor = None
+
+            if self._connection is not None:
+                self._connection.close()
+                self._connection = None
+
+            logger.info("disconnected from database: %s", self)
+
+    def _is_recoverable_connection_error(self, error: Exception) -> bool:
+        return False
+
+    def __str__(self) -> str:
+        '''returns the class name and connection string with hidden password.'''
+        return "%s %s" % (self.__class__.__name__, self._dbcreds.stringWithHiddenPassword())
+
+    @property
+    def database(self) -> str:
+        '''returns the database name'''
+        return self._dbcreds.database
+
+    @property
+    def dbcreds(self) -> DBCredentials:
+        '''returns the database credentials'''
+        return self._dbcreds
+
+    @property
+    def is_connected(self) -> bool:
+        return self._connection is not None
+
+    def reconnect(self):
+        logger.info("reconnecting %s", self)
+        self.disconnect()
+        self.connect()
+
+    def __enter__(self):
+        '''connects to the database'''
+        try:
+            self.connect()
+        except:
+            self.disconnect()
+            raise
+        return self
+
+    def __exit__(self, exc_type, exc_val, exc_tb):
+        '''disconnects from the database'''
+        self.disconnect()
+
+    @staticmethod
+    def _queryAsSingleLine(query, qargs=None):
+        line = ' '.join(single_line_with_single_spaces(query).split())
+        if qargs:
+            line = line % tuple(['\'%s\'' % a if isinstance(a, str) else a for a in qargs])
+        return line
+
+    def executeQuery(self, query, qargs=None, fetch=FETCH_NONE):
+        start = datetime.utcnow()
+        while True:
+            try:
+                return self._do_execute_query(query, qargs, fetch)
+            except DatabaseConnectionError as e:
+                logger.warning(e)
+                if datetime.utcnow() - start < timedelta(seconds=self.__query_timeout):
+                    try:
+                        # reconnect, log retrying..., and do the retry in the next loop iteration
+                        self.reconnect()
+                        logger.info("retrying %s", self._queryAsSingleLine(query, qargs))
+                    except DatabaseConnectionError as ce:
+                        logger.warning(ce)
+                else:
+                    raise
+            except Exception as error:
+                self._log_error_rollback_and_raise(error, self._queryAsSingleLine(query, qargs))
+
+    def _do_execute_query(self, query, qargs=None, fetch=FETCH_NONE):
+        raise NotImplementedError()
+
+    def _log_error_rollback_and_raise(self, e: Exception, query_log_line: str):
+        error_string = single_line_with_single_spaces(e)
+        logger.error("Rolling back query=\'%s\' due to error: \'%s\'" % (query_log_line, error_string))
+        self.rollback()
+
+        # wrap original error in DatabaseExecutionError and raise
+        raise DatabaseExecutionError("Could not execute query '%s' error=%s" % (query_log_line, error_string))
+
+    def _commit_selects_if_needed(self, query):
+        if self.__auto_commit_selects and re.search('select', query, re.IGNORECASE):
+            # prevent dangling in idle transaction on server
+            self.commit()
+
+    def commit(self):
+        if self.is_connected:
+            logger.debug('commit')
+            self._connection.commit()
+
+    def rollback(self):
+        if self.is_connected:
+            logger.debug('rollback')
+            self._connection.rollback()
+
diff --git a/LCS/PyCommon/json_utils.py b/LCS/PyCommon/json_utils.py
index 0ff868fe1f18f5a6066fe7057531139d920b8d19..402ad319a91fac270cc7a0879dae4a0be28c764a 100644
--- a/LCS/PyCommon/json_utils.py
+++ b/LCS/PyCommon/json_utils.py
@@ -24,7 +24,6 @@ def _extend_with_default(validator_class):
     """
     Extend the properties validation so that it adds missing properties with their default values (where one is defined
     in the schema).
-    Note: Make sure that items of type object or array in the schema define empty structures as defaults for this to
     traverse down and add enclosed properties.
     see: <https://python-jsonschema.readthedocs.io/en/stable/faq/#why-doesn-t-my-schema-s-default-property-set-the-default-on-my-instance>
     """
@@ -34,6 +33,15 @@ def _extend_with_default(validator_class):
         for property, subschema in properties.items():
             if "default" in subschema:
                 instance.setdefault(property, subschema["default"])
+            elif "type" not in subschema:
+                # could be anything, probably a $ref.
+                pass
+            elif subschema["type"] == "object":
+                # giving objects the {} default causes that default to be populated by the properties of the object
+                instance.setdefault(property, {})
+            elif subschema["type"] == "array":
+                # giving arrays the [] default causes that default to be populated by the items of the array
+                instance.setdefault(property, [])
         for error in validate_properties(
             validator, properties, instance, schema,
         ):
diff --git a/LCS/PyCommon/oracle.py b/LCS/PyCommon/oracle.py
new file mode 100644
index 0000000000000000000000000000000000000000..de63802072b0cea65a1a1870b3873d3edf2ddeee
--- /dev/null
+++ b/LCS/PyCommon/oracle.py
@@ -0,0 +1,149 @@
+#!/usr/bin/env python3
+
+# Copyright (C) 2012-2015  ASTRON (Netherlands Institute for Radio Astronomy)
+# P.O. Box 2, 7990 AA Dwingeloo, The Netherlands
+#
+# This file is part of the LOFAR software suite.
+# The LOFAR software suite is free software: you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as published
+# by the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# The LOFAR software suite is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with the LOFAR software suite. If not, see <http://www.gnu.org/licenses/>.
+
+# $Id$
+
+'''
+Module with nice postgres helper methods and classes.
+'''
+
+import logging
+from datetime import datetime, timedelta
+import cx_Oracle
+import re
+from lofar.common.dbcredentials import DBCredentials
+from lofar.common.database import AbstractDatabaseConnection, DatabaseError, DatabaseConnectionError, DatabaseExecutionError, FETCH_NONE, FETCH_ONE, FETCH_ALL
+from lofar.common.util import single_line_with_single_spaces
+
+logger = logging.getLogger(__name__)
+
+
+class OracleDBError(DatabaseError):
+    pass
+
+class OracleDBConnectionError(OracleDBError, DatabaseConnectionError):
+    pass
+
+class OracleDBQueryExecutionError(OracleDBError, DatabaseExecutionError):
+    pass
+
+class OracleDatabaseConnection(AbstractDatabaseConnection):
+    def _do_create_connection_and_cursor(self):
+        connection = cx_Oracle.connect(self._dbcreds.user,
+                                       self._dbcreds.password,
+                                       "%s:%s/%s" % (self._dbcreds.host, self._dbcreds.port, self._dbcreds.database))
+
+        cursor = connection.cursor()
+        return connection, cursor
+
+    @property
+    def is_connected(self) -> bool:
+        return super().is_connected and self._connection.handle!=0
+
+    def _is_recoverable_connection_error(self, error: cx_Oracle.DatabaseError) -> bool:
+        '''test if cx_Oracle.DatabaseError is a recoverable connection error'''
+        if isinstance(error, cx_Oracle.OperationalError) and re.search('connection', str(error), re.IGNORECASE):
+            return True
+
+        if error.code is not None:
+            # # see https://docs.oracle.com/cd/B19306_01/server.102/b14219.pdf
+            # TODO: check which oracle error code indicates a recoverable connection error.
+            pass
+
+        return False
+
+    def _do_execute_query(self, query, qargs=None, fetch=FETCH_NONE):
+        '''execute the query and reconnect upon OperationalError'''
+        query_log_line = self._queryAsSingleLine(query, qargs)
+
+        try:
+            self.connect_if_needed()
+
+            # log
+            logger.debug('executing query: %s', query_log_line)
+
+            # execute (and time it)
+            start = datetime.utcnow()
+            if qargs:
+                arg_cntr = 0
+                while '%s' in query:
+                    query = query.replace('%s', ':arg_%03d'%arg_cntr, 1)
+                    arg_cntr += 1
+                assert arg_cntr == len(qargs)
+
+            self._cursor.execute(query, qargs or tuple())
+
+            # use rowfactory to turn the results into dicts of (col_name, value) pairs
+            if self._cursor.description:
+                columns = [col[0] for col in self._cursor.description]
+                self._cursor.rowfactory = lambda *col_args: dict(zip(columns, col_args))
+
+            elapsed = datetime.utcnow() - start
+            elapsed_ms = 1000.0 * elapsed.total_seconds()
+
+            # log execution result
+            logger.info('executed query in %.1fms%s yielding %s rows: %s', elapsed_ms,
+                                                                           ' (SLOW!)' if elapsed_ms > 250 else '', # for easy log grep'ing
+                                                                           self._cursor.rowcount,
+                                                                           query_log_line)
+
+            self._commit_selects_if_needed(query)
+
+            # fetch and return results
+            if fetch == FETCH_ONE:
+                row = self._cursor.fetchone()
+                return row if row is not None else None
+            if fetch == FETCH_ALL:
+                return [row for row in self._cursor.fetchall() if row is not None]
+            return []
+
+        except cx_Oracle.OperationalError as oe:
+            if self._is_recoverable_connection_error(oe):
+                raise OracleDBConnectionError("Could not execute query due to connection errors. '%s' error=%s" %
+                                                (query_log_line,
+                                                 single_line_with_single_spaces(oe)))
+            else:
+                self._log_error_rollback_and_raise(oe, query_log_line)
+
+        except Exception as e:
+            self._log_error_rollback_and_raise(e, query_log_line)
+
+    def _log_error_rollback_and_raise(self, e: Exception, query_log_line: str):
+        error_string = single_line_with_single_spaces(e)
+        logger.error("Rolling back query=\'%s\' due to error: \'%s\'" % (query_log_line, error_string))
+        self.rollback()
+        if isinstance(e, OracleDBError):
+            # just re-raise our OracleDBError
+            raise
+        else:
+            # wrap original error in OracleDBQueryExecutionError
+            raise OracleDBQueryExecutionError("Could not execute query '%s' error=%s" % (query_log_line, error_string))
+
+
+if __name__ == '__main__':
+    logging.basicConfig(format = '%(asctime)s %(levelname)s %(message)s', level = logging.INFO)
+
+    dbcreds = DBCredentials().get('LTA')
+    print(dbcreds.stringWithHiddenPassword())
+
+    with OracleDatabaseConnection(dbcreds=dbcreds) as db:
+        from pprint import pprint
+        pprint(db.executeQuery("SELECT table_name, owner, tablespace_name FROM all_tables", fetch=FETCH_ALL))
+        # pprint(db.executeQuery("SELECT * FROM awoper.aweprojects", fetch=FETCH_ALL))
+        #pprint(db.executeQuery("SELECT * FROM awoper.aweprojectusers", fetch=FETCH_ALL))
diff --git a/LCS/PyCommon/postgres.py b/LCS/PyCommon/postgres.py
index db1092fea0db908ab0cb27664f5a8c34b862ee57..84a50c779d733de0e54498f9337eb858dbf795d5 100644
--- a/LCS/PyCommon/postgres.py
+++ b/LCS/PyCommon/postgres.py
@@ -37,6 +37,7 @@ import psycopg2.extensions
 from lofar.common.util import single_line_with_single_spaces
 from lofar.common.datetimeutils import totalSeconds
 from lofar.common.dbcredentials import DBCredentials
+from lofar.common.database import AbstractDatabaseConnection, DatabaseError, DatabaseConnectionError, DatabaseExecutionError, FETCH_NONE, FETCH_ONE, FETCH_ALL
 
 logger = logging.getLogger(__name__)
 
@@ -115,166 +116,47 @@ def makePostgresNotificationQueries(schema, table, action, column_name=None, quo
     sql_lines = '\n'.join([s.strip() for s in sql.split('\n')]) + '\n'
     return sql_lines
 
-FETCH_NONE=0
-FETCH_ONE=1
-FETCH_ALL=2
-
-class PostgresDBError(Exception):
+class PostgresDBError(DatabaseError):
     pass
 
-class PostgresDBConnectionError(PostgresDBError):
+class PostgresDBConnectionError(PostgresDBError, DatabaseConnectionError):
     pass
 
-class PostgresDBQueryExecutionError(PostgresDBError):
+class PostgresDBQueryExecutionError(PostgresDBError, DatabaseExecutionError):
     pass
 
-class PostgresDatabaseConnection:
-    def __init__(self,
-                 dbcreds: DBCredentials,
-                 auto_commit_selects: bool=False,
-                 num_connect_retries: int=5,
-                 connect_retry_interval: float=1.0,
-                 query_timeout: float=3600):
-        self._dbcreds = dbcreds
-        self._connection = None
-        self._cursor = None
-        self.__auto_commit_selects = auto_commit_selects
-        self.__num_connect_retries = num_connect_retries
-        self.__connect_retry_interval = connect_retry_interval
-        self.__query_timeout = query_timeout
-
-    def connect_if_needed(self):
-        if not self.is_connected:
-            self.connect()
+class PostgresDatabaseConnection(AbstractDatabaseConnection):
+    '''A DatabaseConnection to a postgres database using the common API from lofar AbstractDatabaseConnection'''
+    def _do_create_connection_and_cursor(self):
+        connection = psycopg2.connect(host=self._dbcreds.host,
+                                            user=self._dbcreds.user,
+                                            password=self._dbcreds.password,
+                                            database=self._dbcreds.database,
+                                            port=self._dbcreds.port,
+                                            connect_timeout=5)
 
-    def connect(self):
-        if self.is_connected:
-            logger.debug("already connected to database: %s", self)
-            return
-
-        for retry_cntr in range(self.__num_connect_retries+1):
-            try:
-                logger.debug("connecting to database: %s", self)
-
-                self._connection = psycopg2.connect(host=self._dbcreds.host,
-                                                    user=self._dbcreds.user,
-                                                    password=self._dbcreds.password,
-                                                    database=self._dbcreds.database,
-                                                    port=self._dbcreds.port,
-                                                    connect_timeout=5)
-
-                if self._connection:
-                    self._cursor = self._connection.cursor(cursor_factory=psycopg2.extras.RealDictCursor)
-
-                    logger.info("connected to database: %s", self)
-
-                    # see http://initd.org/psycopg/docs/connection.html#connection.notices
-                    # try to set the notices attribute with a non-list collection,
-                    # so we can log more than 50 messages. Is only available since 2.7, so encapsulate in try/except.
-                    try:
-                        self._connection.notices = collections.deque()
-                    except TypeError:
-                        logger.warning("Cannot overwrite self._connection.notices with a deque... only max 50 notifications available per query. (That's ok, no worries.)")
-
-                    # we have a proper connection, so return
-                    return
-            except psycopg2.DatabaseError as dbe:
-                error_string = single_line_with_single_spaces(dbe)
-                logger.error(error_string)
-
-                if self._is_recoverable_connection_error(dbe):
-                    # try to reconnect on connection-like-errors
-                    if retry_cntr == self.__num_connect_retries:
-                        raise PostgresDBConnectionError("Error while connecting to %s. error=%s" % (self, error_string))
-
-                    logger.info('retrying to connect to %s in %s seconds', self.database, self.__connect_retry_interval)
-                    time.sleep(self.__connect_retry_interval)
-                else:
-                    # non-connection-error, raise generic PostgresDBError
-                    raise PostgresDBError(error_string)
+        cursor = connection.cursor(cursor_factory=psycopg2.extras.RealDictCursor)
+        return connection, cursor
 
-    def disconnect(self):
-        if self._connection is not None or self._cursor is not None:
-            logger.debug("disconnecting from database: %s", self)
-
-            if self._cursor is not None:
-                self._cursor.close()
-                self._cursor = None
-
-            if self._connection is not None:
-                self._connection.close()
-                self._connection = None
-
-            logger.info("disconnected from database: %s", self)
+    @property
+    def is_connected(self) -> bool:
+        return super().is_connected and self._connection.closed==0
 
     def _is_recoverable_connection_error(self, error: psycopg2.DatabaseError) -> bool:
         '''test if psycopg2.DatabaseError is a recoverable connection error'''
         if isinstance(error, psycopg2.OperationalError) and re.search('connection', str(error), re.IGNORECASE):
             return True
 
-        if error.pgcode is not None:
-            # see https://www.postgresql.org/docs/current/errcodes-appendix.html#ERRCODES-TABLE
-            if error.pgcode.startswith('08') or error.pgcode.startswith('57P') or error.pgcode.startswith('53'):
-                return True
+        try:
+            if error.pgcode is not None:
+                # see https://www.postgresql.org/docs/current/errcodes-appendix.html#ERRCODES-TABLE
+                if error.pgcode.startswith('08') or error.pgcode.startswith('57P') or error.pgcode.startswith('53'):
+                    return True
+        except:
+            return False
 
         return False
 
-    def __str__(self) -> str:
-        '''returns the class name and connection string with hidden password.'''
-        return "%s %s" % (self.__class__.__name__, self._dbcreds.stringWithHiddenPassword())
-
-    @property
-    def database(self) -> str:
-        '''returns the database name'''
-        return self._dbcreds.database
-
-    @property
-    def dbcreds(self) -> DBCredentials:
-        '''returns the database credentials'''
-        return self._dbcreds
-
-    @property
-    def is_connected(self) -> bool:
-        return self._connection is not None and self._connection.closed==0
-
-    def reconnect(self):
-        logger.info("reconnecting %s", self)
-        self.disconnect()
-        self.connect()
-
-    def __enter__(self):
-        '''connects to the database'''
-        self.connect()
-        return self
-
-    def __exit__(self, exc_type, exc_val, exc_tb):
-        '''disconnects from the database'''
-        self.disconnect()
-
-    @staticmethod
-    def _queryAsSingleLine(query, qargs=None):
-        line = ' '.join(single_line_with_single_spaces(query).split())
-        if qargs:
-            line = line % tuple(['\'%s\'' % a if isinstance(a, str) else a for a in qargs])
-        return line
-
-    def executeQuery(self, query, qargs=None, fetch=FETCH_NONE):
-        start = datetime.utcnow()
-        while True:
-            try:
-                return self._do_execute_query(query, qargs, fetch)
-            except PostgresDBConnectionError as e:
-                logger.warning(e)
-                if datetime.utcnow() - start < timedelta(seconds=self.__query_timeout):
-                    try:
-                        # reconnect, log retrying..., and do the retry in the next loop iteration
-                        self.reconnect()
-                        logger.info("retrying %s", self._queryAsSingleLine(query, qargs))
-                    except PostgresDBConnectionError as ce:
-                        logger.warning(ce)
-                else:
-                    raise
-
     def _do_execute_query(self, query, qargs=None, fetch=FETCH_NONE):
         '''execute the query and reconnect upon OperationalError'''
         query_log_line = self._queryAsSingleLine(query, qargs)
@@ -333,11 +215,6 @@ class PostgresDatabaseConnection:
             # wrap original error in PostgresDBQueryExecutionError
             raise PostgresDBQueryExecutionError("Could not execute query '%s' error=%s" % (query_log_line, error_string))
 
-    def _commit_selects_if_needed(self, query):
-        if self.__auto_commit_selects and re.search('select', query, re.IGNORECASE):
-            # prevent dangling in idle transaction on server
-            self.commit()
-
     def _log_database_notifications(self):
         try:
             if self._connection.notices:
@@ -350,16 +227,6 @@ class PostgresDatabaseConnection:
         except Exception as e:
             logger.error(str(e))
 
-    def commit(self):
-        if self.is_connected:
-            logger.debug('commit')
-            self._connection.commit()
-
-    def rollback(self):
-        if self.is_connected:
-            logger.debug('rollback')
-            self._connection.rollback()
-
 
 class PostgresListener(PostgresDatabaseConnection):
     ''' This class lets you listen to postgres notifications
diff --git a/LCS/PyCommon/test/t_json_utils.py b/LCS/PyCommon/test/t_json_utils.py
index a315632d8d5cbca4d82b3a9166c6575f4a2b9cea..df044073190350dbd82e7da273a80b1cd6da9950 100755
--- a/LCS/PyCommon/test/t_json_utils.py
+++ b/LCS/PyCommon/test/t_json_utils.py
@@ -53,7 +53,6 @@ class TestJSONUtils(unittest.TestCase):
                   "default": {},
                   "properties": {
                       "sub_a": {"type": "object",
-                       "default": {},
                        "properties": {
                            "prop_a": {"type": "integer", "default": 42},
                            "prop_b": {"type": "number", "default": 3.14}
diff --git a/LCS/PyCommon/test/t_postgres.py b/LCS/PyCommon/test/t_postgres.py
index 8d8b77463e8eae107ce7c109fd77b18aa54d96c3..91e298cfcdc66a93e7c069a0552283b6f460f02d 100755
--- a/LCS/PyCommon/test/t_postgres.py
+++ b/LCS/PyCommon/test/t_postgres.py
@@ -41,8 +41,8 @@ class TestPostgres(MyPostgresTestMixin, unittest.TestCase):
         incorrect_dbcreds.port += 1
 
         # test if connecting fails
-        with mock.patch('lofar.common.postgres.logger') as mocked_logger:
-            with self.assertRaises(PostgresDBConnectionError):
+        with mock.patch('lofar.common.database.logger') as mocked_logger:
+            with self.assertRaises(DatabaseConnectionError):
                 NUM_CONNECT_RETRIES = 2
                 with PostgresDatabaseConnection(dbcreds=incorrect_dbcreds, connect_retry_interval=0.1, num_connect_retries=NUM_CONNECT_RETRIES) as db:
                     pass
@@ -92,7 +92,7 @@ class TestPostgres(MyPostgresTestMixin, unittest.TestCase):
             logger.info("terminated %s test-postgres-database-instance", self.dbcreds.stringWithHiddenPassword())
 
             # prove that the database is down by trying to connect which results in a PostgresDBConnectionError
-            with self.assertRaises(PostgresDBConnectionError):
+            with self.assertRaises(DatabaseConnectionError):
                 with PostgresDatabaseConnection(dbcreds=self.dbcreds, num_connect_retries=0):
                     pass
 
diff --git a/LTA/CMakeLists.txt b/LTA/CMakeLists.txt
index 09f2e770c4c8c878e453fd4e28eb084e777ee1e6..42fe8b5ec425b14492dfdda7ff17633c3305ecac 100644
--- a/LTA/CMakeLists.txt
+++ b/LTA/CMakeLists.txt
@@ -6,3 +6,4 @@ lofar_add_package(LTACommon)
 lofar_add_package(LTAIngest)
 lofar_add_package(ltastorageoverview)
 lofar_add_package(sip)
+lofar_add_package(LTACatalogue)
diff --git a/LTA/LTACatalogue/CMakeLists.txt b/LTA/LTACatalogue/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..6f06bdabd4ef21ff2509710d566fb7d51c588563
--- /dev/null
+++ b/LTA/LTACatalogue/CMakeLists.txt
@@ -0,0 +1,4 @@
+lofar_package(LTACatalogue 1.0 DEPENDS PyCommon)
+
+python_install(lta_catalogue_db.py
+               DESTINATION lofar/lta)
diff --git a/LTA/LTACatalogue/lta_catalogue_db.py b/LTA/LTACatalogue/lta_catalogue_db.py
new file mode 100644
index 0000000000000000000000000000000000000000..65eb1813bc7175ef24be55f6bd7431599f131206
--- /dev/null
+++ b/LTA/LTACatalogue/lta_catalogue_db.py
@@ -0,0 +1,109 @@
+#!/usr/bin/env python3
+
+# Copyright (C) 2012-2015  ASTRON (Netherlands Institute for Radio Astronomy)
+# P.O. Box 2, 7990 AA Dwingeloo, The Netherlands
+#
+# This file is part of the LOFAR software suite.
+# The LOFAR software suite is free software: you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as published
+# by the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# The LOFAR software suite is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with the LOFAR software suite. If not, see <http://www.gnu.org/licenses/>.
+
+# $Id$
+
+'''
+Module with nice postgres helper methods and classes.
+'''
+
+import logging
+from datetime import datetime, timedelta
+from lofar.common.dbcredentials import DBCredentials
+from lofar.common.oracle import OracleDatabaseConnection, FETCH_NONE, FETCH_ONE, FETCH_ALL
+import cx_Oracle
+
+logger = logging.getLogger(__name__)
+
+
+class LTACatalogueDatabaseConnection(OracleDatabaseConnection):
+    '''The LTACatalogueDatabaseConnection is a simple API to query a very limited subset of the full API provided by astrowise.
+    It is intended to be used by some lofar services, and not as a replacement for astrowise.
+    It is also highly discouraged to use this connection object to tinker with the oracle database yourself, unless you really know what you're doing.'''
+
+    DEFAULT_RELEASE_DATE = datetime(2050,1,1)
+
+    def get_projects(self):
+        return self.executeQuery("SELECT * FROM awoper.aweprojects", fetch=FETCH_ALL)
+
+    def get_project_release_date(self, project_name:str) -> datetime:
+        return self.executeQuery("SELECT RELEASEDATE FROM awoper.aweprojects where NAME=%s", qargs=(project_name,), fetch=FETCH_ONE)['RELEASEDATE']
+
+    def get_resources(self) -> []:
+        return self.executeQuery("SELECT * FROM AWOPER.AWERESOURCES_VIEW", fetch=FETCH_ALL)
+
+    def set_project_release_date(self, project_name:str, release_date: datetime):
+        # we update the release date as if we were the IDM system
+        # thus, we insert new release date into the lofaridm.project table where it will be picked up by crontabbed the AWOPER.SYNCFROMIDM procedure
+        # only projects with a default release date of 2050,1,1 are updated in this SYNCFROMIDM procedure, so set it to default first.
+        # after the new release date has been sync'ed and updated to awoper.aweprojects in AWOPER.SYNCFROMIDM, the new release date will be
+        # applied to all its observations/pipelines in another 'crontab'/scheduled job 'AWOPER.SYNC_RELEASE_DATE_CHANGES',
+        # so mind you... Changes in the LTA web UI do not take immediate effect
+        self.executeQuery("UPDATE awoper.aweprojects SET RELEASEDATE=%s WHERE NAME=%s", qargs=(self.DEFAULT_RELEASE_DATE, project_name), fetch=FETCH_NONE)
+        self.executeQuery("UPDATE lofaridm.project SET RELEASEDATE=%s WHERE NAME=%s", qargs=(release_date, project_name), fetch=FETCH_NONE)
+        self.commit()
+
+    def create_project(self, project_name:str, description: str, release_date: datetime=None):
+        # create a new project in the LTA as if we were the IDM system
+        # thus, we insert new project into the lofaridm.project table where it will be picked up by crontabbed the AWOPER.SYNCFROMIDM procedure
+        # so mind you... Changes in the LTA web UI do not take immediate effect
+        # TODO:  at this moment we do not set a PI and/or COI user. Add these when TMSS has/uses a user autorization system.
+        # raises if the project already exists.
+        if release_date is None:
+            release_date = self.DEFAULT_RELEASE_DATE
+        self.executeQuery("INSERT INTO lofaridm.project (name, description, releasedate) VALUES (%s, %s, %s)", qargs=(project_name, description, release_date), fetch=FETCH_NONE)
+        self.commit()
+
+    def add_project_storage_resource(self, project_name:str, nr_of_bytes: int, uri: str, remove_existing_resources: bool=False):
+        # add a new primary storage resource in bytes to the given project.  a new project in the LTA as if we were the IDM system
+        # The URI is usually given as srm://<LTA_SITE_HOST:PORT>/lofar/ops/projects/<PROJECT_NAME_IN_LOWERCASE>/
+        # if remove_existing_resources==True then all existing resources for this given project are remove (and replaced by this new resource)
+        # thus, we insert new project into the lofaridm.project table where it will be picked up by crontabbed the AWOPER.SYNCFROMIDM procedure
+        # so mind you... Changes in the LTA web UI do not take immediate effect
+        # raises if the project wit <project_name> does not exist.
+        project_id = self.executeQuery("SELECT id FROM lofaridm.project WHERE NAME=%s", qargs=(project_name,), fetch=FETCH_ONE)['ID']
+
+        if remove_existing_resources:
+            self.executeQuery("DELETE FROM lofaridm.resource$ WHERE id in (SELECT idr FROM lofaridm.resource_project WHERE idp=%s)", qargs=(project_id,), fetch=FETCH_NONE)
+
+        resource_name = "lta_storage_for_%s_%s" % (project_name, datetime.utcnow().isoformat())
+        self.executeQuery("INSERT INTO lofaridm.resource$ (NAME, TYPE, UNIT, CATEGORY, ALLOCATION, URI) VALUES (%s, %s, %s, %s, %s, %s)",
+                          qargs=(resource_name, "LTA_STORAGE", "B", "Primary", nr_of_bytes, uri), fetch=FETCH_NONE)
+        new_resource_id = self.executeQuery("SELECT id FROM lofaridm.resource$ WHERE NAME=%s", qargs=(resource_name,), fetch=FETCH_ONE)['ID']
+
+        self.executeQuery("INSERT INTO lofaridm.resource_project (IDR, IDP) VALUES (%s, %s)", qargs=(new_resource_id, project_id), fetch=FETCH_NONE)
+
+        self.commit()
+
+
+if __name__ == '__main__':
+    logging.basicConfig(format = '%(asctime)s %(levelname)s %(message)s', level = logging.INFO)
+
+    dbcreds = DBCredentials().get('LTA')
+    print(dbcreds.stringWithHiddenPassword())
+
+    with LTACatalogueDatabaseConnection(dbcreds=dbcreds) as db:
+        from pprint import pprint
+
+        # pprint(db.create_project("Commissioning_TMSS", "A commissioning project for the TMSS project"))
+        db.add_project_storage_resource("Commissioning_TMSS", 1, "my_uri", remove_existing_resources=True)
+
+        pprint(db.get_projects())
+        pprint(db.get_resources())
+
diff --git a/MAC/Deployment/data/StaticMetaData/AntennaFields/NenuFAR-AntennaField.conf b/MAC/Deployment/data/StaticMetaData/AntennaFields/NenuFAR-AntennaField.conf
new file mode 100644
index 0000000000000000000000000000000000000000..3a453183492acd454810a16630f6a9d0e03986eb
--- /dev/null
+++ b/MAC/Deployment/data/StaticMetaData/AntennaFields/NenuFAR-AntennaField.conf
@@ -0,0 +1,213 @@
+# Blitz-0.10 formatted
+#
+# AntennaPositions for the NenuFar array at FR606
+# The LBA parameters are changed, they now contain the
+# NenuFar Mini-array phase centers. The HBA positions are still
+# those of the HBA tiles.
+# LBA reference position is still that of center of LBA array.
+#
+# ITRF2005 target_date = 2015.5
+# Created: 2018-10-05 18:27:07
+#
+
+LBA
+(0,2) [ 4323979.771620000 165608.826246000 4670303.127 ]
+(0,95) x (0,1) x (0,2) [
+-45.584000 -22.692004  42.212000   -45.584000 -22.692004  42.212000 
+-30.918000 -40.706002  29.380000   -30.918000 -40.706002  29.380000 
+-22.196000 -65.411002  22.244000   -22.196000 -65.411002  22.244000 
+ -9.974000 -96.194000  12.072000    -9.974000 -96.194000  12.072000 
+  6.181010 -113.387999  -2.161990     6.181010 -113.387999  -2.161990 
+-40.083000 -73.534003  38.857000   -40.083000 -73.534003  38.857000 
+-29.629000 -96.119002  30.102000   -29.629000 -96.119002  30.102000 
+-13.664990 -149.466001  17.165000   -13.664990 -149.466001  17.165000 
+-29.088990 -132.677002  30.837000   -29.088990 -132.677002  30.837000 
+-48.954990 -129.851004  49.088000   -48.954990 -129.851004  49.088000 
+-66.844000 -103.576006  64.649000   -66.844000 -103.576006  64.649000 
+-89.828000 -97.522008  85.641000   -89.828000 -97.522008  85.641000 
+-77.330000 -76.297007  73.283000   -77.330000 -76.297007  73.283000 
+-106.119010 -57.655009  99.469000   -106.119010 -57.655009  99.469000 
+-130.526010 -40.841012 121.532000   -130.526010 -40.841012 121.532000 
+-91.037010 -39.923008  84.859000   -91.037010 -39.923008  84.859000 
+-106.100010 -10.763009  97.811000   -106.100010 -10.763009  97.811000 
+-118.885010  13.311989 108.798000   -118.885010  13.311989 108.798000 
+-126.078020  61.452989 113.745000   -126.078020  61.452989 113.745000 
+-140.178010   5.793987 128.829990   -140.178010   5.793987 128.829990 
+-155.148020  50.351986 140.832990   -155.148020  50.351986 140.832990 
+-180.822020  15.397983 165.868990   -180.822020  15.397983 165.868990 
+-92.981000 -131.358008  89.941000   -92.981000 -131.358008  89.941000 
+-125.706000 -145.817011 120.611000   -125.706000 -145.817011 120.611000 
+-137.752000 -166.225012 132.461000   -137.752000 -166.225012 132.461000 
+-139.462000 -101.410013 131.800000   -139.462000 -101.410013 131.800000 
+-163.731010 -90.877015 153.802990   -163.731010 -90.877015 153.802990 
+-187.865010 -106.297017 177.084990   -187.865010 -106.297017 177.084990 
+-204.447010 -37.808019 189.759990   -204.447010 -37.808019 189.759990 
+-164.239010 -56.924015 153.116990   -164.239010 -56.924015 153.116990 
+-156.157010 -17.355014 144.444990   -156.157010 -17.355014 144.444990 
+-180.239010 -24.594016 166.922990   -180.239010 -24.594016 166.922990 
+-38.111990 -155.416003  40.065000   -38.111990 -155.416003  40.065000 
+-31.254990 -180.539002  34.662000   -31.254990 -180.539002  34.662000 
+-21.150980 -218.051001  26.602000   -21.150980 -218.051001  26.602000 
+-37.468980 -234.536003  42.188000   -37.468980 -234.536003  42.188000 
+-48.321980 -294.194004  54.529000   -48.321980 -294.194004  54.529000 
+-66.199980 -255.700006  69.692000   -66.199980 -255.700006  69.692000 
+-82.270980 -310.241007  86.653000   -82.270980 -310.241007  86.653000 
+-40.808970 -337.452003  49.500000   -40.808970 -337.452003  49.500000 
+-18.127980 -307.175001  27.380010   -18.127980 -307.175001  27.380010 
+-66.499990 -142.758006  65.789000   -66.499990 -142.758006  65.789000 
+-88.927990 -164.584008  87.346000   -88.927990 -164.584008  87.346000 
+-106.998990 -175.659010 104.864000   -106.998990 -175.659010 104.864000 
+-104.524990 -232.400009 104.708000   -104.524990 -232.400009 104.708000 
+-110.021990 -205.459010 108.679000   -110.021990 -205.459010 108.679000 
+-134.667990 -193.727012 130.864000   -134.667990 -193.727012 130.864000 
+-53.015990 -179.521004  54.799000   -53.015990 -179.521004  54.799000 
+-57.444990 -204.300005  59.829000   -57.444990 -204.300005  59.829000 
+-84.792990 -214.117007  85.791000   -84.792990 -214.117007  85.791000 
+-121.681980 -274.698011 121.985000   -121.681980 -274.698011 121.985000 
+-105.608990 -257.807009 106.557000   -105.608990 -257.807009 106.557000 
+-88.909000 -127.255908  86.106600   -88.909000 -127.255908  86.106600 
+-88.909000 -127.255908  86.106600   -88.909000 -127.255908  86.106600 
+-88.909000 -127.255908  86.106600   -88.909000 -127.255908  86.106600 
+-88.909000 -127.255908  86.106600   -88.909000 -127.255908  86.106600 
+-88.909000 -127.255908  86.106600   -88.909000 -127.255908  86.106600 
+-88.909000 -127.255908  86.106600   -88.909000 -127.255908  86.106600 
+-88.909000 -127.255908  86.106600   -88.909000 -127.255908  86.106600 
+-88.909000 -127.255908  86.106600   -88.909000 -127.255908  86.106600 
+-88.909000 -127.255908  86.106600   -88.909000 -127.255908  86.106600 
+-88.909000 -127.255908  86.106600   -88.909000 -127.255908  86.106600 
+-88.909000 -127.255908  86.106600   -88.909000 -127.255908  86.106600 
+-88.909000 -127.255908  86.106600   -88.909000 -127.255908  86.106600 
+-88.909000 -127.255908  86.106600   -88.909000 -127.255908  86.106600 
+-88.909000 -127.255908  86.106600   -88.909000 -127.255908  86.106600 
+-88.909000 -127.255908  86.106600   -88.909000 -127.255908  86.106600 
+-88.909000 -127.255908  86.106600   -88.909000 -127.255908  86.106600 
+-88.909000 -127.255908  86.106600   -88.909000 -127.255908  86.106600 
+-88.909000 -127.255908  86.106600   -88.909000 -127.255908  86.106600 
+-88.909000 -127.255908  86.106600   -88.909000 -127.255908  86.106600 
+-88.909000 -127.255908  86.106600   -88.909000 -127.255908  86.106600 
+-88.909000 -127.255908  86.106600   -88.909000 -127.255908  86.106600 
+-88.909000 -127.255908  86.106600   -88.909000 -127.255908  86.106600 
+-88.909000 -127.255908  86.106600   -88.909000 -127.255908  86.106600 
+-88.909000 -127.255908  86.106600   -88.909000 -127.255908  86.106600 
+-88.909000 -127.255908  86.106600   -88.909000 -127.255908  86.106600 
+-88.909000 -127.255908  86.106600   -88.909000 -127.255908  86.106600 
+-88.909000 -127.255908  86.106600   -88.909000 -127.255908  86.106600 
+-88.909000 -127.255908  86.106600   -88.909000 -127.255908  86.106600 
+-88.909000 -127.255908  86.106600   -88.909000 -127.255908  86.106600 
+-88.909000 -127.255908  86.106600   -88.909000 -127.255908  86.106600 
+-88.909000 -127.255908  86.106600   -88.909000 -127.255908  86.106600 
+-88.909000 -127.255908  86.106600   -88.909000 -127.255908  86.106600 
+-88.909000 -127.255908  86.106600   -88.909000 -127.255908  86.106600 
+-88.909000 -127.255908  86.106600   -88.909000 -127.255908  86.106600 
+-88.909000 -127.255908  86.106600   -88.909000 -127.255908  86.106600 
+-88.909000 -127.255908  86.106600   -88.909000 -127.255908  86.106600 
+-88.909000 -127.255908  86.106600   -88.909000 -127.255908  86.106600 
+-88.909000 -127.255908  86.106600   -88.909000 -127.255908  86.106600 
+-88.909000 -127.255908  86.106600   -88.909000 -127.255908  86.106600 
+-88.909000 -127.255908  86.106600   -88.909000 -127.255908  86.106600 
+-88.909000 -127.255908  86.106600   -88.909000 -127.255908  86.106600 
+-88.909000 -127.255908  86.106600   -88.909000 -127.255908  86.106600 
+-88.909000 -127.255908  86.106600   -88.909000 -127.255908  86.106600 
+-88.909000 -127.255908  86.106600   -88.909000 -127.255908  86.106600 
+]
+
+HBA
+(0,2) [ 4034101.470070000 487012.791760000 4900230.512 ]
+(0,95) x (0,1) x (0,2) [
+ 20.808000 -15.324998 -15.498990    20.808000 -15.324998 -15.498990 
+ 21.305000 -10.285998 -16.397990    21.305000 -10.285998 -16.397990 
+ 21.802000  -5.241998 -17.293990    21.802000  -5.241998 -17.293990 
+ 22.288000  -0.198998 -18.196990    22.288000  -0.198998 -18.196990 
+ 22.776000   4.841002 -19.095990    22.776000   4.841002 -19.095990 
+ 16.351000 -19.412999 -11.454990    16.351000 -19.412999 -11.454990 
+ 16.852000 -14.368999 -12.354990    16.852000 -14.368999 -12.354990 
+ 17.343000  -9.320999 -13.253990    17.343000  -9.320999 -13.253990 
+ 17.842000  -4.273999 -14.158990    17.842000  -4.273999 -14.158990 
+ 18.326000   0.760001 -15.062990    18.326000   0.760001 -15.062990 
+ 18.827000   5.786001 -15.954990    18.827000   5.786001 -15.954990 
+ 19.317000  10.839001 -16.857990    19.317000  10.839001 -16.857990 
+ 11.894000 -23.508999  -7.425000    11.894000 -23.508999  -7.425000 
+ 12.394000 -18.456999  -8.332000    12.394000 -18.456999  -8.332000 
+ 12.898000 -13.395999  -9.235000    12.898000 -13.395999  -9.235000 
+ 13.392000  -8.355999 -10.119000    13.392000  -8.355999 -10.119000 
+ 13.875000  -3.311999 -11.017000    13.875000  -3.311999 -11.017000 
+ 14.359000   1.721001 -11.921000    14.359000   1.721001 -11.921000 
+ 14.855000   6.744001 -12.818000    14.855000   6.744001 -12.818000 
+ 15.351000  11.786001 -13.719000    15.351000  11.786001 -13.719000 
+ 15.834000  16.807001 -14.645000    15.834000  16.807001 -14.645000 
+  7.934000 -22.554000  -4.271000     7.934000 -22.554000  -4.271000 
+  8.437000 -17.503000  -5.176000     8.437000 -17.503000  -5.176000 
+  8.934000 -12.440999  -6.092000     8.934000 -12.440999  -6.092000 
+  9.440000  -7.394999  -6.980000     9.440000  -7.394999  -6.980000 
+  9.928000  -2.358999  -7.882000     9.928000  -2.358999  -7.882000 
+ 10.417000   2.678001  -8.790000    10.417000   2.678001  -8.790000 
+ 10.902000   7.690001  -9.671000    10.902000   7.690001  -9.671000 
+ 11.384000  12.720001 -10.561000    11.384000  12.720001 -10.561000 
+ 11.888000  17.759001 -11.479000    11.888000  17.759001 -11.479000 
+  3.984000 -21.600000  -1.127000     3.984000 -21.600000  -1.127000 
+  4.470000 -16.550000  -2.015000     4.470000 -16.550000  -2.015000 
+  4.963000 -11.472000  -2.928000     4.963000 -11.472000  -2.928000 
+  5.466000  -6.434000  -3.830000     5.466000  -6.434000  -3.830000 
+  5.965000  -1.413000  -4.735000     5.965000  -1.413000  -4.735000 
+  6.449000   3.622000  -5.627000     6.449000   3.622000  -5.627000 
+  6.933000   8.641000  -6.516000     6.933000   8.641000  -6.516000 
+  7.425000  13.669000  -7.410000     7.425000  13.669000  -7.410000 
+  7.925000  18.716000  -8.322000     7.925000  18.716000  -8.322000 
+  0.024000 -20.662000   2.036000     0.024000 -20.662000   2.036000 
+  0.507000 -15.606000   1.134000     0.507000 -15.606000   1.134000 
+  1.002000 -10.535000   0.229000     1.002000 -10.535000   0.229000 
+  1.491000  -5.481000  -0.670000     1.491000  -5.481000  -0.670000 
+  1.978000  -0.461000  -1.574000     1.978000  -0.461000  -1.574000 
+  2.471000   4.571000  -2.468000     2.471000   4.571000  -2.468000 
+  2.950000   9.595000  -3.354000     2.950000   9.595000  -3.354000 
+  3.449000  14.629000  -4.253000     3.449000  14.629000  -4.253000 
+  3.950000  19.678000  -5.195000     3.950000  19.678000  -5.195000 
+ -3.954000 -19.714001   5.204000    -3.954000 -19.714001   5.204000 
+ -3.468000 -14.631001   4.296000    -3.468000 -14.631001   4.296000 
+ -2.969000  -9.565001   3.368000    -2.969000  -9.565001   3.368000 
+ -2.467000  -4.525001   2.461000    -2.467000  -4.525001   2.461000 
+ -1.964000   0.491999   1.564000    -1.964000   0.491999   1.564000 
+ -1.471000   5.519000   0.663000    -1.471000   5.519000   0.663000 
+ -0.986000  10.537000  -0.217000    -0.986000  10.537000  -0.217000 
+ -0.515000  15.563000  -1.104000    -0.515000  15.563000  -1.104000 
+ -0.049000  20.637000  -2.040000    -0.049000  20.637000  -2.040000 
+ -7.912000 -18.767001   8.358000    -7.912000 -18.767001   8.358000 
+ -7.428000 -13.702001   7.446000    -7.428000 -13.702001   7.446000 
+ -6.937000  -8.614001   6.532000    -6.937000  -8.614001   6.532000 
+ -6.432000  -3.568001   5.627000    -6.432000  -3.568001   5.627000 
+ -5.944000   1.450999   4.725000    -5.944000   1.450999   4.725000 
+ -5.457000   6.481999   3.828000    -5.457000   6.481999   3.828000 
+ -4.967000  11.488999   2.937000    -4.967000  11.488999   2.937000 
+ -4.470000  16.523999   2.032000    -4.470000  16.523999   2.032000 
+ -4.001000  21.586999   1.087000    -4.001000  21.586999   1.087000 
+-11.876000 -17.809001  11.486000   -11.876000 -17.809001  11.486000 
+-11.393000 -12.773001  10.589000   -11.393000 -12.773001  10.589000 
+-10.907000  -7.687001   9.687000   -10.907000  -7.687001   9.687000 
+-10.402000  -2.627001   8.776000   -10.402000  -2.627001   8.776000 
+ -9.901000   2.407999   7.867000    -9.901000   2.407999   7.867000 
+ -9.417000   7.426999   6.978000    -9.417000   7.426999   6.978000 
+ -8.935000  12.445999   6.080000    -8.935000  12.445999   6.080000 
+ -8.438000  17.501999   5.160000    -8.438000  17.501999   5.160000 
+ -7.962000  22.533999   4.231000    -7.962000  22.533999   4.231000 
+-15.838000 -16.854002  14.637000   -15.838000 -16.854002  14.637000 
+-15.353000 -11.833002  13.739000   -15.353000 -11.833002  13.739000 
+-14.868000  -6.736002  12.820000   -14.868000  -6.736002  12.820000 
+-14.369000  -1.665002  11.915000   -14.369000  -1.665002  11.915000 
+-13.872000   3.345998  11.016000   -13.872000   3.345998  11.016000 
+-13.397000   8.345998  10.136000   -13.397000   8.345998  10.136000 
+-12.905000  13.404998   9.225000   -12.905000  13.404998   9.225000 
+-12.395000  18.469998   8.290000   -12.395000  18.469998   8.290000 
+-11.899000  23.503999   7.375000   -11.899000  23.503999   7.375000 
+-19.300000 -10.876002  16.866000   -19.300000 -10.876002  16.866000 
+-18.820000  -5.811002  15.956000   -18.820000  -5.811002  15.956000 
+-18.337000  -0.727002  15.059000   -18.337000  -0.727002  15.059000 
+-17.845000   4.298998  14.166000   -17.845000   4.298998  14.166000 
+-17.352000   9.289998  13.271000   -17.352000   9.289998  13.271000 
+-16.843000  14.360998  12.345000   -16.843000  14.360998  12.345000 
+-16.365000  19.422998  11.405000   -16.365000  19.422998  11.405000 
+-22.772000  -4.894002  19.096000   -22.772000  -4.894002  19.096000 
+-22.292000   0.195998  18.197000   -22.292000   0.195998  18.197000 
+-21.792000   5.231998  17.306000   -21.792000   5.231998  17.306000 
+-21.304000  10.241998  16.409000   -21.304000  10.241998  16.409000 
+-20.819000  15.293998  15.500000   -20.819000  15.293998  15.500000 
+]
diff --git a/RTCP/Cobalt/CoInterface/src/Allocator.cc b/RTCP/Cobalt/CoInterface/src/Allocator.cc
index a6b80b9a1d7f8b28f812a2103fa353039df5c72e..2b15c4eccc503f9aabd6da17df32c9950410656f 100644
--- a/RTCP/Cobalt/CoInterface/src/Allocator.cc
+++ b/RTCP/Cobalt/CoInterface/src/Allocator.cc
@@ -120,6 +120,10 @@ namespace LOFAR
     {
       ScopedLock sl(mutex);
 
+      // if we allocate 0 bytes, we could end up returning the same pointer for a subsequent allocation.
+      // since allocations with 0 bytes shouldn't be dereferenced anyway, we return NULL.
+      if (size == 0) return 0;
+
       // look for a free range large enough
       for (SparseSet<void *>::const_iterator it = freeList.getRanges().begin(); it != freeList.getRanges().end(); it++) {
         void *begin = align(it->begin, alignment);
diff --git a/RTCP/Cobalt/GPUProc/src/Station/StationInput.cc b/RTCP/Cobalt/GPUProc/src/Station/StationInput.cc
index 7a96bc727e347f7a8517865a90acd95780fd4df5..f412199b2a69e33b41ff8b2d5b9101b64fd848ec 100644
--- a/RTCP/Cobalt/GPUProc/src/Station/StationInput.cc
+++ b/RTCP/Cobalt/GPUProc/src/Station/StationInput.cc
@@ -454,6 +454,7 @@ namespace LOFAR {
             //copyRSPTimer.stop();
 
             outputQueue.append(rspData);
+            rspData.reset();
             ASSERT(!rspData);
           }
         }
diff --git a/SAS/TMSS/backend/services/tmss_postgres_listener/bin/tmss_postgres_listener_service b/SAS/TMSS/backend/services/tmss_postgres_listener/bin/tmss_postgres_listener_service
old mode 100644
new mode 100755
diff --git a/SAS/TMSS/backend/services/websocket/CMakeLists.txt b/SAS/TMSS/backend/services/websocket/CMakeLists.txt
index 7d5ea3a2e9bfb03f75528c83db74cdcb92025ce2..ba899270ef576cc4bff54cdfe1c3ffd4dc69b525 100644
--- a/SAS/TMSS/backend/services/websocket/CMakeLists.txt
+++ b/SAS/TMSS/backend/services/websocket/CMakeLists.txt
@@ -1,4 +1,4 @@
-lofar_package(TMSSWebSocketService 0.1 DEPENDS TMSSClient PyCommon pyparameterset PyMessaging)
+lofar_package(TMSSWebSocketService 0.1 DEPENDS TMSSClient PyCommon pyparameterset PyMessaging) # also depends on TMSSBackend, but that dependency is added implicitely because this is a child package
 
 lofar_find_package(PythonInterp 3.6 REQUIRED)
 
diff --git a/SAS/TMSS/backend/services/websocket/lib/websocket_service.py b/SAS/TMSS/backend/services/websocket/lib/websocket_service.py
index e87029d4d684fc20f4f9f7d1e6f19c0a94f8ce59..64aa14b82dca4a2c5592e06f8191d2edaa08b6f2 100644
--- a/SAS/TMSS/backend/services/websocket/lib/websocket_service.py
+++ b/SAS/TMSS/backend/services/websocket/lib/websocket_service.py
@@ -29,13 +29,13 @@ logger = logging.getLogger(__name__)
 
 from lofar.common import dbcredentials
 from lofar.sas.tmss.client.tmssbuslistener import *
-from lofar.sas.tmss.client.tmss_http_rest_client import TMSSsession
 from lofar.common.util import find_free_port
 
 from enum import Enum
 from json import dumps as JSONdumps
 from SimpleWebSocketServer import SimpleWebSocketServer, WebSocket
 from threading import Thread, Event
+from django.apps import apps
 
 DEFAULT_WEBSOCKET_PORT = 5678
 
@@ -60,14 +60,12 @@ class TMSSEventMessageHandlerForWebsocket(TMSSEventMessageHandler):
         TASK_BLUEPRINT = 'task_blueprint'
         TASK_DRAFT = 'task_draft'
 
-    def __init__(self, websocket_port: int=DEFAULT_WEBSOCKET_PORT, rest_client_creds_id: str="TMSSClient"):
+    def __init__(self, websocket_port: int=DEFAULT_WEBSOCKET_PORT):
         super().__init__(log_event_messages=True)
         self.websocket_port = websocket_port
-        self._tmss_client = TMSSsession.create_from_dbcreds_for_ldap(rest_client_creds_id)
         self._run_ws = True
 
     def start_handling(self):
-        self._tmss_client.open()    # Open tmss_client session
         socket_started_event = Event()
 
         # Create and run a simple ws server
@@ -87,7 +85,6 @@ class TMSSEventMessageHandlerForWebsocket(TMSSEventMessageHandler):
 
     def stop_handling(self):
         super().stop_handling()
-        self._tmss_client.close()   # Close tmss_client session
         self._run_ws = False    # Stop the ws server
         self.t.join()
 
@@ -98,10 +95,23 @@ class TMSSEventMessageHandlerForWebsocket(TMSSEventMessageHandler):
 
     def _post_update_on_websocket(self, id, object_type, action):
         # Prepare the json_blob_template
-        json_blob = {'id': id, 'object_type': object_type.value, 'action': action.value}
+        json_blob = {'object_details': {'id': id}, 'object_type': object_type.value, 'action': action.value}
         if action == self.ObjActions.CREATE or action == self.ObjActions.UPDATE:
-            # Fetch the object from DB using Django model API and add it to json_blob
-            json_blob['object'] = self._tmss_client.get_path_as_json_object('/%s/%s' % (object_type.value, id))
+            try:
+                model_class = apps.get_model("tmssapp", object_type.value.replace('_',''))
+                model_instance = model_class.objects.get(id=id)
+                if hasattr(model_instance, 'start_time') and model_instance.start_time is not None:
+                    json_blob['object_details']['start_time'] = model_instance.start_time.isoformat()
+                if hasattr(model_instance, 'stop_time') and model_instance.stop_time is not None:
+                    json_blob['object_details']['stop_time'] = model_instance.stop_time.isoformat()
+                if hasattr(model_instance, 'duration') and model_instance.duration is not None:
+                    json_blob['object_details']['duration'] = model_instance.duration.total_seconds()
+                if hasattr(model_instance, 'status'):
+                    json_blob['object_details']['status'] = model_instance.status
+                if hasattr(model_instance, 'state'):
+                    json_blob['object_details']['state'] = model_instance.state.value
+            except Exception as e:
+                logger.error("Cannot get object details for %s: %s", json_blob, e)
 
         # Send the json_blob as a broadcast message to all connected ws clients
         self._broadcast_notify_websocket(json_blob)
@@ -151,10 +161,9 @@ class TMSSEventMessageHandlerForWebsocket(TMSSEventMessageHandler):
     def onSchedulingUnitBlueprintDeleted(self, id: int):
         self._post_update_on_websocket(id, self.ObjTypes.SCHED_UNIT_BLUEPRINT, self.ObjActions.DELETE)
 
-def create_service(websocket_port: int=DEFAULT_WEBSOCKET_PORT, exchange: str=DEFAULT_BUSNAME, broker: str=DEFAULT_BROKER, rest_client_creds_id: str="TMSSClient"):
+def create_service(websocket_port: int=DEFAULT_WEBSOCKET_PORT, exchange: str=DEFAULT_BUSNAME, broker: str=DEFAULT_BROKER):
     return TMSSBusListener(handler_type=TMSSEventMessageHandlerForWebsocket,
-                           handler_kwargs={'websocket_port': websocket_port,
-                                           'rest_client_creds_id': rest_client_creds_id},
+                           handler_kwargs={'websocket_port': websocket_port},
                            exchange=exchange, broker=broker)
 
 
@@ -180,13 +189,14 @@ def main():
 
     group = OptionGroup(parser, 'Django options')
     parser.add_option_group(group)
-    group.add_option('-R', '--rest_credentials', dest='rest_credentials', type='string', default='TMSSClient', help='django REST API credentials name, default: %default')
+    group.add_option('-C', '--credentials', dest='dbcredentials', type='string', default=os.environ.get('TMSS_DBCREDENTIALS', 'TMSS'), help='django dbcredentials name, default: %default')
 
     (options, args) = parser.parse_args()
 
-    TMSSsession.check_connection_and_exit_on_error(options.rest_credentials)
+    from lofar.sas.tmss.tmss import setup_and_check_tmss_django_database_connection_and_exit_on_error
+    setup_and_check_tmss_django_database_connection_and_exit_on_error(options.dbcredentials)
 
-    with create_service(options.websocket_port, options.exchange, options.broker, rest_client_creds_id=options.rest_credentials):
+    with create_service(options.websocket_port, options.exchange, options.broker):
         waitForInterrupt()
 
 if __name__ == '__main__':
diff --git a/SAS/TMSS/backend/services/websocket/test/t_websocket_service.py b/SAS/TMSS/backend/services/websocket/test/t_websocket_service.py
index 4454c6eec265334f334dfef331eb06d7293e971c..f3f8388cb9b361665964ba3660f926b2653bbfc0 100755
--- a/SAS/TMSS/backend/services/websocket/test/t_websocket_service.py
+++ b/SAS/TMSS/backend/services/websocket/test/t_websocket_service.py
@@ -107,7 +107,7 @@ class TestSubtaskSchedulingService(unittest.TestCase):
         websocket_port = find_free_port(DEFAULT_WEBSOCKET_PORT)
 
         # create and start the service (the object under test)
-        service = create_service(websocket_port=websocket_port, exchange=self.tmp_exchange.address, rest_client_creds_id=self.tmss_test_env.client_credentials.dbcreds_id)
+        service = create_service(websocket_port=websocket_port, exchange=self.tmp_exchange.address)
         with BusListenerJanitor(service):
 
             self.start_ws_client(websocket_port)  # Start ws client
@@ -118,9 +118,13 @@ class TestSubtaskSchedulingService(unittest.TestCase):
                     raise TimeoutError()
                 self.sync_event.clear()
                 # Assert json_blobs
-                json_blob = {'id': json_test['id'], 'object_type': obj_type.value, 'action': action.value}
+                json_blob = {'object_details': {'id': json_test['id']}, 'object_type': obj_type.value, 'action': action.value}
                 if action == self.ObjActions.CREATE or action == self.ObjActions.UPDATE:
-                    json_blob['object'] = json_test
+                    for key in ('start_time', 'stop_time', 'duration', 'status'):
+                        if json_test.get(key) is not None:
+                            json_blob['object_details'][key] = json_test[key]
+                    if json_test.get('state_value') is not None:
+                        json_blob['object_details']['state'] = json_test['state_value']
                 self.assertEqual(json_blob, self.msg_queue.popleft())
 
             # Test creations
diff --git a/SAS/TMSS/backend/src/tmss/tmssapp/serializers/common.py b/SAS/TMSS/backend/src/tmss/tmssapp/serializers/common.py
index 4758646f1d9a4c619bfe5dd87a2c0a06fc31bf3f..c12e879675249229317935fbcd6b883bd18239b0 100644
--- a/SAS/TMSS/backend/src/tmss/tmssapp/serializers/common.py
+++ b/SAS/TMSS/backend/src/tmss/tmssapp/serializers/common.py
@@ -8,6 +8,13 @@ from django.core.exceptions import ImproperlyConfigured
 from .widgets import JSONEditorField
 from rest_flex_fields.serializers import FlexFieldsSerializerMixin
 
+class FloatDurationField(serializers.FloatField):
+
+    # Turn datetime to float representation in seconds.
+    # (Timedeltas are otherwise by default turned into a string representation)
+    def to_representation(self, value):
+        return value.total_seconds()
+
 class RelationalHyperlinkedModelSerializer(serializers.HyperlinkedModelSerializer):
     _accepted_pk_names = ('id', 'name')
 
diff --git a/SAS/TMSS/backend/src/tmss/tmssapp/serializers/scheduling.py b/SAS/TMSS/backend/src/tmss/tmssapp/serializers/scheduling.py
index 717833448d6a408247f2006d04ab067ea9d8cf4b..7c8bd8c29ee090cf6af7f48d6431e03418830c61 100644
--- a/SAS/TMSS/backend/src/tmss/tmssapp/serializers/scheduling.py
+++ b/SAS/TMSS/backend/src/tmss/tmssapp/serializers/scheduling.py
@@ -8,7 +8,7 @@ logger = logging.getLogger(__name__)
 from rest_framework import serializers
 from .. import models
 from .widgets import JSONEditorField
-from .common import RelationalHyperlinkedModelSerializer, AbstractTemplateSerializer, DynamicRelationalHyperlinkedModelSerializer
+from .common import FloatDurationField, RelationalHyperlinkedModelSerializer, AbstractTemplateSerializer, DynamicRelationalHyperlinkedModelSerializer
 
 class SubtaskStateSerializer(DynamicRelationalHyperlinkedModelSerializer):
     class Meta:
@@ -75,11 +75,12 @@ class SubtaskSerializer(DynamicRelationalHyperlinkedModelSerializer):
     # If this is OK then we can extend API with NO url ('flat' values) on more places if required
     cluster_value = serializers.StringRelatedField(source='cluster', label='cluster_value', read_only=True)
     specifications_doc = JSONEditorField(schema_source='specifications_template.schema')
+    duration = FloatDurationField(read_only=True)
 
     class Meta:
         model = models.Subtask
         fields = '__all__'
-        extra_fields = ['cluster_value']
+        extra_fields = ['cluster_value', 'duration']
 
 
 class SubtaskInputSerializer(DynamicRelationalHyperlinkedModelSerializer):
diff --git a/SAS/TMSS/backend/src/tmss/tmssapp/serializers/specification.py b/SAS/TMSS/backend/src/tmss/tmssapp/serializers/specification.py
index d281087554ecbd86d4dd6c60753d9c977fab084e..7ac1a29773ff0b569b11ddd7db01ca73eb160bc8 100644
--- a/SAS/TMSS/backend/src/tmss/tmssapp/serializers/specification.py
+++ b/SAS/TMSS/backend/src/tmss/tmssapp/serializers/specification.py
@@ -5,17 +5,10 @@ This file contains the serializers (for the elsewhere defined data models)
 from rest_framework import serializers
 from .. import models
 from .scheduling import SubtaskSerializer
-from .common import RelationalHyperlinkedModelSerializer, AbstractTemplateSerializer, DynamicRelationalHyperlinkedModelSerializer
+from .common import FloatDurationField, RelationalHyperlinkedModelSerializer, AbstractTemplateSerializer, DynamicRelationalHyperlinkedModelSerializer
 from .widgets import JSONEditorField
 from django.contrib.auth.models import User
 
-class FloatDurationField(serializers.FloatField):
-
-    # Turn datetime to float representation in seconds.
-    # (Timedeltas are otherwise by default turned into a string representation)
-    def to_representation(self, value):
-        return value.total_seconds()
-
 # This is required for keeping a user reference as ForeignKey in other models
 # (I think so that the HyperlinkedModelSerializer can generate a URI)
 class UserSerializer(serializers.Serializer):
diff --git a/SAS/TMSS/backend/src/tmss/workflowapp/migrations/0001_initial.py b/SAS/TMSS/backend/src/tmss/workflowapp/migrations/0001_initial.py
index 9b78279183edf2b6a9a666365f8263f2770c9e36..7b5662531eebc0af1775682642c4f166cde2f02a 100644
--- a/SAS/TMSS/backend/src/tmss/workflowapp/migrations/0001_initial.py
+++ b/SAS/TMSS/backend/src/tmss/workflowapp/migrations/0001_initial.py
@@ -1,4 +1,4 @@
-# Generated by Django 3.0.9 on 2021-01-21 08:10
+# Generated by Django 3.0.9 on 2021-02-11 14:08
 
 from django.db import migrations, models
 import django.db.models.deletion
@@ -9,8 +9,8 @@ class Migration(migrations.Migration):
     initial = True
 
     dependencies = [
-        ('tmssapp', '0001_initial'),
         ('viewflow', '0008_jsonfield_and_artifact'),
+        ('tmssapp', '0001_initial'),
     ]
 
     operations = [
@@ -25,7 +25,7 @@ class Migration(migrations.Migration):
             name='PIVerification',
             fields=[
                 ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
-                ('pi_report', models.CharField(max_length=150)),
+                ('pi_report', models.TextField()),
                 ('pi_accept', models.BooleanField(default=False)),
             ],
         ),
@@ -33,7 +33,7 @@ class Migration(migrations.Migration):
             name='QAReportingSOS',
             fields=[
                 ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
-                ('sos_report', models.CharField(max_length=150)),
+                ('sos_report', models.TextField()),
                 ('quality_within_policy', models.BooleanField(default=False)),
                 ('sos_accept_show_pi', models.BooleanField(default=False)),
             ],
@@ -42,7 +42,7 @@ class Migration(migrations.Migration):
             name='QAReportingTO',
             fields=[
                 ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
-                ('operator_report', models.CharField(max_length=150)),
+                ('operator_report', models.TextField()),
                 ('operator_accept', models.BooleanField(default=False)),
             ],
         ),
diff --git a/SAS/TMSS/backend/src/tmss/workflowapp/models/schedulingunitflow.py b/SAS/TMSS/backend/src/tmss/workflowapp/models/schedulingunitflow.py
index 3c1ed87a6036fe77867ad2cce289a7a3776a65b1..392a7168f104a48d9996eaa276fc4f7f34e10ffe 100644
--- a/SAS/TMSS/backend/src/tmss/workflowapp/models/schedulingunitflow.py
+++ b/SAS/TMSS/backend/src/tmss/workflowapp/models/schedulingunitflow.py
@@ -1,6 +1,6 @@
 # Create your models here.
 
-from django.db.models import CharField, IntegerField,BooleanField, ForeignKey, CASCADE, Model,NullBooleanField
+from django.db.models import TextField, IntegerField,BooleanField, ForeignKey, CASCADE, Model,NullBooleanField
 from viewflow.models import Process, Task
 from viewflow.fields import FlowReferenceField
 from viewflow.compat import _
@@ -9,18 +9,18 @@ from lofar.sas.tmss.tmss.tmssapp.models import SchedulingUnitBlueprint
 
 
 class QAReportingTO(Model):
-    operator_report = CharField(max_length=150)
+    operator_report = TextField()
     operator_accept = BooleanField(default=False)
 
 
 class QAReportingSOS(Model):
-    sos_report = CharField(max_length=150)
+    sos_report = TextField()
     quality_within_policy = BooleanField(default=False)
     sos_accept_show_pi = BooleanField(default=False)
 
 
 class PIVerification(Model):
-    pi_report = CharField(max_length=150)
+    pi_report = TextField()
     pi_accept = BooleanField(default=False)
 
 
diff --git a/SAS/TMSS/backend/test/test_utils.py b/SAS/TMSS/backend/test/test_utils.py
index 0a100a41c23f8b74c884dac85d007dd12978c09c..c7d1aaa6823ff1c03e4488724965ec539faccfe3 100644
--- a/SAS/TMSS/backend/test/test_utils.py
+++ b/SAS/TMSS/backend/test/test_utils.py
@@ -396,7 +396,7 @@ class TMSSTestEnvironment:
             # this implies that _start_pg_listener should be true as well
             self._start_pg_listener = True
             from lofar.sas.tmss.services.websocket_service import create_service
-            self.websocket_service = create_service(exchange=self._exchange, broker=self._broker, rest_client_creds_id=self.client_credentials.dbcreds_id)
+            self.websocket_service = create_service(exchange=self._exchange, broker=self._broker)
             service_threads.append(threading.Thread(target=self.websocket_service.start_listening))
             service_threads[-1].start()
 
diff --git a/SAS/TMSS/frontend/tmss_webapp/.env b/SAS/TMSS/frontend/tmss_webapp/.env
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..fe03ed51b3f8a9b3bc3afcf2850ab7271f31ec22 100644
--- a/SAS/TMSS/frontend/tmss_webapp/.env
+++ b/SAS/TMSS/frontend/tmss_webapp/.env
@@ -0,0 +1 @@
+REACT_APP_WEBSOCKET_URL=ws://localhost:5678/
\ No newline at end of file
diff --git a/SAS/TMSS/frontend/tmss_webapp/package.json b/SAS/TMSS/frontend/tmss_webapp/package.json
index b7c244ab27e1be39f21d882199581a491b5efbcb..4086fab8ac565363e54d1271f53e688091fcc5e5 100644
--- a/SAS/TMSS/frontend/tmss_webapp/package.json
+++ b/SAS/TMSS/frontend/tmss_webapp/package.json
@@ -51,6 +51,7 @@
     "react-table": "^7.2.1",
     "react-table-plugins": "^1.3.1",
     "react-transition-group": "^2.5.1",
+    "react-websocket": "^2.1.0",
     "reactstrap": "^8.5.1",
     "styled-components": "^5.1.1",
     "suneditor-react": "^2.14.4",
diff --git a/SAS/TMSS/frontend/tmss_webapp/src/components/Spreadsheet/BetweenEditor.js b/SAS/TMSS/frontend/tmss_webapp/src/components/Spreadsheet/BetweenEditor.js
index 644620bc7655a8ab4a00b9e3e2ee1aff7d5e44bf..f82de002593b6c8555798e5a41e9f1c778e060dc 100644
--- a/SAS/TMSS/frontend/tmss_webapp/src/components/Spreadsheet/BetweenEditor.js
+++ b/SAS/TMSS/frontend/tmss_webapp/src/components/Spreadsheet/BetweenEditor.js
@@ -61,56 +61,50 @@ export default class BetweenEditor extends Component {
     });
 
   }
- 
-  /*isCancelAfterEnd(){console.log('after')
-  console.log('called')
-    this.copyDateValue();
-  }*/
 
   /**
    * Call the function on click Esc or Close the dialog
    */
-async copyDateValue(){
-  let consolidateDates = '';
-  this.state.rowData.map(row =>{
-    if((row['from'] !== '' && row['from'] !== 'undefined') && (row['until'] !== '' && row['until'] !== 'undefined')){
-      consolidateDates += ((row['from'] !== '')?moment(row['from']).format(DATE_TIME_FORMAT):'' )+","+((row['until'] !== '')?moment(row['until']).format(DATE_TIME_FORMAT):'')+"|";
-    }
-  });
-  await this.props.context.componentParent.updateTime(
-    this.props.node.rowIndex,this.props.colDef.field, consolidateDates 
-  );
-  this.setState({ showDialog: false});
- 
-}
+  async copyDateValue(){
+      let consolidateDates = '';
+      this.state.rowData.map(row =>{
+          if((row['from'] !== '' && row['from'] !== 'undefined') && (row['until'] !== '' && row['until'] !== 'undefined')){
+          consolidateDates += ((row['from'] !== '')?moment(row['from']).format(DATE_TIME_FORMAT):'' )+","+((row['until'] !== '')?moment(row['until']).format(DATE_TIME_FORMAT):'')+"|";
+          }
+      });
+      await this.props.context.componentParent.updateTime(
+          this.props.node.rowIndex,this.props.colDef.field, consolidateDates 
+      );
+      this.setState({ showDialog: false});
+  }
 
-/*
- Set value in relevant field
- */
-updateDateChanges(rowIndex, field, e){
-  let tmpRows = this.state.rowData;
-  let row = tmpRows[rowIndex];
-  row[field] = e.value;
-  tmpRows[rowIndex] = row;
-  if(this.state.rowData.length === rowIndex+1){
-    let line = {'from': '', 'until': ''};
-    tmpRows.push(line);
+  /*
+  Set value in relevant field
+  */
+  updateDateChanges(rowIndex, field, e){
+      let tmpRows = this.state.rowData;
+      let row = tmpRows[rowIndex];
+      row[field] = e.value;
+      tmpRows[rowIndex] = row;
+      if(this.state.rowData.length === rowIndex+1){
+          let line = {'from': '', 'until': ''};
+          tmpRows.push(line);
+      }
+      this.setState({
+        rowData: tmpRows
+      });
   }
-  this.setState({
-    rowData: tmpRows
-  })
-}
 
-/*
-  Remove the the row from dialog
-*/
-removeInput(rowIndex){
-  let tmpRows = this.state.rowData;
-  delete tmpRows[rowIndex];
-  this.setState({
-    rowData: tmpRows
-  })
-}
+  /*
+    Remove the the row from dialog
+  */
+  removeInput(rowIndex){
+      let tmpRows = this.state.rowData;
+      delete tmpRows[rowIndex];
+      this.setState({
+         rowData: tmpRows
+    } );
+  }
 
 render() {
   return (
diff --git a/SAS/TMSS/frontend/tmss_webapp/src/components/Spreadsheet/BetweenRenderer.js b/SAS/TMSS/frontend/tmss_webapp/src/components/Spreadsheet/BetweenRenderer.js
index 90a8ca3d7fc4ca9f22084fd5c9e6db063e80366d..dbcdfad52b86b2a5647f3dab592d96ee1d6e9d90 100644
--- a/SAS/TMSS/frontend/tmss_webapp/src/components/Spreadsheet/BetweenRenderer.js
+++ b/SAS/TMSS/frontend/tmss_webapp/src/components/Spreadsheet/BetweenRenderer.js
@@ -9,10 +9,22 @@ export default class BetweenRenderer extends Component {
     Show cell value in grid
    */
   render() {
-    let row = this.props.agGridReact.props.rowData[this.props.node.rowIndex];
-    let value =  row[this.props.colDef.field];
-    return <> {value && 
-                value
-              }</>;
+    let row = [];
+    let value = '';
+    if (this.props.colDef.field.startsWith('gdef_')) {
+        row = this.props.agGridReact.props.context.componentParent.state.commonRowData[0];
+        value =  row[this.props.colDef.field];
+    }
+    else {
+        row = this.props.agGridReact.props.rowData[this.props.node.rowIndex];
+        value =  row[this.props.colDef.field];
+    }
+   // let row = this.props.agGridReact.props.rowData[this.props.node.rowIndex];
+   // let value =  row[this.props.colDef.field];
+    return  <> 
+                {value && 
+                    value
+                }
+            </>;
   }
 }
\ No newline at end of file
diff --git a/SAS/TMSS/frontend/tmss_webapp/src/components/Spreadsheet/CustomDateComponent.js b/SAS/TMSS/frontend/tmss_webapp/src/components/Spreadsheet/CustomDateComponent.js
index 7e0c18e9b6926bb138c3c6b7667d67f7fa76d930..5d90aeb89f6636d1b733d66910ce716e89a79d35 100644
--- a/SAS/TMSS/frontend/tmss_webapp/src/components/Spreadsheet/CustomDateComponent.js
+++ b/SAS/TMSS/frontend/tmss_webapp/src/components/Spreadsheet/CustomDateComponent.js
@@ -103,12 +103,9 @@ export default class CustomDateComponent extends Component {
   //          LINKING THE UI, THE STATE AND AG-GRID
   //*********************************************************************************
   onDateChanged = (selectedDates) => {
-    //console.log('>>',  selectedDates[0])
     this.props.context.componentParent.updateTime(
       this.props.node.rowIndex,this.props.colDef.field,selectedDates[0]
     );
-
-      
    // this.updateAndNotifyAgGrid(selectedDates[0]);
   };
 }
\ No newline at end of file
diff --git a/SAS/TMSS/frontend/tmss_webapp/src/components/Spreadsheet/MultiSelector.js b/SAS/TMSS/frontend/tmss_webapp/src/components/Spreadsheet/MultiSelector.js
index 25c412381d7d0de2d58b7eef01211fa649f4029d..d3a2ed7731855b86d38c030c219cac7a28932223 100644
--- a/SAS/TMSS/frontend/tmss_webapp/src/components/Spreadsheet/MultiSelector.js
+++ b/SAS/TMSS/frontend/tmss_webapp/src/components/Spreadsheet/MultiSelector.js
@@ -6,45 +6,47 @@ export default class SkySllector extends Component {
   constructor(props) {
     super(props);
           
-    this.dailyOptions= [
-      {name: 'require_day', value: 'require_day'},
-      {name: 'require_night', value: 'require_night'},
-      {name: 'avoid_twilight', value: 'avoid_twilight'}, 
-    ];
+    this.dailyOptions= [];
     this.state= {
       daily: [],
-
+      dailyOptions: [],
     }
- 
     this.callbackUpdateDailyCell = this.callbackUpdateDailyCell.bind(this);
   }
 
   async componentDidMount(){
-    let selectedValues = this.props.data['daily'];
+    let selectedValues = null;
+    if (this.props.colDef.field.startsWith('gdef_')) {
+        selectedValues = this.props.data['gdef_daily'];
+    }
+    else {
+        selectedValues = this.props.data['daily'];
+    }
+    let tmpDailyValue = [];
     if(selectedValues  && selectedValues.length>0){
-      let tmpDailyValue = _.split(selectedValues, ",");
-      await this.setState({
-        daily: tmpDailyValue,
-      });
+        tmpDailyValue = _.split(selectedValues, ",");
     }
- 
+    await this.setState({
+      daily: tmpDailyValue,
+      dailyOptions: this.props.context.componentParent.state.dailyOption
+    });
   }
 
   async callbackUpdateDailyCell(e) {
     this.setState({
-      daily: e.value
+        daily: e.value
     })
     let dailyValue = '';
     let selectedValues = e.value;
     await selectedValues.forEach( key =>{
-      dailyValue += key+",";
+        dailyValue += key+",";
     })
     dailyValue = _.trim(dailyValue)
     dailyValue = dailyValue.replace(/,([^,]*)$/, '' + '$1')   
   
     this.props.context.componentParent.updateCell(
-      this.props.node.rowIndex,this.props.colDef.field,dailyValue
-     );
+        this.props.node.rowIndex,this.props.colDef.field,dailyValue
+    );
      
   }
  
@@ -56,12 +58,14 @@ export default class SkySllector extends Component {
   }
   render() {
     return (
-      <div className="col-sm-6">
-        <MultiSelect  optionLabel="name"   value={this.state.daily} options={this.dailyOptions}
-        optionValue="value" filter={true}
-        onChange={this.callbackUpdateDailyCell}
-        />
-       </div>
+        <div className="col-sm-6">
+            {this.state.dailyOptions.length > 0 && 
+                <MultiSelect  optionLabel="name"   value={this.state.daily} options={this.state.dailyOptions}
+                optionValue="value" filter={true}
+                onChange={this.callbackUpdateDailyCell}
+                />
+            }
+        </div>
     );
   }
 }
\ No newline at end of file
diff --git a/SAS/TMSS/frontend/tmss_webapp/src/components/Spreadsheet/StationEditor.js b/SAS/TMSS/frontend/tmss_webapp/src/components/Spreadsheet/StationEditor.js
index b5280aeab0f64605fdbe20a536648d8169eed3f3..8b97161aac1c61d6ed917b39ba8d046c8243c995 100644
--- a/SAS/TMSS/frontend/tmss_webapp/src/components/Spreadsheet/StationEditor.js
+++ b/SAS/TMSS/frontend/tmss_webapp/src/components/Spreadsheet/StationEditor.js
@@ -3,13 +3,20 @@ import React, { Component } from 'react';
 import { Dialog } from 'primereact/dialog';
 import { Button } from 'primereact/button';
 import Stations from '../../routes/Scheduling/Stations';
+
+//import moment from 'moment';
 import _ from 'lodash';
 
+//const DATE_TIME_FORMAT = 'YYYY-MM-DD HH:mm:ss';
+
 export default class StationEditor extends Component {
   constructor(props) {
     super(props);
     this.tmpRowData = [];
-
+    this.isDelete = false;
+    this.showDelete = false;
+    this.previousValue= '';
+    this.doCancel = true;
     this.state = {
       schedulingUnit: {},
       showDialog: false,
@@ -18,10 +25,7 @@ export default class StationEditor extends Component {
       stationGroup: [],
       customSelectedStations: []     
     };
-    this.formRules = {                 
-      name: {required: true, message: "Name can not be empty"},
-      description: {required: true, message: "Description can not be empty"},
-  };
+    this.formRules = {};
   }
   
   isPopup() {
@@ -34,12 +38,14 @@ export default class StationEditor extends Component {
   async componentDidMount(){
     let tmpStationGroups = [];
     let tmpStationGroup = {};
-     
+    if ( this.props.colDef.field.startsWith('gdef_')) {
+        this.showDelete = true;
+    }
     let rowSU = this.props.agGridReact.props.rowData[this.props.node.rowIndex];
-    let sgCellValue = rowSU[this.props.colDef.field];
+    this.previousValue = rowSU[this.props.colDef.field];
  
-    if(sgCellValue && sgCellValue.length >0){
-      let stationGroups = _.split(sgCellValue,  "|");
+    if(this.previousValue && this.previousValue.length >0){
+      let stationGroups = _.split(this.previousValue,  "|");
       stationGroups.map(stationGroup =>{
         tmpStationGroup = {};
         let sgValue = _.split(stationGroup, ":");
@@ -68,74 +74,58 @@ export default class StationEditor extends Component {
     }
   }
     
-validateForm(fieldName) {
-  let validForm = false;
-  let errors = this.state.errors;
-  let validFields = this.state.validFields;
-  if (fieldName) {
-      delete errors[fieldName];
-      delete validFields[fieldName];
-      if (this.formRules[fieldName]) {
-          const rule = this.formRules[fieldName];
-          const fieldValue = this.state.schedulingUnit[fieldName];
-          if (rule.required) {
-              if (!fieldValue) {
-                  errors[fieldName] = rule.message?rule.message:`${fieldName} is required`;
-              }   else {
-                  validFields[fieldName] = true;
-              }
-          }
-      }
-  }   else {
-      errors = {};
-      validFields = {};
-      for (const fieldName in this.formRules) {
-          const rule = this.formRules[fieldName];
-          const fieldValue = this.state.schedulingUnit[fieldName];
-          if (rule.required) {
-              if (!fieldValue) {
-                  errors[fieldName] = rule.message?rule.message:`${fieldName} is required`;
-              }   else {
-                  validFields[fieldName] = true;
-              }
-          }
-      }
-  }
-  this.setState({errors: errors, validFields: validFields});
-  if (Object.keys(validFields).length === Object.keys(this.formRules).length) {
-      validForm = true;
-  }
-  return validForm && !this.state.missingStationFieldsErrors;
+async deleteStationGroup() {
+    this.isDelete = true;
+    this.setState({ showDialog: false});
 }
 
-async updateStationGroup(){
+async closeStationGroup() {
+  this.isDelete = false;
+  this.doCancel = false;
+  this.setState({ showDialog: false});
+}
+
+async cancelStationGroup() {
+  this.isDelete = false;
+  this.doCancel = true;
+  this.setState({ showDialog: false});
+}
+
+async updateStationGroup() {
     let stationValue = '';
     const station_groups = [];
-    (this.state.selectedStations || []).forEach(key => {
-        let station_group = {};
-        const stations = this.state[key] ? this.state[key].stations : [];
-        const max_nr_missing = parseInt(this.state[key] ? this.state[key].missing_StationFields : 0);
-        station_group = {
-            stations,
-            max_nr_missing
-        };  
-        station_groups.push(station_group);                 
-    });
-    this.state.customSelectedStations.forEach(station => {
-        station_groups.push({
-            stations: station.stations,
-            max_nr_missing: parseInt(station.max_nr_missing)
-        });
-    });
-    if(station_groups){
-        station_groups.map(stationGroup =>{
-            stationValue += stationGroup.stations+':'+stationGroup.max_nr_missing+"|";
-        });
+    if (!this.isDelete) {
+        if (!this.doCancel) {
+            (this.state.selectedStations || []).forEach(key => {
+              let station_group = {};
+              const stations = this.state[key] ? this.state[key].stations : [];
+              const max_nr_missing = parseInt(this.state[key] ? this.state[key].missing_StationFields : 0);
+              station_group = {
+                  stations,
+                  max_nr_missing
+              };  
+              station_groups.push(station_group);                 
+            });
+            this.state.customSelectedStations.forEach(station => {
+                station_groups.push({
+                    stations: station.stations,
+                    max_nr_missing: parseInt(station.max_nr_missing)
+                });
+            });
+            if(station_groups){
+                station_groups.map(stationGroup =>{
+                    stationValue += stationGroup.stations+':'+stationGroup.max_nr_missing+"|";
+                });
+            }
+        }   else {
+            stationValue = this.previousValue;
+        }
     }
-    this.setState({ showDialog: false});
+  
     await this.props.context.componentParent.updateCell(
       this.props.node.rowIndex,this.props.colDef.field, stationValue 
     );
+    this.setState({ showDialog: false});
 }
 
 onUpdateStations = (state, selectedStations, missingStationFieldsErrors, customSelectedStations) => {
@@ -146,31 +136,34 @@ onUpdateStations = (state, selectedStations, missingStationFieldsErrors, customS
       customSelectedStations
   }, () => {
       this.setState({
-          validForm: this.validateForm()
+          validForm: !missingStationFieldsErrors
       });
   });
 };
 
 render() {
-    return (
-        <>  
-          <Dialog header={_.startCase(this.state.dialogTitle)} visible={this.state.showDialog} maximized={false}  
-          onHide={() => {this.updateStationGroup()}} inputId="confirm_dialog" className="stations-dialog"
-          footer={<div>
-                      <Button key="back" label="Close" onClick={() => {this.updateStationGroup()}} />
-                  </div>
-              } >
-             <div className="ag-theme-balham" style={{ height: '90%', width: '1000px', paddingLeft: '20px' }}>
-                  <Stations
-                      stationGroup={this.state.stationGroup}
-                      onUpdateStations={this.onUpdateStations.bind(this)}
-                      height={'30em'}
-                  />
-            </div>
-          </Dialog>
-        
-      </>
-    );
-  }
+  return (
+    <>  
+      <Dialog header={_.startCase(this.state.dialogTitle)} visible={this.state.showDialog} maximized={false}  
+      onHide={() => {this.updateStationGroup()}} inputId="confirm_dialog" className="stations_dialog"
+      footer={<div>
+                  {this.showDelete &&
+                      <Button className="p-button-danger" icon="pi pi-trash" label="Clear All" onClick={() => {this.deleteStationGroup()}} />
+                  }
+                  <Button  label="OK" icon="pi pi-check"  onClick={() => {this.closeStationGroup()}}  disabled={!this.state.validForm} style={{width: '6em'}} />
+                  <Button className="p-button-danger" icon="pi pi-times" label="Cancel" onClick={() => {this.cancelStationGroup()}} />
+              </div>
+    } >
+          <div className="ag-theme-balham" style={{ height: '90%', width: '1000px', paddingLeft: '20px' }}>
+          <Stations
+              stationGroup={this.state.stationGroup}
+              onUpdateStations={this.onUpdateStations.bind(this)}
+              height={'30em'}
+          />
+        </div>
+      </Dialog>
+   </>
+  );
+}
  
 }
\ No newline at end of file
diff --git a/SAS/TMSS/frontend/tmss_webapp/src/components/Spreadsheet/TimeInputmask.js b/SAS/TMSS/frontend/tmss_webapp/src/components/Spreadsheet/TimeInputmask.js
index ef773a00181db906bc02b311308c08e8cab813d0..d8047ddebd03812dffeaafefc1d4cfe711b8a44a 100644
--- a/SAS/TMSS/frontend/tmss_webapp/src/components/Spreadsheet/TimeInputmask.js
+++ b/SAS/TMSS/frontend/tmss_webapp/src/components/Spreadsheet/TimeInputmask.js
@@ -32,12 +32,12 @@ export default class TimeInputMask extends Component {
   render() {
     return (
         <InputMask 
-        value={this.props.value}
-        mask="99:99:99" 
-        placeholder="HH:mm:ss" 
-        className="inputmask" 
-        onComplete={this.callbackUpdateAngle}
-        ref={input =>{this.input = input}}
+          value={this.props.value}
+          mask="99:99:99" 
+          placeholder="HH:mm:ss" 
+          className="inputmask" 
+          onComplete={this.callbackUpdateAngle}
+          ref={input =>{this.input = input}}
          />
     );
   }
diff --git a/SAS/TMSS/frontend/tmss_webapp/src/components/Timeline/CalendarTimeline.js b/SAS/TMSS/frontend/tmss_webapp/src/components/Timeline/CalendarTimeline.js
index b148112a09416472a9093ba56d3a547f163724f3..d57f1f7ea36f59bd3877a84e4cb5c9b01bc06a31 100644
--- a/SAS/TMSS/frontend/tmss_webapp/src/components/Timeline/CalendarTimeline.js
+++ b/SAS/TMSS/frontend/tmss_webapp/src/components/Timeline/CalendarTimeline.js
@@ -675,13 +675,13 @@ export class CalendarTimeline extends Component {
             itemContext.dimensions.height -= 3;
             if (!this.props.showSunTimings && this.state.viewType === UIConstants.timeline.types.NORMAL) {
                 if (item.type === "RESERVATION") {
-                    itemContext.dimensions.top -= 20;
-                    itemContext.dimensions.height += 20;
+                    // itemContext.dimensions.top -= 20;
+                    // itemContext.dimensions.height += 20;
                 }   else {
-                    itemContext.dimensions.top -= 20;
+                    // itemContext.dimensions.top -= 20;
                 }
             }   else if (this.state.viewType === UIConstants.timeline.types.WEEKVIEW) {
-                itemContext.dimensions.top -= (this.props.rowHeight-5);
+                // itemContext.dimensions.top -= (this.props.rowHeight-5);
             }   else {
                 if (item.type === "TASK") {
                     itemContext.dimensions.top += 6;
@@ -1248,12 +1248,15 @@ export class CalendarTimeline extends Component {
      * @param {Object} props 
      */
     async updateTimeline(props) {
+        let group =  DEFAULT_GROUP.concat(props.group);
         if (!this.props.showSunTimings && this.state.viewType === UIConstants.timeline.types.NORMAL) {
             props.items = await this.addStationSunTimes(this.state.defaultStartTime, this.state.defaultEndTime, props.group, props.items);
         }   else if(this.props.showSunTimings && this.state.viewType === UIConstants.timeline.types.NORMAL) {
             this.setNormalSuntimings(this.state.defaultStartTime, this.state.defaultEndTime);
+        }   else if (this.state.viewType === UIConstants.timeline.types.WEEKVIEW) {
+            props.items = await this.addWeekSunTimes(this.state.defaultStartTime, this.state.defaultEndTime, group, props.items);
         }
-        this.setState({group: DEFAULT_GROUP.concat(props.group), items: _.orderBy(props.items, ['type'], ['desc'])});
+        this.setState({group: group, items: _.orderBy(props.items, ['type'], ['desc'])});
     }
 
     render() {
diff --git a/SAS/TMSS/frontend/tmss_webapp/src/components/ViewTable.js b/SAS/TMSS/frontend/tmss_webapp/src/components/ViewTable.js
index 582d29c631c6d11e07937cfb5556041ec1910900..a420bdbbfc193ec1771b8c0c1f0ea3952e28424a 100644
--- a/SAS/TMSS/frontend/tmss_webapp/src/components/ViewTable.js
+++ b/SAS/TMSS/frontend/tmss_webapp/src/components/ViewTable.js
@@ -1,27 +1,27 @@
-import React, {useRef, useState } from "react";
-import { useSortBy, useTable, useFilters, useGlobalFilter, useAsyncDebounce, usePagination, useRowSelect } from 'react-table'
+import React, { useRef, useState } from "react";
+import { useSortBy, useTable, useFilters, useGlobalFilter, useAsyncDebounce, usePagination, useRowSelect, useColumnOrder } from 'react-table'
 import matchSorter from 'match-sorter'
 import _ from 'lodash';
 import moment from 'moment';
 import { useHistory } from "react-router-dom";
-import {OverlayPanel} from 'primereact/overlaypanel';
+import { OverlayPanel } from 'primereact/overlaypanel';
 //import {InputSwitch} from 'primereact/inputswitch';
-import {InputText} from 'primereact/inputtext';
+import { InputText } from 'primereact/inputtext';
 import { Calendar } from 'primereact/calendar';
-import {Paginator} from 'primereact/paginator';
-import {TriStateCheckbox} from 'primereact/tristatecheckbox';
+import { Paginator } from 'primereact/paginator';
+import { TriStateCheckbox } from 'primereact/tristatecheckbox';
 import { Slider } from 'primereact/slider';
 import { Button } from "react-bootstrap";
 import { Link } from "react-router-dom";
 import { InputNumber } from "primereact/inputnumber";
-import {MultiSelect} from 'primereact/multiselect';
+import { MultiSelect } from 'primereact/multiselect';
 import { RadioButton } from 'primereact/radiobutton';
 import { useExportData } from "react-table-plugins";
 import Papa from "papaparse";
 import JsPDF from "jspdf";
 import "jspdf-autotable";
 
-let tbldata =[], filteredData = [] ;
+let tbldata = [], filteredData = [];
 let selectedRows = [];
 let isunittest = false;
 let showTopTotal = true;
@@ -29,21 +29,21 @@ let showGlobalFilter = true;
 let showColumnFilter = true;
 let allowColumnSelection = true;
 let allowRowSelection = false;
-let columnclassname =[];
+let columnclassname = [];
 let parentCallbackFunction, parentCBonSelection;
 let showCSV = false;
 let anyOfFilter = '';
 
 // Define a default UI for filtering
 function GlobalFilter({
-    preGlobalFilteredRows,
-    globalFilter,
-    setGlobalFilter,
-  }) {
+  preGlobalFilteredRows,
+  globalFilter,
+  setGlobalFilter,
+}) {
   const [value, setValue] = React.useState(globalFilter)
-  const onChange = useAsyncDebounce(value => {setGlobalFilter(value || undefined)}, 200)
+  const onChange = useAsyncDebounce(value => { setGlobalFilter(value || undefined) }, 200)
   return (
-    <span style={{marginLeft:"-10px"}}>
+    <span style={{ marginLeft: "-10px" }}>
       <input
         value={value || ""}
         onChange={e => {
@@ -75,11 +75,11 @@ function DefaultColumnFilter({
           setFilter(e.target.value || undefined) // Set undefined to remove the filter entirely
         }}
       />
-      {value && <i onClick={() => {setFilter(undefined); setValue('') }} className="table-reset fa fa-times" />}
+      {value && <i onClick={() => { setFilter(undefined); setValue('') }} className="table-reset fa fa-times" />}
     </div>
   )
 }
- 
+
 /* 
 Generate and download csv 
 */
@@ -94,7 +94,7 @@ function getExportFileBlob({ columns, data, fileType, fileName }) {
     const headerNames = columns.map((column) => column.exportValue);
     const doc = new JsPDF();
     var index = headerNames.indexOf('Action');
-    if (index > -1) { 
+    if (index > -1) {
       headerNames.splice(index, 1);
     }
     doc.autoTable({
@@ -117,35 +117,36 @@ function SelectColumnFilter({
       setValue('');
     }
   }, [filterValue, value]);
-    const options = React.useMemo(() => {
-      const options = new Set()
+  const options = React.useMemo(() => {
+    const options = new Set()
     preFilteredRows.forEach(row => {
       options.add(row.values[id])
     })
     return [...options.values()]
   }, [id, preFilteredRows])
-   // Render a multi-select box
+  // Render a multi-select box
   return (
     <div onClick={e => { e.stopPropagation() }}>
-    <select
-       style={{
-        height: '24.2014px',
-        width: '60px',
-        border:'1px solid lightgrey',
-       }}
-      value={value}
-      onChange={e => { setValue(e.target.value);
-        setFilter(e.target.value|| undefined)
-      }}
-    >
-      <option value="">All</option>
-      {options.map((option, i) => (
-        <option key={i} value={option}>
-          {option}
-        </option>
-      ))}
+      <select
+        style={{
+          height: '24.2014px',
+          width: '60px',
+          border: '1px solid lightgrey',
+        }}
+        value={value}
+        onChange={e => {
+          setValue(e.target.value);
+          setFilter(e.target.value || undefined)
+        }}
+      >
+        <option value="">All</option>
+        {options.map((option, i) => (
+          <option key={i} value={option}>
+            {option}
+          </option>
+        ))}
       </select>
-   </div>
+    </div>
   )
 }
 
@@ -157,63 +158,64 @@ function MultiSelectColumnFilter({
   const [filtertype, setFiltertype] = useState('Any');
   // Set Any / All Filter type
   const setSelectTypeOption = (option) => {
-      setFiltertype(option);
-      anyOfFilter = option
-      if(value !== ''){
-          setFilter(value);
-      }
+    setFiltertype(option);
+    anyOfFilter = option
+    if (value !== '') {
+      setFilter(value);
+    }
   };
 
   React.useEffect(() => {
     if (!filterValue && value) {
-        setValue('');
-        setFiltertype('Any');
+      setValue('');
+      setFiltertype('Any');
     }
   }, [filterValue, value, filtertype]);
-    anyOfFilter = filtertype;
-    const options = React.useMemo(() => {
+  anyOfFilter = filtertype;
+  const options = React.useMemo(() => {
     let options = new Set();
     preFilteredRows.forEach(row => {
-        row.values[id].split(',').forEach( value => {
-            if ( value !== '') {
-                let hasValue = false;
-                options.forEach( option => {
-                    if(option.name === value){
-                       hasValue = true;
-                    }
-                });
-                if(!hasValue) {
-                  let option = { 'name': value, 'value':value};
-                  options.add(option);
-                }
+      row.values[id].split(',').forEach(value => {
+        if (value !== '') {
+          let hasValue = false;
+          options.forEach(option => {
+            if (option.name === value) {
+              hasValue = true;
             }
-        });
-    }); 
+          });
+          if (!hasValue) {
+            let option = { 'name': value, 'value': value };
+            options.add(option);
+          }
+        }
+      });
+    });
     return [...options.values()]
   }, [id, preFilteredRows]);
 
-   // Render a multi-select box
+  // Render a multi-select box
   return (
     <div onClick={e => { e.stopPropagation() }} >
-       <div className="p-field-radiobutton">
-            <RadioButton inputId="filtertype1" name="filtertype" value="Any" onChange={(e) => setSelectTypeOption(e.value)} checked={filtertype === 'Any'} />
-            <label htmlFor="filtertype1">Any</label>
-        </div>
-        <div className="p-field-radiobutton">
-            <RadioButton inputId="filtertype2" name="filtertype" value="All" onChange={(e) => setSelectTypeOption(e.value)} checked={filtertype === 'All'} />
-            <label htmlFor="filtertype2">All</label>
-        </div>  
-        <div style={{position: 'relative'}} >
+      <div className="p-field-radiobutton">
+        <RadioButton inputId="filtertype1" name="filtertype" value="Any" onChange={(e) => setSelectTypeOption(e.value)} checked={filtertype === 'Any'} />
+        <label htmlFor="filtertype1">Any</label>
+      </div>
+      <div className="p-field-radiobutton">
+        <RadioButton inputId="filtertype2" name="filtertype" value="All" onChange={(e) => setSelectTypeOption(e.value)} checked={filtertype === 'All'} />
+        <label htmlFor="filtertype2">All</label>
+      </div>
+      <div style={{ position: 'relative' }} >
         <MultiSelect data-testid="multi-select" id="multi-select" optionLabel="value" optionValue="value" filter={true}
-            value={value}
-            options={options} 
-            onChange={e => { setValue(e.target.value);
-              setFilter(e.target.value|| undefined, filtertype)
-            }}
-            className="multi-select"
+          value={value}
+          options={options}
+          onChange={e => {
+            setValue(e.target.value);
+            setFilter(e.target.value || undefined, filtertype)
+          }}
+          className="multi-select"
         />
-        </div>
-   </div>
+      </div>
+    </div>
   )
 }
 
@@ -238,7 +240,7 @@ function SliderColumnFilter({
 
   return (
     <div onClick={e => { e.stopPropagation() }} className="table-slider">
-    <Slider value={value} onChange={(e) => { setFilter(e.value);setValue(e.value)}}  />
+      <Slider value={value} onChange={(e) => { setFilter(e.value); setValue(e.value) }} />
     </div>
   )
 }
@@ -246,7 +248,7 @@ function SliderColumnFilter({
 // This is a custom filter UI that uses a
 // switch to set the value
 function BooleanColumnFilter({
-  column: { setFilter, filterValue},
+  column: { setFilter, filterValue },
 }) {
   // Calculate the min and max
   // using the preFilteredRows
@@ -258,7 +260,7 @@ function BooleanColumnFilter({
   }, [filterValue, value]);
   return (
     <div onClick={e => { e.stopPropagation() }}>
-      <TriStateCheckbox value={value} style={{'width':'15px','height':'24.2014px'}} onChange={(e) => { setValue(e.value); setFilter(e.value === null ? undefined : e.value); }} />
+      <TriStateCheckbox value={value} style={{ 'width': '15px', 'height': '24.2014px' }} onChange={(e) => { setValue(e.value); setFilter(e.value === null ? undefined : e.value); }} />
     </div>
   )
 }
@@ -266,7 +268,7 @@ function BooleanColumnFilter({
 // This is a custom filter UI that uses a
 // calendar to set the value
 function CalendarColumnFilter({
-  column: { setFilter, filterValue},
+  column: { setFilter, filterValue },
 }) {
   // Calculate the min and max
   // using the preFilteredRows
@@ -277,21 +279,21 @@ function CalendarColumnFilter({
     }
   }, [filterValue, value]);
   return (
-    
+
     <div className="table-filter" onClick={e => { e.stopPropagation() }}>
-       <Calendar value={value} appendTo={document.body} onChange={(e) => {
+      <Calendar value={value} appendTo={document.body} onChange={(e) => {
         const value = moment(e.value, moment.ISO_8601).format("YYYY-MMM-DD")
-          setValue(value); setFilter(value); 
-        }} showIcon></Calendar>
-       {value && <i onClick={() => {setFilter(undefined); setValue('') }} className="tb-cal-reset fa fa-times" />}
-        </div>
+        setValue(value); setFilter(value);
+      }} showIcon></Calendar>
+      {value && <i onClick={() => { setFilter(undefined); setValue('') }} className="tb-cal-reset fa fa-times" />}
+    </div>
   )
 }
 
 // This is a custom filter UI that uses a
 // calendar to set the value
 function DateTimeColumnFilter({
-  column: { setFilter, filterValue},
+  column: { setFilter, filterValue },
 }) {
   const [value, setValue] = useState('');
   React.useEffect(() => {
@@ -300,18 +302,18 @@ function DateTimeColumnFilter({
     }
   }, [filterValue, value]);
   return (
-    
+
     <div className="table-filter" onClick={e => { e.stopPropagation() }}>
-       <Calendar value={value} appendTo={document.body} onChange={(e) => {
+      <Calendar value={value} appendTo={document.body} onChange={(e) => {
         const value = moment(e.value, moment.ISO_8601).format("YYYY-MMM-DD HH:mm:SS")
-          setValue(value); setFilter(value); 
-        }} showIcon
-       // showTime= {true}
-        //showSeconds= {true}
-       // hourFormat= "24"
-        ></Calendar>
-       {value && <i onClick={() => {setFilter(undefined); setValue('') }} className="tb-cal-reset fa fa-times" />}
-        </div>
+        setValue(value); setFilter(value);
+      }} showIcon
+      // showTime= {true}
+      //showSeconds= {true}
+      // hourFormat= "24"
+      ></Calendar>
+      {value && <i onClick={() => { setFilter(undefined); setValue('') }} className="tb-cal-reset fa fa-times" />}
+    </div>
   )
 }
 
@@ -322,21 +324,21 @@ function DateTimeColumnFilter({
  * @param {String} filterValue 
  */
 function fromDatetimeFilterFn(rows, id, filterValue) {
-  const filteredRows = _.filter(rows, function(row) {
-                        // If cell value is null or empty
-                        if (!row.values[id]) {
-                          return false;
-                        }
-                        //Remove microsecond if value passed is UTC string in format "YYYY-MM-DDTHH:mm:ss.sssss"
-                        let rowValue = moment.utc(row.values[id].split('.')[0]);
-                        if (!rowValue.isValid()) {
-                            // For cell data in format 'YYYY-MMM-DD'
-                            rowValue = moment.utc(moment(row.values[id], 'YYYY-MMM-DDTHH:mm:SS').format("YYYY-MM-DDTHH:mm:SS"));
-                        }
-                        const start = moment.utc(moment(filterValue, 'YYYY-MMM-DDTHH:mm:SS').format("YYYY-MM-DDTHH:mm:SS"));
-                        
-                        return (start.isSameOrBefore(rowValue));
-                      } );
+  const filteredRows = _.filter(rows, function (row) {
+    // If cell value is null or empty
+    if (!row.values[id]) {
+      return false;
+    }
+    //Remove microsecond if value passed is UTC string in format "YYYY-MM-DDTHH:mm:ss.sssss"
+    let rowValue = moment.utc(row.values[id].split('.')[0]);
+    if (!rowValue.isValid()) {
+      // For cell data in format 'YYYY-MMM-DD'
+      rowValue = moment.utc(moment(row.values[id], 'YYYY-MMM-DDTHH:mm:SS').format("YYYY-MM-DDTHH:mm:SS"));
+    }
+    const start = moment.utc(moment(filterValue, 'YYYY-MMM-DDTHH:mm:SS').format("YYYY-MM-DDTHH:mm:SS"));
+
+    return (start.isSameOrBefore(rowValue));
+  });
   return filteredRows;
 }
 
@@ -348,36 +350,36 @@ function fromDatetimeFilterFn(rows, id, filterValue) {
  */
 function multiSelectFilterFn(rows, id, filterValue) {
   if (filterValue) {
-        const filteredRows = _.filter(rows, function(row) {
-          if ( filterValue.length === 0){
-            return true;
-          }
-          // If cell value is null or empty
-          if (!row.values[id]) {
-            return false;
-          }
-          let rowValue = row.values[id];
-          let hasData = false;
-          if ( anyOfFilter === 'Any' ) {
-              hasData = false;
-              filterValue.forEach(filter => {
-                  if( rowValue.includes( filter )) {
-                      hasData = true;
-                  }
-              }); 
+    const filteredRows = _.filter(rows, function (row) {
+      if (filterValue.length === 0) {
+        return true;
+      }
+      // If cell value is null or empty
+      if (!row.values[id]) {
+        return false;
+      }
+      let rowValue = row.values[id];
+      let hasData = false;
+      if (anyOfFilter === 'Any') {
+        hasData = false;
+        filterValue.forEach(filter => {
+          if (rowValue.includes(filter)) {
+            hasData = true;
           }
-          else {
-              hasData = true;
-              filterValue.forEach(filter => {
-                  if( !rowValue.includes( filter )) {
-                      hasData = false;
-                  }                  
-              });  
+        });
+      }
+      else {
+        hasData = true;
+        filterValue.forEach(filter => {
+          if (!rowValue.includes(filter)) {
+            hasData = false;
           }
-          return hasData;
-        } );
-        return filteredRows;
-    }
+        });
+      }
+      return hasData;
+    });
+    return filteredRows;
+  }
 }
 
 /**
@@ -388,20 +390,20 @@ function multiSelectFilterFn(rows, id, filterValue) {
  */
 function toDatetimeFilterFn(rows, id, filterValue) {
   let end = moment.utc(moment(filterValue, 'YYYY-MMM-DDTHH:mm:SS').format("YYYY-MM-DDTHH:mm:SS"));
-  end =   moment(end, "DD-MM-YYYY").add(1, 'days');
-  const filteredRows = _.filter(rows, function(row) {
-                        // If cell value is null or empty
-                        if (!row.values[id]) {
-                          return false;
-                        }
-                        //Remove microsecond if value passed is UTC string in format "YYYY-MM-DDTHH:mm:ss.sssss"
-                        let rowValue = moment.utc(row.values[id].split('.')[0]);
-                        if (!rowValue.isValid()) {
-                            // For cell data in format 'YYYY-MMM-DD'
-                            rowValue = moment.utc(moment(row.values[id], 'YYYY-MMM-DDTHH:mm:SS').format("YYYY-MM-DDTHH:mm:SS"));
-                        }
-                        return (end.isSameOrAfter(rowValue));
-                      } );
+  end = moment(end, "DD-MM-YYYY").add(1, 'days');
+  const filteredRows = _.filter(rows, function (row) {
+    // If cell value is null or empty
+    if (!row.values[id]) {
+      return false;
+    }
+    //Remove microsecond if value passed is UTC string in format "YYYY-MM-DDTHH:mm:ss.sssss"
+    let rowValue = moment.utc(row.values[id].split('.')[0]);
+    if (!rowValue.isValid()) {
+      // For cell data in format 'YYYY-MMM-DD'
+      rowValue = moment.utc(moment(row.values[id], 'YYYY-MMM-DDTHH:mm:SS').format("YYYY-MM-DDTHH:mm:SS"));
+    }
+    return (end.isSameOrAfter(rowValue));
+  });
   return filteredRows;
 }
 
@@ -412,28 +414,28 @@ function toDatetimeFilterFn(rows, id, filterValue) {
  * @param {String} filterValue 
  */
 function dateFilterFn(rows, id, filterValue) {
-  const filteredRows = _.filter(rows, function(row) {
-                        // If cell value is null or empty
-                        if (!row.values[id]) {
-                          return false;
-                        }
-                        //Remove microsecond if value passed is UTC string in format "YYYY-MM-DDTHH:mm:ss.sssss"
-                        let rowValue = moment.utc(row.values[id].split('.')[0]);
-                        if (!rowValue.isValid()) {
-                            // For cell data in format 'YYYY-MMM-DD'
-                            rowValue = moment.utc(moment(row.values[id], 'YYYY-MMM-DD').format("YYYY-MM-DDT00:00:00"));
-                        }
-                        const start = moment.utc(moment(filterValue, 'YYYY-MMM-DD').format("YYYY-MM-DDT00:00:00"));
-                        const end = moment.utc(moment(filterValue, 'YYYY-MMM-DD').format("YYYY-MM-DDT23:59:59"));
-                        return (start.isSameOrBefore(rowValue) && end.isSameOrAfter(rowValue));
-                      } );
+  const filteredRows = _.filter(rows, function (row) {
+    // If cell value is null or empty
+    if (!row.values[id]) {
+      return false;
+    }
+    //Remove microsecond if value passed is UTC string in format "YYYY-MM-DDTHH:mm:ss.sssss"
+    let rowValue = moment.utc(row.values[id].split('.')[0]);
+    if (!rowValue.isValid()) {
+      // For cell data in format 'YYYY-MMM-DD'
+      rowValue = moment.utc(moment(row.values[id], 'YYYY-MMM-DD').format("YYYY-MM-DDT00:00:00"));
+    }
+    const start = moment.utc(moment(filterValue, 'YYYY-MMM-DD').format("YYYY-MM-DDT00:00:00"));
+    const end = moment.utc(moment(filterValue, 'YYYY-MMM-DD').format("YYYY-MM-DDT23:59:59"));
+    return (start.isSameOrBefore(rowValue) && end.isSameOrAfter(rowValue));
+  });
   return filteredRows;
 }
 
 // This is a custom UI for our 'between' or number range
 // filter. It uses slider to filter between min and max values.
 function RangeColumnFilter({
-  column: { filterValue = [], preFilteredRows, setFilter, id},
+  column: { filterValue = [], preFilteredRows, setFilter, id },
 }) {
   const [min, max] = React.useMemo(() => {
     let min = 0;
@@ -442,8 +444,8 @@ function RangeColumnFilter({
       min = preFilteredRows[0].values[id];
     }
     preFilteredRows.forEach(row => {
-      min = Math.min(row.values[id]?row.values[id]:0, min);
-      max = Math.max(row.values[id]?row.values[id]:0, max);
+      min = Math.min(row.values[id] ? row.values[id] : 0, min);
+      max = Math.max(row.values[id] ? row.values[id] : 0, max);
     });
     return [min, max];
   }, [id, preFilteredRows]);
@@ -454,12 +456,12 @@ function RangeColumnFilter({
   return (
     <>
       <div className="filter-slider-label">
-        <span style={{float: "left"}}>{filterValue[0]}</span>
-        <span style={{float: "right"}}>{min!==max?filterValue[1]:""}</span>
+        <span style={{ float: "left" }}>{filterValue[0]}</span>
+        <span style={{ float: "right" }}>{min !== max ? filterValue[1] : ""}</span>
       </div>
       <Slider value={filterValue} min={min} max={max} className="filter-slider"
-              style={{}}
-              onChange={(e) => { setFilter(e.value); }} range />
+        style={{}}
+        onChange={(e) => { setFilter(e.value); }} range />
     </>
   );
 }
@@ -470,9 +472,9 @@ function RangeColumnFilter({
 function NumberRangeColumnFilter({
   column: { filterValue = [], preFilteredRows, setFilter, id },
 }) {
-    const [errorProps, setErrorProps] = useState({});
-    const [maxErr, setMaxErr] = useState(false);
-    const [min, max] = React.useMemo(() => {
+  const [errorProps, setErrorProps] = useState({});
+  const [maxErr, setMaxErr] = useState(false);
+  const [min, max] = React.useMemo(() => {
     let min = preFilteredRows.length ? preFilteredRows[0].values[id] : 0
     let max = preFilteredRows.length ? preFilteredRows[0].values[id] : 0
     preFilteredRows.forEach(row => {
@@ -485,8 +487,8 @@ function NumberRangeColumnFilter({
   return (
     <div
       style={{
-      //  display: 'flex',
-      //  flexdirection:'column',
+        //  display: 'flex',
+        //  flexdirection:'column',
         alignItems: 'center'
       }}
     >
@@ -495,16 +497,16 @@ function NumberRangeColumnFilter({
         type="number"
         onChange={e => {
           const val = e.target.value;
-          setFilter((old = []) => [val ? parseFloat (val, 10) : undefined, old[1]]);
+          setFilter((old = []) => [val ? parseFloat(val, 10) : undefined, old[1]]);
         }}
         placeholder={`Min (${min})`}
         style={{
           width: '55px',
-          height:'25px'
-       // marginRight: '0.5rem',
+          height: '25px'
+          // marginRight: '0.5rem',
         }}
       />
-       <InputText
+      <InputText
         value={filterValue[1] || ''}
         type="number"
         {...errorProps}
@@ -516,19 +518,19 @@ function NumberRangeColumnFilter({
             setMaxErr(true);
             setErrorProps({
               tooltip: "Max value should be greater than Min",
-              tooltipOptions: { event: 'hover'}
+              tooltipOptions: { event: 'hover' }
             });
           } else {
             setMaxErr(false);
             setErrorProps({});
           }
-          setFilter((old = []) => [old[0], val ? parseFloat (val, 10) : undefined])
+          setFilter((old = []) => [old[0], val ? parseFloat(val, 10) : undefined])
         }}
         placeholder={`Max (${max})`}
         style={{
           width: '55px',
-          height:'25px'
-        //  marginLeft: '0.5rem',
+          height: '25px'
+          //  marginLeft: '0.5rem',
         }}
       />
     </div>
@@ -541,12 +543,12 @@ function fuzzyTextFilterFn(rows, id, filterValue) {
 }
 
 const filterTypes = {
-  'select': { 
+  'select': {
     fn: SelectColumnFilter,
   },
-  'multiselect': { 
+  'multiselect': {
     fn: MultiSelectColumnFilter,
-    type: multiSelectFilterFn 
+    type: multiSelectFilterFn
   },
   'switch': {
     fn: BooleanColumnFilter
@@ -570,7 +572,7 @@ const filterTypes = {
     fn: RangeColumnFilter,
     type: 'between'
   },
-  'minMax': { 
+  'minMax': {
     fn: NumberRangeColumnFilter,
     type: 'between'
   }
@@ -590,8 +592,8 @@ const IndeterminateCheckbox = React.forwardRef(
 )
 
 // Our table component
-function Table({ columns, data, defaultheader, optionalheader, tablename, defaultSortColumn,defaultpagesize }) {
- 
+function Table({ columns, data, defaultheader, optionalheader, tablename, defaultSortColumn, defaultpagesize, columnOrders, showAction }) {
+
   const filterTypes = React.useMemo(
     () => ({
       // Add a new fuzzyTextFilterFn filter type.
@@ -603,8 +605,8 @@ function Table({ columns, data, defaultheader, optionalheader, tablename, defaul
           const rowValue = row.values[id]
           return rowValue !== undefined
             ? String(rowValue)
-                .toLowerCase()
-                .startsWith(String(filterValue).toLowerCase())
+              .toLowerCase()
+              .startsWith(String(filterValue).toLowerCase())
             : true
         })
       },
@@ -613,73 +615,87 @@ function Table({ columns, data, defaultheader, optionalheader, tablename, defaul
   )
 
   const defaultColumn = React.useMemo(
-      () => ({
-        // Let's set up our default Filter UI
-        Filter: DefaultColumnFilter,
-      
-      }),
-      []
-    )
-
-    const {
-      getTableProps,
-      getTableBodyProps,
-      headerGroups,
-      rows,
-      prepareRow,
-      setAllFilters,
-      allColumns,
-      getToggleHideAllColumnsProps,
-      state,
-      page,
-      preGlobalFilteredRows,
-      setGlobalFilter,
-      setHiddenColumns,
-      gotoPage,
-      setPageSize,
-      selectedFlatRows,
-      exportData,
-      } = useTable(
-        {
-          columns,
-          data,
-          defaultColumn,
-          filterTypes,
-          initialState: { pageIndex: 0,
-            pageSize: (defaultpagesize && defaultpagesize>0)?defaultpagesize:10,
-            sortBy: defaultSortColumn },
-            getExportFileBlob,
-        },
-        useFilters,
-        useGlobalFilter,
-        useSortBy,   
-        usePagination,
-        useRowSelect,
-        useExportData
-      );
-    React.useEffect(() => {
-      setHiddenColumns(
-        columns.filter(column => !column.isVisible).map(column => column.accessor)
-      );
-    }, [setHiddenColumns, columns]);
+    () => ({
+      // Let's set up our default Filter UI
+      Filter: DefaultColumnFilter,
 
-    let op = useRef(null);
+    }),
+    []
+  )
 
-    const [currentpage, setcurrentPage] = React.useState(0);
-    const [currentrows, setcurrentRows] = React.useState(defaultpagesize);
-    const [custompagevalue,setcustompagevalue] = React.useState();
+  const {
+    getTableProps,
+    getTableBodyProps,
+    headerGroups,
+    rows,
+    prepareRow,
+    setAllFilters,
+    allColumns,
+    getToggleHideAllColumnsProps,
+    visibleColumns,
+    state,
+    page,
+    preGlobalFilteredRows,
+    setGlobalFilter,
+    setHiddenColumns,
+    gotoPage,
+    setPageSize,
+    selectedFlatRows,
+    setColumnOrder,
+    exportData,
+  } = useTable(
+    {
+      columns,
+      data,
+      defaultColumn,
+      filterTypes,
+      initialState: {
+        pageIndex: 0,
+        pageSize: (defaultpagesize && defaultpagesize > 0) ? defaultpagesize : 10,
+        sortBy: defaultSortColumn
+      },
+      getExportFileBlob,
+    },
+    useFilters,
+    useGlobalFilter,
+    useSortBy,
+    usePagination,
+    useRowSelect,
+    useColumnOrder,
+    useExportData
+  );
+  React.useEffect(() => {
+    setHiddenColumns(
+      columns.filter(column => !column.isVisible).map(column => column.accessor)
+    );
+    // console.log('columns List', visibleColumns.map((d) => d.id));
+    if (columnOrders && columnOrders.length) {
+      if (showAction === 'true') {
+        setColumnOrder(['Select', 'Action', ...columnOrders]);
+      } else {
+        setColumnOrder(['Select', ...columnOrders]);
+      }
+    }
+    
+  }, [setHiddenColumns, columns]);
+
+  let op = useRef(null);
+
+  const [currentpage, setcurrentPage] = React.useState(0);
+  const [currentrows, setcurrentRows] = React.useState(defaultpagesize);
+  const [custompagevalue, setcustompagevalue] = React.useState();
 
   const onPagination = (e) => {
-      gotoPage(e.page);
-      setcurrentPage(e.first);
-      setcurrentRows(e.rows);
-      setPageSize(e.rows)
-      if([10,25,50,100].includes(e.rows)){
-        setcustompagevalue();
-      }
-    };
+    gotoPage(e.page);
+    setcurrentPage(e.first);
+    setcurrentRows(e.rows);
+    setPageSize(e.rows)
+    if ([10, 25, 50, 100].includes(e.rows)) {
+      setcustompagevalue();
+    }
+  };
   const onCustomPage = (e) => {
-    if(typeof custompagevalue === 'undefined' || custompagevalue == null) return;
+    if (typeof custompagevalue === 'undefined' || custompagevalue == null) return;
     gotoPage(0);
     setcurrentPage(0);
     setcurrentRows(custompagevalue);
@@ -689,7 +705,7 @@ function Table({ columns, data, defaultheader, optionalheader, tablename, defaul
   const onChangeCustompagevalue = (e) => {
     setcustompagevalue(e.target.value);
   }
-  
+
   const onShowAllPage = (e) => {
     gotoPage(e.page);
     setcurrentPage(e.first);
@@ -698,16 +714,16 @@ function Table({ columns, data, defaultheader, optionalheader, tablename, defaul
     setcustompagevalue();
   };
 
-  const onToggleChange = (e) =>{
+  const onToggleChange = (e) => {
     let lsToggleColumns = [];
-    allColumns.forEach( acolumn =>{
+    allColumns.forEach(acolumn => {
       let jsonobj = {};
-      let visible = (acolumn.Header === e.target.id) ? ((acolumn.isVisible)?false:true) :acolumn.isVisible
+      let visible = (acolumn.Header === e.target.id) ? ((acolumn.isVisible) ? false : true) : acolumn.isVisible
       jsonobj['Header'] = acolumn.Header;
       jsonobj['isVisible'] = visible;
-      lsToggleColumns.push(jsonobj) 
+      lsToggleColumns.push(jsonobj)
     })
-    localStorage.setItem(tablename,JSON.stringify(lsToggleColumns))
+    localStorage.setItem(tablename, JSON.stringify(lsToggleColumns))
   }
 
   filteredData = _.map(rows, 'values');
@@ -716,75 +732,75 @@ function Table({ columns, data, defaultheader, optionalheader, tablename, defaul
   }
 
   /* Select only rows than can be selected. This is required when ALL is selected */
-  selectedRows = _.filter(selectedFlatRows, selectedRow => { return (selectedRow.original.canSelect===undefined || selectedRow.original.canSelect)});
+  selectedRows = _.filter(selectedFlatRows, selectedRow => { return (selectedRow.original.canSelect === undefined || selectedRow.original.canSelect) });
   /* Take only the original values passed to the component */
   selectedRows = _.map(selectedRows, 'original');
   /* Callback the parent function if available to pass the selected records on selection */
   if (parentCBonSelection) {
     parentCBonSelection(selectedRows)
   }
-  
+
   return (
     <>
-    <div style={{display: 'flex', justifyContent: 'space-between'}}>
-    <div id="block_container" > 
-      { allowColumnSelection &&
-            <div   style={{textAlign:'left', marginRight:'30px'}}>
-                  <i className="fa fa-columns col-filter-btn" label="Toggle Columns" onClick={(e) => op.current.toggle(e)}  />
-                  {showColumnFilter &&
-                  <div style={{position:"relative",top: "-25px",marginLeft: "50px",color: "#005b9f"}} onClick={() => setAllFilters([])} >
-                    <i class="fas fa-sync-alt" title="Clear All Filters"></i></div>}
-                  <OverlayPanel ref={op} id="overlay_panel" showCloseIcon={false} >
-                    <div>
-                        <div style={{textAlign: 'center'}}>
-                          <label>Select column(s) to view</label>
-                        </div>
-                        <div style={{float: 'left', backgroundColor: '#d1cdd936', width: '250px', height: '400px', overflow: 'auto', marginBottom:'10px', padding:'5px'}}>
-                        <div id="tagleid"  >
-                          <div >
-                            <div style={{marginBottom:'5px'}}>
-                              <IndeterminateCheckbox {...getToggleHideAllColumnsProps()} /> Select All
+      <div style={{ display: 'flex', justifyContent: 'space-between' }}>
+        <div id="block_container" >
+          {allowColumnSelection &&
+            <div style={{ textAlign: 'left', marginRight: '30px' }}>
+              <i className="fa fa-columns col-filter-btn" label="Toggle Columns" onClick={(e) => op.current.toggle(e)} />
+              {showColumnFilter &&
+                <div style={{ position: "relative", top: "-25px", marginLeft: "50px", color: "#005b9f" }} onClick={() => setAllFilters([])} >
+                  <i class="fas fa-sync-alt" title="Clear All Filters"></i></div>}
+              <OverlayPanel ref={op} id="overlay_panel" showCloseIcon={false} >
+                <div>
+                  <div style={{ textAlign: 'center' }}>
+                    <label>Select column(s) to view</label>
+                  </div>
+                  <div style={{ float: 'left', backgroundColor: '#d1cdd936', width: '250px', height: '400px', overflow: 'auto', marginBottom: '10px', padding: '5px' }}>
+                    <div id="tagleid"  >
+                      <div >
+                        <div style={{ marginBottom: '5px' }}>
+                          <IndeterminateCheckbox {...getToggleHideAllColumnsProps()} /> Select All
                             </div>
-                            {allColumns.map(column => (
-                              <div key={column.id} style={{'display':column.id !== 'actionpath'?'block':'none'}}> 
-                                  <input type="checkbox" {...column.getToggleHiddenProps()} 
-                                  id={(defaultheader[column.id])?defaultheader[column.id]:(optionalheader[column.id]?optionalheader[column.id]:column.id)}
-                                  onClick={onToggleChange}
-                                  /> {
-                                    (defaultheader[column.id]) ? defaultheader[column.id] : (optionalheader[column.id] ? optionalheader[column.id] : column.id)}
-                              </div>
-                            ))}
-                            <br />
+                        {allColumns.map(column => (
+                          <div key={column.id} style={{ 'display': column.id !== 'actionpath' ? 'block' : 'none' }}>
+                            <input type="checkbox" {...column.getToggleHiddenProps()}
+                              id={(defaultheader[column.id]) ? defaultheader[column.id] : (optionalheader[column.id] ? optionalheader[column.id] : column.id)}
+                              onClick={onToggleChange}
+                            /> {
+                              (defaultheader[column.id]) ? defaultheader[column.id] : (optionalheader[column.id] ? optionalheader[column.id] : column.id)}
                           </div>
-                        </div>
+                        ))}
+                        <br />
                       </div>
                     </div>
-                  </OverlayPanel>
-              </div> 
-        }
-        <div  style={{textAlign:'right'}}>
-        {tbldata.length>0 && !isunittest && showGlobalFilter &&
+                  </div>
+                </div>
+              </OverlayPanel>
+            </div>
+          }
+          <div style={{ textAlign: 'right' }}>
+            {tbldata.length > 0 && !isunittest && showGlobalFilter &&
               <GlobalFilter
                 preGlobalFilteredRows={preGlobalFilteredRows}
                 globalFilter={state.globalFilter}
                 setGlobalFilter={setGlobalFilter}
               />
             }
-        </div>
-        
-        
-        { showTopTotal && filteredData.length === data.length &&
-          <div className="total_records_top_label"> <label >Total records ({data.length})</label></div>
-        } 
-         
-        { showTopTotal && filteredData.length < data.length &&
+          </div>
+
+
+          {showTopTotal && filteredData.length === data.length &&
+            <div className="total_records_top_label"> <label >Total records ({data.length})</label></div>
+          }
+
+          {showTopTotal && filteredData.length < data.length &&
             <div className="total_records_top_label" ><label >Filtered {filteredData.length} from {data.length}</label></div>}
-        
-      </div>
-      {showCSV && 
-          <div className="total_records_top_label" style={{marginTop: '20px'}} >
-            <a href="#" onClick={() => {exportData("csv", false);}} title="Download CSV" style={{verticalAlign: 'middle'}}>
-                <i class="fas fa-file-csv" style={{color: 'green', fontSize: '20px'}} ></i>
+
+        </div>
+        {showCSV &&
+          <div className="total_records_top_label" style={{ marginTop: '20px' }} >
+            <a href="#" onClick={() => { exportData("csv", false); }} title="Download CSV" style={{ verticalAlign: 'middle' }}>
+              <i class="fas fa-file-csv" style={{ color: 'green', fontSize: '20px' }} ></i>
             </a>
           </div>
           /* 
@@ -794,80 +810,80 @@ function Table({ columns, data, defaultheader, optionalheader, tablename, defaul
               </a>
             </div> */
         }
-    </div>
-     
+      </div>
+
 
       <div className="tmss-table table_container">
         <table {...getTableProps()} data-testid="viewtable" className="viewtable" >
-            <thead>
-              {headerGroups.map(headerGroup =>  (
-                <tr {...headerGroup.getHeaderGroupProps()}>
-                  {headerGroup.headers.map(column => (
-                    <th> 
-                      <div {...column.getHeaderProps(column.getSortByToggleProps())}>
-                        {column.Header !== 'actionpath' && column.render('Header')}
-                        {column.Header !== 'Action'? 
-                          column.isSorted ? (column.isSortedDesc ? <i className="pi pi-sort-down" aria-hidden="true"></i> : <i className="pi pi-sort-up" aria-hidden="true"></i>) : ""
-                          : ""
-                        }
-                      </div>
+          <thead>
+            {headerGroups.map(headerGroup => (
+              <tr {...headerGroup.getHeaderGroupProps()}>
+                {headerGroup.headers.map(column => (
+                  <th>
+                    <div {...column.getHeaderProps(column.getSortByToggleProps())}>
+                      {column.Header !== 'actionpath' && column.render('Header')}
+                      {column.Header !== 'Action' ?
+                        column.isSorted ? (column.isSortedDesc ? <i className="pi pi-sort-down" aria-hidden="true"></i> : <i className="pi pi-sort-up" aria-hidden="true"></i>) : ""
+                        : ""
+                      }
+                    </div>
 
-                      {/* Render the columns filter UI */} 
-                        {column.Header !== 'actionpath' &&
-                          <div className={columnclassname[0][column.Header]}  > 
-                            {column.canFilter && column.Header !== 'Action' ? column.render('Filter') : null}
+                    {/* Render the columns filter UI */}
+                    {column.Header !== 'actionpath' &&
+                      <div className={columnclassname[0][column.Header]}  >
+                        {column.canFilter && column.Header !== 'Action' ? column.render('Filter') : null}
 
-                          </div>
-                        }
-                    </th> 
-                  ))}
-                  </tr>
-                  ))}
-            </thead>
-            <tbody {...getTableBodyProps()}>
-              {page.map((row, i) => {
-                  prepareRow(row)
-                  return (
-                      <tr {...row.getRowProps()}>
-                          {row.cells.map(cell => {
-                              if(cell.column.id !== 'actionpath'){
-                                  return <td {...cell.getCellProps()}>
-                                    {(cell.row.original.links || []).includes(cell.column.id) ? <Link to={cell.row.original.linksURL[cell.column.id]}>{cell.render('Cell')}</Link> : cell.render('Cell')}
-                                    </td>
-                              }
-                              else {
-                                  return "";
-                              }
-                          }
-                        )}
-                      </tr>
-                  );
-                })}
-            </tbody>
-          </table>
+                      </div>
+                    }
+                  </th>
+                ))}
+              </tr>
+            ))}
+          </thead>
+          <tbody {...getTableBodyProps()}>
+            {page.map((row, i) => {
+              prepareRow(row)
+              return (
+                <tr {...row.getRowProps()}>
+                  {row.cells.map(cell => {
+                    if (cell.column.id !== 'actionpath') {
+                      return <td {...cell.getCellProps()}>
+                        {(cell.row.original.links || []).includes(cell.column.id) ? <Link to={cell.row.original.linksURL[cell.column.id]}>{cell.render('Cell')}</Link> : cell.render('Cell')}
+                      </td>
+                    }
+                    else {
+                      return "";
+                    }
+                  }
+                  )}
+                </tr>
+              );
+            })}
+          </tbody>
+        </table>
+      </div>
+      <div className="pagination p-grid" >
+        {filteredData.length === data.length &&
+          <div className="total_records_bottom_label" ><label >Total records ({data.length})</label></div>
+        }
+        {filteredData.length < data.length &&
+          <div className="total_records_bottom_label" ><label >Filtered {filteredData.length} from {data.length}</label></div>
+        }
+        <div>
+          <Paginator rowsPerPageOptions={[10, 25, 50, 100]} first={currentpage} rows={currentrows} totalRecords={rows.length} onPageChange={onPagination}></Paginator>
+        </div>
+        <div>
+          <InputNumber id="custompage" value={custompagevalue} onChange={onChangeCustompagevalue}
+            min={0} style={{ width: '100px' }} />
+          <label >Records/Page</label>
+          <Button onClick={onCustomPage}> Show </Button>
+          <Button onClick={onShowAllPage} style={{ marginLeft: "1em" }}> Show All </Button>
         </div>
-        <div className="pagination p-grid" >
-            {filteredData.length === data.length &&
-                <div className="total_records_bottom_label" ><label >Total records ({data.length})</label></div>
-            }
-            {filteredData.length < data.length &&
-                    <div className="total_records_bottom_label" ><label >Filtered {filteredData.length} from {data.length}</label></div>
-            }
-            <div>
-                <Paginator rowsPerPageOptions={[10,25,50,100]} first={currentpage} rows={currentrows} totalRecords={rows.length} onPageChange={onPagination}></Paginator>
-            </div>
-            <div>
-                <InputNumber id="custompage" value={custompagevalue} onChange ={onChangeCustompagevalue}
-                    min={0} style={{width:'100px'}} />
-                <label >Records/Page</label>
-                <Button onClick={onCustomPage}> Show </Button>
-                <Button onClick={onShowAllPage} style={{marginLeft: "1em"}}> Show All </Button>
-            </div>  
       </div>
     </>
   )
 }
- 
+
 
 // Define a custom filter filter function!
 function filterGreaterThan(rows, id, filterValue) {
@@ -884,90 +900,94 @@ function filterGreaterThan(rows, id, filterValue) {
 filterGreaterThan.autoRemove = val => typeof val !== 'number'
 
 function ViewTable(props) {
-    const history = useHistory();
-    // Data to show in table
-    tbldata = props.data;
-    showCSV= (props.showCSV)?props.showCSV:false;
-
-    parentCallbackFunction = props.filterCallback; 
-    parentCBonSelection = props.onRowSelection;
-    isunittest = props.unittest;
-    columnclassname = props.columnclassname;
-    showTopTotal = props.showTopTotal===undefined?true:props.showTopTotal;
-    showGlobalFilter = props.showGlobalFilter===undefined?true:props.showGlobalFilter;
-    showColumnFilter = props.showColumnFilter===undefined?true:props.showColumnFilter;
-    allowColumnSelection = props.allowColumnSelection===undefined?true:props.allowColumnSelection;
-    allowRowSelection = props.allowRowSelection===undefined?false:props.allowRowSelection;
-    // Default Header to show in table and other columns header will not show until user action on UI
-    let defaultheader = props.defaultcolumns;
-    let optionalheader = props.optionalcolumns;
-    let defaultSortColumn = props.defaultSortColumn;
-    let tablename = (props.tablename)?props.tablename:window.location.pathname;
-    
-    if(!defaultSortColumn){
-      defaultSortColumn =[{}];
-    }
-    let defaultpagesize = (typeof props.defaultpagesize === 'undefined' || props.defaultpagesize == null)?10:props.defaultpagesize;
-    let columns = [];   
-    let defaultdataheader =  Object.keys(defaultheader[0]);
-    let optionaldataheader =  Object.keys(optionalheader[0]);
-
-    /* If allowRowSelection property is true for the component, add checkbox column as 1st column.
-       If the record has property to select, enable the checkbox */
-    if (allowRowSelection) {
-      columns.push({
-        Header: ({ getToggleAllRowsSelectedProps }) => { return (
+  const history = useHistory();
+  // Data to show in table
+  tbldata = props.data;
+  showCSV = (props.showCSV) ? props.showCSV : false;
+
+  parentCallbackFunction = props.filterCallback;
+  parentCBonSelection = props.onRowSelection;
+  isunittest = props.unittest;
+  columnclassname = props.columnclassname;
+  showTopTotal = props.showTopTotal === undefined ? true : props.showTopTotal;
+  showGlobalFilter = props.showGlobalFilter === undefined ? true : props.showGlobalFilter;
+  showColumnFilter = props.showColumnFilter === undefined ? true : props.showColumnFilter;
+  allowColumnSelection = props.allowColumnSelection === undefined ? true : props.allowColumnSelection;
+  allowRowSelection = props.allowRowSelection === undefined ? false : props.allowRowSelection;
+  // Default Header to show in table and other columns header will not show until user action on UI
+  let defaultheader = props.defaultcolumns;
+  let optionalheader = props.optionalcolumns;
+  let defaultSortColumn = props.defaultSortColumn;
+  let tablename = (props.tablename) ? props.tablename : window.location.pathname;
+
+  if (!defaultSortColumn) {
+    defaultSortColumn = [{}];
+  }
+  let defaultpagesize = (typeof props.defaultpagesize === 'undefined' || props.defaultpagesize == null) ? 10 : props.defaultpagesize;
+  let columns = [];
+  let defaultdataheader = Object.keys(defaultheader[0]);
+  let optionaldataheader = Object.keys(optionalheader[0]);
+
+  /* If allowRowSelection property is true for the component, add checkbox column as 1st column.
+     If the record has property to select, enable the checkbox */
+  if (allowRowSelection) {
+    columns.push({
+      Header: ({ getToggleAllRowsSelectedProps }) => {
+        return (
           <div>
-            <IndeterminateCheckbox {...getToggleAllRowsSelectedProps()} style={{width:'15px', height:'15px'}}/>
+            <IndeterminateCheckbox {...getToggleAllRowsSelectedProps()} style={{ width: '15px', height: '15px' }} />
           </div>
-        )},
-        id:'Select',
-        accessor: props.keyaccessor,
-        Cell: ({ row }) => { return (
+        )
+      },
+      id: 'Select',
+      accessor: props.keyaccessor,
+      Cell: ({ row }) => {
+        return (
           <div>
-            {(row.original.canSelect===undefined || row.original.canSelect) &&
-              <IndeterminateCheckbox {...row.getToggleRowSelectedProps()}  style={{width:'15px', height:'15px'}}/>
+            {(row.original.canSelect === undefined || row.original.canSelect) &&
+              <IndeterminateCheckbox {...row.getToggleRowSelectedProps()} style={{ width: '15px', height: '15px' }} />
             }
-            {row.original.canSelect===false &&
-              <input type="checkbox" checked={false} disabled style={{width:'15px', height:'15px'}}></input>
+            {row.original.canSelect === false &&
+              <input type="checkbox" checked={false} disabled style={{ width: '15px', height: '15px' }}></input>
             }
           </div>
-        )},
-        disableFilters: true,
-        disableSortBy: true,
-        isVisible: defaultdataheader.includes(props.keyaccessor),
-      });
-    }
-    
-    if(props.showaction === 'true') {
-      columns.push({
-          Header: 'Action',
-          id:'Action',
-          accessor: props.keyaccessor,
-          Cell: props => <button className='p-link' onClick={navigateTo(props)} ><i className="fa fa-eye" style={{cursor: 'pointer'}}></i></button>,
-          disableFilters: true,
-          disableSortBy: true,
-          isVisible: defaultdataheader.includes(props.keyaccessor),
-        })
-     }
-
-     const navigateTo = (props) => () => {
-       if(props.cell.row.values['actionpath']){
-        return history.push({
-          pathname: props.cell.row.values['actionpath'],
-          state: { 
-            "id": props.value,
-          }
-        })
-       }
-     // Object.entries(props.paths[0]).map(([key,value]) =>{})
+        )
+      },
+      disableFilters: true,
+      disableSortBy: true,
+      isVisible: defaultdataheader.includes(props.keyaccessor),
+    });
+  }
+
+  if (props.showaction === 'true') {
+    columns.push({
+      Header: 'Action',
+      id: 'Action',
+      accessor: props.keyaccessor,
+      Cell: props => <button className='p-link' onClick={navigateTo(props)} ><i className="fa fa-eye" style={{ cursor: 'pointer' }}></i></button>,
+      disableFilters: true,
+      disableSortBy: true,
+      isVisible: defaultdataheader.includes(props.keyaccessor),
+    })
+  }
+
+  const navigateTo = (props) => () => {
+    if (props.cell.row.values['actionpath']) {
+      return history.push({
+        pathname: props.cell.row.values['actionpath'],
+        state: {
+          "id": props.value,
+        }
+      })
     }
+    // Object.entries(props.paths[0]).map(([key,value]) =>{})
+  }
 
   //Default Columns
   defaultdataheader.forEach(header => {
     const isString = typeof defaultheader[0][header] === 'string';
-    const filterFn = (showColumnFilter?(isString ? DefaultColumnFilter : (filterTypes[defaultheader[0][header].filter].fn ? filterTypes[defaultheader[0][header].filter].fn : DefaultColumnFilter)):"");
-    const filtertype = (showColumnFilter?(!isString && filterTypes[defaultheader[0][header].filter].type) ? filterTypes[defaultheader[0][header].filter].type : 'fuzzyText':"");
+    const filterFn = (showColumnFilter ? (isString ? DefaultColumnFilter : (filterTypes[defaultheader[0][header].filter].fn ? filterTypes[defaultheader[0][header].filter].fn : DefaultColumnFilter)) : "");
+    const filtertype = (showColumnFilter ? (!isString && filterTypes[defaultheader[0][header].filter].type) ? filterTypes[defaultheader[0][header].filter].type : 'fuzzyText' : "");
     columns.push({
       Header: isString ? defaultheader[0][header] : defaultheader[0][header].name,
       id: isString ? defaultheader[0][header] : defaultheader[0][header].name,
@@ -979,72 +999,72 @@ function ViewTable(props) {
       // Filter: (showColumnFilter?(isString ? DefaultColumnFilter : (filterTypes[defaultheader[0][header].filter] ? filterTypes[defaultheader[0][header].filter] : DefaultColumnFilter)):""),
       isVisible: true,
       Cell: props => <div> {updatedCellvalue(header, props.value)} </div>,
-   })
-})
-
-//Optional Columns
-optionaldataheader.forEach(header => {
-  const isString = typeof optionalheader[0][header] === 'string';
-  const filterFn = (showColumnFilter?(isString ? DefaultColumnFilter : (filterTypes[optionalheader[0][header].filter].fn ? filterTypes[optionalheader[0][header].filter].fn : DefaultColumnFilter)):"");
-    const filtertype = (showColumnFilter?(!isString && filterTypes[optionalheader[0][header].filter].type) ? filterTypes[optionalheader[0][header].filter].type : 'fuzzyText':"");
+    })
+  })
+
+  //Optional Columns
+  optionaldataheader.forEach(header => {
+    const isString = typeof optionalheader[0][header] === 'string';
+    const filterFn = (showColumnFilter ? (isString ? DefaultColumnFilter : (filterTypes[optionalheader[0][header].filter].fn ? filterTypes[optionalheader[0][header].filter].fn : DefaultColumnFilter)) : "");
+    const filtertype = (showColumnFilter ? (!isString && filterTypes[optionalheader[0][header].filter].type) ? filterTypes[optionalheader[0][header].filter].type : 'fuzzyText' : "");
     columns.push({
       Header: isString ? optionalheader[0][header] : optionalheader[0][header].name,
       id: isString ? header : optionalheader[0][header].name,
-      accessor: isString ? header : optionalheader[0][header].name, 
+      accessor: isString ? header : optionalheader[0][header].name,
       filter: filtertype,
       Filter: filterFn,
       isVisible: false,
       Cell: props => <div> {updatedCellvalue(header, props.value)} </div>,
+    })
+  });
+
+  let togglecolumns = localStorage.getItem(tablename);
+  if (togglecolumns) {
+    togglecolumns = JSON.parse(togglecolumns)
+    columns.forEach(column => {
+      togglecolumns.filter(tcol => {
+        column.isVisible = (tcol.Header === column.Header) ? tcol.isVisible : column.isVisible;
+        return tcol;
       })
-    }); 
-     
-    let togglecolumns = localStorage.getItem(tablename);
-    if(togglecolumns){
-        togglecolumns = JSON.parse(togglecolumns)
-        columns.forEach(column =>{
-            togglecolumns.filter(tcol => {
-               column.isVisible = (tcol.Header === column.Header)?tcol.isVisible:column.isVisible;
-               return tcol;
-            })
-        })
-      }
+    })
+  }
 
-    function updatedCellvalue(key, value){
-      try{
-        if(key === 'blueprint_draft' && _.includes(value,'/task_draft/')){
-            //  'task_draft/' -> len = 12
-            var taskid = _.replace(value.substring((value.indexOf('/task_draft/')+12), value.length),'/','');
-            return  <a href={'/task/view/draft/'+taskid}>{' '+taskid+' '}</a>
-        }else if(key === 'blueprint_draft'){
-          var retval= [];
-          value.forEach((link, index) =>{
-            //  'task_blueprint/' -> len = 16
-            if(_.includes(link,'/task_blueprint/')){
-              var bpid = _.replace(link.substring((link.indexOf('/task_blueprint/')+16), link.length),'/','');
-              retval.push( <a href={'/task/view/blueprint/'+bpid} key={bpid+index} >{'  '+bpid+'  '}</a> )
-            }
-          })
-          return  retval;
-        }else if(typeof value == "boolean"){
-          return value.toString();
-        } else if(typeof value == "string"){
-          const dateval = moment(value, moment.ISO_8601).format("YYYY-MMM-DD HH:mm:ss");
-          if(dateval !== 'Invalid date'){
-            return dateval;
-          } 
-        } 
-      }catch(err){
-        console.error('Error',err)
+  function updatedCellvalue(key, value) {
+    try {
+      if (key === 'blueprint_draft' && _.includes(value, '/task_draft/')) {
+        //  'task_draft/' -> len = 12
+        var taskid = _.replace(value.substring((value.indexOf('/task_draft/') + 12), value.length), '/', '');
+        return <a href={'/task/view/draft/' + taskid}>{' ' + taskid + ' '}</a>
+      } else if (key === 'blueprint_draft') {
+        var retval = [];
+        value.forEach((link, index) => {
+          //  'task_blueprint/' -> len = 16
+          if (_.includes(link, '/task_blueprint/')) {
+            var bpid = _.replace(link.substring((link.indexOf('/task_blueprint/') + 16), link.length), '/', '');
+            retval.push(<a href={'/task/view/blueprint/' + bpid} key={bpid + index} >{'  ' + bpid + '  '}</a>)
+          }
+        })
+        return retval;
+      } else if (typeof value == "boolean") {
+        return value.toString();
+      } else if (typeof value == "string") {
+        const dateval = moment(value, moment.ISO_8601).format("YYYY-MMM-DD HH:mm:ss");
+        if (dateval !== 'Invalid date') {
+          return dateval;
+        }
       }
-      return value;
+    } catch (err) {
+      console.error('Error', err)
     }
- 
+    return value;
+  }
+
   return (
     <div>
-        <Table columns={columns} data={tbldata} defaultheader={defaultheader[0]} optionalheader={optionalheader[0]} 
-                defaultSortColumn={defaultSortColumn} tablename={tablename} defaultpagesize={defaultpagesize}/>
+      <Table columns={columns} data={tbldata} defaultheader={defaultheader[0]} optionalheader={optionalheader[0]} showAction={props.showaction}
+        defaultSortColumn={defaultSortColumn} tablename={tablename} defaultpagesize={defaultpagesize} columnOrders={props.columnOrders} />
     </div>
   )
 }
 
-export default ViewTable
+export default ViewTable
\ No newline at end of file
diff --git a/SAS/TMSS/frontend/tmss_webapp/src/layout/_overrides.scss b/SAS/TMSS/frontend/tmss_webapp/src/layout/_overrides.scss
index 32ef8d9e42d3593cb7e77f324b8443fc2032fdfb..ab16a8fe25ea5667cbcd77dd8ba08c208af9057d 100644
--- a/SAS/TMSS/frontend/tmss_webapp/src/layout/_overrides.scss
+++ b/SAS/TMSS/frontend/tmss_webapp/src/layout/_overrides.scss
@@ -200,8 +200,38 @@
 .p-growl {
     z-index: 3000 !important;
 }
+.viewtable .p-hidden-accessible {
+    position: relative;
+}
+
 .data-product {
     label {
         display: block;
     }
-}
\ No newline at end of file
+}
+
+/**
+In Excel View the for Accordion  background color override
+*/
+.p-accordion .p-accordion-header:not(.p-disabled).p-highlight a {
+    background-color: lightgray !important;
+    border: 1px solid gray !important;
+}
+.p-accordion .p-accordion-header:not(.p-disabled).p-highlight span {
+    color: black;
+}
+.p-accordion .p-accordion-header:not(.p-disabled).p-highlight a .p-accordion-toggle-icon {
+    color: black;
+}
+
+/**
+ In Custom Dialog - to the message section
+ */
+.p-dialog-content {
+    min-height: 7em;
+    align-items: center;
+    display: flex !important;
+}
+.p-grid {
+    width: -webkit-fill-available;
+}
diff --git a/SAS/TMSS/frontend/tmss_webapp/src/layout/components/CustomDialog.js b/SAS/TMSS/frontend/tmss_webapp/src/layout/components/CustomDialog.js
index ea013dca232d1dd5a0cc4e1dcda11542f79af1ce..db545a15577062ce1458d1ad96ac8f27ebd9acba 100644
--- a/SAS/TMSS/frontend/tmss_webapp/src/layout/components/CustomDialog.js
+++ b/SAS/TMSS/frontend/tmss_webapp/src/layout/components/CustomDialog.js
@@ -19,6 +19,7 @@ export class CustomDialog extends Component {
         const isConfirm = this.props.type.toLowerCase()==='confirmation';
         const isWarning = this.props.type.toLowerCase()==='warning';
         const isSuccess = this.props.type.toLowerCase()==='success';
+        const showIcon = (typeof this.props.showIcon === "undefined") ? true : this.props.showIcon;
         // const isError = this.props.type.toLowerCase()==='error';
         let iconClass = isConfirm?"pi-question-circle pi-warning":(isWarning?"pi-info-circle pi-warning": (isSuccess?"pi-check-circle pi-success":"pi-times-circle pi-danger"));
         return (
@@ -30,25 +31,29 @@ export class CustomDialog extends Component {
                                 {/* Action buttons based on 'type' props. If 'actions' passed as props, then type is ignored */}
                                 {!this.props.actions && 
                                 <>
+                                    <Button key="submit" type="primary" onClick={this.props.onSubmit?this.props.onSubmit:this.props.onClose} label={isConfirm?'Yes':'Ok'} />
                                     {isConfirm &&
                                         <Button key="back" onClick={this.props.onCancel} label="No" />
                                     }
-                                    <Button key="submit" type="primary" onClick={this.props.onSubmit?this.props.onSubmit:this.props.onClose} label={isConfirm?'Yes':'Ok'} />
+                                    
                                 </>
                                 }
                                 {/* Action button based on the 'actions' props */}
                                 {this.props.actions && this.props.actions.map((action, index) => {
                                     return (
-                                    <Button key={action.id} label={action.title} onClick={action.callback} />);
+                                        <Button key={action.id} label={action.title} onClick={action.callback} />
+                                    );
                                 })}
                                 </div>
                             } >
                             <div className="p-grid">
-                                <div className="col-lg-2 col-md-2 col-sm-2">
-                                    <span style={{position: 'absolute', top: '50%', '-ms-transform': 'translateY(-50%)', transform: 'translateY(-50%)'}}>
-                                        <i className={`pi pi-large ${iconClass}`}></i>
-                                    </span>
-                                </div>
+                                {showIcon &&
+                                    <div className="col-lg-2 col-md-2 col-sm-2">
+                                        <span style={{position: 'absolute', top: '50%', '-ms-transform': 'translateY(-50%)', transform: 'translateY(-50%)'}}>
+                                            <i className={`pi pi-large ${iconClass}`}></i>
+                                        </span>
+                                    </div>
+                                }
                                 <div className="col-lg-10 col-md-10 col-sm-10">
                                     {/* Display message passed */}
                                     {this.props.message?this.props.message:""}
diff --git a/SAS/TMSS/frontend/tmss_webapp/src/layout/sass/reservation.scss b/SAS/TMSS/frontend/tmss_webapp/src/layout/sass/reservation.scss
index 5031872c644480c2ff08332d8092bbaec8e69a1b..b14c70faab0443a625ae568ecb0cea846472802f 100644
--- a/SAS/TMSS/frontend/tmss_webapp/src/layout/sass/reservation.scss
+++ b/SAS/TMSS/frontend/tmss_webapp/src/layout/sass/reservation.scss
@@ -7,6 +7,6 @@
 .p-select{
     margin-left: 27em;
     position: relative;
-    top: 3.5em;
+    top: 2.2em;
     width: 40em;
 }
\ No newline at end of file
diff --git a/SAS/TMSS/frontend/tmss_webapp/src/routes/Cycle/create.js b/SAS/TMSS/frontend/tmss_webapp/src/routes/Cycle/create.js
index 8e11645ca22f57e71bf20c836ac45bf76423c39a..9f9128ecfb678939717cbe9027cee09c226981ae 100644
--- a/SAS/TMSS/frontend/tmss_webapp/src/routes/Cycle/create.js
+++ b/SAS/TMSS/frontend/tmss_webapp/src/routes/Cycle/create.js
@@ -1,13 +1,14 @@
 import React, {Component} from 'react';
 import { Redirect } from 'react-router-dom';
-import {InputText} from 'primereact/inputtext';
-import {Calendar} from 'primereact/calendar';
-import {InputTextarea} from 'primereact/inputtextarea';
-import {Dropdown} from 'primereact/dropdown';
-import {Button} from 'primereact/button';
-import {Dialog} from 'primereact/components/dialog/Dialog';
-import {Growl} from 'primereact/components/growl/Growl';
-import {ResourceInputList} from './ResourceInputList';
+import { InputText } from 'primereact/inputtext';
+import { Calendar } from 'primereact/calendar';
+import { InputTextarea } from 'primereact/inputtextarea';
+import { Dropdown } from 'primereact/dropdown';
+import { Button } from 'primereact/button';
+import { Dialog } from 'primereact/components/dialog/Dialog';
+import { Growl } from 'primereact/components/growl/Growl';
+import { ResourceInputList } from './ResourceInputList';
+import { CustomDialog } from '../../layout/components/CustomDialog';
 import moment from 'moment'
 import _ from 'lodash';
 
@@ -24,9 +25,13 @@ export class CycleCreate extends Component {
     constructor(props) {
         super(props);
         this.state = {
+            showDialog: false,
+            isDirty: false,
             isLoading: true,
             dialog: { header: '', detail: ''},      
             cycle: {
+                name: '',
+                description: '',
                 projects: [],
                 quota: [],  
                 start: "",
@@ -68,6 +73,8 @@ export class CycleCreate extends Component {
         this.saveCycle = this.saveCycle.bind(this);
         this.cancelCreate = this.cancelCreate.bind(this);
         this.reset = this.reset.bind(this);
+        this.checkIsDirty = this.checkIsDirty.bind(this);
+        this.close = this.close.bind(this);
     }
 
     componentDidMount() {
@@ -111,11 +118,15 @@ export class CycleCreate extends Component {
      */
     addNewResource(){
         if (this.state.newResource) {
-            let resourceList = this.state.resourceList;
+            let resourceList = _.cloneDeep(this.state.resourceList);
             const newResource = _.remove(resourceList, {'name': this.state.newResource});
             let resources = this.state.resources;
             resources.push(newResource[0]);
-            this.setState({resources: resources, resourceList: resourceList, newResource: null});
+            if  ( !this.state.isDirty && !_.isEqual(this.state.resourceList, resourceList) ) {
+                this.setState({resources: resources, resourceList: resourceList, newResource: null, isDirty: true});
+            }   else {
+                this.setState({resources: resources, resourceList: resourceList, newResource: null});
+            }
         }
     }
 
@@ -126,12 +137,16 @@ export class CycleCreate extends Component {
     removeResource(name) {
         let resources = this.state.resources;
         let resourceList = this.state.resourceList;
-        let cycleQuota = this.state.cycleQuota;
+        let cycleQuota = _.cloneDeep(this.state.cycleQuota);
         const removedResource = _.remove(resources, (resource) => { return resource.name === name });
         resourceList.push(removedResource[0]);
         resourceList = _.sortBy(resourceList, 'name');
         delete cycleQuota[name];
-        this.setState({resourceList: resourceList, resources: resources, cycleQuota: cycleQuota});
+        if  ( !this.state.isDirty && !_.isEqual(this.state.cycleQuota, cycleQuota) ) {
+            this.setState({resourceList: resourceList, resources: resources, cycleQuota: cycleQuota, isDirty: true});
+        }   else {
+            this.setState({resourceList: resourceList, resources: resources, cycleQuota: cycleQuota});
+        }
     }
 
     /**
@@ -140,7 +155,7 @@ export class CycleCreate extends Component {
      * @param {any} value 
      */
     setCycleParams(key, value, type) {
-        let cycle = this.state.cycle;
+        let cycle = _.cloneDeep(this.state.cycle);
         switch(type) {
             case 'NUMBER': {
                 cycle[key] = value?parseInt(value):0;
@@ -150,9 +165,12 @@ export class CycleCreate extends Component {
                 cycle[key] = value;                
                 break;
             }
-           
         }
-        this.setState({cycle: cycle, validForm: this.validateForm(key)});
+        if  ( !this.state.isDirty && !_.isEqual(this.state.cycle, cycle) ) {
+            this.setState({cycle: cycle, validForm: this.validateForm(key), isDirty: true});
+        }   else {
+            this.setState({cycle: cycle, validForm: this.validateForm(key)});
+        }
     }
 
     /**
@@ -161,23 +179,28 @@ export class CycleCreate extends Component {
      * @param {InputEvent} event 
      */
     setCycleQuotaParams(key, event) {
-        let cycleQuota = this.state.cycleQuota;
+        let cycleQuota = _.cloneDeep(this.state.cycleQuota);
         if (event.target.value) {
             let resource = _.find(this.state.resources, {'name': key});
             
             let newValue = 0;
             if (this.resourceUnitMap[resource.quantity_value] && 
                 event.target.value.toString().indexOf(this.resourceUnitMap[resource.quantity_value].display)>=0) {
-                newValue = event.target.value.replace(this.resourceUnitMap[resource.quantity_value].display,'');
+                newValue = _.trim(event.target.value.replace(this.resourceUnitMap[resource.quantity_value].display,'',''));
             }   else {
-                newValue = event.target.value;
+                newValue = _.trim(event.target.value);
             }
-            cycleQuota[key] = (newValue==="NaN" || isNaN(newValue))?0:newValue;
+            cycleQuota[key] = (newValue==="NaN" || isNaN(newValue))?0:Number(newValue);
         }   else {
             let cycleQuota = this.state.cycleQuota;
             cycleQuota[key] = 0;
         }
-        this.setState({cycleQuota: cycleQuota});
+
+        if  ( !this.state.isDirty && !_.isEqual(this.state.cycleQuota, cycleQuota) ) {
+            this.setState({cycleQuota: cycleQuota, isDirty: true});
+        }   else {
+            this.setState({cycleQuota: cycleQuota});
+        }
     }
 
     /**
@@ -246,7 +269,7 @@ export class CycleCreate extends Component {
             let stoptime =  _.replace(this.state.cycle['stop'],'00:00:00', '23:59:59');
             cycle['start'] = moment(cycle['start']).format("YYYY-MM-DDTHH:mm:ss");
             cycle['stop'] = moment(stoptime).format("YYYY-MM-DDTHH:mm:ss");
-            this.setState({cycle: cycle});
+            this.setState({cycle: cycle, isDirty: false});
             for (const resource in this.state.cycleQuota) {
                 let resourceType = _.find(this.state.resources, {'name': resource});
                 if(resourceType){
@@ -276,6 +299,21 @@ export class CycleCreate extends Component {
         }
     }
 
+     /**
+     * warn before cancel the page if any changes detected 
+     */
+    checkIsDirty() {
+        if( this.state.isDirty ){
+            this.setState({showDialog: true});
+        } else {
+            this.cancelCreate();
+        }
+    }
+    
+    close() {
+        this.setState({showDialog: false});
+    }
+
     /**
      * Function to cancel form creation and navigate to other page/component
      */
@@ -341,7 +379,7 @@ export class CycleCreate extends Component {
                 
                 <PageHeader location={this.props.location} title={'Cycle - Add'} actions={[{icon:'fa-window-close',
                             title:'Click to Close Add Cycle',
-                            props:{pathname: '/cycle' }}]}/>
+                            type: 'button',  actOn: 'click', props:{ callback: this.checkIsDirty }}]}/>
                 { this.state.isLoading ? <AppLoader /> :
                 <>
                 <div>
@@ -382,7 +420,7 @@ export class CycleCreate extends Component {
                             <label htmlFor="cycleName" className="col-lg-2 col-md-2 col-sm-12">Start Date <span style={{color:'red'}}>*</span></label>
                             <div className="col-lg-3 col-md-3 col-sm-12">
                                 <Calendar
- 				    d dateFormat="dd-M-yy"
+ 				                    d dateFormat="dd-M-yy"
                                     value= {this.state.cycle.start}
                                     onChange= {e => this.setCycleParams('start',e.value)}
                                     onBlur= {e => this.setCycleParams('start',e.value)}
@@ -435,8 +473,8 @@ export class CycleCreate extends Component {
                                 </div>
                                 <div className="p-field p-grid resource-input-grid">
                                     <ResourceInputList list={this.state.resources} unitMap={this.resourceUnitMap} 
-                                                      cycleQuota={this.state.cycleQuota} callback={this.setCycleQuotaParams} 
-                                                      removeInputCallback={this.removeResource} />
+                                        cycleQuota={this.state.cycleQuota} callback={this.setCycleQuotaParams} 
+                                        removeInputCallback={this.removeResource} />
                                 </div>
                             </div>
                         }
@@ -447,7 +485,7 @@ export class CycleCreate extends Component {
                         <Button label="Save" className="p-button-primary" id="save-btn" data-testid="save-btn" icon="pi pi-check" onClick={this.saveCycle} disabled={!this.state.validForm} />
                     </div>
                      <div className="p-col-1">
-                        <Button label="Cancel" className="p-button-danger" icon="pi pi-times" onClick={this.cancelCreate}  />
+                        <Button label="Cancel" className="p-button-danger" icon="pi pi-times" onClick={this.checkIsDirty}  />
                     </div>
                 </div>
                 </>
@@ -471,6 +509,11 @@ export class CycleCreate extends Component {
                                 </div>
                             </div>
                     </Dialog>
+
+                    <CustomDialog type="confirmation" visible={this.state.showDialog} width="40vw"
+                        header={'Add Cycle'} message={'Do you want to leave this page? Your changes may not be saved.'} 
+                        content={''} onClose={this.close} onCancel={this.close} onSubmit={this.cancelCreate}>
+                    </CustomDialog>
                 </div>
                 
             </React.Fragment>
diff --git a/SAS/TMSS/frontend/tmss_webapp/src/routes/Cycle/edit.js b/SAS/TMSS/frontend/tmss_webapp/src/routes/Cycle/edit.js
index d04ac553d56581a384a458044384e5b64a349845..ce35f79a059ea97f43acc334c394927107f82a55 100644
--- a/SAS/TMSS/frontend/tmss_webapp/src/routes/Cycle/edit.js
+++ b/SAS/TMSS/frontend/tmss_webapp/src/routes/Cycle/edit.js
@@ -3,26 +3,30 @@ import { Redirect } from 'react-router-dom';
 import _ from 'lodash';
 import moment from 'moment'
 
-import {InputText} from 'primereact/inputtext';
-import {Calendar} from 'primereact/calendar';
-import {InputTextarea} from 'primereact/inputtextarea';
-import {Dropdown} from 'primereact/dropdown';
+import { InputText } from 'primereact/inputtext';
+import { Calendar } from 'primereact/calendar';
+import { InputTextarea } from 'primereact/inputtextarea';
+import { Dropdown } from 'primereact/dropdown';
 import { Button } from 'primereact/button';
-import {Dialog} from 'primereact/components/dialog/Dialog';
-import {Growl} from 'primereact/components/growl/Growl';
-
-import {ResourceInputList} from './ResourceInputList';
+import { Dialog } from 'primereact/components/dialog/Dialog';
+import { Growl } from 'primereact/components/growl/Growl';
 
+import { ResourceInputList } from './ResourceInputList';
+import { CustomDialog } from '../../layout/components/CustomDialog';
 import AppLoader from '../../layout/components/AppLoader';
 import PageHeader from '../../layout/components/PageHeader';
 import CycleService from '../../services/cycle.service';
 import UnitConverter from '../../utils/unit.converter';
 import UIConstants from '../../utils/ui.constants';
 
+
+
 export class CycleEdit extends Component {
     constructor(props) {
         super(props);
         this.state = {
+            showDialog: false,
+            isDirty: false,
             isLoading: true,
             dialog: { header: '', detail: ''},
             cycle: {
@@ -60,6 +64,8 @@ export class CycleEdit extends Component {
         this.resourceUnitMap = UnitConverter.resourceUnitMap;
         this.tooltipOptions = UIConstants.tooltipOptions;
 
+        this.checkIsDirty = this.checkIsDirty.bind(this);
+        this.close = this.close.bind(this);
         this.getCycleDetails = this.getCycleDetails.bind(this);
         this.cycleOptionTemplate = this.cycleOptionTemplate.bind(this);
         this.setCycleQuotaDefaults = this.setCycleQuotaDefaults.bind(this);
@@ -99,15 +105,18 @@ export class CycleEdit extends Component {
         let resourceList = this.state.resourceList;
         let cycleQuota = {};
         if (cycle) {
-            // Get cycle_quota for the cycle and asssign to the component variable
-            for (const id of cycle.quota_ids) {
-                let quota = await CycleService.getCycleQuota(id);
-                let resource = _.find(resourceList, ['name', quota.resource_type_id]);
-                quota.resource = resource;
-                this.cycleQuota.push(quota);
-                const conversionFactor = this.resourceUnitMap[resource.quantity_value]?this.resourceUnitMap[resource.quantity_value].conversionFactor:1;
-                cycleQuota[quota.resource_type_id] = quota.value / conversionFactor;
-            };
+            if(cycle.quota_ids){
+                 // Get cycle_quota for the cycle and asssign to the component variable
+                for (const id of cycle.quota_ids) {
+                    let quota = await CycleService.getCycleQuota(id);
+                    let resource = _.find(resourceList, ['name', quota.resource_type_id]);
+                    quota.resource = resource;
+                    this.cycleQuota.push(quota);
+                    const conversionFactor = this.resourceUnitMap[resource.quantity_value]?this.resourceUnitMap[resource.quantity_value].conversionFactor:1;
+                    cycleQuota[quota.resource_type_id] = quota.value / conversionFactor;
+                };
+            }
+           
             // Remove the already assigned resources from the resoureList
             const resources = _.remove(resourceList, (resource) => { return _.find(this.cycleQuota, {'resource_type_id': resource.name})!=null });
             this.setState({cycle: cycle, resourceList: resourceList, resources: resources, 
@@ -149,11 +158,16 @@ export class CycleEdit extends Component {
      */
     addNewResource(){
         if (this.state.newResource) {
-            let resourceList = this.state.resourceList;
+            let resourceList = _.cloneDeep(this.state.resourceList);
             const newResource = _.remove(resourceList, {'name': this.state.newResource});
             let resources = this.state.resources?this.state.resources:[];
             resources.push(newResource[0]);
-            this.setState({resources: resources, resourceList: resourceList, newResource: null});
+            if ( !this.state.isDirty && !_.isEqual(this.state.resourceList, resourceList)) {
+                this.setState({resources: resources, resourceList: resourceList, newResource: null, isDirty: true});
+            }   else {
+                this.setState({resources: resources, resourceList: resourceList, newResource: null});
+            }
+            
         }
     }
 
@@ -164,11 +178,16 @@ export class CycleEdit extends Component {
     removeResource(name) {
         let resources = this.state.resources;
         let resourceList = this.state.resourceList;
-        let cycleQuota = this.state.cycleQuota;
+        let cycleQuota = _.cloneDeep(this.state.cycleQuota);
         const removedResource = _.remove(resources, (resource) => { return resource.name === name });
         resourceList.push(removedResource[0]);
         delete cycleQuota[name];
-        this.setState({resourceList: resourceList, resources: resources, cycleQuota: cycleQuota});
+        if ( !this.state.isDirty && !_.isEqual(this.state.cycleQuota, cycleQuota)) {
+            this.setState({resourceList: resourceList, resources: resources, cycleQuota: cycleQuota, isDirty: true});
+        }   else {
+            this.setState({resourceList: resourceList, resources: resources, cycleQuota: cycleQuota});
+        }
+        
     }
 
     /**
@@ -177,7 +196,7 @@ export class CycleEdit extends Component {
      * @param {any} value 
      */
     setCycleParams(key, value, type) {
-        let cycle = this.state.cycle;
+        let cycle = _.cloneDeep(this.state.cycle);
         switch(type) {
             case 'NUMBER': {
                 cycle[key] = value?parseInt(value):0;
@@ -188,7 +207,12 @@ export class CycleEdit extends Component {
                 break;
             }
         }
-        this.setState({cycle: cycle, validForm: this.validateForm(key)});
+        if ( !this.state.isDirty && !_.isEqual(this.state.cycle, cycle)) {
+            this.setState({cycle: cycle, validForm: this.validateForm(key), isDirty: true});
+        }   else {
+            this.setState({cycle: cycle, validForm: this.validateForm(key)});
+        }
+        
     }
 
     /**
@@ -197,22 +221,26 @@ export class CycleEdit extends Component {
      * @param {InputEvent} event 
      */
     setCycleQuotaParams(key, event) {
-        let cycleQuota = this.state.cycleQuota;
+        let cycleQuota = _.cloneDeep(this.state.cycleQuota);
         if (event.target.value) {
             let resource = _.find(this.state.resources, {'name': key});
             let newValue = 0;
             if (this.resourceUnitMap[resource.quantity_value] && 
                 event.target.value.toString().indexOf(this.resourceUnitMap[resource.quantity_value].display)>=0) {
-                newValue = event.target.value.replace(this.resourceUnitMap[resource.quantity_value].display,'');
+                newValue = _.trim(event.target.value.replace(this.resourceUnitMap[resource.quantity_value].display,''));
             }   else {
-                newValue = event.target.value;
+                newValue = _.trim(event.target.value);
             }
-            cycleQuota[key] = (newValue==="NaN" || isNaN(newValue))?0:newValue;
+            cycleQuota[key] = (newValue==="NaN" || isNaN(newValue))?0:Number(newValue);
         }   else {
             let cycleQuota = this.state.cycleQuota;
             cycleQuota[key] = 0;
         }
-        this.setState({cycleQuota: cycleQuota});
+        if ( !this.state.isDirty && !_.isEqual(this.state.cycleQuota, cycleQuota)) {
+            this.setState({cycleQuota: cycleQuota, isDirty: true});
+        }   else {
+            this.setState({cycleQuota: cycleQuota});
+        }
     }
 
     /**
@@ -281,7 +309,7 @@ export class CycleEdit extends Component {
             let stoptime =  _.replace(this.state.cycle['stop'],'00:00:00', '23:59:59');
             cycle['start'] = moment(this.state.cycle['start']).format("YYYY-MM-DDTHH:mm:ss");
             cycle['stop'] = moment(stoptime).format("YYYY-MM-DDTHH:mm:ss");
-            this.setState({cycle: cycle});
+            this.setState({cycle: cycle, isDirty: false});
             CycleService.updateCycle(this.props.match.params.id, this.state.cycle)
                 .then(async (cycle) => { 
                     if (cycle && this.state.cycle.updated_at !== cycle.updated_at) {
@@ -348,6 +376,20 @@ export class CycleEdit extends Component {
         this.setState({dialogVisible: true, dialog: dialog});
     }
 
+     /**
+     * warn before cancel the page if any changes detected 
+     */
+    checkIsDirty() {
+        if( this.state.isDirty ){
+            this.setState({showDialog: true});
+        } else {
+            this.cancelEdit();
+        }
+    }
+    
+    close() {
+        this.setState({showDialog: false});
+    }
     /**
      * Cancel edit and redirect to Cycle View page
      */
@@ -374,8 +416,7 @@ export class CycleEdit extends Component {
                     </div>
                 </div> */}
                 <PageHeader location={this.props.location} title={'Cycle - Edit'} actions={[{icon:'fa-window-close',
-                link: this.props.history.goBack,title:'Click to Close Cycle-Edit', 
-                props:{ pathname: `/cycle/view/${this.state.cycle.name}`}}]}/>
+                title:'Click to Close Cycle-Edit', type: 'button',  actOn: 'click', props:{ callback: this.checkIsDirty }}]}/>
 
                 { this.state.isLoading ? <AppLoader/> :
                 <>
@@ -478,7 +519,7 @@ export class CycleEdit extends Component {
                         <Button label="Save" className="p-button-primary" id="save-btn" data-testid="save-btn" icon="pi pi-check" onClick={this.saveCycle} disabled={!this.state.validForm} />
                     </div>
                     <div className="p-col-1">
-                        <Button label="Cancel" className="p-button-danger" icon="pi pi-times" onClick={this.cancelEdit}  />
+                        <Button label="Cancel" className="p-button-danger" icon="pi pi-times" onClick={this.checkIsDirty}  />
                     </div>
                 </div>
 
@@ -502,6 +543,12 @@ export class CycleEdit extends Component {
                                 </div>
                             </div>
                     </Dialog>
+
+                    <CustomDialog type="confirmation" visible={this.state.showDialog} width="40vw"
+                        header={'Edit Cycle'} message={'Do you want to leave this page? Your changes may not be saved.'} 
+                        content={''} onClose={this.close} onCancel={this.close} onSubmit={this.cancelEdit}>
+                    </CustomDialog>
+
                 </div>
             </React.Fragment>
         );
diff --git a/SAS/TMSS/frontend/tmss_webapp/src/routes/Project/create.js b/SAS/TMSS/frontend/tmss_webapp/src/routes/Project/create.js
index 734294c72903e650f2bca44471ff75a0ff02ed06..c21f5afcd834388b99fe3836cd7d598be970a608 100644
--- a/SAS/TMSS/frontend/tmss_webapp/src/routes/Project/create.js
+++ b/SAS/TMSS/frontend/tmss_webapp/src/routes/Project/create.js
@@ -1,17 +1,17 @@
-import React, {Component} from 'react';
+import React, { Component } from 'react';
 import { Redirect } from 'react-router-dom';
 import _ from 'lodash';
-import {InputText} from 'primereact/inputtext';
-import {InputNumber} from 'primereact/inputnumber';
-import {InputTextarea} from 'primereact/inputtextarea';
-import {Checkbox} from 'primereact/checkbox';
-import {Dropdown} from 'primereact/dropdown';
-import {MultiSelect} from 'primereact/multiselect';
+import { InputText } from 'primereact/inputtext';
+import { InputNumber } from 'primereact/inputnumber';
+import { InputTextarea } from 'primereact/inputtextarea';
+import { Checkbox } from 'primereact/checkbox';
+import { Dropdown } from 'primereact/dropdown';
+import { MultiSelect } from 'primereact/multiselect';
 import { Button } from 'primereact/button';
-import {Dialog} from 'primereact/components/dialog/Dialog';
-import {Growl} from 'primereact/components/growl/Growl';
-
-import {ResourceInputList} from './ResourceInputList';
+import { Dialog } from 'primereact/components/dialog/Dialog';
+import { Growl } from 'primereact/components/growl/Growl';
+import { CustomDialog } from '../../layout/components/CustomDialog';
+import { ResourceInputList } from './ResourceInputList';
 
 import AppLoader from '../../layout/components/AppLoader';
 import PageHeader from '../../layout/components/PageHeader';
@@ -28,10 +28,15 @@ export class ProjectCreate extends Component {
     constructor(props) {
         super(props);
         this.state = {
+            showDialog: false,
+            isDirty: false,
             ltaStorage: [],
             isLoading: true,
             dialog: { header: '', detail: ''},      
             project: {
+                archive_subdirectory: '',
+                name: '',
+                description: '',
                 trigger_priority: 1000,
                 priority_rank: null,
                 quota: [],                          // Mandatory Field in the back end, so an empty array is passed
@@ -78,6 +83,8 @@ export class ProjectCreate extends Component {
         this.saveProject = this.saveProject.bind(this);
         this.cancelCreate = this.cancelCreate.bind(this);
         this.reset = this.reset.bind(this);
+        this.checkIsDirty = this.checkIsDirty.bind(this);
+        this.close = this.close.bind(this);
     }
 
     componentDidMount() {
@@ -151,11 +158,15 @@ export class ProjectCreate extends Component {
      */
     addNewResource(){
         if (this.state.newResource) {
-            let resourceList = this.state.resourceList;
+            let resourceList = _.cloneDeep(this.state.resourceList);
             const newResource = _.remove(resourceList, {'name': this.state.newResource});
             let resources = this.state.resources;
             resources.push(newResource[0]);
-            this.setState({resources: resources, resourceList: resourceList, newResource: null});
+            if  ( !this.state.isDirty && !_.isEqual(this.state.resourceList, resourceList) ) {
+                this.setState({resources: resources, resourceList: resourceList, newResource: null, isDirty: true});
+            }   else {
+                this.setState({resources: resources, resourceList: resourceList, newResource: null});
+            }
         }
     }
 
@@ -166,12 +177,17 @@ export class ProjectCreate extends Component {
     removeResource(name) {
         let resources = this.state.resources;
         let resourceList = this.state.resourceList;
-        let projectQuota = this.state.projectQuota;
+        let projectQuota =  _.cloneDeep(this.state.projectQuota);
         const removedResource = _.remove(resources, (resource) => { return resource.name === name });
         resourceList.push(removedResource[0]);
         resourceList = _.sortBy(resourceList, 'name');
         delete projectQuota[name];
-        this.setState({resourceList: resourceList, resources: resources, projectQuota: projectQuota});
+        if  ( !this.state.isDirty && !_.isEqual(this.state.projectQuota, projectQuota) ) {
+            this.setState({resourceList: resourceList, resources: resources, projectQuota: projectQuota, isDirty: true});
+        }   else {
+            this.setState({resourceList: resourceList, resources: resources, projectQuota: projectQuota});
+        }
+        
     }
 
     /**
@@ -180,7 +196,7 @@ export class ProjectCreate extends Component {
      * @param {any} value 
      */
     setProjectParams(key, value, type) {
-        let project = this.state.project;
+        let project = _.cloneDeep(this.state.project);
         switch(type) {
             case 'NUMBER': {
                 console.log("Parsing Number");
@@ -211,7 +227,11 @@ export class ProjectCreate extends Component {
         if (type==='PROJECT_NAME' & value!=="") {
             validForm = this.validateForm('archive_subdirectory');
         }
-        this.setState({project: project, validForm: validForm});
+        if  ( !this.state.isDirty && !_.isEqual(this.state.project, project) ) {
+            this.setState({project: project, validForm: validForm, isDirty: true});
+        }   else {
+            this.setState({project: project, validForm: validForm});
+        }
     }
 
     /**
@@ -221,22 +241,26 @@ export class ProjectCreate extends Component {
      */
     setProjectQuotaParams(key, event) {
         let projectQuota = this.state.projectQuota;
+        const previousValue = projectQuota[key];
         if (event.target.value) {
             let resource = _.find(this.state.resources, {'name': key});
-            
             let newValue = 0;
             if (this.resourceUnitMap[resource.quantity_value] && 
                 event.target.value.toString().indexOf(this.resourceUnitMap[resource.quantity_value].display)>=0) {
-                newValue = event.target.value.replace(this.resourceUnitMap[resource.quantity_value].display,'');
+                newValue = _.trim(event.target.value.replace(this.resourceUnitMap[resource.quantity_value].display,''));
             }   else {
-                newValue = event.target.value;
+                newValue = _.trim(event.target.value);
             }
-            projectQuota[key] = (newValue==="NaN" || isNaN(newValue))?0:newValue;
+            projectQuota[key] = (newValue==="NaN" || isNaN(newValue))?0:Number(newValue);
         }   else {
-            let projectQuota = this.state.projectQuota;
+           // let projectQuota = this.state.projectQuota;
             projectQuota[key] = 0;
         }
-        this.setState({projectQuota: projectQuota});
+        if  ( !this.state.isDirty && !_.isEqual(previousValue, projectQuota[key]) ) {
+            this.setState({projectQuota: projectQuota, isDirty: true});
+        }   else {
+            this.setState({projectQuota: projectQuota});
+        }
     }
 
     /**
@@ -308,15 +332,30 @@ export class ProjectCreate extends Component {
                         }   else {
                             dialog = {header: 'Success', detail: 'Project saved successfully with default Resource allocations. Do you want to view and edit them?'};
                         }
-                        this.setState({project:project, dialogVisible: true, dialog: dialog})
+                        this.setState({project:project, dialogVisible: true, dialog: dialog, isDirty: false});
                     }   else {
                         this.growl.show({severity: 'error', summary: 'Error Occured', detail: 'Unable to save Project'});
-                        this.setState({errors: project});
+                        this.setState({errors: project, isDirty: false});
                     }
                 });
         }
     }
 
+     /**
+     * warn before cancel the page if any changes detected 
+     */
+    checkIsDirty() {
+        if( this.state.isDirty ){
+            this.setState({showDialog: true});
+        } else {
+            this.cancelCreate();
+        }
+    }
+    
+    close() {
+        this.setState({showDialog: false});
+    }
+
     /**
      * Function to cancel form creation and navigate to other page/component
      */
@@ -374,7 +413,8 @@ export class ProjectCreate extends Component {
         return (
             <React.Fragment>
                 <Growl ref={(el) => this.growl = el} />
-                 <PageHeader location={this.props.location} title={'Project - Add'} actions={[{icon:'fa-window-close',link:this.props.history.goBack, title:'Click to Close Project', props:{ pathname: '/project'}}]}/>
+                 <PageHeader location={this.props.location} title={'Project - Add'} actions={[{icon:'fa-window-close', title:'Click to Close Project',
+                   type: 'button',  actOn: 'click', props:{ callback: this.checkIsDirty }}]}/>
                 { this.state.isLoading ? <AppLoader /> :
                 <>
                 <div>
@@ -543,7 +583,7 @@ export class ProjectCreate extends Component {
                         <Button label="Save" className="p-button-primary" id="save-btn" data-testid="save-btn" icon="pi pi-check" onClick={this.saveProject} disabled={!this.state.validForm} />
                     </div>
                     <div className="col-lg-1 col-md-2 col-sm-6">
-                        <Button label="Cancel" className="p-button-danger" icon="pi pi-times" onClick={this.cancelCreate}  />
+                        <Button label="Cancel" className="p-button-danger" icon="pi pi-times" onClick={this.checkIsDirty}  />
                     </div>
                 </div>
                 </>
@@ -567,6 +607,11 @@ export class ProjectCreate extends Component {
                                 </div>
                             </div>
                     </Dialog>
+
+                    <CustomDialog type="confirmation" visible={this.state.showDialog} width="40vw"
+                        header={'Add Project'} message={'Do you want to leave this page? Your changes may not be saved.'} 
+                        content={''} onClose={this.close} onCancel={this.close} onSubmit={this.cancelCreate}>
+                    </CustomDialog>
                 </div>
             </React.Fragment>
         );
diff --git a/SAS/TMSS/frontend/tmss_webapp/src/routes/Project/edit.js b/SAS/TMSS/frontend/tmss_webapp/src/routes/Project/edit.js
index 5e7ae2b315fa1d92f5efbccd0232646bec6074a4..b8bd0f3e2f9833bf6290e035240e88bad4d9695d 100644
--- a/SAS/TMSS/frontend/tmss_webapp/src/routes/Project/edit.js
+++ b/SAS/TMSS/frontend/tmss_webapp/src/routes/Project/edit.js
@@ -1,18 +1,18 @@
-import React, {Component} from 'react';
+import React, { Component } from 'react';
 import { Redirect } from 'react-router-dom';
 import _ from 'lodash';
 
-import {InputText} from 'primereact/inputtext';
-import {InputNumber} from 'primereact/inputnumber';
-import {InputTextarea} from 'primereact/inputtextarea';
-import {Checkbox} from 'primereact/checkbox';
-import {Dropdown} from 'primereact/dropdown';
-import {MultiSelect} from 'primereact/multiselect';
+import { InputText } from 'primereact/inputtext';
+import { InputNumber } from 'primereact/inputnumber';
+import { InputTextarea } from 'primereact/inputtextarea';
+import { Checkbox } from 'primereact/checkbox';
+import { Dropdown } from 'primereact/dropdown';
+import { MultiSelect } from 'primereact/multiselect';
 import { Button } from 'primereact/button';
-import {Dialog} from 'primereact/components/dialog/Dialog';
-import {Growl} from 'primereact/components/growl/Growl';
-
-import {ResourceInputList} from './ResourceInputList';
+import { Dialog } from 'primereact/components/dialog/Dialog';
+import { Growl } from 'primereact/components/growl/Growl';
+import { CustomDialog } from '../../layout/components/CustomDialog';
+import { ResourceInputList } from './ResourceInputList';
 
 import AppLoader from '../../layout/components/AppLoader';
 import PageHeader from '../../layout/components/PageHeader';
@@ -25,6 +25,8 @@ export class ProjectEdit extends Component {
     constructor(props) {
         super(props);
         this.state = {
+            showDialog: false,
+            isDirty: false,
             isLoading: true,
             ltaStorage: [],
             dialog: { header: '', detail: ''},
@@ -73,6 +75,8 @@ export class ProjectEdit extends Component {
         this.saveProject = this.saveProject.bind(this);
         this.saveProjectQuota = this.saveProjectQuota.bind(this);
         this.cancelEdit = this.cancelEdit.bind(this);
+        this.checkIsDirty = this.checkIsDirty.bind(this);
+        this.close = this.close.bind(this);
     }
 
     componentDidMount() {
@@ -171,12 +175,16 @@ export class ProjectEdit extends Component {
      */
     addNewResource(){
         if (this.state.newResource) {
-            let resourceList = this.state.resourceList;
+            let resourceList = _.cloneDeep(this.state.resourceList);
             const newResource = _.remove(resourceList, {'name': this.state.newResource});
             let resources = this.state.resources?this.state.resources:[];
             resources.push(newResource[0]);
             console.log(resources);
-            this.setState({resources: resources, resourceList: resourceList, newResource: null});
+            if  ( !this.state.isDirty && !_.isEqual(this.state.resourceList, resourceList) ) {
+                this.setState({resources: resources, resourceList: resourceList, newResource: null, isDirty: true});
+            }   else {
+                this.setState({resources: resources, resourceList: resourceList, newResource: null});
+            }
         }
     }
 
@@ -187,11 +195,15 @@ export class ProjectEdit extends Component {
     removeResource(name) {
         let resources = this.state.resources;
         let resourceList = this.state.resourceList;
-        let projectQuota = this.state.projectQuota;
+        let projectQuota =  _.cloneDeep(this.state.projectQuota);
         const removedResource = _.remove(resources, (resource) => { return resource.name === name });
         resourceList.push(removedResource[0]);
         delete projectQuota[name];
-        this.setState({resourceList: resourceList, resources: resources, projectQuota: projectQuota});
+        if  ( !this.state.isDirty && !_.isEqual(this.state.projectQuota, projectQuota) ) {
+            this.setState({resourceList: resourceList, resources: resources, projectQuota: projectQuota, isDirty: true});
+        }   else {
+            this.setState({resourceList: resourceList, resources: resources, projectQuota: projectQuota});
+        }
     }
 
     /**
@@ -200,7 +212,7 @@ export class ProjectEdit extends Component {
      * @param {any} value 
      */
     setProjectParams(key, value, type) {
-        let project = this.state.project;
+        let project = _.cloneDeep(this.state.project);
         switch(type) {
             case 'NUMBER': {
                 console.log("Parsing Number");
@@ -231,7 +243,11 @@ export class ProjectEdit extends Component {
         if (type==='PROJECT_NAME' & value!=="") {
             validForm = this.validateForm('archive_subdirectory');
         }
-        this.setState({project: project, validForm: validForm});
+        if  ( !this.state.isDirty && !_.isEqual(this.state.project, project) ) {
+            this.setState({project: project, validForm: validForm, isDirty: true});
+        }   else {
+            this.setState({project: project, validForm: validForm});
+        }
     }
 
     /**
@@ -241,22 +257,27 @@ export class ProjectEdit extends Component {
      */
     setProjectQuotaParams(key, event) {
         let projectQuota = this.state.projectQuota;
+        const previousValue = projectQuota[key];
         if (event.target.value) {
             let resource = _.find(this.state.resources, {'name': key});
             
             let newValue = 0;
             if (this.resourceUnitMap[resource.quantity_value] && 
                 event.target.value.toString().indexOf(this.resourceUnitMap[resource.quantity_value].display)>=0) {
-                newValue = event.target.value.replace(this.resourceUnitMap[resource.quantity_value].display,'');
+                newValue = _.trim(event.target.value.replace(this.resourceUnitMap[resource.quantity_value].display,''));
             }   else {
-                newValue = event.target.value;
+                newValue = _.trim(event.target.value);
             }
-            projectQuota[key] = (newValue==="NaN" || isNaN(newValue))?0:newValue;
+            projectQuota[key] = (newValue==="NaN" || isNaN(newValue))?0:Number(newValue);
         }   else {
-            let projectQuota = this.state.projectQuota;
+           // let projectQuota = this.state.projectQuota;
             projectQuota[key] = 0;
         }
-        this.setState({projectQuota: projectQuota});
+        if  ( !this.state.isDirty && !_.isEqual(previousValue, projectQuota[key]) ) {
+            this.setState({projectQuota: projectQuota, isDirty: true});
+        }   else {
+            this.setState({projectQuota: projectQuota});
+        }
     }
 
     /**
@@ -375,7 +396,22 @@ export class ProjectEdit extends Component {
         }   else {
             dialog = {header: 'Error', detail: 'Project updated successfully but resource allocation not updated properly. Try again!'};
         }
-        this.setState({dialogVisible: true, dialog: dialog});
+        this.setState({dialogVisible: true, dialog: dialog, isDirty: false});
+    }
+
+    /**
+     * warn before cancel the page if any changes detected 
+     */
+    checkIsDirty() {
+        if( this.state.isDirty ){
+            this.setState({showDialog: true});
+        } else {
+            this.cancelEdit();
+        }
+    }
+    
+    close() {
+        this.setState({showDialog: false});
     }
 
     /**
@@ -393,7 +429,8 @@ export class ProjectEdit extends Component {
         return (
             <React.Fragment>
                <Growl ref={(el) => this.growl = el} />
-                 <PageHeader location={this.props.location} title={'Project - Edit'} actions={[{icon:'fa-window-close',link: this.props.history.goBack,title:'Click to Close Project Edit Page', props : { pathname: `/project/view/${this.state.project.name}`}}]}/>
+                 <PageHeader location={this.props.location} title={'Project - Edit'} actions={[{icon:'fa-window-close',
+                 title:'Click to Close Project Edit Page', type: 'button',  actOn: 'click', props:{ callback: this.checkIsDirty }}]}/>
 
                 { this.state.isLoading ? <AppLoader/> :
                 <>
@@ -559,7 +596,7 @@ export class ProjectEdit extends Component {
                         <Button label="Save" className="p-button-primary" id="save-btn" data-testid="save-btn" icon="pi pi-check" onClick={this.saveProject} disabled={!this.state.validForm} />
                     </div>
                     <div className="p-col-1">
-                        <Button label="Cancel" className="p-button-danger" icon="pi pi-times" onClick={this.cancelEdit}  />
+                        <Button label="Cancel" className="p-button-danger" icon="pi pi-times" onClick={this.checkIsDirty}  />
                     </div>
                 </div>
 
@@ -583,6 +620,11 @@ export class ProjectEdit extends Component {
                                 </div>
                             </div>
                     </Dialog>
+
+                    <CustomDialog type="confirmation" visible={this.state.showDialog} width="40vw"
+                        header={'Edit Project'} message={'Do you want to leave this page? Your changes may not be saved.'} 
+                        content={''} onClose={this.close} onCancel={this.close} onSubmit={this.cancelEdit}>
+                    </CustomDialog>
                 </div>
             </React.Fragment>
         );
diff --git a/SAS/TMSS/frontend/tmss_webapp/src/routes/Scheduling/SchedulingUnitList.js b/SAS/TMSS/frontend/tmss_webapp/src/routes/Scheduling/SchedulingUnitList.js
index 9151a93343a56e6aacadabd5b4a7bd4912a12a73..641ab1a84853bf87650bbc2637f096fff0cc1ea3 100644
--- a/SAS/TMSS/frontend/tmss_webapp/src/routes/Scheduling/SchedulingUnitList.js
+++ b/SAS/TMSS/frontend/tmss_webapp/src/routes/Scheduling/SchedulingUnitList.js
@@ -4,42 +4,72 @@ import moment from 'moment';
 import AppLoader from "./../../layout/components/AppLoader";
 import ViewTable from './../../components/ViewTable';
 import UnitConverter from '../../utils/unit.converter';
-
+import _ from 'lodash';
 import ScheduleService from '../../services/schedule.service';
+import { Link } from 'react-router-dom';
+import WorkflowService from '../../services/workflow.service';
 
 class SchedulingUnitList extends Component{
-     
     constructor(props){
        super(props);
        this.defaultcolumns = {
+        status: {
+            name: "Status",
+            filter: "select"
+        },
         type:{
             name:"Type",
             filter:"select"
         },
-        name:"Name",
-        description:"Description",
-        project:"Project",
-        created_at:{
-            name:"Created At",
-            filter: "date"
-        },
-        updated_at:{
-            name:"Updated At",
-            filter: "date"
-        },
         requirements_template_id:{
-            name: "Template",
+            name: "Template ID",
             filter: "select"
         },
+        project:"Project",
+        name:"Name",
         start_time:"Start Time",
         stop_time:"End time",
         duration:"Duration (HH:mm:ss)",
-        status:"Status"
-        };
+       
+       };
         if (props.hideProjectColumn) {
             delete this.defaultcolumns['project'];
         }
+        this.STATUS_BEFORE_SCHEDULED = ['defining', 'defined', 'schedulable'];  // Statuses before scheduled to get station_group
+        this.mainStationGroups = {};
         this.state = {
+            columnOrders: [ 
+                "Status", 
+                "Type",
+                // "Workflow Status",
+                "workflowStatus",
+                 "id",
+                 "linked_bp_draft",
+                 "Template ID",
+                 "template_description",
+                  "priority",
+                  "Project",
+                  "suSet",
+                  "Name",
+                  "description",
+                  "Start Time",
+                  "End time", 
+                  "Duration (HH:mm:ss)",  
+                  "station_group", 
+                  "task_content", 
+                  "target_observation_sap", 
+                  "target0angle1", 
+                  "target0angle2", 
+                //   "Target 1 - Reference Frame",
+                  "target0referenceframe", 
+                  "target1angle1", 
+                  "target1angle2", 
+                //   "Target 2 - Reference Frame",
+                  "target1referenceframe",
+                  "Cancelled",
+                  "created_at", 
+                  "updated_at", 
+                  ],
             scheduleunit: [],
             paths: [{
                 "View": "/schedulingunit/view",
@@ -48,104 +78,274 @@ class SchedulingUnitList extends Component{
             defaultcolumns: [this.defaultcolumns],
             optionalcolumns:  [{
                 actionpath:"actionpath",
+                // workflowStatus: {
+                //     name: "Workflow Status",
+                //     filter: 'select'
+                // },
+                workflowStatus: 'Workflow Status',
+                id: "Scheduling Unit ID",
+                linked_bp_draft:"Linked Blueprint/ Draft ID",
+                template_description: "Template Description",
+                priority:"Priority",
+                suSet:"Scheduling set",
+                description:"Description",           
+                station_group: 'Stations (CS/RS/IS)',
+                task_content: 'Tasks content (O/P/I)',
+                target_observation_sap: "Number of SAPs in the target observation",
+                do_cancel: {
+                    name: "Cancelled",
+                    filter: "switch",
+                },
+                created_at:"Created_At",
+                updated_at:"Updated_At"
             }],
             columnclassname: [{
+                "Scheduling Unit ID":"filter-input-50",
                 "Template":"filter-input-50",
+                "Project":"filter-input-50",
+                "Priority":"filter-input-50",
                 "Duration (HH:mm:ss)":"filter-input-75",
+                "Linked Blueprint/ Draft ID":"filter-input-50",
                 "Type": "filter-input-75",
-                "Status":"filter-input-100"
+                "Status":"filter-input-100",
+                "Workflow Status":"filter-input-100",
+                "Scheduling unit ID":"filter-input-50",
+                "Stations (CS/RS/IS)":"filter-input-50",
+                "Tasks content (O/P/I)":"filter-input-50",
+                "Number of SAPs in the target observation":"filter-input-50"
             }],
             defaultSortColumn: [{id: "Name", desc: false}],
         }
+       
         this.onRowSelection = this.onRowSelection.bind(this);
         this.reloadData = this.reloadData.bind(this);
+        this.addTargetColumns = this.addTargetColumns.bind(this);
+    }
+
+    /**
+     * Get count of tasks grouped by type (observation, pipeline, ingest)
+     * @param {Array} tasks - array of task(draft or blueprint) objects
+     */
+    getTaskTypeGroupCounts(tasks = []) {
+        const observation = tasks.filter(task => task.specifications_template.type_value === 'observation');
+        const pipeline = tasks.filter(task => task.specifications_template.type_value === 'pipeline');
+        const ingest = tasks.filter(task => task.specifications_template.type_value === 'ingest');
+        return `${observation.length}/${pipeline.length}/${ingest.length}`;
+    }
+
+    /**
+     * Get all stations of the SUs from the observation task or subtask based on the SU status.
+     * @param {Object} schedulingUnit
+     */
+    getSUStations(schedulingUnit) {
+        let stations = [];
+        let tasks = schedulingUnit.task_blueprints?schedulingUnit.task_blueprints:schedulingUnit.task_drafts;
+        /* Get all observation tasks */
+        const observationTasks = _.filter(tasks, (task) => { return task.specifications_template.type_value.toLowerCase() === "observation"});
+        for (const observationTask of observationTasks) {
+            /** If the status of SU is before scheduled, get all stations from the station_groups from the task specification_docs */
+            if ((!schedulingUnit.status || this.STATUS_BEFORE_SCHEDULED.indexOf(schedulingUnit.status.toLowerCase()) >= 0)
+                && observationTask.specifications_doc.station_groups) {
+                for (const grpStations of _.map(observationTask.specifications_doc.station_groups, "stations")) {
+                    stations = _.concat(stations, grpStations);
+                }
+            }   else if (schedulingUnit.status && this.STATUS_BEFORE_SCHEDULED.indexOf(schedulingUnit.status.toLowerCase()) < 0 
+                            && observationTask.subtasks) {
+                /** If the status of SU is scheduled or after get the stations from the subtask specification tasks */
+                for (const subtask of observationTask.subtasks) {
+                    if (subtask.specifications_doc.stations) {
+                        stations = _.concat(stations, subtask.specifications_doc.stations.station_list);
+                    }
+                }
+            }
+        }
+        return _.uniq(stations);
+    }
+
+    /**
+     * Group the SU stations to main groups Core, Remote, International
+     * @param {Object} stationList 
+     */
+    groupSUStations(stationList) {
+        let suStationGroups = {};
+        for (const group in this.mainStationGroups) {
+            suStationGroups[group] = _.intersection(this.mainStationGroups[group], stationList);
+        }
+        return suStationGroups;
+    }
+
+    getStationGroup(itemSU) {
+        const item = {};
+        const itemStations = this.getSUStations(itemSU);
+        const itemStationGroups = this.groupSUStations(itemStations);
+        item.stations = {groups: "", counts: ""};
+        item.suName = itemSU.name;
+        for (const stationgroup of _.keys(itemStationGroups)) {
+            let groups = item.stations.groups;
+            let counts = item.stations.counts;
+            if (groups) {
+                groups = groups.concat("/");
+                counts = counts.concat("/");
+            }
+            // Get station group 1st character and append 'S' to get CS,RS,IS 
+            groups = groups.concat(stationgroup.substring(0,1).concat('S'));
+            counts = counts.concat(itemStationGroups[stationgroup].length);
+            item.stations.groups = groups;
+            item.stations.counts = counts;
+        }
+        return item.stations;
+    }
+
+    /**
+     * Function to get a component with list of links to a list of ids
+     * @param {Array} linkedItems - list of ids
+     * @param {String} type - blueprint or draft
+     */
+    getLinksList = (linkedItems, type) => {
+        return (
+            <>
+                {linkedItems.length>0 && linkedItems.map((item, index) => (
+                    <Link style={{paddingRight: '3px'}} to={`/schedulingunit/view/${type}/${item}`}>{item}</Link>
+                ))}
+            </>
+        );                    
     }
 
     async getSchedulingUnitList () {
         //Get SU Draft/Blueprints for the Project ID. This request is coming from view Project page. Otherwise it will show all SU
-        let project = this.props.project;
-        if(project) {
-            let scheduleunits = await ScheduleService.getSchedulingListByProject(project);
-            if(scheduleunits){
-                this.setState({
-                    scheduleunit: scheduleunits, isLoading: false
-                });
-            }
-        }   else{ 
+        // let project = this.props.project;
+        // if(project) {
+        //     let scheduleunits = await ScheduleService.getSchedulingListByProject(project);
+        //     if(scheduleunits){
+        //         this.setState({
+        //             scheduleunit: scheduleunits, isLoading: false
+        //         });
+        //     }
+        // }   else { 
+            const suTemplate = {};
             const schedulingSet = await ScheduleService.getSchedulingSets();
             const projects = await ScheduleService.getProjectList();
             const promises = [ScheduleService.getSchedulingUnitsExtended('blueprint'), 
-                                ScheduleService.getSchedulingUnitsExtended('draft')];
-            Promise.all(promises).then(responses => {
+                                ScheduleService.getSchedulingUnitsExtended('draft'),
+                                ScheduleService.getMainGroupStations(),
+                                WorkflowService.getWorkflowProcesses()];
+            Promise.all(promises).then(async responses => {
                 const blueprints = responses[0];
                 let scheduleunits = responses[1];
+                this.mainStationGroups = responses[2];
+                let workflowProcesses = responses[3];
                 const output = [];
                 for( const scheduleunit  of scheduleunits){
                     const suSet = schedulingSet.find((suSet) => { return  scheduleunit.scheduling_set_id === suSet.id });
                     const project = projects.find((project) => { return suSet.project_id === project.name});
-                    const blueprintdata = blueprints.filter(i => i.draft_id === scheduleunit.id);
-                    blueprintdata.map(blueP => { 
-                        blueP.duration = moment.utc((blueP.duration || 0)*1000).format('HH:mm:ss');
-                        blueP.type="Blueprint"; 
-                        blueP['actionpath'] ='/schedulingunit/view/blueprint/'+blueP.id;
-                        blueP['created_at'] = moment(blueP['created_at'], moment.ISO_8601).format("YYYY-MMM-DD HH:mm:ss");
-                        blueP['updated_at'] = moment(blueP['updated_at'], moment.ISO_8601).format("YYYY-MMM-DD HH:mm:ss");
-                        blueP.project = project.name;
-                        blueP.canSelect = false;
-                        // blueP.links = ['Project'];
-                        // blueP.linksURL = {
-                        //     'Project': `/project/view/${project.name}`
-                        // }
-                        return blueP; 
-                    });
-                    output.push(...blueprintdata);
-                    scheduleunit['actionpath']='/schedulingunit/view/draft/'+scheduleunit.id;
-                    scheduleunit['type'] = 'Draft';
-                    scheduleunit['duration'] = moment.utc((scheduleunit.duration || 0)*1000).format('HH:mm:ss');
-                    scheduleunit['created_at'] = moment(scheduleunit['created_at'], moment.ISO_8601).format("YYYY-MMM-DD HH:mm:ss");
-                    scheduleunit['updated_at'] = moment(scheduleunit['updated_at'], moment.ISO_8601).format("YYYY-MMM-DD HH:mm:ss");
-                    scheduleunit.project = project.name;
-                    scheduleunit.canSelect = true;
-                    // scheduleunit.links = ['Project'];
-                    // scheduleunit.linksURL = {
-                    //     'Project': `/project/view/${project.name}`
-                    // }
-                    output.push(scheduleunit);
+                    if (!this.props.project || (this.props.project && project.name===this.props.project)) {
+                        scheduleunit['status'] = null;
+                        scheduleunit['workflowStatus'] = null;
+                        if (!suTemplate[scheduleunit.requirements_template_id]) {
+                            const response = await ScheduleService.getSchedulingUnitTemplate(scheduleunit.requirements_template_id);
+                            scheduleunit['template_description'] = response.description;
+                            suTemplate[scheduleunit.requirements_template_id] = response;
+                        } else {
+                            scheduleunit['template_description'] = suTemplate[scheduleunit.requirements_template_id].description;
+                        }
+                        scheduleunit['linked_bp_draft'] = this.getLinksList(scheduleunit.scheduling_unit_blueprints_ids, 'blueprint');
+                        scheduleunit['task_content'] = this.getTaskTypeGroupCounts(scheduleunit['task_drafts']);
+                        scheduleunit['station_group'] = this.getStationGroup(scheduleunit).counts;
+                        const blueprintdata = blueprints.filter(i => i.draft_id === scheduleunit.id);
+                        blueprintdata.map(blueP => { 
+                            const workflowProcess = _.find(workflowProcesses, ['su', blueP.id]);
+                            blueP['workflowStatus'] = workflowProcess?workflowProcess.status: null;
+                            blueP.duration = moment.utc((blueP.duration || 0)*1000).format('HH:mm:ss');
+                            blueP.type="Blueprint"; 
+                            blueP['actionpath'] ='/schedulingunit/view/blueprint/'+blueP.id;
+                            blueP['created_at'] = moment(blueP['created_at'], moment.ISO_8601).format("YYYY-MMM-DD HH:mm:ss");
+                            blueP['updated_at'] = moment(blueP['updated_at'], moment.ISO_8601).format("YYYY-MMM-DD HH:mm:ss");
+                            blueP['task_content'] = this.getTaskTypeGroupCounts(blueP['task_blueprints']);
+                            blueP['linked_bp_draft'] = this.getLinksList([blueP.draft_id], 'draft');
+                            blueP['template_description'] = suTemplate[blueP.requirements_template_id].description;
+                            blueP['station_group'] = this.getStationGroup(blueP).counts;
+                            blueP.project = project.name;
+                            blueP.canSelect = false;
+                            blueP.suSet = suSet.name;
+                            // blueP.links = ['Project'];
+                            // blueP.linksURL = {
+                            //     'Project': `/project/view/${project.name}`
+                            // }
+                            blueP.links = ['Project', 'id'];
+                            blueP.linksURL = {
+                                'Project': `/project/view/${project.name}`,
+                                'id': `/schedulingunit/view/blueprint/${blueP.id}`
+                            }
+                            return blueP; 
+                        });
+                        output.push(...blueprintdata);
+                        scheduleunit['actionpath']='/schedulingunit/view/draft/'+scheduleunit.id;
+                        scheduleunit['type'] = 'Draft';
+                        scheduleunit['duration'] = moment.utc((scheduleunit.duration || 0)*1000).format('HH:mm:ss');
+                        scheduleunit['created_at'] = moment(scheduleunit['created_at'], moment.ISO_8601).format("YYYY-MMM-DD HH:mm:ss");
+                        scheduleunit['updated_at'] = moment(scheduleunit['updated_at'], moment.ISO_8601).format("YYYY-MMM-DD HH:mm:ss");
+                        scheduleunit.project = project.name;
+                        scheduleunit.canSelect = true;
+                        scheduleunit.suSet = suSet.name;
+                        scheduleunit.links = ['Project', 'id'];
+                        scheduleunit.linksURL = {
+                            'Project': `/project/view/${project.name}`,
+                            'id': `/schedulingunit/view/draft/${scheduleunit.id}`
+                        }
+                        output.push(scheduleunit);
+                    }
                 }
-                const defaultColumns = this.defaultcolumns;
-                let columnclassname = this.state.columnclassname[0];
-                output.map(su => {
-                    su.taskDetails = su.type==="Draft"?su.task_drafts:su.task_blueprints;
-                    const targetObserv = su.taskDetails.find(task => task.specifications_template.type_value==='observation' && task.specifications_doc.SAPs);
-                    // Constructing targets in single string to make it clear display 
-                    targetObserv.specifications_doc.SAPs.map((target, index) => {
-                        su[`target${index}angle1`] = UnitConverter.getAngleInput(target.digital_pointing.angle1);
-                        su[`target${index}angle2`] = UnitConverter.getAngleInput(target.digital_pointing.angle2,true);
-                        su[`target${index}referenceframe`] = target.digital_pointing.direction_type;
-                        defaultColumns[`target${index}angle1`] = `Target ${index + 1} - Angle 1`;
-                        defaultColumns[`target${index}angle2`] = `Target ${index + 1} - Angle 2`;
-                        defaultColumns[`target${index}referenceframe`] = {
-                            name: `Target ${index + 1} - Reference Frame`,
-                            filter: "select"
-                        };
-                        columnclassname[`Target ${index + 1} - Angle 1`] = "filter-input-75";
-                        columnclassname[`Target ${index + 1} - Angle 2`] = "filter-input-75";
-                        return target;
-                    });
-                    return su;
-                });
-                this.setState({
-                    scheduleunit: output, isLoading: false, defaultColumns: defaultColumns,
-                    columnclassname: [columnclassname]
-                });
+                this.addTargetColumns(output);
                 this.selectedRows = [];
             });
-        }
+        // }
     }
     
+    addTargetColumns(schedulingUnits) {
+        let optionalColumns = this.state.optionalcolumns[0];
+        let columnclassname = this.state.columnclassname[0];
+        schedulingUnits.map(su => {
+            su.taskDetails = su.type==="Draft"?su.task_drafts:su.task_blueprints;
+            const targetObserv = su.taskDetails.find(task => task.specifications_template.type_value==='observation' && task.specifications_doc.SAPs);
+            // const targetObservationSAPs = su.taskDetails.find(task => task.specifications_template.name==='target observation');
+            // if (targetObservationSAPs.specifications_doc && targetObservationSAPs.specifications_doc.SAPs) {
+            //     su['target_observation_sap'] = targetObservationSAPs.specifications_doc.SAPs.length;
+            // } else {
+            //     su['target_observation_sap'] = 0;
+            // }
+            // Addin target pointing fields as separate column
+            // if (targetObserv && targetObserv.specifications_doc) {
+            if (targetObserv) {
+                su['target_observation_sap'] = targetObserv.specifications_doc.SAPs.length;
+                targetObserv.specifications_doc.SAPs.map((target, index) => {
+                    su[`target${index}angle1`] = UnitConverter.getAngleInput(target.digital_pointing.angle1);
+                    su[`target${index}angle2`] = UnitConverter.getAngleInput(target.digital_pointing.angle2,true);
+                    su[`target${index}referenceframe`] = target.digital_pointing.direction_type;
+                    optionalColumns[`target${index}angle1`] = `Target ${index + 1} - Angle 1`;
+                    optionalColumns[`target${index}angle2`] = `Target ${index + 1} - Angle 2`;
+                    /*optionalColumns[`target${index}referenceframe`] = {
+                        name: `Target ${index + 1} - Reference Frame`,
+                        filter: "select"
+                    };*/ //TODO: Need to check why this code is not working
+                    optionalColumns[`target${index}referenceframe`] = `Target ${index + 1} - Reference Frame`;
+                    columnclassname[`Target ${index + 1} - Angle 1`] = "filter-input-75";
+                    columnclassname[`Target ${index + 1} - Angle 2`] = "filter-input-75";
+                    columnclassname[`Target ${index + 1} - Reference Frame`] = "filter-input-75";
+                    return target;
+                });
+            }   else {
+                su['target_observation_sap'] = 0;
+            }
+            return su;
+        });
+        this.setState({
+            scheduleunit: schedulingUnits, isLoading: false, optionalColumns: [optionalColumns],
+            columnclassname: [columnclassname]
+        });
+    }
+
     componentDidMount(){ 
        this.getSchedulingUnitList();
-        
     }
 
     /**
@@ -188,6 +388,7 @@ class SchedulingUnitList extends Component{
                         defaultcolumns={this.state.defaultcolumns} 
                         optionalcolumns={this.state.optionalcolumns}
                         columnclassname={this.state.columnclassname}
+                        columnOrders={this.state.columnOrders}
                         defaultSortColumn={this.state.defaultSortColumn}
                         showaction="true"
                         keyaccessor="id"
diff --git a/SAS/TMSS/frontend/tmss_webapp/src/routes/Scheduling/Stations.js b/SAS/TMSS/frontend/tmss_webapp/src/routes/Scheduling/Stations.js
index d2c7e01c63d7f72528eb66d0791b5f0a51a9f2ca..b773b1de101889e2ffe5f735074a1d8493f6020f 100644
--- a/SAS/TMSS/frontend/tmss_webapp/src/routes/Scheduling/Stations.js
+++ b/SAS/TMSS/frontend/tmss_webapp/src/routes/Scheduling/Stations.js
@@ -94,7 +94,7 @@ export default (props) => {
                 ...stationState,
                 [StationName]: {
                     stations: response.stations,
-                    missing_StationFields: missing_StationFields ? missing_StationFields.max_nr_missing : ''
+                    missing_StationFields: missing_StationFields ? isNaN(missing_StationFields.max_nr_missing)? 0: missing_StationFields.max_nr_missing : ''
                 },
                 Custom: {
                     stations: [...stationState['Custom'].stations, ...response.stations], 
@@ -163,7 +163,7 @@ export default (props) => {
      */
     const setNoOfmissing_StationFields = (key, value) => {
         let cpmissing_StationFieldsErrors = [...missing_StationFieldsErrors];
-        if (value > state[key].stations.length || value === '') {
+        if (isNaN(value) || value > state[key].stations.length || value.trim() === '') {
             if (!cpmissing_StationFieldsErrors.includes(key)) {
                 cpmissing_StationFieldsErrors.push(key);
             }
@@ -176,7 +176,7 @@ export default (props) => {
             [key]: {
                 ...state[key],
                 missing_StationFields: value,
-                error: value > state[key].stations.length || value === ''
+                error: isNaN(value) || value > state[key].stations.length || value.trim() === ''
             },
         };
         setState(stationState);
@@ -192,7 +192,7 @@ export default (props) => {
      */
     const setMissingFieldsForCustom = (value, index) => {
         const custom_selected_options = [...customStations];
-        if (value > custom_selected_options[index].stations.length || value === '' || !custom_selected_options[index].stations.length) {
+        if (isNaN(value) || value > custom_selected_options[index].stations.length || value.trim() === '' || !custom_selected_options[index].stations.length) {
             custom_selected_options[index].error = true;
         } else {
             custom_selected_options[index].error = false;
diff --git a/SAS/TMSS/frontend/tmss_webapp/src/routes/Scheduling/ViewSchedulingUnit.js b/SAS/TMSS/frontend/tmss_webapp/src/routes/Scheduling/ViewSchedulingUnit.js
index 89217c6cbba5f19854aeed647f34ebd380819f21..8638bb966b71cb53d88bf88d3e84e2bfb5ea5b1e 100644
--- a/SAS/TMSS/frontend/tmss_webapp/src/routes/Scheduling/ViewSchedulingUnit.js
+++ b/SAS/TMSS/frontend/tmss_webapp/src/routes/Scheduling/ViewSchedulingUnit.js
@@ -18,6 +18,7 @@ import { CustomDialog } from '../../layout/components/CustomDialog';
 import { CustomPageSpinner } from '../../components/CustomPageSpinner';
 import { Growl } from 'primereact/components/growl/Growl';
 import Schedulingtaskrelation from './Scheduling.task.relation';
+import UnitConverter from '../../utils/unit.converter';
 import TaskService from '../../services/task.service';
 
 
@@ -35,8 +36,36 @@ class ViewSchedulingUnit extends Component{
             }],
             ingestGroup: {},
             missingStationFieldsErrors: [],
+            columnOrders: [
+                "Status Logs",
+                 "Status",
+                 "Type",
+                 "ID",
+                 "Control ID",
+                 "Name",
+                 "Description",
+                 "Start Time",
+                 "End Time",
+                 "Duration (HH:mm:ss)",
+                 "Relative Start Time (HH:mm:ss)",
+                 "Relative End Time (HH:mm:ss)",
+                 "#Dataproducts",
+                 "size",
+                 "dataSizeOnDisk",
+                 "subtaskContent",
+                 "tags",
+                 "blueprint_draft",
+                 "url",
+                 "Cancelled",
+                 "Created at",
+                 "Updated at"
+             ],
             defaultcolumns: [ {
                 status_logs: "Status Logs",
+                status:{
+                name:"Status",
+                filter: "select"
+                },
                 tasktype:{
                     name:"Type",
                     filter:"select"
@@ -45,29 +74,38 @@ class ViewSchedulingUnit extends Component{
                 subTaskID: 'Control ID',
                 name:"Name",
                 description:"Description",
-                created_at:{
-                    name: "Created at",
+                start_time:{
+                    name:"Start Time",
                     filter: "date"
                 },
-                updated_at:{
-                    name: "Updated at",
+                stop_time:{
+                    name:"End Time",
                     filter: "date"
                 },
+                duration:"Duration (HH:mm:ss)",
+                relative_start_time:"Relative Start Time (HH:mm:ss)",
+                relative_stop_time:"Relative End Time (HH:mm:ss)",
+                noOfOutputProducts: "#Dataproducts",
                 do_cancel:{
                     name: "Cancelled",
                     filter: "switch"
                 },
-                start_time:"Start Time",
-                stop_time:"End Time",
-                duration:"Duration (HH:mm:ss)",
-                status:"Status"
             }],
             optionalcolumns:  [{
-                relative_start_time:"Relative Start Time (HH:mm:ss)",
-                relative_stop_time:"Relative End Time (HH:mm:ss)",
+                size: "Data size",
+                dataSizeOnDisk: "Data size on Disk",
+                subtaskContent: "Subtask Content",
                 tags:"Tags",
                 blueprint_draft:"BluePrint / Task Draft link",
-                url:"URL",
+                url:"API URL",
+                created_at:{
+                    name: "Created at",
+                    filter: "date"
+                },
+                updated_at:{
+                    name: "Updated at",
+                    filter: "date"
+                },
                 actionpath:"actionpath"
             }],
             columnclassname: [{
@@ -78,10 +116,15 @@ class ViewSchedulingUnit extends Component{
                 "Cancelled":"filter-input-50",
                 "Duration (HH:mm:ss)":"filter-input-75",
                 "Template ID":"filter-input-50",
-                "BluePrint / Task Draft link": "filter-input-100",
+                // "BluePrint / Task Draft link": "filter-input-100",
                 "Relative Start Time (HH:mm:ss)": "filter-input-75",
                 "Relative End Time (HH:mm:ss)": "filter-input-75",
-                "Status":"filter-input-100"
+                "Status":"filter-input-100",
+                "#Dataproducts":"filter-input-75",
+                "Data size":"filter-input-50",
+                "Data size on Disk":"filter-input-50",
+                "Subtask Content":"filter-input-75",
+                "BluePrint / Task Draft link":"filter-input-50",
             }],
             stationGroup: [],
             dialog: {header: 'Confirm', detail: 'Do you want to create a Scheduling Unit Blueprint?'},
@@ -128,7 +171,7 @@ class ViewSchedulingUnit extends Component{
             </button>
         );
     };
-    
+
     getSchedulingUnitDetails(schedule_type, schedule_id) {
         ScheduleService.getSchedulingUnitExtended(schedule_type, schedule_id)
             .then(async(schedulingUnit) =>{
@@ -140,13 +183,28 @@ class ViewSchedulingUnit extends Component{
                     let tasks = schedulingUnit.task_drafts?(await this.getFormattedTaskDrafts(schedulingUnit)):this.getFormattedTaskBlueprints(schedulingUnit);
                     let ingestGroup = tasks.map(task => ({name: task.name, canIngest: task.canIngest, type_value: task.type_value, id: task.id }));
                     ingestGroup = _.groupBy(_.filter(ingestGroup, 'type_value'), 'type_value');
-                    tasks.map(task => {
+                    await Promise.all(tasks.map(async task => {
                         task.status_logs = task.tasktype === "Blueprint"?this.subtaskComponent(task):"";
                         //Displaying SubTask ID of the 'control' Task
-                        const subTaskIds = task.subTasks?task.subTasks.filter(sTask => sTask.subTaskTemplate.name.indexOf('control') > 1):[];
+                        const subTaskIds = task.subTasks?task.subTasks.filter(sTask => sTask.subTaskTemplate.name.indexOf('control') >= 0):[];
+                        const promise = [];
+                        subTaskIds.map(subTask => promise.push(ScheduleService.getSubtaskOutputDataproduct(subTask.id)));
+                        const dataProducts = promise.length > 0? await Promise.all(promise):[];
+                        task.dataProducts = [];
+                        task.size = 0;
+                        task.dataSizeOnDisk = 0;
+                        task.noOfOutputProducts = 0;
+                        if (dataProducts.length && dataProducts[0].length) {
+                            task.dataProducts = dataProducts[0];
+                            task.noOfOutputProducts = dataProducts[0].length;
+                            task.size = _.sumBy(dataProducts[0], 'size');
+                            task.dataSizeOnDisk = _.sumBy(dataProducts[0], function(product) { return product.deletedSince?0:product.size});
+                            task.size = UnitConverter.getUIResourceUnit('bytes', (task.size));
+                            task.dataSizeOnDisk = UnitConverter.getUIResourceUnit('bytes', (task.dataSizeOnDisk));
+                        }
                         task.subTaskID = subTaskIds.length ? subTaskIds[0].id : ''; 
                         return task;
-                    });
+                    }));
                     const targetObservation = _.find(tasks, (task)=> {return task.template.type_value==='observation' && task.tasktype.toLowerCase()===schedule_type && task.specifications_doc.station_groups});
                     this.setState({
                         scheduleunitId: schedule_id,
@@ -243,10 +301,12 @@ class ViewSchedulingUnit extends Component{
         }
         //Ingest Task Relation 
         const ingestTask = scheduletasklist.find(task => task.type_value === 'ingest' && task.tasktype.toLowerCase() === 'draft');
-        for (const producer_id of ingestTask.produced_by_ids) {
-            const taskRelation = await ScheduleService.getTaskRelation(producer_id);
-            const producerTask = scheduletasklist.find(task => task.id === taskRelation.producer_id && task.tasktype.toLowerCase() === 'draft');
-            producerTask.canIngest = true;
+        if (ingestTask) {
+            for (const producer_id of ingestTask.produced_by_ids) {
+                const taskRelation = await ScheduleService.getTaskRelation(producer_id);
+                const producerTask = scheduletasklist.find(task => task.id === taskRelation.producer_id && task.tasktype.toLowerCase() === 'draft');
+                producerTask.canIngest = true;
+            }
         }
         return scheduletasklist;
     }
@@ -419,6 +479,7 @@ class ViewSchedulingUnit extends Component{
                         defaultcolumns={this.state.defaultcolumns}
                         optionalcolumns={this.state.optionalcolumns}
                         columnclassname={this.state.columnclassname}
+                        columnOrders={this.state.columnOrders}
                         defaultSortColumn={this.state.defaultSortColumn}
                         showaction="true"
                         keyaccessor="id"
diff --git a/SAS/TMSS/frontend/tmss_webapp/src/routes/Scheduling/create.js b/SAS/TMSS/frontend/tmss_webapp/src/routes/Scheduling/create.js
index 082a6912336dcc03b2fe3c78f89f69b659e7a598..cf5baa7e9a48890f47a9cbda3e4feced52f9af6f 100644
--- a/SAS/TMSS/frontend/tmss_webapp/src/routes/Scheduling/create.js
+++ b/SAS/TMSS/frontend/tmss_webapp/src/routes/Scheduling/create.js
@@ -1,15 +1,14 @@
-import React, {Component} from 'react';
+import React, { Component } from 'react';
 import { Redirect } from 'react-router-dom';
 import _ from 'lodash';
 import $RefParser from "@apidevtools/json-schema-ref-parser";
 import moment from 'moment';
-import {InputText} from 'primereact/inputtext';
-import {InputTextarea} from 'primereact/inputtextarea';
-import {Dropdown} from 'primereact/dropdown';
+import { InputText } from 'primereact/inputtext';
+import { InputTextarea } from 'primereact/inputtextarea';
+import { Dropdown } from 'primereact/dropdown';
 import { Button } from 'primereact/button';
-import {Dialog} from 'primereact/components/dialog/Dialog';
-import {Growl} from 'primereact/components/growl/Growl';
-
+import { Dialog } from 'primereact/components/dialog/Dialog';
+import { Growl } from 'primereact/components/growl/Growl';
 import AppLoader from '../../layout/components/AppLoader';
 import Jeditor from '../../components/JSONEditor/JEditor';
 import UnitConversion from '../../utils/unit.converter';
@@ -21,6 +20,8 @@ import UIConstants from '../../utils/ui.constants';
 import PageHeader from '../../layout/components/PageHeader';
 import SchedulingConstraint from './Scheduling.Constraints';
 import Stations from './Stations';
+import { CustomDialog } from '../../layout/components/CustomDialog';
+import SchedulingSet from './schedulingset.create';
 
 /**
  * Component to create a new SchedulingUnit from Observation strategy template
@@ -29,6 +30,10 @@ export class SchedulingUnitCreate extends Component {
     constructor(props) {
         super(props);
         this.state = {
+            selectedProject: {},
+            showAddSet: false,
+            showDialog: false,
+            isDirty: false,
             isLoading: true,                        // Flag for loading spinner
             dialog: { header: '', detail: ''},      // Dialog properties
             touched: {},
@@ -39,7 +44,9 @@ export class SchedulingUnitCreate extends Component {
             stationOptions: [],
             stationGroup: [],
             customSelectedStations: [],             // custom stations
-            schedulingUnit: {
+            schedulingUnit: {                
+                name: '',
+                description: '',
                 project: (props.match?props.match.params.project:null) || null,
             },
             projectDisabled: (props.match?(props.match.params.project? true:false):false),      // Disable project selection if 
@@ -76,6 +83,9 @@ export class SchedulingUnitCreate extends Component {
         this.saveSchedulingUnit = this.saveSchedulingUnit.bind(this);
         this.cancelCreate = this.cancelCreate.bind(this);
         this.reset = this.reset.bind(this);
+        this.refreshSchedulingSet = this.refreshSchedulingSet.bind(this);
+        this.checkIsDirty = this.checkIsDirty.bind(this);
+        this.close = this.close.bind(this);
     }
 
     componentDidMount() {
@@ -95,8 +105,9 @@ export class SchedulingUnitCreate extends Component {
             //  Setting first value as constraint template
              this.constraintStrategy(this.constraintTemplates[0]);
             if (this.state.schedulingUnit.project) {
+                const selectedProject = _.filter(this.projects, {'name': this.state.schedulingUnit.project});
                 const projectSchedSets = _.filter(this.schedulingSets, {'project_id': this.state.schedulingUnit.project});
-                this.setState({isLoading: false, schedulingSets: projectSchedSets});
+                this.setState({isLoading: false, schedulingSets: projectSchedSets,selectedProject:selectedProject});
             }   else {
                 this.setState({isLoading: false});
             }
@@ -111,7 +122,8 @@ export class SchedulingUnitCreate extends Component {
         const projectSchedSets = _.filter(this.schedulingSets, {'project_id': projectName});
         let schedulingUnit = this.state.schedulingUnit;
         schedulingUnit.project = projectName;
-        this.setState({schedulingUnit: schedulingUnit, schedulingSets: projectSchedSets, validForm: this.validateForm('project')});
+        const selectedProject = _.filter(this.projects, {'name': projectName});
+        this.setState({selectedProject: selectedProject, schedulingUnit: schedulingUnit, schedulingSets: projectSchedSets, validForm: this.validateForm('project'), isDirty: true});
     }
     
     /**
@@ -176,7 +188,7 @@ export class SchedulingUnitCreate extends Component {
             }
             
         }
-        this.setState({observStrategy: observStrategy, paramsSchema: schema, paramsOutput: paramsOutput, stationGroup: station_group});
+        this.setState({observStrategy: observStrategy, paramsSchema: schema, paramsOutput: paramsOutput, stationGroup: station_group, isDirty: true});
 
         // Function called to clear the JSON Editor fields and reload with new schema
         if (this.state.editorFunction) {
@@ -203,12 +215,16 @@ export class SchedulingUnitCreate extends Component {
         if (jsonOutput.scheduler === 'online' || jsonOutput.scheduler === 'dynamic') {
             err = err.filter(e => e.path !== 'root.time.at');
         }
-        this.constraintParamsOutput = jsonOutput;
+       // this.constraintParamsOutput = jsonOutput;
         // condition goes here..
         this.constraintValidEditor = err.length === 0;
-        this.setState({ constraintParamsOutput: jsonOutput, 
-                        constraintValidEditor: err.length === 0,
-                        validForm: this.validateForm()});
+        if  ( !this.state.isDirty && this.state.constraintParamsOutput && !_.isEqual(this.state.constraintParamsOutput, jsonOutput) ) {
+            this.setState({ constraintParamsOutput: jsonOutput, constraintValidEditor: err.length === 0, validForm: this.validateForm(), isDirty: true});
+        }   else {
+            this.setState({ constraintParamsOutput: jsonOutput, constraintValidEditor: err.length === 0, validForm: this.validateForm()});
+        }
+
+        
     }
 
     /**
@@ -230,9 +246,13 @@ export class SchedulingUnitCreate extends Component {
                 [key]: true
             }
         });
-        let schedulingUnit = this.state.schedulingUnit;
+        let schedulingUnit = _.cloneDeep(this.state.schedulingUnit);
         schedulingUnit[key] = value;
-        this.setState({schedulingUnit: schedulingUnit, validForm: this.validateForm(key), validEditor: this.validateEditor()});
+        if  ( !this.state.isDirty && !_.isEqual(this.state.schedulingUnit, schedulingUnit) ) {
+            this.setState({schedulingUnit: schedulingUnit, validForm: this.validateForm(key), validEditor: this.validateEditor(), isDirty: true});
+        }   else {
+            this.setState({schedulingUnit: schedulingUnit, validForm: this.validateForm(key), validEditor: this.validateEditor()});
+        }
         this.validateEditor();
     }
 
@@ -361,12 +381,27 @@ export class SchedulingUnitCreate extends Component {
         if (!schedulingUnit.error) {
             // this.growl.show({severity: 'success', summary: 'Success', detail: 'Scheduling Unit and tasks created successfully!'});
             const dialog = {header: 'Success', detail: 'Scheduling Unit and Tasks are created successfully. Do you want to create another Scheduling Unit?'};
-            this.setState({schedulingUnit: schedulingUnit, dialogVisible: true, dialog: dialog})
+            this.setState({schedulingUnit: schedulingUnit, dialogVisible: true, dialog: dialog, isDirty: false});
         }   else {
             this.growl.show({severity: 'error', summary: 'Error Occured', detail: schedulingUnit.message || 'Unable to save Scheduling Unit/Tasks'});
         }
     }
 
+    /**
+     * warn before cancel the page if any changes detected 
+     */
+    checkIsDirty() {
+        if( this.state.isDirty ){
+            this.setState({showDialog: true});
+        } else {
+            this.cancelCreate();
+        }
+    }
+    
+    close() {
+        this.setState({showDialog: false});
+    }
+
     /**
      * Cancel SU creation and redirect
      */
@@ -388,6 +423,7 @@ export class SchedulingUnitCreate extends Component {
         this.nameInput.element.focus();
         this.setState({
             dialogVisible: false,
+            isDirty: false,
             dialog: { header: '', detail: ''},      
             errors: [],
             schedulingSets: this.props.match.params.project?schedulingSets:[],
@@ -415,25 +451,39 @@ export class SchedulingUnitCreate extends Component {
     }
 
     onUpdateStations = (state, selectedStations, missing_StationFieldsErrors, customSelectedStations) => {
-        this.setState({
-            ...state,
-            selectedStations,
-            missing_StationFieldsErrors,
-            customSelectedStations
-           
-        }, () => {
-            this.setState({
-                validForm: this.validateForm()
+        const selectedStation = this.state.selectedStations;
+        const customStation = this.state.customSelectedStations;
+        if  ( !this.state.isDirty ) {
+            if (selectedStation && !_.isEqual(selectedStation, selectedStations)){
+                this.setState({...state, selectedStations, missing_StationFieldsErrors, customSelectedStations }, () => {
+                    this.setState({ validForm: this.validateForm(), isDirty: true });
+                });
+            }   else if (customStation && !_.isEqual(customStation, customSelectedStations)){
+                this.setState({...state, selectedStations, missing_StationFieldsErrors, customSelectedStations }, () => {
+                    this.setState({ validForm: this.validateForm(), isDirty: true });
+                });
+            }   else {
+                this.setState({...state, selectedStations, missing_StationFieldsErrors, customSelectedStations }, () => {
+                    this.setState({ validForm: this.validateForm() });
+                });
+            }
+        }   else {
+            this.setState({...state, selectedStations, missing_StationFieldsErrors, customSelectedStations }, () => {
+                this.setState({ validForm: this.validateForm() });
             });
-
-        });
+        }
     };
 
+    async refreshSchedulingSet(){
+        this.schedulingSets = await ScheduleService.getSchedulingSets();
+        const filteredSchedluingSets = _.filter(this.schedulingSets, {'project_id': this.state.schedulingUnit.project});
+        this.setState({saveDialogVisible: false, showAddSet: false, schedulingSets: filteredSchedluingSets});
+    }
+
     render() {
         if (this.state.redirect) {
             return <Redirect to={ {pathname: this.state.redirect} }></Redirect>
         }
-        
         const schema = this.state.paramsSchema;
         
         let jeditor = null;
@@ -450,7 +500,8 @@ export class SchedulingUnitCreate extends Component {
             <React.Fragment>
                 <Growl ref={(el) => this.growl = el} />
                 <PageHeader location={this.props.location} title={'Scheduling Unit - Add'} 
-                           actions={[{icon: 'fa-window-close',link: this.props.history.goBack,title:'Click to close Scheduling Unit creation', props : { pathname: `/schedulingunit`}}]}/>
+                           actions={[{icon: 'fa-window-close', title:'Click to close Scheduling Unit creation',
+                           type: 'button',  actOn: 'click', props:{ callback: this.checkIsDirty }}]}/>
                 { this.state.isLoading ? <AppLoader /> :
                 <>
                  <div>
@@ -503,6 +554,13 @@ export class SchedulingUnitCreate extends Component {
                                         options={this.state.schedulingSets} 
                                         onChange={(e) => {this.setSchedUnitParams('scheduling_set_id',e.value)}} 
                                         placeholder="Select Scheduling Set" />
+
+                                        <Button label="" className="p-button-primary" icon="pi pi-plus" 
+                                        onClick={() => {this.setState({showAddSet: true})}}  
+                                        tooltip="Add new Scheduling Set"
+                                        style={{bottom: '2em', left: '25em'}}
+                                        disabled={this.state.schedulingUnit.project !== null ? false : true }/>
+
                                 <label className={(this.state.errors.scheduling_set_id && this.state.touched.scheduling_set_id) ?"error":"info"}>
                                     {(this.state.errors.scheduling_set_id && this.state.touched.scheduling_set_id) ? this.state.errors.scheduling_set_id : "Scheduling Set of the Project"}
                                 </label>
@@ -559,7 +617,7 @@ export class SchedulingUnitCreate extends Component {
                                       disabled={!this.state.constraintValidEditor || !this.state.validEditor || !this.state.validForm} data-testid="save-btn" />
                         </div>
                         <div className="p-col-1">
-                            <Button label="Cancel" className="p-button-danger" icon="pi pi-times" onClick={this.cancelCreate}  />
+                            <Button label="Cancel" className="p-button-danger" icon="pi pi-times" onClick={this.checkIsDirty}  />
                         </div>
                     </div>
                 </div>
@@ -585,6 +643,16 @@ export class SchedulingUnitCreate extends Component {
                                 </div>
                             </div>
                     </Dialog>
+
+                    <CustomDialog type="success" visible={this.state.showAddSet} width="40vw"
+                    header={'Add Scheduling Set’'} message= {<SchedulingSet project={this.state.selectedProject[0]} onCancel={this.refreshSchedulingSet} />} showIcon={false} actions={this.actions}
+                    content={''} onClose={this.refreshSchedulingSet} onCancel={this.refreshSchedulingSet} onSubmit={this.refreshSchedulingSet}
+                    showAction={true}>
+                </CustomDialog>
+                <CustomDialog type="confirmation" visible={this.state.showDialog} width="40vw"
+                    header={'Add Scheduling Unit'} message={'Do you want to leave this page? Your changes may not be saved.'} 
+                    content={''} onClose={this.close} onCancel={this.close} onSubmit={this.cancelCreate}>
+                </CustomDialog>
                 </div>
             </React.Fragment>
         );
diff --git a/SAS/TMSS/frontend/tmss_webapp/src/routes/Scheduling/edit.js b/SAS/TMSS/frontend/tmss_webapp/src/routes/Scheduling/edit.js
index 0c92c2c764bdfad792e9beaefe93facfe3d93d89..31ebfe2212d988a6dff2dcf697f210659fb649de 100644
--- a/SAS/TMSS/frontend/tmss_webapp/src/routes/Scheduling/edit.js
+++ b/SAS/TMSS/frontend/tmss_webapp/src/routes/Scheduling/edit.js
@@ -1,15 +1,15 @@
-import React, {Component} from 'react';
+import React, { Component } from 'react';
 import { Redirect } from 'react-router-dom';
 import moment from 'moment';
 import _ from 'lodash';
 import $RefParser from "@apidevtools/json-schema-ref-parser";
 
-import {InputText} from 'primereact/inputtext';
-import {InputTextarea} from 'primereact/inputtextarea';
-import {Dropdown} from 'primereact/dropdown';
+import { InputText } from 'primereact/inputtext';
+import { InputTextarea } from 'primereact/inputtextarea';
+import { Dropdown } from 'primereact/dropdown';
 import { Button } from 'primereact/button';
-import {Growl} from 'primereact/components/growl/Growl';
-
+import { Growl } from 'primereact/components/growl/Growl';
+import { CustomDialog } from '../../layout/components/CustomDialog';
 import AppLoader from '../../layout/components/AppLoader';
 import PageHeader from '../../layout/components/PageHeader';
 import Jeditor from '../../components/JSONEditor/JEditor';
@@ -29,6 +29,8 @@ export class EditSchedulingUnit extends Component {
     constructor(props) {
         super(props);
         this.state = {
+            showDialog: false,
+            isDirty: false,
             isLoading: true,                        //Flag for loading spinner                     
             dialog: { header: '', detail: ''},      //Dialog properties
             redirect: null,                         //URL to redirect
@@ -71,6 +73,8 @@ export class EditSchedulingUnit extends Component {
         this.saveSchedulingUnit = this.saveSchedulingUnit.bind(this);
         this.cancelCreate = this.cancelCreate.bind(this);
         this.setEditorOutputConstraint = this.setEditorOutputConstraint.bind(this);
+        this.checkIsDirty = this.checkIsDirty.bind(this);
+        this.close = this.close.bind(this);
     }
 
     /**
@@ -189,8 +193,18 @@ export class EditSchedulingUnit extends Component {
         this.paramsOutput = jsonOutput;
         this.validEditor = errors.length === 0;
         this.setState({ paramsOutput: jsonOutput, 
-                        validEditor: errors.length === 0,
-                        validForm: this.validateForm()});
+            validEditor: errors.length === 0,
+            validForm: this.validateForm()});
+        /*if  ( !this.state.isDirty && this.state.paramsOutput && !_.isEqual(this.state.paramsOutput, jsonOutput) ) {
+            this.setState({ paramsOutput: jsonOutput, 
+                validEditor: errors.length === 0,
+                validForm: this.validateForm()});
+        }   else {
+            this.setState({ paramsOutput: jsonOutput, 
+                validEditor: errors.length === 0,
+                validForm: this.validateForm()});
+        }*/
+        
     }
 
     setEditorOutputConstraint(jsonOutput, errors) {
@@ -200,9 +214,16 @@ export class EditSchedulingUnit extends Component {
         }
         this.constraintParamsOutput = jsonOutput || {};
         this.constraintValidEditor = err.length === 0;
-        this.setState({ constraintParamsOutput: jsonOutput, 
-                        constraintValidEditor: err.length === 0,
-                        validForm: this.validateForm()});
+        if  ( !this.state.isDirty && this.state.constraintParamsOutput && !_.isEqual(this.state.constraintParamsOutput, this.constraintParamsOutput) ) {
+            this.setState({ constraintParamsOutput: jsonOutput, 
+                constraintValidEditor: err.length === 0,
+                validForm: this.validateForm(), isDirty: true});
+        }   else {
+            this.setState({ constraintParamsOutput: jsonOutput, 
+                constraintValidEditor: err.length === 0,
+                validForm: this.validateForm()});
+        }
+        
     }
 
     /**
@@ -218,9 +239,14 @@ export class EditSchedulingUnit extends Component {
      * @param {object} value 
      */
     setSchedUnitParams(key, value) {
-        let schedulingUnit = this.state.schedulingUnit;
+        let schedulingUnit = _.cloneDeep(this.state.schedulingUnit);
         schedulingUnit[key] = value;
-        this.setState({schedulingUnit: schedulingUnit, validForm: this.validateForm(key), validEditor: this.validateEditor()});
+        if  ( !this.state.isDirty && !_.isEqual(this.state.schedulingUnit, schedulingUnit) ) {
+            this.setState({schedulingUnit: schedulingUnit, validForm: this.validateForm(key), validEditor: this.validateEditor(), isDirty: true});
+        }   else {
+            this.setState({schedulingUnit: schedulingUnit, validForm: this.validateForm(key), validEditor: this.validateEditor()});
+        }
+       // this.setState({schedulingUnit: schedulingUnit, validForm: this.validateForm(key), validEditor: this.validateEditor()});
         this.validateEditor();
     }
 
@@ -353,9 +379,24 @@ export class EditSchedulingUnit extends Component {
         }   else {
             this.growl.show({severity: 'error', summary: 'Error Occured', detail: 'Template Missing.'});
         }
+        this.setState({isDirty: false});
     }
     
+    /**
+     * warn before cancel the page if any changes detected 
+     */
+    checkIsDirty() {
+        if( this.state.isDirty ){
+                this.setState({showDialog: true});
+        } else {
+            this.cancelCreate();
+        }
+    }
     
+    close() {
+        this.setState({showDialog: false});
+    }
+
     /**
      * Cancel SU creation and redirect
      */
@@ -368,7 +409,28 @@ export class EditSchedulingUnit extends Component {
     }
   
     onUpdateStations = (state, selectedStations, missingStationFieldsErrors, customSelectedStations) => {
-        this.setState({
+        const selectedStation = this.state.selectedStations;
+        const customStation = this.state.customSelectedStations;
+        if  ( !this.state.isDirty ) {
+            if (selectedStation && !_.isEqual(selectedStation, selectedStations)){
+                this.setState({...state, selectedStations, missingStationFieldsErrors, customSelectedStations }, () => {
+                    this.setState({ validForm: this.validateForm(), isDirty: true });
+                });
+            }   else if (customStation && !_.isEqual(customStation, customSelectedStations)){
+                this.setState({...state, selectedStations, missingStationFieldsErrors, customSelectedStations }, () => {
+                    this.setState({ validForm: this.validateForm(), isDirty: true });
+                });
+            }   else {
+                this.setState({...state, selectedStations, missingStationFieldsErrors, customSelectedStations }, () => {
+                    this.setState({ validForm: this.validateForm() });
+                });
+            }
+        }   else {
+            this.setState({...state, selectedStations, missingStationFieldsErrors, customSelectedStations }, () => {
+                this.setState({ validForm: this.validateForm() });
+            });
+        }
+       /* this.setState({
             ...state,
             selectedStations,
             missingStationFieldsErrors,
@@ -377,7 +439,7 @@ export class EditSchedulingUnit extends Component {
             this.setState({
                 validForm: this.validateForm()
             });
-        });
+        });*/
     };
 
     render() {
@@ -400,7 +462,8 @@ export class EditSchedulingUnit extends Component {
             <React.Fragment>
                 <Growl ref={el => (this.growl = el)} />
                 <PageHeader location={this.props.location} title={'Scheduling Unit - Edit'} 
-                           actions={[{icon: 'fa-window-close',link: this.props.history.goBack,title:'Click to Close Scheduling Unit View', props : { pathname: `/schedulingunit/view/draft/${this.props.match.params.id}`}}]}/>
+                           actions={[{icon: 'fa-window-close', title:'Click to Close Scheduling Unit View', 
+                           type: 'button',  actOn: 'click', props:{ callback: this.checkIsDirty }}]}/>
                 { this.state.isLoading ? <AppLoader /> :
                 <>
                 <div>
@@ -480,14 +543,12 @@ export class EditSchedulingUnit extends Component {
                             </div> 
                         </div>
                     </div>
-
                     
                     <Stations
                         stationGroup={this.state.stationGroup}
                         onUpdateStations={this.onUpdateStations.bind(this)}
                     />
 
-
                     {this.state.constraintSchema && <div className="p-fluid">
                         <div className="p-grid">
                             <div className="p-col-12">
@@ -509,9 +570,16 @@ export class EditSchedulingUnit extends Component {
                                     disabled={!this.state.validEditor || !this.state.validForm} data-testid="save-btn" />
                         </div>
                         <div className="p-col-1">
-                            <Button label="Cancel" className="p-button-danger" icon="pi pi-times" onClick={this.cancelCreate}  />
+                            <Button label="Cancel" className="p-button-danger" icon="pi pi-times" onClick={this.checkIsDirty}  />
                         </div>
                     </div>
+
+                    <div className="p-grid" data-testid="confirm_dialog">
+                        <CustomDialog type="confirmation" visible={this.state.showDialog} width="40vw"
+                            header={'Edit Scheduling Unit'} message={'Do you want to leave this page? Your changes may not be saved.'} 
+                            content={''} onClose={this.close} onCancel={this.close} onSubmit={this.cancelCreate}>
+                        </CustomDialog>
+                    </div>
                 </div>
                     
                 </>
diff --git a/SAS/TMSS/frontend/tmss_webapp/src/routes/Scheduling/create.scheduleset.js b/SAS/TMSS/frontend/tmss_webapp/src/routes/Scheduling/excelview.schedulingset.js
similarity index 68%
rename from SAS/TMSS/frontend/tmss_webapp/src/routes/Scheduling/create.scheduleset.js
rename to SAS/TMSS/frontend/tmss_webapp/src/routes/Scheduling/excelview.schedulingset.js
index 8182b7b409ccf8f6d54ebce091b782f5fe5d9682..f15290796a26f00a8bc3520f1241c31bb8f16337 100644
--- a/SAS/TMSS/frontend/tmss_webapp/src/routes/Scheduling/create.scheduleset.js
+++ b/SAS/TMSS/frontend/tmss_webapp/src/routes/Scheduling/excelview.schedulingset.js
@@ -1,26 +1,22 @@
 import React, { Component } from 'react';
 import { Redirect } from 'react-router-dom';
-
 import { Dropdown } from 'primereact/dropdown';
 import { Button } from 'primereact/button';
-import { Dialog } from 'primereact/components/dialog/Dialog';
 import { Growl } from 'primereact/components/growl/Growl';
 import { Checkbox } from 'primereact/checkbox';
-
+import { Accordion, AccordionTab } from 'primereact/accordion';
 import { AgGridReact } from 'ag-grid-react';
 import { AllCommunityModules } from '@ag-grid-community/all-modules';
 import $RefParser from "@apidevtools/json-schema-ref-parser";
-
-import TimeInputmask from './../../components/Spreadsheet/TimeInputmask'
-import DegreeInputmask from './../../components/Spreadsheet/DegreeInputmask'
+import TimeInputmask from '../../components/Spreadsheet/TimeInputmask'
+import DegreeInputmask from '../../components/Spreadsheet/DegreeInputmask'
 import NumericEditor from '../../components/Spreadsheet/numericEditor';
 import BetweenEditor from '../../components/Spreadsheet/BetweenEditor'; 
 import BetweenRenderer from '../../components/Spreadsheet/BetweenRenderer';
 import MultiSelector from '../../components/Spreadsheet/MultiSelector';
 import AppLoader from '../../layout/components/AppLoader';
-
 import PageHeader from '../../layout/components/PageHeader';
-import { CustomDialog } from '../../layout/components/CustomDialog';
+
 import ProjectService from '../../services/project.service';
 import ScheduleService from '../../services/schedule.service';
 import TaskService from '../../services/task.service';
@@ -31,16 +27,17 @@ import UnitConverter from '../../utils/unit.converter'
 import UIConstants from '../../utils/ui.constants';
 import UnitConversion from '../../utils/unit.converter';
 import StationEditor from '../../components/Spreadsheet/StationEditor';
-    
+import SchedulingSet from './schedulingset.create';    
 import moment from 'moment';
 import _ from 'lodash';
 
 import 'ag-grid-community/dist/styles/ag-grid.css';
 import 'ag-grid-community/dist/styles/ag-theme-alpine.css';
 import { CustomPageSpinner } from '../../components/CustomPageSpinner';
+import { CustomDialog } from '../../layout/components/CustomDialog';
 
 const DATE_TIME_FORMAT = 'YYYY-MM-DD HH:mm:ss';
-const BG_COLOR= '#f878788f';
+const BG_COLOR = '#f878788f';
 
 /**
  * Component to create / update Scheduling Unit Drafts using Spreadsheet
@@ -48,13 +45,22 @@ const BG_COLOR= '#f878788f';
 export class SchedulingSetCreate extends Component {
     constructor(props) {
         super(props);
-        this.gridApi = ''
-        this.gridColumnApi = ''
+        this.gridApi = '';
+        this.gridColumnApi = '';
+        this.topGridApi = '';
+        this.topGridColumnApi = '';
         this.rowData = [];
         this.tmpRowData = [];
         this.daily = [];
+        this.dailyOption = [];
+        this.isNewSet = false;
+        //this.dialogMsg = '';
+        //this.dialogType = '';
+        //this.callBackFunction = '';
         this.state = {
+            selectedProject: {},
             copyHeader: false,                    // Copy Table Header to clipboard
+            applyEmptyValue: false,
             dailyOption: [],
             projectDisabled: (props.match?(props.match.params.project? true:false):false),
             isLoading: true, 
@@ -120,17 +126,39 @@ export class SchedulingSetCreate extends Component {
             customSelectedStations: [],
             selectedStations: [],
             defaultStationGroups: [],
-            saveDialogVisible: false,
+            //saveDialogVisible: false,
             defaultCellValues: {},
             showDefault: false,
-        }
+            confirmDialogVisible: false,
+            isDirty: false
+        };
+        this.showIcon = true;
+        this.dialogType = "confirmation";
+        this.dialogHeight = 'auto';
+        this.dialogHeader = "";
+        this.dialogMsg = "";
+        this.dialogContent = "";
+        this.applyToAllRow = false;
+        this.callBackFunction = "";
+        this.onClose = this.close;
+        this.onCancel =this.close;
+        this.applyToEmptyRowOnly = false;    // A SU Row not exists and the Name & Desc are empty
 
+        this.applyToAll =  this.applyToAll.bind(this);
+        this.applyToSelected =  this.applyToSelected.bind(this);
+        this.applyToEmptyRows =  this.applyToEmptyRows.bind(this);
+        this.resetCommonData = this.resetCommonData.bind(this);
+        this.reload = this.reload.bind(this);
+        this.applyChanges =  this.applyChanges.bind(this);
+        this.onTopGridReady = this.onTopGridReady.bind(this);
         this.onGridReady = this.onGridReady.bind(this);
         this.validateForm = this.validateForm.bind(this);
         this.validateEditor = this.validateEditor.bind(this);
         this.saveSchedulingUnit = this.saveSchedulingUnit.bind(this);
         this.cancelCreate = this.cancelCreate.bind(this);
+        this.checkIsDirty = this.checkIsDirty.bind(this);
         this.clipboardEvent = this.clipboardEvent.bind(this);
+        this.topAGGridEvent = this.topAGGridEvent.bind(this);
         this.reset = this.reset.bind(this);
         this.close = this.close.bind(this);
         this.saveSU = this.saveSU.bind(this);
@@ -140,6 +168,13 @@ export class SchedulingSetCreate extends Component {
         this.setDefaultCellValue = this.setDefaultCellValue.bind(this);
         this.copyHeader = this.copyHeader.bind(this);
         this.copyOnlyHeader = this.copyOnlyHeader.bind(this);
+        this.cellValueChageEvent = this.cellValueChageEvent.bind(this);
+        this.onProjectChange =  this.onProjectChange.bind(this);
+        this.showWarning = this.showWarning.bind(this);
+        this.onSchedulingSetChange = this.onSchedulingSetChange.bind(this);
+        this.onStrategyChange = this.onStrategyChange.bind(this);
+        this.refreshSchedulingSet = this.refreshSchedulingSet.bind(this);
+        this.showAddSchedulingSet = this.showAddSchedulingSet.bind(this);
 
         this.projects = [];                         // All projects to load project dropdown
         this.schedulingSets = [];                   // All scheduling sets to be filtered for project
@@ -151,7 +186,6 @@ export class SchedulingSetCreate extends Component {
             project: {required: true, message: "Select project to get Scheduling Sets"},
             scheduling_set_id: {required: true, message: "Select the Scheduling Set"},
         };
-        
     }
 
     componentDidMount() {
@@ -166,13 +200,45 @@ export class SchedulingSetCreate extends Component {
             this.taskTemplates = responses[3];
             if (this.state.schedulingUnit.project) {
                 const projectSchedluingSets = _.filter(this.schedulingSets, {'project_id': this.state.schedulingUnit.project});
-                this.setState({isLoading: false, schedulingSets: projectSchedluingSets});
+                this.setState({isLoading: false, schedulingSets: projectSchedluingSets, allSchedulingSets: this.schedulingSets});
             }   else {
                 this.setState({isLoading: false});
             }
         }); 
     }
     
+    /**
+     * Show warning messgae if any changes not saved when the AG grid reload or cancel the page
+     * @param {*} functionName 
+     */
+    showWarning (functionName) {
+        this.showIcon = true;
+        this.dialogType = "confirmation";
+        this.dialogHeader = "Add Multiple Scheduling Unit(s)";
+        this.dialogMsg = "Do you want to leave the changes? Your changes may not be saved.";
+        this.dialogContent = "";
+        this.callBackFunction = functionName;
+        this.onClose = this.close;
+        this.onCancel = this.close;
+        this.setState({
+            confirmDialogVisible: true,
+        });
+    }
+
+    /**
+     * Trigger when the project drop down get changed and check isDirty
+     * @param {*} projectName 
+     */
+    onProjectChange(projectName) {
+        if (this.state.isDirty) {
+            this.showWarning(() =>{
+                this. changeProject(projectName);
+            });
+        }   else {
+            this.changeProject(projectName);
+        }
+    }
+    
     /**
      * Function to call on change of project and reload scheduling set dropdown
      * @param {string} projectName 
@@ -181,17 +247,37 @@ export class SchedulingSetCreate extends Component {
         const projectSchedluingSets = _.filter(this.schedulingSets, {'project_id': projectName});
         let schedulingUnit = this.state.schedulingUnit;
         schedulingUnit.project = projectName;
-        this.setState({schedulingUnit: schedulingUnit, schedulingSets: projectSchedluingSets, validForm: this.validateForm('project'), rowData: [],observStrategy: {}, copyHeader: false});
+       /* this.setState({confirmDialogVisible: false, isDirty: false, schedulingUnit: schedulingUnit, 
+            schedulingSets: projectSchedluingSets, validForm: this.validateForm('project'), rowData: [], 
+            observStrategy: {}, copyHeader: false, isDirty: false}); */
+
+        const selectedProject = _.filter(this.projects, {'name': projectName});
+        this.setState({confirmDialogVisible: false, isDirty: false, selectedProject: selectedProject, schedulingUnit: schedulingUnit, 
+            schedulingSets: projectSchedluingSets, validForm: this.validateForm('project'), rowData: [],observStrategy: {}, copyHeader: false});
     }
  
+    /**
+     *  Trigger when the Scheduling Set drop down get changed and check isDirty
+     * @param {*} key 
+     * @param {*} value 
+     */
+    onSchedulingSetChange(key, value) {
+        if (this.state.isDirty) {
+            this.showWarning(() =>{
+                this.setSchedulingSetParams(key, value);
+            });
+        }   else {
+            this. setSchedulingSetParams(key, value);
+        }
+    }
+
     /**
      * Function to set form values to the SU object
      * @param {string} key 
      * @param {object} value 
      */
     async setSchedulingSetParams(key, value) {
-        this.setState({isAGLoading: true, copyHeader: false});
-
+        this.setState({isAGLoading: true, copyHeader: false, confirmDialogVisible: false, isDirty: false});
         let schedulingUnit = this.state.schedulingUnit;
         schedulingUnit[key] = value;
 
@@ -205,6 +291,7 @@ export class SchedulingSetCreate extends Component {
                     schedulingUnit: schedulingUnit, validForm: this.validateForm(key), validEditor: this.validateEditor(),
                     schedulingUnitList: schedulingUnitList, schedulingSetId: value, selectedSchedulingSetId: value, observStrategy: observStrategy,
                 });
+                this.isNewSet = false;
                 await this.prepareScheduleUnitListForGrid();
             }  else  { 
                 /* Let user to select Observation Strategy */
@@ -232,7 +319,7 @@ export class SchedulingSetCreate extends Component {
             await $RefParser.resolve(task);
             // Identify the task specification template of every task in the strategy template
             const taskTemplate = _.find(this.taskTemplates, {'name': task['specifications_template']});
-            if (taskTemplate.type_value==='observation' && task.specifications_doc.station_groups) {
+            if (taskTemplate.type_value === 'observation' && task.specifications_doc.station_groups) {
                 station_group = task.specifications_doc.station_groups;
             }
         }
@@ -240,20 +327,39 @@ export class SchedulingSetCreate extends Component {
             defaultStationGroups: station_group,
         })
     }
-    
-   
+
+    /**
+     *  Trigger when the Strategy drop down get changed and check isDirty
+     * @param {*} strategyId 
+     */
+    onStrategyChange(strategyId) {
+        if (this.state.isDirty) {
+            this.showWarning(() =>{
+                this.changeStrategy(strategyId);
+            });
+        }   else {
+            this. changeStrategy(strategyId);
+        }
+    }
 
     /**
      * Function called when observation strategy template is changed. 
      *
      * @param {number} strategyId 
      */
-    async changeStrategy (strategyId) {
-        await this.setState({isAGLoading: true, copyHeader: false, rowData: []});
+    async changeStrategy(strategyId) {
+        await this.setState({noOfSU: 10, isAGLoading: true, copyHeader: false, rowData: [], confirmDialogVisible: false, isDirty: false});
         const observStrategy = _.find(this.observStrategies, {'id': strategyId});
         let schedulingUnitList= await ScheduleService.getSchedulingBySet(this.state.selectedSchedulingSetId);
         schedulingUnitList = _.filter(schedulingUnitList,{'observation_strategy_template_id': strategyId}) ;
         this.setDefaultStationGroup(observStrategy);
+        if(schedulingUnitList.length === 0) {
+            schedulingUnitList = await this.getEmptySchedulingUnit(strategyId);
+            this.isNewSet = true;
+        }
+        else {
+            this.isNewSet = false;
+        }
         await this.setState({
             schedulingUnitList: schedulingUnitList,
             observStrategy: observStrategy,
@@ -266,9 +372,14 @@ export class SchedulingSetCreate extends Component {
                 rowData: []
             });
         }
-        this.setState({isAGLoading: false});
+        this.setState({isAGLoading: false,commonRowData: []});
     }
    
+    async getEmptySchedulingUnit(strategyId){
+        let suList = await ScheduleService.getSchedulingUnitDraft();
+        return [_.find(suList.data.results, {'observation_strategy_template_id': strategyId})];       
+    }
+
     /**
      * Resolve JSON Schema
      */
@@ -325,34 +436,10 @@ export class SchedulingSetCreate extends Component {
     }
    
     /**
-     * Function to generate AG-Grid column definition. 
-     * @param {number} strategyId 
+     * Create AG Grid column properties
      */
-    async createGridColumns(scheduleUnit){
-        let defaultCellValues = {};
-        let schema = await this.getTaskSchema(scheduleUnit, false);
-        schema = await this.resolveSchema(schema);
-        let constraintSchema =  await this.getConstraintSchema(scheduleUnit);
-        constraintSchema = await this.resolveSchema(constraintSchema);
-
-        // AG Grid Cell Specific Properties
-        let dailyOption= [];
-        let dailyProps = Object.keys( constraintSchema.schema.properties.daily.properties); 
-        this.daily = [];
-        dailyProps.forEach(prop => {
-            dailyOption.push({'Name':prop, 'Code':prop});
-            this.daily.push(prop);
-        }) 
-
-        this.setState({
-            dailyOption: this.dailyOption,
-            schedulingConstraintsDoc: scheduleUnit.scheduling_constraints_doc,
-            constraintUrl: scheduleUnit.scheduling_constraints_template,
-            constraintId: scheduleUnit.scheduling_constraints_template_id,
-            daily: this.daily,
-        });
-
-        let cellProps =[];
+    createAGGridAngelColumnsProperty(schema) {
+        let cellProps = [];
         cellProps['angle1'] = {isgroup: true, type:'numberValueColumn', cellRenderer: 'timeInputMask',cellEditor: 'timeInputMask', valueSetter: 'valueSetter', cellStyle: function(params) {
             if (params.value && !Validator.validateTime(params.value)) {     
                 return { backgroundColor: BG_COLOR};
@@ -368,21 +455,20 @@ export class SchedulingSetCreate extends Component {
             }
             }, };
         cellProps['angle3'] = {isgroup: true, cellStyle: function(params) { if (params.value){
-            if (!Number(params.value)) {
+            if (!params.colDef.field.startsWith('gdef') && !Number(params.value)) {
 				return { backgroundColor: BG_COLOR};
 			} 
             else{
 				return { backgroundColor: ''};
 			}
 		} else {
-            return { backgroundColor: BG_COLOR};
+            return  (!params.colDef.field.startsWith('gdef')) ?{ backgroundColor: BG_COLOR} : { backgroundColor: ''}
         }}}; 
         cellProps['direction_type'] = {isgroup: true, cellEditor: 'agSelectCellEditor',default: schema.definitions.pointing.properties.direction_type.default,
             cellEditorParams: {
                 values: schema.definitions.pointing.properties.direction_type.enum,
             }, 
         };
-       
         cellProps['duration'] = { type:'numberValueColumn', cellStyle: function(params) {
             if  (params.value){
                 if ( !Number(params.value)){
@@ -396,13 +482,41 @@ export class SchedulingSetCreate extends Component {
             }
         }, };
 
+        return cellProps;
+    }
+
+    /**
+     * Function to generate AG-Grid column definition. 
+     * @param {number} strategyId 
+     */
+    async createGridColumns(scheduleUnit){
+        let defaultCellValues = {};
+        let schema = await this.getTaskSchema(scheduleUnit, false);
+        schema = await this.resolveSchema(schema);
+        let constraintSchema =  await this.getConstraintSchema(scheduleUnit);
+        constraintSchema = await this.resolveSchema(constraintSchema);
+        // AG Grid Cell Specific Properties
+        let dailyProps = Object.keys( constraintSchema.schema.properties.daily.properties); 
+        this.daily = [];
+        this.dailyOption = [];
+        dailyProps.forEach(prop => {
+            this.dailyOption.push({'name':prop, 'value':prop});
+            this.daily.push(prop);
+        }) 
+        this.setState({
+            dailyOption: this.dailyOption,
+            schedulingConstraintsDoc: scheduleUnit.scheduling_constraints_doc,
+            constraintUrl: scheduleUnit.scheduling_constraints_template,
+            constraintId: scheduleUnit.scheduling_constraints_template_id,
+            daily: this.daily,
+        });
+
+        let cellProps = this.createAGGridAngelColumnsProperty(schema);
         //Ag-grid Colums definition
         // Column order to use clipboard copy
         let colKeyOrder = [];
-        
         colKeyOrder.push("suname");
         colKeyOrder.push("sudesc");
-
         let columnMap = [];
         let colProperty = {};
         let columnDefs = [
@@ -572,7 +686,6 @@ export class SchedulingSetCreate extends Component {
         colKeyOrder.push('md_sun');
         colKeyOrder.push('md_moon');
         colKeyOrder.push('md_jupiter');
-
         defaultCellValues['scheduler'] = constraintSchema.schema.properties.scheduler.default;
         defaultCellValues['min_target_elevation'] = constraintSchema.schema.properties.sky.properties.min_target_elevation.default;
         defaultCellValues['min_calibrator_elevation'] = constraintSchema.schema.properties.sky.properties.min_calibrator_elevation.default;
@@ -589,7 +702,7 @@ export class SchedulingSetCreate extends Component {
             })
             defaultCellValues['stations'] = stationValue;
         }
-        colProperty ={'ID':'id', 'Name':'suname', 'Description':'sudesc'};
+        colProperty = {'ID':'id', 'Name':'suname', 'Description':'sudesc'};
         columnMap['Scheduling Unit'] = colProperty;
         
         let defaultSchema = await this.getTaskTemplateSchema(scheduleUnit, 'Target Observation');
@@ -648,12 +761,56 @@ export class SchedulingSetCreate extends Component {
         }
         columnDefs.push({headerName: 'Stations', field: 'stations', cellRenderer: 'betweenRenderer', cellEditor: 'station', valueSetter: 'newValueSetter'});
         colKeyOrder.push('stations');
+        let globalColmunDef =_.cloneDeep(columnDefs);
+        globalColmunDef = await this.createGlobalColumnDefs(globalColmunDef, schema, constraintSchema);
+
         this.setState({
-            columnDefs:columnDefs,
-            columnMap:columnMap,
-            colKeyOrder:colKeyOrder,
+            columnDefs: columnDefs,
+            globalColmunDef: globalColmunDef,
+            columnMap: columnMap,
+            colKeyOrder: colKeyOrder,
             defaultCellValues: defaultCellValues,
-        })
+        });
+    }
+
+    /**
+     * Create AG Grid column definition
+     * @param {*} globalColmunDef 
+     * @param {*} schema 
+     * @param {*} constraintSchema 
+     */
+    createGlobalColumnDefs(globalColmunDef, schema, constraintSchema) {
+        let schedulerValues = [...' ', ...constraintSchema.schema.properties.scheduler.enum];
+        let direction_type_Values =  [...' ', ...schema.definitions.pointing.properties.direction_type.enum];
+        globalColmunDef.forEach(colDef => {
+            if (colDef.children) {
+                colDef.children.forEach(childColDef => {
+                    if (childColDef.field) {
+                        if(childColDef.field.endsWith('direction_type')) {
+                            childColDef.cellEditorParams.values = direction_type_Values;
+                        }
+                        childColDef.field = 'gdef_'+childColDef.field;
+                        if (childColDef.default) {
+                            childColDef.default = '';
+                        }
+                    }
+                });
+            }   else {
+                    if(colDef.headerName === '#') {
+                        colDef['hide'] = true;
+                    }
+                    if(colDef.field) {
+                        if ( colDef.field.endsWith('scheduler')) {
+                            colDef.cellEditorParams.values = schedulerValues;
+                        }
+                        colDef.field = 'gdef_'+colDef.field;
+                        if (colDef.default) {
+                            colDef.default = '';
+                        }
+                    }
+                }
+        });
+       return globalColmunDef;
     }
 
     async getTaskTemplateSchema(scheduleUnit, taskName) {
@@ -678,7 +835,6 @@ export class SchedulingSetCreate extends Component {
                 let index = 0;
                 for (const param of observStrategy.template.parameters) {
                     if (param.refs[0].indexOf(`/tasks/${taskName}`) > 0) {
-                        // tasksToUpdate[taskName] = taskName;
                         // Resolve the identified template
                         const $templateRefs = await $RefParser.resolve(taskTemplate);
                         let property = { };
@@ -720,9 +876,9 @@ export class SchedulingSetCreate extends Component {
         let schema = { type: 'object', additionalProperties: false, 
                         properties: {}, definitions:{}
                      };
-        let taskDrafts= [];
+        let taskDrafts = [];
         await ScheduleService.getTasksDraftBySchedulingUnitId(scheduleUnit.id).then(response =>{
-            taskDrafts= response.data.results;
+            taskDrafts = response.data.results;
         }); 
         
         for (const taskName in tasks)  {
@@ -769,7 +925,7 @@ export class SchedulingSetCreate extends Component {
                 }
                 index++;
             }
-            if (taskTemplate.type_value==='observation' && task.specifications_doc.station_groups) {
+            if (taskTemplate.type_value === 'observation' && task.specifications_doc.station_groups) {
                 tasksToUpdate[taskName] = taskName;
             }
             this.setState({ paramsOutput: paramsOutput, tasksToUpdate: tasksToUpdate});
@@ -777,44 +933,83 @@ export class SchedulingSetCreate extends Component {
         return schema;
     }
 
-
     /**
      * CallBack Function : update time value in master grid
      */
     async updateTime(rowIndex, field, value) {
-        let row = this.state.rowData[rowIndex];
-        row[field] = value;
-        let tmpRowData =this.state.rowData;
-        tmpRowData[rowIndex]= row;
-        await this.setState({
-           rowData: tmpRowData
-        });
-        this.state.gridApi.setRowData(this.state.rowData);
-        this.state.gridApi.redrawRows();
-      }
-
-      /**
-       * Update the Daily/Station column value from external component
-       * @param {*} rowIndex 
-       * @param {*} field 
-       * @param {*} value 
-       */
+        let row = {};
+        let tmpRowData = [];
+        if ( field.startsWith('gdef_')) {
+            row = this.state.commonRowData[0];
+            row[field] = value;
+            tmpRowData =this.state.commonRowData;
+            tmpRowData[0] = row;
+            await this.setState({
+                commonRowData: tmpRowData
+             });
+             this.state.topGridApi.setRowData(this.state.commonRowData);
+             this.state.topGridApi.redrawRows();
+        }
+        else {
+            row = this.state.rowData[rowIndex];
+            row[field] = value;
+            tmpRowData = this.state.rowData;
+            tmpRowData[rowIndex] = row;
+            await this.setState({
+                rowData: tmpRowData,
+                isDirty: true
+             });
+             this.state.gridApi.setRowData(this.state.rowData);
+             this.state.gridApi.redrawRows();
+        }
+    }
+
+    /**
+     * Update the Daily/Station column value from external component
+     * @param {*} rowIndex 
+     * @param {*} field 
+     * @param {*} value 
+     */
     async updateCell(rowIndex, field, value) {
-        let row = this.state.rowData[rowIndex];
-        row[field] = value;
-        let tmpRowData =this.state.rowData;
-        tmpRowData[rowIndex]= row;
-        await this.setState({
-           rowData: tmpRowData
-        });
-        if(field !== 'daily') {
-            this.state.gridApi.stopEditing();
-            var focusedCell = this.state.gridColumnApi.getColumn(field)
-            this.state.gridApi.ensureColumnVisible(focusedCell);
-            this.state.gridApi.setFocusedCell(rowIndex, focusedCell);
+        let row = {};
+        let tmpRowData = [];
+        if ( field.startsWith('gdef_')) {
+            row = this.state.commonRowData[0];
+            row[field] = value;
+            tmpRowData = this.state.commonRowData;
+            tmpRowData[0] = row;
+            await this.setState({
+                commonRowData: tmpRowData
+             });
+             if(field !== 'gdef_daily') {
+                this.state.topGridApi.stopEditing();
+                var focusedCell = this.state.topGridColumnApi.getColumn(field)
+                this.state.topGridApi.ensureColumnVisible(focusedCell);
+                this.state.topGridApi.setFocusedCell(rowIndex, focusedCell);
+            }
+        }
+        else {
+            row = this.state.rowData[rowIndex];
+            row[field] = value;
+            tmpRowData = this.state.rowData;
+            tmpRowData[rowIndex] = row;
+            await this.setState({
+                rowData: tmpRowData,
+                isDirty: true
+             });
+             if(field !== 'daily') {
+                this.state.gridApi.stopEditing();
+                var focusedCell = this.state.gridColumnApi.getColumn(field)
+                this.state.gridApi.ensureColumnVisible(focusedCell);
+                this.state.gridApi.setFocusedCell(rowIndex, focusedCell);
+            }
         }
     }
  
+    /**
+     * Get Station details
+     * @param {*} schedulingUnit 
+     */
     async getStationGrops(schedulingUnit){
         let stationValue = '';
         if (schedulingUnit && schedulingUnit.id>0) {
@@ -907,11 +1102,13 @@ export class SchedulingSetCreate extends Component {
      * Function to prepare ag-grid row data. 
      */
     async prepareScheduleUnitListForGrid(){
-        if (this.state.schedulingUnitList.length===0) {
+        if (this.state.schedulingUnitList.length === 0) {
             return;
         }
         this.tmpRowData = [];
         let totalSU = this.state.noOfSU;
+        let lastRow = {};
+        let hasSameValue = true;
         //refresh column header
         await this.createGridColumns(this.state.schedulingUnitList[0]);
         let observationPropsList = [];
@@ -985,6 +1182,7 @@ export class SchedulingSetCreate extends Component {
                 }
                
                 observationProps['daily'] = this.fetchDailyFieldValue(constraint.daily);
+                //console.log("SU id:", scheduleunit.id, "Connstraint:", constraint.sky);
                 UnitConversion.radiansToDegree(constraint.sky);
                 observationProps['min_target_elevation'] = constraint.sky.min_target_elevation;
                 observationProps['min_calibrator_elevation'] = constraint.sky.min_calibrator_elevation;
@@ -1000,41 +1198,65 @@ export class SchedulingSetCreate extends Component {
                }
             }
             observationPropsList.push(observationProps);
+            //Set values for global row if all rows has same value
+            if (_.isEmpty(lastRow)) {
+                lastRow = observationProps;
+            }
+            else if (!_.isEqual(
+                    _.omit(lastRow, ['id']),
+                    _.omit(observationProps, ['id'])
+                  ))  {
+                hasSameValue = false;
+            }
+           
+        }
+        let defaultCommonRowData = {};
+        if (hasSameValue) {
+            defaultCommonRowData = observationPropsList[observationPropsList.length-1];
         }
-         
         this.tmpRowData = observationPropsList;
         // find No. of rows filled in array
         let totalCount = this.tmpRowData.length;
          // Prepare No. Of SU for rows for UI
-        if  (this.tmpRowData && this.tmpRowData.length>0){
+        if  (this.tmpRowData && this.tmpRowData.length > 0){
             const paramsOutputKey = Object.keys( this.tmpRowData[0]);
-            const availableCount = this.tmpRowData.length;
+            let availableCount = this.tmpRowData.length;
+            if(this.isNewSet) {
+                availableCount = 0;
+                this.tmpRowData = [];
+            } 
             if  (availableCount >= totalSU){
-                totalSU = availableCount+5;
+                totalSU = availableCount+1;
             }
             for(var i = availableCount; i<totalSU; i++){
                 let emptyRow =  {};
                 paramsOutputKey.forEach(key =>{
                     if  (key === 'id'){
-                        emptyRow[key]= 0;
+                        emptyRow[key] = 0;
                     }  else  {
-                        emptyRow[key]= '';
+                        emptyRow[key] = '';
                     }
                 })
                 this.tmpRowData.push(emptyRow);
             } 
         }
+        if(this.isNewSet) {
+            defaultCommonRowData = this.tmpRowData[this.tmpRowData.length-1];
+        }
         this.setState({
             rowData: this.tmpRowData,
             totalCount: totalCount,
-            noOfSU: totalSU,
+            noOfSU: this.tmpRowData.length,
             emptyRow: this.tmpRowData[this.tmpRowData.length-1],
-            isAGLoading: false
+            isAGLoading: false,
+            commonRowData: [defaultCommonRowData],
+            defaultCommonRowData: defaultCommonRowData,
+            hasSameValue: hasSameValue
         });
-
+        
         this.setDefaultCellValue();
     }
- 
+    
     /**
      * Get Daily column value 
      * @param {*} daily 
@@ -1059,17 +1281,32 @@ export class SchedulingSetCreate extends Component {
      * @param {Stirng} cell -> contains Row ID, Column Name, Value, isDegree
      */
     async updateAngle(rowIndex, field, value, isDegree, isValid){
-        let row = this.state.rowData[rowIndex];
-        row[field] = value;
-        row['isValid'] = isValid;
-        //Convertverted value for Angle 1 & 2, set in SU Row 
-        row[field+'value'] = UnitConverter.getAngleOutput(value,isDegree);
-        let tmpRowData =this.state.rowData;
-        tmpRowData[rowIndex]= row;
-        await this.setState({
-           rowData: tmpRowData
-        });
-      }
+        let row = {};
+        let tmpRowData = [];
+        if ( field.startsWith('gdef_')) {
+            row = this.state.commonRowData[0];
+            row[field] = value;
+            row['isValid'] = isValid;
+            row[field+'value'] = UnitConverter.getAngleOutput(value,isDegree);
+            tmpRowData = this.state.commonRowData;
+            tmpRowData[0] = row;
+            await this.setState({
+                commonRowData: tmpRowData
+             });
+        }
+        else {
+            row = this.state.rowData[rowIndex];
+            row[field] = value;
+            row['isValid'] = isValid;
+            row[field+'value'] = UnitConverter.getAngleOutput(value,isDegree);
+            tmpRowData = this.state.rowData;
+            tmpRowData[rowIndex] = row;
+            await this.setState({
+                rowData: tmpRowData,
+                isDirty: true
+             });
+        }
+    }
     
     /**
      * Read Data from clipboard
@@ -1085,128 +1322,140 @@ export class SchedulingSetCreate extends Component {
         }
     }  
 
-      /**
-     * Copy data to/from clipboard
-     * @param {*} e 
-     */
-    async clipboardEvent(e){
+    async topAGGridEvent(e) {
         var key = e.which || e.keyCode;
         var ctrl = e.ctrlKey ? e.ctrlKey : ((key === 17) ? true : false);
-        if ( key === 67 && ctrl ) {
-            //Ctrl+C
-            var columnsName = this.state.gridColumnApi.getAllGridColumns();
-            var selectedRows = this.state.gridApi.getSelectedRows();
-            let clipboardData = '';
-            if ( this.state.copyHeader ) {
-                var line = '';
-                columnsName.map( column => {
-                    if ( column.colId !== '0'){
-                        line += column.colDef.headerName + '\t';
-                    }
-                })
-                line = _.trim(line);
-                clipboardData += line + '\r\n'; 
-               // this.setState({copyHeader: false});
-            }
-            for(const rowData of selectedRows){
-                var line = '';
-                for(const key of this.state.colKeyOrder){
-                    line += rowData[key] + '\t';
-                }
-                line = _.trim(line);
-                clipboardData += line + '\r\n'; 
-            }
-            clipboardData = _.trim(clipboardData);
-            
-            const queryOpts = { name: 'clipboard-write', allowWithoutGesture: true };
-            await navigator.permissions.query(queryOpts);
-            await navigator.clipboard.writeText(clipboardData);
-        } 
-        else if ( key === 86 && ctrl ) {
-            // Ctrl+V
-            try {
-                var selectedRows = this.state.gridApi.getSelectedNodes();
-                this.tmpRowData = this.state.rowData;
-                let dataRowCount = this.state.totalCount;
-                //Read Clipboard Data
-                let clipboardData = await this.readClipBoard();
-                let selectedRowIndex = 0;
-                if  (selectedRows){
-                    await selectedRows.map(selectedRow =>{
-                        selectedRowIndex = selectedRow.rowIndex;
-                        if  (clipboardData){
-                            clipboardData = _.trim(clipboardData);
-                            let suGridRowData= this.state.emptyRow;
-                            clipboardData = _.trim(clipboardData);
-                            let suRows = clipboardData.split("\n");
-                            suRows.forEach(line =>{
-                                suGridRowData ={};
-                                suGridRowData['id']= 0;
-                                suGridRowData['isValid']= true;
-
-                                if ( this.tmpRowData.length <= selectedRowIndex ) {
-                                    this.tmpRowData.push(this.state.emptyRow);
-                                }
-                                
-                                let colCount = 0;
-                                let suRow = line.split("\t");
-                                for(const key of this.state.colKeyOrder){
-                                    suGridRowData[key]= suRow[colCount];
-                                    colCount++;
-                                }
-                                if (this.tmpRowData[selectedRowIndex].id > 0 ) {
-                                    suGridRowData['id'] = this.tmpRowData[selectedRowIndex].id;
-                                }
-                                this.tmpRowData[selectedRowIndex]= (suGridRowData);
-                                selectedRowIndex++
-                            }) 
-                        }
-                    });
-                    dataRowCount = selectedRowIndex;
-                    let emptyRow = this.state.emptyRow;
-                    let tmpNoOfSU= this.state.noOfSU;
-                    if  (dataRowCount >= tmpNoOfSU){
-                        tmpNoOfSU = dataRowCount;
-                        //Create additional empty row at the end
-                        for(let i= this.tmpRowData.length; i<=tmpNoOfSU; i++){
-                            this.tmpRowData.push(emptyRow);
-                        }
-                    }
-                    await this.setState({
-                        rowData: this.tmpRowData,
-                        noOfSU: this.tmpRowData.length,
-                        totalCount: dataRowCount,
-                    })
-                    this.state.gridApi.setRowData(this.state.rowData);
-                    this.state.gridApi.redrawRows();
+        if ( ctrl && (key === 67 || key === 86)) {
+            this.showIcon = true;
+            this.dialogType = "warning";
+            this.dialogHeader = "Warning";
+            this.dialogMsg = "Copy / Paste is restricted in this grid";
+            this.dialogContent = "";
+            this.callBackFunction = this.close;
+            this.onClose = this.close;
+            this.onCancel = this.close;
+            this.setState({
+                confirmDialogVisible: true,
+            });
+        }
+    }
+
+    /**
+     * Function to copy the data to clipboard
+     */
+    async copyToClipboard(){
+        var columnsName = this.state.gridColumnApi.getAllGridColumns();
+        var selectedRows = this.state.gridApi.getSelectedRows();
+        let clipboardData = '';
+        if ( this.state.copyHeader ) {
+            var line = '';
+            columnsName.map( column => {
+                if ( column.colId !== '0'){
+                    line += column.colDef.headerName + '\t';
                 }
+            })
+            line = _.trim(line);
+            clipboardData += line + '\r\n'; 
+        }
+        for(const rowData of selectedRows){
+            var line = '';
+            for(const key of this.state.colKeyOrder){
+                line += rowData[key] + '\t';
             }
-            catch (err) {
-                console.error('Error: ', err);
-            }
+            line = _.trim(line);
+            clipboardData += line + '\r\n'; 
         }
+        clipboardData = _.trim(clipboardData);
+        
+        const queryOpts = { name: 'clipboard-write', allowWithoutGesture: true };
+        await navigator.permissions.query(queryOpts);
+        await navigator.clipboard.writeText(clipboardData);
+        const headerText = (this.state.copyHeader) ?'with Header' : '';
+        this.growl.show({severity: 'success', summary: '', detail: selectedRows.length+' row(s) copied to clipboard '+headerText });
+    }
 
-        //>>>>>> Resolved Conflicts by Ramesh. Remove or update this block as applicable.
-        /*else if ( key  === 46){
-            this.growl.show({severity: 'success', summary: '', detail: selectedRows.length+' row(s) copied to clipboard '});
-        } 
-       /* else if ( key  === 46){
-            // Delete selected rows
-            let tmpRowData = this.state.rowData;
-          
+    /**
+     * Function to copy the data from clipboard
+     */
+    async copyFromClipboard(){
+        try {
             var selectedRows = this.state.gridApi.getSelectedNodes();
+            this.tmpRowData = this.state.rowData;
+            let dataRowCount = this.state.totalCount;
+            //Read Clipboard Data
+            let clipboardData = await this.readClipBoard();
+            let selectedRowIndex = 0;
             if  (selectedRows){
-               await selectedRows.map(delRow =>{
-                    delete tmpRowData[delRow.rowIndex]
+                await selectedRows.map(selectedRow =>{
+                    selectedRowIndex = selectedRow.rowIndex;
+                    if  (clipboardData){
+                        clipboardData = _.trim(clipboardData);
+                        let suGridRowData = this.state.emptyRow;
+                        clipboardData = _.trim(clipboardData);
+                        let suRows = clipboardData.split("\n");
+                        suRows.forEach(line => {
+                            suGridRowData = {};
+                            suGridRowData['id'] = 0;
+                            suGridRowData['isValid'] = true;
+
+                            if ( this.tmpRowData.length <= selectedRowIndex ) {
+                                this.tmpRowData.push(this.state.emptyRow);
+                            }
+                            
+                            let colCount = 0;
+                            let suRow = line.split("\t");
+                            for(const key of this.state.colKeyOrder){
+                                suGridRowData[key] = suRow[colCount];
+                                colCount++;
+                            }
+                            if (this.tmpRowData[selectedRowIndex].id > 0 ) {
+                                suGridRowData['id'] = this.tmpRowData[selectedRowIndex].id;
+                            }
+                            this.tmpRowData[selectedRowIndex] = (suGridRowData);
+                            selectedRowIndex++
+                        }) 
+                    }
                 });
+                dataRowCount = selectedRowIndex;
+                let emptyRow = this.state.emptyRow;
+                let tmpNoOfSU = this.state.noOfSU;
+                if  (dataRowCount >= tmpNoOfSU){
+                    tmpNoOfSU = dataRowCount;
+                    //Create additional empty row at the end
+                    for(let i= this.tmpRowData.length; i<= tmpNoOfSU; i++){
+                        this.tmpRowData.push(emptyRow);
+                    }
+                }
                 await this.setState({
-                    rowData: tmpRowData
-                 });
-                 this.state.gridApi.setRowData(this.state.rowData);
+                    rowData: this.tmpRowData,
+                    noOfSU: this.tmpRowData.length,
+                    totalCount: dataRowCount,
+                    isDirty: true
+                })
+                this.state.gridApi.setRowData(this.state.rowData);
                 this.state.gridApi.redrawRows();
             }
         }
-        } *///<<<<<< Resolved Conflicts
+        catch (err) {
+            console.error('Error: ', err);
+        }
+    }
+    
+    /**
+     * Copy data to/from clipboard
+     * @param {*} e 
+     */
+    async clipboardEvent(e){
+        var key = e.which || e.keyCode;
+        var ctrl = e.ctrlKey ? e.ctrlKey : ((key === 17) ? true : false);
+        if ( key === 67 && ctrl ) {
+            //Ctrl+C
+            this.copyToClipboard();
+        } 
+        else if ( key === 86 && ctrl ) {
+            // Ctrl+V
+            this.copyFromClipboard();
+        }
     }
  
     /**
@@ -1234,6 +1483,7 @@ export class SchedulingSetCreate extends Component {
             this.growl.show({severity: 'success', summary: '', detail: 'Header copied to clipboard '});
         }
     }
+
     /**
      * Set state to copy the table header to clipboard
      * @param {*} value 
@@ -1259,14 +1509,17 @@ export class SchedulingSetCreate extends Component {
             tmpMandatoryKeys = [];
             const rowData = node.data;
             let isManualScheduler = false;
+            let hasData = true;
             if  (rowData) {
                 for(const key of mandatoryKeys) {
                     if  (rowData[key] === '') {
                         if ( key === 'suname' ){
                             if( rowData['sudesc'] !== ''){
                                 tmpMandatoryKeys.push(key);
+                            }   else {
+                                hasData = false;
                             }
-                        } else if ( key === 'sudesc' ){
+                        }   else if ( key === 'sudesc' ){
                             if( rowData['suname'] !== ''){
                                 tmpMandatoryKeys.push(key);
                             }
@@ -1340,7 +1593,7 @@ export class SchedulingSetCreate extends Component {
                                 } else if(_.endsWith(column.colId, "stations")){
                                     let sgCellValue = rowData[column.colId];
                                     let stationGroups = _.split(sgCellValue,  "|");
-                                    stationGroups.map(stationGroup =>{
+                                    stationGroups.map(stationGroup => {
                                         let sgValue = _.split(stationGroup, ":");
                                         if (rowData['suname'] !== '' && rowData['sudesc'] !== '' && (sgValue[1] === 'undefined' || sgValue[1] === 'NaN' || Number(sgValue[1]) < 0 )){
                                             isValidRow = false;
@@ -1353,31 +1606,55 @@ export class SchedulingSetCreate extends Component {
                     }
                 }
             }
-            if (isValidRow)  {
-                validCount++; 
-                tmpRowData[node.rowIndex]['isValid'] = true;
-            } else {
-                inValidCount++;
-                tmpRowData[node.rowIndex]['isValid'] = false;
-                errorDisplay.push(errorMsg.slice(0, -2));
-            }
+            if(hasData) {
+                if (isValidRow)  {
+                    validCount++; 
+                    tmpRowData[node.rowIndex]['isValid'] = true;
+                } else {
+                    inValidCount++;
+                    tmpRowData[node.rowIndex]['isValid'] = false;
+                    errorDisplay.push(errorMsg.slice(0, -2));
+                }
+            }   
         });
-
         
         if (validCount > 0 && inValidCount === 0) {
             // save SU directly
             this.saveSU();
         } else if (validCount === 0 && inValidCount === 0) {
             // leave with no change
+            this.showIcon = true;
+            this.dialogMsg = 'No valid Scheduling Unit found !';
+            this.dialogType = 'warning';
+            this.onClose = () => {
+                this.setState({confirmDialogVisible: false});
+            };
+            this.setState({
+                confirmDialogVisible: true, 
+            });
+            
         }  else  {
             this.setState({
                 validCount: validCount,
                 inValidCount: inValidCount,
                 tmpRowData: tmpRowData,
-                saveDialogVisible: true,
+                //saveDialogVisible: true,
                 errorDisplay: errorDisplay,
+                confirmDialogVisible: true,
             });
+            this.callBackFunction = this.saveSU;
             this.state.gridApi.redrawRows();
+            this.showIcon = true;
+            this.onCancel = () => {
+                this.setState({confirmDialogVisible: false});
+            };
+            this.onClose = () => {
+                this.setState({confirmDialogVisible: false});
+            };
+            this.dialogType = "confirmation";
+            this.dialogHeader = "Save Scheduling Unit(s)";
+            this.dialogMsg = "Some of the Scheduling Unit(s) has invalid data, Do you want to ignore and save valid Scheduling Unit(s) only?";
+            this.dialogContent = this.showDialogContent;
         }
     }
 
@@ -1397,7 +1674,8 @@ export class SchedulingSetCreate extends Component {
         let existingSUCount = 0;
         try{
             this.setState({
-                saveDialogVisible: false,
+               // saveDialogVisible: false,
+                confirmDialogVisible: false,
                 showSpinner: true
             })
          
@@ -1416,7 +1694,7 @@ export class SchedulingSetCreate extends Component {
                     let paramOutput = {};
                     let result = columnMap[parameter.name];
                     let resultKeys =  Object.keys(result);
-                    resultKeys.forEach(key =>{
+                    resultKeys.forEach(key => {
                         if  (key === 'angle1') {
                             if  (!Validator.validateTime(suRow[result[key]])) {
                                 validRow = false;
@@ -1457,7 +1735,6 @@ export class SchedulingSetCreate extends Component {
                     tmpStationGroup['max_nr_missing'] = Number(sgValue[1]);
                     tmpStationGroups.push(tmpStationGroup);
                     }
-                      
                 })
                      
                 let observStrategy = _.cloneDeep(this.state.observStrategy);
@@ -1496,23 +1773,23 @@ export class SchedulingSetCreate extends Component {
                 //If No SU Constraint create default ( maintain default struc)
                 constraint['scheduler'] = suRow.scheduler;
                 if  (suRow.scheduler === 'dynamic'  || suRow.scheduler === 'online'){
-                    if (!this.isNotEmpty(suRow.timeat)) {
-                        delete constraint.time.timeat;
-                    } else {
+                    if (this.isNotEmpty(suRow.timeat)) {
+                        delete constraint.time.at;
+                    }   /*else {
                         constraint.time.at = `${moment(suRow.timeat).format("YYYY-MM-DDTHH:mm:ss.SSSSS", { trim: false })}Z`;
-                    }
+                    }*/
                   
                     if (!this.isNotEmpty(suRow.timeafter)) {
                         delete constraint.time.after;
-                    } else {
+                    }   /*else {
                         constraint.time.after = `${moment(suRow.timeafter).format("YYYY-MM-DDTHH:mm:ss.SSSSS", { trim: false })}Z`;
-                    }
+                    }*/
                    
                     if (!this.isNotEmpty(suRow.timebefore)) {
                         delete constraint.time.before;
-                    } else {
+                    }   /*else {
                         constraint.time.before = `${moment(suRow.timebefore).format("YYYY-MM-DDTHH:mm:ss.SSSSS", { trim: false })}Z`;
-                    }
+                    }*/
                 }  
                 else  {
                     //mandatory
@@ -1538,7 +1815,7 @@ export class SchedulingSetCreate extends Component {
                     constraint.time.not_between = notbetween; 
                 }
                 let dailyValueSelected = _.split(suRow.daily, ",");
-                this.state.daily.forEach(daily =>{
+                this.state.daily.forEach(daily => {
                     if  (_.includes(dailyValueSelected, daily)){
                         constraint.daily[daily] = true;
                     }  else  {
@@ -1598,10 +1875,20 @@ export class SchedulingSetCreate extends Component {
                 }
             }
             
-            if  ((newSUCount+existingSUCount)>0){
-                const dialog = {header: 'Success', detail: '['+newSUCount+'] Scheduling Units are created & ['+existingSUCount+'] Scheduling Units are updated successfully.'};
-                this.setState({  showSpinner: false, dialogVisible: true, dialog: dialog, isAGLoading: true, copyHeader: false, rowData: []});
+            if  ((newSUCount+existingSUCount) > 0){
+                //const dialog = {header: 'Success', detail: '['+newSUCount+'] Scheduling Units are created & ['+existingSUCount+'] Scheduling Units are updated successfully.'};
+                // this.setState({  showSpinner: false, dialogVisible: true, dialog: dialog, isAGLoading: true, copyHeader: false, rowData: []});
+                this.dialogType = "success";
+                this.dialogHeader = "Success";
+                this.showIcon = true;
+                this.dialogMsg = '['+newSUCount+'] Scheduling Units are created & ['+existingSUCount+'] Scheduling Units are updated successfully.';
+                this.dialogContent = "";
+                this.onCancel = this.close;
+                this.onClose = this.close;
+                this.callBackFunction = this.reset;
+                this.setState({isDirty : false, showSpinner: false, confirmDialogVisible: true, /*dialog: dialog,*/ isAGLoading: true, copyHeader: false, rowData: []});
             }  else  {
+                this.setState({isDirty: false, showSpinner: false,});
                 this.growl.show({severity: 'error', summary: 'Warning', detail: 'No Scheduling Units create/update '});
             }
         }catch(err){
@@ -1628,9 +1915,9 @@ export class SchedulingSetCreate extends Component {
     getBetweenStringValue(dates){
         let returnDate = '';
         if  (dates){
-            dates.forEach(utcDateArray =>{
-                returnDate +=moment.utc(utcDateArray.from).format(DATE_TIME_FORMAT)+",";
-                returnDate +=moment.utc(utcDateArray.to).format(DATE_TIME_FORMAT)+"|";
+            dates.forEach(utcDateArray => {
+                returnDate += moment.utc(utcDateArray.from).format(DATE_TIME_FORMAT)+",";
+                returnDate += moment.utc(utcDateArray.to).format(DATE_TIME_FORMAT)+"|";
             })
         }
        return returnDate;
@@ -1656,17 +1943,18 @@ export class SchedulingSetCreate extends Component {
         return returnDate;      
     }
 
-
     /**
      * Refresh the grid with updated data
      */
     async reset() {
-        let schedulingUnitList= await ScheduleService.getSchedulingBySet(this.state.selectedSchedulingSetId);
+        let schedulingUnitList = await ScheduleService.getSchedulingBySet(this.state.selectedSchedulingSetId);
         schedulingUnitList = _.filter(schedulingUnitList,{'observation_strategy_template_id': this.state.observStrategy.id}) ;
         this.setState({
             schedulingUnitList:  schedulingUnitList,
-            dialogVisible: false
-        })
+            confirmDialogVisible: false,
+            isDirty: false
+        });
+        this.isNewSet = false;
         await this.prepareScheduleUnitListForGrid();
         this.state.gridApi.setRowData(this.state.rowData);
         this.state.gridApi.redrawRows();
@@ -1679,7 +1967,7 @@ export class SchedulingSetCreate extends Component {
         this.setState({redirect: '/schedulingunit'});
     }
 
-   async onGridReady (params) { 
+    async onGridReady (params) { 
         await this.setState({
             gridApi:params.api,
             gridColumnApi:params.columnApi,
@@ -1687,9 +1975,17 @@ export class SchedulingSetCreate extends Component {
         this.state.gridApi.hideOverlay();
     }
  
+    async onTopGridReady (params) {
+        await this.setState({
+            topGridApi:params.api,
+            topGridColumnApi:params.columnApi,
+        })
+        this.state.topGridApi.hideOverlay();
+    }
+
    async setNoOfSUint(value){
-    this.setState({isAGLoading: true});
-       if  (value >= 0 && value < 501){
+        this.setState({isDirty: true, isAGLoading: true});
+        if  (value >= 0 && value < 501){
             await this.setState({
                 noOfSU: value
             })
@@ -1701,16 +1997,14 @@ export class SchedulingSetCreate extends Component {
 
         let noOfSU = this.state.noOfSU;
         this.tmpRowData = [];
-        let totalCount = this.state.totalCount;
         if (this.state.rowData && this.state.rowData.length >0 && this.state.emptyRow) {
             if (this.state.totalCount <= noOfSU) {
-                // set API data
-                for (var count = 0; count < totalCount; count++) {
-                    this.tmpRowData.push(this.state.rowData[count]);
-                }
-                // add empty row
-                for(var i = this.state.totalCount; i < noOfSU; i++) {
-                    this.tmpRowData.push(this.state.emptyRow);
+                for (var count = 0; count < noOfSU; count++) {
+                    if(this.state.rowData.length > count ) {
+                        this.tmpRowData.push(_.cloneDeep(this.state.rowData[count]));
+                    }   else {
+                        this.tmpRowData.push(_.cloneDeep(this.state.emptyRow));
+                    }
                 }
                 this.setState({
                     rowData: this.tmpRowData,
@@ -1770,10 +2064,6 @@ export class SchedulingSetCreate extends Component {
         return validForm;
     }
 
-    close(){
-        this.setState({saveDialogVisible: false})
-    }
-
     /**
      * This function is mainly added for Unit Tests. If this function is removed Unit Tests will fail.
      */
@@ -1785,12 +2075,17 @@ export class SchedulingSetCreate extends Component {
      * Show the content in custom dialog
      */
     showDialogContent(){
-        return <> <br/>Invalid Rows:- Row # and Invalid columns <br/>{this.state.errorDisplay && this.state.errorDisplay.length>0 && 
-            this.state.errorDisplay.map((msg, index) => (
-            <React.Fragment key={index+10} >
-                <span key={'label1-'+ index}>{msg}</span> <br />
-            </React.Fragment>
-        ))} </>
+        if (typeof this.state.errorDisplay === 'undefined' || this.state.errorDisplay.length === 0 ){
+            return "";
+        }
+        else {
+            return <> <br/>Invalid Rows:- Row # and Invalid columns <br/>{this.state.errorDisplay && this.state.errorDisplay.length>0 && 
+                this.state.errorDisplay.map((msg, index) => (
+                <React.Fragment key={index+10} >
+                    <span key={'label1-'+ index}>{msg}</span> <br />
+                </React.Fragment>
+            ))} </>
+        }
     }
 
     /**
@@ -1801,8 +2096,8 @@ export class SchedulingSetCreate extends Component {
             if (!this.state.showDefault){
                 let tmpRowData = this.state.rowData;
                 let defaultValueColumns = Object.keys(this.state.defaultCellValues);
-                await tmpRowData.forEach(rowData =>{
-                    defaultValueColumns.forEach(key =>{
+                await tmpRowData.forEach(rowData => {
+                    defaultValueColumns.forEach(key => {
                         if(!this.isNotEmpty(rowData[key])){
                             rowData[key] = this.state.defaultCellValues[key];
                         }
@@ -1820,6 +2115,220 @@ export class SchedulingSetCreate extends Component {
         }
     }
 
+    /**
+     * Reset the top table values
+     */
+    resetCommonData(){
+        let tmpData = [this.state.defaultCommonRowData]; //[...[this.state.emptyRow]];
+        let gRowData = {};
+        for (const key of _.keys(tmpData[0])) {
+            if (key === 'id') {
+                gRowData[key] = tmpData[0][key];
+            }
+            else if(this.state.hasSameValue) {
+                gRowData['gdef_'+key] = tmpData[0][key];
+            } else {
+                gRowData['gdef_'+key] = '';
+            }
+        }
+        this.setState({commonRowData: [gRowData]});
+    }
+
+    /**
+     * Reload the data from API 
+     */
+    reload(){
+        this.changeStrategy(this.state.observStrategy.id);
+    }
+
+    /**
+     * Appliy the changes to all rows
+     */
+    async applyToAll(){
+        let isNotEmptyRow = true;
+        if (!this.state.applyEmptyValue) {
+            var row = this.state.commonRowData[0];
+            Object.keys(row).forEach(key => {
+                if (key !== 'id' && row[key] !== '') {
+                    isNotEmptyRow = false;
+                }
+            });
+        }   
+        if (!this.state.applyEmptyValue && isNotEmptyRow ) {
+            this.growl.show({severity: 'warn', summary: 'Warning', detail: 'Please enter value in the column(s) above to apply'});
+         }  else {
+            this.dialogType = "confirmation";
+            this.dialogHeader = "Warning";
+            this.showIcon = true;
+            this.dialogMsg = "Do you want to apply the above value(s) to all Scheduling Units?";
+            this.dialogContent = "";
+            this.callBackFunction = this.applyChanges;
+            this.applyToAllRow = true;
+            this.applyToEmptyRowOnly = false;
+            this.onClose = this.close;
+            this.onCancel =this.close;
+            this.setState({confirmDialogVisible: true});
+         }                
+    }
+
+    /**
+     * Apply the changes to selected rows
+     */
+    async applyToSelected(){
+        let isNotEmptyRow = true;
+        let tmpRowData = this.state.gridApi.getSelectedRows();
+        if (!this.state.applyEmptyValue) {
+            var row = this.state.commonRowData[0];
+            Object.keys(row).forEach(key => {
+                if (key !== 'id' && row[key] !== '') {
+                    isNotEmptyRow= false;
+                }
+            });
+        }    
+        if (!this.state.applyEmptyValue && isNotEmptyRow ) {
+            this.growl.show({severity: 'warn', summary: 'Warning', detail: 'Please enter value in the column(s) above to apply'});
+        }   else if(tmpRowData && tmpRowData.length === 0){
+            this.growl.show({severity: 'warn', summary: 'Warning', detail: 'Please select at least one row to apply the changes'});
+        }   else {
+            this.showIcon = true;
+            this.dialogType = "confirmation";
+            this.dialogHeader = "Warning";
+            this.dialogMsg = "Do you want to apply the above value(s) to all selected Scheduling Unit(s) / row(s)?";
+            this.dialogContent = "";
+            this.applyToAllRow = false;
+            this.applyToEmptyRowOnly = false;
+            this.callBackFunction = this.applyChanges;
+            this.onClose = this.close;
+            this.onCancel = this.close;
+            this.setState({confirmDialogVisible: true});
+        }          
+    }
+
+     /**
+     * Apply the changes to Empty rows
+     */
+    async applyToEmptyRows(){
+        let isNotEmptyRow = true;
+        if (!this.state.applyEmptyValue) {
+            var row = this.state.commonRowData[0];
+            Object.keys(row).forEach(key => {
+                if (key !== 'id' && row[key] !== '') {
+                    isNotEmptyRow= false;
+                }
+            });
+        }    
+        if (!this.state.applyEmptyValue && isNotEmptyRow ) {
+            this.growl.show({severity: 'warn', summary: 'Warning', detail: 'Please enter value in the column(s) above to apply'});
+        }   else {
+            this.showIcon = true;
+            this.dialogType = "confirmation";
+            this.dialogHeader = "Warning";
+            this.dialogMsg = "Do you want to apply the above value(s) to all empty rows?";
+            this.dialogContent = "";
+            this.applyToEmptyRowOnly = true;    // Allows only empty to make changes
+            this.applyToAllRow = true;
+            this.callBackFunction = this.applyChanges;
+            this.onClose = this.close;
+            this.onCancel = this.close;
+            this.setState({confirmDialogVisible: true});
+            }
+    }
+
+    /**
+     * Make global changes in table data
+     */
+    async applyChanges() {
+        await this.setState({
+            confirmDialogVisible: false,
+            isDirty: true
+        });
+        
+        let tmpRowData = [];
+        if (this.applyToAllRow) {
+            tmpRowData = this.state.rowData;
+        }
+        else {
+            tmpRowData = this.state.gridApi.getSelectedRows();
+        }
+        var grow = this.state.commonRowData[0];
+        if(tmpRowData.length >0) {
+            for( const row  of tmpRowData) {
+                if (this.applyToEmptyRowOnly && (row['id'] > 0 || (row['suname'] !== '' && row['sudesc'] !== '') ) ){
+                   continue;
+                }
+                Object.keys(row).forEach(key => {
+                    if (key !== 'id') {
+                        let value = grow['gdef_'+key];
+                        if( this.state.applyEmptyValue) {
+                            row[key] = value;
+                        }
+                        else {
+                            row[key] = (_.isEmpty(value))?  row[key] : value;
+                        }
+                    }
+                });
+            }
+            this.state.gridApi.setRowData(this.state.rowData);
+        }
+    }
+
+    /**
+     * Update isDirty when ever cell value updated in AG grid
+     * @param {*} params 
+     */
+    cellValueChageEvent(params) {
+        if( params.value && !_.isEqual(params.value, params.oldValue)) {
+            this.setState({isDirty: true});
+        }
+    }
+
+    /**
+     * warn before cancel the page if any changes detected 
+     */
+    checkIsDirty() {
+        if( this.state.isDirty ){
+            this.showIcon = true;
+            this.dialogType = "confirmation";
+            this.dialogHeader = "Add Multiple Scheduling Unit(s)";
+            this.dialogMsg = "Do you want to leave this page? Your changes may not be saved.";
+            this.dialogContent = "";
+            this.dialogHeight = '5em';
+            this.callBackFunction = this.cancelCreate;
+            this.onClose = this.close;
+            this.onCancel = this.close;
+            this.setState({
+                confirmDialogVisible: true,
+            });
+        } else {
+            this.cancelCreate();
+        }
+    }
+    
+    async refreshSchedulingSet(){
+        this.schedulingSets = await ScheduleService.getSchedulingSets();
+        const filteredSchedluingSets = _.filter(this.schedulingSets, {'project_id': this.state.schedulingUnit.project});
+        this.setState({saveDialogVisible: false, confirmDialogVisible: false, schedulingSets: filteredSchedluingSets});
+    }
+
+    close(){
+        this.setState({confirmDialogVisible: false});
+    }
+
+    showAddSchedulingSet() {
+        this.showIcon = false;
+        this.dialogType = "success";
+        this.dialogHeader = "Add Scheduling Set’";
+        this.dialogMsg = <SchedulingSet project={this.state.selectedProject[0]} onCancel={this.refreshSchedulingSet} />;
+        this.dialogContent = "";
+        this.showIcon = false;
+        this.callBackFunction = this.refreshSchedulingSet;
+        this.onClose = this.refreshSchedulingSet;
+        this.onCancel = this.refreshSchedulingSet;
+        this.setState({
+            confirmDialogVisible: true,
+        });
+    }
+    
     render() {
         if (this.state.redirect) {
             return <Redirect to={ {pathname: this.state.redirect} }></Redirect>
@@ -1827,8 +2336,8 @@ export class SchedulingSetCreate extends Component {
         return (
             <React.Fragment>
                  <Growl ref={(el) => this.growl = el} />
-                 <PageHeader location={this.props.location} title={'Scheduling Set - Add'} 
-                actions={[{icon: 'fa-window-close',title:'Close', props:{pathname: '/schedulingunit' }}]}
+                 <PageHeader location={this.props.location} title={'Scheduling Unit(s) Add Multiple'} 
+                actions={[{icon: 'fa-window-close',title:'Close',  type: 'button',  actOn: 'click', props:{ callback: this.checkIsDirty }}]}
                 />
                 { this.state.isLoading ? <AppLoader /> :
                 <>                   
@@ -1842,7 +2351,7 @@ export class SchedulingSetCreate extends Component {
                                             tooltip="Project" tooltipOptions={this.tooltipOptions}
                                             value={this.state.schedulingUnit.project} disabled={this.state.projectDisabled}
                                             options={this.projects} 
-                                            onChange={(e) => {this.changeProject(e.value)}} 
+                                            onChange={(e) => {this.onProjectChange(e.value)}} 
                                             placeholder="Select Project" />
                                     <label className={this.state.errors.project ?"error":"info"}>
                                         {this.state.errors.project ? this.state.errors.project : "Select Project to get Scheduling Sets"}
@@ -1857,10 +2366,16 @@ export class SchedulingSetCreate extends Component {
                                             options={this.state.schedulingSets} 
                                             onChange={(e) => {this.setSchedulingSetParams('scheduling_set_id',e.value)}} 
                                             placeholder="Select Scheduling Set" />
+                                    <Button label="" className="p-button-primary" icon="pi pi-plus" 
+                                        onClick={this.showAddSchedulingSet}  
+                                        tooltip="Add new Scheduling Set"
+                                        style={{bottom: '2em', left: '25em'}}
+                                        disabled={this.state.schedulingUnit.project !== null ? false : true }/>
                                     <label className={this.state.errors.scheduling_set_id ?"error":"info"}>
                                         {this.state.errors.scheduling_set_id ? this.state.errors.scheduling_set_id : "Scheduling Set of the Project"}
                                     </label>
                                 </div>
+
                             </div>
                             <div className="p-field p-grid">
                                 <label htmlFor="observStrategy" className="col-lg-2 col-md-2 col-sm-12">Observation Strategy <span style={{color:'red'}}>*</span></label>
@@ -1869,7 +2384,7 @@ export class SchedulingSetCreate extends Component {
                                             tooltip="Observation Strategy Template to be used to create the Scheduling Unit" tooltipOptions={this.tooltipOptions}
                                             value={this.state.observStrategy.id} 
                                             options={this.observStrategies} 
-                                            onChange={(e) => {this.changeStrategy(e.value)}} 
+                                            onChange={(e) => {this.onStrategyChange(e.value)}} 
                                             placeholder="Select Strategy" />
                                     <label className={this.state.errors.noOfSU ?"error":"info"}>
                                         {this.state.errors.noOfSU ? this.state.errors.noOfSU : "Select Observation Strategy"}
@@ -1878,7 +2393,6 @@ export class SchedulingSetCreate extends Component {
                                 <div className="col-lg-1 col-md-1 col-sm-12"></div>
                                 <label htmlFor="schedSet" className="col-lg-2 col-md-2 col-sm-12">No of Scheduling Unit <span style={{color:'red'}}>*</span></label>
                                 <div className="col-lg-3 col-md-3 col-sm-12">
-                                
                                     <Dropdown
                                         editable
                                         options={this.state.noOfSUOptions}
@@ -1906,37 +2420,90 @@ export class SchedulingSetCreate extends Component {
                                       />
                                     </div>
                                 </div>
-                              }
+                            }
+                            
                         </div>
                         <>
-                        { this.state.isAGLoading ? <AppLoader /> :
-                        <>
-                            {this.state.observStrategy.id &&
-                                <div className="ag-theme-alpine" style={ {overflowX: 'inherit !importent', height: '500px', marginBottom: '10px' } } onKeyDown={this.clipboardEvent}>
-                                    <AgGridReact 
-                                        suppressClipboardPaste={false}
-                                        columnDefs={this.state.columnDefs}
-                                        columnTypes={this.state.columnTypes}
-                                        defaultColDef={this.state.defaultColDef}
-                                        rowSelection={this.state.rowSelection}
-                                        onGridReady={this.onGridReady}
-                                        rowData={this.state.rowData}
-                                        frameworkComponents={this.state.frameworkComponents}
-                                        context={this.state.context} 
-                                        components={this.state.components}
-                                        modules={this.state.modules}        
-                                        enableRangeSelection={true}
-                                        rowSelection={this.state.rowSelection}
-                                        stopEditingWhenGridLosesFocus={true}
-                                        undoRedoCellEditing={true}
-                                        undoRedoCellEditingLimit={20}
-                                        exportDataAsCsv={true}
-                                    >
-                                    </AgGridReact>
-                                </div>
+                            { this.state.isAGLoading ? <AppLoader /> :
+                                <>
+                                    {this.state.rowData && this.state.rowData.length > 0 &&
+                                    <React.Fragment>
+                                        <Accordion onTabOpen={this.resetCommonData} style={{marginTop: '2em', marginBottom: '2em'}} >
+                                            <AccordionTab header={<React.Fragment><span style={{paddingLeft: '0.5em', paddingRight: '0.5em'}}>Input Values For Multiple Scheduling units</span> <i className="fas fa-clone"></i></React.Fragment>} >
+                                                <div className="ag-theme-alpine" style={ {overflowX: 'inherit !importent', height: '160px', marginBottom: '10px' } }  onKeyDown={this.topAGGridEvent} >
+                                                    <AgGridReact 
+                                                        suppressClipboardPaste={false}
+                                                        columnDefs={this.state.globalColmunDef}
+                                                        columnTypes={this.state.columnTypes}
+                                                        defaultColDef={this.state.defaultColDef}
+                                                        rowSelection={this.state.rowSelection}
+                                                        onGridReady={this.onTopGridReady}
+                                                        rowData={this.state.commonRowData}
+                                                        frameworkComponents={this.state.frameworkComponents}
+                                                        context={this.state.context} 
+                                                        components={this.state.components}
+                                                        modules={this.state.modules}        
+                                                        enableRangeSelection={true}
+                                                    >
+                                                    </AgGridReact>
+                                                
+                                                </div>
+                                                <div className="p-grid p-justify-start" >
+                                                    <label htmlFor="observStrategy" className="p-col-1" style={{width: '14em'}}>Include empty value(s)</label>
+                                                        <Checkbox 
+                                                            tooltip="Copy the input value ( empty values also ) as it is while apply the changes in table" 
+                                                            tooltipOptions={this.tooltipOptions}
+                                                            checked={this.state.applyEmptyValue} 
+                                                            onChange={e => this.setState({'applyEmptyValue': e.target.checked})}
+                                                            style={{marginTop: '10px'}} >
+                                                        </Checkbox>
+                                                    
+                                                    <div className="p-col-1" style={{width: 'auto' , marginLeft: '2em'}}>
+                                                        <Button label="Apply to All Rows" tooltip="Apply changes to all rows in below table" className="p-button-primary" icon="fas fa-check-double" onClick={this.applyToAll}/>
+                                                    </div>
+                                                    <div className="p-col-1" style={{width: 'auto',marginLeft: '2em'}}>
+                                                        <Button label="Apply to Selected Rows" tooltip="Apply changes to selected row in below table" className="p-button-primary" icon="fas fa-check-square"   onClick={this.applyToSelected} />
+                                                    </div>
+                                                    <div className="p-col-1" style={{width: 'auto',marginLeft: '2em'}}>
+                                                        <Button label="Apply to Empty Rows" tooltip="Apply changes to empty row in below table" className="p-button-primary" icon="pi pi-check"   onClick={this.applyToEmptyRows} />
+                                                    </div>
+                                                <div className="p-col-1" style={{width: 'auto',marginLeft: '2em'}}>
+                                                        <Button label="Reset" tooltip="Reset input values" className="p-button-primary" icon="pi pi-refresh" onClick={this.resetCommonData} />
+                                                    </div>
+                                                    {/*} <div className="p-col-1" style={{width: 'auto',marginLeft: '2em'}}>
+                                                        <Button label="Refresh" tooltip="Refresh grid data" className="p-button-primary" icon="pi pi-refresh"   onClick={this.reload} />
+                                                    </div>
+                                                    */}
+                                                </div>
+                                            </AccordionTab>
+                                        </Accordion>  
+                                        </React.Fragment>
+                                    }
+
+                                    {this.state.observStrategy.id &&
+                                        <div className="ag-theme-alpine" style={ {overflowX: 'inherit !importent', height: '500px', marginBottom: '3em', padding: '0.5em' } } onKeyDown={this.clipboardEvent}>
+                                             <label >Scheduling Unit(s) </label>
+                                            <AgGridReact 
+                                                suppressClipboardPaste={false}
+                                                columnDefs={this.state.columnDefs}
+                                                columnTypes={this.state.columnTypes}
+                                                defaultColDef={this.state.defaultColDef}
+                                                rowSelection={this.state.rowSelection}
+                                                onGridReady={this.onGridReady}
+                                                rowData={this.state.rowData}
+                                                frameworkComponents={this.state.frameworkComponents}
+                                                context={this.state.context} 
+                                                components={this.state.components}
+                                                modules={this.state.modules}        
+                                                enableRangeSelection={true}
+                                                enableCellChangeFlash={true}
+                                                onCellValueChanged= {this.cellValueChageEvent}
+                                            >
+                                            </AgGridReact>
+                                        </div>
+                                    }
+                                </>
                             }
-                            </>
-                         }
                         </>
                         <div className="p-grid p-justify-start">
                             <div className="p-col-1">
@@ -1944,36 +2511,16 @@ export class SchedulingSetCreate extends Component {
                                         data-testid="save-btn" />
                             </div>
                             <div className="p-col-1">
-                                <Button label="Cancel" className="p-button-danger" icon="pi pi-times" onClick={this.cancelCreate}  />
+                                <Button label="Cancel" className="p-button-danger" icon="pi pi-times" onClick={this.checkIsDirty}  />
                             </div>
                         </div>
- 
                     </div>
                 </>
                 }
-
-                {/* Dialog component to show messages and get input */}
-                <div className="p-grid" data-testid="confirm_dialog">
-                    <Dialog header={this.state.dialog.header} visible={this.state.dialogVisible} style={{width: '25vw'}} inputId="confirm_dialog"
-                            modal={true}  onHide={() => {this.setState({dialogVisible: false})}} 
-                            footer={<div>
-                                <Button key="back" onClick={this.reset} label="Close" />
-                                </div>
-                            } >
-                            <div className="p-grid">
-                                <div className="col-lg-2 col-md-2 col-sm-2" style={{margin: 'auto'}}>
-                                    <i className="pi pi-check-circle pi-large pi-success"></i>
-                                </div>
-                                <div className="col-lg-10 col-md-10 col-sm-10">
-                                    {this.state.dialog.detail}
-                                </div>
-                            </div>
-                    </Dialog>
-                </div>
-
-                <CustomDialog type="confirmation" visible={this.state.saveDialogVisible} width="40vw"
-                    header={'Save Scheduling Unit(s)'} message={' Some of the Scheduling Unit(s) has invalid data, Do you want to ignore and save valid Scheduling Unit(s) only?'} 
-                    content={this.showDialogContent} onClose={this.close} onCancel={this.close} onSubmit={this.saveSU}>
+                <CustomDialog type={this.dialogType} visible={this.state.confirmDialogVisible} width="40vw" height={this.dialogHeight}
+                    header={this.dialogHeader} message={this.dialogMsg} 
+                    content={this.dialogContent} onClose={this.onClose} onCancel={this.onCancel} onSubmit={this.callBackFunction}
+                    showIcon={this.showIcon} actions={this.actions}>
                 </CustomDialog>
                 <CustomPageSpinner visible={this.state.showSpinner} />
             </React.Fragment>
diff --git a/SAS/TMSS/frontend/tmss_webapp/src/routes/Scheduling/schedulingset.create.js b/SAS/TMSS/frontend/tmss_webapp/src/routes/Scheduling/schedulingset.create.js
new file mode 100644
index 0000000000000000000000000000000000000000..94f205629b8afec137bb323f4046d1c84a59db38
--- /dev/null
+++ b/SAS/TMSS/frontend/tmss_webapp/src/routes/Scheduling/schedulingset.create.js
@@ -0,0 +1,207 @@
+import React, { Component } from 'react';
+import { InputText } from 'primereact/inputtext';
+import { InputTextarea } from 'primereact/inputtextarea';
+import UIConstants from '../../utils/ui.constants';
+import { CustomDialog } from '../../layout/components/CustomDialog';
+import ScheduleService from '../../services/schedule.service';
+import { Growl } from 'primereact/components/growl/Growl';
+
+export class SchedulingSet extends Component {
+
+    constructor(props) {
+        super(props);
+        this.state= {
+            dialogVisible: true,
+            schedulingSet: {
+                project: (props.project) ? props.project.url : null,
+                name: null,
+                description: null,
+            },
+            projectName: (props.project) ? props.project.name : null,
+            errors: [],
+            validFields: {},
+            onCancel: (props.onCancel) ? props.onCancel: null,
+            actions: [ {id:"yes", title: 'Save', callback: this.saveSchedulingSet},
+                         {id:"no", title: 'Cancel', callback: this.props.onCancel} ]
+        };
+        this.actions = [ {id:"yes", title: 'Save', callback: async ()=>{
+                            let schedulingSet = this.state.schedulingSet;
+                            if (!this.isNotEmpty(schedulingSet.name) || !this.isNotEmpty(schedulingSet.description)){
+                                this.growl.show({severity: 'error', summary: 'Error Occured', detail: 'Name and Description are mandatory'});
+                            }   else {
+                                schedulingSet['generator_doc'] = {};
+                                schedulingSet['scheduling_unit_drafts'] = [];
+                                const suSet = await ScheduleService.saveSchedulingSet(schedulingSet);                         
+                                if (suSet.id !== null) {
+                                    this.growl.show({severity: 'success', summary: 'Success', detail: 'Scheduling Set is created successfully.'});
+                                    this.setState({suSet: suSet, dialogVisible: true, });
+                                    this.props.onCancel();
+                                }   else {
+                                    this.growl.show({severity: 'error', summary: 'Error Occured', detail: schedulingSet.message || 'Unable to save Scheduling Set'});
+                                }
+                            }
+                        }},
+                         {id:"no", title: 'Cancel', callback: this.props.onCancel} ];
+
+        this.formRules = {                          // Form validation rules
+            name: {required: true, message: "Name can not be empty"},
+            description: {required: true, message: "Description can not be empty"},
+            project: {required: true, message: "Project can not be empty"},
+        };
+
+        //this.validateForm = this.validateForm.bind(this);
+        this.saveSchedulingSet = this.saveSchedulingSet.bind(this);
+        this.close = this.close.bind(this);
+        this.isNotEmpty = this.isNotEmpty.bind(this);
+    }
+
+    /**
+     * Validation function to validate the form or field based on the form rules.
+     * If no argument passed for fieldName, validates all fields in the form.
+     * @param {string} fieldName 
+     */
+    validateForm(fieldName) {
+        let validForm = false;
+        let errors = this.state.errors;
+        let validFields = this.state.validFields;
+        if (fieldName) {
+            delete errors[fieldName];
+            delete validFields[fieldName];
+            if (this.formRules[fieldName]) {
+                const rule = this.formRules[fieldName];
+                const fieldValue = this.state.schedulingSet[fieldName];
+                if (rule.required) {
+                    if (!fieldValue) {
+                        errors[fieldName] = rule.message?rule.message:`${fieldName} is required`;
+                    }   else {
+                        validFields[fieldName] = true;
+                    }
+                }
+            }
+        }  /* else {
+            errors = {};
+            validFields = {};
+            for (const fieldName in this.formRules) {
+                const rule = this.formRules[fieldName];
+                const fieldValue = this.state.schedulingSet[fieldName];
+                if (rule.required) {
+                    if (!fieldValue) {
+                        errors[fieldName] = rule.message?rule.message:`${fieldName} is required`;
+                    }   else {
+                        validFields[fieldName] = true;
+                    }
+                }
+            }
+        }*/
+        this.setState({errors: errors, validFields: validFields});
+        if (Object.keys(validFields).length === Object.keys(this.formRules).length) {
+            validForm = true;
+        }
+        return validForm;
+    }
+
+    /**
+     * Function to set form values to the SU Set object
+     * @param {string} key 
+     * @param {object} value 
+     */
+    setSchedulingSetParams(key, value) {
+        this.tooltipOptions = UIConstants.tooltipOptions;
+        this.nameInput = React.createRef();         // Ref to Name field for auto focus
+        let schedulingSet = this.state.schedulingSet;
+        schedulingSet[key] = value;
+        let isValid = this.validateForm(key);
+       // isValid= this.validateForm('project');
+        this.setState({schedulingSet: schedulingSet, validForm: isValid});
+    }
+
+    /**
+     * Create Scheduling Set
+     */
+    async saveSchedulingSet(){
+        let schedulingSet = this.state.schedulingSet;
+        schedulingSet['generator_doc'] = {};
+        schedulingSet['scheduling_unit_drafts'] = [];
+        const suSet = await ScheduleService.saveSchedulingSet(schedulingSet);
+        if (suSet.id !== null) {
+            const dialog = {header: 'Success', detail: 'Scheduling Set is created successfully.'};
+            this.setState({suSet: suSet, dialogVisible: false, dialog: dialog});
+        }   else {
+            this.growl.show({severity: 'error', summary: 'Error Occured', detail: schedulingSet.message || 'Unable to save Scheduling Set'});
+        }
+    }
+
+    close(){
+        this.setState({dialogVisible: false});
+    }
+
+     /**
+     * Check is empty string 
+     * @param {*} value 
+     */
+    isNotEmpty(value){
+        if ( value === null || !value || value === 'undefined' || value.length === 0 ){
+            return false;
+        } else {
+            return true;
+        }
+    }
+    render() {
+        return (
+            <>
+                <Growl ref={(el) => this.growl = el} />
+                <CustomDialog type="success" visible={this.state.dialogVisible} width="60vw"
+                    header={'Add Scheduling Set'} 
+                    message=  {
+                    <React.Fragment>
+                        <div className="p-fluid">
+                            <div className="p-field p-grid">
+                                <label htmlFor="project" className="col-lg-2 col-md-2 col-sm-12">Project</label>
+                                <span className="col-lg-4 col-md-4 col-sm-12" style={{fontWeight: 'bold'}}>{this.state.projectName} </span>
+                                <label className={(this.state.errors.project)?"error":"info"}>
+                                    {this.state.errors.project ? this.state.errors.project : ""}
+                                </label>
+                            </div>
+                        </div>
+                        <div className="col-lg-1 col-md-1 col-sm-12"></div>        
+                        <div className="p-fluid">
+                            <div className="p-field p-grid">
+                                <label htmlFor="project" className="col-lg-2 col-md-2 col-sm-12">Name <span style={{color:'red'}}>*</span></label>
+                                <div className="col-lg-4 col-md-4 col-sm-12">
+                                    <InputText className={(this.state.errors.name) ?'input-error':''} 
+                                        id="suSetName"
+                                        tooltip="Enter name of the Scheduling Set" tooltipOptions={this.tooltipOptions} maxLength="128"
+                                        ref={input => {this.nameInput = input;}}
+                                        onChange={(e) => this.setSchedulingSetParams('name', e.target.value)}
+                                        onBlur={(e) => this.setSchedulingSetParams('name', e.target.value)}                                
+                                        value={this.state.schedulingSet.name} autoFocus
+                                    />
+                                    <label className={(this.state.errors.name)?"error":"info"}>
+                                        {this.state.errors.name? this.state.errors.name : "Max 128 characters"}
+                                    </label>
+                                </div>
+                        
+                                <label htmlFor="description" className="col-lg-2 col-md-2 col-sm-12">Description <span style={{color:'red'}}>*</span></label>
+                                <div className="col-lg-4 col-md-4 col-sm-12">
+                                    <InputTextarea className={(this.state.errors.description) ?'input-error':''} rows={3} cols={30} 
+                                        tooltip="Longer description of the Scheduling Set"  maxLength="128"
+                                        value={this.state.schedulingSet.description}
+                                        onChange={(e) => this.setSchedulingSetParams('description', e.target.value)}
+                                        onBlur={(e) => this.setSchedulingSetParams('description', e.target.value)}
+                                    />
+                                    <label className={(this.state.errors.description) ?"error":"info"}>
+                                        {(this.state.errors.description) ? this.state.errors.description : "Max 255 characters"}
+                                    </label>
+                                </div>
+                            </div>
+                        </div>
+                    </React.Fragment>}
+                    content={''} onClose={this.props.onCancel} onCancel={this.props.onCancel} onSubmit={this.saveSU} showAction={true}
+                    actions={this.actions}
+                    showIcon={false}>
+                </CustomDialog>  
+            </>
+        ); 
+    }
+}
+export default SchedulingSet;
\ No newline at end of file
diff --git a/SAS/TMSS/frontend/tmss_webapp/src/routes/Task/edit.js b/SAS/TMSS/frontend/tmss_webapp/src/routes/Task/edit.js
index 3cb5f2e8ac3b8c39edcfc6a4da138599190d6ca2..9384b5734904041783d4cae63c6c2f49466314aa 100644
--- a/SAS/TMSS/frontend/tmss_webapp/src/routes/Task/edit.js
+++ b/SAS/TMSS/frontend/tmss_webapp/src/routes/Task/edit.js
@@ -1,13 +1,13 @@
-import React, {Component} from 'react';
+import React, { Component} from 'react';
 import { Link, Redirect } from 'react-router-dom';
 import _ from 'lodash';
 
-import {InputText} from 'primereact/inputtext';
-import {InputTextarea} from 'primereact/inputtextarea';
-import {Chips} from 'primereact/chips';
-import {Dropdown} from 'primereact/dropdown';
+import { InputText } from 'primereact/inputtext';
+import { InputTextarea } from 'primereact/inputtextarea';
+import { Chips } from 'primereact/chips';
+import { Dropdown } from 'primereact/dropdown';
 import { Button } from 'primereact/button';
-
+import { CustomDialog } from '../../layout/components/CustomDialog';
 import Jeditor from '../../components/JSONEditor/JEditor';
 
 import TaskService from '../../services/task.service';
@@ -21,6 +21,8 @@ export class TaskEdit extends Component {
     constructor(props) {
         super(props);
         this.state = {
+            showDialog: false,
+            isDirty: false,
             task: {
                 name: "",
                 created_at: null,
@@ -47,6 +49,8 @@ export class TaskEdit extends Component {
         this.validateForm = this.validateForm.bind(this);
         this.saveTask = this.saveTask.bind(this);
         this.cancelEdit = this.cancelEdit.bind(this);
+        this.checkIsDirty = this.checkIsDirty.bind(this);
+        this.close = this.close.bind(this);
     }
 
     /**
@@ -71,8 +75,14 @@ export class TaskEdit extends Component {
      */
     setTaskParams(key, value) {
         let task = this.state.task;
+        const taskValue = this.state.task[key];
         task[key] = value;
-        this.setState({task: task, validForm: this.validateForm()});
+        if  ( !this.state.isDirty && taskValue && !_.isEqual(taskValue, value) ) {
+            this.setState({task: task, validForm: this.validateForm(), isDirty: true});
+        }   else {
+            this.setState({task: task, validForm: this.validateForm()});
+        }
+       
     }
 
     /**
@@ -95,7 +105,7 @@ export class TaskEdit extends Component {
 		
         task.specifications_template = template.url;
         this.setState({taskSchema: null});
-        this.setState({task: task, taskSchema: template.schema});
+        this.setState({task: task, taskSchema: template.schema, isDirty: true});
 		 
         this.state.editorFunction();
     }
@@ -126,6 +136,7 @@ export class TaskEdit extends Component {
      * Function to call the servie and pass the values to save
      */
     saveTask() {
+        this.setState({isDirty: false});
         let task = this.state.task;
         task.specifications_doc = this.templateOutput[task.specifications_template_id];
         // Remove read only properties from the object before sending to API
@@ -138,6 +149,21 @@ export class TaskEdit extends Component {
         });
     }
 
+    /**
+     * warn before cancel the page if any changes detected 
+     */
+    checkIsDirty() {
+        if( this.state.isDirty ){
+            this.setState({showDialog: true});
+        } else {
+            this.cancelEdit();
+        }
+    }
+    
+    close() {
+        this.setState({showDialog: false});
+    }
+
     cancelEdit() {
         this.props.history.goBack();
     }
@@ -204,14 +230,16 @@ export class TaskEdit extends Component {
                         </Link>
                     </div>
                     </div> */}
-				<PageHeader location={this.props.location} title={'Task - Edit'} actions={[{icon: 'fa-window-close',link: this.props.history.goBack,title:'Click to Close Task Edit Page' ,props : { pathname:  `/task/view/draft/${this.state.task?this.state.task.id:''}`}}]}/>
+                <PageHeader location={this.props.location} title={'Task - Edit'} actions={[{icon: 'fa-window-close',
+                 title:'Click to Close Task Edit Page', props : { pathname:  `/task/view/draft/${this.state.task?this.state.task.id:''}`}}]}/>
 				{isLoading ? <AppLoader/> :
                 <div>
 			        <div className="p-fluid">
                     <div className="p-field p-grid">
                     <label htmlFor="taskName" className="col-lg-2 col-md-2 col-sm-12">Name <span style={{color:'red'}}>*</span></label>
                     <div className="col-lg-4 col-md-4 col-sm-12">
-                        <InputText className={this.state.errors.name ?'input-error':''} id="taskName" type="text" value={this.state.task.name} onChange={(e) => this.setTaskParams('name', e.target.value)}/>
+                        <InputText className={this.state.errors.name ?'input-error':''} id="taskName" type="text" value={this.state.task.name} 
+                        onChange={(e) => this.setTaskParams('name', e.target.value)}/>
                         <label className="error">
                             {this.state.errors.name ? this.state.errors.name : ""}
                         </label>
@@ -276,8 +304,14 @@ export class TaskEdit extends Component {
                     <Button label="Save" className="p-button-primary" icon="pi pi-check" onClick={this.saveTask} disabled={!this.state.validEditor || !this.state.validForm} />
                 </div>
                 <div className="p-col-1">
-                    <Button label="Cancel" className="p-button-danger" icon="pi pi-times" onClick={this.cancelEdit}  />
+                    <Button label="Cancel" className="p-button-danger" icon="pi pi-times" onClick={this.checkIsDirty}  />
+                </div>
                 </div>
+                <div className="p-grid" data-testid="confirm_dialog">
+                    <CustomDialog type="confirmation" visible={this.state.showDialog} width="40vw"
+                        header={'Edit Task'} message={'Do you want to leave this page? Your changes may not be saved.'} 
+                        content={''} onClose={this.close} onCancel={this.close} onSubmit={this.cancelEdit}>
+                    </CustomDialog>
                 </div>
             </React.Fragment>
         );
diff --git a/SAS/TMSS/frontend/tmss_webapp/src/routes/Timeline/reservation.create.js b/SAS/TMSS/frontend/tmss_webapp/src/routes/Timeline/reservation.create.js
index e95f7a29fd922f3b7ee9ce6ca29a45eea45f4bd3..73856d5af49e1aecdb35d1bd1d94374298352022 100644
--- a/SAS/TMSS/frontend/tmss_webapp/src/routes/Timeline/reservation.create.js
+++ b/SAS/TMSS/frontend/tmss_webapp/src/routes/Timeline/reservation.create.js
@@ -1,17 +1,18 @@
-import React, {Component} from 'react';
+import React, { Component } from 'react';
 import { Redirect } from 'react-router-dom';
-
-import {Growl} from 'primereact/components/growl/Growl';
+import _ from 'lodash';
+import { Growl } from 'primereact/components/growl/Growl';
 import AppLoader from '../../layout/components/AppLoader';
 import PageHeader from '../../layout/components/PageHeader';
 import UIConstants from '../../utils/ui.constants';
-import {Calendar} from 'primereact/calendar';
+import { Calendar } from 'primereact/calendar';
 import { InputMask } from 'primereact/inputmask';
-import {Dropdown} from 'primereact/dropdown';
-import {InputText} from 'primereact/inputtext';
-import {InputTextarea} from 'primereact/inputtextarea';
+import { Dropdown } from 'primereact/dropdown';
+import {InputText } from 'primereact/inputtext';
+import { InputTextarea } from 'primereact/inputtextarea';
 import { Button } from 'primereact/button';
-import {Dialog} from 'primereact/components/dialog/Dialog';
+import { Dialog } from 'primereact/components/dialog/Dialog';
+import { CustomDialog } from '../../layout/components/CustomDialog';
 import ProjectService from '../../services/project.service';
 import ReservationService from '../../services/reservation.service';
 import UnitService from '../../utils/unit.converter';
@@ -24,6 +25,8 @@ export class ReservationCreate extends Component {
     constructor(props) {
         super(props);
         this.state= {
+            showDialog: false,
+            isDirty: false,
             isLoading: true,
             redirect: null, 
             paramsSchema: null,                     // JSON Schema to be generated from strategy template to pass to JSON editor 
@@ -59,6 +62,8 @@ export class ReservationCreate extends Component {
         this.saveReservation = this.saveReservation.bind(this);
         this.reset = this.reset.bind(this);
         this.cancelCreate = this.cancelCreate.bind(this);
+        this.checkIsDirty = this.checkIsDirty.bind(this);
+        this.close = this.close.bind(this);
         this.initReservation = this.initReservation.bind(this);
     }
 
@@ -100,13 +105,21 @@ export class ReservationCreate extends Component {
      * @param {object} value 
      */
     setReservationParams(key, value) {
-         
-        let reservation = this.state.reservation;
+        let reservation = _.cloneDeep(this.state.reservation);
         reservation[key] = value;
-        this.setState({reservation: reservation, validForm: this.validateForm(key), validEditor: this.validateEditor(),touched: { 
-            ...this.state.touched,
-            [key]: true
-        }});
+        if  ( !this.state.isDirty && !_.isEqual(this.state.reservation, reservation) ) {
+            this.setState({reservation: reservation, validForm: this.validateForm(key), validEditor: this.validateEditor(), touched: { 
+                ...this.state.touched,
+                [key]: true
+            }, isDirty: true});
+        }   else {
+            this.setState({reservation: reservation, validForm: this.validateForm(key), validEditor: this.validateEditor(),touched: { 
+                ...this.state.touched,
+                [key]: true
+            }});
+        }
+
+        
     }
 
      /**
@@ -124,7 +137,8 @@ export class ReservationCreate extends Component {
     setParams(key, value, type) {
         if(key === 'duration' && !this.validateDuration( value)) {
             this.setState({
-                durationError: true
+                durationError: true,
+                isDirty: true
             })
             return;
         }
@@ -139,7 +153,7 @@ export class ReservationCreate extends Component {
                 break;
             }
         }
-        this.setState({reservation: reservation, validForm: this.validateForm(key), durationError: false});
+        this.setState({reservation: reservation, validForm: this.validateForm(key), durationError: false, isDirty: true});
     }
      
     /**
@@ -205,9 +219,16 @@ export class ReservationCreate extends Component {
     setEditorOutput(jsonOutput, errors) {
         this.paramsOutput = jsonOutput;
         this.validEditor = errors.length === 0;
-        this.setState({ paramsOutput: jsonOutput, 
-                        validEditor: errors.length === 0,
-                        validForm: this.validateForm()});
+        if  ( !this.state.isDirty && this.state.paramsOutput && !_.isEqual(this.state.paramsOutput, jsonOutput) ) {
+            this.setState({ paramsOutput: jsonOutput, 
+                validEditor: errors.length === 0,
+                validForm: this.validateForm(),
+                isDirty: true});
+        }   else {
+            this.setState({ paramsOutput: jsonOutput, 
+                validEditor: errors.length === 0,
+                validForm: this.validateForm()});
+        }
     }
 
     saveReservation(){
@@ -220,9 +241,9 @@ export class ReservationCreate extends Component {
         reservation = ReservationService.saveReservation(reservation); 
         if (reservation && reservation !== null){
             const dialog = {header: 'Success', detail: 'Reservation is created successfully. Do you want to create another Reservation?'};
-            this.setState({ dialogVisible: true, dialog: dialog,  paramsOutput: {}})
+            this.setState({ dialogVisible: true, dialog: dialog,  paramsOutput: {}, showDialog: false, isDirty: false})
         }  else {
-            this.growl.show({severity: 'error', summary: 'Error Occured', detail: 'Unable to save Reservation'});
+            this.growl.show({severity: 'error', summary: 'Error Occured', detail: 'Unable to save Reservation', showDialog: false, isDirty: false});
         }
     }
 
@@ -248,6 +269,8 @@ export class ReservationCreate extends Component {
             validFields: {},
             touched:false,
             stationGroup: [],
+            showDialog: false, 
+            isDirty: false
         });
         this.initReservation();
     }
@@ -259,6 +282,21 @@ export class ReservationCreate extends Component {
         this.props.history.goBack();
     }
 
+    /**
+     * warn before cancel the page if any changes detected 
+     */
+    checkIsDirty() {
+        if( this.state.isDirty ){
+            this.setState({showDialog: true});
+        } else {
+            this.cancelCreate();
+        }
+    }
+    
+    close() {
+        this.setState({showDialog: false});
+    }
+
     render() {
         if (this.state.redirect) {
             return <Redirect to={ {pathname: this.state.redirect} }></Redirect>
@@ -278,7 +316,8 @@ export class ReservationCreate extends Component {
             <React.Fragment>
                 <Growl ref={(el) => this.growl = el} />
                 <PageHeader location={this.props.location} title={'Reservation - Add'} 
-                           actions={[{icon: 'fa-window-close' ,title:'Click to close Reservation creation', props : { pathname: `/su/timelineview/reservation/reservation/list`}}]}/>
+                           actions={[{icon: 'fa-window-close' ,title:'Click to close Reservation creation', 
+                           type: 'button',  actOn: 'click', props:{ callback: this.checkIsDirty }}]}/>
                 { this.state.isLoading ? <AppLoader /> :
                 <> 
                     <div>
@@ -377,7 +416,7 @@ export class ReservationCreate extends Component {
                                         disabled={!this.state.validEditor || !this.state.validForm} data-testid="save-btn" />
                             </div>
                             <div className="p-col-1">
-                                <Button label="Cancel" className="p-button-danger" icon="pi pi-times" onClick={this.cancelCreate}  />
+                                <Button label="Cancel" className="p-button-danger" icon="pi pi-times" onClick={this.checkIsDirty}  />
                             </div>
                         </div>
                     </div>
@@ -402,6 +441,11 @@ export class ReservationCreate extends Component {
                                 </div>
                             </div>
                     </Dialog>
+
+                    <CustomDialog type="confirmation" visible={this.state.showDialog} width="40vw"
+                            header={'Add Reservation'} message={'Do you want to leave this page? Your changes may not be saved.'} 
+                            content={''} onClose={this.close} onCancel={this.close} onSubmit={this.cancelCreate}>
+                        </CustomDialog>
                 </div>
             </React.Fragment>
         );
diff --git a/SAS/TMSS/frontend/tmss_webapp/src/routes/Timeline/view.js b/SAS/TMSS/frontend/tmss_webapp/src/routes/Timeline/view.js
index f380d527ea32182515a720c017e4126177289f8d..3e4317e965ad5d93f6dd2e6ffa6489706a77ae6b 100644
--- a/SAS/TMSS/frontend/tmss_webapp/src/routes/Timeline/view.js
+++ b/SAS/TMSS/frontend/tmss_webapp/src/routes/Timeline/view.js
@@ -2,6 +2,7 @@ import React, {Component} from 'react';
 import { Redirect } from 'react-router-dom/cjs/react-router-dom.min';
 import moment from 'moment';
 import _ from 'lodash';
+import Websocket from 'react-websocket';
 
 // import SplitPane, { Pane }  from 'react-split-pane';
 import {InputSwitch} from 'primereact/inputswitch';
@@ -17,6 +18,7 @@ import UtilService from '../../services/util.service';
 import TaskService from '../../services/task.service';
 
 import UnitConverter from '../../utils/unit.converter';
+import Validator from '../../utils/validator';
 import SchedulingUnitSummary from '../Scheduling/summary';
 import { Dropdown } from 'primereact/dropdown';
 import { OverlayPanel } from 'primereact/overlaypanel';
@@ -86,6 +88,10 @@ export class TimelineView extends Component {
         this.resizeSUList = this.resizeSUList.bind(this);
         this.suListFilterCallback = this.suListFilterCallback.bind(this);
         this.addStationReservations = this.addStationReservations.bind(this);
+        this.handleData = this.handleData.bind(this);
+        this.addNewData = this.addNewData.bind(this);
+        this.updateExistingData = this.updateExistingData.bind(this);
+        this.updateSchedulingUnit = this.updateSchedulingUnit.bind(this);
     }
 
     async componentDidMount() {
@@ -185,7 +191,8 @@ export class TimelineView extends Component {
     getTimelineItem(suBlueprint) {
         let antennaSet = "";
         for (let task of suBlueprint.tasks) {
-            if (task.specifications_template.type_value.toLowerCase() === "observation") {
+            if (task.specifications_template.type_value.toLowerCase() === "observation"
+                    && task.specifications_doc.antenna_set) {
                 antennaSet = task.specifications_doc.antenna_set;
             }
         }
@@ -441,7 +448,8 @@ export class TimelineView extends Component {
                         currentStartTime: startTime, currentEndTime: endTime});
         // On range change close the Details pane
         // this.closeSUDets();
-        return {group: this.stationView?this.allStationsGroup:_.orderBy(group,["parent", "id"], ['asc', 'desc']), items: items};
+        // console.log(_.orderBy(group, ["parent", "id"], ['asc', 'desc']));
+        return {group: this.stationView?this.allStationsGroup:_.orderBy(_.uniqBy(group, 'id'),["parent", "start"], ['asc', 'asc']), items: items};
     }
 
     /**
@@ -662,6 +670,153 @@ export class TimelineView extends Component {
             }
         }
     }
+
+    /**
+     * Function to call wnen websocket is connected
+     */
+    onConnect() {
+        console.log("WS Opened")
+    }
+
+    /**
+     * Function to call when websocket is disconnected
+     */
+    onDisconnect() {
+        console.log("WS Closed")
+    }
+
+    /**
+     * Handles the message received through websocket
+     * @param {String} data - String of JSON data
+     */
+    handleData(data) {
+        if (data) {
+            const jsonData = JSON.parse(data);
+            if (jsonData.action === 'create') {
+                this.addNewData(jsonData.object_details.id, jsonData.object_type, jsonData.object_details);
+            }   else if (jsonData.action === 'update') {
+                this.updateExistingData(jsonData.object_details.id, jsonData.object_type, jsonData.object_details);
+            }
+        }
+    }
+
+    /**
+     * If any new object that is relevant to the timeline view, load the data to the existing state variable.
+     * @param {Number} id  - id of the object created
+     * @param {String} type  - model name of the object like scheduling_unit_draft, scheduling_unit_blueprint, task_blueprint, etc.,
+     * @param {Object} object - model object with certain properties
+     */
+    addNewData(id, type, object) {
+        switch(type) {
+            /* When a new scheduling_unit_draft is created, it should be added to the existing list of suDraft. */
+            case 'scheduling_unit_draft': {
+                this.updateSUDraft(id);
+                // let suDrafts = this.state.suDrafts;
+                // let suSets = this.state.suSets;
+                // ScheduleService.getSchedulingUnitDraftById(id)
+                // .then(suDraft => {
+                //     suDrafts.push(suDraft);
+                //     _.remove(suSets, function(suSet) { return suSet.id === suDraft.scheduling_set_id});
+                //     suSets.push(suDraft.scheduling_set_object);
+                //     this.setState({suSet: suSets, suDrafts: suDrafts});
+                // });
+                break;
+            }
+            case 'scheduling_unit_blueprint': {
+                this.updateSchedulingUnit(id);
+                break;
+            }
+            case 'task_blueprint': {
+                // this.updateSchedulingUnit(object.scheduling_unit_blueprint_id);
+                break;
+            }
+            default: { break; }
+        }
+    }
+
+    /**
+     * If any if the given properties of the object is modified, update the schedulingUnit object in the list of the state.
+     * It is validated for both scheduling_unit_blueprint and task_blueprint objects
+     * @param {Number} id 
+     * @param {String} type 
+     * @param {Object} object 
+     */
+    updateExistingData(id, type, object) {
+        const objectProps = ['status', 'start_time', 'stop_time', 'duration'];
+        switch(type) {
+            case 'scheduling_unit_draft': {
+                this.updateSUDraft(id);
+                // let suDrafts = this.state.suDrafts;
+                // _.remove(suDrafts, function(suDraft) { return suDraft.id === id});
+                // suDrafts.push(object);
+                // this.setState({suDrafts: suDrafts});
+                break;
+            }
+            case 'scheduling_unit_blueprint': {
+                let suBlueprints = this.state.suBlueprints;
+                let existingSUB = _.find(suBlueprints, ['id', id]);
+                if (Validator.isObjectModified(existingSUB, object, objectProps)) {
+                    this.updateSchedulingUnit(id);
+                }
+                break;
+            }
+            case 'task_blueprint': {
+                // let suBlueprints = this.state.suBlueprints;
+                // let existingSUB = _.find(suBlueprints, ['id', object.scheduling_unit_blueprint_id]);
+                // let existingTask = _.find(existingSUB.tasks, ['id', id]);
+                // if (Validator.isObjectModified(existingTask, object, objectProps)) {
+                //     this.updateSchedulingUnit(object.scheduling_unit_blueprint_id);
+                // }
+                break;
+            }
+            default: { break;}
+        }
+    }
+
+    /**
+     * Add or update the SUDraft object in the state suDraft list after fetching through API call
+     * @param {Number} id 
+     */
+    updateSUDraft(id) {
+        let suDrafts = this.state.suDrafts;
+        let suSets = this.state.suSets;
+        ScheduleService.getSchedulingUnitDraftById(id)
+        .then(suDraft => {
+            _.remove(suDrafts, function(suDraft) { return suDraft.id === id});
+            suDrafts.push(suDraft);
+            _.remove(suSets, function(suSet) { return suSet.id === suDraft.scheduling_set_id});
+            suSets.push(suDraft.scheduling_set_object);
+            this.setState({suSet: suSets, suDrafts: suDrafts});
+        });
+    }
+
+    /**
+     * Fetch the latest SUB object from the backend and format as required for the timeline and pass them to the timeline component
+     * to update the timeline view with latest data.
+     * @param {Number} id 
+     */
+    updateSchedulingUnit(id) {
+        ScheduleService.getSchedulingUnitExtended('blueprint', id, true)
+        .then(suBlueprint => {
+            const suDraft = _.find(this.state.suDrafts, ['id', suBlueprint.draft_id]);
+            const suSet = this.state.suSets.find((suSet) => { return suDraft.scheduling_set_id===suSet.id});
+            const project = this.state.projects.find((project) => { return suSet.project_id===project.name});
+            let suBlueprints = this.state.suBlueprints;
+            suBlueprint['actionpath'] = `/schedulingunit/view/blueprint/${id}`;
+            suBlueprint.suDraft = suDraft;
+            suBlueprint.project = project.name;
+            suBlueprint.suSet = suSet;
+            suBlueprint.durationInSec = suBlueprint.duration;
+            suBlueprint.duration = UnitConverter.getSecsToHHmmss(suBlueprint.duration);
+            suBlueprint.tasks = suBlueprint.task_blueprints;
+            _.remove(suBlueprints, function(suB) { return suB.id === id});
+            suBlueprints.push(suBlueprint);
+            // Set updated suBlueprints in the state and call the dateRangeCallback to create the timeline group and items
+            this.setState({suBlueprints: suBlueprints});
+            this.dateRangeCallback(this.state.currentStartTime, this.state.currentEndTime);
+        });
+    }
+
     render() {
         if (this.state.redirect) {
             return <Redirect to={ {pathname: this.state.redirect} }></Redirect>
@@ -821,6 +976,8 @@ export class TimelineView extends Component {
                     </div>
                 }
                 </OverlayPanel>
+                {!this.state.isLoading &&
+                    <Websocket url={process.env.REACT_APP_WEBSOCKET_URL} onOpen={this.onConnect} onMessage={this.handleData} onClose={this.onDisconnect} /> }
             </React.Fragment>
         );
     }
diff --git a/SAS/TMSS/frontend/tmss_webapp/src/routes/Timeline/week.view.js b/SAS/TMSS/frontend/tmss_webapp/src/routes/Timeline/week.view.js
index 6e595e550a3a146868b9f05d1122937fc113efa7..75b8b2ca961f1a476c01a7cb3f391fe37c431f25 100644
--- a/SAS/TMSS/frontend/tmss_webapp/src/routes/Timeline/week.view.js
+++ b/SAS/TMSS/frontend/tmss_webapp/src/routes/Timeline/week.view.js
@@ -2,6 +2,7 @@ import React, {Component} from 'react';
 import { Redirect } from 'react-router-dom/cjs/react-router-dom.min';
 import moment from 'moment';
 import _ from 'lodash';
+import Websocket from 'react-websocket';
 
 // import SplitPane, { Pane }  from 'react-split-pane';
 // import { Dropdown } from 'primereact/dropdown';
@@ -17,6 +18,7 @@ import UtilService from '../../services/util.service';
 import TaskService from '../../services/task.service';
 
 import UnitConverter from '../../utils/unit.converter';
+import Validator from '../../utils/validator';
 import SchedulingUnitSummary from '../Scheduling/summary';
 import UIConstants from '../../utils/ui.constants';
 import { OverlayPanel } from 'primereact/overlaypanel';
@@ -66,6 +68,10 @@ export class WeekTimelineView extends Component {
         this.dateRangeCallback = this.dateRangeCallback.bind(this);
         this.resizeSUList = this.resizeSUList.bind(this);
         this.suListFilterCallback = this.suListFilterCallback.bind(this);
+        this.handleData = this.handleData.bind(this);
+        this.addNewData = this.addNewData.bind(this);
+        this.updateExistingData = this.updateExistingData.bind(this);
+        this.updateSchedulingUnit = this.updateSchedulingUnit.bind(this);
     }
 
     async componentDidMount() {
@@ -167,7 +173,8 @@ export class WeekTimelineView extends Component {
     async getTimelineItem(suBlueprint, displayDate) {
         let antennaSet = "";
         for (let task of suBlueprint.tasks) {
-            if (task.specifications_template.type_value.toLowerCase() === "observation") {
+            if (task.specifications_template.type_value.toLowerCase() === "observation" 
+                && task.specifications_doc.antenna_set) {
                 antennaSet = task.specifications_doc.antenna_set;
             }
         }
@@ -176,7 +183,7 @@ export class WeekTimelineView extends Component {
             group: moment.utc(suBlueprint.start_time).format("MMM DD ddd"),
             title: "",
             project: suBlueprint.project,
-            name: suBlueprint.suDraft.name,
+            name: suBlueprint.name,
             band: antennaSet?antennaSet.split("_")[0]:"",
             antennaSet: antennaSet,
             duration: suBlueprint.durationInSec?`${(suBlueprint.durationInSec/3600).toFixed(2)}Hrs`:"",
@@ -216,7 +223,8 @@ export class WeekTimelineView extends Component {
                                 //Control Task ID
                                 const subTaskIds = (task.subTasks || []).filter(sTask => sTask.subTaskTemplate.name.indexOf('control') > 1);
                                 task.subTaskID = subTaskIds.length ? subTaskIds[0].id : ''; 
-                                if (task.template.type_value.toLowerCase() === "observation") {
+                                if (task.template.type_value.toLowerCase() === "observation"
+                                    && task.specifications_doc.antenna_set) {
                                     task.antenna_set = task.specifications_doc.antenna_set;
                                     task.band = task.specifications_doc.filter;
                                 }
@@ -270,6 +278,8 @@ export class WeekTimelineView extends Component {
             counts = counts.concat(itemStationGroups[stationgroup].length);
             item.stations.groups = groups;
             item.stations.counts = counts;
+            item.suStartTime = moment.utc(itemSU.start_time);
+            item.suStopTime = moment.utc(itemSU.stop_time);
         }
         this.popOver.toggle(evt);
         this.setState({mouseOverItem: item});
@@ -430,6 +440,144 @@ export class WeekTimelineView extends Component {
         }
     }
 
+    /**
+     * Function to call wnen websocket is connected
+     */
+    onConnect() {
+        console.log("WS Opened")
+    }
+
+    /**
+     * Function to call when websocket is disconnected
+     */
+    onDisconnect() {
+        console.log("WS Closed")
+    }
+
+    /**
+     * Handles the message received through websocket
+     * @param {String} data - String of JSON data
+     */
+    handleData(data) {
+        if (data) {
+            const jsonData = JSON.parse(data);
+            if (jsonData.action === 'create') {
+                this.addNewData(jsonData.object_details.id, jsonData.object_type, jsonData.object_details);
+            }   else if (jsonData.action === 'update') {
+                this.updateExistingData(jsonData.object_details.id, jsonData.object_type, jsonData.object_details);
+            }
+        }
+    }
+
+    /**
+     * If any new object that is relevant to the timeline view, load the data to the existing state variable.
+     * @param {Number} id  - id of the object created
+     * @param {String} type  - model name of the object like scheduling_unit_draft, scheduling_unit_blueprint, task_blueprint, etc.,
+     * @param {Object} object - model object with certain properties
+     */
+    addNewData(id, type, object) {
+        switch(type) {
+            /* When a new scheduling_unit_draft is created, it should be added to the existing list of suDraft. */
+            case 'scheduling_unit_draft': {
+                let suDrafts = this.state.suDrafts;
+                let suSets = this.state.suSets;
+                ScheduleService.getSchedulingUnitDraftById(id)
+                .then(suDraft => {
+                    suDrafts.push(suDraft);
+                    _.remove(suSets, function(suSet) { return suSet.id === suDraft.scheduling_set_id});
+                    suSets.push(suDraft.scheduling_set_object);
+                    this.setState({suSet: suSets, suDrafts: suDrafts});
+                });
+                break;
+            }
+            case 'scheduling_unit_blueprint': {
+                this.updateSchedulingUnit(id);
+                break;
+            }
+            case 'task_blueprint': {
+                // this.updateSchedulingUnit(object.scheduling_unit_blueprint_id);
+                break;
+            }
+            default: { break; }
+        }
+    }
+
+    /**
+     * If any if the given properties of the object is modified, update the schedulingUnit object in the list of the state.
+     * It is validated for both scheduling_unit_blueprint and task_blueprint objects
+     * @param {Number} id 
+     * @param {String} type 
+     * @param {Object} object 
+     */
+    updateExistingData(id, type, object) {
+        const objectProps = ['status', 'start_time', 'stop_time', 'duration'];
+        switch(type) {
+            case 'scheduling_unit_blueprint': {
+                let suBlueprints = this.state.suBlueprints;
+                let existingSUB = _.find(suBlueprints, ['id', id]);
+                if (Validator.isObjectModified(existingSUB, object, objectProps)) {
+                    this.updateSchedulingUnit(id);
+                }
+                break;
+            }
+            case 'task_blueprint': {
+                // let suBlueprints = this.state.suBlueprints;
+                // let existingSUB = _.find(suBlueprints, ['id', object.scheduling_unit_blueprint_id]);
+                // let existingTask = _.find(existingSUB.tasks, ['id', id]);
+                // if (Validator.isObjectModified(existingTask, object, objectProps)) {
+                //     this.updateSchedulingUnit(object.scheduling_unit_blueprint_id);
+                // }
+                break;
+            }
+            default: { break;}
+        }
+    }
+
+    /**
+     * Fetch the latest SUB object from the backend and format as required for the timeline and pass them to the timeline component
+     * to update the timeline view with latest data.
+     * @param {Number} id 
+     */
+    updateSchedulingUnit(id) {
+        ScheduleService.getSchedulingUnitExtended('blueprint', id, true)
+        .then(async(suBlueprint) => {
+            const suDraft = _.find(this.state.suDrafts, ['id', suBlueprint.draft_id]);
+            const suSet = this.state.suSets.find((suSet) => { return suDraft.scheduling_set_id===suSet.id});
+            const project = this.state.projects.find((project) => { return suSet.project_id===project.name});
+            let suBlueprints = this.state.suBlueprints;
+            suBlueprint['actionpath'] = `/schedulingunit/view/blueprint/${id}`;
+            suBlueprint.suDraft = suDraft;
+            suBlueprint.project = project.name;
+            suBlueprint.suSet = suSet;
+            suBlueprint.durationInSec = suBlueprint.duration;
+            suBlueprint.duration = UnitConverter.getSecsToHHmmss(suBlueprint.duration);
+            suBlueprint.tasks = suBlueprint.task_blueprints;
+            // Add Subtask Id as control id for task if subtask type us control. Also add antenna_set & band prpoerties to the task object.
+            for (let task of suBlueprint.tasks) {
+                const subTaskIds = task.subtasks.filter(subtask => {
+                    const template = _.find(this.subtaskTemplates, ['id', subtask.specifications_template_id]);
+                    return (template && template.name.indexOf('control')) > 0;
+                });
+                task.subTaskID = subTaskIds.length ? subTaskIds[0].id : ''; 
+                if (task.specifications_template.type_value.toLowerCase() === "observation"
+                    && task.specifications_doc.antenna_set) {
+                    task.antenna_set = task.specifications_doc.antenna_set;
+                    task.band = task.specifications_doc.filter;
+                }
+            }
+            // Get stations involved for this SUB
+            let stations = this.getSUStations(suBlueprint);
+            suBlueprint.stations = _.uniq(stations);
+            // Remove the old SUB object from the existing list and add the newly fetched SUB
+            _.remove(suBlueprints, function(suB) { return suB.id === id});
+            suBlueprints.push(suBlueprint);
+            this.setState({suBlueprints: suBlueprints});
+            // Create timeline group and items
+            let updatedItemGroupData = await this.dateRangeCallback(this.state.startTime, this.state.endTime, true);
+            this.timeline.updateTimeline(updatedItemGroupData);
+        });
+    }
+
     render() {
         if (this.state.redirect) {
             return <Redirect to={ {pathname: this.state.redirect} }></Redirect>
@@ -539,9 +687,9 @@ export class WeekTimelineView extends Component {
                         <label className={`col-5 su-${mouseOverItem.status}-icon`}>Friends:</label>
                         <div className="col-7">{mouseOverItem.friends?mouseOverItem.friends:"-"}</div>
                         <label className={`col-5 su-${mouseOverItem.status}-icon`}>Start Time:</label>
-                        <div className="col-7">{mouseOverItem.start_time.format("YYYY-MM-DD HH:mm:ss")}</div>
+                        <div className="col-7">{mouseOverItem.suStartTime.format("YYYY-MM-DD HH:mm:ss")}</div>
                         <label className={`col-5 su-${mouseOverItem.status}-icon`}>End Time:</label>
-                        <div className="col-7">{mouseOverItem.end_time.format("YYYY-MM-DD HH:mm:ss")}</div>
+                        <div className="col-7">{mouseOverItem.suStopTime.format("YYYY-MM-DD HH:mm:ss")}</div>
                         <label className={`col-5 su-${mouseOverItem.status}-icon`}>Antenna Set:</label>
                         <div className="col-7">{mouseOverItem.antennaSet}</div>
                         <label className={`col-5 su-${mouseOverItem.status}-icon`}>Stations:</label>
@@ -553,6 +701,9 @@ export class WeekTimelineView extends Component {
                     </div>
                 }
                 </OverlayPanel>
+                {/* Open Websocket after loading all initial data */}
+                {!this.state.isLoading &&
+                    <Websocket url={process.env.REACT_APP_WEBSOCKET_URL} onOpen={this.onConnect} onMessage={this.handleData} onClose={this.onDisconnect} /> }
             </React.Fragment>
         );
     }
diff --git a/SAS/TMSS/frontend/tmss_webapp/src/routes/Workflow/Scheduled.js b/SAS/TMSS/frontend/tmss_webapp/src/routes/Workflow/Scheduled.js
index 5e1cad1b4c4994b239b627675ee6f85e5fc04891..6eda2278a31979af8b1c897cbb695317122d9332 100644
--- a/SAS/TMSS/frontend/tmss_webapp/src/routes/Workflow/Scheduled.js
+++ b/SAS/TMSS/frontend/tmss_webapp/src/routes/Workflow/Scheduled.js
@@ -11,7 +11,7 @@ class Scheduled extends Component {
     }
 
     /**
-     * Method will trigger on click save buton
+     * Method will trigger on click Next buton
      * here onNext props coming from parent, where will handle redirection to other page
      */
     Next() {
@@ -49,10 +49,8 @@ class Scheduled extends Component {
 
                     <div className="p-grid p-justify-start">
                         <div className="p-col-1">
-                            <Button label="Next" className="p-button-primary" icon="pi pi-check" onClick={ this.Next } />
-                        </div>
-                        <div className="p-col-1">
-                            <Button label="Cancel" className="p-button-danger" icon="pi pi-times" style={{ width: '90px' }} />
+                            <Button label="Cancel" className="p-button-danger" icon="pi pi-times" style={{ width: '90px' }} 
+                                onClick={(e) => {this.props.onCancel()}} />
                         </div>
                     </div>
                 </div>
diff --git a/SAS/TMSS/frontend/tmss_webapp/src/routes/Workflow/decide.acceptance.js b/SAS/TMSS/frontend/tmss_webapp/src/routes/Workflow/decide.acceptance.js
index 7087513f513adf2350dc8fd911b7d9c7953da671..c19c652a1a14fb5910cd130398816f800bf14d37 100644
--- a/SAS/TMSS/frontend/tmss_webapp/src/routes/Workflow/decide.acceptance.js
+++ b/SAS/TMSS/frontend/tmss_webapp/src/routes/Workflow/decide.acceptance.js
@@ -3,54 +3,67 @@ import { Button } from 'primereact/button';
 import SunEditor from 'suneditor-react';
 import 'suneditor/dist/css/suneditor.min.css'; // Import Sun Editor's CSS File
 import { Checkbox } from 'primereact/checkbox';
+import WorkflowService from '../../services/workflow.service';
 
 class DecideAcceptance extends Component {
     constructor(props) {
         super(props);
         this.state = {
-            content: props.report,
-            picomment: props.picomment,  //PI Comment Field
-            showEditor: false,           //Sun Editor
-            checked: false,              //Checkbox
-
+            content: '',
+            comment: '',  
+            showEditor: false,           
+            sos_accept_after_pi: false
         };
         this.Next = this.Next.bind(this);
         this.handleChange = this.handleChange.bind(this);
         this.onChangePIComment = this.onChangePIComment.bind(this);
     }
 
-    
-    // Method will trigger on change of operator report sun-editor
-     handleChange(e) {
+    async componentDidMount() {
+        const qaSOSResponse = await WorkflowService.getQAReportingSOS(this.props.process.qa_reporting_sos);
+        const piVerificationResponse = await WorkflowService.getQAPIverification(this.props.process.pi_verification);
         this.setState({
-            content: e
+            content: qaSOSResponse.sos_report,
+            comment: piVerificationResponse.pi_report
         });
-        localStorage.setItem('report_qa', e);
     }
 
-    //PI Comment Editor
-    onChangePIComment(e) {
-        this.setState({
-            picomment: e.target.value
-        });
-        localStorage.setItem('pi_comment', e.target.value);
+     // Method will trigger on change of operator report sun-editor
+     handleChange(e) {
+        if (e === '<p><br></p>') {
+            this.setState({ content: '' });
+            return;
+        }
+        this.setState({ content: e });
     }
 
-     /**
-     * Method will trigger on click save buton
-     * here onNext props coming from parent, where will handle redirection to other page
-     */
-    Next() {
-        this.props.onNext({
-            report: this.state.content,
-            picomment: this.state.picomment
-
+    async Next() {
+        const currentWorkflowTask = await this.props.getCurrentTaskDetails();
+        const promise = [];
+        if (currentWorkflowTask && !currentWorkflowTask.fields.owner) {
+            promise.push(WorkflowService.updateAssignTo(currentWorkflowTask.pk, { owner: this.state.assignTo }));
+        }
+        promise.push(WorkflowService.updateQA_Perform(this.props.id, {"sos_accept_after_pi":this.state.sos_accept_after_pi}));
+        Promise.all(promise).then((responses) => {
+            if (responses.indexOf(null)<0) {
+                this.props.onNext({ report: this.state.content , pireport: this.state.comment});
+            }   else {
+                this.props.onError();
+            } 
         });
+       
     }
+    
 
-    // Not using at present
-    cancelCreate() {
-        this.props.history.goBack();
+    //PI Comment Editor
+    onChangePIComment(a) {
+        if (a === '<p><br></p>') {
+            localStorage.setItem('comment_pi', '');
+            this.setState({ comment: '' });
+            return;
+        }
+        this.setState({comment: a});
+        localStorage.setItem('comment_pi', a);
     }
 
     render() {
@@ -78,7 +91,7 @@ class DecideAcceptance extends Component {
                                 <div className="col-lg-12 col-md-12 col-sm-12">
                                     {this.state.showEditor && <SunEditor setDefaultStyle="min-height: 250px; height: auto;" enableToolbar={true}
                                         onChange={this.onChangePIComment}
-                                        setContents={this.state.picomment}
+                                        setContents={this.state.comment}
                                         setOptions={{
                                             buttonList: [
                                                 ['undo', 'redo', 'bold', 'underline', 'fontColor', 'table', 'link', 'image', 'video', 'italic', 'strike', 'subscript',
@@ -86,24 +99,25 @@ class DecideAcceptance extends Component {
                                             ]
                                         }}
                                     />}
-                                   <div className="operator-report" dangerouslySetInnerHTML={{ __html: this.state.picomment }}></div>
+                                   <div className="pi-report" dangerouslySetInnerHTML={{ __html: this.state.comment }}></div>
                                 </div>
                             </div>
                         <div className="p-field p-grid">
                             <label htmlFor="piAccept" className="col-lg-2 col-md-2 col-sm-12">SDCO accepts after PI</label>
                             <div className="col-lg-3 col-md-3 col-sm-6">
                                 <div className="p-field-checkbox">
-                                    <Checkbox inputId="binary" checked={this.state.checked} onChange={e => this.setState({ checked: e.checked })} />
+                                    <Checkbox inputId="binary" checked={this.state.sos_accept_after_pi} onChange={e => this.setState({ sos_accept_after_pi: e.checked })} />
                                 </div>
                             </div>
                         </div>
                     </div>
                     <div className="p-grid" style={{ marginTop: '20px' }}>
                         <div className="p-col-1">
-                            <Button label="Next" className="p-button-primary" icon="pi pi-check" onClick = { this.Next } />
+                            <Button label="Next" className="p-button-primary" icon="pi pi-check" onClick = { this.Next } disabled={this.props.disableNextButton} />
                         </div>
                         <div className="p-col-1">
-                            <Button label="Cancel" className="p-button-danger" icon="pi pi-times"  style={{ width : '90px' }}  />
+                            <Button label="Cancel" className="p-button-danger" icon="pi pi-times"  style={{ width : '90px' }}
+                                onClick={(e) => { this.props.onCancel()}} />
                         </div>
                     </div>
 
diff --git a/SAS/TMSS/frontend/tmss_webapp/src/routes/Workflow/index.js b/SAS/TMSS/frontend/tmss_webapp/src/routes/Workflow/index.js
index 8fb9718b9d314c0913820172f8f9720b987e2ecf..775c879181f3d8d7fb1b83270b99c32ee357eb76 100644
--- a/SAS/TMSS/frontend/tmss_webapp/src/routes/Workflow/index.js
+++ b/SAS/TMSS/frontend/tmss_webapp/src/routes/Workflow/index.js
@@ -2,6 +2,7 @@ import React, { useEffect, useState } from 'react';
 import PageHeader from '../../layout/components/PageHeader';
 import {Growl} from 'primereact/components/growl/Growl';
 import { Link } from 'react-router-dom';
+import _ from 'lodash';
 import ScheduleService from '../../services/schedule.service';
 import Scheduled from './Scheduled';
 import ProcessingDone from './processing.done';
@@ -9,83 +10,152 @@ import QAreporting from './qa.reporting';
 import QAsos from './qa.sos';
 import PIverification from './pi.verification';
 import DecideAcceptance from './decide.acceptance';
-import IngestDone from './ingest.done';
-import _ from 'lodash';
+import Ingesting from './ingesting';
 import DataProduct from './unpin.data';
 import UnitConverter from '../../utils/unit.converter';
+import AppLoader from '../../layout/components/AppLoader';
+import WorkflowService from '../../services/workflow.service';
+import DataProductService from '../../services/data.product.service';
 
+const RedirectionMap = {
+    'wait scheduled': 1,
+    'wait processed': 2,
+    'qa reporting to': 3,
+    'qa reporting sos':4,
+    'pi verification':5,
+    'decide acceptance':6,
+    'ingest done':7,
+    'unpin data':8
+ };
 
 //Workflow Page Title 
-const pageTitle = ['Scheduled','Processing Done','QA Reporting (TO)', 'QA Reporting (SDCO)', 'PI Verification', 'Decide Acceptance','Ingest Done','Unpin Data'];
+const pageTitle = ['Waiting To Be Scheduled','Scheduled','QA Reporting (TO)', 'QA Reporting (SDCO)', 'PI Verification', 'Decide Acceptance','Ingest','Unpin Data'];
 
 export default (props) => {
     let growl;
+    // const [disableNextButton, setDisableNextButton] = useState(false);
+    const [loader, setLoader] = useState(false);
     const [state, setState] = useState({});
     const [tasks, setTasks] = useState([]);
-    const [currentStep, setCurrentStep] = useState(1);
+    const [QASUProcess, setQASUProcess] = useState();
+    const [currentStep, setCurrentStep] = useState();
     const [schedulingUnit, setSchedulingUnit] = useState();
-    const [ingestTask, setInjestTask] = useState({});
+    // const [ingestTask, setInjestTask] = useState({});
+    // const [QASchedulingTask, setQASchdulingTask] = useState([]);
+
     useEffect(() => {
-        // Clearing Localstorage on start of the page to load fresh
-        clearLocalStorage();
-        ScheduleService.getSchedulingUnitBlueprintById(props.match.params.id)
-        .then(schedulingUnit => {
-            setSchedulingUnit(schedulingUnit);
-        })
-        const promises = [ScheduleService.getSchedulingUnitBlueprintById(props.match.params.id), ScheduleService.getTaskType()]
+        setLoader(true);
+        const promises = [
+            ScheduleService.getSchedulingUnitExtended('blueprint', props.match.params.id),
+            ScheduleService.getTaskType()
+        ]
         Promise.all(promises).then(responses => {
+            const SUB = responses[0];
             setSchedulingUnit(responses[0]);
-            ScheduleService.getTaskBlueprintsBySchedulingUnit(responses[0], true, false, false, true).then(response => {
-                response.map(task => {
-                    task.actionpath = `/task/view/blueprint/${task.id}/dataproducts`;
-                    (task.dataProducts || []).map(product => {
-                        if (product.size) {
-                            if (!task.totalDataSize) {
-                                task.totalDataSize = 0;
-                            }
-                            task.totalDataSize += product.size;
+            setTasks(SUB.task_blueprints);
+            getStatusUpdate(SUB.task_blueprints);
+        });
+    }, []);
 
-                            // For deleted since
-                            if (!product.deleted_since && product.size) {
-                                if (!task.dataSizeNotDeleted) {
-                                    task.dataSizeNotDeleted = 0;
-                                }
-                                task.dataSizeNotDeleted += product.size;
-                            }
-                        }
-                    });
-                    if (task.totalDataSize) {
-                        task.totalDataSize = UnitConverter.getUIResourceUnit('bytes', (task.totalDataSize));
-                    }
-                    if (task.dataSizeNotDeleted) {
-                        task.dataSizeNotDeleted = UnitConverter.getUIResourceUnit('bytes', (task.dataSizeNotDeleted));
-                    }
-                });
-                setTasks(response);
-                setInjestTask(response.find(task => task.template.type_value==='observation'));
-            });
+    
+    /**
+     * Method to fetch data product for each sub task except ingest.
+     * @param {*} taskItems List of tasks
+     */
+    const getDataProductDetails = async (taskItems) => {
+        // setLoader(true);
+        taskItems = taskItems?taskItems:tasks;
+        const taskList = [...taskItems];
+        for (const task of taskList) {
+            if (task.specifications_template.type_value === 'observation' || task.specifications_template.type_value === 'pipeline') {
+                const promises = [];
+                task.subtasks_ids.map(id => promises.push(DataProductService.getSubtaskOutputDataproduct(id)));
+                const dataProducts = await Promise.all(promises);
+                task['dataProducts'] = dataProducts.filter(product => product.data.length).map(product => product.data).flat();
+                task.actionpath = `/task/view/blueprint/${task.id}/dataproducts`;
+                task.totalDataSize = _.sumBy(task['dataProducts'], 'size');
+                task.dataSizeNotDeleted = _.sumBy(task['dataProducts'], function(product) { return product.deletedSince?0:product.size});
+                if (task.totalDataSize) {
+                    task.totalDataSize = UnitConverter.getUIResourceUnit('bytes', (task.totalDataSize));
+                }
+                if (task.dataSizeNotDeleted) {
+                    task.dataSizeNotDeleted = UnitConverter.getUIResourceUnit('bytes', (task.dataSizeNotDeleted));
+                }
+            }
+        }
+        // setInjestTask(taskList.find(task => task.specifications_template.type_value==='ingest'));
+        // setTasks(taskList);
+        // setLoader(false);
+    };
+
+    /**
+     * Method to fetch current step workflow details 
+     * @param {*} taskList List of tasks
+     */
+    const getStatusUpdate = (taskList) => {
+        setLoader(true);
+        const promises = [
+            WorkflowService.getWorkflowProcesses(),
+            WorkflowService.getWorkflowTasks()
+        ]
+        Promise.all(promises).then(async responses => {
+            const suQAProcess = responses[0].find(process => process.su === parseInt(props.match.params.id));
+            setQASUProcess(suQAProcess);
+            const suQAProcessTasks = responses[1].filter(item => item.process === suQAProcess.id);
+            // setQASchdulingTask(suQAProcessTasks);
+            // const workflowLastTask = responses[1].find(task => task.process === suQAProcess.id);
+            const workflowLastTask = (_.orderBy(suQAProcessTasks, ['id'], ['desc']))[0];
+            setCurrentStep(RedirectionMap[workflowLastTask.flow_task.toLowerCase()]);
+            // Need to cross check below if condition if it fails in next click
+            if (workflowLastTask.status === 'NEW') {
+                setCurrentStep(RedirectionMap[workflowLastTask.flow_task.toLowerCase()]);
+            } //else {
+            //     setCurrentStep(3);
+            // }
+            else if (workflowLastTask.status.toLowerCase() === 'done' || workflowLastTask.status.toLowerCase() === 'finished') {
+                await getDataProductDetails(taskList);
+                // setDisableNextButton(true);
+                setCurrentStep(8);
+            }
+            setLoader(false); 
         });
-}, []);
+    }
 
-    const clearLocalStorage = () => {
-        localStorage.removeItem('pi_comment');
-        localStorage.removeItem('report_qa');
+    const getIngestTask = () => {
+        return tasks.find(task => task.specifications_template.type_value==='ingest')
     }
-    
-    //Pages changes step by step
+
+    const getCurrentTaskDetails = async () => {
+        // const response = await WorkflowService.getCurrentTask(props.match.params.id);
+        const response = await WorkflowService.getCurrentTask(QASUProcess.id);
+        return response;
+    };
+
+   //Pages changes step by step
     const onNext = (content) => {
         setState({...state, ...content});
-        setCurrentStep(currentStep + 1);  
+        getStatusUpdate(tasks);
     };
 
+    const onCancel = () => {
+        props.history.goBack();
+    }
+
+    //TODO: Need to customize this function to have different messages.
+    const showMessage = () => {
+        growl.show({severity: 'error', summary: 'Unable to proceed', detail: 'Please clear your browser cookies and try again'});
+    }
+
+    const title = pageTitle[currentStep - 1];
     return (
         <>
             <Growl ref={(el) => growl = el} />
-            <PageHeader location={props.location} title={`${pageTitle[currentStep - 1]}`} actions={[{ icon: 'fa-window-close', link: props.history.goBack, title: 'Click to Close Workflow', props: { pathname: '/schedulingunit/1/workflow' } }]} />
-            {schedulingUnit &&
+            {currentStep && <PageHeader location={props.location} title={`${title}`} actions={[{ icon: 'fa-window-close', link: props.history.goBack, title: 'Click to Close Workflow', props: { pathname: '/schedulingunit/1/workflow' } }]} />}
+            {loader && <AppLoader />}
+            {!loader && schedulingUnit &&
                 <>
                     <div className="p-fluid">
-                        <div className="p-field p-grid">
+                        {currentStep && <div className="p-field p-grid">
                             <label htmlFor="suName" className="col-lg-2 col-md-2 col-sm-12">Scheduling Unit</label>
                             <div className="col-lg-3 col-md-3 col-sm-12">
                                 <Link to={{ pathname: `/schedulingunit/view/blueprint/${schedulingUnit.id}` }}>{schedulingUnit.name}</Link>
@@ -98,24 +168,35 @@ export default (props) => {
                             <label htmlFor="viewPlots" className="col-lg-2 col-md-2 col-sm-12">View Plots</label>
                             <div className="col-lg-3 col-md-3 col-sm-12" style={{ paddingLeft: '2px' }}>
                                 <label className="col-sm-10 " >
-                                    <a href="https://proxy.lofar.eu/inspect/HTML/" target="_blank">Inspection plots</a>
+                                    <a rel="noopener noreferrer" href="https://proxy.lofar.eu/inspect/HTML/" target="_blank">Inspection plots</a>
                                 </label>
                                 <label className="col-sm-10 ">
-                                    <a href="https://proxy.lofar.eu/qa" target="_blank">Adder plots</a>
+                                    <a rel="noopener noreferrer" href="https://proxy.lofar.eu/qa" target="_blank">Adder plots</a>
                                 </label>
                                 <label className="col-sm-10 ">
                                     <a href=" https://proxy.lofar.eu/lofmonitor/" target="_blank">Station Monitor</a>
                                 </label>
                             </div>
-                        </div>
-                        {currentStep === 1 && <Scheduled onNext={onNext} {...state} schedulingUnit={schedulingUnit} />}
-                        {currentStep === 2 && <ProcessingDone onNext={onNext} {...state}/>}
-                        {currentStep === 3 && <QAreporting onNext={onNext}/>}
-                        {currentStep === 4 && <QAsos onNext={onNext} {...state} />}
-                        {currentStep === 5 && <PIverification onNext={onNext} {...state} />}
-                        {currentStep === 6 && <DecideAcceptance onNext={onNext} {...state} />}
-                        {currentStep === 7 && <IngestDone onNext={onNext}{...state} task={ingestTask} />}
-                        {currentStep === 8 && <DataProduct onNext={onNext} tasks={tasks} schedulingUnit={schedulingUnit} />}
+                        </div>}
+                        {currentStep === 1 && <Scheduled onNext={onNext} onCancel={onCancel} 
+                                                schedulingUnit={schedulingUnit} /*disableNextButton={disableNextButton}*/ />}
+                        {currentStep === 2 && <ProcessingDone onNext={onNext} onCancel={onCancel} 
+                                                schedulingUnit={schedulingUnit}  />}
+                        {currentStep === 3 && <QAreporting onNext={onNext} onCancel={onCancel} id={QASUProcess.id} 
+                                                getCurrentTaskDetails={getCurrentTaskDetails} onError={showMessage} />}
+                        {currentStep === 4 && <QAsos onNext={onNext} onCancel={onCancel} id={QASUProcess.id} 
+                                                process={QASUProcess} getCurrentTaskDetails={getCurrentTaskDetails} 
+                                                onError={showMessage} />}
+                        {currentStep === 5 && <PIverification onNext={onNext} onCancel={onCancel} id={QASUProcess.id} 
+                                                process={QASUProcess} getCurrentTaskDetails={getCurrentTaskDetails} 
+                                                onError={showMessage} />}
+                        {currentStep === 6 && <DecideAcceptance onNext={onNext} onCancel={onCancel} id={QASUProcess.id} 
+                                                process={QASUProcess} getCurrentTaskDetails={getCurrentTaskDetails} 
+                                                onError={showMessage} />}
+                        {currentStep === 7 && <Ingesting onNext={onNext} onCancel={onCancel} id={QASUProcess.id} 
+                                                 onError={showMessage} task={getIngestTask()} />}
+                        {currentStep === 8 && <DataProduct onNext={onNext} onCancel={onCancel} onError={showMessage} 
+                                                tasks={tasks} schedulingUnit={schedulingUnit} />}
                     </div>
                 </>
             }
diff --git a/SAS/TMSS/frontend/tmss_webapp/src/routes/Workflow/ingest.done.js b/SAS/TMSS/frontend/tmss_webapp/src/routes/Workflow/ingesting.js
similarity index 66%
rename from SAS/TMSS/frontend/tmss_webapp/src/routes/Workflow/ingest.done.js
rename to SAS/TMSS/frontend/tmss_webapp/src/routes/Workflow/ingesting.js
index 6c830385fa71f8c0eb2bb5da5854de921f68fbe8..77c795899b9b1ea4c4288eafe2bc0d1145abe823 100644
--- a/SAS/TMSS/frontend/tmss_webapp/src/routes/Workflow/ingest.done.js
+++ b/SAS/TMSS/frontend/tmss_webapp/src/routes/Workflow/ingesting.js
@@ -1,8 +1,7 @@
 import React, { Component } from 'react';
 import { Button } from 'primereact/button';
-import { Link } from 'react-router-dom';
 
-class IngestDone extends Component {
+class Ingesting extends Component {
     constructor(props) {
         super(props);
         this.state = { };
@@ -10,10 +9,7 @@ class IngestDone extends Component {
     }
 
     onSave(){
-        this.props.onNext({
-            report: this.props.report,
-            picomment: this.props.picomment
-        });
+        this.props.onNext({});
     }
 
     render(){
@@ -28,23 +24,20 @@ class IngestDone extends Component {
                             <div className="col-lg-1 col-md-1 col-sm-12"></div>
                             <label htmlFor="ingestTask" className="col-lg-2 col-md-2 col-sm-12">Ingest Task</label>
                             <div className="col-lg-3 col-md-3 col-sm-12">
-                            <a href={`${window.location.origin}/task/view/blueprint/${this.props.task.id}`}>{this.props.task.name}</a>
+                            <a rel="noopener noreferrer" href={`${window.location.origin}/task/view/blueprint/${this.props.task.id}`}>{this.props.task.name}</a>
                             </div>
                             <label htmlFor="ingestMonitoring" className="col-lg-2 col-md-2 col-sm-12">Ingest Monitoring</label>
                             <label className="col-sm-10 " >
-                                <a href="http://lexar003.control.lofar:9632/" target="_blank">View Ingest Monitoring &nbsp;<span class="fas fa-desktop"></span></a>
+                                <a rel="noopener noreferrer" href="http://lexar003.control.lofar:9632/" target="_blank">View Ingest Monitoring &nbsp;<span class="fas fa-desktop"></span></a>
                             </label>
-                                
-                            {/* <div className="col-lg-3 col-md-3 col-sm-12">
-                                <Link to={{ pathname: `http://lexar003.control.lofar:9632/` }}> View Ingest Monitoring &nbsp;<span class="fas fa-desktop"></span></Link>
-                            </div> */}
                         </div>
                         <div className="p-grid p-justify-start">
                         <div className="p-col-1">
                             <Button label="Next" className="p-button-primary" icon="pi pi-check"  onClick={ this.onSave }/>
                         </div>
                         <div className="p-col-1">
-                            <Button label="Cancel" className="p-button-danger" icon="pi pi-times"  style={{ width : '90px' }} />
+                            <Button label="Cancel" className="p-button-danger" icon="pi pi-times"  style={{ width : '90px' }}
+                                onClick={(e) => { this.props.onCancel()}} />
                         </div>
                         </div>
                     </div>
@@ -53,4 +46,4 @@ class IngestDone extends Component {
     };
     
 }
-export default IngestDone;
\ No newline at end of file
+export default Ingesting
\ No newline at end of file
diff --git a/SAS/TMSS/frontend/tmss_webapp/src/routes/Workflow/pi.verification.js b/SAS/TMSS/frontend/tmss_webapp/src/routes/Workflow/pi.verification.js
index f63a6fe0591e6dd6acd9fd5bc72c1988c33fc358..dd4492e9314ee077e2effd7620ee433fc66efb46 100644
--- a/SAS/TMSS/frontend/tmss_webapp/src/routes/Workflow/pi.verification.js
+++ b/SAS/TMSS/frontend/tmss_webapp/src/routes/Workflow/pi.verification.js
@@ -3,38 +3,58 @@ import { Button } from 'primereact/button';
 import SunEditor from 'suneditor-react';
 import 'suneditor/dist/css/suneditor.min.css'; // Import Sun Editor's CSS File
 import { Checkbox } from 'primereact/checkbox';
+import WorkflowService from '../../services/workflow.service';
 //import {InputTextarea} from 'primereact/inputtextarea';
 
 class PIverification extends Component {
     constructor(props) {
         super(props);
         this.state = {
-            content: props.report,
+            content: '',
+            comment: '',
             showEditor: false,
+            pi_accept: false
         };
         this.Next = this.Next.bind(this);
         this.handleChange = this.handleChange.bind(this);
         this.onChangePIComment = this.onChangePIComment.bind(this);
     }
+
+    async componentDidMount() {
+        const response = await WorkflowService.getQAReportingSOS(this.props.process.qa_reporting_sos);
+        this.setState({
+            content: response.sos_report
+        });
+    }
     
      /**
-     * Method wiill trigger on change of operator report sun-editor
+     * Method will trigger on change of operator report sun-editor
      */
     handleChange(e) {
-        this.setState({
-            comment: e
-        });
-        localStorage.setItem('report_pi', e);
+        if (e === '<p><br></p>') {
+            this.setState({ content: '' });
+            return;
+        }
+        this.setState({ content: e });
     }
 
-     /**
-     * Method will trigger on click save buton
+    /**
+     * Method will trigger on click save button
      * here onNext props coming from parent, where will handle redirection to other page
      */
-    Next(){
-        this.props.onNext({
-            report: this.state.content,
-            picomment: this.state.comment
+    async Next() {
+        const currentWorkflowTask = await this.props.getCurrentTaskDetails();
+        const promise = [];
+        if (currentWorkflowTask && !currentWorkflowTask.fields.owner) {
+            promise.push(WorkflowService.updateAssignTo(currentWorkflowTask.pk),{ owner: this.state.assignTo });
+        }
+        promise.push(WorkflowService.updateQA_Perform(this.props.id,{"pi_report": this.state.comment, "pi_accept": this.state.pi_accept}));
+        Promise.all(promise).then((responses) => {
+            if (responses.indexOf(null)<0) {
+                this.props.onNext({ report:this.state.content, pireport: this.state.comment});
+            }   else {
+                this.props.onError();
+            }
         });
     }
 
@@ -42,15 +62,11 @@ class PIverification extends Component {
      * Method wiill triigger on change of pi report sun-editor
      */
     onChangePIComment(a) {
-        this.setState({
-            comment: a
-        });
-        localStorage.setItem('comment_pi', a);
-    }
-
-    // Not using at present
-    cancelCreate() {
-        this.props.history.goBack();
+        if (a === '<p><br></p>') {
+            this.setState({ comment: '' });
+            return;
+        }
+        this.setState({comment: a  });
     }
 
     render() {
@@ -74,7 +90,7 @@ class PIverification extends Component {
                              <div className="operator-report" dangerouslySetInnerHTML={{ __html: this.state.content }}></div>
                         </div>
                         <div className="p-grid" style={{ padding: '10px' }}>
-                            <label htmlFor="piReport" >PI Report</label>
+                            <label htmlFor="piReport" >PI Report<span style={{color:'red'}}>*</span></label>
                             <div className="col-lg-12 col-md-12 col-sm-12"></div>
                             <SunEditor setDefaultStyle="min-height: 150px; height: auto;" enableToolbar={true}
                                 setContents={this.state.comment}
@@ -85,25 +101,20 @@ class PIverification extends Component {
                                             'superscript', 'outdent', 'indent', 'fullScreen', 'showBlocks', 'codeView', 'preview', 'print', 'removeFormat']
                                     ]
                                 }} />
-                                   {/* <InputTextarea rows={3} cols={30}
-                                    tooltip="PIReport" tooltipOptions={this.tooltipOptions} maxLength="128"
-                                    data-testid="PIReport"
-                                    value={this.state.piComment}
-                                    onChange={this.onChangePIComment}
-                            /> */}
-                        </div>      
+                            </div>      
                         <div className="p-field p-grid">
                             <label htmlFor="piAccept" className="col-lg-2 col-md-2 col-sm-12">PI Accept</label>
                             <div className="p-field-checkbox">
-                                    <Checkbox inputId="binary" checked={this.state.checked} onChange={e => this.setState({ checked: e.checked })} />
+                                    <Checkbox inputId="binary" checked={this.state.pi_accept} onChange={e => this.setState({ pi_accept: e.checked })} />
                             </div>
                         </div>
                         <div className="p-grid" style={{ marginTop: '20px' }}>
                             <div className="p-col-1">
-                                <Button label="Next" className="p-button-primary" icon="pi pi-check" onClick={ this.Next } />
+                                <Button disabled= {!this.state.comment} label="Next" className="p-button-primary" icon="pi pi-check" onClick={ this.Next } />
                             </div>
                             <div className="p-col-1">
-                                <Button label="Cancel" className="p-button-danger" icon="pi pi-times"  style={{ width : '90px' }} />
+                                <Button label="Cancel" className="p-button-danger" icon="pi pi-times"  style={{ width : '90px' }}
+                                    onClick={(e) => { this.props.onCancel()}} />
                             </div>
                         </div>
                     </div>  
diff --git a/SAS/TMSS/frontend/tmss_webapp/src/routes/Workflow/processing.done.js b/SAS/TMSS/frontend/tmss_webapp/src/routes/Workflow/processing.done.js
index 07c7ca9cdca1ae96d2d8ce166d836303036ccbc0..42bf78d229f16924fc44226fda9b99c1a73ffcf5 100644
--- a/SAS/TMSS/frontend/tmss_webapp/src/routes/Workflow/processing.done.js
+++ b/SAS/TMSS/frontend/tmss_webapp/src/routes/Workflow/processing.done.js
@@ -1,14 +1,15 @@
 import React, { Component } from 'react';
 import { Button } from 'primereact/button';
+import { Link } from 'react-router-dom';
+import moment from 'moment';
 
 class ProcessingDone extends Component {
-
     constructor(props) {
         super(props);
         this.Next = this.Next.bind(this);
     }
-
-     /**
+    
+    /**
      * Method will trigger on click save buton
      * here onNext props coming from parent, where will handle redirection to other page
      */
@@ -19,12 +20,29 @@ class ProcessingDone extends Component {
     render(){
             return(
                     <>
+                         <div className="p-fluid">
+                            <div className="p-field p-grid">
+                                <label htmlFor="startTime" className="col-lg-2 col-md-2 col-sm-12">Start Time</label>
+                                <div className="col-lg-3 col-md-3 col-sm-12">
+                                    <span>{this.props.schedulingUnit.start_time && moment(this.props.schedulingUnit.start_time).format("YYYY-MMM-DD HH:mm:SS")}</span>
+                                </div>
+                                <div className="col-lg-1 col-md-1 col-sm-12"></div>
+                                <label htmlFor="endTime" className="col-lg-2 col-md-2 col-sm-12">End Time</label>
+                                <div className="col-lg-3 col-md-3 col-sm-12">
+                                    <span>{this.props.schedulingUnit.stop_time && moment(this.props.schedulingUnit.stop_time).format("YYYY-MMM-DD HH:mm:SS")}</span>
+                                </div>
+                                <div className="col-lg-1 col-md-1 col-sm-12"></div>
+                                <label htmlFor="timeLine" className="col-lg-2 col-md-2 col-sm-12">Timeline</label>
+                                <div className="col-lg-3 col-md-3 col-sm-12 block-list">
+                                    <Link to={{ pathname: '/su/timelineview' }}>TimeLine View &nbsp; <span class="fas fa-clock"></span></Link>
+                                    <Link to={{ pathname: '/su/timelineview/week' }}>Week Overview &nbsp; <span class="fas fa-calendar-alt"></span></Link>
+                                </div>
+                            </div>
+                         </div>
                         <div className="p-grid p-justify-start">
                         <div className="p-col-1">
-                            <Button label="Next" className="p-button-primary" icon="pi pi-check"  onClick={ this.Next }/>
-                        </div>
-                        <div className="p-col-1">
-                            <Button label="Cancel" className="p-button-danger" icon="pi pi-times"  style={{ width : '90px' }} />
+                            <Button label="Cancel" className="p-button-danger" icon="pi pi-times"  style={{ width : '90px' }} 
+                                onClick={(e) => {this.props.onCancel()}} />
                         </div>
                         </div>
                 
diff --git a/SAS/TMSS/frontend/tmss_webapp/src/routes/Workflow/qa.reporting.js b/SAS/TMSS/frontend/tmss_webapp/src/routes/Workflow/qa.reporting.js
index 1c4684e2c5b5b13e34cd1a2f87a27118c27f33f8..ef425cf3f9c5fd53495ce418c7c9b38cbd8e04a6 100644
--- a/SAS/TMSS/frontend/tmss_webapp/src/routes/Workflow/qa.reporting.js
+++ b/SAS/TMSS/frontend/tmss_webapp/src/routes/Workflow/qa.reporting.js
@@ -3,6 +3,8 @@ import { Button } from 'primereact/button';
 import SunEditor from 'suneditor-react';
 import 'suneditor/dist/css/suneditor.min.css'; // Import Sun Editor's CSS File
 import { Dropdown } from 'primereact/dropdown';
+import WorkflowService from '../../services/workflow.service';
+import { Checkbox } from 'primereact/checkbox';
 //import katex from 'katex' // for mathematical operations on sun editor this component should be added
 //import 'katex/dist/katex.min.css'
 
@@ -11,47 +13,59 @@ class QAreporting extends Component{
     constructor(props) {
         super(props);
         this.state={
-            content: props.report
+            content: '',
+            assignTo: '',
+            operator_accept: false,
         };
         this.Next = this.Next.bind(this);
         this.handleChange = this.handleChange.bind(this);
     }
 
     /**
-     * Method will trigger on click save buton
+     * Method will trigger on click next buton
      * here onNext props coming from parent, where will handle redirection to other page
      */
-     Next() {
-        this.props.onNext({ report: this.state.content });
-     }
+     async Next() {
+        const currentWorkflowTask = await this.props.getCurrentTaskDetails();
+        const promise = [];
+        if (currentWorkflowTask && !currentWorkflowTask.fields.owner) {
+            promise.push(WorkflowService.updateAssignTo(currentWorkflowTask.pk, { owner: this.state.assignTo }));
+        }
+        promise.push(WorkflowService.updateQA_Perform(this.props.id, {"operator_report": this.state.content, "operator_accept": this.state.operator_accept}));
+        Promise.all(promise).then((responses) => {
+            if (responses.indexOf(null)<0) {
+                this.props.onNext({ report: this.state.content });
+            }   else {
+                this.props.onError();
+            } 
+        });
+    }
 
     /**
      * Method will trigger on change of operator report sun-editor
      */
     handleChange(e) {
-        localStorage.setItem('report_qa', e); 
+        if (e === '<p><br></p>') {
+            this.setState({ content: '' });
+            return;
+        }
         this.setState({ content: e });
     }
 
-    //Not using at present
-    cancelCreate() {
-        this.props.history.goBack();
-    }
-
     render() {
         return (
         <>
             <div className="p-fluid">
                 <div className="p-field p-grid">
-                    <label htmlFor="assignTo" className="col-lg-2 col-md-2 col-sm-12">Assign To </label>
+                    <label htmlFor="assignTo" className="col-lg-2 col-md-2 col-sm-12">Assign To</label>
                     <div className="col-lg-3 col-md-3 col-sm-12" data-testid="assignTo" >
-                        <Dropdown inputId="assignToValue" optionLabel="value" optionValue="value"
-                            options={[{ value: 'User 1' }, { value: 'User 2' }, { value: 'User 3' }]}
+                    <Dropdown inputId="assignToValue" value={this.state.assignTo} optionLabel="value" optionValue="id" onChange={(e) => this.setState({assignTo: e.value})}
+                            options={[{ value: 'User 1', id: 1 }, { value: 'User 2', id: 2 }, { value: 'User 3', id: 3 }]}
                             placeholder="Assign To" />
                     </div>
                 </div>
                 <div className="p-grid" style={{ padding: '10px' }}>
-                    <label htmlFor="comments" >Comments</label>
+                    <label htmlFor="comments" >Comments<span style={{color:'red'}}>*</span></label>
                     <div className="col-lg-12 col-md-12 col-sm-12"></div>
                     <SunEditor enableToolbar={true}
                         setDefaultStyle="min-height: 250px; height: auto;"
@@ -64,12 +78,19 @@ class QAreporting extends Component{
                         }} />
                 </div>
             </div>
+            <div className="p-grid">
+                    <div className="p-col-12">
+                        <Checkbox inputId="operator_accept" onChange={e => this.setState({operator_accept: e.checked})} checked={this.state.operator_accept}></Checkbox>
+                        <label htmlFor="operator_accept " className="p-checkbox-label">Operator Accept</label>
+                    </div>
+            </div>
             <div className="p-grid p-justify-start">
                 <div className="p-col-1">
-                    <Button label="Next" className="p-button-primary" icon="pi pi-check" onClick={ this.Next } />
+                <Button disabled= {!this.state.content} label="Next" className="p-button-primary" icon="pi pi-check" onClick={ this.Next } />
                 </div>
                 <div className="p-col-1">
-                    <Button label="Cancel" className="p-button-danger" icon="pi pi-times"  style={{ width : '88px' }}/>
+                    <Button label="Cancel" className="p-button-danger" icon="pi pi-times"  style={{ width : '88px' }} 
+                                onClick={(e) => { this.props.onCancel()}} />
                 </div>
             </div>
         </>
diff --git a/SAS/TMSS/frontend/tmss_webapp/src/routes/Workflow/qa.sos.js b/SAS/TMSS/frontend/tmss_webapp/src/routes/Workflow/qa.sos.js
index 59ef61e29ac4d7f2fe3eb7510fc290e65febff47..b32d13319c490a36c033b4d83a0b5d42d613e08a 100644
--- a/SAS/TMSS/frontend/tmss_webapp/src/routes/Workflow/qa.sos.js
+++ b/SAS/TMSS/frontend/tmss_webapp/src/routes/Workflow/qa.sos.js
@@ -3,42 +3,59 @@ import { Button } from 'primereact/button';
 import SunEditor from 'suneditor-react';
 import 'suneditor/dist/css/suneditor.min.css'; // Import Sun Editor's CSS File
 import { Checkbox } from 'primereact/checkbox';
+import WorkflowService from '../../services/workflow.service';
 
 class QAreportingSDCO extends Component {
     constructor(props) {
         super(props);
         this.state = {
-            content: props.report,
+            content: '',
             showEditor: false,
-            checked: false,
-            pichecked: false
-                        
+            quality_within_policy: false,
+            sos_accept_show_pi: false
         };
         this.Next = this.Next.bind(this);
         this.handleChange = this.handleChange.bind(this);
     }
 
+    async componentDidMount() {
+        const response = await WorkflowService.getQAReportingTo(this.props.process.qa_reporting_to);
+        this.setState({
+            content: response.operator_report
+        });
+    }
+
     /**
      * Method will trigger on change of sun-editor
      */
     handleChange(e) {
-        this.setState({
-            content: e
-        });
-        localStorage.setItem('report_qa', e);
+        if (e === '<p><br></p>') {
+            this.setState({ content: '' });
+            return;
+        }
+        this.setState({ content: e });
     }
 
-    /**
-     * Method will trigger on click save buton
+     /**
+     * Method will trigger on click Next buton
      * here onNext props coming from parent, where will handle redirection to other page
      */
-    Next() {
-        this.props.onNext({
-            report: this.state.content,
-            piChecked: this.state.pichecked
-     })
+    async Next() {
+        const currentWorkflowTask = await this.props.getCurrentTaskDetails();
+        const promise = [];
+        if (currentWorkflowTask && !currentWorkflowTask.fields.owner) {
+            promise.push(WorkflowService.updateAssignTo(currentWorkflowTask.pk, { owner: this.state.assignTo }));
+        }
+        promise.push(WorkflowService.updateQA_Perform(this.props.id, {"sos_report": this.state.content, "sos_accept_show_pi": this.state.sos_accept_show_pi, "quality_within_policy": this.state.quality_within_policy}));
+        Promise.all(promise).then((responses) => {
+            if (responses.indexOf(null)<0) {
+                this.props.onNext({ report: this.state.content });
+            }   else {
+                this.props.onError();
+            }
+        });
     }
-
+  
     //Not using at present
     cancelCreate() {
         this.props.history.goBack();
@@ -53,19 +70,22 @@ class QAreportingSDCO extends Component {
                             <label htmlFor="qualityPolicy" className="col-lg-2 col-md-2 col-sm-12">Quality Policy</label>
                             <div className="col-lg-3 col-md-3 col-sm-12">
                                 <div className="p-field-checkbox">
-                                <Checkbox inputId="binary" checked={this.state.checked} onChange={e => this.setState({ checked: e.checked })} />
+                                <Checkbox inputId="quality_within_policy" checked={this.state.quality_within_policy} onChange={e => this.setState({quality_within_policy: e.checked})} />
                                 </div>
                             </div>
                             <div className="col-lg-1 col-md-1 col-sm-12"></div>
                             <label htmlFor="sdcoAccept" className="col-lg-2 col-md-2 col-sm-12">SDCO Accept</label>
                             <div className="col-lg-3 col-md-3 col-sm-12">
                                 <div className="p-field-checkbox">
-                                    <Checkbox inputId="secondary" pichecked={this.state.pichecked} onChange={e => this.setState({ pichecked: e.pichecked })} />
+                                    <Checkbox inputId="sos_accept_show_pi" checked={this.state.sos_accept_show_pi} onChange={e => this.setState({ sos_accept_show_pi: e.checked })} />
                                 </div>
                             </div>
                         </div>
                         <div className="p-grid" style={{ padding: '10px' }}>
-                           <label htmlFor="operatorReport" >Operator Report {!this.state.showEditor && <span className="con-edit">(Click content to edit)</span>}</label>
+                        <label htmlFor="operatorReport" >
+                               Operator Report {!this.state.showEditor && <span className="con-edit">(Click content to edit)</span>}
+                               <span style={{color:'red'}}>*</span>
+                            </label>
                            <div className="col-lg-12 col-md-12 col-sm-12"></div>
                            {this.state.showEditor && <SunEditor setDefaultStyle="min-height: 250px; height: auto" enableToolbar={true}
                                 onChange={this.handleChange}
@@ -82,16 +102,16 @@ class QAreportingSDCO extends Component {
                     </div>
                     <div className="p-grid" style={{ marginTop: '20px' }}>
                         <div className="p-col-1">
-                            <Button label="Next" className="p-button-primary" icon="pi pi-check" onClick={ this.Next } />
+                            <Button label="Next" disabled= {!this.state.content} className="p-button-primary" icon="pi pi-check" onClick={ this.Next } />
                         </div>
                         <div className="p-col-1">
-                            <Button label="Cancel" className="p-button-danger" icon="pi pi-times"  style={{ width : '90px' }}  />
+                            <Button label="Cancel" className="p-button-danger" icon="pi pi-times"  style={{ width : '90px' }} 
+                                onClick={(e) => { this.props.onCancel()}} />
                         </div>
                     </div>
                 </div>
             </>
         )
     };
-
 }
 export default QAreportingSDCO;
\ No newline at end of file
diff --git a/SAS/TMSS/frontend/tmss_webapp/src/routes/Workflow/unpin.data.js b/SAS/TMSS/frontend/tmss_webapp/src/routes/Workflow/unpin.data.js
index f4893b6f5a35de0f32b79b447da14c99d7382750..ee4de9a3ed910123b1e386eef96589d1af5c82d7 100644
--- a/SAS/TMSS/frontend/tmss_webapp/src/routes/Workflow/unpin.data.js
+++ b/SAS/TMSS/frontend/tmss_webapp/src/routes/Workflow/unpin.data.js
@@ -3,12 +3,12 @@ import { Button } from 'primereact/button';
 import { Dialog } from 'primereact/dialog';
 import ViewTable from './../../components/ViewTable';
 
-export default ({ tasks, schedulingUnit }) => {
+export default ({ tasks, schedulingUnit, onCancel }) => {
     const [showConfirmDialog, setShowConfirmDialog] = useState(false);
     const defaultcolumns = [ {
         name: "Name",
         totalDataSize:"Total Data Size(TB)", 
-        dataSizeNotDeleted :"Data Size Not Deleted(TB)"
+        dataSizeNotDeleted :"Data Size on Disk(TB)"
     }];
     const optionalcolumns = [{
         actionpath:"actionpath",
@@ -25,7 +25,7 @@ export default ({ tasks, schedulingUnit }) => {
         <div className="p-fluid mt-2">
         <label><h6>Details of data products of Tasks</h6></label>
          <ViewTable 
-                 data={tasks.filter(task => task.template.name !== 'ingest' && (task.totalDataSize || task.dataSizeNotDeleted))} 
+                 data={tasks.filter(task => (task.totalDataSize || task.dataSizeNotDeleted))} 
                 optionalcolumns={optionalcolumns}
                 defaultcolumns={defaultcolumns} 
                 defaultSortColumn={defaultSortColumn}
@@ -43,7 +43,8 @@ export default ({ tasks, schedulingUnit }) => {
                     <Button label="Delete" className="p-button-primary" icon="pi pi-trash" onClick={toggleDialog} />
                 </div>
                 <div className="p-col-1">
-                    <Button label="Cancel" className="p-button-danger" icon="pi pi-times" style={{ width: '90px' }} />
+                    <Button label="Cancel" className="p-button-danger" icon="pi pi-times" style={{ width: '90px' }}
+                            onClick={(e) => { onCancel()}} />
                 </div>
             </div>
             <div className="p-grid" data-testid="confirm_dialog">
@@ -66,4 +67,4 @@ export default ({ tasks, schedulingUnit }) => {
             </div>
         </div>
     )
-}
\ No newline at end of file
+}
diff --git a/SAS/TMSS/frontend/tmss_webapp/src/routes/index.js b/SAS/TMSS/frontend/tmss_webapp/src/routes/index.js
index ffaeeac79c33f3fbad5a109796b76171bebc723b..afe449b4d5daa05d04f2207a4647a8dd5ba397a0 100644
--- a/SAS/TMSS/frontend/tmss_webapp/src/routes/index.js
+++ b/SAS/TMSS/frontend/tmss_webapp/src/routes/index.js
@@ -15,7 +15,7 @@ import SchedulingUnitCreate from './Scheduling/create';
 import EditSchedulingUnit from './Scheduling/edit';
 import { CycleList, CycleCreate, CycleView, CycleEdit } from './Cycle';
 import { TimelineView, WeekTimelineView, ReservationCreate, ReservationList } from './Timeline';
-import SchedulingSetCreate from './Scheduling/create.scheduleset';
+import SchedulingSetCreate from './Scheduling/excelview.schedulingset';
 import Workflow from './Workflow';
 
 export const routes = [
diff --git a/SAS/TMSS/frontend/tmss_webapp/src/services/schedule.service.js b/SAS/TMSS/frontend/tmss_webapp/src/services/schedule.service.js
index 506f246c4423d9083548e43ebf5bb806d842a1ba..072ff6ca0dcbf92f0914152c772b9ab3352e2969 100644
--- a/SAS/TMSS/frontend/tmss_webapp/src/services/schedule.service.js
+++ b/SAS/TMSS/frontend/tmss_webapp/src/services/schedule.service.js
@@ -45,17 +45,17 @@ const ScheduleService = {
         }
         return blueprints;
     },
-    getSchedulingUnitExtended: async function (type, id){
+    getSchedulingUnitExtended: async function (type, id, ignoreRef){
         let schedulingUnit = null;
         try {
             const response = await axios.get(`/api/scheduling_unit_${type}_extended/${id}/`);
             schedulingUnit = response.data;
-            if (schedulingUnit) {
+            if (schedulingUnit && !ignoreRef) {
                 if (type === "blueprint") {
                     const schedulingUnitDraft = (await axios.get(`/api/scheduling_unit_draft/${schedulingUnit.draft_id}/`)).data;
                     schedulingUnit.draft_object = schedulingUnitDraft;
                     schedulingUnit.scheduling_set_id = schedulingUnitDraft.scheduling_set_id;
-                    schedulingUnit.scheduling_constraints_doc = schedulingUnitDraft.scheduling_constraints_doc;
+                    schedulingUnit.scheduling_constraints_doc = schedulingUnitDraft.scheduling_constraints_doc?schedulingUnitDraft.scheduling_constraints_doc:{};
                 }   else {
                     // Fetch all blueprints data associated with draft to display the name
                     schedulingUnit.blueprintList = (await this.getBlueprintsByschedulingUnitId(schedulingUnit.id)).data.results;
@@ -137,6 +137,15 @@ const ScheduleService = {
             return null;
         }
     },
+    getSubtaskOutputDataproduct: async function(id){
+        try {
+          const url = `/api/subtask/${id}/output_dataproducts/`;
+          const response = await axios.get(url);
+          return response.data;
+        } catch (error) {
+          console.error('[data.product.getSubtaskOutputDataproduct]',error);
+        }
+    },
     getTaskBlueprintById: async function(id, loadTemplate, loadSubtasks, loadSubtaskTemplate){
         let result;
         try {
@@ -302,11 +311,11 @@ const ScheduleService = {
             if (loadTemplate) {
                 const ingest = scheduletasklist.find(task => task.template.type_value === 'ingest' && task.tasktype.toLowerCase() === 'draft');
                 const promises = [];
-                ingest.produced_by_ids.map(id => promises.push(this.getTaskRelation(id)));
+                ingest.produced_by_ids.forEach(id => promises.push(this.getTaskRelation(id)));
                 const response = await Promise.all(promises);
-                response.map(producer => {
+                response.forEach(producer => {
                     const tasks = scheduletasklist.filter(task => producer.producer_id  === task.id);
-                    tasks.map(task => {
+                    tasks.forEach(task => {
                        task.canIngest = true;
                     });
                 });
@@ -397,6 +406,15 @@ const ScheduleService = {
         });
         return res;
     },
+    getSchedulingUnitTemplate: async function(id){
+        try {
+            const response = await axios.get(`/api/scheduling_unit_template/${id}`);
+            return response.data;
+        }   catch(error) {
+            console.error(error);
+            return null;
+        };
+    },
     getSchedulingSets: async function() {
         try {
             const response = await axios.get('/api/scheduling_set/');
@@ -624,12 +642,21 @@ const ScheduleService = {
         }
         return stationGroups;
     },
-      getProjectList: async function() {
+    getProjectList: async function() {
+    try {
+        const response = await axios.get('/api/project/');
+        return response.data.results;
+    } catch (error) {
+        console.error('[project.services.getProjectList]',error);
+    }
+    },
+    saveSchedulingSet: async function(suSet) {
         try {
-          const response = await axios.get('/api/project/');
-          return response.data.results;
+            const response = await axios.post(('/api/scheduling_set/'), suSet);
+            return response.data;
         } catch (error) {
-          console.error('[project.services.getProjectList]',error);
+            console.log(error.response.data);
+            return error.response.data;
         }
       }
 }
diff --git a/SAS/TMSS/frontend/tmss_webapp/src/services/workflow.service.js b/SAS/TMSS/frontend/tmss_webapp/src/services/workflow.service.js
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..4b8e9d4741f51f5f3ecf4f0b6b814d79b6496057 100644
--- a/SAS/TMSS/frontend/tmss_webapp/src/services/workflow.service.js
+++ b/SAS/TMSS/frontend/tmss_webapp/src/services/workflow.service.js
@@ -0,0 +1,98 @@
+const axios = require('axios');
+
+const WorkflowService = { 
+    getWorkflowProcesses: async function (){
+        let data = [];
+        try {
+            let initResponse = await axios.get('/workflow_api/scheduling_unit_flow/qa_scheduling_unit_process/?ordering=id');
+            data = initResponse.data.results;
+            const totalCount = initResponse.data.count;
+            const initialCount = initResponse.data.results.length;
+            if (initialCount < totalCount) {
+                let nextResponse = await axios.get(`/workflow_api/scheduling_unit_flow/qa_scheduling_unit_process/?ordering=id&limit=${totalCount-initialCount}&offset=${initialCount}`);
+                data = data.concat(nextResponse.data.results);
+            }
+        }   catch(error) {
+            console.log(error);
+        }
+        return data;
+    },
+    getWorkflowTasks: async function (){
+        let data = [];
+        try {
+            let initResponse = await axios.get('/workflow_api/scheduling_unit_flow/qa_scheduling_unit_task/?ordering=id');
+            data = initResponse.data.results;
+            const totalCount = initResponse.data.count;
+            const initialCount = initResponse.data.results.length;
+            if (initialCount < totalCount) {
+                let nextResponse = await axios.get(`/workflow_api/scheduling_unit_flow/qa_scheduling_unit_task/?ordering=id&limit=${totalCount-initialCount}&offset=${initialCount}`);
+                data = data.concat(nextResponse.data.results);
+            }
+        }   catch(error) {
+            console.log(error);
+        }
+        return data;
+    },
+    updateAssignTo: async (id, data) => {
+        try {
+            const response = await axios.post(`/workflow_api/scheduling_unit_flow/qa_scheduling_unit_task/${id}/assign/`, data);
+            return response.data;
+        }   catch(error) {
+            console.error('[workflow.services.updateAssignTo]',error);
+            return null;
+        }
+    },
+    updateQA_Perform: async (id, data) => {
+        try {
+            const response = await axios.post(`/workflow_api/scheduling_unit_flow/qa_scheduling_unit_process/${id}/perform/`, data);
+            return response.data;
+        }   catch(error) {
+            console.error('[workflow.services.updateQA_Perform]',error);
+            return null;
+        }
+    },
+    getSchedulingUnitTask: async () => {
+        try {
+            const response = await axios.get(`/workflow_api/scheduling_unit_flow/qa_scheduling_unit_task/`);
+            return response.data.results;
+        }   catch(error) {
+            console.error('[workflow.services.getSchedulingUnitTask]',error);
+        }
+    },
+    getCurrentTask: async (id) => {
+        let currentTask = null;
+        try {
+            const response = await axios.post(`/workflow_api/scheduling_unit_flow/qa_scheduling_unit_process/${id}/current_task/`);
+            currentTask = response.data[0];
+        }   catch(error) {
+            console.error('[workflow.services.current_task]',error);
+        }
+        return currentTask;
+    },
+    getQAReportingTo: async (id) => {
+        try {
+            const response = await axios.get(`/workflow_api/scheduling_unit_flow/qa_reporting_to/${id}`);
+            return response.data;
+        }   catch(error) {
+            console.error('[workflow.services.qa_reporting_to]',error);
+        }
+    },
+    getQAReportingSOS: async (id) => {
+        try {
+            const response = await axios.get(`/workflow_api/scheduling_unit_flow/qa_reporting_sos/${id}`);
+            return response.data;
+        }   catch(error) {
+            console.error('[workflow.services.qa_reporting_sos]',error);
+        }
+    },
+    getQAPIverification: async (id) => {
+        try {
+            const response = await axios.get(`/workflow_api/scheduling_unit_flow/qa_pi_verification/${id}`);
+            return response.data;
+        }   catch(error) {
+            console.error('[workflow.services.qa_pi_verification]',error);
+        }
+    }
+}
+
+export default WorkflowService;
diff --git a/SAS/TMSS/frontend/tmss_webapp/src/utils/validator.js b/SAS/TMSS/frontend/tmss_webapp/src/utils/validator.js
index b40341265ddb5d38f69424c954e867df9e020813..79107d64b50cb0ccdac9c9c91501dcff1b6c818d 100644
--- a/SAS/TMSS/frontend/tmss_webapp/src/utils/validator.js
+++ b/SAS/TMSS/frontend/tmss_webapp/src/utils/validator.js
@@ -1,34 +1,53 @@
 const Validator = {
     validateTime(value) {
+    const splitOutput = value.split(':');
+        if (splitOutput.length < 3) {
+            return false;
+        }   else {
+            if (parseInt(splitOutput[0]) > 23 || parseInt(splitOutput[1])>59 || parseInt(splitOutput[2])>59) {
+                return false;
+            }
+            const timeValue = parseInt(splitOutput[0]*60*60) + parseInt(splitOutput[1]*60) + parseInt(splitOutput[2]);
+            if (timeValue >= 86400) {
+                return false;
+            }
+        }
+        return true;
+    },
+    validateAngle(value) {
         const splitOutput = value.split(':');
         if (splitOutput.length < 3) {
             return false;
         }   else {
-              if (parseInt(splitOutput[0]) > 23 || parseInt(splitOutput[1])>59 || parseInt(splitOutput[2])>59) {
-                  return false;
-              }
-              const timeValue = parseInt(splitOutput[0]*60*60) + parseInt(splitOutput[1]*60) + parseInt(splitOutput[2]);
-              if (timeValue >= 86400) {
-                  return false;
-              }
-          }
-            return true;
-        },
-        validateAngle(value) {
-            const splitOutput = value.split(':');
-            if (splitOutput.length < 3) {
+            if (parseInt(splitOutput[0]) > 90 || parseInt(splitOutput[1])>59 || parseInt(splitOutput[2])>59) {
+                return false;
+            }
+            const timeValue = parseInt(splitOutput[0]*60*60) + parseInt(splitOutput[1]*60) + parseInt(splitOutput[2]);
+            if (timeValue > 324000) {
                 return false;
-            }   else {
-                  if (parseInt(splitOutput[0]) > 90 || parseInt(splitOutput[1])>59 || parseInt(splitOutput[2])>59) {
-                      return false;
-                  }
-                  const timeValue = parseInt(splitOutput[0]*60*60) + parseInt(splitOutput[1]*60) + parseInt(splitOutput[2]);
-                  if (timeValue > 324000) {
-                      return false;
-                  }
-              }
-              return true;
             }
+        }
+        return true;
+    },
+    /**
+     * Validates whether any of the given property values is modified comparing the old and new object.
+     * @param {Object} oldObject - old object that is already existing in the state list
+     * @param {Object} newObject - new object received from the websocket message
+     * @param {Array} properties - array of string (name of the properties) to veriy
+     */
+    isObjectModified(oldObject, newObject, properties) {
+        let isModified = false;
+        // If oldObject is not found, the object should be got from server
+        if(!oldObject && newObject) {
+            return true;
+        }
+        for (const property of properties) {
+            if (oldObject[property] !== newObject[property]) {
+                isModified = true;
+            }
+        }
+        return isModified;
+    }
 };
 
 export default Validator;